56bad323da7529a5a7ec891d0c9ccb82e5180feb
[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 "driver_i.h"
21 #include "ctrl_iface_dbus.h"
22 #include "ctrl_iface_dbus_handlers.h"
23 #include "eap_peer/eap_methods.h"
24 #include "dbus_dict_helpers.h"
25 #include "ieee802_11_defs.h"
26 #include "wpas_glue.h"
27 #include "eapol_supp/eapol_supp_sm.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) != NULL) {
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         size_t i;
319
320         /* Ensure we've actually got scan results to return */
321         if (wpa_s->scan_res == 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->scan_res->num; i++) {
338                 struct wpa_scan_res *res = wpa_s->scan_res->res[i];
339                 char *path;
340
341                 path = os_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_res *res)
383 {
384         DBusMessage *reply = NULL;
385         DBusMessageIter iter, iter_dict;
386         const u8 *ie;
387
388         /* Dump the properties into a dbus message */
389         reply = dbus_message_new_method_return(message);
390
391         dbus_message_iter_init_append(reply, &iter);
392         if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
393                 goto error;
394
395         if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
396                                              (const char *) res->bssid,
397                                              ETH_ALEN))
398                 goto error;
399
400         ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
401         if (ie) {
402                 if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
403                                                      (const char *) (ie + 2),
404                                                      ie[1]))
405                 goto error;
406         }
407
408         ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
409         if (ie) {
410                 if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
411                                                      (const char *) ie,
412                                                      ie[1] + 2))
413                         goto error;
414         }
415
416         ie = wpa_scan_get_ie(res, WLAN_EID_RSN);
417         if (ie) {
418                 if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
419                                                      (const char *) ie,
420                                                      ie[1] + 2))
421                         goto error;
422         }
423
424         ie = wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE);
425         if (ie) {
426                 if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
427                                                      (const char *) ie,
428                                                      ie[1] + 2))
429                         goto error;
430         }
431
432         if (res->freq) {
433                 if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
434                                                 res->freq))
435                         goto error;
436         }
437         if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
438                                          res->caps))
439                 goto error;
440         if (!(res->flags & WPA_SCAN_QUAL_INVALID) &&
441             !wpa_dbus_dict_append_int32(&iter_dict, "quality", res->qual))
442                 goto error;
443         if (!(res->flags & WPA_SCAN_NOISE_INVALID) &&
444             !wpa_dbus_dict_append_int32(&iter_dict, "noise", res->noise))
445                 goto error;
446         if (!(res->flags & WPA_SCAN_LEVEL_INVALID) &&
447             !wpa_dbus_dict_append_int32(&iter_dict, "level", res->level))
448                 goto error;
449         if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
450                                         wpa_scan_get_max_rate(res) * 500000))
451                 goto error;
452
453         if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
454                 goto error;
455
456         return reply;
457
458 error:
459         if (reply)
460                 dbus_message_unref(reply);
461         return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
462                                       "an internal error occurred returning "
463                                       "BSSID properties.");
464 }
465
466
467 /**
468  * wpas_dbus_iface_capabilities - Return interface capabilities
469  * @message: Pointer to incoming dbus message
470  * @wpa_s: wpa_supplicant structure for a network interface
471  * Returns: A dbus message containing a dict of strings
472  *
473  * Handler function for "capabilities" method call of an interface.
474  */
475 DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
476                                            struct wpa_supplicant *wpa_s)
477 {
478         DBusMessage *reply = NULL;
479         struct wpa_driver_capa capa;
480         int res;
481         DBusMessageIter iter, iter_dict;
482         char **eap_methods;
483         size_t num_items;
484         dbus_bool_t strict = FALSE;
485         DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
486
487         if (!dbus_message_get_args(message, NULL,
488                                    DBUS_TYPE_BOOLEAN, &strict,
489                                    DBUS_TYPE_INVALID))
490                 strict = FALSE;
491
492         reply = dbus_message_new_method_return(message);
493
494         dbus_message_iter_init_append(reply, &iter);
495         if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
496                 goto error;
497
498         /* EAP methods */
499         eap_methods = eap_get_names_as_string_array(&num_items);
500         if (eap_methods) {
501                 dbus_bool_t success = FALSE;
502                 size_t i = 0;
503
504                 success = wpa_dbus_dict_append_string_array(
505                         &iter_dict, "eap", (const char **) eap_methods,
506                         num_items);
507
508                 /* free returned method array */
509                 while (eap_methods[i])
510                         free(eap_methods[i++]);
511                 free(eap_methods);
512
513                 if (!success)
514                         goto error;
515         }
516
517         res = wpa_drv_get_capa(wpa_s, &capa);
518
519         /***** pairwise cipher */
520         if (res < 0) {
521                 if (!strict) {
522                         const char *args[] = {"CCMP", "TKIP", "NONE"};
523                         if (!wpa_dbus_dict_append_string_array(
524                                     &iter_dict, "pairwise", args,
525                                     sizeof(args) / sizeof(char*)))
526                                 goto error;
527                 }
528         } else {
529                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
530                                                       &iter_dict_entry,
531                                                       &iter_dict_val,
532                                                       &iter_array))
533                         goto error;
534
535                 if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
536                         if (!wpa_dbus_dict_string_array_add_element(
537                                     &iter_array, "CCMP"))
538                                 goto error;
539                 }
540
541                 if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
542                         if (!wpa_dbus_dict_string_array_add_element(
543                                     &iter_array, "TKIP"))
544                                 goto error;
545                 }
546
547                 if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
548                         if (!wpa_dbus_dict_string_array_add_element(
549                                     &iter_array, "NONE"))
550                                 goto error;
551                 }
552
553                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
554                                                     &iter_dict_entry,
555                                                     &iter_dict_val,
556                                                     &iter_array))
557                         goto error;
558         }
559
560         /***** group cipher */
561         if (res < 0) {
562                 if (!strict) {
563                         const char *args[] = {
564                                 "CCMP", "TKIP", "WEP104", "WEP40"
565                         };
566                         if (!wpa_dbus_dict_append_string_array(
567                                     &iter_dict, "group", args,
568                                     sizeof(args) / sizeof(char*)))
569                                 goto error;
570                 }
571         } else {
572                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group",
573                                                       &iter_dict_entry,
574                                                       &iter_dict_val,
575                                                       &iter_array))
576                         goto error;
577
578                 if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
579                         if (!wpa_dbus_dict_string_array_add_element(
580                                     &iter_array, "CCMP"))
581                                 goto error;
582                 }
583
584                 if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
585                         if (!wpa_dbus_dict_string_array_add_element(
586                                     &iter_array, "TKIP"))
587                                 goto error;
588                 }
589
590                 if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
591                         if (!wpa_dbus_dict_string_array_add_element(
592                                     &iter_array, "WEP104"))
593                                 goto error;
594                 }
595
596                 if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
597                         if (!wpa_dbus_dict_string_array_add_element(
598                                     &iter_array, "WEP40"))
599                                 goto error;
600                 }
601
602                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
603                                                     &iter_dict_entry,
604                                                     &iter_dict_val,
605                                                     &iter_array))
606                         goto error;
607         }
608
609         /***** key management */
610         if (res < 0) {
611                 if (!strict) {
612                         const char *args[] = {
613                                 "WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
614                                 "NONE"
615                         };
616                         if (!wpa_dbus_dict_append_string_array(
617                                     &iter_dict, "key_mgmt", args,
618                                     sizeof(args) / sizeof(char*)))
619                                 goto error;
620                 }
621         } else {
622                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
623                                                       &iter_dict_entry,
624                                                       &iter_dict_val,
625                                                       &iter_array))
626                         goto error;
627
628                 if (!wpa_dbus_dict_string_array_add_element(&iter_array,
629                                                             "NONE"))
630                         goto error;
631
632                 if (!wpa_dbus_dict_string_array_add_element(&iter_array,
633                                                             "IEEE8021X"))
634                         goto error;
635
636                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
637                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
638                         if (!wpa_dbus_dict_string_array_add_element(
639                                     &iter_array, "WPA-EAP"))
640                                 goto error;
641                 }
642
643                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
644                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
645                         if (!wpa_dbus_dict_string_array_add_element(
646                                     &iter_array, "WPA-PSK"))
647                                 goto error;
648                 }
649
650                 if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
651                         if (!wpa_dbus_dict_string_array_add_element(
652                                     &iter_array, "WPA-NONE"))
653                                 goto error;
654                 }
655
656                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
657                                                     &iter_dict_entry,
658                                                     &iter_dict_val,
659                                                     &iter_array))
660                         goto error;
661         }
662
663         /***** WPA protocol */
664         if (res < 0) {
665                 if (!strict) {
666                         const char *args[] = { "RSN", "WPA" };
667                         if (!wpa_dbus_dict_append_string_array(
668                                     &iter_dict, "proto", args,
669                                     sizeof(args) / sizeof(char*)))
670                                 goto error;
671                 }
672         } else {
673                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
674                                                       &iter_dict_entry,
675                                                       &iter_dict_val,
676                                                       &iter_array))
677                         goto error;
678
679                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
680                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
681                         if (!wpa_dbus_dict_string_array_add_element(
682                                     &iter_array, "RSN"))
683                                 goto error;
684                 }
685
686                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
687                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
688                         if (!wpa_dbus_dict_string_array_add_element(
689                                     &iter_array, "WPA"))
690                                 goto error;
691                 }
692
693                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
694                                                     &iter_dict_entry,
695                                                     &iter_dict_val,
696                                                     &iter_array))
697                         goto error;
698         }
699
700         /***** auth alg */
701         if (res < 0) {
702                 if (!strict) {
703                         const char *args[] = { "OPEN", "SHARED", "LEAP" };
704                         if (!wpa_dbus_dict_append_string_array(
705                                     &iter_dict, "auth_alg", args,
706                                     sizeof(args) / sizeof(char*)))
707                                 goto error;
708                 }
709         } else {
710                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
711                                                       &iter_dict_entry,
712                                                       &iter_dict_val,
713                                                       &iter_array))
714                         goto error;
715
716                 if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
717                         if (!wpa_dbus_dict_string_array_add_element(
718                                     &iter_array, "OPEN"))
719                                 goto error;
720                 }
721
722                 if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
723                         if (!wpa_dbus_dict_string_array_add_element(
724                                     &iter_array, "SHARED"))
725                                 goto error;
726                 }
727
728                 if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
729                         if (!wpa_dbus_dict_string_array_add_element(
730                                     &iter_array, "LEAP"))
731                                 goto error;
732                 }
733
734                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
735                                                     &iter_dict_entry,
736                                                     &iter_dict_val,
737                                                     &iter_array))
738                         goto error;
739         }
740
741         if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
742                 goto error;
743
744         return reply;
745
746 error:
747         if (reply)
748                 dbus_message_unref(reply);
749         return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
750                                       "an internal error occurred returning "
751                                       "interface capabilities.");
752 }
753
754
755 /**
756  * wpas_dbus_iface_add_network - Add a new configured network
757  * @message: Pointer to incoming dbus message
758  * @wpa_s: wpa_supplicant structure for a network interface
759  * Returns: A dbus message containing the object path of the new network
760  *
761  * Handler function for "addNetwork" method call of a network interface.
762  */
763 DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
764                                           struct wpa_supplicant *wpa_s)
765 {
766         DBusMessage *reply = NULL;
767         struct wpa_ssid *ssid;
768         char *path = NULL;
769
770         path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
771         if (path == NULL) {
772                 perror("wpas_dbus_iface_scan_results[dbus]: out of "
773                        "memory.");
774                 wpa_printf(MSG_ERROR, "dbus control interface: not "
775                            "enough memory to send scan results "
776                            "signal.");
777                 goto out;
778         }
779
780         ssid = wpa_config_add_network(wpa_s->conf);
781         if (ssid == NULL) {
782                 reply = dbus_message_new_error(message,
783                                                WPAS_ERROR_ADD_NETWORK_ERROR,
784                                                "wpa_supplicant could not add "
785                                                "a network on this interface.");
786                 goto out;
787         }
788         ssid->disabled = 1;
789         wpa_config_set_network_defaults(ssid);
790
791         /* Construct the object path for this network. */
792         snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
793                  "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
794                  wpa_supplicant_get_dbus_path(wpa_s),
795                  ssid->id);
796
797         reply = dbus_message_new_method_return(message);
798         dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
799                                  &path, DBUS_TYPE_INVALID);
800
801 out:
802         free(path);
803         return reply;
804 }
805
806
807 /**
808  * wpas_dbus_iface_remove_network - Remove a configured network
809  * @message: Pointer to incoming dbus message
810  * @wpa_s: wpa_supplicant structure for a network interface
811  * Returns: A dbus message containing a UINT32 indicating success (1) or
812  *          failure (0)
813  *
814  * Handler function for "removeNetwork" method call of a network interface.
815  */
816 DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
817                                              struct wpa_supplicant *wpa_s)
818 {
819         DBusMessage *reply = NULL;
820         const char *op;
821         char *iface = NULL, *net_id = NULL;
822         int id;
823         struct wpa_ssid *ssid;
824
825         if (!dbus_message_get_args(message, NULL,
826                                    DBUS_TYPE_OBJECT_PATH, &op,
827                                    DBUS_TYPE_INVALID)) {
828                 reply = wpas_dbus_new_invalid_opts_error(message, NULL);
829                 goto out;
830         }
831
832         /* Extract the network ID */
833         iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
834         if (iface == NULL) {
835                 reply = wpas_dbus_new_invalid_network_error(message);
836                 goto out;
837         }
838         /* Ensure the network is actually a child of this interface */
839         if (strcmp(iface, wpa_supplicant_get_dbus_path(wpa_s)) != 0) {
840                 reply = wpas_dbus_new_invalid_network_error(message);
841                 goto out;
842         }
843
844         id = strtoul(net_id, NULL, 10);
845         ssid = wpa_config_get_network(wpa_s->conf, id);
846         if (ssid == NULL) {
847                 reply = wpas_dbus_new_invalid_network_error(message);
848                 goto out;
849         }
850
851         if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
852                 reply = dbus_message_new_error(message,
853                                                WPAS_ERROR_REMOVE_NETWORK_ERROR,
854                                                "error removing the specified "
855                                                "on this interface.");
856                 goto out;
857         }
858
859         if (ssid == wpa_s->current_ssid)
860                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
861         reply = wpas_dbus_new_success_reply(message);
862
863 out:
864         free(iface);
865         free(net_id);
866         return reply;
867 }
868
869
870 static const char *dont_quote[] = {
871         "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
872         "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
873         "bssid", NULL
874 };
875
876 static dbus_bool_t should_quote_opt(const char *key)
877 {
878         int i = 0;
879         while (dont_quote[i] != NULL) {
880                 if (strcmp(key, dont_quote[i]) == 0)
881                         return FALSE;
882                 i++;
883         }
884         return TRUE;
885 }
886
887 /**
888  * wpas_dbus_iface_set_network - Set options for a configured network
889  * @message: Pointer to incoming dbus message
890  * @wpa_s: wpa_supplicant structure for a network interface
891  * @ssid: wpa_ssid structure for a configured network
892  * Returns: a dbus message containing a UINT32 indicating success (1) or
893  *          failure (0)
894  *
895  * Handler function for "set" method call of a configured network.
896  */
897 DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
898                                           struct wpa_supplicant *wpa_s,
899                                           struct wpa_ssid *ssid)
900 {
901         DBusMessage *reply = NULL;
902         struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
903         DBusMessageIter iter, iter_dict;
904
905         dbus_message_iter_init(message, &iter);
906
907         if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) {
908                 reply = wpas_dbus_new_invalid_opts_error(message, NULL);
909                 goto out;
910         }
911
912         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
913                 char *value = NULL;
914                 size_t size = 50;
915                 int ret;
916
917                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
918                         reply = wpas_dbus_new_invalid_opts_error(message,
919                                                                  NULL);
920                         goto out;
921                 }
922
923                 /* Type conversions, since wpa_supplicant wants strings */
924                 if (entry.type == DBUS_TYPE_ARRAY &&
925                     entry.array_type == DBUS_TYPE_BYTE) {
926                         if (entry.array_len <= 0)
927                                 goto error;
928
929                         size = entry.array_len * 2 + 1;
930                         value = os_zalloc(size);
931                         if (value == NULL)
932                                 goto error;
933                         ret = wpa_snprintf_hex(value, size,
934                                         (u8 *) entry.bytearray_value,
935                                         entry.array_len);
936                         if (ret <= 0)
937                                 goto error;
938                 } else if (entry.type == DBUS_TYPE_STRING) {
939                         if (should_quote_opt(entry.key)) {
940                                 size = strlen(entry.str_value);
941                                 /* Zero-length option check */
942                                 if (size <= 0)
943                                         goto error;
944                                 size += 3;  /* For quotes and terminator */
945                                 value = os_zalloc(size);
946                                 if (value == NULL)
947                                         goto error;
948                                 ret = snprintf(value, size, "\"%s\"",
949                                                 entry.str_value);
950                                 if (ret < 0 || (size_t) ret != (size - 1))
951                                         goto error;
952                         } else {
953                                 value = strdup(entry.str_value);
954                                 if (value == NULL)
955                                         goto error;
956                         }
957                 } else if (entry.type == DBUS_TYPE_UINT32) {
958                         value = os_zalloc(size);
959                         if (value == NULL)
960                                 goto error;
961                         ret = snprintf(value, size, "%u", entry.uint32_value);
962                         if (ret <= 0)
963                                 goto error;
964                 } else if (entry.type == DBUS_TYPE_INT32) {
965                         value = os_zalloc(size);
966                         if (value == NULL)
967                                 goto error;
968                         ret = snprintf(value, size, "%d", entry.int32_value);
969                         if (ret <= 0)
970                                 goto error;
971                 } else
972                         goto error;
973
974                 if (wpa_config_set(ssid, entry.key, value, 0) < 0)
975                         goto error;
976
977                 if ((strcmp(entry.key, "psk") == 0 &&
978                      value[0] == '"' && ssid->ssid_len) ||
979                     (strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
980                         wpa_config_update_psk(ssid);
981
982                 free(value);
983                 wpa_dbus_dict_entry_clear(&entry);
984                 continue;
985
986         error:
987                 free(value);
988                 reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
989                 wpa_dbus_dict_entry_clear(&entry);
990                 break;
991         }
992
993         if (!reply)
994                 reply = wpas_dbus_new_success_reply(message);
995
996 out:
997         return reply;
998 }
999
1000
1001 /**
1002  * wpas_dbus_iface_enable_network - Mark a configured network as enabled
1003  * @message: Pointer to incoming dbus message
1004  * @wpa_s: wpa_supplicant structure for a network interface
1005  * @ssid: wpa_ssid structure for a configured network
1006  * Returns: A dbus message containing a UINT32 indicating success (1) or
1007  *          failure (0)
1008  *
1009  * Handler function for "enable" method call of a configured network.
1010  */
1011 DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
1012                                              struct wpa_supplicant *wpa_s,
1013                                              struct wpa_ssid *ssid)
1014 {
1015         if (wpa_s->current_ssid == NULL && ssid->disabled) {
1016                 /*
1017                  * Try to reassociate since there is no current configuration
1018                  * and a new network was made available.
1019                  */
1020                 wpa_s->reassociate = 1;
1021                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1022         }
1023         ssid->disabled = 0;
1024
1025         return wpas_dbus_new_success_reply(message);
1026 }
1027
1028
1029 /**
1030  * wpas_dbus_iface_disable_network - Mark a configured network as disabled
1031  * @message: Pointer to incoming dbus message
1032  * @wpa_s: wpa_supplicant structure for a network interface
1033  * @ssid: wpa_ssid structure for a configured network
1034  * Returns: A dbus message containing a UINT32 indicating success (1) or
1035  *          failure (0)
1036  *
1037  * Handler function for "disable" method call of a configured network.
1038  */
1039 DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
1040                                               struct wpa_supplicant *wpa_s,
1041                                               struct wpa_ssid *ssid)
1042 {
1043         if (ssid == wpa_s->current_ssid)
1044                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1045         ssid->disabled = 1;
1046
1047         return wpas_dbus_new_success_reply(message);
1048 }
1049
1050
1051 /**
1052  * wpas_dbus_iface_select_network - Attempt association with a configured network
1053  * @message: Pointer to incoming dbus message
1054  * @wpa_s: wpa_supplicant structure for a network interface
1055  * Returns: A dbus message containing a UINT32 indicating success (1) or
1056  *          failure (0)
1057  *
1058  * Handler function for "selectNetwork" method call of network interface.
1059  */
1060 DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
1061                                              struct wpa_supplicant *wpa_s)
1062 {
1063         DBusMessage *reply = NULL;
1064         const char *op;
1065         struct wpa_ssid *ssid;
1066         char *iface_obj_path = NULL;
1067         char *network = NULL;
1068
1069         if (strlen(dbus_message_get_signature(message)) == 0) {
1070                 /* Any network */
1071                 ssid = wpa_s->conf->ssid;
1072                 while (ssid) {
1073                         ssid->disabled = 0;
1074                         ssid = ssid->next;
1075                 }
1076                 wpa_s->reassociate = 1;
1077                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1078         } else {
1079                 const char *obj_path;
1080                 int nid;
1081
1082                 if (!dbus_message_get_args(message, NULL,
1083                                            DBUS_TYPE_OBJECT_PATH, &op,
1084                                            DBUS_TYPE_INVALID)) {
1085                         reply = wpas_dbus_new_invalid_opts_error(message,
1086                                                                  NULL);
1087                         goto out;
1088                 }
1089
1090                 /* Extract the network number */
1091                 iface_obj_path = wpas_dbus_decompose_object_path(op,
1092                                                                  &network,
1093                                                                  NULL);
1094                 if (iface_obj_path == NULL) {
1095                         reply = wpas_dbus_new_invalid_iface_error(message);
1096                         goto out;
1097                 }
1098                 /* Ensure the object path really points to this interface */
1099                 obj_path = wpa_supplicant_get_dbus_path(wpa_s);
1100                 if (strcmp(iface_obj_path, obj_path) != 0) {
1101                         reply = wpas_dbus_new_invalid_network_error(message);
1102                         goto out;
1103                 }
1104
1105                 nid = strtoul(network, NULL, 10);
1106                 if (errno == EINVAL) {
1107                         reply = wpas_dbus_new_invalid_network_error(message);
1108                         goto out;
1109                 }
1110
1111                 ssid = wpa_config_get_network(wpa_s->conf, nid);
1112                 if (ssid == NULL) {
1113                         reply = wpas_dbus_new_invalid_network_error(message);
1114                         goto out;
1115                 }
1116
1117                 /* Finally, associate with the network */
1118                 if (ssid != wpa_s->current_ssid && wpa_s->current_ssid)
1119                         wpa_supplicant_disassociate(
1120                                 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1121
1122                 /* Mark all other networks disabled and trigger reassociation
1123                  */
1124                 ssid = wpa_s->conf->ssid;
1125                 while (ssid) {
1126                         ssid->disabled = (nid != ssid->id);
1127                         ssid = ssid->next;
1128                 }
1129                 wpa_s->disconnected = 0;
1130                 wpa_s->reassociate = 1;
1131                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1132         }
1133
1134         reply = wpas_dbus_new_success_reply(message);
1135
1136 out:
1137         free(iface_obj_path);
1138         free(network);
1139         return reply;
1140 }
1141
1142
1143 /**
1144  * wpas_dbus_iface_disconnect - Terminate the current connection
1145  * @message: Pointer to incoming dbus message
1146  * @wpa_s: wpa_supplicant structure for a network interface
1147  * Returns: A dbus message containing a UINT32 indicating success (1) or
1148  *          failure (0)
1149  *
1150  * Handler function for "disconnect" method call of network interface.
1151  */
1152 DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
1153                                          struct wpa_supplicant *wpa_s)
1154 {
1155         wpa_s->disconnected = 1;
1156         wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1157
1158         return wpas_dbus_new_success_reply(message);
1159 }
1160
1161
1162 /**
1163  * wpas_dbus_iface_set_ap_scan - Control roaming mode
1164  * @message: Pointer to incoming dbus message
1165  * @wpa_s: wpa_supplicant structure for a network interface
1166  * Returns: A dbus message containing a UINT32 indicating success (1) or
1167  *          failure (0)
1168  *
1169  * Handler function for "setAPScan" method call.
1170  */
1171 DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
1172                                           struct wpa_supplicant *wpa_s)
1173 {
1174         DBusMessage *reply = NULL;
1175         dbus_uint32_t ap_scan = 1;
1176
1177         if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
1178                                    DBUS_TYPE_INVALID)) {
1179                 reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1180                 goto out;
1181         }
1182
1183         if (ap_scan > 2) {
1184                 reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1185                 goto out;
1186         }
1187         wpa_s->conf->ap_scan = ap_scan;
1188         reply = wpas_dbus_new_success_reply(message);
1189
1190 out:
1191         return reply;
1192 }
1193
1194
1195 /**
1196  * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
1197  * @message: Pointer to incoming dbus message
1198  * @wpa_s: wpa_supplicant structure for a network interface
1199  * Returns: A dbus message containing a UINT32 indicating success (1) or
1200  *          failure (0)
1201  *
1202  * Handler function for "setSmartcardModules" method call.
1203  */
1204 DBusMessage * wpas_dbus_iface_set_smartcard_modules(
1205         DBusMessage *message, struct wpa_supplicant *wpa_s)
1206 {
1207         DBusMessageIter iter, iter_dict;
1208         char *opensc_engine_path = NULL;
1209         char *pkcs11_engine_path = NULL;
1210         char *pkcs11_module_path = NULL;
1211         struct wpa_dbus_dict_entry entry;
1212
1213         if (!dbus_message_iter_init(message, &iter))
1214                 goto error;
1215
1216         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1217                 goto error;
1218
1219         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1220                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1221                         goto error;
1222                 if (!strcmp(entry.key, "opensc_engine_path") &&
1223                     (entry.type == DBUS_TYPE_STRING)) {
1224                         opensc_engine_path = os_strdup(entry.str_value);
1225                         if (opensc_engine_path == NULL)
1226                                 goto error;
1227                 } else if (!strcmp(entry.key, "pkcs11_engine_path") &&
1228                            (entry.type == DBUS_TYPE_STRING)) {
1229                         pkcs11_engine_path = os_strdup(entry.str_value);
1230                         if (pkcs11_engine_path == NULL)
1231                                 goto error;
1232                 } else if (!strcmp(entry.key, "pkcs11_module_path") &&
1233                                  (entry.type == DBUS_TYPE_STRING)) {
1234                         pkcs11_module_path = os_strdup(entry.str_value);
1235                         if (pkcs11_module_path == NULL)
1236                                 goto error;
1237                 } else {
1238                         wpa_dbus_dict_entry_clear(&entry);
1239                         goto error;
1240                 }
1241                 wpa_dbus_dict_entry_clear(&entry);
1242         }
1243
1244 #ifdef EAP_TLS_OPENSSL
1245         os_free(wpa_s->conf->opensc_engine_path);
1246         wpa_s->conf->opensc_engine_path = opensc_engine_path;
1247         os_free(wpa_s->conf->pkcs11_engine_path);
1248         wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
1249         os_free(wpa_s->conf->pkcs11_module_path);
1250         wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
1251 #endif /* EAP_TLS_OPENSSL */
1252
1253         eapol_sm_deinit(wpa_s->eapol);
1254         wpa_supplicant_init_eapol(wpa_s);
1255
1256         return wpas_dbus_new_success_reply(message);
1257
1258 error:
1259         os_free(opensc_engine_path);
1260         os_free(pkcs11_engine_path);
1261         os_free(pkcs11_module_path);
1262         return wpas_dbus_new_invalid_opts_error(message, NULL);
1263 }
1264
1265 /**
1266  * wpas_dbus_iface_get_state - Get interface state
1267  * @message: Pointer to incoming dbus message
1268  * @wpa_s: wpa_supplicant structure for a network interface
1269  * Returns: A dbus message containing a STRING representing the current
1270  *          interface state
1271  *
1272  * Handler function for "state" method call.
1273  */
1274 DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
1275                                         struct wpa_supplicant *wpa_s)
1276 {
1277         DBusMessage *reply = NULL;
1278         const char *str_state;
1279
1280         reply = dbus_message_new_method_return(message);
1281         if (reply != NULL) {
1282                 str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
1283                 dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
1284                                          DBUS_TYPE_INVALID);
1285         }
1286
1287         return reply;
1288 }
1289
1290
1291 /**
1292  * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
1293  * @message: Pointer to incoming dbus message
1294  * @wpa_s: %wpa_supplicant data structure
1295  * Returns: A dbus message containing a UINT32 indicating success (1) or
1296  *          failure (0)
1297  *
1298  * Asks wpa_supplicant to internally store a one or more binary blobs.
1299  */
1300 DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
1301                                         struct wpa_supplicant *wpa_s)
1302 {
1303         DBusMessage *reply = NULL;
1304         struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1305         DBusMessageIter iter, iter_dict;
1306
1307         dbus_message_iter_init(message, &iter);
1308
1309         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1310                 return wpas_dbus_new_invalid_opts_error(message, NULL);
1311
1312         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1313                 struct wpa_config_blob *blob;
1314
1315                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1316                         reply = wpas_dbus_new_invalid_opts_error(message,
1317                                                                  NULL);
1318                         break;
1319                 }
1320
1321                 if (entry.type != DBUS_TYPE_ARRAY ||
1322                     entry.array_type != DBUS_TYPE_BYTE) {
1323                         reply = wpas_dbus_new_invalid_opts_error(
1324                                 message, "Byte array expected.");
1325                         break;
1326                 }
1327
1328                 if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
1329                     !strlen(entry.key)) {
1330                         reply = wpas_dbus_new_invalid_opts_error(
1331                                 message, "Invalid array size.");
1332                         break;
1333                 }
1334
1335                 blob = os_zalloc(sizeof(*blob));
1336                 if (blob == NULL) {
1337                         reply = dbus_message_new_error(
1338                                 message, WPAS_ERROR_ADD_ERROR,
1339                                 "Not enough memory to add blob.");
1340                         break;
1341                 }
1342                 blob->data = os_zalloc(entry.array_len);
1343                 if (blob->data == NULL) {
1344                         reply = dbus_message_new_error(
1345                                 message, WPAS_ERROR_ADD_ERROR,
1346                                 "Not enough memory to add blob data.");
1347                         os_free(blob);
1348                         break;
1349                 }
1350
1351                 blob->name = os_strdup(entry.key);
1352                 blob->len = entry.array_len;
1353                 os_memcpy(blob->data, (u8 *) entry.bytearray_value,
1354                                 entry.array_len);
1355                 if (blob->name == NULL || blob->data == NULL) {
1356                         wpa_config_free_blob(blob);
1357                         reply = dbus_message_new_error(
1358                                 message, WPAS_ERROR_ADD_ERROR,
1359                                 "Error adding blob.");
1360                         break;
1361                 }
1362
1363                 /* Success */
1364                 wpa_config_remove_blob(wpa_s->conf, blob->name);
1365                 wpa_config_set_blob(wpa_s->conf, blob);
1366                 wpa_dbus_dict_entry_clear(&entry);
1367         }
1368         wpa_dbus_dict_entry_clear(&entry);
1369
1370         return reply ? reply : wpas_dbus_new_success_reply(message);
1371 }
1372
1373
1374 /**
1375  * wpas_dbus_iface_remove_blob - Remove named binary blobs
1376  * @message: Pointer to incoming dbus message
1377  * @wpa_s: %wpa_supplicant data structure
1378  * Returns: A dbus message containing a UINT32 indicating success (1) or
1379  *          failure (0)
1380  *
1381  * Asks wpa_supplicant to remove one or more previously stored binary blobs.
1382  */
1383 DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
1384                                           struct wpa_supplicant *wpa_s)
1385 {
1386         DBusMessageIter iter, array;
1387         char *err_msg = NULL;
1388
1389         dbus_message_iter_init(message, &iter);
1390
1391         if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
1392             (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
1393                 return wpas_dbus_new_invalid_opts_error(message, NULL);
1394
1395         dbus_message_iter_recurse(&iter, &array);
1396         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
1397                 const char *name;
1398
1399                 dbus_message_iter_get_basic(&array, &name);
1400                 if (!strlen(name))
1401                         err_msg = "Invalid blob name.";
1402
1403                 if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
1404                         err_msg = "Error removing blob.";
1405                 dbus_message_iter_next(&array);
1406         }
1407
1408         if (err_msg) {
1409                 return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
1410                                               err_msg);
1411         }
1412
1413         return wpas_dbus_new_success_reply(message);
1414 }