Skip to content

Commit

Permalink
Do not rely on getenv ("HOME")'s path conversion
Browse files Browse the repository at this point in the history
In the very early code path where `dll_crt0_1 ()` calls
`user_shared->initialize ()`, the Cygwin runtime calls `internal_pwsid ()`
to initialize the user name in preparation for reading the `fstab` file.

In case `db_home: env` is defined in `/etc/nsswitch.conf`, we need to
look at the environment variable `HOME` and use it, if set.

When all of this happens, though, the `pinfo_init ()` function has had no
chance to run yet (and therefore, `environ_init ()`). At this stage,
therefore, `getenv ()`'s `findenv_func ()` call still finds `getearly ()`
and we get the _verbatim_ value of `HOME`. That is, the Windows form.
But we need the "POSIX" form.

To add insult to injury, later calls to `getpwuid (getuid ())` will
receive a cached version of the home directory via
`cygheap->pg.pwd_cache.win.find_user ()` thanks to the first
`internal_pwsid ()` call caching the result via
`add_user_from_cygserver ()`, read: we will never receive the converted
`HOME` but always the Windows variant.

So, contrary to the assumptions made in 27376c6 (Allow deriving the
current user's home directory via the HOME variable, 2023-03-28), we
cannot assume that `getenv ("HOME")` returned a "POSIX" path.

This is a real problem. Even setting aside that common callers of
`getpwuid ()` (such as OpenSSH) are unable to handle Windows paths in the
`pw_dir` attribute, the Windows path never makes it back to the caller
unscathed. The value returned from `fetch_home_env ()` is not actually
used as-is. Instead, the `fetch_account_from_windows ()` method uses it
to write a pseudo `/etc/passwd`-formatted line that is _then_ parsed via
the `pwdgrp::parse_passwd ()` method which sees no problem with
misinterpreting the colon after the drive letter as a field separator of
that `/etc/passwd`-formatted line, and instead of a Windows path, we now
have a mere drive letter.

Let's detect when the `HOME` value is still in Windows format in
`fetch_home_env ()`, and convert it in that case.

For good measure, interpret this "Windows format" not only to include
absolute paths with drive prefixes, but also UNC paths.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
  • Loading branch information
dscho committed Jul 9, 2024
1 parent 27a7508 commit 1b8d886
Showing 1 changed file with 7 additions and 1 deletion.
8 changes: 7 additions & 1 deletion winsup/cygwin/uinfo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -934,7 +934,13 @@ fetch_home_env (void)
/* If `HOME` is set, prefer it */
const char *home = getenv ("HOME");
if (home)
return strdup (home);
{
/* In the very early code path of `user_info::initialize ()`, the value
of the environment variable `HOME` is still in its Windows form. */
if (isdrive (home) || home[0] == '\\')
return (char *) cygwin_create_path (CCP_WIN_A_TO_POSIX, home);
return strdup (home);
}

/* If `HOME` is unset, fall back to `HOMEDRIVE``HOMEPATH`
(without a directory separator, as `HOMEPATH` starts with one). */
Expand Down

0 comments on commit 1b8d886

Please sign in to comment.