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