chiark / gitweb /
socket: verify socket type properly when desrializing
[elogind.git] / src / dbus.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   systemd 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 General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/epoll.h>
23 #include <sys/timerfd.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <dbus/dbus.h>
27
28 #include "dbus.h"
29 #include "log.h"
30 #include "strv.h"
31 #include "cgroup.h"
32 #include "dbus-unit.h"
33 #include "dbus-job.h"
34 #include "dbus-manager.h"
35 #include "dbus-service.h"
36 #include "dbus-socket.h"
37 #include "dbus-target.h"
38 #include "dbus-device.h"
39 #include "dbus-mount.h"
40 #include "dbus-automount.h"
41 #include "dbus-snapshot.h"
42 #include "dbus-swap.h"
43 #include "dbus-timer.h"
44 #include "dbus-path.h"
45
46 static const char bus_properties_interface[] = BUS_PROPERTIES_INTERFACE;
47 static const char bus_introspectable_interface[] = BUS_INTROSPECTABLE_INTERFACE;
48
49 const char *const bus_interface_table[] = {
50         "org.freedesktop.DBus.Properties",     bus_properties_interface,
51         "org.freedesktop.DBus.Introspectable", bus_introspectable_interface,
52         "org.freedesktop.systemd1.Manager",    bus_manager_interface,
53         "org.freedesktop.systemd1.Job",        bus_job_interface,
54         "org.freedesktop.systemd1.Unit",       bus_unit_interface,
55         "org.freedesktop.systemd1.Service",    bus_service_interface,
56         "org.freedesktop.systemd1.Socket",     bus_socket_interface,
57         "org.freedesktop.systemd1.Target",     bus_target_interface,
58         "org.freedesktop.systemd1.Device",     bus_device_interface,
59         "org.freedesktop.systemd1.Mount",      bus_mount_interface,
60         "org.freedesktop.systemd1.Automount",  bus_automount_interface,
61         "org.freedesktop.systemd1.Snapshot",   bus_snapshot_interface,
62         "org.freedesktop.systemd1.Swap",       bus_swap_interface,
63         "org.freedesktop.systemd1.Timer",      bus_timer_interface,
64         "org.freedesktop.systemd1.Path",       bus_path_interface,
65         NULL
66 };
67
68 static const char *error_to_dbus(int error);
69
70 static void api_bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data)  {
71         Manager *m = data;
72
73         assert(bus);
74         assert(m);
75
76         if (!m->api_bus)
77                 return;
78
79         assert(m->api_bus == bus);
80
81         m->request_api_bus_dispatch = status != DBUS_DISPATCH_COMPLETE;
82 }
83
84 static void system_bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data)  {
85         Manager *m = data;
86
87         assert(bus);
88         assert(m);
89
90         if (!m->system_bus)
91                 return;
92
93         assert(m->system_bus == bus);
94
95         m->request_system_bus_dispatch = status != DBUS_DISPATCH_COMPLETE;
96 }
97
98 static uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
99         unsigned flags;
100         uint32_t events = 0;
101
102         assert(bus_watch);
103
104         /* no watch flags for disabled watches */
105         if (!dbus_watch_get_enabled(bus_watch))
106                 return 0;
107
108         flags = dbus_watch_get_flags(bus_watch);
109
110         if (flags & DBUS_WATCH_READABLE)
111                 events |= EPOLLIN;
112         if (flags & DBUS_WATCH_WRITABLE)
113                 events |= EPOLLOUT;
114
115         return events | EPOLLHUP | EPOLLERR;
116 }
117
118 static unsigned events_to_bus_flags(uint32_t events) {
119         unsigned flags = 0;
120
121         if (events & EPOLLIN)
122                 flags |= DBUS_WATCH_READABLE;
123         if (events & EPOLLOUT)
124                 flags |= DBUS_WATCH_WRITABLE;
125         if (events & EPOLLHUP)
126                 flags |= DBUS_WATCH_HANGUP;
127         if (events & EPOLLERR)
128                 flags |= DBUS_WATCH_ERROR;
129
130         return flags;
131 }
132
133 void bus_watch_event(Manager *m, Watch *w, int events) {
134         assert(m);
135         assert(w);
136
137         /* This is called by the event loop whenever there is
138          * something happening on D-Bus' file handles. */
139
140         if (!dbus_watch_get_enabled(w->data.bus_watch))
141                 return;
142
143         dbus_watch_handle(w->data.bus_watch, events_to_bus_flags(events));
144 }
145
146 static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) {
147         Manager *m = data;
148         Watch *w;
149         struct epoll_event ev;
150
151         assert(bus_watch);
152         assert(m);
153
154         if (!(w = new0(Watch, 1)))
155                 return FALSE;
156
157         w->fd = dbus_watch_get_unix_fd(bus_watch);
158         w->type = WATCH_DBUS_WATCH;
159         w->data.bus_watch = bus_watch;
160
161         zero(ev);
162         ev.events = bus_flags_to_events(bus_watch);
163         ev.data.ptr = w;
164
165         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
166
167                 if (errno != EEXIST) {
168                         free(w);
169                         return FALSE;
170                 }
171
172                 /* Hmm, bloody D-Bus creates multiple watches on the
173                  * same fd. epoll() does not like that. As a dirty
174                  * hack we simply dup() the fd and hence get a second
175                  * one we can safely add to the epoll(). */
176
177                 if ((w->fd = dup(w->fd)) < 0) {
178                         free(w);
179                         return FALSE;
180                 }
181
182                 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
183                         free(w);
184                         close_nointr_nofail(w->fd);
185                         return FALSE;
186                 }
187
188                 w->fd_is_dupped = true;
189         }
190
191         dbus_watch_set_data(bus_watch, w, NULL);
192
193         return TRUE;
194 }
195
196 static void bus_remove_watch(DBusWatch *bus_watch, void *data) {
197         Manager *m = data;
198         Watch *w;
199
200         assert(bus_watch);
201         assert(m);
202
203         if (!(w = dbus_watch_get_data(bus_watch)))
204                 return;
205
206         assert(w->type == WATCH_DBUS_WATCH);
207         assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
208
209         if (w->fd_is_dupped)
210                 close_nointr_nofail(w->fd);
211
212         free(w);
213 }
214
215 static void bus_toggle_watch(DBusWatch *bus_watch, void *data) {
216         Manager *m = data;
217         Watch *w;
218         struct epoll_event ev;
219
220         assert(bus_watch);
221         assert(m);
222
223         assert_se(w = dbus_watch_get_data(bus_watch));
224         assert(w->type == WATCH_DBUS_WATCH);
225
226         zero(ev);
227         ev.events = bus_flags_to_events(bus_watch);
228         ev.data.ptr = w;
229
230         assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_MOD, w->fd, &ev) == 0);
231 }
232
233 static int bus_timeout_arm(Manager *m, Watch *w) {
234         struct itimerspec its;
235
236         assert(m);
237         assert(w);
238
239         zero(its);
240
241         if (dbus_timeout_get_enabled(w->data.bus_timeout)) {
242                 timespec_store(&its.it_value, dbus_timeout_get_interval(w->data.bus_timeout) * USEC_PER_MSEC);
243                 its.it_interval = its.it_interval;
244         }
245
246         if (timerfd_settime(w->fd, 0, &its, NULL) < 0)
247                 return -errno;
248
249         return 0;
250 }
251
252 void bus_timeout_event(Manager *m, Watch *w, int events) {
253         assert(m);
254         assert(w);
255
256         /* This is called by the event loop whenever there is
257          * something happening on D-Bus' file handles. */
258
259         if (!(dbus_timeout_get_enabled(w->data.bus_timeout)))
260                 return;
261
262         dbus_timeout_handle(w->data.bus_timeout);
263 }
264
265 static dbus_bool_t bus_add_timeout(DBusTimeout *timeout, void *data) {
266         Manager *m = data;
267         Watch *w;
268         struct epoll_event ev;
269
270         assert(timeout);
271         assert(m);
272
273         if (!(w = new0(Watch, 1)))
274                 return FALSE;
275
276         if (!(w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
277                 goto fail;
278
279         w->type = WATCH_DBUS_TIMEOUT;
280         w->data.bus_timeout = timeout;
281
282         if (bus_timeout_arm(m, w) < 0)
283                 goto fail;
284
285         zero(ev);
286         ev.events = EPOLLIN;
287         ev.data.ptr = w;
288
289         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0)
290                 goto fail;
291
292         dbus_timeout_set_data(timeout, w, NULL);
293
294         return TRUE;
295
296 fail:
297         if (w->fd >= 0)
298                 close_nointr_nofail(w->fd);
299
300         free(w);
301         return FALSE;
302 }
303
304 static void bus_remove_timeout(DBusTimeout *timeout, void *data) {
305         Manager *m = data;
306         Watch *w;
307
308         assert(timeout);
309         assert(m);
310
311         if (!(w = dbus_timeout_get_data(timeout)))
312                 return;
313
314         assert(w->type == WATCH_DBUS_TIMEOUT);
315         assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
316         close_nointr_nofail(w->fd);
317         free(w);
318 }
319
320 static void bus_toggle_timeout(DBusTimeout *timeout, void *data) {
321         Manager *m = data;
322         Watch *w;
323         int r;
324
325         assert(timeout);
326         assert(m);
327
328         assert_se(w = dbus_timeout_get_data(timeout));
329         assert(w->type == WATCH_DBUS_TIMEOUT);
330
331         if ((r = bus_timeout_arm(m, w)) < 0)
332                 log_error("Failed to rearm timer: %s", strerror(-r));
333 }
334
335 static DBusHandlerResult api_bus_message_filter(DBusConnection  *connection, DBusMessage  *message, void *data) {
336         Manager *m = data;
337         DBusError error;
338         DBusMessage *reply = NULL;
339
340         assert(connection);
341         assert(message);
342         assert(m);
343
344         dbus_error_init(&error);
345
346         /* log_debug("Got D-Bus request: %s.%s() on %s", */
347         /*           dbus_message_get_interface(message), */
348         /*           dbus_message_get_member(message), */
349         /*           dbus_message_get_path(message)); */
350
351         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
352                 log_error("Warning! API D-Bus connection terminated.");
353                 bus_done_api(m);
354
355         } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
356                 const char *name, *old_owner, *new_owner;
357
358                 if (!dbus_message_get_args(message, &error,
359                                            DBUS_TYPE_STRING, &name,
360                                            DBUS_TYPE_STRING, &old_owner,
361                                            DBUS_TYPE_STRING, &new_owner,
362                                            DBUS_TYPE_INVALID))
363                         log_error("Failed to parse NameOwnerChanged message: %s", error.message);
364                 else  {
365                         if (set_remove(m->subscribed, (char*) name))
366                                 log_debug("Subscription client vanished: %s (left: %u)", name, set_size(m->subscribed));
367
368                         if (old_owner[0] == 0)
369                                 old_owner = NULL;
370
371                         if (new_owner[0] == 0)
372                                 new_owner = NULL;
373
374                         manager_dispatch_bus_name_owner_changed(m, name, old_owner, new_owner);
375                 }
376         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Activator", "ActivationRequest")) {
377                 const char *name;
378
379                 if (!dbus_message_get_args(message, &error,
380                                            DBUS_TYPE_STRING, &name,
381                                            DBUS_TYPE_INVALID))
382                         log_error("Failed to parse ActivationRequest message: %s", error.message);
383                 else  {
384                         int r;
385                         Unit *u;
386
387                         log_debug("Got D-Bus activation request for %s", name);
388
389                         r = manager_load_unit(m, name, NULL, &u);
390
391                         if (r >= 0 && u->meta.only_by_dependency)
392                                 r = -EPERM;
393
394                         if (r >= 0)
395                                 r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, NULL);
396
397                         if (r < 0) {
398                                 const char *id, *text;
399
400                                 if (!(reply = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure")))
401                                         goto oom;
402
403                                 id = error_to_dbus(r);
404                                 text = strerror(-r);
405
406                                 if (!dbus_message_set_destination(reply, DBUS_SERVICE_DBUS) ||
407                                     !dbus_message_append_args(reply,
408                                                               DBUS_TYPE_STRING, &name,
409                                                               DBUS_TYPE_STRING, &id,
410                                                               DBUS_TYPE_STRING, &text,
411                                                               DBUS_TYPE_INVALID))
412                                         goto oom;
413                         }
414
415                         /* On success we don't do anything, the service will be spwaned now */
416                 }
417         }
418
419         dbus_error_free(&error);
420
421         if (reply) {
422                 if (!dbus_connection_send(connection, reply, NULL))
423                         goto oom;
424
425                 dbus_message_unref(reply);
426         }
427
428         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
429
430 oom:
431         if (reply)
432                 dbus_message_unref(reply);
433
434         dbus_error_free(&error);
435
436         return DBUS_HANDLER_RESULT_NEED_MEMORY;
437 }
438
439 static DBusHandlerResult system_bus_message_filter(DBusConnection  *connection, DBusMessage  *message, void *data) {
440         Manager *m = data;
441         DBusError error;
442
443         assert(connection);
444         assert(message);
445         assert(m);
446
447         dbus_error_init(&error);
448
449         /* log_debug("Got D-Bus request: %s.%s() on %s", */
450         /*           dbus_message_get_interface(message), */
451         /*           dbus_message_get_member(message), */
452         /*           dbus_message_get_path(message)); */
453
454         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
455                 log_error("Warning! System D-Bus connection terminated.");
456                 bus_done_system(m);
457
458         } if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
459                 const char *cgroup;
460
461                 if (!dbus_message_get_args(message, &error,
462                                            DBUS_TYPE_STRING, &cgroup,
463                                            DBUS_TYPE_INVALID))
464                         log_error("Failed to parse Released message: %s", error.message);
465                 else
466                         cgroup_notify_empty(m, cgroup);
467         }
468
469         dbus_error_free(&error);
470         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
471 }
472
473 unsigned bus_dispatch(Manager *m) {
474         assert(m);
475
476         if (m->queued_message) {
477                 /* If we cannot get rid of this message we won't
478                  * dispatch any D-Bus messages, so that we won't end
479                  * up wanting to queue another message. */
480
481                 if (!dbus_connection_send(m->api_bus, m->queued_message, NULL))
482                         return 0;
483
484                 dbus_message_unref(m->queued_message);
485                 m->queued_message = NULL;
486         }
487
488         if (m->request_api_bus_dispatch) {
489                 if (dbus_connection_dispatch(m->api_bus) == DBUS_DISPATCH_COMPLETE)
490                         m->request_api_bus_dispatch = false;
491
492                 return 1;
493         }
494
495         if (m->request_system_bus_dispatch) {
496                 if (dbus_connection_dispatch(m->system_bus) == DBUS_DISPATCH_COMPLETE)
497                         m->request_system_bus_dispatch = false;
498
499                 return 1;
500         }
501
502         return 0;
503 }
504
505 static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) {
506         DBusMessage *reply;
507         DBusError error;
508
509         dbus_error_init(&error);
510
511         assert_se(reply = dbus_pending_call_steal_reply(pending));
512
513         switch (dbus_message_get_type(reply)) {
514
515         case DBUS_MESSAGE_TYPE_ERROR:
516
517                 assert_se(dbus_set_error_from_message(&error, reply));
518                 log_warning("RequestName() failed: %s", error.message);
519                 break;
520
521         case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
522                 uint32_t r;
523
524                 if (!dbus_message_get_args(reply,
525                                            &error,
526                                            DBUS_TYPE_UINT32, &r,
527                                            DBUS_TYPE_INVALID)) {
528                         log_error("Failed to parse RequestName() reply: %s", error.message);
529                         break;
530                 }
531
532                 if (r == 1)
533                         log_debug("Successfully acquired name.");
534                 else
535                         log_error("Name already owned.");
536
537                 break;
538         }
539
540         default:
541                 assert_not_reached("Invalid reply message");
542         }
543
544         dbus_message_unref(reply);
545         dbus_error_free(&error);
546 }
547
548 static int request_name(Manager *m) {
549         const char *name = "org.freedesktop.systemd1";
550         uint32_t flags = 0;
551         DBusMessage *message = NULL;
552         DBusPendingCall *pending = NULL;
553
554         if (!(message = dbus_message_new_method_call(
555                               DBUS_SERVICE_DBUS,
556                               DBUS_PATH_DBUS,
557                               DBUS_INTERFACE_DBUS,
558                               "RequestName")))
559                 goto oom;
560
561         if (!dbus_message_append_args(
562                             message,
563                             DBUS_TYPE_STRING, &name,
564                             DBUS_TYPE_UINT32, &flags,
565                             DBUS_TYPE_INVALID))
566                 goto oom;
567
568         if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
569                 goto oom;
570
571         if (!dbus_pending_call_set_notify(pending, request_name_pending_cb, m, NULL))
572                 goto oom;
573
574         dbus_message_unref(message);
575         dbus_pending_call_unref(pending);
576
577         /* We simple ask for the name and don't wait for it. Sooner or
578          * later we'll have it. */
579
580         return 0;
581
582 oom:
583         if (pending) {
584                 dbus_pending_call_cancel(pending);
585                 dbus_pending_call_unref(pending);
586         }
587
588         if (message)
589                 dbus_message_unref(message);
590
591         return -ENOMEM;
592 }
593
594 static void query_name_list_pending_cb(DBusPendingCall *pending, void *userdata) {
595         DBusMessage *reply;
596         DBusError error;
597         Manager *m = userdata;
598
599         assert(m);
600
601         dbus_error_init(&error);
602
603         assert_se(reply = dbus_pending_call_steal_reply(pending));
604
605         switch (dbus_message_get_type(reply)) {
606
607         case DBUS_MESSAGE_TYPE_ERROR:
608
609                 assert_se(dbus_set_error_from_message(&error, reply));
610                 log_warning("ListNames() failed: %s", error.message);
611                 break;
612
613         case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
614                 int r;
615                 char **l;
616
617                 if ((r = bus_parse_strv(reply, &l)) < 0)
618                         log_warning("Failed to parse ListNames() reply: %s", strerror(-r));
619                 else {
620                         char **t;
621
622                         STRV_FOREACH(t, l)
623                                 /* This is a bit hacky, we say the
624                                  * owner of the name is the name
625                                  * itself, because we don't want the
626                                  * extra traffic to figure out the
627                                  * real owner. */
628                                 manager_dispatch_bus_name_owner_changed(m, *t, NULL, *t);
629
630                         strv_free(l);
631                 }
632
633                 break;
634         }
635
636         default:
637                 assert_not_reached("Invalid reply message");
638         }
639
640         dbus_message_unref(reply);
641         dbus_error_free(&error);
642 }
643
644 static int query_name_list(Manager *m) {
645         DBusMessage *message = NULL;
646         DBusPendingCall *pending = NULL;
647
648         /* Asks for the currently installed bus names */
649
650         if (!(message = dbus_message_new_method_call(
651                               DBUS_SERVICE_DBUS,
652                               DBUS_PATH_DBUS,
653                               DBUS_INTERFACE_DBUS,
654                               "ListNames")))
655                 goto oom;
656
657         if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
658                 goto oom;
659
660         if (!dbus_pending_call_set_notify(pending, query_name_list_pending_cb, m, NULL))
661                 goto oom;
662
663         dbus_message_unref(message);
664         dbus_pending_call_unref(pending);
665
666         /* We simple ask for the list and don't wait for it. Sooner or
667          * later we'll get it. */
668
669         return 0;
670
671 oom:
672         if (pending) {
673                 dbus_pending_call_cancel(pending);
674                 dbus_pending_call_unref(pending);
675         }
676
677         if (message)
678                 dbus_message_unref(message);
679
680         return -ENOMEM;
681 }
682
683 static int bus_setup_loop(Manager *m, DBusConnection *bus) {
684         assert(m);
685         assert(bus);
686
687         dbus_connection_set_exit_on_disconnect(bus, FALSE);
688
689         if (!dbus_connection_set_watch_functions(bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
690             !dbus_connection_set_timeout_functions(bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL))
691                 return -ENOMEM;
692
693         return 0;
694 }
695
696 int bus_init_system(Manager *m) {
697         DBusError error;
698         char *id;
699         int r;
700
701         assert(m);
702
703         dbus_error_init(&error);
704
705         if (m->system_bus)
706                 return 0;
707
708         if (m->running_as != MANAGER_SESSION && m->api_bus)
709                 m->system_bus = m->api_bus;
710         else {
711                 if (!(m->system_bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
712                         log_debug("Failed to get system D-Bus connection, retrying later: %s", error.message);
713                         dbus_error_free(&error);
714                         return 0;
715                 }
716
717                 dbus_connection_set_dispatch_status_function(m->system_bus, system_bus_dispatch_status, m, NULL);
718                 m->request_system_bus_dispatch = true;
719
720                 if ((r = bus_setup_loop(m, m->system_bus)) < 0) {
721                         bus_done_system(m);
722                         return r;
723                 }
724         }
725
726         if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL)) {
727                 bus_done_system(m);
728                 return -ENOMEM;
729         }
730
731         dbus_bus_add_match(m->system_bus,
732                            "type='signal',"
733                            "interface='org.freedesktop.systemd1.Agent',"
734                            "path='/org/freedesktop/systemd1/agent'",
735                            &error);
736
737         if (dbus_error_is_set(&error)) {
738                 log_error("Failed to register match: %s", error.message);
739                 dbus_error_free(&error);
740                 bus_done_system(m);
741                 return -ENOMEM;
742         }
743
744         log_debug("Successfully connected to system D-Bus bus %s as %s",
745                   strnull((id = dbus_connection_get_server_id(m->system_bus))),
746                   strnull(dbus_bus_get_unique_name(m->system_bus)));
747         dbus_free(id);
748
749         return 0;
750 }
751
752 int bus_init_api(Manager *m) {
753         DBusError error;
754         char *id;
755         int r;
756
757         assert(m);
758
759         dbus_error_init(&error);
760
761         if (m->api_bus)
762                 return 0;
763
764         if (m->name_data_slot < 0)
765                 if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot))
766                         return -ENOMEM;
767
768         if (m->running_as != MANAGER_SESSION && m->system_bus)
769                 m->api_bus = m->system_bus;
770         else {
771                 if (!(m->api_bus = dbus_bus_get_private(m->running_as == MANAGER_SESSION ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error))) {
772                         log_debug("Failed to get API D-Bus connection, retrying later: %s", error.message);
773                         dbus_error_free(&error);
774                         return 0;
775                 }
776
777                 dbus_connection_set_dispatch_status_function(m->api_bus, api_bus_dispatch_status, m, NULL);
778                 m->request_api_bus_dispatch = true;
779
780                 if ((r = bus_setup_loop(m, m->api_bus)) < 0) {
781                         bus_done_api(m);
782                         return r;
783                 }
784         }
785
786         if (!dbus_connection_register_object_path(m->api_bus, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
787             !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
788             !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
789             !dbus_connection_add_filter(m->api_bus, api_bus_message_filter, m, NULL)) {
790                 bus_done_api(m);
791                 return -ENOMEM;
792         }
793
794         /* Get NameOwnerChange messages */
795         dbus_bus_add_match(m->api_bus,
796                            "type='signal',"
797                            "sender='"DBUS_SERVICE_DBUS"',"
798                            "interface='"DBUS_INTERFACE_DBUS"',"
799                            "path='"DBUS_PATH_DBUS"'",
800                            &error);
801
802         if (dbus_error_is_set(&error)) {
803                 log_error("Failed to register match: %s", error.message);
804                 dbus_error_free(&error);
805                 bus_done_api(m);
806                 return -ENOMEM;
807         }
808
809         /* Get activation requests */
810         dbus_bus_add_match(m->api_bus,
811                            "type='signal',"
812                            "sender='"DBUS_SERVICE_DBUS"',"
813                            "interface='org.freedesktop.systemd1.Activator',"
814                            "path='"DBUS_PATH_DBUS"'",
815                            &error);
816
817         if (dbus_error_is_set(&error)) {
818                 log_error("Failed to register match: %s", error.message);
819                 dbus_error_free(&error);
820                 bus_done_api(m);
821                 return -ENOMEM;
822         }
823
824         if ((r = request_name(m)) < 0) {
825                 bus_done_api(m);
826                 return r;
827         }
828
829         if ((r = query_name_list(m)) < 0) {
830                 bus_done_api(m);
831                 return r;
832         }
833
834         log_debug("Successfully connected to API D-Bus bus %s as %s",
835                   strnull((id = dbus_connection_get_server_id(m->api_bus))),
836                   strnull(dbus_bus_get_unique_name(m->api_bus)));
837         dbus_free(id);
838
839         if (!m->subscribed)
840                 if (!(m->subscribed = set_new(string_hash_func, string_compare_func)))
841                         return -ENOMEM;
842
843         return 0;
844 }
845
846 void bus_done_api(Manager *m) {
847         assert(m);
848
849         if (m->api_bus) {
850                 if (m->system_bus == m->api_bus)
851                         m->system_bus = NULL;
852
853                 dbus_connection_set_dispatch_status_function(m->api_bus, NULL, NULL, NULL);
854                 dbus_connection_flush(m->api_bus);
855                 dbus_connection_close(m->api_bus);
856                 dbus_connection_unref(m->api_bus);
857                 m->api_bus = NULL;
858         }
859
860         if (m->subscribed) {
861                 char *c;
862
863                 while ((c = set_steal_first(m->subscribed)))
864                         free(c);
865
866                 set_free(m->subscribed);
867                 m->subscribed = NULL;
868         }
869
870        if (m->name_data_slot >= 0)
871                dbus_pending_call_free_data_slot(&m->name_data_slot);
872
873        if (m->queued_message) {
874                dbus_message_unref(m->queued_message);
875                m->queued_message = NULL;
876        }
877 }
878
879 void bus_done_system(Manager *m) {
880         assert(m);
881
882         if (m->system_bus == m->api_bus)
883                 bus_done_api(m);
884
885         if (m->system_bus) {
886                 dbus_connection_set_dispatch_status_function(m->system_bus, NULL, NULL, NULL);
887                 dbus_connection_flush(m->system_bus);
888                 dbus_connection_close(m->system_bus);
889                 dbus_connection_unref(m->system_bus);
890                 m->system_bus = NULL;
891         }
892 }
893
894 static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) {
895         Manager *m = userdata;
896         DBusMessage *reply;
897         DBusError error;
898         const char *name;
899
900         dbus_error_init(&error);
901
902         assert_se(name = dbus_pending_call_get_data(pending, m->name_data_slot));
903         assert_se(reply = dbus_pending_call_steal_reply(pending));
904
905         switch (dbus_message_get_type(reply)) {
906
907         case DBUS_MESSAGE_TYPE_ERROR:
908
909                 assert_se(dbus_set_error_from_message(&error, reply));
910                 log_warning("GetConnectionUnixProcessID() failed: %s", error.message);
911                 break;
912
913         case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
914                 uint32_t r;
915
916                 if (!dbus_message_get_args(reply,
917                                            &error,
918                                            DBUS_TYPE_UINT32, &r,
919                                            DBUS_TYPE_INVALID)) {
920                         log_error("Failed to parse GetConnectionUnixProcessID() reply: %s", error.message);
921                         break;
922                 }
923
924                 manager_dispatch_bus_query_pid_done(m, name, (pid_t) r);
925                 break;
926         }
927
928         default:
929                 assert_not_reached("Invalid reply message");
930         }
931
932         dbus_message_unref(reply);
933         dbus_error_free(&error);
934 }
935
936 int bus_query_pid(Manager *m, const char *name) {
937         DBusMessage *message = NULL;
938         DBusPendingCall *pending = NULL;
939         char *n = NULL;
940
941         assert(m);
942         assert(name);
943
944         if (!(message = dbus_message_new_method_call(
945                               DBUS_SERVICE_DBUS,
946                               DBUS_PATH_DBUS,
947                               DBUS_INTERFACE_DBUS,
948                               "GetConnectionUnixProcessID")))
949                 goto oom;
950
951         if (!(dbus_message_append_args(
952                               message,
953                               DBUS_TYPE_STRING, &name,
954                               DBUS_TYPE_INVALID)))
955                 goto oom;
956
957         if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
958                 goto oom;
959
960         if (!(n = strdup(name)))
961                 goto oom;
962
963         if (!dbus_pending_call_set_data(pending, m->name_data_slot, n, free))
964                 goto oom;
965
966         n = NULL;
967
968         if (!dbus_pending_call_set_notify(pending, query_pid_pending_cb, m, NULL))
969                 goto oom;
970
971         dbus_message_unref(message);
972         dbus_pending_call_unref(pending);
973
974         return 0;
975
976 oom:
977         free(n);
978
979         if (pending) {
980                 dbus_pending_call_cancel(pending);
981                 dbus_pending_call_unref(pending);
982         }
983
984         if (message)
985                 dbus_message_unref(message);
986
987         return -ENOMEM;
988 }
989
990 DBusHandlerResult bus_default_message_handler(Manager *m, DBusMessage *message, const char*introspection, const BusProperty *properties) {
991         DBusError error;
992         DBusMessage *reply = NULL;
993         int r;
994
995         assert(m);
996         assert(message);
997
998         dbus_error_init(&error);
999
1000         if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
1001
1002                 if (!(reply = dbus_message_new_method_return(message)))
1003                         goto oom;
1004
1005                 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
1006                         goto oom;
1007
1008         } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && properties) {
1009                 const char *interface, *property;
1010                 const BusProperty *p;
1011
1012                 if (!dbus_message_get_args(
1013                             message,
1014                             &error,
1015                             DBUS_TYPE_STRING, &interface,
1016                             DBUS_TYPE_STRING, &property,
1017                             DBUS_TYPE_INVALID))
1018                         return bus_send_error_reply(m, message, &error, -EINVAL);
1019
1020                 for (p = properties; p->property; p++)
1021                         if (streq(p->interface, interface) && streq(p->property, property))
1022                                 break;
1023
1024                 if (p->property) {
1025                         DBusMessageIter iter, sub;
1026
1027                         if (!(reply = dbus_message_new_method_return(message)))
1028                                 goto oom;
1029
1030                         dbus_message_iter_init_append(reply, &iter);
1031
1032                         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
1033                                 goto oom;
1034
1035                         if ((r = p->append(m, &sub, property, (void*) p->data)) < 0) {
1036
1037                                 if (r == -ENOMEM)
1038                                         goto oom;
1039
1040                                 dbus_message_unref(reply);
1041                                 return bus_send_error_reply(m, message, NULL, r);
1042                         }
1043
1044                         if (!dbus_message_iter_close_container(&iter, &sub))
1045                                 goto oom;
1046                 }
1047         } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && properties) {
1048                 const char *interface;
1049                 const BusProperty *p;
1050                 DBusMessageIter iter, sub, sub2, sub3;
1051                 bool any = false;
1052
1053                 if (!dbus_message_get_args(
1054                             message,
1055                             &error,
1056                             DBUS_TYPE_STRING, &interface,
1057                             DBUS_TYPE_INVALID))
1058                         return bus_send_error_reply(m, message, &error, -EINVAL);
1059
1060                 if (!(reply = dbus_message_new_method_return(message)))
1061                         goto oom;
1062
1063                 dbus_message_iter_init_append(reply, &iter);
1064
1065                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
1066                         goto oom;
1067
1068                 for (p = properties; p->property; p++) {
1069                         if (!streq(p->interface, interface))
1070                                 continue;
1071
1072                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
1073                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
1074                             !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
1075                                 goto oom;
1076
1077                         if ((r = p->append(m, &sub3, p->property, (void*) p->data)) < 0) {
1078
1079                                 if (r == -ENOMEM)
1080                                         goto oom;
1081
1082                                 dbus_message_unref(reply);
1083                                 return bus_send_error_reply(m, message, NULL, r);
1084                         }
1085
1086                         if (!dbus_message_iter_close_container(&sub2, &sub3) ||
1087                             !dbus_message_iter_close_container(&sub, &sub2))
1088                                 goto oom;
1089
1090                         any = true;
1091                 }
1092
1093                 if (!dbus_message_iter_close_container(&iter, &sub))
1094                         goto oom;
1095         }
1096
1097         if (reply) {
1098                 if (!dbus_connection_send(m->api_bus, reply, NULL))
1099                         goto oom;
1100
1101                 dbus_message_unref(reply);
1102                 return DBUS_HANDLER_RESULT_HANDLED;
1103         }
1104
1105         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1106
1107 oom:
1108         if (reply)
1109                 dbus_message_unref(reply);
1110
1111         dbus_error_free(&error);
1112
1113         return DBUS_HANDLER_RESULT_NEED_MEMORY;
1114 }
1115
1116 static const char *error_to_dbus(int error) {
1117
1118         switch(error) {
1119
1120         case -EINVAL:
1121                 return DBUS_ERROR_INVALID_ARGS;
1122
1123         case -ENOMEM:
1124                 return DBUS_ERROR_NO_MEMORY;
1125
1126         case -EPERM:
1127         case -EACCES:
1128                 return DBUS_ERROR_ACCESS_DENIED;
1129
1130         case -ESRCH:
1131                 return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
1132
1133         case -ENOENT:
1134                 return DBUS_ERROR_FILE_NOT_FOUND;
1135
1136         case -EEXIST:
1137                 return DBUS_ERROR_FILE_EXISTS;
1138
1139         case -ETIMEDOUT:
1140                 return DBUS_ERROR_TIMEOUT;
1141
1142         case -EIO:
1143                 return DBUS_ERROR_IO_ERROR;
1144
1145         case -ENETRESET:
1146         case -ECONNABORTED:
1147         case -ECONNRESET:
1148                 return DBUS_ERROR_DISCONNECTED;
1149         }
1150
1151         return DBUS_ERROR_FAILED;
1152 }
1153
1154 DBusHandlerResult bus_send_error_reply(Manager *m, DBusMessage *message, DBusError *bus_error, int error) {
1155         DBusMessage *reply = NULL;
1156         const char *name, *text;
1157
1158         if (bus_error && dbus_error_is_set(bus_error)) {
1159                 name = bus_error->name;
1160                 text = bus_error->message;
1161         } else {
1162                 name = error_to_dbus(error);
1163                 text = strerror(-error);
1164         }
1165
1166         if (!(reply = dbus_message_new_error(message, name, text)))
1167                 goto oom;
1168
1169         if (!dbus_connection_send(m->api_bus, reply, NULL))
1170                 goto oom;
1171
1172         dbus_message_unref(reply);
1173
1174         if (bus_error)
1175                 dbus_error_free(bus_error);
1176
1177         return DBUS_HANDLER_RESULT_HANDLED;
1178
1179 oom:
1180         if (reply)
1181                 dbus_message_unref(reply);
1182
1183         if (bus_error)
1184                 dbus_error_free(bus_error);
1185
1186         return DBUS_HANDLER_RESULT_NEED_MEMORY;
1187 }
1188
1189 int bus_property_append_string(Manager *m, DBusMessageIter *i, const char *property, void *data) {
1190         const char *t = data;
1191
1192         assert(m);
1193         assert(i);
1194         assert(property);
1195
1196         if (!t)
1197                 t = "";
1198
1199         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
1200                 return -ENOMEM;
1201
1202         return 0;
1203 }
1204
1205 int bus_property_append_strv(Manager *m, DBusMessageIter *i, const char *property, void *data) {
1206         DBusMessageIter sub;
1207         char **t = data;
1208
1209         assert(m);
1210         assert(i);
1211         assert(property);
1212
1213         if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
1214                 return -ENOMEM;
1215
1216         STRV_FOREACH(t, t)
1217                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t))
1218                         return -ENOMEM;
1219
1220         if (!dbus_message_iter_close_container(i, &sub))
1221                 return -ENOMEM;
1222
1223         return 0;
1224 }
1225
1226 int bus_property_append_bool(Manager *m, DBusMessageIter *i, const char *property, void *data) {
1227         bool *b = data;
1228         dbus_bool_t db;
1229
1230         assert(m);
1231         assert(i);
1232         assert(property);
1233         assert(b);
1234
1235         db = *b;
1236
1237         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
1238                 return -ENOMEM;
1239
1240         return 0;
1241 }
1242
1243 int bus_property_append_uint64(Manager *m, DBusMessageIter *i, const char *property, void *data) {
1244         assert(m);
1245         assert(i);
1246         assert(property);
1247         assert(data);
1248
1249         /* Let's ensure that pid_t is actually 64bit, and hence this
1250          * function can be used for usec_t */
1251         assert_cc(sizeof(uint64_t) == sizeof(usec_t));
1252
1253         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
1254                 return -ENOMEM;
1255
1256         return 0;
1257 }
1258
1259 int bus_property_append_uint32(Manager *m, DBusMessageIter *i, const char *property, void *data) {
1260         assert(m);
1261         assert(i);
1262         assert(property);
1263         assert(data);
1264
1265         /* Let's ensure that pid_t and mode_t is actually 32bit, and
1266          * hence this function can be used for pid_t/mode_t */
1267         assert_cc(sizeof(uint32_t) == sizeof(pid_t));
1268         assert_cc(sizeof(uint32_t) == sizeof(mode_t));
1269         assert_cc(sizeof(uint32_t) == sizeof(unsigned));
1270
1271         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
1272                 return -ENOMEM;
1273
1274         return 0;
1275 }
1276
1277 int bus_property_append_int32(Manager *m, DBusMessageIter *i, const char *property, void *data) {
1278         assert(m);
1279         assert(i);
1280         assert(property);
1281         assert(data);
1282
1283         assert_cc(sizeof(int32_t) == sizeof(int));
1284
1285         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
1286                 return -ENOMEM;
1287
1288         return 0;
1289 }
1290
1291 int bus_parse_strv(DBusMessage *m, char ***_l) {
1292         DBusMessageIter iter, sub;
1293         unsigned n = 0, i = 0;
1294         char **l;
1295
1296         assert(m);
1297         assert(_l);
1298
1299         if (!dbus_message_iter_init(m, &iter) ||
1300             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1301             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
1302             return -EINVAL;
1303
1304         dbus_message_iter_recurse(&iter, &sub);
1305
1306         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1307                 n++;
1308                 dbus_message_iter_next(&sub);
1309         }
1310
1311         if (!(l = new(char*, n+1)))
1312                 return -ENOMEM;
1313
1314         assert_se(dbus_message_iter_init(m, &iter));
1315         dbus_message_iter_recurse(&iter, &sub);
1316
1317         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1318                 const char *s;
1319
1320                 assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
1321                 dbus_message_iter_get_basic(&sub, &s);
1322
1323                 if (!(l[i++] = strdup(s))) {
1324                         strv_free(l);
1325                         return -ENOMEM;
1326                 }
1327
1328                 dbus_message_iter_next(&sub);
1329         }
1330
1331         assert(i == n);
1332         l[i] = NULL;
1333
1334         if (_l)
1335                 *_l = l;
1336
1337         return 0;
1338 }