diff options
-rw-r--r-- | man/systemd.exec.xml | 5 | ||||
-rw-r--r-- | src/core/dynamic-user.c | 51 | ||||
-rw-r--r-- | src/core/dynamic-user.h | 9 | ||||
-rw-r--r-- | src/core/execute.c | 4 |
4 files changed, 38 insertions, 31 deletions
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 802eb41c47..2f5192eb60 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -206,7 +206,10 @@ enabled for a unit, the name of the dynamic user/group is implicitly derived from the unit name. If the unit name without the type suffix qualifies as valid user name it is used directly, otherwise a name incorporating a hash of it is used. If a statically allocated user or group of the configured name already exists, it is used - and no dynamic user/group is allocated. Dynamic users/groups are allocated from the UID/GID range + and no dynamic user/group is allocated. Note that if <varname>User=</varname> is specified and the static group + with the name exists, then it is required that the static user with the name already exists. Similarly, + if <varname>Group=</varname> is specified and the static user with the name exists, then it is required that + the static group with the name already exists. Dynamic users/groups are allocated from the UID/GID range 61184…65519. It is recommended to avoid this range for regular system or login users. At any point in time each UID/GID from this range is only assigned to zero or one dynamically allocated users/groups in use. However, UID/GIDs are recycled after a unit is terminated. Care should be taken that any processes running diff --git a/src/core/dynamic-user.c b/src/core/dynamic-user.c index f1b5ee7ecb..8f229d27ff 100644 --- a/src/core/dynamic-user.c +++ b/src/core/dynamic-user.c @@ -82,7 +82,7 @@ static int dynamic_user_add(Manager *m, const char *name, int storage_socket[2], return 0; } -int dynamic_user_acquire(Manager *m, const char *name, DynamicUser** ret) { +static int dynamic_user_acquire(Manager *m, const char *name, DynamicUser** ret) { _cleanup_close_pair_ int storage_socket[2] = { -1, -1 }; DynamicUser *d; int r; @@ -421,7 +421,7 @@ static void unlink_uid_lock(int lock_fd, uid_t uid, const char *name) { (void) make_uid_symlinks(uid, name, false); /* remove direct lookup symlinks */ } -int dynamic_user_realize(DynamicUser *d, char **suggested_dirs, uid_t *ret) { +static int dynamic_user_realize(DynamicUser *d, char **suggested_dirs, uid_t *ret, bool is_user) { _cleanup_close_ int etc_passwd_lock_fd = -1, uid_lock_fd = -1; uid_t uid = UID_INVALID; @@ -460,19 +460,28 @@ int dynamic_user_realize(DynamicUser *d, char **suggested_dirs, uid_t *ret) { struct passwd *p; struct group *g; - /* OK, this is not a numeric UID. Let's see if there's a user by this name */ - p = getpwnam(d->name); - if (p) - uid = p->pw_uid; - - /* Let's see if there's a group by this name */ - g = getgrnam(d->name); - if (g) { - /* If the UID/GID of the user/group of the same don't match, refuse operation */ - if (uid != UID_INVALID && uid != (uid_t) g->gr_gid) - return -EILSEQ; - - uid = (uid_t) g->gr_gid; + if (is_user) { + /* OK, this is not a numeric UID. Let's see if there's a user by this name */ + p = getpwnam(d->name); + if (p) + uid = p->pw_uid; + else { + /* if the user does not exist but the group with the same name exists, refuse operation */ + g = getgrnam(d->name); + if (g) + return -EILSEQ; + } + } else { + /* Let's see if there's a group by this name */ + g = getgrnam(d->name); + if (g) + uid = (uid_t) g->gr_gid; + else { + /* if the group does not exist but the user with the same name exists, refuse operation */ + p = getpwnam(d->name); + if (p) + return -EILSEQ; + } } } @@ -526,7 +535,7 @@ finish: return r; } -int dynamic_user_current(DynamicUser *d, uid_t *ret) { +static int dynamic_user_current(DynamicUser *d, uid_t *ret) { _cleanup_close_ int lock_fd = -1; uid_t uid; int r; @@ -555,7 +564,7 @@ finish: return r; } -DynamicUser* dynamic_user_ref(DynamicUser *d) { +static DynamicUser* dynamic_user_ref(DynamicUser *d) { if (!d) return NULL; @@ -565,7 +574,7 @@ DynamicUser* dynamic_user_ref(DynamicUser *d) { return d; } -DynamicUser* dynamic_user_unref(DynamicUser *d) { +static DynamicUser* dynamic_user_unref(DynamicUser *d) { if (!d) return NULL; @@ -608,7 +617,7 @@ finish: return r; } -DynamicUser* dynamic_user_destroy(DynamicUser *d) { +static DynamicUser* dynamic_user_destroy(DynamicUser *d) { if (!d) return NULL; @@ -814,13 +823,13 @@ int dynamic_creds_realize(DynamicCreds *creds, char **suggested_paths, uid_t *ui /* Realize both the referenced user and group */ if (creds->user) { - r = dynamic_user_realize(creds->user, suggested_paths, &u); + r = dynamic_user_realize(creds->user, suggested_paths, &u, true); if (r < 0) return r; } if (creds->group && creds->group != creds->user) { - r = dynamic_user_realize(creds->group, suggested_paths, &g); + r = dynamic_user_realize(creds->group, suggested_paths, &g, false); if (r < 0) return r; } else diff --git a/src/core/dynamic-user.h b/src/core/dynamic-user.h index e7de4f46ae..a0cb378115 100644 --- a/src/core/dynamic-user.h +++ b/src/core/dynamic-user.h @@ -43,15 +43,6 @@ struct DynamicUser { char name[]; }; -int dynamic_user_acquire(Manager *m, const char *name, DynamicUser **ret); - -int dynamic_user_realize(DynamicUser *d, char **suggested_paths, uid_t *ret); -int dynamic_user_current(DynamicUser *d, uid_t *ret); - -DynamicUser* dynamic_user_ref(DynamicUser *d); -DynamicUser* dynamic_user_unref(DynamicUser *d); -DynamicUser* dynamic_user_destroy(DynamicUser *d); - int dynamic_user_serialize(Manager *m, FILE *f, FDSet *fds); void dynamic_user_deserialize_one(Manager *m, const char *value, FDSet *fds); void dynamic_user_vacuum(Manager *m, bool close_user); diff --git a/src/core/execute.c b/src/core/execute.c index d2c684f44b..7404288ff8 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2795,6 +2795,10 @@ static int exec_child( r = dynamic_creds_realize(dcreds, suggested_paths, &uid, &gid); if (r < 0) { *exit_status = EXIT_USER; + if (r == -EILSEQ) { + log_unit_error(unit, "Failed to update dynamic user credentials: User or group with specified name already exists."); + return -EOPNOTSUPP; + } return log_unit_error_errno(unit, r, "Failed to update dynamic user credentials: %m"); } |