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