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