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