summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/release/2.6.03
-rw-r--r--winsup/utils/passwd.c92
2 files changed, 52 insertions, 43 deletions
diff --git a/winsup/cygwin/release/2.6.0 b/winsup/cygwin/release/2.6.0
index eb39f8fec..ffa6c17d1 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 9510be514..70778b88d 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.");