Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

774 lines
22 KiB

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