chiark / gitweb /
driverd: implement AddMatch/RemoveMatch logic
[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 = 0, 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_MATCH_NAME_{ADD,REMOVE,CHANGE} and
727          * KDBUS_MATCH_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_MATCH_NAME_ADD
735          * WELLKNOWN, UNIQUE, ""       → KDBUS_MATCH_NAME_REMOVE
736          * WELLKNOWN, UNIQUE, UNIQUE   → KDBUS_MATCH_NAME_CHANGE
737          * UNIQUE, "", UNIQUE          → KDBUS_MATCH_ID_ADD
738          * UNIQUE, UNIQUE, ""          → KDBUS_MATCH_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         }
759
760         if (!isempty(new_owner)) {
761                 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
762                 if (r < 0)
763                         return r;
764                 if (r == 0)
765                         return 0;
766                 if (is_name_id > 0 && new_owner_id != name_id)
767                         return 0;
768         }
769
770         if (is_name_id <= 0) {
771                 struct kdbus_cmd_match *m;
772                 size_t sz, l;
773
774                 /* If the name argument is missing or is a well-known
775                  * name, then add KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE}
776                  * matches for it */
777
778                 l = name ? strlen(name) : 0;
779
780                 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
781                             offsetof(struct kdbus_item, name_change) +
782                             offsetof(struct kdbus_notify_name_change, name) +
783                             l+1);
784
785                 m = alloca0(sz);
786                 m->size = sz;
787                 m->cookie = cookie;
788                 m->src_id = KDBUS_SRC_ID_KERNEL;
789
790                 item = m->items;
791                 item->size =
792                         offsetof(struct kdbus_item, name_change) +
793                         offsetof(struct kdbus_notify_name_change, name) +
794                         l+1;
795
796                 item->name_change.old.id = old_owner_id;
797                 item->name_change.new.id = new_owner_id;
798
799                 if (name)
800                         strcpy(item->name_change.name, name);
801
802                 /* If the old name is unset or empty, then
803                  * this can match against added names */
804                 if (!old_owner || old_owner[0] == 0) {
805                         item->type = KDBUS_MATCH_NAME_ADD;
806
807                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
808                         if (r < 0)
809                                 return -errno;
810                 }
811
812                 /* If the new name is unset or empty, then
813                  * this can match against removed names */
814                 if (!new_owner || new_owner[0] == 0) {
815                         item->type = KDBUS_MATCH_NAME_REMOVE;
816
817                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
818                         if (r < 0)
819                                 return -errno;
820                 }
821
822                 /* If the neither name is explicitly set to
823                  * the empty string, then this can match
824                  * agains changed names */
825                 if (!(old_owner && old_owner[0] == 0) &&
826                     !(new_owner && new_owner[0] == 0)) {
827                         item->type = KDBUS_MATCH_NAME_CHANGE;
828
829                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
830                         if (r < 0)
831                                 return -errno;
832                 }
833         }
834
835         if (is_name_id != 0) {
836                 struct kdbus_cmd_match *m;
837                 uint64_t sz;
838
839                 /* If the name argument is missing or is a unique
840                  * name, then add KDBUS_MATCH_ID_{ADD,REMOVE} matches
841                  * for it */
842
843                 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
844                             offsetof(struct kdbus_item, id_change) +
845                             sizeof(struct kdbus_notify_id_change));
846
847                 m = alloca0(sz);
848                 m->size = sz;
849                 m->cookie = cookie;
850                 m->src_id = KDBUS_SRC_ID_KERNEL;
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_MATCH_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_MATCH_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_SRC_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 = offsetof(struct kdbus_cmd_match, items);
905
906         for (i = 0; i < n_components; i++) {
907                 struct bus_match_component *c = &components[i];
908
909                 switch (c->type) {
910
911                 case BUS_MATCH_SENDER:
912                         if (!streq(c->value_str, "org.freedesktop.DBus"))
913                                 matches_name_change = false;
914
915                         r = bus_kernel_parse_unique_name(c->value_str, &src_id);
916                         if (r < 0)
917                                 return r;
918
919                         if (r > 0) {
920                                 sender = c->value_str;
921                                 sender_length = strlen(sender);
922                                 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
923                         }
924
925                         break;
926
927                 case BUS_MATCH_MESSAGE_TYPE:
928                         if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
929                                 matches_name_change = false;
930
931                         bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
932                         using_bloom = true;
933                         break;
934
935                 case BUS_MATCH_INTERFACE:
936                         if (!streq(c->value_str, "org.freedesktop.DBus"))
937                                 matches_name_change = false;
938
939                         bloom_add_pair(bloom, "interface", c->value_str);
940                         using_bloom = true;
941                         break;
942
943                 case BUS_MATCH_MEMBER:
944                         if (!streq(c->value_str, "NameOwnerChanged"))
945                                 matches_name_change = false;
946
947                         bloom_add_pair(bloom, "member", c->value_str);
948                         using_bloom = true;
949                         break;
950
951                 case BUS_MATCH_PATH:
952                         if (!streq(c->value_str, "/org/freedesktop/DBus"))
953                                 matches_name_change = false;
954
955                         bloom_add_pair(bloom, "path", c->value_str);
956                         using_bloom = true;
957                         break;
958
959                 case BUS_MATCH_PATH_NAMESPACE:
960                         if (!streq(c->value_str, "/")) {
961                                 bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
962                                 using_bloom = true;
963                         }
964                         break;
965
966                 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
967                         char buf[sizeof("arg")-1 + 2 + 1];
968
969                         if (c->type - BUS_MATCH_ARG < 3)
970                                 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
971
972                         snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
973                         bloom_add_pair(bloom, buf, c->value_str);
974                         using_bloom = true;
975                         break;
976                 }
977
978                 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
979                         char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
980
981                         snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
982                         bloom_add_pair(bloom, buf, c->value_str);
983                         using_bloom = true;
984                         break;
985                 }
986
987                 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
988                         char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
989
990                         snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
991                         bloom_add_pair(bloom, buf, c->value_str);
992                         using_bloom = true;
993                         break;
994                 }
995
996                 case BUS_MATCH_DESTINATION:
997                         /* The bloom filter does not include
998                            the destination, since it is only
999                            available for broadcast messages
1000                            which do not carry a destination
1001                            since they are undirected. */
1002                         break;
1003
1004                 case BUS_MATCH_ROOT:
1005                 case BUS_MATCH_VALUE:
1006                 case BUS_MATCH_LEAF:
1007                 case _BUS_MATCH_NODE_TYPE_MAX:
1008                 case _BUS_MATCH_NODE_TYPE_INVALID:
1009                         assert_not_reached("Invalid match type?");
1010                 }
1011         }
1012
1013         if (using_bloom)
1014                 sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
1015
1016         m = alloca0(sz);
1017         m->size = sz;
1018         m->cookie = cookie;
1019         m->src_id = src_id;
1020         m->id = id;
1021
1022         item = m->items;
1023
1024         if (using_bloom) {
1025                 item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
1026                 item->type = KDBUS_MATCH_BLOOM;
1027                 memcpy(item->data64, bloom, BLOOM_SIZE);
1028
1029                 item = KDBUS_ITEM_NEXT(item);
1030         }
1031
1032         if (sender) {
1033                 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1034                 item->type = KDBUS_MATCH_SRC_NAME;
1035                 memcpy(item->str, sender, sender_length + 1);
1036         }
1037
1038         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1039         if (r < 0)
1040                 return -errno;
1041
1042         if (matches_name_change) {
1043
1044                 /* If this match could theoretically match
1045                  * NameOwnerChanged messages, we need to
1046                  * install a second non-bloom filter explitly
1047                  * for it */
1048
1049                 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1050                 if (r < 0)
1051                         return r;
1052         }
1053
1054         return 0;
1055 }
1056
1057 static int bus_add_match_internal_dbus1(
1058                 sd_bus *bus,
1059                 const char *match) {
1060
1061         assert(bus);
1062         assert(match);
1063
1064         return sd_bus_call_method(
1065                         bus,
1066                         "org.freedesktop.DBus",
1067                         "/",
1068                         "org.freedesktop.DBus",
1069                         "AddMatch",
1070                         NULL,
1071                         NULL,
1072                         "s",
1073                         match);
1074 }
1075
1076 int bus_add_match_internal(
1077                 sd_bus *bus,
1078                 const char *match,
1079                 struct bus_match_component *components,
1080                 unsigned n_components,
1081                 uint64_t cookie) {
1082
1083         assert(bus);
1084         assert(match);
1085
1086         if (bus->is_kernel)
1087                 return bus_add_match_internal_kernel(bus, 0, components, n_components, cookie);
1088         else
1089                 return bus_add_match_internal_dbus1(bus, match);
1090 }
1091
1092 int bus_remove_match_internal_kernel(
1093                 sd_bus *bus,
1094                 uint64_t id,
1095                 uint64_t cookie) {
1096
1097         struct kdbus_cmd_match m;
1098         int r;
1099
1100         assert(bus);
1101
1102         zero(m);
1103         m.size = offsetof(struct kdbus_cmd_match, items);
1104         m.cookie = cookie;
1105         m.id = id;
1106
1107         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1108         if (r < 0)
1109                 return -errno;
1110
1111         return 0;
1112 }
1113
1114 static int bus_remove_match_internal_dbus1(
1115                 sd_bus *bus,
1116                 const char *match) {
1117
1118         assert(bus);
1119         assert(match);
1120
1121         return sd_bus_call_method(
1122                         bus,
1123                         "org.freedesktop.DBus",
1124                         "/",
1125                         "org.freedesktop.DBus",
1126                         "RemoveMatch",
1127                         NULL,
1128                         NULL,
1129                         "s",
1130                         match);
1131 }
1132
1133 int bus_remove_match_internal(
1134                 sd_bus *bus,
1135                 const char *match,
1136                 uint64_t cookie) {
1137
1138         assert(bus);
1139         assert(match);
1140
1141         if (bus->is_kernel)
1142                 return bus_remove_match_internal_kernel(bus, 0, cookie);
1143         else
1144                 return bus_remove_match_internal_dbus1(bus, match);
1145 }
1146
1147 _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1148         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1149         const char *mid;
1150         int r;
1151
1152         assert_return(bus, -EINVAL);
1153         assert_return(name, -EINVAL);
1154         assert_return(machine, -EINVAL);
1155         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1156         assert_return(!bus_pid_changed(bus), -ECHILD);
1157         assert_return(service_name_is_valid(name), -EINVAL);
1158
1159         if (streq_ptr(name, bus->unique_name))
1160                 return sd_id128_get_machine(machine);
1161
1162         r = sd_bus_message_new_method_call(
1163                         bus,
1164                         name,
1165                         "/",
1166                         "org.freedesktop.DBus.Peer",
1167                         "GetMachineId", &m);
1168         if (r < 0)
1169                 return r;
1170
1171         r = sd_bus_message_set_no_auto_start(m, true);
1172         if (r < 0)
1173                 return r;
1174
1175         r = sd_bus_call(bus, m, 0, NULL, &reply);
1176         if (r < 0)
1177                 return r;
1178
1179         r = sd_bus_message_read(reply, "s", &mid);
1180         if (r < 0)
1181                 return r;
1182
1183         return sd_id128_from_string(mid, machine);
1184 }