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