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