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) {
75 assert_return(c, NULL);
97 m = container_of(c, sd_bus_message, creds);
98 sd_bus_message_unref(m);
105 _public_ uint64_t sd_bus_creds_get_mask(sd_bus_creds *c) {
111 sd_bus_creds* bus_creds_new(void) {
114 c = new0(sd_bus_creds, 1);
123 _public_ int sd_bus_creds_new_from_pid(pid_t pid, uint64_t mask, sd_bus_creds **ret) {
127 assert_return(pid >= 0, -EINVAL);
128 assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
129 assert_return(ret, -EINVAL);
138 r = bus_creds_add_more(c, mask, pid, 0);
144 /* Check if the process existed at all, in case we haven't
145 * figured that out already */
146 if (kill(pid, 0) < 0 && errno == ESRCH) {
147 sd_bus_creds_unref(c);
155 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
156 assert_return(c, -EINVAL);
157 assert_return(uid, -EINVAL);
158 assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA);
164 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
165 assert_return(c, -EINVAL);
166 assert_return(gid, -EINVAL);
167 assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA);
173 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
174 assert_return(c, -EINVAL);
175 assert_return(pid, -EINVAL);
176 assert_return(c->mask & SD_BUS_CREDS_PID, -ENODATA);
183 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
184 assert_return(c, -EINVAL);
185 assert_return(tid, -EINVAL);
186 assert_return(c->mask & SD_BUS_CREDS_TID, -ENODATA);
193 _public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
194 assert_return(c, -EINVAL);
195 assert_return(usec, -EINVAL);
196 assert_return(c->mask & SD_BUS_CREDS_PID_STARTTIME, -ENODATA);
198 assert(c->pid_starttime > 0);
199 *usec = c->pid_starttime;
203 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
204 assert_return(c, -EINVAL);
205 assert_return(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT, -ENODATA);
212 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
213 assert_return(c, -EINVAL);
214 assert_return(ret, -EINVAL);
215 assert_return(c->mask & SD_BUS_CREDS_COMM, -ENODATA);
222 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
223 assert_return(c, -EINVAL);
224 assert_return(ret, -EINVAL);
225 assert_return(c->mask & SD_BUS_CREDS_TID_COMM, -ENODATA);
232 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
233 assert_return(c, -EINVAL);
234 assert_return(ret, -EINVAL);
235 assert_return(c->mask & SD_BUS_CREDS_EXE, -ENODATA);
242 _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
243 assert_return(c, -EINVAL);
244 assert_return(ret, -EINVAL);
245 assert_return(c->mask & SD_BUS_CREDS_CGROUP, -ENODATA);
252 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
255 assert_return(c, -EINVAL);
256 assert_return(ret, -EINVAL);
257 assert_return(c->mask & SD_BUS_CREDS_UNIT, -ENODATA);
262 r = cg_path_get_unit(c->cgroup, (char**) &c->unit);
271 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
274 assert_return(c, -EINVAL);
275 assert_return(ret, -EINVAL);
276 assert_return(c->mask & SD_BUS_CREDS_USER_UNIT, -ENODATA);
281 r = cg_path_get_user_unit(c->cgroup, (char**) &c->user_unit);
290 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
293 assert_return(c, -EINVAL);
294 assert_return(ret, -EINVAL);
295 assert_return(c->mask & SD_BUS_CREDS_SLICE, -ENODATA);
300 r = cg_path_get_slice(c->cgroup, (char**) &c->slice);
309 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
312 assert_return(c, -EINVAL);
313 assert_return(ret, -EINVAL);
314 assert_return(c->mask & SD_BUS_CREDS_SESSION, -ENODATA);
319 r = cg_path_get_session(c->cgroup, (char**) &c->session);
328 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
329 assert_return(c, -EINVAL);
330 assert_return(uid, -EINVAL);
331 assert_return(c->mask & SD_BUS_CREDS_OWNER_UID, -ENODATA);
335 return cg_path_get_owner_uid(c->cgroup, uid);
338 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
339 assert_return(c, -EINVAL);
340 assert_return(c->cmdline, -ESRCH);
341 assert_return(c->mask & SD_BUS_CREDS_CMDLINE, -ENODATA);
345 if (!c->cmdline_array) {
346 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
347 if (!c->cmdline_array)
351 *cmdline = c->cmdline_array;
355 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
356 assert_return(c, -EINVAL);
357 assert_return(sessionid, -EINVAL);
358 assert_return(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID, -ENODATA);
360 *sessionid = c->audit_session_id;
364 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
365 assert_return(c, -EINVAL);
366 assert_return(uid, -EINVAL);
367 assert_return(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID, -ENODATA);
369 *uid = c->audit_login_uid;
373 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
374 assert_return(c, -EINVAL);
375 assert_return(unique_name, -EINVAL);
376 assert_return(c->mask & SD_BUS_CREDS_UNIQUE_NAME, -ENODATA);
378 *unique_name = c->unique_name;
382 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
383 assert_return(c, -EINVAL);
384 assert_return(well_known_names, -EINVAL);
385 assert_return(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES, -ENODATA);
387 *well_known_names = c->well_known_names;
391 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
395 assert(c->capability);
397 sz = c->capability_size / 4;
398 if ((size_t) capability >= sz*8)
401 return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
404 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
405 assert_return(c, -EINVAL);
406 assert_return(capability >= 0, -EINVAL);
407 assert_return(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS, -ENODATA);
409 return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
412 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
413 assert_return(c, -EINVAL);
414 assert_return(capability >= 0, -EINVAL);
415 assert_return(c->mask & SD_BUS_CREDS_PERMITTED_CAPS, -ENODATA);
417 return has_cap(c, CAP_OFFSET_PERMITTED, capability);
420 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
421 assert_return(c, -EINVAL);
422 assert_return(capability >= 0, -EINVAL);
423 assert_return(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS, -ENODATA);
425 return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
428 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
429 assert_return(c, -EINVAL);
430 assert_return(capability >= 0, -EINVAL);
431 assert_return(c->mask & SD_BUS_CREDS_BOUNDING_CAPS, -ENODATA);
433 return has_cap(c, CAP_OFFSET_BOUNDING, capability);
436 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
443 p += strspn(p, WHITESPACE);
450 if (!c->capability) {
451 c->capability = new0(uint8_t, sz * 4);
455 c->capability_size = sz * 4;
458 for (i = 0; i < sz; i ++) {
461 x = unhexchar(p[i*2]);
462 y = unhexchar(p[i*2+1]);
467 c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
473 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
478 assert(c->allocated);
480 missing = mask & ~c->mask;
484 /* Try to retrieve PID from creds if it wasn't passed to us */
485 if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
488 if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
491 /* Without pid we cannot do much... */
495 if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
496 SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
497 SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
499 _cleanup_fclose_ FILE *f = NULL;
503 p = procfs_file_alloca(pid, "status");
507 return errno == ENOENT ? -ESRCH : -errno;
509 FOREACH_LINE(line, f, return -errno) {
512 if (missing & SD_BUS_CREDS_UID) {
513 p = startswith(line, "Uid:");
517 p += strspn(p, WHITESPACE);
518 if (sscanf(p, "%lu", &uid) != 1)
521 c->uid = (uid_t) uid;
522 c->mask |= SD_BUS_CREDS_UID;
527 if (missing & SD_BUS_CREDS_GID) {
528 p = startswith(line, "Gid:");
532 p += strspn(p, WHITESPACE);
533 if (sscanf(p, "%lu", &gid) != 1)
536 c->gid = (uid_t) gid;
537 c->mask |= SD_BUS_CREDS_GID;
542 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
543 p = startswith(line, "CapEff:");
545 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
549 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
554 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
555 p = startswith(line, "CapPrm:");
557 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
561 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
566 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
567 p = startswith(line, "CapInh:");
569 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
573 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
578 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
579 p = startswith(line, "CapBnd:");
581 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
585 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
592 if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
593 unsigned long long st;
595 r = get_starttime_of_pid(pid, &st);
599 c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
600 c->mask |= SD_BUS_CREDS_PID_STARTTIME;
603 if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
606 p = procfs_file_alloca(pid, "attr/current");
607 r = read_one_line_file(p, &c->label);
608 if (r < 0 && r != -ENOENT && r != -EINVAL)
611 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
614 if (missing & SD_BUS_CREDS_COMM) {
615 r = get_process_comm(pid, &c->comm);
619 c->mask |= SD_BUS_CREDS_COMM;
622 if (missing & SD_BUS_CREDS_EXE) {
623 r = get_process_exe(pid, &c->exe);
627 c->mask |= SD_BUS_CREDS_EXE;
630 if (missing & SD_BUS_CREDS_CMDLINE) {
633 p = procfs_file_alloca(pid, "cmdline");
634 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
638 if (c->cmdline_size == 0) {
642 c->mask |= SD_BUS_CREDS_CMDLINE;
645 if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
646 _cleanup_free_ char *p = NULL;
648 if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0)
651 r = read_one_line_file(p, &c->tid_comm);
653 return r == -ENOENT ? -ESRCH : r;
655 c->mask |= SD_BUS_CREDS_TID_COMM;
658 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)) {
660 r = cg_pid_get_path(NULL, pid, &c->cgroup);
664 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);
667 if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
668 r = audit_session_from_pid(pid, &c->audit_session_id);
669 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
672 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
675 if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
676 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
677 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
680 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
686 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
687 _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
693 if ((mask & ~c->mask) == 0) {
694 /* There's already all data we need. */
696 *ret = sd_bus_creds_ref(c);
704 /* Copy the original data over */
706 if (c->mask & mask & SD_BUS_CREDS_UID) {
708 n->mask |= SD_BUS_CREDS_UID;
711 if (c->mask & mask & SD_BUS_CREDS_GID) {
713 n->mask |= SD_BUS_CREDS_GID;
716 if (c->mask & mask & SD_BUS_CREDS_PID) {
718 n->mask |= SD_BUS_CREDS_PID;
721 if (c->mask & mask & SD_BUS_CREDS_TID) {
723 n->mask |= SD_BUS_CREDS_TID;
726 if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
727 n->pid_starttime = c->pid_starttime;
728 n->mask |= SD_BUS_CREDS_PID_STARTTIME;
731 if (c->mask & mask & SD_BUS_CREDS_COMM) {
732 n->comm = strdup(c->comm);
736 n->mask |= SD_BUS_CREDS_COMM;
739 if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
740 n->tid_comm = strdup(c->tid_comm);
744 n->mask |= SD_BUS_CREDS_TID_COMM;
747 if (c->mask & mask & SD_BUS_CREDS_EXE) {
748 n->exe = strdup(c->exe);
752 n->mask |= SD_BUS_CREDS_EXE;
755 if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
756 n->cmdline = memdup(c->cmdline, c->cmdline_size);
760 n->cmdline_size = c->cmdline_size;
761 n->mask |= SD_BUS_CREDS_CMDLINE;
764 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)) {
765 n->cgroup = strdup(c->cgroup);
769 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);
772 if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
773 n->capability = memdup(c->capability, c->capability_size);
777 n->capability_size = c->capability_size;
778 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);
781 if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
782 n->audit_session_id = c->audit_session_id;
783 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
786 if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
787 n->audit_login_uid = c->audit_login_uid;
788 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
791 if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
792 n->unique_name = strdup(c->unique_name);
797 if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
798 n->well_known_names = strv_copy(c->well_known_names);
799 if (!n->well_known_names)
805 r = bus_creds_add_more(n, mask,
806 c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
807 c->mask & SD_BUS_CREDS_TID ? c->tid : 0);