Merge pull request #7059 from yuwata/dynamic-user-7013

dynamic-user: permit the case static uid and gid are different
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2017-10-18 08:37:12 +02:00 committed by GitHub
commit 895265ad7d
4 changed files with 38 additions and 31 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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");
}