From 66bb413b20c3ae24439b6ccbdb846fa80c46de8c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 29 Nov 2023 23:49:00 +0100 Subject: [PATCH 1/7] fixup! Allow overriding the home directory via the HOME variable In preparation for integrating the patches that made it upstream via https://inbox.sourceware.org/cygwin-patches/cover.1684753872.git.johannes.schindelin@gmx.de/, let's revert the original patches from Git for Windows' branch thicket. This reverts commit 81a0e5d4a9566ebc22b857de5c61f0e12fa32192. Signed-off-by: Johannes Schindelin --- winsup/cygwin/local_includes/cygheap.h | 3 +- winsup/cygwin/uinfo.cc | 49 -------------------------- 2 files changed, 1 insertion(+), 51 deletions(-) diff --git a/winsup/cygwin/local_includes/cygheap.h b/winsup/cygwin/local_includes/cygheap.h index c33f378500..4828e57e66 100644 --- a/winsup/cygwin/local_includes/cygheap.h +++ b/winsup/cygwin/local_includes/cygheap.h @@ -406,8 +406,7 @@ class cygheap_pwdgrp NSS_SCHEME_UNIX, NSS_SCHEME_DESC, NSS_SCHEME_PATH, - NSS_SCHEME_FREEATTR, - NSS_SCHEME_ENV + NSS_SCHEME_FREEATTR }; struct nss_scheme_t { nss_scheme_method method; diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index fefd984f84..b910878dbe 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -738,8 +738,6 @@ cygheap_pwdgrp::nss_init_line (const char *line) scheme[idx].method = NSS_SCHEME_UNIX; else if (NSS_CMP ("desc")) scheme[idx].method = NSS_SCHEME_DESC; - else if (NSS_CMP ("env")) - scheme[idx].method = NSS_SCHEME_ENV; else if (NSS_NCMP ("/")) { const char *e = c + strcspn (c, " \t"); @@ -928,40 +926,6 @@ 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 (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)) - { - 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()); - } - - return NULL; -} - char * cygheap_pwdgrp::get_home (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, PCWSTR dnsdomain, PCWSTR name, bool full_qualified) @@ -1021,10 +985,6 @@ cygheap_pwdgrp::get_home (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, } } break; - case NSS_SCHEME_ENV: - if (RtlEqualSid (sid, cygheap->user.sid ())) - home = fetch_home_env (); - break; } } return home; @@ -1059,10 +1019,6 @@ cygheap_pwdgrp::get_home (PUSER_INFO_3 ui, cygpsid &sid, PCWSTR dom, home = fetch_from_path (NULL, ui, sid, home_scheme[idx].attrib, dom, NULL, name, full_qualified); break; - case NSS_SCHEME_ENV: - if (RtlEqualSid (sid, cygheap->user.sid ())) - home = fetch_home_env (); - break; } } return home; @@ -1082,7 +1038,6 @@ cygheap_pwdgrp::get_shell (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, case NSS_SCHEME_FALLBACK: return NULL; case NSS_SCHEME_WINDOWS: - case NSS_SCHEME_ENV: break; case NSS_SCHEME_CYGWIN: if (pldap->fetch_ad_account (sid, false, dnsdomain)) @@ -1147,7 +1102,6 @@ cygheap_pwdgrp::get_shell (PUSER_INFO_3 ui, cygpsid &sid, PCWSTR dom, case NSS_SCHEME_CYGWIN: case NSS_SCHEME_UNIX: case NSS_SCHEME_FREEATTR: - case NSS_SCHEME_ENV: break; case NSS_SCHEME_DESC: if (ui) @@ -1229,8 +1183,6 @@ cygheap_pwdgrp::get_gecos (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, sys_wcstombs_alloc (&gecos, HEAP_NOTHEAP, val); } break; - case NSS_SCHEME_ENV: - break; } } if (gecos) @@ -1257,7 +1209,6 @@ cygheap_pwdgrp::get_gecos (PUSER_INFO_3 ui, cygpsid &sid, PCWSTR dom, case NSS_SCHEME_CYGWIN: case NSS_SCHEME_UNIX: case NSS_SCHEME_FREEATTR: - case NSS_SCHEME_ENV: break; case NSS_SCHEME_DESC: if (ui) From 94c27b7454b479c335fd83685b1e973ab6fdae2d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 29 Nov 2023 23:50:00 +0100 Subject: [PATCH 2/7] fixup! Respect `db_home` setting even for the SYSTEM account In preparation for integrating the patches that made it upstream via https://inbox.sourceware.org/cygwin-patches/cover.1684753872.git.johannes.schindelin@gmx.de/, let's revert the original patches from Git for Windows' branch thicket. This reverts commit 22854f66a429d9bd583621f5b6e365fe9b88cd9d. Signed-off-by: Johannes Schindelin --- winsup/cygwin/uinfo.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index b910878dbe..1dbd82655e 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -2194,11 +2194,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) it to a well-known group here. */ if (acc_type == SidTypeUser && (sid_sub_auth_count (sid) <= 3 || sid_id_auth (sid) == 11)) - { - acc_type = SidTypeWellKnownGroup; - home = cygheap->pg.get_home (pldap, sid, dom, domain, name, - fully_qualified_name); - } + acc_type = SidTypeWellKnownGroup; switch ((int) acc_type) { case SidTypeUser: From 8f9fcab47a1ac1457ac08d24b2e146f37082ea29 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 29 Nov 2023 23:50:05 +0100 Subject: [PATCH 3/7] fixup! Respect the `db_home: env` setting under more circumstances In preparation for integrating the patches that made it upstream via https://inbox.sourceware.org/cygwin-patches/cover.1684753872.git.johannes.schindelin@gmx.de/, let's revert the original patches from Git for Windows' branch thicket. This reverts commit f0d56412872d931e55fde9406d390e2070f2befb. Signed-off-by: Johannes Schindelin --- winsup/cygwin/uinfo.cc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 1dbd82655e..00a447d450 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -998,8 +998,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: @@ -2138,9 +2136,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) @@ -2690,11 +2685,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, From 83137f963888a0e94c5c90e651930be10a1275f1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 28 Mar 2023 10:17:14 +0200 Subject: [PATCH 4/7] 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 --- winsup/cygwin/local_includes/cygheap.h | 3 +- winsup/cygwin/uinfo.cc | 51 ++++++++++++++++++++++++++ winsup/doc/ntsec.xml | 22 +++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/local_includes/cygheap.h b/winsup/cygwin/local_includes/cygheap.h index 4828e57e66..c33f378500 100644 --- a/winsup/cygwin/local_includes/cygheap.h +++ b/winsup/cygwin/local_includes/cygheap.h @@ -406,7 +406,8 @@ class cygheap_pwdgrp NSS_SCHEME_UNIX, NSS_SCHEME_DESC, NSS_SCHEME_PATH, - NSS_SCHEME_FREEATTR + NSS_SCHEME_FREEATTR, + NSS_SCHEME_ENV }; struct nss_scheme_t { nss_scheme_method method; diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 00a447d450..df2474459c 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -738,6 +738,8 @@ cygheap_pwdgrp::nss_init_line (const char *line) scheme[idx].method = NSS_SCHEME_UNIX; else if (NSS_CMP ("desc")) scheme[idx].method = NSS_SCHEME_DESC; + else if (NSS_CMP ("env")) + scheme[idx].method = NSS_SCHEME_ENV; else if (NSS_NCMP ("/")) { const char *e = c + strcspn (c, " \t"); @@ -926,6 +928,42 @@ fetch_from_path (cyg_ldap *pldap, PUSER_INFO_3 ui, cygpsid &sid, PCWSTR str, 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 * cygheap_pwdgrp::get_home (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, PCWSTR dnsdomain, PCWSTR name, bool full_qualified) @@ -985,6 +1023,10 @@ cygheap_pwdgrp::get_home (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, } } break; + case NSS_SCHEME_ENV: + if (RtlEqualSid (sid, cygheap->user.sid ())) + home = fetch_home_env (); + break; } } return home; @@ -1017,6 +1059,10 @@ cygheap_pwdgrp::get_home (PUSER_INFO_3 ui, cygpsid &sid, PCWSTR dom, home = fetch_from_path (NULL, ui, sid, home_scheme[idx].attrib, dom, NULL, name, full_qualified); break; + case NSS_SCHEME_ENV: + if (RtlEqualSid (sid, cygheap->user.sid ())) + home = fetch_home_env (); + break; } } return home; @@ -1036,6 +1082,7 @@ cygheap_pwdgrp::get_shell (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, case NSS_SCHEME_FALLBACK: return NULL; case NSS_SCHEME_WINDOWS: + case NSS_SCHEME_ENV: break; case NSS_SCHEME_CYGWIN: if (pldap->fetch_ad_account (sid, false, dnsdomain)) @@ -1100,6 +1147,7 @@ cygheap_pwdgrp::get_shell (PUSER_INFO_3 ui, cygpsid &sid, PCWSTR dom, case NSS_SCHEME_CYGWIN: case NSS_SCHEME_UNIX: case NSS_SCHEME_FREEATTR: + case NSS_SCHEME_ENV: break; case NSS_SCHEME_DESC: if (ui) @@ -1181,6 +1229,8 @@ cygheap_pwdgrp::get_gecos (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, sys_wcstombs_alloc (&gecos, HEAP_NOTHEAP, val); } break; + case NSS_SCHEME_ENV: + break; } } if (gecos) @@ -1207,6 +1257,7 @@ cygheap_pwdgrp::get_gecos (PUSER_INFO_3 ui, cygpsid &sid, PCWSTR dom, case NSS_SCHEME_CYGWIN: case NSS_SCHEME_UNIX: case NSS_SCHEME_FREEATTR: + case NSS_SCHEME_ENV: break; case NSS_SCHEME_DESC: if (ui) 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 From a24bc22df45b3a90060fe351cbadac741f67f541 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 3 Apr 2023 16:45:03 +0200 Subject: [PATCH 5/7] Respect `db_home` setting even for SYSTEM/Microsoft accounts We should not blindly set the home directory of the SYSTEM account (or of Microsoft accounts) to `/home/`, especially `/etc/nsswitch.conf` defines `db_home: env`, in which case we want to respect the `HOME` variable. Signed-off-by: Johannes Schindelin --- winsup/cygwin/uinfo.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index df2474459c..4c03176e91 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -2240,7 +2240,11 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) it to a well-known group here. */ if (acc_type == SidTypeUser && (sid_sub_auth_count (sid) <= 3 || sid_id_auth (sid) == 11)) - acc_type = SidTypeWellKnownGroup; + { + acc_type = SidTypeWellKnownGroup; + home = cygheap->pg.get_home ((PUSER_INFO_3) NULL, sid, dom, name, + fully_qualified_name); + } switch ((int) acc_type) { case SidTypeUser: From 27a7508e9cf89be0ff70b4976ee82b8295ad09b0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 22 May 2023 13:12:56 +0200 Subject: [PATCH 6/7] uinfo: special-case IIS APPPOOL accounts The account under which Azure Web Apps run is an IIS APPOOL account that is generated on the fly. These are special because the virtual machines on which thes Apps run are not domain-joined, yet the accounts are domain accounts. To support the use case where such a Web App needs to call `ssh` (e.g. to deploy from a Git repository that is accessible only via SSH), we do need OpenSSH's `getpwuid (getuid ())` invocation to work. But currently it does not. Concretely, `getuid ()` returns -1 for these accounts, and OpenSSH fails to find the correct home directory (_especially_ when that home directory was overridden via a `db_home: env` line in `/etc/nsswitch.conf`). This can be verified e.g. in a Kudu console (for details about Kudu consoles, see https://github.com/projectkudu/kudu/wiki/Kudu-console): the domain is `IIS APPPOOL`, the account name is the name of the Azure Web App, the SID starts with 'S-1-5-82-`, and `pwdgrp::fetch_account_from_windows()` runs into the code path where "[...] 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." Since these IIS APPPOOL accounts are relatively similar to AzureAD accounts in this scenario, let's imitate the latter to support also the former. Reported-by: David Ebbo Helped-by: Corinna Vinschen Signed-off-by: Johannes Schindelin --- winsup/cygwin/uinfo.cc | 107 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 9 deletions(-) diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 4c03176e91..8716811b7e 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -1490,9 +1490,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 +1520,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 +1831,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 +2064,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 +2094,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 +2176,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 @@ -2259,7 +2317,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 ()) { @@ -2348,7 +2408,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; @@ -2361,6 +2421,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. */ @@ -2632,6 +2707,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) { From 1b8d886206ddb2f516f2448edac43f03054aca6c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 22 May 2023 13:13:02 +0200 Subject: [PATCH 7/7] Do not rely on `getenv ("HOME")`'s path conversion 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 27376c60a9 (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 --- winsup/cygwin/uinfo.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 8716811b7e..f963841789 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -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). */