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