diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/nw/svcdlls/nwwks/client/logon.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/nw/svcdlls/nwwks/client/logon.c')
-rw-r--r-- | private/nw/svcdlls/nwwks/client/logon.c | 2539 |
1 files changed, 2539 insertions, 0 deletions
diff --git a/private/nw/svcdlls/nwwks/client/logon.c b/private/nw/svcdlls/nwwks/client/logon.c new file mode 100644 index 000000000..f539fce2c --- /dev/null +++ b/private/nw/svcdlls/nwwks/client/logon.c @@ -0,0 +1,2539 @@ +/*++ + +Copyright (c) 1993, 1994 Microsoft Corporation + +Module Name: + + logon.c + +Abstract: + + This module contains NetWare credential management code. + +Author: + + Rita Wong (ritaw) 15-Feb-1993 + +Revision History: + + Yi-Hsin Sung (yihsins) 10-July-1993 + Moved all dialog handling to nwdlg.c + +--*/ + +#include <nwclient.h> +#include <ntmsv1_0.h> +#include <nwsnames.h> +#include <nwcanon.h> +#include <validc.h> +#include <nwevent.h> + +#include <nwdlg.h> + +#include <nwreg.h> +#include <nwlsa.h> +#include <nwauth.h> +#include <nwapi.h> +#include <nwmisc.h> +#include <ndsapi32.h> + + +//-------------------------------------------------------------------// +// // +// Local Function Prototypes // +// // +//-------------------------------------------------------------------// + +VOID +NwpInitializeRegistry( + IN LPWSTR NewUserSid, + OUT LPWSTR PreferredServer, + IN DWORD PreferredServerSize, + OUT PDWORD LogonScriptOptions, + OUT PDWORD PrintOption + ); + +DWORD +NwpReadRegInfo( + IN HKEY WkstaKey, + IN LPWSTR CurrentUserSid, + OUT LPWSTR PreferredServer, + IN DWORD PreferredServerSize, + OUT PDWORD PrintOption + ); + +DWORD +NwpGetCurrentUser( + OUT LPWSTR *SidString, + OUT LPWSTR *UserName + ); + +DWORD +NwpGetUserSid( + IN PLUID LogonId, + OUT LPWSTR *UserSidString + ); + +BOOL +NwpPollWorkstationStart( + VOID + ); + +VOID +NwpSaveServiceCredential( + IN PLUID LogonId, + IN LPWSTR UserName, + IN LPWSTR Password + ); + +DWORD +NwpSetCredentialInLsa( + IN PLUID LogonId, + IN LPWSTR UserName, + IN LPWSTR Password + ); + +NTSTATUS NwNdsOpenRdrHandle( + OUT PHANDLE phNwRdrHandle + ); + +DWORD +NwpReadLogonScriptOptions( + IN LPWSTR CurrentUserSid, + OUT PDWORD pLogonScriptOptions, + OUT PDWORD pPreferredServerExists + ); + +LPWSTR +NwpConstructLogonScript( + IN DWORD LogonScriptOptions + ); + +VOID +NwpSelectServers( + IN HWND DialogHandle, + IN PCHANGE_PW_DLG_PARAM Credential + ); + +//////////////////////////////////////////////////////////////////////////// + +DWORD +APIENTRY +NPLogonNotify( + PLUID lpLogonId, + LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + LPWSTR *lpLogonScript + ) +/*++ + +Routine Description: + + This function is called by Winlogon after the interactive + user has successfully logged on to the local machine. We + are given the username and password, which + are displayed in the NetWare specific logon dialog if + needed. + +Arguments: + + lpLogonId - Ignored. + + lpAuthentInfoType - Supplies a string which if is + L"MSV1_0:Interactive" means that the user has been logged + on by the Microsoft primary authenticator. + + lpAuthentInfo - Supplies a pointer to the credentials which + the user was logged on with. + + lpPreviousAuthentInfoType - Ignored. + + lpPreviousAuthentInfo - Ignored. + + lpStationName - Supplies a string which if it is L"WinSta_0" + means that Winlogon logged on the user. + + StationHandle - Supplies the handle to the window which to display + our specific dialog. + + lpLogonScripts - Receives a pointer to memory allocated by this + routine which contains a MULTI_SZ string of a program to run on + the command line with arguments, e.g. L"myprogram\0arg1\0arg2\0". + This memory must be freed by the caller with LocalFree. + +Return Value: + + WN_SUCCESS - Successfully saved default credentials. + + WN_NOT_SUPPORTED - Primary authenticator is not Microsoft or + is not interactive via Winlogon. + + ERROR_FILE_NOT_FOUND - Could not get our own provider DLL handle. + +--*/ +{ + DWORD status = NO_ERROR; + int Result = FALSE; + LPWSTR NewUserSid = NULL; + BOOL LogonAttempted = FALSE; + PMSV1_0_INTERACTIVE_LOGON NewLogonInfo = + (PMSV1_0_INTERACTIVE_LOGON) lpAuthentInfo; + + WCHAR NwpServerBuffer[MAX_PATH + 1]; + WCHAR NwpPasswordBuffer[NW_MAX_PASSWORD_LEN + 1]; + DWORD NwpPrintOption = NW_PRINT_OPTION_DEFAULT; + DWORD NwpLogonScriptOptions = NW_LOGONSCRIPT_DEFAULT ; + BOOL cPasswordDlgClickOK = 0; + BOOL ServiceLogin = FALSE ; + + DBG_UNREFERENCED_PARAMETER(lpPreviousAuthentInfoType); + DBG_UNREFERENCED_PARAMETER(lpPreviousAuthentInfo); + +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("\nNWPROVAU: NPLogonNotify\n")); + } +#endif + + RpcTryExcept { + + if (_wcsicmp(lpAuthentInfoType, L"MSV1_0:Interactive") != 0) + { + + // + // We only handle a logon where Microsoft is the primary + // authenticator and it is an interactive logon via Winlogon. + // + status = WN_NOT_SUPPORTED; + goto EndOfTry; + } + + if (_wcsicmp(lpStationName, L"SvcCtl") == 0) + { + ServiceLogin = TRUE ; + } + + + // + // Initialize credential variables + // + NwpServerBuffer[0] = NW_INVALID_SERVER_CHAR; + NwpServerBuffer[1] = 0; + + RtlZeroMemory(NwpPasswordBuffer, sizeof(NwpPasswordBuffer)); + + if (NewLogonInfo->Password.Buffer != NULL) { + + // + // check for max length to avoid overflowing. + // + if (NewLogonInfo->Password.Length > + (sizeof(NwpPasswordBuffer) - sizeof(WCHAR))) { + + status = ERROR_INVALID_PARAMETER ; + goto EndOfTry; + } + + wcsncpy( + NwpPasswordBuffer, + NewLogonInfo->Password.Buffer, + NewLogonInfo->Password.Length / sizeof(WCHAR) + ); + } + +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("\tMessageType : %lu\n", NewLogonInfo->MessageType)); + KdPrint(("\tLogonDomainName : %ws\n", NewLogonInfo->LogonDomainName.Buffer)); + KdPrint(("\tUserName : %ws\n", NewLogonInfo->UserName.Buffer)); + KdPrint(("\tPassword : %ws\n", NwpPasswordBuffer)); + } +#endif + + // + // if Interactive login, get user related info + // + if (!ServiceLogin) + { + // + // Get the user SID so that the user Netware username and + // preferred server is saved under a SID key rather than the + // LogonDomain*UserName key. We do this by making ourselves + // a logon process, and call the special MSV1.0 GetUserInfo + // interface. + // + status = NwpGetUserSid(lpLogonId, &NewUserSid); + + if (status != NO_ERROR) { + goto EndOfTry; + } + + // + // Initialize the registry: + // 1) Delete the CurrentUser value if it exists (was not clean up + // previously because user did not log off--rebooted machine). + // 2) Read the current user's PreferredServer and PrintOption + // value so that we can display the user's original + // preferred server. + // + NwpInitializeRegistry( NewUserSid, + NwpServerBuffer, + sizeof( NwpServerBuffer ) / + sizeof( NwpServerBuffer[0]), + &NwpLogonScriptOptions, + &NwpPrintOption ); + } + + // + // Poll until the NetWare workstation has started, then validate + // the user credential. + // + (void) NwpPollWorkstationStart(); + + // + // If service login, notify the redir with the username/passwd/ + // LUID triplet and save the logon ID in the registry so that + // workstation can pick up if stopped and restarted. + // + if (ServiceLogin) + { + NwpSaveServiceCredential( + lpLogonId, + NewLogonInfo->UserName.Buffer, + NwpPasswordBuffer + ); + + (void) NwrLogonUser( + NULL, + lpLogonId, + NewLogonInfo->UserName.Buffer, + NwpPasswordBuffer, + NULL, + NULL, + 0 + ); + + } + else + { + // + // We need to save the user credentials at least once so that + // the CURRENTUSER Value is stored in the registry. + // This must be done before any RPC calls but after polling + // workstation start. + // + NwpSaveLogonCredential( + NewUserSid, + lpLogonId, + NewLogonInfo->UserName.Buffer, + NwpPasswordBuffer, + NULL // Don't save the preferred server + ); + +// +// Let the logon set the printer options for each user. +// Set the provider name and burst options in the service also. +// + // + // We need to set the print option at least once. + // This also makes the redir aware of the provider name, + // + (void) NwrSetInfo( + NULL, + NwpPrintOption, + NULL // Need to be NULL so that we will not try to + // attach to the server before logging on + ); + + + if (*NwpServerBuffer != NW_INVALID_SERVER_CHAR ) { + + // + // Preferred server exists. So, try to log the user on. + // + INT nResult; + + while (1) + { + WCHAR *DefaultTree = NULL ; + WCHAR *DefaultContext = NULL; + WCHAR *PreferredServer = NULL; + PROMPTDLGPARAM PasswdPromptParam; + +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("\tNwrLogonUser\n")); + KdPrint(("\tUserName : %ws\n",NewLogonInfo->UserName.Buffer)); + KdPrint(("\tServer : %ws\n", NwpServerBuffer)); + } +#endif + + + // + // make sure user is logged off + // + (void) NwrLogoffUser(NULL, lpLogonId) ; + + status = NwrLogonUser( + NULL, + lpLogonId, + NewLogonInfo->UserName.Buffer, + NwpPasswordBuffer, + NwpServerBuffer, // now either TREE or SERVER + NULL, + 0 + ); + + + if (status != ERROR_INVALID_PASSWORD) + break ; + + PasswdPromptParam.UserName = NewLogonInfo->UserName.Buffer; + PasswdPromptParam.ServerName = NwpServerBuffer ; + PasswdPromptParam.Password = NwpPasswordBuffer; + PasswdPromptParam.PasswordSize = sizeof(NwpPasswordBuffer)/ + sizeof(NwpPasswordBuffer[0]) ; + Result = DialogBoxParamW( + hmodNW, + MAKEINTRESOURCEW(DLG_PASSWORD_PROMPT), + (HWND) StationHandle, + NwpPasswdPromptDlgProc, + (LPARAM) &PasswdPromptParam + ); + + if (Result == -1 || Result == IDCANCEL) + { + status = ERROR_INVALID_PASSWORD ; + break ; + } + else + { + cPasswordDlgClickOK++; + } + } + + if (status == NW_PASSWORD_HAS_EXPIRED) + { + WCHAR szNumber[16] ; + DWORD status1, dwMsgId, dwGraceLogins = 0 ; + LPWSTR apszInsertStrings[3] ; + + // + // get the grace login count + // + status1 = NwGetGraceLoginCount( + NwpServerBuffer, // BUGBUG + NewLogonInfo->UserName.Buffer, + &dwGraceLogins) ; + + // + // if hit error, just dont use the number + // + if (status1 == NO_ERROR) + { + dwMsgId = IDS_PASSWORD_HAS_EXPIRED ; // use setpass.exe + wsprintfW(szNumber, L"%ld", dwGraceLogins) ; + } + else + { + dwMsgId = IDS_PASSWORD_HAS_EXPIRED1 ; // use setpass.exe + } + + apszInsertStrings[0] = NwpServerBuffer ; // BUGBUG + apszInsertStrings[1] = szNumber ; + apszInsertStrings[2] = NULL ; + + // + // put up message on password expiry + // + (void) NwpMessageBoxIns( + (HWND) StationHandle, + IDS_NETWARE_TITLE, + dwMsgId, + apszInsertStrings, + MB_OK | MB_SETFOREGROUND | + MB_ICONINFORMATION ); + + status = NO_ERROR ; + } + + + if ( status != NO_ERROR ) + { + WCHAR *pszErrorLocation = NwpServerBuffer ; //BUGBUG + DWORD dwMsgId = IDS_LOGIN_FAILURE_WARNING; + + if (status == ERROR_ACCOUNT_RESTRICTION) + { + dwMsgId = IDS_LOGIN_ACC_RESTRICTION; + } + + if (status == ERROR_SHARING_PAUSED) + { + status = IDS_LOGIN_DISABLED; + } + + if (*NwpServerBuffer == L'*') + { + // + // Format into nicer string for user + // + WCHAR *pszTmp = LocalAlloc(LMEM_ZEROINIT, + (wcslen(NwpServerBuffer)+2) * + sizeof(WCHAR)) ; + if (pszTmp) + { + pszErrorLocation = pszTmp ; + + // + // This code formats the NDS + // tree UNC to: Tree(Context) + // + wcscpy(pszErrorLocation, NwpServerBuffer+1) ; + + if (pszTmp = wcschr(pszErrorLocation, L'\\')) + { + *pszTmp = L'(' ; + wcscat(pszErrorLocation, L")") ; + } + } + } + + nResult = NwpMessageBoxError( + (HWND) StationHandle, + IDS_AUTH_FAILURE_TITLE, + dwMsgId, + status, + pszErrorLocation, + MB_YESNO | MB_ICONEXCLAMATION ); + + if (pszErrorLocation != NwpServerBuffer) + { + (void) LocalFree(pszErrorLocation) ; + } + + // + // User chose not to select another preferred server, + // hence just return success. + // + if ( nResult == IDNO ) { + status = NO_ERROR; + } + } + + // + // The user might have changed the password in the password + // prompt dialog. Hence, we need to save the credentials + // ( the password ) again. Although the user might choose + // to select another server, he might canceled out of the + // login dialog. We must save logon credentials here no matter + // what. + // + NwpSaveLogonCredential( + NewUserSid, + lpLogonId, + NewLogonInfo->UserName.Buffer, + NwpPasswordBuffer, + NwpServerBuffer + ); + } + + // + // Only prompt user with the NetWare login dialog if + // no preferred server was found or an error occurred + // while authenticating the user. + // + if ( ( status != NO_ERROR) + || (*NwpServerBuffer == NW_INVALID_SERVER_CHAR) + ) + { + + LOGINDLGPARAM LoginParam; + + if ( cPasswordDlgClickOK > 0 ) + { + // Password might have changed in the password prompt + // dialog. We want to always first use the NT password + // when validating a user on a server. Hence, + // we need to copy back the original NT password into + // NwpPasswordBuffer. + + RtlZeroMemory(NwpPasswordBuffer, sizeof(NwpPasswordBuffer)); + if (NewLogonInfo->Password.Buffer != NULL) + { + wcsncpy( + NwpPasswordBuffer, + NewLogonInfo->Password.Buffer, + NewLogonInfo->Password.Length / sizeof(WCHAR) + ); + } + } + + LoginParam.UserName = NewLogonInfo->UserName.Buffer; + LoginParam.ServerName = NwpServerBuffer ; + LoginParam.Password = NwpPasswordBuffer; + LoginParam.NewUserSid = NewUserSid; + LoginParam.pLogonId = lpLogonId; + LoginParam.ServerNameSize = sizeof( NwpServerBuffer ) / + sizeof( NwpServerBuffer[0]); + LoginParam.PasswordSize = sizeof( NwpPasswordBuffer ) / + sizeof( NwpPasswordBuffer[0]); + LoginParam.LogonScriptOptions = NwpLogonScriptOptions; + Result = DialogBoxParamW( + hmodNW, + MAKEINTRESOURCEW(DLG_NETWARE_LOGIN), + (HWND) StationHandle, + NwpLoginDlgProc, + (LPARAM) &LoginParam + ); + + if (Result == -1) { + status = GetLastError(); + KdPrint(("NWPROVAU: DialogBox failed %lu\n", status)); + goto EndOfTry; + } + + } + } + +EndOfTry: ; + + } + RpcExcept(1) { + +#if DBG + DWORD XceptCode; + + + XceptCode = RpcExceptionCode(); + IF_DEBUG(LOGON) { + KdPrint(("NWPROVAU: NPLogonNotify: Exception code is x%08lx\n", XceptCode)); + } + status = NwpMapRpcError(XceptCode); +#else + status = NwpMapRpcError(RpcExceptionCode()); +#endif + + } + RpcEndExcept; + + + if (!ServiceLogin) { + DWORD fPServer = 0; + + NwpReadLogonScriptOptions( NewUserSid, + &NwpLogonScriptOptions, + &fPServer ); + if ( fPServer && ( NwpLogonScriptOptions & NW_LOGONSCRIPT_ENABLED ) ) + { + *lpLogonScript = NwpConstructLogonScript( NwpLogonScriptOptions ); + + // + // set scripts to run synchronously. ignore error if we cant. + // not a disaster. + // + (void) NwrSetLogonScript(NULL, SYNC_LOGONSCRIPT) ; + } + else + { + *lpLogonScript = LocalAlloc(LMEM_ZEROINIT, sizeof(WCHAR)); + } + } + else + *lpLogonScript = NULL; + + if (NewUserSid != NULL) { + (void) LocalFree((HLOCAL) NewUserSid); + } + + // + // Clear the password + // + RtlZeroMemory(NwpPasswordBuffer, sizeof(NwpPasswordBuffer)); + + if (status == WN_NO_NETWORK) { + // + // We don't care if the workstation has not started because + // we tuck the logon credential in the registry to be picked + // up by the workstation when it starts up. If we return + // ERROR_NO_NETWORK, MPR will poll us forever, causing us + // to continuously display the login dialog over and over + // again. + // + status = NO_ERROR; + } + + if (status != NO_ERROR) { + SetLastError(status); + } + + return status; +} + + + +DWORD +APIENTRY +NPPasswordChangeNotify( + LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + DWORD dwChangeInfo + ) +/*++ + +Routine Description: + + This function is called after the interactive user has selected to + change the password for the local logon via the Ctrl-Alt-Del dialog. + It is also called when the user cannot login because the password + has expired and must be changed. + +Arguments: + + lpAuthentInfoType - Supplies a string which if is + L"MSV1_0:Interactive" means that the user has been logged + on by the Microsoft primary authenticator. + + lpAuthentInfo - Supplies a pointer to the credentials to + change to. + + lpPreviousAuthentInfoType - Supplies a pointer to the old + credentials. + + lpPreviousAuthentInfo - Ignored. + + lpStationName - Supplies a string which if it is L"WinSta_0" + means that Winlogon logged on the user. + + StationHandle - Supplies the handle to the window which to display + our specific dialog. + + dwChangeInfo - Ignored. + +Return Value: + + WN_SUCCESS - successful operation. + + WN_NOT_SUPPORTED - Only support change password if MS v1.0 is + the primary authenticator and is done through Winlogon. + + WN_NO_NETWORK - Workstation service did not start. + +--*/ +{ + DWORD status = NO_ERROR; + + + CHANGE_PW_DLG_PARAM Credential; + + PMSV1_0_INTERACTIVE_LOGON NewCredential = + (PMSV1_0_INTERACTIVE_LOGON) lpAuthentInfo; + PMSV1_0_INTERACTIVE_LOGON OldCredential = + (PMSV1_0_INTERACTIVE_LOGON) lpPreviousAuthentInfo; + + + + DBG_UNREFERENCED_PARAMETER(lpPreviousAuthentInfoType); + DBG_UNREFERENCED_PARAMETER(dwChangeInfo); + + Credential.UserName = NULL; + + RpcTryExcept { + + if ((_wcsicmp(lpAuthentInfoType, L"MSV1_0:Interactive") != 0) || + (_wcsicmp(lpStationName, L"WinSta0") != 0)) { + + // + // We only handle a logon where Microsoft is the primary + // authenticator and it is an interactive logon via Winlogon. + // + status = WN_NOT_SUPPORTED; + goto EndOfTry; + } + + + if (NewCredential == NULL || OldCredential == NULL) { + + // + // Credentials not given to us by Winlogon or + // user did not type the old and new passwords. + // + +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWPROVAU: PasswordChangeNotify got NULL for new and old credential pointers\n")); + } +#endif + + (void) NwpMessageBoxError( + (HWND) StationHandle, + IDS_CHANGE_PASSWORD_TITLE, + IDS_BAD_PASSWORDS, + 0, + NULL, + MB_OK | MB_ICONSTOP + ); + + status = WN_NOT_SUPPORTED; + goto EndOfTry; + } + + Credential.UserName = LocalAlloc( + LMEM_ZEROINIT, + (NW_MAX_USERNAME_LEN + 3 + + (2 * NW_MAX_PASSWORD_LEN)) * sizeof(WCHAR) + ); + + if (Credential.UserName == NULL) { + status = ERROR_NOT_ENOUGH_MEMORY; + goto EndOfTry; + } + + Credential.OldPassword = (LPWSTR) ((DWORD) Credential.UserName + + (NW_MAX_USERNAME_LEN + 1) * sizeof(WCHAR)); + Credential.NewPassword = (LPWSTR) ((DWORD) Credential.OldPassword + + (NW_MAX_PASSWORD_LEN + 1) * sizeof(WCHAR)); + + + if (NewCredential->UserName.Length == 0) { + + // + // UserName is not specified. Try to get interactive user's name. + // + + DWORD CharNeeded = NW_MAX_USERNAME_LEN + 1; + + +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWPROVAU: PasswordChangeNotify got empty string for username\n")); + } +#endif + + if (! GetUserNameW(Credential.UserName, &CharNeeded)) { + + // + // Could not get interactive user's name. Give up. + // + (void) NwpMessageBoxError( + (HWND) StationHandle, + IDS_CHANGE_PASSWORD_TITLE, + 0, + ERROR_BAD_USERNAME, + NULL, + MB_OK | MB_ICONSTOP + ); + } + } + else { + wcsncpy( + Credential.UserName, + NewCredential->UserName.Buffer, + NewCredential->UserName.Length / sizeof(WCHAR) + ); + } + + if (OldCredential->Password.Length > 0) + { + wcsncpy( + Credential.OldPassword, + OldCredential->Password.Buffer, + OldCredential->Password.Length / sizeof(WCHAR) + ); + } + else + { + Credential.OldPassword[0] = 0; + } + + if (NewCredential->Password.Length > 0) + { + wcsncpy( + Credential.NewPassword, + NewCredential->Password.Buffer, + NewCredential->Password.Length / sizeof(WCHAR) + ); + } + else + { + Credential.NewPassword[0] = 0; + } + + // + // Encode the passwords. + // + { + UCHAR EncodeSeed = NW_ENCODE_SEED2; + UNICODE_STRING PasswordStr; + + + RtlInitUnicodeString(&PasswordStr, Credential.OldPassword); + RtlRunEncodeUnicodeString(&EncodeSeed, &PasswordStr); + + RtlInitUnicodeString(&PasswordStr, Credential.NewPassword); + RtlRunEncodeUnicodeString(&EncodeSeed, &PasswordStr); + } + + NwpSelectServers(StationHandle, &Credential); + +EndOfTry: ; + + } + RpcExcept(1) { + +#if DBG + DWORD XceptCode; + + + XceptCode = RpcExceptionCode(); + IF_DEBUG(LOGON) { + KdPrint(("NWPROVAU: NPPasswordChangeNotify: Exception code is x%08lx\n", XceptCode)); + } + status = NwpMapRpcError(XceptCode); +#else + status = NwpMapRpcError(RpcExceptionCode()); +#endif + + } + RpcEndExcept; + + if (Credential.UserName != NULL) { + LocalFree(Credential.UserName); + } + + if (status != NO_ERROR) { + SetLastError(status); + } + + return status; + +} + + +VOID +NwpInitializeRegistry( + IN LPWSTR NewUserSid, + OUT LPWSTR PreferredServer, + IN DWORD PreferredServerSize, + OUT PDWORD pLogonScriptOptions, + OUT PDWORD PrintOption + ) +/*++ + +Routine Description: + + This routine initializes the registry before putting up the + logon dialog. + 1) Deletes the CurrentUser value if it was not cleaned up from + the last logoff. + 2) Reads the current user's original PreferredServer value + 3) Reads the current user's PrintOption value + +Arguments: + + NewUserSid - Supplies the newly logged on user's SID in string format + which is the key name to find the password and preferred server. + +Return Value: + + None. + +--*/ +{ + LONG RegError; + HKEY WkstaKey; + + + NwDeleteCurrentUser(); + + // + // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + // \NWCWorkstation\Parameters\Option + // + RegError = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_WORKSTATION_OPTION_REGKEY, + REG_OPTION_NON_VOLATILE, + KEY_READ, + &WkstaKey + ); + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpInitializeRegistry open NWCWorkstation\\Parameters\\Option key unexpected error %lu!\n", RegError)); + return; + } + + // + // Get user's preferred server information. + // + (void) NwpReadRegInfo(WkstaKey, + NewUserSid, + PreferredServer, + PreferredServerSize, + PrintOption + ); + + (void) RegCloseKey(WkstaKey); + (void) NwpReadLogonScriptOptions( NewUserSid, pLogonScriptOptions, NULL ); +} + + +DWORD +NwpReadRegInfo( + IN HKEY WkstaKey, + IN LPWSTR CurrentUserSid, + OUT LPWSTR PreferredServer, + IN DWORD PreferredServerSize, + OUT PDWORD PrintOption + ) +/*++ + +Routine Description: + + This routine reads the user's preferred server and print option + from the registry. + +Arguments: + + WkstaKey - Supplies the handle to the parameters key under the NetWare + workstation service key. + + CurrentUserSid - Supplies the SID string of the user whose information + to read. + + PreferredServer - Receives the user's preferred server. + + PrintOption - Receives the user's print option. + +Return Value: + + None. + +--*/ +{ + LONG RegError; + + HKEY UserKey; + + DWORD ValueType; + DWORD BytesNeeded; + + // + // Open current user's key to read the original preferred server. + // + RegError = RegOpenKeyExW( + WkstaKey, + CurrentUserSid, + REG_OPTION_NON_VOLATILE, + KEY_READ, + &UserKey + ); + + if (RegError != NO_ERROR) { + + if ( (RegError == ERROR_FILE_NOT_FOUND) || + (RegError == ERROR_PATH_NOT_FOUND) ) { + + // + // If key doesnt exist assume first time. Use default + // if present. + // + + LONG RegError1 ; + HKEY WkstaParamKey ; + DWORD Disposition, dwScriptOptions, + dwScriptOptionsSize = sizeof(dwScriptOptions); + + // + // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + // \NWCWorkstation\Parameters + // + RegError1 = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_WORKSTATION_REGKEY, + REG_OPTION_NON_VOLATILE, + KEY_READ, + &WkstaParamKey + ); + + if (RegError1 != NO_ERROR) { + + return (DWORD) RegError; // return original error + } + + BytesNeeded = PreferredServerSize; + + RegError1 = RegQueryValueExW( + WkstaParamKey, + NW_DEFAULTSERVER_VALUENAME, + NULL, + &ValueType, + (LPBYTE) PreferredServer, + &BytesNeeded + ); + + + if (RegError1 != NO_ERROR) { + + (void) RegCloseKey(WkstaParamKey); + PreferredServer[0] = NW_INVALID_SERVER_CHAR; + PreferredServer[1] = 0; + return (DWORD) RegError; // return original error + } + + RegError1 = RegQueryValueExW( + WkstaParamKey, + NW_DEFAULTSCRIPTOPTIONS_VALUENAME, + NULL, + &ValueType, + (LPBYTE) &dwScriptOptions, + &dwScriptOptionsSize + ); + + (void) RegCloseKey(WkstaParamKey); + + if (RegError1 != NO_ERROR) { + + dwScriptOptions = NW_LOGONSCRIPT_ENABLED | + NW_LOGONSCRIPT_4X_ENABLED ; + } + + // + // We have a default. now write out the info for the current + // user now. Note we also write out the login script option. + // Errors here are not reported. + // + + + // + // Create the key under NWCWorkstation\Parameters\Option\<usersid> + // + RegError = RegCreateKeyExW( + WkstaKey, + CurrentUserSid, + 0, + WIN31_CLASS, + REG_OPTION_NON_VOLATILE, + KEY_WRITE | WRITE_DAC, + NULL, // security attr + &UserKey, + &Disposition + ); + + if (RegError == NO_ERROR) { + + RegError = NwLibSetEverybodyPermission( UserKey, + KEY_SET_VALUE ); + + if ( RegError == NO_ERROR ) + { + // + // Write the PreferredServer. Errors ignored. + // + RegError = RegSetValueExW( + UserKey, + NW_SERVER_VALUENAME, + 0, + REG_SZ, + (LPVOID) PreferredServer, + (wcslen(PreferredServer) + 1) * sizeof(WCHAR) + ); + + (void) RegCloseKey(UserKey) ; + + (void) NwpSaveLogonScriptOptions( + CurrentUserSid, + dwScriptOptions + ) ; + } + else { + + (void) RegCloseKey(UserKey) ; + } + } + + + *PrintOption = NW_PRINT_OPTION_DEFAULT; + return NO_ERROR; + + } + return (DWORD) RegError; + } + + + // + // Read PreferredServer value + // + BytesNeeded = PreferredServerSize; + + RegError = RegQueryValueExW( + UserKey, + NW_SERVER_VALUENAME, + NULL, + &ValueType, + (LPBYTE) PreferredServer, + &BytesNeeded + ); + + ASSERT(BytesNeeded <= PreferredServerSize); + + if (RegError != NO_ERROR) { +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWPROVAU: Attempt to read original preferred server failed %lu\n", + RegError)); + } +#endif + PreferredServer[0] = NW_INVALID_SERVER_CHAR; // Display login dialog + PreferredServer[1] = 0; + goto CleanExit; + } + + // + // Read PrintOption value into NwpPrintOption. + // + BytesNeeded = sizeof(PrintOption); + + RegError = RegQueryValueExW( + UserKey, + NW_PRINTOPTION_VALUENAME, + NULL, + &ValueType, + (LPBYTE) PrintOption, + &BytesNeeded + ); + + if (RegError != NO_ERROR ) { +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWPROVAU: Attempt to read original print option failed %lu\n", RegError)); + } +#endif + + *PrintOption = NW_PRINT_OPTION_DEFAULT; + goto CleanExit; + } + +CleanExit: + + (void) RegCloseKey(UserKey); + + return NO_ERROR; +} + +DWORD +NwpReadLogonScriptOptions( + IN LPWSTR CurrentUserSid, + OUT PDWORD pLogonScriptOptions, + OUT PDWORD pPreferredServerExists + + ) +/*++ + +Routine Description: + + This routine reads the user's logon script options from the registry. + +Arguments: + + CurrentUserSid - Supplies the SID string of the user whose information + to read. + + pLogonScriptOptions - Receives the user's script options + + pPreferredServerExists - Prefered server specified + +Return Value: + + None. + +--*/ +{ + LONG RegError; + + HKEY UserKey; + + DWORD ValueType; + DWORD BytesNeeded; + HKEY WkstaKey; + WCHAR PreferredServer[MAX_PATH + 1]; + + // + // initialize output values + // + *pLogonScriptOptions = 0 ; + if (pPreferredServerExists) + *pPreferredServerExists = 0 ; + + + // + // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + // \NWCWorkstation\Parameters\Option + // + RegError = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_WORKSTATION_OPTION_REGKEY, + REG_OPTION_NON_VOLATILE, + KEY_READ, + &WkstaKey + ); + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpReadLogonScriptOptions open NWCWorkstation\\Parameters\\Option key unexpected error %lu!\n", RegError)); + return (DWORD) RegError; + } + + // + // Open current user's key + // + RegError = RegOpenKeyExW( + WkstaKey, + CurrentUserSid, + REG_OPTION_NON_VOLATILE, + KEY_READ, + &UserKey + ); + + if (RegError != NO_ERROR) { +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWPROVAU: Open of CurrentUser %ws existing key failed %lu\n", + CurrentUserSid, RegError)); + } +#endif + (void) RegCloseKey(WkstaKey); + return (DWORD) RegError; + } + + + // + // Read LogonScriptOption value + // + BytesNeeded = sizeof(*pLogonScriptOptions); + + RegError = RegQueryValueExW( + UserKey, + NW_LOGONSCRIPT_VALUENAME, + NULL, + &ValueType, + (LPBYTE) pLogonScriptOptions, + &BytesNeeded + ); + + if (RegError != NO_ERROR ) { +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWPROVAU: Attempt to read original logon script option failed %lu\n", RegError)); + } +#endif + + // leave *pLogonScriptOptions as 0 + } + + if ( pPreferredServerExists != NULL ) { + + // + // Read PreferredServer value + // + BytesNeeded = sizeof( PreferredServer ); + + RegError = RegQueryValueExW( + UserKey, + NW_SERVER_VALUENAME, + NULL, + &ValueType, + (LPBYTE) PreferredServer, + &BytesNeeded + ); + + ASSERT(BytesNeeded <= sizeof(PreferredServer)); + + if (RegError != NO_ERROR) { +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWPROVAU: Attempt to read original preferred server failed %lu\n", + RegError)); + } +#endif + *pPreferredServerExists = FALSE; + } + else { + if ( lstrcmp( PreferredServer, L"" ) ) + *pPreferredServerExists = TRUE; + else + *pPreferredServerExists = FALSE; + } + } + + (void) RegCloseKey(UserKey); + (void) RegCloseKey(WkstaKey); + + return NO_ERROR; +} + +LPWSTR +NwpConstructLogonScript( + IN DWORD LogonScriptOptions +) +/*++ + +Routine Description: + + This routine constructs the multi-string for the logon script, + based on the options + +Arguments: + + LogonScriptOptions - Logon Script options + +Return Value: + + Allocated multi-string + +--*/ +{ + LPWSTR pLogonScript; + DWORD BytesNeeded; + +#define NW_NETWARE_SCRIPT_NAME L"nwscript.exe" +#define NW_NETWARE_DEBUG_NAME L"ntsd " + + if ( !( LogonScriptOptions & NW_LOGONSCRIPT_ENABLED ) ) { + return NULL; + } + + BytesNeeded = MAX_PATH * sizeof(WCHAR); + + if (pLogonScript = LocalAlloc( LMEM_ZEROINIT, BytesNeeded)) + { + DWORD dwSkipBytes = 0 ; + UINT retval ; + +#if DBG + // + // if have exact match then start under NTSD. + // + if ( LogonScriptOptions == (NW_LOGONSCRIPT_ENABLED | + NW_LOGONSCRIPT_4X_ENABLED | + NW_LOGONSCRIPT_DEBUG) ) { + + retval = GetSystemDirectory(pLogonScript, + BytesNeeded ); + if (retval == 0) { + + (void)LocalFree(pLogonScript) ; + return(NULL) ; + } + wcscat( pLogonScript, L"\\" ); + wcscat( pLogonScript, NW_NETWARE_DEBUG_NAME ); + dwSkipBytes = (retval * sizeof(WCHAR)) + + sizeof(NW_NETWARE_DEBUG_NAME) ; + BytesNeeded -= dwSkipBytes ; + } +#endif + + retval = GetSystemDirectory(pLogonScript + (dwSkipBytes/sizeof(WCHAR)), + BytesNeeded ); + + if (retval == 0) { + + (void)LocalFree(pLogonScript) ; + return(NULL) ; + } + + wcscat( pLogonScript, L"\\" ); + wcscat( pLogonScript, NW_NETWARE_SCRIPT_NAME ); + } + + return (pLogonScript); + +} + +DWORD +NwpSaveLogonScriptOptions( + IN LPWSTR CurrentUserSid, + IN DWORD LogonScriptOptions + ) +/*++ + +Routine Description: + + This routine saves the logon script options in the registry. + +Arguments: + + CurrentUserSid - Supplies the user's SID string + + LogonScriptOptions - Logon script options + +Return Value: + + Error from registry + +--*/ +{ + LONG RegError; + HKEY WkstaOptionKey; + HKEY CurrentUserOptionKey; + + // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + // \NWCWorkstation\Parameters\Option + // + RegError = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_WORKSTATION_OPTION_REGKEY, + REG_OPTION_NON_VOLATILE, + KEY_WRITE | KEY_CREATE_SUB_KEY | DELETE, + &WkstaOptionKey + ); + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpSaveLogonScriptOptions open NWCWorkstation\\Parameters\\Option key unexpected error %lu!\n", RegError)); + return RegError; + } + + // + // Open the <NewUser> key under Option + // + RegError = RegOpenKeyExW( + WkstaOptionKey, + CurrentUserSid, + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + &CurrentUserOptionKey + ); + + (void) RegCloseKey(WkstaOptionKey); + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpSaveLogonScriptOptions failed to save options %lu\n", RegError)); + return RegError; + } + + // + // Write the options + // + RegError = RegSetValueExW( + CurrentUserOptionKey, + NW_LOGONSCRIPT_VALUENAME, + 0, + REG_DWORD, + (LPVOID) &LogonScriptOptions, + sizeof(LogonScriptOptions) + ); + + (void) RegCloseKey(CurrentUserOptionKey); + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpSaveLogonScriptOptions failed to save options %lu\n", RegError)); + } + + return RegError; + +} + + +VOID +NwpSaveLogonCredential( + IN LPWSTR NewUserSid, + IN PLUID LogonId, + IN LPWSTR UserName, + IN LPWSTR Password, + IN LPWSTR PreferredServer OPTIONAL + ) +/*++ + +Routine Description: + + This routine saves the user logon credential in the registry + and LSA's memory. This is normally called when NwrLogonUser is + successful. + +Arguments: + + NewUserSid - Supplies the newly logged on user's SID string to be + set as the CurrentUser value as well as the name of the key for + the user's preferred server. + + LogonId - Supplies the user's logon ID. If NULL is specified, + just read the existing logon ID from the registry rather + than save a new one. + + UserName - Supplies the name of the user. + + Password - Supplies the password which the user wants to use on + the NetWare network. + + PreferredServer - Supplies the name of the preferred server. + +Return Value: + + Error from redirector if login is rejected. + +--*/ +{ + DWORD status; + + LONG RegError; + HKEY WkstaKey; + HKEY WkstaLogonKey; + HKEY WkstaOptionKey; + HKEY NewUserLogonKey; + HKEY NewUserOptionKey; + +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWPROVAU: NwpSaveLogonCredential: %ws, %ws, %ws, %ws\n", + NewUserSid, UserName, Password, PreferredServer)); + } +#endif + + // + // Write the logon credential to the registry. NewUserSid should be + // written last so that if it can be read by the workstation service, + // it's an indication that all other credential information has been + // written. + // + + // + // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + // \NWCWorkstation\Parameters\Logon + // + RegError = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_WORKSTATION_LOGON_REGKEY, + REG_OPTION_NON_VOLATILE, + KEY_WRITE | KEY_CREATE_SUB_KEY | DELETE, + &WkstaLogonKey + ); + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpSaveLogonCredential open NWCWorkstation\\Parameters\\Logon key unexpected error %lu!\n", RegError)); + return; + } + + // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + // \NWCWorkstation\Parameters\Option + // + RegError = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_WORKSTATION_OPTION_REGKEY, + REG_OPTION_NON_VOLATILE, + KEY_WRITE | KEY_CREATE_SUB_KEY | DELETE, + &WkstaOptionKey + ); + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpSaveLogonCredential open NWCWorkstation\\Parameters\\Option key unexpected error %lu!\n", RegError)); + (void) RegCloseKey( WkstaLogonKey ); + return; + } + + // + // Open the <NewUser> key under Logon + // + RegError = RegOpenKeyExW( + WkstaLogonKey, + NewUserSid, + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + &NewUserLogonKey + ); + + + if (RegError == ERROR_FILE_NOT_FOUND) + { + DWORD Disposition; + + // + // Create <NewUser> key under NWCWorkstation\Parameters\Logon + // + RegError = RegCreateKeyExW( + WkstaLogonKey, + NewUserSid, + 0, + WIN31_CLASS, + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + NULL, // security attr + &NewUserLogonKey, + &Disposition + ); + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpSaveLogonCredential create Logon\\%ws key unexpected error %lu!\n", NewUserSid, RegError)); + + (void) RegCloseKey(WkstaLogonKey); + (void) RegCloseKey(WkstaOptionKey); + return; + } + } + else if (RegError != NO_ERROR) + { + KdPrint(("NWPROVAU: NwpSaveLogonCredential open Logon\\%ws unexpected error %lu!\n", NewUserSid, RegError)); + + (void) RegCloseKey(WkstaLogonKey); + (void) RegCloseKey(WkstaOptionKey); + return; + } + + (void) RegCloseKey(WkstaLogonKey); + + // + // Open the <NewUser> key under Option + // + RegError = RegOpenKeyExW( + WkstaOptionKey, + NewUserSid, + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + &NewUserOptionKey + ); + + + if (RegError == ERROR_FILE_NOT_FOUND) + { + DWORD Disposition; + + // + // Create <NewUser> key under NWCWorkstation\Parameters\Option + // + RegError = RegCreateKeyExW( + WkstaOptionKey, + NewUserSid, + 0, + WIN31_CLASS, + REG_OPTION_NON_VOLATILE, + KEY_WRITE | WRITE_DAC, + NULL, // security attr + &NewUserOptionKey, + &Disposition + ); + + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpSaveLogonCredential create Option\\%ws key unexpected error %lu!\n", NewUserSid, RegError)); + + (void) RegCloseKey(WkstaOptionKey); + (void) RegCloseKey(NewUserLogonKey); + return; + } + + RegError = NwLibSetEverybodyPermission( NewUserOptionKey, + KEY_SET_VALUE ); + + if ( RegError != NO_ERROR ) + { + KdPrint(("NWPROVAU: NwpSaveLogonCredential set security on Option\\%ws key unexpected error %lu!\n", NewUserSid, RegError)); + + (void) RegCloseKey(WkstaOptionKey); + (void) RegCloseKey(NewUserLogonKey); + return; + } + + } + else if (RegError != NO_ERROR) + { + KdPrint(("NWPROVAU: NwpSaveLogonCredential open Option\\%ws unexpected error %lu!\n", NewUserSid, RegError)); + + (void) RegCloseKey(WkstaOptionKey); + (void) RegCloseKey(NewUserLogonKey); + return; + } + + (void) RegCloseKey(WkstaOptionKey); + + // + // Successfully opened or created an existing user entry. + // We will now save the credential in LSA. + // + status = NwpSetCredentialInLsa( + LogonId, + UserName, + Password + ); + + if (status != NO_ERROR) { + // + // Could not save new credential. + // + KdPrint(("NWPROVAU: NwpSaveLogonCredential failed to set credential %lu\n", status)); + } + + // + // Write the logon ID to the registry. + // + RegError = RegSetValueExW( + NewUserLogonKey, + NW_LOGONID_VALUENAME, + 0, + REG_BINARY, + (LPVOID) LogonId, + sizeof(LUID) + ); + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpSaveLogonCredential failed to save logon ID %lu\n", RegError)); + } + + (void) RegCloseKey(NewUserLogonKey); + + // + // If PreferredServer is not supplied, then that means we don't want to + // save the preferred server into the registry. + // + + if (ARGUMENT_PRESENT(PreferredServer)) + { + // + // Write the PreferredServer + // + RegError = RegSetValueExW( + NewUserOptionKey, + NW_SERVER_VALUENAME, + 0, + REG_SZ, + (LPVOID) PreferredServer, + (wcslen(PreferredServer) + 1) * sizeof(WCHAR) + ); + + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpSaveLogonCredential failed to save PreferredServer %ws %lu\n", PreferredServer, RegError)); + } + } + + (void) RegCloseKey(NewUserOptionKey); + + // + // Write the NewUser string as the CurrentUser value. + // + + // + // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + // \NWCWorkstation\Parameters + // + RegError = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_WORKSTATION_REGKEY, + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + &WkstaKey + ); + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpSaveLogonCredential open NWCWorkstation\\Parameters key unexpected error %lu!\n", RegError)); + return; + } + + RegError = RegSetValueExW( + WkstaKey, + NW_CURRENTUSER_VALUENAME, + 0, + REG_SZ, + (LPVOID) NewUserSid, + (wcslen(NewUserSid) + 1) * sizeof(WCHAR) + ); + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpSaveLogonCredential failed to save NewUser %ws %lu\n", NewUserSid, RegError)); + } + + RegCloseKey( WkstaKey ); + +} + + +VOID +NwpSaveServiceCredential( + IN PLUID LogonId, + IN LPWSTR UserName, + IN LPWSTR Password + ) +/*++ + +Routine Description: + + This routine saves the service logon ID in the registry and + the credential in LSA's memory. + +Arguments: + + LogonId - Supplies the service's logon ID. + + UserName - Supplies the name of the service. + + Password - Supplies the password of the service. + +Return Value: + + None. + +--*/ +{ + DWORD status; + + LONG RegError; + HKEY ServiceLogonKey; + HKEY LogonIdKey; + + DWORD Disposition; + WCHAR LogonIdKeyName[NW_MAX_LOGON_ID_LEN]; + + // + // Write the logon ID to the registry. + + // + // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + // \NWCWorkstation\Parameters\ServiceLogon, create if does not exist + // + RegError = RegCreateKeyExW( + HKEY_LOCAL_MACHINE, + NW_SERVICE_LOGON_REGKEY, + 0, + WIN31_CLASS, + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + NULL, // security attr + &ServiceLogonKey, + &Disposition + ); + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpSaveServiceCredential open NWCWorkstation\\Parameters\\ServiceLogon key unexpected error %lu!\n", RegError)); + return; + } + + NwLuidToWStr(LogonId, LogonIdKeyName); + + // + // Create the logon ID key under ServiceLogon + // + RegError = RegCreateKeyExW( + ServiceLogonKey, + LogonIdKeyName, + 0, + WIN31_CLASS, + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + NULL, // security attr + &LogonIdKey, + &Disposition + ); + + RegCloseKey(ServiceLogonKey); + + if (RegError != NO_ERROR) { + KdPrint(("NWPROVAU: NwpSaveServiceCredential create NWCWorkstation\\Parameters\\ServiceLogon\\<LogonId> key unexpected error %lu!\n", RegError)); + return; + } + + RegCloseKey(LogonIdKey); + + // + // Save the service logon credential in LSA. + // + status = NwpSetCredentialInLsa( + LogonId, + UserName, + Password + ); + + if (status != NO_ERROR) { + // + // Could not save new credential. + // + KdPrint(("NWPROVAU: NwpSaveServiceCredential failed to set credential %lu\n", status)); + } +} + + +DWORD +NwpGetUserSid( + IN PLUID LogonId, + OUT LPWSTR *UserSidString + ) +/*++ + +Routine Description: + + This routine looks up the SID of a user given the user's logon ID. + It does this by making the current process a logon process and then + call to LSA to get the user SID. + +Arguments: + + LogonId - Supplies the logon ID of the user to lookup the SID. + + UserSidString - Receives a pointer to a buffer allocated by this routine + which contains the user SID in string form. This must be freed with + LocalFree when done. + +Return Value: + + NO_ERROR or reason for failure. + +--*/ +{ + DWORD status; + NTSTATUS ntstatus; + NTSTATUS AuthPackageStatus; + + STRING InputString; + LSA_OPERATIONAL_MODE SecurityMode = 0; + + HANDLE LsaHandle; + ULONG AuthPackageId; + + MSV1_0_GETUSERINFO_REQUEST UserInfoRequest; + PMSV1_0_GETUSERINFO_RESPONSE UserInfoResponse = NULL; + ULONG UserInfoResponseLength; + + + + + // + // Register this process as a logon process so that we can call + // MS V 1.0 authentication package. + // + RtlInitString(&InputString, "Microsoft NetWare Credential Manager"); + + ntstatus = LsaRegisterLogonProcess( + &InputString, + &LsaHandle, + &SecurityMode + ); + + if (! NT_SUCCESS(ntstatus)) { + KdPrint(("NWPROVAU: LsaRegisterLogonProcess returns x%08lx\n", + ntstatus)); + return RtlNtStatusToDosError(ntstatus); + } + + // + // Look up the MS V1.0 authentication package + // + RtlInitString(&InputString, MSV1_0_PACKAGE_NAME); + + ntstatus = LsaLookupAuthenticationPackage( + LsaHandle, + &InputString, + &AuthPackageId + ); + + if (! NT_SUCCESS(ntstatus)) { + KdPrint(("NWPROVAU: LsaLookupAuthenticationPackage returns x%08lx\n", + ntstatus)); + status = RtlNtStatusToDosError(ntstatus); + goto CleanExit; + } + + // + // Ask authentication package for user information. + // + UserInfoRequest.MessageType = MsV1_0GetUserInfo; + RtlCopyLuid(&UserInfoRequest.LogonId, LogonId); + + ntstatus = LsaCallAuthenticationPackage( + LsaHandle, + AuthPackageId, + &UserInfoRequest, + sizeof(MSV1_0_GETUSERINFO_REQUEST), + (PVOID *) &UserInfoResponse, + &UserInfoResponseLength, + &AuthPackageStatus + ); + + if (NT_SUCCESS(ntstatus)) { + ntstatus = AuthPackageStatus; + } + if (! NT_SUCCESS(ntstatus)) { + KdPrint(("NWPROVAU: LsaCallAuthenticationPackage returns x%08lx\n", + ntstatus)); + status = RtlNtStatusToDosError(ntstatus); + goto CleanExit; + } + + // + // Convert the SID to string. This routine also allocates the + // output buffer. + // + status = NwpConvertSid( + UserInfoResponse->UserSid, + UserSidString + ); + +CleanExit: + if (UserInfoResponse != NULL) { + (void) LsaFreeReturnBuffer((PVOID) UserInfoResponse); + } + + (void) LsaDeregisterLogonProcess(LsaHandle); + + return status; +} + + +DWORD +NwpConvertSid( + IN PSID Sid, + OUT LPWSTR *UserSidString + ) +{ + NTSTATUS ntstatus; + UNICODE_STRING SidString; + + + // + // Initialize output pointer + // + *UserSidString = NULL; + + ntstatus = RtlConvertSidToUnicodeString( + &SidString, + Sid, + TRUE // Allocate destination string + ); + + if (ntstatus != STATUS_SUCCESS) { + KdPrint(("NWPROVAU: RtlConvertSidToUnicodeString returns %08lx\n", + ntstatus)); + return RtlNtStatusToDosError(ntstatus); + } + + // + // Create the buffer to return the SID string + // + if ((*UserSidString = (LPVOID) LocalAlloc( + LMEM_ZEROINIT, + SidString.Length + sizeof(WCHAR) + )) == NULL) { + RtlFreeUnicodeString(&SidString); + return ERROR_NOT_ENOUGH_MEMORY; + } + + memcpy(*UserSidString, SidString.Buffer, SidString.Length); + + RtlFreeUnicodeString(&SidString); + +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWPROVAU: NwpConvertSid got %ws\n", *UserSidString)); + } +#endif + + return NO_ERROR; +} + + +BOOL +NwpPollWorkstationStart( + VOID + ) +/*++ + +Routine Description: + + This routine polls for the workstation to complete starting. + It gives up after 90 seconds. + +Arguments: + + None. + +Return Value: + + Returns TRUE if the NetWare workstation is running; FALSE otherwise. + +--*/ +{ + DWORD err; + SC_HANDLE ScManager = NULL; + SC_HANDLE Service = NULL; + SERVICE_STATUS ServiceStatus; + DWORD TryCount = 0; + BOOL Started = FALSE; + + + if ((ScManager = OpenSCManager( + NULL, + NULL, + SC_MANAGER_CONNECT + )) == (SC_HANDLE) NULL) { + + err = GetLastError(); + + KdPrint(("NWPROVAU: NwpPollWorkstationStart: OpenSCManager failed %lu\n", + err)); + goto CleanExit; + } + + if ((Service = OpenService( + ScManager, + NW_WORKSTATION_SERVICE, + SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG + )) == (SC_HANDLE) NULL) { + + err = GetLastError(); + + (void) CloseServiceHandle(ScManager); + + KdPrint(("NWPROVAU: NwpPollWorkstationStart: OpenService failed %lu\n", + err)); + goto CleanExit; + } + + + do { + if (! QueryServiceStatus( + Service, + &ServiceStatus + )) { + + err = GetLastError(); + KdPrint(("NWPROVAU: NwpPollWorkstationStart: QueryServiceStatus failed %lu\n", + err)); + goto CleanExit; + } + + if ( (ServiceStatus.dwCurrentState == SERVICE_RUNNING) || + (ServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING) || + (ServiceStatus.dwCurrentState == SERVICE_PAUSE_PENDING) || + (ServiceStatus.dwCurrentState == SERVICE_PAUSED) ) { + + Started = TRUE; + } + else if (ServiceStatus.dwCurrentState == SERVICE_START_PENDING || + (ServiceStatus.dwCurrentState == SERVICE_STOPPED && + ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED)) { + + // + // If workstation is stopped and never started before but it's + // not auto-start, don't poll. + // + if (TryCount == 0 && + ServiceStatus.dwCurrentState == SERVICE_STOPPED && + ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED) { + + BYTE OutBuffer[sizeof(QUERY_SERVICE_CONFIGW) + 256]; + DWORD BytesNeeded; + + + if (QueryServiceConfigW( + Service, + (LPQUERY_SERVICE_CONFIGW) OutBuffer, + sizeof(OutBuffer), + &BytesNeeded + )) { + + if (((LPQUERY_SERVICE_CONFIGW) OutBuffer)->dwStartType != + SERVICE_AUTO_START) { + +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWPROVAU: NwpPollWorkstationStart: Not waiting for the workstation to start\n")); + } +#endif + + goto CleanExit; + } + } + else { + err = GetLastError(); + KdPrint(("NWPROVAU: QueryServiceConfig failed %lu, BytesNeeded %lu\n", + err, BytesNeeded)); + } + + } + + + // + // Wait only if the workstation is start pending, or it has not + // been attempted to start before. + // + + Sleep(5000); // Sleep for 5 seconds before rechecking. + TryCount++; + } + else { + goto CleanExit; + } + + } while (! Started && TryCount < 18); + + if (Started) { + +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWPROVAU: NetWare workstation is started after we've polled %lu times\n", + TryCount)); + } +#endif + + } + +CleanExit: + if (ScManager != NULL) { + (void) CloseServiceHandle(ScManager); + } + + if (Service != NULL) { + (void) CloseServiceHandle(Service); + } + + return Started; +} + + + +DWORD +NwpSetCredentialInLsa( + IN PLUID LogonId, + IN LPWSTR UserName, + IN LPWSTR Password + ) +/*++ + +Routine Description: + + This routine calls to the NetWare authentication package to save + the user credential. + +Arguments: + + LogonId - Supplies the logon ID of the user. + + UserName - Supplies the username. + + Password - Supplies the password. + + +Return Value: + + NO_ERROR or reason for failure. + +--*/ +{ + DWORD status; + NTSTATUS ntstatus; + NTSTATUS AuthPackageStatus; + + STRING InputString; + LSA_OPERATIONAL_MODE SecurityMode = 0; + + HANDLE LsaHandle; + + ULONG AuthPackageId; + + NWAUTH_SET_CREDENTIAL_REQUEST SetCredRequest; + PCHAR DummyOutput; + ULONG DummyOutputLength; + + UNICODE_STRING PasswordStr; + UCHAR EncodeSeed = NW_ENCODE_SEED; + + + // + // Register this process as a logon process so that we can call + // NetWare authentication package. + // + RtlInitString(&InputString, "Microsoft NetWare Credential Manager"); + + ntstatus = LsaRegisterLogonProcess( + &InputString, + &LsaHandle, + &SecurityMode + ); + + if (! NT_SUCCESS(ntstatus)) { + KdPrint(("NWPROVAU: NwpSetCredential: LsaRegisterLogonProcess returns x%08lx\n", + ntstatus)); + return RtlNtStatusToDosError(ntstatus); + } + + // + // Look up the NetWare authentication package + // + RtlInitString(&InputString, NW_AUTH_PACKAGE_NAME); + + ntstatus = LsaLookupAuthenticationPackage( + LsaHandle, + &InputString, + &AuthPackageId + ); + + if (! NT_SUCCESS(ntstatus)) { + KdPrint(("NWPROVAU: NwpSetCredential: LsaLookupAuthenticationPackage returns x%08lx\n", + ntstatus)); + status = RtlNtStatusToDosError(ntstatus); + goto CleanExit; + } + + // + // Ask authentication package for user information. + // + SetCredRequest.MessageType = NwAuth_SetCredential; + RtlCopyLuid(&SetCredRequest.LogonId, LogonId); + wcscpy(SetCredRequest.UserName, UserName); + wcscpy(SetCredRequest.Password, Password); + + // + // Encode the password. + // + RtlInitUnicodeString(&PasswordStr, SetCredRequest.Password); + RtlRunEncodeUnicodeString(&EncodeSeed, &PasswordStr); + + ntstatus = LsaCallAuthenticationPackage( + LsaHandle, + AuthPackageId, + &SetCredRequest, + sizeof(SetCredRequest), + (PVOID *) &DummyOutput, + &DummyOutputLength, + &AuthPackageStatus + ); + + if (NT_SUCCESS(ntstatus)) { + ntstatus = AuthPackageStatus; + } + if (! NT_SUCCESS(ntstatus)) { + KdPrint(("NWPROVAU: NwpSetCredential: LsaCallAuthenticationPackage returns x%08lx\n", + ntstatus)); + status = RtlNtStatusToDosError(ntstatus); + } + else { + status = NO_ERROR; + } + +CleanExit: + (void) LsaDeregisterLogonProcess(LsaHandle); + + return status; +} + +NTSTATUS NwNdsOpenRdrHandle( + OUT PHANDLE phNwRdrHandle +) +{ + + NTSTATUS ntstatus; + IO_STATUS_BLOCK IoStatusBlock; + OBJECT_ATTRIBUTES ObjectAttributes; + ACCESS_MASK DesiredAccess = SYNCHRONIZE | GENERIC_READ; + + WCHAR NameStr[] = L"\\Device\\NwRdr"; + UNICODE_STRING uOpenName; + + // + // Prepare the open name. + // + + RtlInitUnicodeString( &uOpenName, NameStr ); + + // + // Set up the object attributes. + // + + InitializeObjectAttributes( + &ObjectAttributes, + &uOpenName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL ); + + ntstatus = NtOpenFile( + phNwRdrHandle, + DesiredAccess, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_VALID_FLAGS, + FILE_SYNCHRONOUS_IO_NONALERT ); + + if ( !NT_ERROR(ntstatus) && + !NT_INFORMATION(ntstatus) && + !NT_WARNING(ntstatus)) { + + return IoStatusBlock.Status; + + } + + return ntstatus; +} + +VOID +NwpSelectServers( + IN HWND DialogHandle, + IN PCHANGE_PW_DLG_PARAM Credential + ) +/*++ + +Routine Description: + + This routine displays the dialog for user to select individual trees + to change password on. It then changes the password on the selected + list. After the password has been changed, it displays a dialog which lists + the 3.X bindery servers where the change could not be made. + +Arguments: + + DialogHandle - Supplies the handle to display dialog. + + Credential - Provides on input the old and new passwords, and + the logged in user's name. Other field are ignored + on input and consecuently used within this function. + +Return Value: + + None. + +--*/ +{ + INT Result; + + Credential->TreeList = NULL; + Credential->UserList = NULL; + Credential->Entries = 0; + Credential->ChangedOne = FALSE; + + Result = DialogBoxParamW( hmodNW, + MAKEINTRESOURCEW(DLG_PW_SELECT_SERVERS), + (HWND) DialogHandle, + NwpSelectServersDlgProc, + (LPARAM) Credential ); + + if ( Result == IDOK ) + { + // + // Display list of trees (if any) for which password was changed. + // + DialogBoxParamW( hmodNW, + MAKEINTRESOURCEW(DLG_PW_CHANGED), + (HWND) DialogHandle, + NwpChangePasswordSuccessDlgProc, + (LPARAM) Credential ); + + if ( Credential->TreeList != NULL ) + { + LocalFree( Credential->TreeList ); + } + + // + // Display a dialog to tell users to use SetPass if they have an + // account on a NetWare 3.X server. + // + NwpMessageBoxError( DialogHandle, + IDS_NETWARE_TITLE, + IDS_CHANGE_PASSWORD_INFO, + 0, + NULL, + MB_OK ); + } +} |