chiark / gitweb /
tree-wide: remove Lennart's copyright lines
[elogind.git] / src / libelogind / sd-bus / bus-creds.c
index 39cbdba9c32dcd83f846987650721870df53c322..7104a5371a6c914289ae5cbd7124038f2b1546f3 100644 (file)
@@ -1,38 +1,29 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
-  This file is part of systemd.
-
-  Copyright 2013 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
 #include <linux/capability.h>
+#include <stdlib.h>
 
-#include "util.h"
-#include "formats-util.h"
-#include "capability.h"
-#include "cgroup-util.h"
-#include "fileio.h"
-#include "audit.h"
+#include "alloc-util.h"
+#include "audit-util.h"
+#include "bus-creds.h"
+#include "bus-label.h"
 #include "bus-message.h"
 #include "bus-util.h"
+#include "capability-util.h"
+#include "cgroup-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "format-util.h"
+#include "hexdecoct.h"
+#include "parse-util.h"
+#include "process-util.h"
+#include "string-util.h"
 #include "strv.h"
-#include "bus-creds.h"
-#include "bus-label.h"
+#include "terminal-util.h"
+#include "user-util.h"
+#include "util.h"
 
 enum {
         CAP_OFFSET_INHERITABLE = 0,
@@ -51,8 +42,10 @@ void bus_creds_done(sd_bus_creds *c) {
         free(c->unit);
         free(c->user_unit);
         free(c->slice);
+        free(c->user_slice);
         free(c->unescaped_description);
         free(c->supplementary_gids);
+        free(c->tty);
 
         free(c->well_known_names); /* note that this is an strv, but
                                     * we only free the array, not the
@@ -65,7 +58,9 @@ void bus_creds_done(sd_bus_creds *c) {
 }
 
 _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
-        assert_return(c, NULL);
+
+        if (!c)
+                return NULL;
 
         if (c->allocated) {
                 assert(c->n_ref > 0);
@@ -103,11 +98,9 @@ _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
                         free(c->cgroup_root);
                         free(c->description);
 
-                        free(c->supplementary_gids);
-                        c->supplementary_gids = NULL;
+                        c->supplementary_gids = mfree(c->supplementary_gids);
 
-                        strv_free(c->well_known_names);
-                        c->well_known_names = NULL;
+                        c->well_known_names = strv_free(c->well_known_names);
 
                         bus_creds_done(c);
 
@@ -120,7 +113,6 @@ _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
                 sd_bus_message_unref(m);
         }
 
-
         return NULL;
 }
 
@@ -130,6 +122,12 @@ _public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
         return c->mask;
 }
 
+_public_ uint64_t sd_bus_creds_get_augmented_mask(const sd_bus_creds *c) {
+        assert_return(c, 0);
+
+        return c->augmented;
+}
+
 sd_bus_creds* bus_creds_new(void) {
         sd_bus_creds *c;
 
@@ -151,7 +149,7 @@ _public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t m
         assert_return(ret, -EINVAL);
 
         if (pid == 0)
-                pid = getpid();
+                pid = getpid_cached();
 
         c = bus_creds_new();
         if (!c)
@@ -207,7 +205,6 @@ _public_ int sd_bus_creds_get_suid(sd_bus_creds *c, uid_t *suid) {
         return 0;
 }
 
-
 _public_ int sd_bus_creds_get_fsuid(sd_bus_creds *c, uid_t *fsuid) {
         assert_return(c, -EINVAL);
         assert_return(fsuid, -EINVAL);
@@ -230,7 +227,6 @@ _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
         return 0;
 }
 
-
 _public_ int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) {
         assert_return(c, -EINVAL);
         assert_return(egid, -EINVAL);
@@ -287,6 +283,23 @@ _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
         return 0;
 }
 
+_public_ int sd_bus_creds_get_ppid(sd_bus_creds *c, pid_t *ppid) {
+        assert_return(c, -EINVAL);
+        assert_return(ppid, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_PPID))
+                return -ENODATA;
+
+        /* PID 1 has no parent process. Let's distinguish the case of
+         * not knowing and not having a parent process by the returned
+         * error code. */
+        if (c->ppid == 0)
+                return -ENXIO;
+
+        *ppid = c->ppid;
+        return 0;
+}
+
 _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
         assert_return(c, -EINVAL);
         assert_return(tid, -EINVAL);
@@ -341,7 +354,9 @@ _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
         if (!(c->mask & SD_BUS_CREDS_EXE))
                 return -ENODATA;
 
-        assert(c->exe);
+        if (!c->exe)
+                return -ENXIO;
+
         *ret = c->exe;
         return 0;
 }
