]> code.delx.au - pulseaudio/blob - src/modules/dbus/module-dbus-protocol.c
Plug some memory leaks and an invalid read
[pulseaudio] / src / modules / dbus / module-dbus-protocol.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2009 Tanu Kaskinen
5 Copyright 2006 Lennart Poettering
6 Copyright 2006 Shams E. King
7
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation; either version 2.1 of the License,
11 or (at your option) any later version.
12
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <dbus/dbus.h>
29
30 #include <pulse/mainloop-api.h>
31 #include <pulse/timeval.h>
32 #include <pulse/xmalloc.h>
33
34 #include <pulsecore/client.h>
35 #include <pulsecore/core-util.h>
36 #include <pulsecore/dbus-util.h>
37 #include <pulsecore/idxset.h>
38 #include <pulsecore/macro.h>
39 #include <pulsecore/modargs.h>
40 #include <pulsecore/module.h>
41 #include <pulsecore/protocol-dbus.h>
42
43 #include "iface-client.h"
44 #include "iface-core.h"
45
46 #include "module-dbus-protocol-symdef.h"
47
48 PA_MODULE_DESCRIPTION("D-Bus interface");
49 PA_MODULE_USAGE(
50 "access=local|remote|local,remote "
51 "tcp_port=<port number> "
52 "tcp_listen=<hostname>");
53 PA_MODULE_LOAD_ONCE(TRUE);
54 PA_MODULE_AUTHOR("Tanu Kaskinen");
55 PA_MODULE_VERSION(PACKAGE_VERSION);
56
57 enum server_type {
58 SERVER_TYPE_LOCAL,
59 SERVER_TYPE_TCP
60 };
61
62 struct server;
63 struct connection;
64
65 struct userdata {
66 pa_module *module;
67 pa_bool_t local_access;
68 pa_bool_t remote_access;
69 uint32_t tcp_port;
70 char *tcp_listen;
71
72 struct server *local_server;
73 struct server *tcp_server;
74
75 pa_idxset *connections;
76
77 pa_defer_event *cleanup_event;
78
79 pa_dbus_protocol *dbus_protocol;
80 pa_dbusiface_core *core_iface;
81 };
82
83 struct server {
84 struct userdata *userdata;
85 enum server_type type;
86 DBusServer *dbus_server;
87 };
88
89 struct connection {
90 struct server *server;
91 pa_dbus_wrap_connection *wrap_conn;
92 pa_client *client;
93 };
94
95 static const char* const valid_modargs[] = {
96 "access",
97 "tcp_port",
98 "tcp_listen",
99 NULL
100 };
101
102 static void connection_free(struct connection *c) {
103 pa_assert(c);
104
105 pa_assert_se(pa_dbus_protocol_unregister_connection(c->server->userdata->dbus_protocol, pa_dbus_wrap_connection_get(c->wrap_conn)) >= 0);
106
107 pa_client_free(c->client);
108 pa_dbus_wrap_connection_free(c->wrap_conn);
109 pa_xfree(c);
110 }
111
112 /* Called from pa_client_kill(). */
113 static void client_kill_cb(pa_client *c) {
114 struct connection *conn;
115
116 pa_assert(c);
117 pa_assert(c->userdata);
118
119 conn = c->userdata;
120 connection_free(conn);
121 c->userdata = NULL;
122
123 pa_log_info("Connection killed.");
124 }
125
126 /* Called from pa_client_send_event(). */
127 static void client_send_event_cb(pa_client *c, const char *name, pa_proplist *data) {
128 struct connection *conn = NULL;
129 DBusMessage *signal_msg = NULL;
130 DBusMessageIter msg_iter;
131
132 pa_assert(c);
133 pa_assert(name);
134 pa_assert(data);
135 pa_assert(c->userdata);
136
137 conn = c->userdata;
138
139 pa_assert_se(signal_msg = dbus_message_new_signal(pa_dbusiface_core_get_client_path(conn->server->userdata->core_iface, c),
140 PA_DBUSIFACE_CLIENT_INTERFACE,
141 "ClientEvent"));
142 dbus_message_iter_init_append(signal_msg, &msg_iter);
143 pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name));
144 pa_dbus_append_proplist(&msg_iter, data);
145
146 pa_assert_se(dbus_connection_send(pa_dbus_wrap_connection_get(conn->wrap_conn), signal_msg, NULL));
147 dbus_message_unref(signal_msg);
148 }
149
150 /* Called by D-Bus at the authentication phase. */
151 static dbus_bool_t user_check_cb(DBusConnection *connection, unsigned long uid, void *data) {
152 pa_log_debug("Allowing connection by user %lu.", uid);
153
154 return TRUE;
155 }
156
157 static DBusHandlerResult disconnection_filter_cb(DBusConnection *connection, DBusMessage *message, void *user_data) {
158 struct connection *c = user_data;
159
160 pa_assert(connection);
161 pa_assert(message);
162 pa_assert(c);
163
164 if (dbus_message_is_signal(message, "org.freedesktop.DBus.Local", "Disconnected")) {
165 /* The connection died. Now we want to free the connection object, but
166 * let's wait until this message is fully processed, in case someone
167 * else is interested in this signal too. */
168 c->server->userdata->module->core->mainloop->defer_enable(c->server->userdata->cleanup_event, 1);
169 }
170
171 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
172 }
173
174 /* Called by D-Bus when a new client connection is received. */
175 static void connection_new_cb(DBusServer *dbus_server, DBusConnection *new_connection, void *data) {
176 struct server *s = data;
177 struct connection *c;
178 pa_client_new_data new_data;
179 pa_client *client;
180
181 pa_assert(new_connection);
182 pa_assert(s);
183
184 pa_client_new_data_init(&new_data);
185 new_data.module = s->userdata->module;
186 new_data.driver = __FILE__;
187 pa_proplist_sets(new_data.proplist, PA_PROP_APPLICATION_NAME, "D-Bus client");
188 client = pa_client_new(s->userdata->module->core, &new_data);
189 pa_client_new_data_done(&new_data);
190
191 if (!client) {
192 dbus_connection_close(new_connection);
193 return;
194 }
195
196 if (s->type == SERVER_TYPE_TCP || s->userdata->module->core->server_type == PA_SERVER_TYPE_SYSTEM) {
197 /* FIXME: Here we allow anyone from anywhere to access the server,
198 * anonymously. Access control should be configurable. */
199 dbus_connection_set_unix_user_function(new_connection, user_check_cb, NULL, NULL);
200 dbus_connection_set_allow_anonymous(new_connection, TRUE);
201 }
202
203 c = pa_xnew(struct connection, 1);
204 c->server = s;
205 c->wrap_conn = pa_dbus_wrap_connection_new_from_existing(s->userdata->module->core->mainloop, TRUE, new_connection);
206 c->client = client;
207
208 c->client->kill = client_kill_cb;
209 c->client->send_event = client_send_event_cb;
210 c->client->userdata = c;
211
212 pa_assert_se(dbus_connection_add_filter(new_connection, disconnection_filter_cb, c, NULL));
213
214 pa_idxset_put(s->userdata->connections, c, NULL);
215
216 pa_assert_se(pa_dbus_protocol_register_connection(s->userdata->dbus_protocol, new_connection, c->client) >= 0);
217 }
218
219 /* Called by PA mainloop when a D-Bus fd watch event needs handling. */
220 static void io_event_cb(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
221 unsigned int flags = 0;
222 DBusWatch *watch = userdata;
223
224 #if HAVE_DBUS_WATCH_GET_UNIX_FD
225 pa_assert(fd == dbus_watch_get_unix_fd(watch));
226 #else
227 pa_assert(fd == dbus_watch_get_fd(watch));
228 #endif
229
230 if (!dbus_watch_get_enabled(watch)) {
231 pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd);
232 return;
233 }
234
235 if (events & PA_IO_EVENT_INPUT)
236 flags |= DBUS_WATCH_READABLE;
237 if (events & PA_IO_EVENT_OUTPUT)
238 flags |= DBUS_WATCH_WRITABLE;
239 if (events & PA_IO_EVENT_HANGUP)
240 flags |= DBUS_WATCH_HANGUP;
241 if (events & PA_IO_EVENT_ERROR)
242 flags |= DBUS_WATCH_ERROR;
243
244 dbus_watch_handle(watch, flags);
245 }
246
247 /* Called by PA mainloop when a D-Bus timer event needs handling. */
248 static void time_event_cb(pa_mainloop_api *mainloop, pa_time_event* e, const struct timeval *tv, void *userdata) {
249 DBusTimeout *timeout = userdata;
250
251 if (dbus_timeout_get_enabled(timeout)) {
252 struct timeval next = *tv;
253 dbus_timeout_handle(timeout);
254
255 /* restart it for the next scheduled time */
256 pa_timeval_add(&next, (pa_usec_t) dbus_timeout_get_interval(timeout) * 1000);
257 mainloop->time_restart(e, &next);
258 }
259 }
260
261 /* Translates D-Bus fd watch event flags to PA IO event flags. */
262 static pa_io_event_flags_t get_watch_flags(DBusWatch *watch) {
263 unsigned int flags;
264 pa_io_event_flags_t events = 0;
265
266 pa_assert(watch);
267
268 flags = dbus_watch_get_flags(watch);
269
270 /* no watch flags for disabled watches */
271 if (!dbus_watch_get_enabled(watch))
272 return PA_IO_EVENT_NULL;
273
274 if (flags & DBUS_WATCH_READABLE)
275 events |= PA_IO_EVENT_INPUT;
276 if (flags & DBUS_WATCH_WRITABLE)
277 events |= PA_IO_EVENT_OUTPUT;
278
279 return events | PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
280 }
281
282 /* Called by D-Bus when a D-Bus fd watch event is added. */
283 static dbus_bool_t watch_add_cb(DBusWatch *watch, void *data) {
284 struct server *s = data;
285 pa_mainloop_api *mainloop;
286 pa_io_event *ev;
287
288 pa_assert(watch);
289 pa_assert(s);
290
291 mainloop = s->userdata->module->core->mainloop;
292
293 ev = mainloop->io_new(
294 mainloop,
295 #if HAVE_DBUS_WATCH_GET_UNIX_FD
296 dbus_watch_get_unix_fd(watch),
297 #else
298 dbus_watch_get_fd(watch),
299 #endif
300 get_watch_flags(watch), io_event_cb, watch);
301
302 dbus_watch_set_data(watch, ev, NULL);
303
304 return TRUE;
305 }
306
307 /* Called by D-Bus when a D-Bus fd watch event is removed. */
308 static void watch_remove_cb(DBusWatch *watch, void *data) {
309 struct server *s = data;
310 pa_io_event *ev;
311
312 pa_assert(watch);
313 pa_assert(s);
314
315 if ((ev = dbus_watch_get_data(watch)))
316 s->userdata->module->core->mainloop->io_free(ev);
317 }
318
319 /* Called by D-Bus when a D-Bus fd watch event is toggled. */
320 static void watch_toggled_cb(DBusWatch *watch, void *data) {
321 struct server *s = data;
322 pa_io_event *ev;
323
324 pa_assert(watch);
325 pa_assert(s);
326
327 pa_assert_se(ev = dbus_watch_get_data(watch));
328
329 /* get_watch_flags() checks if the watch is enabled */
330 s->userdata->module->core->mainloop->io_enable(ev, get_watch_flags(watch));
331 }
332
333 /* Called by D-Bus when a D-Bus timer event is added. */
334 static dbus_bool_t timeout_add_cb(DBusTimeout *timeout, void *data) {
335 struct server *s = data;
336 pa_mainloop_api *mainloop;
337 pa_time_event *ev;
338 struct timeval tv;
339
340 pa_assert(timeout);
341 pa_assert(s);
342
343 if (!dbus_timeout_get_enabled(timeout))
344 return FALSE;
345
346 mainloop = s->userdata->module->core->mainloop;
347
348 pa_gettimeofday(&tv);
349 pa_timeval_add(&tv, (pa_usec_t) dbus_timeout_get_interval(timeout) * 1000);
350
351 ev = mainloop->time_new(mainloop, &tv, time_event_cb, timeout);
352
353 dbus_timeout_set_data(timeout, ev, NULL);
354
355 return TRUE;
356 }
357
358 /* Called by D-Bus when a D-Bus timer event is removed. */
359 static void timeout_remove_cb(DBusTimeout *timeout, void *data) {
360 struct server *s = data;
361 pa_time_event *ev;
362
363 pa_assert(timeout);
364 pa_assert(s);
365
366 if ((ev = dbus_timeout_get_data(timeout)))
367 s->userdata->module->core->mainloop->time_free(ev);
368 }
369
370 /* Called by D-Bus when a D-Bus timer event is toggled. */
371 static void timeout_toggled_cb(DBusTimeout *timeout, void *data) {
372 struct server *s = data;
373 pa_mainloop_api *mainloop;
374 pa_time_event *ev;
375
376 pa_assert(timeout);
377 pa_assert(s);
378
379 mainloop = s->userdata->module->core->mainloop;
380
381 pa_assert_se(ev = dbus_timeout_get_data(timeout));
382
383 if (dbus_timeout_get_enabled(timeout)) {
384 struct timeval tv;
385
386 pa_gettimeofday(&tv);
387 pa_timeval_add(&tv, (pa_usec_t) dbus_timeout_get_interval(timeout) * 1000);
388
389 mainloop->time_restart(ev, &tv);
390 } else
391 mainloop->time_restart(ev, NULL);
392 }
393
394 static void server_free(struct server *s) {
395 pa_assert(s);
396
397 if (s->dbus_server) {
398 dbus_server_disconnect(s->dbus_server);
399 dbus_server_unref(s->dbus_server);
400 }
401
402 pa_xfree(s);
403 }
404
405 static struct server *start_server(struct userdata *u, const char *address, enum server_type type) {
406 /* XXX: We assume that when we unref the DBusServer instance at module
407 * shutdown, nobody else holds any references to it. If we stop assuming
408 * that someday, dbus_server_set_new_connection_function,
409 * dbus_server_set_watch_functions and dbus_server_set_timeout_functions
410 * calls should probably register free callbacks, instead of providing NULL
411 * as they do now. */
412
413 struct server *s = NULL;
414 DBusError error;
415
416 pa_assert(u);
417 pa_assert(address);
418
419 dbus_error_init(&error);
420
421 s = pa_xnew0(struct server, 1);
422 s->userdata = u;
423 s->type = type;
424 s->dbus_server = dbus_server_listen(address, &error);
425
426 if (dbus_error_is_set(&error)) {
427 pa_log("dbus_server_listen() failed: %s: %s", error.name, error.message);
428 goto fail;
429 }
430
431 dbus_server_set_new_connection_function(s->dbus_server, connection_new_cb, s, NULL);
432
433 if (!dbus_server_set_watch_functions(s->dbus_server, watch_add_cb, watch_remove_cb, watch_toggled_cb, s, NULL)) {
434 pa_log("dbus_server_set_watch_functions() ran out of memory.");
435 goto fail;
436 }
437
438 if (!dbus_server_set_timeout_functions(s->dbus_server, timeout_add_cb, timeout_remove_cb, timeout_toggled_cb, s, NULL)) {
439 pa_log("dbus_server_set_timeout_functions() ran out of memory.");
440 goto fail;
441 }
442
443 return s;
444
445 fail:
446 if (s)
447 server_free(s);
448
449 dbus_error_free(&error);
450
451 return NULL;
452 }
453
454 static struct server *start_local_server(struct userdata *u) {
455 struct server *s = NULL;
456 char *address = NULL;
457
458 pa_assert(u);
459
460 address = pa_get_dbus_address_from_server_type(u->module->core->server_type);
461
462 s = start_server(u, address, SERVER_TYPE_LOCAL); /* May return NULL */
463
464 pa_xfree(address);
465
466 return s;
467 }
468
469 static struct server *start_tcp_server(struct userdata *u) {
470 struct server *s = NULL;
471 char *address = NULL;
472
473 pa_assert(u);
474
475 address = pa_sprintf_malloc("tcp:host=%s,port=%u", u->tcp_listen, u->tcp_port);
476
477 s = start_server(u, address, SERVER_TYPE_TCP); /* May return NULL */
478
479 pa_xfree(address);
480
481 return s;
482 }
483
484 static int get_access_arg(pa_modargs *ma, pa_bool_t *local_access, pa_bool_t *remote_access) {
485 const char *value = NULL;
486
487 pa_assert(ma);
488 pa_assert(local_access);
489 pa_assert(remote_access);
490
491 if (!(value = pa_modargs_get_value(ma, "access", NULL)))
492 return 0;
493
494 if (!strcmp(value, "local")) {
495 *local_access = TRUE;
496 *remote_access = FALSE;
497 } else if (!strcmp(value, "remote")) {
498 *local_access = FALSE;
499 *remote_access = TRUE;
500 } else if (!strcmp(value, "local,remote")) {
501 *local_access = TRUE;
502 *remote_access = TRUE;
503 } else
504 return -1;
505
506 return 0;
507 }
508
509 /* Frees dead client connections. */
510 static void cleanup_cb(pa_mainloop_api *a, pa_defer_event *e, void *userdata) {
511 struct userdata *u = userdata;
512 struct connection *conn = NULL;
513 uint32_t idx;
514
515 PA_IDXSET_FOREACH(conn, u->connections, idx) {
516 if (!dbus_connection_get_is_connected(pa_dbus_wrap_connection_get(conn->wrap_conn))) {
517 pa_idxset_remove_by_data(u->connections, conn, NULL);
518 connection_free(conn);
519 }
520 }
521
522 u->module->core->mainloop->defer_enable(e, 0);
523 }
524
525 int pa__init(pa_module *m) {
526 struct userdata *u = NULL;
527 pa_modargs *ma = NULL;
528
529 pa_assert(m);
530
531 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
532 pa_log("Failed to parse module arguments.");
533 goto fail;
534 }
535
536 m->userdata = u = pa_xnew0(struct userdata, 1);
537 u->module = m;
538 u->local_access = TRUE;
539 u->remote_access = FALSE;
540 u->tcp_port = PA_DBUS_DEFAULT_PORT;
541
542 if (get_access_arg(ma, &u->local_access, &u->remote_access) < 0) {
543 pa_log("Invalid access argument: '%s'", pa_modargs_get_value(ma, "access", NULL));
544 goto fail;
545 }
546
547 if (pa_modargs_get_value_u32(ma, "tcp_port", &u->tcp_port) < 0 || u->tcp_port < 1 || u->tcp_port > 49150) {
548 pa_log("Invalid tcp_port argument: '%s'", pa_modargs_get_value(ma, "tcp_port", NULL));
549 goto fail;
550 }
551
552 u->tcp_listen = pa_xstrdup(pa_modargs_get_value(ma, "tcp_listen", "0.0.0.0"));
553
554 if (u->local_access && !(u->local_server = start_local_server(u))) {
555 pa_log("Starting the local D-Bus server failed.");
556 goto fail;
557 }
558
559 if (u->remote_access && !(u->tcp_server = start_tcp_server(u))) {
560 pa_log("Starting the D-Bus server for remote connections failed.");
561 goto fail;
562 }
563
564 u->connections = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
565
566 u->cleanup_event = m->core->mainloop->defer_new(m->core->mainloop, cleanup_cb, u);
567 m->core->mainloop->defer_enable(u->cleanup_event, 0);
568
569 u->dbus_protocol = pa_dbus_protocol_get(m->core);
570 u->core_iface = pa_dbusiface_core_new(m->core);
571
572 pa_modargs_free(ma);
573
574 return 0;
575
576 fail:
577 if (ma)
578 pa_modargs_free(ma);
579
580 pa__done(m);
581
582 return -1;
583 }
584
585 void pa__done(pa_module *m) {
586 struct userdata *u;
587 struct connection *c;
588
589 pa_assert(m);
590
591 if (!(u = m->userdata))
592 return;
593
594 if (u->core_iface)
595 pa_dbusiface_core_free(u->core_iface);
596
597 while ((c = pa_idxset_steal_first(u->connections, NULL)))
598 connection_free(c);
599
600 pa_idxset_free(u->connections, NULL, NULL);
601
602 /* This must not be called before the connections are freed, because if
603 * there are any connections left, they will emit the
604 * org.freedesktop.DBus.Local.Disconnected signal, and
605 * disconnection_filter_cb() will be called. disconnection_filter_cb() then
606 * tries to enable the defer event, and if it's already freed, an assertion
607 * will be hit in mainloop.c. */
608 if (u->cleanup_event)
609 m->core->mainloop->defer_free(u->cleanup_event);
610
611 if (u->tcp_server)
612 server_free(u->tcp_server);
613
614 if (u->local_server)
615 server_free(u->local_server);
616
617 if (u->dbus_protocol)
618 pa_dbus_protocol_unref(u->dbus_protocol);
619
620 pa_xfree(u->tcp_listen);
621 pa_xfree(u);
622 m->userdata = NULL;
623 }