chiark / gitweb /
b9700068b6acaf20847c94e90e606c00556d8db5
[elogind.git] / src / libsystemd-bus / bus-control.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
24 #endif
25
26 #include <stddef.h>
27 #include <errno.h>
28
29 #include "strv.h"
30 #include "sd-bus.h"
31 #include "bus-internal.h"
32 #include "bus-message.h"
33 #include "bus-control.h"
34 #include "bus-bloom.h"
35 #include "bus-util.h"
36
37 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
38         int r;
39
40         assert_return(bus, -EINVAL);
41         assert_return(unique, -EINVAL);
42         assert_return(!bus_pid_changed(bus), -ECHILD);
43
44         r = bus_ensure_running(bus);
45         if (r < 0)
46                 return r;
47
48         *unique = bus->unique_name;
49         return 0;
50 }
51
52 static int bus_request_name_kernel(sd_bus *bus, const char *name, unsigned flags) {
53         struct kdbus_cmd_name *n;
54         size_t l;
55         int r;
56
57         assert(bus);
58         assert(name);
59
60         l = strlen(name);
61         n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
62         n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
63         kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags);
64         memcpy(n->name, name, l+1);
65
66 #ifdef HAVE_VALGRIND_MEMCHECK_H
67         VALGRIND_MAKE_MEM_DEFINED(n, n->size);
68 #endif
69
70         r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
71         if (r < 0)
72                 return -errno;
73
74         if (n->flags & KDBUS_NAME_IN_QUEUE)
75                 return 0;
76
77         return 1;
78 }
79
80 static int bus_request_name_dbus1(sd_bus *bus, const char *name, unsigned flags) {
81         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
82         uint32_t ret;
83         int r;
84
85         assert(bus);
86         assert(name);
87
88         r = sd_bus_call_method(
89                         bus,
90                         "org.freedesktop.DBus",
91                         "/",
92                         "org.freedesktop.DBus",
93                         "RequestName",
94                         NULL,
95                         &reply,
96                         "su",
97                         name,
98                         flags);
99         if (r < 0)
100                 return r;
101
102         r = sd_bus_message_read(reply, "u", &ret);
103         if (r < 0)
104                 return r;
105
106         if (ret == BUS_NAME_ALREADY_OWNER)
107                 return -EALREADY;
108         else if (ret == BUS_NAME_EXISTS)
109                 return -EEXIST;
110         else if (ret == BUS_NAME_IN_QUEUE)
111                 return 0;
112         else if (ret == BUS_NAME_PRIMARY_OWNER)
113                 return 1;
114
115         return -EIO;
116 }
117
118 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, unsigned flags) {
119         assert_return(bus, -EINVAL);
120         assert_return(name, -EINVAL);
121         assert_return(bus->bus_client, -EINVAL);
122         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
123         assert_return(!bus_pid_changed(bus), -ECHILD);
124         assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_DO_NOT_QUEUE)), -EINVAL);
125
126         if (bus->is_kernel)
127                 return bus_request_name_kernel(bus, name, flags);
128         else
129                 return bus_request_name_dbus1(bus, name, flags);
130 }
131
132 static int bus_release_name_kernel(sd_bus *bus, const char *name) {
133         struct kdbus_cmd_name *n;
134         size_t l;
135         int r;
136
137         assert(bus);
138         assert(name);
139
140         l = strlen(name);
141         n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
142         n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
143         memcpy(n->name, name, l+1);
144
145 #ifdef HAVE_VALGRIND_MEMCHECK_H
146         VALGRIND_MAKE_MEM_DEFINED(n, n->size);
147 #endif
148         r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
149         if (r < 0)
150                 return -errno;
151
152         return n->flags;
153 }
154
155 static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
156         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
157         uint32_t ret;
158         int r;
159
160         assert(bus);
161         assert(name);
162
163         r = sd_bus_call_method(
164                         bus,
165                         "org.freedesktop.DBus",
166                         "/",
167                         "org.freedesktop.DBus",
168                         "ReleaseName",
169                         NULL,
170                         &reply,
171                         "s",
172                         name);
173         if (r < 0)
174                 return r;
175
176         r = sd_bus_message_read(reply, "u", &ret);
177         if (r < 0)
178                 return r;
179         if (ret == BUS_NAME_NON_EXISTENT)
180                 return -ENOENT;
181         if (ret == BUS_NAME_NOT_OWNER)
182                 return -EADDRNOTAVAIL;
183         if (ret == BUS_NAME_RELEASED)
184                 return 0;
185
186         return -EINVAL;
187 }
188
189 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
190         assert_return(bus, -EINVAL);
191         assert_return(name, -EINVAL);
192         assert_return(bus->bus_client, -EINVAL);
193         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
194         assert_return(!bus_pid_changed(bus), -ECHILD);
195
196         if (bus->is_kernel)
197                 return bus_release_name_kernel(bus, name);
198         else
199                 return bus_release_name_dbus1(bus, name);
200 }
201
202 static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
203         struct kdbus_cmd_name_list cmd = {};
204         struct kdbus_name_list *name_list;
205         struct kdbus_cmd_name *name;
206         uint64_t previous_id = 0;
207         int r;
208
209         /* Caller will free half-constructed list on failure... */
210
211         cmd.flags = flags;
212
213         r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
214         if (r < 0)
215                 return -errno;
216
217         name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
218
219         KDBUS_ITEM_FOREACH(name, name_list, names) {
220
221                 if ((flags & KDBUS_NAME_LIST_UNIQUE) && name->id != previous_id) {
222                         char *n;
223
224                         if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0)
225                                 return -ENOMEM;
226
227                         r = strv_push(x, n);
228                         if (r < 0) {
229                                 free(n);
230                                 return -ENOMEM;
231                         }
232
233                         previous_id = name->id;
234                 }
235
236                 if (name->size > sizeof(*name)) {
237                         r = strv_extend(x, name->name);
238                         if (r < 0)
239                                 return -ENOMEM;
240                 }
241         }
242
243         r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_FREE, &cmd.offset);
244         if (r < 0)
245                 return -errno;
246
247         return 0;
248 }
249
250 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
251         _cleanup_strv_free_ char **x = NULL, **y = NULL;
252         int r;
253
254         if (acquired) {
255                 r = kernel_get_list(bus, KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES, &x);
256                 if (r < 0)
257                         return r;
258         }
259
260         if (activatable) {
261                 r = kernel_get_list(bus, KDBUS_NAME_LIST_STARTERS, &y);
262                 if (r < 0)
263                         return r;
264
265                 *activatable = y;
266                 y = NULL;
267         }
268
269         if (acquired) {
270                 *acquired = x;
271                 x = NULL;
272         }
273
274         return 0;
275 }
276
277 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
278         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
279         _cleanup_strv_free_ char **x = NULL, **y = NULL;
280         int r;
281
282         if (acquired) {
283                 r = sd_bus_call_method(
284                                 bus,
285                                 "org.freedesktop.DBus",
286                                 "/",
287                                 "org.freedesktop.DBus",
288                                 "ListNames",
289                                 NULL,
290                                 &reply,
291                                 NULL);
292                 if (r < 0)
293                         return r;
294
295                 r = sd_bus_message_read_strv(reply, &x);
296                 if (r < 0)
297                         return r;
298
299                 reply = sd_bus_message_unref(reply);
300         }
301
302         if (activatable) {
303                 r = sd_bus_call_method(
304                                 bus,
305                                 "org.freedesktop.DBus",
306                                 "/",
307                                 "org.freedesktop.DBus",
308                                 "ListActivatableNames",
309                                 NULL,
310                                 &reply,
311                                 NULL);
312                 if (r < 0)
313                         return r;
314
315                 r = sd_bus_message_read_strv(reply, &y);
316                 if (r < 0)
317                         return r;
318
319                 *activatable = y;
320                 y = NULL;
321         }
322
323         if (acquired) {
324                 *acquired = x;
325                 x = NULL;
326         }
327
328         return 0;
329 }
330
331 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
332         assert_return(bus, -EINVAL);
333         assert_return(acquired || activatable, -EINVAL);
334         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
335         assert_return(!bus_pid_changed(bus), -ECHILD);
336
337         if (bus->is_kernel)
338                 return bus_list_names_kernel(bus, acquired, activatable);
339         else
340                 return bus_list_names_dbus1(bus, acquired, activatable);
341 }
342
343 static int bus_get_owner_kdbus(
344                 sd_bus *bus,
345                 const char *name,
346                 uint64_t mask,
347                 sd_bus_creds **creds) {
348
349         _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
350         struct kdbus_cmd_conn_info *cmd;
351         struct kdbus_conn_info *conn_info;
352         struct kdbus_item *item;
353         size_t size;
354         uint64_t m, id;
355         int r;
356
357         r = bus_kernel_parse_unique_name(name, &id);
358         if (r < 0)
359                 return r;
360         if (r > 0) {
361                 size = offsetof(struct kdbus_cmd_conn_info, name);
362                 cmd = alloca0(size);
363                 cmd->id = id;
364         } else {
365                 size = offsetof(struct kdbus_cmd_conn_info, name) + strlen(name) + 1;
366                 cmd = alloca0(size);
367                 strcpy(cmd->name, name);
368         }
369         cmd->flags = KDBUS_ATTACH_NAMES;
370
371         cmd->size = size;
372         r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
373         if (r < 0)
374                 return -errno;
375
376         conn_info = (struct kdbus_conn_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
377
378         c = bus_creds_new();
379         if (!c)
380                 return -ENOMEM;
381
382         if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
383                 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0)
384                         return -ENOMEM;
385
386                 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
387         }
388
389         KDBUS_ITEM_FOREACH(item, conn_info, items) {
390
391                 switch (item->type) {
392
393                 case KDBUS_ITEM_CREDS:
394                         m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID |
395                              SD_BUS_CREDS_TID | SD_BUS_CREDS_PID_STARTTIME) & mask;
396
397                         if (m) {
398                                 c->uid = item->creds.uid;
399                                 c->pid = item->creds.pid;
400                                 c->gid = item->creds.gid;
401                                 c->tid = item->creds.tid;
402                                 c->pid_starttime = item->creds.starttime;
403                                 c->mask |= m;
404                         }
405                         break;
406
407                 case KDBUS_ITEM_PID_COMM:
408                         if (mask & SD_BUS_CREDS_COMM) {
409                                 c->comm = strdup(item->str);
410                                 if (!c->comm) {
411                                         r = -ENOMEM;
412                                         goto fail;
413                                 }
414
415                                 c->mask |= SD_BUS_CREDS_COMM;
416                         }
417                         break;
418
419                 case KDBUS_ITEM_TID_COMM:
420                         if (mask & SD_BUS_CREDS_TID_COMM) {
421                                 c->tid_comm = strdup(item->str);
422                                 if (!c->tid_comm) {
423                                         r = -ENOMEM;
424                                         goto fail;
425                                 }
426
427                                 c->mask |= SD_BUS_CREDS_TID_COMM;
428                         }
429                         break;
430
431                 case KDBUS_ITEM_EXE:
432                         if (mask & SD_BUS_CREDS_EXE) {
433                                 c->exe = strdup(item->str);
434                                 if (!c->exe) {
435                                         r = -ENOMEM;
436                                         goto fail;
437                                 }
438
439                                 c->mask |= SD_BUS_CREDS_EXE;
440                         }
441                         break;
442
443                 case KDBUS_ITEM_CMDLINE:
444                         if (mask & SD_BUS_CREDS_CMDLINE) {
445                                 c->cmdline_size = item->size - KDBUS_ITEM_HEADER_SIZE;
446                                 c->cmdline = memdup(item->data, c->cmdline_size);
447                                 if (!c->cmdline) {
448                                         r = -ENOMEM;
449                                         goto fail;
450                                 }
451
452                                 c->mask |= SD_BUS_CREDS_CMDLINE;
453                         }
454                         break;
455
456                 case KDBUS_ITEM_CGROUP:
457                         m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
458                              SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
459                              SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
460
461                         if (m) {
462                                 c->cgroup = strdup(item->str);
463                                 if (!c->cgroup) {
464                                         r = -ENOMEM;
465                                         goto fail;
466                                 }
467
468                                 c->mask |= m;
469                         }
470                         break;
471
472                 case KDBUS_ITEM_CAPS:
473                         m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
474                              SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
475
476                         if (m) {
477                                 c->capability_size = item->size - KDBUS_ITEM_HEADER_SIZE;
478                                 c->capability = memdup(item->data, c->capability_size);
479                                 if (!c->capability) {
480                                         r = -ENOMEM;
481                                         goto fail;
482                                 }
483
484                                 c->mask |= m;
485                         }
486                         break;
487
488                 case KDBUS_ITEM_SECLABEL:
489                         if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
490                                 c->label = strdup(item->str);
491                                 if (!c->label) {
492                                         r = -ENOMEM;
493                                         goto fail;
494                                 }
495
496                                 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
497                         }
498                         break;
499
500                 case KDBUS_ITEM_AUDIT:
501                         m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask;
502
503                         if (m) {
504                                 c->audit_session_id = item->audit.sessionid;
505                                 c->audit_login_uid = item->audit.loginuid;
506                                 c->mask |= m;
507                         }
508                         break;
509
510                 case KDBUS_ITEM_NAME:
511                         if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
512                                 r = strv_extend(&c->well_known_names, item->name.name);
513                                 if (r < 0)
514                                         goto fail;
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_ITEM_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 }