@@ -358,7 +373,10 @@ _public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
         return 0;
 }
 
+#if 0 /// UNNEEDED by elogind
 _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
+        int r;
+
         assert_return(c, -EINVAL);
         assert_return(ret, -EINVAL);
 
@@ -367,14 +385,25 @@ _public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
 
         assert(c->cgroup);
 
-        if (!c->unit)
-                return -ESRCH;
+        if (!c->unit) {
+                const char *shifted;
+
+                r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
+                if (r < 0)
+                        return r;
+
+                r = cg_path_get_unit(shifted, (char**) &c->unit);
+                if (r < 0)
+                        return r;
+        }
 
         *ret = c->unit;
         return 0;
 }
 
 _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
+        int r;
+
         assert_return(c, -EINVAL);
         assert_return(ret, -EINVAL);
 
@@ -383,14 +412,26 @@ _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
 
         assert(c->cgroup);
 
-        if (!c->user_unit)
-                return -ESRCH;
+        if (!c->user_unit) {
+                const char *shifted;
+
+                r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
+                if (r < 0)
+                        return r;
+
+                r = cg_path_get_user_unit(shifted, (char**) &c->user_unit);
+                if (r < 0)
+                        return r;
+        }
 
         *ret = c->user_unit;
         return 0;
 }
+#endif // 0
 
 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
+        int r;
+
         assert_return(c, -EINVAL);
         assert_return(ret, -EINVAL);
 
@@ -399,13 +440,49 @@ _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
 
         assert(c->cgroup);
 
-        if (!c->slice)
-                return -ESRCH;
+        if (!c->slice) {
+                const char *shifted;
+
+                r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
+                if (r < 0)
+                        return r;
+
+                r = cg_path_get_slice(shifted, (char**) &c->slice);
+                if (r < 0)
+                        return r;
+        }
 
         *ret = c->slice;
         return 0;
 }
 
+_public_ int sd_bus_creds_get_user_slice(sd_bus_creds *c, const char **ret) {
+        int r;
+
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_USER_SLICE))
+                return -ENODATA;
+
+        assert(c->cgroup);
+
+        if (!c->user_slice) {
+                const char *shifted;
+
+                r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
+                if (r < 0)
+                        return r;
+
+                r = cg_path_get_user_slice(shifted, (char**) &c->user_slice);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = c->user_slice;
+        return 0;
+}
+
 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
         int r;
 
@@ -420,10 +497,13 @@ _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
         if (!c->session) {
                 const char *shifted;
 
+                log_debug_elogind("Shifting cgroup \"%s\", root \"%s\"",
+                                  c->cgroup, c->cgroup_root ? c->cgroup_root : "NULL");
                 r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
                 if (r < 0)
                         return r;
 
+                log_debug_elogind("Shifted: \"%s\"", shifted);
                 r = cg_path_get_session(shifted, (char**) &c->session);
                 if (r < 0)
                         return r;
@@ -446,10 +526,12 @@ _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
         assert(c->cgroup);
 
         r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
+        log_debug_elogind("Shifted to %s from %s/%s for c->uid %u (result %d)",
+                          shifted, c->cgroup_root, c->cgroup, c->uid, r);
         if (r < 0)
                 return r;
 
-        return -ESRCH;
+        return cg_path_get_owner_uid(shifted, uid);
 }
 
 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
@@ -458,8 +540,8 @@ _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
         if (!(c->mask & SD_BUS_CREDS_CMDLINE))
                 return -ENODATA;
 
-        assert_return(c->cmdline, -ESRCH);
-        assert(c->cmdline);
+        if (!c->cmdline)
+                return -ENXIO;
 
         if (!c->cmdline_array) {
                 c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
@@ -478,6 +560,9 @@ _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessio
         if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
                 return -ENODATA;
 
+        if (!audit_session_is_valid(c->audit_session_id))
+                return -ENXIO;
+
         *sessionid = c->audit_session_id;
         return 0;
 }
@@ -489,10 +574,27 @@ _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
         if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
                 return -ENODATA;
 
