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