/*++ 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 #include #include #include #include #include //-------------------------------------------------------------------// // // // 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 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 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; }