+        if (!uid_is_valid(c->audit_login_uid))
+                return -ENXIO;
+
         *uid = c->audit_login_uid;
         return 0;
 }
 
+_public_ int sd_bus_creds_get_tty(sd_bus_creds *c, const char **ret) {
+        assert_return(c, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_TTY))
+                return -ENODATA;
+
+        if (!c->tty)
+                return -ENXIO;
+
+        *ret = c->tty;
+        return 0;
+}
+
 _public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
         assert_return(c, -EINVAL);
         assert_return(unique_name, -EINVAL);
@@ -563,10 +665,11 @@ static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
         assert(capability >= 0);
         assert(c->capability);
 
-        sz = DIV_ROUND_UP(cap_last_cap(), 32U);
-        if ((unsigned)capability > cap_last_cap())
+        if ((unsigned) capability > cap_last_cap())
                 return 0;
 
+        sz = DIV_ROUND_UP(cap_last_cap(), 32U);
+
         return !!(c->capability[offset * sz + CAP_TO_INDEX(capability)] & CAP_TO_MASK(capability));
 }
 
@@ -663,32 +766,32 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
         if (!(mask & SD_BUS_CREDS_AUGMENT))
                 return 0;
 
-        missing = mask & ~c->mask;
-        if (missing == 0)
-                return 0;
-
         /* Try to retrieve PID from creds if it wasn't passed to us */
-        if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
+        if (pid > 0) {
+                c->pid = pid;
+                c->mask |= SD_BUS_CREDS_PID;
+        } else if (c->mask & SD_BUS_CREDS_PID)
                 pid = c->pid;
+        else
+                /* Without pid we cannot do much... */
+                return 0;
 
+        /* Try to retrieve TID from creds if it wasn't passed to us */
         if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
-                tid = c->pid;
+                tid = c->tid;
 
-        /* Without pid we cannot do much... */
-        if (pid <= 0)
+        /* Calculate what we shall and can add */
+        missing = mask & ~(c->mask|SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_AUGMENT);
+        if (missing == 0)
                 return 0;
 
-        if (pid > 0) {
-                c->pid = pid;
-                c->mask |= SD_BUS_CREDS_PID;
-        }
-
         if (tid > 0) {
                 c->tid = tid;
                 c->mask |= SD_BUS_CREDS_TID;
         }
 
-        if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
+        if (missing & (SD_BUS_CREDS_PPID |
+                       SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
                        SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
                        SD_BUS_CREDS_SUPPLEMENTARY_GIDS |
                        SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
@@ -703,7 +806,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
                 if (!f) {
                         if (errno == ENOENT)
                                 return -ESRCH;
-                        else if (errno != EPERM && errno != EACCES)
+                        else if (!IN_SET(errno, EPERM, EACCES))
                                 return -errno;
                 } else {
                         char line[LINE_MAX];
@@ -711,6 +814,25 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
                         FOREACH_LINE(line, f, return -errno) {
                                 truncate_nl(line);
 
+                                if (missing & SD_BUS_CREDS_PPID) {
+                                        p = startswith(line, "PPid:");
+                                        if (p) {
+                                                p += strspn(p, WHITESPACE);
+
+                                                /* Explicitly check for PPID 0 (which is the case for PID 1) */
+                                                if (!streq(p, "0")) {
+                                                        r = parse_pid(p, &c->ppid);
+                                                        if (r < 0)
+                                                                return r;
+
+                                                } else
+                                                        c->ppid = 0;
+
+                                                c->mask |= SD_BUS_CREDS_PPID;
+                                                continue;
+                                        }
+                                }
+
                                 if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) {
                                         p = startswith(line, "Uid:");
                                         if (p) {
@@ -720,10 +842,15 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
                                                 if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4)
                                                         return -EIO;
 
-                                                c->uid = (uid_t) uid;
-                                                c->euid = (uid_t) euid;
-                                                c->suid = (uid_t) suid;
-                                                c->fsuid = (uid_t) fsuid;
+                                                if (missing & SD_BUS_CREDS_UID)
+                                                        c->uid = (uid_t) uid;
+                                                if (missing & SD_BUS_CREDS_EUID)
+                                                        c->euid = (uid_t) euid;
+                                                if (missing & SD_BUS_CREDS_SUID)
+                                                        c->suid = (uid_t) suid;
+                                                if (missing & SD_BUS_CREDS_FSUID)
+                                                        c->fsuid = (uid_t) fsuid;
+
                                                 c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID);
                                                 continue;
                                         }
@@ -738,10 +865,15 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
                                                 if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4)
                                                         return -EIO;
 
-                                                c->gid = (gid_t) gid;
-                                                c->egid = (gid_t) egid;
-                                                c->sgid = (gid_t) sgid;
-                                                c->fsgid = (gid_t) fsgid;
+                                                if (missing & SD_BUS_CREDS_GID)
+                                                        c->gid = (gid_t) gid;
+                                                if (missing & SD_BUS_CREDS_EGID)
+                                                        c->egid = (gid_t) egid;
+                                                if (missing & SD_BUS_CREDS_SGID)
+                                                        c->sgid = (gid_t) sgid;
+                                                if (missing & SD_BUS_CREDS_FSGID)
+                                                        c->fsgid = (gid_t) fsgid;
+
                                                 c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID);
                                                 continue;
                                         }
