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