summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/systemd.exec.xml5
-rw-r--r--src/core/dynamic-user.c51
-rw-r--r--src/core/dynamic-user.h9
-rw-r--r--src/core/execute.c4
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");
}