D-Bus(old): Remove duplicated blob->data check
[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 (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 (network == NULL ||
1106                     os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
1107                         reply = wpas_dbus_new_invalid_network_error(message);
1108                         goto out;
1109                 }
1110
1111                 nid = strtoul(network, NULL, 10);
1112                 if (errno == EINVAL) {
1113                         reply = wpas_dbus_new_invalid_network_error(message);
1114                         goto out;
1115                 }
1116
1117                 ssid = wpa_config_get_network(wpa_s->conf, nid);
1118                 if (ssid == NULL) {
1119                         reply = wpas_dbus_new_invalid_network_error(message);
1120                         goto out;
1121                 }
1122         }
1123
1124         /* Finally, associate with the network */
1125         wpa_supplicant_select_network(wpa_s, ssid);
1126
1127         reply = wpas_dbus_new_success_reply(message);
1128
1129 out:
1130         os_free(iface_obj_path);
1131         os_free(network);
1132         return reply;
1133 }
1134
1135
1136 /**
1137  * wpas_dbus_iface_disconnect - Terminate the current connection
1138  * @message: Pointer to incoming dbus message
1139  * @wpa_s: wpa_supplicant structure for a network interface
1140  * Returns: A dbus message containing a UINT32 indicating success (1) or
1141  *          failure (0)
1142  *
1143  * Handler function for "disconnect" method call of network interface.
1144  */
1145 DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
1146                                          struct wpa_supplicant *wpa_s)
1147 {
1148         wpa_s->disconnected = 1;
1149         wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1150
1151         return wpas_dbus_new_success_reply(message);
1152 }
1153
1154
1155 /**
1156  * wpas_dbus_iface_set_ap_scan - Control roaming mode
1157  * @message: Pointer to incoming dbus message
1158  * @wpa_s: wpa_supplicant structure for a network interface
1159  * Returns: A dbus message containing a UINT32 indicating success (1) or
1160  *          failure (0)
1161  *
1162  * Handler function for "setAPScan" method call.
1163  */
1164 DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
1165                                           struct wpa_supplicant *wpa_s)
1166 {
1167         DBusMessage *reply = NULL;
1168         dbus_uint32_t ap_scan = 1;
1169
1170         if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
1171                                    DBUS_TYPE_INVALID)) {
1172                 reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1173                 goto out;
1174         }
1175
1176         if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
1177                 reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1178                 goto out;
1179         }
1180
1181         reply = wpas_dbus_new_success_reply(message);
1182
1183 out:
1184         return reply;
1185 }
1186
1187
1188 /**
1189  * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
1190  * @message: Pointer to incoming dbus message
1191  * @wpa_s: wpa_supplicant structure for a network interface
1192  * Returns: A dbus message containing a UINT32 indicating success (1) or
1193  *          failure (0)
1194  *
1195  * Handler function for "setSmartcardModules" method call.
1196  */
1197 DBusMessage * wpas_dbus_iface_set_smartcard_modules(
1198         DBusMessage *message, struct wpa_supplicant *wpa_s)
1199 {
1200         DBusMessageIter iter, iter_dict;
1201         char *opensc_engine_path = NULL;
1202         char *pkcs11_engine_path = NULL;
1203         char *pkcs11_module_path = NULL;
1204         struct wpa_dbus_dict_entry entry;
1205
1206         if (!dbus_message_iter_init(message, &iter))
1207                 goto error;
1208
1209         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1210                 goto error;
1211
1212         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1213                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1214                         goto error;
1215                 if (!strcmp(entry.key, "opensc_engine_path") &&
1216                     (entry.type == DBUS_TYPE_STRING)) {
1217                         os_free(opensc_engine_path);
1218                         opensc_engine_path = os_strdup(entry.str_value);
1219                         if (opensc_engine_path == NULL)
1220                                 goto error;
1221                 } else if (!strcmp(entry.key, "pkcs11_engine_path") &&
1222                            (entry.type == DBUS_TYPE_STRING)) {
1223                         os_free(pkcs11_engine_path);
1224                         pkcs11_engine_path = os_strdup(entry.str_value);
1225                         if (pkcs11_engine_path == NULL)
1226                                 goto error;
1227                 } else if (!strcmp(entry.key, "pkcs11_module_path") &&
1228                                  (entry.type == DBUS_TYPE_STRING)) {
1229                         os_free(pkcs11_module_path);
1230                         pkcs11_module_path = os_strdup(entry.str_value);
1231                         if (pkcs11_module_path == NULL)
1232                                 goto error;
1233                 } else {
1234                         wpa_dbus_dict_entry_clear(&entry);
1235                         goto error;
1236                 }
1237                 wpa_dbus_dict_entry_clear(&entry);
1238         }
1239
1240         os_free(wpa_s->conf->opensc_engine_path);
1241         wpa_s->conf->opensc_engine_path = opensc_engine_path;
1242         os_free(wpa_s->conf->pkcs11_engine_path);
1243         wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
1244         os_free(wpa_s->conf->pkcs11_module_path);
1245         wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
1246
1247         wpa_sm_set_eapol(wpa_s->wpa, NULL);
1248         eapol_sm_deinit(wpa_s->eapol);
1249         wpa_s->eapol = NULL;
1250         wpa_supplicant_init_eapol(wpa_s);
1251         wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
1252
1253         return wpas_dbus_new_success_reply(message);
1254
1255 error:
1256         os_free(opensc_engine_path);
1257         os_free(pkcs11_engine_path);
1258         os_free(pkcs11_module_path);
1259         return wpas_dbus_new_invalid_opts_error(message, NULL);
1260 }
1261
1262
1263 /**
1264  * wpas_dbus_iface_get_state - Get interface state
1265  * @message: Pointer to incoming dbus message
1266  * @wpa_s: wpa_supplicant structure for a network interface
1267  * Returns: A dbus message containing a STRING representing the current
1268  *          interface state
1269  *
1270  * Handler function for "state" method call.
1271  */
1272 DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
1273                                         struct wpa_supplicant *wpa_s)
1274 {
1275         DBusMessage *reply = NULL;
1276         const char *str_state;
1277
1278         reply = dbus_message_new_method_return(message);
1279         if (reply != NULL) {
1280                 str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
1281                 dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
1282                                          DBUS_TYPE_INVALID);
1283         }
1284
1285         return reply;
1286 }
1287
1288
1289 /**
1290  * wpas_dbus_iface_get_scanning - Get interface scanning state
1291  * @message: Pointer to incoming dbus message
1292  * @wpa_s: wpa_supplicant structure for a network interface
1293  * Returns: A dbus message containing whether the interface is scanning
1294  *
1295  * Handler function for "scanning" method call.
1296  */
1297 DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
1298                                            struct wpa_supplicant *wpa_s)
1299 {
1300         DBusMessage *reply = NULL;
1301         dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
1302
1303         reply = dbus_message_new_method_return(message);
1304         if (reply != NULL) {
1305                 dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
1306                                          DBUS_TYPE_INVALID);
1307         } else {
1308                 wpa_printf(MSG_ERROR, "dbus: Not enough memory to return "
1309                            "scanning state");
1310         }
1311
1312         return reply;
1313 }
1314
1315
1316 #ifndef CONFIG_NO_CONFIG_BLOBS
1317
1318 /**
1319  * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
1320  * @message: Pointer to incoming dbus message
1321  * @wpa_s: %wpa_supplicant data structure
1322  * Returns: A dbus message containing a UINT32 indicating success (1) or
1323  *          failure (0)
1324  *
1325  * Asks wpa_supplicant to internally store a one or more binary blobs.
1326  */
1327 DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
1328                                         struct wpa_supplicant *wpa_s)
1329 {
1330         DBusMessage *reply = NULL;
1331         struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1332         DBusMessageIter iter, iter_dict;
1333
1334         dbus_message_iter_init(message, &iter);
1335
1336         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1337                 return wpas_dbus_new_invalid_opts_error(message, NULL);
1338
1339         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1340                 struct wpa_config_blob *blob;
1341
1342                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1343                         reply = wpas_dbus_new_invalid_opts_error(message,
1344                                                                  NULL);
1345                         break;
1346                 }
1347
1348                 if (entry.type != DBUS_TYPE_ARRAY ||
1349                     entry.array_type != DBUS_TYPE_BYTE) {
1350                         reply = wpas_dbus_new_invalid_opts_error(
1351                                 message, "Byte array expected.");
1352                         break;
1353                 }
1354
1355                 if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
1356                     !strlen(entry.key)) {
1357                         reply = wpas_dbus_new_invalid_opts_error(
1358                                 message, "Invalid array size.");
1359                         break;
1360                 }
1361
1362                 blob = os_zalloc(sizeof(*blob));
1363                 if (blob == NULL) {
1364                         reply = dbus_message_new_error(
1365                                 message, WPAS_ERROR_ADD_ERROR,
1366                                 "Not enough memory to add blob.");
1367                         break;
1368                 }
1369                 blob->data = os_zalloc(entry.array_len);
1370                 if (blob->data == NULL) {
1371                         reply = dbus_message_new_error(
1372                                 message, WPAS_ERROR_ADD_ERROR,
1373                                 "Not enough memory to add blob data.");
1374                         os_free(blob);
1375                         break;
1376                 }
1377
1378                 blob->name = os_strdup(entry.key);
1379                 blob->len = entry.array_len;
1380                 os_memcpy(blob->data, (u8 *) entry.bytearray_value,
1381                                 entry.array_len);
1382                 if (blob->name == NULL) {
1383                         wpa_config_free_blob(blob);
1384                         reply = dbus_message_new_error(
1385                                 message, WPAS_ERROR_ADD_ERROR,
1386                                 "Error adding blob.");
1387                         break;
1388                 }
1389
1390                 /* Success */
1391                 if (!wpa_config_remove_blob(wpa_s->conf, blob->name))
1392                         wpas_notify_blob_removed(wpa_s, blob->name);
1393                 wpa_config_set_blob(wpa_s->conf, blob);
1394                 wpas_notify_blob_added(wpa_s, blob->name);
1395
1396                 wpa_dbus_dict_entry_clear(&entry);
1397         }
1398         wpa_dbus_dict_entry_clear(&entry);
1399
1400         return reply ? reply : wpas_dbus_new_success_reply(message);
1401 }
1402
1403
1404 /**
1405  * wpas_dbus_iface_remove_blob - Remove named binary blobs
1406  * @message: Pointer to incoming dbus message
1407  * @wpa_s: %wpa_supplicant data structure
1408  * Returns: A dbus message containing a UINT32 indicating success (1) or
1409  *          failure (0)
1410  *
1411  * Asks wpa_supplicant to remove one or more previously stored binary blobs.
1412  */
1413 DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
1414                                            struct wpa_supplicant *wpa_s)
1415 {
1416         DBusMessageIter iter, array;
1417         char *err_msg = NULL;
1418
1419         dbus_message_iter_init(message, &iter);
1420
1421         if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
1422             (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
1423                 return wpas_dbus_new_invalid_opts_error(message, NULL);
1424
1425         dbus_message_iter_recurse(&iter, &array);
1426         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
1427                 const char *name;
1428
1429                 dbus_message_iter_get_basic(&array, &name);
1430                 if (!os_strlen(name))
1431                         err_msg = "Invalid blob name.";
1432                 else 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 }