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) {
99 m = container_of(c, sd_bus_message, creds);
100 sd_bus_message_unref(m);
107 _public_ uint64_t sd_bus_creds_get_mask(sd_bus_creds *c) {
113 sd_bus_creds* bus_creds_new(void) {
116 c = new0(sd_bus_creds, 1);
125 _public_ int sd_bus_creds_new_from_pid(pid_t pid, uint64_t mask, sd_bus_creds **ret) {
129 assert_return(pid >= 0, -EINVAL);
130 assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
131 assert_return(ret, -EINVAL);
140 r = bus_creds_add_more(c, mask, pid, 0);
146 /* Check if the process existed at all, in case we haven't
147 * figured that out already */
148 if (kill(pid, 0) < 0 && errno == ESRCH) {
149 sd_bus_creds_unref(c);
157 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
158 assert_return(c, -EINVAL);
159 assert_return(uid, -EINVAL);
161 if (!(c->mask & SD_BUS_CREDS_UID))
168 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
169 assert_return(c, -EINVAL);
170 assert_return(gid, -EINVAL);
172 if (!(c->mask & SD_BUS_CREDS_UID))
179 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
180 assert_return(c, -EINVAL);
181 assert_return(pid, -EINVAL);
183 if (!(c->mask & SD_BUS_CREDS_PID))
191 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
192 assert_return(c, -EINVAL);
193 assert_return(tid, -EINVAL);
195 if (!(c->mask & SD_BUS_CREDS_TID))
203 _public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
204 assert_return(c, -EINVAL);
205 assert_return(usec, -EINVAL);
207 if (!(c->mask & SD_BUS_CREDS_PID_STARTTIME))
210 assert(c->pid_starttime > 0);
211 *usec = c->pid_starttime;
215 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
216 assert_return(c, -EINVAL);
218 if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
226 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
227 assert_return(c, -EINVAL);
228 assert_return(ret, -EINVAL);
230 if (!(c->mask & SD_BUS_CREDS_COMM))
238 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
239 assert_return(c, -EINVAL);
240 assert_return(ret, -EINVAL);
242 if (!(c->mask & SD_BUS_CREDS_TID_COMM))
250 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
251 assert_return(c, -EINVAL);
252 assert_return(ret, -EINVAL);
254 if (!(c->mask & SD_BUS_CREDS_EXE))
262 _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
263 assert_return(c, -EINVAL);
264 assert_return(ret, -EINVAL);
266 if (!(c->mask & SD_BUS_CREDS_CGROUP))
274 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
277 assert_return(c, -EINVAL);
278 assert_return(ret, -EINVAL);
280 if (!(c->mask & SD_BUS_CREDS_UNIT))
286 r = cg_path_get_unit(c->cgroup, (char**) &c->unit);
295 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
298 assert_return(c, -EINVAL);
299 assert_return(ret, -EINVAL);
301 if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
307 r = cg_path_get_user_unit(c->cgroup, (char**) &c->user_unit);
316 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
319 assert_return(c, -EINVAL);
320 assert_return(ret, -EINVAL);
322 if (!(c->mask & SD_BUS_CREDS_SLICE))
328 r = cg_path_get_slice(c->cgroup, (char**) &c->slice);
337 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
340 assert_return(c, -EINVAL);
341 assert_return(ret, -EINVAL);
343 if (!(c->mask & SD_BUS_CREDS_SESSION))
349 r = cg_path_get_session(c->cgroup, (char**) &c->session);
358 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
359 assert_return(c, -EINVAL);
360 assert_return(uid, -EINVAL);
362 if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
367 return cg_path_get_owner_uid(c->cgroup, uid);
370 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
371 assert_return(c, -EINVAL);
373 if (!(c->mask & SD_BUS_CREDS_CMDLINE))
376 assert_return(c->cmdline, -ESRCH);
379 if (!c->cmdline_array) {
380 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
381 if (!c->cmdline_array)
385 *cmdline = c->cmdline_array;
389 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
390 assert_return(c, -EINVAL);
391 assert_return(sessionid, -EINVAL);
393 if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
396 *sessionid = c->audit_session_id;
400 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
401 assert_return(c, -EINVAL);
402 assert_return(uid, -EINVAL);
404 if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
407 *uid = c->audit_login_uid;
411 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
412 assert_return(c, -EINVAL);
413 assert_return(unique_name, -EINVAL);
415 if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
418 *unique_name = c->unique_name;
422 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
423 assert_return(c, -EINVAL);
424 assert_return(well_known_names, -EINVAL);
426 if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
429 *well_known_names = c->well_known_names;
433 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
437 assert(c->capability);
439 sz = c->capability_size / 4;
440 if ((size_t) capability >= sz*8)
443 return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
446 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
447 assert_return(c, -EINVAL);
448 assert_return(capability >= 0, -EINVAL);
450 if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
453 return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
456 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
457 assert_return(c, -EINVAL);
458 assert_return(capability >= 0, -EINVAL);
460 if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
463 return has_cap(c, CAP_OFFSET_PERMITTED, capability);
466 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
467 assert_return(c, -EINVAL);
468 assert_return(capability >= 0, -EINVAL);
470 if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
473 return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
476 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
477 assert_return(c, -EINVAL);
478 assert_return(capability >= 0, -EINVAL);
480 if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
483 return has_cap(c, CAP_OFFSET_BOUNDING, capability);
486 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
493 p += strspn(p, WHITESPACE);
500 if (!c->capability) {
501 c->capability = new0(uint8_t, sz * 4);
505 c->capability_size = sz * 4;
508 for (i = 0; i < sz; i ++) {
511 x = unhexchar(p[i*2]);
512 y = unhexchar(p[i*2+1]);
517 c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
523 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
528 assert(c->allocated);
530 missing = mask & ~c->mask;
534 /* Try to retrieve PID from creds if it wasn't passed to us */
535 if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
538 if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
541 /* Without pid we cannot do much... */
545 if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
546 SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
547 SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
549 _cleanup_fclose_ FILE *f = NULL;
553 p = procfs_file_alloca(pid, "status");
557 return errno == ENOENT ? -ESRCH : -errno;
559 FOREACH_LINE(line, f, return -errno) {
562 if (missing & SD_BUS_CREDS_UID) {
563 p = startswith(line, "Uid:");
567 p += strspn(p, WHITESPACE);
568 if (sscanf(p, "%lu", &uid) != 1)
571 c->uid = (uid_t) uid;
572 c->mask |= SD_BUS_CREDS_UID;
577 if (missing & SD_BUS_CREDS_GID) {
578 p = startswith(line, "Gid:");
582 p += strspn(p, WHITESPACE);
583 if (sscanf(p, "%lu", &gid) != 1)
586 c->gid = (uid_t) gid;
587 c->mask |= SD_BUS_CREDS_GID;
592 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
593 p = startswith(line, "CapEff:");
595 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
599 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
604 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
605 p = startswith(line, "CapPrm:");
607 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
611 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
616 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
617 p = startswith(line, "CapInh:");
619 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
623 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
628 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
629 p = startswith(line, "CapBnd:");
631 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
635 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
642 if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
643 unsigned long long st;
645 r = get_starttime_of_pid(pid, &st);
649 c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
650 c->mask |= SD_BUS_CREDS_PID_STARTTIME;
653 if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
656 p = procfs_file_alloca(pid, "attr/current");
657 r = read_one_line_file(p, &c->label);
658 if (r < 0 && r != -ENOENT && r != -EINVAL)
661 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
664 if (missing & SD_BUS_CREDS_COMM) {
665 r = get_process_comm(pid, &c->comm);
669 c->mask |= SD_BUS_CREDS_COMM;
672 if (missing & SD_BUS_CREDS_EXE) {
673 r = get_process_exe(pid, &c->exe);
677 c->mask |= SD_BUS_CREDS_EXE;
680 if (missing & SD_BUS_CREDS_CMDLINE) {
683 p = procfs_file_alloca(pid, "cmdline");
684 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
688 if (c->cmdline_size == 0) {
692 c->mask |= SD_BUS_CREDS_CMDLINE;
695 if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
696 _cleanup_free_ char *p = NULL;
698 if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0)
701 r = read_one_line_file(p, &c->tid_comm);
703 return r == -ENOENT ? -ESRCH : r;
705 c->mask |= SD_BUS_CREDS_TID_COMM;
708 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)) {
710 r = cg_pid_get_path(NULL, pid, &c->cgroup);
714 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);
717 if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
718 r = audit_session_from_pid(pid, &c->audit_session_id);
719 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
722 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
725 if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
726 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
727 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
730 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
736 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
737 _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
743 if ((mask & ~c->mask) == 0) {
744 /* There's already all data we need. */
746 *ret = sd_bus_creds_ref(c);
754 /* Copy the original data over */
756 if (c->mask & mask & SD_BUS_CREDS_UID) {
758 n->mask |= SD_BUS_CREDS_UID;
761 if (c->mask & mask & SD_BUS_CREDS_GID) {
763 n->mask |= SD_BUS_CREDS_GID;
766 if (c->mask & mask & SD_BUS_CREDS_PID) {
768 n->mask |= SD_BUS_CREDS_PID;
771 if (c->mask & mask & SD_BUS_CREDS_TID) {
773 n->mask |= SD_BUS_CREDS_TID;
776 if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
777 n->pid_starttime = c->pid_starttime;
778 n->mask |= SD_BUS_CREDS_PID_STARTTIME;
781 if (c->mask & mask & SD_BUS_CREDS_COMM) {
782 n->comm = strdup(c->comm);
786 n->mask |= SD_BUS_CREDS_COMM;
789 if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
790 n->tid_comm = strdup(c->tid_comm);
794 n->mask |= SD_BUS_CREDS_TID_COMM;
797 if (c->mask & mask & SD_BUS_CREDS_EXE) {
798 n->exe = strdup(c->exe);
802 n->mask |= SD_BUS_CREDS_EXE;
805 if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
806 n->cmdline = memdup(c->cmdline, c->cmdline_size);
810 n->cmdline_size = c->cmdline_size;
811 n->mask |= SD_BUS_CREDS_CMDLINE;
814 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)) {
815 n->cgroup = strdup(c->cgroup);
819 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);
822 if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
823 n->capability = memdup(c->capability, c->capability_size);
827 n->capability_size = c->capability_size;
828 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);
831 if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
832 n->audit_session_id = c->audit_session_id;
833 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
836 if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
837 n->audit_login_uid = c->audit_login_uid;
838 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
841 if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
842 n->unique_name = strdup(c->unique_name);
847 if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
848 n->well_known_names = strv_copy(c->well_known_names);
849 if (!n->well_known_names)
855 r = bus_creds_add_more(n, mask,
856 c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
857 c->mask & SD_BUS_CREDS_TID ? c->tid : 0);