chiark / gitweb /
bus: bus_open_user_systemd() fall back to bus if runtime dir is not set
[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_creds_unref_ sd_bus_creds *c = NULL;
407         struct kdbus_cmd_name_info *cmd;
408         struct kdbus_name_info *name_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_name_info, name);
419                 cmd = alloca0(size);
420                 cmd->id = id;
421         } else {
422                 size = offsetof(struct kdbus_cmd_name_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_NAME_INFO, cmd);
429         if (r < 0)
430                 return -errno;
431
432         name_info = (struct kdbus_name_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) name_info->id) < 0)
440                         return -ENOMEM;
441
442                 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
443         }
444
445         KDBUS_PART_FOREACH(item, name_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_MAX, -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                 size_t sz, l;
672
673                 /* If the name argument is missing or is a well-known
674                  * name, then add KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE}
675                  * matches for it */
676
677                 l = name ? strlen(name) : 0;
678
679                 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
680                             offsetof(struct kdbus_item, name_change) +
681                             offsetof(struct kdbus_notify_name_change, name) +
682                             l+1);
683
684                 {
685                         union {
686                                 uint8_t buffer[sz];
687                                 struct kdbus_cmd_match match;
688                         } m;
689
690                         memzero(&m, sz);
691
692                         m.match.size = sz;
693                         m.match.cookie = cookie;
694                         m.match.src_id = KDBUS_SRC_ID_KERNEL;
695
696                         item = m.match.items;
697                         item->size =
698                                 offsetof(struct kdbus_item, name_change) +
699                                 offsetof(struct kdbus_notify_name_change, name) +
700                                 l+1;
701
702                         item->name_change.old_id = old_owner_id;
703                         item->name_change.new_id = new_owner_id;
704
705                         if (name)
706                                 strcpy(item->name_change.name, name);
707
708                         /* If the old name is unset or empty, then
709                          * this can match against added names */
710                         if (!old_owner || old_owner[0] == 0) {
711                                 item->type = KDBUS_MATCH_NAME_ADD;
712
713                                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
714                                 if (r < 0)
715                                         return -errno;
716                         }
717
718                         /* If the new name is unset or empty, then
719                          * this can match against removed names */
720                         if (!new_owner || new_owner[0] == 0) {
721                                 item->type = KDBUS_MATCH_NAME_REMOVE;
722
723                                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
724                                 if (r < 0)
725                                         return -errno;
726                         }
727
728                         /* If the neither name is explicitly set to
729                          * the empty string, then this can match
730                          * agains changed names */
731                         if (!(old_owner && old_owner[0] == 0) &&
732                             !(new_owner && new_owner[0] == 0)) {
733                                 item->type = KDBUS_MATCH_NAME_CHANGE;
734
735                                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
736                                 if (r < 0)
737                                         return -errno;
738                         }
739                 }
740         }
741
742         if (is_name_id != 0) {
743                 uint64_t sz =
744                         ALIGN8(offsetof(struct kdbus_cmd_match, items) +
745                                offsetof(struct kdbus_item, id_change) +
746                                sizeof(struct kdbus_notify_id_change));
747                 union {
748                         uint8_t buffer[sz];
749                         struct kdbus_cmd_match match;
750                 } m;
751
752                 /* If the name argument is missing or is a unique
753                  * name, then add KDBUS_MATCH_ID_{ADD,REMOVE} matches
754                  * for it */
755
756                 memzero(&m, sz);
757
758                 m.match.size = sz;
759                 m.match.cookie = cookie;
760                 m.match.src_id = KDBUS_SRC_ID_KERNEL;
761
762                 item = m.match.items;
763                 item->size = offsetof(struct kdbus_item, id_change) + sizeof(struct kdbus_notify_id_change);
764                 item->id_change.id = name_id;
765
766                 /* If the old name is unset or empty, then this can
767                  * match against added ids */
768                 if (!old_owner || old_owner[0] == 0) {
769                         item->type = KDBUS_MATCH_ID_ADD;
770
771                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
772                         if (r < 0)
773                                 return -errno;
774                 }
775
776                 /* If thew new name is unset or empty, then this can
777                 match against removed ids */
778                 if (!new_owner || new_owner[0] == 0) {
779                         item->type = KDBUS_MATCH_ID_REMOVE;
780
781                         r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
782                         if (r < 0)
783                                 return -errno;
784                 }
785         }
786
787         return 0;
788 }
789
790 int bus_add_match_internal(
791                 sd_bus *bus,
792                 const char *match,
793                 struct bus_match_component *components,
794                 unsigned n_components,
795                 uint64_t cookie) {
796
797         int r;
798
799         assert(bus);
800         assert(match);
801
802         if (bus->is_kernel) {
803                 struct kdbus_cmd_match *m;
804                 struct kdbus_item *item;
805                 uint64_t bloom[BLOOM_SIZE/8];
806                 size_t sz;
807                 const char *sender = NULL;
808                 size_t sender_length = 0;
809                 uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
810                 bool using_bloom = false;
811                 unsigned i;
812                 bool matches_name_change = true;
813                 const char *name_change_arg[3] = {};
814
815                 zero(bloom);
816
817                 sz = offsetof(struct kdbus_cmd_match, items);
818
819                 for (i = 0; i < n_components; i++) {
820                         struct bus_match_component *c = &components[i];
821
822                         switch (c->type) {
823
824                         case BUS_MATCH_SENDER:
825                                 if (!streq(c->value_str, "org.freedesktop.DBus"))
826                                         matches_name_change = false;
827
828                                 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
829                                 if (r < 0)
830                                         return r;
831
832                                 if (r > 0) {
833                                         sender = c->value_str;
834                                         sender_length = strlen(sender);
835                                         sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
836                                 }
837
838                                 break;
839
840                         case BUS_MATCH_MESSAGE_TYPE:
841                                 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
842                                         matches_name_change = false;
843
844                                 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
845                                 using_bloom = true;
846                                 break;
847
848                         case BUS_MATCH_INTERFACE:
849                                 if (!streq(c->value_str, "org.freedesktop.DBus"))
850                                         matches_name_change = false;
851
852                                 bloom_add_pair(bloom, "interface", c->value_str);
853                                 using_bloom = true;
854                                 break;
855
856                         case BUS_MATCH_MEMBER:
857                                 if (!streq(c->value_str, "NameOwnerChanged"))
858                                         matches_name_change = false;
859
860                                 bloom_add_pair(bloom, "member", c->value_str);
861                                 using_bloom = true;
862                                 break;
863
864                         case BUS_MATCH_PATH:
865                                 if (!streq(c->value_str, "/org/freedesktop/DBus"))
866                                         matches_name_change = false;
867
868                                 bloom_add_pair(bloom, "path", c->value_str);
869                                 using_bloom = true;
870                                 break;
871
872                         case BUS_MATCH_PATH_NAMESPACE:
873                                 if (!streq(c->value_str, "/")) {
874                                         bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
875                                         using_bloom = true;
876                                 }
877                                 break;
878
879                         case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
880                                 char buf[sizeof("arg")-1 + 2 + 1];
881
882                                 if (c->type - BUS_MATCH_ARG < 3)
883                                         name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
884
885                                 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
886                                 bloom_add_pair(bloom, buf, c->value_str);
887                                 using_bloom = true;
888                                 break;
889                         }
890
891                         case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
892                                 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
893
894                                 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
895                                 bloom_add_pair(bloom, buf, c->value_str);
896                                 using_bloom = true;
897                                 break;
898                         }
899
900                         case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
901                                 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
902
903                                 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
904                                 bloom_add_pair(bloom, buf, c->value_str);
905                                 using_bloom = true;
906                                 break;
907                         }
908
909                         case BUS_MATCH_DESTINATION:
910                                 /* The bloom filter does not include
911                                    the destination, since it is only
912                                    available for broadcast messages
913                                    which do not carry a destination
914                                    since they are undirected. */
915                                 break;
916
917                         case BUS_MATCH_ROOT:
918                         case BUS_MATCH_VALUE:
919                         case BUS_MATCH_LEAF:
920                         case _BUS_MATCH_NODE_TYPE_MAX:
921                         case _BUS_MATCH_NODE_TYPE_INVALID:
922                                 assert_not_reached("Invalid match type?");
923                         }
924                 }
925
926                 if (using_bloom)
927                         sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
928
929                 m = alloca0(sz);
930                 m->size = sz;
931                 m->cookie = cookie;
932                 m->src_id = src_id;
933
934                 item = m->items;
935
936                 if (using_bloom) {
937                         item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
938                         item->type = KDBUS_MATCH_BLOOM;
939                         memcpy(item->data64, bloom, BLOOM_SIZE);
940
941                         item = KDBUS_PART_NEXT(item);
942                 }
943
944                 if (sender) {
945                         item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
946                         item->type = KDBUS_MATCH_SRC_NAME;
947                         memcpy(item->str, sender, sender_length + 1);
948                 }
949
950                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
951                 if (r < 0)
952                         return -errno;
953
954                 if (matches_name_change) {
955
956                         /* If this match could theoretically match
957                          * NameOwnerChanged messages, we need to
958                          * install a second non-bloom filter explitly
959                          * for it */
960
961                         r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
962                         if (r < 0)
963                                 return r;
964                 }
965
966                 return 0;
967         } else
968                 return sd_bus_call_method(
969                                 bus,
970                                 "org.freedesktop.DBus",
971                                 "/",
972                                 "org.freedesktop.DBus",
973                                 "AddMatch",
974                                 NULL,
975                                 NULL,
976                                 "s",
977                                 match);
978 }
979
980 int bus_remove_match_internal(
981                 sd_bus *bus,
982                 const char *match,
983                 uint64_t cookie) {
984
985         int r;
986
987         assert(bus);
988         assert(match);
989
990         if (bus->is_kernel) {
991                 struct kdbus_cmd_match m;
992
993                 zero(m);
994                 m.size = offsetof(struct kdbus_cmd_match, items);
995                 m.cookie = cookie;
996
997                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
998                 if (r < 0)
999                         return -errno;
1000
1001                 return 0;
1002
1003         } else {
1004                 return sd_bus_call_method(
1005                                 bus,
1006                                 "org.freedesktop.DBus",
1007                                 "/",
1008                                 "org.freedesktop.DBus",
1009                                 "RemoveMatch",
1010                                 NULL,
1011                                 NULL,
1012                                 "s",
1013                                 match);
1014         }
1015 }
1016
1017 _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1018         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1019         const char *mid;
1020         int r;
1021
1022         assert_return(bus, -EINVAL);
1023         assert_return(name, -EINVAL);
1024         assert_return(machine, -EINVAL);
1025         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1026         assert_return(!bus_pid_changed(bus), -ECHILD);
1027
1028         if (streq_ptr(name, bus->unique_name))
1029                 return sd_id128_get_machine(machine);
1030
1031         r = sd_bus_message_new_method_call(
1032                         bus,
1033                         name,
1034                         "/",
1035                         "org.freedesktop.DBus.Peer",
1036                         "GetMachineId", &m);
1037         if (r < 0)
1038                 return r;
1039
1040         r = sd_bus_message_set_no_auto_start(m, true);
1041         if (r < 0)
1042                 return r;
1043
1044         r = sd_bus_call(bus, m, 0, NULL, &reply);
1045         if (r < 0)
1046                 return r;
1047
1048         r = sd_bus_message_read(reply, "s", &mid);
1049         if (r < 0)
1050                 return r;
1051
1052         return sd_id128_from_string(mid, machine);
1053 }