From 9da440b1b3d8476394e6ffcaf687e0f89932e6ac Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 11 Oct 2017 12:46:27 +0900 Subject: [PATCH 1/4] dynamic-user: label functions not necessary to export as static --- src/core/dynamic-user.c | 12 ++++++------ src/core/dynamic-user.h | 9 --------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/core/dynamic-user.c b/src/core/dynamic-user.c index f1b5ee7ecb..a191341186 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) { _cleanup_close_ int etc_passwd_lock_fd = -1, uid_lock_fd = -1; uid_t uid = UID_INVALID; @@ -526,7 +526,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 +555,7 @@ finish: return r; } -DynamicUser* dynamic_user_ref(DynamicUser *d) { +static DynamicUser* dynamic_user_ref(DynamicUser *d) { if (!d) return NULL; @@ -565,7 +565,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 +608,7 @@ finish: return r; } -DynamicUser* dynamic_user_destroy(DynamicUser *d) { +static DynamicUser* dynamic_user_destroy(DynamicUser *d) { if (!d) return NULL; 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); From 9ec655cbbd7505ef465e0444da0622e46099ce42 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 11 Oct 2017 14:41:13 +0900 Subject: [PATCH 2/4] dynamic-user: permit the case static uid and gid are different This makes systemd supports the case that DynamicUser=yes and static user and group exist such that uid and gid of them are different. We only refuse the operation when user does not exist but the group with the same name exists. Fixes #7013. --- src/core/dynamic-user.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/core/dynamic-user.c b/src/core/dynamic-user.c index a191341186..8f229d27ff 100644 --- a/src/core/dynamic-user.c +++ b/src/core/dynamic-user.c @@ -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 */ } -static 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 @@ static int dynamic_user_realize(DynamicUser *d, char **suggested_dirs, uid_t *re 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; + } } } @@ -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 From e2b0cc3415980f7a145f8772f4ae0a4ad0fbe85a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 18 Oct 2017 08:57:54 +0900 Subject: [PATCH 3/4] core: fix invalid error message The error message corresponds to EILSEQ is "Invalid or incomplete multibyte or wide character", and is not suitable in this case. So, let's show a custom error message when the function dynamic_creds_realize() returns -EILSEQ. --- src/core/execute.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/execute.c b/src/core/execute.c index c4dfac96d9..36dbc28707 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2798,6 +2798,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"); } From 3bd493dc93e1be976fb9868c349a4711b97d2790 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 18 Oct 2017 15:30:00 +0900 Subject: [PATCH 4/4] man: comment a requirement about the static user or group when DynamicUser=yes --- man/systemd.exec.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index dfae0572d8..68291264bd 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 User= 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 Group= 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