fix: create relative home path correctly

Currently, supplying a relative path via the --prefix flag to the
useradd command triggers a bug in the creation of home directories. The
code seems to unintentionally prepend a leading "/" to all paths,
quietly transforming a relative prefixed home path into an absolute
path. This can be seen in the following strace logs from running
"useradd --create-home --prefix tmp/root squat":

```
access("tmp/root//home/squat", F_OK)    = -1 ENOENT (No such file or directory)
access("/mp", F_OK)                     = 0
access("/mp/root", F_OK)                = 0
access("/mp/root/home", F_OK)           = 0
access("/mp/root/home/squat", F_OK)     = -1 ENOENT (No such file or directory)
mkdir("/mp/root/home/squat", 000)       = 0
chown("/mp/root/home/squat", 0, 0)      = 0
chmod("/mp/root/home/squat", 0755)      = 0
chown("tmp/root//home/squat", 1000, 1000) = -1 ENOENT (No such file or directory)
chmod("tmp/root//home/squat", 0700)     = -1 ENOENT (No such file or directory)
```

Note that the relative path is correctly probed in the beginning and it
is only during the recursive creation that the path is turned into an
absolute path. This invocation results in the creation of a "/mp"
hierarchy in the root of the filesystem.

Similar problems occur when using `--prefix ./tmp/root`.

This commit fixes the handling of relative paths by not assuming that
the given path is anchored with a "/".

Signed-off-by: Lucas Servén Marín <lserven@gmail.com>
This commit is contained in:
Lucas Servén Marín 2021-04-29 14:09:31 +02:00
parent b30e9614c3
commit 2c542f6c65
No known key found for this signature in database
GPG Key ID: 586FEAF680DA74AD

View File

@ -2171,7 +2171,6 @@ static void create_home (void)
Prog, user_home);
fail_exit (E_HOMEDIR);
}
++bhome;
#ifdef WITH_SELINUX
if (set_selinux_file_context (prefix_user_home) != 0) {
@ -2188,7 +2187,11 @@ static void create_home (void)
*/
cp = strtok (bhome, "/");
while (cp) {
strcat (path, "/");
/* Avoid turning a relative path into an absolute path.
*/
if (bhome[0] == '/' || strlen (path) != 0) {
strcat (path, "/");
}
strcat (path, cp);
if (access (path, F_OK) != 0) {
/* Check if parent directory is BTRFS, fail if requesting