Branch data Line data Source code
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 : 0 : _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 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
21 : : int r;
22 : :
23 [ # # # # ]: 0 : assert_return(bus, -EINVAL);
24 [ # # # # ]: 0 : assert_return(bus = bus_resolve(bus), -ENOPKG);
25 [ # # # # ]: 0 : assert_return(!bus_pid_changed(bus), -ECHILD);
26 : :
27 [ # # ]: 0 : if (!BUS_IS_OPEN(bus->state))
28 : 0 : return -ENOTCONN;
29 : :
30 : 0 : r = sd_bus_message_new_signal(bus, &m, path, interface, member);
31 [ # # ]: 0 : if (r < 0)
32 : 0 : return r;
33 : :
34 [ # # ]: 0 : if (!isempty(types)) {
35 : : va_list ap;
36 : :
37 : 0 : va_start(ap, types);
38 : 0 : r = sd_bus_message_appendv(m, types, ap);
39 : 0 : va_end(ap);
40 [ # # ]: 0 : if (r < 0)
41 : 0 : return r;
42 : : }
43 : :
44 : 0 : return sd_bus_send(bus, m, NULL);
45 : : }
46 : :
47 : 136 : _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 : 136 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
59 : : int r;
60 : :
61 [ - + - + ]: 136 : assert_return(bus, -EINVAL);
62 [ - + - + ]: 136 : assert_return(bus = bus_resolve(bus), -ENOPKG);
63 [ - + - + ]: 136 : assert_return(!bus_pid_changed(bus), -ECHILD);
64 : :
65 [ + + ]: 136 : if (!BUS_IS_OPEN(bus->state))
66 : 64 : return -ENOTCONN;
67 : :
68 : 72 : r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
69 [ - + ]: 72 : if (r < 0)
70 : 0 : return r;
71 : :
72 [ + + ]: 72 : if (!isempty(types)) {
73 : : va_list ap;
74 : :
75 : 68 : va_start(ap, types);
76 : 68 : r = sd_bus_message_appendv(m, types, ap);
77 : 68 : va_end(ap);
78 [ - + ]: 68 : if (r < 0)
79 : 0 : return r;
80 : : }
81 : :
82 : 72 : return sd_bus_call_async(bus, slot, m, callback, userdata, 0);
83 : : }
84 : :
85 : 124 : _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 : 124 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
96 : : int r;
97 : :
98 [ - + - + ]: 124 : bus_assert_return(bus, -EINVAL, error);
99 [ - + - + ]: 124 : bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
100 : :
101 [ - + ]: 124 : if (!BUS_IS_OPEN(bus->state)) {
102 : 0 : r = -ENOTCONN;
103 : 0 : goto fail;
104 : : }
105 : :
106 : 124 : r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
107 [ - + ]: 124 : if (r < 0)
108 : 0 : goto fail;
109 : :
110 [ + + ]: 124 : if (!isempty(types)) {
111 : : va_list ap;
112 : :
113 : 56 : va_start(ap, types);
114 : 56 : r = sd_bus_message_appendv(m, types, ap);
115 : 56 : va_end(ap);
116 [ - + ]: 56 : if (r < 0)
117 : 0 : goto fail;
118 : : }
119 : :
120 : 124 : return sd_bus_call(bus, m, 0, error, reply);
121 : :
122 : 0 : fail:
123 : 0 : return sd_bus_error_set_errno(error, r);
124 : : }
125 : :
126 : 80 : _public_ int sd_bus_reply_method_return(
127 : : sd_bus_message *call,
128 : : const char *types, ...) {
129 : :
130 : 80 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
131 : : int r;
132 : :
133 [ - + - + ]: 80 : assert_return(call, -EINVAL);
134 [ - + - + ]: 80 : assert_return(call->sealed, -EPERM);
135 [ - + - + ]: 80 : assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
136 [ - + - + ]: 80 : assert_return(call->bus, -EINVAL);
137 [ - + - + ]: 80 : assert_return(!bus_pid_changed(call->bus), -ECHILD);
138 : :
139 [ - + ]: 80 : if (!BUS_IS_OPEN(call->bus->state))
140 : 0 : return -ENOTCONN;
141 : :
142 [ + + ]: 80 : if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
143 : 12 : return 0;
144 : :
145 : 68 : r = sd_bus_message_new_method_return(call, &m);
146 [ - + ]: 68 : if (r < 0)
147 : 0 : return r;
148 : :
149 [ + + ]: 68 : if (!isempty(types)) {
150 : : va_list ap;
151 : :
152 : 12 : va_start(ap, types);
153 : 12 : r = sd_bus_message_appendv(m, types, ap);
154 : 12 : va_end(ap);
155 [ - + ]: 12 : if (r < 0)
156 : 0 : return r;
157 : : }
158 : :
159 : 68 : return sd_bus_send(call->bus, m, NULL);
160 : : }
161 : :
162 : 16 : _public_ int sd_bus_reply_method_error(
163 : : sd_bus_message *call,
164 : : const sd_bus_error *e) {
165 : :
166 : 16 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
167 : : int r;
168 : :
169 [ - + - + ]: 16 : assert_return(call, -EINVAL);
170 [ - + - + ]: 16 : assert_return(call->sealed, -EPERM);
171 [ - + - + ]: 16 : assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
172 [ - + - + ]: 16 : assert_return(sd_bus_error_is_set(e), -EINVAL);
173 [ - + - + ]: 16 : assert_return(call->bus, -EINVAL);
174 [ - + - + ]: 16 : assert_return(!bus_pid_changed(call->bus), -ECHILD);
175 : :
176 [ - + ]: 16 : if (!BUS_IS_OPEN(call->bus->state))
177 : 0 : return -ENOTCONN;
178 : :
179 [ - + ]: 16 : if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
180 : 0 : return 0;
181 : :
182 : 16 : r = sd_bus_message_new_method_error(call, &m, e);
183 [ - + ]: 16 : if (r < 0)
184 : 0 : return r;
185 : :
186 : 16 : return sd_bus_send(call->bus, m, NULL);
187 : : }
188 : :
189 : 16 : _public_ int sd_bus_reply_method_errorf(
190 : : sd_bus_message *call,
191 : : const char *name,
192 : : const char *format,
193 : : ...) {
194 : :
195 : 16 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
196 : : va_list ap;
197 : :
198 [ - + - + ]: 16 : assert_return(call, -EINVAL);
199 [ - + - + ]: 16 : assert_return(call->sealed, -EPERM);
200 [ - + - + ]: 16 : assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
201 [ - + - + ]: 16 : assert_return(call->bus, -EINVAL);
202 [ - + - + ]: 16 : assert_return(!bus_pid_changed(call->bus), -ECHILD);
203 : :
204 [ - + ]: 16 : if (!BUS_IS_OPEN(call->bus->state))
205 : 0 : return -ENOTCONN;
206 : :
207 [ - + ]: 16 : if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
208 : 0 : return 0;
209 : :
210 : 16 : va_start(ap, format);
211 : 16 : bus_error_setfv(&error, name, format, ap);
212 : 16 : va_end(ap);
213 : :
214 : 16 : return sd_bus_reply_method_error(call, &error);
215 : : }
216 : :
217 : 0 : _public_ int sd_bus_reply_method_errno(
218 : : sd_bus_message *call,
219 : : int error,
220 : : const sd_bus_error *p) {
221 : :
222 : 0 : _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
223 : :
224 [ # # # # ]: 0 : assert_return(call, -EINVAL);
225 [ # # # # ]: 0 : assert_return(call->sealed, -EPERM);
226 [ # # # # ]: 0 : assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
227 [ # # # # ]: 0 : assert_return(call->bus, -EINVAL);
228 [ # # # # ]: 0 : assert_return(!bus_pid_changed(call->bus), -ECHILD);
229 : :
230 [ # # ]: 0 : if (!BUS_IS_OPEN(call->bus->state))
231 : 0 : return -ENOTCONN;
232 : :
233 [ # # ]: 0 : if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
234 : 0 : return 0;
235 : :
236 [ # # ]: 0 : if (sd_bus_error_is_set(p))
237 : 0 : return sd_bus_reply_method_error(call, p);
238 : :
239 : 0 : sd_bus_error_set_errno(&berror, error);
240 : :
241 : 0 : return sd_bus_reply_method_error(call, &berror);
242 : : }
243 : :
244 : 0 : _public_ int sd_bus_reply_method_errnof(
245 : : sd_bus_message *call,
246 : : int error,
247 : : const char *format,
248 : : ...) {
249 : :
250 : 0 : _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
251 : : va_list ap;
252 : :
253 [ # # # # ]: 0 : assert_return(call, -EINVAL);
254 [ # # # # ]: 0 : assert_return(call->sealed, -EPERM);
255 [ # # # # ]: 0 : assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
256 [ # # # # ]: 0 : assert_return(call->bus, -EINVAL);
257 [ # # # # ]: 0 : assert_return(!bus_pid_changed(call->bus), -ECHILD);
258 : :
259 [ # # ]: 0 : if (!BUS_IS_OPEN(call->bus->state))
260 : 0 : return -ENOTCONN;
261 : :
262 [ # # ]: 0 : if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
263 : 0 : return 0;
264 : :
265 : 0 : va_start(ap, format);
266 : 0 : sd_bus_error_set_errnofv(&berror, error, format, ap);
267 : 0 : va_end(ap);
268 : :
269 : 0 : return sd_bus_reply_method_error(call, &berror);
270 : : }
271 : :
272 : 12 : _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 : 12 : sd_bus_message *rep = NULL;
283 : : int r;
284 : :
285 [ - + - + ]: 12 : bus_assert_return(bus, -EINVAL, error);
286 [ + - - + : 12 : bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
- + ]
287 [ - + - + ]: 12 : bus_assert_return(member_name_is_valid(member), -EINVAL, error);
288 [ - + - + ]: 12 : bus_assert_return(reply, -EINVAL, error);
289 [ - + - + ]: 12 : bus_assert_return(signature_is_single(type, false), -EINVAL, error);
290 [ - + - + ]: 12 : bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
291 : :
292 [ - + ]: 12 : if (!BUS_IS_OPEN(bus->state)) {
293 : 0 : r = -ENOTCONN;
294 : 0 : goto fail;
295 : : }
296 : :
297 : 12 : r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
298 [ - + ]: 12 : if (r < 0)
299 : 0 : return r;
300 : :
301 : 12 : r = sd_bus_message_enter_container(rep, 'v', type);
302 [ - + ]: 12 : if (r < 0) {
303 : 0 : sd_bus_message_unref(rep);
304 : 0 : goto fail;
305 : : }
306 : :
307 : 12 : *reply = rep;
308 : 12 : return 0;
309 : :
310 : 0 : fail:
311 : 0 : return sd_bus_error_set_errno(error, r);
312 : : }
313 : :
314 : 0 : _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 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
324 : : int r;
325 : :
326 [ # # # # ]: 0 : bus_assert_return(bus, -EINVAL, error);
327 [ # # # # : 0 : bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
# # ]
328 [ # # # # ]: 0 : bus_assert_return(member_name_is_valid(member), -EINVAL, error);
329 [ # # # # ]: 0 : bus_assert_return(bus_type_is_trivial(type), -EINVAL, error);
330 [ # # # # ]: 0 : bus_assert_return(ptr, -EINVAL, error);
331 [ # # # # ]: 0 : bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
332 : :
333 [ # # ]: 0 : if (!BUS_IS_OPEN(bus->state)) {
334 : 0 : r = -ENOTCONN;
335 : 0 : goto fail;
336 : : }
337 : :
338 : 0 : r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
339 [ # # ]: 0 : if (r < 0)
340 : 0 : return r;
341 : :
342 : 0 : r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
343 [ # # ]: 0 : if (r < 0)
344 : 0 : goto fail;
345 : :
346 : 0 : r = sd_bus_message_read_basic(reply, type, ptr);
347 [ # # ]: 0 : if (r < 0)
348 : 0 : goto fail;
349 : :
350 : 0 : return 0;
351 : :
352 : 0 : fail:
353 : 0 : return sd_bus_error_set_errno(error, r);
354 : : }
355 : :
356 : 0 : _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 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
366 : : const char *s;
367 : : char *n;
368 : : int r;
369 : :
370 [ # # # # ]: 0 : bus_assert_return(bus, -EINVAL, error);
371 [ # # # # : 0 : bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
# # ]
372 [ # # # # ]: 0 : bus_assert_return(member_name_is_valid(member), -EINVAL, error);
373 [ # # # # ]: 0 : bus_assert_return(ret, -EINVAL, error);
374 [ # # # # ]: 0 : bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
375 : :
376 [ # # ]: 0 : if (!BUS_IS_OPEN(bus->state)) {
377 : 0 : r = -ENOTCONN;
378 : 0 : goto fail;
379 : : }
380 : :
381 : 0 : r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
382 [ # # ]: 0 : if (r < 0)
383 : 0 : return r;
384 : :
385 : 0 : r = sd_bus_message_enter_container(reply, 'v', "s");
386 [ # # ]: 0 : if (r < 0)
387 : 0 : goto fail;
388 : :
389 : 0 : r = sd_bus_message_read_basic(reply, 's', &s);
390 [ # # ]: 0 : if (r < 0)
391 : 0 : goto fail;
392 : :
393 : 0 : n = strdup(s);
394 [ # # ]: 0 : if (!n) {
395 : 0 : r = -ENOMEM;
396 : 0 : goto fail;
397 : : }
398 : :
399 : 0 : *ret = n;
400 : 0 : return 0;
401 : :
402 : 0 : fail:
403 : 0 : return sd_bus_error_set_errno(error, r);
404 : : }
405 : :
406 : 0 : _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 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
416 : : int r;
417 : :
418 [ # # # # ]: 0 : bus_assert_return(bus, -EINVAL, error);
419 [ # # # # : 0 : bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
# # ]
420 [ # # # # ]: 0 : bus_assert_return(member_name_is_valid(member), -EINVAL, error);
421 [ # # # # ]: 0 : bus_assert_return(ret, -EINVAL, error);
422 [ # # # # ]: 0 : bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
423 : :
424 [ # # ]: 0 : if (!BUS_IS_OPEN(bus->state)) {
425 : 0 : r = -ENOTCONN;
426 : 0 : goto fail;
427 : : }
428 : :
429 : 0 : r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
430 [ # # ]: 0 : if (r < 0)
431 : 0 : return r;
432 : :
433 : 0 : r = sd_bus_message_enter_container(reply, 'v', NULL);
434 [ # # ]: 0 : if (r < 0)
435 : 0 : goto fail;
436 : :
437 : 0 : r = sd_bus_message_read_strv(reply, ret);
438 [ # # ]: 0 : if (r < 0)
439 : 0 : goto fail;
440 : :
441 : 0 : return 0;
442 : :
443 : 0 : fail:
444 : 0 : return sd_bus_error_set_errno(error, r);
445 : : }
446 : :
447 : 12 : _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 : 12 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
457 : : va_list ap;
458 : : int r;
459 : :
460 [ - + - + ]: 12 : bus_assert_return(bus, -EINVAL, error);
461 [ + - - + : 12 : bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
- + ]
462 [ - + - + ]: 12 : bus_assert_return(member_name_is_valid(member), -EINVAL, error);
463 [ - + - + ]: 12 : bus_assert_return(signature_is_single(type, false), -EINVAL, error);
464 [ - + - + ]: 12 : bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
465 : :
466 [ - + ]: 12 : if (!BUS_IS_OPEN(bus->state)) {
467 : 0 : r = -ENOTCONN;
468 : 0 : goto fail;
469 : : }
470 : :
471 : 12 : r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
472 [ - + ]: 12 : if (r < 0)
473 : 0 : goto fail;
474 : :
475 : 12 : r = sd_bus_message_append(m, "ss", strempty(interface), member);
476 [ - + ]: 12 : if (r < 0)
477 : 0 : goto fail;
478 : :
479 : 12 : r = sd_bus_message_open_container(m, 'v', type);
480 [ - + ]: 12 : if (r < 0)
481 : 0 : goto fail;
482 : :
483 : 12 : va_start(ap, type);
484 : 12 : r = sd_bus_message_appendv(m, type, ap);
485 : 12 : va_end(ap);
486 [ - + ]: 12 : if (r < 0)
487 : 0 : goto fail;
488 : :
489 : 12 : r = sd_bus_message_close_container(m);
490 [ - + ]: 12 : if (r < 0)
491 : 0 : goto fail;
492 : :
493 : 12 : return sd_bus_call(bus, m, 0, error, NULL);
494 : :
495 : 0 : fail:
496 : 0 : return sd_bus_error_set_errno(error, r);
497 : : }
498 : :
499 : 52 : _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 [ - + - + ]: 52 : assert_return(call, -EINVAL);
503 [ - + - + ]: 52 : assert_return(call->sealed, -EPERM);
504 [ - + - + ]: 52 : assert_return(call->bus, -EINVAL);
505 [ - + - + ]: 52 : assert_return(!bus_pid_changed(call->bus), -ECHILD);
506 : :
507 [ - + ]: 52 : if (!BUS_IS_OPEN(call->bus->state))
508 : 0 : return -ENOTCONN;
509 : :
510 : 52 : c = sd_bus_message_get_creds(call);
511 : :
512 : : /* All data we need? */
513 [ - + # # ]: 52 : if (c && (mask & ~c->mask) == 0) {
514 : 0 : *creds = sd_bus_creds_ref(c);
515 : 0 : return 0;
516 : : }
517 : :
518 : : /* No data passed? Or not enough data passed to retrieve the missing bits? */
519 [ - + # # ]: 52 : 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 [ - + ]: 52 : if (call->sender)
524 : : /* There's a sender, but the creds are missing. */
525 : 0 : 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 : 52 : return sd_bus_get_owner_creds(call->bus, mask, creds);
531 : : }
532 : :
533 : 0 : return bus_creds_extend_by_pid(c, mask, creds);
534 : : }
535 : :
536 : 52 : _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
537 : 52 : _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
538 : : uid_t our_uid;
539 : 52 : bool know_caps = false;
540 : : int r;
541 : :
542 [ - + - + ]: 52 : assert_return(call, -EINVAL);
543 [ - + - + ]: 52 : assert_return(call->sealed, -EPERM);
544 [ - + - + ]: 52 : assert_return(call->bus, -EINVAL);
545 [ - + - + ]: 52 : assert_return(!bus_pid_changed(call->bus), -ECHILD);
546 : :
547 [ - + ]: 52 : if (!BUS_IS_OPEN(call->bus->state))
548 : 0 : return -ENOTCONN;
549 : :
550 [ + - ]: 52 : if (capability >= 0) {
551 : :
552 : 52 : r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
553 [ - + ]: 52 : if (r < 0)
554 : 0 : 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 [ - + - + ]: 52 : assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
562 : :
563 : 52 : r = sd_bus_creds_has_effective_cap(creds, capability);
564 [ - + ]: 52 : if (r > 0)
565 : 0 : return 1;
566 [ - + ]: 52 : if (r == 0)
567 : 0 : know_caps = true;
568 : : } else {
569 : 0 : r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
570 [ # # ]: 0 : if (r < 0)
571 : 0 : return r;
572 : : }
573 : :
574 : : /* Now, check the UID, but only if the capability check wasn't
575 : : * sufficient */
576 : 52 : our_uid = getuid();
577 [ - + # # : 52 : 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 [ - + - + ]: 104 : 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 : 52 : r = sd_bus_creds_get_euid(creds, &sender_uid);
589 [ - + ]: 52 : if (r < 0)
590 : 0 : r = sd_bus_creds_get_uid(creds, &sender_uid);
591 : :
592 [ + - ]: 52 : if (r >= 0) {
593 : : /* Sender has same UID as us, then let's grant access */
594 [ + - ]: 52 : if (sender_uid == our_uid)
595 : 52 : return 1;
596 : :
597 : : /* Sender is root, we are not root. */
598 [ # # # # ]: 0 : if (our_uid != 0 && sender_uid == 0)
599 : 0 : return 1;
600 : : }
601 : : }
602 : :
603 : 0 : 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 : 4 : _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 [ - + - + ]: 4 : assert_return(bus, -EINVAL);
636 [ - + - + ]: 4 : assert_return(bus = bus_resolve(bus), -ENOPKG);
637 [ - + - + ]: 4 : assert_return(!bus_pid_changed(bus), -ECHILD);
638 [ - + # # : 4 : assert_return(!sender || service_name_is_valid(sender), -EINVAL);
- + ]
639 [ - + # # : 4 : assert_return(!path || object_path_is_valid(path), -EINVAL);
- + ]
640 [ + - - + : 4 : assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
- + ]
641 [ + - - + : 4 : assert_return(!member || member_name_is_valid(member), -EINVAL);
- + ]
642 : :
643 [ - + - + : 108 : expression = make_expression(sender, path, interface, member);
- + - + -
+ - + + -
+ - + - +
- + - + -
+ + + - -
+ - + + +
+ - ]
644 : :
645 : 4 : return sd_bus_add_match(bus, ret, expression, callback, userdata);
646 : : }
647 : :
648 : 104 : _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 [ - + - + ]: 104 : assert_return(bus, -EINVAL);
662 [ - + - + ]: 104 : assert_return(bus = bus_resolve(bus), -ENOPKG);
663 [ - + - + ]: 104 : assert_return(!bus_pid_changed(bus), -ECHILD);
664 [ + + - + : 104 : assert_return(!sender || service_name_is_valid(sender), -EINVAL);
- + ]
665 [ + - - + : 104 : assert_return(!path || object_path_is_valid(path), -EINVAL);
- + ]
666 [ + - - + : 104 : assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
- + ]
667 [ + - - + : 104 : assert_return(!member || member_name_is_valid(member), -EINVAL);
- + ]
668 : :
669 [ + + + + : 2808 : expression = make_expression(sender, path, interface, member);
+ + + - +
- + - + -
+ - + - +
- + - + -
+ + + - -
+ - + + +
+ - ]
670 : :
671 : 104 : return sd_bus_add_match_async(bus, ret, expression, callback, install_callback, userdata);
672 : : }
|