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