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