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
51 free(c->unescaped_conn_name);
53 strv_free(c->cmdline_array);
54 strv_free(c->well_known_names);
57 _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
58 assert_return(c, NULL);
66 /* If this is an embedded creds structure, then
67 * forward ref counting to the message */
68 m = container_of(c, sd_bus_message, creds);
69 sd_bus_message_ref(m);
75 _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
102 m = container_of(c, sd_bus_message, creds);
103 sd_bus_message_unref(m);
110 _public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
116 sd_bus_creds* bus_creds_new(void) {
119 c = new0(sd_bus_creds, 1);
128 _public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
132 assert_return(pid >= 0, -EINVAL);
133 assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
134 assert_return(ret, -EINVAL);
143 r = bus_creds_add_more(c, mask, pid, 0);
145 sd_bus_creds_unref(c);
149 /* Check if the process existed at all, in case we haven't
150 * figured that out already */
151 if (!pid_is_alive(pid)) {
152 sd_bus_creds_unref(c);
160 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
161 assert_return(c, -EINVAL);
162 assert_return(uid, -EINVAL);
164 if (!(c->mask & SD_BUS_CREDS_UID))
171 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
172 assert_return(c, -EINVAL);
173 assert_return(gid, -EINVAL);
175 if (!(c->mask & SD_BUS_CREDS_UID))
182 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
183 assert_return(c, -EINVAL);
184 assert_return(pid, -EINVAL);
186 if (!(c->mask & SD_BUS_CREDS_PID))
194 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
195 assert_return(c, -EINVAL);
196 assert_return(tid, -EINVAL);
198 if (!(c->mask & SD_BUS_CREDS_TID))
206 _public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
207 assert_return(c, -EINVAL);
208 assert_return(usec, -EINVAL);
210 if (!(c->mask & SD_BUS_CREDS_PID_STARTTIME))
213 assert(c->pid_starttime > 0);
214 *usec = c->pid_starttime;
218 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
219 assert_return(c, -EINVAL);
221 if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
229 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
230 assert_return(c, -EINVAL);
231 assert_return(ret, -EINVAL);
233 if (!(c->mask & SD_BUS_CREDS_COMM))
241 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
242 assert_return(c, -EINVAL);
243 assert_return(ret, -EINVAL);
245 if (!(c->mask & SD_BUS_CREDS_TID_COMM))
253 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
254 assert_return(c, -EINVAL);
255 assert_return(ret, -EINVAL);
257 if (!(c->mask & SD_BUS_CREDS_EXE))
265 _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
266 assert_return(c, -EINVAL);
267 assert_return(ret, -EINVAL);
269 if (!(c->mask & SD_BUS_CREDS_CGROUP))
277 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
280 assert_return(c, -EINVAL);
281 assert_return(ret, -EINVAL);
283 if (!(c->mask & SD_BUS_CREDS_UNIT))
291 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
295 r = cg_path_get_unit(shifted, (char**) &c->unit);
304 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
307 assert_return(c, -EINVAL);
308 assert_return(ret, -EINVAL);
310 if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
318 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
322 r = cg_path_get_user_unit(shifted, (char**) &c->user_unit);
331 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
334 assert_return(c, -EINVAL);
335 assert_return(ret, -EINVAL);
337 if (!(c->mask & SD_BUS_CREDS_SLICE))
345 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
349 r = cg_path_get_slice(shifted, (char**) &c->slice);
358 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
361 assert_return(c, -EINVAL);
362 assert_return(ret, -EINVAL);
364 if (!(c->mask & SD_BUS_CREDS_SESSION))
372 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
376 r = cg_path_get_session(shifted, (char**) &c->session);
385 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
389 assert_return(c, -EINVAL);
390 assert_return(uid, -EINVAL);
392 if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
397 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
401 return cg_path_get_owner_uid(shifted, uid);
404 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
405 assert_return(c, -EINVAL);
407 if (!(c->mask & SD_BUS_CREDS_CMDLINE))
410 assert_return(c->cmdline, -ESRCH);
413 if (!c->cmdline_array) {
414 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
415 if (!c->cmdline_array)
419 *cmdline = c->cmdline_array;
423 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
424 assert_return(c, -EINVAL);
425 assert_return(sessionid, -EINVAL);
427 if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
430 *sessionid = c->audit_session_id;
434 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
435 assert_return(c, -EINVAL);
436 assert_return(uid, -EINVAL);
438 if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
441 *uid = c->audit_login_uid;
445 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
446 assert_return(c, -EINVAL);
447 assert_return(unique_name, -EINVAL);
449 if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
452 *unique_name = c->unique_name;
456 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
457 assert_return(c, -EINVAL);
458 assert_return(well_known_names, -EINVAL);
460 if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
463 *well_known_names = c->well_known_names;
467 _public_ int sd_bus_creds_get_connection_name(sd_bus_creds *c, const char **ret) {
468 assert_return(c, -EINVAL);
469 assert_return(ret, -EINVAL);
471 if (!(c->mask & SD_BUS_CREDS_CONNECTION_NAME))
474 assert(c->conn_name);
476 if (!c->unescaped_conn_name) {
477 c->unescaped_conn_name = sd_bus_label_unescape(c->conn_name);
478 if (!c->unescaped_conn_name)
482 *ret = c->unescaped_conn_name;
486 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
490 assert(c->capability);
492 sz = c->capability_size / 4;
493 if ((size_t) capability >= sz*8)
496 return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
499 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
500 assert_return(c, -EINVAL);
501 assert_return(capability >= 0, -EINVAL);
503 if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
506 return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
509 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
510 assert_return(c, -EINVAL);
511 assert_return(capability >= 0, -EINVAL);
513 if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
516 return has_cap(c, CAP_OFFSET_PERMITTED, capability);
519 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
520 assert_return(c, -EINVAL);
521 assert_return(capability >= 0, -EINVAL);
523 if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
526 return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
529 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
530 assert_return(c, -EINVAL);
531 assert_return(capability >= 0, -EINVAL);
533 if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
536 return has_cap(c, CAP_OFFSET_BOUNDING, capability);
539 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
546 p += strspn(p, WHITESPACE);
553 if (!c->capability) {
554 c->capability = new0(uint8_t, sz * 4);
558 c->capability_size = sz * 4;
561 for (i = 0; i < sz; i ++) {
564 x = unhexchar(p[i*2]);
565 y = unhexchar(p[i*2+1]);
570 c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
576 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
581 assert(c->allocated);
583 missing = mask & ~c->mask;
587 /* Try to retrieve PID from creds if it wasn't passed to us */
588 if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
591 if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
594 /* Without pid we cannot do much... */
598 if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
599 SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
600 SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
602 _cleanup_fclose_ FILE *f = NULL;
606 p = procfs_file_alloca(pid, "status");
610 return errno == ENOENT ? -ESRCH : -errno;
612 FOREACH_LINE(line, f, return -errno) {
615 if (missing & SD_BUS_CREDS_UID) {
616 p = startswith(line, "Uid:");
620 p += strspn(p, WHITESPACE);
621 if (sscanf(p, "%lu", &uid) != 1)
624 c->uid = (uid_t) uid;
625 c->mask |= SD_BUS_CREDS_UID;
630 if (missing & SD_BUS_CREDS_GID) {
631 p = startswith(line, "Gid:");
635 p += strspn(p, WHITESPACE);
636 if (sscanf(p, "%lu", &gid) != 1)
639 c->gid = (uid_t) gid;
640 c->mask |= SD_BUS_CREDS_GID;
645 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
646 p = startswith(line, "CapEff:");
648 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
652 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
657 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
658 p = startswith(line, "CapPrm:");
660 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
664 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
669 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
670 p = startswith(line, "CapInh:");
672 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
676 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
681 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
682 p = startswith(line, "CapBnd:");
684 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
688 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
695 if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
696 unsigned long long st;
698 r = get_starttime_of_pid(pid, &st);
702 c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
703 c->mask |= SD_BUS_CREDS_PID_STARTTIME;
706 if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
709 p = procfs_file_alloca(pid, "attr/current");
710 r = read_one_line_file(p, &c->label);
711 if (r < 0 && r != -ENOENT && r != -EINVAL)
714 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
717 if (missing & SD_BUS_CREDS_COMM) {
718 r = get_process_comm(pid, &c->comm);
722 c->mask |= SD_BUS_CREDS_COMM;
725 if (missing & SD_BUS_CREDS_EXE) {
726 r = get_process_exe(pid, &c->exe);
730 c->mask |= SD_BUS_CREDS_EXE;
733 if (missing & SD_BUS_CREDS_CMDLINE) {
736 p = procfs_file_alloca(pid, "cmdline");
737 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
741 if (c->cmdline_size == 0) {
745 c->mask |= SD_BUS_CREDS_CMDLINE;
748 if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
749 _cleanup_free_ char *p = NULL;
751 if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0)
754 r = read_one_line_file(p, &c->tid_comm);
756 return r == -ENOENT ? -ESRCH : r;
758 c->mask |= SD_BUS_CREDS_TID_COMM;
761 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)) {
763 r = cg_pid_get_path(NULL, pid, &c->cgroup);
767 r = cg_get_root_path(&c->cgroup_root);
771 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);
774 if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
775 r = audit_session_from_pid(pid, &c->audit_session_id);
776 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
779 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
782 if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
783 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
784 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
787 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
793 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
794 _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
800 if ((mask & ~c->mask) == 0) {
801 /* There's already all data we need. */
803 *ret = sd_bus_creds_ref(c);
811 /* Copy the original data over */
813 if (c->mask & mask & SD_BUS_CREDS_UID) {
815 n->mask |= SD_BUS_CREDS_UID;
818 if (c->mask & mask & SD_BUS_CREDS_GID) {
820 n->mask |= SD_BUS_CREDS_GID;
823 if (c->mask & mask & SD_BUS_CREDS_PID) {
825 n->mask |= SD_BUS_CREDS_PID;
828 if (c->mask & mask & SD_BUS_CREDS_TID) {
830 n->mask |= SD_BUS_CREDS_TID;
833 if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
834 n->pid_starttime = c->pid_starttime;
835 n->mask |= SD_BUS_CREDS_PID_STARTTIME;
838 if (c->mask & mask & SD_BUS_CREDS_COMM) {
839 n->comm = strdup(c->comm);
843 n->mask |= SD_BUS_CREDS_COMM;
846 if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
847 n->tid_comm = strdup(c->tid_comm);
851 n->mask |= SD_BUS_CREDS_TID_COMM;
854 if (c->mask & mask & SD_BUS_CREDS_EXE) {
855 n->exe = strdup(c->exe);
859 n->mask |= SD_BUS_CREDS_EXE;
862 if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
863 n->cmdline = memdup(c->cmdline, c->cmdline_size);
867 n->cmdline_size = c->cmdline_size;
868 n->mask |= SD_BUS_CREDS_CMDLINE;
871 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)) {
872 n->cgroup = strdup(c->cgroup);
876 n->cgroup_root = strdup(c->cgroup_root);
880 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);
883 if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
884 n->capability = memdup(c->capability, c->capability_size);
888 n->capability_size = c->capability_size;
889 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);
892 if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
893 n->audit_session_id = c->audit_session_id;
894 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
897 if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
898 n->audit_login_uid = c->audit_login_uid;
899 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
902 if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
903 n->unique_name = strdup(c->unique_name);
908 if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
909 n->well_known_names = strv_copy(c->well_known_names);
910 if (!n->well_known_names)
916 r = bus_creds_add_more(n, mask,
917 c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
918 c->mask & SD_BUS_CREDS_TID ? c->tid : 0);