|
|
/******************************************************************************
* * Copyright (c) 2000 Microsoft Corporation * * Module Name: * srpasswd.cpp * * Abstract: * password filter routines to restore user's latest passwords * * Revision History: * Henry Lee (henrylee) 06/27/2000 created * *****************************************************************************/
#include "stdwin.h"
#include <ntlsa.h>
#include <ntsam.h>
extern "C" { #include <ntsamp.h>
#include <recovery.h>
}
#include "rstrcore.h"
extern CSRClientLoader g_CSRClientLoader;
//+---------------------------------------------------------------------------
//
// Function: RegisterNotificationDLL
//
// Synopsis: registers/unregisters this DLL
//
// Arguments: [fRegister] -- TRUE to register, FALSE to unregister
// [hKeyLM] -- key for HKEY_LOCAL_MACHINE or System
//
// History: 12-Apr-2000 HenryLee Created
//
//----------------------------------------------------------------------------
DWORD RegisterNotificationDLL (HKEY hKeyLM, BOOL fRegister) { HKEY hKey = NULL; DWORD dwErr = ERROR_SUCCESS; ULONG ulType; ULONG ulSize = MAX_PATH * sizeof(WCHAR); WCHAR wcsBuffer[MAX_PATH]; WCHAR wcsFileName[MAX_PATH];
GetModuleFileNameW (g_hInst, wcsFileName, MAX_PATH); const ULONG ccFileName = lstrlenW (wcsFileName) + 1;
if (hKeyLM == HKEY_LOCAL_MACHINE) { lstrcpy (wcsBuffer, L"System\\CurrentControlSet\\Control\\Lsa"); } else { lstrcpy(wcsBuffer, L"CurrentControlSet\\Control\\Lsa"); ChangeCCS(hKeyLM, wcsBuffer); }
dwErr = RegOpenKeyExW (hKeyLM, wcsBuffer, 0, KEY_READ | KEY_WRITE, &hKey);
if (dwErr != ERROR_SUCCESS) goto Err;
dwErr = RegQueryValueEx (hKey, L"Notification Packages", 0, &ulType, (BYTE *) wcsBuffer, &ulSize);
if (dwErr != ERROR_SUCCESS) goto Err;
for (ULONG i=0; i < ulSize/sizeof(WCHAR); i += lstrlenW(&wcsBuffer[i])+1) { if (fRegister) // append at end
{ if (lstrcmpi (&wcsBuffer[i], wcsFileName) == 0) goto Err; // it's already registered
if (wcsBuffer[i] == L'\0') // end of list
{ lstrcpy (&wcsBuffer[i], wcsFileName); wcsBuffer[ i + ccFileName ] = L'\0'; // add double NULL
ulSize += ccFileName * sizeof(WCHAR); break; } } else // remove from the end
{ if (lstrcmpi (&wcsBuffer[i], wcsFileName) == 0) { wcsBuffer[i] = L'\0'; ulSize -= ccFileName * sizeof(WCHAR); break; } } }
dwErr = RegSetValueExW (hKey, L"Notification Packages", 0, ulType, (BYTE *) wcsBuffer, ulSize); Err: if (hKey != NULL) RegCloseKey (hKey);
return dwErr; }
//+---------------------------------------------------------------------------
//
// Function: GetDomainId
//
// Synopsis: stolen from setup, get the local domain ID
//
// Arguments: [ServerHandle] -- handle to the local SAM server
// [pDomainId] -- output domain ID
//
// History: 12-Apr-2000 HenryLee Created
//
//----------------------------------------------------------------------------
NTSTATUS GetDomainId (SAM_HANDLE ServerHandle, PSID * pDomainId ) { NTSTATUS status = STATUS_SUCCESS; SAM_ENUMERATE_HANDLE EnumContext; PSAM_RID_ENUMERATION EnumBuffer = NULL; DWORD CountReturned = 0; PSID LocalDomainId = NULL; DWORD LocalBuiltinDomainSid[sizeof(SID) / sizeof(DWORD) + SID_MAX_SUB_AUTHORITIES]; SID_IDENTIFIER_AUTHORITY BuiltinAuthority = SECURITY_NT_AUTHORITY; BOOL bExit = FALSE;
//
// Compute the builtin domain sid.
//
RtlInitializeSid((PSID) LocalBuiltinDomainSid, &BuiltinAuthority, 1); *(RtlSubAuthoritySid((PSID)LocalBuiltinDomainSid, 0)) = SECURITY_BUILTIN_DOMAIN_RID;
//
// Loop getting the list of domain ids from SAM
//
EnumContext = 0; do { //
// Get several domain names.
//
status = SamEnumerateDomainsInSamServer ( ServerHandle, &EnumContext, (PVOID *) &EnumBuffer, 8192, &CountReturned );
if (!NT_SUCCESS (status)) { goto exit; }
if (status != STATUS_MORE_ENTRIES) { bExit = TRUE; }
//
// Lookup the domain ids for the domains
//
for (ULONG i = 0; i < CountReturned; i++) { //
// Free the sid from the previous iteration.
//
if (LocalDomainId != NULL) { SamFreeMemory (LocalDomainId); LocalDomainId = NULL; }
//
// Lookup the domain id
//
status = SamLookupDomainInSamServer ( ServerHandle, &EnumBuffer[i].Name, &LocalDomainId );
if (!NT_SUCCESS (status)) { goto exit; }
if (RtlEqualSid ((PSID)LocalBuiltinDomainSid, LocalDomainId)) { continue; }
*pDomainId = LocalDomainId; LocalDomainId = NULL; status = STATUS_SUCCESS; goto exit; }
SamFreeMemory(EnumBuffer); EnumBuffer = NULL; } while (!bExit);
status = STATUS_NO_SUCH_DOMAIN;
exit: if (EnumBuffer != NULL) SamFreeMemory(EnumBuffer);
return status; }
//+---------------------------------------------------------------------------
//
// Function: ForAllUsers
//
// Synopsis: iterate password changing for all local users
//
// Arguments: [hSam] -- handle to open SAM hive
// [hSecurity] -- handle to open SECURITY hive
// [hSystem] -- handle to open SYSTEM hive
//
// History: 12-Apr-2000 HenryLee Created
//
//----------------------------------------------------------------------------
NTSTATUS ForAllUsers (HKEY hSam, HKEY hSecurity, HKEY hSystem) { NTSTATUS nts = STATUS_SUCCESS; NTSTATUS ntsEnum = STATUS_SUCCESS; BOOLEAN bPresent; BOOLEAN bNonNull; SAM_HANDLE ServerHandle = NULL; SAM_HANDLE DomainHandle = NULL; SAM_HANDLE UserHandle; SAM_ENUMERATE_HANDLE EnumerationContext = NULL; SAM_RID_ENUMERATION *SamRidEnumeration; ULONG CountOfEntries; ULONG UserRid; UNICODE_STRING us; PSID LocalDomainId = NULL; USER_INTERNAL1_INFORMATION UserPasswordInfo;
RtlInitUnicodeString (&us, L""); // this machine
nts = SamConnect (&us, &ServerHandle, SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN | SAM_SERVER_ENUMERATE_DOMAINS, NULL);
if (!NT_SUCCESS(nts)) goto Err;
nts = GetDomainId (ServerHandle, &LocalDomainId);
if (!NT_SUCCESS(nts)) goto Err;
nts = SamOpenDomain( ServerHandle, DOMAIN_READ | DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP | DOMAIN_READ_PASSWORD_PARAMETERS, LocalDomainId, &DomainHandle );
if (!NT_SUCCESS(nts)) goto Err; do { ntsEnum = nts = SamEnumerateUsersInDomain ( DomainHandle, &EnumerationContext, 0, (PVOID *) &SamRidEnumeration, 0, &CountOfEntries);
if (nts != STATUS_MORE_ENTRIES && !NT_SUCCESS(nts)) { goto Err; }
for (UINT i=0; i < CountOfEntries; i++) { ULONG UserRid = SamRidEnumeration[i].RelativeId;
nts = SamRetrieveOwfPasswordUser( UserRid, hSecurity, hSam, hSystem, NULL, /* boot key not supported */ 0, /* boot key not supported */ &UserPasswordInfo.NtOwfPassword, &bPresent, &bNonNull);
if (!NT_SUCCESS(nts)) continue; nts = SamOpenUser (DomainHandle, USER_READ_ACCOUNT | USER_WRITE_ACCOUNT | USER_CHANGE_PASSWORD | USER_FORCE_PASSWORD_CHANGE, UserRid, &UserHandle);
if (NT_SUCCESS(nts)) { UserPasswordInfo.NtPasswordPresent = bPresent; UserPasswordInfo.LmPasswordPresent = FALSE; UserPasswordInfo.PasswordExpired = FALSE;
nts = SamSetInformationUser(UserHandle, UserInternal1Information, &UserPasswordInfo);
SamCloseHandle (UserHandle); } }
SamFreeMemory (SamRidEnumeration); } while (ntsEnum == STATUS_MORE_ENTRIES);
Err: if (ServerHandle != NULL) SamCloseHandle (ServerHandle);
if (DomainHandle != NULL) SamCloseHandle (DomainHandle);
if (LocalDomainId != NULL) SamFreeMemory (LocalDomainId);
return nts; }
//+---------------------------------------------------------------------------
//
// Function: RestoreLsaSecrets
//
// Synopsis: restore machine account and autologon passwords
//
// Arguments:
//
// History: 12-Apr-2000 HenryLee Created
//
//----------------------------------------------------------------------------
DWORD RestoreLsaSecrets () { HKEY hKey = NULL; LSA_OBJECT_ATTRIBUTES loa; LSA_HANDLE hLsa = NULL; DWORD dwErr = ERROR_SUCCESS; ULONG ulSize = 0; ULONG ulType = 0; WCHAR wcsBuffer [MAX_PATH];
loa.Length = sizeof(LSA_OBJECT_ATTRIBUTES); loa.RootDirectory = NULL; loa.ObjectName = NULL; loa.Attributes = 0; loa.SecurityDescriptor = NULL; loa.SecurityQualityOfService = NULL;
if (LSA_SUCCESS (LsaOpenPolicy(NULL, &loa, POLICY_VIEW_LOCAL_INFORMATION, &hLsa))) { dwErr = RegOpenKeyExW (HKEY_LOCAL_MACHINE, s_cszSRRegKey, 0, KEY_READ | KEY_WRITE, &hKey);
if (dwErr != ERROR_SUCCESS) goto Err;
ulSize = MAX_PATH * sizeof(WCHAR); if (ERROR_SUCCESS == RegQueryValueEx (hKey, s_cszMachineSecret, 0, &ulType, (BYTE *) wcsBuffer, &ulSize)) { wcsBuffer [ulSize / 2] = L'\0'; dwErr = SetLsaSecret (hLsa, s_cszMachineSecret, wcsBuffer); if (ERROR_SUCCESS != dwErr) goto Err;
RegDeleteValueW (hKey, s_cszMachineSecret); }
ulSize = MAX_PATH * sizeof(WCHAR); if (ERROR_SUCCESS == RegQueryValueEx (hKey, s_cszAutologonSecret, 0, &ulType, (BYTE *) wcsBuffer, &ulSize)) { wcsBuffer [ulSize / 2] = L'\0'; dwErr = SetLsaSecret (hLsa, s_cszAutologonSecret, wcsBuffer); if (ERROR_SUCCESS != dwErr) goto Err;
RegDeleteValueW (hKey, s_cszAutologonSecret); } } Err: if (hKey != NULL) RegCloseKey (hKey);
return dwErr; }
//+---------------------------------------------------------------------------
//
// Function: RestoreRIDs
//
// Synopsis: restore next availble RID and password
//
// Arguments:
//
// History: 12-Apr-2000 HenryLee Created
//
//----------------------------------------------------------------------------
DWORD RestoreRIDs (WCHAR *pszSamPath) { HKEY hKeySam = NULL; DWORD dwErr = ERROR_SUCCESS; ULONG ulNextRid = 0; ULONG ulOldRid = 0;
TENTER("RestoreRIDs");
dwErr = RegLoadKeyW (HKEY_LOCAL_MACHINE, s_cszRestoreSAMHiveName, pszSamPath); if (dwErr != ERROR_SUCCESS) { trace(0, "! RegLoadKeyW : %ld", dwErr); goto Err; }
dwErr = RegOpenKeyW (HKEY_LOCAL_MACHINE, s_cszSamHiveName, &hKeySam); if (dwErr != ERROR_SUCCESS) { trace(0, "! RegOpenKeyW on %S: %ld", s_cszSamHiveName, dwErr); goto Err; }
dwErr = RtlNtStatusToDosError(SamGetNextAvailableRid (hKeySam, &ulNextRid)); if (dwErr != ERROR_SUCCESS) { trace(0, "! SamGetNextAvailableRid : %ld", dwErr); goto Err; }
RegCloseKey (hKeySam); hKeySam = NULL;
dwErr = RegOpenKeyW (HKEY_LOCAL_MACHINE, s_cszRestoreSAMHiveName, &hKeySam); if (dwErr != ERROR_SUCCESS) { trace(0, "! RegOpenKeyW on %S: %ld", s_cszRestoreSAMHiveName, dwErr); goto Err; }
// as an optimization we don't set the RID if it didn't change
if (NT_SUCCESS(SamGetNextAvailableRid (hKeySam, &ulOldRid)) && ulNextRid > ulOldRid) { dwErr = RtlNtStatusToDosError(SamSetNextAvailableRid (hKeySam, ulNextRid)); if (dwErr != ERROR_SUCCESS) { trace(0, "! SamSetNextAvailableRid : %ld", dwErr); } }
Err: if (hKeySam != NULL) { RegCloseKey (hKeySam); } RegUnLoadKeyW (HKEY_LOCAL_MACHINE, s_cszRestoreSAMHiveName);
TLEAVE(); return dwErr; }
DWORD RestorePasswords () { HKEY hKeySam = NULL, hKeySecurity = NULL, hKeySystem = NULL; DWORD dwErr = ERROR_SUCCESS; WCHAR wcsSystem [MAX_PATH]; WCHAR wcsPath [MAX_PATH]; BOOLEAN OldPriv; CRestorePoint rp; DWORD dwTemp;
InitAsyncTrace(); TENTER("RestorePasswords"); // Attempt to get restore privilege
dwErr = RtlNtStatusToDosError (RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &OldPriv));
if (dwErr != ERROR_SUCCESS) { trace(0, "! RtlAdjustPrivilege : %ld", dwErr); goto Err0; }
if (FALSE == GetSystemDrive (wcsSystem)) { dwErr = GetLastError(); trace(0, "! GetSystemDrive : %ld", dwErr); goto Err; }
dwErr = GetCurrentRestorePoint(rp); if (dwErr != ERROR_SUCCESS) { trace(0, "! GetCurrentRestorePoint : %ld", dwErr); goto Err; }
MakeRestorePath (wcsPath, wcsSystem, rp.GetDir()); lstrcatW (wcsPath, SNAPSHOT_DIR_NAME); lstrcatW (wcsPath, L"\\"); lstrcatW (wcsPath, s_cszHKLMFilePrefix); lstrcatW (wcsPath, s_cszSamHiveName);
dwErr = RegLoadKeyW (HKEY_LOCAL_MACHINE, s_cszRestoreSAMHiveName, wcsPath); if (dwErr != ERROR_SUCCESS) { trace(0, "! RegLoadKeyW on %S: %ld", s_cszRestoreSAMHiveName, dwErr); goto Err; }
dwErr = RegOpenKeyW (HKEY_LOCAL_MACHINE, s_cszRestoreSAMHiveName, &hKeySam); if (dwErr != ERROR_SUCCESS) { trace(0, "! RegOpenKeyW on %S: %ld", s_cszRestoreSAMHiveName, dwErr); goto Err; }
MakeRestorePath (wcsPath, wcsSystem, rp.GetDir()); lstrcatW (wcsPath, SNAPSHOT_DIR_NAME); lstrcatW (wcsPath, L"\\"); lstrcatW (wcsPath, s_cszHKLMFilePrefix); lstrcatW (wcsPath, s_cszSecurityHiveName);
dwErr = RegLoadKeyW (HKEY_LOCAL_MACHINE, s_cszRestoreSECURITYHiveName, wcsPath); if (dwErr != ERROR_SUCCESS) { trace(0, "! RegLoadKeyW on %S: %ld", s_cszRestoreSECURITYHiveName, dwErr); goto Err; } dwErr = RegOpenKeyW (HKEY_LOCAL_MACHINE, s_cszRestoreSECURITYHiveName,&hKeySecurity); if (dwErr != ERROR_SUCCESS) { trace(0, "! RegOpenKeyW on %S: %ld", s_cszRestoreSECURITYHiveName, dwErr); goto Err; }
MakeRestorePath (wcsPath, wcsSystem, rp.GetDir()); lstrcatW (wcsPath, SNAPSHOT_DIR_NAME); lstrcatW (wcsPath, L"\\"); lstrcatW (wcsPath, s_cszHKLMFilePrefix); lstrcatW (wcsPath, s_cszSystemHiveName);
dwErr = RegLoadKeyW (HKEY_LOCAL_MACHINE, s_cszRestoreSYSTEMHiveName, wcsPath); if (dwErr != ERROR_SUCCESS) { trace(0, "! RegLoadKeyW on %S: %ld", s_cszRestoreSYSTEMHiveName, dwErr); goto Err; }
dwErr = RegOpenKeyW (HKEY_LOCAL_MACHINE, s_cszRestoreSYSTEMHiveName, &hKeySystem); if (dwErr != ERROR_SUCCESS) { trace(0, "! RegOpenKeyW on %S: %ld", s_cszRestoreSYSTEMHiveName, dwErr); goto Err; }
dwErr = RtlNtStatusToDosError(ForAllUsers(hKeySam,hKeySecurity,hKeySystem)); if (dwErr != ERROR_SUCCESS) { trace(0, "! ForAllUsers : %ld", dwErr); goto Err; }
dwErr = RestoreLsaSecrets (); if (dwErr != ERROR_SUCCESS) { trace(0, "! RestoreLsaSecrets : %ld", dwErr); }
Err: if (hKeySam != NULL) { RegCloseKey (hKeySam); }
dwTemp = RegUnLoadKeyW (HKEY_LOCAL_MACHINE, s_cszRestoreSAMHiveName); if (ERROR_SUCCESS != dwTemp) { trace(0, "! RegUnLoadKeyW 0n %S : %ld", s_cszRestoreSAMHiveName, dwTemp); } if (hKeySecurity != NULL) { RegCloseKey (hKeySecurity); } dwTemp = RegUnLoadKeyW (HKEY_LOCAL_MACHINE, s_cszRestoreSECURITYHiveName); if (ERROR_SUCCESS != dwTemp) { trace(0, "! RegUnLoadKeyW 0n %S : %ld", s_cszRestoreSECURITYHiveName, dwTemp); } if (hKeySystem != NULL) { RegCloseKey (hKeySystem); } dwTemp = RegUnLoadKeyW (HKEY_LOCAL_MACHINE, s_cszRestoreSYSTEMHiveName); if (ERROR_SUCCESS != dwTemp) { trace(0, "! RegUnLoadKeyW 0n %S : %ld", s_cszRestoreSYSTEMHiveName, dwTemp); } // restore the old privilege
RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, OldPriv, FALSE, &OldPriv);
Err0: // unregister this notification package
RegisterNotificationDLL (HKEY_LOCAL_MACHINE, FALSE);
TermAsyncTrace(); return dwErr; }
//+---------------------------------------------------------------------------
//
// Function: WaitForSAM
//
// Synopsis: waits for SAM database to initialize
//
// Arguments:
//
// History: 12-Apr-2000 HenryLee Created
//
//----------------------------------------------------------------------------
DWORD WINAPI WaitForSAM (VOID *pv) { NTSTATUS nts = STATUS_SUCCESS; DWORD dwErr = ERROR_SUCCESS; DWORD WaitStatus; UNICODE_STRING EventName; HANDLE EventHandle; OBJECT_ATTRIBUTES EventAttributes;
// Load SRClient
g_CSRClientLoader.LoadSrClient(); //
// open SAM event
//
RtlInitUnicodeString( &EventName, L"\\SAM_SERVICE_STARTED"); InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
nts = NtOpenEvent( &EventHandle, SYNCHRONIZE|EVENT_MODIFY_STATE, &EventAttributes );
if ( !NT_SUCCESS(nts)) { if( nts == STATUS_OBJECT_NAME_NOT_FOUND ) { //
// SAM hasn't created this event yet, let us create it now.
// SAM opens this event to set it.
//
nts = NtCreateEvent( &EventHandle, SYNCHRONIZE|EVENT_MODIFY_STATE, &EventAttributes, NotificationEvent, FALSE ); // The event is initially not signaled
if( nts == STATUS_OBJECT_NAME_EXISTS || nts == STATUS_OBJECT_NAME_COLLISION ) { //
// second chance, if the SAM created the event before we did
//
nts = NtOpenEvent( &EventHandle, SYNCHRONIZE|EVENT_MODIFY_STATE, &EventAttributes ); } }
} //
// Loop waiting.
//
if (NT_SUCCESS(nts)) { WaitStatus = WaitForSingleObject( EventHandle, 60*1000 ); // 60 Seconds
if ( WaitStatus == WAIT_TIMEOUT ) { nts = STATUS_TIMEOUT; } else if ( WaitStatus != WAIT_OBJECT_0 ) { nts = STATUS_UNSUCCESSFUL; } }
(VOID) NtClose( EventHandle );
if (NT_SUCCESS(nts)) // Okay, SAM is available
{ dwErr = RestorePasswords(); } else { dwErr = RtlNtStatusToDosError (nts); }
return dwErr; }
//+---------------------------------------------------------------------------
//
// Function: InitializeChangeNotify and PasswordChangeNotify
//
// Synopsis: callback functions from SAM
//
// Arguments:
//
// History: 12-Apr-2000 HenryLee Created
//
//----------------------------------------------------------------------------
BOOLEAN NTAPI InitializeChangeNotify () { // we will call LoadSRClient from WaitForSAM
HANDLE hThread = CreateThread (NULL, 0, WaitForSAM, NULL, 0, NULL); return TRUE; }
NTSTATUS NTAPI PasswordChangeNotify ( PUNICODE_STRING UserName, ULONG RelativeId, PUNICODE_STRING NewPassword ) { return STATUS_SUCCESS; }
|