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 <corinna@vinschen.de>
This commit is contained in:
parent
abd37f0c79
commit
472e5439e7
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
EvalRet (NERR_UserNotFound, user);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
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.");
|
||||
|
|
Loading…
Reference in New Issue