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"
31 #include "bus-creds.h"
34 CAP_OFFSET_INHERITABLE = 0,
35 CAP_OFFSET_PERMITTED = 1,
36 CAP_OFFSET_EFFECTIVE = 2,
37 CAP_OFFSET_BOUNDING = 3
40 void bus_creds_done(sd_bus_creds *c) {
43 /* For internal bus cred structures that are allocated by
51 free(c->cmdline_array);
54 _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
55 assert_return(c, NULL);
63 /* If this is an embedded creds structure, then
64 * forward ref counting to the message */
65 m = container_of(c, sd_bus_message, creds);
66 sd_bus_message_ref(m);
72 _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
73 assert_return(c, NULL);
94 m = container_of(c, sd_bus_message, creds);
95 sd_bus_message_unref(m);
102 _public_ uint64_t sd_bus_creds_get_mask(sd_bus_creds *c) {
108 sd_bus_creds* bus_creds_new(void) {
111 c = new0(sd_bus_creds, 1);
120 _public_ int sd_bus_creds_new_from_pid(pid_t pid, uint64_t mask, sd_bus_creds **ret) {
124 assert_return(pid >= 0, -EINVAL);
125 assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
126 assert_return(ret, -EINVAL);
135 r = bus_creds_add_more(c, mask, pid, 0);
141 /* Check if the process existed at all, in case we haven't
142 * figured that out already */
143 if (kill(pid, 0) < 0 && errno == ESRCH) {
144 sd_bus_creds_unref(c);
152 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
153 assert_return(c, -EINVAL);
154 assert_return(uid, -EINVAL);
155 assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA);
161 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
162 assert_return(c, -EINVAL);
163 assert_return(gid, -EINVAL);
164 assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA);
170 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
171 assert_return(c, -EINVAL);
172 assert_return(pid, -EINVAL);
173 assert_return(c->mask & SD_BUS_CREDS_PID, -ENODATA);
180 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
181 assert_return(c, -EINVAL);
182 assert_return(tid, -EINVAL);
183 assert_return(c->mask & SD_BUS_CREDS_TID, -ENODATA);
190 _public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
191 assert_return(c, -EINVAL);
192 assert_return(usec, -EINVAL);
193 assert_return(c->mask & SD_BUS_CREDS_PID_STARTTIME, -ENODATA);
195 assert(c->pid_starttime > 0);
196 *usec = c->pid_starttime;
200 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
201 assert_return(c, -EINVAL);
202 assert_return(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT, -ENODATA);
209 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
210 assert_return(c, -EINVAL);
211 assert_return(ret, -EINVAL);
212 assert_return(c->mask & SD_BUS_CREDS_COMM, -ENODATA);
219 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
220 assert_return(c, -EINVAL);
221 assert_return(ret, -EINVAL);
222 assert_return(c->mask & SD_BUS_CREDS_TID_COMM, -ENODATA);
229 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
230 assert_return(c, -EINVAL);
231 assert_return(ret, -EINVAL);
232 assert_return(c->mask & SD_BUS_CREDS_EXE, -ENODATA);
239 _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
240 assert_return(c, -EINVAL);
241 assert_return(ret, -EINVAL);
242 assert_return(c->mask & SD_BUS_CREDS_CGROUP, -ENODATA);
249 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
252 assert_return(c, -EINVAL);
253 assert_return(ret, -EINVAL);
254 assert_return(c->mask & SD_BUS_CREDS_UNIT, -ENODATA);
259 r = cg_path_get_unit(c->cgroup, (char**) &c->unit);
268 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
271 assert_return(c, -EINVAL);
272 assert_return(ret, -EINVAL);
273 assert_return(c->mask & SD_BUS_CREDS_USER_UNIT, -ENODATA);
278 r = cg_path_get_user_unit(c->cgroup, (char**) &c->user_unit);
287 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
290 assert_return(c, -EINVAL);
291 assert_return(ret, -EINVAL);
292 assert_return(c->mask & SD_BUS_CREDS_SLICE, -ENODATA);
297 r = cg_path_get_slice(c->cgroup, (char**) &c->slice);
306 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
309 assert_return(c, -EINVAL);
310 assert_return(ret, -EINVAL);
311 assert_return(c->mask & SD_BUS_CREDS_SESSION, -ENODATA);
316 r = cg_path_get_session(c->cgroup, (char**) &c->session);
325 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
326 assert_return(c, -EINVAL);
327 assert_return(uid, -EINVAL);
328 assert_return(c->mask & SD_BUS_CREDS_OWNER_UID, -ENODATA);
332 return cg_path_get_owner_uid(c->cgroup, uid);
335 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
340 assert_return(c, -EINVAL);
341 assert_return(c->cmdline, -ESRCH);
342 assert_return(c->mask & SD_BUS_CREDS_CMDLINE, -ENODATA);
346 for (p = c->cmdline, n = 0; p < c->cmdline + c->cmdline_length; p++)
350 *(char***) &c->cmdline_array = new(char*, n + 1);
351 if (!c->cmdline_array)
354 for (p = c->cmdline, i = 0, first = true; p < c->cmdline + c->cmdline_length; p++) {
356 c->cmdline_array[i++] = (char*) p;
361 c->cmdline_array[i] = NULL;
362 *cmdline = c->cmdline_array;
367 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
368 assert_return(c, -EINVAL);
369 assert_return(sessionid, -EINVAL);
370 assert_return(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID, -ENODATA);
372 *sessionid = c->audit_session_id;
376 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
377 assert_return(c, -EINVAL);
378 assert_return(uid, -EINVAL);
379 assert_return(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID, -ENODATA);
381 *uid = c->audit_login_uid;
385 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
389 assert(c->capability);
391 sz = c->capability_size / 4;
392 if ((size_t) capability >= sz*8)
395 return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
398 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
399 assert_return(c, -EINVAL);
400 assert_return(capability >= 0, -EINVAL);
401 assert_return(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS, -ENODATA);
403 return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
406 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
407 assert_return(c, -EINVAL);
408 assert_return(capability >= 0, -EINVAL);
409 assert_return(c->mask & SD_BUS_CREDS_PERMITTED_CAPS, -ENODATA);
411 return has_cap(c, CAP_OFFSET_PERMITTED, capability);
414 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
415 assert_return(c, -EINVAL);
416 assert_return(capability >= 0, -EINVAL);
417 assert_return(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS, -ENODATA);
419 return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
422 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
423 assert_return(c, -EINVAL);
424 assert_return(capability >= 0, -EINVAL);
425 assert_return(c->mask & SD_BUS_CREDS_BOUNDING_CAPS, -ENODATA);
427 return has_cap(c, CAP_OFFSET_BOUNDING, capability);
430 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
437 p += strspn(p, WHITESPACE);
444 if (!c->capability) {
445 c->capability = new0(uint8_t, sz * 4);
449 c->capability_size = sz * 4;
452 for (i = 0; i < sz; i ++) {
455 x = unhexchar(p[i*2]);
456 y = unhexchar(p[i*2+1]);
461 c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
467 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
472 assert(c->allocated);
474 missing = mask & ~c->mask;
478 /* Try to retrieve PID from creds if it wasn't passed to us */
479 if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
482 if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
485 /* Without pid we cannot do much... */
489 if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
490 SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
491 SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
493 _cleanup_fclose_ FILE *f = NULL;
497 p = procfs_file_alloca(pid, "status");
501 return errno == ENOENT ? -ESRCH : -errno;
503 FOREACH_LINE(line, f, return -errno) {
506 if (missing & SD_BUS_CREDS_UID) {
507 p = startswith(line, "Uid:");
511 p += strspn(p, WHITESPACE);
512 if (sscanf(p, "%lu", &uid) != 1)
515 c->uid = (uid_t) uid;
516 c->mask |= SD_BUS_CREDS_UID;
521 if (missing & SD_BUS_CREDS_GID) {
522 p = startswith(line, "Gid:");
526 p += strspn(p, WHITESPACE);
527 if (sscanf(p, "%lu", &gid) != 1)
530 c->gid = (uid_t) gid;
531 c->mask |= SD_BUS_CREDS_GID;
536 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
537 p = startswith(line, "CapEff:");
539 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
543 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
548 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
549 p = startswith(line, "CapPrm:");
551 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
555 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
560 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
561 p = startswith(line, "CapInh:");
563 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
567 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
572 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
573 p = startswith(line, "CapBnd:");
575 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
579 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
586 if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
587 unsigned long long st;
589 r = get_starttime_of_pid(pid, &st);
593 c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
594 c->mask |= SD_BUS_CREDS_PID_STARTTIME;
597 if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
600 p = procfs_file_alloca(pid, "attr/current");
601 r = read_one_line_file(p, &c->label);
602 if (r < 0 && r != -ENOENT && r != -EINVAL)
605 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
608 if (missing & SD_BUS_CREDS_COMM) {
609 r = get_process_comm(pid, &c->comm);
613 c->mask |= SD_BUS_CREDS_COMM;
616 if (missing & SD_BUS_CREDS_EXE) {
617 r = get_process_exe(pid, &c->exe);
621 c->mask |= SD_BUS_CREDS_EXE;
624 if (missing & SD_BUS_CREDS_CMDLINE) {
627 p = procfs_file_alloca(pid, "cmdline");
628 r = read_full_file(p, &c->cmdline, &c->cmdline_length);
632 if (c->cmdline_length == 0) {
636 c->mask |= SD_BUS_CREDS_CMDLINE;
639 if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
640 _cleanup_free_ char *p = NULL;
642 if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0)
645 r = read_one_line_file(p, &c->tid_comm);
647 return r == -ENOENT ? -ESRCH : r;
649 c->mask |= SD_BUS_CREDS_TID_COMM;
652 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)) {
654 r = cg_pid_get_path(NULL, pid, &c->cgroup);
658 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);
661 if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
662 r = audit_session_from_pid(pid, &c->audit_session_id);
663 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
666 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
669 if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
670 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
671 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
674 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
680 _public_ int sd_bus_creds_extend(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
681 _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
684 assert_return(c, -EINVAL);
685 assert_return(ret, -EINVAL);
687 if ((mask & ~c->mask) == 0) {
688 /* There's already all data we need. */
690 *ret = sd_bus_creds_ref(c);
698 /* Copy the original data over */
700 if (c->mask & mask & SD_BUS_CREDS_UID) {
702 n->mask |= SD_BUS_CREDS_UID;
705 if (c->mask & mask & SD_BUS_CREDS_GID) {
707 n->mask |= SD_BUS_CREDS_GID;
710 if (c->mask & mask & SD_BUS_CREDS_PID) {
712 n->mask |= SD_BUS_CREDS_PID;
715 if (c->mask & mask & SD_BUS_CREDS_TID) {
717 n->mask |= SD_BUS_CREDS_TID;
720 if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
721 n->pid_starttime = c->pid_starttime;
722 n->mask |= SD_BUS_CREDS_PID_STARTTIME;
725 if (c->mask & mask & SD_BUS_CREDS_COMM) {
726 n->comm = strdup(c->comm);
730 n->mask |= SD_BUS_CREDS_COMM;
733 if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
734 n->tid_comm = strdup(c->tid_comm);
738 n->mask |= SD_BUS_CREDS_TID_COMM;
741 if (c->mask & mask & SD_BUS_CREDS_EXE) {
742 n->exe = strdup(c->exe);
746 n->mask |= SD_BUS_CREDS_EXE;
749 if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
750 n->cmdline = memdup(c->cmdline, c->cmdline_length);
754 n->cmdline_length = c->cmdline_length;
755 n->mask |= SD_BUS_CREDS_CMDLINE;
758 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)) {
759 n->cgroup = strdup(c->cgroup);
763 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);
766 if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
767 n->capability = memdup(c->capability, c->capability_size);
771 n->capability_size = c->capability_size;
772 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);
775 if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
776 n->audit_session_id = c->audit_session_id;
777 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
780 if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
781 n->audit_login_uid = c->audit_login_uid;
782 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
787 r = bus_creds_add_more(n, mask,
788 c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
789 c->mask & SD_BUS_CREDS_TID ? c->tid : 0);