@@ -832,7 +964,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
                 p = procfs_file_alloca(pid, "attr/current");
                 r = read_one_line_file(p, &c->label);
                 if (r < 0) {
-                        if (r != -ENOENT && r != -EINVAL && r != -EPERM && r != -EACCES)
+                        if (!IN_SET(r, -ENOENT, -EINVAL, -EPERM, -EACCES))
                                 return r;
                 } else
                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
@@ -841,7 +973,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
         if (missing & SD_BUS_CREDS_COMM) {
                 r = get_process_comm(pid, &c->comm);
                 if (r < 0) {
-                        if (r != -EPERM && r != -EACCES)
+                        if (!IN_SET(r, -EPERM, -EACCES))
                                 return r;
                 } else
                         c->mask |= SD_BUS_CREDS_COMM;
@@ -849,8 +981,18 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
 
         if (missing & SD_BUS_CREDS_EXE) {
                 r = get_process_exe(pid, &c->exe);
-                if (r < 0) {
-                        if (r != -EPERM && r != -EACCES)
+                if (r == -ESRCH) {
+                        /* Unfortunately we cannot really distinguish
+                         * the case here where the process does not
+                         * exist, and /proc/$PID/exe being unreadable
+                         * because $PID is a kernel thread. Hence,
+                         * assume it is a kernel thread, and rely on
+                         * that this case is caught with a later
+                         * call. */
+                        c->exe = NULL;
+                        c->mask |= SD_BUS_CREDS_EXE;
+                } else if (r < 0) {
+                        if (!IN_SET(r, -EPERM, -EACCES))
                                 return r;
                 } else
                         c->mask |= SD_BUS_CREDS_EXE;
@@ -861,17 +1003,16 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
 
                 p = procfs_file_alloca(pid, "cmdline");
                 r = read_full_file(p, &c->cmdline, &c->cmdline_size);
+                if (r == -ENOENT)
+                        return -ESRCH;
                 if (r < 0) {
-                        if (r == -ENOENT)
-                                return -ESRCH;
-                        if (r != -EPERM && r != -EACCES)
+                        if (!IN_SET(r, -EPERM, -EACCES))
                                 return r;
                 } else {
-                        if (c->cmdline_size == 0) {
-                                free(c->cmdline);
-                                c->cmdline = NULL;
-                        } else
-                                c->mask |= SD_BUS_CREDS_CMDLINE;
+                        if (c->cmdline_size == 0)
+                                c->cmdline = mfree(c->cmdline);
+
+                        c->mask |= SD_BUS_CREDS_CMDLINE;
                 }
         }
 
@@ -882,34 +1023,43 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
                         return -ENOMEM;
 
                 r = read_one_line_file(p, &c->tid_comm);
+                if (r == -ENOENT)
+                        return -ESRCH;
                 if (r < 0) {
-                        if (r == -ENOENT)
-                                return -ESRCH;
-                        if (r != -EPERM && r != -EACCES)
+                        if (!IN_SET(r, -EPERM, -EACCES))
                                 return r;
                 } else
                         c->mask |= SD_BUS_CREDS_TID_COMM;
         }
 
-        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)) {
+        if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
 
-                r = cg_pid_get_path(NULL, pid, &c->cgroup);
-                if (r < 0) {
-                        if (r != -EPERM && r != -EACCES)
-                                return r;
-                } else {
+                if (!c->cgroup) {
+                        r = cg_pid_get_path(NULL, pid, &c->cgroup);
+                        if (r < 0) {
+                                if (!IN_SET(r, -EPERM, -EACCES))
+                                        return r;
+                        }
+                }
+
+                if (!c->cgroup_root) {
                         r = cg_get_root_path(&c->cgroup_root);
                         if (r < 0)
                                 return r;
-
-                        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);
                 }
+
+                if (c->cgroup)
+                        c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID);
         }
 
         if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
                 r = audit_session_from_pid(pid, &c->audit_session_id);
