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