• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * WPA Supplicant / dbus-based control interface
3  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14 
15 #include "includes.h"
16 #include <dbus/dbus.h>
17 
18 #include "common.h"
19 #include "eloop.h"
20 #include "wps/wps.h"
21 #include "../config.h"
22 #include "../wpa_supplicant_i.h"
23 #include "../bss.h"
24 #include "dbus_old.h"
25 #include "dbus_old_handlers.h"
26 #include "dbus_common_i.h"
27 
28 
29 /**
30  * wpas_dbus_decompose_object_path - Decompose an interface object path into parts
31  * @path: The dbus object path
32  * @network: (out) the configured network this object path refers to, if any
33  * @bssid: (out) the scanned bssid this object path refers to, if any
34  * Returns: The object path of the network interface this path refers to
35  *
36  * For a given object path, decomposes the object path into object id, network,
37  * and BSSID parts, if those parts exist.
38  */
wpas_dbus_decompose_object_path(const char * path,char ** network,char ** bssid)39 char * wpas_dbus_decompose_object_path(const char *path, char **network,
40 				       char **bssid)
41 {
42 	const unsigned int dev_path_prefix_len =
43 		strlen(WPAS_DBUS_PATH_INTERFACES "/");
44 	char *obj_path_only;
45 	char *next_sep;
46 
47 	/* Be a bit paranoid about path */
48 	if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/",
49 			     dev_path_prefix_len))
50 		return NULL;
51 
52 	/* Ensure there's something at the end of the path */
53 	if ((path + dev_path_prefix_len)[0] == '\0')
54 		return NULL;
55 
56 	obj_path_only = os_strdup(path);
57 	if (obj_path_only == NULL)
58 		return NULL;
59 
60 	next_sep = strchr(obj_path_only + dev_path_prefix_len, '/');
61 	if (next_sep != NULL) {
62 		const char *net_part = strstr(next_sep,
63 					      WPAS_DBUS_NETWORKS_PART "/");
64 		const char *bssid_part = strstr(next_sep,
65 						WPAS_DBUS_BSSIDS_PART "/");
66 
67 		if (network && net_part) {
68 			/* Deal with a request for a configured network */
69 			const char *net_name = net_part +
70 				strlen(WPAS_DBUS_NETWORKS_PART "/");
71 			*network = NULL;
72 			if (strlen(net_name))
73 				*network = os_strdup(net_name);
74 		} else if (bssid && bssid_part) {
75 			/* Deal with a request for a scanned BSSID */
76 			const char *bssid_name = bssid_part +
77 				strlen(WPAS_DBUS_BSSIDS_PART "/");
78 			if (strlen(bssid_name))
79 				*bssid = os_strdup(bssid_name);
80 			else
81 				*bssid = NULL;
82 		}
83 
84 		/* Cut off interface object path before "/" */
85 		*next_sep = '\0';
86 	}
87 
88 	return obj_path_only;
89 }
90 
91 
92 /**
93  * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message
94  * @message: Pointer to incoming dbus message this error refers to
95  * Returns: A dbus error message
96  *
97  * Convenience function to create and return an invalid interface error
98  */
wpas_dbus_new_invalid_iface_error(DBusMessage * message)99 DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
100 {
101 	return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE,
102 				      "wpa_supplicant knows nothing about "
103 				      "this interface.");
104 }
105 
106 
107 /**
108  * wpas_dbus_new_invalid_network_error - Return a new invalid network error message
109  * @message: Pointer to incoming dbus message this error refers to
110  * Returns: a dbus error message
111  *
112  * Convenience function to create and return an invalid network error
113  */
wpas_dbus_new_invalid_network_error(DBusMessage * message)114 DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message)
115 {
116 	return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK,
117 				      "The requested network does not exist.");
118 }
119 
120 
121 /**
122  * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message
123  * @message: Pointer to incoming dbus message this error refers to
124  * Returns: a dbus error message
125  *
126  * Convenience function to create and return an invalid bssid error
127  */
wpas_dbus_new_invalid_bssid_error(DBusMessage * message)128 static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message)
129 {
130 	return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID,
131 				      "The BSSID requested was invalid.");
132 }
133 
134 
135 /**
136  * wpas_dispatch_network_method - dispatch messages for configured networks
137  * @message: the incoming dbus message
138  * @wpa_s: a network interface's data
139  * @network_id: id of the configured network we're interested in
140  * Returns: a reply dbus message, or a dbus error message
141  *
142  * This function dispatches all incoming dbus messages for configured networks.
143  */
wpas_dispatch_network_method(DBusMessage * message,struct wpa_supplicant * wpa_s,int network_id)144 static DBusMessage * wpas_dispatch_network_method(DBusMessage *message,
145 						  struct wpa_supplicant *wpa_s,
146 						  int network_id)
147 {
148 	DBusMessage *reply = NULL;
149 	const char *method = dbus_message_get_member(message);
150 	struct wpa_ssid *ssid;
151 
152 	ssid = wpa_config_get_network(wpa_s->conf, network_id);
153 	if (ssid == NULL)
154 		return wpas_dbus_new_invalid_network_error(message);
155 
156 	if (!strcmp(method, "set"))
157 		reply = wpas_dbus_iface_set_network(message, wpa_s, ssid);
158 	else if (!strcmp(method, "enable"))
159 		reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid);
160 	else if (!strcmp(method, "disable"))
161 		reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid);
162 
163 	return reply;
164 }
165 
166 
167 /**
168  * wpas_dispatch_bssid_method - dispatch messages for scanned networks
169  * @message: the incoming dbus message
170  * @wpa_s: a network interface's data
171  * @bssid: bssid of the scanned network we're interested in
172  * Returns: a reply dbus message, or a dbus error message
173  *
174  * This function dispatches all incoming dbus messages for scanned networks.
175  */
wpas_dispatch_bssid_method(DBusMessage * message,struct wpa_supplicant * wpa_s,const char * bssid_txt)176 static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message,
177 						struct wpa_supplicant *wpa_s,
178 						const char *bssid_txt)
179 {
180 	u8 bssid[ETH_ALEN];
181 	struct wpa_bss *bss;
182 
183 	if (hexstr2bin(bssid_txt, bssid, ETH_ALEN) < 0)
184 		return wpas_dbus_new_invalid_bssid_error(message);
185 
186 	bss = wpa_bss_get_bssid(wpa_s, bssid);
187 	if (bss == NULL)
188 		return wpas_dbus_new_invalid_bssid_error(message);
189 
190 	/* Dispatch the method call against the scanned bssid */
191 	if (os_strcmp(dbus_message_get_member(message), "properties") == 0)
192 		return wpas_dbus_bssid_properties(message, wpa_s, bss);
193 
194 	return NULL;
195 }
196 
197 
198 /**
199  * wpas_iface_message_handler - Dispatch messages for interfaces or networks
200  * @connection: Connection to the system message bus
201  * @message: An incoming dbus message
202  * @user_data: A pointer to a dbus control interface data structure
203  * Returns: Whether or not the message was handled
204  *
205  * This function dispatches all incoming dbus messages for network interfaces,
206  * or objects owned by them, such as scanned BSSIDs and configured networks.
207  */
wpas_iface_message_handler(DBusConnection * connection,DBusMessage * message,void * user_data)208 static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
209 						    DBusMessage *message,
210 						    void *user_data)
211 {
212 	struct wpa_supplicant *wpa_s = user_data;
213 	const char *method = dbus_message_get_member(message);
214 	const char *path = dbus_message_get_path(message);
215 	const char *msg_interface = dbus_message_get_interface(message);
216 	char *iface_obj_path = NULL;
217 	char *network = NULL;
218 	char *bssid = NULL;
219 	DBusMessage *reply = NULL;
220 
221 	/* Caller must specify a message interface */
222 	if (!msg_interface)
223 		goto out;
224 
225 	iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
226 	                                                 &bssid);
227 	if (iface_obj_path == NULL) {
228 		reply = wpas_dbus_new_invalid_iface_error(message);
229 		goto out;
230 	}
231 
232 	/* Make sure the message's object path actually refers to the
233 	 * wpa_supplicant structure it's supposed to (which is wpa_s)
234 	 */
235 	if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
236 	                                          iface_obj_path) != wpa_s) {
237 		reply = wpas_dbus_new_invalid_iface_error(message);
238 		goto out;
239 	}
240 
241 	if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
242 		/* A method for one of this interface's configured networks */
243 		int nid = strtoul(network, NULL, 10);
244 		if (errno != EINVAL)
245 			reply = wpas_dispatch_network_method(message, wpa_s,
246 							     nid);
247 		else
248 			reply = wpas_dbus_new_invalid_network_error(message);
249 	} else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) {
250 		/* A method for one of this interface's scanned BSSIDs */
251 		reply = wpas_dispatch_bssid_method(message, wpa_s, bssid);
252 	} else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) {
253 		/* A method for an interface only. */
254 		if (!strcmp(method, "scan"))
255 			reply = wpas_dbus_iface_scan(message, wpa_s);
256 		else if (!strcmp(method, "scanResults"))
257 			reply = wpas_dbus_iface_scan_results(message, wpa_s);
258 		else if (!strcmp(method, "addNetwork"))
259 			reply = wpas_dbus_iface_add_network(message, wpa_s);
260 		else if (!strcmp(method, "removeNetwork"))
261 			reply = wpas_dbus_iface_remove_network(message, wpa_s);
262 		else if (!strcmp(method, "selectNetwork"))
263 			reply = wpas_dbus_iface_select_network(message, wpa_s);
264 		else if (!strcmp(method, "capabilities"))
265 			reply = wpas_dbus_iface_capabilities(message, wpa_s);
266 		else if (!strcmp(method, "disconnect"))
267 			reply = wpas_dbus_iface_disconnect(message, wpa_s);
268 		else if (!strcmp(method, "setAPScan"))
269 			reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
270 		else if (!strcmp(method, "setSmartcardModules"))
271 			reply = wpas_dbus_iface_set_smartcard_modules(message,
272 								      wpa_s);
273 		else if (!strcmp(method, "state"))
274 			reply = wpas_dbus_iface_get_state(message, wpa_s);
275 		else if (!strcmp(method, "scanning"))
276 			reply = wpas_dbus_iface_get_scanning(message, wpa_s);
277 		else if (!strcmp(method, "setBlobs"))
278 			reply = wpas_dbus_iface_set_blobs(message, wpa_s);
279 		else if (!strcmp(method, "removeBlobs"))
280 			reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
281 #ifdef CONFIG_WPS
282 		else if (!os_strcmp(method, "wpsPbc"))
283 			reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
284 		else if (!os_strcmp(method, "wpsPin"))
285 			reply = wpas_dbus_iface_wps_pin(message, wpa_s);
286 		else if (!os_strcmp(method, "wpsReg"))
287 			reply = wpas_dbus_iface_wps_reg(message, wpa_s);
288 #endif /* CONFIG_WPS */
289 		else if (!os_strcmp(method, "flush"))
290 			reply = wpas_dbus_iface_flush(message, wpa_s);
291 	}
292 
293 	/* If the message was handled, send back the reply */
294 	if (reply) {
295 		if (!dbus_message_get_no_reply(message))
296 			dbus_connection_send(connection, reply, NULL);
297 		dbus_message_unref(reply);
298 	}
299 
300 out:
301 	os_free(iface_obj_path);
302 	os_free(network);
303 	os_free(bssid);
304 	return reply ? DBUS_HANDLER_RESULT_HANDLED :
305 		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
306 }
307 
308 
309 /**
310  * wpas_message_handler - dispatch incoming dbus messages
311  * @connection: connection to the system message bus
312  * @message: an incoming dbus message
313  * @user_data: a pointer to a dbus control interface data structure
314  * Returns: whether or not the message was handled
315  *
316  * This function dispatches all incoming dbus messages to the correct
317  * handlers, depending on what the message's target object path is,
318  * and what the method call is.
319  */
wpas_message_handler(DBusConnection * connection,DBusMessage * message,void * user_data)320 static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
321 	DBusMessage *message, void *user_data)
322 {
323 	struct wpas_dbus_priv *ctrl_iface = user_data;
324 	const char *method;
325 	const char *path;
326 	const char *msg_interface;
327 	DBusMessage *reply = NULL;
328 
329 	method = dbus_message_get_member(message);
330 	path = dbus_message_get_path(message);
331 	msg_interface = dbus_message_get_interface(message);
332 	if (!method || !path || !ctrl_iface || !msg_interface)
333 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
334 
335 	/* Validate the method interface */
336 	if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
337 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
338 
339 	if (!strcmp(path, WPAS_DBUS_PATH)) {
340 		/* dispatch methods against our global dbus interface here */
341 		if (!strcmp(method, "addInterface")) {
342 			reply = wpas_dbus_global_add_interface(
343 				message, ctrl_iface->global);
344 		} else if (!strcmp(method, "removeInterface")) {
345 			reply = wpas_dbus_global_remove_interface(
346 				message, ctrl_iface->global);
347 		} else if (!strcmp(method, "getInterface")) {
348 			reply = wpas_dbus_global_get_interface(
349 				message, ctrl_iface->global);
350 		} else if (!strcmp(method, "setDebugParams")) {
351 			reply = wpas_dbus_global_set_debugparams(
352 				message, ctrl_iface->global);
353 		}
354 	}
355 
356 	/* If the message was handled, send back the reply */
357 	if (reply) {
358 		if (!dbus_message_get_no_reply(message))
359 			dbus_connection_send(connection, reply, NULL);
360 		dbus_message_unref(reply);
361 	}
362 
363 	return reply ? DBUS_HANDLER_RESULT_HANDLED :
364 		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
365 }
366 
367 
368 /**
369  * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal
370  * @wpa_s: %wpa_supplicant network interface data
371  * Returns: 0 on success, -1 on failure
372  *
373  * Notify listeners that this interface has updated scan results.
374  */
wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant * wpa_s)375 void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
376 {
377 	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
378 	DBusMessage *_signal;
379 
380 	/* Do nothing if the control interface is not turned on */
381 	if (iface == NULL)
382 		return;
383 
384 	_signal = dbus_message_new_signal(wpa_s->dbus_path,
385 					  WPAS_DBUS_IFACE_INTERFACE,
386 					  "ScanResultsAvailable");
387 	if (_signal == NULL) {
388 		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
389 			   "results signal");
390 		return;
391 	}
392 	dbus_connection_send(iface->con, _signal, NULL);
393 	dbus_message_unref(_signal);
394 }
395 
396 
397 /**
398  * wpa_supplicant_dbus_notify_state_change - Send a state change signal
399  * @wpa_s: %wpa_supplicant network interface data
400  * @new_state: new state wpa_supplicant is entering
401  * @old_state: old state wpa_supplicant is leaving
402  * Returns: 0 on success, -1 on failure
403  *
404  * Notify listeners that wpa_supplicant has changed state
405  */
wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant * wpa_s,enum wpa_states new_state,enum wpa_states old_state)406 void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
407 					     enum wpa_states new_state,
408 					     enum wpa_states old_state)
409 {
410 	struct wpas_dbus_priv *iface;
411 	DBusMessage *_signal = NULL;
412 	const char *new_state_str, *old_state_str;
413 
414 	if (wpa_s->dbus_path == NULL)
415 		return; /* Skip signal since D-Bus setup is not yet ready */
416 
417 	/* Do nothing if the control interface is not turned on */
418 	if (wpa_s->global == NULL)
419 		return;
420 	iface = wpa_s->global->dbus;
421 	if (iface == NULL)
422 		return;
423 
424 	/* Only send signal if state really changed */
425 	if (new_state == old_state)
426 		return;
427 
428 	_signal = dbus_message_new_signal(wpa_s->dbus_path,
429 					  WPAS_DBUS_IFACE_INTERFACE,
430 					  "StateChange");
431 	if (_signal == NULL) {
432 		wpa_printf(MSG_ERROR,
433 		           "dbus: wpa_supplicant_dbus_notify_state_change: "
434 		           "could not create dbus signal; likely out of "
435 		           "memory");
436 		return;
437 	}
438 
439 	new_state_str = wpa_supplicant_state_txt(new_state);
440 	old_state_str = wpa_supplicant_state_txt(old_state);
441 	if (new_state_str == NULL || old_state_str == NULL) {
442 		wpa_printf(MSG_ERROR,
443 		           "dbus: wpa_supplicant_dbus_notify_state_change: "
444 		           "Could not convert state strings");
445 		goto out;
446 	}
447 
448 	if (!dbus_message_append_args(_signal,
449 	                              DBUS_TYPE_STRING, &new_state_str,
450 	                              DBUS_TYPE_STRING, &old_state_str,
451 	                              DBUS_TYPE_INVALID)) {
452 		wpa_printf(MSG_ERROR,
453 		           "dbus: wpa_supplicant_dbus_notify_state_change: "
454 		           "Not enough memory to construct state change "
455 		           "signal");
456 		goto out;
457 	}
458 
459 	dbus_connection_send(iface->con, _signal, NULL);
460 
461 out:
462 	dbus_message_unref(_signal);
463 }
464 
465 
466 /**
467  * wpa_supplicant_dbus_notify_scanning - send scanning status
468  * @wpa_s: %wpa_supplicant network interface data
469  * Returns: 0 on success, -1 on failure
470  *
471  * Notify listeners of interface scanning state changes
472  */
wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant * wpa_s)473 void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
474 {
475 	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
476 	DBusMessage *_signal;
477 	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
478 
479 	/* Do nothing if the control interface is not turned on */
480 	if (iface == NULL)
481 		return;
482 
483 	_signal = dbus_message_new_signal(wpa_s->dbus_path,
484 					  WPAS_DBUS_IFACE_INTERFACE,
485 					  "Scanning");
486 	if (_signal == NULL) {
487 		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
488 			   "results signal");
489 		return;
490 	}
491 
492 	if (dbus_message_append_args(_signal,
493 	                             DBUS_TYPE_BOOLEAN, &scanning,
494 	                             DBUS_TYPE_INVALID)) {
495 		dbus_connection_send(iface->con, _signal, NULL);
496 	} else {
497 		wpa_printf(MSG_ERROR, "dbus: Not enough memory to construct "
498 			   "signal");
499 	}
500 	dbus_message_unref(_signal);
501 }
502 
503 
504 #ifdef CONFIG_WPS
wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant * wpa_s,const struct wps_credential * cred)505 void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
506 					 const struct wps_credential *cred)
507 {
508 	struct wpas_dbus_priv *iface;
509 	DBusMessage *_signal = NULL;
510 
511 	/* Do nothing if the control interface is not turned on */
512 	if (wpa_s->global == NULL)
513 		return;
514 	iface = wpa_s->global->dbus;
515 	if (iface == NULL)
516 		return;
517 
518 	_signal = dbus_message_new_signal(wpa_s->dbus_path,
519 					  WPAS_DBUS_IFACE_INTERFACE,
520 					  "WpsCred");
521 	if (_signal == NULL) {
522 		wpa_printf(MSG_ERROR,
523 		           "dbus: wpa_supplicant_dbus_notify_wps_cred: "
524 		           "Could not create dbus signal; likely out of "
525 		           "memory");
526 		return;
527 	}
528 
529 	if (!dbus_message_append_args(_signal,
530 	                              DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
531 				      &cred->cred_attr, cred->cred_attr_len,
532 	                              DBUS_TYPE_INVALID)) {
533 		wpa_printf(MSG_ERROR,
534 		           "dbus: wpa_supplicant_dbus_notify_wps_cred: "
535 		           "Not enough memory to construct signal");
536 		goto out;
537 	}
538 
539 	dbus_connection_send(iface->con, _signal, NULL);
540 
541 out:
542 	dbus_message_unref(_signal);
543 }
544 #else /* CONFIG_WPS */
wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant * wpa_s,const struct wps_credential * cred)545 void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
546 					 const struct wps_credential *cred)
547 {
548 }
549 #endif /* CONFIG_WPS */
550 
wpa_supplicant_dbus_notify_certification(struct wpa_supplicant * wpa_s,int depth,const char * subject,const char * cert_hash,const struct wpabuf * cert)551 void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
552 					      int depth, const char *subject,
553 					      const char *cert_hash,
554 					      const struct wpabuf *cert)
555 {
556 	struct wpas_dbus_priv *iface;
557 	DBusMessage *_signal = NULL;
558 	const char *hash;
559 	const char *cert_hex;
560 	int cert_hex_len;
561 
562 	/* Do nothing if the control interface is not turned on */
563 	if (wpa_s->global == NULL)
564 		return;
565 	iface = wpa_s->global->dbus;
566 	if (iface == NULL)
567 		return;
568 
569 	_signal = dbus_message_new_signal(wpa_s->dbus_path,
570 					  WPAS_DBUS_IFACE_INTERFACE,
571 					  "Certification");
572 	if (_signal == NULL) {
573 		wpa_printf(MSG_ERROR,
574 		           "dbus: wpa_supplicant_dbus_notify_certification: "
575 		           "Could not create dbus signal; likely out of "
576 		           "memory");
577 		return;
578 	}
579 
580 	hash = cert_hash ? cert_hash : "";
581 	cert_hex = cert ? wpabuf_head(cert) : "";
582 	cert_hex_len = cert ? wpabuf_len(cert) : 0;
583 
584 	if (!dbus_message_append_args(_signal,
585 				      DBUS_TYPE_INT32,&depth,
586 				      DBUS_TYPE_STRING, &subject,
587 	                              DBUS_TYPE_STRING, &hash,
588 	                              DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
589 				      &cert_hex, cert_hex_len,
590 	                              DBUS_TYPE_INVALID)) {
591 		wpa_printf(MSG_ERROR,
592 		           "dbus: wpa_supplicant_dbus_notify_certification: "
593 		           "Not enough memory to construct signal");
594 		goto out;
595 	}
596 
597 	dbus_connection_send(iface->con, _signal, NULL);
598 
599 out:
600 	dbus_message_unref(_signal);
601 
602 }
603 
604 
605 /**
606  * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
607  * @global: Pointer to global data from wpa_supplicant_init()
608  * Returns: 0 on success, -1 on failure
609  *
610  * Initialize the dbus control interface and start receiving commands from
611  * external programs over the bus.
612  */
wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv * iface)613 int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface)
614 {
615 	DBusError error;
616 	int ret = -1;
617 	DBusObjectPathVTable wpas_vtable = {
618 		NULL, &wpas_message_handler, NULL, NULL, NULL, NULL
619 	};
620 
621 	/* Register the message handler for the global dbus interface */
622 	if (!dbus_connection_register_object_path(iface->con,
623 						  WPAS_DBUS_PATH, &wpas_vtable,
624 						  iface)) {
625 		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
626 			   "handler");
627 		return -1;
628 	}
629 
630 	/* Register our service with the message bus */
631 	dbus_error_init(&error);
632 	switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE,
633 				      0, &error)) {
634 	case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
635 		ret = 0;
636 		break;
637 	case DBUS_REQUEST_NAME_REPLY_EXISTS:
638 	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
639 	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
640 		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
641 			   "already registered");
642 		break;
643 	default:
644 		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
645 			   "%s %s", error.name, error.message);
646 		break;
647 	}
648 	dbus_error_free(&error);
649 
650 	if (ret != 0)
651 		return -1;
652 
653 	wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE
654 		   "'.");
655 
656 	return 0;
657 }
658 
659 
660 /**
661  * wpas_dbus_register_new_iface - Register a new interface with dbus
662  * @wpa_s: %wpa_supplicant interface description structure to register
663  * Returns: 0 on success, -1 on error
664  *
665  * Registers a new interface with dbus and assigns it a dbus object path.
666  */
wpas_dbus_register_iface(struct wpa_supplicant * wpa_s)667 int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
668 {
669 	struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
670 	DBusConnection * con;
671 	u32 next;
672 	DBusObjectPathVTable vtable = {
673 		NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL
674 	};
675 
676 	/* Do nothing if the control interface is not turned on */
677 	if (ctrl_iface == NULL)
678 		return 0;
679 
680 	con = ctrl_iface->con;
681 	next = ctrl_iface->next_objid++;
682 
683 	/* Create and set the interface's object path */
684 	wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
685 	if (wpa_s->dbus_path == NULL)
686 		return -1;
687 	os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX,
688 		    WPAS_DBUS_PATH_INTERFACES "/%u",
689 		    next);
690 
691 	/* Register the message handler for the interface functions */
692 	if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable,
693 					       wpa_s)) {
694 		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
695 			   "handler for interface %s", wpa_s->ifname);
696 		return -1;
697 	}
698 
699 	return 0;
700 }
701 
702 
703 /**
704  * wpas_dbus_unregister_iface - Unregister an interface from dbus
705  * @wpa_s: wpa_supplicant interface structure
706  * Returns: 0 on success, -1 on failure
707  *
708  * Unregisters the interface with dbus
709  */
wpas_dbus_unregister_iface(struct wpa_supplicant * wpa_s)710 int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
711 {
712 	struct wpas_dbus_priv *ctrl_iface;
713 	DBusConnection *con;
714 
715 	/* Do nothing if the control interface is not turned on */
716 	if (wpa_s == NULL || wpa_s->global == NULL)
717 		return 0;
718 	ctrl_iface = wpa_s->global->dbus;
719 	if (ctrl_iface == NULL)
720 		return 0;
721 
722 	con = ctrl_iface->con;
723 	if (!dbus_connection_unregister_object_path(con, wpa_s->dbus_path))
724 		return -1;
725 
726 	os_free(wpa_s->dbus_path);
727 	wpa_s->dbus_path = NULL;
728 
729 	return 0;
730 }
731 
732 
733 /**
734  * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface
735  * @global: Pointer to global data from wpa_supplicant_init()
736  * @path: Pointer to a dbus object path representing an interface
737  * Returns: Pointer to the interface or %NULL if not found
738  */
wpa_supplicant_get_iface_by_dbus_path(struct wpa_global * global,const char * path)739 struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
740 	struct wpa_global *global, const char *path)
741 {
742 	struct wpa_supplicant *wpa_s;
743 
744 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
745 		if (strcmp(wpa_s->dbus_path, path) == 0)
746 			return wpa_s;
747 	}
748 	return NULL;
749 }
750