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