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