]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
de1c301e 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 | ||
349cc4a5 | 21 | #if HAVE_VALGRIND_MEMCHECK_H |
75722f1d LP |
22 | #include <valgrind/memcheck.h> |
23 | #endif | |
24 | ||
de1c301e | 25 | #include <errno.h> |
cf0fbc49 | 26 | #include <stddef.h> |
de1c301e | 27 | |
de1c301e | 28 | #include "sd-bus.h" |
07630cea | 29 | |
b5efdb8a | 30 | #include "alloc-util.h" |
ee104e11 | 31 | #include "bus-control.h" |
de1c301e LP |
32 | #include "bus-internal.h" |
33 | #include "bus-message.h" | |
057171ef | 34 | #include "bus-util.h" |
430f0182 | 35 | #include "capability-util.h" |
15a5e950 | 36 | #include "stdio-util.h" |
07630cea LP |
37 | #include "string-util.h" |
38 | #include "strv.h" | |
ee104e11 | 39 | #include "user-util.h" |
de1c301e | 40 | |
d9f644e2 | 41 | _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) { |
20902f3e LP |
42 | int r; |
43 | ||
9bb058a1 LS |
44 | assert_return(bus, -EINVAL); |
45 | assert_return(unique, -EINVAL); | |
46 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
20902f3e | 47 | |
33c62dcb LP |
48 | if (!bus->bus_client) |
49 | return -EINVAL; | |
50 | ||
20902f3e LP |
51 | r = bus_ensure_running(bus); |
52 | if (r < 0) | |
53 | return r; | |
de1c301e | 54 | |
20902f3e LP |
55 | *unique = bus->unique_name; |
56 | return 0; | |
de1c301e LP |
57 | } |
58 | ||
98c5bbc8 LP |
59 | static int validate_request_name_parameters( |
60 | sd_bus *bus, | |
61 | const char *name, | |
62 | uint64_t flags, | |
63 | uint32_t *ret_param) { | |
64 | ||
65 | uint32_t param = 0; | |
66 | ||
67 | assert(bus); | |
68 | assert(name); | |
69 | assert(ret_param); | |
de1c301e | 70 | |
e8bd7b09 LP |
71 | assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL); |
72 | assert_return(service_name_is_valid(name), -EINVAL); | |
73 | assert_return(name[0] != ':', -EINVAL); | |
74 | ||
75 | if (!bus->bus_client) | |
76 | return -EINVAL; | |
77 | ||
78 | /* Don't allow requesting the special driver and local names */ | |
79 | if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local")) | |
80 | return -EINVAL; | |
81 | ||
82 | if (!BUS_IS_OPEN(bus->state)) | |
83 | return -ENOTCONN; | |
e7176abb | 84 | |
29a07cdb LP |
85 | if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT) |
86 | param |= BUS_NAME_ALLOW_REPLACEMENT; | |
87 | if (flags & SD_BUS_NAME_REPLACE_EXISTING) | |
88 | param |= BUS_NAME_REPLACE_EXISTING; | |
89 | if (!(flags & SD_BUS_NAME_QUEUE)) | |
90 | param |= BUS_NAME_DO_NOT_QUEUE; | |
91 | ||
98c5bbc8 LP |
92 | *ret_param = param; |
93 | ||
94 | return 0; | |
95 | } | |
96 | ||
97 | _public_ int sd_bus_request_name( | |
98 | sd_bus *bus, | |
99 | const char *name, | |
100 | uint64_t flags) { | |
101 | ||
102 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; | |
103 | uint32_t ret, param = 0; | |
104 | int r; | |
105 | ||
106 | assert_return(bus, -EINVAL); | |
107 | assert_return(name, -EINVAL); | |
108 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
109 | ||
110 | r = validate_request_name_parameters(bus, name, flags, ¶m); | |
111 | if (r < 0) | |
112 | return r; | |
113 | ||
e7176abb LP |
114 | r = sd_bus_call_method( |
115 | bus, | |
116 | "org.freedesktop.DBus", | |
cd789fdf | 117 | "/org/freedesktop/DBus", |
e7176abb LP |
118 | "org.freedesktop.DBus", |
119 | "RequestName", | |
120 | NULL, | |
121 | &reply, | |
122 | "su", | |
123 | name, | |
29a07cdb | 124 | param); |
e7176abb LP |
125 | if (r < 0) |
126 | return r; | |
127 | ||
128 | r = sd_bus_message_read(reply, "u", &ret); | |
129 | if (r < 0) | |
130 | return r; | |
131 | ||
98c5bbc8 LP |
132 | switch (ret) { |
133 | ||
134 | case BUS_NAME_ALREADY_OWNER: | |
e7176abb | 135 | return -EALREADY; |
98c5bbc8 LP |
136 | |
137 | case BUS_NAME_EXISTS: | |
e7176abb | 138 | return -EEXIST; |
98c5bbc8 LP |
139 | |
140 | case BUS_NAME_IN_QUEUE: | |
e7176abb | 141 | return 0; |
98c5bbc8 LP |
142 | |
143 | case BUS_NAME_PRIMARY_OWNER: | |
c0a09132 | 144 | return 1; |
98c5bbc8 | 145 | } |
e7176abb | 146 | |
c0a09132 | 147 | return -EIO; |
e7176abb LP |
148 | } |
149 | ||
98c5bbc8 LP |
150 | static int default_request_name_handler( |
151 | sd_bus_message *m, | |
152 | void *userdata, | |
153 | sd_bus_error *ret_error) { | |
154 | ||
e8bd7b09 LP |
155 | uint32_t ret; |
156 | int r; | |
157 | ||
98c5bbc8 LP |
158 | assert(m); |
159 | ||
160 | if (sd_bus_message_is_method_error(m, NULL)) { | |
161 | log_debug_errno(sd_bus_message_get_errno(m), | |
162 | "Unable to request name, failing connection: %s", | |
163 | sd_bus_message_get_error(m)->message); | |
164 | ||
165 | bus_enter_closing(sd_bus_message_get_bus(m)); | |
166 | return 1; | |
167 | } | |
168 | ||
169 | r = sd_bus_message_read(m, "u", &ret); | |
170 | if (r < 0) | |
171 | return r; | |
172 | ||
173 | switch (ret) { | |
174 | ||
175 | case BUS_NAME_ALREADY_OWNER: | |
176 | log_debug("Already owner of requested service name, ignoring."); | |
177 | return 1; | |
178 | ||
179 | case BUS_NAME_IN_QUEUE: | |
180 | log_debug("In queue for requested service name."); | |
181 | return 1; | |
182 | ||
183 | case BUS_NAME_PRIMARY_OWNER: | |
184 | log_debug("Successfully acquired requested service name."); | |
185 | return 1; | |
186 | ||
187 | case BUS_NAME_EXISTS: | |
188 | log_debug("Requested service name already owned, failing connection."); | |
189 | bus_enter_closing(sd_bus_message_get_bus(m)); | |
190 | return 1; | |
191 | } | |
192 | ||
193 | log_debug("Unexpected response from RequestName(), failing connection."); | |
194 | bus_enter_closing(sd_bus_message_get_bus(m)); | |
195 | return 1; | |
196 | } | |
197 | ||
198 | _public_ int sd_bus_request_name_async( | |
199 | sd_bus *bus, | |
200 | sd_bus_slot **ret_slot, | |
201 | const char *name, | |
202 | uint64_t flags, | |
203 | sd_bus_message_handler_t callback, | |
204 | void *userdata) { | |
205 | ||
206 | uint32_t param = 0; | |
207 | int r; | |
208 | ||
9bb058a1 LS |
209 | assert_return(bus, -EINVAL); |
210 | assert_return(name, -EINVAL); | |
9bb058a1 | 211 | assert_return(!bus_pid_changed(bus), -ECHILD); |
98c5bbc8 LP |
212 | |
213 | r = validate_request_name_parameters(bus, name, flags, ¶m); | |
214 | if (r < 0) | |
215 | return r; | |
216 | ||
217 | return sd_bus_call_method_async( | |
218 | bus, | |
219 | ret_slot, | |
220 | "org.freedesktop.DBus", | |
221 | "/org/freedesktop/DBus", | |
222 | "org.freedesktop.DBus", | |
223 | "RequestName", | |
224 | callback ?: default_request_name_handler, | |
225 | userdata, | |
226 | "su", | |
227 | name, | |
228 | param); | |
229 | } | |
230 | ||
231 | static int validate_release_name_parameters( | |
232 | sd_bus *bus, | |
233 | const char *name) { | |
234 | ||
235 | assert(bus); | |
236 | assert(name); | |
237 | ||
45fd5e4d LP |
238 | assert_return(service_name_is_valid(name), -EINVAL); |
239 | assert_return(name[0] != ':', -EINVAL); | |
de1c301e | 240 | |
33c62dcb LP |
241 | if (!bus->bus_client) |
242 | return -EINVAL; | |
243 | ||
e8bd7b09 | 244 | /* Don't allow releasing the special driver and local names */ |
210a6882 LP |
245 | if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local")) |
246 | return -EINVAL; | |
247 | ||
a3d59cd1 LP |
248 | if (!BUS_IS_OPEN(bus->state)) |
249 | return -ENOTCONN; | |
250 | ||
98c5bbc8 LP |
251 | return 0; |
252 | } | |
253 | ||
254 | _public_ int sd_bus_release_name( | |
255 | sd_bus *bus, | |
256 | const char *name) { | |
257 | ||
258 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; | |
259 | uint32_t ret; | |
260 | int r; | |
261 | ||
262 | assert_return(bus, -EINVAL); | |
263 | assert_return(name, -EINVAL); | |
264 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
265 | ||
266 | r = validate_release_name_parameters(bus, name); | |
267 | if (r < 0) | |
268 | return r; | |
269 | ||
e7176abb LP |
270 | r = sd_bus_call_method( |
271 | bus, | |
272 | "org.freedesktop.DBus", | |
cd789fdf | 273 | "/org/freedesktop/DBus", |
e7176abb LP |
274 | "org.freedesktop.DBus", |
275 | "ReleaseName", | |
276 | NULL, | |
277 | &reply, | |
278 | "s", | |
279 | name); | |
280 | if (r < 0) | |
281 | return r; | |
282 | ||
283 | r = sd_bus_message_read(reply, "u", &ret); | |
284 | if (r < 0) | |
285 | return r; | |
98c5bbc8 LP |
286 | |
287 | switch (ret) { | |
288 | ||
289 | case BUS_NAME_NON_EXISTENT: | |
043ccd83 | 290 | return -ESRCH; |
98c5bbc8 LP |
291 | |
292 | case BUS_NAME_NOT_OWNER: | |
043ccd83 | 293 | return -EADDRINUSE; |
98c5bbc8 LP |
294 | |
295 | case BUS_NAME_RELEASED: | |
e7176abb | 296 | return 0; |
98c5bbc8 LP |
297 | } |
298 | ||
299 | return -EIO; | |
300 | } | |
301 | ||
302 | static int default_release_name_handler( | |
303 | sd_bus_message *m, | |
304 | void *userdata, | |
305 | sd_bus_error *ret_error) { | |
306 | ||
307 | uint32_t ret; | |
308 | int r; | |
309 | ||
310 | assert(m); | |
311 | ||
312 | if (sd_bus_message_is_method_error(m, NULL)) { | |
313 | log_debug_errno(sd_bus_message_get_errno(m), | |
314 | "Unable to release name, failing connection: %s", | |
315 | sd_bus_message_get_error(m)->message); | |
e7176abb | 316 | |
98c5bbc8 LP |
317 | bus_enter_closing(sd_bus_message_get_bus(m)); |
318 | return 1; | |
319 | } | |
320 | ||
321 | r = sd_bus_message_read(m, "u", &ret); | |
322 | if (r < 0) | |
323 | return r; | |
324 | ||
325 | switch (ret) { | |
326 | ||
327 | case BUS_NAME_NON_EXISTENT: | |
328 | log_debug("Name asked to release is not taken currently, ignoring."); | |
329 | return 1; | |
330 | ||
331 | case BUS_NAME_NOT_OWNER: | |
332 | log_debug("Name asked to release is owned by somebody else, ignoring."); | |
333 | return 1; | |
334 | ||
335 | case BUS_NAME_RELEASED: | |
336 | log_debug("Name successfully released."); | |
337 | return 1; | |
338 | } | |
339 | ||
340 | log_debug("Unexpected response from ReleaseName(), failing connection."); | |
341 | bus_enter_closing(sd_bus_message_get_bus(m)); | |
342 | return 1; | |
343 | } | |
344 | ||
345 | _public_ int sd_bus_release_name_async( | |
346 | sd_bus *bus, | |
347 | sd_bus_slot **ret_slot, | |
348 | const char *name, | |
349 | sd_bus_message_handler_t callback, | |
350 | void *userdata) { | |
351 | ||
352 | int r; | |
353 | ||
354 | assert_return(bus, -EINVAL); | |
355 | assert_return(name, -EINVAL); | |
356 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
357 | ||
358 | r = validate_release_name_parameters(bus, name); | |
359 | if (r < 0) | |
360 | return r; | |
361 | ||
362 | return sd_bus_call_method_async( | |
363 | bus, | |
364 | ret_slot, | |
365 | "org.freedesktop.DBus", | |
366 | "/org/freedesktop/DBus", | |
367 | "org.freedesktop.DBus", | |
368 | "ReleaseName", | |
369 | callback ?: default_release_name_handler, | |
370 | userdata, | |
371 | "s", | |
372 | name); | |
e7176abb LP |
373 | } |
374 | ||
e8bd7b09 LP |
375 | _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) { |
376 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; | |
377 | _cleanup_strv_free_ char **x = NULL, **y = NULL; | |
378 | int r; | |
379 | ||
9bb058a1 | 380 | assert_return(bus, -EINVAL); |
e8bd7b09 | 381 | assert_return(acquired || activatable, -EINVAL); |
9bb058a1 | 382 | assert_return(!bus_pid_changed(bus), -ECHILD); |
de1c301e | 383 | |
33c62dcb LP |
384 | if (!bus->bus_client) |
385 | return -EINVAL; | |
386 | ||
a3d59cd1 LP |
387 | if (!BUS_IS_OPEN(bus->state)) |
388 | return -ENOTCONN; | |
389 | ||
71f2ab46 LP |
390 | if (acquired) { |
391 | r = sd_bus_call_method( | |
392 | bus, | |
393 | "org.freedesktop.DBus", | |
cd789fdf | 394 | "/org/freedesktop/DBus", |
71f2ab46 LP |
395 | "org.freedesktop.DBus", |
396 | "ListNames", | |
397 | NULL, | |
398 | &reply, | |
399 | NULL); | |
400 | if (r < 0) | |
401 | return r; | |
402 | ||
403 | r = sd_bus_message_read_strv(reply, &x); | |
404 | if (r < 0) | |
405 | return r; | |
406 | ||
407 | reply = sd_bus_message_unref(reply); | |
408 | } | |
409 | ||
410 | if (activatable) { | |
411 | r = sd_bus_call_method( | |
412 | bus, | |
413 | "org.freedesktop.DBus", | |
cd789fdf | 414 | "/org/freedesktop/DBus", |
71f2ab46 LP |
415 | "org.freedesktop.DBus", |
416 | "ListActivatableNames", | |
417 | NULL, | |
418 | &reply, | |
419 | NULL); | |
420 | if (r < 0) | |
421 | return r; | |
422 | ||
423 | r = sd_bus_message_read_strv(reply, &y); | |
424 | if (r < 0) | |
425 | return r; | |
426 | ||
427 | *activatable = y; | |
428 | y = NULL; | |
429 | } | |
430 | ||
431 | if (acquired) { | |
432 | *acquired = x; | |
433 | x = NULL; | |
a4297f08 | 434 | } |
de1c301e | 435 | |
49b832c5 LP |
436 | return 0; |
437 | } | |
438 | ||
e8bd7b09 | 439 | _public_ int sd_bus_get_name_creds( |
e7176abb LP |
440 | sd_bus *bus, |
441 | const char *name, | |
442 | uint64_t mask, | |
443 | sd_bus_creds **creds) { | |
444 | ||
4afd3348 LP |
445 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL; |
446 | _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; | |
e7176abb LP |
447 | const char *unique = NULL; |
448 | pid_t pid = 0; | |
449 | int r; | |
450 | ||
e8bd7b09 LP |
451 | assert_return(bus, -EINVAL); |
452 | assert_return(name, -EINVAL); | |
453 | assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP); | |
454 | assert_return(mask == 0 || creds, -EINVAL); | |
455 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
456 | assert_return(service_name_is_valid(name), -EINVAL); | |
457 | ||
458 | if (!bus->bus_client) | |
459 | return -EINVAL; | |
460 | ||
461 | /* Turn off augmenting if this isn't a local connection. If the connection is not local, then /proc is not | |
462 | * going to match. */ | |
463 | if (!bus->is_local) | |
464 | mask &= ~SD_BUS_CREDS_AUGMENT; | |
465 | ||
466 | if (streq(name, "org.freedesktop.DBus.Local")) | |
467 | return -EINVAL; | |
468 | ||
469 | if (streq(name, "org.freedesktop.DBus")) | |
470 | return sd_bus_get_owner_creds(bus, mask, creds); | |
471 | ||
472 | if (!BUS_IS_OPEN(bus->state)) | |
473 | return -ENOTCONN; | |
474 | ||
e7176abb LP |
475 | /* Only query the owner if the caller wants to know it or if |
476 | * the caller just wants to check whether a name exists */ | |
477 | if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) { | |
478 | r = sd_bus_call_method( | |
479 | bus, | |
480 | "org.freedesktop.DBus", | |
cd789fdf | 481 | "/org/freedesktop/DBus", |
e7176abb LP |
482 | "org.freedesktop.DBus", |
483 | "GetNameOwner", | |
484 | NULL, | |
485 | &reply_unique, | |
486 | "s", | |
487 | name); | |
488 | if (r < 0) | |
489 | return r; | |
490 | ||
491 | r = sd_bus_message_read(reply_unique, "s", &unique); | |
492 | if (r < 0) | |
493 | return r; | |
494 | } | |
495 | ||
496 | if (mask != 0) { | |
40f35505 LP |
497 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
498 | bool need_pid, need_uid, need_selinux, need_separate_calls; | |
e7176abb LP |
499 | c = bus_creds_new(); |
500 | if (!c) | |
501 | return -ENOMEM; | |
502 | ||
503 | if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) { | |
504 | c->unique_name = strdup(unique); | |
505 | if (!c->unique_name) | |
506 | return -ENOMEM; | |
507 | ||
508 | c->mask |= SD_BUS_CREDS_UNIQUE_NAME; | |
509 | } | |
49b832c5 | 510 | |
40f35505 LP |
511 | need_pid = (mask & SD_BUS_CREDS_PID) || |
512 | ((mask & SD_BUS_CREDS_AUGMENT) && | |
513 | (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID| | |
514 | SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID| | |
515 | SD_BUS_CREDS_SUPPLEMENTARY_GIDS| | |
516 | SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE| | |
517 | SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID| | |
518 | SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS| | |
519 | SD_BUS_CREDS_SELINUX_CONTEXT| | |
520 | SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))); | |
521 | need_uid = mask & SD_BUS_CREDS_EUID; | |
522 | need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT; | |
705a415f | 523 | |
40f35505 LP |
524 | if (need_pid + need_uid + need_selinux > 1) { |
525 | ||
526 | /* If we need more than one of the credentials, then use GetConnectionCredentials() */ | |
49b832c5 | 527 | |
e7176abb LP |
528 | r = sd_bus_call_method( |
529 | bus, | |
530 | "org.freedesktop.DBus", | |
cd789fdf | 531 | "/org/freedesktop/DBus", |
e7176abb | 532 | "org.freedesktop.DBus", |
40f35505 LP |
533 | "GetConnectionCredentials", |
534 | &error, | |
e7176abb LP |
535 | &reply, |
536 | "s", | |
40f35505 | 537 | unique ?: name); |
49b832c5 | 538 | |
40f35505 | 539 | if (r < 0) { |
e7176abb | 540 | |
40f35505 LP |
541 | if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) |
542 | return r; | |
49b832c5 | 543 | |
40f35505 LP |
544 | /* If we got an unknown method error, fall back to the invidual calls... */ |
545 | need_separate_calls = true; | |
546 | sd_bus_error_free(&error); | |
49b832c5 | 547 | |
40f35505 LP |
548 | } else { |
549 | need_separate_calls = false; | |
49b832c5 | 550 | |
40f35505 LP |
551 | r = sd_bus_message_enter_container(reply, 'a', "{sv}"); |
552 | if (r < 0) | |
553 | return r; | |
49b832c5 | 554 | |
40f35505 LP |
555 | for (;;) { |
556 | const char *m; | |
49b832c5 | 557 | |
40f35505 LP |
558 | r = sd_bus_message_enter_container(reply, 'e', "sv"); |
559 | if (r < 0) | |
560 | return r; | |
561 | if (r == 0) | |
562 | break; | |
49b832c5 | 563 | |
40f35505 LP |
564 | r = sd_bus_message_read(reply, "s", &m); |
565 | if (r < 0) | |
566 | return r; | |
49b832c5 | 567 | |
40f35505 LP |
568 | if (need_uid && streq(m, "UnixUserID")) { |
569 | uint32_t u; | |
49b832c5 | 570 | |
40f35505 LP |
571 | r = sd_bus_message_read(reply, "v", "u", &u); |
572 | if (r < 0) | |
573 | return r; | |
574 | ||
575 | c->euid = u; | |
576 | c->mask |= SD_BUS_CREDS_EUID; | |
577 | ||
578 | } else if (need_pid && streq(m, "ProcessID")) { | |
579 | uint32_t p; | |
580 | ||
581 | r = sd_bus_message_read(reply, "v", "u", &p); | |
582 | if (r < 0) | |
583 | return r; | |
584 | ||
585 | pid = p; | |
586 | if (mask & SD_BUS_CREDS_PID) { | |
587 | c->pid = p; | |
588 | c->mask |= SD_BUS_CREDS_PID; | |
589 | } | |
590 | ||
591 | } else if (need_selinux && streq(m, "LinuxSecurityLabel")) { | |
592 | const void *p = NULL; | |
593 | size_t sz = 0; | |
594 | ||
595 | r = sd_bus_message_enter_container(reply, 'v', "ay"); | |
596 | if (r < 0) | |
597 | return r; | |
598 | ||
599 | r = sd_bus_message_read_array(reply, 'y', &p, &sz); | |
600 | if (r < 0) | |
601 | return r; | |
602 | ||
603 | free(c->label); | |
604 | c->label = strndup(p, sz); | |
605 | if (!c->label) | |
606 | return -ENOMEM; | |
607 | ||
608 | c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; | |
609 | ||
610 | r = sd_bus_message_exit_container(reply); | |
611 | if (r < 0) | |
612 | return r; | |
613 | } else { | |
614 | r = sd_bus_message_skip(reply, "v"); | |
615 | if (r < 0) | |
616 | return r; | |
617 | } | |
618 | ||
619 | r = sd_bus_message_exit_container(reply); | |
620 | if (r < 0) | |
621 | return r; | |
622 | } | |
623 | ||
624 | r = sd_bus_message_exit_container(reply); | |
625 | if (r < 0) | |
359c09b1 | 626 | return r; |
40f35505 LP |
627 | |
628 | if (need_pid && pid == 0) | |
629 | return -EPROTO; | |
630 | } | |
631 | ||
632 | } else /* When we only need a single field, then let's use separate calls */ | |
633 | need_separate_calls = true; | |
634 | ||
635 | if (need_separate_calls) { | |
636 | if (need_pid) { | |
637 | uint32_t u; | |
638 | ||
639 | r = sd_bus_call_method( | |
640 | bus, | |
641 | "org.freedesktop.DBus", | |
642 | "/org/freedesktop/DBus", | |
643 | "org.freedesktop.DBus", | |
644 | "GetConnectionUnixProcessID", | |
645 | NULL, | |
646 | &reply, | |
647 | "s", | |
648 | unique ?: name); | |
359c09b1 LP |
649 | if (r < 0) |
650 | return r; | |
e7176abb | 651 | |
40f35505 LP |
652 | r = sd_bus_message_read(reply, "u", &u); |
653 | if (r < 0) | |
654 | return r; | |
e7176abb | 655 | |
40f35505 LP |
656 | pid = u; |
657 | if (mask & SD_BUS_CREDS_PID) { | |
658 | c->pid = u; | |
659 | c->mask |= SD_BUS_CREDS_PID; | |
660 | } | |
661 | ||
662 | reply = sd_bus_message_unref(reply); | |
663 | } | |
664 | ||
665 | if (need_uid) { | |
666 | uint32_t u; | |
667 | ||
668 | r = sd_bus_call_method( | |
669 | bus, | |
670 | "org.freedesktop.DBus", | |
671 | "/org/freedesktop/DBus", | |
672 | "org.freedesktop.DBus", | |
673 | "GetConnectionUnixUser", | |
674 | NULL, | |
675 | &reply, | |
676 | "s", | |
677 | unique ? unique : name); | |
678 | if (r < 0) | |
679 | return r; | |
680 | ||
681 | r = sd_bus_message_read(reply, "u", &u); | |
682 | if (r < 0) | |
683 | return r; | |
684 | ||
685 | c->euid = u; | |
686 | c->mask |= SD_BUS_CREDS_EUID; | |
687 | ||
688 | reply = sd_bus_message_unref(reply); | |
689 | } | |
690 | ||
691 | if (need_selinux) { | |
692 | const void *p = NULL; | |
693 | size_t sz = 0; | |
694 | ||
695 | r = sd_bus_call_method( | |
696 | bus, | |
697 | "org.freedesktop.DBus", | |
698 | "/org/freedesktop/DBus", | |
699 | "org.freedesktop.DBus", | |
700 | "GetConnectionSELinuxSecurityContext", | |
701 | &error, | |
702 | &reply, | |
703 | "s", | |
704 | unique ? unique : name); | |
705 | if (r < 0) { | |
706 | if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown")) | |
707 | return r; | |
708 | ||
709 | /* no data is fine */ | |
710 | } else { | |
711 | r = sd_bus_message_read_array(reply, 'y', &p, &sz); | |
712 | if (r < 0) | |
713 | return r; | |
714 | ||
715 | c->label = strndup(p, sz); | |
716 | if (!c->label) | |
717 | return -ENOMEM; | |
718 | ||
719 | c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; | |
720 | } | |
359c09b1 | 721 | } |
49b832c5 | 722 | } |
e7176abb LP |
723 | |
724 | r = bus_creds_add_more(c, mask, pid, 0); | |
725 | if (r < 0) | |
726 | return r; | |
49b832c5 LP |
727 | } |
728 | ||
729 | if (creds) { | |
730 | *creds = c; | |
731 | c = NULL; | |
732 | } | |
733 | ||
e7176abb | 734 | return 0; |
49b832c5 LP |
735 | } |
736 | ||
e8bd7b09 LP |
737 | _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { |
738 | _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; | |
739 | bool do_label, do_groups; | |
740 | pid_t pid = 0; | |
741 | int r; | |
49b832c5 LP |
742 | |
743 | assert_return(bus, -EINVAL); | |
15411c0c | 744 | assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP); |
e8bd7b09 | 745 | assert_return(ret, -EINVAL); |
49b832c5 | 746 | assert_return(!bus_pid_changed(bus), -ECHILD); |
51c7d5aa | 747 | |
a3d59cd1 LP |
748 | if (!BUS_IS_OPEN(bus->state)) |
749 | return -ENOTCONN; | |
750 | ||
e8bd7b09 LP |
751 | if (!bus->is_local) |
752 | mask &= ~SD_BUS_CREDS_AUGMENT; | |
7fc04b12 LP |
753 | |
754 | do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT); | |
18ac4643 | 755 | do_groups = bus->n_groups != (size_t) -1 && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS); |
8f44e3ea | 756 | |
c4e6556c | 757 | /* Avoid allocating anything if we have no chance of returning useful data */ |
18ac4643 | 758 | if (!bus->ucred_valid && !do_label && !do_groups) |
8f44e3ea DM |
759 | return -ENODATA; |
760 | ||
761 | c = bus_creds_new(); | |
762 | if (!c) | |
763 | return -ENOMEM; | |
764 | ||
765 | if (bus->ucred_valid) { | |
bbcc701e | 766 | if (pid_is_valid(bus->ucred.pid)) { |
52cfc037 LP |
767 | pid = c->pid = bus->ucred.pid; |
768 | c->mask |= SD_BUS_CREDS_PID & mask; | |
769 | } | |
8f44e3ea | 770 | |
bbcc701e | 771 | if (uid_is_valid(bus->ucred.uid)) { |
05bae4a6 DH |
772 | c->euid = bus->ucred.uid; |
773 | c->mask |= SD_BUS_CREDS_EUID & mask; | |
52cfc037 LP |
774 | } |
775 | ||
bbcc701e | 776 | if (gid_is_valid(bus->ucred.gid)) { |
05bae4a6 DH |
777 | c->egid = bus->ucred.gid; |
778 | c->mask |= SD_BUS_CREDS_EGID & mask; | |
52cfc037 | 779 | } |
8f44e3ea DM |
780 | } |
781 | ||
c4e6556c | 782 | if (do_label) { |
8f44e3ea | 783 | c->label = strdup(bus->label); |
505e77ca | 784 | if (!c->label) |
8f44e3ea | 785 | return -ENOMEM; |
8f44e3ea DM |
786 | |
787 | c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; | |
788 | } | |
789 | ||
18ac4643 LP |
790 | if (do_groups) { |
791 | c->supplementary_gids = newdup(gid_t, bus->groups, bus->n_groups); | |
792 | if (!c->supplementary_gids) | |
793 | return -ENOMEM; | |
794 | ||
795 | c->n_supplementary_gids = bus->n_groups; | |
796 | ||
797 | c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS; | |
798 | } | |
799 | ||
705a415f LP |
800 | r = bus_creds_add_more(c, mask, pid, 0); |
801 | if (r < 0) | |
802 | return r; | |
803 | ||
8f44e3ea | 804 | *ret = c; |
505e77ca | 805 | c = NULL; |
8f44e3ea DM |
806 | return 0; |
807 | } | |
808 | ||
e8bd7b09 | 809 | #define append_eavesdrop(bus, m) \ |
c7db1984 | 810 | ((bus)->is_monitor \ |
63c372cb | 811 | ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \ |
09365592 LP |
812 | : (m)) |
813 | ||
e8bd7b09 | 814 | int bus_add_match_internal( |
e7176abb | 815 | sd_bus *bus, |
0259b87f | 816 | const char *match) { |
777d7a61 | 817 | |
09365592 LP |
818 | const char *e; |
819 | ||
e7176abb | 820 | assert(bus); |
777d7a61 | 821 | |
e8bd7b09 LP |
822 | if (!bus->bus_client) |
823 | return -EINVAL; | |
824 | ||
825 | e = append_eavesdrop(bus, match); | |
09365592 | 826 | |
e7176abb LP |
827 | return sd_bus_call_method( |
828 | bus, | |
829 | "org.freedesktop.DBus", | |
cd789fdf | 830 | "/org/freedesktop/DBus", |
e7176abb LP |
831 | "org.freedesktop.DBus", |
832 | "AddMatch", | |
833 | NULL, | |
834 | NULL, | |
835 | "s", | |
09365592 | 836 | e); |
7593c7a4 LP |
837 | } |
838 | int bus_add_match_internal_async( | |
839 | sd_bus *bus, | |
840 | sd_bus_slot **ret_slot, | |
841 | const char *match, | |
842 | sd_bus_message_handler_t callback, | |
843 | void *userdata) { | |
844 | ||
845 | const char *e; | |
846 | ||
847 | assert(bus); | |
848 | ||
849 | if (!bus->bus_client) | |
850 | return -EINVAL; | |
851 | ||
852 | e = append_eavesdrop(bus, match); | |
853 | ||
854 | return sd_bus_call_method_async( | |
855 | bus, | |
856 | ret_slot, | |
857 | "org.freedesktop.DBus", | |
858 | "/org/freedesktop/DBus", | |
859 | "org.freedesktop.DBus", | |
860 | "AddMatch", | |
861 | callback, | |
862 | userdata, | |
863 | "s", | |
864 | e); | |
de1c301e LP |
865 | } |
866 | ||
e8bd7b09 | 867 | int bus_remove_match_internal( |
e7176abb LP |
868 | sd_bus *bus, |
869 | const char *match) { | |
777d7a61 | 870 | |
09365592 LP |
871 | const char *e; |
872 | ||
e7176abb LP |
873 | assert(bus); |
874 | assert(match); | |
875 | ||
e8bd7b09 LP |
876 | if (!bus->bus_client) |
877 | return -EINVAL; | |
878 | ||
879 | e = append_eavesdrop(bus, match); | |
09365592 | 880 | |
acd34015 LP |
881 | /* Fire and forget */ |
882 | ||
883 | return sd_bus_call_method_async( | |
e7176abb | 884 | bus, |
acd34015 | 885 | NULL, |
e7176abb | 886 | "org.freedesktop.DBus", |
cd789fdf | 887 | "/org/freedesktop/DBus", |
e7176abb LP |
888 | "org.freedesktop.DBus", |
889 | "RemoveMatch", | |
890 | NULL, | |
891 | NULL, | |
892 | "s", | |
09365592 | 893 | e); |
e7176abb LP |
894 | } |
895 | ||
056f95d0 | 896 | _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) { |
4afd3348 | 897 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; |
70666185 LP |
898 | const char *mid; |
899 | int r; | |
900 | ||
8d162091 LP |
901 | assert_return(bus, -EINVAL); |
902 | assert_return(name, -EINVAL); | |
903 | assert_return(machine, -EINVAL); | |
8d162091 | 904 | assert_return(!bus_pid_changed(bus), -ECHILD); |
45fd5e4d | 905 | assert_return(service_name_is_valid(name), -EINVAL); |
70666185 | 906 | |
33c62dcb LP |
907 | if (!bus->bus_client) |
908 | return -EINVAL; | |
909 | ||
a3d59cd1 LP |
910 | if (!BUS_IS_OPEN(bus->state)) |
911 | return -ENOTCONN; | |
912 | ||
70666185 LP |
913 | if (streq_ptr(name, bus->unique_name)) |
914 | return sd_id128_get_machine(machine); | |
915 | ||
8d162091 LP |
916 | r = sd_bus_message_new_method_call( |
917 | bus, | |
151b9b96 | 918 | &m, |
8d162091 LP |
919 | name, |
920 | "/", | |
921 | "org.freedesktop.DBus.Peer", | |
151b9b96 | 922 | "GetMachineId"); |
8d162091 LP |
923 | if (r < 0) |
924 | return r; | |
925 | ||
eee9ec0e | 926 | r = sd_bus_message_set_auto_start(m, false); |
8d162091 LP |
927 | if (r < 0) |
928 | return r; | |
70666185 | 929 | |
8d162091 | 930 | r = sd_bus_call(bus, m, 0, NULL, &reply); |
70666185 LP |
931 | if (r < 0) |
932 | return r; | |
933 | ||
934 | r = sd_bus_message_read(reply, "s", &mid); | |
935 | if (r < 0) | |
936 | return r; | |
937 | ||
938 | return sd_id128_from_string(mid, machine); | |
939 | } |