Allow deriving the current user's home directory via the HOME variable
This patch hails from Git for Windows (where the Cygwin runtime is used in the form of a slightly modified MSYS2 runtime), where it is a well-established technique to let the `$HOME` variable define where the current user's home directory is, falling back to `$HOMEDRIVE$HOMEPATH` and `$USERPROFILE`. The idea is that we want to share user-specific settings between programs, whether they be Cygwin, MSYS2 or not. Unfortunately, we cannot blindly activate the "db_home: windows" setting because in some setups, the user's home directory is set to a hidden directory via an UNC path (\\share\some\hidden\folder$) -- something many programs cannot handle correctly, e.g. `cmd.exe` and other native Windows applications that users want to employ as Git helpers. The established technique is to allow setting the user's home directory via the environment variables mentioned above: `$HOMEDRIVE$HOMEPATH` or `$USERPROFILE`. This has the additional advantage that it is much faster than querying the Windows user database. Of course this scheme needs to be opt-in. For that reason, it needs to be activated explicitly via `db_home: env` in `/etc/nsswitch.conf`. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
parent
fc6e89c937
commit
27376c60a9
|
@ -358,7 +358,8 @@ public:
|
||||||
NSS_SCHEME_UNIX,
|
NSS_SCHEME_UNIX,
|
||||||
NSS_SCHEME_DESC,
|
NSS_SCHEME_DESC,
|
||||||
NSS_SCHEME_PATH,
|
NSS_SCHEME_PATH,
|
||||||
NSS_SCHEME_FREEATTR
|
NSS_SCHEME_FREEATTR,
|
||||||
|
NSS_SCHEME_ENV
|
||||||
};
|
};
|
||||||
struct nss_scheme_t {
|
struct nss_scheme_t {
|
||||||
nss_scheme_method method;
|
nss_scheme_method method;
|
||||||
|
|
|
@ -733,6 +733,8 @@ cygheap_pwdgrp::nss_init_line (const char *line)
|
||||||
scheme[idx].method = NSS_SCHEME_UNIX;
|
scheme[idx].method = NSS_SCHEME_UNIX;
|
||||||
else if (NSS_CMP ("desc"))
|
else if (NSS_CMP ("desc"))
|
||||||
scheme[idx].method = NSS_SCHEME_DESC;
|
scheme[idx].method = NSS_SCHEME_DESC;
|
||||||
|
else if (NSS_CMP ("env"))
|
||||||
|
scheme[idx].method = NSS_SCHEME_ENV;
|
||||||
else if (NSS_NCMP ("/"))
|
else if (NSS_NCMP ("/"))
|
||||||
{
|
{
|
||||||
const char *e = c + strcspn (c, " \t");
|
const char *e = c + strcspn (c, " \t");
|
||||||
|
@ -921,6 +923,42 @@ fetch_from_path (cyg_ldap *pldap, PUSER_INFO_3 ui, cygpsid &sid, PCWSTR str,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
fetch_home_env (void)
|
||||||
|
{
|
||||||
|
/* If `HOME` is set, prefer it */
|
||||||
|
const char *home = getenv ("HOME");
|
||||||
|
if (home)
|
||||||
|
return strdup (home);
|
||||||
|
|
||||||
|
/* If `HOME` is unset, fall back to `HOMEDRIVE``HOMEPATH`
|
||||||
|
(without a directory separator, as `HOMEPATH` starts with one). */
|
||||||
|
const char *home_drive = getenv ("HOMEDRIVE");
|
||||||
|
if (home_drive)
|
||||||
|
{
|
||||||
|
const char *home_path = getenv ("HOMEPATH");
|
||||||
|
if (home_path)
|
||||||
|
{
|
||||||
|
tmp_pathbuf tp;
|
||||||
|
char *p = tp.c_get (), *q;
|
||||||
|
|
||||||
|
// concatenate HOMEDRIVE and HOMEPATH
|
||||||
|
q = stpncpy (p, home_drive, NT_MAX_PATH);
|
||||||
|
strlcpy (q, home_path, NT_MAX_PATH - (q - p));
|
||||||
|
return (char *) cygwin_create_path (CCP_WIN_A_TO_POSIX, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If neither `HOME` nor `HOMEDRIVE``HOMEPATH` are set, fall back
|
||||||
|
to `USERPROFILE`; In corporate setups, this might point to a
|
||||||
|
disconnected network share, hence this is the last fall back. */
|
||||||
|
home = getenv ("USERPROFILE");
|
||||||
|
if (home)
|
||||||
|
return (char *) cygwin_create_path (CCP_WIN_A_TO_POSIX, home);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
cygheap_pwdgrp::get_home (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom,
|
cygheap_pwdgrp::get_home (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom,
|
||||||
PCWSTR dnsdomain, PCWSTR name, bool full_qualified)
|
PCWSTR dnsdomain, PCWSTR name, bool full_qualified)
|
||||||
|
@ -980,6 +1018,10 @@ cygheap_pwdgrp::get_home (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NSS_SCHEME_ENV:
|
||||||
|
if (RtlEqualSid (sid, cygheap->user.sid ()))
|
||||||
|
home = fetch_home_env ();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return home;
|
return home;
|
||||||
|
@ -1012,6 +1054,10 @@ cygheap_pwdgrp::get_home (PUSER_INFO_3 ui, cygpsid &sid, PCWSTR dom,
|
||||||
home = fetch_from_path (NULL, ui, sid, home_scheme[idx].attrib,
|
home = fetch_from_path (NULL, ui, sid, home_scheme[idx].attrib,
|
||||||
dom, NULL, name, full_qualified);
|
dom, NULL, name, full_qualified);
|
||||||
break;
|
break;
|
||||||
|
case NSS_SCHEME_ENV:
|
||||||
|
if (RtlEqualSid (sid, cygheap->user.sid ()))
|
||||||
|
home = fetch_home_env ();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return home;
|
return home;
|
||||||
|
@ -1031,6 +1077,7 @@ cygheap_pwdgrp::get_shell (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom,
|
||||||
case NSS_SCHEME_FALLBACK:
|
case NSS_SCHEME_FALLBACK:
|
||||||
return NULL;
|
return NULL;
|
||||||
case NSS_SCHEME_WINDOWS:
|
case NSS_SCHEME_WINDOWS:
|
||||||
|
case NSS_SCHEME_ENV:
|
||||||
break;
|
break;
|
||||||
case NSS_SCHEME_CYGWIN:
|
case NSS_SCHEME_CYGWIN:
|
||||||
if (pldap->fetch_ad_account (sid, false, dnsdomain))
|
if (pldap->fetch_ad_account (sid, false, dnsdomain))
|
||||||
|
@ -1095,6 +1142,7 @@ cygheap_pwdgrp::get_shell (PUSER_INFO_3 ui, cygpsid &sid, PCWSTR dom,
|
||||||
case NSS_SCHEME_CYGWIN:
|
case NSS_SCHEME_CYGWIN:
|
||||||
case NSS_SCHEME_UNIX:
|
case NSS_SCHEME_UNIX:
|
||||||
case NSS_SCHEME_FREEATTR:
|
case NSS_SCHEME_FREEATTR:
|
||||||
|
case NSS_SCHEME_ENV:
|
||||||
break;
|
break;
|
||||||
case NSS_SCHEME_DESC:
|
case NSS_SCHEME_DESC:
|
||||||
if (ui)
|
if (ui)
|
||||||
|
@ -1176,6 +1224,8 @@ cygheap_pwdgrp::get_gecos (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom,
|
||||||
sys_wcstombs_alloc (&gecos, HEAP_NOTHEAP, val);
|
sys_wcstombs_alloc (&gecos, HEAP_NOTHEAP, val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NSS_SCHEME_ENV:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (gecos)
|
if (gecos)
|
||||||
|
@ -1202,6 +1252,7 @@ cygheap_pwdgrp::get_gecos (PUSER_INFO_3 ui, cygpsid &sid, PCWSTR dom,
|
||||||
case NSS_SCHEME_CYGWIN:
|
case NSS_SCHEME_CYGWIN:
|
||||||
case NSS_SCHEME_UNIX:
|
case NSS_SCHEME_UNIX:
|
||||||
case NSS_SCHEME_FREEATTR:
|
case NSS_SCHEME_FREEATTR:
|
||||||
|
case NSS_SCHEME_ENV:
|
||||||
break;
|
break;
|
||||||
case NSS_SCHEME_DESC:
|
case NSS_SCHEME_DESC:
|
||||||
if (ui)
|
if (ui)
|
||||||
|
|
|
@ -1203,6 +1203,17 @@ schemata are the following:
|
||||||
See <xref linkend="ntsec-mapping-nsswitch-desc"></xref>
|
See <xref linkend="ntsec-mapping-nsswitch-desc"></xref>
|
||||||
for a more detailed description.</listitem>
|
for a more detailed description.</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>env</literal></term>
|
||||||
|
<listitem>Derives the home directory of the current user from the
|
||||||
|
environment variable <literal>HOME</literal> (falling back to
|
||||||
|
<literal>HOMEDRIVE\HOMEPATH</literal> and
|
||||||
|
<literal>USERPROFILE</literal>, in that order). This is faster
|
||||||
|
than the <term><literal>windows</literal></term> schema at the
|
||||||
|
expense of determining only the current user's home directory
|
||||||
|
correctly. This schema is skipped for any other account.
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -1335,6 +1346,17 @@ of each schema when used with <literal>db_home:</literal>
|
||||||
See <xref linkend="ntsec-mapping-nsswitch-desc"></xref>
|
See <xref linkend="ntsec-mapping-nsswitch-desc"></xref>
|
||||||
for a detailed description.</listitem>
|
for a detailed description.</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>env</literal></term>
|
||||||
|
<listitem>Derives the home directory of the current user from the
|
||||||
|
environment variable <literal>HOME</literal> (falling back to
|
||||||
|
<literal>HOMEDRIVE\HOMEPATH</literal> and
|
||||||
|
<literal>USERPROFILE</literal>, in that order). This is faster
|
||||||
|
than the <term><literal>windows</literal></term> schema at the
|
||||||
|
expense of determining only the current user's home directory
|
||||||
|
correctly. This schema is skipped for any other account.
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><literal>@ad_attribute</literal></term>
|
<term><literal>@ad_attribute</literal></term>
|
||||||
<listitem>AD only: The user's home directory is set to the path given
|
<listitem>AD only: The user's home directory is set to the path given
|
||||||
|
|
Loading…
Reference in New Issue