diff options
Diffstat (limited to 'private/nw/svcdlls/nwwks/server/credentl.c')
-rw-r--r-- | private/nw/svcdlls/nwwks/server/credentl.c | 1462 |
1 files changed, 1462 insertions, 0 deletions
diff --git a/private/nw/svcdlls/nwwks/server/credentl.c b/private/nw/svcdlls/nwwks/server/credentl.c new file mode 100644 index 000000000..b26544c0f --- /dev/null +++ b/private/nw/svcdlls/nwwks/server/credentl.c @@ -0,0 +1,1462 @@ +/*++ + +Copyright (c) 1993, 1994 Microsoft Corporation + +Module Name: + + credentl.c + +Abstract: + + This module contains credential management routines supported by + NetWare Workstation service. + +Author: + + Rita Wong (ritaw) 15-Feb-1993 + +Revision History: + + 13-Apr-1994 Added change password code written by ColinW, AndyHe, + TerenceS, and RitaW. + +--*/ + +#include <nw.h> +#include <nwreg.h> +#include <nwlsa.h> +#include <nwauth.h> +#include <nwxchg.h> +#include <nwapi.h> + + +//-------------------------------------------------------------------// +// // +// Global variables // +// // +//-------------------------------------------------------------------// + +// +// Variables to coordinate reading of user logon credential from the +// registry if the user logged on before the workstation is started. +// +STATIC BOOL NwLogonNotifiedRdr; + + +STATIC +DWORD +NwpRegisterLogonProcess( + OUT PHANDLE LsaHandle, + OUT PULONG AuthPackageId + ); + +STATIC +VOID +NwpGetServiceCredentials( + IN HANDLE LsaHandle, + IN ULONG AuthPackageId + ); + +STATIC +DWORD +NwpGetCredentialInLsa( + IN HANDLE LsaHandle, + IN ULONG AuthPackageId, + IN PLUID LogonId, + OUT LPWSTR *UserName, + OUT LPWSTR *Password + ); + + +DWORD +NwrLogonUser( + IN LPWSTR Reserved OPTIONAL, + IN PLUID LogonId, + IN LPWSTR UserName, + IN LPWSTR Password OPTIONAL, + IN LPWSTR PreferredServerName OPTIONAL, + OUT LPWSTR LogonCommand OPTIONAL, + IN DWORD LogonCommandLength + ) +/*++ + +Routine Description: + + This function logs on the user to NetWare network. It passes the + user logon credential to the redirector to be used as the default + credential when attaching to any server. + +Arguments: + + Reserved - Must be NULL. + + UserName - Specifies the name of the user who logged on. + + Password - Specifies the password of the user who logged on. + + PreferredServerName - Specifies the user's preferred server. + + LogonCommand - Receives the string which is the command to execute + on the command prompt for the user if logon is successful. + +Return Value: + + NO_ERROR or error from redirector. + +--*/ +{ + DWORD status; + LUID SystemId = SYSTEM_LUID ; + + UNREFERENCED_PARAMETER(Reserved); + + EnterCriticalSection(&NwLoggedOnCritSec); + + status = NwRdrLogonUser( + LogonId, + UserName, + wcslen(UserName) * sizeof(WCHAR), + Password, + (ARGUMENT_PRESENT(Password) ? + wcslen(Password) * sizeof(WCHAR) : + 0), + PreferredServerName, + (ARGUMENT_PRESENT(PreferredServerName) ? + wcslen(PreferredServerName) * sizeof(WCHAR) : + 0) + ); + + if (status == NO_ERROR || status == NW_PASSWORD_HAS_EXPIRED) { + NwLogonNotifiedRdr = TRUE; + if (RtlEqualLuid(LogonId, &SystemId)) + GatewayLoggedOn = TRUE ; + } + + LeaveCriticalSection(&NwLoggedOnCritSec); + + + if (ARGUMENT_PRESENT(LogonCommand) && (LogonCommandLength >= sizeof(WCHAR))) { + LogonCommand[0] = 0; + } + + return status; +} + + +DWORD +NwrLogoffUser( + IN LPWSTR Reserved OPTIONAL, + IN PLUID LogonId + ) +/*++ + +Routine Description: + + This function tells the redirector to log off the interactive + user. + +Arguments: + + Reserved - Must be NULL. + + LogonId - PLUID identifying the logged on process. if NULL, then gateway. + +Return Value: + + +--*/ +{ + DWORD status = NO_ERROR ; + LUID SystemId = SYSTEM_LUID ; + + UNREFERENCED_PARAMETER(Reserved); + + EnterCriticalSection(&NwLoggedOnCritSec); + + if (GatewayLoggedOn || !RtlEqualLuid(LogonId, &SystemId)) + status = NwRdrLogoffUser(LogonId); + + if (status == NO_ERROR && RtlEqualLuid(LogonId, &SystemId)) + GatewayLoggedOn = FALSE ; + + LeaveCriticalSection(&NwLoggedOnCritSec); + + return status ; +} + + +DWORD +NwrSetInfo( + IN LPWSTR Reserved OPTIONAL, + IN DWORD PrintOption, + IN LPWSTR PreferredServerName OPTIONAL + ) +/*++ + +Routine Description: + + This function sets the preferred server and print option in + the redirector for the interactive user. + +Arguments: + + Reserved - Must be NULL. + + PreferredServerName - Specifies the user's preferred server. + + PrintOption - Specifies the user's print option flag + +Return Value: + + NO_ERROR or error from redirector. + +--*/ +{ + DWORD err; + + UNREFERENCED_PARAMETER(Reserved); + + NwPrintOption = PrintOption; + + err = NwRdrSetInfo( + PrintOption, + NwPacketBurstSize, // just reset to current + PreferredServerName, + (PreferredServerName != NULL ? + wcslen( PreferredServerName) * sizeof( WCHAR ) : 0 ), + NwProviderName, // just reset to current + wcslen( NwProviderName ) * sizeof( WCHAR ) + ); + + return err; +} + +DWORD +NwrSetLogonScript( + IN LPWSTR Reserved OPTIONAL, + IN DWORD ScriptOptions + ) +/*++ + +Routine Description: + + This function sets logon script related info. Currently, all that is + supported is to turn the Run Logon Scripts Synchronously flag on and off. + We do this using the global flag and not per user because at NPLogonNotify + time we dont have per user registry yet. And rather than turn on & leave + on, we turn on as need so that users that dont run NW scripts dont need + wait. + +Arguments: + + Reserved - Must be NULL. + + ScriptOptions - options for logon scripts. + +Return Value: + + Win32 error from calls made. + +--*/ +{ + DWORD dwSync, err = NO_ERROR ; + HKEY hKeyWinLogon = NULL, hKeyNWC = NULL ; + + UNREFERENCED_PARAMETER(Reserved); + + // + // *** Note that in this function we intentionally do not impersonate *** + // *** since we are modifying registry under \SOFTWARE & \SYSTEM. *** + // + + // + // Check the parameters. + // + if (ScriptOptions == SYNC_LOGONSCRIPT) + { + dwSync = 1 ; // this is value WinLogon needs to sync login scripts. + } + else if (ScriptOptions == RESET_SYNC_LOGONSCRIPT) + { + dwSync = 0 ; + } + else + { + return(ERROR_INVALID_PARAMETER) ; + } + + // + // + // Open HKEY_LOCAL_MACHINE\System\CurrentVersion\Services\NwcWorkstation + // \Parameters. We use this location to record the fact we temporarily + // turned on the Sync Scripts Flag. + // + err = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_WORKSTATION_REGKEY, + 0, + KEY_READ | KEY_WRITE, // desired access + &hKeyNWC) ; + if ( err ) + { + return err ; + } + + // + // We are resetting. Check if we turned the flag on. If no, then leave + // it be. + // + if (ScriptOptions == RESET_SYNC_LOGONSCRIPT) + { + DWORD dwType, dwValue = 0 ; + DWORD dwSize = sizeof(dwValue) ; + + err = RegQueryValueExW( + hKeyNWC, + NW_SYNCLOGONSCRIPT_VALUENAME, + NULL, + &dwType, // ignored + (LPBYTE) &dwValue, + &dwSize) ; + + if ((err != NO_ERROR) || (dwValue == 0)) + { + // + // value not there or zero. ie. assume we didnt set. quit now. + // + goto ExitPoint ; + } + } + + // + // + // Open HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion + // \WinLogon. + // + err = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + WINLOGON_REGKEY, + 0, + KEY_READ | KEY_WRITE, // desired access + &hKeyWinLogon) ; + if ( err ) + { + goto ExitPoint ; + } + + // + // We are setting. Check if flag is already on. If yes, then leave + // it be. + // + if (ScriptOptions == SYNC_LOGONSCRIPT) + { + DWORD dwType, dwValue = 0 ; + DWORD dwSize = sizeof(dwValue) ; + + err = RegQueryValueExW( + hKeyWinLogon, + SYNCLOGONSCRIPT_VALUENAME, + NULL, + &dwType, // ignored + (LPBYTE) &dwValue, + &dwSize) ; + + if ((err == NO_ERROR) && (dwValue == 1)) + { + // + // already on. nothing to do. just return. + // + goto ExitPoint ; + } + } + // + // Write out value to make logon scripts synchronous. Or to reset it. + // + err = RegSetValueExW( + hKeyWinLogon, + SYNCLOGONSCRIPT_VALUENAME, + 0, + REG_DWORD, + (LPBYTE) &dwSync, // either 1 or 0. + sizeof(dwSync)) ; + + if (err == NO_ERROR) + { + DWORD dwValue = (ScriptOptions == SYNC_LOGONSCRIPT) ? 1 : 0 ; + // + // We have successfully set WinLogon flag. Record (or clear) + // our own flag. + // + err = RegSetValueExW( + hKeyNWC, + NW_SYNCLOGONSCRIPT_VALUENAME, + 0, + REG_DWORD, + (LPBYTE) &dwValue, + sizeof(dwValue)) ; + } + +ExitPoint: + + if (hKeyWinLogon) + (void) RegCloseKey( hKeyWinLogon ); + if (hKeyNWC) + (void) RegCloseKey( hKeyNWC ); + + return err; +} + + +DWORD +NwrValidateUser( + IN LPWSTR Reserved OPTIONAL, + IN LPWSTR PreferredServerName + ) +/*++ + +Routine Description: + + This function checks whether the user can be authenticated + successfully on the given server. + +Arguments: + + Reserved - Must be NULL. + + PreferredServerName - Specifies the user's preferred server. + +Return Value: + + NO_ERROR or error that occurred during authentication. + +--*/ +{ + DWORD status ; + UNREFERENCED_PARAMETER(Reserved); + + + if ( ( PreferredServerName != NULL ) + && ( *PreferredServerName != 0 ) + ) + { + // + // Impersonate the client + // + if ((status = NwImpersonateClient()) != NO_ERROR) + { + return status ; + } + + status = NwConnectToServer( PreferredServerName ) ; + + (void) NwRevertToSelf() ; + + return status ; + + } + + return NO_ERROR; +} + + +VOID +NwInitializeLogon( + VOID + ) +/*++ + +Routine Description: + + This function initializes the data in the workstation which handles + user logon. It is called by the initialization thread. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + // + // Initialize logon flag. When the redirector LOGON FsCtl has been + // called, this flag will be set to TRUE. Initialize the + // critical section to serialize access to NwLogonNotifiedRdr flag. + // + NwLogonNotifiedRdr = FALSE; + + +} + + + +VOID +NwGetLogonCredential( + VOID + ) +/*++ + +Routine Description: + + This function reads the user and service logon IDs from the registry so + that it can get the credentials from LSA. + + It handles the case where the user has logged on before the workstation + is started. This function is called by the initialization thread + after opening up the RPC interface so that if user logon is happening + concurrently, the provider is given a chance to call the NwrLogonUser API + first, making it no longer necessary for the workstation to also + retrieve the credential from the registry. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + + DWORD status; + LONG RegError; + + HANDLE LsaHandle; + ULONG AuthPackageId; + + HKEY WkstaKey = NULL; + HKEY WkstaLogonKey = NULL; + HKEY WkstaOptionKey = NULL; + HKEY CurrentUserLogonKey = NULL; + HKEY CurrentUserOptionKey = NULL; + + LPWSTR PreferredServer = NULL; + LPWSTR CurrentUser = NULL; + LPWSTR UserName = NULL; + LPWSTR Password = NULL; + PLUID LogonId = NULL; + PDWORD PrintOption = NULL; + + + + EnterCriticalSection(&NwLoggedOnCritSec); + + if (NwLogonNotifiedRdr) { + // + // Logon credential's already made known to the redirector by + // the provider calling the NwrLogonUser API. + // +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("\nNWWORKSTATION: Redirector already has logon credential\n")); + } +#endif + LeaveCriticalSection(&NwLoggedOnCritSec); + return; + } + +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWWORKSTATION: Main init--NwGetLogonCredential\n")); + } +#endif + + status = NwpRegisterLogonProcess(&LsaHandle, &AuthPackageId); + + if (status != NO_ERROR) { + LeaveCriticalSection(&NwLoggedOnCritSec); + return; + } + + // + // Tell the redirector about service credentials + // + NwpGetServiceCredentials(LsaHandle, AuthPackageId); + + + // + // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + // \NWCWorkstation\Parameters + // + RegError = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_WORKSTATION_REGKEY, + REG_OPTION_NON_VOLATILE, // options + KEY_READ, // desired access + &WkstaKey + ); + + if (RegError != ERROR_SUCCESS) { + KdPrint(("NWWORKSTATION: NwGetLogonCredential: RegOpenKeyExW Parameter returns unexpected error %lu!!\n", RegError)); + goto CleanExit; + } + + // + // Read the current user SID string from the registry so we can + // read user information stored under the SID key. + // + status = NwReadRegValue( + WkstaKey, + NW_CURRENTUSER_VALUENAME, + &CurrentUser + ); + + if (status != NO_ERROR) { + goto CleanExit; + } + +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWWORKSTATION: Read the current user SID value %ws\n", CurrentUser)); + } +#endif + + // + // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + // \NWCWorkstation\Parameters\Logon + // + RegError = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_WORKSTATION_LOGON_REGKEY, + REG_OPTION_NON_VOLATILE, // options + KEY_READ, // desired access + &WkstaLogonKey + ); + + if (RegError != ERROR_SUCCESS) { + KdPrint(("NWWORKSTATION: NwGetLogonCredential: RegOpenKeyExW Parameter\\Logon returns unexpected error %lu!!\n", + RegError)); + goto CleanExit; + } + + // + // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + // \NWCWorkstation\Parameters\Option + // + RegError = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_WORKSTATION_OPTION_REGKEY, + REG_OPTION_NON_VOLATILE, // options + KEY_READ, // desired access + &WkstaOptionKey + ); + + if (RegError != ERROR_SUCCESS) { + KdPrint(("NWWORKSTATION: NwGetLogonCredential: RegOpenKeyExW Parameter\\Option returns unexpected error %lu!!\n", + RegError)); + goto CleanExit; + } + + // + // Open the <CurrentUser> key under Logon + // + RegError = RegOpenKeyExW( + WkstaLogonKey, + CurrentUser, + REG_OPTION_NON_VOLATILE, + KEY_READ, + &CurrentUserLogonKey + ); + + if (RegError != ERROR_SUCCESS) { + KdPrint(("NWWORKSTATION: NwGetLogonCredential: Open %ws key under Logon failed %lu\n", CurrentUser, RegError)); + goto CleanExit; + } + + // + // Open the <CurrentUser> key under Option + // + RegError = RegOpenKeyExW( + WkstaOptionKey, + CurrentUser, + REG_OPTION_NON_VOLATILE, + KEY_READ, + &CurrentUserOptionKey + ); + + if (RegError == NO_ERROR) { + + // + // Read the logon ID value. + // + status = NwReadRegValue( + CurrentUserLogonKey, + NW_LOGONID_VALUENAME, + (LPWSTR *) &LogonId + ); + + if (status != NO_ERROR) { + KdPrint(("NWWORKSTATION: NwGetLogonCredential: Could not read logon ID from reg %lu\n", + status)); + LogonId = NULL; + goto CleanExit; + } + + // + // Get the username and password from LSA + // + status = NwpGetCredentialInLsa( + LsaHandle, + AuthPackageId, + LogonId, + &UserName, + &Password + ); + + if (status != NO_ERROR) { + KdPrint(("NWWORKSTATION: NwGetLogonCredential: Could not get username & password from LSA %lu\n", + status)); + UserName = NULL; + goto CleanExit; + } + + // + // Read the preferred server value. + // + status = NwReadRegValue( + CurrentUserOptionKey, + NW_SERVER_VALUENAME, + &PreferredServer + ); + + if (status != NO_ERROR) { + +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWWORKSTATION: NwGetLogonCredential: Could not read preferred server from reg %lu\n", status)); + } +#endif + + PreferredServer = NULL; + } + + // + // Read the print option value. + // + status = NwReadRegValue( + CurrentUserOptionKey, + NW_PRINTOPTION_VALUENAME, + (LPWSTR *) &PrintOption + ); + if (status != NO_ERROR) { + +#if DBG + IF_DEBUG(LOGON) { + KdPrint(("NWWORKSTATION: NwGetLogonCredential: Could not read print option from reg %lu\n", status)); + } +#endif + NwPrintOption = NW_PRINT_OPTION_DEFAULT; + } else { + NwPrintOption = *PrintOption; + } + + } + else { + KdPrint(("NWWORKSTATION: NwGetLogonCredential: Open %ws key under Option failed %lu\n", CurrentUser, RegError)); + goto CleanExit; + } + + // + // Pass the interactive user credential to the redirector + // + (void) NwRdrLogonUser( + LogonId, + UserName, + wcslen(UserName) * sizeof(WCHAR), + Password, + wcslen(Password) * sizeof(WCHAR), + PreferredServer, + ((PreferredServer != NULL) ? + wcslen(PreferredServer) * sizeof(WCHAR) : + 0) + ); + + // + // NwGetLogonCredential is called after NwInitializeWkstaInfo. + // Hence, provider name and packet size is read already + // + (void) NwRdrSetInfo( + NwPrintOption, + NwPacketBurstSize, + PreferredServer, + ((PreferredServer != NULL) ? + wcslen(PreferredServer) * sizeof(WCHAR) : 0), + NwProviderName, + ((NwProviderName != NULL) ? + wcslen(NwProviderName) * sizeof(WCHAR) : 0 ) + ); + +CleanExit: + (void) LsaDeregisterLogonProcess(LsaHandle); + + if (UserName != NULL) { + // + // Freeing the UserName pointer frees both the + // username and password buffers. + // + (void) LsaFreeReturnBuffer((PVOID) UserName); + } + + if (LogonId != NULL) { + (void) LocalFree((HLOCAL) LogonId); + } + + if (PrintOption != NULL) { + (void) LocalFree((HLOCAL) PrintOption); + } + + if (PreferredServer != NULL) { + (void) LocalFree((HLOCAL) PreferredServer); + } + + if (CurrentUser != NULL) { + (void) LocalFree((HLOCAL) CurrentUser); + } + + + if ( WkstaLogonKey ) { + (void) RegCloseKey(WkstaLogonKey); + } + + if ( WkstaOptionKey ) { + (void) RegCloseKey(WkstaOptionKey); + } + + if ( CurrentUserLogonKey ) { + (void) RegCloseKey(CurrentUserLogonKey); + } + + if ( CurrentUserOptionKey ) { + (void) RegCloseKey(CurrentUserOptionKey); + } + + (void) RegCloseKey(WkstaKey); + + LeaveCriticalSection(&NwLoggedOnCritSec); +} + +STATIC +VOID +NwpGetServiceCredentials( + IN HANDLE LsaHandle, + IN ULONG AuthPackageId + ) +/*++ + +Routine Description: + + This function reads the service logon IDs from the registry + so that it can get the service credentials from LSA. It then + notifies the redirector of the service logons. + +Arguments: + + LsaHandle - Supplies the handle to LSA. + + AuthPackageId - Supplies the NetWare authentication package ID. + +Return Value: + + None. + +--*/ +{ + DWORD status; + LONG RegError; + + LPWSTR UserName = NULL; + LPWSTR Password = NULL; + + HKEY ServiceLogonKey; + DWORD Index = 0; + WCHAR LogonIdKey[NW_MAX_LOGON_ID_LEN]; + LUID LogonId; + + + RegError = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_SERVICE_LOGON_REGKEY, + REG_OPTION_NON_VOLATILE, + KEY_READ, + &ServiceLogonKey + ); + + if (RegError == ERROR_SUCCESS) { + + do { + + RegError = RegEnumKeyW( + ServiceLogonKey, + Index, + LogonIdKey, + sizeof(LogonIdKey) / sizeof(WCHAR) + ); + + if (RegError == ERROR_SUCCESS) { + + // + // Got a logon id key. + // + + NwWStrToLuid(LogonIdKey, &LogonId); + + status = NwpGetCredentialInLsa( + LsaHandle, + AuthPackageId, + &LogonId, + &UserName, + &Password + ); + + if (status == NO_ERROR) { + + (void) NwRdrLogonUser( + &LogonId, + UserName, + wcslen(UserName) * sizeof(WCHAR), + Password, + wcslen(Password) * sizeof(WCHAR), + NULL, + 0 + ); + + // + // Freeing the UserName pointer frees both the + // username and password buffers. + // + (void) LsaFreeReturnBuffer((PVOID) UserName); + + } + + } + else if (RegError != ERROR_NO_MORE_ITEMS) { + KdPrint(("NWWORKSTATION: NwpGetServiceCredentials failed to enum logon IDs RegError=%lu\n", + RegError)); + } + + Index++; + + } while (RegError == ERROR_SUCCESS); + } + + (void) RegCloseKey(ServiceLogonKey); +} + + +DWORD +NwGatewayLogon( + VOID + ) +/*++ + +Routine Description: + + This function reads the gateway logon credential from the registry, + LSA secret, and does the gateway logon. + +Arguments: + + None. + +Return Value: + + NO_ERROR or reason for failure. + +--*/ +{ + + DWORD status = NO_ERROR; + LONG RegError; + LUID LogonId = SYSTEM_LUID ; + DWORD GatewayEnabled, RegValueType, GatewayEnabledSize ; + + HKEY WkstaKey = NULL; + LPWSTR GatewayAccount = NULL; + + PUNICODE_STRING Password = NULL; + PUNICODE_STRING OldPassword = NULL; + + + // + // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + // \NWCWorkstation\Parameters + // + RegError = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + NW_WORKSTATION_REGKEY, + REG_OPTION_NON_VOLATILE, // options + KEY_READ, // desired access + &WkstaKey + ); + + if (RegError != ERROR_SUCCESS) { + return RegError; + } + + // + // Check to see if it is enabled + // + RegValueType = REG_DWORD ; + GatewayEnabled = 0 ; + GatewayEnabledSize = sizeof(GatewayEnabled) ; + RegError = RegQueryValueExW( + WkstaKey, + NW_GATEWAY_ENABLE, + NULL, + &RegValueType, + (LPBYTE)&GatewayEnabled, + &GatewayEnabledSize) ; + + if (status != NO_ERROR || GatewayEnabled == 0) { + goto CleanExit; + } + + + // + // Read the gateway account from the registry. + // + status = NwReadRegValue( + WkstaKey, + NW_GATEWAYACCOUNT_VALUENAME, + &GatewayAccount + ); + + if (status != NO_ERROR) { + goto CleanExit; + } + + // + // Read the password from its secret object in LSA. + // + status = NwGetPassword( + GATEWAY_USER, + &Password, // Must be freed with LsaFreeMemory + &OldPassword // Must be freed with LsaFreeMemory + ); + + if (status != NO_ERROR) { + goto CleanExit; + } + + EnterCriticalSection(&NwLoggedOnCritSec); + + status = NwRdrLogonUser( + &LogonId, + GatewayAccount, + ((GatewayAccount != NULL) ? + wcslen(GatewayAccount) * sizeof(WCHAR) : + 0), + Password->Buffer, + Password->Length, + NULL, + 0 ); + + if (status == NO_ERROR) + GatewayLoggedOn = TRUE ; + + LeaveCriticalSection(&NwLoggedOnCritSec); + + if (status != NO_ERROR) + { + // + // log the error in the event log + // + + WCHAR Number[16] ; + LPWSTR InsertStrings[1] ; + + wsprintfW(Number, L"%d", status) ; + InsertStrings[0] = Number ; + + NwLogEvent(EVENT_NWWKSTA_GATEWAY_LOGON_FAILED, + 1, + InsertStrings, + 0) ; + } + else + { + + // + // create the gateway redirections if any. not fatal if error. + // the function will log any errors to event log. + // + if (Password->Length) + { + LPWSTR Passwd = (LPWSTR) LocalAlloc(LPTR, + Password->Length + sizeof(WCHAR)) ; + if (Passwd) + { + wcsncpy(Passwd, + Password->Buffer, + Password->Length / sizeof(WCHAR)) ; + (void) NwCreateRedirections(GatewayAccount, + Passwd) ; + RtlZeroMemory((LPBYTE)Passwd, + Password->Length) ; + (void) LocalFree((HLOCAL)Passwd); + } + } + else + { + (void) NwCreateRedirections(GatewayAccount, + NULL) ; + } + } + + +CleanExit: + + if (Password != NULL) { + if (Password->Buffer) + RtlZeroMemory(Password->Buffer, Password->Length) ; + (void) LsaFreeMemory((PVOID) Password); + } + + if (OldPassword != NULL) { + if (OldPassword->Buffer) + RtlZeroMemory(OldPassword->Buffer, OldPassword->Length) ; + (void) LsaFreeMemory((PVOID) OldPassword); + } + + if (GatewayAccount != NULL) { + (void) LocalFree((HLOCAL) GatewayAccount); + } + + (void) RegCloseKey(WkstaKey); + return status ; +} + +DWORD +NwGatewayLogoff( + VOID + ) +/*++ + +Routine Description: + + This function logs off the gateway account. + +Arguments: + + None. + +Return Value: + + NO_ERROR or reason for failure. + +--*/ +{ + + DWORD status = NO_ERROR; + LUID LogonId = SYSTEM_LUID ; + + EnterCriticalSection(&NwLoggedOnCritSec); + + if (GatewayLoggedOn) + { + status = NwRdrLogoffUser(&LogonId); + + if (status == NO_ERROR) + GatewayLoggedOn = FALSE ; + } + + LeaveCriticalSection(&NwLoggedOnCritSec); + + return status ; + +} + +STATIC +DWORD +NwpRegisterLogonProcess( + OUT PHANDLE LsaHandle, + OUT PULONG AuthPackageId + ) +/*++ + +Routine Description: + + This function registers the workstation service as a logon process + so that it can call LSA to retrieve user credentials. + +Arguments: + + LsaHandle - Receives the handle to LSA. + + AuthPackageId - Receives the NetWare authentication package ID. + +Return Value: + + NO_ERROR or reason for failure. + +--*/ +{ + DWORD status = NO_ERROR; + NTSTATUS ntstatus; + STRING InputString; + LSA_OPERATIONAL_MODE SecurityMode = 0; + + // + // Register this process as a logon process so that we can call + // NetWare authentication package. + // + RtlInitString(&InputString, "Client Service for NetWare"); + + ntstatus = LsaRegisterLogonProcess( + &InputString, + LsaHandle, + &SecurityMode + ); + + if (! NT_SUCCESS(ntstatus)) { + KdPrint(("NWPROVAU: NwInitializeLogon: 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)); + + (void) LsaDeregisterLogonProcess(*LsaHandle); + } + + status = RtlNtStatusToDosError(ntstatus); + + return status; +} + +STATIC +DWORD +NwpGetCredentialInLsa( + IN HANDLE LsaHandle, + IN ULONG AuthPackageId, + IN PLUID LogonId, + OUT LPWSTR *UserName, + OUT LPWSTR *Password + ) +/*++ + +Routine Description: + + This function retrieves the username and password information + from LSA given the logon ID. + +Arguments: + + LsaHandle - Supplies the handle to LSA. + + AuthPackageId - Supplies the NetWare authentication package ID. + + LogonId - Supplies the logon ID. + + UserName - Receives a pointer to the username. + + Password - Receives a pointer to the password. + +Return Value: + + NO_ERROR or reason for failure. + +--*/ +{ + DWORD status; + NTSTATUS ntstatus; + NTSTATUS AuthPackageStatus; + + NWAUTH_GET_CREDENTIAL_REQUEST GetCredRequest; + PNWAUTH_GET_CREDENTIAL_RESPONSE GetCredResponse; + ULONG ResponseLength; + + UNICODE_STRING PasswordStr; + + // + // Ask authentication package for credential. + // + GetCredRequest.MessageType = NwAuth_GetCredential; + RtlCopyLuid(&GetCredRequest.LogonId, LogonId); + + ntstatus = LsaCallAuthenticationPackage( + LsaHandle, + AuthPackageId, + &GetCredRequest, + sizeof(GetCredRequest), + (PVOID *) &GetCredResponse, + &ResponseLength, + &AuthPackageStatus + ); + + if (NT_SUCCESS(ntstatus)) { + ntstatus = AuthPackageStatus; + } + if (! NT_SUCCESS(ntstatus)) { + KdPrint(("NWPROVAU: NwpGetCredentialInLsa: LsaCallAuthenticationPackage returns x%08lx\n", + ntstatus)); + status = RtlNtStatusToDosError(ntstatus); + } + else { + + *UserName = GetCredResponse->UserName; + *Password = GetCredResponse->Password; + + // + // Decode the password. + // + RtlInitUnicodeString(&PasswordStr, GetCredResponse->Password); + RtlRunDecodeUnicodeString(NW_ENCODE_SEED, &PasswordStr); + + status = NO_ERROR; + } + + return status; +} + +DWORD +NwrChangePassword( + IN LPWSTR Reserved OPTIONAL, + IN DWORD UserLuid, + IN LPWSTR UserName, + IN LPWSTR OldPassword, + IN LPWSTR NewPassword, + IN LPWSTR TreeName + ) +/*++ + +Routine Description: + + This function changes the password for the specified user on + the list of servers. If we encounter a failure on changing + password for a particular server, we: + + 1) Send the new password over to the server to verify if it is + already the current password. + + 2) If not, return ERROR_INVALID_PASSWORD and the index into + the Servers array indicating the server which failed so that + we can prompt the user to enter an alternate old password. + + When the password has been changed successfully on a server, we + notify the redirector so that the cached credential can be updated. + + NOTE: All errors returned from this routine, except for the fatal + ERROR_NOT_ENOUGH_MEMORY error, indicates that the password + could not be changed on a particular server indexed by + LastProcessed. The client-side continues to call us with + the remaining list of servers. + + If you add to this routine to return other fatal errors, + please make sure the client-side code aborts from calling + us with the rest of the servers on getting those errors. + +Arguments: + + Reserved - Must be NULL. + + +Return Value: + + ERROR_BAD_NETPATH - Could not connect to the server indexed by + LastProcessed. + + ERROR_BAD_USERNAME - The username could not be found on the server + indexed by LastProcessed. + + ERROR_INVALID_PASSWORD - The change password operation failed on + the server indexed by LastProcessed. + + ERROR_NOT_ENOUGH_MEMORY - Out of memory error. This fatal error + will terminate the client-side from trying to process password + change request on the remaining servers. + +--*/ +{ + DWORD status; + NTSTATUS ntstatus; + HANDLE hNwRdr = NULL; + UNICODE_STRING UserNameStr; + UNICODE_STRING OldPasswordStr; + UNICODE_STRING NewPasswordStr; + UNICODE_STRING TreeNameStr; + BOOL fImpersonateClient = FALSE; + + UNREFERENCED_PARAMETER( Reserved ) ; + UNREFERENCED_PARAMETER( UserLuid ) ; + + RtlInitUnicodeString( &UserNameStr, UserName ); + + RtlInitUnicodeString( &OldPasswordStr, OldPassword ); + RtlRunDecodeUnicodeString( NW_ENCODE_SEED2, &OldPasswordStr ); + + RtlInitUnicodeString( &NewPasswordStr, NewPassword ); + RtlRunDecodeUnicodeString( NW_ENCODE_SEED2, &NewPasswordStr ); + + RtlInitUnicodeString( &TreeNameStr, TreeName ); + + // + // Impersonate the client + // + if ((status = NwImpersonateClient()) != NO_ERROR) + { + goto ErrorExit; + } + + fImpersonateClient = TRUE; + + // + // Open a NDS tree connection handle to \\treename + // + ntstatus = NwNdsOpenTreeHandle( &TreeNameStr, &hNwRdr ); + + if ( ntstatus != STATUS_SUCCESS ) + { + status = RtlNtStatusToDosError(ntstatus); + goto ErrorExit; + } + + (void) NwRevertToSelf() ; + fImpersonateClient = FALSE; + + ntstatus = NwNdsChangePassword( hNwRdr, + &TreeNameStr, + &UserNameStr, + &OldPasswordStr, + &NewPasswordStr ); + + if ( ntstatus != NO_ERROR ) + { + status = RtlNtStatusToDosError(ntstatus); + goto ErrorExit; + } + + CloseHandle( hNwRdr ); + hNwRdr = NULL; + + return NO_ERROR ; + +ErrorExit: + + if ( fImpersonateClient ) + (void) NwRevertToSelf() ; + + if ( hNwRdr ) + CloseHandle( hNwRdr ); + + hNwRdr = NULL; + + return status; +} + |