-                if (r < 0) {
-                        if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
+                if (r == -ENODATA) {
+                        /* ENODATA means: no audit session id assigned */
+                        c->audit_session_id = AUDIT_SESSION_INVALID;
+                        c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
+                } else if (r < 0) {
+                        if (!IN_SET(r, -EOPNOTSUPP, -ENOENT, -EPERM, -EACCES))
                                 return r;
                 } else
                         c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
@@ -917,18 +1067,48 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
 
         if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
                 r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
-                if (r < 0) {
-                        if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
+                if (r == -ENODATA) {
+                        /* ENODATA means: no audit login uid assigned */
+                        c->audit_login_uid = UID_INVALID;
+                        c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
+                } else if (r < 0) {
+                        if (!IN_SET(r, -EOPNOTSUPP, -ENOENT, -EPERM, -EACCES))
                                 return r;
                 } else
                         c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
         }
 
+        if (missing & SD_BUS_CREDS_TTY) {
+                r = get_ctty(pid, NULL, &c->tty);
+                if (r == -ENXIO) {
+                        /* ENXIO means: process has no controlling TTY */
+                        c->tty = NULL;
+                        c->mask |= SD_BUS_CREDS_TTY;
+                } else if (r < 0) {
+                        if (!IN_SET(r, -EPERM, -EACCES, -ENOENT))
+                                return r;
+                } else
+                        c->mask |= SD_BUS_CREDS_TTY;
+        }
+
+        /* In case only the exe path was to be read we cannot
+         * distinguish the case where the exe path was unreadable
+         * because the process was a kernel thread, or when the
+         * process didn't exist at all. Hence, let's do a final check,
+         * to be sure. */
+        if (!pid_is_alive(pid))
+                return -ESRCH;
+
+        if (tid > 0 && tid != pid && !pid_is_unwaited(tid))
+                return -ESRCH;
+
+        c->augmented = missing & c->mask;
+
         return 0;
 }
 
 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
-        _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL;
+        _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *n = NULL;
         int r;
 
         assert(c);
@@ -948,6 +1128,21 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
 
         /* Copy the original data over */
 
+        if (c->mask & mask & SD_BUS_CREDS_PID) {
+                n->pid = c->pid;
+                n->mask |= SD_BUS_CREDS_PID;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_TID) {
+                n->tid = c->tid;
+                n->mask |= SD_BUS_CREDS_TID;
+        }
+
+        if (c->mask & mask & SD_BUS_CREDS_PPID) {
+                n->ppid = c->ppid;
+                n->mask |= SD_BUS_CREDS_PPID;
+        }
+
         if (c->mask & mask & SD_BUS_CREDS_UID) {
                 n->uid = c->uid;
                 n->mask |= SD_BUS_CREDS_UID;
@@ -989,24 +1184,22 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
         }
 
         if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
-                n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
-                if (!n->supplementary_gids)
-                        return -ENOMEM;
-                n->n_supplementary_gids = c->n_supplementary_gids;
-                n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
-        }
-
-        if (c->mask & mask & SD_BUS_CREDS_PID) {
-                n->pid = c->pid;
-                n->mask |= SD_BUS_CREDS_PID;
-        }
+                if (c->supplementary_gids) {
+                        n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
+                        if (!n->supplementary_gids)
+                                return -ENOMEM;
+                        n->n_supplementary_gids = c->n_supplementary_gids;
+                } else {
+                        n->supplementary_gids = NULL;
+                        n->n_supplementary_gids = 0;
+                }
 
