]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-creds.c
sd-bus: when bus operations are to be executed on direct connections always fail
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-creds.c
CommitLineData
5b12334d
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
22#include <stdlib.h>
7d9fcc2b 23#include <linux/capability.h>
5b12334d
LP
24
25#include "util.h"
6482f626 26#include "formats-util.h"
0b452006 27#include "process-util.h"
34a5d5e5 28#include "capability.h"
5b12334d
LP
29#include "cgroup-util.h"
30#include "fileio.h"
31#include "audit.h"
32#include "bus-message.h"
33#include "bus-util.h"
49b832c5 34#include "strv.h"
5b12334d 35#include "bus-creds.h"
a6278b88 36#include "bus-label.h"
5b12334d
LP
37
38enum {
39 CAP_OFFSET_INHERITABLE = 0,
40 CAP_OFFSET_PERMITTED = 1,
41 CAP_OFFSET_EFFECTIVE = 2,
42 CAP_OFFSET_BOUNDING = 3
43};
44
45void bus_creds_done(sd_bus_creds *c) {
46 assert(c);
47
48 /* For internal bus cred structures that are allocated by
49 * something else */
50
51 free(c->session);
52 free(c->unit);
53 free(c->user_unit);
54 free(c->slice);
455971c1 55 free(c->unescaped_description);
606303a9 56 free(c->supplementary_gids);
5b12334d 57
50c45216
LP
58 free(c->well_known_names); /* note that this is an strv, but
59 * we only free the array, not the
60 * strings the array points to. The
61 * full strv we only free if
62 * c->allocated is set, see
63 * below. */
64
49b832c5 65 strv_free(c->cmdline_array);
5b12334d
LP
66}
67
68_public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
69 assert_return(c, NULL);
70
71 if (c->allocated) {
72 assert(c->n_ref > 0);
73 c->n_ref++;
74 } else {
75 sd_bus_message *m;
76
77 /* If this is an embedded creds structure, then
78 * forward ref counting to the message */
79 m = container_of(c, sd_bus_message, creds);
80 sd_bus_message_ref(m);
81 }
82
83 return c;
84}
85
86_public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
5b1bc83f
LP
87
88 if (!c)
89 return NULL;
5b12334d
LP
90
91 if (c->allocated) {
92 assert(c->n_ref > 0);
93 c->n_ref--;
94
95 if (c->n_ref == 0) {
5b12334d
LP
96 free(c->comm);
97 free(c->tid_comm);
98 free(c->exe);
99 free(c->cmdline);
100 free(c->cgroup);
101 free(c->capability);
102 free(c->label);
49b832c5 103 free(c->unique_name);
751bc6ac 104 free(c->cgroup_root);
455971c1 105 free(c->description);
606303a9 106
e12d81ae 107 free(c->supplementary_gids);
606303a9 108 c->supplementary_gids = NULL;
50c45216
LP
109
110 strv_free(c->well_known_names);
111 c->well_known_names = NULL;
112
113 bus_creds_done(c);
114
5b12334d
LP
115 free(c);
116 }
117 } else {
118 sd_bus_message *m;
119
120 m = container_of(c, sd_bus_message, creds);
121 sd_bus_message_unref(m);
122 }
123
124
125 return NULL;
126}
127
4cf8496d 128_public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
5b12334d
LP
129 assert_return(c, 0);
130
131 return c->mask;
132}
133
0f514420
LP
134_public_ uint64_t sd_bus_creds_get_augmented_mask(const sd_bus_creds *c) {
135 assert_return(c, 0);
136
137 return c->augmented;
138}
139
5b12334d
LP
140sd_bus_creds* bus_creds_new(void) {
141 sd_bus_creds *c;
142
143 c = new0(sd_bus_creds, 1);
144 if (!c)
145 return NULL;
146
147 c->allocated = true;
148 c->n_ref = 1;
149 return c;
150}
151
151b9b96 152_public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
5b12334d
LP
153 sd_bus_creds *c;
154 int r;
155
156 assert_return(pid >= 0, -EINVAL);
15411c0c 157 assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
5b12334d
LP
158 assert_return(ret, -EINVAL);
159
160 if (pid == 0)
161 pid = getpid();
162
163 c = bus_creds_new();
164 if (!c)
165 return -ENOMEM;
166
705a415f 167 r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pid, 0);
5b12334d 168 if (r < 0) {
0349c608 169 sd_bus_creds_unref(c);
5b12334d
LP
170 return r;
171 }
172
173 /* Check if the process existed at all, in case we haven't
174 * figured that out already */
9f5650ae 175 if (!pid_is_alive(pid)) {
5b12334d
LP
176 sd_bus_creds_unref(c);
177 return -ESRCH;
178 }
179
180 *ret = c;
181 return 0;
182}
183
184_public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
185 assert_return(c, -EINVAL);
186 assert_return(uid, -EINVAL);
6a4abbc8
LP
187
188 if (!(c->mask & SD_BUS_CREDS_UID))
189 return -ENODATA;
5b12334d
LP
190
191 *uid = c->uid;
192 return 0;
193}
194
705a415f
LP
195_public_ int sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *euid) {
196 assert_return(c, -EINVAL);
197 assert_return(euid, -EINVAL);
198
199 if (!(c->mask & SD_BUS_CREDS_EUID))
200 return -ENODATA;
201
202 *euid = c->euid;
203 return 0;
204}
205
206_public_ int sd_bus_creds_get_suid(sd_bus_creds *c, uid_t *suid) {
207 assert_return(c, -EINVAL);
208 assert_return(suid, -EINVAL);
209
210 if (!(c->mask & SD_BUS_CREDS_SUID))
211 return -ENODATA;
212
213 *suid = c->suid;
214 return 0;
215}
216
217
218_public_ int sd_bus_creds_get_fsuid(sd_bus_creds *c, uid_t *fsuid) {
219 assert_return(c, -EINVAL);
220 assert_return(fsuid, -EINVAL);
221
222 if (!(c->mask & SD_BUS_CREDS_FSUID))
223 return -ENODATA;
224
225 *fsuid = c->fsuid;
226 return 0;
227}
228
5b12334d
LP
229_public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
230 assert_return(c, -EINVAL);
231 assert_return(gid, -EINVAL);
6a4abbc8 232
1c021669 233 if (!(c->mask & SD_BUS_CREDS_GID))
6a4abbc8 234 return -ENODATA;
5b12334d
LP
235
236 *gid = c->gid;
237 return 0;
238}
239
705a415f
LP
240_public_ int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) {
241 assert_return(c, -EINVAL);
242 assert_return(egid, -EINVAL);
243
244 if (!(c->mask & SD_BUS_CREDS_EGID))
245 return -ENODATA;
246
247 *egid = c->egid;
248 return 0;
249}
250
251_public_ int sd_bus_creds_get_sgid(sd_bus_creds *c, gid_t *sgid) {
252 assert_return(c, -EINVAL);
253 assert_return(sgid, -EINVAL);
254
255 if (!(c->mask & SD_BUS_CREDS_SGID))
256 return -ENODATA;
257
258 *sgid = c->sgid;
259 return 0;
260}
261
705a415f
LP
262_public_ int sd_bus_creds_get_fsgid(sd_bus_creds *c, gid_t *fsgid) {
263 assert_return(c, -EINVAL);
264 assert_return(fsgid, -EINVAL);
265
266 if (!(c->mask & SD_BUS_CREDS_FSGID))
267 return -ENODATA;
268
269 *fsgid = c->fsgid;
270 return 0;
271}
272
02581590
LP
273_public_ int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) {
274 assert_return(c, -EINVAL);
275 assert_return(gids, -EINVAL);
276
277 if (!(c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS))
278 return -ENODATA;
279
280 *gids = c->supplementary_gids;
281 return (int) c->n_supplementary_gids;
282}
283
5b12334d
LP
284_public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
285 assert_return(c, -EINVAL);
286 assert_return(pid, -EINVAL);
6a4abbc8
LP
287
288 if (!(c->mask & SD_BUS_CREDS_PID))
289 return -ENODATA;
5b12334d
LP
290
291 assert(c->pid > 0);
292 *pid = c->pid;
293 return 0;
294}
295
1386e47d
LP
296_public_ int sd_bus_creds_get_ppid(sd_bus_creds *c, pid_t *ppid) {
297 assert_return(c, -EINVAL);
298 assert_return(ppid, -EINVAL);
299
300 if (!(c->mask & SD_BUS_CREDS_PPID))
301 return -ENODATA;
302
303 *ppid = c->ppid;
304 return 0;
305}
306
5b12334d
LP
307_public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
308 assert_return(c, -EINVAL);
309 assert_return(tid, -EINVAL);
6a4abbc8
LP
310
311 if (!(c->mask & SD_BUS_CREDS_TID))
312 return -ENODATA;
5b12334d
LP
313
314 assert(c->tid > 0);
315 *tid = c->tid;
316 return 0;
317}
318
5b12334d
LP
319_public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
320 assert_return(c, -EINVAL);
6a4abbc8
LP
321
322 if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
323 return -ENODATA;
5b12334d
LP
324
325 assert(c->label);
326 *ret = c->label;
327 return 0;
328}
329
330_public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
331 assert_return(c, -EINVAL);
332 assert_return(ret, -EINVAL);
6a4abbc8
LP
333
334 if (!(c->mask & SD_BUS_CREDS_COMM))
335 return -ENODATA;
5b12334d
LP
336
337 assert(c->comm);
338 *ret = c->comm;
339 return 0;
340}
341
342_public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
343 assert_return(c, -EINVAL);
344 assert_return(ret, -EINVAL);
6a4abbc8
LP
345
346 if (!(c->mask & SD_BUS_CREDS_TID_COMM))
347 return -ENODATA;
5b12334d
LP
348
349 assert(c->tid_comm);
350 *ret = c->tid_comm;
351 return 0;
352}
353
354_public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
355 assert_return(c, -EINVAL);
356 assert_return(ret, -EINVAL);
6a4abbc8
LP
357
358 if (!(c->mask & SD_BUS_CREDS_EXE))
359 return -ENODATA;
5b12334d
LP
360
361 assert(c->exe);
362 *ret = c->exe;
363 return 0;
364}
365
366_public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
367 assert_return(c, -EINVAL);
368 assert_return(ret, -EINVAL);
6a4abbc8
LP
369
370 if (!(c->mask & SD_BUS_CREDS_CGROUP))
371 return -ENODATA;
5b12334d
LP
372
373 assert(c->cgroup);
374 *ret = c->cgroup;
375 return 0;
376}
377
378_public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
379 int r;
380
381 assert_return(c, -EINVAL);
382 assert_return(ret, -EINVAL);
6a4abbc8
LP
383
384 if (!(c->mask & SD_BUS_CREDS_UNIT))
385 return -ENODATA;
5b12334d
LP
386
387 assert(c->cgroup);
388
389 if (!c->unit) {
751bc6ac
LP
390 const char *shifted;
391
392 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
393 if (r < 0)
394 return r;
395
396 r = cg_path_get_unit(shifted, (char**) &c->unit);
5b12334d
LP
397 if (r < 0)
398 return r;
399 }
400
401 *ret = c->unit;
402 return 0;
403}
404
405_public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
406 int r;
407
408 assert_return(c, -EINVAL);
409 assert_return(ret, -EINVAL);
6a4abbc8
LP
410
411 if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
412 return -ENODATA;
5b12334d
LP
413
414 assert(c->cgroup);
415
416 if (!c->user_unit) {
751bc6ac
LP
417 const char *shifted;
418
419 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
420 if (r < 0)
421 return r;
422
423 r = cg_path_get_user_unit(shifted, (char**) &c->user_unit);
5b12334d
LP
424 if (r < 0)
425 return r;
426 }
427
428 *ret = c->user_unit;
429 return 0;
430}
431
432_public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
433 int r;
434
435 assert_return(c, -EINVAL);
436 assert_return(ret, -EINVAL);
6a4abbc8
LP
437
438 if (!(c->mask & SD_BUS_CREDS_SLICE))
439 return -ENODATA;
5b12334d
LP
440
441 assert(c->cgroup);
442
443 if (!c->slice) {
751bc6ac
LP
444 const char *shifted;
445
446 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
447 if (r < 0)
448 return r;
449
450 r = cg_path_get_slice(shifted, (char**) &c->slice);
5b12334d
LP
451 if (r < 0)
452 return r;
453 }
454
455 *ret = c->slice;
456 return 0;
457}
458
459_public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
460 int r;
461
462 assert_return(c, -EINVAL);
463 assert_return(ret, -EINVAL);
6a4abbc8
LP
464
465 if (!(c->mask & SD_BUS_CREDS_SESSION))
466 return -ENODATA;
5b12334d
LP
467
468 assert(c->cgroup);
469
470 if (!c->session) {
751bc6ac
LP
471 const char *shifted;
472
473 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
474 if (r < 0)
475 return r;
476
477 r = cg_path_get_session(shifted, (char**) &c->session);
5b12334d
LP
478 if (r < 0)
479 return r;
480 }
481
482 *ret = c->session;
483 return 0;
484}
485
486_public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
751bc6ac
LP
487 const char *shifted;
488 int r;
489
5b12334d
LP
490 assert_return(c, -EINVAL);
491 assert_return(uid, -EINVAL);
6a4abbc8
LP
492
493 if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
494 return -ENODATA;
5b12334d
LP
495
496 assert(c->cgroup);
497
751bc6ac
LP
498 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
499 if (r < 0)
500 return r;
501
502 return cg_path_get_owner_uid(shifted, uid);
5b12334d
LP
503}
504
505_public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
5b12334d 506 assert_return(c, -EINVAL);
6a4abbc8
LP
507
508 if (!(c->mask & SD_BUS_CREDS_CMDLINE))
509 return -ENODATA;
5b12334d 510
689bd78d 511 assert_return(c->cmdline, -ESRCH);
5b12334d
LP
512 assert(c->cmdline);
513
49b832c5
LP
514 if (!c->cmdline_array) {
515 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
516 if (!c->cmdline_array)
517 return -ENOMEM;
5b12334d
LP
518 }
519
5b12334d 520 *cmdline = c->cmdline_array;
5b12334d
LP
521 return 0;
522}
523
524_public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
525 assert_return(c, -EINVAL);
526 assert_return(sessionid, -EINVAL);
6a4abbc8
LP
527
528 if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
529 return -ENODATA;
5b12334d
LP
530
531 *sessionid = c->audit_session_id;
532 return 0;
533}
534
535_public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
536 assert_return(c, -EINVAL);
537 assert_return(uid, -EINVAL);
6a4abbc8
LP
538
539 if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
540 return -ENODATA;
5b12334d
LP
541
542 *uid = c->audit_login_uid;
543 return 0;
544}
545
49b832c5
LP
546_public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
547 assert_return(c, -EINVAL);
548 assert_return(unique_name, -EINVAL);
6a4abbc8
LP
549
550 if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
551 return -ENODATA;
49b832c5
LP
552
553 *unique_name = c->unique_name;
554 return 0;
555}
556
557_public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
558 assert_return(c, -EINVAL);
559 assert_return(well_known_names, -EINVAL);
6a4abbc8
LP
560
561 if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
562 return -ENODATA;
49b832c5 563
ac653862
LP
564 /* As a special hack we return the bus driver as well-known
565 * names list when this is requested. */
566 if (c->well_known_names_driver) {
567 static const char* const wkn[] = {
568 "org.freedesktop.DBus",
569 NULL
570 };
571
572 *well_known_names = (char**) wkn;
573 return 0;
574 }
575
fb6d9b77
LP
576 if (c->well_known_names_local) {
577 static const char* const wkn[] = {
578 "org.freedesktop.DBus.Local",
579 NULL
580 };
581
582 *well_known_names = (char**) wkn;
583 return 0;
584 }
585
65dae17a 586 *well_known_names = c->well_known_names;
49b832c5
LP
587 return 0;
588}
589
455971c1 590_public_ int sd_bus_creds_get_description(sd_bus_creds *c, const char **ret) {
cccb0b2c
LP
591 assert_return(c, -EINVAL);
592 assert_return(ret, -EINVAL);
593
455971c1 594 if (!(c->mask & SD_BUS_CREDS_DESCRIPTION))
cccb0b2c
LP
595 return -ENODATA;
596
455971c1 597 assert(c->description);
2578d51e 598
455971c1
LP
599 if (!c->unescaped_description) {
600 c->unescaped_description = bus_label_unescape(c->description);
601 if (!c->unescaped_description)
2578d51e
LP
602 return -ENOMEM;
603 }
604
455971c1 605 *ret = c->unescaped_description;
cccb0b2c
LP
606 return 0;
607}
608
5b12334d
LP
609static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
610 size_t sz;
611
612 assert(c);
34a5d5e5 613 assert(capability >= 0);
5b12334d
LP
614 assert(c->capability);
615
da634f97 616 if ((unsigned) capability > cap_last_cap())
5b12334d
LP
617 return 0;
618
da634f97
LP
619 sz = DIV_ROUND_UP(cap_last_cap(), 32U);
620
7d9fcc2b 621 return !!(c->capability[offset * sz + CAP_TO_INDEX(capability)] & CAP_TO_MASK(capability));
5b12334d
LP
622}
623
624_public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
625 assert_return(c, -EINVAL);
626 assert_return(capability >= 0, -EINVAL);
6a4abbc8
LP
627
628 if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
629 return -ENODATA;
5b12334d
LP
630
631 return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
632}
633
634_public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
635 assert_return(c, -EINVAL);
636 assert_return(capability >= 0, -EINVAL);
6a4abbc8
LP
637
638 if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
639 return -ENODATA;
5b12334d
LP
640
641 return has_cap(c, CAP_OFFSET_PERMITTED, capability);
642}
643
644_public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
645 assert_return(c, -EINVAL);
646 assert_return(capability >= 0, -EINVAL);
6a4abbc8
LP
647
648 if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
649 return -ENODATA;
5b12334d
LP
650
651 return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
652}
653
654_public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
655 assert_return(c, -EINVAL);
656 assert_return(capability >= 0, -EINVAL);
6a4abbc8
LP
657
658 if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
659 return -ENODATA;
5b12334d
LP
660
661 return has_cap(c, CAP_OFFSET_BOUNDING, capability);
662}
663
664static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
34a5d5e5 665 size_t sz, max;
7d9fcc2b 666 unsigned i, j;
5b12334d
LP
667
668 assert(c);
669 assert(p);
670
7d9fcc2b 671 max = DIV_ROUND_UP(cap_last_cap(), 32U);
5b12334d
LP
672 p += strspn(p, WHITESPACE);
673
674 sz = strlen(p);
7d9fcc2b 675 if (sz % 8 != 0)
5b12334d
LP
676 return -EINVAL;
677
7d9fcc2b 678 sz /= 8;
34a5d5e5
DH
679 if (sz > max)
680 return -EINVAL;
681
5b12334d 682 if (!c->capability) {
7d9fcc2b 683 c->capability = new0(uint32_t, max * 4);
5b12334d
LP
684 if (!c->capability)
685 return -ENOMEM;
5b12334d
LP
686 }
687
688 for (i = 0; i < sz; i ++) {
7d9fcc2b 689 uint32_t v = 0;
5b12334d 690
7d9fcc2b
DH
691 for (j = 0; j < 8; ++j) {
692 int t;
5b12334d 693
7d9fcc2b
DH
694 t = unhexchar(*p++);
695 if (t < 0)
696 return -EINVAL;
5b12334d 697
7d9fcc2b
DH
698 v = (v << 4) | t;
699 }
700
701 c->capability[offset * max + (sz - i - 1)] = v;
5b12334d
LP
702 }
703
704 return 0;
705}
706
707int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
708 uint64_t missing;
709 int r;
710
711 assert(c);
712 assert(c->allocated);
713
705a415f
LP
714 if (!(mask & SD_BUS_CREDS_AUGMENT))
715 return 0;
716
5b12334d
LP
717 /* Try to retrieve PID from creds if it wasn't passed to us */
718 if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
719 pid = c->pid;
720
5b12334d
LP
721 /* Without pid we cannot do much... */
722 if (pid <= 0)
723 return 0;
724
0f514420
LP
725 /* Try to retrieve TID from creds if it wasn't passed to us */
726 if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
727 tid = c->tid;
728
729 /* Calculate what we shall and can add */
730 missing = mask & ~(c->mask|SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_AUGMENT);
731 if (missing == 0)
732 return 0;
733
734 c->pid = pid;
735 c->mask |= SD_BUS_CREDS_PID;
705a415f
LP
736
737 if (tid > 0) {
738 c->tid = tid;
739 c->mask |= SD_BUS_CREDS_TID;
740 }
741
1386e47d
LP
742 if (missing & (SD_BUS_CREDS_PPID |
743 SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
705a415f 744 SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
02581590 745 SD_BUS_CREDS_SUPPLEMENTARY_GIDS |
5b12334d
LP
746 SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
747 SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
748
749 _cleanup_fclose_ FILE *f = NULL;
5b12334d
LP
750 const char *p;
751
752 p = procfs_file_alloca(pid, "status");
753
754 f = fopen(p, "re");
705a415f
LP
755 if (!f) {
756 if (errno == ENOENT)
757 return -ESRCH;
758 else if (errno != EPERM && errno != EACCES)
759 return -errno;
760 } else {
761 char line[LINE_MAX];
762
763 FOREACH_LINE(line, f, return -errno) {
764 truncate_nl(line);
765
1386e47d
LP
766 if (missing & SD_BUS_CREDS_PPID) {
767 p = startswith(line, "PPid:");
768 if (p) {
769 p += strspn(p, WHITESPACE);
770
3a698817
LP
771 /* Explicitly check for PPID 0 (which is the case for PID 1) */
772 if (!streq(p, "0")) {
773 r = parse_pid(p, &c->ppid);
774 if (r < 0)
775 return r;
776
777 c->mask |= SD_BUS_CREDS_PPID;
778 }
1386e47d
LP
779 continue;
780 }
781 }
782
705a415f
LP
783 if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) {
784 p = startswith(line, "Uid:");
785 if (p) {
786 unsigned long uid, euid, suid, fsuid;
787
788 p += strspn(p, WHITESPACE);
789 if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4)
790 return -EIO;
791
f887fa73
LP
792 if (missing & SD_BUS_CREDS_UID)
793 c->uid = (uid_t) uid;
794 if (missing & SD_BUS_CREDS_EUID)
795 c->euid = (uid_t) euid;
796 if (missing & SD_BUS_CREDS_SUID)
797 c->suid = (uid_t) suid;
798 if (missing & SD_BUS_CREDS_FSUID)
799 c->fsuid = (uid_t) fsuid;
800
705a415f
LP
801 c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID);
802 continue;
803 }
5b12334d 804 }
5b12334d 805
705a415f
LP
806 if (missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) {
807 p = startswith(line, "Gid:");
808 if (p) {
809 unsigned long gid, egid, sgid, fsgid;
810
811 p += strspn(p, WHITESPACE);
812 if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4)
813 return -EIO;
814
f887fa73
LP
815 if (missing & SD_BUS_CREDS_GID)
816 c->gid = (gid_t) gid;
817 if (missing & SD_BUS_CREDS_EGID)
818 c->egid = (gid_t) egid;
819 if (missing & SD_BUS_CREDS_SGID)
820 c->sgid = (gid_t) sgid;
821 if (missing & SD_BUS_CREDS_FSGID)
822 c->fsgid = (gid_t) fsgid;
823
705a415f
LP
824 c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID);
825 continue;
826 }
5b12334d 827 }
5b12334d 828
02581590
LP
829 if (missing & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
830 p = startswith(line, "Groups:");
831 if (p) {
832 size_t allocated = 0;
833
834 for (;;) {
835 unsigned long g;
836 int n = 0;
837
838 p += strspn(p, WHITESPACE);
839 if (*p == 0)
840 break;
841
842 if (sscanf(p, "%lu%n", &g, &n) != 1)
843 return -EIO;
844
845 if (!GREEDY_REALLOC(c->supplementary_gids, allocated, c->n_supplementary_gids+1))
846 return -ENOMEM;
847
848 c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) g;
849 p += n;
850 }
851
852 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
853 continue;
854 }
855 }
856
705a415f
LP
857 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
858 p = startswith(line, "CapEff:");
859 if (p) {
860 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
861 if (r < 0)
862 return r;
5b12334d 863
705a415f
LP
864 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
865 continue;
866 }
5b12334d 867 }
5b12334d 868
705a415f
LP
869 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
870 p = startswith(line, "CapPrm:");
871 if (p) {
872 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
873 if (r < 0)
874 return r;
5b12334d 875
705a415f
LP
876 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
877 continue;
878 }
5b12334d 879 }
5b12334d 880
705a415f
LP
881 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
882 p = startswith(line, "CapInh:");
883 if (p) {
884 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
885 if (r < 0)
886 return r;
5b12334d 887
705a415f
LP
888 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
889 continue;
890 }
5b12334d 891 }
5b12334d 892
705a415f
LP
893 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
894 p = startswith(line, "CapBnd:");
895 if (p) {
896 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
897 if (r < 0)
898 return r;
5b12334d 899
705a415f
LP
900 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
901 continue;
902 }
5b12334d
LP
903 }
904 }
905 }
906 }
907
5b12334d
LP
908 if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
909 const char *p;
910
911 p = procfs_file_alloca(pid, "attr/current");
912 r = read_one_line_file(p, &c->label);
705a415f
LP
913 if (r < 0) {
914 if (r != -ENOENT && r != -EINVAL && r != -EPERM && r != -EACCES)
915 return r;
916 } else
5b12334d
LP
917 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
918 }
919
920 if (missing & SD_BUS_CREDS_COMM) {
921 r = get_process_comm(pid, &c->comm);
705a415f
LP
922 if (r < 0) {
923 if (r != -EPERM && r != -EACCES)
924 return r;
925 } else
926 c->mask |= SD_BUS_CREDS_COMM;
5b12334d
LP
927 }
928
929 if (missing & SD_BUS_CREDS_EXE) {
930 r = get_process_exe(pid, &c->exe);
705a415f
LP
931 if (r < 0) {
932 if (r != -EPERM && r != -EACCES)
933 return r;
934 } else
935 c->mask |= SD_BUS_CREDS_EXE;
5b12334d
LP
936 }
937
938 if (missing & SD_BUS_CREDS_CMDLINE) {
939 const char *p;
940
941 p = procfs_file_alloca(pid, "cmdline");
49b832c5 942 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
705a415f
LP
943 if (r < 0) {
944 if (r == -ENOENT)
945 return -ESRCH;
946 if (r != -EPERM && r != -EACCES)
947 return r;
948 } else {
949 if (c->cmdline_size == 0) {
950 free(c->cmdline);
951 c->cmdline = NULL;
952 } else
953 c->mask |= SD_BUS_CREDS_CMDLINE;
954 }
5b12334d
LP
955 }
956
957 if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
958 _cleanup_free_ char *p = NULL;
959
de0671ee 960 if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
5b12334d
LP
961 return -ENOMEM;
962
963 r = read_one_line_file(p, &c->tid_comm);
705a415f
LP
964 if (r < 0) {
965 if (r == -ENOENT)
966 return -ESRCH;
967 if (r != -EPERM && r != -EACCES)
968 return r;
969 } else
970 c->mask |= SD_BUS_CREDS_TID_COMM;
5b12334d
LP
971 }
972
973 if (missing & (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)) {
974
822d9b6e
LP
975 if (!c->cgroup) {
976 r = cg_pid_get_path(NULL, pid, &c->cgroup);
977 if (r < 0) {
978 if (r != -EPERM && r != -EACCES)
979 return r;
980 }
981 }
982
983 if (!c->cgroup_root) {
705a415f
LP
984 r = cg_get_root_path(&c->cgroup_root);
985 if (r < 0)
986 return r;
822d9b6e 987 }
705a415f 988
822d9b6e 989 if (c->cgroup)
705a415f 990 c->mask |= missing & (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);
5b12334d
LP
991 }
992
993 if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
994 r = audit_session_from_pid(pid, &c->audit_session_id);
705a415f 995 if (r < 0) {
15411c0c 996 if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
705a415f
LP
997 return r;
998 } else
5b12334d
LP
999 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1000 }
1001
1002 if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
1003 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
705a415f 1004 if (r < 0) {
15411c0c 1005 if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
705a415f
LP
1006 return r;
1007 } else
5b12334d
LP
1008 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1009 }
1010
0f514420
LP
1011 c->augmented = missing & c->mask;
1012
5b12334d
LP
1013 return 0;
1014}
1015
49b832c5 1016int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
5b12334d
LP
1017 _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
1018 int r;
1019
49b832c5
LP
1020 assert(c);
1021 assert(ret);
5b12334d 1022
705a415f
LP
1023 if ((mask & ~c->mask) == 0 || (!(mask & SD_BUS_CREDS_AUGMENT))) {
1024 /* There's already all data we need, or augmentation
1025 * wasn't turned on. */
5b12334d
LP
1026
1027 *ret = sd_bus_creds_ref(c);
1028 return 0;
1029 }
1030
1031 n = bus_creds_new();
1032 if (!n)
1033 return -ENOMEM;
1034
1035 /* Copy the original data over */
1036
da634f97
LP
1037 if (c->mask & mask & SD_BUS_CREDS_PID) {
1038 n->pid = c->pid;
1039 n->mask |= SD_BUS_CREDS_PID;
1040 }
1041
1042 if (c->mask & mask & SD_BUS_CREDS_TID) {
1043 n->tid = c->tid;
1044 n->mask |= SD_BUS_CREDS_TID;
1045 }
1046
1386e47d
LP
1047 if (c->mask & mask & SD_BUS_CREDS_PPID) {
1048 n->ppid = c->ppid;
1049 n->mask |= SD_BUS_CREDS_PPID;
1050 }
1051
5b12334d
LP
1052 if (c->mask & mask & SD_BUS_CREDS_UID) {
1053 n->uid = c->uid;
1054 n->mask |= SD_BUS_CREDS_UID;
1055 }
1056
705a415f
LP
1057 if (c->mask & mask & SD_BUS_CREDS_EUID) {
1058 n->euid = c->euid;
1059 n->mask |= SD_BUS_CREDS_EUID;
1060 }
1061
1062 if (c->mask & mask & SD_BUS_CREDS_SUID) {
1063 n->suid = c->suid;
1064 n->mask |= SD_BUS_CREDS_SUID;
1065 }
1066
1067 if (c->mask & mask & SD_BUS_CREDS_FSUID) {
1068 n->fsuid = c->fsuid;
1069 n->mask |= SD_BUS_CREDS_FSUID;
1070 }
1071
5b12334d
LP
1072 if (c->mask & mask & SD_BUS_CREDS_GID) {
1073 n->gid = c->gid;
1074 n->mask |= SD_BUS_CREDS_GID;
1075 }
1076
705a415f
LP
1077 if (c->mask & mask & SD_BUS_CREDS_EGID) {
1078 n->egid = c->egid;
1079 n->mask |= SD_BUS_CREDS_EGID;
1080 }
1081
1082 if (c->mask & mask & SD_BUS_CREDS_SGID) {
1083 n->sgid = c->sgid;
1084 n->mask |= SD_BUS_CREDS_SGID;
1085 }
1086
1087 if (c->mask & mask & SD_BUS_CREDS_FSGID) {
1088 n->fsgid = c->fsgid;
1089 n->mask |= SD_BUS_CREDS_FSGID;
1090 }
1091
02581590
LP
1092 if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
1093 n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
1094 if (!n->supplementary_gids)
1095 return -ENOMEM;
1096 n->n_supplementary_gids = c->n_supplementary_gids;
1097 n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
1098 }
1099
5b12334d
LP
1100 if (c->mask & mask & SD_BUS_CREDS_COMM) {
1101 n->comm = strdup(c->comm);
1102 if (!n->comm)
1103 return -ENOMEM;
1104
1105 n->mask |= SD_BUS_CREDS_COMM;
1106 }
1107
1108 if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
1109 n->tid_comm = strdup(c->tid_comm);
1110 if (!n->tid_comm)
1111 return -ENOMEM;
1112
1113 n->mask |= SD_BUS_CREDS_TID_COMM;
1114 }
1115
1116 if (c->mask & mask & SD_BUS_CREDS_EXE) {
1117 n->exe = strdup(c->exe);
1118 if (!n->exe)
1119 return -ENOMEM;
1120
1121 n->mask |= SD_BUS_CREDS_EXE;
1122 }
1123
1124 if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
49b832c5 1125 n->cmdline = memdup(c->cmdline, c->cmdline_size);
5b12334d
LP
1126 if (!n->cmdline)
1127 return -ENOMEM;
1128
49b832c5 1129 n->cmdline_size = c->cmdline_size;
5b12334d
LP
1130 n->mask |= SD_BUS_CREDS_CMDLINE;
1131 }
1132
1133 if (c->mask & mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID)) {
1134 n->cgroup = strdup(c->cgroup);
1135 if (!n->cgroup)
1136 return -ENOMEM;
1137
751bc6ac
LP
1138 n->cgroup_root = strdup(c->cgroup_root);
1139 if (!n->cgroup_root)
1140 return -ENOMEM;
1141
5b12334d
LP
1142 n->mask |= mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID);
1143 }
1144
1145 if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
34a5d5e5 1146 n->capability = memdup(c->capability, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4);
5b12334d
LP
1147 if (!n->capability)
1148 return -ENOMEM;
1149
5b12334d
LP
1150 n->mask |= c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS);
1151 }
1152
a6ede528
LP
1153 if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
1154 n->label = strdup(c->label);
1155 if (!n->label)
1156 return -ENOMEM;
1157 n->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1158 }
1159
5b12334d
LP
1160 if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
1161 n->audit_session_id = c->audit_session_id;
1162 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
1163 }
5b12334d
LP
1164 if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
1165 n->audit_login_uid = c->audit_login_uid;
1166 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
1167 }
1168
49b832c5
LP
1169 if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
1170 n->unique_name = strdup(c->unique_name);
1171 if (!n->unique_name)
1172 return -ENOMEM;
a6ede528 1173 n->mask |= SD_BUS_CREDS_UNIQUE_NAME;
49b832c5
LP
1174 }
1175
1176 if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
65dae17a 1177 n->well_known_names = strv_copy(c->well_known_names);
49b832c5
LP
1178 if (!n->well_known_names)
1179 return -ENOMEM;
da634f97
LP
1180 n->well_known_names_driver = c->well_known_names_driver;
1181 n->well_known_names_local = c->well_known_names_local;
a6ede528
LP
1182 n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
1183 }
1184
1185 if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) {
1186 n->description = strdup(c->description);
1187 if (!n->description)
1188 return -ENOMEM;
1189 n->mask |= SD_BUS_CREDS_DESCRIPTION;
49b832c5
LP
1190 }
1191
0f514420
LP
1192 n->augmented = c->augmented & n->mask;
1193
5b12334d
LP
1194 /* Get more data */
1195
0f514420 1196 r = bus_creds_add_more(n, mask, 0, 0);
5b12334d
LP
1197 if (r < 0)
1198 return r;
1199
1200 *ret = n;
1201 n = NULL;
1202 return 0;
1203}