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