]>
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" | |
30 | ||
31 | #include "sd-bus.h" | |
32 | #include "bus-internal.h" | |
33 | #include "bus-message.h" | |
392d5b37 | 34 | #include "bus-control.h" |
c7819669 | 35 | #include "bus-bloom.h" |
40ca29a1 | 36 | #include "bus-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 | ||
d9f644e2 | 53 | _public_ int sd_bus_request_name(sd_bus *bus, const char *name, int flags) { |
d4100e24 | 54 | _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; |
de1c301e LP |
55 | uint32_t ret; |
56 | int r; | |
57 | ||
9bb058a1 LS |
58 | assert_return(bus, -EINVAL); |
59 | assert_return(name, -EINVAL); | |
60 | assert_return(bus->bus_client, -EINVAL); | |
61 | assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); | |
62 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
de1c301e | 63 | |
f08838da LP |
64 | if (bus->is_kernel) { |
65 | struct kdbus_cmd_name *n; | |
66 | size_t l; | |
67 | ||
68 | l = strlen(name); | |
ed5c5dbd | 69 | n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1); |
f08838da | 70 | n->size = offsetof(struct kdbus_cmd_name, name) + l + 1; |
3519d4c8 | 71 | kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags); |
f08838da LP |
72 | memcpy(n->name, name, l+1); |
73 | ||
75722f1d LP |
74 | #ifdef HAVE_VALGRIND_MEMCHECK_H |
75 | VALGRIND_MAKE_MEM_DEFINED(n, n->size); | |
76 | #endif | |
77 | ||
f08838da | 78 | r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n); |
ed99569d DM |
79 | if (r < 0) { |
80 | if (errno == -EALREADY) | |
81 | return SD_BUS_NAME_ALREADY_OWNER; | |
82 | ||
83 | if (errno == -EEXIST) | |
84 | return SD_BUS_NAME_EXISTS; | |
85 | ||
f08838da | 86 | return -errno; |
ed99569d DM |
87 | } |
88 | ||
89 | if (n->flags & KDBUS_NAME_IN_QUEUE) | |
90 | return SD_BUS_NAME_IN_QUEUE; | |
f08838da | 91 | |
ed99569d | 92 | return SD_BUS_NAME_PRIMARY_OWNER; |
f08838da LP |
93 | } else { |
94 | r = sd_bus_call_method( | |
95 | bus, | |
96 | "org.freedesktop.DBus", | |
97 | "/", | |
98 | "org.freedesktop.DBus", | |
99 | "RequestName", | |
100 | NULL, | |
101 | &reply, | |
102 | "su", | |
103 | name, | |
104 | flags); | |
105 | if (r < 0) | |
106 | return r; | |
107 | ||
108 | r = sd_bus_message_read(reply, "u", &ret); | |
109 | if (r < 0) | |
110 | return r; | |
111 | ||
112 | return ret; | |
113 | } | |
de1c301e LP |
114 | } |
115 | ||
d9f644e2 | 116 | _public_ int sd_bus_release_name(sd_bus *bus, const char *name) { |
d4100e24 | 117 | _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; |
de1c301e LP |
118 | uint32_t ret; |
119 | int r; | |
120 | ||
9bb058a1 LS |
121 | assert_return(bus, -EINVAL); |
122 | assert_return(name, -EINVAL); | |
123 | assert_return(bus->bus_client, -EINVAL); | |
124 | assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); | |
125 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
de1c301e | 126 | |
f08838da LP |
127 | if (bus->is_kernel) { |
128 | struct kdbus_cmd_name *n; | |
129 | size_t l; | |
130 | ||
131 | l = strlen(name); | |
ed5c5dbd | 132 | n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1); |
f08838da | 133 | n->size = offsetof(struct kdbus_cmd_name, name) + l + 1; |
f08838da LP |
134 | memcpy(n->name, name, l+1); |
135 | ||
75722f1d LP |
136 | #ifdef HAVE_VALGRIND_MEMCHECK_H |
137 | VALGRIND_MAKE_MEM_DEFINED(n, n->size); | |
138 | #endif | |
f08838da LP |
139 | r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n); |
140 | if (r < 0) | |
141 | return -errno; | |
142 | ||
9b3848f2 | 143 | return n->flags; |
f08838da LP |
144 | } else { |
145 | r = sd_bus_call_method( | |
146 | bus, | |
147 | "org.freedesktop.DBus", | |
148 | "/", | |
149 | "org.freedesktop.DBus", | |
150 | "ReleaseName", | |
151 | NULL, | |
152 | &reply, | |
153 | "s", | |
154 | name); | |
155 | if (r < 0) | |
156 | return r; | |
157 | ||
158 | r = sd_bus_message_read(reply, "u", &ret); | |
159 | if (r < 0) | |
160 | return r; | |
161 | } | |
de1c301e LP |
162 | |
163 | return ret; | |
164 | } | |
165 | ||
d9f644e2 | 166 | _public_ int sd_bus_list_names(sd_bus *bus, char ***l) { |
d4100e24 | 167 | _cleanup_bus_message_unref_ sd_bus_message *reply1 = NULL, *reply2 = NULL; |
de1c301e LP |
168 | char **x = NULL; |
169 | int r; | |
170 | ||
9bb058a1 LS |
171 | assert_return(bus, -EINVAL); |
172 | assert_return(l, -EINVAL); | |
173 | assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); | |
174 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
de1c301e | 175 | |
b1473984 | 176 | if (bus->is_kernel) { |
1d0e3c98 DM |
177 | _cleanup_free_ struct kdbus_cmd_name_list *cmd = NULL; |
178 | struct kdbus_name_list *name_list; | |
b1473984 | 179 | struct kdbus_cmd_name *name; |
de1c301e | 180 | |
1d0e3c98 DM |
181 | cmd = malloc0(sizeof(struct kdbus_cmd_name_list *)); |
182 | if (!cmd) | |
183 | return -ENOMEM; | |
b1473984 | 184 | |
1d0e3c98 | 185 | cmd->flags = KDBUS_NAME_LIST_UNIQUE_NAMES; |
b1473984 | 186 | |
1d0e3c98 DM |
187 | r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_NAME_LIST, cmd); |
188 | if (r < 0) | |
189 | return -errno; | |
b1473984 | 190 | |
1d0e3c98 | 191 | name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd->offset); |
b1473984 | 192 | |
1d0e3c98 | 193 | KDBUS_PART_FOREACH(name, name_list, names) { |
b6bd53c1 DM |
194 | char *n; |
195 | ||
196 | if (name->size > sizeof(*name)) | |
197 | n = name->name; | |
198 | else | |
199 | asprintf(&n, ":1.%llu", (unsigned long long) name->id); | |
200 | ||
201 | r = strv_extend(&x, n); | |
b1473984 DM |
202 | if (r < 0) |
203 | return -ENOMEM; | |
204 | } | |
205 | ||
1d0e3c98 DM |
206 | r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_FREE, &cmd->offset); |
207 | if (r < 0) | |
208 | return -errno; | |
209 | ||
b1473984 DM |
210 | *l = x; |
211 | } else { | |
212 | r = sd_bus_call_method( | |
213 | bus, | |
214 | "org.freedesktop.DBus", | |
215 | "/", | |
216 | "org.freedesktop.DBus", | |
217 | "ListNames", | |
218 | NULL, | |
219 | &reply1, | |
220 | NULL); | |
221 | if (r < 0) | |
222 | return r; | |
223 | ||
224 | r = sd_bus_call_method( | |
225 | bus, | |
226 | "org.freedesktop.DBus", | |
227 | "/", | |
228 | "org.freedesktop.DBus", | |
229 | "ListActivatableNames", | |
230 | NULL, | |
231 | &reply2, | |
232 | NULL); | |
233 | if (r < 0) | |
234 | return r; | |
235 | ||
236 | r = bus_message_read_strv_extend(reply1, &x); | |
237 | if (r < 0) { | |
238 | strv_free(x); | |
239 | return r; | |
240 | } | |
241 | ||
242 | r = bus_message_read_strv_extend(reply2, &x); | |
243 | if (r < 0) { | |
244 | strv_free(x); | |
245 | return r; | |
246 | } | |
247 | ||
248 | *l = strv_uniq(x); | |
89ffcd2a | 249 | } |
de1c301e | 250 | |
de1c301e LP |
251 | return 0; |
252 | } | |
253 | ||
c931748d | 254 | static int sd_bus_get_owner_dbus( |
a4297f08 LP |
255 | sd_bus *bus, |
256 | const char *name, | |
257 | uint64_t mask, | |
258 | char **owner, | |
259 | sd_bus_creds **creds) { | |
de1c301e | 260 | |
d4100e24 | 261 | _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; |
5b12334d | 262 | _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; |
a4297f08 | 263 | _cleanup_free_ char *unique = NULL; |
5b12334d | 264 | pid_t pid = 0; |
de1c301e LP |
265 | int r; |
266 | ||
a4297f08 LP |
267 | /* Only query the owner if the caller wants to know it or if |
268 | * the caller just wants to check whether a name exists */ | |
269 | if (owner || mask == 0) { | |
270 | const char *found; | |
de1c301e | 271 | |
5b12334d LP |
272 | r = sd_bus_call_method( |
273 | bus, | |
274 | "org.freedesktop.DBus", | |
275 | "/", | |
276 | "org.freedesktop.DBus", | |
a4297f08 | 277 | "GetNameOwner", |
5b12334d LP |
278 | NULL, |
279 | &reply, | |
280 | "s", | |
281 | name); | |
282 | if (r < 0) | |
283 | return r; | |
de1c301e | 284 | |
a4297f08 | 285 | r = sd_bus_message_read(reply, "s", &found); |
5b12334d LP |
286 | if (r < 0) |
287 | return r; | |
de1c301e | 288 | |
a4297f08 LP |
289 | unique = strdup(found); |
290 | if (!unique) | |
291 | return -ENOMEM; | |
de1c301e | 292 | |
5b12334d LP |
293 | reply = sd_bus_message_unref(reply); |
294 | } | |
295 | ||
a4297f08 LP |
296 | if (mask != 0) { |
297 | c = bus_creds_new(); | |
298 | if (!c) | |
299 | return -ENOMEM; | |
5b12334d | 300 | |
a4297f08 LP |
301 | if ((mask & SD_BUS_CREDS_PID) || |
302 | mask & ~(SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_SELINUX_CONTEXT)) { | |
303 | uint32_t u; | |
304 | ||
305 | r = sd_bus_call_method( | |
306 | bus, | |
307 | "org.freedesktop.DBus", | |
308 | "/", | |
309 | "org.freedesktop.DBus", | |
310 | "GetConnectionUnixProcessID", | |
311 | NULL, | |
312 | &reply, | |
313 | "s", | |
314 | name); | |
315 | if (r < 0) | |
316 | return r; | |
317 | ||
318 | r = sd_bus_message_read(reply, "u", &u); | |
319 | if (r < 0) | |
320 | return r; | |
321 | ||
322 | pid = u; | |
323 | if (mask & SD_BUS_CREDS_PID) { | |
324 | c->pid = u; | |
325 | c->mask |= SD_BUS_CREDS_PID; | |
326 | } | |
327 | ||
328 | reply = sd_bus_message_unref(reply); | |
329 | } | |
5b12334d | 330 | |
a4297f08 LP |
331 | if (mask & SD_BUS_CREDS_UID) { |
332 | uint32_t u; | |
333 | ||
334 | r = sd_bus_call_method( | |
335 | bus, | |
336 | "org.freedesktop.DBus", | |
337 | "/", | |
338 | "org.freedesktop.DBus", | |
339 | "GetConnectionUnixUser", | |
340 | NULL, | |
341 | &reply, | |
342 | "s", | |
343 | name); | |
344 | if (r < 0) | |
345 | return r; | |
346 | ||
347 | r = sd_bus_message_read(reply, "u", &u); | |
348 | if (r < 0) | |
349 | return r; | |
350 | ||
351 | c->uid = u; | |
352 | c->mask |= SD_BUS_CREDS_UID; | |
353 | ||
354 | reply = sd_bus_message_unref(reply); | |
355 | } | |
5b12334d | 356 | |
a4297f08 LP |
357 | if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) { |
358 | const void *p; | |
359 | size_t sz; | |
360 | ||
361 | r = sd_bus_call_method( | |
362 | bus, | |
363 | "org.freedesktop.DBus", | |
364 | "/", | |
365 | "org.freedesktop.DBus", | |
366 | "GetConnectionSELinuxSecurityContext", | |
367 | NULL, | |
368 | &reply, | |
369 | "s", | |
370 | name); | |
371 | if (r < 0) | |
372 | return r; | |
373 | ||
374 | r = sd_bus_message_read_array(reply, 'y', &p, &sz); | |
375 | if (r < 0) | |
376 | return r; | |
377 | ||
378 | c->label = strndup(p, sz); | |
379 | if (!c->label) | |
380 | return -ENOMEM; | |
381 | ||
382 | c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; | |
383 | } | |
5b12334d | 384 | |
a4297f08 | 385 | r = bus_creds_add_more(c, mask, pid, 0); |
5b12334d LP |
386 | if (r < 0) |
387 | return r; | |
5b12334d | 388 | } |
de1c301e | 389 | |
a4297f08 LP |
390 | if (creds) { |
391 | *creds = c; | |
392 | c = NULL; | |
393 | } | |
de1c301e | 394 | |
a4297f08 LP |
395 | if (owner) { |
396 | *owner = unique; | |
397 | unique = NULL; | |
398 | } | |
de1c301e | 399 | |
de1c301e LP |
400 | return 0; |
401 | } | |
402 | ||
777d7a61 LP |
403 | static int add_name_change_match(sd_bus *bus, |
404 | uint64_t cookie, | |
405 | const char *name, | |
406 | const char *old_owner, | |
407 | const char *new_owner) { | |
408 | ||
409 | uint64_t name_id = 0, old_owner_id = 0, new_owner_id = 0; | |
410 | int is_name_id = -1, r; | |
411 | struct kdbus_item *item; | |
412 | ||
413 | assert(bus); | |
414 | ||
415 | /* If we encounter a match that could match against | |
416 | * NameOwnerChanged messages, then we need to create | |
417 | * KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE} and | |
418 | * KDBUS_MATCH_ID_{ADD,REMOVE} matches for it, possibly | |
419 | * multiple if the match is underspecified. | |
420 | * | |
421 | * The NameOwnerChanged signals take three parameters with | |
422 | * unique or well-known names, but only some forms actually | |
423 | * exist: | |
424 | * | |
425 | * WELLKNOWN, "", UNIQUE → KDBUS_MATCH_NAME_ADD | |
426 | * WELLKNOWN, UNIQUE, "" → KDBUS_MATCH_NAME_REMOVE | |
427 | * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_MATCH_NAME_CHANGE | |
428 | * UNIQUE, "", UNIQUE → KDBUS_MATCH_ID_ADD | |
429 | * UNIQUE, UNIQUE, "" → KDBUS_MATCH_ID_REMOVE | |
430 | * | |
431 | * For the latter two the two unique names must be identical. | |
432 | * | |
433 | * */ | |
434 | ||
435 | if (name) { | |
436 | is_name_id = bus_kernel_parse_unique_name(name, &name_id); | |
437 | if (is_name_id < 0) | |
438 | return 0; | |
439 | } | |
440 | ||
441 | if (old_owner) { | |
442 | r = bus_kernel_parse_unique_name(old_owner, &old_owner_id); | |
443 | if (r < 0) | |
444 | return 0; | |
445 | if (r == 0) | |
446 | return 0; | |
447 | if (is_name_id > 0 && old_owner_id != name_id) | |
448 | return 0; | |
449 | } | |
450 | ||
451 | if (new_owner) { | |
452 | r = bus_kernel_parse_unique_name(new_owner, &new_owner_id); | |
453 | if (r < 0) | |
454 | return r; | |
455 | if (r == 0) | |
456 | return 0; | |
457 | if (is_name_id > 0 && new_owner_id != name_id) | |
458 | return 0; | |
459 | } | |
460 | ||
461 | if (is_name_id <= 0) { | |
462 | size_t sz, l; | |
463 | ||
464 | /* If the name argument is missing or is a well-known | |
465 | * name, then add KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE} | |
466 | * matches for it */ | |
467 | ||
468 | l = name ? strlen(name) : 0; | |
469 | ||
470 | sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) + | |
471 | offsetof(struct kdbus_item, name_change) + | |
472 | offsetof(struct kdbus_notify_name_change, name) + | |
473 | l+1); | |
474 | ||
475 | { | |
476 | union { | |
477 | uint8_t buffer[sz]; | |
478 | struct kdbus_cmd_match match; | |
479 | } m; | |
480 | ||
481 | memzero(&m, sz); | |
482 | ||
483 | m.match.size = sz; | |
484 | m.match.cookie = cookie; | |
485 | m.match.src_id = KDBUS_SRC_ID_KERNEL; | |
486 | ||
487 | item = m.match.items; | |
488 | item->size = | |
489 | offsetof(struct kdbus_item, name_change) + | |
490 | offsetof(struct kdbus_notify_name_change, name) + | |
491 | l+1; | |
492 | ||
493 | item->name_change.old_id = old_owner_id; | |
494 | item->name_change.new_id = new_owner_id; | |
495 | ||
496 | if (name) | |
497 | strcpy(item->name_change.name, name); | |
498 | ||
499 | /* If the old name is unset or empty, then | |
500 | * this can match against added names */ | |
501 | if (!old_owner || old_owner[0] == 0) { | |
502 | item->type = KDBUS_MATCH_NAME_ADD; | |
503 | ||
504 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); | |
505 | if (r < 0) | |
506 | return -errno; | |
507 | } | |
508 | ||
509 | /* If the new name is unset or empty, then | |
510 | * this can match against removed names */ | |
511 | if (!new_owner || new_owner[0] == 0) { | |
512 | item->type = KDBUS_MATCH_NAME_REMOVE; | |
513 | ||
514 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); | |
515 | if (r < 0) | |
516 | return -errno; | |
517 | } | |
518 | ||
519 | /* If the neither name is explicitly set to | |
520 | * the empty string, then this can match | |
521 | * agains changed names */ | |
522 | if (!(old_owner && old_owner[0] == 0) && | |
523 | !(new_owner && new_owner[0] == 0)) { | |
524 | item->type = KDBUS_MATCH_NAME_CHANGE; | |
525 | ||
526 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); | |
527 | if (r < 0) | |
528 | return -errno; | |
529 | } | |
530 | } | |
531 | } | |
532 | ||
533 | if (is_name_id != 0) { | |
534 | uint64_t sz = | |
535 | ALIGN8(offsetof(struct kdbus_cmd_match, items) + | |
c6dfb87f KS |
536 | offsetof(struct kdbus_item, id_change) + |
537 | sizeof(struct kdbus_notify_id_change)); | |
777d7a61 LP |
538 | union { |
539 | uint8_t buffer[sz]; | |
540 | struct kdbus_cmd_match match; | |
541 | } m; | |
542 | ||
543 | /* If the name argument is missing or is a unique | |
544 | * name, then add KDBUS_MATCH_ID_{ADD,REMOVE} matches | |
545 | * for it */ | |
546 | ||
547 | memzero(&m, sz); | |
548 | ||
549 | m.match.size = sz; | |
550 | m.match.cookie = cookie; | |
551 | m.match.src_id = KDBUS_SRC_ID_KERNEL; | |
552 | ||
553 | item = m.match.items; | |
554 | item->size = offsetof(struct kdbus_item, id_change) + sizeof(struct kdbus_notify_id_change); | |
555 | item->id_change.id = name_id; | |
556 | ||
557 | /* If the old name is unset or empty, then this can | |
558 | * match against added ids */ | |
559 | if (!old_owner || old_owner[0] == 0) { | |
560 | item->type = KDBUS_MATCH_ID_ADD; | |
561 | ||
562 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); | |
563 | if (r < 0) | |
564 | return -errno; | |
565 | } | |
566 | ||
567 | /* If thew new name is unset or empty, then this can | |
568 | match against removed ids */ | |
569 | if (!new_owner || new_owner[0] == 0) { | |
570 | item->type = KDBUS_MATCH_ID_REMOVE; | |
571 | ||
572 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); | |
573 | if (r < 0) | |
574 | return -errno; | |
575 | } | |
576 | } | |
577 | ||
578 | return 0; | |
579 | } | |
580 | ||
1d0e3c98 | 581 | static int kdbus_name_info( |
60189035 DM |
582 | sd_bus *bus, |
583 | const char *name, | |
584 | uint64_t mask, | |
585 | char **owner, | |
586 | sd_bus_creds **creds) { | |
587 | ||
588 | _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; | |
589 | _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; | |
1d0e3c98 | 590 | _cleanup_free_ struct kdbus_cmd_name_info *cmd = NULL; |
60189035 | 591 | _cleanup_free_ char *unique = NULL; |
1d0e3c98 | 592 | struct kdbus_name_info *name_info; |
60189035 DM |
593 | struct kdbus_item *item; |
594 | uint64_t attach_flags, m; | |
1d0e3c98 | 595 | size_t size; |
60189035 DM |
596 | int r; |
597 | ||
598 | r = kdbus_translate_attach_flags(mask, &attach_flags); | |
599 | if (r < 0) | |
600 | return r; | |
601 | ||
1d0e3c98 DM |
602 | size = sizeof(struct kdbus_cmd_name_info) + strlen(name) + 1; |
603 | cmd = malloc0(size); | |
604 | if (!cmd) | |
605 | return -ENOMEM; | |
60189035 | 606 | |
1d0e3c98 DM |
607 | cmd ->size = size; |
608 | cmd->attach_flags = attach_flags; | |
609 | strcpy(cmd->name, name); | |
60189035 | 610 | |
1d0e3c98 DM |
611 | r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_NAME_INFO, cmd); |
612 | if (r < 0) | |
613 | return -errno; | |
60189035 | 614 | |
1d0e3c98 | 615 | name_info = (struct kdbus_name_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset); |
60189035 DM |
616 | |
617 | asprintf(&unique, ":1.%llu", (unsigned long long) name_info->id); | |
618 | ||
619 | c = bus_creds_new(); | |
620 | if (!c) | |
621 | return -ENOMEM; | |
622 | ||
623 | KDBUS_PART_FOREACH(item, name_info, items) { | |
624 | switch (item->type) { | |
625 | case KDBUS_ITEM_CREDS: | |
626 | m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID | | |
627 | SD_BUS_CREDS_TID | SD_BUS_CREDS_PID_STARTTIME) & mask; | |
628 | ||
629 | if (m) { | |
630 | c->uid = item->creds.uid; | |
631 | c->pid = item->creds.pid; | |
632 | c->gid = item->creds.gid; | |
633 | c->tid = item->creds.tid; | |
634 | c->pid_starttime = item->creds.starttime; | |
635 | c->mask |= m; | |
636 | } | |
637 | break; | |
638 | ||
639 | case KDBUS_ITEM_PID_COMM: | |
640 | if (mask & SD_BUS_CREDS_COMM) { | |
641 | c->comm = strdup(item->str); | |
642 | if (!c->comm) | |
643 | return -ENOMEM; | |
644 | ||
645 | c->mask |= SD_BUS_CREDS_COMM; | |
646 | } | |
647 | break; | |
648 | ||
649 | case KDBUS_ITEM_TID_COMM: | |
650 | if (mask & SD_BUS_CREDS_TID_COMM) { | |
651 | c->tid_comm = strdup(item->str); | |
652 | if (!c->tid_comm) | |
653 | return -ENOMEM; | |
654 | ||
655 | c->mask |= SD_BUS_CREDS_TID_COMM; | |
656 | } | |
657 | break; | |
658 | ||
659 | case KDBUS_ITEM_EXE: | |
660 | if (mask & SD_BUS_CREDS_EXE) { | |
661 | c->exe = strdup(item->str); | |
662 | if (!c->exe) | |
663 | return -ENOMEM; | |
664 | ||
665 | c->mask |= SD_BUS_CREDS_EXE; | |
666 | } | |
667 | break; | |
668 | ||
669 | case KDBUS_ITEM_CMDLINE: | |
670 | if (mask & SD_BUS_CREDS_CMDLINE) { | |
671 | c->cmdline_length = item->size - KDBUS_PART_HEADER_SIZE; | |
672 | c->cmdline = memdup(item->data, c->cmdline_length); | |
673 | if (!c->cmdline) | |
674 | return -ENOMEM; | |
675 | ||
676 | c->mask |= SD_BUS_CREDS_CMDLINE; | |
677 | } | |
678 | break; | |
679 | ||
680 | case KDBUS_ITEM_CGROUP: | |
681 | m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT | | |
682 | SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE | | |
683 | SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask; | |
684 | ||
685 | if (m) { | |
686 | c->cgroup = strdup(item->str); | |
687 | if (!c->cgroup) | |
688 | return -ENOMEM; | |
689 | ||
690 | c->mask |= m; | |
691 | } | |
692 | break; | |
693 | ||
694 | case KDBUS_ITEM_CAPS: | |
695 | m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS | | |
696 | SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask; | |
697 | ||
698 | if (m) { | |
699 | c->capability_size = item->size - KDBUS_PART_HEADER_SIZE; | |
700 | c->capability = memdup(item->data, c->capability_size); | |
701 | if (!c->capability) | |
702 | return -ENOMEM; | |
703 | ||
704 | c->mask |= m; | |
705 | } | |
706 | break; | |
707 | ||
708 | case KDBUS_ITEM_SECLABEL: | |
709 | if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) { | |
710 | c->label = strdup(item->str); | |
711 | if (!c->label) | |
712 | return -ENOMEM; | |
713 | ||
714 | c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; | |
715 | } | |
716 | break; | |
717 | ||
718 | case KDBUS_ITEM_AUDIT: | |
719 | m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask; | |
720 | ||
721 | if (m) { | |
722 | c->audit_session_id = item->audit.sessionid; | |
723 | c->audit_login_uid = item->audit.loginuid; | |
724 | c->mask |= m; | |
725 | } | |
726 | break; | |
727 | } | |
728 | } | |
729 | ||
1d0e3c98 DM |
730 | r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_FREE, &cmd->offset); |
731 | if (r < 0) | |
732 | return -errno; | |
733 | ||
60189035 DM |
734 | if (creds) { |
735 | *creds = c; | |
736 | c = NULL; | |
737 | } | |
738 | ||
739 | if (owner) { | |
740 | *owner = unique; | |
741 | unique = NULL; | |
742 | } | |
743 | ||
744 | return 0; | |
745 | } | |
746 | ||
c931748d DM |
747 | _public_ int sd_bus_get_owner( |
748 | sd_bus *bus, | |
749 | const char *name, | |
750 | uint64_t mask, | |
751 | char **owner, | |
752 | sd_bus_creds **creds) { | |
753 | ||
754 | assert_return(bus, -EINVAL); | |
755 | assert_return(name, -EINVAL); | |
756 | assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP); | |
757 | assert_return(mask == 0 || creds, -EINVAL); | |
758 | assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); | |
759 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
60189035 DM |
760 | |
761 | if (bus->is_kernel) | |
1d0e3c98 | 762 | return kdbus_name_info(bus, name, mask, owner, creds); |
c931748d DM |
763 | |
764 | return sd_bus_get_owner_dbus(bus, name, mask, owner, creds); | |
765 | } | |
766 | ||
c7819669 LP |
767 | int bus_add_match_internal( |
768 | sd_bus *bus, | |
769 | const char *match, | |
770 | struct bus_match_component *components, | |
771 | unsigned n_components, | |
772 | uint64_t cookie) { | |
773 | ||
774 | int r; | |
775 | ||
392d5b37 LP |
776 | assert(bus); |
777 | assert(match); | |
de1c301e | 778 | |
c7819669 LP |
779 | if (bus->is_kernel) { |
780 | struct kdbus_cmd_match *m; | |
781 | struct kdbus_item *item; | |
782 | uint64_t bloom[BLOOM_SIZE/8]; | |
783 | size_t sz; | |
784 | const char *sender = NULL; | |
785 | size_t sender_length = 0; | |
786 | uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY; | |
787 | bool using_bloom = false; | |
788 | unsigned i; | |
777d7a61 LP |
789 | bool matches_name_change = true; |
790 | const char *name_change_arg[3] = {}; | |
c7819669 LP |
791 | |
792 | zero(bloom); | |
793 | ||
794 | sz = offsetof(struct kdbus_cmd_match, items); | |
795 | ||
796 | for (i = 0; i < n_components; i++) { | |
797 | struct bus_match_component *c = &components[i]; | |
798 | ||
799 | switch (c->type) { | |
800 | ||
801 | case BUS_MATCH_SENDER: | |
777d7a61 LP |
802 | if (!streq(c->value_str, "org.freedesktop.DBus")) |
803 | matches_name_change = false; | |
804 | ||
c7819669 LP |
805 | r = bus_kernel_parse_unique_name(c->value_str, &src_id); |
806 | if (r < 0) | |
807 | return r; | |
808 | ||
809 | if (r > 0) { | |
810 | sender = c->value_str; | |
811 | sender_length = strlen(sender); | |
812 | sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1); | |
813 | } | |
814 | ||
815 | break; | |
816 | ||
86312ab8 | 817 | case BUS_MATCH_MESSAGE_TYPE: |
777d7a61 LP |
818 | if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL) |
819 | matches_name_change = false; | |
820 | ||
86312ab8 LP |
821 | bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8)); |
822 | using_bloom = true; | |
c7819669 LP |
823 | break; |
824 | ||
825 | case BUS_MATCH_INTERFACE: | |
777d7a61 LP |
826 | if (!streq(c->value_str, "org.freedesktop.DBus")) |
827 | matches_name_change = false; | |
828 | ||
c7819669 LP |
829 | bloom_add_pair(bloom, "interface", c->value_str); |
830 | using_bloom = true; | |
831 | break; | |
832 | ||
833 | case BUS_MATCH_MEMBER: | |
777d7a61 LP |
834 | if (!streq(c->value_str, "NameOwnerChanged")) |
835 | matches_name_change = false; | |
836 | ||
c7819669 LP |
837 | bloom_add_pair(bloom, "member", c->value_str); |
838 | using_bloom = true; | |
839 | break; | |
840 | ||
841 | case BUS_MATCH_PATH: | |
777d7a61 LP |
842 | if (!streq(c->value_str, "/org/freedesktop/DBus")) |
843 | matches_name_change = false; | |
844 | ||
c7819669 LP |
845 | bloom_add_pair(bloom, "path", c->value_str); |
846 | using_bloom = true; | |
847 | break; | |
848 | ||
849 | case BUS_MATCH_PATH_NAMESPACE: | |
f11e11e3 LP |
850 | if (!streq(c->value_str, "/")) { |
851 | bloom_add_pair(bloom, "path-slash-prefix", c->value_str); | |
852 | using_bloom = true; | |
853 | } | |
c7819669 LP |
854 | break; |
855 | ||
86312ab8 LP |
856 | case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: { |
857 | char buf[sizeof("arg")-1 + 2 + 1]; | |
858 | ||
777d7a61 LP |
859 | if (c->type - BUS_MATCH_ARG < 3) |
860 | name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str; | |
861 | ||
86312ab8 LP |
862 | snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG); |
863 | bloom_add_pair(bloom, buf, c->value_str); | |
864 | using_bloom = true; | |
865 | break; | |
866 | } | |
867 | ||
868 | case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: { | |
869 | char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")]; | |
870 | ||
871 | snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH); | |
872 | bloom_add_pair(bloom, buf, c->value_str); | |
873 | using_bloom = true; | |
874 | break; | |
875 | } | |
876 | ||
877 | case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: { | |
878 | char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")]; | |
879 | ||
880 | snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE); | |
881 | bloom_add_pair(bloom, buf, c->value_str); | |
882 | using_bloom = true; | |
883 | break; | |
884 | } | |
885 | ||
886 | case BUS_MATCH_DESTINATION: | |
887 | /* The bloom filter does not include | |
888 | the destination, since it is only | |
889 | available for broadcast messages | |
890 | which do not carry a destination | |
891 | since they are undirected. */ | |
c7819669 LP |
892 | break; |
893 | ||
894 | case BUS_MATCH_ROOT: | |
895 | case BUS_MATCH_VALUE: | |
896 | case BUS_MATCH_LEAF: | |
897 | case _BUS_MATCH_NODE_TYPE_MAX: | |
898 | case _BUS_MATCH_NODE_TYPE_INVALID: | |
899 | assert_not_reached("Invalid match type?"); | |
900 | } | |
901 | } | |
902 | ||
903 | if (using_bloom) | |
904 | sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE); | |
905 | ||
906 | m = alloca0(sz); | |
907 | m->size = sz; | |
908 | m->cookie = cookie; | |
909 | m->src_id = src_id; | |
910 | ||
911 | item = m->items; | |
912 | ||
913 | if (using_bloom) { | |
914 | item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE; | |
915 | item->type = KDBUS_MATCH_BLOOM; | |
916 | memcpy(item->data64, bloom, BLOOM_SIZE); | |
917 | ||
9eb34e82 | 918 | item = KDBUS_PART_NEXT(item); |
c7819669 LP |
919 | } |
920 | ||
921 | if (sender) { | |
922 | item->size = offsetof(struct kdbus_item, str) + sender_length + 1; | |
923 | item->type = KDBUS_MATCH_SRC_NAME; | |
924 | memcpy(item->str, sender, sender_length + 1); | |
925 | } | |
926 | ||
927 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); | |
928 | if (r < 0) | |
929 | return -errno; | |
930 | ||
777d7a61 LP |
931 | if (matches_name_change) { |
932 | ||
933 | /* If this match could theoretically match | |
934 | * NameOwnerChanged messages, we need to | |
935 | * install a second non-bloom filter explitly | |
936 | * for it */ | |
937 | ||
938 | r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]); | |
939 | if (r < 0) | |
940 | return r; | |
941 | } | |
942 | ||
943 | return 0; | |
944 | } else | |
c7819669 LP |
945 | return sd_bus_call_method( |
946 | bus, | |
947 | "org.freedesktop.DBus", | |
948 | "/", | |
949 | "org.freedesktop.DBus", | |
950 | "AddMatch", | |
951 | NULL, | |
952 | NULL, | |
953 | "s", | |
954 | match); | |
de1c301e LP |
955 | } |
956 | ||
c7819669 LP |
957 | int bus_remove_match_internal( |
958 | sd_bus *bus, | |
959 | const char *match, | |
960 | uint64_t cookie) { | |
961 | ||
962 | int r; | |
963 | ||
392d5b37 LP |
964 | assert(bus); |
965 | assert(match); | |
de1c301e | 966 | |
c7819669 LP |
967 | if (bus->is_kernel) { |
968 | struct kdbus_cmd_match m; | |
969 | ||
970 | zero(m); | |
971 | m.size = offsetof(struct kdbus_cmd_match, items); | |
972 | m.cookie = cookie; | |
973 | ||
974 | r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m); | |
975 | if (r < 0) | |
976 | return -errno; | |
977 | ||
777d7a61 LP |
978 | return 0; |
979 | ||
c7819669 LP |
980 | } else { |
981 | return sd_bus_call_method( | |
982 | bus, | |
983 | "org.freedesktop.DBus", | |
984 | "/", | |
985 | "org.freedesktop.DBus", | |
986 | "RemoveMatch", | |
987 | NULL, | |
988 | NULL, | |
989 | "s", | |
990 | match); | |
991 | } | |
de1c301e | 992 | } |
70666185 | 993 | |
d9f644e2 | 994 | _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) { |
8d162091 | 995 | _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; |
70666185 LP |
996 | const char *mid; |
997 | int r; | |
998 | ||
8d162091 LP |
999 | assert_return(bus, -EINVAL); |
1000 | assert_return(name, -EINVAL); | |
1001 | assert_return(machine, -EINVAL); | |
1002 | assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); | |
1003 | assert_return(!bus_pid_changed(bus), -ECHILD); | |
70666185 LP |
1004 | |
1005 | if (streq_ptr(name, bus->unique_name)) | |
1006 | return sd_id128_get_machine(machine); | |
1007 | ||
8d162091 LP |
1008 | r = sd_bus_message_new_method_call( |
1009 | bus, | |
1010 | name, | |
1011 | "/", | |
1012 | "org.freedesktop.DBus.Peer", | |
1013 | "GetMachineId", &m); | |
1014 | if (r < 0) | |
1015 | return r; | |
1016 | ||
1017 | r = sd_bus_message_set_no_auto_start(m, true); | |
1018 | if (r < 0) | |
1019 | return r; | |
70666185 | 1020 | |
8d162091 | 1021 | r = sd_bus_call(bus, m, 0, NULL, &reply); |
70666185 LP |
1022 | if (r < 0) |
1023 | return r; | |
1024 | ||
1025 | r = sd_bus_message_read(reply, "s", &mid); | |
1026 | if (r < 0) | |
1027 | return r; | |
1028 | ||
1029 | return sd_id128_from_string(mid, machine); | |
1030 | } |