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