chiark / gitweb /
sd-bus: when credentials of the "org.freedesktop.DBus" service are queried return...
[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                 c = bus_creds_new();
790                 if (!c)
791                         return -ENOMEM;
792
793                 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
794                         c->unique_name = strdup(unique);
795                         if (!c->unique_name)
796                                 return -ENOMEM;
797
798                         c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
799                 }
800
801                 if ((mask & SD_BUS_CREDS_PID) ||
802                     ((mask & SD_BUS_CREDS_AUGMENT) &&
803                      (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
804                               SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
805                               SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
806                               SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
807                               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|
808                               SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
809                               SD_BUS_CREDS_SELINUX_CONTEXT|
810                               SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
811
812                         uint32_t u;
813
814                         r = sd_bus_call_method(
815                                         bus,
816                                         "org.freedesktop.DBus",
817                                         "/org/freedesktop/DBus",
818                                         "org.freedesktop.DBus",
819                                         "GetConnectionUnixProcessID",
820                                         NULL,
821                                         &reply,
822                                         "s",
823                                         unique ? unique : name);
824                         if (r < 0)
825                                 return r;
826
827                         r = sd_bus_message_read(reply, "u", &u);
828                         if (r < 0)
829                                 return r;
830
831                         pid = u;
832                         if (mask & SD_BUS_CREDS_PID) {
833                                 c->pid = u;
834                                 c->mask |= SD_BUS_CREDS_PID;
835                         }
836
837                         reply = sd_bus_message_unref(reply);
838                 }
839
840                 if (mask & SD_BUS_CREDS_EUID) {
841                         uint32_t u;
842
843                         r = sd_bus_call_method(
844                                         bus,
845                                         "org.freedesktop.DBus",
846                                         "/org/freedesktop/DBus",
847                                         "org.freedesktop.DBus",
848                                         "GetConnectionUnixUser",
849                                         NULL,
850                                         &reply,
851                                         "s",
852                                         unique ? unique : name);
853                         if (r < 0)
854                                 return r;
855
856                         r = sd_bus_message_read(reply, "u", &u);
857                         if (r < 0)
858                                 return r;
859
860                         c->euid = u;
861                         c->mask |= SD_BUS_CREDS_EUID;
862
863                         reply = sd_bus_message_unref(reply);
864                 }
865
866                 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
867                         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
868                         const void *p = NULL;
869                         size_t sz = 0;
870
871                         r = sd_bus_call_method(
872                                         bus,
873                                         "org.freedesktop.DBus",
874                                         "/org/freedesktop/DBus",
875                                         "org.freedesktop.DBus",
876                                         "GetConnectionSELinuxSecurityContext",
877                                         &error,
878                                         &reply,
879                                         "s",
880                                         unique ? unique : name);
881                         if (r < 0) {
882                                 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
883                                         return r;
884                         } else {
885                                 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
886                                 if (r < 0)
887                                         return r;
888
889                                 c->label = strndup(p, sz);
890                                 if (!c->label)
891                                         return -ENOMEM;
892
893                                 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
894                         }
895                 }
896
897                 r = bus_creds_add_more(c, mask, pid, 0);
898                 if (r < 0)
899                         return r;
900         }
901
902         if (creds) {
903                 *creds = c;
904                 c = NULL;
905         }
906
907         return 0;
908 }
909
910 _public_ int sd_bus_get_name_creds(
911                 sd_bus *bus,
912                 const char *name,
913                 uint64_t mask,
914                 sd_bus_creds **creds) {
915
916         assert_return(bus, -EINVAL);
917         assert_return(name, -EINVAL);
918         assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
919         assert_return(mask == 0 || creds, -EINVAL);
920         assert_return(!bus_pid_changed(bus), -ECHILD);
921         assert_return(service_name_is_valid(name), -EINVAL);
922
923         if (!bus->bus_client)
924                 return -EINVAL;
925
926         if (streq(name, "org.freedesktop.DBus.Local"))
927                 return -EINVAL;
928
929         if (streq(name, "org.freedesktop.DBus"))
930                 return sd_bus_get_owner_creds(bus, mask, creds);
931
932         if (!BUS_IS_OPEN(bus->state))
933                 return -ENOTCONN;
934
935         if (bus->is_kernel)
936                 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
937         else
938                 return bus_get_name_creds_dbus1(bus, name, mask, creds);
939 }
940
941 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
942         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
943         struct kdbus_cmd_info cmd = {
944                 .size = sizeof(struct kdbus_cmd_info),
945         };
946         struct kdbus_info *creator_info;
947         pid_t pid = 0;
948         int r;
949
950         c = bus_creds_new();
951         if (!c)
952                 return -ENOMEM;
953
954         /* If augmentation is on, and the bus doesn't didn't allow us
955          * to get the bits we want, then ask for the PID/TID so that we
956          * can read the rest from /proc. */
957         if ((mask & SD_BUS_CREDS_AUGMENT) &&
958             (mask & (SD_BUS_CREDS_PPID|
959                      SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
960                      SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
961                      SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
962                      SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
963                      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|
964                      SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
965                      SD_BUS_CREDS_SELINUX_CONTEXT|
966                      SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
967                 mask |= SD_BUS_CREDS_PID;
968
969         cmd.attach_flags = attach_flags_to_kdbus(mask);
970
971         r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
972         if (r < 0)
973                 return -errno;
974
975         creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
976
977         r = bus_populate_creds_from_items(bus, creator_info, mask, c);
978         bus_kernel_cmd_free(bus, cmd.offset);
979         if (r < 0)
980                 return r;
981
982         r = bus_creds_add_more(c, mask, pid, 0);
983         if (r < 0)
984                 return r;
985
986         *ret = c;
987         c = NULL;
988         return 0;
989 }
990
991 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
992         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
993         pid_t pid = 0;
994         bool do_label;
995         int r;
996
997         assert(bus);
998
999         do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
1000
1001         /* Avoid allocating anything if we have no chance of returning useful data */
1002         if (!bus->ucred_valid && !do_label)
1003                 return -ENODATA;
1004
1005         c = bus_creds_new();
1006         if (!c)
1007                 return -ENOMEM;
1008
1009         if (bus->ucred_valid) {
1010                 if (bus->ucred.pid > 0) {
1011                         pid = c->pid = bus->ucred.pid;
1012                         c->mask |= SD_BUS_CREDS_PID & mask;
1013                 }
1014
1015                 if (bus->ucred.uid != UID_INVALID) {
1016                         c->euid = bus->ucred.uid;
1017                         c->mask |= SD_BUS_CREDS_EUID & mask;
1018                 }
1019
1020                 if (bus->ucred.gid != GID_INVALID) {
1021                         c->egid = bus->ucred.gid;
1022                         c->mask |= SD_BUS_CREDS_EGID & mask;
1023                 }
1024         }
1025
1026         if (do_label) {
1027                 c->label = strdup(bus->label);
1028                 if (!c->label)
1029                         return -ENOMEM;
1030
1031                 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1032         }
1033
1034         r = bus_creds_add_more(c, mask, pid, 0);
1035         if (r < 0)
1036                 return r;
1037
1038         *ret = c;
1039         c = NULL;
1040         return 0;
1041 }
1042
1043 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
1044         assert_return(bus, -EINVAL);
1045         assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
1046         assert_return(ret, -EINVAL);
1047         assert_return(!bus_pid_changed(bus), -ECHILD);
1048
1049         if (!BUS_IS_OPEN(bus->state))
1050                 return -ENOTCONN;
1051
1052         if (bus->is_kernel)
1053                 return bus_get_owner_creds_kdbus(bus, mask, ret);
1054         else
1055                 return bus_get_owner_creds_dbus1(bus, mask, ret);
1056 }
1057
1058 static int add_name_change_match(sd_bus *bus,
1059                                  uint64_t cookie,
1060                                  const char *name,
1061                                  const char *old_owner,
1062                                  const char *new_owner) {
1063
1064         uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
1065         int is_name_id = -1, r;
1066         struct kdbus_item *item;
1067
1068         assert(bus);
1069
1070         /* If we encounter a match that could match against
1071          * NameOwnerChanged messages, then we need to create
1072          * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1073          * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1074          * multiple if the match is underspecified.
1075          *
1076          * The NameOwnerChanged signals take three parameters with
1077          * unique or well-known names, but only some forms actually
1078          * exist:
1079          *
1080          * WELLKNOWN, "", UNIQUE       â†’ KDBUS_ITEM_NAME_ADD
1081          * WELLKNOWN, UNIQUE, ""       â†’ KDBUS_ITEM_NAME_REMOVE
1082          * WELLKNOWN, UNIQUE, UNIQUE   â†’ KDBUS_ITEM_NAME_CHANGE
1083          * UNIQUE, "", UNIQUE          â†’ KDBUS_ITEM_ID_ADD
1084          * UNIQUE, UNIQUE, ""          â†’ KDBUS_ITEM_ID_REMOVE
1085          *
1086          * For the latter two the two unique names must be identical.
1087          *
1088          * */
1089
1090         if (name) {
1091                 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1092                 if (is_name_id < 0)
1093                         return 0;
1094         }
1095
1096         if (!isempty(old_owner)) {
1097                 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1098                 if (r < 0)
1099                         return 0;
1100                 if (r == 0)
1101                         return 0;
1102                 if (is_name_id > 0 && old_owner_id != name_id)
1103                         return 0;
1104         } else
1105                 old_owner_id = KDBUS_MATCH_ID_ANY;
1106
1107         if (!isempty(new_owner)) {
1108                 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1109                 if (r < 0)
1110                         return r;
1111                 if (r == 0)
1112                         return 0;
1113                 if (is_name_id > 0 && new_owner_id != name_id)
1114                         return 0;
1115         } else
1116                 new_owner_id = KDBUS_MATCH_ID_ANY;
1117
1118         if (is_name_id <= 0) {
1119                 struct kdbus_cmd_match *m;
1120                 size_t sz, l;
1121
1122                 /* If the name argument is missing or is a well-known
1123                  * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1124                  * matches for it */
1125
1126                 l = name ? strlen(name) + 1 : 0;
1127
1128                 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1129                             offsetof(struct kdbus_item, name_change) +
1130                             offsetof(struct kdbus_notify_name_change, name) +
1131                             l);
1132
1133                 m = alloca0_align(sz, 8);
1134                 m->size = sz;
1135                 m->cookie = cookie;
1136
1137                 item = m->items;
1138                 item->size =
1139                         offsetof(struct kdbus_item, name_change) +
1140                         offsetof(struct kdbus_notify_name_change, name) +
1141                         l;
1142
1143                 item->name_change.old_id.id = old_owner_id;
1144                 item->name_change.new_id.id = new_owner_id;
1145
1146                 memcpy_safe(item->name_change.name, name, l);
1147
1148                 /* If the old name is unset or empty, then
1149                  * this can match against added names */
1150                 if (isempty(old_owner)) {
1151                         item->type = KDBUS_ITEM_NAME_ADD;
1152
1153                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1154                         if (r < 0)
1155                                 return -errno;
1156                 }
1157
1158                 /* If the new name is unset or empty, then
1159                  * this can match against removed names */
1160                 if (isempty(new_owner)) {
1161                         item->type = KDBUS_ITEM_NAME_REMOVE;
1162
1163                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1164                         if (r < 0)
1165                                 return -errno;
1166                 }
1167
1168                 /* The CHANGE match we need in either case, because
1169                  * what is reported as a name change by the kernel
1170                  * might just be an owner change between starter and
1171                  * normal clients. For userspace such a change should
1172                  * be considered a removal/addition, hence let's
1173                  * subscribe to this unconditionally. */
1174                 item->type = KDBUS_ITEM_NAME_CHANGE;
1175                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1176                 if (r < 0)
1177                         return -errno;
1178         }
1179
1180         if (is_name_id != 0) {
1181                 struct kdbus_cmd_match *m;
1182                 uint64_t sz;
1183
1184                 /* If the name argument is missing or is a unique
1185                  * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1186                  * for it */
1187
1188                 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1189                             offsetof(struct kdbus_item, id_change) +
1190                             sizeof(struct kdbus_notify_id_change));
1191
1192                 m = alloca0_align(sz, 8);
1193                 m->size = sz;
1194                 m->cookie = cookie;
1195
1196                 item = m->items;
1197                 item->size =
1198                         offsetof(struct kdbus_item, id_change) +
1199                         sizeof(struct kdbus_notify_id_change);
1200                 item->id_change.id = name_id;
1201
1202                 /* If the old name is unset or empty, then this can
1203                  * match against added ids */
1204                 if (isempty(old_owner)) {
1205                         item->type = KDBUS_ITEM_ID_ADD;
1206                         if (!isempty(new_owner))
1207                                 item->id_change.id = new_owner_id;
1208
1209                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1210                         if (r < 0)
1211                                 return -errno;
1212                 }
1213
1214                 /* If thew new name is unset or empty, then this can
1215                  * match against removed ids */
1216                 if (isempty(new_owner)) {
1217                         item->type = KDBUS_ITEM_ID_REMOVE;
1218                         if (!isempty(old_owner))
1219                                 item->id_change.id = old_owner_id;
1220
1221                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1222                         if (r < 0)
1223                                 return -errno;
1224                 }
1225         }
1226
1227         return 0;
1228 }
1229
1230 int bus_add_match_internal_kernel(
1231                 sd_bus *bus,
1232                 struct bus_match_component *components,
1233                 unsigned n_components,
1234                 uint64_t cookie) {
1235
1236         struct kdbus_cmd_match *m;
1237         struct kdbus_item *item;
1238         uint64_t *bloom;
1239         size_t sz;
1240         const char *sender = NULL;
1241         size_t sender_length = 0;
1242         uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY;
1243         bool using_bloom = false;
1244         unsigned i;
1245         bool matches_name_change = true;
1246         const char *name_change_arg[3] = {};
1247         int r;
1248
1249         assert(bus);
1250
1251         /* Monitor streams don't support matches, make this a NOP */
1252         if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1253                 return 0;
1254
1255         bloom = alloca0(bus->bloom_size);
1256
1257         sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1258
1259         for (i = 0; i < n_components; i++) {
1260                 struct bus_match_component *c = &components[i];
1261
1262                 switch (c->type) {
1263
1264                 case BUS_MATCH_SENDER:
1265                         if (!streq(c->value_str, "org.freedesktop.DBus"))
1266                                 matches_name_change = false;
1267
1268                         r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1269                         if (r < 0)
1270                                 return r;
1271                         else if (r > 0)
1272                                 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1273                         else  {
1274                                 sender = c->value_str;
1275                                 sender_length = strlen(sender);
1276                                 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1277                         }
1278
1279                         break;
1280
1281                 case BUS_MATCH_MESSAGE_TYPE:
1282                         if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1283                                 matches_name_change = false;
1284
1285                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1286                         using_bloom = true;
1287                         break;
1288
1289                 case BUS_MATCH_INTERFACE:
1290                         if (!streq(c->value_str, "org.freedesktop.DBus"))
1291                                 matches_name_change = false;
1292
1293                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1294                         using_bloom = true;
1295                         break;
1296
1297                 case BUS_MATCH_MEMBER:
1298                         if (!streq(c->value_str, "NameOwnerChanged"))
1299                                 matches_name_change = false;
1300
1301                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1302                         using_bloom = true;
1303                         break;
1304
1305                 case BUS_MATCH_PATH:
1306                         if (!streq(c->value_str, "/org/freedesktop/DBus"))
1307                                 matches_name_change = false;
1308
1309                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1310                         using_bloom = true;
1311                         break;
1312
1313                 case BUS_MATCH_PATH_NAMESPACE:
1314                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1315                         using_bloom = true;
1316                         break;
1317
1318                 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1319                         char buf[sizeof("arg")-1 + 2 + 1];
1320
1321                         if (c->type - BUS_MATCH_ARG < 3)
1322                                 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1323
1324                         xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
1325                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1326                         using_bloom = true;
1327                         break;
1328                 }
1329
1330                 case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: {
1331                         char buf[sizeof("arg")-1 + 2 + sizeof("-has")];
1332
1333                         xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS);
1334                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1335                         using_bloom = true;
1336                         break;
1337                 }
1338
1339                 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST:
1340                         /*
1341                          * XXX: DBus spec defines arg[0..63]path= matching to be
1342                          * a two-way glob. That is, if either string is a prefix
1343                          * of the other, it matches.
1344                          * This is really hard to realize in bloom-filters, as
1345                          * we would have to create a bloom-match for each prefix
1346                          * of @c->value_str. This is excessive, hence we just
1347                          * ignore all those matches and accept everything from
1348                          * the kernel. People should really avoid those matches.
1349                          * If they're used in real-life some day, we will have
1350                          * to properly support multiple-matches here.
1351                          */
1352                         break;
1353
1354                 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1355                         char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1356
1357                         xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1358                         bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1359                         using_bloom = true;
1360                         break;
1361                 }
1362
1363                 case BUS_MATCH_DESTINATION:
1364                         /*
1365                          * Kernel only supports matching on destination IDs, but
1366                          * not on destination names. So just skip the
1367                          * destination name restriction and verify it in
1368                          * user-space on retrieval.
1369                          */
1370                         r = bus_kernel_parse_unique_name(c->value_str, &dst_id);
1371                         if (r < 0)
1372                                 return r;
1373                         else if (r > 0)
1374                                 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1375
1376                         /* if not a broadcast, it cannot be a name-change */
1377                         if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST)
1378                                 matches_name_change = false;
1379
1380                         break;
1381
1382                 case BUS_MATCH_ROOT:
1383                 case BUS_MATCH_VALUE:
1384                 case BUS_MATCH_LEAF:
1385                 case _BUS_MATCH_NODE_TYPE_MAX:
1386                 case _BUS_MATCH_NODE_TYPE_INVALID:
1387                         assert_not_reached("Invalid match type?");
1388                 }
1389         }
1390
1391         if (using_bloom)
1392                 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1393
1394         m = alloca0_align(sz, 8);
1395         m->size = sz;
1396         m->cookie = cookie;
1397
1398         item = m->items;
1399
1400         if (src_id != KDBUS_MATCH_ID_ANY) {
1401                 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1402                 item->type = KDBUS_ITEM_ID;
1403                 item->id = src_id;
1404                 item = KDBUS_ITEM_NEXT(item);
1405         }
1406
1407         if (dst_id != KDBUS_MATCH_ID_ANY) {
1408                 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1409                 item->type = KDBUS_ITEM_DST_ID;
1410                 item->id = dst_id;
1411                 item = KDBUS_ITEM_NEXT(item);
1412         }
1413
1414         if (using_bloom) {
1415                 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1416                 item->type = KDBUS_ITEM_BLOOM_MASK;
1417                 memcpy(item->data64, bloom, bus->bloom_size);
1418                 item = KDBUS_ITEM_NEXT(item);
1419         }
1420
1421         if (sender) {
1422                 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1423                 item->type = KDBUS_ITEM_NAME;
1424                 memcpy(item->str, sender, sender_length + 1);
1425         }
1426
1427         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1428         if (r < 0)
1429                 return -errno;
1430
1431         if (matches_name_change) {
1432
1433                 /* If this match could theoretically match
1434                  * NameOwnerChanged messages, we need to
1435                  * install a second non-bloom filter explitly
1436                  * for it */
1437
1438                 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1439                 if (r < 0)
1440                         return r;
1441         }
1442
1443         return 0;
1444 }
1445
1446 #define internal_match(bus, m)                                          \
1447         ((bus)->hello_flags & KDBUS_HELLO_MONITOR                       \
1448          ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
1449          : (m))
1450
1451 static int bus_add_match_internal_dbus1(
1452                 sd_bus *bus,
1453                 const char *match) {
1454
1455         const char *e;
1456
1457         assert(bus);
1458         assert(match);
1459
1460         e = internal_match(bus, match);
1461
1462         return sd_bus_call_method(
1463                         bus,
1464                         "org.freedesktop.DBus",
1465                         "/org/freedesktop/DBus",
1466                         "org.freedesktop.DBus",
1467                         "AddMatch",
1468                         NULL,
1469                         NULL,
1470                         "s",
1471                         e);
1472 }
1473
1474 int bus_add_match_internal(
1475                 sd_bus *bus,
1476                 const char *match,
1477                 struct bus_match_component *components,
1478                 unsigned n_components,
1479                 uint64_t cookie) {
1480
1481         assert(bus);
1482
1483         if (!bus->bus_client)
1484                 return -EINVAL;
1485
1486         if (bus->is_kernel)
1487                 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1488         else
1489                 return bus_add_match_internal_dbus1(bus, match);
1490 }
1491
1492 int bus_remove_match_internal_kernel(
1493                 sd_bus *bus,
1494                 uint64_t cookie) {
1495
1496         struct kdbus_cmd_match m = {
1497                 .size = offsetof(struct kdbus_cmd_match, items),
1498                 .cookie = cookie,
1499         };
1500         int r;
1501
1502         assert(bus);
1503
1504         /* Monitor streams don't support matches, make this a NOP */
1505         if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1506                 return 0;
1507
1508         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1509         if (r < 0)
1510                 return -errno;
1511
1512         return 0;
1513 }
1514
1515 static int bus_remove_match_internal_dbus1(
1516                 sd_bus *bus,
1517                 const char *match) {
1518
1519         const char *e;
1520
1521         assert(bus);
1522         assert(match);
1523
1524         e = internal_match(bus, match);
1525
1526         return sd_bus_call_method(
1527                         bus,
1528                         "org.freedesktop.DBus",
1529                         "/org/freedesktop/DBus",
1530                         "org.freedesktop.DBus",
1531                         "RemoveMatch",
1532                         NULL,
1533                         NULL,
1534                         "s",
1535                         e);
1536 }
1537
1538 int bus_remove_match_internal(
1539                 sd_bus *bus,
1540                 const char *match,
1541                 uint64_t cookie) {
1542
1543         assert(bus);
1544
1545         if (!bus->bus_client)
1546                 return -EINVAL;
1547
1548         if (bus->is_kernel)
1549                 return bus_remove_match_internal_kernel(bus, cookie);
1550         else
1551                 return bus_remove_match_internal_dbus1(bus, match);
1552 }
1553
1554 #if 0 /// UNNEEDED by elogind
1555 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1556         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
1557         const char *mid;
1558         int r;
1559
1560         assert_return(bus, -EINVAL);
1561         assert_return(name, -EINVAL);
1562         assert_return(machine, -EINVAL);
1563         assert_return(!bus_pid_changed(bus), -ECHILD);
1564         assert_return(service_name_is_valid(name), -EINVAL);
1565
1566         if (!bus->bus_client)
1567                 return -EINVAL;
1568
1569         if (!BUS_IS_OPEN(bus->state))
1570                 return -ENOTCONN;
1571
1572         if (streq_ptr(name, bus->unique_name))
1573                 return sd_id128_get_machine(machine);
1574
1575         r = sd_bus_message_new_method_call(
1576                         bus,
1577                         &m,
1578                         name,
1579                         "/",
1580                         "org.freedesktop.DBus.Peer",
1581                         "GetMachineId");
1582         if (r < 0)
1583                 return r;
1584
1585         r = sd_bus_message_set_auto_start(m, false);
1586         if (r < 0)
1587                 return r;
1588
1589         r = sd_bus_call(bus, m, 0, NULL, &reply);
1590         if (r < 0)
1591                 return r;
1592
1593         r = sd_bus_message_read(reply, "s", &mid);
1594         if (r < 0)
1595                 return r;
1596
1597         return sd_id128_from_string(mid, machine);
1598 }
1599 #endif // 0