diff options
Diffstat (limited to 'private/windows/gina/msgina/chngepwd.c')
-rw-r--r-- | private/windows/gina/msgina/chngepwd.c | 1262 |
1 files changed, 1262 insertions, 0 deletions
diff --git a/private/windows/gina/msgina/chngepwd.c b/private/windows/gina/msgina/chngepwd.c new file mode 100644 index 000000000..38decf1b2 --- /dev/null +++ b/private/windows/gina/msgina/chngepwd.c @@ -0,0 +1,1262 @@ +/****************************** Module Header ******************************\ +* Module Name: chngpwd.c +* +* Copyright (c) 1991, Microsoft Corporation +* +* Implementation of change-password functionality of winlogon +* +* History: +* 12-09-91 Davidc Created. +\***************************************************************************/ + +#include "msgina.h" +#include <stdio.h> +#include <wchar.h> + +// #define VERBOSE_UTILS + +#ifdef VERBOSE_UTILS +#define VerbosePrint(s) WLPrint(s) +#else +#define VerbosePrint(s) +#endif + +// +// Define the structure used to pass data into the change password dialog +// + +typedef struct _MPR_DATA { + struct _MPR_DATA * Next; + PWSTR pszProviderName; +} MPR_DATA, * PMPR_DATA; + +typedef struct { + PGLOBALS pGlobals; + PWCHAR UserName; + PWCHAR Domain; + PWCHAR OldPassword; + BOOL AnyDomain; + BOOL Impersonate; + BOOL AllowProviderOnly; + PMPR_DATA MprList; +} CHANGE_PASSWORD_DATA; +typedef CHANGE_PASSWORD_DATA *PCHANGE_PASSWORD_DATA; + + +// +// Private prototypes +// +BOOL WINAPI ChangePasswordDlgProc(HWND, UINT, WPARAM, LPARAM); +BOOL ChangePasswordDlgInit(HWND, LONG); +DLG_RETURN_TYPE AttemptPasswordChange(HWND); + +DLG_RETURN_TYPE +HandleFailedChangePassword( + HWND hDlg, + NTSTATUS Status, + PWCHAR UserName, + PWCHAR Domain, + PMSV1_0_CHANGEPASSWORD_RESPONSE pChangePasswordResponse + ); + +BOOL WINAPI +ChangePasswordHelpDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam + ); + + + + +/***************************************************************************\ +* FUNCTION: ChangePassword +* +* PURPOSE: Attempts to change a user's password +* +* ARGUMENTS: +* +* hwnd - the most recent parent window +* pGlobals - pointer to global data for this instance. +* The password information of this data will be +* updated upon successful change of the primary +* authenticator's password information. +* UserName - the name of the user to change +* Domain - the domain name to change the password on +* AnyDomain - if TRUE the user may select any trusted domain, or +* enter the name of any other domain +* +* RETURNS: +* +* MSGINA_DLG_SUCCESS - the password was changed successfully. +* MSGINA_DLG_FAILURE - the user's password could not be changed. +* DLG_INTERRUPTED() - this is a set of possible interruptions (see winlogon.h) +* +* HISTORY: +* +* 12-09-91 Davidc Created. +* +\***************************************************************************/ + +DLG_RETURN_TYPE +ChangePassword( + HWND hwnd, + PGLOBALS pGlobals, + PWCHAR UserName, + PWCHAR Domain, + BOOL AnyDomain) +{ + CHANGE_PASSWORD_DATA PasswordData; + DLG_RETURN_TYPE Result; + HWND hwndOldFocus = GetFocus(); + + PasswordData.pGlobals = pGlobals; + PasswordData.UserName = UserName; + PasswordData.Domain = Domain; + PasswordData.OldPassword = NULL; + PasswordData.AnyDomain = AnyDomain; + PasswordData.Impersonate = TRUE; + PasswordData.AllowProviderOnly = TRUE; + PasswordData.MprList = NULL; + + pWlxFuncs->WlxSetTimeout(hGlobalWlx, LOGON_TIMEOUT); + + Result = pWlxFuncs->WlxDialogBoxParam( hGlobalWlx, + hDllInstance, + MAKEINTRESOURCE(IDD_CHANGEPWD_DIALOG), + hwnd, + ChangePasswordDlgProc, + (LONG)&PasswordData); + SetFocus(hwndOldFocus); + return(Result); +} + + +/***************************************************************************\ +* FUNCTION: ChangePasswordLogon +* +* PURPOSE: Attempts to change a user's password during the logon process. +* This is the same as a normal change password except that the user +* does not have to enter the old password and can only change the +* password in the specified domain. This routine is intended to be +* called during logon when it is discovered that the user's +* password has expired. +* +* ARGUMENTS: +* +* hwnd - the most recent parent window +* pGlobals - pointer to global data for this instance +* UserName - the name of the user to change +* Domain - the domain name to change the password on +* OldPassword - the old user password +* NewPassword - points to a buffer that the new password is written +* into if the password is changed successfully. +* NewPasswordMaxBytes - the size of the newpassword buffer. +* +* RETURNS: +* +* MSGINA_DLG_SUCCESS - the password was changed successfully, NewPassword +* contains the new password text. +* MSGINA_DLG_FAILURE - the user's password could not be changed. +* DLG_INTERRUPTED() - this is a set of possible interruptions (see winlogon.h) +* +* HISTORY: +* +* 12-09-91 Davidc Created. +* +\***************************************************************************/ + +DLG_RETURN_TYPE +ChangePasswordLogon( + HWND hwnd, + PGLOBALS pGlobals, + PWCHAR UserName, + PWCHAR Domain, + PWCHAR OldPassword + ) +{ + CHANGE_PASSWORD_DATA PasswordData; + DLG_RETURN_TYPE Result; + + PasswordData.pGlobals = pGlobals; + PasswordData.UserName = UserName; + PasswordData.Domain = Domain; + PasswordData.OldPassword = OldPassword; + PasswordData.AnyDomain = FALSE; + PasswordData.Impersonate = FALSE; + PasswordData.AllowProviderOnly = FALSE; + PasswordData.MprList = NULL; + + pWlxFuncs->WlxSetTimeout(hGlobalWlx, LOGON_TIMEOUT); + + Result = pWlxFuncs->WlxDialogBoxParam( hGlobalWlx, + hDllInstance, + MAKEINTRESOURCE( IDD_CHANGEPWD_DIALOG ), + hwnd, + ChangePasswordDlgProc, + (LONG)&PasswordData); + + return(Result); +} + + + +/****************************************************************************\ +* +* FUNCTION: ChangePasswordDlgProc +* +* PURPOSE: Processes messages for ChangePassword dialog +* +* HISTORY: +* +* 12-09-91 Davidc Created. +* +\****************************************************************************/ + +BOOL WINAPI ChangePasswordDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam + ) +{ + PCHANGE_PASSWORD_DATA pPasswordData = (PCHANGE_PASSWORD_DATA)GetWindowLong(hDlg, GWL_USERDATA); + PGLOBALS pGlobals; + DLG_RETURN_TYPE Result; + int Index; + PMPR_DATA pData; + LONG ProviderKey; + + switch (message) { + + case WM_INITDIALOG: + { + if (!ChangePasswordDlgInit(hDlg, lParam)) { + EndDialog(hDlg, MSGINA_DLG_FAILURE); + } + return(SetPasswordFocus(hDlg)); + } + + case WM_CLOSE: + while (pPasswordData->MprList) + { + pData = pPasswordData->MprList; + pPasswordData->MprList = pData->Next; + LocalFree( pData ); + } + return( TRUE ); + + case WM_COMMAND: + { + + switch (LOWORD(wParam)) { + case ID_NEXT: + { + + } + case IDOK: + { + pGlobals=pPasswordData->pGlobals; + + // + // Deal with combo-box UI requirements + // + + if (HandleComboBoxOK(hDlg, IDD_CHANGEPWD_DOMAIN)) { + return(TRUE); + } + + Index = SendMessage( GetDlgItem( hDlg, IDD_CHANGEPWD_DOMAIN ), + CB_GETCURSEL, + 0, 0 ); + + if ( Index != -1 ) + { + + pData = (PMPR_DATA) SendMessage( + GetDlgItem( hDlg, IDD_CHANGEPWD_DOMAIN), + CB_GETITEMDATA, + Index, 0 ); + } + else + { + pData = NULL; + } + + if ( pData ) + { + HWND hwndOwner; + WCHAR TempBuf[MAX_STRING_BYTES]; + TCHAR UserName[MAX_STRING_BYTES]; + TCHAR Domain[MAX_STRING_BYTES]; + TCHAR Password[MAX_STRING_BYTES]; + TCHAR NewPassword[MAX_STRING_BYTES]; + TCHAR ConfirmNewPassword[MAX_STRING_BYTES]; + WLX_MPR_NOTIFY_INFO MprInfo; + + GetDlgItemText(hDlg, IDD_CHANGEPWD_NAME, TempBuf, MAX_STRING_BYTES); + MprInfo.pszUserName = DupString(TempBuf); + + GetDlgItemText(hDlg, IDD_CHANGEPWD_DOMAIN, TempBuf, MAX_STRING_BYTES); + MprInfo.pszDomain = DupString(TempBuf); + + GetDlgItemText(hDlg, IDD_CHANGEPWD_OLD, TempBuf, MAX_STRING_BYTES); + MprInfo.pszOldPassword = DupString(TempBuf); + + GetDlgItemText(hDlg, IDD_CHANGEPWD_NEW, TempBuf, MAX_STRING_BYTES); + MprInfo.pszPassword = DupString(TempBuf); + + + // + // Hide this dialog and pass our parent as the owner + // of any provider dialogs + // + + ShowWindow(hDlg, SW_HIDE); + hwndOwner = GetParent(hDlg); + + Result = pWlxFuncs->WlxChangePasswordNotifyEx( + hGlobalWlx, + &MprInfo, + 0, + pData->pszProviderName, + NULL ); + + + EndDialog(hDlg, MSGINA_DLG_SUCCESS ); + return(TRUE); + + } + + + Result = AttemptPasswordChange(hDlg); + + if (Result == MSGINA_DLG_FAILURE) { + // + // Let the user try again + // We always make the user re-enter at least the new password. + // + SetDlgItemText(hDlg, IDD_CHANGEPWD_NEW, NULL); + SetDlgItemText(hDlg, IDD_CHANGEPWD_CONFIRM, NULL); + + SetPasswordFocus(hDlg); + + //EndDialog(hDlg, Result); + return(TRUE); + } + + + // + // We're finished - either success or an interrupt + // + if (DLG_SUCCEEDED( Result )) { + + LPTSTR NewUserName; + LPTSTR NewDomain; + + // + // Return the new password to the caller if the password + // was changed on the account they passed in. Be sure to + // hide it so that it isn't recognizable in pagefiles. + // + + NewUserName = AllocAndGetDlgItemText(hDlg, IDD_CHANGEPWD_NAME); + if (NewUserName != NULL) { + + if (lstrcmp(NewUserName, pPasswordData->UserName) == 0) { + + NewDomain = AllocAndGetDlgItemText(hDlg, IDD_CHANGEPWD_DOMAIN); + if (NewDomain != NULL) { + + if (lstrcmp(NewDomain, pPasswordData->Domain) == 0) { + + // + // Return the new password to the caller + // + + GetDlgItemText(hDlg, + IDD_CHANGEPWD_NEW, + pGlobals->Password, + sizeof(pGlobals->Password)); + + // + // Hide the password. + // Use the existing seed. + // + + RtlInitUnicodeString( + &pGlobals->PasswordString, + pGlobals->Password); + HidePassword( + &pGlobals->Seed, + &pGlobals->PasswordString); + } + Free(NewDomain); + } + } + Free(NewUserName); + } + } + + EndDialog(hDlg, Result); + return(TRUE); + } + + case IDCANCEL: + { + EndDialog(hDlg, MSGINA_DLG_FAILURE); + return(TRUE); + } + + case IDD_CHANGEPWD_HELP: + { + LPTSTR Id; + PGLOBALS pGlobals = pPasswordData->pGlobals; + + if (GetWindowLong(GetDlgItem(hDlg, IDD_CHANGEPWD_OLD), GWL_STYLE) & WS_VISIBLE) { + + Id = (LPTSTR) IDD_CHANGE_PASSWORD_HELP; + + } else { + + Id = (LPTSTR) IDD_CHANGE_PASSWORD_EXPIRED_HELP; + } + + Result = pWlxFuncs->WlxDialogBoxParam( hGlobalWlx, + hDllInstance, + Id, + hDlg, + ChangePasswordHelpDlgProc, + (LONG)pGlobals); + + if ( Result != MSGINA_DLG_SUCCESS ) + { + EndDialog( hDlg, SetInterruptFlag( MSGINA_DLG_FAILURE ) ); + } + return(TRUE); + } + } + + break; + } + + case WLX_WM_SAS: + { + // Ignore it + return(TRUE); + } + } + + // We didn't process this message + return FALSE; +} + +VOID +AddNetworkProviders( + CHANGE_PASSWORD_DATA * pData, + HWND hDlg, + UINT Id) + +{ + WCHAR szProviderName[128]; + WCHAR szKeyPath[MAX_PATH]; + PWSTR pszProviders; + PWSTR pszScan; + PWSTR pszStart; + WCHAR Save; + HKEY hKey; + DWORD dwType; + DWORD dwLen; + DWORD Class; + int err; + HWND hCB; + int Index; + PMPR_DATA pMprData; + + + err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, + TEXT("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"), + 0, + KEY_READ, + &hKey ); + + if ( err ) + { + return; + } + + err = RegQueryValueEx( hKey, + TEXT("ProviderOrder"), + NULL, + &dwType, + NULL, + &dwLen ); + + if ( (err) || (dwType != REG_SZ) ) + { + RegCloseKey( hKey ); + return; + } + + pszProviders = LocalAlloc( LMEM_FIXED, dwLen ); + + if ( !pszProviders ) + { + RegCloseKey( hKey ); + return; + } + + err = RegQueryValueEx( hKey, + TEXT("ProviderOrder"), + NULL, + &dwType, + (PUCHAR) pszProviders, + &dwLen ); + + RegCloseKey( hKey ); + if ( err ) + { + LocalFree( pszProviders ); + return; + } + + // + // Initialize things. + // + + pszStart = pszProviders; + + hCB = GetDlgItem( hDlg, Id ); + + szProviderName[0] = TEXT('<'); + szProviderName[1] = TEXT(' '); + + + while ( *pszStart ) + { + pszScan = pszStart; + while ( (*pszScan) && (*pszScan != TEXT(',') ) ) + { + pszScan++; + } + + Save = *pszScan; + + *pszScan = TEXT('\0'); + + wsprintf( szKeyPath, + TEXT("System\\CurrentControlSet\\Services\\%s\\networkprovider"), + pszStart ); + + err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, + szKeyPath, + 0, + KEY_READ, + &hKey ); + + if ( err == 0 ) + { + + dwLen = sizeof(DWORD) ; + + err = RegQueryValueEx( hKey, + TEXT("Class"), + NULL, + &dwType, + (PUCHAR) &Class, + &dwLen ); + + if ( (err == 0) && (dwType == REG_DWORD) ) + { + if ( Class & WN_CREDENTIAL_CLASS ) + { + + pMprData = LocalAlloc( LMEM_FIXED, + sizeof(MPR_DATA) + + (wcslen( pszStart ) + 1) * sizeof(WCHAR) ); + + if (pMprData) + { + + pMprData->pszProviderName = (PWSTR) (pMprData + 1); + + wcscpy( pMprData->pszProviderName, pszStart ); + + pMprData->Next = pData->MprList; + pData->MprList = pMprData; + + dwLen = 126 * sizeof(WCHAR); + + err = RegQueryValueEx( hKey, + TEXT("Name"), + NULL, + &dwType, + (PUCHAR) &szProviderName[2], + &dwLen ); + + wcscpy( &szProviderName[ (dwLen / sizeof(WCHAR) ) + 2 ], + TEXT(" >") ); + + Index = SendMessage( hCB, + CB_ADDSTRING, + 0, + (LONG) szProviderName ); + + SendMessage( hCB, CB_SETITEMDATA, Index, (LONG) pMprData ); + + } + } + } + + RegCloseKey( hKey ); + + } + + *pszScan = Save; + if ( *pszScan ) + { + pszStart = pszScan + 1; + } + else + { + pszStart = NULL; + break; + } + + } + + LocalFree( pszProviders ); + + +} + +/****************************************************************************\ +* +* FUNCTION: ChangePasswordDlgInit +* +* PURPOSE: Handles initialization of change password dialog +* +* RETURNS: TRUE on success, FALSE on failure +* +* HISTORY: +* +* 12-09-91 Davidc Created. +* +\****************************************************************************/ + +BOOL +ChangePasswordDlgInit( + HWND hDlg, + LONG lParam + ) +{ + PCHANGE_PASSWORD_DATA pPasswordData = (PCHANGE_PASSWORD_DATA)lParam; + PGLOBALS pGlobals = pPasswordData->pGlobals; + DLG_RETURN_TYPE Result; + + // Store our structure pointer + SetWindowLong(hDlg, GWL_USERDATA, lParam); + + // Set up the initial text field contents + + SetDlgItemText(hDlg, IDD_CHANGEPWD_NAME, pPasswordData->UserName); + SetDlgItemText(hDlg, IDD_CHANGEPWD_OLD, pPasswordData->OldPassword); + + // If the user can choose their domain, fill the domain combobox + // with the known domains and the local machine name. Otherwise + // disable the domain combobox. + + if (pPasswordData->AnyDomain) { + Result = FillTrustedDomainCB(pGlobals, hDlg, IDD_CHANGEPWD_DOMAIN, + pPasswordData->Domain, TRUE); + if (DLG_INTERRUPTED(Result)) { + EndDialog(hDlg, Result); + } + if ( pPasswordData->AllowProviderOnly ) + { + AddNetworkProviders( pPasswordData, hDlg, IDD_CHANGEPWD_DOMAIN ); + } + } else { + SendDlgItemMessage(hDlg, IDD_CHANGEPWD_DOMAIN, CB_ADDSTRING, 0, (LONG)pPasswordData->Domain); + SendDlgItemMessage(hDlg, IDD_CHANGEPWD_DOMAIN, CB_SETCURSEL, 0, 0); + EnableWindow(GetDlgItem(hDlg, IDD_CHANGEPWD_DOMAIN), FALSE); + } + + CentreWindow(hDlg); + + SetupSystemMenu(hDlg); + + return TRUE; +} + + +/****************************************************************************\ +* +* FUNCTION: AttemptPasswordChange +* +* PURPOSE: Tries to change the user's password using the current values in +* the change-password dialog controls +* +* RETURNS: MSGINA_DLG_SUCCESS if the password was changed successfully. +* MSGINA_DLG_FAILURE if the change failed +* DLG_INTERRUPTED() - this is a set of possible interruptions (see winlogon.h) +* +* NOTES: If the password change failed, this routine displays the necessary +* dialogs explaining what failed and why before returning. +* This routine also clears the fields that need re-entry before +* returning so the calling routine can call SetPasswordFocus on +* the dialog to put the focus in the appropriate place. +* +* HISTORY: +* +* 12-09-91 Davidc Created. +* +\****************************************************************************/ + +DLG_RETURN_TYPE +AttemptPasswordChange( + HWND hDlg + ) +{ + PCHANGE_PASSWORD_DATA pPasswordData = (PCHANGE_PASSWORD_DATA)GetWindowLong(hDlg, GWL_USERDATA); + PGLOBALS pGlobals = pPasswordData->pGlobals; + TCHAR UserName[MAX_STRING_BYTES]; + TCHAR Domain[MAX_STRING_BYTES]; + TCHAR Password[MAX_STRING_BYTES]; + TCHAR NewPassword[MAX_STRING_BYTES]; + TCHAR ConfirmNewPassword[MAX_STRING_BYTES]; + DLG_RETURN_TYPE Result; + DLG_RETURN_TYPE ReturnResult = MSGINA_DLG_SUCCESS; + NTSTATUS Status; + NTSTATUS ProtocolStatus; + PMSV1_0_CHANGEPASSWORD_REQUEST pChangePasswordRequest = NULL; + PMSV1_0_CHANGEPASSWORD_RESPONSE pChangePasswordResponse; + PWCHAR DomainU; + PWCHAR UserNameU; + PWCHAR PasswordU; + PWCHAR NewPasswordU; + int Length; + ULONG RequestBufferSize; + ULONG ResponseBufferSize; + DWORD ChangeInfo = 0; + HWND hwndOwner; + HANDLE ImpersonationHandle; + WLX_MPR_NOTIFY_INFO MprInfo; + UCHAR Seed = 0; + PSECURITY_SEED_AND_LENGTH SeedAndLength; + int MprResult; + + + GetDlgItemText(hDlg, IDD_CHANGEPWD_NAME, UserName, MAX_STRING_BYTES); + GetDlgItemText(hDlg, IDD_CHANGEPWD_DOMAIN, Domain, MAX_STRING_BYTES); + GetDlgItemText(hDlg, IDD_CHANGEPWD_OLD, Password, MAX_STRING_BYTES); + GetDlgItemText(hDlg, IDD_CHANGEPWD_NEW, NewPassword, MAX_STRING_BYTES); + GetDlgItemText(hDlg, IDD_CHANGEPWD_CONFIRM, ConfirmNewPassword, MAX_STRING_BYTES); + + // + // Check that new passwords match + // + if (lstrcmp(NewPassword, ConfirmNewPassword) != 0) { + Result = TimeoutMessageBox(hDlg, IDS_NO_PASSWORD_CONFIRM, + IDS_CHANGE_PASSWORD, + MB_OK | MB_ICONEXCLAMATION, + TIMEOUT_CURRENT); + if (DLG_INTERRUPTED(Result)) { + Result = SetInterruptFlag( MSGINA_DLG_FAILURE ); + } + else + { + Result = MSGINA_DLG_FAILURE ; + } + return(Result); + } + + + // + // Determine request buffer size needed, including room for + // strings. Set string pointers to offsets as we step through + // sizing each one. + // + RequestBufferSize = sizeof(*pChangePasswordRequest); + + UserNameU = (PVOID)RequestBufferSize; + RequestBufferSize += (lstrlen(UserName)+1) * sizeof(WCHAR); + + DomainU = (PVOID)RequestBufferSize; + RequestBufferSize += (lstrlen(Domain)+1) * sizeof(WCHAR); + + PasswordU = (PVOID)RequestBufferSize; + RequestBufferSize += (lstrlen(Password)+1) * sizeof(WCHAR); + + NewPasswordU = (PVOID)RequestBufferSize; + RequestBufferSize += (lstrlen(NewPassword)+1) * sizeof(WCHAR); + + // + // Allocate request buffer + // + pChangePasswordRequest = Alloc(RequestBufferSize); + if (NULL == pChangePasswordRequest) { + DebugLog((DEB_ERROR, "cannot allocate change password request buffer (%ld bytes).", RequestBufferSize)); + return MSGINA_DLG_FAILURE; + } + + // + // Fixup string offsets to string pointers for request. + // + UserNameU = (PVOID) ((PBYTE)pChangePasswordRequest + (ULONG)UserNameU); + DomainU = (PVOID) ((PBYTE)pChangePasswordRequest + (ULONG)DomainU); + PasswordU = (PVOID) ((PBYTE)pChangePasswordRequest + (ULONG)PasswordU); + NewPasswordU = (PVOID) ((PBYTE)pChangePasswordRequest + (ULONG)NewPasswordU); + + // + // Setup MSV1_0ChangePassword request. + // + pChangePasswordRequest->MessageType = MsV1_0ChangePassword; + + // strings are already unicode, just copy them // lhb tracks //REVIEW + lstrcpy((LPTSTR)UserNameU,UserName); + lstrcpy((LPTSTR)DomainU,Domain); + lstrcpy((LPTSTR)PasswordU,Password); + lstrcpy((LPTSTR)NewPasswordU,NewPassword); + + Length = lstrlen(UserName); + UserNameU[Length] = 0; + RtlInitUnicodeString( + &pChangePasswordRequest->AccountName, + UserNameU + ); + Length = lstrlen(Domain); + DomainU[Length] = 0; + RtlInitUnicodeString( + &pChangePasswordRequest->DomainName, + DomainU + ); + Length = lstrlen(Password); + PasswordU[Length] = 0; + RtlInitUnicodeString( + &pChangePasswordRequest->OldPassword, + PasswordU + ); + Length = lstrlen(NewPassword); + NewPasswordU[Length] = 0; + RtlInitUnicodeString( + &pChangePasswordRequest->NewPassword, + NewPasswordU + ); + + // + // Make sure the passwords are short enough that we can run-encode them. + // + + if ((pChangePasswordRequest->OldPassword.Length > 127) || + (pChangePasswordRequest->NewPassword.Length > 127)) { + + Status = STATUS_ILL_FORMED_PASSWORD; + + } else { + + HidePassword(NULL,&pChangePasswordRequest->OldPassword); + HidePassword(NULL,&pChangePasswordRequest->NewPassword); + + Status = STATUS_SUCCESS ; + } + + // + // If that succeeded, try to change the password + // + + if (NT_SUCCESS(Status)) { + // + // This could take some time, put up a wait cursor + // + + SetupCursor(TRUE); + + // + // We want to impersonate if and only if the user is actually logged + // on. Otherwise we'll be impersonating SYSTEM, which is bad. + // + + if (pPasswordData->Impersonate) { + + ImpersonationHandle = ImpersonateUser( + &pGlobals->UserProcessData, + NULL + ); + + if (NULL == ImpersonationHandle) { + DebugLog((DEB_ERROR, "cannot impersonate user")); + Free(pChangePasswordRequest); + return MSGINA_DLG_FAILURE; + } + } + + // + // Tell msv1_0 whether or not we're impersonating. + // + + pChangePasswordRequest->Impersonating = pPasswordData->Impersonate; + + // + // Call off to the authentication package to do the work + // + + Status = LsaCallAuthenticationPackage( + pGlobals->LsaHandle, + pGlobals->AuthenticationPackage, + pChangePasswordRequest, + RequestBufferSize, + (PVOID)&pChangePasswordResponse, + &ResponseBufferSize, + &ProtocolStatus + ); + + if (pPasswordData->Impersonate) { + + if (!StopImpersonating(ImpersonationHandle)) { + + DebugLog((DEB_ERROR, "AttemptPasswordChange: Failed to revert to self")); + + // + // Blow up + // + + ASSERT(FALSE); + } + } + + // + // Restore the normal cursor + // + + SetupCursor(FALSE); + } + + // + // Free up the request buffer + // + + Free(pChangePasswordRequest); + + // + // Get the most informative status code + // + + if ( NT_SUCCESS(Status) ) { + Status = ProtocolStatus; + } + else + { + DebugLog((DEB_TRACE, "FAILED in call to LsaCallAuthenticationPackage, status %x\n", Status )); + + } + + if (NT_SUCCESS(Status)) { + + // + // Success + // + + Result = TimeoutMessageBox(hDlg, + IDS_PASSWORD_CHANGED, + IDS_CHANGE_PASSWORD, + MB_OK | MB_ICONINFORMATION, + TIMEOUT_CURRENT); + + + } else { + + ReturnResult = MSGINA_DLG_FAILURE; + + // + // Failure, explain it to the user + // + + Result = HandleFailedChangePassword(hDlg, + Status, + UserName, + Domain, + pChangePasswordResponse + ); + } + + + // + // Only call other providers if the change password attempt succeeded. + // + + if (NT_SUCCESS(Status)) { + + // + // Let other providers know about the change + // + + // + // If the domain is one from our combo-box + // then it is valid for logons. + // + + if (CB_ERR != SendMessage(GetDlgItem(hDlg, IDD_CHANGEPWD_DOMAIN), + CB_FINDSTRINGEXACT, + (WPARAM)-1, + (LPARAM)Domain)) { + + ChangeInfo |= WN_VALID_LOGON_ACCOUNT; + } + + // + // Hide this dialog and pass our parent as the owner + // of any provider dialogs + // + + ShowWindow(hDlg, SW_HIDE); + hwndOwner = GetParent(hDlg); + + MprInfo.pszUserName = DupString(UserName); + MprInfo.pszDomain = DupString(Domain); + MprInfo.pszPassword = DupString(NewPassword); + MprInfo.pszOldPassword = DupString(Password); + + MprResult = pWlxFuncs->WlxChangePasswordNotify( + hGlobalWlx, + &MprInfo, + ChangeInfo | WN_NT_PASSWORD_CHANGED); + + + + + } + + // + // Free up the return buffer + // + + if (pChangePasswordResponse != NULL) { + LsaFreeReturnBuffer(pChangePasswordResponse); + } + + // + // Find out what happened to the message box: + // + + if ( Result != IDOK ) + { + // + // mbox was interrupted + // + + ReturnResult = SetInterruptFlag( ReturnResult ); + } + + return(ReturnResult); +} + + +/****************************************************************************\ +* +* FUNCTION: HandleFailedChangePassword +* +* PURPOSE: Tells the user why their change-password attempt failed. +* +* RETURNS: MSGINA_DLG_FAILURE - we told them what the problem was successfully. +* DLG_INTERRUPTED() - a set of return values - see winlogon.h +* +* HISTORY: +* +* 21-Sep-92 Davidc Created. +* +\****************************************************************************/ + +DLG_RETURN_TYPE +HandleFailedChangePassword( + HWND hDlg, + NTSTATUS Status, + PWCHAR UserName, + PWCHAR Domain, + PMSV1_0_CHANGEPASSWORD_RESPONSE pChangePasswordResponse + ) +{ + DLG_RETURN_TYPE Result; + TCHAR Buffer1[MAX_STRING_BYTES]; + TCHAR Buffer2[MAX_STRING_BYTES]; + + switch (Status) { + + case STATUS_CANT_ACCESS_DOMAIN_INFO: + case STATUS_NO_SUCH_DOMAIN: + + LoadString(hDllInstance, IDS_CHANGE_PWD_NO_DOMAIN, Buffer1, sizeof(Buffer1)); + _snwprintf(Buffer2, sizeof(Buffer2), Buffer1, Domain); + + LoadString(hDllInstance, IDS_CHANGE_PASSWORD, Buffer1, sizeof(Buffer1)); + + Result = TimeoutMessageBoxlpstr(hDlg, Buffer2, + Buffer1, + MB_OK | MB_ICONEXCLAMATION, + TIMEOUT_CURRENT); + break; + + + case STATUS_NO_SUCH_USER: + case STATUS_WRONG_PASSWORD_CORE: + case STATUS_WRONG_PASSWORD: + + Result = TimeoutMessageBox(hDlg, IDS_INCORRECT_NAME_OR_PWD_CHANGE, + IDS_CHANGE_PASSWORD, + MB_OK | MB_ICONEXCLAMATION, + TIMEOUT_CURRENT); + + // Force re-entry of the old password + if (GetWindowLong(GetDlgItem(hDlg, IDD_CHANGEPWD_OLD), GWL_STYLE) & WS_VISIBLE) { + SetDlgItemText(hDlg, IDD_CHANGEPWD_OLD, NULL); + } + + break; + + + case STATUS_ACCESS_DENIED: + + Result = TimeoutMessageBox(hDlg, IDS_NO_PERMISSION_CHANGE_PWD, + IDS_CHANGE_PASSWORD, + MB_OK | MB_ICONEXCLAMATION, + TIMEOUT_CURRENT); + break; + + + case STATUS_ACCOUNT_RESTRICTION: + + Result = TimeoutMessageBox(hDlg, IDS_ACCOUNT_RESTRICTION_CHANGE, + IDS_CHANGE_PASSWORD, + MB_OK | MB_ICONEXCLAMATION, + TIMEOUT_CURRENT); + break; + + case STATUS_BACKUP_CONTROLLER: + + Result = TimeoutMessageBox(hDlg, IDS_REQUIRES_PRIMARY_CONTROLLER, + IDS_CHANGE_PASSWORD, + MB_OK | MB_ICONEXCLAMATION, + TIMEOUT_CURRENT); + break; + + + case STATUS_PASSWORD_RESTRICTION: + + + if (pChangePasswordResponse->PasswordInfoValid) { + + LoadString(hDllInstance, IDS_PASSWORD_SPEC, Buffer1, sizeof(Buffer1)); + _snwprintf(Buffer2, sizeof(Buffer2), Buffer1, + pChangePasswordResponse->DomainPasswordInfo.MinPasswordLength, + pChangePasswordResponse->DomainPasswordInfo.PasswordHistoryLength + ); + } else { + LoadString(hDllInstance, IDS_GENERAL_PASSWORD_SPEC, Buffer2, sizeof(Buffer2)); + } + + LoadString(hDllInstance, IDS_ENTER_PASSWORDS, Buffer1, sizeof(Buffer1)); + wcsncat(Buffer2, TEXT(" "), sizeof(Buffer2) - sizeof(TCHAR)*(lstrlen(Buffer2) - 1)); + wcsncat(Buffer2, Buffer1, sizeof(Buffer2) - sizeof(TCHAR)*(lstrlen(Buffer2) - 1)); + + LoadString(hDllInstance, IDS_CHANGE_PASSWORD, Buffer1, sizeof(Buffer1)); + + Result = TimeoutMessageBoxlpstr(hDlg, Buffer2, + Buffer1, + MB_OK | MB_ICONEXCLAMATION, + TIMEOUT_CURRENT); + break; + + +#ifdef LATER + // + // LATER Check for minimum password age + // + if ( FALSE ) { + int PasswordAge = 0, RequiredAge = 0; + TCHAR Buffer1[MAX_STRING_BYTES]; + TCHAR Buffer2[MAX_STRING_BYTES]; + + LoadString(hDllInstance, IDS_PASSWORD_MINIMUM_AGE, Buffer1, sizeof(Buffer1)); + _snwprintf(Buffer2, sizeof(Buffer2), Buffer1, PasswordAge, RequiredAge); + + LoadString(hDllInstance, IDS_NO_PERMISSION_CHANGE_PWD, Buffer1, sizeof(Buffer1)); + lstrcat(Buffer1, TEXT(" ")); + lstrcat(Buffer1, Buffer2); + + LoadString(hDllInstance, IDS_CHANGE_PASSWORD, Buffer2, sizeof(Buffer2)); + + Result = TimeoutMessageBoxlpstr(hDlg, Buffer1, + Buffer2, + MB_OK | MB_ICONEXCLAMATION, + TIMEOUT_CURRENT); + } +#endif + + + default: + + DebugLog((DEB_ERROR, "Change password failure status = 0x%lx", Status)); + + LoadString(hDllInstance, IDS_UNKNOWN_CHANGE_PWD_FAILURE, Buffer1, sizeof(Buffer1)); + _snwprintf(Buffer2, sizeof(Buffer2), Buffer1, Status); + + LoadString(hDllInstance, IDS_CHANGE_PASSWORD, Buffer1, sizeof(Buffer1)); + + Result = TimeoutMessageBoxlpstr(hDlg, Buffer2, + Buffer1, + MB_OK | MB_ICONEXCLAMATION, + TIMEOUT_CURRENT); + break; + } + + return(Result); + + UNREFERENCED_PARAMETER(UserName); +} + +/***************************************************************************\ +* FUNCTION: ChangePasswordHelpDlgProc +* +* PURPOSE: Processes messages for change password help dialog +* +* RETURNS: MSGINA_DLG_SUCCESS - the dialog was shown and dismissed successfully. +* MSGINA_DLG_FAILURE - the dialog could not be shown +* DLG_INTERRUPTED() - a set defined in winlogon.h +* +* HISTORY: +* +* 3-17-93 Robertre Created. +* +\***************************************************************************/ + +BOOL WINAPI +ChangePasswordHelpDlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam + ) +{ + PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hDlg, GWL_USERDATA); + + switch (message) { + + case WM_INITDIALOG: + SetWindowLong(hDlg, GWL_USERDATA, lParam); + CentreWindow(hDlg); + return(TRUE); + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDCANCEL: + case IDOK: + EndDialog(hDlg, MSGINA_DLG_SUCCESS); + return(TRUE); + } + break; + } + + // We didn't process this message + return FALSE; +} |