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