chiark / gitweb /
a38ce0cb600b40f8f64360b0c083deb7e594c68a
[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                         "/org/freedesktop/DBus",
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                         "/org/freedesktop/DBus",
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                                 "/org/freedesktop/DBus",
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                                 "/org/freedesktop/DBus",
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                                 "/org/freedesktop/DBus",
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                                         "/org/freedesktop/DBus",
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                                         "/org/freedesktop/DBus",
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                                         "/org/freedesktop/DBus",
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                         memcpy(item->name_change.name, name, l);
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 =
858                         offsetof(struct kdbus_item, id_change) +
859                         sizeof(struct kdbus_notify_id_change);
860                 item->id_change.id = name_id;
861
862                 /* If the old name is unset or empty, then this can
863                  * match against added ids */
864                 if (!old_owner || old_owner[0] == 0) {
865                         item->type = KDBUS_ITEM_ID_ADD;
866
867                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
868                         if (r < 0)
869                                 return -errno;
870                 }
871
872                 /* If thew new name is unset or empty, then this can
873                  * match against removed ids */
874                 if (!new_owner || new_owner[0] == 0) {
875                         item->type = KDBUS_ITEM_ID_REMOVE;
876
877                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
878                         if (r < 0)
879                                 return -errno;
880                 }
881         }
882
883         return 0;
884 }
885
886 int bus_add_match_internal_kernel(
887                 sd_bus *bus,
888                 uint64_t id,
889                 struct bus_match_component *components,
890                 unsigned n_components,
891                 uint64_t cookie) {
892
893         struct kdbus_cmd_match *m;
894         struct kdbus_item *item;
895         uint64_t bloom[BLOOM_SIZE/8];
896         size_t sz;
897         const char *sender = NULL;
898         size_t sender_length = 0;
899         uint64_t src_id = KDBUS_MATCH_ID_ANY;
900         bool using_bloom = false;
901         unsigned i;
902         bool matches_name_change = true;
903         const char *name_change_arg[3] = {};
904         int r;
905
906         assert(bus);
907
908         zero(bloom);
909
910         sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
911                     offsetof(struct kdbus_item, id) + sizeof(uint64_t));
912
913         for (i = 0; i < n_components; i++) {
914                 struct bus_match_component *c = &components[i];
915
916                 switch (c->type) {
917
918                 case BUS_MATCH_SENDER:
919                         if (!streq(c->value_str, "org.freedesktop.DBus"))
920                                 matches_name_change = false;
921
922                         r = bus_kernel_parse_unique_name(c->value_str, &src_id);
923                         if (r < 0)
924                                 return r;
925
926                         if (r > 0) {
927                                 sender = c->value_str;
928                                 sender_length = strlen(sender);
929                                 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
930                         }
931
932                         break;
933
934                 case BUS_MATCH_MESSAGE_TYPE:
935                         if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
936                                 matches_name_change = false;
937
938                         bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
939                         using_bloom = true;
940                         break;
941
942                 case BUS_MATCH_INTERFACE:
943                         if (!streq(c->value_str, "org.freedesktop.DBus"))
944                                 matches_name_change = false;
945
946                         bloom_add_pair(bloom, "interface", c->value_str);
947                         using_bloom = true;
948                         break;
949
950                 case BUS_MATCH_MEMBER:
951                         if (!streq(c->value_str, "NameOwnerChanged"))
952                                 matches_name_change = false;
953
954                         bloom_add_pair(bloom, "member", c->value_str);
955                         using_bloom = true;
956                         break;
957
958                 case BUS_MATCH_PATH:
959                         if (!streq(c->value_str, "/org/freedesktop/DBus"))
960                                 matches_name_change = false;
961
962                         bloom_add_pair(bloom, "path", c->value_str);
963                         using_bloom = true;
964                         break;
965
966                 case BUS_MATCH_PATH_NAMESPACE:
967                         if (!streq(c->value_str, "/")) {
968                                 bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
969                                 using_bloom = true;
970                         }
971                         break;
972
973                 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
974                         char buf[sizeof("arg")-1 + 2 + 1];
975
976                         if (c->type - BUS_MATCH_ARG < 3)
977                                 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
978
979                         snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
980                         bloom_add_pair(bloom, buf, c->value_str);
981                         using_bloom = true;
982                         break;
983                 }
984
985                 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
986                         char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
987
988                         snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
989                         bloom_add_pair(bloom, buf, c->value_str);
990                         using_bloom = true;
991                         break;
992                 }
993
994                 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
995                         char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
996
997                         snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
998                         bloom_add_pair(bloom, buf, c->value_str);
999                         using_bloom = true;
1000                         break;
1001                 }
1002
1003                 case BUS_MATCH_DESTINATION:
1004                         /* The bloom filter does not include
1005                            the destination, since it is only
1006                            available for broadcast messages
1007                            which do not carry a destination
1008                            since they are undirected. */
1009                         break;
1010
1011                 case BUS_MATCH_ROOT:
1012                 case BUS_MATCH_VALUE:
1013                 case BUS_MATCH_LEAF:
1014                 case _BUS_MATCH_NODE_TYPE_MAX:
1015                 case _BUS_MATCH_NODE_TYPE_INVALID:
1016                         assert_not_reached("Invalid match type?");
1017                 }
1018         }
1019
1020         if (using_bloom)
1021                 sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
1022
1023         m = alloca0(sz);
1024         m->size = sz;
1025         m->cookie = cookie;
1026         m->id = id;
1027
1028         item = m->items;
1029         item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1030         item->type = KDBUS_ITEM_ID;
1031         item->id = src_id;
1032
1033         if (using_bloom) {
1034                 item = KDBUS_ITEM_NEXT(item);
1035                 item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
1036                 item->type = KDBUS_ITEM_BLOOM;
1037                 memcpy(item->data64, bloom, BLOOM_SIZE);
1038         }
1039
1040         if (sender) {
1041                 item = KDBUS_ITEM_NEXT(item);
1042                 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1043                 item->type = KDBUS_ITEM_NAME;
1044                 memcpy(item->str, sender, sender_length + 1);
1045         }
1046
1047         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1048         if (r < 0)
1049                 return -errno;
1050
1051         if (matches_name_change) {
1052
1053                 /* If this match could theoretically match
1054                  * NameOwnerChanged messages, we need to
1055                  * install a second non-bloom filter explitly
1056                  * for it */
1057
1058                 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1059                 if (r < 0)
1060                         return r;
1061         }
1062
1063         return 0;
1064 }
1065
1066 static int bus_add_match_internal_dbus1(
1067                 sd_bus *bus,
1068                 const char *match) {
1069
1070         assert(bus);
1071         assert(match);
1072
1073         return sd_bus_call_method(
1074                         bus,
1075                         "org.freedesktop.DBus",
1076                         "/org/freedesktop/DBus",
1077                         "org.freedesktop.DBus",
1078                         "AddMatch",
1079                         NULL,
1080                         NULL,
1081                         "s",
1082                         match);
1083 }
1084
1085 int bus_add_match_internal(
1086                 sd_bus *bus,
1087                 const char *match,
1088                 struct bus_match_component *components,
1089                 unsigned n_components,
1090                 uint64_t cookie) {
1091
1092         assert(bus);
1093         assert(match);
1094
1095         if (bus->is_kernel)
1096                 return bus_add_match_internal_kernel(bus, 0, components, n_components, cookie);
1097         else
1098                 return bus_add_match_internal_dbus1(bus, match);
1099 }
1100
1101 int bus_remove_match_internal_kernel(
1102                 sd_bus *bus,
1103                 uint64_t id,
1104                 uint64_t cookie) {
1105
1106         struct kdbus_cmd_match m;
1107         int r;
1108
1109         assert(bus);
1110
1111         zero(m);
1112         m.size = offsetof(struct kdbus_cmd_match, items);
1113         m.cookie = cookie;
1114         m.id = id;
1115
1116         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1117         if (r < 0)
1118                 return -errno;
1119
1120         return 0;
1121 }
1122
1123 static int bus_remove_match_internal_dbus1(
1124                 sd_bus *bus,
1125                 const char *match) {
1126
1127         assert(bus);
1128         assert(match);
1129
1130         return sd_bus_call_method(
1131                         bus,
1132                         "org.freedesktop.DBus",
1133                         "/org/freedesktop/DBus",
1134                         "org.freedesktop.DBus",
1135                         "RemoveMatch",
1136                         NULL,
1137                         NULL,
1138                         "s",
1139                         match);
1140 }
1141
1142 int bus_remove_match_internal(
1143                 sd_bus *bus,
1144                 const char *match,
1145                 uint64_t cookie) {
1146
1147         assert(bus);
1148         assert(match);
1149
1150         if (bus->is_kernel)
1151                 return bus_remove_match_internal_kernel(bus, 0, cookie);
1152         else
1153                 return bus_remove_match_internal_dbus1(bus, match);
1154 }
1155
1156 _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1157         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1158         const char *mid;
1159         int r;
1160
1161         assert_return(bus, -EINVAL);
1162         assert_return(name, -EINVAL);
1163         assert_return(machine, -EINVAL);
1164         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1165         assert_return(!bus_pid_changed(bus), -ECHILD);
1166         assert_return(service_name_is_valid(name), -EINVAL);
1167
1168         if (streq_ptr(name, bus->unique_name))
1169                 return sd_id128_get_machine(machine);
1170
1171         r = sd_bus_message_new_method_call(
1172                         bus,
1173                         name,
1174                         "/",
1175                         "org.freedesktop.DBus.Peer",
1176                         "GetMachineId", &m);
1177         if (r < 0)
1178                 return r;
1179
1180         r = sd_bus_message_set_no_auto_start(m, true);
1181         if (r < 0)
1182                 return r;
1183
1184         r = sd_bus_call(bus, m, 0, NULL, &reply);
1185         if (r < 0)
1186                 return r;
1187
1188         r = sd_bus_message_read(reply, "s", &mid);
1189         if (r < 0)
1190                 return r;
1191
1192         return sd_id128_from_string(mid, machine);
1193 }