chiark / gitweb /
dbus: Do send out "replies" to signals
[elogind.git] / src / shared / dbus-common.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
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 Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 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   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <assert.h>
23 #include <sys/socket.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <dbus/dbus.h>
29 #include <string.h>
30 #include <sys/epoll.h>
31
32 #include "log.h"
33 #include "dbus-common.h"
34 #include "util.h"
35 #include "missing.h"
36 #include "def.h"
37 #include "strv.h"
38
39 int bus_check_peercred(DBusConnection *c) {
40         int fd;
41         struct ucred ucred;
42         socklen_t l;
43
44         assert(c);
45
46         assert_se(dbus_connection_get_unix_fd(c, &fd));
47
48         l = sizeof(struct ucred);
49         if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) {
50                 log_error("SO_PEERCRED failed: %m");
51                 return -errno;
52         }
53
54         if (l != sizeof(struct ucred)) {
55                 log_error("SO_PEERCRED returned wrong size.");
56                 return -E2BIG;
57         }
58
59         if (ucred.uid != 0 && ucred.uid != geteuid())
60                 return -EPERM;
61
62         return 1;
63 }
64
65 static int sync_auth(DBusConnection *bus, DBusError *error) {
66         usec_t begin, tstamp;
67
68         assert(bus);
69
70         /* This complexity should probably move into D-Bus itself:
71          *
72          * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
73
74         begin = tstamp = now(CLOCK_MONOTONIC);
75         for (;;) {
76
77                 if (tstamp > begin + DEFAULT_TIMEOUT_USEC)
78                         break;
79
80                 if (dbus_connection_get_is_authenticated(bus))
81                         break;
82
83                 if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
84                         break;
85
86                 tstamp = now(CLOCK_MONOTONIC);
87         }
88
89         if (!dbus_connection_get_is_connected(bus)) {
90                 dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication.");
91                 return -ECONNREFUSED;
92         }
93
94         if (!dbus_connection_get_is_authenticated(bus)) {
95                 dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time.");
96                 return -EACCES;
97         }
98
99         return 0;
100 }
101
102 int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError *error) {
103         DBusConnection *bus = NULL;
104         int r;
105         bool private = true;
106
107         assert(_bus);
108
109         if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) {
110                 /* If we are root, then let's talk directly to the
111                  * system instance, instead of going via the bus */
112
113                 bus = dbus_connection_open_private("unix:path=/run/systemd/private", error);
114                 if (!bus)
115                         return -EIO;
116
117         } else {
118                 if (t == DBUS_BUS_SESSION) {
119                         const char *e;
120
121                         /* If we are supposed to talk to the instance,
122                          * try via XDG_RUNTIME_DIR first, then
123                          * fallback to normal bus access */
124
125                         e = secure_getenv("XDG_RUNTIME_DIR");
126                         if (e) {
127                                 char *p;
128
129                                 if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
130                                         return -ENOMEM;
131
132                                 bus = dbus_connection_open_private(p, NULL);
133                                 free(p);
134                         }
135                 }
136
137                 if (!bus) {
138                         bus = dbus_bus_get_private(t, error);
139                         if (!bus)
140                                 return -EIO;
141
142                         private = false;
143                 }
144         }
145
146         dbus_connection_set_exit_on_disconnect(bus, FALSE);
147
148         if (private) {
149                 if (bus_check_peercred(bus) < 0) {
150                         dbus_connection_close(bus);
151                         dbus_connection_unref(bus);
152
153                         dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
154                         return -EACCES;
155                 }
156         }
157
158         r = sync_auth(bus, error);
159         if (r < 0) {
160                 dbus_connection_close(bus);
161                 dbus_connection_unref(bus);
162                 return r;
163         }
164
165         if (_private)
166                 *_private = private;
167
168         *_bus = bus;
169         return 0;
170 }
171
172 int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) {
173         DBusConnection *bus;
174         char *p = NULL;
175         int r;
176
177         assert(_bus);
178         assert(user || host);
179
180         if (user && host)
181                 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host);
182         else if (user)
183                 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@localhost,argv3=systemd-stdio-bridge", user);
184         else if (host)
185                 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host);
186
187         if (!p) {
188                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
189                 return -ENOMEM;
190         }
191
192         bus = dbus_connection_open_private(p, error);
193         free(p);
194
195         if (!bus)
196                 return -EIO;
197
198         dbus_connection_set_exit_on_disconnect(bus, FALSE);
199
200         if ((r = sync_auth(bus, error)) < 0) {
201                 dbus_connection_close(bus);
202                 dbus_connection_unref(bus);
203                 return r;
204         }
205
206         if (!dbus_bus_register(bus, error)) {
207                 dbus_connection_close(bus);
208                 dbus_connection_unref(bus);
209                 return r;
210         }
211
212         *_bus = bus;
213         return 0;
214 }
215
216 int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) {
217         DBusConnection *bus;
218         int r;
219
220         assert(_bus);
221
222         /* Don't bother with PolicyKit if we are root */
223         if (geteuid() == 0)
224                 return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error);
225
226         bus = dbus_connection_open_private("unixexec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error);
227         if (!bus)
228                 return -EIO;
229
230         dbus_connection_set_exit_on_disconnect(bus, FALSE);
231
232         r = sync_auth(bus, error);
233         if (r < 0) {
234                 dbus_connection_close(bus);
235                 dbus_connection_unref(bus);
236                 return r;
237         }
238
239         if (!dbus_bus_register(bus, error)) {
240                 dbus_connection_close(bus);
241                 dbus_connection_unref(bus);
242                 return r;
243         }
244
245         *_bus = bus;
246         return 0;
247 }
248
249 const char *bus_error_message(const DBusError *error) {
250         if (!error)
251                 return NULL;
252
253         /* Sometimes the D-Bus server is a little bit too verbose with
254          * its error messages, so let's override them here */
255         if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED))
256                 return "Access denied";
257
258         return error->message;
259 }
260
261 const char *bus_error_message_or_strerror(const DBusError *error, int err) {
262
263         if (error && dbus_error_is_set(error))
264                 return bus_error_message(error);
265
266         return strerror(err);
267 }
268
269 DBusHandlerResult bus_default_message_handler(
270                 DBusConnection *c,
271                 DBusMessage *message,
272                 const char *introspection,
273                 const char *interfaces,
274                 const BusBoundProperties *bound_properties) {
275
276         DBusError error;
277         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
278         int r;
279
280         assert(c);
281         assert(message);
282
283         dbus_error_init(&error);
284
285         if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
286
287                 reply = dbus_message_new_method_return(message);
288                 if (!reply)
289                         goto oom;
290
291                 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
292                         goto oom;
293
294         } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) {
295                 const char *interface, *property;
296                 const BusBoundProperties *bp;
297                 const BusProperty *p;
298                 void *data;
299                 DBusMessageIter iter, sub;
300
301                 if (!dbus_message_get_args(
302                             message,
303                             &error,
304                             DBUS_TYPE_STRING, &interface,
305                             DBUS_TYPE_STRING, &property,
306                             DBUS_TYPE_INVALID))
307                         return bus_send_error_reply(c, message, &error, -EINVAL);
308
309                 for (bp = bound_properties; bp->interface; bp++) {
310                         if (!streq(bp->interface, interface))
311                                 continue;
312
313                         for (p = bp->properties; p->property; p++)
314                                 if (streq(p->property, property))
315                                         goto get_prop;
316                 }
317
318                 /* no match */
319                 if (!nulstr_contains(interfaces, interface))
320                         dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
321                 else
322                         dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
323
324                 return bus_send_error_reply(c, message, &error, -EINVAL);
325
326 get_prop:
327                 reply = dbus_message_new_method_return(message);
328                 if (!reply)
329                         goto oom;
330
331                 dbus_message_iter_init_append(reply, &iter);
332
333                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
334                         goto oom;
335
336                 data = (char*)bp->base + p->offset;
337                 if (p->indirect)
338                         data = *(void**)data;
339
340                 r = p->append(&sub, property, data);
341                 if (r == -ENOMEM)
342                         goto oom;
343                 if (r < 0)
344                         return bus_send_error_reply(c, message, NULL, r);
345
346                 if (!dbus_message_iter_close_container(&iter, &sub))
347                         goto oom;
348
349         } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && bound_properties) {
350                 const char *interface;
351                 const BusBoundProperties *bp;
352                 const BusProperty *p;
353                 DBusMessageIter iter, sub, sub2, sub3;
354
355                 if (!dbus_message_get_args(
356                             message,
357                             &error,
358                             DBUS_TYPE_STRING, &interface,
359                             DBUS_TYPE_INVALID))
360                         return bus_send_error_reply(c, message, &error, -EINVAL);
361
362                 if (interface[0] && !nulstr_contains(interfaces, interface)) {
363                         dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
364                         return bus_send_error_reply(c, message, &error, -EINVAL);
365                 }
366
367                 reply = dbus_message_new_method_return(message);
368                 if (!reply)
369                         goto oom;
370
371                 dbus_message_iter_init_append(reply, &iter);
372
373                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
374                         goto oom;
375
376                 for (bp = bound_properties; bp->interface; bp++) {
377                         if (interface[0] && !streq(bp->interface, interface))
378                                 continue;
379
380                         for (p = bp->properties; p->property; p++) {
381                                 void *data;
382
383                                 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
384                                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
385                                     !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
386                                         goto oom;
387
388                                 data = (char*)bp->base + p->offset;
389                                 if (p->indirect)
390                                         data = *(void**)data;
391                                 r = p->append(&sub3, p->property, data);
392                                 if (r == -ENOMEM)
393                                         goto oom;
394                                 if (r < 0)
395                                         return bus_send_error_reply(c, message, NULL, r);
396
397                                 if (!dbus_message_iter_close_container(&sub2, &sub3) ||
398                                     !dbus_message_iter_close_container(&sub, &sub2))
399                                         goto oom;
400                         }
401                 }
402
403                 if (!dbus_message_iter_close_container(&iter, &sub))
404                         goto oom;
405
406         } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && bound_properties) {
407                 const char *interface, *property;
408                 DBusMessageIter iter;
409                 const BusBoundProperties *bp;
410                 const BusProperty *p;
411                 DBusMessageIter sub;
412                 char *sig;
413                 void *data;
414                 DBusMessage *changed;
415
416                 if (!dbus_message_iter_init(message, &iter) ||
417                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
418                         return bus_send_error_reply(c, message, NULL, -EINVAL);
419
420                 dbus_message_iter_get_basic(&iter, &interface);
421
422                 if (!dbus_message_iter_next(&iter) ||
423                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
424                         return bus_send_error_reply(c, message, NULL, -EINVAL);
425
426                 dbus_message_iter_get_basic(&iter, &property);
427
428                 if (!dbus_message_iter_next(&iter) ||
429                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT ||
430                     dbus_message_iter_has_next(&iter))
431                         return bus_send_error_reply(c, message, NULL, -EINVAL);
432
433                 for (bp = bound_properties; bp->interface; bp++) {
434                         if (!streq(bp->interface, interface))
435                                 continue;
436
437                         for (p = bp->properties; p->property; p++)
438                                 if (streq(p->property, property))
439                                         goto set_prop;
440                 }
441
442                 /* no match */
443                 if (!nulstr_contains(interfaces, interface))
444                         dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
445                 else
446                         dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
447
448                 return bus_send_error_reply(c, message, &error, -EINVAL);
449
450 set_prop:
451                 if (!p->set) {
452                         dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
453                         return bus_send_error_reply(c, message, &error, -EINVAL);
454                 }
455
456                 dbus_message_iter_recurse(&iter, &sub);
457
458                 sig = dbus_message_iter_get_signature(&sub);
459                 if (!sig)
460                         goto oom;
461
462                 if (!streq(sig, p->signature)) {
463                         dbus_free(sig);
464                         return bus_send_error_reply(c, message, NULL, -EINVAL);
465                 }
466                 dbus_free(sig);
467
468                 data = (uint8_t*) bp->base + p->offset;
469                 if (p->indirect)
470                         data = *(void**)data;
471
472                 r = p->set(&sub, property, data);
473                 if (r == -ENOMEM)
474                         goto oom;
475                 else if (r < 0)
476                         return bus_send_error_reply(c, message, NULL, r);
477
478                 reply = dbus_message_new_method_return(message);
479                 if (!reply)
480                         goto oom;
481
482                 /* Send out a signal about this, but it doesn't really
483                  * matter if this fails, so eat all errors */
484                 changed = bus_properties_changed_one_new(
485                                 dbus_message_get_path(message),
486                                 interface,
487                                 property);
488                 if (changed) {
489                         dbus_connection_send(c, changed, NULL);
490                         dbus_message_unref(changed);
491                 }
492
493
494         } else {
495                 const char *interface = dbus_message_get_interface(message);
496
497                 if (!interface || !nulstr_contains(interfaces, interface)) {
498                         dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
499                         return bus_send_error_reply(c, message, &error, -EINVAL);
500                 }
501         }
502
503         if (reply) {
504                 if (!bus_maybe_send_reply(c, message, reply))
505                         goto oom;
506
507                 return DBUS_HANDLER_RESULT_HANDLED;
508         }
509
510         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
511
512 oom:
513         dbus_error_free(&error);
514
515         return DBUS_HANDLER_RESULT_NEED_MEMORY;
516 }
517
518 int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) {
519         const char *t = data;
520
521         assert(i);
522         assert(property);
523
524         if (!t)
525                 t = "";
526
527         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
528                 return -ENOMEM;
529
530         return 0;
531 }
532
533 int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
534         char **t = data;
535
536         assert(i);
537         assert(property);
538
539         return bus_append_strv_iter(i, t);
540 }
541
542 int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
543         bool *b = data;
544         dbus_bool_t db;
545
546         assert(i);
547         assert(property);
548         assert(b);
549
550         db = *b;
551
552         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
553                 return -ENOMEM;
554
555         return 0;
556 }
557
558 int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) {
559         int *b = data;
560         dbus_bool_t db;
561
562         assert(i);
563         assert(property);
564         assert(b);
565
566         db = *b > 0;
567
568         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
569                 return -ENOMEM;
570
571         return 0;
572 }
573
574 int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) {
575         assert(i);
576         assert(property);
577         assert(data);
578
579         /* Let's ensure that usec_t is actually 64bit, and hence this
580          * function can be used for usec_t */
581         assert_cc(sizeof(uint64_t) == sizeof(usec_t));
582
583         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
584                 return -ENOMEM;
585
586         return 0;
587 }
588
589 int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) {
590         assert(i);
591         assert(property);
592         assert(data);
593
594         /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually
595          * 32bit, and hence this function can be used for
596          * pid_t/mode_t/uid_t/gid_t */
597         assert_cc(sizeof(uint32_t) == sizeof(pid_t));
598         assert_cc(sizeof(uint32_t) == sizeof(mode_t));
599         assert_cc(sizeof(uint32_t) == sizeof(unsigned));
600         assert_cc(sizeof(uint32_t) == sizeof(uid_t));
601         assert_cc(sizeof(uint32_t) == sizeof(gid_t));
602
603         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
604                 return -ENOMEM;
605
606         return 0;
607 }
608
609 int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) {
610         assert(i);
611         assert(property);
612         assert(data);
613
614         assert_cc(sizeof(int32_t) == sizeof(int));
615
616         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
617                 return -ENOMEM;
618
619         return 0;
620 }
621
622 int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) {
623         uint64_t u;
624
625         assert(i);
626         assert(property);
627         assert(data);
628
629         u = (uint64_t) *(size_t*) data;
630
631         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
632                 return -ENOMEM;
633
634         return 0;
635 }
636
637 int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) {
638         uint64_t u;
639
640         assert(i);
641         assert(property);
642         assert(data);
643
644         u = (uint64_t) *(unsigned long*) data;
645
646         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
647                 return -ENOMEM;
648
649         return 0;
650 }
651
652 int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
653         int64_t l;
654
655         assert(i);
656         assert(property);
657         assert(data);
658
659         l = (int64_t) *(long*) data;
660
661         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l))
662                 return -ENOMEM;
663
664         return 0;
665 }
666
667 int bus_property_set_uint64(DBusMessageIter *i, const char *property, void *data) {
668         uint64_t *t = data;
669
670         assert(i);
671         assert(property);
672
673         dbus_message_iter_get_basic(i, t);
674         return 0;
675 }
676
677 const char *bus_errno_to_dbus(int error) {
678
679         switch(error) {
680
681         case -EINVAL:
682                 return DBUS_ERROR_INVALID_ARGS;
683
684         case -ENOMEM:
685                 return DBUS_ERROR_NO_MEMORY;
686
687         case -EPERM:
688         case -EACCES:
689                 return DBUS_ERROR_ACCESS_DENIED;
690
691         case -ESRCH:
692                 return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
693
694         case -ENOENT:
695                 return DBUS_ERROR_FILE_NOT_FOUND;
696
697         case -EEXIST:
698                 return DBUS_ERROR_FILE_EXISTS;
699
700         case -ETIMEDOUT:
701         case -ETIME:
702                 return DBUS_ERROR_TIMEOUT;
703
704         case -EIO:
705                 return DBUS_ERROR_IO_ERROR;
706
707         case -ENETRESET:
708         case -ECONNABORTED:
709         case -ECONNRESET:
710                 return DBUS_ERROR_DISCONNECTED;
711         }
712
713         return DBUS_ERROR_FAILED;
714 }
715
716 dbus_bool_t bus_maybe_send_reply (DBusConnection   *c,
717                                   DBusMessage *message,
718                                   DBusMessage *reply)
719 {
720         /* Some parts of systemd "reply" to signals, which of course
721          * have the no-reply flag set.  We will be defensive here and
722          * still send out a reply if we're passed a signal.
723          */
724         if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL &&
725             dbus_message_get_no_reply(message))
726                 return TRUE;
727         return dbus_connection_send(c, reply, NULL);
728 }
729
730 DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
731         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
732         const char *name, *text;
733
734         if (berror && dbus_error_is_set(berror)) {
735                 name = berror->name;
736                 text = berror->message;
737         } else {
738                 name = bus_errno_to_dbus(error);
739                 text = strerror(-error);
740         }
741
742         reply = dbus_message_new_error(message, name, text);
743         if (!reply)
744                 goto oom;
745
746         if (!bus_maybe_send_reply(c, message, reply))
747                 goto oom;
748
749         if (berror)
750                 dbus_error_free(berror);
751
752         return DBUS_HANDLER_RESULT_HANDLED;
753
754 oom:
755         if (reply)
756                 dbus_message_unref(reply);
757
758         if (berror)
759                 dbus_error_free(berror);
760
761         return DBUS_HANDLER_RESULT_NEED_MEMORY;
762 }
763
764 DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
765         DBusMessage *m;
766         DBusMessageIter iter, sub;
767         const char *i;
768
769         assert(interface);
770         assert(properties);
771
772         m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
773         if (!m)
774                 goto oom;
775
776         dbus_message_iter_init_append(m, &iter);
777
778         /* We won't send any property values, since they might be
779          * large and sometimes not cheap to generated */
780
781         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
782             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
783             !dbus_message_iter_close_container(&iter, &sub) ||
784             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
785                 goto oom;
786
787         NULSTR_FOREACH(i, properties)
788                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
789                         goto oom;
790
791         if (!dbus_message_iter_close_container(&iter, &sub))
792                 goto oom;
793
794         return m;
795
796 oom:
797         if (m)
798                 dbus_message_unref(m);
799
800         return NULL;
801 }
802
803 DBusMessage* bus_properties_changed_one_new(const char *path, const char *interface, const char *property) {
804         DBusMessage *m;
805         DBusMessageIter iter, sub;
806
807         assert(interface);
808         assert(property);
809
810         m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
811         if (!m)
812                 goto oom;
813
814         dbus_message_iter_init_append(m, &iter);
815
816         /* We won't send any property values, since they might be
817          * large and sometimes not cheap to generated */
818
819         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
820             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
821             !dbus_message_iter_close_container(&iter, &sub) ||
822             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
823                 goto oom;
824
825         if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property))
826                 goto oom;
827
828         if (!dbus_message_iter_close_container(&iter, &sub))
829                 goto oom;
830
831         return m;
832
833 oom:
834         if (m)
835                 dbus_message_unref(m);
836
837         return NULL;
838 }
839
840 uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
841         unsigned flags;
842         uint32_t events = 0;
843
844         assert(bus_watch);
845
846         /* no watch flags for disabled watches */
847         if (!dbus_watch_get_enabled(bus_watch))
848                 return 0;
849
850         flags = dbus_watch_get_flags(bus_watch);
851
852         if (flags & DBUS_WATCH_READABLE)
853                 events |= EPOLLIN;
854         if (flags & DBUS_WATCH_WRITABLE)
855                 events |= EPOLLOUT;
856
857         return events | EPOLLHUP | EPOLLERR;
858 }
859
860 unsigned bus_events_to_flags(uint32_t events) {
861         unsigned flags = 0;
862
863         if (events & EPOLLIN)
864                 flags |= DBUS_WATCH_READABLE;
865         if (events & EPOLLOUT)
866                 flags |= DBUS_WATCH_WRITABLE;
867         if (events & EPOLLHUP)
868                 flags |= DBUS_WATCH_HANGUP;
869         if (events & EPOLLERR)
870                 flags |= DBUS_WATCH_ERROR;
871
872         return flags;
873 }
874
875 int bus_parse_strv(DBusMessage *m, char ***_l) {
876         DBusMessageIter iter;
877
878         assert(m);
879         assert(_l);
880
881         if (!dbus_message_iter_init(m, &iter))
882                 return -EINVAL;
883
884         return bus_parse_strv_iter(&iter, _l);
885 }
886
887 int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
888         DBusMessageIter sub;
889         unsigned n = 0, i = 0;
890         char **l;
891
892         assert(iter);
893         assert(_l);
894
895         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
896             dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
897             return -EINVAL;
898
899         dbus_message_iter_recurse(iter, &sub);
900
901         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
902                 n++;
903                 dbus_message_iter_next(&sub);
904         }
905
906         l = new(char*, n+1);
907         if (!l)
908                 return -ENOMEM;
909
910         dbus_message_iter_recurse(iter, &sub);
911
912         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
913                 const char *s;
914
915                 assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
916                 dbus_message_iter_get_basic(&sub, &s);
917
918                 if (!(l[i++] = strdup(s))) {
919                         strv_free(l);
920                         return -ENOMEM;
921                 }
922
923                 dbus_message_iter_next(&sub);
924         }
925
926         assert(i == n);
927         l[i] = NULL;
928
929         if (_l)
930                 *_l = l;
931
932         return 0;
933 }
934
935 int bus_parse_strv_pairs_iter(DBusMessageIter *iter, char ***_l) {
936         DBusMessageIter sub, sub2;
937         unsigned n = 0, i = 0;
938         char **l;
939
940         assert(iter);
941         assert(_l);
942
943         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
944             dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRUCT)
945             return -EINVAL;
946
947         dbus_message_iter_recurse(iter, &sub);
948
949         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
950                 n++;
951                 dbus_message_iter_next(&sub);
952         }
953
954         l = new(char*, n*2+1);
955         if (!l)
956                 return -ENOMEM;
957
958         dbus_message_iter_recurse(iter, &sub);
959
960         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
961                 const char *a, *b;
962
963                 assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
964
965                 dbus_message_iter_recurse(&sub, &sub2);
966
967                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &a, true) < 0 ||
968                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &b, false) < 0)
969                         return -EINVAL;
970
971                 l[i] = strdup(a);
972                 if (!l[i]) {
973                         strv_free(l);
974                         return -ENOMEM;
975                 }
976
977                 l[++i] = strdup(b);
978                 if (!l[i]) {
979                         strv_free(l);
980                         return -ENOMEM;
981                 }
982
983                 i++;
984                 dbus_message_iter_next(&sub);
985         }
986
987         assert(i == n*2);
988         l[i] = NULL;
989
990         if (_l)
991                 *_l = l;
992
993         return 0;
994 }
995
996 int bus_parse_unit_info(DBusMessageIter *iter, struct unit_info *u) {
997         DBusMessageIter sub;
998
999         assert(iter);
1000         assert(u);
1001
1002         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT)
1003                 return -EINVAL;
1004
1005         dbus_message_iter_recurse(iter, &sub);
1006
1007         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->id, true) < 0 ||
1008             bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->description, true) < 0 ||
1009             bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
1010             bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
1011             bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
1012             bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->following, true) < 0 ||
1013             bus_iter_get_basic_and_next(&sub, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
1014             bus_iter_get_basic_and_next(&sub, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
1015             bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
1016             bus_iter_get_basic_and_next(&sub, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
1017                 log_error("Failed to parse reply.");
1018                 return -EIO;
1019         }
1020
1021         return 0;
1022 }
1023
1024 int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
1025         DBusMessageIter sub;
1026
1027         assert(iter);
1028
1029         if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
1030                 return -ENOMEM;
1031
1032         STRV_FOREACH(l, l)
1033                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
1034                         return -ENOMEM;
1035
1036         if (!dbus_message_iter_close_container(iter, &sub))
1037                 return -ENOMEM;
1038
1039         return 0;
1040 }
1041
1042 int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
1043
1044         assert(iter);
1045         assert(data);
1046
1047         if (dbus_message_iter_get_arg_type(iter) != type)
1048                 return -EIO;
1049
1050         dbus_message_iter_get_basic(iter, data);
1051
1052         if (!dbus_message_iter_next(iter) != !next)
1053                 return -EIO;
1054
1055         return 0;
1056 }
1057
1058 int generic_print_property(const char *name, DBusMessageIter *iter, bool all) {
1059         assert(name);
1060         assert(iter);
1061
1062         switch (dbus_message_iter_get_arg_type(iter)) {
1063
1064         case DBUS_TYPE_STRING: {
1065                 const char *s;
1066                 dbus_message_iter_get_basic(iter, &s);
1067
1068                 if (all || !isempty(s))
1069                         printf("%s=%s\n", name, s);
1070
1071                 return 1;
1072         }
1073
1074         case DBUS_TYPE_BOOLEAN: {
1075                 dbus_bool_t b;
1076
1077                 dbus_message_iter_get_basic(iter, &b);
1078                 printf("%s=%s\n", name, yes_no(b));
1079
1080                 return 1;
1081         }
1082
1083         case DBUS_TYPE_UINT64: {
1084                 uint64_t u;
1085                 dbus_message_iter_get_basic(iter, &u);
1086
1087                 /* Yes, heuristics! But we can change this check
1088                  * should it turn out to not be sufficient */
1089
1090                 if (endswith(name, "Timestamp")) {
1091                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
1092
1093                         t = format_timestamp(timestamp, sizeof(timestamp), u);
1094                         if (t || all)
1095                                 printf("%s=%s\n", name, strempty(t));
1096
1097                 } else if (strstr(name, "USec")) {
1098                         char timespan[FORMAT_TIMESPAN_MAX];
1099
1100                         printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
1101                 } else
1102                         printf("%s=%llu\n", name, (unsigned long long) u);
1103
1104                 return 1;
1105         }
1106
1107         case DBUS_TYPE_UINT32: {
1108                 uint32_t u;
1109                 dbus_message_iter_get_basic(iter, &u);
1110
1111                 if (strstr(name, "UMask") || strstr(name, "Mode"))
1112                         printf("%s=%04o\n", name, u);
1113                 else
1114                         printf("%s=%u\n", name, (unsigned) u);
1115
1116                 return 1;
1117         }
1118
1119         case DBUS_TYPE_INT32: {
1120                 int32_t i;
1121                 dbus_message_iter_get_basic(iter, &i);
1122
1123                 printf("%s=%i\n", name, (int) i);
1124                 return 1;
1125         }
1126
1127         case DBUS_TYPE_DOUBLE: {
1128                 double d;
1129                 dbus_message_iter_get_basic(iter, &d);
1130
1131                 printf("%s=%g\n", name, d);
1132                 return 1;
1133         }
1134
1135         case DBUS_TYPE_ARRAY:
1136
1137                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
1138                         DBusMessageIter sub;
1139                         bool space = false;
1140
1141                         dbus_message_iter_recurse(iter, &sub);
1142                         if (all ||
1143                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1144                                 printf("%s=", name);
1145
1146                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1147                                         const char *s;
1148
1149                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
1150                                         dbus_message_iter_get_basic(&sub, &s);
1151                                         printf("%s%s", space ? " " : "", s);
1152
1153                                         space = true;
1154                                         dbus_message_iter_next(&sub);
1155                                 }
1156
1157                                 puts("");
1158                         }
1159
1160                         return 1;
1161
1162                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
1163                         DBusMessageIter sub;
1164
1165                         dbus_message_iter_recurse(iter, &sub);
1166                         if (all ||
1167                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1168                                 printf("%s=", name);
1169
1170                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1171                                         uint8_t u;
1172
1173                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1174                                         dbus_message_iter_get_basic(&sub, &u);
1175                                         printf("%02x", u);
1176
1177                                         dbus_message_iter_next(&sub);
1178                                 }
1179
1180                                 puts("");
1181                         }
1182
1183                         return 1;
1184
1185                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_UINT32) {
1186                         DBusMessageIter sub;
1187
1188                         dbus_message_iter_recurse(iter, &sub);
1189                         if (all ||
1190                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1191                                 printf("%s=", name);
1192
1193                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1194                                         uint32_t u;
1195
1196                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32);
1197                                         dbus_message_iter_get_basic(&sub, &u);
1198                                         printf("%08x", u);
1199
1200                                         dbus_message_iter_next(&sub);
1201                                 }
1202
1203                                 puts("");
1204                         }
1205
1206                         return 1;
1207                 }
1208
1209                 break;
1210         }
1211
1212         return 0;
1213 }
1214
1215 static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
1216         DBusMessage *reply;
1217         DBusConnection *bus = userdata;
1218
1219         assert_se(reply = dbus_pending_call_steal_reply(pending));
1220         dbus_message_unref(reply);
1221
1222         dbus_connection_close(bus);
1223 }
1224
1225 void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
1226         _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
1227         DBusPendingCall *pending = NULL;
1228
1229         assert(bus);
1230
1231         /* We unregister the name here, but we continue to process
1232          * requests, until we get the response for it, so that all
1233          * requests are guaranteed to be processed. */
1234
1235         m = dbus_message_new_method_call(
1236                         DBUS_SERVICE_DBUS,
1237                         DBUS_PATH_DBUS,
1238                         DBUS_INTERFACE_DBUS,
1239                         "ReleaseName");
1240         if (!m)
1241                 goto oom;
1242
1243         if (!dbus_message_append_args(
1244                             m,
1245                             DBUS_TYPE_STRING,
1246                             &name,
1247                             DBUS_TYPE_INVALID))
1248                 goto oom;
1249
1250         if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
1251                 goto oom;
1252
1253         if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
1254                 goto oom;
1255
1256         dbus_pending_call_unref(pending);
1257
1258         return;
1259
1260 oom:
1261         log_oom();
1262
1263         if (pending) {
1264                 dbus_pending_call_cancel(pending);
1265                 dbus_pending_call_unref(pending);
1266         }
1267 }
1268
1269 DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
1270         usec_t *remain_until = userdata;
1271
1272         assert(bus);
1273         assert(m);
1274         assert(remain_until);
1275
1276         /* Every time we get a new message we reset out timeout */
1277         *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
1278
1279         if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
1280                 dbus_connection_close(bus);
1281
1282         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1283 }
1284
1285 /* This mimics dbus_bus_get_unix_user() */
1286 pid_t bus_get_unix_process_id(
1287                 DBusConnection *connection,
1288                 const char *name,
1289                 DBusError *error) {
1290
1291         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
1292         uint32_t pid = 0;
1293
1294         m = dbus_message_new_method_call(
1295                         DBUS_SERVICE_DBUS,
1296                         DBUS_PATH_DBUS,
1297                         DBUS_INTERFACE_DBUS,
1298                         "GetConnectionUnixProcessID");
1299         if (!m) {
1300                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
1301                 return 0;
1302         }
1303
1304         if (!dbus_message_append_args(
1305                             m,
1306                             DBUS_TYPE_STRING, &name,
1307                             DBUS_TYPE_INVALID)) {
1308                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
1309                 return 0;
1310         }
1311
1312         reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
1313         if (!reply)
1314                 return 0;
1315
1316         if (dbus_set_error_from_message(error, reply))
1317                 return 0;
1318
1319         if (!dbus_message_get_args(
1320                             reply, error,
1321                             DBUS_TYPE_UINT32, &pid,
1322                             DBUS_TYPE_INVALID))
1323                 return 0;
1324
1325         return (pid_t) pid;
1326 }
1327
1328 bool bus_error_is_no_service(const DBusError *error) {
1329         assert(error);
1330
1331         if (!dbus_error_is_set(error))
1332                 return false;
1333
1334         if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
1335                 return true;
1336
1337         if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
1338                 return true;
1339
1340         return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
1341 }
1342
1343 int bus_method_call_with_reply(
1344                 DBusConnection *bus,
1345                 const char *destination,
1346                 const char *path,
1347                 const char *interface,
1348                 const char *method,
1349                 DBusMessage **return_reply,
1350                 DBusError *return_error,
1351                 int first_arg_type, ...) {
1352
1353         DBusError error;
1354         _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
1355         DBusMessage *reply;
1356         va_list ap;
1357         int r = 0;
1358
1359         dbus_error_init(&error);
1360         assert(bus);
1361
1362         m = dbus_message_new_method_call(destination, path, interface, method);
1363         if (!m) {
1364                 r = log_oom();
1365                 goto finish;
1366         }
1367
1368         va_start(ap, first_arg_type);
1369         if (!dbus_message_append_args_valist(m, first_arg_type, ap)) {
1370                 va_end(ap);
1371                 r = log_oom();
1372                 goto finish;
1373         }
1374         va_end(ap);
1375
1376         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1377         if (!reply) {
1378                 if (!return_error)
1379                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1380
1381                 if (bus_error_is_no_service(&error))
1382                         r = -ENOENT;
1383                 else if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED))
1384                         r = -EACCES;
1385                 else if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY))
1386                         r = -ETIMEDOUT;
1387                 else
1388                         r = -EIO;
1389                 goto finish;
1390         }
1391
1392         if (return_reply)
1393                 *return_reply = reply;
1394         else
1395                 dbus_message_unref(reply);
1396
1397 finish:
1398         if (return_error)
1399                 *return_error = error;
1400         else
1401                 dbus_error_free(&error);
1402
1403         return r;
1404 }
1405
1406 void bus_message_unrefp(DBusMessage **reply) {
1407         if (!reply)
1408                 return;
1409
1410         if (!*reply)
1411                 return;
1412
1413         dbus_message_unref(*reply);
1414 }
1415
1416 const char *bus_message_get_sender_with_fallback(DBusMessage *m) {
1417         const char *s;
1418
1419         assert(m);
1420
1421         s = dbus_message_get_sender(m);
1422         if (s)
1423                 return s;
1424
1425         /* When the message came in from a direct connection the
1426          * message will have no sender. We fix that here. */
1427
1428         return ":no-sender";
1429 }