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