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