diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc
index fefd984f84..f963841789 100644
--- a/winsup/cygwin/uinfo.cc
+++ b/winsup/cygwin/uinfo.cc
@@ -928,37 +928,45 @@ fetch_from_path (cyg_ldap *pldap, PUSER_INFO_3 ui, cygpsid &sid, PCWSTR str,
return ret;
}
-static size_t
-fetch_env(LPCWSTR key, char *buf, size_t size)
-{
- WCHAR wbuf[32767];
- DWORD max = sizeof wbuf / sizeof *wbuf;
- DWORD len = GetEnvironmentVariableW (key, wbuf, max);
-
- if (!len || len >= max)
- return 0;
-
- len = sys_wcstombs (buf, size, wbuf, len);
- return len && len < size ? len : 0;
-}
-
static char *
fetch_home_env (void)
{
- char home[32767];
- size_t max = sizeof home / sizeof *home, len;
+ /* If `HOME` is set, prefer it */
+ const char *home = getenv ("HOME");
+ if (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 (fetch_env (L"HOME", home, max)
- || ((len = fetch_env (L"HOMEDRIVE", home, max))
- && fetch_env (L"HOMEPATH", home + len, max - len))
- || fetch_env (L"USERPROFILE", home, max))
+ /* 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)
{
- tmp_pathbuf tp;
- cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE,
- home, tp.c_get(), NT_MAX_PATH);
- return strdup(tp.c_get());
+ 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;
}
@@ -1038,8 +1046,6 @@ cygheap_pwdgrp::get_home (PUSER_INFO_3 ui, cygpsid &sid, PCWSTR dom,
for (uint16_t idx = 0; !home && idx < NSS_SCHEME_MAX; ++idx)
{
- if (!ui && home_scheme[idx].method != NSS_SCHEME_ENV)
- continue;
switch (home_scheme[idx].method)
{
case NSS_SCHEME_FALLBACK:
@@ -1490,9 +1496,9 @@ get_logon_sid ()
}
}
-/* Fetch special AzureAD group, which is part of the token group list but
- *not* recognized by LookupAccountSid (ERROR_NONE_MAPPED). */
-static cygsid azure_grp_sid ("");
+/* Fetch special AzureAD and IIS APPPOOL groups, which are part of the token
+ group list but *not* recognized by LookupAccountSid (ERROR_NONE_MAPPED). */
+static cygsid azure_grp_sid (""), iis_apppool_grp_sid ("");
static void
get_azure_grp_sid ()
@@ -1520,6 +1526,36 @@ get_azure_grp_sid ()
}
}
+static void
+get_iis_apppool_grp_sid ()
+{
+ if (PSID (iis_apppool_grp_sid) == NO_SID)
+ {
+ NTSTATUS status;
+ ULONG size;
+ tmp_pathbuf tp;
+ PTOKEN_GROUPS groups = (PTOKEN_GROUPS) tp.w_get ();
+
+ status = NtQueryInformationToken (hProcToken, TokenGroups, groups,
+ 2 * NT_MAX_PATH, &size);
+ if (!NT_SUCCESS (status))
+ debug_printf ("NtQueryInformationToken (TokenGroups) %y", status);
+ else
+ {
+ for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
+ {
+ PSID sid = groups->Groups[pg].Sid;
+ if (sid_id_auth (sid) == 5 &&
+ sid_sub_auth (sid, 0) == SECURITY_APPPOOL_ID_BASE_RID)
+ {
+ iis_apppool_grp_sid = sid;
+ break;
+ }
+ }
+ }
+ }
+}
+
void *
pwdgrp::add_account_post_fetch (char *line, bool lock)
{
@@ -1801,6 +1837,16 @@ pwdgrp::construct_sid_from_name (cygsid &sid, wchar_t *name, wchar_t *sep)
}
return false;
}
+ if (sep && wcscmp (name, L"IIS APPPOOL\\Group") == 0)
+ {
+ get_iis_apppool_grp_sid ();
+ if (PSID (logon_sid) != NO_SID)
+ {
+ sid = iis_apppool_grp_sid;
+ return true;
+ }
+ return false;
+ }
if (!sep && wcscmp (name, L"CurrentSession") == 0)
{
get_logon_sid ();
@@ -2024,8 +2070,11 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
/* Last but not least, some validity checks on the name style. */
if (!fq_name)
{
- /* AzureAD user must be prepended by "domain" name. */
- if (sid_id_auth (sid) == 12)
+ /* AzureAD and IIS APPPOOL users must be prepended by "domain"
+ name. */
+ if (sid_id_auth (sid) == 12 ||
+ (sid_id_auth (sid) == 5 &&
+ sid_sub_auth (sid, 0) == SECURITY_APPPOOL_ID_BASE_RID))
return NULL;
/* name_only account is either builtin or primary domain, or
account domain on non-domain machines. */
@@ -2051,8 +2100,10 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
}
else
{
- /* AzureAD accounts should be fully qualifed either. */
- if (sid_id_auth (sid) == 12)
+ /* AzureAD and IIS APPPOOL accounts should be fully qualifed either. */
+ if (sid_id_auth (sid) == 12 ||
+ (sid_id_auth (sid) == 5 &&
+ sid_sub_auth (sid, 0) == SECURITY_APPPOOL_ID_BASE_RID))
break;
/* Otherwise, no fully_qualified for builtin accounts, except for
NT SERVICE, for which we require the prefix. Note that there's
@@ -2131,6 +2182,19 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
sid = csid = azure_grp_sid;
break;
}
+ else if (arg.id == 0x1002)
+ {
+ /* IIS APPPOOL S-1-5-82-* user */
+ csid = cygheap->user.saved_sid ();
+ }
+ else if (arg.id == 0x1003)
+ {
+ /* Special IIS APPPOOL group SID */
+ get_iis_apppool_grp_sid ();
+ /* LookupAccountSidW will fail. */
+ sid = csid = iis_apppool_grp_sid;
+ break;
+ }
else if (arg.id == 0xfffe)
{
/* Special case "nobody" for reproducible construction of a
@@ -2187,9 +2251,6 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
{
/* Just some fake. */
sid = csid.create (99, 1, 0);
- if (arg.id == cygheap->user.real_uid)
- home = cygheap->pg.get_home(NULL, cygheap->user.sid(),
- NULL, NULL, false);
break;
}
else if (arg.id >= UNIX_POSIX_OFFSET)
@@ -2245,7 +2306,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
&& (sid_sub_auth_count (sid) <= 3 || sid_id_auth (sid) == 11))
{
acc_type = SidTypeWellKnownGroup;
- home = cygheap->pg.get_home (pldap, sid, dom, domain, name,
+ home = cygheap->pg.get_home ((PUSER_INFO_3) NULL, sid, dom, name,
fully_qualified_name);
}
switch ((int) acc_type)
@@ -2262,7 +2323,9 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
Those we let pass, but no others. */
bool its_ok = false;
- if (sid_id_auth (sid) == 12)
+ if (sid_id_auth (sid) == 12 ||
+ (sid_id_auth (sid) == 5 &&
+ sid_sub_auth (sid, 0) == SECURITY_APPPOOL_ID_BASE_RID))
its_ok = true;
else if (wincap.has_microsoft_accounts ())
{
@@ -2351,7 +2414,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
posix_offset = fetch_posix_offset (td, &loc_ldap);
}
}
- /* AzureAD S-1-12-1-W-X-Y-Z user */
+ /* AzureAD S-1-12-1-W-X-Y-Z and IIS APPOOL S-1-5-82-* user */
else if (sid_id_auth (sid) == 12)
{
uid = gid = 0x1000;
@@ -2364,6 +2427,21 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
name, fully_qualified_name);
break;
}
+ /* IIS APPOOL S-1-5-82-* user */
+ else if (sid_id_auth (sid) == 5 &&
+ sid_sub_auth (sid, 0) == SECURITY_APPPOOL_ID_BASE_RID)
+ {
+ uid = 0x1002;
+ gid = 0x1003;
+ fully_qualified_name = true;
+ home = cygheap->pg.get_home ((PUSER_INFO_3) NULL, sid, dom, name,
+ fully_qualified_name);
+ shell = cygheap->pg.get_shell ((PUSER_INFO_3) NULL, sid, dom,
+ name, fully_qualified_name);
+ gecos = cygheap->pg.get_gecos ((PUSER_INFO_3) NULL, sid, dom,
+ name, fully_qualified_name);
+ break;
+ }
/* If the domain returned by LookupAccountSid is not our machine
name, and if our machine is no domain member, we lose. We have
nobody to ask for the POSIX offset. */
@@ -2635,6 +2713,20 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
fully_qualified_name = true;
acc_type = SidTypeUnknown;
}
+ else if (sid_id_auth (sid) == 5 &&
+ sid_sub_auth (sid, 0) == SECURITY_APPPOOL_ID_BASE_RID)
+ {
+ /* Special IIS APPPOOL group SID which can't be resolved by
+ LookupAccountSid (ERROR_NONE_MAPPED). This is only allowed
+ as group entry, not as passwd entry. */
+ if (is_passwd ())
+ return NULL;
+ uid = gid = 0x1003;
+ wcpcpy (dom, L"IIS APPPOOL");
+ wcpcpy (name = namebuf, L"Group");
+ fully_qualified_name = true;
+ acc_type = SidTypeUnknown;
+ }
else if (sid_id_auth (sid) == 5 /* SECURITY_NT_AUTHORITY */
&& sid_sub_auth (sid, 0) == SECURITY_LOGON_IDS_RID)
{
@@ -2743,11 +2835,10 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
logon. Unless it's the SYSTEM account. This conveniently allows to
logon interactively as SYSTEM for debugging purposes. */
else if (acc_type != SidTypeUser && sid != well_known_system_sid)
- __small_sprintf (linebuf, "%W:*:%u:%u:U-%W\\%W,%s:%s:/sbin/nologin",
+ __small_sprintf (linebuf, "%W:*:%u:%u:U-%W\\%W,%s:/:/sbin/nologin",
posix_name, uid, gid,
dom, name,
- sid.string ((char *) sidstr),
- home ? home : "/");
+ sid.string ((char *) sidstr));
else
__small_sprintf (linebuf, "%W:*:%u:%u:%s%sU-%W\\%W,%s:%s%W:%s",
posix_name, uid, gid,
diff --git a/winsup/doc/ntsec.xml b/winsup/doc/ntsec.xml
index d61b585171..8f07c2258f 100644
--- a/winsup/doc/ntsec.xml
+++ b/winsup/doc/ntsec.xml
@@ -1221,6 +1221,17 @@ schemata are the following:
See
for a more detailed description.
+
+ env
+ Derives the home directory of the current user from the
+ environment variable HOME (falling back to
+ HOMEDRIVE\HOMEPATH and
+ USERPROFILE, in that order). This is faster
+ than the windows schema at the
+ expense of determining only the current user's home directory
+ correctly. This schema is skipped for any other account.
+
+
@@ -1353,6 +1364,17 @@ of each schema when used with db_home:
See
for a detailed description.
+
+ env
+ Derives the home directory of the current user from the
+ environment variable HOME (falling back to
+ HOMEDRIVE\HOMEPATH and
+ USERPROFILE, in that order). This is faster
+ than the windows schema at the
+ expense of determining only the current user's home directory
+ correctly. This schema is skipped for any other account.
+
+
@ad_attribute
AD only: The user's home directory is set to the path given