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