]>
Commit | Line | Data |
---|---|---|
60f067b4 JS |
1 | /*** |
2 | This file is part of systemd. | |
3 | ||
4 | Copyright 2013 Lennart Poettering | |
5 | ||
6 | systemd is free software; you can redistribute it and/or modify it | |
7 | under the terms of the GNU Lesser General Public License as published by | |
8 | the Free Software Foundation; either version 2.1 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | systemd is distributed in the hope that it will be useful, but | |
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | Lesser General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU Lesser General Public License | |
17 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
18 | ***/ | |
19 | ||
20 | #ifdef HAVE_VALGRIND_MEMCHECK_H | |
21 | #include <valgrind/memcheck.h> | |
22 | #endif | |
23 | ||
60f067b4 | 24 | #include <errno.h> |
db2df898 | 25 | #include <stddef.h> |
60f067b4 | 26 | |
60f067b4 | 27 | #include "sd-bus.h" |
db2df898 MP |
28 | |
29 | #include "alloc-util.h" | |
30 | #include "bus-bloom.h" | |
31 | #include "bus-control.h" | |
60f067b4 JS |
32 | #include "bus-internal.h" |
33 | #include "bus-message.h" | |
60f067b4 | 34 | #include "bus-util.h" |
db2df898 MP |
35 | #include "capability-util.h" |
36 | #include "stdio-util.h" | |
37 | #include "string-util.h" | |
38 | #include "strv.h" | |
39 | #include "user-util.h" | |
60f067b4 JS |
40 | |
41 | _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) { | |
42 | int r; | |
43 | ||
44 | assert_return(bus, -EINVAL); | |
45 | assert_return(unique, -EINVAL); | |
46 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
47 | ||
e3bff60a MP |
48 | if (!bus->bus_client) |
49 | return -EINVAL; | |
50 | ||
60f067b4 JS |
51 | r = bus_ensure_running(bus); |
52 | if (r < 0) | |
53 | return r; | |
54 | ||
55 | *unique = bus->unique_name; | |
56 | return 0; | |
57 | } | |
58 | ||
59 | static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) { | |
e735f4d4 | 60 | struct kdbus_cmd *n; |
60f067b4 JS |
61 | size_t size, l; |
62 | int r; | |
63 | ||
64 | assert(bus); | |
65 | assert(name); | |
66 | ||
5eef597e | 67 | l = strlen(name) + 1; |
e735f4d4 | 68 | size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l); |
5eef597e | 69 | n = alloca0_align(size, 8); |
60f067b4 | 70 | n->size = size; |
f47781d8 | 71 | n->flags = request_name_flags_to_kdbus(flags); |
5eef597e MP |
72 | |
73 | n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l; | |
74 | n->items[0].type = KDBUS_ITEM_NAME; | |
75 | memcpy(n->items[0].str, name, l); | |
60f067b4 JS |
76 | |
77 | #ifdef HAVE_VALGRIND_MEMCHECK_H | |
78 | VALGRIND_MAKE_MEM_DEFINED(n, n->size); | |
79 | #endif | |
80 | ||
81 | r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n); | |
82 | if (r < 0) | |
83 | return -errno; | |
84 | ||
e3bff60a | 85 | if (n->return_flags & KDBUS_NAME_IN_QUEUE) |
60f067b4 JS |
86 | return 0; |
87 | ||
88 | return 1; | |
89 | } | |
90 | ||
91 | static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) { | |
4c89c718 | 92 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; |
60f067b4 JS |
93 | uint32_t ret, param = 0; |
94 | int r; | |
95 | ||
96 | assert(bus); | |
97 | assert(name); | |
98 | ||
99 | if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT) | |
100 | param |= BUS_NAME_ALLOW_REPLACEMENT; | |
101 | if (flags & SD_BUS_NAME_REPLACE_EXISTING) | |
102 | param |= BUS_NAME_REPLACE_EXISTING; | |
103 | if (!(flags & SD_BUS_NAME_QUEUE)) | |
104 | param |= BUS_NAME_DO_NOT_QUEUE; | |
105 | ||
106 | r = sd_bus_call_method( | |
107 | bus, | |
108 | "org.freedesktop.DBus", | |
109 | "/org/freedesktop/DBus", | |
110 | "org.freedesktop.DBus", | |
111 | "RequestName", | |
112 | NULL, | |
113 | &reply, | |
114 | "su", | |
115 | name, | |
116 | param); | |
117 | if (r < 0) | |
118 | return r; | |
119 | ||
120 | r = sd_bus_message_read(reply, "u", &ret); | |
121 | if (r < 0) | |
122 | return r; | |
123 | ||
124 | if (ret == BUS_NAME_ALREADY_OWNER) | |
125 | return -EALREADY; | |
126 | else if (ret == BUS_NAME_EXISTS) | |
127 | return -EEXIST; | |
128 | else if (ret == BUS_NAME_IN_QUEUE) | |
129 | return 0; | |
130 | else if (ret == BUS_NAME_PRIMARY_OWNER) | |
131 | return 1; | |
132 | ||
133 | return -EIO; | |
134 | } | |
135 | ||
136 | _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) { | |
137 | assert_return(bus, -EINVAL); | |
138 | assert_return(name, -EINVAL); | |
60f067b4 JS |
139 | assert_return(!bus_pid_changed(bus), -ECHILD); |
140 | assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL); | |
141 | assert_return(service_name_is_valid(name), -EINVAL); | |
142 | assert_return(name[0] != ':', -EINVAL); | |
143 | ||
e3bff60a MP |
144 | if (!bus->bus_client) |
145 | return -EINVAL; | |
146 | ||
e735f4d4 MP |
147 | /* Don't allow requesting the special driver and local names */ |
148 | if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local")) | |
149 | return -EINVAL; | |
150 | ||
60f067b4 JS |
151 | if (!BUS_IS_OPEN(bus->state)) |
152 | return -ENOTCONN; | |
153 | ||
154 | if (bus->is_kernel) | |
155 | return bus_request_name_kernel(bus, name, flags); | |
156 | else | |
157 | return bus_request_name_dbus1(bus, name, flags); | |
158 | } | |
159 | ||
160 | static int bus_release_name_kernel(sd_bus *bus, const char *name) { | |
e735f4d4 | 161 | struct kdbus_cmd *n; |
5eef597e | 162 | size_t size, l; |
60f067b4 JS |
163 | int r; |
164 | ||
165 | assert(bus); | |
166 | assert(name); | |
167 | ||
5eef597e | 168 | l = strlen(name) + 1; |
e735f4d4 | 169 | size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l); |
5eef597e MP |
170 | n = alloca0_align(size, 8); |
171 | n->size = size; | |
172 | ||
173 | n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l; | |
174 | n->items[0].type = KDBUS_ITEM_NAME; | |
175 | memcpy(n->items[0].str, name, l); | |
60f067b4 JS |
176 | |
177 | #ifdef HAVE_VALGRIND_MEMCHECK_H | |
178 | VALGRIND_MAKE_MEM_DEFINED(n, n->size); | |
179 | #endif | |
180 | r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n); | |
181 | if (r < 0) | |
182 | return -errno; | |
183 | ||
5eef597e | 184 | return 0; |
60f067b4 JS |
185 | } |
186 | ||
187 | static int bus_release_name_dbus1(sd_bus *bus, const char *name) { | |
4c89c718 | 188 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; |
60f067b4 JS |
189 | uint32_t ret; |
190 | int r; | |
191 | ||
192 | assert(bus); | |
193 | assert(name); | |
194 | ||
195 | r = sd_bus_call_method( | |
196 | bus, | |
197 | "org.freedesktop.DBus", | |
198 | "/org/freedesktop/DBus", | |
199 | "org.freedesktop.DBus", | |
200 | "ReleaseName", | |
201 | NULL, | |
202 | &reply, | |
203 | "s", | |
204 | name); | |
205 | if (r < 0) | |
206 | return r; | |
207 | ||
208 | r = sd_bus_message_read(reply, "u", &ret); | |
209 | if (r < 0) | |
210 | return r; | |
211 | if (ret == BUS_NAME_NON_EXISTENT) | |
212 | return -ESRCH; | |
213 | if (ret == BUS_NAME_NOT_OWNER) | |
214 | return -EADDRINUSE; | |
215 | if (ret == BUS_NAME_RELEASED) | |
216 | return 0; | |
217 | ||
218 | return -EINVAL; | |
219 | } | |
220 | ||
221 | _public_ int sd_bus_release_name(sd_bus *bus, const char *name) { | |
222 | assert_return(bus, -EINVAL); | |
223 | assert_return(name, -EINVAL); | |
60f067b4 JS |
224 | assert_return(!bus_pid_changed(bus), -ECHILD); |
225 | assert_return(service_name_is_valid(name), -EINVAL); | |
226 | assert_return(name[0] != ':', -EINVAL); | |
227 | ||
e3bff60a MP |
228 | if (!bus->bus_client) |
229 | return -EINVAL; | |
230 | ||
e735f4d4 MP |
231 | /* Don't allow releasing the special driver and local names */ |
232 | if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local")) | |
233 | return -EINVAL; | |
234 | ||
60f067b4 JS |
235 | if (!BUS_IS_OPEN(bus->state)) |
236 | return -ENOTCONN; | |
237 | ||
238 | if (bus->is_kernel) | |
239 | return bus_release_name_kernel(bus, name); | |
240 | else | |
241 | return bus_release_name_dbus1(bus, name); | |
242 | } | |
243 | ||
244 | static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { | |
e735f4d4 MP |
245 | struct kdbus_cmd_list cmd = { |
246 | .size = sizeof(cmd), | |
247 | .flags = flags, | |
248 | }; | |
249 | struct kdbus_info *name_list, *name; | |
60f067b4 JS |
250 | uint64_t previous_id = 0; |
251 | int r; | |
252 | ||
253 | /* Caller will free half-constructed list on failure... */ | |
254 | ||
e735f4d4 | 255 | r = ioctl(bus->input_fd, KDBUS_CMD_LIST, &cmd); |
60f067b4 JS |
256 | if (r < 0) |
257 | return -errno; | |
258 | ||
e735f4d4 | 259 | name_list = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset); |
60f067b4 | 260 | |
e735f4d4 | 261 | KDBUS_FOREACH(name, name_list, cmd.list_size) { |
5eef597e | 262 | struct kdbus_item *item; |
5eef597e | 263 | |
13d276d0 | 264 | if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id && !(name->flags & KDBUS_HELLO_ACTIVATOR)) { |
60f067b4 JS |
265 | char *n; |
266 | ||
e735f4d4 | 267 | if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) { |
5eef597e MP |
268 | r = -ENOMEM; |
269 | goto fail; | |
270 | } | |
60f067b4 JS |
271 | |
272 | r = strv_consume(x, n); | |
273 | if (r < 0) | |
5eef597e | 274 | goto fail; |
60f067b4 | 275 | |
e735f4d4 | 276 | previous_id = name->id; |
60f067b4 JS |
277 | } |
278 | ||
5fd56512 MP |
279 | KDBUS_ITEM_FOREACH(item, name, items) { |
280 | if (item->type == KDBUS_ITEM_OWNED_NAME) { | |
281 | if (service_name_is_valid(item->name.name)) { | |
282 | r = strv_extend(x, item->name.name); | |
283 | if (r < 0) { | |
284 | r = -ENOMEM; | |
285 | goto fail; | |
286 | } | |
287 | } | |
5eef597e | 288 | } |
60f067b4 JS |
289 | } |
290 | } | |
291 | ||
5eef597e | 292 | r = 0; |
60f067b4 | 293 | |
5eef597e | 294 | fail: |
f47781d8 | 295 | bus_kernel_cmd_free(bus, cmd.offset); |
5eef597e | 296 | return r; |
60f067b4 JS |
297 | } |
298 | ||
299 | static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) { | |
300 | _cleanup_strv_free_ char **x = NULL, **y = NULL; | |
301 | int r; | |
302 | ||
303 | if (acquired) { | |
e735f4d4 | 304 | r = kernel_get_list(bus, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES, &x); |
60f067b4 JS |
305 | if (r < 0) |
306 | return r; | |
307 | } | |
308 | ||
309 | if (activatable) { | |
e735f4d4 | 310 | r = kernel_get_list(bus, KDBUS_LIST_ACTIVATORS, &y); |
60f067b4 JS |
311 | if (r < 0) |
312 | return r; | |
313 | ||
314 | *activatable = y; | |
315 | y = NULL; | |
316 | } | |
317 | ||
318 | if (acquired) { | |
319 | *acquired = x; | |
320 | x = NULL; | |
321 | } | |
322 | ||
323 | return 0; | |
324 | } | |
325 | ||
326 | static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) { | |
4c89c718 | 327 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; |
60f067b4 JS |
328 | _cleanup_strv_free_ char **x = NULL, **y = NULL; |
329 | int r; | |
330 | ||
331 | if (acquired) { | |
332 | r = sd_bus_call_method( | |
333 | bus, | |
334 | "org.freedesktop.DBus", | |
335 | "/org/freedesktop/DBus", | |
336 | "org.freedesktop.DBus", | |
337 | "ListNames", | |
338 | NULL, | |
339 | &reply, | |
340 | NULL); | |
341 | if (r < 0) | |
342 | return r; | |
343 | ||
344 | r = sd_bus_message_read_strv(reply, &x); | |
345 | if (r < 0) | |
346 | return r; | |
347 | ||
348 | reply = sd_bus_message_unref(reply); | |
349 | } | |
350 | ||
351 | if (activatable) { | |
352 | r = sd_bus_call_method( | |
353 | bus, | |
354 | "org.freedesktop.DBus", | |
355 | "/org/freedesktop/DBus", | |
356 | "org.freedesktop.DBus", | |
357 | "ListActivatableNames", | |
358 | NULL, | |
359 | &reply, | |
360 | NULL); | |
361 | if (r < 0) | |
362 | return r; | |
363 | ||
364 | r = sd_bus_message_read_strv(reply, &y); | |
365 | if (r < 0) | |
366 | return r; | |
367 | ||
368 | *activatable = y; | |
369 | y = NULL; | |
370 | } | |
371 | ||
372 | if (acquired) { | |
373 | *acquired = x; | |
374 | x = NULL; | |
375 | } | |
376 | ||
377 | return 0; | |
378 | } | |
379 | ||
380 | _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) { | |
381 | assert_return(bus, -EINVAL); | |
382 | assert_return(acquired || activatable, -EINVAL); | |
383 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
384 | ||
e3bff60a MP |
385 | if (!bus->bus_client) |
386 | return -EINVAL; | |
387 | ||
60f067b4 JS |
388 | if (!BUS_IS_OPEN(bus->state)) |
389 | return -ENOTCONN; | |
390 | ||
391 | if (bus->is_kernel) | |
392 | return bus_list_names_kernel(bus, acquired, activatable); | |
393 | else | |
394 | return bus_list_names_dbus1(bus, acquired, activatable); | |
395 | } | |
396 | ||
f47781d8 MP |
397 | static int bus_populate_creds_from_items( |
398 | sd_bus *bus, | |
399 | struct kdbus_info *info, | |
400 | uint64_t mask, | |
401 | sd_bus_creds *c) { | |
60f067b4 | 402 | |
60f067b4 | 403 | struct kdbus_item *item; |
5eef597e | 404 | uint64_t m; |
60f067b4 JS |
405 | int r; |
406 | ||
f47781d8 MP |
407 | assert(bus); |
408 | assert(info); | |
409 | assert(c); | |
410 | ||
5eef597e | 411 | KDBUS_ITEM_FOREACH(item, info, items) { |
60f067b4 JS |
412 | |
413 | switch (item->type) { | |
414 | ||
f47781d8 MP |
415 | case KDBUS_ITEM_PIDS: |
416 | ||
417 | if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) { | |
418 | c->pid = (pid_t) item->pids.pid; | |
419 | c->mask |= SD_BUS_CREDS_PID; | |
420 | } | |
421 | ||
422 | if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) { | |
423 | c->tid = (pid_t) item->pids.tid; | |
424 | c->mask |= SD_BUS_CREDS_TID; | |
425 | } | |
426 | ||
e3bff60a MP |
427 | if (mask & SD_BUS_CREDS_PPID) { |
428 | if (item->pids.ppid > 0) { | |
429 | c->ppid = (pid_t) item->pids.ppid; | |
430 | c->mask |= SD_BUS_CREDS_PPID; | |
431 | } else if (item->pids.pid == 1) { | |
432 | /* The structure doesn't | |
86f210e9 | 433 | * really distinguish the case |
e3bff60a MP |
434 | * where a process has no |
435 | * parent and where we don't | |
436 | * know it because it could | |
437 | * not be translated due to | |
438 | * namespaces. However, we | |
439 | * know that PID 1 has no | |
440 | * parent process, hence let's | |
441 | * patch that in, manually. */ | |
442 | c->ppid = 0; | |
443 | c->mask |= SD_BUS_CREDS_PPID; | |
444 | } | |
445 | } | |
446 | ||
f47781d8 MP |
447 | break; |
448 | ||
60f067b4 | 449 | case KDBUS_ITEM_CREDS: |
60f067b4 | 450 | |
f47781d8 | 451 | if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) { |
60f067b4 | 452 | c->uid = (uid_t) item->creds.uid; |
f47781d8 MP |
453 | c->mask |= SD_BUS_CREDS_UID; |
454 | } | |
455 | ||
456 | if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) { | |
457 | c->euid = (uid_t) item->creds.euid; | |
458 | c->mask |= SD_BUS_CREDS_EUID; | |
459 | } | |
460 | ||
461 | if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) { | |
462 | c->suid = (uid_t) item->creds.suid; | |
463 | c->mask |= SD_BUS_CREDS_SUID; | |
464 | } | |
465 | ||
466 | if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) { | |
467 | c->fsuid = (uid_t) item->creds.fsuid; | |
468 | c->mask |= SD_BUS_CREDS_FSUID; | |
469 | } | |
470 | ||
471 | if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) { | |
60f067b4 | 472 | c->gid = (gid_t) item->creds.gid; |
f47781d8 | 473 | c->mask |= SD_BUS_CREDS_GID; |
60f067b4 JS |
474 | } |
475 | ||
f47781d8 MP |
476 | if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) { |
477 | c->egid = (gid_t) item->creds.egid; | |
478 | c->mask |= SD_BUS_CREDS_EGID; | |
479 | } | |
480 | ||
481 | if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) { | |
482 | c->sgid = (gid_t) item->creds.sgid; | |
483 | c->mask |= SD_BUS_CREDS_SGID; | |
60f067b4 JS |
484 | } |
485 | ||
f47781d8 MP |
486 | if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) { |
487 | c->fsgid = (gid_t) item->creds.fsgid; | |
488 | c->mask |= SD_BUS_CREDS_FSGID; | |
60f067b4 JS |
489 | } |
490 | ||
491 | break; | |
492 | ||
493 | case KDBUS_ITEM_PID_COMM: | |
494 | if (mask & SD_BUS_CREDS_COMM) { | |
f47781d8 MP |
495 | r = free_and_strdup(&c->comm, item->str); |
496 | if (r < 0) | |
497 | return r; | |
60f067b4 JS |
498 | |
499 | c->mask |= SD_BUS_CREDS_COMM; | |
500 | } | |
501 | break; | |
502 | ||
503 | case KDBUS_ITEM_TID_COMM: | |
504 | if (mask & SD_BUS_CREDS_TID_COMM) { | |
f47781d8 MP |
505 | r = free_and_strdup(&c->tid_comm, item->str); |
506 | if (r < 0) | |
507 | return r; | |
60f067b4 JS |
508 | |
509 | c->mask |= SD_BUS_CREDS_TID_COMM; | |
510 | } | |
511 | break; | |
512 | ||
513 | case KDBUS_ITEM_EXE: | |
514 | if (mask & SD_BUS_CREDS_EXE) { | |
f47781d8 MP |
515 | r = free_and_strdup(&c->exe, item->str); |
516 | if (r < 0) | |
517 | return r; | |
60f067b4 JS |
518 | |
519 | c->mask |= SD_BUS_CREDS_EXE; | |
520 | } | |
521 | break; | |
522 | ||
523 | case KDBUS_ITEM_CMDLINE: | |
524 | if (mask & SD_BUS_CREDS_CMDLINE) { | |
f47781d8 | 525 | c->cmdline_size = item->size - offsetof(struct kdbus_item, data); |
60f067b4 | 526 | c->cmdline = memdup(item->data, c->cmdline_size); |
5eef597e MP |
527 | if (!c->cmdline) |
528 | return -ENOMEM; | |
60f067b4 JS |
529 | |
530 | c->mask |= SD_BUS_CREDS_CMDLINE; | |
531 | } | |
532 | break; | |
533 | ||
534 | case KDBUS_ITEM_CGROUP: | |
535 | m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT | | |
536 | SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE | | |
537 | SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask; | |
538 | ||
539 | if (m) { | |
f47781d8 MP |
540 | r = free_and_strdup(&c->cgroup, item->str); |
541 | if (r < 0) | |
542 | return r; | |
60f067b4 | 543 | |
5eef597e MP |
544 | r = bus_get_root_path(bus); |
545 | if (r < 0) | |
546 | return r; | |
60f067b4 | 547 | |
f47781d8 MP |
548 | r = free_and_strdup(&c->cgroup_root, bus->cgroup_root); |
549 | if (r < 0) | |
550 | return r; | |
60f067b4 JS |
551 | |
552 | c->mask |= m; | |
553 | } | |
554 | break; | |
555 | ||
556 | case KDBUS_ITEM_CAPS: | |
557 | m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS | | |
558 | SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask; | |
559 | ||
560 | if (m) { | |
e735f4d4 MP |
561 | if (item->caps.last_cap != cap_last_cap() || |
562 | item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4) | |
563 | return -EBADMSG; | |
564 | ||
565 | c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps)); | |
5eef597e MP |
566 | if (!c->capability) |
567 | return -ENOMEM; | |
60f067b4 JS |
568 | |
569 | c->mask |= m; | |
570 | } | |
571 | break; | |
572 | ||
573 | case KDBUS_ITEM_SECLABEL: | |
574 | if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) { | |
f47781d8 MP |
575 | r = free_and_strdup(&c->label, item->str); |
576 | if (r < 0) | |
577 | return r; | |
60f067b4 JS |
578 | |
579 | c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; | |
580 | } | |
581 | break; | |
582 | ||
583 | case KDBUS_ITEM_AUDIT: | |
e3bff60a | 584 | if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID) { |
f47781d8 MP |
585 | c->audit_session_id = (uint32_t) item->audit.sessionid; |
586 | c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID; | |
587 | } | |
60f067b4 | 588 | |
e3bff60a | 589 | if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) { |
f47781d8 MP |
590 | c->audit_login_uid = (uid_t) item->audit.loginuid; |
591 | c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID; | |
60f067b4 JS |
592 | } |
593 | break; | |
594 | ||
f47781d8 | 595 | case KDBUS_ITEM_OWNED_NAME: |
60f067b4 JS |
596 | if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) { |
597 | r = strv_extend(&c->well_known_names, item->name.name); | |
598 | if (r < 0) | |
5eef597e | 599 | return r; |
60f067b4 JS |
600 | |
601 | c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES; | |
602 | } | |
603 | break; | |
604 | ||
f47781d8 MP |
605 | case KDBUS_ITEM_CONN_DESCRIPTION: |
606 | if (mask & SD_BUS_CREDS_DESCRIPTION) { | |
607 | r = free_and_strdup(&c->description, item->str); | |
608 | if (r < 0) | |
609 | return r; | |
610 | ||
611 | c->mask |= SD_BUS_CREDS_DESCRIPTION; | |
612 | } | |
613 | break; | |
614 | ||
615 | case KDBUS_ITEM_AUXGROUPS: | |
616 | if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) { | |
e3bff60a | 617 | size_t i, n; |
f47781d8 MP |
618 | uid_t *g; |
619 | ||
e3bff60a MP |
620 | n = (item->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t); |
621 | g = new(gid_t, n); | |
f47781d8 | 622 | if (!g) |
5eef597e | 623 | return -ENOMEM; |
60f067b4 | 624 | |
e3bff60a MP |
625 | for (i = 0; i < n; i++) |
626 | g[i] = item->data64[i]; | |
627 | ||
f47781d8 MP |
628 | free(c->supplementary_gids); |
629 | c->supplementary_gids = g; | |
630 | c->n_supplementary_gids = n; | |
631 | ||
632 | c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS; | |
60f067b4 JS |
633 | } |
634 | break; | |
635 | } | |
636 | } | |
637 | ||
5eef597e MP |
638 | return 0; |
639 | } | |
640 | ||
f47781d8 | 641 | int bus_get_name_creds_kdbus( |
5eef597e MP |
642 | sd_bus *bus, |
643 | const char *name, | |
644 | uint64_t mask, | |
f47781d8 | 645 | bool allow_activator, |
5eef597e MP |
646 | sd_bus_creds **creds) { |
647 | ||
4c89c718 | 648 | _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; |
5eef597e MP |
649 | struct kdbus_cmd_info *cmd; |
650 | struct kdbus_info *conn_info; | |
651 | size_t size, l; | |
652 | uint64_t id; | |
653 | int r; | |
654 | ||
e735f4d4 | 655 | if (streq(name, "org.freedesktop.DBus")) |
e3bff60a | 656 | return -EOPNOTSUPP; |
e735f4d4 | 657 | |
5eef597e MP |
658 | r = bus_kernel_parse_unique_name(name, &id); |
659 | if (r < 0) | |
660 | return r; | |
661 | if (r > 0) { | |
662 | size = offsetof(struct kdbus_cmd_info, items); | |
663 | cmd = alloca0_align(size, 8); | |
664 | cmd->id = id; | |
665 | } else { | |
666 | l = strlen(name) + 1; | |
667 | size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l); | |
668 | cmd = alloca0_align(size, 8); | |
669 | cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l; | |
670 | cmd->items[0].type = KDBUS_ITEM_NAME; | |
671 | memcpy(cmd->items[0].str, name, l); | |
672 | } | |
673 | ||
e735f4d4 MP |
674 | /* If augmentation is on, and the bus didn't provide us |
675 | * the bits we want, then ask for the PID/TID so that we | |
f47781d8 MP |
676 | * can read the rest from /proc. */ |
677 | if ((mask & SD_BUS_CREDS_AUGMENT) && | |
e3bff60a MP |
678 | (mask & (SD_BUS_CREDS_PPID| |
679 | SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID| | |
f47781d8 MP |
680 | SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID| |
681 | SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE| | |
682 | 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| | |
683 | SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS| | |
684 | SD_BUS_CREDS_SELINUX_CONTEXT| | |
685 | SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))) | |
e735f4d4 MP |
686 | mask |= SD_BUS_CREDS_PID; |
687 | ||
688 | cmd->size = size; | |
e3bff60a | 689 | cmd->attach_flags = attach_flags_to_kdbus(mask); |
5eef597e MP |
690 | |
691 | r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd); | |
692 | if (r < 0) | |
693 | return -errno; | |
694 | ||
695 | conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset); | |
696 | ||
697 | /* Non-activated names are considered not available */ | |
f47781d8 | 698 | if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) { |
5eef597e MP |
699 | if (name[0] == ':') |
700 | r = -ENXIO; | |
701 | else | |
702 | r = -ESRCH; | |
703 | goto fail; | |
704 | } | |
705 | ||
706 | c = bus_creds_new(); | |
707 | if (!c) { | |
708 | r = -ENOMEM; | |
709 | goto fail; | |
710 | } | |
711 | ||
712 | if (mask & SD_BUS_CREDS_UNIQUE_NAME) { | |
713 | if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) { | |
714 | r = -ENOMEM; | |
715 | goto fail; | |
716 | } | |
717 | ||
718 | c->mask |= SD_BUS_CREDS_UNIQUE_NAME; | |
719 | } | |
720 | ||
f47781d8 MP |
721 | /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of |
722 | them in case the service has no names. This does not mean | |
723 | however that the list of owned names could not be | |
724 | acquired. Hence, let's explicitly clarify that the data is | |
725 | complete. */ | |
726 | c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES; | |
727 | ||
5eef597e MP |
728 | r = bus_populate_creds_from_items(bus, conn_info, mask, c); |
729 | if (r < 0) | |
730 | goto fail; | |
731 | ||
f47781d8 MP |
732 | r = bus_creds_add_more(c, mask, 0, 0); |
733 | if (r < 0) | |
734 | goto fail; | |
735 | ||
60f067b4 JS |
736 | if (creds) { |
737 | *creds = c; | |
738 | c = NULL; | |
739 | } | |
740 | ||
741 | r = 0; | |
742 | ||
743 | fail: | |
f47781d8 | 744 | bus_kernel_cmd_free(bus, cmd->offset); |
60f067b4 JS |
745 | return r; |
746 | } | |
747 | ||
5eef597e | 748 | static int bus_get_name_creds_dbus1( |
60f067b4 JS |
749 | sd_bus *bus, |
750 | const char *name, | |
751 | uint64_t mask, | |
752 | sd_bus_creds **creds) { | |
753 | ||
4c89c718 MP |
754 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL; |
755 | _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; | |
60f067b4 JS |
756 | const char *unique = NULL; |
757 | pid_t pid = 0; | |
758 | int r; | |
759 | ||
760 | /* Only query the owner if the caller wants to know it or if | |
761 | * the caller just wants to check whether a name exists */ | |
762 | if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) { | |
763 | r = sd_bus_call_method( | |
764 | bus, | |
765 | "org.freedesktop.DBus", | |
766 | "/org/freedesktop/DBus", | |
767 | "org.freedesktop.DBus", | |
768 | "GetNameOwner", | |
769 | NULL, | |
770 | &reply_unique, | |
771 | "s", | |
772 | name); | |
773 | if (r < 0) | |
774 | return r; | |
775 | ||
776 | r = sd_bus_message_read(reply_unique, "s", &unique); | |
777 | if (r < 0) | |
778 | return r; | |
779 | } | |
780 | ||
781 | if (mask != 0) { | |
782 | c = bus_creds_new(); | |
783 | if (!c) | |
784 | return -ENOMEM; | |
785 | ||
786 | if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) { | |
787 | c->unique_name = strdup(unique); | |
788 | if (!c->unique_name) | |
789 | return -ENOMEM; | |
790 | ||
791 | c->mask |= SD_BUS_CREDS_UNIQUE_NAME; | |
792 | } | |
793 | ||
f47781d8 MP |
794 | if ((mask & SD_BUS_CREDS_PID) || |
795 | ((mask & SD_BUS_CREDS_AUGMENT) && | |
e735f4d4 | 796 | (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID| |
f47781d8 MP |
797 | SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID| |
798 | SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE| | |
799 | 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| | |
800 | SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS| | |
801 | SD_BUS_CREDS_SELINUX_CONTEXT| | |
802 | SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) { | |
803 | ||
60f067b4 JS |
804 | uint32_t u; |
805 | ||
806 | r = sd_bus_call_method( | |
807 | bus, | |
808 | "org.freedesktop.DBus", | |
809 | "/org/freedesktop/DBus", | |
810 | "org.freedesktop.DBus", | |
811 | "GetConnectionUnixProcessID", | |
812 | NULL, | |
813 | &reply, | |
814 | "s", | |
815 | unique ? unique : name); | |
816 | if (r < 0) | |
817 | return r; | |
818 | ||
819 | r = sd_bus_message_read(reply, "u", &u); | |
820 | if (r < 0) | |
821 | return r; | |
822 | ||
823 | pid = u; | |
824 | if (mask & SD_BUS_CREDS_PID) { | |
825 | c->pid = u; | |
826 | c->mask |= SD_BUS_CREDS_PID; | |
827 | } | |
828 | ||
829 | reply = sd_bus_message_unref(reply); | |
830 | } | |
831 | ||
e735f4d4 | 832 | if (mask & SD_BUS_CREDS_EUID) { |
60f067b4 JS |
833 | uint32_t u; |
834 | ||
835 | r = sd_bus_call_method( | |
836 | bus, | |
837 | "org.freedesktop.DBus", | |
838 | "/org/freedesktop/DBus", | |
839 | "org.freedesktop.DBus", | |
840 | "GetConnectionUnixUser", | |
841 | NULL, | |
842 | &reply, | |
843 | "s", | |
844 | unique ? unique : name); | |
845 | if (r < 0) | |
846 | return r; | |
847 | ||
848 | r = sd_bus_message_read(reply, "u", &u); | |
849 | if (r < 0) | |
850 | return r; | |
851 | ||
e735f4d4 MP |
852 | c->euid = u; |
853 | c->mask |= SD_BUS_CREDS_EUID; | |
60f067b4 JS |
854 | |
855 | reply = sd_bus_message_unref(reply); | |
856 | } | |
857 | ||
858 | if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) { | |
4c89c718 | 859 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
60f067b4 JS |
860 | const void *p = NULL; |
861 | size_t sz = 0; | |
862 | ||
863 | r = sd_bus_call_method( | |
864 | bus, | |
865 | "org.freedesktop.DBus", | |
866 | "/org/freedesktop/DBus", | |
867 | "org.freedesktop.DBus", | |
868 | "GetConnectionSELinuxSecurityContext", | |
f47781d8 | 869 | &error, |
60f067b4 JS |
870 | &reply, |
871 | "s", | |
872 | unique ? unique : name); | |
f47781d8 MP |
873 | if (r < 0) { |
874 | if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown")) | |
875 | return r; | |
876 | } else { | |
877 | r = sd_bus_message_read_array(reply, 'y', &p, &sz); | |
878 | if (r < 0) | |
879 | return r; | |
60f067b4 | 880 | |
f47781d8 MP |
881 | c->label = strndup(p, sz); |
882 | if (!c->label) | |
883 | return -ENOMEM; | |
60f067b4 | 884 | |
f47781d8 MP |
885 | c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; |
886 | } | |
60f067b4 JS |
887 | } |
888 | ||
889 | r = bus_creds_add_more(c, mask, pid, 0); | |
890 | if (r < 0) | |
891 | return r; | |
892 | } | |
893 | ||
894 | if (creds) { | |
895 | *creds = c; | |
896 | c = NULL; | |
897 | } | |
898 | ||
899 | return 0; | |
900 | } | |
901 | ||
5eef597e | 902 | _public_ int sd_bus_get_name_creds( |
60f067b4 JS |
903 | sd_bus *bus, |
904 | const char *name, | |
905 | uint64_t mask, | |
906 | sd_bus_creds **creds) { | |
907 | ||
908 | assert_return(bus, -EINVAL); | |
909 | assert_return(name, -EINVAL); | |
e3bff60a | 910 | assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP); |
60f067b4 JS |
911 | assert_return(mask == 0 || creds, -EINVAL); |
912 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
913 | assert_return(service_name_is_valid(name), -EINVAL); | |
e3bff60a MP |
914 | |
915 | if (!bus->bus_client) | |
916 | return -EINVAL; | |
60f067b4 | 917 | |
e735f4d4 MP |
918 | if (streq(name, "org.freedesktop.DBus.Local")) |
919 | return -EINVAL; | |
920 | ||
60f067b4 JS |
921 | if (!BUS_IS_OPEN(bus->state)) |
922 | return -ENOTCONN; | |
923 | ||
924 | if (bus->is_kernel) | |
f47781d8 | 925 | return bus_get_name_creds_kdbus(bus, name, mask, false, creds); |
60f067b4 | 926 | else |
5eef597e MP |
927 | return bus_get_name_creds_dbus1(bus, name, mask, creds); |
928 | } | |
929 | ||
f47781d8 | 930 | static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { |
4c89c718 | 931 | _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; |
f47781d8 | 932 | struct kdbus_cmd_info cmd = { |
e735f4d4 | 933 | .size = sizeof(struct kdbus_cmd_info), |
f47781d8 MP |
934 | }; |
935 | struct kdbus_info *creator_info; | |
5eef597e MP |
936 | pid_t pid = 0; |
937 | int r; | |
938 | ||
f47781d8 MP |
939 | c = bus_creds_new(); |
940 | if (!c) | |
941 | return -ENOMEM; | |
5eef597e | 942 | |
f47781d8 MP |
943 | /* If augmentation is on, and the bus doesn't didn't allow us |
944 | * to get the bits we want, then ask for the PID/TID so that we | |
945 | * can read the rest from /proc. */ | |
946 | if ((mask & SD_BUS_CREDS_AUGMENT) && | |
e3bff60a MP |
947 | (mask & (SD_BUS_CREDS_PPID| |
948 | SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID| | |
f47781d8 MP |
949 | SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID| |
950 | SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE| | |
951 | 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| | |
952 | SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS| | |
953 | SD_BUS_CREDS_SELINUX_CONTEXT| | |
954 | SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))) | |
e735f4d4 MP |
955 | mask |= SD_BUS_CREDS_PID; |
956 | ||
e3bff60a | 957 | cmd.attach_flags = attach_flags_to_kdbus(mask); |
f47781d8 MP |
958 | |
959 | r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd); | |
960 | if (r < 0) | |
961 | return -errno; | |
962 | ||
963 | creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset); | |
964 | ||
965 | r = bus_populate_creds_from_items(bus, creator_info, mask, c); | |
966 | bus_kernel_cmd_free(bus, cmd.offset); | |
967 | if (r < 0) | |
968 | return r; | |
969 | ||
970 | r = bus_creds_add_more(c, mask, pid, 0); | |
971 | if (r < 0) | |
972 | return r; | |
973 | ||
974 | *ret = c; | |
975 | c = NULL; | |
976 | return 0; | |
977 | } | |
978 | ||
979 | static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { | |
4c89c718 | 980 | _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; |
f47781d8 | 981 | pid_t pid = 0; |
db2df898 | 982 | bool do_label; |
f47781d8 | 983 | int r; |
db2df898 MP |
984 | |
985 | assert(bus); | |
986 | ||
987 | do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT); | |
5eef597e | 988 | |
86f210e9 MP |
989 | /* Avoid allocating anything if we have no chance of returning useful data */ |
990 | if (!bus->ucred_valid && !do_label) | |
5eef597e MP |
991 | return -ENODATA; |
992 | ||
993 | c = bus_creds_new(); | |
994 | if (!c) | |
995 | return -ENOMEM; | |
996 | ||
997 | if (bus->ucred_valid) { | |
f47781d8 MP |
998 | if (bus->ucred.pid > 0) { |
999 | pid = c->pid = bus->ucred.pid; | |
1000 | c->mask |= SD_BUS_CREDS_PID & mask; | |
1001 | } | |
1002 | ||
1003 | if (bus->ucred.uid != UID_INVALID) { | |
e735f4d4 MP |
1004 | c->euid = bus->ucred.uid; |
1005 | c->mask |= SD_BUS_CREDS_EUID & mask; | |
f47781d8 | 1006 | } |
5eef597e | 1007 | |
f47781d8 | 1008 | if (bus->ucred.gid != GID_INVALID) { |
e735f4d4 MP |
1009 | c->egid = bus->ucred.gid; |
1010 | c->mask |= SD_BUS_CREDS_EGID & mask; | |
f47781d8 | 1011 | } |
5eef597e MP |
1012 | } |
1013 | ||
86f210e9 | 1014 | if (do_label) { |
5eef597e MP |
1015 | c->label = strdup(bus->label); |
1016 | if (!c->label) | |
1017 | return -ENOMEM; | |
1018 | ||
1019 | c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; | |
1020 | } | |
1021 | ||
f47781d8 MP |
1022 | r = bus_creds_add_more(c, mask, pid, 0); |
1023 | if (r < 0) | |
1024 | return r; | |
5eef597e MP |
1025 | |
1026 | *ret = c; | |
1027 | c = NULL; | |
1028 | return 0; | |
60f067b4 JS |
1029 | } |
1030 | ||
f47781d8 MP |
1031 | _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { |
1032 | assert_return(bus, -EINVAL); | |
e3bff60a | 1033 | assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP); |
f47781d8 MP |
1034 | assert_return(ret, -EINVAL); |
1035 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
1036 | ||
1037 | if (!BUS_IS_OPEN(bus->state)) | |
1038 | return -ENOTCONN; | |
1039 | ||
1040 | if (bus->is_kernel) | |
1041 | return bus_get_owner_creds_kdbus(bus, mask, ret); | |
1042 | else | |
1043 | return bus_get_owner_creds_dbus1(bus, mask, ret); | |
1044 | } | |
1045 | ||
60f067b4 JS |
1046 | static int add_name_change_match(sd_bus *bus, |
1047 | uint64_t cookie, | |
1048 | const char *name, | |
1049 | const char *old_owner, | |
1050 | const char *new_owner) { | |
1051 | ||
1052 | uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0; | |
1053 | int is_name_id = -1, r; | |
1054 | struct kdbus_item *item; | |
1055 | ||
1056 | assert(bus); | |
1057 | ||
1058 | /* If we encounter a match that could match against | |
1059 | * NameOwnerChanged messages, then we need to create | |
1060 | * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and | |
1061 | * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly | |
1062 | * multiple if the match is underspecified. | |
1063 | * | |
1064 | * The NameOwnerChanged signals take three parameters with | |
1065 | * unique or well-known names, but only some forms actually | |
1066 | * exist: | |
1067 | * | |
1068 | * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD | |
1069 | * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE | |
1070 | * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE | |
1071 | * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD | |
1072 | * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE | |
1073 | * | |
1074 | * For the latter two the two unique names must be identical. | |
1075 | * | |
1076 | * */ | |
1077 | ||
1078 | if (name) { | |
1079 | is_name_id = bus_kernel_parse_unique_name(name, &name_id); | |
1080 | if (is_name_id < 0) | |
1081 | return 0; | |
1082 | } | |
1083 | ||
1084 | if (!isempty(old_owner)) { | |
1085 | r = bus_kernel_parse_unique_name(old_owner, &old_owner_id); | |
1086 | if (r < 0) | |
1087 | return 0; | |
1088 | if (r == 0) | |
1089 | return 0; | |
1090 | if (is_name_id > 0 && old_owner_id != name_id) | |
1091 | return 0; | |
1092 | } else | |
1093 | old_owner_id = KDBUS_MATCH_ID_ANY; | |
1094 | ||
1095 | if (!isempty(new_owner)) { | |
1096 | r = bus_kernel_parse_unique_name(new_owner, &new_owner_id); | |
1097 | if (r < 0) | |
1098 | return r; | |
1099 | if (r == 0) | |
1100 | return 0; | |
1101 | if (is_name_id > 0 && new_owner_id != name_id) | |
1102 | return 0; | |
1103 | } else | |
1104 | new_owner_id = KDBUS_MATCH_ID_ANY; | |
1105 | ||
1106 | if (is_name_id <= 0) { | |
1107 | struct kdbus_cmd_match *m; | |
1108 | size_t sz, l; | |
1109 | ||
1110 | /* If the name argument is missing or is a well-known | |
1111 | * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} | |
1112 | * matches for it */ | |
1113 | ||
1114 | l = name ? strlen(name) + 1 : 0; | |
1115 | ||
1116 | sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) + | |
1117 | offsetof(struct kdbus_item, name_change) + | |
1118 | offsetof(struct kdbus_notify_name_change, name) + | |
1119 | l); | |
1120 | ||
5eef597e | 1121 | m = alloca0_align(sz, 8); |
60f067b4 JS |
1122 | m->size = sz; |
1123 | m->cookie = cookie; | |
1124 | ||
1125 | item = m->items; | |
1126 | item->size = | |
1127 | offsetof(struct kdbus_item, name_change) + | |
1128 | offsetof(struct kdbus_notify_name_change, name) + | |
1129 | l; | |
1130 | ||
5eef597e MP |
1131 | item->name_change.old_id.id = old_owner_id; |
1132 | item->name_change.new_id.id = new_owner_id; | |
60f067b4 JS |
1133 | |
1134 | if (name) | |
1135 | memcpy(item->name_change.name, name, l); | |
1136 | ||
1137 | /* If the old name is unset or empty, then | |
1138 | * this can match against added names */ | |
7035cd9e | 1139 | if (isempty(old_owner)) { |
60f067b4 JS |
1140 | item->type = KDBUS_ITEM_NAME_ADD; |
1141 | ||
1142 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); | |
1143 | if (r < 0) | |
1144 | return -errno; | |
1145 | } | |
1146 | ||
1147 | /* If the new name is unset or empty, then | |
1148 | * this can match against removed names */ | |
7035cd9e | 1149 | if (isempty(new_owner)) { |
60f067b4 JS |
1150 | item->type = KDBUS_ITEM_NAME_REMOVE; |
1151 | ||
1152 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); | |
1153 | if (r < 0) | |
1154 | return -errno; | |
1155 | } | |
1156 | ||
1157 | /* The CHANGE match we need in either case, because | |
1158 | * what is reported as a name change by the kernel | |
1159 | * might just be an owner change between starter and | |
1160 | * normal clients. For userspace such a change should | |
1161 | * be considered a removal/addition, hence let's | |
1162 | * subscribe to this unconditionally. */ | |
1163 | item->type = KDBUS_ITEM_NAME_CHANGE; | |
1164 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); | |
1165 | if (r < 0) | |
1166 | return -errno; | |
1167 | } | |
1168 | ||
1169 | if (is_name_id != 0) { | |
1170 | struct kdbus_cmd_match *m; | |
1171 | uint64_t sz; | |
1172 | ||
1173 | /* If the name argument is missing or is a unique | |
1174 | * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches | |
1175 | * for it */ | |
1176 | ||
1177 | sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) + | |
1178 | offsetof(struct kdbus_item, id_change) + | |
1179 | sizeof(struct kdbus_notify_id_change)); | |
1180 | ||
5eef597e | 1181 | m = alloca0_align(sz, 8); |
60f067b4 JS |
1182 | m->size = sz; |
1183 | m->cookie = cookie; | |
1184 | ||
1185 | item = m->items; | |
1186 | item->size = | |
1187 | offsetof(struct kdbus_item, id_change) + | |
1188 | sizeof(struct kdbus_notify_id_change); | |
1189 | item->id_change.id = name_id; | |
1190 | ||
1191 | /* If the old name is unset or empty, then this can | |
1192 | * match against added ids */ | |
7035cd9e | 1193 | if (isempty(old_owner)) { |
60f067b4 | 1194 | item->type = KDBUS_ITEM_ID_ADD; |
7035cd9e MP |
1195 | if (!isempty(new_owner)) |
1196 | item->id_change.id = new_owner_id; | |
60f067b4 JS |
1197 | |
1198 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); | |
1199 | if (r < 0) | |
1200 | return -errno; | |
1201 | } | |
1202 | ||
1203 | /* If thew new name is unset or empty, then this can | |
1204 | * match against removed ids */ | |
7035cd9e | 1205 | if (isempty(new_owner)) { |
60f067b4 | 1206 | item->type = KDBUS_ITEM_ID_REMOVE; |
7035cd9e MP |
1207 | if (!isempty(old_owner)) |
1208 | item->id_change.id = old_owner_id; | |
60f067b4 JS |
1209 | |
1210 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); | |
1211 | if (r < 0) | |
1212 | return -errno; | |
1213 | } | |
1214 | } | |
1215 | ||
1216 | return 0; | |
1217 | } | |
1218 | ||
1219 | int bus_add_match_internal_kernel( | |
1220 | sd_bus *bus, | |
1221 | struct bus_match_component *components, | |
1222 | unsigned n_components, | |
1223 | uint64_t cookie) { | |
1224 | ||
1225 | struct kdbus_cmd_match *m; | |
1226 | struct kdbus_item *item; | |
1227 | uint64_t *bloom; | |
1228 | size_t sz; | |
1229 | const char *sender = NULL; | |
1230 | size_t sender_length = 0; | |
fb183854 | 1231 | uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY; |
60f067b4 JS |
1232 | bool using_bloom = false; |
1233 | unsigned i; | |
1234 | bool matches_name_change = true; | |
1235 | const char *name_change_arg[3] = {}; | |
1236 | int r; | |
1237 | ||
1238 | assert(bus); | |
1239 | ||
f47781d8 MP |
1240 | /* Monitor streams don't support matches, make this a NOP */ |
1241 | if (bus->hello_flags & KDBUS_HELLO_MONITOR) | |
1242 | return 0; | |
1243 | ||
60f067b4 JS |
1244 | bloom = alloca0(bus->bloom_size); |
1245 | ||
1246 | sz = ALIGN8(offsetof(struct kdbus_cmd_match, items)); | |
1247 | ||
1248 | for (i = 0; i < n_components; i++) { | |
1249 | struct bus_match_component *c = &components[i]; | |
1250 | ||
1251 | switch (c->type) { | |
1252 | ||
1253 | case BUS_MATCH_SENDER: | |
1254 | if (!streq(c->value_str, "org.freedesktop.DBus")) | |
1255 | matches_name_change = false; | |
1256 | ||
1257 | r = bus_kernel_parse_unique_name(c->value_str, &src_id); | |
1258 | if (r < 0) | |
1259 | return r; | |
1260 | else if (r > 0) | |
1261 | sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t)); | |
1262 | else { | |
1263 | sender = c->value_str; | |
1264 | sender_length = strlen(sender); | |
1265 | sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1); | |
1266 | } | |
1267 | ||
1268 | break; | |
1269 | ||
1270 | case BUS_MATCH_MESSAGE_TYPE: | |
1271 | if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL) | |
1272 | matches_name_change = false; | |
1273 | ||
1274 | bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8)); | |
1275 | using_bloom = true; | |
1276 | break; | |
1277 | ||
1278 | case BUS_MATCH_INTERFACE: | |
1279 | if (!streq(c->value_str, "org.freedesktop.DBus")) | |
1280 | matches_name_change = false; | |
1281 | ||
1282 | bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str); | |
1283 | using_bloom = true; | |
1284 | break; | |
1285 | ||
1286 | case BUS_MATCH_MEMBER: | |
1287 | if (!streq(c->value_str, "NameOwnerChanged")) | |
1288 | matches_name_change = false; | |
1289 | ||
1290 | bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str); | |
1291 | using_bloom = true; | |
1292 | break; | |
1293 | ||
1294 | case BUS_MATCH_PATH: | |
1295 | if (!streq(c->value_str, "/org/freedesktop/DBus")) | |
1296 | matches_name_change = false; | |
1297 | ||
1298 | bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str); | |
1299 | using_bloom = true; | |
1300 | break; | |
1301 | ||
1302 | case BUS_MATCH_PATH_NAMESPACE: | |
86f210e9 MP |
1303 | bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str); |
1304 | using_bloom = true; | |
60f067b4 JS |
1305 | break; |
1306 | ||
1307 | case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: { | |
1308 | char buf[sizeof("arg")-1 + 2 + 1]; | |
1309 | ||
1310 | if (c->type - BUS_MATCH_ARG < 3) | |
1311 | name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str; | |
1312 | ||
e735f4d4 | 1313 | xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG); |
60f067b4 JS |
1314 | bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str); |
1315 | using_bloom = true; | |
1316 | break; | |
1317 | } | |
1318 | ||
13d276d0 MP |
1319 | case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: { |
1320 | char buf[sizeof("arg")-1 + 2 + sizeof("-has")]; | |
1321 | ||
1322 | xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS); | |
1323 | bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str); | |
1324 | using_bloom = true; | |
1325 | break; | |
1326 | } | |
1327 | ||
1328 | case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: | |
86f210e9 MP |
1329 | /* |
1330 | * XXX: DBus spec defines arg[0..63]path= matching to be | |
1331 | * a two-way glob. That is, if either string is a prefix | |
1332 | * of the other, it matches. | |
1333 | * This is really hard to realize in bloom-filters, as | |
1334 | * we would have to create a bloom-match for each prefix | |
1335 | * of @c->value_str. This is excessive, hence we just | |
1336 | * ignore all those matches and accept everything from | |
1337 | * the kernel. People should really avoid those matches. | |
1338 | * If they're used in real-life some day, we will have | |
1339 | * to properly support multiple-matches here. | |
1340 | */ | |
60f067b4 | 1341 | break; |
60f067b4 JS |
1342 | |
1343 | case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: { | |
1344 | char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")]; | |
1345 | ||
e735f4d4 | 1346 | xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE); |
60f067b4 JS |
1347 | bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str); |
1348 | using_bloom = true; | |
1349 | break; | |
1350 | } | |
1351 | ||
13d276d0 | 1352 | case BUS_MATCH_DESTINATION: |
fb183854 MP |
1353 | /* |
1354 | * Kernel only supports matching on destination IDs, but | |
1355 | * not on destination names. So just skip the | |
1356 | * destination name restriction and verify it in | |
1357 | * user-space on retrieval. | |
1358 | */ | |
1359 | r = bus_kernel_parse_unique_name(c->value_str, &dst_id); | |
1360 | if (r < 0) | |
1361 | return r; | |
1362 | else if (r > 0) | |
1363 | sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t)); | |
1364 | ||
7035cd9e MP |
1365 | /* if not a broadcast, it cannot be a name-change */ |
1366 | if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST) | |
1367 | matches_name_change = false; | |
1368 | ||
60f067b4 JS |
1369 | break; |
1370 | ||
1371 | case BUS_MATCH_ROOT: | |
1372 | case BUS_MATCH_VALUE: | |
1373 | case BUS_MATCH_LEAF: | |
1374 | case _BUS_MATCH_NODE_TYPE_MAX: | |
1375 | case _BUS_MATCH_NODE_TYPE_INVALID: | |
1376 | assert_not_reached("Invalid match type?"); | |
1377 | } | |
1378 | } | |
1379 | ||
1380 | if (using_bloom) | |
1381 | sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size); | |
1382 | ||
5eef597e | 1383 | m = alloca0_align(sz, 8); |
60f067b4 JS |
1384 | m->size = sz; |
1385 | m->cookie = cookie; | |
1386 | ||
1387 | item = m->items; | |
1388 | ||
1389 | if (src_id != KDBUS_MATCH_ID_ANY) { | |
1390 | item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t); | |
1391 | item->type = KDBUS_ITEM_ID; | |
1392 | item->id = src_id; | |
1393 | item = KDBUS_ITEM_NEXT(item); | |
1394 | } | |
1395 | ||
fb183854 MP |
1396 | if (dst_id != KDBUS_MATCH_ID_ANY) { |
1397 | item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t); | |
1398 | item->type = KDBUS_ITEM_DST_ID; | |
1399 | item->id = dst_id; | |
1400 | item = KDBUS_ITEM_NEXT(item); | |
1401 | } | |
1402 | ||
60f067b4 JS |
1403 | if (using_bloom) { |
1404 | item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size; | |
1405 | item->type = KDBUS_ITEM_BLOOM_MASK; | |
1406 | memcpy(item->data64, bloom, bus->bloom_size); | |
1407 | item = KDBUS_ITEM_NEXT(item); | |
1408 | } | |
1409 | ||
1410 | if (sender) { | |
1411 | item->size = offsetof(struct kdbus_item, str) + sender_length + 1; | |
1412 | item->type = KDBUS_ITEM_NAME; | |
1413 | memcpy(item->str, sender, sender_length + 1); | |
1414 | } | |
1415 | ||
1416 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); | |
1417 | if (r < 0) | |
1418 | return -errno; | |
1419 | ||
1420 | if (matches_name_change) { | |
1421 | ||
1422 | /* If this match could theoretically match | |
1423 | * NameOwnerChanged messages, we need to | |
1424 | * install a second non-bloom filter explitly | |
1425 | * for it */ | |
1426 | ||
1427 | r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]); | |
1428 | if (r < 0) | |
1429 | return r; | |
1430 | } | |
1431 | ||
1432 | return 0; | |
1433 | } | |
1434 | ||
1435 | #define internal_match(bus, m) \ | |
1436 | ((bus)->hello_flags & KDBUS_HELLO_MONITOR \ | |
e735f4d4 | 1437 | ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \ |
60f067b4 JS |
1438 | : (m)) |
1439 | ||
1440 | static int bus_add_match_internal_dbus1( | |
1441 | sd_bus *bus, | |
1442 | const char *match) { | |
1443 | ||
1444 | const char *e; | |
1445 | ||
1446 | assert(bus); | |
1447 | assert(match); | |
1448 | ||
1449 | e = internal_match(bus, match); | |
1450 | ||
1451 | return sd_bus_call_method( | |
1452 | bus, | |
1453 | "org.freedesktop.DBus", | |
1454 | "/org/freedesktop/DBus", | |
1455 | "org.freedesktop.DBus", | |
1456 | "AddMatch", | |
1457 | NULL, | |
1458 | NULL, | |
1459 | "s", | |
1460 | e); | |
1461 | } | |
1462 | ||
1463 | int bus_add_match_internal( | |
1464 | sd_bus *bus, | |
1465 | const char *match, | |
1466 | struct bus_match_component *components, | |
1467 | unsigned n_components, | |
1468 | uint64_t cookie) { | |
1469 | ||
1470 | assert(bus); | |
1471 | ||
e3bff60a MP |
1472 | if (!bus->bus_client) |
1473 | return -EINVAL; | |
1474 | ||
60f067b4 JS |
1475 | if (bus->is_kernel) |
1476 | return bus_add_match_internal_kernel(bus, components, n_components, cookie); | |
1477 | else | |
1478 | return bus_add_match_internal_dbus1(bus, match); | |
1479 | } | |
1480 | ||
1481 | int bus_remove_match_internal_kernel( | |
1482 | sd_bus *bus, | |
1483 | uint64_t cookie) { | |
1484 | ||
e735f4d4 MP |
1485 | struct kdbus_cmd_match m = { |
1486 | .size = offsetof(struct kdbus_cmd_match, items), | |
1487 | .cookie = cookie, | |
1488 | }; | |
60f067b4 JS |
1489 | int r; |
1490 | ||
1491 | assert(bus); | |
1492 | ||
f47781d8 MP |
1493 | /* Monitor streams don't support matches, make this a NOP */ |
1494 | if (bus->hello_flags & KDBUS_HELLO_MONITOR) | |
1495 | return 0; | |
1496 | ||
60f067b4 JS |
1497 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m); |
1498 | if (r < 0) | |
1499 | return -errno; | |
1500 | ||
1501 | return 0; | |
1502 | } | |
1503 | ||
1504 | static int bus_remove_match_internal_dbus1( | |
1505 | sd_bus *bus, | |
1506 | const char *match) { | |
1507 | ||
1508 | const char *e; | |
1509 | ||
1510 | assert(bus); | |
1511 | assert(match); | |
1512 | ||
1513 | e = internal_match(bus, match); | |
1514 | ||
1515 | return sd_bus_call_method( | |
1516 | bus, | |
1517 | "org.freedesktop.DBus", | |
1518 | "/org/freedesktop/DBus", | |
1519 | "org.freedesktop.DBus", | |
1520 | "RemoveMatch", | |
1521 | NULL, | |
1522 | NULL, | |
1523 | "s", | |
1524 | e); | |
1525 | } | |
1526 | ||
1527 | int bus_remove_match_internal( | |
1528 | sd_bus *bus, | |
1529 | const char *match, | |
1530 | uint64_t cookie) { | |
1531 | ||
1532 | assert(bus); | |
1533 | ||
e3bff60a MP |
1534 | if (!bus->bus_client) |
1535 | return -EINVAL; | |
1536 | ||
60f067b4 JS |
1537 | if (bus->is_kernel) |
1538 | return bus_remove_match_internal_kernel(bus, cookie); | |
1539 | else | |
1540 | return bus_remove_match_internal_dbus1(bus, match); | |
1541 | } | |
1542 | ||
5eef597e | 1543 | _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) { |
4c89c718 | 1544 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; |
60f067b4 JS |
1545 | const char *mid; |
1546 | int r; | |
1547 | ||
1548 | assert_return(bus, -EINVAL); | |
1549 | assert_return(name, -EINVAL); | |
1550 | assert_return(machine, -EINVAL); | |
1551 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
1552 | assert_return(service_name_is_valid(name), -EINVAL); | |
1553 | ||
e3bff60a MP |
1554 | if (!bus->bus_client) |
1555 | return -EINVAL; | |
1556 | ||
60f067b4 JS |
1557 | if (!BUS_IS_OPEN(bus->state)) |
1558 | return -ENOTCONN; | |
1559 | ||
1560 | if (streq_ptr(name, bus->unique_name)) | |
1561 | return sd_id128_get_machine(machine); | |
1562 | ||
1563 | r = sd_bus_message_new_method_call( | |
1564 | bus, | |
1565 | &m, | |
1566 | name, | |
1567 | "/", | |
1568 | "org.freedesktop.DBus.Peer", | |
1569 | "GetMachineId"); | |
1570 | if (r < 0) | |
1571 | return r; | |
1572 | ||
1573 | r = sd_bus_message_set_auto_start(m, false); | |
1574 | if (r < 0) | |
1575 | return r; | |
1576 | ||
1577 | r = sd_bus_call(bus, m, 0, NULL, &reply); | |
1578 | if (r < 0) | |
1579 | return r; | |
1580 | ||
1581 | r = sd_bus_message_read(reply, "s", &mid); | |
1582 | if (r < 0) | |
1583 | return r; | |
1584 | ||
1585 | return sd_id128_from_string(mid, machine); | |
1586 | } |