3fbe5d3391c9826db271f5e9fe30790655d43996
[wpasupplicant] / 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 "driver_i.h"
21 #include "ctrl_iface_dbus.h"
22 #include "ctrl_iface_dbus_handlers.h"
23 #include "eap_peer/eap_methods.h"
24 #include "dbus_dict_helpers.h"
25 #include "ieee802_11_defs.h"
26 #include "wpas_glue.h"
27 #include "eapol_supp/eapol_supp_sm.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 (!(res->flags & WPA_SCAN_QUAL_INVALID) &&
489             !wpa_dbus_dict_append_int32(&iter_dict, "quality", res->qual))
490                 goto error;
491         if (!(res->flags & WPA_SCAN_NOISE_INVALID) &&
492             !wpa_dbus_dict_append_int32(&iter_dict, "noise", res->noise))
493                 goto error;
494         if (!(res->flags & WPA_SCAN_LEVEL_INVALID) &&
495             !wpa_dbus_dict_append_int32(&iter_dict, "level", res->level))
496                 goto error;
497         if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
498                                         wpa_scan_get_max_rate(res) * 500000))
499                 goto error;
500
501         if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
502                 goto error;
503
504         return reply;
505
506 error:
507         if (reply)
508                 dbus_message_unref(reply);
509         return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
510                                       "an internal error occurred returning "
511                                       "BSSID properties.");
512 }
513
514
515 /**
516  * wpas_dbus_iface_capabilities - Return interface capabilities
517  * @message: Pointer to incoming dbus message
518  * @wpa_s: wpa_supplicant structure for a network interface
519  * Returns: A dbus message containing a dict of strings
520  *
521  * Handler function for "capabilities" method call of an interface.
522  */
523 DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
524                                            struct wpa_supplicant *wpa_s)
525 {
526         DBusMessage *reply = NULL;
527         struct wpa_driver_capa capa;
528         int res;
529         DBusMessageIter iter, iter_dict;
530         char **eap_methods;
531         size_t num_items;
532         dbus_bool_t strict = FALSE;
533         DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
534
535         if (!dbus_message_get_args(message, NULL,
536                                    DBUS_TYPE_BOOLEAN, &strict,
537                                    DBUS_TYPE_INVALID))
538                 strict = FALSE;
539
540         reply = dbus_message_new_method_return(message);
541
542         dbus_message_iter_init_append(reply, &iter);
543         if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
544                 goto error;
545
546         /* EAP methods */
547         eap_methods = eap_get_names_as_string_array(&num_items);
548         if (eap_methods) {
549                 dbus_bool_t success = FALSE;
550                 size_t i = 0;
551
552                 success = wpa_dbus_dict_append_string_array(
553                         &iter_dict, "eap", (const char **) eap_methods,
554                         num_items);
555
556                 /* free returned method array */
557                 while (eap_methods[i])
558                         free(eap_methods[i++]);
559                 free(eap_methods);
560
561                 if (!success)
562                         goto error;
563         }
564
565         res = wpa_drv_get_capa(wpa_s, &capa);
566
567         /***** pairwise cipher */
568         if (res < 0) {
569                 if (!strict) {
570                         const char *args[] = {"CCMP", "TKIP", "NONE"};
571                         if (!wpa_dbus_dict_append_string_array(
572                                     &iter_dict, "pairwise", args,
573                                     sizeof(args) / sizeof(char*)))
574                                 goto error;
575                 }
576         } else {
577                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
578                                                       &iter_dict_entry,
579                                                       &iter_dict_val,
580                                                       &iter_array))
581                         goto error;
582
583                 if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
584                         if (!wpa_dbus_dict_string_array_add_element(
585                                     &iter_array, "CCMP"))
586                                 goto error;
587                 }
588
589                 if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
590                         if (!wpa_dbus_dict_string_array_add_element(
591                                     &iter_array, "TKIP"))
592                                 goto error;
593                 }
594
595                 if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
596                         if (!wpa_dbus_dict_string_array_add_element(
597                                     &iter_array, "NONE"))
598                                 goto error;
599                 }
600
601                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
602                                                     &iter_dict_entry,
603                                                     &iter_dict_val,
604                                                     &iter_array))
605                         goto error;
606         }
607
608         /***** group cipher */
609         if (res < 0) {
610                 if (!strict) {
611                         const char *args[] = {
612                                 "CCMP", "TKIP", "WEP104", "WEP40"
613                         };
614                         if (!wpa_dbus_dict_append_string_array(
615                                     &iter_dict, "group", args,
616                                     sizeof(args) / sizeof(char*)))
617                                 goto error;
618                 }
619         } else {
620                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group",
621                                                       &iter_dict_entry,
622                                                       &iter_dict_val,
623                                                       &iter_array))
624                         goto error;
625
626                 if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
627                         if (!wpa_dbus_dict_string_array_add_element(
628                                     &iter_array, "CCMP"))
629                                 goto error;
630                 }
631
632                 if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
633                         if (!wpa_dbus_dict_string_array_add_element(
634                                     &iter_array, "TKIP"))
635                                 goto error;
636                 }
637
638                 if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
639                         if (!wpa_dbus_dict_string_array_add_element(
640                                     &iter_array, "WEP104"))
641                                 goto error;
642                 }
643
644                 if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
645                         if (!wpa_dbus_dict_string_array_add_element(
646                                     &iter_array, "WEP40"))
647                                 goto error;
648                 }
649
650                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
651                                                     &iter_dict_entry,
652                                                     &iter_dict_val,
653                                                     &iter_array))
654                         goto error;
655         }
656
657         /***** key management */
658         if (res < 0) {
659                 if (!strict) {
660                         const char *args[] = {
661                                 "WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
662                                 "NONE"
663                         };
664                         if (!wpa_dbus_dict_append_string_array(
665                                     &iter_dict, "key_mgmt", args,
666                                     sizeof(args) / sizeof(char*)))
667                                 goto error;
668                 }
669         } else {
670                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
671                                                       &iter_dict_entry,
672                                                       &iter_dict_val,
673                                                       &iter_array))
674                         goto error;
675
676                 if (!wpa_dbus_dict_string_array_add_element(&iter_array,
677                                                             "NONE"))
678                         goto error;
679
680                 if (!wpa_dbus_dict_string_array_add_element(&iter_array,
681                                                             "IEEE8021X"))
682                         goto error;
683
684                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
685                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
686                         if (!wpa_dbus_dict_string_array_add_element(
687                                     &iter_array, "WPA-EAP"))
688                                 goto error;
689                 }
690
691                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
692                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
693                         if (!wpa_dbus_dict_string_array_add_element(
694                                     &iter_array, "WPA-PSK"))
695                                 goto error;
696                 }
697
698                 if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
699                         if (!wpa_dbus_dict_string_array_add_element(
700                                     &iter_array, "WPA-NONE"))
701                                 goto error;
702                 }
703
704                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
705                                                     &iter_dict_entry,
706                                                     &iter_dict_val,
707                                                     &iter_array))
708                         goto error;
709         }
710
711         /***** WPA protocol */
712         if (res < 0) {
713                 if (!strict) {
714                         const char *args[] = { "RSN", "WPA" };
715                         if (!wpa_dbus_dict_append_string_array(
716                                     &iter_dict, "proto", args,
717                                     sizeof(args) / sizeof(char*)))
718                                 goto error;
719                 }
720         } else {
721                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
722                                                       &iter_dict_entry,
723                                                       &iter_dict_val,
724                                                       &iter_array))
725                         goto error;
726
727                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
728                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
729                         if (!wpa_dbus_dict_string_array_add_element(
730                                     &iter_array, "RSN"))
731                                 goto error;
732                 }
733
734                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
735                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
736                         if (!wpa_dbus_dict_string_array_add_element(
737                                     &iter_array, "WPA"))
738                                 goto error;
739                 }
740
741                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
742                                                     &iter_dict_entry,
743                                                     &iter_dict_val,
744                                                     &iter_array))
745                         goto error;
746         }
747
748         /***** auth alg */
749         if (res < 0) {
750                 if (!strict) {
751                         const char *args[] = { "OPEN", "SHARED", "LEAP" };
752                         if (!wpa_dbus_dict_append_string_array(
753                                     &iter_dict, "auth_alg", args,
754                                     sizeof(args) / sizeof(char*)))
755                                 goto error;
756                 }
757         } else {
758                 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
759                                                       &iter_dict_entry,
760                                                       &iter_dict_val,
761                                                       &iter_array))
762                         goto error;
763
764                 if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
765                         if (!wpa_dbus_dict_string_array_add_element(
766                                     &iter_array, "OPEN"))
767                                 goto error;
768                 }
769
770                 if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
771                         if (!wpa_dbus_dict_string_array_add_element(
772                                     &iter_array, "SHARED"))
773                                 goto error;
774                 }
775
776                 if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
777                         if (!wpa_dbus_dict_string_array_add_element(
778                                     &iter_array, "LEAP"))
779                                 goto error;
780                 }
781
782                 if (!wpa_dbus_dict_end_string_array(&iter_dict,
783                                                     &iter_dict_entry,
784                                                     &iter_dict_val,
785                                                     &iter_array))
786                         goto error;
787         }
788
789         if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
790                 goto error;
791
792         return reply;
793
794 error:
795         if (reply)
796                 dbus_message_unref(reply);
797         return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
798                                       "an internal error occurred returning "
799                                       "interface capabilities.");
800 }
801
802
803 /**
804  * wpas_dbus_iface_add_network - Add a new configured network
805  * @message: Pointer to incoming dbus message
806  * @wpa_s: wpa_supplicant structure for a network interface
807  * Returns: A dbus message containing the object path of the new network
808  *
809  * Handler function for "addNetwork" method call of a network interface.
810  */
811 DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
812                                           struct wpa_supplicant *wpa_s)
813 {
814         DBusMessage *reply = NULL;
815         struct wpa_ssid *ssid;
816         char *path = NULL;
817
818         path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
819         if (path == NULL) {
820                 perror("wpas_dbus_iface_scan_results[dbus]: out of "
821                        "memory.");
822                 wpa_printf(MSG_ERROR, "dbus control interface: not "
823                            "enough memory to send scan results "
824                            "signal.");
825                 goto out;
826         }
827
828         ssid = wpa_config_add_network(wpa_s->conf);
829         if (ssid == NULL) {
830                 reply = dbus_message_new_error(message,
831                                                WPAS_ERROR_ADD_NETWORK_ERROR,
832                                                "wpa_supplicant could not add "
833                                                "a network on this interface.");
834                 goto out;
835         }
836         ssid->disabled = 1;
837         wpa_config_set_network_defaults(ssid);
838
839         /* Construct the object path for this network. */
840         snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
841                  "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
842                  wpa_supplicant_get_dbus_path(wpa_s),
843                  ssid->id);
844
845         reply = dbus_message_new_method_return(message);
846         dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
847                                  &path, DBUS_TYPE_INVALID);
848
849 out:
850         free(path);
851         return reply;
852 }
853
854
855 /**
856  * wpas_dbus_iface_remove_network - Remove a configured network
857  * @message: Pointer to incoming dbus message
858  * @wpa_s: wpa_supplicant structure for a network interface
859  * Returns: A dbus message containing a UINT32 indicating success (1) or
860  *          failure (0)
861  *
862  * Handler function for "removeNetwork" method call of a network interface.
863  */
864 DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
865                                              struct wpa_supplicant *wpa_s)
866 {
867         DBusMessage *reply = NULL;
868         const char *op;
869         char *iface = NULL, *net_id = NULL;
870         int id;
871         struct wpa_ssid *ssid;
872
873         if (!dbus_message_get_args(message, NULL,
874                                    DBUS_TYPE_OBJECT_PATH, &op,
875                                    DBUS_TYPE_INVALID)) {
876                 reply = wpas_dbus_new_invalid_opts_error(message, NULL);
877                 goto out;
878         }
879
880         /* Extract the network ID */
881         iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
882         if (iface == NULL) {
883                 reply = wpas_dbus_new_invalid_network_error(message);
884                 goto out;
885         }
886         /* Ensure the network is actually a child of this interface */
887         if (strcmp(iface, wpa_supplicant_get_dbus_path(wpa_s)) != 0) {
888                 reply = wpas_dbus_new_invalid_network_error(message);
889                 goto out;
890         }
891
892         id = strtoul(net_id, NULL, 10);
893         ssid = wpa_config_get_network(wpa_s->conf, id);
894         if (ssid == NULL) {
895                 reply = wpas_dbus_new_invalid_network_error(message);
896                 goto out;
897         }
898
899         if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
900                 reply = dbus_message_new_error(message,
901                                                WPAS_ERROR_REMOVE_NETWORK_ERROR,
902                                                "error removing the specified "
903                                                "on this interface.");
904                 goto out;
905         }
906
907         if (ssid == wpa_s->current_ssid)
908                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
909         reply = wpas_dbus_new_success_reply(message);
910
911 out:
912         free(iface);
913         free(net_id);
914         return reply;
915 }
916
917
918 static const char *dont_quote[] = {
919         "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
920         "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
921         "bssid", NULL
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  * wpas_dbus_iface_set_network - Set options for a configured network
937  * @message: Pointer to incoming dbus message
938  * @wpa_s: wpa_supplicant structure for a network interface
939  * @ssid: wpa_ssid structure for a configured network
940  * Returns: a dbus message containing a UINT32 indicating success (1) or
941  *          failure (0)
942  *
943  * Handler function for "set" method call of a configured network.
944  */
945 DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
946                                           struct wpa_supplicant *wpa_s,
947                                           struct wpa_ssid *ssid)
948 {
949         DBusMessage *reply = NULL;
950         struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
951         DBusMessageIter iter, iter_dict;
952
953         dbus_message_iter_init(message, &iter);
954
955         if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) {
956                 reply = wpas_dbus_new_invalid_opts_error(message, NULL);
957                 goto out;
958         }
959
960         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
961                 char *value = NULL;
962                 size_t size = 50;
963                 int ret;
964
965                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
966                         reply = wpas_dbus_new_invalid_opts_error(message,
967                                                                  NULL);
968                         goto out;
969                 }
970
971                 /* Type conversions, since wpa_supplicant wants strings */
972                 if (entry.type == DBUS_TYPE_ARRAY &&
973                     entry.array_type == DBUS_TYPE_BYTE) {
974                         if (entry.array_len <= 0)
975                                 goto error;
976
977                         size = entry.array_len * 2 + 1;
978                         value = os_zalloc(size);
979                         if (value == NULL)
980                                 goto error;
981                         ret = wpa_snprintf_hex(value, size,
982                                         (u8 *) entry.bytearray_value,
983                                         entry.array_len);
984                         if (ret <= 0)
985                                 goto error;
986                 } else if (entry.type == DBUS_TYPE_STRING) {
987                         if (should_quote_opt(entry.key)) {
988                                 size = strlen(entry.str_value);
989                                 /* Zero-length option check */
990                                 if (size <= 0)
991                                         goto error;
992                                 size += 3;  /* For quotes and terminator */
993                                 value = os_zalloc(size);
994                                 if (value == NULL)
995                                         goto error;
996                                 ret = snprintf(value, size, "\"%s\"",
997                                                 entry.str_value);
998                                 if (ret < 0 || (size_t) ret != (size - 1))
999                                         goto error;
1000                         } else {
1001                                 value = strdup(entry.str_value);
1002                                 if (value == NULL)
1003                                         goto error;
1004                         }
1005                 } else if (entry.type == DBUS_TYPE_UINT32) {
1006                         value = os_zalloc(size);
1007                         if (value == NULL)
1008                                 goto error;
1009                         ret = snprintf(value, size, "%u", entry.uint32_value);
1010                         if (ret <= 0)
1011                                 goto error;
1012                 } else if (entry.type == DBUS_TYPE_INT32) {
1013                         value = os_zalloc(size);
1014                         if (value == NULL)
1015                                 goto error;
1016                         ret = snprintf(value, size, "%d", entry.int32_value);
1017                         if (ret <= 0)
1018                                 goto error;
1019                 } else
1020                         goto error;
1021
1022                 if (wpa_config_set(ssid, entry.key, value, 0) < 0)
1023                         goto error;
1024
1025                 if ((strcmp(entry.key, "psk") == 0 &&
1026                      value[0] == '"' && ssid->ssid_len) ||
1027                     (strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
1028                         wpa_config_update_psk(ssid);
1029
1030                 free(value);
1031                 wpa_dbus_dict_entry_clear(&entry);
1032                 continue;
1033
1034         error:
1035                 free(value);
1036                 reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
1037                 wpa_dbus_dict_entry_clear(&entry);
1038                 break;
1039         }
1040
1041         if (!reply)
1042                 reply = wpas_dbus_new_success_reply(message);
1043
1044 out:
1045         return reply;
1046 }
1047
1048
1049 /**
1050  * wpas_dbus_iface_enable_network - Mark a configured network as enabled
1051  * @message: Pointer to incoming dbus message
1052  * @wpa_s: wpa_supplicant structure for a network interface
1053  * @ssid: wpa_ssid structure for a configured network
1054  * Returns: A dbus message containing a UINT32 indicating success (1) or
1055  *          failure (0)
1056  *
1057  * Handler function for "enable" method call of a configured network.
1058  */
1059 DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
1060                                              struct wpa_supplicant *wpa_s,
1061                                              struct wpa_ssid *ssid)
1062 {
1063         if (wpa_s->current_ssid == NULL && ssid->disabled) {
1064                 /*
1065                  * Try to reassociate since there is no current configuration
1066                  * and a new network was made available.
1067                  */
1068                 wpa_s->reassociate = 1;
1069                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1070         }
1071         ssid->disabled = 0;
1072
1073         return wpas_dbus_new_success_reply(message);
1074 }
1075
1076
1077 /**
1078  * wpas_dbus_iface_disable_network - Mark a configured network as disabled
1079  * @message: Pointer to incoming dbus message
1080  * @wpa_s: wpa_supplicant structure for a network interface
1081  * @ssid: wpa_ssid structure for a configured network
1082  * Returns: A dbus message containing a UINT32 indicating success (1) or
1083  *          failure (0)
1084  *
1085  * Handler function for "disable" method call of a configured network.
1086  */
1087 DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
1088                                               struct wpa_supplicant *wpa_s,
1089                                               struct wpa_ssid *ssid)
1090 {
1091         if (ssid == wpa_s->current_ssid)
1092                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1093         ssid->disabled = 1;
1094
1095         return wpas_dbus_new_success_reply(message);
1096 }
1097
1098
1099 /**
1100  * wpas_dbus_iface_select_network - Attempt association with a configured network
1101  * @message: Pointer to incoming dbus message
1102  * @wpa_s: wpa_supplicant structure for a network interface
1103  * Returns: A dbus message containing a UINT32 indicating success (1) or
1104  *          failure (0)
1105  *
1106  * Handler function for "selectNetwork" method call of network interface.
1107  */
1108 DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
1109                                              struct wpa_supplicant *wpa_s)
1110 {
1111         DBusMessage *reply = NULL;
1112         const char *op;
1113         struct wpa_ssid *ssid;
1114         char *iface_obj_path = NULL;
1115         char *network = NULL;
1116
1117         if (strlen(dbus_message_get_signature(message)) == 0) {
1118                 /* Any network */
1119                 ssid = wpa_s->conf->ssid;
1120                 while (ssid) {
1121                         ssid->disabled = 0;
1122                         ssid = ssid->next;
1123                 }
1124                 wpa_s->reassociate = 1;
1125                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1126         } else {
1127                 const char *obj_path;
1128                 int nid;
1129
1130                 if (!dbus_message_get_args(message, NULL,
1131                                            DBUS_TYPE_OBJECT_PATH, &op,
1132                                            DBUS_TYPE_INVALID)) {
1133                         reply = wpas_dbus_new_invalid_opts_error(message,
1134                                                                  NULL);
1135                         goto out;
1136                 }
1137
1138                 /* Extract the network number */
1139                 iface_obj_path = wpas_dbus_decompose_object_path(op,
1140                                                                  &network,
1141                                                                  NULL);
1142                 if (iface_obj_path == NULL) {
1143                         reply = wpas_dbus_new_invalid_iface_error(message);
1144                         goto out;
1145                 }
1146                 /* Ensure the object path really points to this interface */
1147                 obj_path = wpa_supplicant_get_dbus_path(wpa_s);
1148                 if (strcmp(iface_obj_path, obj_path) != 0) {
1149                         reply = wpas_dbus_new_invalid_network_error(message);
1150                         goto out;
1151                 }
1152
1153                 nid = strtoul(network, NULL, 10);
1154                 if (errno == EINVAL) {
1155                         reply = wpas_dbus_new_invalid_network_error(message);
1156                         goto out;
1157                 }
1158
1159                 ssid = wpa_config_get_network(wpa_s->conf, nid);
1160                 if (ssid == NULL) {
1161                         reply = wpas_dbus_new_invalid_network_error(message);
1162                         goto out;
1163                 }
1164
1165                 /* Finally, associate with the network */
1166                 if (ssid != wpa_s->current_ssid && wpa_s->current_ssid)
1167                         wpa_supplicant_disassociate(
1168                                 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1169
1170                 /* Mark all other networks disabled and trigger reassociation
1171                  */
1172                 ssid = wpa_s->conf->ssid;
1173                 while (ssid) {
1174                         ssid->disabled = (nid != ssid->id);
1175                         ssid = ssid->next;
1176                 }
1177                 wpa_s->disconnected = 0;
1178                 wpa_s->reassociate = 1;
1179                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1180         }
1181
1182         reply = wpas_dbus_new_success_reply(message);
1183
1184 out:
1185         free(iface_obj_path);
1186         free(network);
1187         return reply;
1188 }
1189
1190
1191 /**
1192  * wpas_dbus_iface_disconnect - Terminate the current connection
1193  * @message: Pointer to incoming dbus message
1194  * @wpa_s: wpa_supplicant structure for a network interface
1195  * Returns: A dbus message containing a UINT32 indicating success (1) or
1196  *          failure (0)
1197  *
1198  * Handler function for "disconnect" method call of network interface.
1199  */
1200 DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
1201                                          struct wpa_supplicant *wpa_s)
1202 {
1203         wpa_s->disconnected = 1;
1204         wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1205
1206         return wpas_dbus_new_success_reply(message);
1207 }
1208
1209
1210 /**
1211  * wpas_dbus_iface_set_ap_scan - Control roaming mode
1212  * @message: Pointer to incoming dbus message
1213  * @wpa_s: wpa_supplicant structure for a network interface
1214  * Returns: A dbus message containing a UINT32 indicating success (1) or
1215  *          failure (0)
1216  *
1217  * Handler function for "setAPScan" method call.
1218  */
1219 DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
1220                                           struct wpa_supplicant *wpa_s)
1221 {
1222         DBusMessage *reply = NULL;
1223         dbus_uint32_t ap_scan = 1;
1224
1225         if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
1226                                    DBUS_TYPE_INVALID)) {
1227                 reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1228                 goto out;
1229         }
1230
1231         if (ap_scan > 2) {
1232                 reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1233                 goto out;
1234         }
1235         wpa_s->conf->ap_scan = ap_scan;
1236         reply = wpas_dbus_new_success_reply(message);
1237
1238 out:
1239         return reply;
1240 }
1241
1242
1243 /**
1244  * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
1245  * @message: Pointer to incoming dbus message
1246  * @wpa_s: wpa_supplicant structure for a network interface
1247  * Returns: A dbus message containing a UINT32 indicating success (1) or
1248  *          failure (0)
1249  *
1250  * Handler function for "setSmartcardModules" method call.
1251  */
1252 DBusMessage * wpas_dbus_iface_set_smartcard_modules(
1253         DBusMessage *message, struct wpa_supplicant *wpa_s)
1254 {
1255         DBusMessageIter iter, iter_dict;
1256         char *opensc_engine_path = NULL;
1257         char *pkcs11_engine_path = NULL;
1258         char *pkcs11_module_path = NULL;
1259         struct wpa_dbus_dict_entry entry;
1260
1261         if (!dbus_message_iter_init(message, &iter))
1262                 goto error;
1263
1264         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1265                 goto error;
1266
1267         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1268                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1269                         goto error;
1270                 if (!strcmp(entry.key, "opensc_engine_path") &&
1271                     (entry.type == DBUS_TYPE_STRING)) {
1272                         opensc_engine_path = os_strdup(entry.str_value);
1273                         if (opensc_engine_path == NULL)
1274                                 goto error;
1275                 } else if (!strcmp(entry.key, "pkcs11_engine_path") &&
1276                            (entry.type == DBUS_TYPE_STRING)) {
1277                         pkcs11_engine_path = os_strdup(entry.str_value);
1278                         if (pkcs11_engine_path == NULL)
1279                                 goto error;
1280                 } else if (!strcmp(entry.key, "pkcs11_module_path") &&
1281                                  (entry.type == DBUS_TYPE_STRING)) {
1282                         pkcs11_module_path = os_strdup(entry.str_value);
1283                         if (pkcs11_module_path == NULL)
1284                                 goto error;
1285                 } else {
1286                         wpa_dbus_dict_entry_clear(&entry);
1287                         goto error;
1288                 }
1289                 wpa_dbus_dict_entry_clear(&entry);
1290         }
1291
1292 #ifdef EAP_TLS_OPENSSL
1293         os_free(wpa_s->conf->opensc_engine_path);
1294         wpa_s->conf->opensc_engine_path = opensc_engine_path;
1295         os_free(wpa_s->conf->pkcs11_engine_path);
1296         wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
1297         os_free(wpa_s->conf->pkcs11_module_path);
1298         wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
1299 #endif /* EAP_TLS_OPENSSL */
1300
1301         eapol_sm_deinit(wpa_s->eapol);
1302         wpa_supplicant_init_eapol(wpa_s);
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_set_blobs - Store named binary blobs (ie, for certificates)
1341  * @message: Pointer to incoming dbus message
1342  * @wpa_s: %wpa_supplicant data structure
1343  * Returns: A dbus message containing a UINT32 indicating success (1) or
1344  *          failure (0)
1345  *
1346  * Asks wpa_supplicant to internally store a one or more binary blobs.
1347  */
1348 DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
1349                                         struct wpa_supplicant *wpa_s)
1350 {
1351         DBusMessage *reply = NULL;
1352         struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1353         DBusMessageIter iter, iter_dict;
1354
1355         dbus_message_iter_init(message, &iter);
1356
1357         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1358                 return wpas_dbus_new_invalid_opts_error(message, NULL);
1359
1360         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1361                 struct wpa_config_blob *blob;
1362
1363                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1364                         reply = wpas_dbus_new_invalid_opts_error(message,
1365                                                                  NULL);
1366                         break;
1367                 }
1368
1369                 if (entry.type != DBUS_TYPE_ARRAY ||
1370                     entry.array_type != DBUS_TYPE_BYTE) {
1371                         reply = wpas_dbus_new_invalid_opts_error(
1372                                 message, "Byte array expected.");
1373                         break;
1374                 }
1375
1376                 if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
1377                     !strlen(entry.key)) {
1378                         reply = wpas_dbus_new_invalid_opts_error(
1379                                 message, "Invalid array size.");
1380                         break;
1381                 }
1382
1383                 blob = os_zalloc(sizeof(*blob));
1384                 if (blob == NULL) {
1385                         reply = dbus_message_new_error(
1386                                 message, WPAS_ERROR_ADD_ERROR,
1387                                 "Not enough memory to add blob.");
1388                         break;
1389                 }
1390                 blob->data = os_zalloc(entry.array_len);
1391                 if (blob->data == NULL) {
1392                         reply = dbus_message_new_error(
1393                                 message, WPAS_ERROR_ADD_ERROR,
1394                                 "Not enough memory to add blob data.");
1395                         os_free(blob);
1396                         break;
1397                 }
1398
1399                 blob->name = os_strdup(entry.key);
1400                 blob->len = entry.array_len;
1401                 os_memcpy(blob->data, (u8 *) entry.bytearray_value,
1402                                 entry.array_len);
1403                 if (blob->name == NULL || blob->data == NULL) {
1404                         wpa_config_free_blob(blob);
1405                         reply = dbus_message_new_error(
1406                                 message, WPAS_ERROR_ADD_ERROR,
1407                                 "Error adding blob.");
1408                         break;
1409                 }
1410
1411                 /* Success */
1412                 wpa_config_remove_blob(wpa_s->conf, blob->name);
1413                 wpa_config_set_blob(wpa_s->conf, blob);
1414                 wpa_dbus_dict_entry_clear(&entry);
1415         }
1416         wpa_dbus_dict_entry_clear(&entry);
1417
1418         return reply ? reply : wpas_dbus_new_success_reply(message);
1419 }
1420
1421
1422 /**
1423  * wpas_dbus_iface_remove_blob - Remove named binary blobs
1424  * @message: Pointer to incoming dbus message
1425  * @wpa_s: %wpa_supplicant data structure
1426  * Returns: A dbus message containing a UINT32 indicating success (1) or
1427  *          failure (0)
1428  *
1429  * Asks wpa_supplicant to remove one or more previously stored binary blobs.
1430  */
1431 DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
1432                                           struct wpa_supplicant *wpa_s)
1433 {
1434         DBusMessageIter iter, array;
1435         char *err_msg = NULL;
1436
1437         dbus_message_iter_init(message, &iter);
1438
1439         if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
1440             (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
1441                 return wpas_dbus_new_invalid_opts_error(message, NULL);
1442
1443         dbus_message_iter_recurse(&iter, &array);
1444         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
1445                 const char *name;
1446
1447                 dbus_message_iter_get_basic(&array, &name);
1448                 if (!strlen(name))
1449                         err_msg = "Invalid blob name.";
1450
1451                 if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
1452                         err_msg = "Error removing blob.";
1453                 dbus_message_iter_next(&array);
1454         }
1455
1456         if (err_msg) {
1457                 return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
1458                                               err_msg);
1459         }
1460
1461         return wpas_dbus_new_success_reply(message);
1462 }