1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
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.
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.
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/>.
22 #include <linux/capability.h>
26 #include "bus-creds.h"
27 #include "bus-label.h"
28 #include "bus-message.h"
30 #include "capability.h"
31 #include "cgroup-util.h"
34 #include "formats-util.h"
35 #include "hexdecoct.h"
36 #include "parse-util.h"
37 #include "process-util.h"
38 #include "string-util.h"
40 #include "terminal-util.h"
44 CAP_OFFSET_INHERITABLE
= 0,
45 CAP_OFFSET_PERMITTED
= 1,
46 CAP_OFFSET_EFFECTIVE
= 2,
47 CAP_OFFSET_BOUNDING
= 3
50 void bus_creds_done(sd_bus_creds
*c
) {
53 /* For internal bus cred structures that are allocated by
61 free(c
->unescaped_description
);
62 free(c
->supplementary_gids
);
65 free(c
->well_known_names
); /* note that this is an strv, but
66 * we only free the array, not the
67 * strings the array points to. The
68 * full strv we only free if
69 * c->allocated is set, see
72 strv_free(c
->cmdline_array
);
75 _public_ sd_bus_creds
*sd_bus_creds_ref(sd_bus_creds
*c
) {
76 assert_return(c
, NULL
);
84 /* If this is an embedded creds structure, then
85 * forward ref counting to the message */
86 m
= container_of(c
, sd_bus_message
, creds
);
87 sd_bus_message_ref(m
);
93 _public_ sd_bus_creds
*sd_bus_creds_unref(sd_bus_creds
*c
) {
110 free(c
->unique_name
);
111 free(c
->cgroup_root
);
112 free(c
->description
);
114 c
->supplementary_gids
= mfree(c
->supplementary_gids
);
116 c
->well_known_names
= strv_free(c
->well_known_names
);
125 m
= container_of(c
, sd_bus_message
, creds
);
126 sd_bus_message_unref(m
);
133 _public_
uint64_t sd_bus_creds_get_mask(const sd_bus_creds
*c
) {
139 _public_
uint64_t sd_bus_creds_get_augmented_mask(const sd_bus_creds
*c
) {
145 sd_bus_creds
* bus_creds_new(void) {
148 c
= new0(sd_bus_creds
, 1);
157 _public_
int sd_bus_creds_new_from_pid(sd_bus_creds
**ret
, pid_t pid
, uint64_t mask
) {
161 assert_return(pid
>= 0, -EINVAL
);
162 assert_return(mask
<= _SD_BUS_CREDS_ALL
, -EOPNOTSUPP
);
163 assert_return(ret
, -EINVAL
);
172 r
= bus_creds_add_more(c
, mask
| SD_BUS_CREDS_AUGMENT
, pid
, 0);
174 sd_bus_creds_unref(c
);
178 /* Check if the process existed at all, in case we haven't
179 * figured that out already */
180 if (!pid_is_alive(pid
)) {
181 sd_bus_creds_unref(c
);
189 _public_
int sd_bus_creds_get_uid(sd_bus_creds
*c
, uid_t
*uid
) {
190 assert_return(c
, -EINVAL
);
191 assert_return(uid
, -EINVAL
);
193 if (!(c
->mask
& SD_BUS_CREDS_UID
))
200 _public_
int sd_bus_creds_get_euid(sd_bus_creds
*c
, uid_t
*euid
) {
201 assert_return(c
, -EINVAL
);
202 assert_return(euid
, -EINVAL
);
204 if (!(c
->mask
& SD_BUS_CREDS_EUID
))
211 _public_
int sd_bus_creds_get_suid(sd_bus_creds
*c
, uid_t
*suid
) {
212 assert_return(c
, -EINVAL
);
213 assert_return(suid
, -EINVAL
);
215 if (!(c
->mask
& SD_BUS_CREDS_SUID
))
223 _public_
int sd_bus_creds_get_fsuid(sd_bus_creds
*c
, uid_t
*fsuid
) {
224 assert_return(c
, -EINVAL
);
225 assert_return(fsuid
, -EINVAL
);
227 if (!(c
->mask
& SD_BUS_CREDS_FSUID
))
234 _public_
int sd_bus_creds_get_gid(sd_bus_creds
*c
, gid_t
*gid
) {
235 assert_return(c
, -EINVAL
);
236 assert_return(gid
, -EINVAL
);
238 if (!(c
->mask
& SD_BUS_CREDS_GID
))
245 _public_
int sd_bus_creds_get_egid(sd_bus_creds
*c
, gid_t
*egid
) {
246 assert_return(c
, -EINVAL
);
247 assert_return(egid
, -EINVAL
);
249 if (!(c
->mask
& SD_BUS_CREDS_EGID
))
256 _public_
int sd_bus_creds_get_sgid(sd_bus_creds
*c
, gid_t
*sgid
) {
257 assert_return(c
, -EINVAL
);
258 assert_return(sgid
, -EINVAL
);
260 if (!(c
->mask
& SD_BUS_CREDS_SGID
))
267 _public_
int sd_bus_creds_get_fsgid(sd_bus_creds
*c
, gid_t
*fsgid
) {
268 assert_return(c
, -EINVAL
);
269 assert_return(fsgid
, -EINVAL
);
271 if (!(c
->mask
& SD_BUS_CREDS_FSGID
))
278 _public_
int sd_bus_creds_get_supplementary_gids(sd_bus_creds
*c
, const gid_t
**gids
) {
279 assert_return(c
, -EINVAL
);
280 assert_return(gids
, -EINVAL
);
282 if (!(c
->mask
& SD_BUS_CREDS_SUPPLEMENTARY_GIDS
))
285 *gids
= c
->supplementary_gids
;
286 return (int) c
->n_supplementary_gids
;
289 _public_
int sd_bus_creds_get_pid(sd_bus_creds
*c
, pid_t
*pid
) {
290 assert_return(c
, -EINVAL
);
291 assert_return(pid
, -EINVAL
);
293 if (!(c
->mask
& SD_BUS_CREDS_PID
))
301 _public_
int sd_bus_creds_get_ppid(sd_bus_creds
*c
, pid_t
*ppid
) {
302 assert_return(c
, -EINVAL
);
303 assert_return(ppid
, -EINVAL
);
305 if (!(c
->mask
& SD_BUS_CREDS_PPID
))
308 /* PID 1 has no parent process. Let's distinguish the case of
309 * not knowing and not having a parent process by the returned
318 _public_
int sd_bus_creds_get_tid(sd_bus_creds
*c
, pid_t
*tid
) {
319 assert_return(c
, -EINVAL
);
320 assert_return(tid
, -EINVAL
);
322 if (!(c
->mask
& SD_BUS_CREDS_TID
))
330 _public_
int sd_bus_creds_get_selinux_context(sd_bus_creds
*c
, const char **ret
) {
331 assert_return(c
, -EINVAL
);
333 if (!(c
->mask
& SD_BUS_CREDS_SELINUX_CONTEXT
))
341 _public_
int sd_bus_creds_get_comm(sd_bus_creds
*c
, const char **ret
) {
342 assert_return(c
, -EINVAL
);
343 assert_return(ret
, -EINVAL
);
345 if (!(c
->mask
& SD_BUS_CREDS_COMM
))
353 _public_
int sd_bus_creds_get_tid_comm(sd_bus_creds
*c
, const char **ret
) {
354 assert_return(c
, -EINVAL
);
355 assert_return(ret
, -EINVAL
);
357 if (!(c
->mask
& SD_BUS_CREDS_TID_COMM
))
365 _public_
int sd_bus_creds_get_exe(sd_bus_creds
*c
, const char **ret
) {
366 assert_return(c
, -EINVAL
);
367 assert_return(ret
, -EINVAL
);
369 if (!(c
->mask
& SD_BUS_CREDS_EXE
))
379 _public_
int sd_bus_creds_get_cgroup(sd_bus_creds
*c
, const char **ret
) {
380 assert_return(c
, -EINVAL
);
381 assert_return(ret
, -EINVAL
);
383 if (!(c
->mask
& SD_BUS_CREDS_CGROUP
))
391 _public_
int sd_bus_creds_get_unit(sd_bus_creds
*c
, const char **ret
) {
394 assert_return(c
, -EINVAL
);
395 assert_return(ret
, -EINVAL
);
397 if (!(c
->mask
& SD_BUS_CREDS_UNIT
))
405 r
= cg_shift_path(c
->cgroup
, c
->cgroup_root
, &shifted
);
409 r
= cg_path_get_unit(shifted
, (char**) &c
->unit
);
418 _public_
int sd_bus_creds_get_user_unit(sd_bus_creds
*c
, const char **ret
) {
421 assert_return(c
, -EINVAL
);
422 assert_return(ret
, -EINVAL
);
424 if (!(c
->mask
& SD_BUS_CREDS_USER_UNIT
))
432 r
= cg_shift_path(c
->cgroup
, c
->cgroup_root
, &shifted
);
436 r
= cg_path_get_user_unit(shifted
, (char**) &c
->user_unit
);
445 _public_
int sd_bus_creds_get_slice(sd_bus_creds
*c
, const char **ret
) {
448 assert_return(c
, -EINVAL
);
449 assert_return(ret
, -EINVAL
);
451 if (!(c
->mask
& SD_BUS_CREDS_SLICE
))
459 r
= cg_shift_path(c
->cgroup
, c
->cgroup_root
, &shifted
);
463 r
= cg_path_get_slice(shifted
, (char**) &c
->slice
);
472 _public_
int sd_bus_creds_get_user_slice(sd_bus_creds
*c
, const char **ret
) {
475 assert_return(c
, -EINVAL
);
476 assert_return(ret
, -EINVAL
);
478 if (!(c
->mask
& SD_BUS_CREDS_USER_SLICE
))
483 if (!c
->user_slice
) {
486 r
= cg_shift_path(c
->cgroup
, c
->cgroup_root
, &shifted
);
490 r
= cg_path_get_user_slice(shifted
, (char**) &c
->user_slice
);
495 *ret
= c
->user_slice
;
499 _public_
int sd_bus_creds_get_session(sd_bus_creds
*c
, const char **ret
) {
502 assert_return(c
, -EINVAL
);
503 assert_return(ret
, -EINVAL
);
505 if (!(c
->mask
& SD_BUS_CREDS_SESSION
))
513 r
= cg_shift_path(c
->cgroup
, c
->cgroup_root
, &shifted
);
517 r
= cg_path_get_session(shifted
, (char**) &c
->session
);
526 _public_
int sd_bus_creds_get_owner_uid(sd_bus_creds
*c
, uid_t
*uid
) {
530 assert_return(c
, -EINVAL
);
531 assert_return(uid
, -EINVAL
);
533 if (!(c
->mask
& SD_BUS_CREDS_OWNER_UID
))
538 r
= cg_shift_path(c
->cgroup
, c
->cgroup_root
, &shifted
);
542 return cg_path_get_owner_uid(shifted
, uid
);
545 _public_
int sd_bus_creds_get_cmdline(sd_bus_creds
*c
, char ***cmdline
) {
546 assert_return(c
, -EINVAL
);
548 if (!(c
->mask
& SD_BUS_CREDS_CMDLINE
))
554 if (!c
->cmdline_array
) {
555 c
->cmdline_array
= strv_parse_nulstr(c
->cmdline
, c
->cmdline_size
);
556 if (!c
->cmdline_array
)
560 *cmdline
= c
->cmdline_array
;
564 _public_
int sd_bus_creds_get_audit_session_id(sd_bus_creds
*c
, uint32_t *sessionid
) {
565 assert_return(c
, -EINVAL
);
566 assert_return(sessionid
, -EINVAL
);
568 if (!(c
->mask
& SD_BUS_CREDS_AUDIT_SESSION_ID
))
571 if (c
->audit_session_id
== AUDIT_SESSION_INVALID
)
574 *sessionid
= c
->audit_session_id
;
578 _public_
int sd_bus_creds_get_audit_login_uid(sd_bus_creds
*c
, uid_t
*uid
) {
579 assert_return(c
, -EINVAL
);
580 assert_return(uid
, -EINVAL
);
582 if (!(c
->mask
& SD_BUS_CREDS_AUDIT_LOGIN_UID
))
585 if (c
->audit_login_uid
== UID_INVALID
)
588 *uid
= c
->audit_login_uid
;
592 _public_
int sd_bus_creds_get_tty(sd_bus_creds
*c
, const char **ret
) {
593 assert_return(c
, -EINVAL
);
594 assert_return(ret
, -EINVAL
);
596 if (!(c
->mask
& SD_BUS_CREDS_TTY
))
606 _public_
int sd_bus_creds_get_unique_name(sd_bus_creds
*c
, const char **unique_name
) {
607 assert_return(c
, -EINVAL
);
608 assert_return(unique_name
, -EINVAL
);
610 if (!(c
->mask
& SD_BUS_CREDS_UNIQUE_NAME
))
613 *unique_name
= c
->unique_name
;
617 _public_
int sd_bus_creds_get_well_known_names(sd_bus_creds
*c
, char ***well_known_names
) {
618 assert_return(c
, -EINVAL
);
619 assert_return(well_known_names
, -EINVAL
);
621 if (!(c
->mask
& SD_BUS_CREDS_WELL_KNOWN_NAMES
))
624 /* As a special hack we return the bus driver as well-known
625 * names list when this is requested. */
626 if (c
->well_known_names_driver
) {
627 static const char* const wkn
[] = {
628 "org.freedesktop.DBus",
632 *well_known_names
= (char**) wkn
;
636 if (c
->well_known_names_local
) {
637 static const char* const wkn
[] = {
638 "org.freedesktop.DBus.Local",
642 *well_known_names
= (char**) wkn
;
646 *well_known_names
= c
->well_known_names
;
650 _public_
int sd_bus_creds_get_description(sd_bus_creds
*c
, const char **ret
) {
651 assert_return(c
, -EINVAL
);
652 assert_return(ret
, -EINVAL
);
654 if (!(c
->mask
& SD_BUS_CREDS_DESCRIPTION
))
657 assert(c
->description
);
659 if (!c
->unescaped_description
) {
660 c
->unescaped_description
= bus_label_unescape(c
->description
);
661 if (!c
->unescaped_description
)
665 *ret
= c
->unescaped_description
;
669 static int has_cap(sd_bus_creds
*c
, unsigned offset
, int capability
) {
673 assert(capability
>= 0);
674 assert(c
->capability
);
676 if ((unsigned) capability
> cap_last_cap())
679 sz
= DIV_ROUND_UP(cap_last_cap(), 32U);
681 return !!(c
->capability
[offset
* sz
+ CAP_TO_INDEX(capability
)] & CAP_TO_MASK(capability
));
684 _public_
int sd_bus_creds_has_effective_cap(sd_bus_creds
*c
, int capability
) {
685 assert_return(c
, -EINVAL
);
686 assert_return(capability
>= 0, -EINVAL
);
688 if (!(c
->mask
& SD_BUS_CREDS_EFFECTIVE_CAPS
))
691 return has_cap(c
, CAP_OFFSET_EFFECTIVE
, capability
);
694 _public_
int sd_bus_creds_has_permitted_cap(sd_bus_creds
*c
, int capability
) {
695 assert_return(c
, -EINVAL
);
696 assert_return(capability
>= 0, -EINVAL
);
698 if (!(c
->mask
& SD_BUS_CREDS_PERMITTED_CAPS
))
701 return has_cap(c
, CAP_OFFSET_PERMITTED
, capability
);
704 _public_
int sd_bus_creds_has_inheritable_cap(sd_bus_creds
*c
, int capability
) {
705 assert_return(c
, -EINVAL
);
706 assert_return(capability
>= 0, -EINVAL
);
708 if (!(c
->mask
& SD_BUS_CREDS_INHERITABLE_CAPS
))
711 return has_cap(c
, CAP_OFFSET_INHERITABLE
, capability
);
714 _public_
int sd_bus_creds_has_bounding_cap(sd_bus_creds
*c
, int capability
) {
715 assert_return(c
, -EINVAL
);
716 assert_return(capability
>= 0, -EINVAL
);
718 if (!(c
->mask
& SD_BUS_CREDS_BOUNDING_CAPS
))
721 return has_cap(c
, CAP_OFFSET_BOUNDING
, capability
);
724 static int parse_caps(sd_bus_creds
*c
, unsigned offset
, const char *p
) {
731 max
= DIV_ROUND_UP(cap_last_cap(), 32U);
732 p
+= strspn(p
, WHITESPACE
);
742 if (!c
->capability
) {
743 c
->capability
= new0(uint32_t, max
* 4);
748 for (i
= 0; i
< sz
; i
++) {
751 for (j
= 0; j
< 8; ++j
) {
761 c
->capability
[offset
* max
+ (sz
- i
- 1)] = v
;
767 int bus_creds_add_more(sd_bus_creds
*c
, uint64_t mask
, pid_t pid
, pid_t tid
) {
772 assert(c
->allocated
);
774 if (!(mask
& SD_BUS_CREDS_AUGMENT
))
777 /* Try to retrieve PID from creds if it wasn't passed to us */
780 c
->mask
|= SD_BUS_CREDS_PID
;
781 } else if (c
->mask
& SD_BUS_CREDS_PID
)
784 /* Without pid we cannot do much... */
787 /* Try to retrieve TID from creds if it wasn't passed to us */
788 if (tid
<= 0 && (c
->mask
& SD_BUS_CREDS_TID
))
791 /* Calculate what we shall and can add */
792 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
);
798 c
->mask
|= SD_BUS_CREDS_TID
;
801 if (missing
& (SD_BUS_CREDS_PPID
|
802 SD_BUS_CREDS_UID
| SD_BUS_CREDS_EUID
| SD_BUS_CREDS_SUID
| SD_BUS_CREDS_FSUID
|
803 SD_BUS_CREDS_GID
| SD_BUS_CREDS_EGID
| SD_BUS_CREDS_SGID
| SD_BUS_CREDS_FSGID
|
804 SD_BUS_CREDS_SUPPLEMENTARY_GIDS
|
805 SD_BUS_CREDS_EFFECTIVE_CAPS
| SD_BUS_CREDS_INHERITABLE_CAPS
|
806 SD_BUS_CREDS_PERMITTED_CAPS
| SD_BUS_CREDS_BOUNDING_CAPS
)) {
808 _cleanup_fclose_
FILE *f
= NULL
;
811 p
= procfs_file_alloca(pid
, "status");
817 else if (errno
!= EPERM
&& errno
!= EACCES
)
822 FOREACH_LINE(line
, f
, return -errno
) {
825 if (missing
& SD_BUS_CREDS_PPID
) {
826 p
= startswith(line
, "PPid:");
828 p
+= strspn(p
, WHITESPACE
);
830 /* Explicitly check for PPID 0 (which is the case for PID 1) */
831 if (!streq(p
, "0")) {
832 r
= parse_pid(p
, &c
->ppid
);
839 c
->mask
|= SD_BUS_CREDS_PPID
;
844 if (missing
& (SD_BUS_CREDS_UID
|SD_BUS_CREDS_EUID
|SD_BUS_CREDS_SUID
|SD_BUS_CREDS_FSUID
)) {
845 p
= startswith(line
, "Uid:");
847 unsigned long uid
, euid
, suid
, fsuid
;
849 p
+= strspn(p
, WHITESPACE
);
850 if (sscanf(p
, "%lu %lu %lu %lu", &uid
, &euid
, &suid
, &fsuid
) != 4)
853 if (missing
& SD_BUS_CREDS_UID
)
854 c
->uid
= (uid_t
) uid
;
855 if (missing
& SD_BUS_CREDS_EUID
)
856 c
->euid
= (uid_t
) euid
;
857 if (missing
& SD_BUS_CREDS_SUID
)
858 c
->suid
= (uid_t
) suid
;
859 if (missing
& SD_BUS_CREDS_FSUID
)
860 c
->fsuid
= (uid_t
) fsuid
;
862 c
->mask
|= missing
& (SD_BUS_CREDS_UID
|SD_BUS_CREDS_EUID
|SD_BUS_CREDS_SUID
|SD_BUS_CREDS_FSUID
);
867 if (missing
& (SD_BUS_CREDS_GID
|SD_BUS_CREDS_EGID
|SD_BUS_CREDS_SGID
|SD_BUS_CREDS_FSGID
)) {
868 p
= startswith(line
, "Gid:");
870 unsigned long gid
, egid
, sgid
, fsgid
;
872 p
+= strspn(p
, WHITESPACE
);
873 if (sscanf(p
, "%lu %lu %lu %lu", &gid
, &egid
, &sgid
, &fsgid
) != 4)
876 if (missing
& SD_BUS_CREDS_GID
)
877 c
->gid
= (gid_t
) gid
;
878 if (missing
& SD_BUS_CREDS_EGID
)
879 c
->egid
= (gid_t
) egid
;
880 if (missing
& SD_BUS_CREDS_SGID
)
881 c
->sgid
= (gid_t
) sgid
;
882 if (missing
& SD_BUS_CREDS_FSGID
)
883 c
->fsgid
= (gid_t
) fsgid
;
885 c
->mask
|= missing
& (SD_BUS_CREDS_GID
|SD_BUS_CREDS_EGID
|SD_BUS_CREDS_SGID
|SD_BUS_CREDS_FSGID
);
890 if (missing
& SD_BUS_CREDS_SUPPLEMENTARY_GIDS
) {
891 p
= startswith(line
, "Groups:");
893 size_t allocated
= 0;
899 p
+= strspn(p
, WHITESPACE
);
903 if (sscanf(p
, "%lu%n", &g
, &n
) != 1)
906 if (!GREEDY_REALLOC(c
->supplementary_gids
, allocated
, c
->n_supplementary_gids
+1))
909 c
->supplementary_gids
[c
->n_supplementary_gids
++] = (gid_t
) g
;
913 c
->mask
|= SD_BUS_CREDS_SUPPLEMENTARY_GIDS
;
918 if (missing
& SD_BUS_CREDS_EFFECTIVE_CAPS
) {
919 p
= startswith(line
, "CapEff:");
921 r
= parse_caps(c
, CAP_OFFSET_EFFECTIVE
, p
);
925 c
->mask
|= SD_BUS_CREDS_EFFECTIVE_CAPS
;
930 if (missing
& SD_BUS_CREDS_PERMITTED_CAPS
) {
931 p
= startswith(line
, "CapPrm:");
933 r
= parse_caps(c
, CAP_OFFSET_PERMITTED
, p
);
937 c
->mask
|= SD_BUS_CREDS_PERMITTED_CAPS
;
942 if (missing
& SD_BUS_CREDS_INHERITABLE_CAPS
) {
943 p
= startswith(line
, "CapInh:");
945 r
= parse_caps(c
, CAP_OFFSET_INHERITABLE
, p
);
949 c
->mask
|= SD_BUS_CREDS_INHERITABLE_CAPS
;
954 if (missing
& SD_BUS_CREDS_BOUNDING_CAPS
) {
955 p
= startswith(line
, "CapBnd:");
957 r
= parse_caps(c
, CAP_OFFSET_BOUNDING
, p
);
961 c
->mask
|= SD_BUS_CREDS_BOUNDING_CAPS
;
969 if (missing
& SD_BUS_CREDS_SELINUX_CONTEXT
) {
972 p
= procfs_file_alloca(pid
, "attr/current");
973 r
= read_one_line_file(p
, &c
->label
);
975 if (r
!= -ENOENT
&& r
!= -EINVAL
&& r
!= -EPERM
&& r
!= -EACCES
)
978 c
->mask
|= SD_BUS_CREDS_SELINUX_CONTEXT
;
981 if (missing
& SD_BUS_CREDS_COMM
) {
982 r
= get_process_comm(pid
, &c
->comm
);
984 if (r
!= -EPERM
&& r
!= -EACCES
)
987 c
->mask
|= SD_BUS_CREDS_COMM
;
990 if (missing
& SD_BUS_CREDS_EXE
) {
991 r
= get_process_exe(pid
, &c
->exe
);
993 /* Unfortunately we cannot really distinguish
994 * the case here where the process does not
995 * exist, and /proc/$PID/exe being unreadable
996 * because $PID is a kernel thread. Hence,
997 * assume it is a kernel thread, and rely on
998 * that this case is caught with a later
1001 c
->mask
|= SD_BUS_CREDS_EXE
;
1003 if (r
!= -EPERM
&& r
!= -EACCES
)
1006 c
->mask
|= SD_BUS_CREDS_EXE
;
1009 if (missing
& SD_BUS_CREDS_CMDLINE
) {
1012 p
= procfs_file_alloca(pid
, "cmdline");
1013 r
= read_full_file(p
, &c
->cmdline
, &c
->cmdline_size
);
1017 if (r
!= -EPERM
&& r
!= -EACCES
)
1020 if (c
->cmdline_size
== 0)
1021 c
->cmdline
= mfree(c
->cmdline
);
1023 c
->mask
|= SD_BUS_CREDS_CMDLINE
;
1027 if (tid
> 0 && (missing
& SD_BUS_CREDS_TID_COMM
)) {
1028 _cleanup_free_
char *p
= NULL
;
1030 if (asprintf(&p
, "/proc/"PID_FMT
"/task/"PID_FMT
"/comm", pid
, tid
) < 0)
1033 r
= read_one_line_file(p
, &c
->tid_comm
);
1037 if (r
!= -EPERM
&& r
!= -EACCES
)
1040 c
->mask
|= SD_BUS_CREDS_TID_COMM
;
1043 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 r
= cg_pid_get_path(NULL
, pid
, &c
->cgroup
);
1048 if (r
!= -EPERM
&& r
!= -EACCES
)
1053 if (!c
->cgroup_root
) {
1054 r
= cg_get_root_path(&c
->cgroup_root
);
1060 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 if (missing
& SD_BUS_CREDS_AUDIT_SESSION_ID
) {
1064 r
= audit_session_from_pid(pid
, &c
->audit_session_id
);
1065 if (r
== -ENODATA
) {
1066 /* ENODATA means: no audit session id assigned */
1067 c
->audit_session_id
= AUDIT_SESSION_INVALID
;
1068 c
->mask
|= SD_BUS_CREDS_AUDIT_SESSION_ID
;
1070 if (r
!= -EOPNOTSUPP
&& r
!= -ENOENT
&& r
!= -EPERM
&& r
!= -EACCES
)
1073 c
->mask
|= SD_BUS_CREDS_AUDIT_SESSION_ID
;
1076 if (missing
& SD_BUS_CREDS_AUDIT_LOGIN_UID
) {
1077 r
= audit_loginuid_from_pid(pid
, &c
->audit_login_uid
);
1078 if (r
== -ENODATA
) {
1079 /* ENODATA means: no audit login uid assigned */
1080 c
->audit_login_uid
= UID_INVALID
;
1081 c
->mask
|= SD_BUS_CREDS_AUDIT_LOGIN_UID
;
1083 if (r
!= -EOPNOTSUPP
&& r
!= -ENOENT
&& r
!= -EPERM
&& r
!= -EACCES
)
1086 c
->mask
|= SD_BUS_CREDS_AUDIT_LOGIN_UID
;
1089 if (missing
& SD_BUS_CREDS_TTY
) {
1090 r
= get_ctty(pid
, NULL
, &c
->tty
);
1092 /* ENXIO means: process has no controlling TTY */
1094 c
->mask
|= SD_BUS_CREDS_TTY
;
1096 if (r
!= -EPERM
&& r
!= -EACCES
&& r
!= -ENOENT
)
1099 c
->mask
|= SD_BUS_CREDS_TTY
;
1102 /* In case only the exe path was to be read we cannot
1103 * distinguish the case where the exe path was unreadable
1104 * because the process was a kernel thread, or when the
1105 * process didn't exist at all. Hence, let's do a final check,
1107 if (!pid_is_alive(pid
))
1110 if (tid
> 0 && tid
!= pid
&& !pid_is_unwaited(tid
))
1113 c
->augmented
= missing
& c
->mask
;
1118 int bus_creds_extend_by_pid(sd_bus_creds
*c
, uint64_t mask
, sd_bus_creds
**ret
) {
1119 _cleanup_bus_creds_unref_ sd_bus_creds
*n
= NULL
;
1125 if ((mask
& ~c
->mask
) == 0 || (!(mask
& SD_BUS_CREDS_AUGMENT
))) {
1126 /* There's already all data we need, or augmentation
1127 * wasn't turned on. */
1129 *ret
= sd_bus_creds_ref(c
);
1133 n
= bus_creds_new();
1137 /* Copy the original data over */
1139 if (c
->mask
& mask
& SD_BUS_CREDS_PID
) {
1141 n
->mask
|= SD_BUS_CREDS_PID
;
1144 if (c
->mask
& mask
& SD_BUS_CREDS_TID
) {
1146 n
->mask
|= SD_BUS_CREDS_TID
;
1149 if (c
->mask
& mask
& SD_BUS_CREDS_PPID
) {
1151 n
->mask
|= SD_BUS_CREDS_PPID
;
1154 if (c
->mask
& mask
& SD_BUS_CREDS_UID
) {
1156 n
->mask
|= SD_BUS_CREDS_UID
;
1159 if (c
->mask
& mask
& SD_BUS_CREDS_EUID
) {
1161 n
->mask
|= SD_BUS_CREDS_EUID
;
1164 if (c
->mask
& mask
& SD_BUS_CREDS_SUID
) {
1166 n
->mask
|= SD_BUS_CREDS_SUID
;
1169 if (c
->mask
& mask
& SD_BUS_CREDS_FSUID
) {
1170 n
->fsuid
= c
->fsuid
;
1171 n
->mask
|= SD_BUS_CREDS_FSUID
;
1174 if (c
->mask
& mask
& SD_BUS_CREDS_GID
) {
1176 n
->mask
|= SD_BUS_CREDS_GID
;
1179 if (c
->mask
& mask
& SD_BUS_CREDS_EGID
) {
1181 n
->mask
|= SD_BUS_CREDS_EGID
;
1184 if (c
->mask
& mask
& SD_BUS_CREDS_SGID
) {
1186 n
->mask
|= SD_BUS_CREDS_SGID
;
1189 if (c
->mask
& mask
& SD_BUS_CREDS_FSGID
) {
1190 n
->fsgid
= c
->fsgid
;
1191 n
->mask
|= SD_BUS_CREDS_FSGID
;
1194 if (c
->mask
& mask
& SD_BUS_CREDS_SUPPLEMENTARY_GIDS
) {
1195 if (c
->supplementary_gids
) {
1196 n
->supplementary_gids
= newdup(gid_t
, c
->supplementary_gids
, c
->n_supplementary_gids
);
1197 if (!n
->supplementary_gids
)
1199 n
->n_supplementary_gids
= c
->n_supplementary_gids
;
1201 n
->supplementary_gids
= NULL
;
1202 n
->n_supplementary_gids
= 0;
1205 n
->mask
|= SD_BUS_CREDS_SUPPLEMENTARY_GIDS
;
1208 if (c
->mask
& mask
& SD_BUS_CREDS_COMM
) {
1211 n
->comm
= strdup(c
->comm
);
1215 n
->mask
|= SD_BUS_CREDS_COMM
;
1218 if (c
->mask
& mask
& SD_BUS_CREDS_TID_COMM
) {
1219 assert(c
->tid_comm
);
1221 n
->tid_comm
= strdup(c
->tid_comm
);
1225 n
->mask
|= SD_BUS_CREDS_TID_COMM
;
1228 if (c
->mask
& mask
& SD_BUS_CREDS_EXE
) {
1230 n
->exe
= strdup(c
->exe
);
1236 n
->mask
|= SD_BUS_CREDS_EXE
;
1239 if (c
->mask
& mask
& SD_BUS_CREDS_CMDLINE
) {
1241 n
->cmdline
= memdup(c
->cmdline
, c
->cmdline_size
);
1245 n
->cmdline_size
= c
->cmdline_size
;
1248 n
->cmdline_size
= 0;
1251 n
->mask
|= SD_BUS_CREDS_CMDLINE
;
1254 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 n
->cgroup
= strdup(c
->cgroup
);
1261 n
->cgroup_root
= strdup(c
->cgroup_root
);
1262 if (!n
->cgroup_root
)
1265 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 if (c
->mask
& mask
& (SD_BUS_CREDS_EFFECTIVE_CAPS
|SD_BUS_CREDS_PERMITTED_CAPS
|SD_BUS_CREDS_INHERITABLE_CAPS
|SD_BUS_CREDS_BOUNDING_CAPS
)) {
1269 assert(c
->capability
);
1271 n
->capability
= memdup(c
->capability
, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4);
1275 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 if (c
->mask
& mask
& SD_BUS_CREDS_SELINUX_CONTEXT
) {
1281 n
->label
= strdup(c
->label
);
1284 n
->mask
|= SD_BUS_CREDS_SELINUX_CONTEXT
;
1287 if (c
->mask
& mask
& SD_BUS_CREDS_AUDIT_SESSION_ID
) {
1288 n
->audit_session_id
= c
->audit_session_id
;
1289 n
->mask
|= SD_BUS_CREDS_AUDIT_SESSION_ID
;
1291 if (c
->mask
& mask
& SD_BUS_CREDS_AUDIT_LOGIN_UID
) {
1292 n
->audit_login_uid
= c
->audit_login_uid
;
1293 n
->mask
|= SD_BUS_CREDS_AUDIT_LOGIN_UID
;
1296 if (c
->mask
& mask
& SD_BUS_CREDS_TTY
) {
1298 n
->tty
= strdup(c
->tty
);
1303 n
->mask
|= SD_BUS_CREDS_TTY
;
1306 if (c
->mask
& mask
& SD_BUS_CREDS_UNIQUE_NAME
) {
1307 assert(c
->unique_name
);
1309 n
->unique_name
= strdup(c
->unique_name
);
1310 if (!n
->unique_name
)
1312 n
->mask
|= SD_BUS_CREDS_UNIQUE_NAME
;
1315 if (c
->mask
& mask
& SD_BUS_CREDS_WELL_KNOWN_NAMES
) {
1316 if (strv_isempty(c
->well_known_names
))
1317 n
->well_known_names
= NULL
;
1319 n
->well_known_names
= strv_copy(c
->well_known_names
);
1320 if (!n
->well_known_names
)
1323 n
->well_known_names_driver
= c
->well_known_names_driver
;
1324 n
->well_known_names_local
= c
->well_known_names_local
;
1325 n
->mask
|= SD_BUS_CREDS_WELL_KNOWN_NAMES
;
1328 if (c
->mask
& mask
& SD_BUS_CREDS_DESCRIPTION
) {
1329 assert(c
->description
);
1330 n
->description
= strdup(c
->description
);
1331 if (!n
->description
)
1333 n
->mask
|= SD_BUS_CREDS_DESCRIPTION
;
1336 n
->augmented
= c
->augmented
& n
->mask
;
1340 r
= bus_creds_add_more(n
, mask
, 0, 0);