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