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