Check os_snprintf() result more consistently - manual
[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) {
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 (wpa_config_remove_network(wpa_s->conf, id) < 0) {
870                 reply = dbus_message_new_error(message,
871                                                WPAS_ERROR_REMOVE_NETWORK_ERROR,
872                                                "error removing the specified "
873                                                "on this interface.");
874                 goto out;
875         }
876
877         if (ssid == wpa_s->current_ssid)
878                 wpa_supplicant_deauthenticate(wpa_s,
879                                               WLAN_REASON_DEAUTH_LEAVING);
880         reply = wpas_dbus_new_success_reply(message);
881
882 out:
883         os_free(iface);
884         os_free(net_id);
885         return reply;
886 }
887
888
889 static const char *dont_quote[] = {
890         "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
891         "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
892         "bssid", NULL
893 };
894
895
896 static dbus_bool_t should_quote_opt(const char *key)
897 {
898         int i = 0;
899         while (dont_quote[i] != NULL) {
900                 if (strcmp(key, dont_quote[i]) == 0)
901                         return FALSE;
902                 i++;
903         }
904         return TRUE;
905 }
906
907
908 /**
909  * wpas_dbus_iface_set_network - Set options for a configured network
910  * @message: Pointer to incoming dbus message
911  * @wpa_s: wpa_supplicant structure for a network interface
912  * @ssid: wpa_ssid structure for a configured network
913  * Returns: a dbus message containing a UINT32 indicating success (1) or
914  *          failure (0)
915  *
916  * Handler function for "set" method call of a configured network.
917  */
918 DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
919                                           struct wpa_supplicant *wpa_s,
920                                           struct wpa_ssid *ssid)
921 {
922         DBusMessage *reply = NULL;
923         struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
924         DBusMessageIter iter, iter_dict;
925
926         dbus_message_iter_init(message, &iter);
927
928         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) {
929                 reply = wpas_dbus_new_invalid_opts_error(message, NULL);
930                 goto out;
931         }
932
933         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
934                 char *value = NULL;
935                 size_t size = 50;
936                 int ret;
937
938                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
939                         reply = wpas_dbus_new_invalid_opts_error(message,
940                                                                  NULL);
941                         goto out;
942                 }
943
944                 /* Type conversions, since wpa_supplicant wants strings */
945                 if (entry.type == DBUS_TYPE_ARRAY &&
946                     entry.array_type == DBUS_TYPE_BYTE) {
947                         if (entry.array_len <= 0)
948                                 goto error;
949
950                         size = entry.array_len * 2 + 1;
951                         value = os_zalloc(size);
952                         if (value == NULL)
953                                 goto error;
954                         ret = wpa_snprintf_hex(value, size,
955                                                (u8 *) entry.bytearray_value,
956                                                entry.array_len);
957                         if (ret <= 0)
958                                 goto error;
959                 } else if (entry.type == DBUS_TYPE_STRING) {
960                         if (should_quote_opt(entry.key)) {
961                                 size = os_strlen(entry.str_value);
962                                 /* Zero-length option check */
963                                 if (size <= 0)
964                                         goto error;
965                                 size += 3;  /* For quotes and terminator */
966                                 value = os_zalloc(size);
967                                 if (value == NULL)
968                                         goto error;
969                                 ret = os_snprintf(value, size, "\"%s\"",
970                                                   entry.str_value);
971                                 if (os_snprintf_error(size, ret))
972                                         goto error;
973                         } else {
974                                 value = os_strdup(entry.str_value);
975                                 if (value == NULL)
976                                         goto error;
977                         }
978                 } else if (entry.type == DBUS_TYPE_UINT32) {
979                         value = os_zalloc(size);
980                         if (value == NULL)
981                                 goto error;
982                         ret = os_snprintf(value, size, "%u",
983                                           entry.uint32_value);
984                         if (os_snprintf_error(size, ret))
985                                 goto error;
986                 } else if (entry.type == DBUS_TYPE_INT32) {
987                         value = os_zalloc(size);
988                         if (value == NULL)
989                                 goto error;
990                         ret = os_snprintf(value, size, "%d",
991                                           entry.int32_value);
992                         if (os_snprintf_error(size, ret))
993                                 goto error;
994                 } else
995                         goto error;
996
997                 if (wpa_config_set(ssid, entry.key, value, 0) < 0)
998                         goto error;
999
1000                 if ((os_strcmp(entry.key, "psk") == 0 &&
1001                      value[0] == '"' && ssid->ssid_len) ||
1002                     (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
1003                         wpa_config_update_psk(ssid);
1004                 else if (os_strcmp(entry.key, "priority") == 0)
1005                         wpa_config_update_prio_list(wpa_s->conf);
1006
1007                 os_free(value);
1008                 wpa_dbus_dict_entry_clear(&entry);
1009                 continue;
1010
1011         error:
1012                 os_free(value);
1013                 reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
1014                 wpa_dbus_dict_entry_clear(&entry);
1015                 break;
1016         }
1017
1018         if (!reply)
1019                 reply = wpas_dbus_new_success_reply(message);
1020
1021 out:
1022         return reply;
1023 }
1024
1025
1026 /**
1027  * wpas_dbus_iface_enable_network - Mark a configured network as enabled
1028  * @message: Pointer to incoming dbus message
1029  * @wpa_s: wpa_supplicant structure for a network interface
1030  * @ssid: wpa_ssid structure for a configured network
1031  * Returns: A dbus message containing a UINT32 indicating success (1) or
1032  *          failure (0)
1033  *
1034  * Handler function for "enable" method call of a configured network.
1035  */
1036 DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
1037                                              struct wpa_supplicant *wpa_s,
1038                                              struct wpa_ssid *ssid)
1039 {
1040         wpa_supplicant_enable_network(wpa_s, ssid);
1041         return wpas_dbus_new_success_reply(message);
1042 }
1043
1044
1045 /**
1046  * wpas_dbus_iface_disable_network - Mark a configured network as disabled
1047  * @message: Pointer to incoming dbus message
1048  * @wpa_s: wpa_supplicant structure for a network interface
1049  * @ssid: wpa_ssid structure for a configured network
1050  * Returns: A dbus message containing a UINT32 indicating success (1) or
1051  *          failure (0)
1052  *
1053  * Handler function for "disable" method call of a configured network.
1054  */
1055 DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
1056                                               struct wpa_supplicant *wpa_s,
1057                                               struct wpa_ssid *ssid)
1058 {
1059         wpa_supplicant_disable_network(wpa_s, ssid);
1060         return wpas_dbus_new_success_reply(message);
1061 }
1062
1063
1064 /**
1065  * wpas_dbus_iface_select_network - Attempt association with a configured network
1066  * @message: Pointer to incoming dbus message
1067  * @wpa_s: wpa_supplicant structure for a network interface
1068  * Returns: A dbus message containing a UINT32 indicating success (1) or
1069  *          failure (0)
1070  *
1071  * Handler function for "selectNetwork" method call of network interface.
1072  */
1073 DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
1074                                              struct wpa_supplicant *wpa_s)
1075 {
1076         DBusMessage *reply = NULL;
1077         const char *op;
1078         struct wpa_ssid *ssid;
1079         char *iface_obj_path = NULL;
1080         char *network = NULL;
1081
1082         if (os_strlen(dbus_message_get_signature(message)) == 0) {
1083                 /* Any network */
1084                 ssid = NULL;
1085         } else {
1086                 int nid;
1087
1088                 if (!dbus_message_get_args(message, NULL,
1089                                            DBUS_TYPE_OBJECT_PATH, &op,
1090                                            DBUS_TYPE_INVALID)) {
1091                         reply = wpas_dbus_new_invalid_opts_error(message,
1092                                                                  NULL);
1093                         goto out;
1094                 }
1095
1096                 /* Extract the network number */
1097                 iface_obj_path = wpas_dbus_decompose_object_path(op,
1098                                                                  &network,
1099                                                                  NULL);
1100                 if (iface_obj_path == NULL) {
1101                         reply = wpas_dbus_new_invalid_iface_error(message);
1102                         goto out;
1103                 }
1104                 /* Ensure the object path really points to this interface */
1105                 if (os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
1106                         reply = wpas_dbus_new_invalid_network_error(message);
1107                         goto out;
1108                 }
1109
1110                 nid = strtoul(network, NULL, 10);
1111                 if (errno == EINVAL) {
1112                         reply = wpas_dbus_new_invalid_network_error(message);
1113                         goto out;
1114                 }
1115
1116                 ssid = wpa_config_get_network(wpa_s->conf, nid);
1117                 if (ssid == NULL) {
1118                         reply = wpas_dbus_new_invalid_network_error(message);
1119                         goto out;
1120                 }
1121         }
1122
1123         /* Finally, associate with the network */
1124         wpa_supplicant_select_network(wpa_s, ssid);
1125
1126         reply = wpas_dbus_new_success_reply(message);
1127
1128 out:
1129         os_free(iface_obj_path);
1130         os_free(network);
1131         return reply;
1132 }
1133
1134
1135 /**
1136  * wpas_dbus_iface_disconnect - Terminate the current connection
1137  * @message: Pointer to incoming dbus message
1138  * @wpa_s: wpa_supplicant structure for a network interface
1139  * Returns: A dbus message containing a UINT32 indicating success (1) or
1140  *          failure (0)
1141  *
1142  * Handler function for "disconnect" method call of network interface.
1143  */
1144 DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
1145                                          struct wpa_supplicant *wpa_s)
1146 {
1147         wpa_s->disconnected = 1;
1148         wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1149
1150         return wpas_dbus_new_success_reply(message);
1151 }
1152
1153
1154 /**
1155  * wpas_dbus_iface_set_ap_scan - Control roaming mode
1156  * @message: Pointer to incoming dbus message
1157  * @wpa_s: wpa_supplicant structure for a network interface
1158  * Returns: A dbus message containing a UINT32 indicating success (1) or
1159  *          failure (0)
1160  *
1161  * Handler function for "setAPScan" method call.
1162  */
1163 DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
1164                                           struct wpa_supplicant *wpa_s)
1165 {
1166         DBusMessage *reply = NULL;
1167         dbus_uint32_t ap_scan = 1;
1168
1169         if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
1170                                    DBUS_TYPE_INVALID)) {
1171                 reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1172                 goto out;
1173         }
1174
1175         if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
1176                 reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1177                 goto out;
1178         }
1179
1180         reply = wpas_dbus_new_success_reply(message);
1181
1182 out:
1183         return reply;
1184 }
1185
1186
1187 /**
1188  * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
1189  * @message: Pointer to incoming dbus message
1190  * @wpa_s: wpa_supplicant structure for a network interface
1191  * Returns: A dbus message containing a UINT32 indicating success (1) or
1192  *          failure (0)
1193  *
1194  * Handler function for "setSmartcardModules" method call.
1195  */
1196 DBusMessage * wpas_dbus_iface_set_smartcard_modules(
1197         DBusMessage *message, struct wpa_supplicant *wpa_s)
1198 {
1199         DBusMessageIter iter, iter_dict;
1200         char *opensc_engine_path = NULL;
1201         char *pkcs11_engine_path = NULL;
1202         char *pkcs11_module_path = NULL;
1203         struct wpa_dbus_dict_entry entry;
1204
1205         if (!dbus_message_iter_init(message, &iter))
1206                 goto error;
1207
1208         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1209                 goto error;
1210
1211         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1212                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1213                         goto error;
1214                 if (!strcmp(entry.key, "opensc_engine_path") &&
1215                     (entry.type == DBUS_TYPE_STRING)) {
1216                         os_free(opensc_engine_path);
1217                         opensc_engine_path = os_strdup(entry.str_value);
1218                         if (opensc_engine_path == NULL)
1219                                 goto error;
1220                 } else if (!strcmp(entry.key, "pkcs11_engine_path") &&
1221                            (entry.type == DBUS_TYPE_STRING)) {
1222                         os_free(pkcs11_engine_path);
1223                         pkcs11_engine_path = os_strdup(entry.str_value);
1224                         if (pkcs11_engine_path == NULL)
1225                                 goto error;
1226                 } else if (!strcmp(entry.key, "pkcs11_module_path") &&
1227                                  (entry.type == DBUS_TYPE_STRING)) {
1228                         os_free(pkcs11_module_path);
1229                         pkcs11_module_path = os_strdup(entry.str_value);
1230                         if (pkcs11_module_path == NULL)
1231                                 goto error;
1232                 } else {
1233                         wpa_dbus_dict_entry_clear(&entry);
1234                         goto error;
1235                 }
1236                 wpa_dbus_dict_entry_clear(&entry);
1237         }
1238
1239         os_free(wpa_s->conf->opensc_engine_path);
1240         wpa_s->conf->opensc_engine_path = opensc_engine_path;
1241         os_free(wpa_s->conf->pkcs11_engine_path);
1242         wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
1243         os_free(wpa_s->conf->pkcs11_module_path);
1244         wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
1245
1246         wpa_sm_set_eapol(wpa_s->wpa, NULL);
1247         eapol_sm_deinit(wpa_s->eapol);
1248         wpa_s->eapol = NULL;
1249         wpa_supplicant_init_eapol(wpa_s);
1250         wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
1251
1252         return wpas_dbus_new_success_reply(message);
1253
1254 error:
1255         os_free(opensc_engine_path);
1256         os_free(pkcs11_engine_path);
1257         os_free(pkcs11_module_path);
1258         return wpas_dbus_new_invalid_opts_error(message, NULL);
1259 }
1260
1261
1262 /**
1263  * wpas_dbus_iface_get_state - Get interface state
1264  * @message: Pointer to incoming dbus message
1265  * @wpa_s: wpa_supplicant structure for a network interface
1266  * Returns: A dbus message containing a STRING representing the current
1267  *          interface state
1268  *
1269  * Handler function for "state" method call.
1270  */
1271 DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
1272                                         struct wpa_supplicant *wpa_s)
1273 {
1274         DBusMessage *reply = NULL;
1275         const char *str_state;
1276
1277         reply = dbus_message_new_method_return(message);
1278         if (reply != NULL) {
1279                 str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
1280                 dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
1281                                          DBUS_TYPE_INVALID);
1282         }
1283
1284         return reply;
1285 }
1286
1287
1288 /**
1289  * wpas_dbus_iface_get_scanning - Get interface scanning state
1290  * @message: Pointer to incoming dbus message
1291  * @wpa_s: wpa_supplicant structure for a network interface
1292  * Returns: A dbus message containing whether the interface is scanning
1293  *
1294  * Handler function for "scanning" method call.
1295  */
1296 DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
1297                                            struct wpa_supplicant *wpa_s)
1298 {
1299         DBusMessage *reply = NULL;
1300         dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
1301
1302         reply = dbus_message_new_method_return(message);
1303         if (reply != NULL) {
1304                 dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
1305                                          DBUS_TYPE_INVALID);
1306         } else {
1307                 wpa_printf(MSG_ERROR, "dbus: Not enough memory to return "
1308                            "scanning state");
1309         }
1310
1311         return reply;
1312 }
1313
1314
1315 #ifndef CONFIG_NO_CONFIG_BLOBS
1316
1317 /**
1318  * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
1319  * @message: Pointer to incoming dbus message
1320  * @wpa_s: %wpa_supplicant data structure
1321  * Returns: A dbus message containing a UINT32 indicating success (1) or
1322  *          failure (0)
1323  *
1324  * Asks wpa_supplicant to internally store a one or more binary blobs.
1325  */
1326 DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
1327                                         struct wpa_supplicant *wpa_s)
1328 {
1329         DBusMessage *reply = NULL;
1330         struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1331         DBusMessageIter iter, iter_dict;
1332
1333         dbus_message_iter_init(message, &iter);
1334
1335         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1336                 return wpas_dbus_new_invalid_opts_error(message, NULL);
1337
1338         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1339                 struct wpa_config_blob *blob;
1340
1341                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1342                         reply = wpas_dbus_new_invalid_opts_error(message,
1343                                                                  NULL);
1344                         break;
1345                 }
1346
1347                 if (entry.type != DBUS_TYPE_ARRAY ||
1348                     entry.array_type != DBUS_TYPE_BYTE) {
1349                         reply = wpas_dbus_new_invalid_opts_error(
1350                                 message, "Byte array expected.");
1351                         break;
1352                 }
1353
1354                 if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
1355                     !strlen(entry.key)) {
1356                         reply = wpas_dbus_new_invalid_opts_error(
1357                                 message, "Invalid array size.");
1358                         break;
1359                 }
1360
1361                 blob = os_zalloc(sizeof(*blob));
1362                 if (blob == NULL) {
1363                         reply = dbus_message_new_error(
1364                                 message, WPAS_ERROR_ADD_ERROR,
1365                                 "Not enough memory to add blob.");
1366                         break;
1367                 }
1368                 blob->data = os_zalloc(entry.array_len);
1369                 if (blob->data == NULL) {
1370                         reply = dbus_message_new_error(
1371                                 message, WPAS_ERROR_ADD_ERROR,
1372                                 "Not enough memory to add blob data.");
1373                         os_free(blob);
1374                         break;
1375                 }
1376
1377                 blob->name = os_strdup(entry.key);
1378                 blob->len = entry.array_len;
1379                 os_memcpy(blob->data, (u8 *) entry.bytearray_value,
1380                                 entry.array_len);
1381                 if (blob->name == NULL || blob->data == NULL) {
1382                         wpa_config_free_blob(blob);
1383                         reply = dbus_message_new_error(
1384                                 message, WPAS_ERROR_ADD_ERROR,
1385                                 "Error adding blob.");
1386                         break;
1387                 }
1388
1389                 /* Success */
1390                 if (!wpa_config_remove_blob(wpa_s->conf, blob->name))
1391                         wpas_notify_blob_removed(wpa_s, blob->name);
1392                 wpa_config_set_blob(wpa_s->conf, blob);
1393                 wpas_notify_blob_added(wpa_s, blob->name);
1394
1395                 wpa_dbus_dict_entry_clear(&entry);
1396         }
1397         wpa_dbus_dict_entry_clear(&entry);
1398
1399         return reply ? reply : wpas_dbus_new_success_reply(message);
1400 }
1401
1402
1403 /**
1404  * wpas_dbus_iface_remove_blob - Remove named binary blobs
1405  * @message: Pointer to incoming dbus message
1406  * @wpa_s: %wpa_supplicant data structure
1407  * Returns: A dbus message containing a UINT32 indicating success (1) or
1408  *          failure (0)
1409  *
1410  * Asks wpa_supplicant to remove one or more previously stored binary blobs.
1411  */
1412 DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
1413                                            struct wpa_supplicant *wpa_s)
1414 {
1415         DBusMessageIter iter, array;
1416         char *err_msg = NULL;
1417
1418         dbus_message_iter_init(message, &iter);
1419
1420         if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
1421             (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
1422                 return wpas_dbus_new_invalid_opts_error(message, NULL);
1423
1424         dbus_message_iter_recurse(&iter, &array);
1425         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
1426                 const char *name;
1427
1428                 dbus_message_iter_get_basic(&array, &name);
1429                 if (!os_strlen(name))
1430                         err_msg = "Invalid blob name.";
1431
1432                 if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
1433                         err_msg = "Error removing blob.";
1434                 else
1435                         wpas_notify_blob_removed(wpa_s, name);
1436                 dbus_message_iter_next(&array);
1437         }
1438
1439         if (err_msg)
1440                 return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
1441                                               err_msg);
1442
1443         return wpas_dbus_new_success_reply(message);
1444 }
1445
1446 #endif /* CONFIG_NO_CONFIG_BLOBS */
1447
1448
1449 /**
1450  * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
1451  * @message: Pointer to incoming dbus message
1452  * @wpa_s: %wpa_supplicant data structure
1453  * Returns: a dbus message containing a UINT32 indicating success (1) or
1454  *          failure (0), or returns a dbus error message with more information
1455  *
1456  * Handler function for "flush" method call. Handles requests for an
1457  * interface with an optional "age" parameter that specifies the minimum
1458  * age of a BSS to be flushed.
1459  */
1460 DBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
1461                                     struct wpa_supplicant *wpa_s)
1462 {
1463         int flush_age = 0;
1464
1465         if (os_strlen(dbus_message_get_signature(message)) != 0 &&
1466             !dbus_message_get_args(message, NULL,
1467                                    DBUS_TYPE_INT32, &flush_age,
1468                                    DBUS_TYPE_INVALID)) {
1469                 return wpas_dbus_new_invalid_opts_error(message, NULL);
1470         }
1471
1472         if (flush_age == 0)
1473                 wpa_bss_flush(wpa_s);
1474         else
1475                 wpa_bss_flush_by_age(wpa_s, flush_age);
1476
1477         return wpas_dbus_new_success_reply(message);
1478 }