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