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