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