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) {
100 m = container_of(c, sd_bus_message, creds);
101 sd_bus_message_unref(m);
108 _public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
114 sd_bus_creds* bus_creds_new(void) {
117 c = new0(sd_bus_creds, 1);
126 _public_ int sd_bus_creds_new_from_pid(pid_t pid, uint64_t mask, sd_bus_creds **ret) {
130 assert_return(pid >= 0, -EINVAL);
131 assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
132 assert_return(ret, -EINVAL);
141 r = bus_creds_add_more(c, mask, pid, 0);
143 sd_bus_creds_unref(c);
147 /* Check if the process existed at all, in case we haven't
148 * figured that out already */
149 if (kill(pid, 0) < 0 && errno == ESRCH) {
150 sd_bus_creds_unref(c);
158 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
159 assert_return(c, -EINVAL);
160 assert_return(uid, -EINVAL);
162 if (!(c->mask & SD_BUS_CREDS_UID))
169 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
170 assert_return(c, -EINVAL);
171 assert_return(gid, -EINVAL);
173 if (!(c->mask & SD_BUS_CREDS_UID))
180 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
181 assert_return(c, -EINVAL);
182 assert_return(pid, -EINVAL);
184 if (!(c->mask & SD_BUS_CREDS_PID))
192 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
193 assert_return(c, -EINVAL);
194 assert_return(tid, -EINVAL);
196 if (!(c->mask & SD_BUS_CREDS_TID))
204 _public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
205 assert_return(c, -EINVAL);
206 assert_return(usec, -EINVAL);
208 if (!(c->mask & SD_BUS_CREDS_PID_STARTTIME))
211 assert(c->pid_starttime > 0);
212 *usec = c->pid_starttime;
216 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
217 assert_return(c, -EINVAL);
219 if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
227 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
228 assert_return(c, -EINVAL);
229 assert_return(ret, -EINVAL);
231 if (!(c->mask & SD_BUS_CREDS_COMM))
239 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
240 assert_return(c, -EINVAL);
241 assert_return(ret, -EINVAL);
243 if (!(c->mask & SD_BUS_CREDS_TID_COMM))
251 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
252 assert_return(c, -EINVAL);
253 assert_return(ret, -EINVAL);
255 if (!(c->mask & SD_BUS_CREDS_EXE))
263 _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
264 assert_return(c, -EINVAL);
265 assert_return(ret, -EINVAL);
267 if (!(c->mask & SD_BUS_CREDS_CGROUP))
275 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
278 assert_return(c, -EINVAL);
279 assert_return(ret, -EINVAL);
281 if (!(c->mask & SD_BUS_CREDS_UNIT))
289 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
293 r = cg_path_get_unit(shifted, (char**) &c->unit);
302 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
305 assert_return(c, -EINVAL);
306 assert_return(ret, -EINVAL);
308 if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
316 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
320 r = cg_path_get_user_unit(shifted, (char**) &c->user_unit);
329 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
332 assert_return(c, -EINVAL);
333 assert_return(ret, -EINVAL);
335 if (!(c->mask & SD_BUS_CREDS_SLICE))
343 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
347 r = cg_path_get_slice(shifted, (char**) &c->slice);
356 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
359 assert_return(c, -EINVAL);
360 assert_return(ret, -EINVAL);
362 if (!(c->mask & SD_BUS_CREDS_SESSION))
370 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
374 r = cg_path_get_session(shifted, (char**) &c->session);
383 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
387 assert_return(c, -EINVAL);
388 assert_return(uid, -EINVAL);
390 if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
395 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
399 return cg_path_get_owner_uid(shifted, uid);
402 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
403 assert_return(c, -EINVAL);
405 if (!(c->mask & SD_BUS_CREDS_CMDLINE))
408 assert_return(c->cmdline, -ESRCH);
411 if (!c->cmdline_array) {
412 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
413 if (!c->cmdline_array)
417 *cmdline = c->cmdline_array;
421 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
422 assert_return(c, -EINVAL);
423 assert_return(sessionid, -EINVAL);
425 if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
428 *sessionid = c->audit_session_id;
432 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
433 assert_return(c, -EINVAL);
434 assert_return(uid, -EINVAL);
436 if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
439 *uid = c->audit_login_uid;
443 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
444 assert_return(c, -EINVAL);
445 assert_return(unique_name, -EINVAL);
447 if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
450 *unique_name = c->unique_name;
454 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
455 assert_return(c, -EINVAL);
456 assert_return(well_known_names, -EINVAL);
458 if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
461 *well_known_names = c->well_known_names;
465 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
469 assert(c->capability);
471 sz = c->capability_size / 4;
472 if ((size_t) capability >= sz*8)
475 return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
478 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
479 assert_return(c, -EINVAL);
480 assert_return(capability >= 0, -EINVAL);
482 if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
485 return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
488 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
489 assert_return(c, -EINVAL);
490 assert_return(capability >= 0, -EINVAL);
492 if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
495 return has_cap(c, CAP_OFFSET_PERMITTED, capability);
498 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
499 assert_return(c, -EINVAL);
500 assert_return(capability >= 0, -EINVAL);
502 if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
505 return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
508 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
509 assert_return(c, -EINVAL);
510 assert_return(capability >= 0, -EINVAL);
512 if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
515 return has_cap(c, CAP_OFFSET_BOUNDING, capability);
518 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
525 p += strspn(p, WHITESPACE);
532 if (!c->capability) {
533 c->capability = new0(uint8_t, sz * 4);
537 c->capability_size = sz * 4;
540 for (i = 0; i < sz; i ++) {
543 x = unhexchar(p[i*2]);
544 y = unhexchar(p[i*2+1]);
549 c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
555 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
560 assert(c->allocated);
562 missing = mask & ~c->mask;
566 /* Try to retrieve PID from creds if it wasn't passed to us */
567 if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
570 if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
573 /* Without pid we cannot do much... */
577 if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
578 SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
579 SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
581 _cleanup_fclose_ FILE *f = NULL;
585 p = procfs_file_alloca(pid, "status");
589 return errno == ENOENT ? -ESRCH : -errno;
591 FOREACH_LINE(line, f, return -errno) {
594 if (missing & SD_BUS_CREDS_UID) {
595 p = startswith(line, "Uid:");
599 p += strspn(p, WHITESPACE);
600 if (sscanf(p, "%lu", &uid) != 1)
603 c->uid = (uid_t) uid;
604 c->mask |= SD_BUS_CREDS_UID;
609 if (missing & SD_BUS_CREDS_GID) {
610 p = startswith(line, "Gid:");
614 p += strspn(p, WHITESPACE);
615 if (sscanf(p, "%lu", &gid) != 1)
618 c->gid = (uid_t) gid;
619 c->mask |= SD_BUS_CREDS_GID;
624 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
625 p = startswith(line, "CapEff:");
627 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
631 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
636 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
637 p = startswith(line, "CapPrm:");
639 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
643 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
648 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
649 p = startswith(line, "CapInh:");
651 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
655 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
660 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
661 p = startswith(line, "CapBnd:");
663 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
667 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
674 if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
675 unsigned long long st;
677 r = get_starttime_of_pid(pid, &st);
681 c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
682 c->mask |= SD_BUS_CREDS_PID_STARTTIME;
685 if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
688 p = procfs_file_alloca(pid, "attr/current");
689 r = read_one_line_file(p, &c->label);
690 if (r < 0 && r != -ENOENT && r != -EINVAL)
693 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
696 if (missing & SD_BUS_CREDS_COMM) {
697 r = get_process_comm(pid, &c->comm);
701 c->mask |= SD_BUS_CREDS_COMM;
704 if (missing & SD_BUS_CREDS_EXE) {
705 r = get_process_exe(pid, &c->exe);
709 c->mask |= SD_BUS_CREDS_EXE;
712 if (missing & SD_BUS_CREDS_CMDLINE) {
715 p = procfs_file_alloca(pid, "cmdline");
716 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
720 if (c->cmdline_size == 0) {
724 c->mask |= SD_BUS_CREDS_CMDLINE;
727 if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
728 _cleanup_free_ char *p = NULL;
730 if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0)
733 r = read_one_line_file(p, &c->tid_comm);
735 return r == -ENOENT ? -ESRCH : r;
737 c->mask |= SD_BUS_CREDS_TID_COMM;
740 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)) {
742 r = cg_pid_get_path(NULL, pid, &c->cgroup);
746 r = cg_get_root_path(&c->cgroup_root);
750 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);
753 if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
754 r = audit_session_from_pid(pid, &c->audit_session_id);
755 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
758 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
761 if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
762 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
763 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
766 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
772 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
773 _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
779 if ((mask & ~c->mask) == 0) {
780 /* There's already all data we need. */
782 *ret = sd_bus_creds_ref(c);
790 /* Copy the original data over */
792 if (c->mask & mask & SD_BUS_CREDS_UID) {
794 n->mask |= SD_BUS_CREDS_UID;
797 if (c->mask & mask & SD_BUS_CREDS_GID) {
799 n->mask |= SD_BUS_CREDS_GID;
802 if (c->mask & mask & SD_BUS_CREDS_PID) {
804 n->mask |= SD_BUS_CREDS_PID;
807 if (c->mask & mask & SD_BUS_CREDS_TID) {
809 n->mask |= SD_BUS_CREDS_TID;
812 if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
813 n->pid_starttime = c->pid_starttime;
814 n->mask |= SD_BUS_CREDS_PID_STARTTIME;
817 if (c->mask & mask & SD_BUS_CREDS_COMM) {
818 n->comm = strdup(c->comm);
822 n->mask |= SD_BUS_CREDS_COMM;
825 if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
826 n->tid_comm = strdup(c->tid_comm);
830 n->mask |= SD_BUS_CREDS_TID_COMM;
833 if (c->mask & mask & SD_BUS_CREDS_EXE) {
834 n->exe = strdup(c->exe);
838 n->mask |= SD_BUS_CREDS_EXE;
841 if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
842 n->cmdline = memdup(c->cmdline, c->cmdline_size);
846 n->cmdline_size = c->cmdline_size;
847 n->mask |= SD_BUS_CREDS_CMDLINE;
850 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)) {
851 n->cgroup = strdup(c->cgroup);
855 n->cgroup_root = strdup(c->cgroup_root);
859 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);
862 if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
863 n->capability = memdup(c->capability, c->capability_size);
867 n->capability_size = c->capability_size;
868 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);
871 if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
872 n->audit_session_id = c->audit_session_id;
873 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
876 if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
877 n->audit_login_uid = c->audit_login_uid;
878 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
881 if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
882 n->unique_name = strdup(c->unique_name);
887 if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
888 n->well_known_names = strv_copy(c->well_known_names);
889 if (!n->well_known_names)
895 r = bus_creds_add_more(n, mask,
896 c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
897 c->mask & SD_BUS_CREDS_TID ? c->tid : 0);