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