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/>.
25 #include "cgroup-util.h"
28 #include "bus-message.h"
30 #include "time-util.h"
32 #include "bus-creds.h"
35 CAP_OFFSET_INHERITABLE = 0,
36 CAP_OFFSET_PERMITTED = 1,
37 CAP_OFFSET_EFFECTIVE = 2,
38 CAP_OFFSET_BOUNDING = 3
41 void bus_creds_done(sd_bus_creds *c) {
44 /* For internal bus cred structures that are allocated by
52 strv_free(c->cmdline_array);
53 strv_free(c->well_known_names);
56 _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
57 assert_return(c, NULL);
65 /* If this is an embedded creds structure, then
66 * forward ref counting to the message */
67 m = container_of(c, sd_bus_message, creds);
68 sd_bus_message_ref(m);
74 _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
101 m = container_of(c, sd_bus_message, creds);
102 sd_bus_message_unref(m);
109 _public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
115 sd_bus_creds* bus_creds_new(void) {
118 c = new0(sd_bus_creds, 1);
127 _public_ int sd_bus_creds_new_from_pid(pid_t pid, uint64_t mask, sd_bus_creds **ret) {
131 assert_return(pid >= 0, -EINVAL);
132 assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
133 assert_return(ret, -EINVAL);
142 r = bus_creds_add_more(c, mask, pid, 0);
144 sd_bus_creds_unref(c);
148 /* Check if the process existed at all, in case we haven't
149 * figured that out already */
150 if (kill(pid, 0) < 0 && errno == ESRCH) {
151 sd_bus_creds_unref(c);
159 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
160 assert_return(c, -EINVAL);
161 assert_return(uid, -EINVAL);
163 if (!(c->mask & SD_BUS_CREDS_UID))
170 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
171 assert_return(c, -EINVAL);
172 assert_return(gid, -EINVAL);
174 if (!(c->mask & SD_BUS_CREDS_UID))
181 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
182 assert_return(c, -EINVAL);
183 assert_return(pid, -EINVAL);
185 if (!(c->mask & SD_BUS_CREDS_PID))
193 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
194 assert_return(c, -EINVAL);
195 assert_return(tid, -EINVAL);
197 if (!(c->mask & SD_BUS_CREDS_TID))
205 _public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
206 assert_return(c, -EINVAL);
207 assert_return(usec, -EINVAL);
209 if (!(c->mask & SD_BUS_CREDS_PID_STARTTIME))
212 assert(c->pid_starttime > 0);
213 *usec = c->pid_starttime;
217 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
218 assert_return(c, -EINVAL);
220 if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
228 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
229 assert_return(c, -EINVAL);
230 assert_return(ret, -EINVAL);
232 if (!(c->mask & SD_BUS_CREDS_COMM))
240 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
241 assert_return(c, -EINVAL);
242 assert_return(ret, -EINVAL);
244 if (!(c->mask & SD_BUS_CREDS_TID_COMM))
252 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
253 assert_return(c, -EINVAL);
254 assert_return(ret, -EINVAL);
256 if (!(c->mask & SD_BUS_CREDS_EXE))
264 _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
265 assert_return(c, -EINVAL);
266 assert_return(ret, -EINVAL);
268 if (!(c->mask & SD_BUS_CREDS_CGROUP))
276 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
279 assert_return(c, -EINVAL);
280 assert_return(ret, -EINVAL);
282 if (!(c->mask & SD_BUS_CREDS_UNIT))
290 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
294 r = cg_path_get_unit(shifted, (char**) &c->unit);
303 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
306 assert_return(c, -EINVAL);
307 assert_return(ret, -EINVAL);
309 if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
317 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
321 r = cg_path_get_user_unit(shifted, (char**) &c->user_unit);
330 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
333 assert_return(c, -EINVAL);
334 assert_return(ret, -EINVAL);
336 if (!(c->mask & SD_BUS_CREDS_SLICE))
344 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
348 r = cg_path_get_slice(shifted, (char**) &c->slice);
357 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
360 assert_return(c, -EINVAL);
361 assert_return(ret, -EINVAL);
363 if (!(c->mask & SD_BUS_CREDS_SESSION))
371 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
375 r = cg_path_get_session(shifted, (char**) &c->session);
384 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
388 assert_return(c, -EINVAL);
389 assert_return(uid, -EINVAL);
391 if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
396 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
400 return cg_path_get_owner_uid(shifted, uid);
403 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
404 assert_return(c, -EINVAL);
406 if (!(c->mask & SD_BUS_CREDS_CMDLINE))
409 assert_return(c->cmdline, -ESRCH);
412 if (!c->cmdline_array) {
413 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
414 if (!c->cmdline_array)
418 *cmdline = c->cmdline_array;
422 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
423 assert_return(c, -EINVAL);
424 assert_return(sessionid, -EINVAL);
426 if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
429 *sessionid = c->audit_session_id;
433 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
434 assert_return(c, -EINVAL);
435 assert_return(uid, -EINVAL);
437 if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
440 *uid = c->audit_login_uid;
444 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
445 assert_return(c, -EINVAL);
446 assert_return(unique_name, -EINVAL);
448 if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
451 *unique_name = c->unique_name;
455 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
456 assert_return(c, -EINVAL);
457 assert_return(well_known_names, -EINVAL);
459 if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
462 *well_known_names = c->well_known_names;
466 _public_ int sd_bus_creds_get_connection_name(sd_bus_creds *c, const char **ret) {
467 assert_return(c, -EINVAL);
468 assert_return(ret, -EINVAL);
470 if (!(c->mask & SD_BUS_CREDS_CONNECTION_NAME))
473 assert(c->conn_name);
478 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
482 assert(c->capability);
484 sz = c->capability_size / 4;
485 if ((size_t) capability >= sz*8)
488 return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
491 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
492 assert_return(c, -EINVAL);
493 assert_return(capability >= 0, -EINVAL);
495 if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
498 return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
501 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
502 assert_return(c, -EINVAL);
503 assert_return(capability >= 0, -EINVAL);
505 if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
508 return has_cap(c, CAP_OFFSET_PERMITTED, capability);
511 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
512 assert_return(c, -EINVAL);
513 assert_return(capability >= 0, -EINVAL);
515 if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
518 return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
521 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
522 assert_return(c, -EINVAL);
523 assert_return(capability >= 0, -EINVAL);
525 if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
528 return has_cap(c, CAP_OFFSET_BOUNDING, capability);
531 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
538 p += strspn(p, WHITESPACE);
545 if (!c->capability) {
546 c->capability = new0(uint8_t, sz * 4);
550 c->capability_size = sz * 4;
553 for (i = 0; i < sz; i ++) {
556 x = unhexchar(p[i*2]);
557 y = unhexchar(p[i*2+1]);
562 c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
568 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
573 assert(c->allocated);
575 missing = mask & ~c->mask;
579 /* Try to retrieve PID from creds if it wasn't passed to us */
580 if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
583 if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
586 /* Without pid we cannot do much... */
590 if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
591 SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
592 SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
594 _cleanup_fclose_ FILE *f = NULL;
598 p = procfs_file_alloca(pid, "status");
602 return errno == ENOENT ? -ESRCH : -errno;
604 FOREACH_LINE(line, f, return -errno) {
607 if (missing & SD_BUS_CREDS_UID) {
608 p = startswith(line, "Uid:");
612 p += strspn(p, WHITESPACE);
613 if (sscanf(p, "%lu", &uid) != 1)
616 c->uid = (uid_t) uid;
617 c->mask |= SD_BUS_CREDS_UID;
622 if (missing & SD_BUS_CREDS_GID) {
623 p = startswith(line, "Gid:");
627 p += strspn(p, WHITESPACE);
628 if (sscanf(p, "%lu", &gid) != 1)
631 c->gid = (uid_t) gid;
632 c->mask |= SD_BUS_CREDS_GID;
637 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
638 p = startswith(line, "CapEff:");
640 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
644 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
649 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
650 p = startswith(line, "CapPrm:");
652 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
656 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
661 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
662 p = startswith(line, "CapInh:");
664 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
668 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
673 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
674 p = startswith(line, "CapBnd:");
676 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
680 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
687 if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
688 unsigned long long st;
690 r = get_starttime_of_pid(pid, &st);
694 c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
695 c->mask |= SD_BUS_CREDS_PID_STARTTIME;
698 if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
701 p = procfs_file_alloca(pid, "attr/current");
702 r = read_one_line_file(p, &c->label);
703 if (r < 0 && r != -ENOENT && r != -EINVAL)
706 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
709 if (missing & SD_BUS_CREDS_COMM) {
710 r = get_process_comm(pid, &c->comm);
714 c->mask |= SD_BUS_CREDS_COMM;
717 if (missing & SD_BUS_CREDS_EXE) {
718 r = get_process_exe(pid, &c->exe);
722 c->mask |= SD_BUS_CREDS_EXE;
725 if (missing & SD_BUS_CREDS_CMDLINE) {
728 p = procfs_file_alloca(pid, "cmdline");
729 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
733 if (c->cmdline_size == 0) {
737 c->mask |= SD_BUS_CREDS_CMDLINE;
740 if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
741 _cleanup_free_ char *p = NULL;
743 if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0)
746 r = read_one_line_file(p, &c->tid_comm);
748 return r == -ENOENT ? -ESRCH : r;
750 c->mask |= SD_BUS_CREDS_TID_COMM;
753 if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
755 r = cg_pid_get_path(NULL, pid, &c->cgroup);
759 r = cg_get_root_path(&c->cgroup_root);
763 c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID);
766 if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
767 r = audit_session_from_pid(pid, &c->audit_session_id);
768 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
771 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
774 if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
775 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
776 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
779 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
785 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
786 _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
792 if ((mask & ~c->mask) == 0) {
793 /* There's already all data we need. */
795 *ret = sd_bus_creds_ref(c);
803 /* Copy the original data over */
805 if (c->mask & mask & SD_BUS_CREDS_UID) {
807 n->mask |= SD_BUS_CREDS_UID;
810 if (c->mask & mask & SD_BUS_CREDS_GID) {
812 n->mask |= SD_BUS_CREDS_GID;
815 if (c->mask & mask & SD_BUS_CREDS_PID) {
817 n->mask |= SD_BUS_CREDS_PID;
820 if (c->mask & mask & SD_BUS_CREDS_TID) {
822 n->mask |= SD_BUS_CREDS_TID;
825 if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
826 n->pid_starttime = c->pid_starttime;
827 n->mask |= SD_BUS_CREDS_PID_STARTTIME;
830 if (c->mask & mask & SD_BUS_CREDS_COMM) {
831 n->comm = strdup(c->comm);
835 n->mask |= SD_BUS_CREDS_COMM;
838 if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
839 n->tid_comm = strdup(c->tid_comm);
843 n->mask |= SD_BUS_CREDS_TID_COMM;
846 if (c->mask & mask & SD_BUS_CREDS_EXE) {
847 n->exe = strdup(c->exe);
851 n->mask |= SD_BUS_CREDS_EXE;
854 if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
855 n->cmdline = memdup(c->cmdline, c->cmdline_size);
859 n->cmdline_size = c->cmdline_size;
860 n->mask |= SD_BUS_CREDS_CMDLINE;
863 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_OWNER_UID)) {
864 n->cgroup = strdup(c->cgroup);
868 n->cgroup_root = strdup(c->cgroup_root);
872 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_OWNER_UID);
875 if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
876 n->capability = memdup(c->capability, c->capability_size);
880 n->capability_size = c->capability_size;
881 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);
884 if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
885 n->audit_session_id = c->audit_session_id;
886 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
889 if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
890 n->audit_login_uid = c->audit_login_uid;
891 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
894 if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
895 n->unique_name = strdup(c->unique_name);
900 if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
901 n->well_known_names = strv_copy(c->well_known_names);
902 if (!n->well_known_names)
908 r = bus_creds_add_more(n, mask,
909 c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
910 c->mask & SD_BUS_CREDS_TID ? c->tid : 0);