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