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