chiark / gitweb /
bus: rework sd_bus_list_names() to return two lists for acquired and activatable...
[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
114                 return -EIO;
115
116         return 1;
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.size = sizeof(struct kdbus_cmd_name_list);
212         cmd.flags = flags;
213
214         r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
215         if (r < 0)
216                 return -errno;
217
218         name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
219
220         KDBUS_PART_FOREACH(name, name_list, names) {
221
222                 if (name->size > sizeof(*name)) {
223                         r = strv_extend(x, name->name);
224                         if (r < 0)
225                                 return -ENOMEM;
226                 } else {
227                         char *n;
228
229                         if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0)
230                                 return -ENOMEM;
231
232                         r = strv_push(x, n);
233                         if (r < 0) {
234                                 free(n);
235                                 return -ENOMEM;
236                         }
237                 }
238
239         }
240
241         r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_FREE, &cmd.offset);
242         if (r < 0)
243                 return -errno;
244
245         return 0;
246 }
247
248 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
249         _cleanup_strv_free_ char **x = NULL, **y = NULL;
250         int r;
251
252         if (acquired) {
253                 r = kernel_get_list(bus, KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES, &x);
254                 if (r < 0)
255                         return r;
256         }
257
258         if (activatable) {
259                 r = kernel_get_list(bus, KDBUS_NAME_LIST_STARTERS, &y);
260                 if (r < 0)
261                         return r;
262
263                 *activatable = y;
264                 y = NULL;
265         }
266
267         if (acquired) {
268                 *acquired = x;
269                 x = NULL;
270         }
271
272         return 0;
273 }
274
275 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
276         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
277         _cleanup_strv_free_ char **x = NULL, **y = NULL;
278         int r;
279
280         if (acquired) {
281                 r = sd_bus_call_method(
282                                 bus,
283                                 "org.freedesktop.DBus",
284                                 "/",
285                                 "org.freedesktop.DBus",
286                                 "ListNames",
287                                 NULL,
288                                 &reply,
289                                 NULL);
290                 if (r < 0)
291                         return r;
292
293                 r = sd_bus_message_read_strv(reply, &x);
294                 if (r < 0)
295                         return r;
296
297                 reply = sd_bus_message_unref(reply);
298         }
299
300         if (activatable) {
301                 r = sd_bus_call_method(
302                                 bus,
303                                 "org.freedesktop.DBus",
304                                 "/",
305                                 "org.freedesktop.DBus",
306                                 "ListActivatableNames",
307                                 NULL,
308                                 &reply,
309                                 NULL);
310                 if (r < 0)
311                         return r;
312
313                 r = sd_bus_message_read_strv(reply, &y);
314                 if (r < 0)
315                         return r;
316
317                 *activatable = y;
318                 y = NULL;
319         }
320
321         if (acquired) {
322                 *acquired = x;
323                 x = NULL;
324         }
325
326         return 0;
327 }
328
329 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
330         assert_return(bus, -EINVAL);
331         assert_return(acquired || activatable, -EINVAL);
332         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
333         assert_return(!bus_pid_changed(bus), -ECHILD);
334
335         if (bus->is_kernel)
336                 return bus_list_names_kernel(bus, acquired, activatable);
337         else
338                 return bus_list_names_dbus1(bus, acquired, activatable);
339 }
340
341 static int bus_get_owner_kdbus(
342                 sd_bus *bus,
343                 const char *name,
344                 uint64_t mask,
345                 sd_bus_creds **creds) {
346
347         _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
348         struct kdbus_cmd_conn_info *cmd;
349         struct kdbus_conn_info *conn_info;
350         struct kdbus_item *item;
351         size_t size;
352         uint64_t m, id;
353         int r;
354
355         r = bus_kernel_parse_unique_name(name, &id);
356         if (r < 0)
357                 return r;
358         if (r > 0) {
359                 size = offsetof(struct kdbus_cmd_conn_info, name);
360                 cmd = alloca0(size);
361                 cmd->id = id;
362         } else {
363                 size = offsetof(struct kdbus_cmd_conn_info, name) + strlen(name) + 1;
364                 cmd = alloca0(size);
365                 strcpy(cmd->name, name);
366         }
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 }