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