From ce882ee3cb988300a1a7fbb8a5457d3daa422632 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 27 Apr 2015 11:58:08 +0200 Subject: [PATCH 1/3] Allow overriding the home directory via the HOME variable In Git for Windows, it is a well-established technique to use the `$HOME` variable to define where the current user's home directory is, falling back to `$HOMEDRIVE$HOMEPATH` and `$USERPROFILE`. This strategy is particular important when Cygwin, or command-line programs depending on the HOME variable, cannot cope with the Windows' idea of the user's home directory e.g. when it is set to a hidden directory via an UNC path (\\share\some\hidden\folder$). Of course this strategy needs to be opt-in. For that reason, this strategy is activated via the `env` keyword in the `db_home` line in `/etc/nsswitch.conf`. Signed-off-by: Johannes Schindelin --- winsup/cygwin/cygheap.h | 3 ++- winsup/cygwin/uinfo.cc | 49 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index 8877cc358c..ced50a1c74 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -403,7 +403,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 4c94d83650..999e2781a7 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -805,6 +805,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"); @@ -993,6 +995,40 @@ 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) @@ -1052,6 +1088,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; @@ -1084,6 +1124,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; @@ -1103,6 +1147,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)) @@ -1167,6 +1212,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) @@ -1248,6 +1294,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) @@ -1274,6 +1322,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) From 791cfa4c7ee19dc9722f52b3593359947893eba1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 25 Sep 2015 17:15:41 +0200 Subject: [PATCH 2/3] Respect `db_home` setting even for the SYSTEM account We should not blindly set the home directory of the SYSTEM account to /home/SYSTEM, especially not when that value disagrees with what is configured via the `db_home` line in the `/etc/nsswitch.conf` file. This fixes https://github.com/git-for-windows/git/issues/435 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 999e2781a7..b15af8d8d4 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -2318,7 +2318,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 (pldap, sid, dom, domain, name, + fully_qualified_name); + } switch ((int) acc_type) { case SidTypeUser: From c92d9b9aa777aa4d46be9bb6d5a0a2f60ea06fb6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 7 Jan 2016 15:54:27 +0000 Subject: [PATCH 3/3] Respect the `db_home: env` setting under more circumstances In particular when we cannot figure out a uid for the current user, we should still respect the `db_home: env` setting. Such a situation occurs for example when the domain returned by `LookupAccountSid()` is not our machine name and at the same time our machine is no domain member: In that case, we have nobody to ask for the POSIX offset necessary to come up with the uid. It is important that even in such cases, the HOME environment variable can be used to override the home directory, e.g. when Git for Windows is used by an account that was generated on the fly, e.g. for transient use in a cloud scenario. Reported by David Ebbo. Signed-off-by: Johannes Schindelin --- winsup/cygwin/uinfo.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index b15af8d8d4..282d0f432d 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -1105,6 +1105,8 @@ 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: @@ -2265,6 +2267,9 @@ 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) @@ -2825,10 +2830,11 @@ 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:/:/sbin/nologin", + __small_sprintf (linebuf, "%W:*:%u:%u:U-%W\\%W,%s:%s:/sbin/nologin", posix_name, uid, gid, dom, name, - sid.string ((char *) sidstr)); + sid.string ((char *) sidstr), + home ? home : "/"); else __small_sprintf (linebuf, "%W:*:%u:%u:%s%sU-%W\\%W,%s:%s%W:%s", posix_name, uid, gid,