-        if (c->mask & mask & SD_BUS_CREDS_TID) {
-                n->tid = c->tid;
-                n->mask |= SD_BUS_CREDS_TID;
+                n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
         }
 
         if (c->mask & mask & SD_BUS_CREDS_COMM) {
+                assert(c->comm);
+
                 n->comm = strdup(c->comm);
                 if (!n->comm)
                         return -ENOMEM;
@@ -1015,6 +1208,8 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
         }
 
         if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
+                assert(c->tid_comm);
+
                 n->tid_comm = strdup(c->tid_comm);
                 if (!n->tid_comm)
                         return -ENOMEM;
@@ -1023,23 +1218,34 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
         }
 
         if (c->mask & mask & SD_BUS_CREDS_EXE) {
-                n->exe = strdup(c->exe);
-                if (!n->exe)
-                        return -ENOMEM;
+                if (c->exe) {
+                        n->exe = strdup(c->exe);
+                        if (!n->exe)
+                                return -ENOMEM;
+                } else
+                        n->exe = NULL;
 
                 n->mask |= SD_BUS_CREDS_EXE;
         }
 
         if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
-                n->cmdline = memdup(c->cmdline, c->cmdline_size);
-                if (!n->cmdline)
-                        return -ENOMEM;
+                if (c->cmdline) {
+                        n->cmdline = memdup(c->cmdline, c->cmdline_size);
+                        if (!n->cmdline)
+                                return -ENOMEM;
+
+                        n->cmdline_size = c->cmdline_size;
+                } else {
+                        n->cmdline = NULL;
+                        n->cmdline_size = 0;
+                }
 
-                n->cmdline_size = c->cmdline_size;
                 n->mask |= SD_BUS_CREDS_CMDLINE;
         }
 
-        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)) {
+        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_USER_SLICE|SD_BUS_CREDS_OWNER_UID)) {
+                assert(c->cgroup);
+
                 n->cgroup = strdup(c->cgroup);
                 if (!n->cgroup)
                         return -ENOMEM;
@@ -1048,10 +1254,12 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
                 if (!n->cgroup_root)
                         return -ENOMEM;
 
-                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);
+                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_USER_SLICE|SD_BUS_CREDS_OWNER_UID);
         }
 
         if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
+                assert(c->capability);
+
                 n->capability = memdup(c->capability, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4);
                 if (!n->capability)
                         return -ENOMEM;
@@ -1060,6 +1268,8 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
         }
 
         if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
+                assert(c->label);
+
                 n->label = strdup(c->label);
                 if (!n->label)
                         return -ENOMEM;
@@ -1075,7 +1285,19 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
                 n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
         }
 
+        if (c->mask & mask & SD_BUS_CREDS_TTY) {
+                if (c->tty) {
+                        n->tty = strdup(c->tty);
+                        if (!n->tty)
+                                return -ENOMEM;
+                } else
+                        n->tty = NULL;
+                n->mask |= SD_BUS_CREDS_TTY;
+        }
+
         if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
+                assert(c->unique_name);
+
                 n->unique_name = strdup(c->unique_name);
                 if (!n->unique_name)
                         return -ENOMEM;
@@ -1083,28 +1305,35 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
         }
 
         if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
-                n->well_known_names = strv_copy(c->well_known_names);
-                if (!n->well_known_names)
-                        return -ENOMEM;
+                if (strv_isempty(c->well_known_names))
+                        n->well_known_names = NULL;
+                else {
+                        n->well_known_names = strv_copy(c->well_known_names);
+                        if (!n->well_known_names)
+                                return -ENOMEM;
+                }
+                n->well_known_names_driver = c->well_known_names_driver;
+                n->well_known_names_local = c->well_known_names_local;
                 n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
         }
 
         if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) {
+                assert(c->description);
                 n->description = strdup(c->description);
                 if (!n->description)
                         return -ENOMEM;
                 n->mask |= SD_BUS_CREDS_DESCRIPTION;
         }
 
+        n->augmented = c->augmented & n->mask;
+
         /* Get more data */
 
-        r = bus_creds_add_more(n, mask,
-                               c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
-                               c->mask & SD_BUS_CREDS_TID ? c->tid : 0);
+        r = bus_creds_add_more(n, mask, 0, 0);
         if (r < 0)
                 return r;
 
-        *ret = n;
-        n = NULL;
+        *ret = TAKE_PTR(n);
+
         return 0;
 }