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