chiark / gitweb /
Fix service file to match installed elogind binary location
[elogind.git] / src / libelogind / sd-bus / bus-creds.c
index 1ac12a7bf7fce346374c32b82365f76c1b8e70cc..d52bbff840c1dca09b4be20e1ddea55b1107a61f 100644 (file)
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
 /***
   This file is part of systemd.
 
   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 "process-util.h"
-#include "terminal-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,
@@ -53,6 +57,7 @@ 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);
@@ -68,7 +73,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);
@@ -106,11 +113,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);
 
@@ -302,6 +307,12 @@ _public_ int sd_bus_creds_get_ppid(sd_bus_creds *c, pid_t *ppid) {
         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;
 }
@@ -360,7 +371,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;
 }
@@ -377,7 +390,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);
 
@@ -386,14 +402,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);
 
@@ -402,14 +429,25 @@ _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;
 }
 
 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
+        int r;
+
         assert_return(c, -EINVAL);
         assert_return(ret, -EINVAL);
 
@@ -418,13 +456,50 @@ _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;
+}
+#endif // 0
+
 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
         int r;
 
@@ -439,10 +514,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;
@@ -468,7 +546,12 @@ _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
         if (r < 0)
                 return r;
 
-        return -ESRCH;
+#if 0 /// elogind does not support systemd slices
+        return cg_path_get_owner_uid(shifted, uid);
+#else
+        *uid = c->uid;
+        return 0;
+#endif // 0
 }
 
 _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
@@ -477,8 +560,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);
@@ -497,6 +580,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 (c->audit_session_id == AUDIT_SESSION_INVALID)
+                return -ENXIO;
+
         *sessionid = c->audit_session_id;
         return 0;
 }
@@ -508,6 +594,9 @@ _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 (c->audit_login_uid == UID_INVALID)
+                return -ENXIO;
+
         *uid = c->audit_login_uid;
         return 0;
 }
@@ -519,6 +608,9 @@ _public_ int sd_bus_creds_get_tty(sd_bus_creds *c, const char **ret) {
         if (!(c->mask & SD_BUS_CREDS_TTY))
                 return -ENODATA;
 
+        if (!c->tty)
+                return -ENXIO;
+
         *ret = c->tty;
         return 0;
 }
@@ -695,11 +787,13 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
                 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;
-
-        /* Without pid we cannot do much... */
-        if (pid <= 0)
+        else
+                /* Without pid we cannot do much... */
                 return 0;
 
         /* Try to retrieve TID from creds if it wasn't passed to us */
@@ -711,9 +805,6 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
         if (missing == 0)
                 return 0;
 
-        c->pid = pid;
-        c->mask |= SD_BUS_CREDS_PID;
-
         if (tid > 0) {
                 c->tid = tid;
                 c->mask |= SD_BUS_CREDS_TID;
@@ -754,8 +845,10 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
                                                         if (r < 0)
                                                                 return r;
 
-                                                        c->mask |= SD_BUS_CREDS_PPID;
-                                                }
+                                                } else
+                                                        c->ppid = 0;
+
+                                                c->mask |= SD_BUS_CREDS_PPID;
                                                 continue;
                                         }
                                 }
@@ -908,7 +1001,17 @@ 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 == -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 (r != -EPERM && r != -EACCES)
                                 return r;
                 } else
@@ -920,17 +1023,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)
                                 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;
                 }
         }
 
@@ -941,16 +1043,16 @@ 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)
                                 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)) {
 
                 if (!c->cgroup) {
                         r = cg_pid_get_path(NULL, pid, &c->cgroup);
@@ -967,13 +1069,17 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
                 }
 
                 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_SESSION|SD_BUS_CREDS_OWNER_UID);
+                        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 (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES)
                                 return r;
                 } else
                         c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
@@ -981,8 +1087,12 @@ 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 (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES)
                                 return r;
                 } else
                         c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
@@ -990,20 +1100,35 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
 
         if (missing & SD_BUS_CREDS_TTY) {
                 r = get_ctty(pid, NULL, &c->tty);
-                if (r < 0) {
+                if (r == -ENXIO) {
+                        /* ENXIO means: process has no controlling TTY */
+                        c->tty = NULL;
+                        c->mask |= SD_BUS_CREDS_TTY;
+                } else if (r < 0) {
                         if (r != -EPERM && r != -EACCES && r != -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);
@@ -1079,14 +1204,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;
+                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;
+                }
+
                 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;
@@ -1095,6 +1228,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;
@@ -1103,23 +1238,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;
@@ -1128,10 +1274,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;
@@ -1140,6 +1288,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;
@@ -1166,6 +1316,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_UNIQUE_NAME) {
+                assert(c->unique_name);
+
                 n->unique_name = strdup(c->unique_name);
                 if (!n->unique_name)
                         return -ENOMEM;
@@ -1173,15 +1325,20 @@ 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;