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