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