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