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