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