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