]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-control.c
bus: fix return message if StartServiceByName() in the driver fails due
[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:
2dc9970b 410 m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID) & mask;
49b832c5
LP
411
412 if (m) {
413 c->uid = item->creds.uid;
414 c->pid = item->creds.pid;
415 c->gid = item->creds.gid;
2dc9970b
LP
416 c->mask |= m;
417 }
418
419 if (mask & SD_BUS_CREDS_TID && item->creds.tid > 0) {
49b832c5 420 c->tid = item->creds.tid;
2dc9970b
LP
421 c->mask |= SD_BUS_CREDS_TID;
422 }
423
424 if (mask & SD_BUS_CREDS_PID_STARTTIME && item->creds.starttime > 0) {
49b832c5 425 c->pid_starttime = item->creds.starttime;
2dc9970b 426 c->mask |= SD_BUS_CREDS_PID_STARTTIME;
49b832c5 427 }
2dc9970b 428
49b832c5
LP
429 break;
430
431 case KDBUS_ITEM_PID_COMM:
432 if (mask & SD_BUS_CREDS_COMM) {
433 c->comm = strdup(item->str);
434 if (!c->comm) {
435 r = -ENOMEM;
436 goto fail;
437 }
438
439 c->mask |= SD_BUS_CREDS_COMM;
440 }
441 break;
442
443 case KDBUS_ITEM_TID_COMM:
444 if (mask & SD_BUS_CREDS_TID_COMM) {
445 c->tid_comm = strdup(item->str);
446 if (!c->tid_comm) {
447 r = -ENOMEM;
448 goto fail;
449 }
450
451 c->mask |= SD_BUS_CREDS_TID_COMM;
452 }
453 break;
454
455 case KDBUS_ITEM_EXE:
456 if (mask & SD_BUS_CREDS_EXE) {
457 c->exe = strdup(item->str);
458 if (!c->exe) {
459 r = -ENOMEM;
460 goto fail;
461 }
462
463 c->mask |= SD_BUS_CREDS_EXE;
464 }
465 break;
466
467 case KDBUS_ITEM_CMDLINE:
468 if (mask & SD_BUS_CREDS_CMDLINE) {
a8d4cac5 469 c->cmdline_size = item->size - KDBUS_ITEM_HEADER_SIZE;
49b832c5
LP
470 c->cmdline = memdup(item->data, c->cmdline_size);
471 if (!c->cmdline) {
472 r = -ENOMEM;
473 goto fail;
474 }
475
e7176abb
LP
476 c->mask |= SD_BUS_CREDS_CMDLINE;
477 }
478 break;
479
480 case KDBUS_ITEM_CGROUP:
481 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
482 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
483 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
484
485 if (m) {
486 c->cgroup = strdup(item->str);
487 if (!c->cgroup) {
488 r = -ENOMEM;
489 goto fail;
490 }
491
492 c->mask |= m;
493 }
494 break;
495
496 case KDBUS_ITEM_CAPS:
497 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
498 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
499
500 if (m) {
a8d4cac5 501 c->capability_size = item->size - KDBUS_ITEM_HEADER_SIZE;
e7176abb
LP
502 c->capability = memdup(item->data, c->capability_size);
503 if (!c->capability) {
504 r = -ENOMEM;
505 goto fail;
506 }
507
508 c->mask |= m;
509 }
510 break;
511
512 case KDBUS_ITEM_SECLABEL:
513 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
514 c->label = strdup(item->str);
515 if (!c->label) {
516 r = -ENOMEM;
517 goto fail;
518 }
519
520 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
521 }
522 break;
523
524 case KDBUS_ITEM_AUDIT:
525 m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask;
526
527 if (m) {
528 c->audit_session_id = item->audit.sessionid;
529 c->audit_login_uid = item->audit.loginuid;
530 c->mask |= m;
531 }
532 break;
533
65dae17a 534 case KDBUS_ITEM_NAME:
45fd5e4d 535 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
65dae17a
KS
536 r = strv_extend(&c->well_known_names, item->name.name);
537 if (r < 0)
e7176abb 538 goto fail;
e7176abb
LP
539
540 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
541 }
542 break;
543 }
544 }
545
546 if (creds) {
547 *creds = c;
548 c = NULL;
549 }
550
551 r = 0;
552
553fail:
554 ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd->offset);
555 return r;
556}
557
558static int bus_get_owner_dbus1(
559 sd_bus *bus,
560 const char *name,
561 uint64_t mask,
562 sd_bus_creds **creds) {
563
564 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
565 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
566 const char *unique = NULL;
567 pid_t pid = 0;
568 int r;
569
570 /* Only query the owner if the caller wants to know it or if
571 * the caller just wants to check whether a name exists */
572 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
573 r = sd_bus_call_method(
574 bus,
575 "org.freedesktop.DBus",
cd789fdf 576 "/org/freedesktop/DBus",
e7176abb
LP
577 "org.freedesktop.DBus",
578 "GetNameOwner",
579 NULL,
580 &reply_unique,
581 "s",
582 name);
583 if (r < 0)
584 return r;
585
586 r = sd_bus_message_read(reply_unique, "s", &unique);
587 if (r < 0)
588 return r;
589 }
590
591 if (mask != 0) {
592 c = bus_creds_new();
593 if (!c)
594 return -ENOMEM;
595
596 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
597 c->unique_name = strdup(unique);
598 if (!c->unique_name)
599 return -ENOMEM;
600
601 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
602 }
49b832c5 603
e7176abb
LP
604 if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_GID|
605 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
606 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|
607 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
608 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)) {
609 uint32_t u;
49b832c5 610
e7176abb
LP
611 r = sd_bus_call_method(
612 bus,
613 "org.freedesktop.DBus",
cd789fdf 614 "/org/freedesktop/DBus",
e7176abb
LP
615 "org.freedesktop.DBus",
616 "GetConnectionUnixProcessID",
617 NULL,
618 &reply,
619 "s",
620 unique ? unique : name);
621 if (r < 0)
622 return r;
49b832c5 623
e7176abb
LP
624 r = sd_bus_message_read(reply, "u", &u);
625 if (r < 0)
626 return r;
627
628 pid = u;
629 if (mask & SD_BUS_CREDS_PID) {
630 c->pid = u;
631 c->mask |= SD_BUS_CREDS_PID;
49b832c5 632 }
49b832c5 633
e7176abb
LP
634 reply = sd_bus_message_unref(reply);
635 }
49b832c5 636
e7176abb
LP
637 if (mask & SD_BUS_CREDS_UID) {
638 uint32_t u;
49b832c5 639
e7176abb
LP
640 r = sd_bus_call_method(
641 bus,
642 "org.freedesktop.DBus",
cd789fdf 643 "/org/freedesktop/DBus",
e7176abb
LP
644 "org.freedesktop.DBus",
645 "GetConnectionUnixUser",
646 NULL,
647 &reply,
648 "s",
649 unique ? unique : name);
650 if (r < 0)
651 return r;
49b832c5 652
e7176abb
LP
653 r = sd_bus_message_read(reply, "u", &u);
654 if (r < 0)
655 return r;
49b832c5 656
e7176abb
LP
657 c->uid = u;
658 c->mask |= SD_BUS_CREDS_UID;
49b832c5 659
e7176abb
LP
660 reply = sd_bus_message_unref(reply);
661 }
49b832c5 662
e7176abb
LP
663 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
664 const void *p;
665 size_t sz;
49b832c5 666
e7176abb
LP
667 r = sd_bus_call_method(
668 bus,
669 "org.freedesktop.DBus",
cd789fdf 670 "/org/freedesktop/DBus",
e7176abb
LP
671 "org.freedesktop.DBus",
672 "GetConnectionSELinuxSecurityContext",
673 NULL,
674 &reply,
675 "s",
676 unique ? unique : name);
677 if (r < 0)
678 return r;
49b832c5 679
e7176abb
LP
680 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
681 if (r < 0)
682 return r;
683
684 c->label = strndup(p, sz);
685 if (!c->label)
686 return -ENOMEM;
687
688 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
49b832c5 689 }
e7176abb
LP
690
691 r = bus_creds_add_more(c, mask, pid, 0);
692 if (r < 0)
693 return r;
49b832c5
LP
694 }
695
696 if (creds) {
697 *creds = c;
698 c = NULL;
699 }
700
e7176abb 701 return 0;
49b832c5
LP
702}
703
704_public_ int sd_bus_get_owner(
705 sd_bus *bus,
706 const char *name,
707 uint64_t mask,
708 sd_bus_creds **creds) {
709
710 assert_return(bus, -EINVAL);
711 assert_return(name, -EINVAL);
95c4fe82 712 assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
49b832c5
LP
713 assert_return(mask == 0 || creds, -EINVAL);
714 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
715 assert_return(!bus_pid_changed(bus), -ECHILD);
45fd5e4d 716 assert_return(service_name_is_valid(name), -EINVAL);
0721804f 717 assert_return(bus->bus_client, -ENODATA);
49b832c5
LP
718
719 if (bus->is_kernel)
720 return bus_get_owner_kdbus(bus, name, mask, creds);
721 else
e7176abb 722 return bus_get_owner_dbus1(bus, name, mask, creds);
de1c301e
LP
723}
724
777d7a61
LP
725static int add_name_change_match(sd_bus *bus,
726 uint64_t cookie,
727 const char *name,
728 const char *old_owner,
729 const char *new_owner) {
730
5a884f93 731 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
777d7a61
LP
732 int is_name_id = -1, r;
733 struct kdbus_item *item;
734
735 assert(bus);
736
737 /* If we encounter a match that could match against
738 * NameOwnerChanged messages, then we need to create
73842d62
DM
739 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
740 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
777d7a61
LP
741 * multiple if the match is underspecified.
742 *
743 * The NameOwnerChanged signals take three parameters with
744 * unique or well-known names, but only some forms actually
745 * exist:
746 *
73842d62
DM
747 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
748 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
749 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
750 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
751 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
777d7a61
LP
752 *
753 * For the latter two the two unique names must be identical.
754 *
755 * */
756
757 if (name) {
758 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
759 if (is_name_id < 0)
760 return 0;
761 }
762
33cb6e79 763 if (!isempty(old_owner)) {
777d7a61
LP
764 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
765 if (r < 0)
766 return 0;
767 if (r == 0)
768 return 0;
769 if (is_name_id > 0 && old_owner_id != name_id)
770 return 0;
73842d62
DM
771 } else
772 old_owner_id = KDBUS_MATCH_ID_ANY;
777d7a61 773
33cb6e79 774 if (!isempty(new_owner)) {
777d7a61
LP
775 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
776 if (r < 0)
777 return r;
778 if (r == 0)
779 return 0;
780 if (is_name_id > 0 && new_owner_id != name_id)
781 return 0;
73842d62
DM
782 } else
783 new_owner_id = KDBUS_MATCH_ID_ANY;
777d7a61
LP
784
785 if (is_name_id <= 0) {
006a0b87 786 struct kdbus_cmd_match *m;
777d7a61
LP
787 size_t sz, l;
788
789 /* If the name argument is missing or is a well-known
73842d62 790 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
777d7a61
LP
791 * matches for it */
792
8da4de03 793 l = name ? strlen(name) + 1 : 0;
777d7a61
LP
794
795 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
796 offsetof(struct kdbus_item, name_change) +
797 offsetof(struct kdbus_notify_name_change, name) +
8da4de03 798 l);
777d7a61 799
006a0b87
LP
800 m = alloca0(sz);
801 m->size = sz;
802 m->cookie = cookie;
777d7a61 803
006a0b87
LP
804 item = m->items;
805 item->size =
806 offsetof(struct kdbus_item, name_change) +
807 offsetof(struct kdbus_notify_name_change, name) +
8da4de03 808 l;
777d7a61 809
ceceaf09
DM
810 item->name_change.old.id = old_owner_id;
811 item->name_change.new.id = new_owner_id;
777d7a61 812
006a0b87 813 if (name)
dff91e8b 814 memcpy(item->name_change.name, name, l);
777d7a61 815
006a0b87
LP
816 /* If the old name is unset or empty, then
817 * this can match against added names */
818 if (!old_owner || old_owner[0] == 0) {
73842d62 819 item->type = KDBUS_ITEM_NAME_ADD;
777d7a61 820
006a0b87
LP
821 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
822 if (r < 0)
823 return -errno;
824 }
777d7a61 825
006a0b87
LP
826 /* If the new name is unset or empty, then
827 * this can match against removed names */
828 if (!new_owner || new_owner[0] == 0) {
73842d62 829 item->type = KDBUS_ITEM_NAME_REMOVE;
777d7a61 830
006a0b87
LP
831 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
832 if (r < 0)
833 return -errno;
834 }
777d7a61 835
85a0aa17
LP
836 /* The CHANGE match we need in either case, because
837 * what is reported as a name change by the kernel
838 * might just be an owner change between starter and
839 * normal clients. For userspace such a change should
840 * be considered a removal/addition, hence let's
841 * subscribe to this unconditionally. */
842 item->type = KDBUS_ITEM_NAME_CHANGE;
843 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
844 if (r < 0)
845 return -errno;
777d7a61
LP
846 }
847
848 if (is_name_id != 0) {
006a0b87
LP
849 struct kdbus_cmd_match *m;
850 uint64_t sz;
777d7a61
LP
851
852 /* If the name argument is missing or is a unique
73842d62 853 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
777d7a61
LP
854 * for it */
855
006a0b87
LP
856 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
857 offsetof(struct kdbus_item, id_change) +
858 sizeof(struct kdbus_notify_id_change));
777d7a61 859
006a0b87
LP
860 m = alloca0(sz);
861 m->size = sz;
862 m->cookie = cookie;
777d7a61 863
006a0b87 864 item = m->items;
dff91e8b
LP
865 item->size =
866 offsetof(struct kdbus_item, id_change) +
867 sizeof(struct kdbus_notify_id_change);
ff2ea192 868 item->id_change.id = name_id;
777d7a61
LP
869
870 /* If the old name is unset or empty, then this can
871 * match against added ids */
872 if (!old_owner || old_owner[0] == 0) {
73842d62 873 item->type = KDBUS_ITEM_ID_ADD;
777d7a61
LP
874
875 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
876 if (r < 0)
877 return -errno;
878 }
879
880 /* If thew new name is unset or empty, then this can
73842d62 881 * match against removed ids */
777d7a61 882 if (!new_owner || new_owner[0] == 0) {
73842d62 883 item->type = KDBUS_ITEM_ID_REMOVE;
777d7a61
LP
884
885 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
886 if (r < 0)
887 return -errno;
888 }
889 }
890
891 return 0;
892}
893
53461b74 894int bus_add_match_internal_kernel(
c7819669 895 sd_bus *bus,
53461b74 896 uint64_t id,
c7819669
LP
897 struct bus_match_component *components,
898 unsigned n_components,
899 uint64_t cookie) {
900
e7176abb
LP
901 struct kdbus_cmd_match *m;
902 struct kdbus_item *item;
903 uint64_t bloom[BLOOM_SIZE/8];
904 size_t sz;
905 const char *sender = NULL;
906 size_t sender_length = 0;
73842d62 907 uint64_t src_id = KDBUS_MATCH_ID_ANY;
e7176abb
LP
908 bool using_bloom = false;
909 unsigned i;
910 bool matches_name_change = true;
911 const char *name_change_arg[3] = {};
c7819669
LP
912 int r;
913
392d5b37 914 assert(bus);
de1c301e 915
e7176abb 916 zero(bloom);
c7819669 917
85feb8e4 918 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
c7819669 919
e7176abb
LP
920 for (i = 0; i < n_components; i++) {
921 struct bus_match_component *c = &components[i];
777d7a61 922
e7176abb 923 switch (c->type) {
c7819669 924
e7176abb
LP
925 case BUS_MATCH_SENDER:
926 if (!streq(c->value_str, "org.freedesktop.DBus"))
927 matches_name_change = false;
777d7a61 928
e7176abb
LP
929 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
930 if (r < 0)
931 return r;
85feb8e4
LP
932 else if (r > 0)
933 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
934 else {
e7176abb
LP
935 sender = c->value_str;
936 sender_length = strlen(sender);
937 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
938 }
777d7a61 939
e7176abb 940 break;
c7819669 941
e7176abb
LP
942 case BUS_MATCH_MESSAGE_TYPE:
943 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
944 matches_name_change = false;
777d7a61 945
e7176abb
LP
946 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
947 using_bloom = true;
948 break;
c7819669 949
e7176abb
LP
950 case BUS_MATCH_INTERFACE:
951 if (!streq(c->value_str, "org.freedesktop.DBus"))
952 matches_name_change = false;
c7819669 953
e7176abb
LP
954 bloom_add_pair(bloom, "interface", c->value_str);
955 using_bloom = true;
956 break;
86312ab8 957
e7176abb
LP
958 case BUS_MATCH_MEMBER:
959 if (!streq(c->value_str, "NameOwnerChanged"))
960 matches_name_change = false;
777d7a61 961
e7176abb
LP
962 bloom_add_pair(bloom, "member", c->value_str);
963 using_bloom = true;
964 break;
86312ab8 965
e7176abb
LP
966 case BUS_MATCH_PATH:
967 if (!streq(c->value_str, "/org/freedesktop/DBus"))
968 matches_name_change = false;
86312ab8 969
e7176abb
LP
970 bloom_add_pair(bloom, "path", c->value_str);
971 using_bloom = true;
972 break;
973
974 case BUS_MATCH_PATH_NAMESPACE:
975 if (!streq(c->value_str, "/")) {
976 bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
86312ab8 977 using_bloom = true;
86312ab8 978 }
e7176abb 979 break;
86312ab8 980
e7176abb
LP
981 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
982 char buf[sizeof("arg")-1 + 2 + 1];
86312ab8 983
e7176abb
LP
984 if (c->type - BUS_MATCH_ARG < 3)
985 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
86312ab8 986
e7176abb
LP
987 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
988 bloom_add_pair(bloom, buf, c->value_str);
989 using_bloom = true;
990 break;
c7819669
LP
991 }
992
e7176abb
LP
993 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
994 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
c7819669 995
e7176abb
LP
996 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
997 bloom_add_pair(bloom, buf, c->value_str);
998 using_bloom = true;
999 break;
1000 }
c7819669 1001
e7176abb
LP
1002 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1003 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
c7819669 1004
e7176abb
LP
1005 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1006 bloom_add_pair(bloom, buf, c->value_str);
1007 using_bloom = true;
1008 break;
c7819669
LP
1009 }
1010
e7176abb
LP
1011 case BUS_MATCH_DESTINATION:
1012 /* The bloom filter does not include
1013 the destination, since it is only
1014 available for broadcast messages
1015 which do not carry a destination
1016 since they are undirected. */
1017 break;
1018
1019 case BUS_MATCH_ROOT:
1020 case BUS_MATCH_VALUE:
1021 case BUS_MATCH_LEAF:
1022 case _BUS_MATCH_NODE_TYPE_MAX:
1023 case _BUS_MATCH_NODE_TYPE_INVALID:
1024 assert_not_reached("Invalid match type?");
c7819669 1025 }
e7176abb
LP
1026 }
1027
1028 if (using_bloom)
1029 sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
1030
1031 m = alloca0(sz);
1032 m->size = sz;
1033 m->cookie = cookie;
98531b57 1034 m->owner_id = id;
e7176abb
LP
1035
1036 item = m->items;
1037
85feb8e4
LP
1038 if (src_id != KDBUS_MATCH_ID_ANY) {
1039 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1040 item->type = KDBUS_ITEM_ID;
1041 item->id = src_id;
73842d62 1042 item = KDBUS_ITEM_NEXT(item);
85feb8e4
LP
1043 }
1044
1045 if (using_bloom) {
e7176abb 1046 item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
73842d62 1047 item->type = KDBUS_ITEM_BLOOM;
e7176abb 1048 memcpy(item->data64, bloom, BLOOM_SIZE);
85feb8e4 1049 item = KDBUS_ITEM_NEXT(item);
e7176abb
LP
1050 }
1051
1052 if (sender) {
1053 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
73842d62 1054 item->type = KDBUS_ITEM_NAME;
e7176abb
LP
1055 memcpy(item->str, sender, sender_length + 1);
1056 }
1057
1058 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1059 if (r < 0)
1060 return -errno;
1061
1062 if (matches_name_change) {
1063
1064 /* If this match could theoretically match
1065 * NameOwnerChanged messages, we need to
1066 * install a second non-bloom filter explitly
1067 * for it */
c7819669 1068
e7176abb 1069 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
c7819669 1070 if (r < 0)
e7176abb
LP
1071 return r;
1072 }
c7819669 1073
e7176abb
LP
1074 return 0;
1075}
777d7a61 1076
e7176abb
LP
1077static int bus_add_match_internal_dbus1(
1078 sd_bus *bus,
1079 const char *match) {
777d7a61 1080
e7176abb
LP
1081 assert(bus);
1082 assert(match);
777d7a61 1083
e7176abb
LP
1084 return sd_bus_call_method(
1085 bus,
1086 "org.freedesktop.DBus",
cd789fdf 1087 "/org/freedesktop/DBus",
e7176abb
LP
1088 "org.freedesktop.DBus",
1089 "AddMatch",
1090 NULL,
1091 NULL,
1092 "s",
1093 match);
de1c301e
LP
1094}
1095
e7176abb
LP
1096int bus_add_match_internal(
1097 sd_bus *bus,
1098 const char *match,
1099 struct bus_match_component *components,
1100 unsigned n_components,
1101 uint64_t cookie) {
1102
1103 assert(bus);
1104 assert(match);
1105
1106 if (bus->is_kernel)
53461b74 1107 return bus_add_match_internal_kernel(bus, 0, components, n_components, cookie);
e7176abb
LP
1108 else
1109 return bus_add_match_internal_dbus1(bus, match);
1110}
1111
53461b74 1112int bus_remove_match_internal_kernel(
c7819669 1113 sd_bus *bus,
53461b74 1114 uint64_t id,
c7819669
LP
1115 uint64_t cookie) {
1116
e7176abb 1117 struct kdbus_cmd_match m;
c7819669
LP
1118 int r;
1119
392d5b37 1120 assert(bus);
de1c301e 1121
e7176abb
LP
1122 zero(m);
1123 m.size = offsetof(struct kdbus_cmd_match, items);
1124 m.cookie = cookie;
98531b57 1125 m.owner_id = id;
c7819669 1126
e7176abb
LP
1127 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1128 if (r < 0)
1129 return -errno;
c7819669 1130
e7176abb
LP
1131 return 0;
1132}
c7819669 1133
e7176abb
LP
1134static int bus_remove_match_internal_dbus1(
1135 sd_bus *bus,
1136 const char *match) {
777d7a61 1137
e7176abb
LP
1138 assert(bus);
1139 assert(match);
1140
1141 return sd_bus_call_method(
1142 bus,
1143 "org.freedesktop.DBus",
cd789fdf 1144 "/org/freedesktop/DBus",
e7176abb
LP
1145 "org.freedesktop.DBus",
1146 "RemoveMatch",
1147 NULL,
1148 NULL,
1149 "s",
1150 match);
1151}
1152
1153int bus_remove_match_internal(
1154 sd_bus *bus,
1155 const char *match,
1156 uint64_t cookie) {
1157
1158 assert(bus);
1159 assert(match);
1160
1161 if (bus->is_kernel)
53461b74 1162 return bus_remove_match_internal_kernel(bus, 0, cookie);
e7176abb
LP
1163 else
1164 return bus_remove_match_internal_dbus1(bus, match);
de1c301e 1165}
70666185 1166
d9f644e2 1167_public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
8d162091 1168 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
70666185
LP
1169 const char *mid;
1170 int r;
1171
8d162091
LP
1172 assert_return(bus, -EINVAL);
1173 assert_return(name, -EINVAL);
1174 assert_return(machine, -EINVAL);
1175 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1176 assert_return(!bus_pid_changed(bus), -ECHILD);
45fd5e4d 1177 assert_return(service_name_is_valid(name), -EINVAL);
70666185
LP
1178
1179 if (streq_ptr(name, bus->unique_name))
1180 return sd_id128_get_machine(machine);
1181
8d162091
LP
1182 r = sd_bus_message_new_method_call(
1183 bus,
1184 name,
1185 "/",
1186 "org.freedesktop.DBus.Peer",
1187 "GetMachineId", &m);
1188 if (r < 0)
1189 return r;
1190
1191 r = sd_bus_message_set_no_auto_start(m, true);
1192 if (r < 0)
1193 return r;
70666185 1194
8d162091 1195 r = sd_bus_call(bus, m, 0, NULL, &reply);
70666185
LP
1196 if (r < 0)
1197 return r;
1198
1199 r = sd_bus_message_read(reply, "s", &mid);
1200 if (r < 0)
1201 return r;
1202
1203 return sd_id128_from_string(mid, machine);
1204}