|
|
/*++
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
|