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