chiark / gitweb /
aaddb7d374a93de9b28680bd342aa00ea7c60ce4
[elogind.git] / src / libsystemd-bus / bus-control.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
24 #endif
25
26 #include <stddef.h>
27 #include <errno.h>
28
29 #include "strv.h"
30
31 #include "sd-bus.h"
32 #include "bus-internal.h"
33 #include "bus-message.h"
34 #include "bus-control.h"
35 #include "bus-bloom.h"
36 #include "bus-util.h"
37
38 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
39         int r;
40
41         assert_return(bus, -EINVAL);
42         assert_return(unique, -EINVAL);
43         assert_return(!bus_pid_changed(bus), -ECHILD);
44
45         r = bus_ensure_running(bus);
46         if (r < 0)
47                 return r;
48
49         *unique = bus->unique_name;
50         return 0;
51 }
52
53 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, int flags) {
54         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
55         uint32_t ret;
56         int r;
57
58         assert_return(bus, -EINVAL);
59         assert_return(name, -EINVAL);
60         assert_return(bus->bus_client, -EINVAL);
61         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
62         assert_return(!bus_pid_changed(bus), -ECHILD);
63
64         if (bus->is_kernel) {
65                 struct kdbus_cmd_name *n;
66                 size_t l;
67
68                 l = strlen(name);
69                 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
70                 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
71                 kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags);
72                 memcpy(n->name, name, l+1);
73
74 #ifdef HAVE_VALGRIND_MEMCHECK_H
75                 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
76 #endif
77
78                 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
79                 if (r < 0) {
80                         if (errno == -EALREADY)
81                                 return SD_BUS_NAME_ALREADY_OWNER;
82
83                         if (errno == -EEXIST)
84                                 return SD_BUS_NAME_EXISTS;
85
86                         return -errno;
87                 }
88
89                 if (n->flags & KDBUS_NAME_IN_QUEUE)
90                         return SD_BUS_NAME_IN_QUEUE;
91
92                 return SD_BUS_NAME_PRIMARY_OWNER;
93         } else {
94                 r = sd_bus_call_method(
95                                 bus,
96                                 "org.freedesktop.DBus",
97                                 "/",
98                                 "org.freedesktop.DBus",
99                                 "RequestName",
100                                 NULL,
101                                 &reply,
102                                 "su",
103                                 name,
104                                 flags);
105                 if (r < 0)
106                         return r;
107
108                 r = sd_bus_message_read(reply, "u", &ret);
109                 if (r < 0)
110                         return r;
111
112                 return ret;
113         }
114 }
115
116 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
117         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
118         uint32_t ret;
119         int r;
120
121         assert_return(bus, -EINVAL);
122         assert_return(name, -EINVAL);
123         assert_return(bus->bus_client, -EINVAL);
124         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
125         assert_return(!bus_pid_changed(bus), -ECHILD);
126
127         if (bus->is_kernel) {
128                 struct kdbus_cmd_name *n;
129                 size_t l;
130
131                 l = strlen(name);
132                 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
133                 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
134                 memcpy(n->name, name, l+1);
135
136 #ifdef HAVE_VALGRIND_MEMCHECK_H
137                 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
138 #endif
139                 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
140                 if (r < 0)
141                         return -errno;
142
143                 return n->flags;
144         } else {
145                 r = sd_bus_call_method(
146                                 bus,
147                                 "org.freedesktop.DBus",
148                                 "/",
149                                 "org.freedesktop.DBus",
150                                 "ReleaseName",
151                                 NULL,
152                                 &reply,
153                                 "s",
154                                 name);
155                 if (r < 0)
156                         return r;
157
158                 r = sd_bus_message_read(reply, "u", &ret);
159                 if (r < 0)
160                         return r;
161         }
162
163         return ret;
164 }
165
166 _public_ int sd_bus_list_names(sd_bus *bus, char ***l) {
167         _cleanup_bus_message_unref_ sd_bus_message *reply1 = NULL, *reply2 = NULL;
168         char **x = NULL;
169         int r;
170
171         assert_return(bus, -EINVAL);
172         assert_return(l, -EINVAL);
173         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
174         assert_return(!bus_pid_changed(bus), -ECHILD);
175
176         if (bus->is_kernel) {
177                 _cleanup_free_ struct kdbus_cmd_name_list *cmd = NULL;
178                 struct kdbus_name_list *name_list;
179                 struct kdbus_cmd_name *name;
180
181                 cmd = malloc0(sizeof(struct kdbus_cmd_name_list *));
182                 if (!cmd)
183                         return -ENOMEM;
184
185                 cmd->flags = KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES;
186
187                 r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_NAME_LIST, cmd);
188                 if (r < 0)
189                         return -errno;
190
191                 name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
192
193                 KDBUS_PART_FOREACH(name, name_list, names) {
194                         char *n;
195
196                         if (name->size > sizeof(*name))
197                                 n = name->name;
198                         else
199                                 asprintf(&n, ":1.%llu", (unsigned long long) name->id);
200
201                         r = strv_extend(&x, n);
202                         if (r < 0)
203                                 return -ENOMEM;
204                 }
205
206                 r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_FREE, &cmd->offset);
207                 if (r < 0)
208                         return -errno;
209
210                 *l = x;
211         } else {
212                 r = sd_bus_call_method(
213                                 bus,
214                                 "org.freedesktop.DBus",
215                                 "/",
216                                 "org.freedesktop.DBus",
217                                 "ListNames",
218                                 NULL,
219                                 &reply1,
220                                 NULL);
221                 if (r < 0)
222                         return r;
223
224                 r = sd_bus_call_method(
225                                 bus,
226                                 "org.freedesktop.DBus",
227                                 "/",
228                                 "org.freedesktop.DBus",
229                                 "ListActivatableNames",
230                                 NULL,
231                                 &reply2,
232                                 NULL);
233                 if (r < 0)
234                         return r;
235
236                 r = bus_message_read_strv_extend(reply1, &x);
237                 if (r < 0) {
238                         strv_free(x);
239                         return r;
240                 }
241
242                 r = bus_message_read_strv_extend(reply2, &x);
243                 if (r < 0) {
244                         strv_free(x);
245                         return r;
246                 }
247
248                 *l = strv_uniq(x);
249         }
250
251         return 0;
252 }
253
254 static int bus_get_owner_dbus(
255                 sd_bus *bus,
256                 const char *name,
257                 uint64_t mask,
258                 sd_bus_creds **creds) {
259
260         _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
261         _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
262         const char *unique = NULL;
263         pid_t pid = 0;
264         int r;
265
266         /* Only query the owner if the caller wants to know it or if
267          * the caller just wants to check whether a name exists */
268         if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
269                 r = sd_bus_call_method(
270                                 bus,
271                                 "org.freedesktop.DBus",
272                                 "/",
273                                 "org.freedesktop.DBus",
274                                 "GetNameOwner",
275                                 NULL,
276                                 &reply_unique,
277                                 "s",
278                                 name);
279                 if (r < 0)
280                         return r;
281
282                 r = sd_bus_message_read(reply_unique, "s", &unique);
283                 if (r < 0)
284                         return r;
285         }
286
287         if (mask != 0) {
288                 c = bus_creds_new();
289                 if (!c)
290                         return -ENOMEM;
291
292                 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
293                         c->unique_name = strdup(unique);
294                         if (!c->unique_name)
295                                 return -ENOMEM;
296
297                         c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
298                 }
299
300                 if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_GID|
301                             SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
302                             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|
303                             SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
304                             SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)) {
305                         uint32_t u;
306
307                         r = sd_bus_call_method(
308                                         bus,
309                                         "org.freedesktop.DBus",
310                                         "/",
311                                         "org.freedesktop.DBus",
312                                         "GetConnectionUnixProcessID",
313                                         NULL,
314                                         &reply,
315                                         "s",
316                                         unique ? unique : name);
317                         if (r < 0)
318                                 return r;
319
320                         r = sd_bus_message_read(reply, "u", &u);
321                         if (r < 0)
322                                 return r;
323
324                         pid = u;
325                         if (mask & SD_BUS_CREDS_PID) {
326                                 c->pid = u;
327                                 c->mask |= SD_BUS_CREDS_PID;
328                         }
329
330                         reply = sd_bus_message_unref(reply);
331                 }
332
333                 if (mask & SD_BUS_CREDS_UID) {
334                         uint32_t u;
335
336                         r = sd_bus_call_method(
337                                         bus,
338                                         "org.freedesktop.DBus",
339                                         "/",
340                                         "org.freedesktop.DBus",
341                                         "GetConnectionUnixUser",
342                                         NULL,
343                                         &reply,
344                                         "s",
345                                         unique ? unique : name);
346                         if (r < 0)
347                                 return r;
348
349                         r = sd_bus_message_read(reply, "u", &u);
350                         if (r < 0)
351                                 return r;
352
353                         c->uid = u;
354                         c->mask |= SD_BUS_CREDS_UID;
355
356                         reply = sd_bus_message_unref(reply);
357                 }
358
359                 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
360                         const void *p;
361                         size_t sz;
362
363                         r = sd_bus_call_method(
364                                         bus,
365                                         "org.freedesktop.DBus",
366                                         "/",
367                                         "org.freedesktop.DBus",
368                                         "GetConnectionSELinuxSecurityContext",
369                                         NULL,
370                                         &reply,
371                                         "s",
372                                         unique ? unique : name);
373                         if (r < 0)
374                                 return r;
375
376                         r = sd_bus_message_read_array(reply, 'y', &p, &sz);
377                         if (r < 0)
378                                 return r;
379
380                         c->label = strndup(p, sz);
381                         if (!c->label)
382                                 return -ENOMEM;
383
384                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
385                 }
386
387                 r = bus_creds_add_more(c, mask, pid, 0);
388                 if (r < 0)
389                         return r;
390         }
391
392         if (creds) {
393                 *creds = c;
394                 c = NULL;
395         }
396
397         return 0;
398 }
399
400 static int bus_get_owner_kdbus(
401                 sd_bus *bus,
402                 const char *name,
403                 uint64_t mask,
404                 sd_bus_creds **creds) {
405
406         _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
407         struct kdbus_cmd_conn_info *cmd;
408         struct kdbus_conn_info *conn_info;
409         struct kdbus_item *item;
410         size_t size;
411         uint64_t m, id;
412         int r;
413
414         r = bus_kernel_parse_unique_name(name, &id);
415         if (r < 0)
416                 return r;
417         if (r > 0) {
418                 size = offsetof(struct kdbus_cmd_conn_info, name);
419                 cmd = alloca0(size);
420                 cmd->id = id;
421         } else {
422                 size = offsetof(struct kdbus_cmd_conn_info, name) + strlen(name) + 1;
423                 cmd = alloca0(size);
424                 strcpy(cmd->name, name);
425         }
426
427         cmd->size = size;
428         r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
429         if (r < 0)
430                 return -errno;
431
432         conn_info = (struct kdbus_conn_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
433
434         c = bus_creds_new();
435         if (!c)
436                 return -ENOMEM;
437
438         if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
439                 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0)
440                         return -ENOMEM;
441
442                 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
443         }
444
445         KDBUS_PART_FOREACH(item, conn_info, items) {
446
447                 switch (item->type) {
448
449                 case KDBUS_ITEM_CREDS:
450                         m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID |
451                              SD_BUS_CREDS_TID | SD_BUS_CREDS_PID_STARTTIME) & mask;
452
453                         if (m) {
454                                 c->uid = item->creds.uid;
455                                 c->pid = item->creds.pid;
456                                 c->gid = item->creds.gid;
457                                 c->tid = item->creds.tid;
458                                 c->pid_starttime = item->creds.starttime;
459                                 c->mask |= m;
460                         }
461                         break;
462
463                 case KDBUS_ITEM_PID_COMM:
464                         if (mask & SD_BUS_CREDS_COMM) {
465                                 c->comm = strdup(item->str);
466                                 if (!c->comm) {
467                                         r = -ENOMEM;
468                                         goto fail;
469                                 }
470
471                                 c->mask |= SD_BUS_CREDS_COMM;
472                         }
473                         break;
474
475                 case KDBUS_ITEM_TID_COMM:
476                         if (mask & SD_BUS_CREDS_TID_COMM) {
477                                 c->tid_comm = strdup(item->str);
478                                 if (!c->tid_comm) {
479                                         r = -ENOMEM;
480                                         goto fail;
481                                 }
482
483                                 c->mask |= SD_BUS_CREDS_TID_COMM;
484                         }
485                         break;
486
487                 case KDBUS_ITEM_EXE:
488                         if (mask & SD_BUS_CREDS_EXE) {
489                                 c->exe = strdup(item->str);
490                                 if (!c->exe) {
491                                         r = -ENOMEM;
492                                         goto fail;
493                                 }
494
495                                 c->mask |= SD_BUS_CREDS_EXE;
496                         }
497                         break;
498
499                 case KDBUS_ITEM_CMDLINE:
500                         if (mask & SD_BUS_CREDS_CMDLINE) {
501                                 c->cmdline_size = item->size - KDBUS_PART_HEADER_SIZE;
502                                 c->cmdline = memdup(item->data, c->cmdline_size);
503                                 if (!c->cmdline) {
504                                         r = -ENOMEM;
505                                         goto fail;
506                                 }
507
508                                 c->mask |= SD_BUS_CREDS_CMDLINE;
509                         }
510                         break;
511
512                 case KDBUS_ITEM_CGROUP:
513                         m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
514                              SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
515                              SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
516
517                         if (m) {
518                                 c->cgroup = strdup(item->str);
519                                 if (!c->cgroup) {
520                                         r = -ENOMEM;
521                                         goto fail;
522                                 }
523
524                                 c->mask |= m;
525                         }
526                         break;
527
528                 case KDBUS_ITEM_CAPS:
529                         m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
530                              SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
531
532                         if (m) {
533                                 c->capability_size = item->size - KDBUS_PART_HEADER_SIZE;
534                                 c->capability = memdup(item->data, c->capability_size);
535                                 if (!c->capability) {
536                                         r = -ENOMEM;
537                                         goto fail;
538                                 }
539
540                                 c->mask |= m;
541                         }
542                         break;
543
544                 case KDBUS_ITEM_SECLABEL:
545                         if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
546                                 c->label = strdup(item->str);
547                                 if (!c->label) {
548                                         r = -ENOMEM;
549                                         goto fail;
550                                 }
551
552                                 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
553                         }
554                         break;
555
556                 case KDBUS_ITEM_AUDIT:
557                         m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask;
558
559                         if (m) {
560                                 c->audit_session_id = item->audit.sessionid;
561                                 c->audit_login_uid = item->audit.loginuid;
562                                 c->mask |= m;
563                         }
564                         break;
565
566                 case KDBUS_ITEM_NAMES:
567                         if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
568                                 c->well_known_names_size = item->size - KDBUS_PART_HEADER_SIZE;
569                                 c->well_known_names = memdup(item->data, c->well_known_names_size);
570                                 if (!c->well_known_names) {
571                                         r = -ENOMEM;
572                                         goto fail;
573                                 }
574
575                                 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
576                         }
577                         break;
578                 }
579         }
580
581         if (creds) {
582                 *creds = c;
583                 c = NULL;
584         }
585
586         r = 0;
587
588 fail:
589         ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd->offset);
590         return r;
591 }
592
593 _public_ int sd_bus_get_owner(
594                 sd_bus *bus,
595                 const char *name,
596                 uint64_t mask,
597                 sd_bus_creds **creds) {
598
599         assert_return(bus, -EINVAL);
600         assert_return(name, -EINVAL);
601         assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
602         assert_return(mask == 0 || creds, -EINVAL);
603         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
604         assert_return(!bus_pid_changed(bus), -ECHILD);
605
606         if (bus->is_kernel)
607                 return bus_get_owner_kdbus(bus, name, mask, creds);
608         else
609                 return bus_get_owner_dbus(bus, name, mask, creds);
610 }
611
612 static int add_name_change_match(sd_bus *bus,
613                                  uint64_t cookie,
614                                  const char *name,
615                                  const char *old_owner,
616                                  const char *new_owner) {
617
618         uint64_t name_id = 0, old_owner_id = 0, new_owner_id = 0;
619         int is_name_id = -1, r;
620         struct kdbus_item *item;
621
622         assert(bus);
623
624         /* If we encounter a match that could match against
625          * NameOwnerChanged messages, then we need to create
626          * KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE} and
627          * KDBUS_MATCH_ID_{ADD,REMOVE} matches for it, possibly
628          * multiple if the match is underspecified.
629          *
630          * The NameOwnerChanged signals take three parameters with
631          * unique or well-known names, but only some forms actually
632          * exist:
633          *
634          * WELLKNOWN, "", UNIQUE       â†’ KDBUS_MATCH_NAME_ADD
635          * WELLKNOWN, UNIQUE, ""       â†’ KDBUS_MATCH_NAME_REMOVE
636          * WELLKNOWN, UNIQUE, UNIQUE   â†’ KDBUS_MATCH_NAME_CHANGE
637          * UNIQUE, "", UNIQUE          â†’ KDBUS_MATCH_ID_ADD
638          * UNIQUE, UNIQUE, ""          â†’ KDBUS_MATCH_ID_REMOVE
639          *
640          * For the latter two the two unique names must be identical.
641          *
642          * */
643
644         if (name) {
645                 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
646                 if (is_name_id < 0)
647                         return 0;
648         }
649
650         if (old_owner) {
651                 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
652                 if (r < 0)
653                         return 0;
654                 if (r == 0)
655                         return 0;
656                 if (is_name_id > 0 && old_owner_id != name_id)
657                         return 0;
658         }
659
660         if (new_owner) {
661                 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
662                 if (r < 0)
663                         return r;
664                 if (r == 0)
665                         return 0;
666                 if (is_name_id > 0 && new_owner_id != name_id)
667                         return 0;
668         }
669
670         if (is_name_id <= 0) {
671                 struct kdbus_cmd_match *m;
672                 size_t sz, l;
673
674                 /* If the name argument is missing or is a well-known
675                  * name, then add KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE}
676                  * matches for it */
677
678                 l = name ? strlen(name) : 0;
679
680                 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
681                             offsetof(struct kdbus_item, name_change) +
682                             offsetof(struct kdbus_notify_name_change, name) +
683                             l+1);
684
685                 m = alloca0(sz);
686                 m->size = sz;
687                 m->cookie = cookie;
688                 m->src_id = KDBUS_SRC_ID_KERNEL;
689
690                 item = m->items;
691                 item->size =
692                         offsetof(struct kdbus_item, name_change) +
693                         offsetof(struct kdbus_notify_name_change, name) +
694                         l+1;
695
696                 item->name_change.old_id = old_owner_id;
697                 item->name_change.new_id = new_owner_id;
698
699                 if (name)
700                         strcpy(item->name_change.name, name);
701
702                 /* If the old name is unset or empty, then
703                  * this can match against added names */
704                 if (!old_owner || old_owner[0] == 0) {
705                         item->type = KDBUS_MATCH_NAME_ADD;
706
707                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
708                         if (r < 0)
709                                 return -errno;
710                 }
711
712                 /* If the new name is unset or empty, then
713                  * this can match against removed names */
714                 if (!new_owner || new_owner[0] == 0) {
715                         item->type = KDBUS_MATCH_NAME_REMOVE;
716
717                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
718                         if (r < 0)
719                                 return -errno;
720                 }
721
722                 /* If the neither name is explicitly set to
723                  * the empty string, then this can match
724                  * agains changed names */
725                 if (!(old_owner && old_owner[0] == 0) &&
726                     !(new_owner && new_owner[0] == 0)) {
727                         item->type = KDBUS_MATCH_NAME_CHANGE;
728
729                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
730                         if (r < 0)
731                                 return -errno;
732                 }
733         }
734
735         if (is_name_id != 0) {
736                 struct kdbus_cmd_match *m;
737                 uint64_t sz;
738
739                 /* If the name argument is missing or is a unique
740                  * name, then add KDBUS_MATCH_ID_{ADD,REMOVE} matches
741                  * for it */
742
743                 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
744                             offsetof(struct kdbus_item, id_change) +
745                             sizeof(struct kdbus_notify_id_change));
746
747                 m = alloca0(sz);
748                 m->size = sz;
749                 m->cookie = cookie;
750                 m->src_id = KDBUS_SRC_ID_KERNEL;
751
752                 item = m->items;
753                 item->size = offsetof(struct kdbus_item, id_change) + sizeof(struct kdbus_notify_id_change);
754                 item->id_change.id = name_id;
755
756                 /* If the old name is unset or empty, then this can
757                  * match against added ids */
758                 if (!old_owner || old_owner[0] == 0) {
759                         item->type = KDBUS_MATCH_ID_ADD;
760
761                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
762                         if (r < 0)
763                                 return -errno;
764                 }
765
766                 /* If thew new name is unset or empty, then this can
767                 match against removed ids */
768                 if (!new_owner || new_owner[0] == 0) {
769                         item->type = KDBUS_MATCH_ID_REMOVE;
770
771                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
772                         if (r < 0)
773                                 return -errno;
774                 }
775         }
776
777         return 0;
778 }
779
780 int bus_add_match_internal(
781                 sd_bus *bus,
782                 const char *match,
783                 struct bus_match_component *components,
784                 unsigned n_components,
785                 uint64_t cookie) {
786
787         int r;
788
789         assert(bus);
790         assert(match);
791
792         if (bus->is_kernel) {
793                 struct kdbus_cmd_match *m;
794                 struct kdbus_item *item;
795                 uint64_t bloom[BLOOM_SIZE/8];
796                 size_t sz;
797                 const char *sender = NULL;
798                 size_t sender_length = 0;
799                 uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
800                 bool using_bloom = false;
801                 unsigned i;
802                 bool matches_name_change = true;
803                 const char *name_change_arg[3] = {};
804
805                 zero(bloom);
806
807                 sz = offsetof(struct kdbus_cmd_match, items);
808
809                 for (i = 0; i < n_components; i++) {
810                         struct bus_match_component *c = &components[i];
811
812                         switch (c->type) {
813
814                         case BUS_MATCH_SENDER:
815                                 if (!streq(c->value_str, "org.freedesktop.DBus"))
816                                         matches_name_change = false;
817
818                                 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
819                                 if (r < 0)
820                                         return r;
821
822                                 if (r > 0) {
823                                         sender = c->value_str;
824                                         sender_length = strlen(sender);
825                                         sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
826                                 }
827
828                                 break;
829
830                         case BUS_MATCH_MESSAGE_TYPE:
831                                 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
832                                         matches_name_change = false;
833
834                                 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
835                                 using_bloom = true;
836                                 break;
837
838                         case BUS_MATCH_INTERFACE:
839                                 if (!streq(c->value_str, "org.freedesktop.DBus"))
840                                         matches_name_change = false;
841
842                                 bloom_add_pair(bloom, "interface", c->value_str);
843                                 using_bloom = true;
844                                 break;
845
846                         case BUS_MATCH_MEMBER:
847                                 if (!streq(c->value_str, "NameOwnerChanged"))
848                                         matches_name_change = false;
849
850                                 bloom_add_pair(bloom, "member", c->value_str);
851                                 using_bloom = true;
852                                 break;
853
854                         case BUS_MATCH_PATH:
855                                 if (!streq(c->value_str, "/org/freedesktop/DBus"))
856                                         matches_name_change = false;
857
858                                 bloom_add_pair(bloom, "path", c->value_str);
859                                 using_bloom = true;
860                                 break;
861
862                         case BUS_MATCH_PATH_NAMESPACE:
863                                 if (!streq(c->value_str, "/")) {
864                                         bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
865                                         using_bloom = true;
866                                 }
867                                 break;
868
869                         case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
870                                 char buf[sizeof("arg")-1 + 2 + 1];
871
872                                 if (c->type - BUS_MATCH_ARG < 3)
873                                         name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
874
875                                 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
876                                 bloom_add_pair(bloom, buf, c->value_str);
877                                 using_bloom = true;
878                                 break;
879                         }
880
881                         case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
882                                 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
883
884                                 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
885                                 bloom_add_pair(bloom, buf, c->value_str);
886                                 using_bloom = true;
887                                 break;
888                         }
889
890                         case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
891                                 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
892
893                                 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
894                                 bloom_add_pair(bloom, buf, c->value_str);
895                                 using_bloom = true;
896                                 break;
897                         }
898
899                         case BUS_MATCH_DESTINATION:
900                                 /* The bloom filter does not include
901                                    the destination, since it is only
902                                    available for broadcast messages
903                                    which do not carry a destination
904                                    since they are undirected. */
905                                 break;
906
907                         case BUS_MATCH_ROOT:
908                         case BUS_MATCH_VALUE:
909                         case BUS_MATCH_LEAF:
910                         case _BUS_MATCH_NODE_TYPE_MAX:
911                         case _BUS_MATCH_NODE_TYPE_INVALID:
912                                 assert_not_reached("Invalid match type?");
913                         }
914                 }
915
916                 if (using_bloom)
917                         sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
918
919                 m = alloca0(sz);
920                 m->size = sz;
921                 m->cookie = cookie;
922                 m->src_id = src_id;
923
924                 item = m->items;
925
926                 if (using_bloom) {
927                         item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
928                         item->type = KDBUS_MATCH_BLOOM;
929                         memcpy(item->data64, bloom, BLOOM_SIZE);
930
931                         item = KDBUS_PART_NEXT(item);
932                 }
933
934                 if (sender) {
935                         item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
936                         item->type = KDBUS_MATCH_SRC_NAME;
937                         memcpy(item->str, sender, sender_length + 1);
938                 }
939
940                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
941                 if (r < 0)
942                         return -errno;
943
944                 if (matches_name_change) {
945
946                         /* If this match could theoretically match
947                          * NameOwnerChanged messages, we need to
948                          * install a second non-bloom filter explitly
949                          * for it */
950
951                         r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
952                         if (r < 0)
953                                 return r;
954                 }
955
956                 return 0;
957         } else
958                 return sd_bus_call_method(
959                                 bus,
960                                 "org.freedesktop.DBus",
961                                 "/",
962                                 "org.freedesktop.DBus",
963                                 "AddMatch",
964                                 NULL,
965                                 NULL,
966                                 "s",
967                                 match);
968 }
969
970 int bus_remove_match_internal(
971                 sd_bus *bus,
972                 const char *match,
973                 uint64_t cookie) {
974
975         int r;
976
977         assert(bus);
978         assert(match);
979
980         if (bus->is_kernel) {
981                 struct kdbus_cmd_match m;
982
983                 zero(m);
984                 m.size = offsetof(struct kdbus_cmd_match, items);
985                 m.cookie = cookie;
986
987                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
988                 if (r < 0)
989                         return -errno;
990
991                 return 0;
992
993         } else {
994                 return sd_bus_call_method(
995                                 bus,
996                                 "org.freedesktop.DBus",
997                                 "/",
998                                 "org.freedesktop.DBus",
999                                 "RemoveMatch",
1000                                 NULL,
1001                                 NULL,
1002                                 "s",
1003                                 match);
1004         }
1005 }
1006
1007 _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1008         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1009         const char *mid;
1010         int r;
1011
1012         assert_return(bus, -EINVAL);
1013         assert_return(name, -EINVAL);
1014         assert_return(machine, -EINVAL);
1015         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1016         assert_return(!bus_pid_changed(bus), -ECHILD);
1017
1018         if (streq_ptr(name, bus->unique_name))
1019                 return sd_id128_get_machine(machine);
1020
1021         r = sd_bus_message_new_method_call(
1022                         bus,
1023                         name,
1024                         "/",
1025                         "org.freedesktop.DBus.Peer",
1026                         "GetMachineId", &m);
1027         if (r < 0)
1028                 return r;
1029
1030         r = sd_bus_message_set_no_auto_start(m, true);
1031         if (r < 0)
1032                 return r;
1033
1034         r = sd_bus_call(bus, m, 0, NULL, &reply);
1035         if (r < 0)
1036                 return r;
1037
1038         r = sd_bus_message_read(reply, "s", &mid);
1039         if (r < 0)
1040                 return r;
1041
1042         return sd_id128_from_string(mid, machine);
1043 }