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