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