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