]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-control.c
bus: fix sender match creation on kdbus
[thirdparty/systemd.git] / src / libsystemd-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"
de1c301e 36
d9f644e2 37_public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
20902f3e
LP
38 int r;
39
9bb058a1
LS
40 assert_return(bus, -EINVAL);
41 assert_return(unique, -EINVAL);
42 assert_return(!bus_pid_changed(bus), -ECHILD);
20902f3e
LP
43
44 r = bus_ensure_running(bus);
45 if (r < 0)
46 return r;
de1c301e 47
20902f3e
LP
48 *unique = bus->unique_name;
49 return 0;
de1c301e
LP
50}
51
29a07cdb 52static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
e7176abb 53 struct kdbus_cmd_name *n;
45fd5e4d 54 size_t size, l;
de1c301e
LP
55 int r;
56
e7176abb
LP
57 assert(bus);
58 assert(name);
f08838da 59
e7176abb 60 l = strlen(name);
45fd5e4d
LP
61 size = offsetof(struct kdbus_cmd_name, name) + l + 1;
62 n = alloca0(size);
63 n->size = size;
e7176abb
LP
64 kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags);
65 memcpy(n->name, name, l+1);
f08838da 66
75722f1d 67#ifdef HAVE_VALGRIND_MEMCHECK_H
e7176abb 68 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
75722f1d
LP
69#endif
70
e7176abb
LP
71 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
72 if (r < 0)
73 return -errno;
f08838da 74
e7176abb
LP
75 if (n->flags & KDBUS_NAME_IN_QUEUE)
76 return 0;
f08838da 77
e7176abb 78 return 1;
de1c301e
LP
79}
80
29a07cdb 81static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
d4100e24 82 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
29a07cdb 83 uint32_t ret, param = 0;
de1c301e
LP
84 int r;
85
e7176abb
LP
86 assert(bus);
87 assert(name);
88
29a07cdb
LP
89 if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
90 param |= BUS_NAME_ALLOW_REPLACEMENT;
91 if (flags & SD_BUS_NAME_REPLACE_EXISTING)
92 param |= BUS_NAME_REPLACE_EXISTING;
93 if (!(flags & SD_BUS_NAME_QUEUE))
94 param |= BUS_NAME_DO_NOT_QUEUE;
95
e7176abb
LP
96 r = sd_bus_call_method(
97 bus,
98 "org.freedesktop.DBus",
cd789fdf 99 "/org/freedesktop/DBus",
e7176abb
LP
100 "org.freedesktop.DBus",
101 "RequestName",
102 NULL,
103 &reply,
104 "su",
105 name,
29a07cdb 106 param);
e7176abb
LP
107 if (r < 0)
108 return r;
109
110 r = sd_bus_message_read(reply, "u", &ret);
111 if (r < 0)
112 return r;
113
0461f8cd 114 if (ret == BUS_NAME_ALREADY_OWNER)
e7176abb 115 return -EALREADY;
0461f8cd 116 else if (ret == BUS_NAME_EXISTS)
e7176abb 117 return -EEXIST;
0461f8cd 118 else if (ret == BUS_NAME_IN_QUEUE)
e7176abb 119 return 0;
c0a09132
LP
120 else if (ret == BUS_NAME_PRIMARY_OWNER)
121 return 1;
e7176abb 122
c0a09132 123 return -EIO;
e7176abb
LP
124}
125
29a07cdb 126_public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
9bb058a1
LS
127 assert_return(bus, -EINVAL);
128 assert_return(name, -EINVAL);
129 assert_return(bus->bus_client, -EINVAL);
130 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
131 assert_return(!bus_pid_changed(bus), -ECHILD);
29a07cdb 132 assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
45fd5e4d
LP
133 assert_return(service_name_is_valid(name), -EINVAL);
134 assert_return(name[0] != ':', -EINVAL);
de1c301e 135
e7176abb
LP
136 if (bus->is_kernel)
137 return bus_request_name_kernel(bus, name, flags);
138 else
139 return bus_request_name_dbus1(bus, name, flags);
140}
f08838da 141
e7176abb
LP
142static int bus_release_name_kernel(sd_bus *bus, const char *name) {
143 struct kdbus_cmd_name *n;
144 size_t l;
145 int r;
f08838da 146
e7176abb
LP
147 assert(bus);
148 assert(name);
f08838da 149
e7176abb
LP
150 l = strlen(name);
151 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
152 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
153 memcpy(n->name, name, l+1);
f08838da 154
e7176abb
LP
155#ifdef HAVE_VALGRIND_MEMCHECK_H
156 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
157#endif
158 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
159 if (r < 0)
160 return -errno;
de1c301e 161
e7176abb 162 return n->flags;
de1c301e
LP
163}
164
e7176abb
LP
165static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
166 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
167 uint32_t ret;
de1c301e
LP
168 int r;
169
e7176abb
LP
170 assert(bus);
171 assert(name);
172
173 r = sd_bus_call_method(
174 bus,
175 "org.freedesktop.DBus",
cd789fdf 176 "/org/freedesktop/DBus",
e7176abb
LP
177 "org.freedesktop.DBus",
178 "ReleaseName",
179 NULL,
180 &reply,
181 "s",
182 name);
183 if (r < 0)
184 return r;
185
186 r = sd_bus_message_read(reply, "u", &ret);
187 if (r < 0)
188 return r;
0461f8cd 189 if (ret == BUS_NAME_NON_EXISTENT)
043ccd83 190 return -ESRCH;
0461f8cd 191 if (ret == BUS_NAME_NOT_OWNER)
043ccd83 192 return -EADDRINUSE;
0461f8cd 193 if (ret == BUS_NAME_RELEASED)
e7176abb
LP
194 return 0;
195
196 return -EINVAL;
197}
198
199_public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
9bb058a1 200 assert_return(bus, -EINVAL);
e7176abb
LP
201 assert_return(name, -EINVAL);
202 assert_return(bus->bus_client, -EINVAL);
9bb058a1
LS
203 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
204 assert_return(!bus_pid_changed(bus), -ECHILD);
45fd5e4d
LP
205 assert_return(service_name_is_valid(name), -EINVAL);
206 assert_return(name[0] != ':', -EINVAL);
de1c301e 207
e7176abb
LP
208 if (bus->is_kernel)
209 return bus_release_name_kernel(bus, name);
210 else
211 return bus_release_name_dbus1(bus, name);
212}
de1c301e 213
71f2ab46
LP
214static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
215 struct kdbus_cmd_name_list cmd = {};
e7176abb
LP
216 struct kdbus_name_list *name_list;
217 struct kdbus_cmd_name *name;
7f7030e2 218 uint64_t previous_id = 0;
e7176abb 219 int r;
b1473984 220
71f2ab46 221 /* Caller will free half-constructed list on failure... */
b1473984 222
71f2ab46 223 cmd.flags = flags;
b1473984 224
71f2ab46 225 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
e7176abb
LP
226 if (r < 0)
227 return -errno;
b1473984 228
71f2ab46 229 name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
b6bd53c1 230
a8d4cac5 231 KDBUS_ITEM_FOREACH(name, name_list, names) {
b6bd53c1 232
98531b57 233 if ((flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != previous_id) {
71f2ab46
LP
234 char *n;
235
98531b57 236 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0)
71f2ab46
LP
237 return -ENOMEM;
238
239 r = strv_push(x, n);
240 if (r < 0) {
241 free(n);
242 return -ENOMEM;
243 }
7f7030e2 244
98531b57 245 previous_id = name->owner_id;
71f2ab46 246 }
b1473984 247
45fd5e4d 248 if (name->size > sizeof(*name) && service_name_is_valid(name->name)) {
7f7030e2
LP
249 r = strv_extend(x, name->name);
250 if (r < 0)
251 return -ENOMEM;
252 }
89ffcd2a 253 }
de1c301e 254
45fd5e4d 255 r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd.offset);
e7176abb
LP
256 if (r < 0)
257 return -errno;
258
de1c301e
LP
259 return 0;
260}
261
71f2ab46
LP
262static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
263 _cleanup_strv_free_ char **x = NULL, **y = NULL;
de1c301e
LP
264 int r;
265
71f2ab46
LP
266 if (acquired) {
267 r = kernel_get_list(bus, KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES, &x);
268 if (r < 0)
269 return r;
270 }
a4297f08 271
71f2ab46 272 if (activatable) {
07442eff 273 r = kernel_get_list(bus, KDBUS_NAME_LIST_ACTIVATORS, &y);
71f2ab46
LP
274 if (r < 0)
275 return r;
5b12334d 276
71f2ab46
LP
277 *activatable = y;
278 y = NULL;
5b12334d 279 }
de1c301e 280
71f2ab46
LP
281 if (acquired) {
282 *acquired = x;
283 x = NULL;
284 }
285
286 return 0;
287}
288
289static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
290 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
291 _cleanup_strv_free_ char **x = NULL, **y = NULL;
292 int r;
293
294 if (acquired) {
295 r = sd_bus_call_method(
296 bus,
297 "org.freedesktop.DBus",
cd789fdf 298 "/org/freedesktop/DBus",
71f2ab46
LP
299 "org.freedesktop.DBus",
300 "ListNames",
301 NULL,
302 &reply,
303 NULL);
304 if (r < 0)
305 return r;
306
307 r = sd_bus_message_read_strv(reply, &x);
308 if (r < 0)
309 return r;
310
311 reply = sd_bus_message_unref(reply);
312 }
313
314 if (activatable) {
315 r = sd_bus_call_method(
316 bus,
317 "org.freedesktop.DBus",
cd789fdf 318 "/org/freedesktop/DBus",
71f2ab46
LP
319 "org.freedesktop.DBus",
320 "ListActivatableNames",
321 NULL,
322 &reply,
323 NULL);
324 if (r < 0)
325 return r;
326
327 r = sd_bus_message_read_strv(reply, &y);
328 if (r < 0)
329 return r;
330
331 *activatable = y;
332 y = NULL;
333 }
334
335 if (acquired) {
336 *acquired = x;
337 x = NULL;
a4297f08 338 }
de1c301e 339
49b832c5
LP
340 return 0;
341}
342
71f2ab46 343_public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
e7176abb 344 assert_return(bus, -EINVAL);
71f2ab46 345 assert_return(acquired || activatable, -EINVAL);
e7176abb
LP
346 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
347 assert_return(!bus_pid_changed(bus), -ECHILD);
348
349 if (bus->is_kernel)
71f2ab46 350 return bus_list_names_kernel(bus, acquired, activatable);
e7176abb 351 else
71f2ab46 352 return bus_list_names_dbus1(bus, acquired, activatable);
e7176abb
LP
353}
354
49b832c5
LP
355static int bus_get_owner_kdbus(
356 sd_bus *bus,
357 const char *name,
358 uint64_t mask,
359 sd_bus_creds **creds) {
360
49b832c5 361 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
c85a5a24
DM
362 struct kdbus_cmd_conn_info *cmd;
363 struct kdbus_conn_info *conn_info;
49b832c5
LP
364 struct kdbus_item *item;
365 size_t size;
366 uint64_t m, id;
367 int r;
368
369 r = bus_kernel_parse_unique_name(name, &id);
370 if (r < 0)
371 return r;
372 if (r > 0) {
c85a5a24 373 size = offsetof(struct kdbus_cmd_conn_info, name);
49b832c5
LP
374 cmd = alloca0(size);
375 cmd->id = id;
376 } else {
c85a5a24 377 size = offsetof(struct kdbus_cmd_conn_info, name) + strlen(name) + 1;
49b832c5
LP
378 cmd = alloca0(size);
379 strcpy(cmd->name, name);
a4297f08 380 }
f7d85951 381 cmd->flags = KDBUS_ATTACH_NAMES;
de1c301e 382
49b832c5 383 cmd->size = size;
c85a5a24 384 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
49b832c5
LP
385 if (r < 0)
386 return -errno;
387
c85a5a24 388 conn_info = (struct kdbus_conn_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
49b832c5 389
c2073383
LP
390 /* Non-activated names are considered not available */
391 if (conn_info->flags & KDBUS_HELLO_ACTIVATOR)
392 return name[0] == ':' ? -ENXIO : -ENOENT;
393
49b832c5
LP
394 c = bus_creds_new();
395 if (!c)
396 return -ENOMEM;
397
398 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
c85a5a24 399 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0)
49b832c5
LP
400 return -ENOMEM;
401
402 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
403 }
404
a8d4cac5 405 KDBUS_ITEM_FOREACH(item, conn_info, items) {
49b832c5
LP
406
407 switch (item->type) {
408
409 case KDBUS_ITEM_CREDS:
410 m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID |
411 SD_BUS_CREDS_TID | SD_BUS_CREDS_PID_STARTTIME) & mask;
412
413 if (m) {
414 c->uid = item->creds.uid;
415 c->pid = item->creds.pid;
416 c->gid = item->creds.gid;
417 c->tid = item->creds.tid;
418 c->pid_starttime = item->creds.starttime;
419 c->mask |= m;
420 }
421 break;
422
423 case KDBUS_ITEM_PID_COMM:
424 if (mask & SD_BUS_CREDS_COMM) {
425 c->comm = strdup(item->str);
426 if (!c->comm) {
427 r = -ENOMEM;
428 goto fail;
429 }
430
431 c->mask |= SD_BUS_CREDS_COMM;
432 }
433 break;
434
435 case KDBUS_ITEM_TID_COMM:
436 if (mask & SD_BUS_CREDS_TID_COMM) {
437 c->tid_comm = strdup(item->str);
438 if (!c->tid_comm) {
439 r = -ENOMEM;
440 goto fail;
441 }
442
443 c->mask |= SD_BUS_CREDS_TID_COMM;
444 }
445 break;
446
447 case KDBUS_ITEM_EXE:
448 if (mask & SD_BUS_CREDS_EXE) {
449 c->exe = strdup(item->str);
450 if (!c->exe) {
451 r = -ENOMEM;
452 goto fail;
453 }
454
455 c->mask |= SD_BUS_CREDS_EXE;
456 }
457 break;
458
459 case KDBUS_ITEM_CMDLINE:
460 if (mask & SD_BUS_CREDS_CMDLINE) {
a8d4cac5 461 c->cmdline_size = item->size - KDBUS_ITEM_HEADER_SIZE;
49b832c5
LP
462 c->cmdline = memdup(item->data, c->cmdline_size);
463 if (!c->cmdline) {
464 r = -ENOMEM;
465 goto fail;
466 }
467
e7176abb
LP
468 c->mask |= SD_BUS_CREDS_CMDLINE;
469 }
470 break;
471
472 case KDBUS_ITEM_CGROUP:
473 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
474 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
475 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
476
477 if (m) {
478 c->cgroup = strdup(item->str);
479 if (!c->cgroup) {
480 r = -ENOMEM;
481 goto fail;
482 }
483
484 c->mask |= m;
485 }
486 break;
487
488 case KDBUS_ITEM_CAPS:
489 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
490 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
491
492 if (m) {
a8d4cac5 493 c->capability_size = item->size - KDBUS_ITEM_HEADER_SIZE;
e7176abb
LP
494 c->capability = memdup(item->data, c->capability_size);
495 if (!c->capability) {
496 r = -ENOMEM;
497 goto fail;
498 }
499
500 c->mask |= m;
501 }
502 break;
503
504 case KDBUS_ITEM_SECLABEL:
505 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
506 c->label = strdup(item->str);
507 if (!c->label) {
508 r = -ENOMEM;
509 goto fail;
510 }
511
512 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
513 }
514 break;
515
516 case KDBUS_ITEM_AUDIT:
517 m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask;
518
519 if (m) {
520 c->audit_session_id = item->audit.sessionid;
521 c->audit_login_uid = item->audit.loginuid;
522 c->mask |= m;
523 }
524 break;
525
65dae17a 526 case KDBUS_ITEM_NAME:
45fd5e4d 527 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
65dae17a
KS
528 r = strv_extend(&c->well_known_names, item->name.name);
529 if (r < 0)
e7176abb 530 goto fail;
e7176abb
LP
531
532 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
533 }
534 break;
535 }
536 }
537
538 if (creds) {
539 *creds = c;
540 c = NULL;
541 }
542
543 r = 0;
544
545fail:
546 ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd->offset);
547 return r;
548}
549
550static int bus_get_owner_dbus1(
551 sd_bus *bus,
552 const char *name,
553 uint64_t mask,
554 sd_bus_creds **creds) {
555
556 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
557 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
558 const char *unique = NULL;
559 pid_t pid = 0;
560 int r;
561
562 /* Only query the owner if the caller wants to know it or if
563 * the caller just wants to check whether a name exists */
564 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
565 r = sd_bus_call_method(
566 bus,
567 "org.freedesktop.DBus",
cd789fdf 568 "/org/freedesktop/DBus",
e7176abb
LP
569 "org.freedesktop.DBus",
570 "GetNameOwner",
571 NULL,
572 &reply_unique,
573 "s",
574 name);
575 if (r < 0)
576 return r;
577
578 r = sd_bus_message_read(reply_unique, "s", &unique);
579 if (r < 0)
580 return r;
581 }
582
583 if (mask != 0) {
584 c = bus_creds_new();
585 if (!c)
586 return -ENOMEM;
587
588 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
589 c->unique_name = strdup(unique);
590 if (!c->unique_name)
591 return -ENOMEM;
592
593 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
594 }
49b832c5 595
e7176abb
LP
596 if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_GID|
597 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
598 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|
599 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
600 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)) {
601 uint32_t u;
49b832c5 602
e7176abb
LP
603 r = sd_bus_call_method(
604 bus,
605 "org.freedesktop.DBus",
cd789fdf 606 "/org/freedesktop/DBus",
e7176abb
LP
607 "org.freedesktop.DBus",
608 "GetConnectionUnixProcessID",
609 NULL,
610 &reply,
611 "s",
612 unique ? unique : name);
613 if (r < 0)
614 return r;
49b832c5 615
e7176abb
LP
616 r = sd_bus_message_read(reply, "u", &u);
617 if (r < 0)
618 return r;
619
620 pid = u;
621 if (mask & SD_BUS_CREDS_PID) {
622 c->pid = u;
623 c->mask |= SD_BUS_CREDS_PID;
49b832c5 624 }
49b832c5 625
e7176abb
LP
626 reply = sd_bus_message_unref(reply);
627 }
49b832c5 628
e7176abb
LP
629 if (mask & SD_BUS_CREDS_UID) {
630 uint32_t u;
49b832c5 631
e7176abb
LP
632 r = sd_bus_call_method(
633 bus,
634 "org.freedesktop.DBus",
cd789fdf 635 "/org/freedesktop/DBus",
e7176abb
LP
636 "org.freedesktop.DBus",
637 "GetConnectionUnixUser",
638 NULL,
639 &reply,
640 "s",
641 unique ? unique : name);
642 if (r < 0)
643 return r;
49b832c5 644
e7176abb
LP
645 r = sd_bus_message_read(reply, "u", &u);
646 if (r < 0)
647 return r;
49b832c5 648
e7176abb
LP
649 c->uid = u;
650 c->mask |= SD_BUS_CREDS_UID;
49b832c5 651
e7176abb
LP
652 reply = sd_bus_message_unref(reply);
653 }
49b832c5 654
e7176abb
LP
655 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
656 const void *p;
657 size_t sz;
49b832c5 658
e7176abb
LP
659 r = sd_bus_call_method(
660 bus,
661 "org.freedesktop.DBus",
cd789fdf 662 "/org/freedesktop/DBus",
e7176abb
LP
663 "org.freedesktop.DBus",
664 "GetConnectionSELinuxSecurityContext",
665 NULL,
666 &reply,
667 "s",
668 unique ? unique : name);
669 if (r < 0)
670 return r;
49b832c5 671
e7176abb
LP
672 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
673 if (r < 0)
674 return r;
675
676 c->label = strndup(p, sz);
677 if (!c->label)
678 return -ENOMEM;
679
680 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
49b832c5 681 }
e7176abb
LP
682
683 r = bus_creds_add_more(c, mask, pid, 0);
684 if (r < 0)
685 return r;
49b832c5
LP
686 }
687
688 if (creds) {
689 *creds = c;
690 c = NULL;
691 }
692
e7176abb 693 return 0;
49b832c5
LP
694}
695
696_public_ int sd_bus_get_owner(
697 sd_bus *bus,
698 const char *name,
699 uint64_t mask,
700 sd_bus_creds **creds) {
701
702 assert_return(bus, -EINVAL);
703 assert_return(name, -EINVAL);
95c4fe82 704 assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
49b832c5
LP
705 assert_return(mask == 0 || creds, -EINVAL);
706 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
707 assert_return(!bus_pid_changed(bus), -ECHILD);
45fd5e4d 708 assert_return(service_name_is_valid(name), -EINVAL);
0721804f 709 assert_return(bus->bus_client, -ENODATA);
49b832c5
LP
710
711 if (bus->is_kernel)
712 return bus_get_owner_kdbus(bus, name, mask, creds);
713 else
e7176abb 714 return bus_get_owner_dbus1(bus, name, mask, creds);
de1c301e
LP
715}
716
777d7a61
LP
717static int add_name_change_match(sd_bus *bus,
718 uint64_t cookie,
719 const char *name,
720 const char *old_owner,
721 const char *new_owner) {
722
5a884f93 723 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
777d7a61
LP
724 int is_name_id = -1, r;
725 struct kdbus_item *item;
726
727 assert(bus);
728
729 /* If we encounter a match that could match against
730 * NameOwnerChanged messages, then we need to create
73842d62
DM
731 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
732 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
777d7a61
LP
733 * multiple if the match is underspecified.
734 *
735 * The NameOwnerChanged signals take three parameters with
736 * unique or well-known names, but only some forms actually
737 * exist:
738 *
73842d62
DM
739 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
740 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
741 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
742 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
743 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
777d7a61
LP
744 *
745 * For the latter two the two unique names must be identical.
746 *
747 * */
748
749 if (name) {
750 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
751 if (is_name_id < 0)
752 return 0;
753 }
754
33cb6e79 755 if (!isempty(old_owner)) {
777d7a61
LP
756 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
757 if (r < 0)
758 return 0;
759 if (r == 0)
760 return 0;
761 if (is_name_id > 0 && old_owner_id != name_id)
762 return 0;
73842d62
DM
763 } else
764 old_owner_id = KDBUS_MATCH_ID_ANY;
777d7a61 765
33cb6e79 766 if (!isempty(new_owner)) {
777d7a61
LP
767 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
768 if (r < 0)
769 return r;
770 if (r == 0)
771 return 0;
772 if (is_name_id > 0 && new_owner_id != name_id)
773 return 0;
73842d62
DM
774 } else
775 new_owner_id = KDBUS_MATCH_ID_ANY;
777d7a61
LP
776
777 if (is_name_id <= 0) {
006a0b87 778 struct kdbus_cmd_match *m;
777d7a61
LP
779 size_t sz, l;
780
781 /* If the name argument is missing or is a well-known
73842d62 782 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
777d7a61
LP
783 * matches for it */
784
8da4de03 785 l = name ? strlen(name) + 1 : 0;
777d7a61
LP
786
787 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
788 offsetof(struct kdbus_item, name_change) +
789 offsetof(struct kdbus_notify_name_change, name) +
8da4de03 790 l);
777d7a61 791
006a0b87
LP
792 m = alloca0(sz);
793 m->size = sz;
794 m->cookie = cookie;
777d7a61 795
006a0b87
LP
796 item = m->items;
797 item->size =
798 offsetof(struct kdbus_item, name_change) +
799 offsetof(struct kdbus_notify_name_change, name) +
8da4de03 800 l;
777d7a61 801
ceceaf09
DM
802 item->name_change.old.id = old_owner_id;
803 item->name_change.new.id = new_owner_id;
777d7a61 804
006a0b87 805 if (name)
dff91e8b 806 memcpy(item->name_change.name, name, l);
777d7a61 807
006a0b87
LP
808 /* If the old name is unset or empty, then
809 * this can match against added names */
810 if (!old_owner || old_owner[0] == 0) {
73842d62 811 item->type = KDBUS_ITEM_NAME_ADD;
777d7a61 812
006a0b87
LP
813 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
814 if (r < 0)
815 return -errno;
816 }
777d7a61 817
006a0b87
LP
818 /* If the new name is unset or empty, then
819 * this can match against removed names */
820 if (!new_owner || new_owner[0] == 0) {
73842d62 821 item->type = KDBUS_ITEM_NAME_REMOVE;
777d7a61 822
006a0b87
LP
823 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
824 if (r < 0)
825 return -errno;
826 }
777d7a61 827
85a0aa17
LP
828 /* The CHANGE match we need in either case, because
829 * what is reported as a name change by the kernel
830 * might just be an owner change between starter and
831 * normal clients. For userspace such a change should
832 * be considered a removal/addition, hence let's
833 * subscribe to this unconditionally. */
834 item->type = KDBUS_ITEM_NAME_CHANGE;
835 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
836 if (r < 0)
837 return -errno;
777d7a61
LP
838 }
839
840 if (is_name_id != 0) {
006a0b87
LP
841 struct kdbus_cmd_match *m;
842 uint64_t sz;
777d7a61
LP
843
844 /* If the name argument is missing or is a unique
73842d62 845 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
777d7a61
LP
846 * for it */
847
006a0b87
LP
848 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
849 offsetof(struct kdbus_item, id_change) +
850 sizeof(struct kdbus_notify_id_change));
777d7a61 851
006a0b87
LP
852 m = alloca0(sz);
853 m->size = sz;
854 m->cookie = cookie;
777d7a61 855
006a0b87 856 item = m->items;
dff91e8b
LP
857 item->size =
858 offsetof(struct kdbus_item, id_change) +
859 sizeof(struct kdbus_notify_id_change);
ff2ea192 860 item->id_change.id = name_id;
777d7a61
LP
861
862 /* If the old name is unset or empty, then this can
863 * match against added ids */
864 if (!old_owner || old_owner[0] == 0) {
73842d62 865 item->type = KDBUS_ITEM_ID_ADD;
777d7a61
LP
866
867 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
868 if (r < 0)
869 return -errno;
870 }
871
872 /* If thew new name is unset or empty, then this can
73842d62 873 * match against removed ids */
777d7a61 874 if (!new_owner || new_owner[0] == 0) {
73842d62 875 item->type = KDBUS_ITEM_ID_REMOVE;
777d7a61
LP
876
877 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
878 if (r < 0)
879 return -errno;
880 }
881 }
882
883 return 0;
884}
885
53461b74 886int bus_add_match_internal_kernel(
c7819669 887 sd_bus *bus,
53461b74 888 uint64_t id,
c7819669
LP
889 struct bus_match_component *components,
890 unsigned n_components,
891 uint64_t cookie) {
892
e7176abb
LP
893 struct kdbus_cmd_match *m;
894 struct kdbus_item *item;
895 uint64_t bloom[BLOOM_SIZE/8];
896 size_t sz;
897 const char *sender = NULL;
898 size_t sender_length = 0;
73842d62 899 uint64_t src_id = KDBUS_MATCH_ID_ANY;
e7176abb
LP
900 bool using_bloom = false;
901 unsigned i;
902 bool matches_name_change = true;
903 const char *name_change_arg[3] = {};
c7819669
LP
904 int r;
905
392d5b37 906 assert(bus);
de1c301e 907
e7176abb 908 zero(bloom);
c7819669 909
73842d62
DM
910 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
911 offsetof(struct kdbus_item, id) + sizeof(uint64_t));
c7819669 912
e7176abb
LP
913 for (i = 0; i < n_components; i++) {
914 struct bus_match_component *c = &components[i];
777d7a61 915
e7176abb 916 switch (c->type) {
c7819669 917
e7176abb
LP
918 case BUS_MATCH_SENDER:
919 if (!streq(c->value_str, "org.freedesktop.DBus"))
920 matches_name_change = false;
777d7a61 921
e7176abb
LP
922 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
923 if (r < 0)
924 return r;
c7819669 925
d711a957 926 if (r == 0) {
e7176abb
LP
927 sender = c->value_str;
928 sender_length = strlen(sender);
929 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
930 }
777d7a61 931
e7176abb 932 break;
c7819669 933
e7176abb
LP
934 case BUS_MATCH_MESSAGE_TYPE:
935 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
936 matches_name_change = false;
777d7a61 937
e7176abb
LP
938 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
939 using_bloom = true;
940 break;
c7819669 941
e7176abb
LP
942 case BUS_MATCH_INTERFACE:
943 if (!streq(c->value_str, "org.freedesktop.DBus"))
944 matches_name_change = false;
c7819669 945
e7176abb
LP
946 bloom_add_pair(bloom, "interface", c->value_str);
947 using_bloom = true;
948 break;
86312ab8 949
e7176abb
LP
950 case BUS_MATCH_MEMBER:
951 if (!streq(c->value_str, "NameOwnerChanged"))
952 matches_name_change = false;
777d7a61 953
e7176abb
LP
954 bloom_add_pair(bloom, "member", c->value_str);
955 using_bloom = true;
956 break;
86312ab8 957
e7176abb
LP
958 case BUS_MATCH_PATH:
959 if (!streq(c->value_str, "/org/freedesktop/DBus"))
960 matches_name_change = false;
86312ab8 961
e7176abb
LP
962 bloom_add_pair(bloom, "path", c->value_str);
963 using_bloom = true;
964 break;
965
966 case BUS_MATCH_PATH_NAMESPACE:
967 if (!streq(c->value_str, "/")) {
968 bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
86312ab8 969 using_bloom = true;
86312ab8 970 }
e7176abb 971 break;
86312ab8 972
e7176abb
LP
973 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
974 char buf[sizeof("arg")-1 + 2 + 1];
86312ab8 975
e7176abb
LP
976 if (c->type - BUS_MATCH_ARG < 3)
977 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
86312ab8 978
e7176abb
LP
979 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
980 bloom_add_pair(bloom, buf, c->value_str);
981 using_bloom = true;
982 break;
c7819669
LP
983 }
984
e7176abb
LP
985 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
986 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
c7819669 987
e7176abb
LP
988 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
989 bloom_add_pair(bloom, buf, c->value_str);
990 using_bloom = true;
991 break;
992 }
c7819669 993
e7176abb
LP
994 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
995 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
c7819669 996
e7176abb
LP
997 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
998 bloom_add_pair(bloom, buf, c->value_str);
999 using_bloom = true;
1000 break;
c7819669
LP
1001 }
1002
e7176abb
LP
1003 case BUS_MATCH_DESTINATION:
1004 /* The bloom filter does not include
1005 the destination, since it is only
1006 available for broadcast messages
1007 which do not carry a destination
1008 since they are undirected. */
1009 break;
1010
1011 case BUS_MATCH_ROOT:
1012 case BUS_MATCH_VALUE:
1013 case BUS_MATCH_LEAF:
1014 case _BUS_MATCH_NODE_TYPE_MAX:
1015 case _BUS_MATCH_NODE_TYPE_INVALID:
1016 assert_not_reached("Invalid match type?");
c7819669 1017 }
e7176abb
LP
1018 }
1019
1020 if (using_bloom)
1021 sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
1022
1023 m = alloca0(sz);
1024 m->size = sz;
1025 m->cookie = cookie;
98531b57 1026 m->owner_id = id;
e7176abb
LP
1027
1028 item = m->items;
73842d62
DM
1029 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1030 item->type = KDBUS_ITEM_ID;
1031 item->id = src_id;
e7176abb
LP
1032
1033 if (using_bloom) {
73842d62 1034 item = KDBUS_ITEM_NEXT(item);
e7176abb 1035 item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
73842d62 1036 item->type = KDBUS_ITEM_BLOOM;
e7176abb 1037 memcpy(item->data64, bloom, BLOOM_SIZE);
e7176abb
LP
1038 }
1039
1040 if (sender) {
73842d62 1041 item = KDBUS_ITEM_NEXT(item);
e7176abb 1042 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
73842d62 1043 item->type = KDBUS_ITEM_NAME;
e7176abb
LP
1044 memcpy(item->str, sender, sender_length + 1);
1045 }
1046
1047 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1048 if (r < 0)
1049 return -errno;
1050
1051 if (matches_name_change) {
1052
1053 /* If this match could theoretically match
1054 * NameOwnerChanged messages, we need to
1055 * install a second non-bloom filter explitly
1056 * for it */
c7819669 1057
e7176abb 1058 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
c7819669 1059 if (r < 0)
e7176abb
LP
1060 return r;
1061 }
c7819669 1062
e7176abb
LP
1063 return 0;
1064}
777d7a61 1065
e7176abb
LP
1066static int bus_add_match_internal_dbus1(
1067 sd_bus *bus,
1068 const char *match) {
777d7a61 1069
e7176abb
LP
1070 assert(bus);
1071 assert(match);
777d7a61 1072
e7176abb
LP
1073 return sd_bus_call_method(
1074 bus,
1075 "org.freedesktop.DBus",
cd789fdf 1076 "/org/freedesktop/DBus",
e7176abb
LP
1077 "org.freedesktop.DBus",
1078 "AddMatch",
1079 NULL,
1080 NULL,
1081 "s",
1082 match);
de1c301e
LP
1083}
1084
e7176abb
LP
1085int bus_add_match_internal(
1086 sd_bus *bus,
1087 const char *match,
1088 struct bus_match_component *components,
1089 unsigned n_components,
1090 uint64_t cookie) {
1091
1092 assert(bus);
1093 assert(match);
1094
1095 if (bus->is_kernel)
53461b74 1096 return bus_add_match_internal_kernel(bus, 0, components, n_components, cookie);
e7176abb
LP
1097 else
1098 return bus_add_match_internal_dbus1(bus, match);
1099}
1100
53461b74 1101int bus_remove_match_internal_kernel(
c7819669 1102 sd_bus *bus,
53461b74 1103 uint64_t id,
c7819669
LP
1104 uint64_t cookie) {
1105
e7176abb 1106 struct kdbus_cmd_match m;
c7819669
LP
1107 int r;
1108
392d5b37 1109 assert(bus);
de1c301e 1110
e7176abb
LP
1111 zero(m);
1112 m.size = offsetof(struct kdbus_cmd_match, items);
1113 m.cookie = cookie;
98531b57 1114 m.owner_id = id;
c7819669 1115
e7176abb
LP
1116 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1117 if (r < 0)
1118 return -errno;
c7819669 1119
e7176abb
LP
1120 return 0;
1121}
c7819669 1122
e7176abb
LP
1123static int bus_remove_match_internal_dbus1(
1124 sd_bus *bus,
1125 const char *match) {
777d7a61 1126
e7176abb
LP
1127 assert(bus);
1128 assert(match);
1129
1130 return sd_bus_call_method(
1131 bus,
1132 "org.freedesktop.DBus",
cd789fdf 1133 "/org/freedesktop/DBus",
e7176abb
LP
1134 "org.freedesktop.DBus",
1135 "RemoveMatch",
1136 NULL,
1137 NULL,
1138 "s",
1139 match);
1140}
1141
1142int bus_remove_match_internal(
1143 sd_bus *bus,
1144 const char *match,
1145 uint64_t cookie) {
1146
1147 assert(bus);
1148 assert(match);
1149
1150 if (bus->is_kernel)
53461b74 1151 return bus_remove_match_internal_kernel(bus, 0, cookie);
e7176abb
LP
1152 else
1153 return bus_remove_match_internal_dbus1(bus, match);
de1c301e 1154}
70666185 1155
d9f644e2 1156_public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
8d162091 1157 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
70666185
LP
1158 const char *mid;
1159 int r;
1160
8d162091
LP
1161 assert_return(bus, -EINVAL);
1162 assert_return(name, -EINVAL);
1163 assert_return(machine, -EINVAL);
1164 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1165 assert_return(!bus_pid_changed(bus), -ECHILD);
45fd5e4d 1166 assert_return(service_name_is_valid(name), -EINVAL);
70666185
LP
1167
1168 if (streq_ptr(name, bus->unique_name))
1169 return sd_id128_get_machine(machine);
1170
8d162091
LP
1171 r = sd_bus_message_new_method_call(
1172 bus,
1173 name,
1174 "/",
1175 "org.freedesktop.DBus.Peer",
1176 "GetMachineId", &m);
1177 if (r < 0)
1178 return r;
1179
1180 r = sd_bus_message_set_no_auto_start(m, true);
1181 if (r < 0)
1182 return r;
70666185 1183
8d162091 1184 r = sd_bus_call(bus, m, 0, NULL, &reply);
70666185
LP
1185 if (r < 0)
1186 return r;
1187
1188 r = sd_bus_message_read(reply, "s", &mid);
1189 if (r < 0)
1190 return r;
1191
1192 return sd_id128_from_string(mid, machine);
1193}