]> git.proxmox.com Git - systemd.git/blame - src/libsystemd/sd-bus/bus-control.c
Imported Upstream version 229
[systemd.git] / src / libsystemd / sd-bus / bus-control.c
CommitLineData
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
59static 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
91static 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
160static 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
187static 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
244static 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 294fail:
f47781d8 295 bus_kernel_cmd_free(bus, cmd.offset);
5eef597e 296 return r;
60f067b4
JS
297}
298
299static 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
326static 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
397static 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 641int 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
743fail:
f47781d8 744 bus_kernel_cmd_free(bus, cmd->offset);
60f067b4
JS
745 return r;
746}
747
5eef597e 748static 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 930static 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
979static 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
1046static 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
1219int 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
1440static 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
1463int 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
1481int 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
1504static 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
1527int 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}