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.
 
 
 
 
 
 

589 lines
14 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
dpapi.cpp
Abstract:
This module contains the DPAPI initialization routines, called by the LSA
Author:
Pete Skelly (petesk) 22-Mar-00
--*/
#include <pch.cpp>
#pragma hdrstop
#include "pasrec.h"
CCryptProvList* g_pCProvList = NULL;
TOKEN_SOURCE DPAPITokenSource;
PLSA_SECPKG_FUNCTION_TABLE g_pSecpkgTable;
#ifdef RETAIL_LOG_SUPPORT
HANDLE g_hParamEvent = NULL;
HKEY g_hKeyParams = NULL;
HANDLE g_hWait = NULL;
DEFINE_DEBUG2(DPAPI);
DEBUG_KEY DPAPIDebugKeys[] = {
{DEB_ERROR, "Error"},
{DEB_WARN, "Warn"},
{DEB_TRACE, "Trace"},
{DEB_TRACE_API, "API"},
{DEB_TRACE_CRED, "Cred"},
{DEB_TRACE_CTXT, "Ctxt"},
{DEB_TRACE_LSESS, "LSess"},
{DEB_TRACE_LOGON, "Logon"},
{DEB_TRACE_TIME, "Time"},
{DEB_TRACE_LOCKS, "Locks"},
{DEB_TRACE_LEAKS, "Leaks"},
{0, NULL},
};
VOID
DPAPIWatchParamKey(
PVOID pCtxt,
BOOLEAN fWaitStatus);
VOID
DPAPIInitializeDebugging(
BOOL fMonitorRegistry)
{
DPAPIInitDebug(DPAPIDebugKeys);
if(fMonitorRegistry)
{
g_hParamEvent = CreateEvent(NULL,
FALSE,
FALSE,
NULL);
if (NULL == g_hParamEvent)
{
D_DebugLog((DEB_WARN, "CreateEvent for ParamEvent failed - 0x%x\n", GetLastError()));
}
else
{
DPAPIWatchParamKey(g_hParamEvent, FALSE);
}
}
}
////////////////////////////////////////////////////////////////////
//
// Name: DPAPIGetRegParams
//
// Synopsis: Gets the debug paramaters from the registry
//
// Arguments: HKEY to HKLM/System/CCS/LSA/DPAPI
//
// Notes: Sets DPAPIInfolevel for debug spew
//
void
DPAPIGetRegParams(HKEY ParamKey)
{
DWORD cbType, tmpInfoLevel = DPAPIInfoLevel, cbSize = sizeof(DWORD);
DWORD dwErr;
dwErr = RegQueryValueExW(
ParamKey,
WSZ_DPAPIDEBUGLEVEL,
NULL,
&cbType,
(LPBYTE)&tmpInfoLevel,
&cbSize
);
if (dwErr != ERROR_SUCCESS)
{
if (dwErr == ERROR_FILE_NOT_FOUND)
{
// no registry value is present, don't want info
// so reset to defaults
#if DBG
DPAPIInfoLevel = DEB_ERROR;
#else // fre
DPAPIInfoLevel = 0;
#endif
}
else
{
D_DebugLog((DEB_WARN, "Failed to query DebugLevel: 0x%x\n", dwErr));
}
}
// TBD: Validate flags?
DPAPIInfoLevel = tmpInfoLevel;
dwErr = RegQueryValueExW(
ParamKey,
WSZ_FILELOG,
NULL,
&cbType,
(LPBYTE)&tmpInfoLevel,
&cbSize
);
if (dwErr == ERROR_SUCCESS)
{
DPAPISetLoggingOption((BOOL)tmpInfoLevel);
}
else if (dwErr == ERROR_FILE_NOT_FOUND)
{
DPAPISetLoggingOption(FALSE);
}
return;
}
////////////////////////////////////////////////////////////////////
//
// Name: DPAPIWaitCleanup
//
// Synopsis: Cleans up wait from DPAPIWatchParamKey()
//
// Arguments: <none>
//
// Notes: .
//
void
DPAPIWaitCleanup()
{
NTSTATUS Status = STATUS_SUCCESS;
if (NULL != g_hWait)
{
Status = RtlDeregisterWait(g_hWait);
if (NT_SUCCESS(Status) && NULL != g_hParamEvent )
{
CloseHandle(g_hParamEvent);
}
}
}
////////////////////////////////////////////////////////////////////
//
// Name: DPAPIWatchParamKey
//
// Synopsis: Sets RegNotifyChangeKeyValue() on param key, initializes
// debug level, then utilizes thread pool to wait on
// changes to this registry key. Enables dynamic debug
// level changes, as this function will also be callback
// if registry key modified.
//
// Arguments: pCtxt is actually a HANDLE to an event. This event
// will be triggered when key is modified.
//
// Notes: .
//
VOID
DPAPIWatchParamKey(
PVOID pCtxt,
BOOLEAN fWaitStatus)
{
NTSTATUS Status;
LONG lRes = ERROR_SUCCESS;
if (NULL == g_hKeyParams) // first time we've been called.
{
lRes = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
DPAPI_PARAMETER_PATH,
0,
KEY_READ,
&g_hKeyParams);
if (ERROR_SUCCESS != lRes)
{
D_DebugLog((DEB_WARN,"Failed to open DPAPI key: 0x%x\n", lRes));
goto Reregister;
}
}
if (NULL != g_hWait)
{
Status = RtlDeregisterWait(g_hWait);
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_WARN, "Failed to Deregister wait on registry key: 0x%x\n", Status));
goto Reregister;
}
}
lRes = RegNotifyChangeKeyValue(
g_hKeyParams,
FALSE,
REG_NOTIFY_CHANGE_LAST_SET,
(HANDLE) pCtxt,
TRUE);
if (ERROR_SUCCESS != lRes)
{
D_DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", lRes));
// we're tanked now. No further notifications, so get this one
}
DPAPIGetRegParams(g_hKeyParams);
Reregister:
Status = RtlRegisterWait(&g_hWait,
(HANDLE) pCtxt,
DPAPIWatchParamKey,
(HANDLE) pCtxt,
INFINITE,
WT_EXECUTEINPERSISTENTIOTHREAD|
WT_EXECUTEONLYONCE);
}
#endif // RETAIL_LOG_SUPPORT
RPC_STATUS
RPC_ENTRY
ProtectCallback(
RPC_IF_HANDLE idIF,
PVOID pCtx)
{
RPC_STATUS Status;
PWSTR pBinding = NULL;
PWSTR pProtSeq = NULL;
Status = RpcBindingToStringBinding(pCtx, &pBinding);
if(Status != RPC_S_OK)
{
goto cleanup;
}
Status = RpcStringBindingParse(pBinding,
NULL,
&pProtSeq,
NULL,
NULL,
NULL);
if(Status != RPC_S_OK)
{
goto cleanup;
}
// Make sure caller is using local RPC
if(CompareString(LOCALE_INVARIANT,
NORM_IGNORECASE,
pProtSeq,
-1,
DPAPI_LOCAL_PROT_SEQ,
-1) != CSTR_EQUAL)
{
Status = ERROR_ACCESS_DENIED;
goto cleanup;
}
Status = RPC_S_OK;
cleanup:
if(pProtSeq)
{
RpcStringFree(&pProtSeq);
}
if(pBinding)
{
RpcStringFree(&pBinding);
}
return Status;
}
//
// FUNCTION: DPAPIInitialize
//
// COMMENTS:
//
DWORD
NTAPI
DPAPIInitialize(
LSA_SECPKG_FUNCTION_TABLE *pSecpkgTable)
{
DWORD dwLastError = ERROR_SUCCESS;
BOOL fStartedKeyService = FALSE;
BOOL bListConstruct = FALSE;
LONG lRes = ERROR_SUCCESS;
RPC_STATUS status;
dwLastError = RtlInitializeCriticalSection(&g_csCredHistoryCache);
if(!NT_SUCCESS(dwLastError))
{
goto cleanup;
}
DPAPIInitializeDebugging(TRUE);
// Initialize stuff necessary to create tokens etc, just as if
// we're a security package.
g_pSecpkgTable = pSecpkgTable;
CopyMemory( DPAPITokenSource.SourceName, DPAPI_PACKAGE_NAME_A, strlen(DPAPI_PACKAGE_NAME_A) );
AllocateLocallyUniqueId( &DPAPITokenSource.SourceIdentifier );
g_pCProvList = new CCryptProvList;
if(g_pCProvList)
{
if(!g_pCProvList->Initialize())
{
delete g_pCProvList;
g_pCProvList = NULL;
}
}
IntializeGlobals();
if(!InitializeKeyManagement())
{
dwLastError = STATUS_NO_MEMORY;
goto cleanup;
}
status = RpcServerUseProtseqEpW(DPAPI_LOCAL_PROT_SEQ, //ncalrpc
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
DPAPI_LOCAL_ENDPOINT, //protected_storage
NULL); //Security Descriptor
if(RPC_S_DUPLICATE_ENDPOINT == status)
{
status = RPC_S_OK;
}
if (status)
{
dwLastError = status;
goto cleanup;
}
status = RpcServerUseProtseqEpW(DPAPI_BACKUP_PROT_SEQ, //ncacn_np
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
DPAPI_BACKUP_ENDPOINT, //protected_storage
NULL); //Security Descriptor
if(RPC_S_DUPLICATE_ENDPOINT == status)
{
status = RPC_S_OK;
}
if (status)
{
dwLastError = status;
goto cleanup;
}
status = RpcServerRegisterIfEx(s_ICryptProtect_v1_0_s_ifspec,
NULL,
NULL,
RPC_IF_AUTOLISTEN,
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
ProtectCallback);
if (status)
{
dwLastError = status;
goto cleanup;
}
status = RpcServerRegisterIfEx(s_PasswordRecovery_v1_0_s_ifspec,
NULL,
NULL,
RPC_IF_AUTOLISTEN,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
ProtectCallback);
if (status)
{
dwLastError = status;
goto cleanup;
}
//
// Start the Backup Key server
// note: it only starts when the current machine is an domain controller.
//
dwLastError = StartBackupKeyServer();
if(dwLastError != ERROR_SUCCESS) {
goto cleanup;
}
return dwLastError;
cleanup:
DPAPIShutdown();
return dwLastError;
}
DWORD
NTAPI
DPAPIShutdown( )
{
//
// ignore errors because we are shutting down
//
(void)RpcServerUnregisterIf(s_ICryptProtect_v1_0_s_ifspec, 0, 0);
//
// stop backup key server
// Note: this function knows internally whether the backup key server
// really started or not.
//
StopBackupKeyServer();
if(g_pCProvList)
{
delete g_pCProvList;
g_pCProvList = NULL;
}
TeardownKeyManagement();
ShutdownGlobals();
return ERROR_SUCCESS;
}
#ifdef RETAIL_LOG_SUPPORT
VOID
DPAPIDumpHexData(
DWORD LogLevel,
PSTR pszPrefix,
PBYTE pbData,
DWORD cbData)
{
DWORD i,count;
CHAR digits[]="0123456789abcdef";
CHAR pbLine[MAX_PATH];
DWORD cbLine;
DWORD cbHeader;
DWORD_PTR address;
if((DPAPIInfoLevel & LogLevel) == 0)
{
return;
}
if(pbData == NULL || cbData == 0)
{
return;
}
if(pszPrefix)
{
strcpy(pbLine, pszPrefix);
cbHeader = strlen(pszPrefix);
}
else
{
pbLine[0] = '\0';
cbHeader = 0;
}
for(; cbData ; cbData -= count, pbData += count)
{
count = (cbData > 16) ? 16:cbData;
cbLine = cbHeader;
address = (DWORD_PTR)pbData;
#if defined(_WIN64)
pbLine[cbLine++] = digits[(address >> 0x3c) & 0x0f];
pbLine[cbLine++] = digits[(address >> 0x38) & 0x0f];
pbLine[cbLine++] = digits[(address >> 0x34) & 0x0f];
pbLine[cbLine++] = digits[(address >> 0x30) & 0x0f];
pbLine[cbLine++] = digits[(address >> 0x2c) & 0x0f];
pbLine[cbLine++] = digits[(address >> 0x28) & 0x0f];
pbLine[cbLine++] = digits[(address >> 0x24) & 0x0f];
pbLine[cbLine++] = digits[(address >> 0x20) & 0x0f];
#endif
pbLine[cbLine++] = digits[(address >> 0x1c) & 0x0f];
pbLine[cbLine++] = digits[(address >> 0x18) & 0x0f];
pbLine[cbLine++] = digits[(address >> 0x14) & 0x0f];
pbLine[cbLine++] = digits[(address >> 0x10) & 0x0f];
pbLine[cbLine++] = digits[(address >> 0x0c) & 0x0f];
pbLine[cbLine++] = digits[(address >> 0x08) & 0x0f];
pbLine[cbLine++] = digits[(address >> 0x04) & 0x0f];
pbLine[cbLine++] = digits[(address ) & 0x0f];
pbLine[cbLine++] = ' ';
pbLine[cbLine++] = ' ';
for(i = 0; i < count; i++)
{
pbLine[cbLine++] = digits[pbData[i]>>4];
pbLine[cbLine++] = digits[pbData[i]&0x0f];
if(i == 7)
{
pbLine[cbLine++] = ':';
}
else
{
pbLine[cbLine++] = ' ';
}
}
for(; i < 16; i++)
{
pbLine[cbLine++] = ' ';
pbLine[cbLine++] = ' ';
pbLine[cbLine++] = ' ';
}
pbLine[cbLine++] = ' ';
for(i = 0; i < count; i++)
{
//
// 37 is for %
//
if(pbData[i] < 32 || pbData[i] > 126 || pbData[i] == 37)
{
pbLine[cbLine++] = '.';
}
else
{
pbLine[cbLine++] = pbData[i];
}
}
pbLine[cbLine++] = '\n';
pbLine[cbLine++] = 0;
D_DebugLog((LogLevel, pbLine));
}
}
#endif