• 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 
17 #include "common.h"
18 #include "config.h"
19 #include "wpa_supplicant_i.h"
20 #include "ctrl_iface_dbus.h"
21 #include "ctrl_iface_dbus_handlers.h"
22 #include "eap_peer/eap_methods.h"
23 #include "dbus_dict_helpers.h"
24 #include "ieee802_11_defs.h"
25 #include "wpas_glue.h"
26 #include "eapol_supp/eapol_supp_sm.h"
27 #include "wpa.h"
28 
29 extern int wpa_debug_level;
30 extern int wpa_debug_show_keys;
31 extern int wpa_debug_timestamp;
32 
33 /**
34  * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
35  * @message: Pointer to incoming dbus message this error refers to
36  * Returns: a dbus error message
37  *
38  * Convenience function to create and return an invalid options error
39  */
wpas_dbus_new_invalid_opts_error(DBusMessage * message,const char * arg)40 static DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
41 						      const char *arg)
42 {
43 	DBusMessage *reply;
44 
45 	reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS,
46 				      "Did not receive correct message "
47 				      "arguments.");
48 	if (arg != NULL)
49 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
50 					 DBUS_TYPE_INVALID);
51 
52 	return reply;
53 }
54 
55 
56 /**
57  * wpas_dbus_new_success_reply - Return a new success reply message
58  * @message: Pointer to incoming dbus message this reply refers to
59  * Returns: a dbus message containing a single UINT32 that indicates
60  *          success (ie, a value of 1)
61  *
62  * Convenience function to create and return a success reply message
63  */
wpas_dbus_new_success_reply(DBusMessage * message)64 static DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message)
65 {
66 	DBusMessage *reply;
67 	unsigned int success = 1;
68 
69 	reply = dbus_message_new_method_return(message);
70 	dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success,
71 				 DBUS_TYPE_INVALID);
72 	return reply;
73 }
74 
75 
wpas_dbus_free_wpa_interface(struct wpa_interface * iface)76 static void wpas_dbus_free_wpa_interface(struct wpa_interface *iface)
77 {
78 	free((char *) iface->driver);
79 	free((char *) iface->driver_param);
80 	free((char *) iface->confname);
81 	free((char *) iface->bridge_ifname);
82 }
83 
84 
85 /**
86  * wpas_dbus_global_add_interface - Request registration of a network interface
87  * @message: Pointer to incoming dbus message
88  * @global: %wpa_supplicant global data structure
89  * Returns: The object path of the new interface object,
90  *          or a dbus error message with more information
91  *
92  * Handler function for "addInterface" method call. Handles requests
93  * by dbus clients to register a network interface that wpa_supplicant
94  * will manage.
95  */
wpas_dbus_global_add_interface(DBusMessage * message,struct wpa_global * global)96 DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
97 					     struct wpa_global *global)
98 {
99 	struct wpa_interface iface;
100 	char *ifname = NULL;
101 	DBusMessage *reply = NULL;
102 	DBusMessageIter iter;
103 
104 	memset(&iface, 0, sizeof(iface));
105 
106 	dbus_message_iter_init(message, &iter);
107 
108 	/* First argument: interface name (DBUS_TYPE_STRING)
109 	 *    Required; must be non-zero length
110 	 */
111 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
112 		goto error;
113 	dbus_message_iter_get_basic(&iter, &ifname);
114 	if (!strlen(ifname))
115 		goto error;
116 	iface.ifname = ifname;
117 
118 	/* Second argument: dict of options */
119 	if (dbus_message_iter_next(&iter)) {
120 		DBusMessageIter iter_dict;
121 		struct wpa_dbus_dict_entry entry;
122 
123 		if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
124 			goto error;
125 		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
126 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
127 				goto error;
128 			if (!strcmp(entry.key, "driver") &&
129 			    (entry.type == DBUS_TYPE_STRING)) {
130 				iface.driver = strdup(entry.str_value);
131 				if (iface.driver == NULL)
132 					goto error;
133 			} else if (!strcmp(entry.key, "driver-params") &&
134 				   (entry.type == DBUS_TYPE_STRING)) {
135 				iface.driver_param = strdup(entry.str_value);
136 				if (iface.driver_param == NULL)
137 					goto error;
138 			} else if (!strcmp(entry.key, "config-file") &&
139 				   (entry.type == DBUS_TYPE_STRING)) {
140 				iface.confname = strdup(entry.str_value);
141 				if (iface.confname == NULL)
142 					goto error;
143 			} else if (!strcmp(entry.key, "bridge-ifname") &&
144 				   (entry.type == DBUS_TYPE_STRING)) {
145 				iface.bridge_ifname = strdup(entry.str_value);
146 				if (iface.bridge_ifname == NULL)
147 					goto error;
148 			} else {
149 				wpa_dbus_dict_entry_clear(&entry);
150 				goto error;
151 			}
152 			wpa_dbus_dict_entry_clear(&entry);
153 		}
154 	}
155 
156 	/*
157 	 * Try to get the wpa_supplicant record for this iface, return
158 	 * an error if we already control it.
159 	 */
160 	if (wpa_supplicant_get_iface(global, iface.ifname) != NULL) {
161 		reply = dbus_message_new_error(message,
162 					       WPAS_ERROR_EXISTS_ERROR,
163 					       "wpa_supplicant already "
164 					       "controls this interface.");
165 	} else {
166 		struct wpa_supplicant *wpa_s;
167 		/* Otherwise, have wpa_supplicant attach to it. */
168 		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
169 			const char *path = wpa_supplicant_get_dbus_path(wpa_s);
170 			reply = dbus_message_new_method_return(message);
171 			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
172 			                         &path, DBUS_TYPE_INVALID);
173 		} else {
174 			reply = dbus_message_new_error(message,
175 						       WPAS_ERROR_ADD_ERROR,
176 						       "wpa_supplicant "
177 						       "couldn't grab this "
178 						       "interface.");
179 		}
180 	}
181 	wpas_dbus_free_wpa_interface(&iface);
182 	return reply;
183 
184 error:
185 	wpas_dbus_free_wpa_interface(&iface);
186 	return wpas_dbus_new_invalid_opts_error(message, NULL);
187 }
188 
189 
190 /**
191  * wpas_dbus_global_remove_interface - Request deregistration of an interface
192  * @message: Pointer to incoming dbus message
193  * @global: wpa_supplicant global data structure
194  * Returns: a dbus message containing a UINT32 indicating success (1) or
195  *          failure (0), or returns a dbus error message with more information
196  *
197  * Handler function for "removeInterface" method call.  Handles requests
198  * by dbus clients to deregister a network interface that wpa_supplicant
199  * currently manages.
200  */
wpas_dbus_global_remove_interface(DBusMessage * message,struct wpa_global * global)201 DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
202 						struct wpa_global *global)
203 {
204 	struct wpa_supplicant *wpa_s;
205 	char *path;
206 	DBusMessage *reply = NULL;
207 
208 	if (!dbus_message_get_args(message, NULL,
209 				   DBUS_TYPE_OBJECT_PATH, &path,
210 				   DBUS_TYPE_INVALID)) {
211 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
212 		goto out;
213 	}
214 
215 	wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path);
216 	if (wpa_s == NULL) {
217 		reply = wpas_dbus_new_invalid_iface_error(message);
218 		goto out;
219 	}
220 
221 	if (!wpa_supplicant_remove_iface(global, wpa_s)) {
222 		reply = wpas_dbus_new_success_reply(message);
223 	} else {
224 		reply = dbus_message_new_error(message,
225 					       WPAS_ERROR_REMOVE_ERROR,
226 					       "wpa_supplicant couldn't "
227 					       "remove this interface.");
228 	}
229 
230 out:
231 	return reply;
232 }
233 
234 
235 /**
236  * wpas_dbus_global_get_interface - Get the object path for an interface name
237  * @message: Pointer to incoming dbus message
238  * @global: %wpa_supplicant global data structure
239  * Returns: The object path of the interface object,
240  *          or a dbus error message with more information
241  *
242  * Handler function for "getInterface" method call. Handles requests
243  * by dbus clients for the object path of an specific network interface.
244  */
wpas_dbus_global_get_interface(DBusMessage * message,struct wpa_global * global)245 DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
246 					     struct wpa_global *global)
247 {
248 	DBusMessage *reply = NULL;
249 	const char *ifname;
250 	const char *path;
251 	struct wpa_supplicant *wpa_s;
252 
253 	if (!dbus_message_get_args(message, NULL,
254 	                           DBUS_TYPE_STRING, &ifname,
255 	                           DBUS_TYPE_INVALID)) {
256 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
257 		goto out;
258 	}
259 
260 	wpa_s = wpa_supplicant_get_iface(global, ifname);
261 	if (wpa_s == NULL) {
262 		reply = wpas_dbus_new_invalid_iface_error(message);
263 		goto out;
264 	}
265 
266 	path = wpa_supplicant_get_dbus_path(wpa_s);
267 	if (path == NULL) {
268 		reply = dbus_message_new_error(message,
269 		                               WPAS_ERROR_INTERNAL_ERROR,
270 		                               "an internal error occurred "
271 		                               "getting the interface.");
272 		goto out;
273 	}
274 
275 	reply = dbus_message_new_method_return(message);
276 	dbus_message_append_args(reply,
277 	                         DBUS_TYPE_OBJECT_PATH, &path,
278 	                         DBUS_TYPE_INVALID);
279 
280 out:
281 	return reply;
282 }
283 
284 /**
285  * wpas_dbus_global_set_debugparams- Set the debug params
286  * @message: Pointer to incoming dbus message
287  * @global: %wpa_supplicant global data structure
288  * Returns: a dbus message containing a UINT32 indicating success (1) or
289  *          failure (0), or returns a dbus error message with more information
290  *
291  * Handler function for "setDebugParams" method call. Handles requests
292  * by dbus clients for the object path of an specific network interface.
293  */
wpas_dbus_global_set_debugparams(DBusMessage * message,struct wpa_global * global)294 DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
295 					       struct wpa_global *global)
296 {
297 	DBusMessage *reply = NULL;
298 	int debug_level;
299 	dbus_bool_t debug_timestamp;
300 	dbus_bool_t debug_show_keys;
301 
302 	if (!dbus_message_get_args(message, NULL,
303 	                           DBUS_TYPE_INT32, &debug_level,
304 	                           DBUS_TYPE_BOOLEAN, &debug_timestamp,
305 	                           DBUS_TYPE_BOOLEAN, &debug_show_keys,
306 	                           DBUS_TYPE_INVALID)) {
307 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
308 		goto out;
309 	}
310 
311 	/* check for allowed debuglevels */
312 	if (debug_level != MSG_MSGDUMP &&
313 	    debug_level != MSG_DEBUG &&
314 	    debug_level != MSG_INFO &&
315 	    debug_level != MSG_WARNING &&
316 	    debug_level != MSG_ERROR) {
317 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
318 		goto out;
319 	}
320 
321 	wpa_debug_level = debug_level;
322 	wpa_debug_timestamp = debug_timestamp ? 1 : 0;
323 	wpa_debug_show_keys = debug_show_keys ? 1 : 0;
324 	reply = wpas_dbus_new_success_reply(message);
325 
326 out:
327 	return reply;
328 }
329 
330 /**
331  * wpas_dbus_iface_scan - Request a wireless scan on an interface
332  * @message: Pointer to incoming dbus message
333  * @wpa_s: wpa_supplicant structure for a network interface
334  * Returns: a dbus message containing a UINT32 indicating success (1) or
335  *          failure (0)
336  *
337  * Handler function for "scan" method call of a network device. Requests
338  * that wpa_supplicant perform a wireless scan as soon as possible
339  * on a particular wireless interface.
340  */
wpas_dbus_iface_scan(DBusMessage * message,struct wpa_supplicant * wpa_s)341 DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
342 				   struct wpa_supplicant *wpa_s)
343 {
344 	wpa_s->scan_req = 2;
345 	wpa_supplicant_req_scan(wpa_s, 0, 0);
346 	return wpas_dbus_new_success_reply(message);
347 }
348 
349 
350 /**
351  * wpas_dbus_iface_scan_results - Get the results of a recent scan request
352  * @message: Pointer to incoming dbus message
353  * @wpa_s: wpa_supplicant structure for a network interface
354  * Returns: a dbus message containing a dbus array of objects paths, or returns
355  *          a dbus error message if not scan results could be found
356  *
357  * Handler function for "scanResults" method call of a network device. Returns
358  * a dbus message containing the object paths of wireless networks found.
359  */
wpas_dbus_iface_scan_results(DBusMessage * message,struct wpa_supplicant * wpa_s)360 DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
361 					   struct wpa_supplicant *wpa_s)
362 {
363 	DBusMessage *reply = NULL;
364 	DBusMessageIter iter;
365 	DBusMessageIter sub_iter;
366 	size_t i;
367 
368 	/* Ensure we've actually got scan results to return */
369 	if (wpa_s->scan_res == NULL &&
370 	    wpa_supplicant_get_scan_results(wpa_s) < 0) {
371 		reply = dbus_message_new_error(message, WPAS_ERROR_SCAN_ERROR,
372 					       "An error ocurred getting scan "
373 					       "results.");
374 		goto out;
375 	}
376 
377 	/* Create and initialize the return message */
378 	reply = dbus_message_new_method_return(message);
379 	dbus_message_iter_init_append(reply, &iter);
380 	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
381 					 DBUS_TYPE_OBJECT_PATH_AS_STRING,
382 					 &sub_iter);
383 
384 	/* Loop through scan results and append each result's object path */
385 	for (i = 0; i < wpa_s->scan_res->num; i++) {
386 		struct wpa_scan_res *res = wpa_s->scan_res->res[i];
387 		char *path;
388 
389 		path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
390 		if (path == NULL) {
391 			perror("wpas_dbus_iface_scan_results[dbus]: out of "
392 			       "memory.");
393 			wpa_printf(MSG_ERROR, "dbus control interface: not "
394 				   "enough memory to send scan results "
395 				   "signal.");
396 			break;
397 		}
398 		/* Construct the object path for this network.  Note that ':'
399 		 * is not a valid character in dbus object paths.
400 		 */
401 		snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
402 			 "%s/" WPAS_DBUS_BSSIDS_PART "/"
403 			 WPAS_DBUS_BSSID_FORMAT,
404 			 wpa_supplicant_get_dbus_path(wpa_s),
405 			 MAC2STR(res->bssid));
406 		dbus_message_iter_append_basic(&sub_iter,
407 					       DBUS_TYPE_OBJECT_PATH, &path);
408 		free(path);
409 	}
410 
411 	dbus_message_iter_close_container(&iter, &sub_iter);
412 
413 out:
414 	return reply;
415 }
416 
417 
418 /**
419  * wpas_dbus_bssid_properties - Return the properties of a scanned network
420  * @message: Pointer to incoming dbus message
421  * @wpa_s: wpa_supplicant structure for a network interface
422  * @res: wpa_supplicant scan result for which to get properties
423  * Returns: a dbus message containing the properties for the requested network
424  *
425  * Handler function for "properties" method call of a scanned network.
426  * Returns a dbus message containing the the properties.
427  */
wpas_dbus_bssid_properties(DBusMessage * message,struct wpa_supplicant * wpa_s,struct wpa_scan_res * res)428 DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
429 					 struct wpa_supplicant *wpa_s,
430 					 struct wpa_scan_res *res)
431 {
432 	DBusMessage *reply = NULL;
433 	DBusMessageIter iter, iter_dict;
434 	const u8 *ie;
435 
436 	/* Dump the properties into a dbus message */
437 	reply = dbus_message_new_method_return(message);
438 
439 	dbus_message_iter_init_append(reply, &iter);
440 	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
441 		goto error;
442 
443 	if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
444 					     (const char *) res->bssid,
445 					     ETH_ALEN))
446 		goto error;
447 
448 	ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
449 	if (ie) {
450 		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
451 						     (const char *) (ie + 2),
452 						     ie[1]))
453 		goto error;
454 	}
455 
456 	ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
457 	if (ie) {
458 		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
459 						     (const char *) ie,
460 						     ie[1] + 2))
461 			goto error;
462 	}
463 
464 	ie = wpa_scan_get_ie(res, WLAN_EID_RSN);
465 	if (ie) {
466 		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
467 						     (const char *) ie,
468 						     ie[1] + 2))
469 			goto error;
470 	}
471 
472 	ie = wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE);
473 	if (ie) {
474 		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
475 						     (const char *) ie,
476 						     ie[1] + 2))
477 			goto error;
478 	}
479 
480 	if (res->freq) {
481 		if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
482 						res->freq))
483 			goto error;
484 	}
485 	if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
486 					 res->caps))
487 		goto error;
488 	if (!wpa_dbus_dict_append_int32(&iter_dict, "quality", res->qual))
489 		goto error;
490 	if (!wpa_dbus_dict_append_int32(&iter_dict, "noise", res->noise))
491 		goto error;
492 	if (!wpa_dbus_dict_append_int32(&iter_dict, "level", res->level))
493 		goto error;
494 	if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
495 					wpa_scan_get_max_rate(res) * 500000))
496 		goto error;
497 
498 	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
499 		goto error;
500 
501 	return reply;
502 
503 error:
504 	if (reply)
505 		dbus_message_unref(reply);
506 	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
507 				      "an internal error occurred returning "
508 				      "BSSID properties.");
509 }
510 
511 
512 /**
513  * wpas_dbus_iface_capabilities - Return interface capabilities
514  * @message: Pointer to incoming dbus message
515  * @wpa_s: wpa_supplicant structure for a network interface
516  * Returns: A dbus message containing a dict of strings
517  *
518  * Handler function for "capabilities" method call of an interface.
519  */
wpas_dbus_iface_capabilities(DBusMessage * message,struct wpa_supplicant * wpa_s)520 DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
521 					   struct wpa_supplicant *wpa_s)
522 {
523 	DBusMessage *reply = NULL;
524 	struct wpa_driver_capa capa;
525 	int res;
526 	DBusMessageIter iter, iter_dict;
527 	char **eap_methods;
528 	size_t num_items;
529 	dbus_bool_t strict = FALSE;
530 	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
531 
532 	if (!dbus_message_get_args(message, NULL,
533 				   DBUS_TYPE_BOOLEAN, &strict,
534 				   DBUS_TYPE_INVALID))
535 		strict = FALSE;
536 
537 	reply = dbus_message_new_method_return(message);
538 
539 	dbus_message_iter_init_append(reply, &iter);
540 	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
541 		goto error;
542 
543 	/* EAP methods */
544 	eap_methods = eap_get_names_as_string_array(&num_items);
545 	if (eap_methods) {
546 		dbus_bool_t success = FALSE;
547 		size_t i = 0;
548 
549 		success = wpa_dbus_dict_append_string_array(
550 			&iter_dict, "eap", (const char **) eap_methods,
551 			num_items);
552 
553 		/* free returned method array */
554 		while (eap_methods[i])
555 			free(eap_methods[i++]);
556 		free(eap_methods);
557 
558 		if (!success)
559 			goto error;
560 	}
561 
562 	res = wpa_drv_get_capa(wpa_s, &capa);
563 
564 	/***** pairwise cipher */
565 	if (res < 0) {
566 		if (!strict) {
567 			const char *args[] = {"CCMP", "TKIP", "NONE"};
568 			if (!wpa_dbus_dict_append_string_array(
569 				    &iter_dict, "pairwise", args,
570 				    sizeof(args) / sizeof(char*)))
571 				goto error;
572 		}
573 	} else {
574 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
575 						      &iter_dict_entry,
576 						      &iter_dict_val,
577 						      &iter_array))
578 			goto error;
579 
580 		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
581 			if (!wpa_dbus_dict_string_array_add_element(
582 				    &iter_array, "CCMP"))
583 				goto error;
584 		}
585 
586 		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
587 			if (!wpa_dbus_dict_string_array_add_element(
588 				    &iter_array, "TKIP"))
589 				goto error;
590 		}
591 
592 		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
593 			if (!wpa_dbus_dict_string_array_add_element(
594 				    &iter_array, "NONE"))
595 				goto error;
596 		}
597 
598 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
599 						    &iter_dict_entry,
600 						    &iter_dict_val,
601 						    &iter_array))
602 			goto error;
603 	}
604 
605 	/***** group cipher */
606 	if (res < 0) {
607 		if (!strict) {
608 			const char *args[] = {
609 				"CCMP", "TKIP", "WEP104", "WEP40"
610 			};
611 			if (!wpa_dbus_dict_append_string_array(
612 				    &iter_dict, "group", args,
613 				    sizeof(args) / sizeof(char*)))
614 				goto error;
615 		}
616 	} else {
617 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group",
618 						      &iter_dict_entry,
619 						      &iter_dict_val,
620 						      &iter_array))
621 			goto error;
622 
623 		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
624 			if (!wpa_dbus_dict_string_array_add_element(
625 				    &iter_array, "CCMP"))
626 				goto error;
627 		}
628 
629 		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
630 			if (!wpa_dbus_dict_string_array_add_element(
631 				    &iter_array, "TKIP"))
632 				goto error;
633 		}
634 
635 		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
636 			if (!wpa_dbus_dict_string_array_add_element(
637 				    &iter_array, "WEP104"))
638 				goto error;
639 		}
640 
641 		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
642 			if (!wpa_dbus_dict_string_array_add_element(
643 				    &iter_array, "WEP40"))
644 				goto error;
645 		}
646 
647 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
648 						    &iter_dict_entry,
649 						    &iter_dict_val,
650 						    &iter_array))
651 			goto error;
652 	}
653 
654 	/***** key management */
655 	if (res < 0) {
656 		if (!strict) {
657 			const char *args[] = {
658 				"WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
659 				"NONE"
660 			};
661 			if (!wpa_dbus_dict_append_string_array(
662 				    &iter_dict, "key_mgmt", args,
663 				    sizeof(args) / sizeof(char*)))
664 				goto error;
665 		}
666 	} else {
667 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
668 						      &iter_dict_entry,
669 						      &iter_dict_val,
670 						      &iter_array))
671 			goto error;
672 
673 		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
674 							    "NONE"))
675 			goto error;
676 
677 		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
678 							    "IEEE8021X"))
679 			goto error;
680 
681 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
682 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
683 			if (!wpa_dbus_dict_string_array_add_element(
684 				    &iter_array, "WPA-EAP"))
685 				goto error;
686 		}
687 
688 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
689 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
690 			if (!wpa_dbus_dict_string_array_add_element(
691 				    &iter_array, "WPA-PSK"))
692 				goto error;
693 		}
694 
695 		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
696 			if (!wpa_dbus_dict_string_array_add_element(
697 				    &iter_array, "WPA-NONE"))
698 				goto error;
699 		}
700 
701 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
702 						    &iter_dict_entry,
703 						    &iter_dict_val,
704 						    &iter_array))
705 			goto error;
706 	}
707 
708 	/***** WPA protocol */
709 	if (res < 0) {
710 		if (!strict) {
711 			const char *args[] = { "RSN", "WPA" };
712 			if (!wpa_dbus_dict_append_string_array(
713 				    &iter_dict, "proto", args,
714 				    sizeof(args) / sizeof(char*)))
715 				goto error;
716 		}
717 	} else {
718 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
719 						      &iter_dict_entry,
720 						      &iter_dict_val,
721 						      &iter_array))
722 			goto error;
723 
724 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
725 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
726 			if (!wpa_dbus_dict_string_array_add_element(
727 				    &iter_array, "RSN"))
728 				goto error;
729 		}
730 
731 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
732 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
733 			if (!wpa_dbus_dict_string_array_add_element(
734 				    &iter_array, "WPA"))
735 				goto error;
736 		}
737 
738 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
739 						    &iter_dict_entry,
740 						    &iter_dict_val,
741 						    &iter_array))
742 			goto error;
743 	}
744 
745 	/***** auth alg */
746 	if (res < 0) {
747 		if (!strict) {
748 			const char *args[] = { "OPEN", "SHARED", "LEAP" };
749 			if (!wpa_dbus_dict_append_string_array(
750 				    &iter_dict, "auth_alg", args,
751 				    sizeof(args) / sizeof(char*)))
752 				goto error;
753 		}
754 	} else {
755 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
756 						      &iter_dict_entry,
757 						      &iter_dict_val,
758 						      &iter_array))
759 			goto error;
760 
761 		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
762 			if (!wpa_dbus_dict_string_array_add_element(
763 				    &iter_array, "OPEN"))
764 				goto error;
765 		}
766 
767 		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
768 			if (!wpa_dbus_dict_string_array_add_element(
769 				    &iter_array, "SHARED"))
770 				goto error;
771 		}
772 
773 		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
774 			if (!wpa_dbus_dict_string_array_add_element(
775 				    &iter_array, "LEAP"))
776 				goto error;
777 		}
778 
779 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
780 						    &iter_dict_entry,
781 						    &iter_dict_val,
782 						    &iter_array))
783 			goto error;
784 	}
785 
786 	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
787 		goto error;
788 
789 	return reply;
790 
791 error:
792 	if (reply)
793 		dbus_message_unref(reply);
794 	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
795 				      "an internal error occurred returning "
796 				      "interface capabilities.");
797 }
798 
799 
800 /**
801  * wpas_dbus_iface_add_network - Add a new configured network
802  * @message: Pointer to incoming dbus message
803  * @wpa_s: wpa_supplicant structure for a network interface
804  * Returns: A dbus message containing the object path of the new network
805  *
806  * Handler function for "addNetwork" method call of a network interface.
807  */
wpas_dbus_iface_add_network(DBusMessage * message,struct wpa_supplicant * wpa_s)808 DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
809 					  struct wpa_supplicant *wpa_s)
810 {
811 	DBusMessage *reply = NULL;
812 	struct wpa_ssid *ssid;
813 	char *path = NULL;
814 
815 	path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
816 	if (path == NULL) {
817 		perror("wpas_dbus_iface_scan_results[dbus]: out of "
818 		       "memory.");
819 		wpa_printf(MSG_ERROR, "dbus control interface: not "
820 			   "enough memory to send scan results "
821 			   "signal.");
822 		goto out;
823 	}
824 
825 	ssid = wpa_config_add_network(wpa_s->conf);
826 	if (ssid == NULL) {
827 		reply = dbus_message_new_error(message,
828 					       WPAS_ERROR_ADD_NETWORK_ERROR,
829 					       "wpa_supplicant could not add "
830 					       "a network on this interface.");
831 		goto out;
832 	}
833 	ssid->disabled = 1;
834 	wpa_config_set_network_defaults(ssid);
835 
836 	/* Construct the object path for this network. */
837 	snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
838 		 "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
839 		 wpa_supplicant_get_dbus_path(wpa_s),
840 		 ssid->id);
841 
842 	reply = dbus_message_new_method_return(message);
843 	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
844 				 &path, DBUS_TYPE_INVALID);
845 
846 out:
847 	free(path);
848 	return reply;
849 }
850 
851 
852 /**
853  * wpas_dbus_iface_remove_network - Remove a configured network
854  * @message: Pointer to incoming dbus message
855  * @wpa_s: wpa_supplicant structure for a network interface
856  * Returns: A dbus message containing a UINT32 indicating success (1) or
857  *          failure (0)
858  *
859  * Handler function for "removeNetwork" method call of a network interface.
860  */
wpas_dbus_iface_remove_network(DBusMessage * message,struct wpa_supplicant * wpa_s)861 DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
862 					     struct wpa_supplicant *wpa_s)
863 {
864 	DBusMessage *reply = NULL;
865 	const char *op;
866 	char *iface = NULL, *net_id = NULL;
867 	int id;
868 	struct wpa_ssid *ssid;
869 
870 	if (!dbus_message_get_args(message, NULL,
871 	                           DBUS_TYPE_OBJECT_PATH, &op,
872 	                           DBUS_TYPE_INVALID)) {
873 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
874 		goto out;
875 	}
876 
877 	/* Extract the network ID */
878 	iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
879 	if (iface == NULL) {
880 		reply = wpas_dbus_new_invalid_network_error(message);
881 		goto out;
882 	}
883 	/* Ensure the network is actually a child of this interface */
884 	if (strcmp(iface, wpa_supplicant_get_dbus_path(wpa_s)) != 0) {
885 		reply = wpas_dbus_new_invalid_network_error(message);
886 		goto out;
887 	}
888 
889 	id = strtoul(net_id, NULL, 10);
890 	ssid = wpa_config_get_network(wpa_s->conf, id);
891 	if (ssid == NULL) {
892 		reply = wpas_dbus_new_invalid_network_error(message);
893 		goto out;
894 	}
895 
896 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
897 		reply = dbus_message_new_error(message,
898 					       WPAS_ERROR_REMOVE_NETWORK_ERROR,
899 					       "error removing the specified "
900 					       "on this interface.");
901 		goto out;
902 	}
903 
904 	if (ssid == wpa_s->current_ssid)
905 		wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
906 	reply = wpas_dbus_new_success_reply(message);
907 
908 out:
909 	free(iface);
910 	free(net_id);
911 	return reply;
912 }
913 
914 
915 static const char *dont_quote[] = {
916 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
917 	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
918 	"bssid", NULL
919 };
920 
should_quote_opt(const char * key)921 static dbus_bool_t should_quote_opt(const char *key)
922 {
923 	int i = 0;
924 	while (dont_quote[i] != NULL) {
925 		if (strcmp(key, dont_quote[i]) == 0)
926 			return FALSE;
927 		i++;
928 	}
929 	return TRUE;
930 }
931 
932 /**
933  * wpas_dbus_iface_set_network - Set options for a configured network
934  * @message: Pointer to incoming dbus message
935  * @wpa_s: wpa_supplicant structure for a network interface
936  * @ssid: wpa_ssid structure for a configured network
937  * Returns: a dbus message containing a UINT32 indicating success (1) or
938  *          failure (0)
939  *
940  * Handler function for "set" method call of a configured network.
941  */
wpas_dbus_iface_set_network(DBusMessage * message,struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)942 DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
943 					  struct wpa_supplicant *wpa_s,
944 					  struct wpa_ssid *ssid)
945 {
946 	DBusMessage *reply = NULL;
947 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
948 	DBusMessageIter	iter, iter_dict;
949 
950 	dbus_message_iter_init(message, &iter);
951 
952 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) {
953 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
954 		goto out;
955 	}
956 
957 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
958 		char *value = NULL;
959 		size_t size = 50;
960 		int ret;
961 
962 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
963 			reply = wpas_dbus_new_invalid_opts_error(message,
964 								 NULL);
965 			goto out;
966 		}
967 
968 		/* Type conversions, since wpa_supplicant wants strings */
969 		if (entry.type == DBUS_TYPE_ARRAY &&
970 		    entry.array_type == DBUS_TYPE_BYTE) {
971 			if (entry.array_len <= 0)
972 				goto error;
973 
974 			size = entry.array_len * 2 + 1;
975 			value = os_zalloc(size);
976 			if (value == NULL)
977 				goto error;
978 			ret = wpa_snprintf_hex(value, size,
979 					(u8 *) entry.bytearray_value,
980 					entry.array_len);
981 			if (ret <= 0)
982 				goto error;
983 		} else if (entry.type == DBUS_TYPE_STRING) {
984 			if (should_quote_opt(entry.key)) {
985 				size = strlen(entry.str_value);
986 				/* Zero-length option check */
987 				if (size <= 0)
988 					goto error;
989 				size += 3;  /* For quotes and terminator */
990 				value = os_zalloc(size);
991 				if (value == NULL)
992 					goto error;
993 				ret = snprintf(value, size, "\"%s\"",
994 						entry.str_value);
995 				if (ret < 0 || (size_t) ret != (size - 1))
996 					goto error;
997 			} else {
998 				value = strdup(entry.str_value);
999 				if (value == NULL)
1000 					goto error;
1001 			}
1002 		} else if (entry.type == DBUS_TYPE_UINT32) {
1003 			value = os_zalloc(size);
1004 			if (value == NULL)
1005 				goto error;
1006 			ret = snprintf(value, size, "%u", entry.uint32_value);
1007 			if (ret <= 0)
1008 				goto error;
1009 		} else if (entry.type == DBUS_TYPE_INT32) {
1010 			value = os_zalloc(size);
1011 			if (value == NULL)
1012 				goto error;
1013 			ret = snprintf(value, size, "%d", entry.int32_value);
1014 			if (ret <= 0)
1015 				goto error;
1016 		} else
1017 			goto error;
1018 
1019 		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
1020 			goto error;
1021 
1022 		if ((strcmp(entry.key, "psk") == 0 &&
1023 		     value[0] == '"' && ssid->ssid_len) ||
1024 		    (strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
1025 			wpa_config_update_psk(ssid);
1026 
1027 		free(value);
1028 		wpa_dbus_dict_entry_clear(&entry);
1029 		continue;
1030 
1031 	error:
1032 		free(value);
1033 		reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
1034 		wpa_dbus_dict_entry_clear(&entry);
1035 		break;
1036 	}
1037 
1038 	if (!reply)
1039 		reply = wpas_dbus_new_success_reply(message);
1040 
1041 out:
1042 	return reply;
1043 }
1044 
1045 
1046 /**
1047  * wpas_dbus_iface_enable_network - Mark a configured network as enabled
1048  * @message: Pointer to incoming dbus message
1049  * @wpa_s: wpa_supplicant structure for a network interface
1050  * @ssid: wpa_ssid structure for a configured network
1051  * Returns: A dbus message containing a UINT32 indicating success (1) or
1052  *          failure (0)
1053  *
1054  * Handler function for "enable" method call of a configured network.
1055  */
wpas_dbus_iface_enable_network(DBusMessage * message,struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)1056 DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
1057 					     struct wpa_supplicant *wpa_s,
1058 					     struct wpa_ssid *ssid)
1059 {
1060 	if (wpa_s->current_ssid == NULL && ssid->disabled) {
1061 		/*
1062 		 * Try to reassociate since there is no current configuration
1063 		 * and a new network was made available.
1064 		 */
1065 		wpa_s->reassociate = 1;
1066 		wpa_supplicant_req_scan(wpa_s, 0, 0);
1067 	}
1068 	ssid->disabled = 0;
1069 
1070 	return wpas_dbus_new_success_reply(message);
1071 }
1072 
1073 
1074 /**
1075  * wpas_dbus_iface_disable_network - Mark a configured network as disabled
1076  * @message: Pointer to incoming dbus message
1077  * @wpa_s: wpa_supplicant structure for a network interface
1078  * @ssid: wpa_ssid structure for a configured network
1079  * Returns: A dbus message containing a UINT32 indicating success (1) or
1080  *          failure (0)
1081  *
1082  * Handler function for "disable" method call of a configured network.
1083  */
wpas_dbus_iface_disable_network(DBusMessage * message,struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)1084 DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
1085 					      struct wpa_supplicant *wpa_s,
1086 					      struct wpa_ssid *ssid)
1087 {
1088 	if (ssid == wpa_s->current_ssid)
1089 		wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1090 	ssid->disabled = 1;
1091 
1092 	return wpas_dbus_new_success_reply(message);
1093 }
1094 
1095 
1096 /**
1097  * wpas_dbus_iface_select_network - Attempt association with a configured network
1098  * @message: Pointer to incoming dbus message
1099  * @wpa_s: wpa_supplicant structure for a network interface
1100  * Returns: A dbus message containing a UINT32 indicating success (1) or
1101  *          failure (0)
1102  *
1103  * Handler function for "selectNetwork" method call of network interface.
1104  */
wpas_dbus_iface_select_network(DBusMessage * message,struct wpa_supplicant * wpa_s)1105 DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
1106 					     struct wpa_supplicant *wpa_s)
1107 {
1108 	DBusMessage *reply = NULL;
1109 	const char *op;
1110 	struct wpa_ssid *ssid;
1111 	char *iface_obj_path = NULL;
1112 	char *network = NULL;
1113 
1114 	if (strlen(dbus_message_get_signature(message)) == 0) {
1115 		/* Any network */
1116 		ssid = wpa_s->conf->ssid;
1117 		while (ssid) {
1118 			ssid->disabled = 0;
1119 			ssid = ssid->next;
1120 		}
1121 		wpa_s->reassociate = 1;
1122 		wpa_supplicant_req_scan(wpa_s, 0, 0);
1123 	} else {
1124 		const char *obj_path;
1125 		int nid;
1126 
1127 		if (!dbus_message_get_args(message, NULL,
1128 					   DBUS_TYPE_OBJECT_PATH, &op,
1129 					   DBUS_TYPE_INVALID)) {
1130 			reply = wpas_dbus_new_invalid_opts_error(message,
1131 								 NULL);
1132 			goto out;
1133 		}
1134 
1135 		/* Extract the network number */
1136 		iface_obj_path = wpas_dbus_decompose_object_path(op,
1137 								 &network,
1138 								 NULL);
1139 		if (iface_obj_path == NULL) {
1140 			reply = wpas_dbus_new_invalid_iface_error(message);
1141 			goto out;
1142 		}
1143 		/* Ensure the object path really points to this interface */
1144 		obj_path = wpa_supplicant_get_dbus_path(wpa_s);
1145 		if (strcmp(iface_obj_path, obj_path) != 0) {
1146 			reply = wpas_dbus_new_invalid_network_error(message);
1147 			goto out;
1148 		}
1149 
1150 		nid = strtoul(network, NULL, 10);
1151 		if (errno == EINVAL) {
1152 			reply = wpas_dbus_new_invalid_network_error(message);
1153 			goto out;
1154 		}
1155 
1156 		ssid = wpa_config_get_network(wpa_s->conf, nid);
1157 		if (ssid == NULL) {
1158 			reply = wpas_dbus_new_invalid_network_error(message);
1159 			goto out;
1160 		}
1161 
1162 		/* Finally, associate with the network */
1163 		if (ssid != wpa_s->current_ssid && wpa_s->current_ssid)
1164 			wpa_supplicant_disassociate(
1165 				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1166 
1167 		/* Mark all other networks disabled and trigger reassociation
1168 		 */
1169 		ssid = wpa_s->conf->ssid;
1170 		while (ssid) {
1171 			ssid->disabled = (nid != ssid->id);
1172 			ssid = ssid->next;
1173 		}
1174 		wpa_s->disconnected = 0;
1175 		wpa_s->reassociate = 1;
1176 		wpa_supplicant_req_scan(wpa_s, 0, 0);
1177 	}
1178 
1179 	reply = wpas_dbus_new_success_reply(message);
1180 
1181 out:
1182 	free(iface_obj_path);
1183 	free(network);
1184 	return reply;
1185 }
1186 
1187 
1188 /**
1189  * wpas_dbus_iface_disconnect - Terminate the current connection
1190  * @message: Pointer to incoming dbus message
1191  * @wpa_s: wpa_supplicant structure for a network interface
1192  * Returns: A dbus message containing a UINT32 indicating success (1) or
1193  *          failure (0)
1194  *
1195  * Handler function for "disconnect" method call of network interface.
1196  */
wpas_dbus_iface_disconnect(DBusMessage * message,struct wpa_supplicant * wpa_s)1197 DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
1198 					 struct wpa_supplicant *wpa_s)
1199 {
1200 	wpa_s->disconnected = 1;
1201 	wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1202 
1203 	return wpas_dbus_new_success_reply(message);
1204 }
1205 
1206 
1207 /**
1208  * wpas_dbus_iface_set_ap_scan - Control roaming mode
1209  * @message: Pointer to incoming dbus message
1210  * @wpa_s: wpa_supplicant structure for a network interface
1211  * Returns: A dbus message containing a UINT32 indicating success (1) or
1212  *          failure (0)
1213  *
1214  * Handler function for "setAPScan" method call.
1215  */
wpas_dbus_iface_set_ap_scan(DBusMessage * message,struct wpa_supplicant * wpa_s)1216 DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
1217 					  struct wpa_supplicant *wpa_s)
1218 {
1219 	DBusMessage *reply = NULL;
1220 	dbus_uint32_t ap_scan = 1;
1221 
1222 	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
1223 				   DBUS_TYPE_INVALID)) {
1224 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1225 		goto out;
1226 	}
1227 
1228 	if (ap_scan > 2) {
1229 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1230 		goto out;
1231 	}
1232 	wpa_s->conf->ap_scan = ap_scan;
1233 	reply = wpas_dbus_new_success_reply(message);
1234 
1235 out:
1236 	return reply;
1237 }
1238 
1239 
1240 /**
1241  * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
1242  * @message: Pointer to incoming dbus message
1243  * @wpa_s: wpa_supplicant structure for a network interface
1244  * Returns: A dbus message containing a UINT32 indicating success (1) or
1245  *          failure (0)
1246  *
1247  * Handler function for "setSmartcardModules" method call.
1248  */
wpas_dbus_iface_set_smartcard_modules(DBusMessage * message,struct wpa_supplicant * wpa_s)1249 DBusMessage * wpas_dbus_iface_set_smartcard_modules(
1250 	DBusMessage *message, struct wpa_supplicant *wpa_s)
1251 {
1252 	DBusMessageIter iter, iter_dict;
1253 	char *opensc_engine_path = NULL;
1254 	char *pkcs11_engine_path = NULL;
1255 	char *pkcs11_module_path = NULL;
1256 	struct wpa_dbus_dict_entry entry;
1257 
1258 	if (!dbus_message_iter_init(message, &iter))
1259 		goto error;
1260 
1261 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1262 		goto error;
1263 
1264 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1265 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1266 			goto error;
1267 		if (!strcmp(entry.key, "opensc_engine_path") &&
1268 		    (entry.type == DBUS_TYPE_STRING)) {
1269 			opensc_engine_path = os_strdup(entry.str_value);
1270 			if (opensc_engine_path == NULL)
1271 				goto error;
1272 		} else if (!strcmp(entry.key, "pkcs11_engine_path") &&
1273 			   (entry.type == DBUS_TYPE_STRING)) {
1274 			pkcs11_engine_path = os_strdup(entry.str_value);
1275 			if (pkcs11_engine_path == NULL)
1276 				goto error;
1277 		} else if (!strcmp(entry.key, "pkcs11_module_path") &&
1278 				 (entry.type == DBUS_TYPE_STRING)) {
1279 			pkcs11_module_path = os_strdup(entry.str_value);
1280 			if (pkcs11_module_path == NULL)
1281 				goto error;
1282 		} else {
1283 			wpa_dbus_dict_entry_clear(&entry);
1284 			goto error;
1285 		}
1286 		wpa_dbus_dict_entry_clear(&entry);
1287 	}
1288 
1289 #ifdef EAP_TLS_OPENSSL
1290 	os_free(wpa_s->conf->opensc_engine_path);
1291 	wpa_s->conf->opensc_engine_path = opensc_engine_path;
1292 	os_free(wpa_s->conf->pkcs11_engine_path);
1293 	wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
1294 	os_free(wpa_s->conf->pkcs11_module_path);
1295 	wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
1296 #endif /* EAP_TLS_OPENSSL */
1297 
1298 	wpa_sm_set_eapol(wpa_s->wpa, NULL);
1299 	eapol_sm_deinit(wpa_s->eapol);
1300 	wpa_s->eapol = NULL;
1301 	wpa_supplicant_init_eapol(wpa_s);
1302 	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
1303 
1304 	return wpas_dbus_new_success_reply(message);
1305 
1306 error:
1307 	os_free(opensc_engine_path);
1308 	os_free(pkcs11_engine_path);
1309 	os_free(pkcs11_module_path);
1310 	return wpas_dbus_new_invalid_opts_error(message, NULL);
1311 }
1312 
1313 /**
1314  * wpas_dbus_iface_get_state - Get interface state
1315  * @message: Pointer to incoming dbus message
1316  * @wpa_s: wpa_supplicant structure for a network interface
1317  * Returns: A dbus message containing a STRING representing the current
1318  *          interface state
1319  *
1320  * Handler function for "state" method call.
1321  */
wpas_dbus_iface_get_state(DBusMessage * message,struct wpa_supplicant * wpa_s)1322 DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
1323 					struct wpa_supplicant *wpa_s)
1324 {
1325 	DBusMessage *reply = NULL;
1326 	const char *str_state;
1327 
1328 	reply = dbus_message_new_method_return(message);
1329 	if (reply != NULL) {
1330 		str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
1331 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
1332 					 DBUS_TYPE_INVALID);
1333 	}
1334 
1335 	return reply;
1336 }
1337 
1338 
1339 /**
1340  * wpas_dbus_iface_get_scanning - Get interface scanning state
1341  * @message: Pointer to incoming dbus message
1342  * @wpa_s: wpa_supplicant structure for a network interface
1343  * Returns: A dbus message containing whether the interface is scanning
1344  *
1345  * Handler function for "scanning" method call.
1346  */
wpas_dbus_iface_get_scanning(DBusMessage * message,struct wpa_supplicant * wpa_s)1347 DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
1348 					   struct wpa_supplicant *wpa_s)
1349 {
1350 	DBusMessage *reply = NULL;
1351 	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
1352 
1353 	reply = dbus_message_new_method_return(message);
1354 	if (reply != NULL) {
1355 		dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
1356 					 DBUS_TYPE_INVALID);
1357 	} else {
1358 		perror("wpas_dbus_iface_get_scanning[dbus]: out of "
1359 		       "memory.");
1360 		wpa_printf(MSG_ERROR, "dbus control interface: not enough "
1361 			   "memory to return scanning state.");
1362 	}
1363 
1364 	return reply;
1365 }
1366 
1367 
1368 /**
1369  * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
1370  * @message: Pointer to incoming dbus message
1371  * @wpa_s: %wpa_supplicant data structure
1372  * Returns: A dbus message containing a UINT32 indicating success (1) or
1373  *          failure (0)
1374  *
1375  * Asks wpa_supplicant to internally store a one or more binary blobs.
1376  */
wpas_dbus_iface_set_blobs(DBusMessage * message,struct wpa_supplicant * wpa_s)1377 DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
1378 					struct wpa_supplicant *wpa_s)
1379 {
1380 	DBusMessage *reply = NULL;
1381 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1382 	DBusMessageIter	iter, iter_dict;
1383 
1384 	dbus_message_iter_init(message, &iter);
1385 
1386 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1387 		return wpas_dbus_new_invalid_opts_error(message, NULL);
1388 
1389 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1390 		struct wpa_config_blob *blob;
1391 
1392 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1393 			reply = wpas_dbus_new_invalid_opts_error(message,
1394 								 NULL);
1395 			break;
1396 		}
1397 
1398 		if (entry.type != DBUS_TYPE_ARRAY ||
1399 		    entry.array_type != DBUS_TYPE_BYTE) {
1400 			reply = wpas_dbus_new_invalid_opts_error(
1401 				message, "Byte array expected.");
1402 			break;
1403 		}
1404 
1405 		if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
1406 		    !strlen(entry.key)) {
1407 			reply = wpas_dbus_new_invalid_opts_error(
1408 				message, "Invalid array size.");
1409 			break;
1410 		}
1411 
1412 		blob = os_zalloc(sizeof(*blob));
1413 		if (blob == NULL) {
1414 			reply = dbus_message_new_error(
1415 				message, WPAS_ERROR_ADD_ERROR,
1416 				"Not enough memory to add blob.");
1417 			break;
1418 		}
1419 		blob->data = os_zalloc(entry.array_len);
1420 		if (blob->data == NULL) {
1421 			reply = dbus_message_new_error(
1422 				message, WPAS_ERROR_ADD_ERROR,
1423 				"Not enough memory to add blob data.");
1424 			os_free(blob);
1425 			break;
1426 		}
1427 
1428 		blob->name = os_strdup(entry.key);
1429 		blob->len = entry.array_len;
1430 		os_memcpy(blob->data, (u8 *) entry.bytearray_value,
1431 				entry.array_len);
1432 		if (blob->name == NULL || blob->data == NULL) {
1433 			wpa_config_free_blob(blob);
1434 			reply = dbus_message_new_error(
1435 				message, WPAS_ERROR_ADD_ERROR,
1436 				"Error adding blob.");
1437 			break;
1438 		}
1439 
1440 		/* Success */
1441 		wpa_config_remove_blob(wpa_s->conf, blob->name);
1442 		wpa_config_set_blob(wpa_s->conf, blob);
1443 		wpa_dbus_dict_entry_clear(&entry);
1444 	}
1445 	wpa_dbus_dict_entry_clear(&entry);
1446 
1447 	return reply ? reply : wpas_dbus_new_success_reply(message);
1448 }
1449 
1450 
1451 /**
1452  * wpas_dbus_iface_remove_blob - Remove named binary blobs
1453  * @message: Pointer to incoming dbus message
1454  * @wpa_s: %wpa_supplicant data structure
1455  * Returns: A dbus message containing a UINT32 indicating success (1) or
1456  *          failure (0)
1457  *
1458  * Asks wpa_supplicant to remove one or more previously stored binary blobs.
1459  */
wpas_dbus_iface_remove_blobs(DBusMessage * message,struct wpa_supplicant * wpa_s)1460 DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
1461 					  struct wpa_supplicant *wpa_s)
1462 {
1463 	DBusMessageIter iter, array;
1464 	char *err_msg = NULL;
1465 
1466 	dbus_message_iter_init(message, &iter);
1467 
1468 	if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
1469 	    (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
1470 		return wpas_dbus_new_invalid_opts_error(message, NULL);
1471 
1472 	dbus_message_iter_recurse(&iter, &array);
1473 	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
1474 		const char *name;
1475 
1476 		dbus_message_iter_get_basic(&array, &name);
1477 		if (!strlen(name))
1478 			err_msg = "Invalid blob name.";
1479 
1480 		if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
1481 			err_msg = "Error removing blob.";
1482 		dbus_message_iter_next(&array);
1483 	}
1484 
1485 	if (err_msg) {
1486 		return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
1487 					      err_msg);
1488 	}
1489 
1490 	return wpas_dbus_new_success_reply(message);
1491 }
1492