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