diff --git a/newlib/libc/stdlib/mbtowc_r.c b/newlib/libc/stdlib/mbtowc_r.c index 986595cfdc..47287564c2 100644 --- a/newlib/libc/stdlib/mbtowc_r.c +++ b/newlib/libc/stdlib/mbtowc_r.c @@ -48,7 +48,7 @@ _DEFUN (__ascii_mbtowc, (r, pwc, s, n, charset, state), if (n == 0) return -2; -#ifdef __CYGWIN__ +#ifdef STRICTLY_7BIT_ASCII if ((wchar_t)*t >= 0x80) { r->_errno = EILSEQ; diff --git a/newlib/libc/stdlib/wctomb_r.c b/newlib/libc/stdlib/wctomb_r.c index c93962fa43..e70349f33f 100644 --- a/newlib/libc/stdlib/wctomb_r.c +++ b/newlib/libc/stdlib/wctomb_r.c @@ -41,7 +41,7 @@ _DEFUN (__ascii_wctomb, (r, s, wchar, charset, state), if (s == NULL) return 0; -#ifdef __CYGWIN__ +#ifdef STRICTLY_7BIT_ASCII if ((size_t)wchar >= 0x80) #else if ((size_t)wchar >= 0x100) diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index fd848144f4..097d50fb96 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -414,7 +414,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/environ.cc b/winsup/cygwin/environ.cc index daef751a67..47b6138c99 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -1148,9 +1148,17 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, { bool calc_tl = !no_envblock; #ifdef __MSYS__ - /* Don't pass timezone environment to non-msys applications */ + /* Don't pass non-standard timezone to non-msys applications */ if (!keep_posix && ascii_strncasematch(*srcp, "TZ=", 3)) - goto next1; + { + const char *v = *srcp + 3; + if (*v == ':') + goto next1; + for (; *v; v++) + if (!isalpha(*v) && !isdigit(*v) && + *v != '-' && *v != '+' && *v != ':') + goto next1; + } #endif /* Look for entries that require special attention */ for (unsigned i = 0; i < SPENVS_SIZE; i++) @@ -1255,7 +1263,7 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, Note that this doesn't stop invalid strings without '=' in it etc., but we're opting for speed here for now. Adding complete checking would be pretty expensive. */ - if (len == 1 || !*rest) + if (len == 1) continue; /* See if this entry requires posix->win32 conversion. */ diff --git a/winsup/cygwin/how-to-debug-cygwin.txt b/winsup/cygwin/how-to-debug-cygwin.txt index fcf53a27f2..703d21f608 100644 --- a/winsup/cygwin/how-to-debug-cygwin.txt +++ b/winsup/cygwin/how-to-debug-cygwin.txt @@ -126,3 +126,9 @@ set CYGWIN_DEBUG=cat.exe:gdb.exe program will crash, probably in small_printf. At that point, a 'bt' command should show you the offending call to strace_printf with the improper format string. + +9. Debug output without strace + + If you cannot use gdb, or if the program behaves differently using strace + for whatever reason, you can still use the small_printf() function to + output debugging messages directly to stderr. diff --git a/winsup/cygwin/msys2_path_conv.cc b/winsup/cygwin/msys2_path_conv.cc index c347bd4cb8..2487156d77 100644 --- a/winsup/cygwin/msys2_path_conv.cc +++ b/winsup/cygwin/msys2_path_conv.cc @@ -200,7 +200,7 @@ void ppl_convert(const char** from, const char* to, char** dst, const char* dste void find_end_of_posix_list(const char** to, int* in_string) { - for (; **to != '\0' && (in_string ? (**to != *in_string) : **to != ' '); ++*to) { + for (; **to != '\0' && (!in_string || **to != *in_string); ++*to) { } if (**to == *in_string) { @@ -237,6 +237,7 @@ void find_end_of_rooted_path(const char** from, const char** to, int* in_string) void sub_convert(const char** from, const char** to, char** dst, const char* dstend, int* in_string) { const char* copy_from = *from; path_type type = find_path_start_and_type(from, false, *to); + debug_printf("found type %d for path %s", type, copy_from); if (type == POSIX_PATH_LIST) { find_end_of_posix_list(to, in_string); @@ -300,12 +301,6 @@ const char* convert(char *dst, size_t dstlen, const char *src) { } continue; } - - if (isspace(*srcit)) { - //sub_convert(&srcbeg, &srcit, &dstit, dstend, &in_string); - //srcbeg = srcit + 1; - break; - } } sub_convert(&srcbeg, &srcit, &dstit, dstend, &in_string); @@ -341,8 +336,67 @@ path_type find_path_start_and_type(const char** src, int recurse, const char* en if (*it == '\0' || it == end) return NONE; - if (!isalnum(*it) && *it != '/' && *it != '\\' && *it != ':' && *it != '-' && *it != '.') { - return find_path_start_and_type(move(src, 1), true, end); + /* Let's not convert ~/.file to ~C:\msys64\.file */ + if (*it == '~') { +skip_p2w: + *src = end; + return NONE; + } + + /* + * Skip path mangling when environment indicates it. + */ + const char *no_pathconv = getenv ("MSYS_NO_PATHCONV"); + + if (no_pathconv) + goto skip_p2w; + + /* + * Prevent Git's :file.txt and :/message syntax from beeing modified. + */ + if (*it == ':') + goto skip_p2w; + + while (it != end && *it) { + switch (*it) { + case '`': + case '\'': + case '"': + case '*': + case '?': + case '[': + case ']': + goto skip_p2w; + case '/': + if (it + 1 < end && it[1] == '~') + goto skip_p2w; + break; + case ':': + // Avoid mangling IPv6 addresses + if (it + 1 < end && it[1] == ':') + goto skip_p2w; + + // Leave Git's :./name syntax alone + if (it + 1 < end && it[1] == '.') { + if (it + 2 < end && it[2] == '/') + goto skip_p2w; + if (it + 3 < end && it[2] == '.' && it[3] == '/') + goto skip_p2w; + } + break; + case '@': + // Paths do not contain '@@' + if (it + 1 < end && it[1] == '@') + goto skip_p2w; + } + ++it; + } + it = *src; + + while (!isalnum(*it) && !(0x80 & *it) && *it != '/' && *it != '\\' && *it != ':' && *it != '-' && *it != '.') { + recurse = true; + it = ++*src; + if (it == end || *it == '\0') return NONE; } path_type result = NONE; @@ -404,6 +458,8 @@ path_type find_path_start_and_type(const char** src, int recurse, const char* en int starts_with_minus = 0; int starts_with_minus_alpha = 0; + int only_dots = *it == '.'; + int has_slashes = 0; if (*it == '-') { starts_with_minus = 1; it += 1; @@ -447,11 +503,17 @@ path_type find_path_start_and_type(const char** src, int recurse, const char* en if (ch == '/' && *(it2 + 1) == '/') { return URL; } else { + if (!only_dots && !has_slashes) + goto skip_p2w; return POSIX_PATH_LIST; } } else if (memchr(it2, '=', end - it) == NULL) { return SIMPLE_WINDOWS_PATH; } + } else if (ch != '.') { + only_dots = 0; + if (ch == '/' || ch == '\\') + has_slashes = 1; } } diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index e4d62c1936..ef521af763 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -734,11 +734,11 @@ path_conv::check (const char *src, unsigned opt, need_directory = 1; *--tail = '\0'; } - /* Special case for "/" must set need_directory, without removing + /* Special case for "/" must not set need_directory, neither remove trailing slash */ else if (tail == path_copy + 1 && isslash (tail[-1])) { - need_directory = 1; + need_directory = 0; } path_end = tail; diff --git a/winsup/cygwin/strfuncs.cc b/winsup/cygwin/strfuncs.cc index ad6773823b..8b811322f3 100644 --- a/winsup/cygwin/strfuncs.cc +++ b/winsup/cygwin/strfuncs.cc @@ -639,7 +639,11 @@ sys_cp_mbstowcs (mbtowc_p f_mbtowc, const char *charset, wchar_t *dst, to store them in a symmetric way. */ bytes = 1; if (dst) +#ifdef STRICTLY_7BIT_ASCII *ptr = L'\xf000' | *pmbs; +#else + *ptr = *pmbs; +#endif memset (&ps, 0, sizeof ps); } diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 17ee7f5c93..8aeefaac25 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -780,6 +780,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"); @@ -970,6 +972,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) @@ -1029,6 +1065,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; @@ -1042,6 +1082,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: @@ -1060,6 +1102,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; @@ -1079,6 +1125,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)) @@ -1143,6 +1190,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: shell = fetch_from_description (ui->usri3_comment, L"shell=\"", 7); @@ -1223,6 +1271,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) @@ -1249,6 +1299,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: gecos = fetch_from_description (ui->usri3_comment, L"gecos=\"", 7); @@ -2025,6 +2076,9 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) { /* Just some fake. */ sid = csid = "S-1-99-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) @@ -2080,7 +2134,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 (acc_type) { case SidTypeUser: @@ -2513,10 +2571,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,