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