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) {
99 m = container_of(c, sd_bus_message, creds);
100 sd_bus_message_unref(m);
107 _public_ uint64_t sd_bus_creds_get_mask(sd_bus_creds *c) {
113 sd_bus_creds* bus_creds_new(void) {
116 c = new0(sd_bus_creds, 1);
125 _public_ int sd_bus_creds_new_from_pid(pid_t pid, uint64_t mask, sd_bus_creds **ret) {
129 assert_return(pid >= 0, -EINVAL);
130 assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
131 assert_return(ret, -EINVAL);
140 r = bus_creds_add_more(c, mask, pid, 0);
146 /* Check if the process existed at all, in case we haven't
147 * figured that out already */
148 if (kill(pid, 0) < 0 && errno == ESRCH) {
149 sd_bus_creds_unref(c);
157 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
158 assert_return(c, -EINVAL);
159 assert_return(uid, -EINVAL);
160 assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA);
166 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
167 assert_return(c, -EINVAL);
168 assert_return(gid, -EINVAL);
169 assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA);
175 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
176 assert_return(c, -EINVAL);
177 assert_return(pid, -EINVAL);
178 assert_return(c->mask & SD_BUS_CREDS_PID, -ENODATA);
185 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
186 assert_return(c, -EINVAL);
187 assert_return(tid, -EINVAL);
188 assert_return(c->mask & SD_BUS_CREDS_TID, -ENODATA);
195 _public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
196 assert_return(c, -EINVAL);
197 assert_return(usec, -EINVAL);
198 assert_return(c->mask & SD_BUS_CREDS_PID_STARTTIME, -ENODATA);
200 assert(c->pid_starttime > 0);
201 *usec = c->pid_starttime;
205 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
206 assert_return(c, -EINVAL);
207 assert_return(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT, -ENODATA);
214 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
215 assert_return(c, -EINVAL);
216 assert_return(ret, -EINVAL);
217 assert_return(c->mask & SD_BUS_CREDS_COMM, -ENODATA);
224 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
225 assert_return(c, -EINVAL);
226 assert_return(ret, -EINVAL);
227 assert_return(c->mask & SD_BUS_CREDS_TID_COMM, -ENODATA);
234 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
235 assert_return(c, -EINVAL);
236 assert_return(ret, -EINVAL);
237 assert_return(c->mask & SD_BUS_CREDS_EXE, -ENODATA);
244 _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
245 assert_return(c, -EINVAL);
246 assert_return(ret, -EINVAL);
247 assert_return(c->mask & SD_BUS_CREDS_CGROUP, -ENODATA);
254 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
257 assert_return(c, -EINVAL);
258 assert_return(ret, -EINVAL);
259 assert_return(c->mask & SD_BUS_CREDS_UNIT, -ENODATA);
264 r = cg_path_get_unit(c->cgroup, (char**) &c->unit);
273 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
276 assert_return(c, -EINVAL);
277 assert_return(ret, -EINVAL);
278 assert_return(c->mask & SD_BUS_CREDS_USER_UNIT, -ENODATA);
283 r = cg_path_get_user_unit(c->cgroup, (char**) &c->user_unit);
292 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
295 assert_return(c, -EINVAL);
296 assert_return(ret, -EINVAL);
297 assert_return(c->mask & SD_BUS_CREDS_SLICE, -ENODATA);
302 r = cg_path_get_slice(c->cgroup, (char**) &c->slice);
311 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
314 assert_return(c, -EINVAL);
315 assert_return(ret, -EINVAL);
316 assert_return(c->mask & SD_BUS_CREDS_SESSION, -ENODATA);
321 r = cg_path_get_session(c->cgroup, (char**) &c->session);
330 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
331 assert_return(c, -EINVAL);
332 assert_return(uid, -EINVAL);
333 assert_return(c->mask & SD_BUS_CREDS_OWNER_UID, -ENODATA);
337 return cg_path_get_owner_uid(c->cgroup, uid);
340 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
341 assert_return(c, -EINVAL);
342 assert_return(c->cmdline, -ESRCH);
343 assert_return(c->mask & SD_BUS_CREDS_CMDLINE, -ENODATA);
347 if (!c->cmdline_array) {
348 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
349 if (!c->cmdline_array)
353 *cmdline = c->cmdline_array;
357 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
358 assert_return(c, -EINVAL);
359 assert_return(sessionid, -EINVAL);
360 assert_return(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID, -ENODATA);
362 *sessionid = c->audit_session_id;
366 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
367 assert_return(c, -EINVAL);
368 assert_return(uid, -EINVAL);
369 assert_return(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID, -ENODATA);
371 *uid = c->audit_login_uid;
375 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
376 assert_return(c, -EINVAL);
377 assert_return(unique_name, -EINVAL);
378 assert_return(c->mask & SD_BUS_CREDS_UNIQUE_NAME, -ENODATA);
380 *unique_name = c->unique_name;
384 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
385 assert_return(c, -EINVAL);
386 assert_return(well_known_names, -EINVAL);
387 assert_return(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES, -ENODATA);
389 *well_known_names = c->well_known_names;
393 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
397 assert(c->capability);
399 sz = c->capability_size / 4;
400 if ((size_t) capability >= sz*8)
403 return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
406 _public_ int sd_bus_creds_has_effective_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_EFFECTIVE_CAPS, -ENODATA);
411 return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
414 _public_ int sd_bus_creds_has_permitted_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_PERMITTED_CAPS, -ENODATA);
419 return has_cap(c, CAP_OFFSET_PERMITTED, capability);
422 _public_ int sd_bus_creds_has_inheritable_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_INHERITABLE_CAPS, -ENODATA);
427 return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
430 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
431 assert_return(c, -EINVAL);
432 assert_return(capability >= 0, -EINVAL);
433 assert_return(c->mask & SD_BUS_CREDS_BOUNDING_CAPS, -ENODATA);
435 return has_cap(c, CAP_OFFSET_BOUNDING, capability);
438 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
445 p += strspn(p, WHITESPACE);
452 if (!c->capability) {
453 c->capability = new0(uint8_t, sz * 4);
457 c->capability_size = sz * 4;
460 for (i = 0; i < sz; i ++) {
463 x = unhexchar(p[i*2]);
464 y = unhexchar(p[i*2+1]);
469 c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
475 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
480 assert(c->allocated);
482 missing = mask & ~c->mask;
486 /* Try to retrieve PID from creds if it wasn't passed to us */
487 if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
490 if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
493 /* Without pid we cannot do much... */
497 if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
498 SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
499 SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
501 _cleanup_fclose_ FILE *f = NULL;
505 p = procfs_file_alloca(pid, "status");
509 return errno == ENOENT ? -ESRCH : -errno;
511 FOREACH_LINE(line, f, return -errno) {
514 if (missing & SD_BUS_CREDS_UID) {
515 p = startswith(line, "Uid:");
519 p += strspn(p, WHITESPACE);
520 if (sscanf(p, "%lu", &uid) != 1)
523 c->uid = (uid_t) uid;
524 c->mask |= SD_BUS_CREDS_UID;
529 if (missing & SD_BUS_CREDS_GID) {
530 p = startswith(line, "Gid:");
534 p += strspn(p, WHITESPACE);
535 if (sscanf(p, "%lu", &gid) != 1)
538 c->gid = (uid_t) gid;
539 c->mask |= SD_BUS_CREDS_GID;
544 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
545 p = startswith(line, "CapEff:");
547 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
551 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
556 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
557 p = startswith(line, "CapPrm:");
559 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
563 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
568 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
569 p = startswith(line, "CapInh:");
571 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
575 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
580 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
581 p = startswith(line, "CapBnd:");
583 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
587 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
594 if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
595 unsigned long long st;
597 r = get_starttime_of_pid(pid, &st);
601 c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
602 c->mask |= SD_BUS_CREDS_PID_STARTTIME;
605 if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
608 p = procfs_file_alloca(pid, "attr/current");
609 r = read_one_line_file(p, &c->label);
610 if (r < 0 && r != -ENOENT && r != -EINVAL)
613 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
616 if (missing & SD_BUS_CREDS_COMM) {
617 r = get_process_comm(pid, &c->comm);
621 c->mask |= SD_BUS_CREDS_COMM;
624 if (missing & SD_BUS_CREDS_EXE) {
625 r = get_process_exe(pid, &c->exe);
629 c->mask |= SD_BUS_CREDS_EXE;
632 if (missing & SD_BUS_CREDS_CMDLINE) {
635 p = procfs_file_alloca(pid, "cmdline");
636 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
640 if (c->cmdline_size == 0) {
644 c->mask |= SD_BUS_CREDS_CMDLINE;
647 if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
648 _cleanup_free_ char *p = NULL;
650 if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0)
653 r = read_one_line_file(p, &c->tid_comm);
655 return r == -ENOENT ? -ESRCH : r;
657 c->mask |= SD_BUS_CREDS_TID_COMM;
660 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)) {
662 r = cg_pid_get_path(NULL, pid, &c->cgroup);
666 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);
669 if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
670 r = audit_session_from_pid(pid, &c->audit_session_id);
671 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
674 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
677 if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
678 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
679 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
682 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
688 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
689 _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
695 if ((mask & ~c->mask) == 0) {
696 /* There's already all data we need. */
698 *ret = sd_bus_creds_ref(c);
706 /* Copy the original data over */
708 if (c->mask & mask & SD_BUS_CREDS_UID) {
710 n->mask |= SD_BUS_CREDS_UID;
713 if (c->mask & mask & SD_BUS_CREDS_GID) {
715 n->mask |= SD_BUS_CREDS_GID;
718 if (c->mask & mask & SD_BUS_CREDS_PID) {
720 n->mask |= SD_BUS_CREDS_PID;
723 if (c->mask & mask & SD_BUS_CREDS_TID) {
725 n->mask |= SD_BUS_CREDS_TID;
728 if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
729 n->pid_starttime = c->pid_starttime;
730 n->mask |= SD_BUS_CREDS_PID_STARTTIME;
733 if (c->mask & mask & SD_BUS_CREDS_COMM) {
734 n->comm = strdup(c->comm);
738 n->mask |= SD_BUS_CREDS_COMM;
741 if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
742 n->tid_comm = strdup(c->tid_comm);
746 n->mask |= SD_BUS_CREDS_TID_COMM;
749 if (c->mask & mask & SD_BUS_CREDS_EXE) {
750 n->exe = strdup(c->exe);
754 n->mask |= SD_BUS_CREDS_EXE;
757 if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
758 n->cmdline = memdup(c->cmdline, c->cmdline_size);
762 n->cmdline_size = c->cmdline_size;
763 n->mask |= SD_BUS_CREDS_CMDLINE;
766 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)) {
767 n->cgroup = strdup(c->cgroup);
771 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);
774 if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
775 n->capability = memdup(c->capability, c->capability_size);
779 n->capability_size = c->capability_size;
780 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);
783 if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
784 n->audit_session_id = c->audit_session_id;
785 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
788 if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
789 n->audit_login_uid = c->audit_login_uid;
790 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
793 if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
794 n->unique_name = strdup(c->unique_name);
799 if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
800 n->well_known_names = strv_copy(c->well_known_names);
801 if (!n->well_known_names)
807 r = bus_creds_add_more(n, mask,
808 c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
809 c->mask & SD_BUS_CREDS_TID ? c->tid : 0);