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