chiark / gitweb /
Prep v239: Fix and add debug messages to method_can_shutdown_or_sleep()
[elogind.git] / src / libelogind / sd-bus / bus-convenience.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 ***/
4
5 #include "bus-internal.h"
6 #include "bus-message.h"
7 #include "bus-signature.h"
8 #include "bus-type.h"
9 #include "bus-util.h"
10 #include "string-util.h"
11
12 _public_ int sd_bus_emit_signal(
13                 sd_bus *bus,
14                 const char *path,
15                 const char *interface,
16                 const char *member,
17                 const char *types, ...) {
18
19         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
20         int r;
21
22         assert_return(bus, -EINVAL);
23         assert_return(bus = bus_resolve(bus), -ENOPKG);
24         assert_return(!bus_pid_changed(bus), -ECHILD);
25
26         if (!BUS_IS_OPEN(bus->state))
27                 return -ENOTCONN;
28
29         r = sd_bus_message_new_signal(bus, &m, path, interface, member);
30         if (r < 0)
31                 return r;
32
33         if (!isempty(types)) {
34                 va_list ap;
35
36                 va_start(ap, types);
37                 r = sd_bus_message_appendv(m, types, ap);
38                 va_end(ap);
39                 if (r < 0)
40                         return r;
41         }
42
43         return sd_bus_send(bus, m, NULL);
44 }
45
46 _public_ int sd_bus_call_method_async(
47                 sd_bus *bus,
48                 sd_bus_slot **slot,
49                 const char *destination,
50                 const char *path,
51                 const char *interface,
52                 const char *member,
53                 sd_bus_message_handler_t callback,
54                 void *userdata,
55                 const char *types, ...) {
56
57         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
58         int r;
59
60         assert_return(bus, -EINVAL);
61         assert_return(bus = bus_resolve(bus), -ENOPKG);
62         assert_return(!bus_pid_changed(bus), -ECHILD);
63
64         if (!BUS_IS_OPEN(bus->state))
65                 return -ENOTCONN;
66
67         r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
68         if (r < 0)
69                 return r;
70
71         if (!isempty(types)) {
72                 va_list ap;
73
74                 va_start(ap, types);
75                 r = sd_bus_message_appendv(m, types, ap);
76                 va_end(ap);
77                 if (r < 0)
78                         return r;
79         }
80
81         return sd_bus_call_async(bus, slot, m, callback, userdata, 0);
82 }
83
84 _public_ int sd_bus_call_method(
85                 sd_bus *bus,
86                 const char *destination,
87                 const char *path,
88                 const char *interface,
89                 const char *member,
90                 sd_bus_error *error,
91                 sd_bus_message **reply,
92                 const char *types, ...) {
93
94         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
95         int r;
96
97         bus_assert_return(bus, -EINVAL, error);
98         bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
99
100         if (!BUS_IS_OPEN(bus->state)) {
101                 r = -ENOTCONN;
102                 goto fail;
103         }
104
105         r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
106         if (r < 0)
107                 goto fail;
108
109         if (!isempty(types)) {
110                 va_list ap;
111
112                 va_start(ap, types);
113                 r = sd_bus_message_appendv(m, types, ap);
114                 va_end(ap);
115                 if (r < 0)
116                         goto fail;
117         }
118
119         return sd_bus_call(bus, m, 0, error, reply);
120
121 fail:
122         return sd_bus_error_set_errno(error, r);
123 }
124
125 _public_ int sd_bus_reply_method_return(
126                 sd_bus_message *call,
127                 const char *types, ...) {
128
129         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
130         int r;
131
132         assert_return(call, -EINVAL);
133         assert_return(call->sealed, -EPERM);
134         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
135         assert_return(call->bus, -EINVAL);
136         assert_return(!bus_pid_changed(call->bus), -ECHILD);
137
138         if (!BUS_IS_OPEN(call->bus->state))
139                 return -ENOTCONN;
140
141         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
142                 return 0;
143
144         r = sd_bus_message_new_method_return(call, &m);
145         if (r < 0)
146                 return r;
147
148         if (!isempty(types)) {
149                 va_list ap;
150
151                 va_start(ap, types);
152                 r = sd_bus_message_appendv(m, types, ap);
153                 va_end(ap);
154                 if (r < 0)
155                         return r;
156         }
157
158         return sd_bus_send(call->bus, m, NULL);
159 }
160
161 _public_ int sd_bus_reply_method_error(
162                 sd_bus_message *call,
163                 const sd_bus_error *e) {
164
165         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
166         int r;
167
168         assert_return(call, -EINVAL);
169         assert_return(call->sealed, -EPERM);
170         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
171         assert_return(sd_bus_error_is_set(e), -EINVAL);
172         assert_return(call->bus, -EINVAL);
173         assert_return(!bus_pid_changed(call->bus), -ECHILD);
174
175         if (!BUS_IS_OPEN(call->bus->state))
176                 return -ENOTCONN;
177
178         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
179                 return 0;
180
181         r = sd_bus_message_new_method_error(call, &m, e);
182         if (r < 0)
183                 return r;
184
185         return sd_bus_send(call->bus, m, NULL);
186 }
187
188 _public_ int sd_bus_reply_method_errorf(
189                 sd_bus_message *call,
190                 const char *name,
191                 const char *format,
192                 ...) {
193
194         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
195         va_list ap;
196
197         assert_return(call, -EINVAL);
198         assert_return(call->sealed, -EPERM);
199         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
200         assert_return(call->bus, -EINVAL);
201         assert_return(!bus_pid_changed(call->bus), -ECHILD);
202
203         if (!BUS_IS_OPEN(call->bus->state))
204                 return -ENOTCONN;
205
206         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
207                 return 0;
208
209         va_start(ap, format);
210         bus_error_setfv(&error, name, format, ap);
211         va_end(ap);
212
213         return sd_bus_reply_method_error(call, &error);
214 }
215
216 _public_ int sd_bus_reply_method_errno(
217                 sd_bus_message *call,
218                 int error,
219                 const sd_bus_error *p) {
220
221         _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
222
223         assert_return(call, -EINVAL);
224         assert_return(call->sealed, -EPERM);
225         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
226         assert_return(call->bus, -EINVAL);
227         assert_return(!bus_pid_changed(call->bus), -ECHILD);
228
229         if (!BUS_IS_OPEN(call->bus->state))
230                 return -ENOTCONN;
231
232         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
233                 return 0;
234
235         if (sd_bus_error_is_set(p))
236                 return sd_bus_reply_method_error(call, p);
237
238         sd_bus_error_set_errno(&berror, error);
239
240         return sd_bus_reply_method_error(call, &berror);
241 }
242
243 _public_ int sd_bus_reply_method_errnof(
244                 sd_bus_message *call,
245                 int error,
246                 const char *format,
247                 ...) {
248
249         _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
250         va_list ap;
251
252         assert_return(call, -EINVAL);
253         assert_return(call->sealed, -EPERM);
254         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
255         assert_return(call->bus, -EINVAL);
256         assert_return(!bus_pid_changed(call->bus), -ECHILD);
257
258         if (!BUS_IS_OPEN(call->bus->state))
259                 return -ENOTCONN;
260
261         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
262                 return 0;
263
264         va_start(ap, format);
265         sd_bus_error_set_errnofv(&berror, error, format, ap);
266         va_end(ap);
267
268         return sd_bus_reply_method_error(call, &berror);
269 }
270
271 _public_ int sd_bus_get_property(
272                 sd_bus *bus,
273                 const char *destination,
274                 const char *path,
275                 const char *interface,
276                 const char *member,
277                 sd_bus_error *error,
278                 sd_bus_message **reply,
279                 const char *type) {
280
281         sd_bus_message *rep = NULL;
282         int r;
283
284         bus_assert_return(bus, -EINVAL, error);
285         bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
286         bus_assert_return(member_name_is_valid(member), -EINVAL, error);
287         bus_assert_return(reply, -EINVAL, error);
288         bus_assert_return(signature_is_single(type, false), -EINVAL, error);
289         bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
290
291         if (!BUS_IS_OPEN(bus->state)) {
292                 r = -ENOTCONN;
293                 goto fail;
294         }
295
296         r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
297         if (r < 0)
298                 return r;
299
300         r = sd_bus_message_enter_container(rep, 'v', type);
301         if (r < 0) {
302                 sd_bus_message_unref(rep);
303                 goto fail;
304         }
305
306         *reply = rep;
307         return 0;
308
309 fail:
310         return sd_bus_error_set_errno(error, r);
311 }
312
313 _public_ int sd_bus_get_property_trivial(
314                 sd_bus *bus,
315                 const char *destination,
316                 const char *path,
317                 const char *interface,
318                 const char *member,
319                 sd_bus_error *error,
320                 char type, void *ptr) {
321
322         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
323         int r;
324
325         bus_assert_return(bus, -EINVAL, error);
326         bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
327         bus_assert_return(member_name_is_valid(member), -EINVAL, error);
328         bus_assert_return(bus_type_is_trivial(type), -EINVAL, error);
329         bus_assert_return(ptr, -EINVAL, error);
330         bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
331
332         if (!BUS_IS_OPEN(bus->state)) {
333                 r = -ENOTCONN;
334                 goto fail;
335         }
336
337         r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
338         if (r < 0)
339                 return r;
340
341         r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
342         if (r < 0)
343                 goto fail;
344
345         r = sd_bus_message_read_basic(reply, type, ptr);
346         if (r < 0)
347                 goto fail;
348
349         return 0;
350
351 fail:
352         return sd_bus_error_set_errno(error, r);
353 }
354
355 _public_ int sd_bus_get_property_string(
356                 sd_bus *bus,
357                 const char *destination,
358                 const char *path,
359                 const char *interface,
360                 const char *member,
361                 sd_bus_error *error,
362                 char **ret) {
363
364         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
365         const char *s;
366         char *n;
367         int r;
368
369         bus_assert_return(bus, -EINVAL, error);
370         bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
371         bus_assert_return(member_name_is_valid(member), -EINVAL, error);
372         bus_assert_return(ret, -EINVAL, error);
373         bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
374
375         if (!BUS_IS_OPEN(bus->state)) {
376                 r = -ENOTCONN;
377                 goto fail;
378         }
379
380         r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
381         if (r < 0)
382                 return r;
383
384         r = sd_bus_message_enter_container(reply, 'v', "s");
385         if (r < 0)
386                 goto fail;
387
388         r = sd_bus_message_read_basic(reply, 's', &s);
389         if (r < 0)
390                 goto fail;
391
392         n = strdup(s);
393         if (!n) {
394                 r = -ENOMEM;
395                 goto fail;
396         }
397
398         *ret = n;
399         return 0;
400
401 fail:
402         return sd_bus_error_set_errno(error, r);
403 }
404
405 _public_ int sd_bus_get_property_strv(
406                 sd_bus *bus,
407                 const char *destination,
408                 const char *path,
409                 const char *interface,
410                 const char *member,
411                 sd_bus_error *error,
412                 char ***ret) {
413
414         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
415         int r;
416
417         bus_assert_return(bus, -EINVAL, error);
418         bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
419         bus_assert_return(member_name_is_valid(member), -EINVAL, error);
420         bus_assert_return(ret, -EINVAL, error);
421         bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
422
423         if (!BUS_IS_OPEN(bus->state)) {
424                 r = -ENOTCONN;
425                 goto fail;
426         }
427
428         r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
429         if (r < 0)
430                 return r;
431
432         r = sd_bus_message_enter_container(reply, 'v', NULL);
433         if (r < 0)
434                 goto fail;
435
436         r = sd_bus_message_read_strv(reply, ret);
437         if (r < 0)
438                 goto fail;
439
440         return 0;
441
442 fail:
443         return sd_bus_error_set_errno(error, r);
444 }
445
446 _public_ int sd_bus_set_property(
447                 sd_bus *bus,
448                 const char *destination,
449                 const char *path,
450                 const char *interface,
451                 const char *member,
452                 sd_bus_error *error,
453                 const char *type, ...) {
454
455         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
456         va_list ap;
457         int r;
458
459         bus_assert_return(bus, -EINVAL, error);
460         bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
461         bus_assert_return(member_name_is_valid(member), -EINVAL, error);
462         bus_assert_return(signature_is_single(type, false), -EINVAL, error);
463         bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
464
465         if (!BUS_IS_OPEN(bus->state)) {
466                 r = -ENOTCONN;
467                 goto fail;
468         }
469
470         r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
471         if (r < 0)
472                 goto fail;
473
474         r = sd_bus_message_append(m, "ss", strempty(interface), member);
475         if (r < 0)
476                 goto fail;
477
478         r = sd_bus_message_open_container(m, 'v', type);
479         if (r < 0)
480                 goto fail;
481
482         va_start(ap, type);
483         r = sd_bus_message_appendv(m, type, ap);
484         va_end(ap);
485         if (r < 0)
486                 goto fail;
487
488         r = sd_bus_message_close_container(m);
489         if (r < 0)
490                 goto fail;
491
492         return sd_bus_call(bus, m, 0, error, NULL);
493
494 fail:
495         return sd_bus_error_set_errno(error, r);
496 }
497
498 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
499         sd_bus_creds *c;
500
501         assert_return(call, -EINVAL);
502         assert_return(call->sealed, -EPERM);
503         assert_return(call->bus, -EINVAL);
504         assert_return(!bus_pid_changed(call->bus), -ECHILD);
505
506         if (!BUS_IS_OPEN(call->bus->state))
507                 return -ENOTCONN;
508
509         c = sd_bus_message_get_creds(call);
510
511         /* All data we need? */
512         if (c && (mask & ~c->mask) == 0) {
513                 *creds = sd_bus_creds_ref(c);
514                 return 0;
515         }
516
517         /* No data passed? Or not enough data passed to retrieve the missing bits? */
518         if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
519                 /* We couldn't read anything from the call, let's try
520                  * to get it from the sender or peer. */
521
522                 if (call->sender)
523                         /* There's a sender, but the creds are missing. */
524                         return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
525                 else
526                         /* There's no sender. For direct connections
527                          * the credentials of the AF_UNIX peer matter,
528                          * which may be queried via sd_bus_get_owner_creds(). */
529                         return sd_bus_get_owner_creds(call->bus, mask, creds);
530         }
531
532         log_debug_elogind("Called by UID %u ; %s [%s] (%s)", c->uid,
533                           c->unique_name ? c->unique_name : "no name",
534                           c->label       ? c->label       : "no label",
535                           c->description ? c->description : "no desc");
536
537         return bus_creds_extend_by_pid(c, mask, creds);
538 }
539
540 _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
541         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
542         uid_t our_uid;
543         bool know_caps = false;
544         int r;
545
546         assert_return(call, -EINVAL);
547         assert_return(call->sealed, -EPERM);
548         assert_return(call->bus, -EINVAL);
549         assert_return(!bus_pid_changed(call->bus), -ECHILD);
550
551         if (!BUS_IS_OPEN(call->bus->state))
552                 return -ENOTCONN;
553
554         if (capability >= 0) {
555
556                 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
557                 if (r < 0)
558                         return r;
559
560                 /* We cannot use augmented caps for authorization,
561                  * since then data is acquired raceful from
562                  * /proc. This can never actually happen, but let's
563                  * better be safe than sorry, and do an extra check
564                  * here. */
565                 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
566
567                 r = sd_bus_creds_has_effective_cap(creds, capability);
568                 if (r > 0)
569                         return 1;
570                 if (r == 0)
571                         know_caps = true;
572         } else {
573                 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
574                 if (r < 0)
575                         return r;
576         }
577
578         /* Now, check the UID, but only if the capability check wasn't
579          * sufficient */
580         our_uid = getuid();
581         if (our_uid != 0 || !know_caps || capability < 0) {
582                 uid_t sender_uid;
583
584                 /* We cannot use augmented uid/euid for authorization,
585                  * since then data is acquired raceful from
586                  * /proc. This can never actually happen, but let's
587                  * better be safe than sorry, and do an extra check
588                  * here. */
589                 assert_return((sd_bus_creds_get_augmented_mask(creds) & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
590
591                 /* Try to use the EUID, if we have it. */
592                 r = sd_bus_creds_get_euid(creds, &sender_uid);
593                 if (r < 0)
594                         r = sd_bus_creds_get_uid(creds, &sender_uid);
595
596                 if (r >= 0) {
597                         /* Sender has same UID as us, then let's grant access */
598                         if (sender_uid == our_uid)
599                                 return 1;
600
601                         /* Sender is root, we are not root. */
602                         if (our_uid != 0 && sender_uid == 0)
603                                 return 1;
604                 }
605         }
606
607         return 0;
608 }
609
610 #define make_expression(sender, path, interface, member)        \
611         strjoina(                                               \
612                 "type='signal'",                                \
613                 sender ? ",sender='" : "",                      \
614                 sender ?: "",                                   \
615                 sender ? "'" : "",                              \
616                 path ? ",path='" : "",                          \
617                 path ?: "",                                     \
618                 path ? "'" : "",                                \
619                 interface ? ",interface='" : "",                \
620                 interface ?: "",                                \
621                 interface ? "'" : "",                           \
622                 member ? ",member='" : "",                      \
623                 member ?: "",                                   \
624                 member ? "'" : ""                               \
625         )
626
627 _public_ int sd_bus_match_signal(
628                 sd_bus *bus,
629                 sd_bus_slot **ret,
630                 const char *sender,
631                 const char *path,
632                 const char *interface,
633                 const char *member,
634                 sd_bus_message_handler_t callback,
635                 void *userdata) {
636
637         const char *expression;
638
639         assert_return(bus, -EINVAL);
640         assert_return(bus = bus_resolve(bus), -ENOPKG);
641         assert_return(!bus_pid_changed(bus), -ECHILD);
642         assert_return(!sender || service_name_is_valid(sender), -EINVAL);
643         assert_return(!path || object_path_is_valid(path), -EINVAL);
644         assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
645         assert_return(!member || member_name_is_valid(member), -EINVAL);
646
647         expression = make_expression(sender, path, interface, member);
648
649         return sd_bus_add_match(bus, ret, expression, callback, userdata);
650 }
651
652 _public_ int sd_bus_match_signal_async(
653                 sd_bus *bus,
654                 sd_bus_slot **ret,
655                 const char *sender,
656                 const char *path,
657                 const char *interface,
658                 const char *member,
659                 sd_bus_message_handler_t callback,
660                 sd_bus_message_handler_t install_callback,
661                 void *userdata) {
662
663         const char *expression;
664
665         assert_return(bus, -EINVAL);
666         assert_return(bus = bus_resolve(bus), -ENOPKG);
667         assert_return(!bus_pid_changed(bus), -ECHILD);
668         assert_return(!sender || service_name_is_valid(sender), -EINVAL);
669         assert_return(!path || object_path_is_valid(path), -EINVAL);
670         assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
671         assert_return(!member || member_name_is_valid(member), -EINVAL);
672
673         expression = make_expression(sender, path, interface, member);
674
675         return sd_bus_add_match_async(bus, ret, expression, callback, install_callback, userdata);
676 }