https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=472e5439e7c7c7ecb552149de494f91540b55f8b
commit 472e5439e7c7c7ecb552149de494f91540b55f8b Author: Corinna Vinschen <cori...@vinschen.de> Date: Wed Aug 31 12:08:34 2016 +0200 Fix passwd getting error 1265 when running on newer Windows On Windows 8.1 and later, the NetUserChangePassword call apparently doesn't accept the usual "\\server" string anymore, but requires to use the "domain" instead, otherwise it emits en error code 1265, ERROR_DOWNGRADE_DETECTED. Since this is accepted by pre-8.1 as well, use the domain indiscriminately when calling NetUserChangePassword from passwd(1). While at it, do some minor cleanup in passwd.c. Signed-off-by: Corinna Vinschen <cori...@vinschen.de> Diff: --- winsup/cygwin/release/2.6.0 | 3 ++ winsup/utils/passwd.c | 92 ++++++++++++++++++++++++--------------------- 2 files changed, 52 insertions(+), 43 deletions(-) diff --git a/winsup/cygwin/release/2.6.0 b/winsup/cygwin/release/2.6.0 index eb39f8f..ffa6c17 100644 --- a/winsup/cygwin/release/2.6.0 +++ b/winsup/cygwin/release/2.6.0 @@ -84,3 +84,6 @@ Bug Fixes - Fix off_t typedef on 64-bit. Addresses: https://sourceware.org/ml/newlib/2016/msg01028.html + +- Fix weird problem running passwd on newer Windows versions. + Addresses: https://cygwin.com/ml/cygwin/2016-08/msg00608.html diff --git a/winsup/utils/passwd.c b/winsup/utils/passwd.c index 9510be5..70778b8 100644 --- a/winsup/utils/passwd.c +++ b/winsup/utils/passwd.c @@ -113,57 +113,57 @@ EvalRet (int ret, const char *user) } PUSER_INFO_3 -GetPW (char *user, int print_win_name, LPWSTR *server) +GetPW (char *user, int print_win_name, LPWSTR *server, LPWSTR domain) { char usr_buf[UNLEN + 1]; WCHAR name[UNLEN + 1]; DWORD ret; PUSER_INFO_3 ui; struct passwd *pw; - char *domain = (char *) alloca (INTERNET_MAX_HOST_NAME_LENGTH + 1); + char dom[INTERNET_MAX_HOST_NAME_LENGTH + 1]; /* Get the Win32 username and a suitable server. */ - if ((pw = getpwnam (user))) + pw = getpwnam (user); + if (!pw) { - cygwin_internal (CW_EXTRACT_DOMAIN_AND_USER, pw, domain, usr_buf); - if (strcasecmp (pw->pw_name, usr_buf)) - { - /* Hack to avoid problem with LookupAccountSid after impersonation */ - if (strcasecmp (usr_buf, "SYSTEM")) - { - user = usr_buf; - if (print_win_name) - printf ("Windows username : %s\n", user); - } - } - if (!*server) - { - PDOMAIN_CONTROLLER_INFOW dci; - char machine[INTERNET_MAX_HOST_NAME_LENGTH + 1]; - DWORD mlen = sizeof machine; - WCHAR wdom[INTERNET_MAX_HOST_NAME_LENGTH + 1]; - - /* If we can't fetch the local machine name, or if the machine name - is not the same as the user's domain name, try to fetch the DC via - DsGetDcName. Otherwise, just stick to a NULL servername, since - that's the same as using the local machine. */ - if (!GetComputerNameExA (ComputerNameNetBIOS, machine, &mlen) - || strcasecmp (domain, machine) != 0) - { - mbstowcs (wdom, domain, INTERNET_MAX_HOST_NAME_LENGTH + 1); - if (!DsGetDcNameW (NULL, wdom, NULL, NULL, DS_IS_FLAT_NAME, &dci)) - *server = dci->DomainControllerName; - } - } + EvalRet (NERR_UserNotFound, user); + return NULL; + } + + cygwin_internal (CW_EXTRACT_DOMAIN_AND_USER, pw, dom, usr_buf); + /* Hack to avoid problem with LookupAccountSid after impersonation + using the simple NtCreateToken method. */ + if (strcasecmp (pw->pw_name, usr_buf) && strcasecmp (usr_buf, "SYSTEM")) + { + user = usr_buf; + if (print_win_name) + printf ("Windows username : %s\n", user); } mbstowcs (name, user, UNLEN + 1); + mbstowcs (domain, dom, INTERNET_MAX_HOST_NAME_LENGTH + 1); + if (!*server) + { + PDOMAIN_CONTROLLER_INFOW dci; + WCHAR machine[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + DWORD mlen = INTERNET_MAX_HOST_NAME_LENGTH + 1; + + /* If the machine name is not the same as the user's domain name we're + in a domain. Fetch the DC via DsGetDcName. Otherwise, just stick + to a NULL servername, since that's the same as using the local + machine. */ + if ((!GetComputerNameExW (ComputerNameNetBIOS, machine, &mlen) + || wcscasecmp (domain, machine) != 0) + && !DsGetDcNameW (NULL, domain, NULL, NULL, DS_IS_FLAT_NAME, &dci)) + *server = dci->DomainControllerName; + } + ret = NetUserGetInfo (*server, name, 3, (void *) &ui); return EvalRet (ret, user) ? NULL : ui; } int -ChangePW (const char *user, PCWSTR name, const char *oldpwd, const char *pwd, - int justcheck, LPCWSTR server) +ChangePW (const char *user, PCWSTR domain, PCWSTR name, const char *oldpwd, + const char *pwd, int justcheck, PCWSTR server) { WCHAR oldpass[512], pass[512]; DWORD ret; @@ -179,7 +179,11 @@ ChangePW (const char *user, PCWSTR name, const char *oldpwd, const char *pwd, else { mbstowcs (oldpass, oldpwd, 512); - ret = NetUserChangePassword (server, name, oldpass, pass); + /* NetUserChangePassword has changed between W7 and W8.1. For some + reason it doesn't accept the usual "\\server" servername anymore, + rather you have to use the domain name as server parameter, otherwise + you suffer an error 1265, ERROR_DOWNGRADE_DETECTED. */ + ret = NetUserChangePassword (domain, name, oldpass, pass); } if (justcheck && ret != ERROR_INVALID_PASSWORD) return 0; @@ -189,7 +193,7 @@ ChangePW (const char *user, PCWSTR name, const char *oldpwd, const char *pwd, } void -PrintPW (PUSER_INFO_3 ui, LPCWSTR server) +PrintPW (PUSER_INFO_3 ui, PCWSTR server) { time_t t = time (NULL) - ui->usri3_password_age; int ret; @@ -230,7 +234,7 @@ PrintPW (PUSER_INFO_3 ui, LPCWSTR server) } int -SetModals (int xarg, int narg, int iarg, int Larg, LPCWSTR server) +SetModals (int xarg, int narg, int iarg, int Larg, PCWSTR server) { int ret; PUSER_MODALS_INFO_0 mi; @@ -379,7 +383,9 @@ int main (int argc, char **argv) { char *logonserver; - char user[UNLEN + 1], oldpwd[_PASSWORD_LEN + 1], newpwd[_PASSWORD_LEN + 1]; + char user[UNLEN + 1]; + WCHAR domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + char oldpwd[_PASSWORD_LEN + 1], newpwd[_PASSWORD_LEN + 1]; int ret = 0; int cnt = 0; int opt; @@ -604,7 +610,7 @@ main (int argc, char **argv) } } - ui = GetPW (user, 1, &server); + ui = GetPW (user, 1, &server, domain); if (!ui) return 1; @@ -652,7 +658,7 @@ main (int argc, char **argv) if (!caller_is_admin ()) { strcpy (oldpwd, getpass ("Old password: ")); - if (ChangePW (user, ui->usri3_name, oldpwd, oldpwd, 1, server)) + if (ChangePW (user, domain, ui->usri3_name, oldpwd, oldpwd, 1, server)) return 1; } @@ -661,8 +667,8 @@ main (int argc, char **argv) strcpy (newpwd, getpass ("New password: ")); if (strcmp (newpwd, getpass ("Re-enter new password: "))) eprint (0, "Password is not identical."); - else if (!ChangePW (user, ui->usri3_name, *oldpwd ? oldpwd : NULL, - newpwd, 0, server)) + else if (!ChangePW (user, domain, ui->usri3_name, + *oldpwd ? oldpwd : NULL, newpwd, 0, server)) ret = 1; if (!ret && cnt < 2) eprint (0, "Try again.");