Add setSmartcardModules DBus message to set pkcs11 and opensc options
[wpasupplicant] / wpa_supplicant / ctrl_iface_dbus.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 "eloop.h"
19 #include "config.h"
20 #include "wpa_supplicant_i.h"
21 #include "ctrl_iface_dbus.h"
22 #include "ctrl_iface_dbus_handlers.h"
23
24 #define _DBUS_VERSION (DBUS_VERSION_MAJOR << 8 | DBUS_VERSION_MINOR)
25 #define DBUS_VER(major, minor) ((major) << 8 | (minor))
26
27 #if _DBUS_VERSION < DBUS_VER(1,1)
28 #define dbus_watch_get_unix_fd dbus_watch_get_fd
29 #endif
30
31
32 struct ctrl_iface_dbus_priv {
33         DBusConnection *con;
34         int should_dispatch;
35         struct wpa_global *global;
36
37         u32 next_objid;
38 };
39
40
41 static void process_watch(struct ctrl_iface_dbus_priv *iface,
42                           DBusWatch *watch, eloop_event_type type)
43 {
44         dbus_connection_ref(iface->con);
45
46         iface->should_dispatch = 0;
47
48         if (type == EVENT_TYPE_READ)
49                 dbus_watch_handle(watch, DBUS_WATCH_READABLE);
50         else if (type == EVENT_TYPE_WRITE)
51                 dbus_watch_handle(watch, DBUS_WATCH_WRITABLE);
52         else if (type == EVENT_TYPE_EXCEPTION)
53                 dbus_watch_handle(watch, DBUS_WATCH_ERROR);
54
55         if (iface->should_dispatch) {
56                 while (dbus_connection_get_dispatch_status(iface->con) ==
57                        DBUS_DISPATCH_DATA_REMAINS)
58                         dbus_connection_dispatch(iface->con);
59                 iface->should_dispatch = 0;
60         }
61
62         dbus_connection_unref(iface->con);
63 }
64
65
66 static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx)
67 {
68         process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION);
69 }
70
71
72 static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx)
73 {
74         process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ);
75 }
76
77
78 static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx)
79 {
80         process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE);
81 }
82
83
84 static void connection_setup_add_watch(struct ctrl_iface_dbus_priv *iface,
85                                        DBusWatch *watch)
86 {
87         unsigned int flags;
88         int fd;
89
90         if (!dbus_watch_get_enabled(watch))
91                 return;
92
93         flags = dbus_watch_get_flags(watch);
94         fd = dbus_watch_get_unix_fd(watch);
95
96         eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception,
97                             iface, watch);
98
99         if (flags & DBUS_WATCH_READABLE) {
100                 eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
101                                     iface, watch);
102         }
103         if (flags & DBUS_WATCH_WRITABLE) {
104                 eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
105                                     iface, watch);
106         }
107
108         dbus_watch_set_data(watch, iface, NULL);
109 }
110
111
112 static void connection_setup_remove_watch(struct ctrl_iface_dbus_priv *iface,
113                                           DBusWatch *watch)
114 {
115         unsigned int flags;
116         int fd;
117
118         flags = dbus_watch_get_flags(watch);
119         fd = dbus_watch_get_unix_fd(watch);
120
121         eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION);
122
123         if (flags & DBUS_WATCH_READABLE)
124                 eloop_unregister_sock(fd, EVENT_TYPE_READ);
125         if (flags & DBUS_WATCH_WRITABLE)
126                 eloop_unregister_sock(fd, EVENT_TYPE_WRITE);
127
128         dbus_watch_set_data(watch, NULL, NULL);
129 }
130
131
132 static dbus_bool_t add_watch(DBusWatch *watch, void *data)
133 {
134         connection_setup_add_watch(data, watch);
135         return TRUE;
136 }
137
138
139 static void remove_watch(DBusWatch *watch, void *data)
140 {
141         connection_setup_remove_watch(data, watch);
142 }
143
144
145 static void watch_toggled(DBusWatch *watch, void *data)
146 {
147         if (dbus_watch_get_enabled(watch))
148                 add_watch(watch, data);
149         else
150                 remove_watch(watch, data);
151 }
152
153
154 static void process_timeout(void *eloop_ctx, void *sock_ctx)
155 {
156         DBusTimeout *timeout = sock_ctx;
157
158         dbus_timeout_handle(timeout);
159 }
160
161
162 static void connection_setup_add_timeout(struct ctrl_iface_dbus_priv *iface,
163                                          DBusTimeout *timeout)
164 {
165         if (!dbus_timeout_get_enabled(timeout))
166                 return;
167
168         eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000,
169                                process_timeout, iface, timeout);
170
171         dbus_timeout_set_data(timeout, iface, NULL);
172 }
173
174
175 static void connection_setup_remove_timeout(struct ctrl_iface_dbus_priv *iface,
176                                             DBusTimeout *timeout)
177 {
178         eloop_cancel_timeout(process_timeout, iface, timeout);
179         dbus_timeout_set_data(timeout, NULL, NULL);
180 }
181
182
183 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
184 {
185         if (!dbus_timeout_get_enabled(timeout))
186                 return TRUE;
187
188         connection_setup_add_timeout(data, timeout);
189
190         return TRUE;
191 }
192
193
194 static void remove_timeout(DBusTimeout *timeout, void *data)
195 {
196         connection_setup_remove_timeout(data, timeout);
197 }
198
199
200 static void timeout_toggled(DBusTimeout *timeout, void *data)
201 {
202         if (dbus_timeout_get_enabled(timeout))
203                 add_timeout(timeout, data);
204         else
205                 remove_timeout(timeout, data);
206 }
207
208
209 static void process_wakeup_main(int sig, void *eloop_ctx, void *signal_ctx)
210 {
211         struct ctrl_iface_dbus_priv *iface = signal_ctx;
212
213         if (sig != SIGPOLL || !iface->con)
214                 return;
215
216         if (dbus_connection_get_dispatch_status(iface->con) !=
217             DBUS_DISPATCH_DATA_REMAINS)
218                 return;
219
220         /* Only dispatch once - we do not want to starve other events */
221         dbus_connection_ref(iface->con);
222         dbus_connection_dispatch(iface->con);
223         dbus_connection_unref(iface->con);
224 }
225
226
227 /**
228  * wakeup_main - Attempt to wake our mainloop up
229  * @data: dbus control interface private data
230  *
231  * Try to wake up the main eloop so it will process
232  * dbus events that may have happened.
233  */
234 static void wakeup_main(void *data)
235 {
236         struct ctrl_iface_dbus_priv *iface = data;
237
238         /* Use SIGPOLL to break out of the eloop select() */
239         raise(SIGPOLL);
240         iface->should_dispatch = 1;
241 }
242
243
244 /**
245  * connection_setup_wakeup_main - Tell dbus about our wakeup_main function
246  * @iface: dbus control interface private data
247  * Returns: 0 on success, -1 on failure
248  *
249  * Register our wakeup_main handler with dbus
250  */
251 static int connection_setup_wakeup_main(struct ctrl_iface_dbus_priv *iface)
252 {
253         if (eloop_register_signal(SIGPOLL, process_wakeup_main, iface))
254                 return -1;
255
256         dbus_connection_set_wakeup_main_function(iface->con, wakeup_main,
257                                                  iface, NULL);
258
259         return 0;
260 }
261
262
263 /**
264  * wpa_supplicant_dbus_next_objid - Return next available object id
265  * @iface: dbus control interface private data
266  * Returns: Object id
267  */
268 u32 wpa_supplicant_dbus_next_objid (struct ctrl_iface_dbus_priv *iface)
269 {
270         return iface->next_objid++;
271 }
272
273
274 /**
275  * wpas_dbus_decompose_object_path - Decompose an interface object path into parts
276  * @path: The dbus object path
277  * @network: (out) the configured network this object path refers to, if any
278  * @bssid: (out) the scanned bssid this object path refers to, if any
279  * Returns: The object path of the network interface this path refers to
280  *
281  * For a given object path, decomposes the object path into object id, network,
282  * and BSSID parts, if those parts exist.
283  */
284 char * wpas_dbus_decompose_object_path(const char *path, char **network,
285                                        char **bssid)
286 {
287         const unsigned int dev_path_prefix_len =
288                 strlen(WPAS_DBUS_PATH_INTERFACES "/");
289         char *obj_path_only;
290         char *next_sep;
291
292         /* Be a bit paranoid about path */
293         if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/",
294                              dev_path_prefix_len))
295                 return NULL;
296
297         /* Ensure there's something at the end of the path */
298         if ((path + dev_path_prefix_len)[0] == '\0')
299                 return NULL;
300
301         obj_path_only = strdup(path);
302         if (obj_path_only == NULL)
303                 return NULL;
304
305         next_sep = strchr(obj_path_only + dev_path_prefix_len, '/');
306         if (next_sep != NULL) {
307                 const char *net_part = strstr(next_sep,
308                                               WPAS_DBUS_NETWORKS_PART "/");
309                 const char *bssid_part = strstr(next_sep,
310                                                 WPAS_DBUS_BSSIDS_PART "/");
311
312                 if (network && net_part) {
313                         /* Deal with a request for a configured network */
314                         const char *net_name = net_part +
315                                 strlen(WPAS_DBUS_NETWORKS_PART "/");
316                         *network = NULL;
317                         if (strlen(net_name))
318                                 *network = strdup(net_name);
319                 } else if (bssid && bssid_part) {
320                         /* Deal with a request for a scanned BSSID */
321                         const char *bssid_name = bssid_part +
322                                 strlen(WPAS_DBUS_BSSIDS_PART "/");
323                         if (strlen(bssid_name))
324                                 *bssid = strdup(bssid_name);
325                         else
326                                 *bssid = NULL;
327                 }
328
329                 /* Cut off interface object path before "/" */
330                 *next_sep = '\0';
331         }
332
333         return obj_path_only;
334 }
335
336
337 /**
338  * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message
339  * @message: Pointer to incoming dbus message this error refers to
340  * Returns: A dbus error message
341  *
342  * Convenience function to create and return an invalid interface error
343  */
344 DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
345 {
346         return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE,
347                                       "wpa_supplicant knows nothing about "
348                                       "this interface.");
349 }
350
351
352 /**
353  * wpas_dbus_new_invalid_network_error - Return a new invalid network error message
354  * @message: Pointer to incoming dbus message this error refers to
355  * Returns: a dbus error message
356  *
357  * Convenience function to create and return an invalid network error
358  */
359 DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message)
360 {
361         return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK,
362                                       "The requested network does not exist.");
363 }
364
365
366 /**
367  * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message
368  * @message: Pointer to incoming dbus message this error refers to
369  * Returns: a dbus error message
370  *
371  * Convenience function to create and return an invalid bssid error
372  */
373 static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message)
374 {
375         return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID,
376                                       "The BSSID requested was invalid.");
377 }
378
379
380 /**
381  * wpas_dispatch_network_method - dispatch messages for configured networks
382  * @message: the incoming dbus message
383  * @wpa_s: a network interface's data
384  * @network_id: id of the configured network we're interested in
385  * Returns: a reply dbus message, or a dbus error message
386  *
387  * This function dispatches all incoming dbus messages for configured networks.
388  */
389 static DBusMessage * wpas_dispatch_network_method(DBusMessage *message,
390                                                   struct wpa_supplicant *wpa_s,
391                                                   int network_id)
392 {
393         DBusMessage *reply = NULL;
394         const char *method = dbus_message_get_member(message);
395         struct wpa_ssid *ssid;
396
397         ssid = wpa_config_get_network(wpa_s->conf, network_id);
398         if (ssid == NULL)
399                 return wpas_dbus_new_invalid_network_error(message);
400
401         if (!strcmp(method, "set"))
402                 reply = wpas_dbus_iface_set_network(message, wpa_s, ssid);
403         else if (!strcmp(method, "enable"))
404                 reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid);
405         else if (!strcmp(method, "disable"))
406                 reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid);
407
408         return reply;
409 }
410
411
412 /**
413  * wpas_dispatch_bssid_method - dispatch messages for scanned networks
414  * @message: the incoming dbus message
415  * @wpa_s: a network interface's data
416  * @bssid: bssid of the scanned network we're interested in
417  * Returns: a reply dbus message, or a dbus error message
418  *
419  * This function dispatches all incoming dbus messages for scanned networks.
420  */
421 static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message,
422                                                 struct wpa_supplicant *wpa_s,
423                                                 const char *bssid)
424 {
425         DBusMessage *reply = NULL;
426         const char *method = dbus_message_get_member(message);
427         struct wpa_scan_res *res = NULL;
428         size_t i;
429
430         /* Ensure we actually have scan data */
431         if (wpa_s->scan_res == NULL &&
432             wpa_supplicant_get_scan_results(wpa_s) < 0) {
433                 reply = wpas_dbus_new_invalid_bssid_error(message);
434                 goto out;
435         }
436
437         /* Find the bssid's scan data */
438         for (i = 0; i < wpa_s->scan_res->num; i++) {
439                 struct wpa_scan_res *search_res = wpa_s->scan_res->res[i];
440                 char mac_str[18];
441
442                 memset(mac_str, 0, sizeof(mac_str));
443                 snprintf(mac_str, sizeof(mac_str) - 1, WPAS_DBUS_BSSID_FORMAT,
444                          MAC2STR(search_res->bssid));
445                 if (!strcmp(bssid, mac_str)) {
446                         res = search_res;
447                         break;
448                 }
449         }
450
451         if (!res) {
452                 reply = wpas_dbus_new_invalid_bssid_error(message);
453                 goto out;
454         }
455
456         /* Dispatch the method call against the scanned bssid */
457         if (!strcmp(method, "properties"))
458                 reply = wpas_dbus_bssid_properties(message, wpa_s, res);
459
460 out:
461         return reply;
462 }
463
464
465 /**
466  * wpas_iface_message_handler - Dispatch messages for interfaces or networks
467  * @connection: Connection to the system message bus
468  * @message: An incoming dbus message
469  * @user_data: A pointer to a dbus control interface data structure
470  * Returns: Whether or not the message was handled
471  *
472  * This function dispatches all incoming dbus messages for network interfaces,
473  * or objects owned by them, such as scanned BSSIDs and configured networks.
474  */
475 static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
476                                                     DBusMessage *message,
477                                                     void *user_data)
478 {
479         struct wpa_supplicant *wpa_s = user_data;
480         const char *method = dbus_message_get_member(message);
481         const char *path = dbus_message_get_path(message);
482         const char *msg_interface = dbus_message_get_interface(message);
483         char *iface_obj_path = NULL;
484         char *network = NULL;
485         char *bssid = NULL;
486         DBusMessage *reply = NULL;
487
488         /* Caller must specify a message interface */
489         if (!msg_interface)
490                 goto out;
491
492         iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
493                                                          &bssid);
494         if (iface_obj_path == NULL) {
495                 reply = wpas_dbus_new_invalid_iface_error(message);
496                 goto out;
497         }
498
499         /* Make sure the message's object path actually refers to the
500          * wpa_supplicant structure it's supposed to (which is wpa_s)
501          */
502         if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
503                                                   iface_obj_path) != wpa_s) {
504                 reply = wpas_dbus_new_invalid_iface_error(message);
505                 goto out;
506         }
507
508         if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
509                 /* A method for one of this interface's configured networks */
510                 int nid = strtoul(network, NULL, 10);
511                 if (errno != EINVAL)
512                         reply = wpas_dispatch_network_method(message, wpa_s,
513                                                              nid);
514                 else
515                         reply = wpas_dbus_new_invalid_network_error(message);
516         } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) {
517                 /* A method for one of this interface's scanned BSSIDs */
518                 reply = wpas_dispatch_bssid_method(message, wpa_s, bssid);
519         } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) {
520                 /* A method for an interface only. */
521                 if (!strcmp(method, "scan"))
522                         reply = wpas_dbus_iface_scan(message, wpa_s);
523                 else if (!strcmp(method, "scanResults"))
524                         reply = wpas_dbus_iface_scan_results(message, wpa_s);
525                 else if (!strcmp(method, "addNetwork"))
526                         reply = wpas_dbus_iface_add_network(message, wpa_s);
527                 else if (!strcmp(method, "removeNetwork"))
528                         reply = wpas_dbus_iface_remove_network(message, wpa_s);
529                 else if (!strcmp(method, "selectNetwork"))
530                         reply = wpas_dbus_iface_select_network(message, wpa_s);
531                 else if (!strcmp(method, "capabilities"))
532                         reply = wpas_dbus_iface_capabilities(message, wpa_s);
533                 else if (!strcmp(method, "disconnect"))
534                         reply = wpas_dbus_iface_disconnect(message, wpa_s);
535                 else if (!strcmp(method, "setAPScan"))
536                         reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
537                 else if (!strcmp(method, "setSmartcardModules"))
538                         reply = wpas_dbus_iface_set_smartcard_modules(message,
539                                                                       wpa_s);
540                 else if (!strcmp(method, "state"))
541                         reply = wpas_dbus_iface_get_state(message, wpa_s);
542                 else if (!strcmp(method, "setBlobs"))
543                         reply = wpas_dbus_iface_set_blobs(message, wpa_s);
544                 else if (!strcmp(method, "removeBlobs"))
545                         reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
546         }
547
548         /* If the message was handled, send back the reply */
549         if (reply) {
550                 dbus_connection_send(connection, reply, NULL);
551                 dbus_message_unref(reply);
552         }
553
554 out:
555         free(iface_obj_path);
556         free(network);
557         free(bssid);
558         return reply ? DBUS_HANDLER_RESULT_HANDLED :
559                 DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
560 }
561
562
563 /**
564  * wpas_message_handler - dispatch incoming dbus messages
565  * @connection: connection to the system message bus
566  * @message: an incoming dbus message
567  * @user_data: a pointer to a dbus control interface data structure
568  * Returns: whether or not the message was handled
569  *
570  * This function dispatches all incoming dbus messages to the correct
571  * handlers, depending on what the message's target object path is,
572  * and what the method call is.
573  */
574 static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
575         DBusMessage *message, void *user_data)
576 {
577         struct ctrl_iface_dbus_priv *ctrl_iface = user_data;
578         const char *method;
579         const char *path;
580         const char *msg_interface;
581         DBusMessage *reply = NULL;
582
583         method = dbus_message_get_member(message);
584         path = dbus_message_get_path(message);
585         msg_interface = dbus_message_get_interface(message);
586         if (!method || !path || !ctrl_iface || !msg_interface)
587                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
588
589         /* Validate the method interface */
590         if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
591                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
592
593         if (!strcmp(path, WPAS_DBUS_PATH)) {
594                 /* dispatch methods against our global dbus interface here */
595                 if (!strcmp(method, "addInterface")) {
596                         reply = wpas_dbus_global_add_interface(
597                                 message, ctrl_iface->global);
598                 } else if (!strcmp(method, "removeInterface")) {
599                         reply = wpas_dbus_global_remove_interface(
600                                 message, ctrl_iface->global);
601                 } else if (!strcmp(method, "getInterface")) {
602                         reply = wpas_dbus_global_get_interface(
603                                 message, ctrl_iface->global);
604                 }
605         }
606
607         /* If the message was handled, send back the reply */
608         if (reply) {
609                 dbus_connection_send(connection, reply, NULL);
610                 dbus_message_unref(reply);
611         }
612
613         return reply ? DBUS_HANDLER_RESULT_HANDLED :
614                 DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
615 }
616
617
618 /**
619  * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal
620  * @wpa_s: %wpa_supplicant network interface data
621  * Returns: 0 on success, -1 on failure
622  *
623  * Notify listeners that this interface has updated scan results.
624  */
625 void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
626 {
627         struct ctrl_iface_dbus_priv *iface = wpa_s->global->dbus_ctrl_iface;
628         DBusMessage *_signal;
629         const char *path;
630
631         /* Do nothing if the control interface is not turned on */
632         if (iface == NULL)
633                 return;
634
635         path = wpa_supplicant_get_dbus_path(wpa_s);
636         if (path == NULL) {
637                 perror("wpa_supplicant_dbus_notify_scan_results[dbus]: "
638                        "interface didn't have a dbus path");
639                 wpa_printf(MSG_ERROR,
640                            "wpa_supplicant_dbus_notify_scan_results[dbus]: "
641                            "interface didn't have a dbus path; can't send "
642                            "scan result signal.");
643                 return;
644         }
645         _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
646                                           "ScanResultsAvailable");
647         if (_signal == NULL) {
648                 perror("wpa_supplicant_dbus_notify_scan_results[dbus]: "
649                        "couldn't create dbus signal; likely out of memory");
650                 wpa_printf(MSG_ERROR, "dbus control interface: not enough "
651                            "memory to send scan results signal.");
652                 return;
653         }
654         dbus_connection_send(iface->con, _signal, NULL);
655         dbus_message_unref(_signal);
656 }
657
658
659 /**
660  * wpa_supplicant_dbus_notify_state_change - Send a state change signal
661  * @wpa_s: %wpa_supplicant network interface data
662  * @new_state: new state wpa_supplicant is entering
663  * @old_state: old state wpa_supplicant is leaving
664  * Returns: 0 on success, -1 on failure
665  *
666  * Notify listeners that wpa_supplicant has changed state
667  */
668 void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
669                                              wpa_states new_state,
670                                              wpa_states old_state)
671 {
672         struct ctrl_iface_dbus_priv *iface;
673         DBusMessage *_signal = NULL;
674         const char *path;
675         const char *new_state_str, *old_state_str;
676
677         /* Do nothing if the control interface is not turned on */
678         if (wpa_s->global == NULL)
679                 return;
680         iface = wpa_s->global->dbus_ctrl_iface;
681         if (iface == NULL)
682                 return;
683
684         /* Only send signal if state really changed */
685         if (new_state == old_state)
686                 return;
687
688         path = wpa_supplicant_get_dbus_path(wpa_s);
689         if (path == NULL) {
690                 perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
691                        "interface didn't have a dbus path");
692                 wpa_printf(MSG_ERROR,
693                            "wpa_supplicant_dbus_notify_state_change[dbus]: "
694                            "interface didn't have a dbus path; can't send "
695                            "signal.");
696                 return;
697         }
698         _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
699                                           "StateChange");
700         if (_signal == NULL) {
701                 perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
702                        "couldn't create dbus signal; likely out of memory");
703                 wpa_printf(MSG_ERROR,
704                            "wpa_supplicant_dbus_notify_state_change[dbus]: "
705                            "couldn't create dbus signal; likely out of "
706                            "memory.");
707                 return;
708         }
709
710         new_state_str = wpa_supplicant_state_txt(new_state);
711         old_state_str = wpa_supplicant_state_txt(old_state);
712         if (new_state_str == NULL || old_state_str == NULL) {
713                 perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
714                        "couldn't convert state strings");
715                 wpa_printf(MSG_ERROR,
716                            "wpa_supplicant_dbus_notify_state_change[dbus]: "
717                            "couldn't convert state strings.");
718                 goto out;
719         }
720
721         if (!dbus_message_append_args(_signal,
722                                       DBUS_TYPE_STRING, &new_state_str,
723                                       DBUS_TYPE_STRING, &old_state_str,
724                                       DBUS_TYPE_INVALID)) {
725                 perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
726                        "not enough memory to construct state change signal.");
727                 wpa_printf(MSG_ERROR,
728                            "wpa_supplicant_dbus_notify_state_change[dbus]: "
729                            "not enough memory to construct state change "
730                            "signal.");
731                 goto out;
732         }
733
734         dbus_connection_send(iface->con, _signal, NULL);
735
736 out:
737         dbus_message_unref(_signal);
738 }
739
740
741 /**
742  * integrate_with_eloop - Register our mainloop integration with dbus
743  * @connection: connection to the system message bus
744  * @iface: a dbus control interface data structure
745  * Returns: 0 on success, -1 on failure
746  *
747  * We register our mainloop integration functions with dbus here.
748  */
749 static int integrate_with_eloop(DBusConnection *connection,
750         struct ctrl_iface_dbus_priv *iface)
751 {
752         if (!dbus_connection_set_watch_functions(connection, add_watch,
753                                                  remove_watch, watch_toggled,
754                                                  iface, NULL)) {
755                 perror("dbus_connection_set_watch_functions[dbus]");
756                 wpa_printf(MSG_ERROR, "Not enough memory to set up dbus.");
757                 return -1;
758         }
759
760         if (!dbus_connection_set_timeout_functions(connection, add_timeout,
761                                                    remove_timeout,
762                                                    timeout_toggled, iface,
763                                                    NULL)) {
764                 perror("dbus_connection_set_timeout_functions[dbus]");
765                 wpa_printf(MSG_ERROR, "Not enough memory to set up dbus.");
766                 return -1;
767         }
768
769         if (connection_setup_wakeup_main(iface) < 0) {
770                 perror("connection_setup_wakeup_main[dbus]");
771                 wpa_printf(MSG_ERROR, "Could not setup main wakeup function.");
772                 return -1;
773         }
774
775         return 0;
776 }
777
778
779 /**
780  * dispatch_initial_dbus_messages - Dispatch initial dbus messages after
781  *     claiming bus name
782  * @eloop_ctx: the DBusConnection to dispatch on
783  * @timeout_ctx: unused
784  *
785  * If clients are quick to notice that wpa_supplicant claimed its bus name,
786  * there may have been messages that came in before initialization was
787  * all finished.  Dispatch those here.
788  */
789 static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx)
790 {
791         DBusConnection *con = eloop_ctx;
792
793         while (dbus_connection_get_dispatch_status(con) ==
794                DBUS_DISPATCH_DATA_REMAINS)
795                 dbus_connection_dispatch(con);
796 }
797
798
799 /**
800  * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
801  * @global: Pointer to global data from wpa_supplicant_init()
802  * Returns: Pointer to dbus_ctrl_iface date or %NULL on failure
803  *
804  * Initialize the dbus control interface and start receiving commands from
805  * external programs over the bus.
806  */
807 struct ctrl_iface_dbus_priv *
808 wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global)
809 {
810         struct ctrl_iface_dbus_priv *iface;
811         DBusError error;
812         int ret = -1;
813         DBusObjectPathVTable wpas_vtable = {
814                 NULL, &wpas_message_handler, NULL, NULL, NULL, NULL
815         };
816
817         iface = os_zalloc(sizeof(struct ctrl_iface_dbus_priv));
818         if (iface == NULL)
819                 return NULL;
820
821         iface->global = global;
822
823         /* Get a reference to the system bus */
824         dbus_error_init(&error);
825         iface->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
826         dbus_error_free(&error);
827         if (!iface->con) {
828                 perror("dbus_bus_get[ctrl_iface_dbus]");
829                 wpa_printf(MSG_ERROR, "Could not acquire the system bus.");
830                 goto fail;
831         }
832
833         /* Tell dbus about our mainloop integration functions */
834         if (integrate_with_eloop(iface->con, iface))
835                 goto fail;
836
837         /* Register the message handler for the global dbus interface */
838         if (!dbus_connection_register_object_path(iface->con,
839                                                   WPAS_DBUS_PATH, &wpas_vtable,
840                                                   iface)) {
841                 perror("dbus_connection_register_object_path[dbus]");
842                 wpa_printf(MSG_ERROR, "Could not set up DBus message "
843                            "handler.");
844                 goto fail;
845         }
846
847         /* Register our service with the message bus */
848         dbus_error_init(&error);
849         switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE,
850                                       0, &error)) {
851         case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
852                 ret = 0;
853                 break;
854         case DBUS_REQUEST_NAME_REPLY_EXISTS:
855         case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
856         case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
857                 perror("dbus_bus_request_name[dbus]");
858                 wpa_printf(MSG_ERROR, "Could not request DBus service name: "
859                            "already registered.");
860                 break;
861         default:
862                 perror("dbus_bus_request_name[dbus]");
863                 wpa_printf(MSG_ERROR, "Could not request DBus service name: "
864                            "%s %s.", error.name, error.message);
865                 break;
866         }
867         dbus_error_free(&error);
868
869         if (ret != 0)
870                 goto fail;
871
872         wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE
873                    "'.");
874
875         /*
876          * Dispatch initial DBus messages that may have come in since the bus
877          * name was claimed above. Happens when clients are quick to notice the
878          * wpa_supplicant service.
879          *
880          * FIXME: is there a better solution to this problem?
881          */
882         eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
883                                iface->con, NULL);
884
885         return iface;
886
887 fail:
888         wpa_supplicant_dbus_ctrl_iface_deinit(iface);
889         return NULL;
890 }
891
892
893 /**
894  * wpa_supplicant_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface
895  * @iface: Pointer to dbus private data from
896  * wpa_supplicant_dbus_ctrl_iface_init()
897  *
898  * Deinitialize the dbus control interface that was initialized with
899  * wpa_supplicant_dbus_ctrl_iface_init().
900  */
901 void wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface)
902 {
903         if (iface == NULL)
904                 return;
905
906         if (iface->con) {
907                 eloop_cancel_timeout(dispatch_initial_dbus_messages,
908                                      iface->con, NULL);
909                 dbus_connection_set_watch_functions(iface->con, NULL, NULL,
910                                                     NULL, NULL, NULL);
911                 dbus_connection_set_timeout_functions(iface->con, NULL, NULL,
912                                                       NULL, NULL, NULL);
913                 dbus_connection_unref(iface->con);
914         }
915
916         memset(iface, 0, sizeof(struct ctrl_iface_dbus_priv));
917         free(iface);
918 }
919
920
921 /**
922  * wpas_dbus_register_new_iface - Register a new interface with dbus
923  * @global: Global %wpa_supplicant data
924  * @wpa_s: %wpa_supplicant interface description structure to register
925  * Returns: 0 on success, -1 on error
926  *
927  * Registers a new interface with dbus and assigns it a dbus object path.
928  */
929 int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
930 {
931         struct ctrl_iface_dbus_priv *ctrl_iface =
932                 wpa_s->global->dbus_ctrl_iface;
933         DBusConnection * con;
934         u32 next;
935         DBusObjectPathVTable vtable = {
936                 NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL
937         };
938         char *path;
939         int ret = -1;
940
941         /* Do nothing if the control interface is not turned on */
942         if (ctrl_iface == NULL)
943                 return 0;
944
945         con = ctrl_iface->con;
946         next = wpa_supplicant_dbus_next_objid(ctrl_iface);
947
948         /* Create and set the interface's object path */
949         path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
950         if (path == NULL)
951                 return -1;
952         snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
953                  WPAS_DBUS_PATH_INTERFACES "/%u",
954                  next);
955         if (wpa_supplicant_set_dbus_path(wpa_s, path)) {
956                 wpa_printf(MSG_DEBUG,
957                            "Failed to set dbus path for interface %s",
958                            wpa_s->ifname);
959                 goto out;
960         }
961
962         /* Register the message handler for the interface functions */
963         if (!dbus_connection_register_fallback(con, path, &vtable, wpa_s)) {
964                 perror("wpas_dbus_register_iface [dbus]");
965                 wpa_printf(MSG_ERROR, "Could not set up DBus message "
966                            "handler for interface %s.", wpa_s->ifname);
967                 goto out;
968         }
969         ret = 0;
970
971 out:
972         free(path);
973         return ret;
974 }
975
976
977 /**
978  * wpas_dbus_unregister_iface - Unregister an interface from dbus
979  * @wpa_s: wpa_supplicant interface structure
980  * Returns: 0 on success, -1 on failure
981  *
982  * Unregisters the interface with dbus
983  */
984 int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
985 {
986         struct ctrl_iface_dbus_priv *ctrl_iface;
987         DBusConnection *con;
988         const char *path;
989
990         /* Do nothing if the control interface is not turned on */
991         if (wpa_s == NULL || wpa_s->global == NULL)
992                 return 0;
993         ctrl_iface = wpa_s->global->dbus_ctrl_iface;
994         if (ctrl_iface == NULL)
995                 return 0;
996
997         con = ctrl_iface->con;
998         path = wpa_supplicant_get_dbus_path(wpa_s);
999
1000         if (!dbus_connection_unregister_object_path(con, path))
1001                 return -1;
1002
1003         free(wpa_s->dbus_path);
1004         wpa_s->dbus_path = NULL;
1005
1006         return 0;
1007 }
1008
1009
1010 /**
1011  * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface
1012  * @global: Pointer to global data from wpa_supplicant_init()
1013  * @path: Pointer to a dbus object path representing an interface
1014  * Returns: Pointer to the interface or %NULL if not found
1015  */
1016 struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
1017         struct wpa_global *global, const char *path)
1018 {
1019         struct wpa_supplicant *wpa_s;
1020
1021         for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
1022                 if (strcmp(wpa_s->dbus_path, path) == 0)
1023                         return wpa_s;
1024         }
1025         return NULL;
1026 }
1027
1028
1029 /**
1030  * wpa_supplicant_set_dbus_path - Assign a dbus path to an interface
1031  * @wpa_s: wpa_supplicant interface structure
1032  * @path: dbus path to set on the interface
1033  * Returns: 0 on succes, -1 on error
1034  */
1035 int wpa_supplicant_set_dbus_path(struct wpa_supplicant *wpa_s,
1036                                   const char *path)
1037 {
1038         u32 len = strlen (path);
1039         if (len >= WPAS_DBUS_OBJECT_PATH_MAX)
1040                 return -1;
1041         if (wpa_s->dbus_path)
1042                 return -1;
1043         wpa_s->dbus_path = strdup(path);
1044         return 0;
1045 }
1046
1047
1048 /**
1049  * wpa_supplicant_get_dbus_path - Get an interface's dbus path
1050  * @wpa_s: %wpa_supplicant interface structure
1051  * Returns: Interface's dbus object path, or %NULL on error
1052  */
1053 const char * wpa_supplicant_get_dbus_path(struct wpa_supplicant *wpa_s)
1054 {
1055         return wpa_s->dbus_path;
1056 }