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