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"
33 #include "bus-label.h"
36 CAP_OFFSET_INHERITABLE = 0,
37 CAP_OFFSET_PERMITTED = 1,
38 CAP_OFFSET_EFFECTIVE = 2,
39 CAP_OFFSET_BOUNDING = 3
42 void bus_creds_done(sd_bus_creds *c) {
45 /* For internal bus cred structures that are allocated by
52 free(c->unescaped_conn_name);
54 strv_free(c->cmdline_array);
55 strv_free(c->well_known_names);
58 _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
59 assert_return(c, NULL);
67 /* If this is an embedded creds structure, then
68 * forward ref counting to the message */
69 m = container_of(c, sd_bus_message, creds);
70 sd_bus_message_ref(m);
76 _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
103 m = container_of(c, sd_bus_message, creds);
104 sd_bus_message_unref(m);
111 _public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
117 sd_bus_creds* bus_creds_new(void) {
120 c = new0(sd_bus_creds, 1);
129 _public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
133 assert_return(pid >= 0, -EINVAL);
134 assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
135 assert_return(ret, -EINVAL);
144 r = bus_creds_add_more(c, mask, pid, 0);
146 sd_bus_creds_unref(c);
150 /* Check if the process existed at all, in case we haven't
151 * figured that out already */
152 if (!pid_is_alive(pid)) {
153 sd_bus_creds_unref(c);
161 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
162 assert_return(c, -EINVAL);
163 assert_return(uid, -EINVAL);
165 if (!(c->mask & SD_BUS_CREDS_UID))
172 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
173 assert_return(c, -EINVAL);
174 assert_return(gid, -EINVAL);
176 if (!(c->mask & SD_BUS_CREDS_UID))
183 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
184 assert_return(c, -EINVAL);
185 assert_return(pid, -EINVAL);
187 if (!(c->mask & SD_BUS_CREDS_PID))
195 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
196 assert_return(c, -EINVAL);
197 assert_return(tid, -EINVAL);
199 if (!(c->mask & SD_BUS_CREDS_TID))
207 _public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
208 assert_return(c, -EINVAL);
209 assert_return(usec, -EINVAL);
211 if (!(c->mask & SD_BUS_CREDS_PID_STARTTIME))
214 assert(c->pid_starttime > 0);
215 *usec = c->pid_starttime;
219 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
220 assert_return(c, -EINVAL);
222 if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
230 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
231 assert_return(c, -EINVAL);
232 assert_return(ret, -EINVAL);
234 if (!(c->mask & SD_BUS_CREDS_COMM))
242 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
243 assert_return(c, -EINVAL);
244 assert_return(ret, -EINVAL);
246 if (!(c->mask & SD_BUS_CREDS_TID_COMM))
254 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
255 assert_return(c, -EINVAL);
256 assert_return(ret, -EINVAL);
258 if (!(c->mask & SD_BUS_CREDS_EXE))
266 _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
267 assert_return(c, -EINVAL);
268 assert_return(ret, -EINVAL);
270 if (!(c->mask & SD_BUS_CREDS_CGROUP))
278 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
281 assert_return(c, -EINVAL);
282 assert_return(ret, -EINVAL);
284 if (!(c->mask & SD_BUS_CREDS_UNIT))
292 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
296 r = cg_path_get_unit(shifted, (char**) &c->unit);
305 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
308 assert_return(c, -EINVAL);
309 assert_return(ret, -EINVAL);
311 if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
319 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
323 r = cg_path_get_user_unit(shifted, (char**) &c->user_unit);
332 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
335 assert_return(c, -EINVAL);
336 assert_return(ret, -EINVAL);
338 if (!(c->mask & SD_BUS_CREDS_SLICE))
346 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
350 r = cg_path_get_slice(shifted, (char**) &c->slice);
359 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
362 assert_return(c, -EINVAL);
363 assert_return(ret, -EINVAL);
365 if (!(c->mask & SD_BUS_CREDS_SESSION))
373 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
377 r = cg_path_get_session(shifted, (char**) &c->session);
386 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
390 assert_return(c, -EINVAL);
391 assert_return(uid, -EINVAL);
393 if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
398 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
402 return cg_path_get_owner_uid(shifted, uid);
405 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
406 assert_return(c, -EINVAL);
408 if (!(c->mask & SD_BUS_CREDS_CMDLINE))
411 assert_return(c->cmdline, -ESRCH);
414 if (!c->cmdline_array) {
415 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
416 if (!c->cmdline_array)
420 *cmdline = c->cmdline_array;
424 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
425 assert_return(c, -EINVAL);
426 assert_return(sessionid, -EINVAL);
428 if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
431 *sessionid = c->audit_session_id;
435 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
436 assert_return(c, -EINVAL);
437 assert_return(uid, -EINVAL);
439 if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
442 *uid = c->audit_login_uid;
446 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
447 assert_return(c, -EINVAL);
448 assert_return(unique_name, -EINVAL);
450 if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
453 *unique_name = c->unique_name;
457 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
458 assert_return(c, -EINVAL);
459 assert_return(well_known_names, -EINVAL);
461 if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
464 *well_known_names = c->well_known_names;
468 _public_ int sd_bus_creds_get_connection_name(sd_bus_creds *c, const char **ret) {
469 assert_return(c, -EINVAL);
470 assert_return(ret, -EINVAL);
472 if (!(c->mask & SD_BUS_CREDS_CONNECTION_NAME))
475 assert(c->conn_name);
477 if (!c->unescaped_conn_name) {
478 c->unescaped_conn_name = bus_label_unescape(c->conn_name);
479 if (!c->unescaped_conn_name)
483 *ret = c->unescaped_conn_name;
487 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
491 assert(c->capability);
493 sz = c->capability_size / 4;
494 if ((size_t) capability >= sz*8)
497 return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
500 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
501 assert_return(c, -EINVAL);
502 assert_return(capability >= 0, -EINVAL);
504 if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
507 return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
510 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
511 assert_return(c, -EINVAL);
512 assert_return(capability >= 0, -EINVAL);
514 if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
517 return has_cap(c, CAP_OFFSET_PERMITTED, capability);
520 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
521 assert_return(c, -EINVAL);
522 assert_return(capability >= 0, -EINVAL);
524 if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
527 return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
530 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
531 assert_return(c, -EINVAL);
532 assert_return(capability >= 0, -EINVAL);
534 if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
537 return has_cap(c, CAP_OFFSET_BOUNDING, capability);
540 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
547 p += strspn(p, WHITESPACE);
554 if (!c->capability) {
555 c->capability = new0(uint8_t, sz * 4);
559 c->capability_size = sz * 4;
562 for (i = 0; i < sz; i ++) {
565 x = unhexchar(p[i*2]);
566 y = unhexchar(p[i*2+1]);
571 c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
577 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
582 assert(c->allocated);
584 missing = mask & ~c->mask;
588 /* Try to retrieve PID from creds if it wasn't passed to us */
589 if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
592 if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
595 /* Without pid we cannot do much... */
599 if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
600 SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
601 SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
603 _cleanup_fclose_ FILE *f = NULL;
607 p = procfs_file_alloca(pid, "status");
611 return errno == ENOENT ? -ESRCH : -errno;
613 FOREACH_LINE(line, f, return -errno) {
616 if (missing & SD_BUS_CREDS_UID) {
617 p = startswith(line, "Uid:");
621 p += strspn(p, WHITESPACE);
622 if (sscanf(p, "%lu", &uid) != 1)
625 c->uid = (uid_t) uid;
626 c->mask |= SD_BUS_CREDS_UID;
631 if (missing & SD_BUS_CREDS_GID) {
632 p = startswith(line, "Gid:");
636 p += strspn(p, WHITESPACE);
637 if (sscanf(p, "%lu", &gid) != 1)
640 c->gid = (uid_t) gid;
641 c->mask |= SD_BUS_CREDS_GID;
646 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
647 p = startswith(line, "CapEff:");
649 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
653 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
658 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
659 p = startswith(line, "CapPrm:");
661 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
665 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
670 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
671 p = startswith(line, "CapInh:");
673 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
677 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
682 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
683 p = startswith(line, "CapBnd:");
685 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
689 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
696 if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
697 unsigned long long st;
699 r = get_starttime_of_pid(pid, &st);
703 c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
704 c->mask |= SD_BUS_CREDS_PID_STARTTIME;
707 if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
710 p = procfs_file_alloca(pid, "attr/current");
711 r = read_one_line_file(p, &c->label);
712 if (r < 0 && r != -ENOENT && r != -EINVAL)
715 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
718 if (missing & SD_BUS_CREDS_COMM) {
719 r = get_process_comm(pid, &c->comm);
723 c->mask |= SD_BUS_CREDS_COMM;
726 if (missing & SD_BUS_CREDS_EXE) {
727 r = get_process_exe(pid, &c->exe);
731 c->mask |= SD_BUS_CREDS_EXE;
734 if (missing & SD_BUS_CREDS_CMDLINE) {
737 p = procfs_file_alloca(pid, "cmdline");
738 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
742 if (c->cmdline_size == 0) {
746 c->mask |= SD_BUS_CREDS_CMDLINE;
749 if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
750 _cleanup_free_ char *p = NULL;
752 if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
755 r = read_one_line_file(p, &c->tid_comm);
757 return r == -ENOENT ? -ESRCH : r;
759 c->mask |= SD_BUS_CREDS_TID_COMM;
762 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)) {
764 r = cg_pid_get_path(NULL, pid, &c->cgroup);
768 r = cg_get_root_path(&c->cgroup_root);
772 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);
775 if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
776 r = audit_session_from_pid(pid, &c->audit_session_id);
777 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
780 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
783 if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
784 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
785 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
788 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
794 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
795 _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
801 if ((mask & ~c->mask) == 0) {
802 /* There's already all data we need. */
804 *ret = sd_bus_creds_ref(c);
812 /* Copy the original data over */
814 if (c->mask & mask & SD_BUS_CREDS_UID) {
816 n->mask |= SD_BUS_CREDS_UID;
819 if (c->mask & mask & SD_BUS_CREDS_GID) {
821 n->mask |= SD_BUS_CREDS_GID;
824 if (c->mask & mask & SD_BUS_CREDS_PID) {
826 n->mask |= SD_BUS_CREDS_PID;
829 if (c->mask & mask & SD_BUS_CREDS_TID) {
831 n->mask |= SD_BUS_CREDS_TID;
834 if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
835 n->pid_starttime = c->pid_starttime;
836 n->mask |= SD_BUS_CREDS_PID_STARTTIME;
839 if (c->mask & mask & SD_BUS_CREDS_COMM) {
840 n->comm = strdup(c->comm);
844 n->mask |= SD_BUS_CREDS_COMM;
847 if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
848 n->tid_comm = strdup(c->tid_comm);
852 n->mask |= SD_BUS_CREDS_TID_COMM;
855 if (c->mask & mask & SD_BUS_CREDS_EXE) {
856 n->exe = strdup(c->exe);
860 n->mask |= SD_BUS_CREDS_EXE;
863 if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
864 n->cmdline = memdup(c->cmdline, c->cmdline_size);
868 n->cmdline_size = c->cmdline_size;
869 n->mask |= SD_BUS_CREDS_CMDLINE;
872 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)) {
873 n->cgroup = strdup(c->cgroup);
877 n->cgroup_root = strdup(c->cgroup_root);
881 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);
884 if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
885 n->capability = memdup(c->capability, c->capability_size);
889 n->capability_size = c->capability_size;
890 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);
893 if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
894 n->audit_session_id = c->audit_session_id;
895 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
898 if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
899 n->audit_login_uid = c->audit_login_uid;
900 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
903 if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
904 n->unique_name = strdup(c->unique_name);
909 if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
910 n->well_known_names = strv_copy(c->well_known_names);
911 if (!n->well_known_names)
917 r = bus_creds_add_more(n, mask,
918 c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
919 c->mask & SD_BUS_CREDS_TID ? c->tid : 0);