chiark / gitweb /
9e815a6c94f513096537e52da7f04ac9eb82eef8
[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_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_message_unref_ sd_bus_message *reply = NULL;
407         _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
408         struct kdbus_cmd_name_info *cmd;
409         struct kdbus_name_info *name_info;
410         struct kdbus_item *item;
411         size_t size;
412         uint64_t m, id;
413         int r;
414
415         r = bus_kernel_parse_unique_name(name, &id);
416         if (r < 0)
417                 return r;
418         if (r > 0) {
419                 size = offsetof(struct kdbus_cmd_name_info, name);
420                 cmd = alloca0(size);
421                 cmd->id = id;
422         } else {
423                 size = offsetof(struct kdbus_cmd_name_info, name) + strlen(name) + 1;
424                 cmd = alloca0(size);
425                 strcpy(cmd->name, name);
426         }
427
428         cmd->size = size;
429
430         r = kdbus_translate_attach_flags(mask, (uint64_t*) &cmd->attach_flags);
431         if (r < 0)
432                 return r;
433
434         r = ioctl(bus->input_fd, KDBUS_CMD_NAME_INFO, cmd);
435         if (r < 0)
436                 return -errno;
437
438         name_info = (struct kdbus_name_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
439
440         c = bus_creds_new();
441         if (!c)
442                 return -ENOMEM;
443
444         if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
445                 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) name_info->id) < 0)
446                         return -ENOMEM;
447
448                 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
449         }
450
451         KDBUS_PART_FOREACH(item, name_info, items) {
452
453                 switch (item->type) {
454
455                 case KDBUS_ITEM_CREDS:
456                         m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID |
457                              SD_BUS_CREDS_TID | SD_BUS_CREDS_PID_STARTTIME) & mask;
458
459                         if (m) {
460                                 c->uid = item->creds.uid;
461                                 c->pid = item->creds.pid;
462                                 c->gid = item->creds.gid;
463                                 c->tid = item->creds.tid;
464                                 c->pid_starttime = item->creds.starttime;
465                                 c->mask |= m;
466                         }
467                         break;
468
469                 case KDBUS_ITEM_PID_COMM:
470                         if (mask & SD_BUS_CREDS_COMM) {
471                                 c->comm = strdup(item->str);
472                                 if (!c->comm) {
473                                         r = -ENOMEM;
474                                         goto fail;
475                                 }
476
477                                 c->mask |= SD_BUS_CREDS_COMM;
478                         }
479                         break;
480
481                 case KDBUS_ITEM_TID_COMM:
482                         if (mask & SD_BUS_CREDS_TID_COMM) {
483                                 c->tid_comm = strdup(item->str);
484                                 if (!c->tid_comm) {
485                                         r = -ENOMEM;
486                                         goto fail;
487                                 }
488
489                                 c->mask |= SD_BUS_CREDS_TID_COMM;
490                         }
491                         break;
492
493                 case KDBUS_ITEM_EXE:
494                         if (mask & SD_BUS_CREDS_EXE) {
495                                 c->exe = strdup(item->str);
496                                 if (!c->exe) {
497                                         r = -ENOMEM;
498                                         goto fail;
499                                 }
500
501                                 c->mask |= SD_BUS_CREDS_EXE;
502                         }
503                         break;
504
505                 case KDBUS_ITEM_CMDLINE:
506                         if (mask & SD_BUS_CREDS_CMDLINE) {
507                                 c->cmdline_size = item->size - KDBUS_PART_HEADER_SIZE;
508                                 c->cmdline = memdup(item->data, c->cmdline_size);
509                                 if (!c->cmdline) {
510                                         r = -ENOMEM;
511                                         goto fail;
512                                 }
513
514                                 c->mask |= SD_BUS_CREDS_CMDLINE;
515                         }
516                         break;
517
518                 case KDBUS_ITEM_CGROUP:
519                         m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
520                              SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
521                              SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
522
523                         if (m) {
524                                 c->cgroup = strdup(item->str);
525                                 if (!c->cgroup) {
526                                         r = -ENOMEM;
527                                         goto fail;
528                                 }
529
530                                 c->mask |= m;
531                         }
532                         break;
533
534                 case KDBUS_ITEM_CAPS:
535                         m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
536                              SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
537
538                         if (m) {
539                                 c->capability_size = item->size - KDBUS_PART_HEADER_SIZE;
540                                 c->capability = memdup(item->data, c->capability_size);
541                                 if (!c->capability) {
542                                         r = -ENOMEM;
543                                         goto fail;
544                                 }
545
546                                 c->mask |= m;
547                         }
548                         break;
549
550                 case KDBUS_ITEM_SECLABEL:
551                         if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
552                                 c->label = strdup(item->str);
553                                 if (!c->label) {
554                                         r = -ENOMEM;
555                                         goto fail;
556                                 }
557
558                                 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
559                         }
560                         break;
561
562                 case KDBUS_ITEM_AUDIT:
563                         m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask;
564
565                         if (m) {
566                                 c->audit_session_id = item->audit.sessionid;
567                                 c->audit_login_uid = item->audit.loginuid;
568                                 c->mask |= m;
569                         }
570                         break;
571
572                 case KDBUS_ITEM_NAMES:
573                         if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
574                                 c->well_known_names_size = item->size - KDBUS_PART_HEADER_SIZE;
575                                 c->well_known_names = memdup(item->data, c->well_known_names_size);
576                                 if (!c->well_known_names) {
577                                         r = -ENOMEM;
578                                         goto fail;
579                                 }
580
581                                 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
582                         }
583                         break;
584                 }
585         }
586
587         if (creds) {
588                 *creds = c;
589                 c = NULL;
590         }
591
592         r = 0;
593
594 fail:
595         ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd->offset);
596         return r;
597 }
598
599 _public_ int sd_bus_get_owner(
600                 sd_bus *bus,
601                 const char *name,
602                 uint64_t mask,
603                 sd_bus_creds **creds) {
604
605         assert_return(bus, -EINVAL);
606         assert_return(name, -EINVAL);
607         assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
608         assert_return(mask == 0 || creds, -EINVAL);
609         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
610         assert_return(!bus_pid_changed(bus), -ECHILD);
611
612         if (bus->is_kernel)
613                 return bus_get_owner_kdbus(bus, name, mask, creds);
614         else
615                 return bus_get_owner_dbus(bus, name, mask, creds);
616 }
617
618 static int add_name_change_match(sd_bus *bus,
619                                  uint64_t cookie,
620                                  const char *name,
621                                  const char *old_owner,
622                                  const char *new_owner) {
623
624         uint64_t name_id = 0, old_owner_id = 0, new_owner_id = 0;
625         int is_name_id = -1, r;
626         struct kdbus_item *item;
627
628         assert(bus);
629
630         /* If we encounter a match that could match against
631          * NameOwnerChanged messages, then we need to create
632          * KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE} and
633          * KDBUS_MATCH_ID_{ADD,REMOVE} matches for it, possibly
634          * multiple if the match is underspecified.
635          *
636          * The NameOwnerChanged signals take three parameters with
637          * unique or well-known names, but only some forms actually
638          * exist:
639          *
640          * WELLKNOWN, "", UNIQUE       → KDBUS_MATCH_NAME_ADD
641          * WELLKNOWN, UNIQUE, ""       → KDBUS_MATCH_NAME_REMOVE
642          * WELLKNOWN, UNIQUE, UNIQUE   → KDBUS_MATCH_NAME_CHANGE
643          * UNIQUE, "", UNIQUE          → KDBUS_MATCH_ID_ADD
644          * UNIQUE, UNIQUE, ""          → KDBUS_MATCH_ID_REMOVE
645          *
646          * For the latter two the two unique names must be identical.
647          *
648          * */
649
650         if (name) {
651                 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
652                 if (is_name_id < 0)
653                         return 0;
654         }
655
656         if (old_owner) {
657                 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
658                 if (r < 0)
659                         return 0;
660                 if (r == 0)
661                         return 0;
662                 if (is_name_id > 0 && old_owner_id != name_id)
663                         return 0;
664         }
665
666         if (new_owner) {
667                 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
668                 if (r < 0)
669                         return r;
670                 if (r == 0)
671                         return 0;
672                 if (is_name_id > 0 && new_owner_id != name_id)
673                         return 0;
674         }
675
676         if (is_name_id <= 0) {
677                 size_t sz, l;
678
679                 /* If the name argument is missing or is a well-known
680                  * name, then add KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE}
681                  * matches for it */
682
683                 l = name ? strlen(name) : 0;
684
685                 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
686                             offsetof(struct kdbus_item, name_change) +
687                             offsetof(struct kdbus_notify_name_change, name) +
688                             l+1);
689
690                 {
691                         union {
692                                 uint8_t buffer[sz];
693                                 struct kdbus_cmd_match match;
694                         } m;
695
696                         memzero(&m, sz);
697
698                         m.match.size = sz;
699                         m.match.cookie = cookie;
700                         m.match.src_id = KDBUS_SRC_ID_KERNEL;
701
702                         item = m.match.items;
703                         item->size =
704                                 offsetof(struct kdbus_item, name_change) +
705                                 offsetof(struct kdbus_notify_name_change, name) +
706                                 l+1;
707
708                         item->name_change.old_id = old_owner_id;
709                         item->name_change.new_id = new_owner_id;
710
711                         if (name)
712                                 strcpy(item->name_change.name, name);
713
714                         /* If the old name is unset or empty, then
715                          * this can match against added names */
716                         if (!old_owner || old_owner[0] == 0) {
717                                 item->type = KDBUS_MATCH_NAME_ADD;
718
719                                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
720                                 if (r < 0)
721                                         return -errno;
722                         }
723
724                         /* If the new name is unset or empty, then
725                          * this can match against removed names */
726                         if (!new_owner || new_owner[0] == 0) {
727                                 item->type = KDBUS_MATCH_NAME_REMOVE;
728
729                                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
730                                 if (r < 0)
731                                         return -errno;
732                         }
733
734                         /* If the neither name is explicitly set to
735                          * the empty string, then this can match
736                          * agains changed names */
737                         if (!(old_owner && old_owner[0] == 0) &&
738                             !(new_owner && new_owner[0] == 0)) {
739                                 item->type = KDBUS_MATCH_NAME_CHANGE;
740
741                                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
742                                 if (r < 0)
743                                         return -errno;
744                         }
745                 }
746         }
747
748         if (is_name_id != 0) {
749                 uint64_t sz =
750                         ALIGN8(offsetof(struct kdbus_cmd_match, items) +
751                                offsetof(struct kdbus_item, id_change) +
752                                sizeof(struct kdbus_notify_id_change));
753                 union {
754                         uint8_t buffer[sz];
755                         struct kdbus_cmd_match match;
756                 } m;
757
758                 /* If the name argument is missing or is a unique
759                  * name, then add KDBUS_MATCH_ID_{ADD,REMOVE} matches
760                  * for it */
761
762                 memzero(&m, sz);
763
764                 m.match.size = sz;
765                 m.match.cookie = cookie;
766                 m.match.src_id = KDBUS_SRC_ID_KERNEL;
767
768                 item = m.match.items;
769                 item->size = offsetof(struct kdbus_item, id_change) + sizeof(struct kdbus_notify_id_change);
770                 item->id_change.id = name_id;
771
772                 /* If the old name is unset or empty, then this can
773                  * match against added ids */
774                 if (!old_owner || old_owner[0] == 0) {
775                         item->type = KDBUS_MATCH_ID_ADD;
776
777                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
778                         if (r < 0)
779                                 return -errno;
780                 }
781
782                 /* If thew new name is unset or empty, then this can
783                 match against removed ids */
784                 if (!new_owner || new_owner[0] == 0) {
785                         item->type = KDBUS_MATCH_ID_REMOVE;
786
787                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
788                         if (r < 0)
789                                 return -errno;
790                 }
791         }
792
793         return 0;
794 }
795
796 int bus_add_match_internal(
797                 sd_bus *bus,
798                 const char *match,
799                 struct bus_match_component *components,
800                 unsigned n_components,
801                 uint64_t cookie) {
802
803         int r;
804
805         assert(bus);
806         assert(match);
807
808         if (bus->is_kernel) {
809                 struct kdbus_cmd_match *m;
810                 struct kdbus_item *item;
811                 uint64_t bloom[BLOOM_SIZE/8];
812                 size_t sz;
813                 const char *sender = NULL;
814                 size_t sender_length = 0;
815                 uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
816                 bool using_bloom = false;
817                 unsigned i;
818                 bool matches_name_change = true;
819                 const char *name_change_arg[3] = {};
820
821                 zero(bloom);
822
823                 sz = offsetof(struct kdbus_cmd_match, items);
824
825                 for (i = 0; i < n_components; i++) {
826                         struct bus_match_component *c = &components[i];
827
828                         switch (c->type) {
829
830                         case BUS_MATCH_SENDER:
831                                 if (!streq(c->value_str, "org.freedesktop.DBus"))
832                                         matches_name_change = false;
833
834                                 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
835                                 if (r < 0)
836                                         return r;
837
838                                 if (r > 0) {
839                                         sender = c->value_str;
840                                         sender_length = strlen(sender);
841                                         sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
842                                 }
843
844                                 break;
845
846                         case BUS_MATCH_MESSAGE_TYPE:
847                                 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
848                                         matches_name_change = false;
849
850                                 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
851                                 using_bloom = true;
852                                 break;
853
854                         case BUS_MATCH_INTERFACE:
855                                 if (!streq(c->value_str, "org.freedesktop.DBus"))
856                                         matches_name_change = false;
857
858                                 bloom_add_pair(bloom, "interface", c->value_str);
859                                 using_bloom = true;
860                                 break;
861
862                         case BUS_MATCH_MEMBER:
863                                 if (!streq(c->value_str, "NameOwnerChanged"))
864                                         matches_name_change = false;
865
866                                 bloom_add_pair(bloom, "member", c->value_str);
867                                 using_bloom = true;
868                                 break;
869
870                         case BUS_MATCH_PATH:
871                                 if (!streq(c->value_str, "/org/freedesktop/DBus"))
872                                         matches_name_change = false;
873
874                                 bloom_add_pair(bloom, "path", c->value_str);
875                                 using_bloom = true;
876                                 break;
877
878                         case BUS_MATCH_PATH_NAMESPACE:
879                                 if (!streq(c->value_str, "/")) {
880                                         bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
881                                         using_bloom = true;
882                                 }
883                                 break;
884
885                         case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
886                                 char buf[sizeof("arg")-1 + 2 + 1];
887
888                                 if (c->type - BUS_MATCH_ARG < 3)
889                                         name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
890
891                                 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
892                                 bloom_add_pair(bloom, buf, c->value_str);
893                                 using_bloom = true;
894                                 break;
895                         }
896
897                         case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
898                                 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
899
900                                 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
901                                 bloom_add_pair(bloom, buf, c->value_str);
902                                 using_bloom = true;
903                                 break;
904                         }
905
906                         case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
907                                 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
908
909                                 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
910                                 bloom_add_pair(bloom, buf, c->value_str);
911                                 using_bloom = true;
912                                 break;
913                         }
914
915                         case BUS_MATCH_DESTINATION:
916                                 /* The bloom filter does not include
917                                    the destination, since it is only
918                                    available for broadcast messages
919                                    which do not carry a destination
920                                    since they are undirected. */
921                                 break;
922
923                         case BUS_MATCH_ROOT:
924                         case BUS_MATCH_VALUE:
925                         case BUS_MATCH_LEAF:
926                         case _BUS_MATCH_NODE_TYPE_MAX:
927                         case _BUS_MATCH_NODE_TYPE_INVALID:
928                                 assert_not_reached("Invalid match type?");
929                         }
930                 }
931
932                 if (using_bloom)
933                         sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
934
935                 m = alloca0(sz);
936                 m->size = sz;
937                 m->cookie = cookie;
938                 m->src_id = src_id;
939
940                 item = m->items;
941
942                 if (using_bloom) {
943                         item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
944                         item->type = KDBUS_MATCH_BLOOM;
945                         memcpy(item->data64, bloom, BLOOM_SIZE);
946
947                         item = KDBUS_PART_NEXT(item);
948                 }
949
950                 if (sender) {
951                         item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
952                         item->type = KDBUS_MATCH_SRC_NAME;
953                         memcpy(item->str, sender, sender_length + 1);
954                 }
955
956                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
957                 if (r < 0)
958                         return -errno;
959
960                 if (matches_name_change) {
961
962                         /* If this match could theoretically match
963                          * NameOwnerChanged messages, we need to
964                          * install a second non-bloom filter explitly
965                          * for it */
966
967                         r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
968                         if (r < 0)
969                                 return r;
970                 }
971
972                 return 0;
973         } else
974                 return sd_bus_call_method(
975                                 bus,
976                                 "org.freedesktop.DBus",
977                                 "/",
978                                 "org.freedesktop.DBus",
979                                 "AddMatch",
980                                 NULL,
981                                 NULL,
982                                 "s",
983                                 match);
984 }
985
986 int bus_remove_match_internal(
987                 sd_bus *bus,
988                 const char *match,
989                 uint64_t cookie) {
990
991         int r;
992
993         assert(bus);
994         assert(match);
995
996         if (bus->is_kernel) {
997                 struct kdbus_cmd_match m;
998
999                 zero(m);
1000                 m.size = offsetof(struct kdbus_cmd_match, items);
1001                 m.cookie = cookie;
1002
1003                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1004                 if (r < 0)
1005                         return -errno;
1006
1007                 return 0;
1008
1009         } else {
1010                 return sd_bus_call_method(
1011                                 bus,
1012                                 "org.freedesktop.DBus",
1013                                 "/",
1014                                 "org.freedesktop.DBus",
1015                                 "RemoveMatch",
1016                                 NULL,
1017                                 NULL,
1018                                 "s",
1019                                 match);
1020         }
1021 }
1022
1023 _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1024         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1025         const char *mid;
1026         int r;
1027
1028         assert_return(bus, -EINVAL);
1029         assert_return(name, -EINVAL);
1030         assert_return(machine, -EINVAL);
1031         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1032         assert_return(!bus_pid_changed(bus), -ECHILD);
1033
1034         if (streq_ptr(name, bus->unique_name))
1035                 return sd_id128_get_machine(machine);
1036
1037         r = sd_bus_message_new_method_call(
1038                         bus,
1039                         name,
1040                         "/",
1041                         "org.freedesktop.DBus.Peer",
1042                         "GetMachineId", &m);
1043         if (r < 0)
1044                 return r;
1045
1046         r = sd_bus_message_set_no_auto_start(m, true);
1047         if (r < 0)
1048                 return r;
1049
1050         r = sd_bus_call(bus, m, 0, NULL, &reply);
1051         if (r < 0)
1052                 return r;
1053
1054         r = sd_bus_message_read(reply, "s", &mid);
1055         if (r < 0)
1056                 return r;
1057
1058         return sd_id128_from_string(mid, machine);
1059 }