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