confd: map new users to existing home directories

UNIX home directories are persistent across reboots, but user accounts
are not.  If multiple users exist in startup-config and one or more are
removed, we must use the UID of their $HOME on the next reboot to ensure
they do not lose their files.

If a home directory exists and its UID is already in /etc/passwd we have
triggered an unsupported use-case and must remove the home directory on
disk before recreating it empty.  This should not happen, but may occur
on upgrades from a time before UIDs started at 1000 and instead shared
the UID range with reserved system accounts.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2024-04-30 15:51:17 +02:00
committed by Tobias Waldekranz
parent fbeeed7a2c
commit 3f87945f75
+61 -1
View File
@@ -671,6 +671,35 @@ static char *sys_find_usable_shell(sr_session_ctx_t *sess, char *name)
return shell;
}
static uid_t sys_home_exists(char *user)
{
char path[strlen(user) + 10];
struct stat st;
snprintf(path, sizeof(path), "/home/%s", user);
if (stat(path, &st))
return 0;
return st.st_uid;
}
static int sys_uid_busy(char *user, uid_t uid)
{
struct passwd *pw;
int rc = 0;
setpwent();
while ((pw = getpwent())) {
if (pw->pw_uid != uid)
continue;
if (strcmp(pw->pw_name, user))
rc = -1;
}
endpwent();
return rc;
}
static int sys_del_user(char *user)
{
char *args[] = {
@@ -692,11 +721,39 @@ static int sys_del_user(char *user)
static int sys_add_new_user(sr_session_ctx_t *sess, char *name)
{
char *shell = sys_find_usable_shell(sess, name);
char *args[] = {
char uid_str[10];
char *eargs[] = {
"adduser", "-d", "-s", shell, "-u", NULL, "-H", name, NULL
};
char *nargs[] = {
"adduser", "-d", "-s", shell, name, NULL
};
bool do_chown = false;
char **args;
uid_t uid;
int err;
uid = sys_home_exists(name);
if (uid) {
if (sys_uid_busy(name, uid)) {
/* Exists but owned by someone else. */
ERROR("Creating user %s, /home/%s existed but was owned by another uid (%d)",
name, name, uid);
ERROR("Cleaning up stale /home/%s", name);
systemf("rm -rf /home/%s", name);
args = nargs;
} else {
/* Not in passwd or owned by us already */
do_chown = true;
NOTE("Reusing uid %d and /home/%s for new user %s", uid, name, name);
snprintf(uid_str, sizeof(uid_str), "%d", uid);
eargs[5] = uid_str;
args = eargs;
}
} else
args = nargs;
/**
* The Busybox implementation of 'adduser -d' sets the password
* to "*", which prevents new users from logging in until Augeas
@@ -708,7 +765,10 @@ static int sys_add_new_user(sr_session_ctx_t *sess, char *name)
ERROR("Failed creating new user \"%s\"\n", name);
return SR_ERR_SYS;
}
NOTE("New user \"%s\" created\n", name);
if (do_chown)
systemf("chown -R %s:%s /home/%s", name, name, name);
/*
* OpenSSH in Infix has been set up to use /var/run/sshd/%s.keys