chiark / gitweb /
c6403d3bae2b4ce8cf05d63114c58ff35ab128f5
[elogind.git] / src / libelogind / sd-bus / bus-control.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2013 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #ifdef HAVE_VALGRIND_MEMCHECK_H
21 #include <valgrind/memcheck.h>
22 #endif
23
24 #include <errno.h>
25 #include <stddef.h>
26
27 #include "sd-bus.h"
28
29 #include "alloc-util.h"
30 #include "bus-bloom.h"
31 #include "bus-control.h"
32 #include "bus-internal.h"
33 #include "bus-message.h"
34 #include "bus-util.h"
35 #include "capability-util.h"
36 #include "stdio-util.h"
37 #include "string-util.h"
38 #include "strv.h"
39 #include "user-util.h"
40
41 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
42         int r;
43
44         assert_return(bus, -EINVAL);
45         assert_return(unique, -EINVAL);
46         assert_return(!bus_pid_changed(bus), -ECHILD);
47
48         if (!bus->bus_client)
49                 return -EINVAL;
50
51         r = bus_ensure_running(bus);
52         if (r < 0)
53                 return r;
54
55         *unique = bus->unique_name;
56         return 0;
57 }
58
59 static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
60         struct kdbus_cmd *n;
61         size_t size, l;
62         int r;
63
64         assert(bus);
65         assert(name);
66
67         l = strlen(name) + 1;
68         size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
69         n = alloca0_align(size, 8);
70         n->size = size;
71         n->flags = request_name_flags_to_kdbus(flags);
72
73         n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
74         n->items[0].type = KDBUS_ITEM_NAME;
75         memcpy(n->items[0].str, name, l);
76
77 #ifdef HAVE_VALGRIND_MEMCHECK_H
78         VALGRIND_MAKE_MEM_DEFINED(n, n->size);
79 #endif
80
81         r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
82         if (r < 0)
83                 return -errno;
84
85         if (n->return_flags & KDBUS_NAME_IN_QUEUE)
86                 return 0;
87
88         return 1;
89 }
90
91 static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
92         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
93         uint32_t ret, param = 0;
94         int r;
95
96         assert(bus);
97         assert(name);
98
99         if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
100                 param |= BUS_NAME_ALLOW_REPLACEMENT;
101         if (flags & SD_BUS_NAME_REPLACE_EXISTING)
102                 param |= BUS_NAME_REPLACE_EXISTING;
103         if (!(flags & SD_BUS_NAME_QUEUE))
104                 param |= BUS_NAME_DO_NOT_QUEUE;
105
106         r = sd_bus_call_method(
107                         bus,
108                         "org.freedesktop.DBus",
109                         "/org/freedesktop/DBus",
110                         "org.freedesktop.DBus",
111                         "RequestName",
112                         NULL,
113                         &reply,
114                         "su",
115                         name,
116                         param);
117         if (r < 0)
118                 return r;
119
120         r = sd_bus_message_read(reply, "u", &ret);
121         if (r < 0)
122                 return r;
123
124         if (ret == BUS_NAME_ALREADY_OWNER)
125                 return -EALREADY;
126         else if (ret == BUS_NAME_EXISTS)
127                 return -EEXIST;
128         else if (ret == BUS_NAME_IN_QUEUE)
129                 return 0;
130         else if (ret == BUS_NAME_PRIMARY_OWNER)
131                 return 1;
132
133         return -EIO;
134 }
135
136 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
137         assert_return(bus, -EINVAL);
138         assert_return(name, -EINVAL);
139         assert_return(!bus_pid_changed(bus), -ECHILD);
140         assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
141         assert_return(service_name_is_valid(name), -EINVAL);
142         assert_return(name[0] != ':', -EINVAL);
143
144         if (!bus->bus_client)
145                 return -EINVAL;
146
147         /* Don't allow requesting the special driver and local names */
148         if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
149                 return -EINVAL;
150
151         if (!BUS_IS_OPEN(bus->state))
152                 return -ENOTCONN;
153
154         if (bus->is_kernel)
155                 return bus_request_name_kernel(bus, name, flags);
156         else
157                 return bus_request_name_dbus1(bus, name, flags);
158 }
159
160 static int bus_release_name_kernel(sd_bus *bus, const char *name) {
161         struct kdbus_cmd *n;
162         size_t size, l;
163         int r;
164
165         assert(bus);
166         assert(name);
167
168         l = strlen(name) + 1;
169         size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
170         n = alloca0_align(size, 8);
171         n->size = size;
172
173         n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
174         n->items[0].type = KDBUS_ITEM_NAME;
175         memcpy(n->items[0].str, name, l);
176
177 #ifdef HAVE_VALGRIND_MEMCHECK_H
178         VALGRIND_MAKE_MEM_DEFINED(n, n->size);
179 #endif
180         r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
181         if (r < 0)
182                 return -errno;
183
184         return 0;
185 }
186
187 static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
188         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
189         uint32_t ret;
190         int r;
191
192         assert(bus);
193         assert(name);
194
195         r = sd_bus_call_method(
196                         bus,
197                         "org.freedesktop.DBus",
198                         "/org/freedesktop/DBus",
199                         "org.freedesktop.DBus",
200                         "ReleaseName",
201                         NULL,
202                         &reply,
203                         "s",
204                         name);
205         if (r < 0)
206                 return r;
207
208         r = sd_bus_message_read(reply, "u", &ret);
209         if (r < 0)
210                 return r;
211         if (ret == BUS_NAME_NON_EXISTENT)
212                 return -ESRCH;
213         if (ret == BUS_NAME_NOT_OWNER)
214                 return -EADDRINUSE;
215         if (ret == BUS_NAME_RELEASED)
216                 return 0;
217
218         return -EINVAL;
219 }
220
221 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
222         assert_return(bus, -EINVAL);
223         assert_return(name, -EINVAL);
224         assert_return(!bus_pid_changed(bus), -ECHILD);
225         assert_return(service_name_is_valid(name), -EINVAL);
226         assert_return(name[0] != ':', -EINVAL);
227
228         if (!bus->bus_client)
229                 return -EINVAL;
230
231         /* Don't allow releasing the special driver and local names */
232         if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
233                 return -EINVAL;
234
235         if (!BUS_IS_OPEN(bus->state))
236                 return -ENOTCONN;
237
238         if (bus->is_kernel)
239                 return bus_release_name_kernel(bus, name);
240         else
241                 return bus_release_name_dbus1(bus, name);
242 }
243
244 static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
245         struct kdbus_cmd_list cmd = {
246                 .size = sizeof(cmd),
247                 .flags = flags,
248         };
249         struct kdbus_info *name_list, *name;
250         uint64_t previous_id = 0;
251         int r;
252
253         /* Caller will free half-constructed list on failure... */
254
255         r = ioctl(bus->input_fd, KDBUS_CMD_LIST, &cmd);
256         if (r < 0)
257                 return -errno;
258
259         name_list = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
260
261         KDBUS_FOREACH(name, name_list, cmd.list_size) {
262                 struct kdbus_item *item;
263
264                 if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id && !(name->flags & KDBUS_HELLO_ACTIVATOR)) {
265                         char *n;
266
267 #pragma GCC diagnostic push
268 #pragma GCC diagnostic ignored "-Wformat"
269                         if (asprintf(&n, ":1.%llu", name->id) < 0) {
270                                 r = -ENOMEM;
271                                 goto fail;
272                         }
273 #pragma GCC diagnostic pop
274
275                         r = strv_consume(x, n);
276                         if (r < 0)
277                                 goto fail;
278
279                         previous_id = name->id;
280                 }
281
282                 KDBUS_ITEM_FOREACH(item, name, items) {
283                         if (item->type == KDBUS_ITEM_OWNED_NAME) {
284                                 if (service_name_is_valid(item->name.name)) {
285                                         r = strv_extend(x, item->name.name);
286                                         if (r < 0) {
287                                                 r = -ENOMEM;
288                                                 goto fail;
289                                         }
290                                 }
291                         }
292                 }
293         }
294
295         r = 0;
296
297 fail:
298         bus_kernel_cmd_free(bus, cmd.offset);
299         return r;
300 }
301
302 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
303         _cleanup_strv_free_ char **x = NULL, **y = NULL;
304         int r;
305
306         if (acquired) {
307                 r = kernel_get_list(bus, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES, &x);
308                 if (r < 0)
309                         return r;
310         }
311
312         if (activatable) {
313                 r = kernel_get_list(bus, KDBUS_LIST_ACTIVATORS, &y);
314                 if (r < 0)
315                         return r;
316
317                 *activatable = y;
318                 y = NULL;
319         }
320
321         if (acquired) {
322                 *acquired = x;
323                 x = NULL;
324         }
325
326         return 0;
327 }
328
329 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
330         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
331         _cleanup_strv_free_ char **x = NULL, **y = NULL;
332         int r;
333
334         if (acquired) {
335                 r = sd_bus_call_method(
336                                 bus,
337                                 "org.freedesktop.DBus",
338                                 "/org/freedesktop/DBus",
339                                 "org.freedesktop.DBus",
340                                 "ListNames",
341                                 NULL,
342                                 &reply,
343                                 NULL);
344                 if (r < 0)
345                         return r;
346
347                 r = sd_bus_message_read_strv(reply, &x);
348                 if (r < 0)
349                         return r;
350
351                 reply = sd_bus_message_unref(reply);
352         }
353
354         if (activatable) {
355                 r = sd_bus_call_method(
356                                 bus,
357                                 "org.freedesktop.DBus",
358                                 "/org/freedesktop/DBus",
359                                 "org.freedesktop.DBus",
360                                 "ListActivatableNames",
361                                 NULL,
362                                 &reply,
363                                 NULL);
364                 if (r < 0)
365                         return r;
366
367                 r = sd_bus_message_read_strv(reply, &y);
368                 if (r < 0)
369                         return r;
370
371                 *activatable = y;
372                 y = NULL;
373         }
374
375         if (acquired) {
376                 *acquired = x;
377                 x = NULL;
378         }
379
380         return 0;
381 }
382
383 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
384         assert_return(bus, -EINVAL);
385         assert_return(acquired || activatable, -EINVAL);
386         assert_return(!bus_pid_changed(bus), -ECHILD);
387
388         if (!bus->bus_client)
389                 return -EINVAL;
390
391         if (!BUS_IS_OPEN(bus->state))
392                 return -ENOTCONN;
393
394         if (bus->is_kernel)
395                 return bus_list_names_kernel(bus, acquired, activatable);
396         else
397                 return bus_list_names_dbus1(bus, acquired, activatable);
398 }
399
400 static int bus_populate_creds_from_items(
401                 sd_bus *bus,
402                 struct kdbus_info *info,
403                 uint64_t mask,
404                 sd_bus_creds *c) {
405
406         struct kdbus_item *item;
407         uint64_t m;
408         int r;
409
410         assert(bus);
411         assert(info);
412         assert(c);
413
414         KDBUS_ITEM_FOREACH(item, info, items) {
415
416                 switch (item->type) {
417
418                 case KDBUS_ITEM_PIDS:
419
420                         if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
421                                 c->pid = (pid_t) item->pids.pid;
422                                 c->mask |= SD_BUS_CREDS_PID;
423                         }
424
425                         if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
426                                 c->tid = (pid_t) item->pids.tid;
427                                 c->mask |= SD_BUS_CREDS_TID;
428                         }
429
430                         if (mask & SD_BUS_CREDS_PPID) {
431                                 if (item->pids.ppid > 0) {
432                                         c->ppid = (pid_t) item->pids.ppid;
433                                         c->mask |= SD_BUS_CREDS_PPID;
434                                 } else if (item->pids.pid == 1) {
435                                         /* The structure doesn't
436                                          * really distinguish the case
437                                          * where a process has no
438                                          * parent and where we don't
439                                          * know it because it could
440                                          * not be translated due to
441                                          * namespaces. However, we
442                                          * know that PID 1 has no
443                                          * parent process, hence let's
444                                          * patch that in, manually. */
445                                         c->ppid = 0;
446                                         c->mask |= SD_BUS_CREDS_PPID;
447                                 }
448                         }
449
450                         break;
451
452                 case KDBUS_ITEM_CREDS:
453
454                         if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
455                                 c->uid = (uid_t) item->creds.uid;
456                                 c->mask |= SD_BUS_CREDS_UID;
457                         }
458
459                         if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
460                                 c->euid = (uid_t) item->creds.euid;
461                                 c->mask |= SD_BUS_CREDS_EUID;
462                         }
463
464                         if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
465                                 c->suid = (uid_t) item->creds.suid;
466                                 c->mask |= SD_BUS_CREDS_SUID;
467                         }
468
469                         if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
470                                 c->fsuid = (uid_t) item->creds.fsuid;
471                                 c->mask |= SD_BUS_CREDS_FSUID;
472                         }
473
474                         if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
475                                 c->gid = (gid_t) item->creds.gid;
476                                 c->mask |= SD_BUS_CREDS_GID;
477                         }
478
479                         if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
480                                 c->egid = (gid_t) item->creds.egid;
481                                 c->mask |= SD_BUS_CREDS_EGID;
482                         }
483
484                         if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
485                                 c->sgid = (gid_t) item->creds.sgid;
486                                 c->mask |= SD_BUS_CREDS_SGID;
487                         }
488
489                         if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
490                                 c->fsgid = (gid_t) item->creds.fsgid;
491                                 c->mask |= SD_BUS_CREDS_FSGID;
492                         }
493
494                         break;
495
496                 case KDBUS_ITEM_PID_COMM:
497                         if (mask & SD_BUS_CREDS_COMM) {
498                                 r = free_and_strdup(&c->comm, item->str);
499                                 if (r < 0)
500                                         return r;
501
502                                 c->mask |= SD_BUS_CREDS_COMM;
503                         }
504                         break;
505
506                 case KDBUS_ITEM_TID_COMM:
507                         if (mask & SD_BUS_CREDS_TID_COMM) {
508                                 r = free_and_strdup(&c->tid_comm, item->str);
509                                 if (r < 0)
510                                         return r;
511
512                                 c->mask |= SD_BUS_CREDS_TID_COMM;
513                         }
514                         break;
515
516                 case KDBUS_ITEM_EXE:
517                         if (mask & SD_BUS_CREDS_EXE) {
518                                 r = free_and_strdup(&c->exe, item->str);
519                                 if (r < 0)
520                                         return r;
521
522                                 c->mask |= SD_BUS_CREDS_EXE;
523                         }
524                         break;
525
526                 case KDBUS_ITEM_CMDLINE:
527                         if (mask & SD_BUS_CREDS_CMDLINE) {
528                                 c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
529                                 c->cmdline = memdup(item->data, c->cmdline_size);
530                                 if (!c->cmdline)
531                                         return -ENOMEM;
532
533                                 c->mask |= SD_BUS_CREDS_CMDLINE;
534                         }
535                         break;
536
537                 case KDBUS_ITEM_CGROUP:
538                         m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
539                              SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
540                              SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
541
542                         if (m) {
543                                 r = free_and_strdup(&c->cgroup, item->str);
544                                 if (r < 0)
545                                         return r;
546
547                                 r = bus_get_root_path(bus);
548                                 if (r < 0)
549                                         return r;
550
551                                 r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
552                                 if (r < 0)
553                                         return r;
554
555                                 c->mask |= m;
556                         }
557                         break;
558
559                 case KDBUS_ITEM_CAPS:
560                         m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
561                              SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
562
563                         if (m) {
564                                 if (item->caps.last_cap != cap_last_cap() ||
565                                     item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4)
566                                         return -EBADMSG;
567
568                                 c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps));
569                                 if (!c->capability)
570                                         return -ENOMEM;
571
572                                 c->mask |= m;
573                         }
574                         break;
575
576                 case KDBUS_ITEM_SECLABEL:
577                         if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
578                                 r = free_and_strdup(&c->label, item->str);
579                                 if (r < 0)
580                                         return r;
581
582                                 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
583                         }
584                         break;
585
586                 case KDBUS_ITEM_AUDIT:
587                         if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
588                                 c->audit_session_id = (uint32_t) item->audit.sessionid;
589                                 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
590                         }
591
592                         if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
593                                 c->audit_login_uid = (uid_t) item->audit.loginuid;
594                                 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
595                         }
596                         break;
597
598                 case KDBUS_ITEM_OWNED_NAME:
599                         if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
600                                 r = strv_extend(&c->well_known_names, item->name.name);
601                                 if (r < 0)
602                                         return r;
603
604                                 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
605                         }
606                         break;
607
608                 case KDBUS_ITEM_CONN_DESCRIPTION:
609                         if (mask & SD_BUS_CREDS_DESCRIPTION) {
610                                 r = free_and_strdup(&c->description, item->str);
611                                 if (r < 0)
612                                         return r;
613
614                                 c->mask |= SD_BUS_CREDS_DESCRIPTION;
615                         }
616                         break;
617
618                 case KDBUS_ITEM_AUXGROUPS:
619                         if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
620                                 size_t i, n;
621                                 uid_t *g;
622
623                                 n = (item->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t);
624                                 g = new(gid_t, n);
625                                 if (!g)
626                                         return -ENOMEM;
627
628                                 for (i = 0; i < n; i++)
629                                         g[i] = item->data64[i];
630
631                                 free(c->supplementary_gids);
632                                 c->supplementary_gids = g;
633                                 c->n_supplementary_gids = n;
634
635                                 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
636                         }
637                         break;
638                 }
639         }
640
641         return 0;
642 }
643
644 int bus_get_name_creds_kdbus(
645                 sd_bus *bus,
646                 const char *name,
647                 uint64_t mask,
648                 bool allow_activator,
649                 sd_bus_creds **creds) {
650
651         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
652         struct kdbus_cmd_info *cmd;
653         struct kdbus_info *conn_info;
654         size_t size, l;
655         uint64_t id;
656         int r;
657
658         if (streq(name, "org.freedesktop.DBus"))
659                 return -EOPNOTSUPP;
660
661         r = bus_kernel_parse_unique_name(name, &id);
662         if (r < 0)
663                 return r;
664         if (r > 0) {
665                 size = offsetof(struct kdbus_cmd_info, items);
666                 cmd = alloca0_align(size, 8);
667                 cmd->id = id;
668         } else {
669                 l = strlen(name) + 1;
670                 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
671                 cmd = alloca0_align(size, 8);
672                 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
673                 cmd->items[0].type = KDBUS_ITEM_NAME;
674                 memcpy(cmd->items[0].str, name, l);
675         }
676
677         /* If augmentation is on, and the bus didn't provide us
678          * the bits we want, then ask for the PID/TID so that we
679          * can read the rest from /proc. */
680         if ((mask & SD_BUS_CREDS_AUGMENT) &&
681             (mask & (SD_BUS_CREDS_PPID|
682                      SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
683                      SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
684                      SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
685                      SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
686                      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|
687                      SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
688                      SD_BUS_CREDS_SELINUX_CONTEXT|
689                      SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
690                 mask |= SD_BUS_CREDS_PID;
691
692         cmd->size = size;
693         cmd->attach_flags = attach_flags_to_kdbus(mask);
694
695         r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
696         if (r < 0)
697                 return -errno;
698
699         conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
700
701         /* Non-activated names are considered not available */
702         if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
703                 if (name[0] == ':')
704                         r = -ENXIO;
705                 else
706                         r = -ESRCH;
707                 goto fail;
708         }
709
710         c = bus_creds_new();
711         if (!c) {
712                 r = -ENOMEM;
713                 goto fail;
714         }
715
716         if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
717 #pragma GCC diagnostic push
718 #pragma GCC diagnostic ignored "-Wformat"
719                 if (asprintf(&c->unique_name, ":1.%llu", conn_info->id) < 0) {
720                         r = -ENOMEM;
721                         goto fail;
722                 }
723 #pragma GCC diagnostic pop
724
725                 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
726         }
727
728         /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
729            them in case the service has no names. This does not mean
730            however that the list of owned names could not be
731            acquired. Hence, let's explicitly clarify that the data is
732            complete. */
733         c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
734
735         r = bus_populate_creds_from_items(bus, conn_info, mask, c);
736         if (r < 0)
737                 goto fail;
738
739         r = bus_creds_add_more(c, mask, 0, 0);
740         if (r < 0)
741                 goto fail;
742
743         if (creds) {
744                 *creds = c;
745                 c = NULL;
746         }
747
748         r = 0;
749
750 fail:
751         bus_kernel_cmd_free(bus, cmd->offset);
752         return r;
753 }
754
755 static int bus_get_name_creds_dbus1(
756                 sd_bus *bus,
757                 const char *name,
758                 uint64_t mask,
759                 sd_bus_creds **creds) {
760
761         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL;
762         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
763         const char *unique = NULL;
764         pid_t pid = 0;
765         int r;
766
767         /* Only query the owner if the caller wants to know it or if
768          * the caller just wants to check whether a name exists */
769         if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
770                 r = sd_bus_call_method(
771                                 bus,
772                                 "org.freedesktop.DBus",
773                                 "/org/freedesktop/DBus",
774                                 "org.freedesktop.DBus",
775                                 "GetNameOwner",
776                                 NULL,
777                                 &reply_unique,
778                                 "s",
779                                 name);
780                 if (r < 0)
781                         return r;
782
783                 r = sd_bus_message_read(reply_unique, "s", &unique);
784                 if (r < 0)
785                         return r;
786         }
787
788         if (mask != 0) {
789                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
790                 bool need_pid, need_uid, need_selinux, need_separate_calls;
791                 c = bus_creds_new();
792                 if (!c)
793                         return -ENOMEM;
794
795                 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
796                         c->unique_name = strdup(unique);
797                         if (!c->unique_name)
798                                 return -ENOMEM;
799
800                         c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
801                 }
802
803                 need_pid = (mask & SD_BUS_CREDS_PID) ||
804                         ((mask & SD_BUS_CREDS_AUGMENT) &&
805                          (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
806                                   SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
807                                   SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
808                                   SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
809                                   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|
810                                   SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
811                                   SD_BUS_CREDS_SELINUX_CONTEXT|
812                                   SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)));
813                 need_uid = mask & SD_BUS_CREDS_EUID;
814                 need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT;
815
816                 if (need_pid + need_uid + need_selinux > 1) {
817
818                         /* If we need more than one of the credentials, then use GetConnectionCredentials() */
819
820                         r = sd_bus_call_method(
821                                         bus,
822                                         "org.freedesktop.DBus",
823                                         "/org/freedesktop/DBus",
824                                         "org.freedesktop.DBus",
825                                         "GetConnectionCredentials",
826                                         &error,
827                                         &reply,
828                                         "s",
829                                         unique ?: name);
830
831                         if (r < 0) {
832
833                                 if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
834                                         return r;
835
836                                 /* If we got an unknown method error, fall back to the invidual calls... */
837                                 need_separate_calls = true;
838                                 sd_bus_error_free(&error);
839
840                         } else {
841                                 need_separate_calls = false;
842
843                                 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
844                                 if (r < 0)
845                                         return r;
846
847                                 for (;;) {
848                                         const char *m;
849
850                                         r = sd_bus_message_enter_container(reply, 'e', "sv");
851                                         if (r < 0)
852                                                 return r;
853                                         if (r == 0)
854                                                 break;
855
856                                         r = sd_bus_message_read(reply, "s", &m);
857                                         if (r < 0)
858                                                 return r;
859
860                                         if (need_uid && streq(m, "UnixUserID")) {
861                                                 uint32_t u;
862
863                                                 r = sd_bus_message_read(reply, "v", "u", &u);
864                                                 if (r < 0)
865                                                         return r;
866
867                                                 c->euid = u;
868                                                 c->mask |= SD_BUS_CREDS_EUID;
869
870                                         } else if (need_pid && streq(m, "ProcessID")) {
871                                                 uint32_t p;
872
873                                                 r = sd_bus_message_read(reply, "v", "u", &p);
874                                                 if (r < 0)
875                                                         return r;
876
877                                                 pid = p;
878                                                 if (mask & SD_BUS_CREDS_PID) {
879                                                         c->pid = p;
880                                                         c->mask |= SD_BUS_CREDS_PID;
881                                                 }
882
883                                         } else if (need_selinux && streq(m, "LinuxSecurityLabel")) {
884                                                 const void *p = NULL;
885                                                 size_t sz = 0;
886
887                                                 r = sd_bus_message_enter_container(reply, 'v', "ay");
888                                                 if (r < 0)
889                                                         return r;
890
891                                                 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
892                                                 if (r < 0)
893                                                         return r;
894
895                                                 free(c->label);
896                                                 c->label = strndup(p, sz);
897                                                 if (!c->label)
898                                                         return -ENOMEM;
899
900                                                 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
901
902                                                 r = sd_bus_message_exit_container(reply);
903                                                 if (r < 0)
904                                                         return r;
905                                         } else {
906                                                 r = sd_bus_message_skip(reply, "v");
907                                                 if (r < 0)
908                                                         return r;
909                                         }
910
911                                         r = sd_bus_message_exit_container(reply);
912                                         if (r < 0)
913                                                 return r;
914                                 }
915
916                                 r = sd_bus_message_exit_container(reply);
917                                 if (r < 0)
918                                         return r;
919
920                                 if (need_pid && pid == 0)
921                                         return -EPROTO;
922                         }
923
924                 } else /* When we only need a single field, then let's use separate calls */
925                         need_separate_calls = true;
926
927                 if (need_separate_calls) {
928                         if (need_pid) {
929                                 uint32_t u;
930
931                                 r = sd_bus_call_method(
932                                                 bus,
933                                                 "org.freedesktop.DBus",
934                                                 "/org/freedesktop/DBus",
935                                                 "org.freedesktop.DBus",
936                                                 "GetConnectionUnixProcessID",
937                                                 NULL,
938                                                 &reply,
939                                                 "s",
940                                                 unique ?: name);
941                                 if (r < 0)
942                                         return r;
943
944                                 r = sd_bus_message_read(reply, "u", &u);
945                                 if (r < 0)
946                                         return r;
947
948                                 pid = u;
949                                 if (mask & SD_BUS_CREDS_PID) {
950                                         c->pid = u;
951                                         c->mask |= SD_BUS_CREDS_PID;
952                                 }
953
954                                 reply = sd_bus_message_unref(reply);
955                         }
956
957                         if (need_uid) {
958                                 uint32_t u;
959
960                                 r = sd_bus_call_method(
961                                                 bus,
962                                                 "org.freedesktop.DBus",
963                                                 "/org/freedesktop/DBus",
964                                                 "org.freedesktop.DBus",
965                                                 "GetConnectionUnixUser",
966                                                 NULL,
967                                                 &reply,
968                                                 "s",
969                                                 unique ? unique : name);
970                                 if (r < 0)
971                                         return r;
972
973                                 r = sd_bus_message_read(reply, "u", &u);
974                                 if (r < 0)
975                                         return r;
976
977                                 c->euid = u;
978                                 c->mask |= SD_BUS_CREDS_EUID;
979
980                                 reply = sd_bus_message_unref(reply);
981                         }
982
983                         if (need_selinux) {
984                                 const void *p = NULL;
985                                 size_t sz = 0;
986
987                                 r = sd_bus_call_method(
988                                                 bus,
989                                                 "org.freedesktop.DBus",
990                                                 "/org/freedesktop/DBus",
991                                                 "org.freedesktop.DBus",
992                                                 "GetConnectionSELinuxSecurityContext",
993                                                 &error,
994                                                 &reply,
995                                                 "s",
996                                                 unique ? unique : name);
997                                 if (r < 0) {
998                                         if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
999                                                 return r;
1000
1001                                         /* no data is fine */
1002                                 } else {
1003                                         r = sd_bus_message_read_array(reply, 'y', &p, &sz);
1004                                         if (r < 0)
1005                                                 return r;
1006
1007                                         c->label = strndup(p, sz);
1008                                         if (!c->label)
1009                                                 return -ENOMEM;
1010
1011                                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1012                                 }
1013                         }
1014                 }
1015
1016                 r = bus_creds_add_more(c, mask, pid, 0);
1017                 if (r < 0)
1018                         return r;
1019         }
1020
1021         if (creds) {
1022                 *creds = c;
1023                 c = NULL;
1024         }
1025
1026         return 0;
1027 }
1028
1029 _public_ int sd_bus_get_name_creds(
1030                 sd_bus *bus,
1031                 const char *name,
1032                 uint64_t mask,
1033                 sd_bus_creds **creds) {
1034
1035         assert_return(bus, -EINVAL);
1036         assert_return(name, -EINVAL);
1037         assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
1038         assert_return(mask == 0 || creds, -EINVAL);
1039         assert_return(!bus_pid_changed(bus), -ECHILD);
1040         assert_return(service_name_is_valid(name), -EINVAL);
1041
1042         if (!bus->bus_client)
1043                 return -EINVAL;
1044
1045         if (streq(name, "org.freedesktop.DBus.Local"))
1046                 return -EINVAL;
1047
1048         if (streq(name, "org.freedesktop.DBus"))
1049                 return sd_bus_get_owner_creds(bus, mask, creds);
1050
1051         if (!BUS_IS_OPEN(bus->state))
1052                 return -ENOTCONN;
1053
1054         if (bus->is_kernel)
1055                 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
1056         else
1057                 return bus_get_name_creds_dbus1(bus, name, mask, creds);
1058 }
1059
1060 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
1061         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
1062         struct kdbus_cmd_info cmd = {
1063                 .size = sizeof(struct kdbus_cmd_info),
1064         };
1065         struct kdbus_info *creator_info;
1066         pid_t pid = 0;
1067         int r;
1068
1069         c = bus_creds_new();
1070         if (!c)
1071                 return -ENOMEM;
1072
1073         /* If augmentation is on, and the bus doesn't didn't allow us
1074          * to get the bits we want, then ask for the PID/TID so that we
1075          * can read the rest from /proc. */
1076         if ((mask & SD_BUS_CREDS_AUGMENT) &&
1077             (mask & (SD_BUS_CREDS_PPID|
1078                      SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
1079                      SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
1080                      SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
1081                      SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
1082                      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|
1083                      SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
1084                      SD_BUS_CREDS_SELINUX_CONTEXT|
1085                      SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
1086                 mask |= SD_BUS_CREDS_PID;
1087
1088         cmd.attach_flags = attach_flags_to_kdbus(mask);
1089
1090         r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
1091         if (r < 0)
1092                 return -errno;
1093
1094         creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
1095
1096         r = bus_populate_creds_from_items(bus, creator_info, mask, c);
1097         bus_kernel_cmd_free(bus, cmd.offset);
1098         if (r < 0)
1099                 return r;
1100
1101         r = bus_creds_add_more(c, mask, pid, 0);
1102         if (r < 0)
1103                 return r;
1104
1105         *ret = c;
1106         c = NULL;
1107         return 0;
1108 }
1109
1110 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
1111         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
1112         pid_t pid = 0;
1113         bool do_label;
1114         int r;
1115
1116         assert(bus);
1117
1118         do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
1119
1120         /* Avoid allocating anything if we have no chance of returning useful data */
1121         if (!bus->ucred_valid && !do_label)
1122                 return -ENODATA;
1123
1124         c = bus_creds_new();
1125         if (!c)
1126                 return -ENOMEM;
1127
1128         if (bus->ucred_valid) {
1129                 if (bus->ucred.pid > 0) {
1130                         pid = c->pid = bus->ucred.pid;
1131                         c->mask |= SD_BUS_CREDS_PID & mask;
1132                 }
1133
1134                 if (bus->ucred.uid != UID_INVALID) {
1135                         c->euid = bus->ucred.uid;
1136                         c->mask |= SD_BUS_CREDS_EUID & mask;
1137                 }
1138
1139                 if (bus->ucred.gid != GID_INVALID) {
1140                         c->egid = bus->ucred.gid;
1141                         c->mask |= SD_BUS_CREDS_EGID & mask;
1142                 }
1143         }
1144
1145         if (do_label) {
1146                 c->label = strdup(bus->label);
1147                 if (!c->label)
1148                         return -ENOMEM;
1149
1150                 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1151         }
1152
1153         r = bus_creds_add_more(c, mask, pid, 0);
1154         if (r < 0)
1155                 return r;
1156
1157         *ret = c;
1158         c = NULL;
1159         return 0;
1160 }
1161
1162 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
1163         assert_return(bus, -EINVAL);
1164         assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
1165         assert_return(ret, -EINVAL);
1166         assert_return(!bus_pid_changed(bus), -ECHILD);
1167
1168         if (!BUS_IS_OPEN(bus->state))
1169                 return -ENOTCONN;
1170
1171         if (bus->is_kernel)
1172                 return bus_get_owner_creds_kdbus(bus, mask, ret);
1173         else
1174                 return bus_get_owner_creds_dbus1(bus, mask, ret);
1175 }
1176
1177 static int add_name_change_match(sd_bus *bus,
1178                                  uint64_t cookie,
1179                                  const char *name,
1180                                  const char *old_owner,
1181                                  const char *new_owner) {
1182
1183         uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
1184         int is_name_id = -1, r;
1185         struct kdbus_item *item;
1186
1187         assert(bus);
1188
1189         /* If we encounter a match that could match against
1190          * NameOwnerChanged messages, then we need to create
1191          * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1192          * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1193          * multiple if the match is underspecified.
1194          *
1195          * The NameOwnerChanged signals take three parameters with
1196          * unique or well-known names, but only some forms actually
1197          * exist:
1198          *
1199          * WELLKNOWN, "", UNIQUE       â†’ KDBUS_ITEM_NAME_ADD
1200          * WELLKNOWN, UNIQUE, ""       â†’ KDBUS_ITEM_NAME_REMOVE
1201          * WELLKNOWN, UNIQUE, UNIQUE   â†’ KDBUS_ITEM_NAME_CHANGE
1202          * UNIQUE, "", UNIQUE          â†’ KDBUS_ITEM_ID_ADD
1203          * UNIQUE, UNIQUE, ""          â†’ KDBUS_ITEM_ID_REMOVE
1204          *
1205          * For the latter two the two unique names must be identical.
1206          *
1207          * */
1208
1209         if (name) {
1210                 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1211                 if (is_name_id < 0)
1212                         return 0;
1213         }
1214
1215         if (!isempty(old_owner)) {
1216                 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1217                 if (r < 0)
1218                         return 0;
1219                 if (r == 0)
1220                         return 0;
1221                 if (is_name_id > 0 && old_owner_id != name_id)
1222                         return 0;
1223         } else
1224                 old_owner_id = KDBUS_MATCH_ID_ANY;
1225
1226         if (!isempty(new_owner)) {
1227                 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1228                 if (r < 0)
1229                         return r;
1230                 if (r == 0)
1231                         return 0;
1232                 if (is_name_id > 0 && new_owner_id != name_id)
1233                         return 0;
1234         } else
1235                 new_owner_id = KDBUS_MATCH_ID_ANY;
1236
1237         if (is_name_id <= 0) {
1238                 struct kdbus_cmd_match *m;
1239                 size_t sz, l;
1240
1241                 /* If the name argument is missing or is a well-known
1242                  * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1243                  * matches for it */
1244
1245                 l = name ? strlen(name) + 1 : 0;
1246
1247                 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1248                             offsetof(struct kdbus_item, name_change) +
1249                             offsetof(struct kdbus_notify_name_change, name) +
1250                             l);
1251
1252                 m = alloca0_align(sz, 8);
1253                 m->size = sz;
1254                 m->cookie = cookie;
1255
1256                 item = m->items;
1257                 item->size =
1258                         offsetof(struct kdbus_item, name_change) +
1259                         offsetof(struct kdbus_notify_name_change, name) +
1260                         l;
1261
1262                 item->name_change.old_id.id = old_owner_id;
1263                 item->name_change.new_id.id = new_owner_id;
1264
1265                 memcpy_safe(item->name_change.name, name, l);
1266
1267                 /* If the old name is unset or empty, then
1268                  * this can match against added names */
1269                 if (isempty(old_owner)) {
1270                         item->type = KDBUS_ITEM_NAME_ADD;
1271
1272                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1273                         if (r < 0)
1274                                 return -errno;
1275                 }
1276
1277                 /* If the new name is unset or empty, then
1278                  * this can match against removed names */
1279                 if (isempty(new_owner)) {
1280                         item->type = KDBUS_ITEM_NAME_REMOVE;
1281
1282                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1283                         if (r < 0)
1284                                 return -errno;
1285                 }
1286
1287                 /* The CHANGE match we need in either case, because
1288                  * what is reported as a name change by the kernel
1289                  * might just be an owner change between starter and
1290                  * normal clients. For userspace such a change should
1291                  * be considered a removal/addition, hence let's
1292                  * subscribe to this unconditionally. */
1293                 item->type = KDBUS_ITEM_NAME_CHANGE;
1294                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1295                 if (r < 0)
1296                         return -errno;
1297         }
1298
1299         if (is_name_id != 0) {
1300                 struct kdbus_cmd_match *m;
1301                 uint64_t sz;
1302
1303                 /* If the name argument is missing or is a unique
1304                  * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1305                  * for it */
1306
1307                 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1308                             offsetof(struct kdbus_item, id_change) +
1309                             sizeof(struct kdbus_notify_id_change));
1310
1311                 m = alloca0_align(sz, 8);
1312                 m->size = sz;
1313                 m->cookie = cookie;
1314
1315                 item = m->items;
1316                 item->size =
1317                         offsetof(struct kdbus_item, id_change) +
1318                         sizeof(struct kdbus_notify_id_change);
1319                 item->id_change.id = name_id;
1320
1321                 /* If the old name is unset or empty, then this can
1322                  * match against added ids */
1323                 if (isempty(old_owner)) {
1324                         item->type = KDBUS_ITEM_ID_ADD;
1325                         if (!isempty(new_owner))
1326                                 item->id_change.id = new_owner_id;
1327
1328                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1329                         if (r < 0)
1330                                 return -errno;
1331                 }
1332
1333                 /* If thew new name is unset or empty, then this can
1334                  * match against removed ids */
1335                 if (isempty(new_owner)) {
1336                         item->type = KDBUS_ITEM_ID_REMOVE;
1337                         if (!isempty(old_owner))
1338                                 item->id_change.id = old_owner_id;
1339
1340                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1341                         if (r < 0)
1342                                 return -errno;
1343                 }
1344         }
1345
1346         return 0;
1347 }
1348
1349 int bus_add_match_internal_kernel(
1350                 sd_bus *bus,
1351                 struct bus_match_component *components,
1352                 unsigned n_components,
1353                 uint64_t cookie) {
1354
1355         struct kdbus_cmd_match *m;
1356         struct kdbus_item *item;
1357         uint64_t *bloom;
1358         size_t sz;
1359         const char *sender = NULL;
1360         size_t sender_length = 0;
1361         uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY;
1362         bool using_bloom = false;
1363         unsigned i;
1364         bool matches_name_change = true;
1365         const char *name_change_arg[3] = {};
1366         int r;
1367
1368         assert(bus);
1369
1370         /* Monitor streams don't support matches, make this a NOP */
1371         if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1372                 return 0;
1373
1374         bloom = alloca0(bus->bloom_size);
1375
1376         sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1377
1378         for (i = 0; i < n_components; i++) {
1379                 struct bus_match_component *c = &components[i];
1380
1381                 switch (c->type) {
1382
1383                 case BUS_MATCH_SENDER:
1384                         if (!streq(c->value_str, "org.freedesktop.DBus"))
1385                                 matches_name_change = false;
1386
1387                         r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1388                         if (r < 0)
1389                                 return r;
1390                         else if (r > 0)
1391                                 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1392                         else  {
1393                                 sender = c->value_str;
1394                                 sender_length = strlen(sender);
1395                                 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1396                         }
1397
1398                         break;
1399
1400                 case BUS_MATCH_MESSAGE_TYPE:
1401                         if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1402                                 matches_name_change = false;
1403
1404                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1405                         using_bloom = true;
1406                         break;
1407
1408                 case BUS_MATCH_INTERFACE:
1409                         if (!streq(c->value_str, "org.freedesktop.DBus"))
1410                                 matches_name_change = false;
1411
1412                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1413                         using_bloom = true;
1414                         break;
1415
1416                 case BUS_MATCH_MEMBER:
1417                         if (!streq(c->value_str, "NameOwnerChanged"))
1418                                 matches_name_change = false;
1419
1420                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1421                         using_bloom = true;
1422                         break;
1423
1424                 case BUS_MATCH_PATH:
1425                         if (!streq(c->value_str, "/org/freedesktop/DBus"))
1426                                 matches_name_change = false;
1427
1428                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1429                         using_bloom = true;
1430                         break;
1431
1432                 case BUS_MATCH_PATH_NAMESPACE:
1433                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1434                         using_bloom = true;
1435                         break;
1436
1437                 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1438                         char buf[sizeof("arg")-1 + 2 + 1];
1439
1440                         if (c->type - BUS_MATCH_ARG < 3)
1441                                 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1442
1443                         xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
1444                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1445                         using_bloom = true;
1446                         break;
1447                 }
1448
1449                 case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: {
1450                         char buf[sizeof("arg")-1 + 2 + sizeof("-has")];
1451
1452                         xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS);
1453                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1454                         using_bloom = true;
1455                         break;
1456                 }
1457
1458                 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST:
1459                         /*
1460                          * XXX: DBus spec defines arg[0..63]path= matching to be
1461                          * a two-way glob. That is, if either string is a prefix
1462                          * of the other, it matches.
1463                          * This is really hard to realize in bloom-filters, as
1464                          * we would have to create a bloom-match for each prefix
1465                          * of @c->value_str. This is excessive, hence we just
1466                          * ignore all those matches and accept everything from
1467                          * the kernel. People should really avoid those matches.
1468                          * If they're used in real-life some day, we will have
1469                          * to properly support multiple-matches here.
1470                          */
1471                         break;
1472
1473                 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1474                         char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1475
1476                         xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1477                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1478                         using_bloom = true;
1479                         break;
1480                 }
1481
1482                 case BUS_MATCH_DESTINATION:
1483                         /*
1484                          * Kernel only supports matching on destination IDs, but
1485                          * not on destination names. So just skip the
1486                          * destination name restriction and verify it in
1487                          * user-space on retrieval.
1488                          */
1489                         r = bus_kernel_parse_unique_name(c->value_str, &dst_id);
1490                         if (r < 0)
1491                                 return r;
1492                         else if (r > 0)
1493                                 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1494
1495                         /* if not a broadcast, it cannot be a name-change */
1496                         if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST)
1497                                 matches_name_change = false;
1498
1499                         break;
1500
1501                 case BUS_MATCH_ROOT:
1502                 case BUS_MATCH_VALUE:
1503                 case BUS_MATCH_LEAF:
1504                 case _BUS_MATCH_NODE_TYPE_MAX:
1505                 case _BUS_MATCH_NODE_TYPE_INVALID:
1506                         assert_not_reached("Invalid match type?");
1507                 }
1508         }
1509
1510         if (using_bloom)
1511                 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1512
1513         m = alloca0_align(sz, 8);
1514         m->size = sz;
1515         m->cookie = cookie;
1516
1517         item = m->items;
1518
1519         if (src_id != KDBUS_MATCH_ID_ANY) {
1520                 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1521                 item->type = KDBUS_ITEM_ID;
1522                 item->id = src_id;
1523                 item = KDBUS_ITEM_NEXT(item);
1524         }
1525
1526         if (dst_id != KDBUS_MATCH_ID_ANY) {
1527                 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1528                 item->type = KDBUS_ITEM_DST_ID;
1529                 item->id = dst_id;
1530                 item = KDBUS_ITEM_NEXT(item);
1531         }
1532
1533         if (using_bloom) {
1534                 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1535                 item->type = KDBUS_ITEM_BLOOM_MASK;
1536                 memcpy(item->data64, bloom, bus->bloom_size);
1537                 item = KDBUS_ITEM_NEXT(item);
1538         }
1539
1540         if (sender) {
1541                 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1542                 item->type = KDBUS_ITEM_NAME;
1543                 memcpy(item->str, sender, sender_length + 1);
1544         }
1545
1546         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1547         if (r < 0)
1548                 return -errno;
1549
1550         if (matches_name_change) {
1551
1552                 /* If this match could theoretically match
1553                  * NameOwnerChanged messages, we need to
1554                  * install a second non-bloom filter explitly
1555                  * for it */
1556
1557                 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1558                 if (r < 0)
1559                         return r;
1560         }
1561
1562         return 0;
1563 }
1564
1565 #define internal_match(bus, m)                                          \
1566         ((bus)->hello_flags & KDBUS_HELLO_MONITOR                       \
1567          ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
1568          : (m))
1569
1570 static int bus_add_match_internal_dbus1(
1571                 sd_bus *bus,
1572                 const char *match) {
1573
1574         const char *e;
1575
1576         assert(bus);
1577         assert(match);
1578
1579         e = internal_match(bus, match);
1580
1581         return sd_bus_call_method(
1582                         bus,
1583                         "org.freedesktop.DBus",
1584                         "/org/freedesktop/DBus",
1585                         "org.freedesktop.DBus",
1586                         "AddMatch",
1587                         NULL,
1588                         NULL,
1589                         "s",
1590                         e);
1591 }
1592
1593 int bus_add_match_internal(
1594                 sd_bus *bus,
1595                 const char *match,
1596                 struct bus_match_component *components,
1597                 unsigned n_components,
1598                 uint64_t cookie) {
1599
1600         assert(bus);
1601
1602         if (!bus->bus_client)
1603                 return -EINVAL;
1604
1605         if (bus->is_kernel)
1606                 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1607         else
1608                 return bus_add_match_internal_dbus1(bus, match);
1609 }
1610
1611 int bus_remove_match_internal_kernel(
1612                 sd_bus *bus,
1613                 uint64_t cookie) {
1614
1615         struct kdbus_cmd_match m = {
1616                 .size = offsetof(struct kdbus_cmd_match, items),
1617                 .cookie = cookie,
1618         };
1619         int r;
1620
1621         assert(bus);
1622
1623         /* Monitor streams don't support matches, make this a NOP */
1624         if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1625                 return 0;
1626
1627         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1628         if (r < 0)
1629                 return -errno;
1630
1631         return 0;
1632 }
1633
1634 static int bus_remove_match_internal_dbus1(
1635                 sd_bus *bus,
1636                 const char *match) {
1637
1638         const char *e;
1639
1640         assert(bus);
1641         assert(match);
1642
1643         e = internal_match(bus, match);
1644
1645         return sd_bus_call_method(
1646                         bus,
1647                         "org.freedesktop.DBus",
1648                         "/org/freedesktop/DBus",
1649                         "org.freedesktop.DBus",
1650                         "RemoveMatch",
1651                         NULL,
1652                         NULL,
1653                         "s",
1654                         e);
1655 }
1656
1657 int bus_remove_match_internal(
1658                 sd_bus *bus,
1659                 const char *match,
1660                 uint64_t cookie) {
1661
1662         assert(bus);
1663
1664         if (!bus->bus_client)
1665                 return -EINVAL;
1666
1667         if (bus->is_kernel)
1668                 return bus_remove_match_internal_kernel(bus, cookie);
1669         else
1670                 return bus_remove_match_internal_dbus1(bus, match);
1671 }
1672
1673 #if 0 /// UNNEEDED by elogind
1674 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1675         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
1676         const char *mid;
1677         int r;
1678
1679         assert_return(bus, -EINVAL);
1680         assert_return(name, -EINVAL);
1681         assert_return(machine, -EINVAL);
1682         assert_return(!bus_pid_changed(bus), -ECHILD);
1683         assert_return(service_name_is_valid(name), -EINVAL);
1684
1685         if (!bus->bus_client)
1686                 return -EINVAL;
1687
1688         if (!BUS_IS_OPEN(bus->state))
1689                 return -ENOTCONN;
1690
1691         if (streq_ptr(name, bus->unique_name))
1692                 return sd_id128_get_machine(machine);
1693
1694         r = sd_bus_message_new_method_call(
1695                         bus,
1696                         &m,
1697                         name,
1698                         "/",
1699                         "org.freedesktop.DBus.Peer",
1700                         "GetMachineId");
1701         if (r < 0)
1702                 return r;
1703
1704         r = sd_bus_message_set_auto_start(m, false);
1705         if (r < 0)
1706                 return r;
1707
1708         r = sd_bus_call(bus, m, 0, NULL, &reply);
1709         if (r < 0)
1710                 return r;
1711
1712         r = sd_bus_message_read(reply, "s", &mid);
1713         if (r < 0)
1714                 return r;
1715
1716         return sd_id128_from_string(mid, machine);
1717 }
1718 #endif // 0