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