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_array);
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);
92 free(c->well_known_names);
98 m = container_of(c, sd_bus_message, creds);
99 sd_bus_message_unref(m);
106 _public_ uint64_t sd_bus_creds_get_mask(sd_bus_creds *c) {
112 sd_bus_creds* bus_creds_new(void) {
115 c = new0(sd_bus_creds, 1);
124 _public_ int sd_bus_creds_new_from_pid(pid_t pid, uint64_t mask, sd_bus_creds **ret) {
128 assert_return(pid >= 0, -EINVAL);
129 assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
130 assert_return(ret, -EINVAL);
139 r = bus_creds_add_more(c, mask, pid, 0);
145 /* Check if the process existed at all, in case we haven't
146 * figured that out already */
147 if (kill(pid, 0) < 0 && errno == ESRCH) {
148 sd_bus_creds_unref(c);
156 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
157 assert_return(c, -EINVAL);
158 assert_return(uid, -EINVAL);
159 assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA);
165 _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
166 assert_return(c, -EINVAL);
167 assert_return(gid, -EINVAL);
168 assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA);
174 _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
175 assert_return(c, -EINVAL);
176 assert_return(pid, -EINVAL);
177 assert_return(c->mask & SD_BUS_CREDS_PID, -ENODATA);
184 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
185 assert_return(c, -EINVAL);
186 assert_return(tid, -EINVAL);
187 assert_return(c->mask & SD_BUS_CREDS_TID, -ENODATA);
194 _public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
195 assert_return(c, -EINVAL);
196 assert_return(usec, -EINVAL);
197 assert_return(c->mask & SD_BUS_CREDS_PID_STARTTIME, -ENODATA);
199 assert(c->pid_starttime > 0);
200 *usec = c->pid_starttime;
204 _public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
205 assert_return(c, -EINVAL);
206 assert_return(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT, -ENODATA);
213 _public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
214 assert_return(c, -EINVAL);
215 assert_return(ret, -EINVAL);
216 assert_return(c->mask & SD_BUS_CREDS_COMM, -ENODATA);
223 _public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
224 assert_return(c, -EINVAL);
225 assert_return(ret, -EINVAL);
226 assert_return(c->mask & SD_BUS_CREDS_TID_COMM, -ENODATA);
233 _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
234 assert_return(c, -EINVAL);
235 assert_return(ret, -EINVAL);
236 assert_return(c->mask & SD_BUS_CREDS_EXE, -ENODATA);
243 _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
244 assert_return(c, -EINVAL);
245 assert_return(ret, -EINVAL);
246 assert_return(c->mask & SD_BUS_CREDS_CGROUP, -ENODATA);
253 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
256 assert_return(c, -EINVAL);
257 assert_return(ret, -EINVAL);
258 assert_return(c->mask & SD_BUS_CREDS_UNIT, -ENODATA);
263 r = cg_path_get_unit(c->cgroup, (char**) &c->unit);
272 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
275 assert_return(c, -EINVAL);
276 assert_return(ret, -EINVAL);
277 assert_return(c->mask & SD_BUS_CREDS_USER_UNIT, -ENODATA);
282 r = cg_path_get_user_unit(c->cgroup, (char**) &c->user_unit);
291 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
294 assert_return(c, -EINVAL);
295 assert_return(ret, -EINVAL);
296 assert_return(c->mask & SD_BUS_CREDS_SLICE, -ENODATA);
301 r = cg_path_get_slice(c->cgroup, (char**) &c->slice);
310 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
313 assert_return(c, -EINVAL);
314 assert_return(ret, -EINVAL);
315 assert_return(c->mask & SD_BUS_CREDS_SESSION, -ENODATA);
320 r = cg_path_get_session(c->cgroup, (char**) &c->session);
329 _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
330 assert_return(c, -EINVAL);
331 assert_return(uid, -EINVAL);
332 assert_return(c->mask & SD_BUS_CREDS_OWNER_UID, -ENODATA);
336 return cg_path_get_owner_uid(c->cgroup, uid);
339 _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 if (!c->cmdline_array) {
347 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
348 if (!c->cmdline_array)
352 *cmdline = c->cmdline_array;
356 _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
357 assert_return(c, -EINVAL);
358 assert_return(sessionid, -EINVAL);
359 assert_return(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID, -ENODATA);
361 *sessionid = c->audit_session_id;
365 _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
366 assert_return(c, -EINVAL);
367 assert_return(uid, -EINVAL);
368 assert_return(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID, -ENODATA);
370 *uid = c->audit_login_uid;
374 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
375 assert_return(c, -EINVAL);
376 assert_return(unique_name, -EINVAL);
377 assert_return(c->mask & SD_BUS_CREDS_UNIQUE_NAME, -ENODATA);
379 *unique_name = c->unique_name;
383 _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
384 assert_return(c, -EINVAL);
385 assert_return(well_known_names, -EINVAL);
386 assert_return(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES, -ENODATA);
388 assert(c->well_known_names);
390 if (!c->well_known_names_array) {
391 c->well_known_names_array = strv_parse_nulstr(c->well_known_names, c->well_known_names_size);
392 if (!c->well_known_names_array)
396 *well_known_names = c->well_known_names_array;
400 static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
404 assert(c->capability);
406 sz = c->capability_size / 4;
407 if ((size_t) capability >= sz*8)
410 return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
413 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
414 assert_return(c, -EINVAL);
415 assert_return(capability >= 0, -EINVAL);
416 assert_return(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS, -ENODATA);
418 return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
421 _public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
422 assert_return(c, -EINVAL);
423 assert_return(capability >= 0, -EINVAL);
424 assert_return(c->mask & SD_BUS_CREDS_PERMITTED_CAPS, -ENODATA);
426 return has_cap(c, CAP_OFFSET_PERMITTED, capability);
429 _public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
430 assert_return(c, -EINVAL);
431 assert_return(capability >= 0, -EINVAL);
432 assert_return(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS, -ENODATA);
434 return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
437 _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
438 assert_return(c, -EINVAL);
439 assert_return(capability >= 0, -EINVAL);
440 assert_return(c->mask & SD_BUS_CREDS_BOUNDING_CAPS, -ENODATA);
442 return has_cap(c, CAP_OFFSET_BOUNDING, capability);
445 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
452 p += strspn(p, WHITESPACE);
459 if (!c->capability) {
460 c->capability = new0(uint8_t, sz * 4);
464 c->capability_size = sz * 4;
467 for (i = 0; i < sz; i ++) {
470 x = unhexchar(p[i*2]);
471 y = unhexchar(p[i*2+1]);
476 c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
482 int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
487 assert(c->allocated);
489 missing = mask & ~c->mask;
493 /* Try to retrieve PID from creds if it wasn't passed to us */
494 if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
497 if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
500 /* Without pid we cannot do much... */
504 if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
505 SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
506 SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
508 _cleanup_fclose_ FILE *f = NULL;
512 p = procfs_file_alloca(pid, "status");
516 return errno == ENOENT ? -ESRCH : -errno;
518 FOREACH_LINE(line, f, return -errno) {
521 if (missing & SD_BUS_CREDS_UID) {
522 p = startswith(line, "Uid:");
526 p += strspn(p, WHITESPACE);
527 if (sscanf(p, "%lu", &uid) != 1)
530 c->uid = (uid_t) uid;
531 c->mask |= SD_BUS_CREDS_UID;
536 if (missing & SD_BUS_CREDS_GID) {
537 p = startswith(line, "Gid:");
541 p += strspn(p, WHITESPACE);
542 if (sscanf(p, "%lu", &gid) != 1)
545 c->gid = (uid_t) gid;
546 c->mask |= SD_BUS_CREDS_GID;
551 if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
552 p = startswith(line, "CapEff:");
554 r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
558 c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
563 if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
564 p = startswith(line, "CapPrm:");
566 r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
570 c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
575 if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
576 p = startswith(line, "CapInh:");
578 r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
582 c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
587 if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
588 p = startswith(line, "CapBnd:");
590 r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
594 c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
601 if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
602 unsigned long long st;
604 r = get_starttime_of_pid(pid, &st);
608 c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
609 c->mask |= SD_BUS_CREDS_PID_STARTTIME;
612 if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
615 p = procfs_file_alloca(pid, "attr/current");
616 r = read_one_line_file(p, &c->label);
617 if (r < 0 && r != -ENOENT && r != -EINVAL)
620 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
623 if (missing & SD_BUS_CREDS_COMM) {
624 r = get_process_comm(pid, &c->comm);
628 c->mask |= SD_BUS_CREDS_COMM;
631 if (missing & SD_BUS_CREDS_EXE) {
632 r = get_process_exe(pid, &c->exe);
636 c->mask |= SD_BUS_CREDS_EXE;
639 if (missing & SD_BUS_CREDS_CMDLINE) {
642 p = procfs_file_alloca(pid, "cmdline");
643 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
647 if (c->cmdline_size == 0) {
651 c->mask |= SD_BUS_CREDS_CMDLINE;
654 if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
655 _cleanup_free_ char *p = NULL;
657 if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0)
660 r = read_one_line_file(p, &c->tid_comm);
662 return r == -ENOENT ? -ESRCH : r;
664 c->mask |= SD_BUS_CREDS_TID_COMM;
667 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)) {
669 r = cg_pid_get_path(NULL, pid, &c->cgroup);
673 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);
676 if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
677 r = audit_session_from_pid(pid, &c->audit_session_id);
678 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
681 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
684 if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
685 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
686 if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
689 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
695 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
696 _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
702 if ((mask & ~c->mask) == 0) {
703 /* There's already all data we need. */
705 *ret = sd_bus_creds_ref(c);
713 /* Copy the original data over */
715 if (c->mask & mask & SD_BUS_CREDS_UID) {
717 n->mask |= SD_BUS_CREDS_UID;
720 if (c->mask & mask & SD_BUS_CREDS_GID) {
722 n->mask |= SD_BUS_CREDS_GID;
725 if (c->mask & mask & SD_BUS_CREDS_PID) {
727 n->mask |= SD_BUS_CREDS_PID;
730 if (c->mask & mask & SD_BUS_CREDS_TID) {
732 n->mask |= SD_BUS_CREDS_TID;
735 if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
736 n->pid_starttime = c->pid_starttime;
737 n->mask |= SD_BUS_CREDS_PID_STARTTIME;
740 if (c->mask & mask & SD_BUS_CREDS_COMM) {
741 n->comm = strdup(c->comm);
745 n->mask |= SD_BUS_CREDS_COMM;
748 if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
749 n->tid_comm = strdup(c->tid_comm);
753 n->mask |= SD_BUS_CREDS_TID_COMM;
756 if (c->mask & mask & SD_BUS_CREDS_EXE) {
757 n->exe = strdup(c->exe);
761 n->mask |= SD_BUS_CREDS_EXE;
764 if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
765 n->cmdline = memdup(c->cmdline, c->cmdline_size);
769 n->cmdline_size = c->cmdline_size;
770 n->mask |= SD_BUS_CREDS_CMDLINE;
773 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)) {
774 n->cgroup = strdup(c->cgroup);
778 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);
781 if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
782 n->capability = memdup(c->capability, c->capability_size);
786 n->capability_size = c->capability_size;
787 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);
790 if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
791 n->audit_session_id = c->audit_session_id;
792 n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
795 if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
796 n->audit_login_uid = c->audit_login_uid;
797 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
800 if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
801 n->unique_name = strdup(c->unique_name);
806 if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
807 n->well_known_names = memdup(c->well_known_names, c->well_known_names_size);
808 if (!n->well_known_names)
811 n->well_known_names_size = c->well_known_names_size;
816 r = bus_creds_add_more(n, mask,
817 c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
818 c->mask & SD_BUS_CREDS_TID ? c->tid : 0);