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

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. dpapi.cpp
  5. Abstract:
  6. This module contains the DPAPI initialization routines, called by the LSA
  7. Author:
  8. Pete Skelly (petesk) 22-Mar-00
  9. --*/
  10. #include <pch.cpp>
  11. #pragma hdrstop
  12. #include "pasrec.h"
  13. CCryptProvList* g_pCProvList = NULL;
  14. TOKEN_SOURCE DPAPITokenSource;
  15. PLSA_SECPKG_FUNCTION_TABLE g_pSecpkgTable;
  16. #ifdef RETAIL_LOG_SUPPORT
  17. HANDLE g_hParamEvent = NULL;
  18. HKEY g_hKeyParams = NULL;
  19. HANDLE g_hWait = NULL;
  20. DEFINE_DEBUG2(DPAPI);
  21. DEBUG_KEY DPAPIDebugKeys[] = {
  22. {DEB_ERROR, "Error"},
  23. {DEB_WARN, "Warn"},
  24. {DEB_TRACE, "Trace"},
  25. {DEB_TRACE_API, "API"},
  26. {DEB_TRACE_CRED, "Cred"},
  27. {DEB_TRACE_CTXT, "Ctxt"},
  28. {DEB_TRACE_LSESS, "LSess"},
  29. {DEB_TRACE_LOGON, "Logon"},
  30. {DEB_TRACE_TIME, "Time"},
  31. {DEB_TRACE_LOCKS, "Locks"},
  32. {DEB_TRACE_LEAKS, "Leaks"},
  33. {0, NULL},
  34. };
  35. VOID
  36. DPAPIWatchParamKey(
  37. PVOID pCtxt,
  38. BOOLEAN fWaitStatus);
  39. VOID
  40. DPAPIInitializeDebugging(
  41. BOOL fMonitorRegistry)
  42. {
  43. DPAPIInitDebug(DPAPIDebugKeys);
  44. if(fMonitorRegistry)
  45. {
  46. g_hParamEvent = CreateEvent(NULL,
  47. FALSE,
  48. FALSE,
  49. NULL);
  50. if (NULL == g_hParamEvent)
  51. {
  52. D_DebugLog((DEB_WARN, "CreateEvent for ParamEvent failed - 0x%x\n", GetLastError()));
  53. }
  54. else
  55. {
  56. DPAPIWatchParamKey(g_hParamEvent, FALSE);
  57. }
  58. }
  59. }
  60. ////////////////////////////////////////////////////////////////////
  61. //
  62. // Name: DPAPIGetRegParams
  63. //
  64. // Synopsis: Gets the debug paramaters from the registry
  65. //
  66. // Arguments: HKEY to HKLM/System/CCS/LSA/DPAPI
  67. //
  68. // Notes: Sets DPAPIInfolevel for debug spew
  69. //
  70. void
  71. DPAPIGetRegParams(HKEY ParamKey)
  72. {
  73. DWORD cbType, tmpInfoLevel = DPAPIInfoLevel, cbSize = sizeof(DWORD);
  74. DWORD dwErr;
  75. dwErr = RegQueryValueExW(
  76. ParamKey,
  77. WSZ_DPAPIDEBUGLEVEL,
  78. NULL,
  79. &cbType,
  80. (LPBYTE)&tmpInfoLevel,
  81. &cbSize
  82. );
  83. if (dwErr != ERROR_SUCCESS)
  84. {
  85. if (dwErr == ERROR_FILE_NOT_FOUND)
  86. {
  87. // no registry value is present, don't want info
  88. // so reset to defaults
  89. #if DBG
  90. DPAPIInfoLevel = DEB_ERROR;
  91. #else // fre
  92. DPAPIInfoLevel = 0;
  93. #endif
  94. }
  95. else
  96. {
  97. D_DebugLog((DEB_WARN, "Failed to query DebugLevel: 0x%x\n", dwErr));
  98. }
  99. }
  100. // TBD: Validate flags?
  101. DPAPIInfoLevel = tmpInfoLevel;
  102. dwErr = RegQueryValueExW(
  103. ParamKey,
  104. WSZ_FILELOG,
  105. NULL,
  106. &cbType,
  107. (LPBYTE)&tmpInfoLevel,
  108. &cbSize
  109. );
  110. if (dwErr == ERROR_SUCCESS)
  111. {
  112. DPAPISetLoggingOption((BOOL)tmpInfoLevel);
  113. }
  114. else if (dwErr == ERROR_FILE_NOT_FOUND)
  115. {
  116. DPAPISetLoggingOption(FALSE);
  117. }
  118. return;
  119. }
  120. ////////////////////////////////////////////////////////////////////
  121. //
  122. // Name: DPAPIWaitCleanup
  123. //
  124. // Synopsis: Cleans up wait from DPAPIWatchParamKey()
  125. //
  126. // Arguments: <none>
  127. //
  128. // Notes: .
  129. //
  130. void
  131. DPAPIWaitCleanup()
  132. {
  133. NTSTATUS Status = STATUS_SUCCESS;
  134. if (NULL != g_hWait)
  135. {
  136. Status = RtlDeregisterWait(g_hWait);
  137. if (NT_SUCCESS(Status) && NULL != g_hParamEvent )
  138. {
  139. CloseHandle(g_hParamEvent);
  140. }
  141. }
  142. }
  143. ////////////////////////////////////////////////////////////////////
  144. //
  145. // Name: DPAPIWatchParamKey
  146. //
  147. // Synopsis: Sets RegNotifyChangeKeyValue() on param key, initializes
  148. // debug level, then utilizes thread pool to wait on
  149. // changes to this registry key. Enables dynamic debug
  150. // level changes, as this function will also be callback
  151. // if registry key modified.
  152. //
  153. // Arguments: pCtxt is actually a HANDLE to an event. This event
  154. // will be triggered when key is modified.
  155. //
  156. // Notes: .
  157. //
  158. VOID
  159. DPAPIWatchParamKey(
  160. PVOID pCtxt,
  161. BOOLEAN fWaitStatus)
  162. {
  163. NTSTATUS Status;
  164. LONG lRes = ERROR_SUCCESS;
  165. if (NULL == g_hKeyParams) // first time we've been called.
  166. {
  167. lRes = RegOpenKeyExW(
  168. HKEY_LOCAL_MACHINE,
  169. DPAPI_PARAMETER_PATH,
  170. 0,
  171. KEY_READ,
  172. &g_hKeyParams);
  173. if (ERROR_SUCCESS != lRes)
  174. {
  175. D_DebugLog((DEB_WARN,"Failed to open DPAPI key: 0x%x\n", lRes));
  176. goto Reregister;
  177. }
  178. }
  179. if (NULL != g_hWait)
  180. {
  181. Status = RtlDeregisterWait(g_hWait);
  182. if (!NT_SUCCESS(Status))
  183. {
  184. D_DebugLog((DEB_WARN, "Failed to Deregister wait on registry key: 0x%x\n", Status));
  185. goto Reregister;
  186. }
  187. }
  188. lRes = RegNotifyChangeKeyValue(
  189. g_hKeyParams,
  190. FALSE,
  191. REG_NOTIFY_CHANGE_LAST_SET,
  192. (HANDLE) pCtxt,
  193. TRUE);
  194. if (ERROR_SUCCESS != lRes)
  195. {
  196. D_DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", lRes));
  197. // we're tanked now. No further notifications, so get this one
  198. }
  199. DPAPIGetRegParams(g_hKeyParams);
  200. Reregister:
  201. Status = RtlRegisterWait(&g_hWait,
  202. (HANDLE) pCtxt,
  203. DPAPIWatchParamKey,
  204. (HANDLE) pCtxt,
  205. INFINITE,
  206. WT_EXECUTEINPERSISTENTIOTHREAD|
  207. WT_EXECUTEONLYONCE);
  208. }
  209. #endif // RETAIL_LOG_SUPPORT
  210. RPC_STATUS
  211. RPC_ENTRY
  212. ProtectCallback(
  213. RPC_IF_HANDLE idIF,
  214. PVOID pCtx)
  215. {
  216. RPC_STATUS Status;
  217. PWSTR pBinding = NULL;
  218. PWSTR pProtSeq = NULL;
  219. Status = RpcBindingToStringBinding(pCtx, &pBinding);
  220. if(Status != RPC_S_OK)
  221. {
  222. goto cleanup;
  223. }
  224. Status = RpcStringBindingParse(pBinding,
  225. NULL,
  226. &pProtSeq,
  227. NULL,
  228. NULL,
  229. NULL);
  230. if(Status != RPC_S_OK)
  231. {
  232. goto cleanup;
  233. }
  234. // Make sure caller is using local RPC
  235. if(CompareString(LOCALE_INVARIANT,
  236. NORM_IGNORECASE,
  237. pProtSeq,
  238. -1,
  239. DPAPI_LOCAL_PROT_SEQ,
  240. -1) != CSTR_EQUAL)
  241. {
  242. Status = ERROR_ACCESS_DENIED;
  243. goto cleanup;
  244. }
  245. Status = RPC_S_OK;
  246. cleanup:
  247. if(pProtSeq)
  248. {
  249. RpcStringFree(&pProtSeq);
  250. }
  251. if(pBinding)
  252. {
  253. RpcStringFree(&pBinding);
  254. }
  255. return Status;
  256. }
  257. //
  258. // FUNCTION: DPAPIInitialize
  259. //
  260. // COMMENTS:
  261. //
  262. DWORD
  263. NTAPI
  264. DPAPIInitialize(
  265. LSA_SECPKG_FUNCTION_TABLE *pSecpkgTable)
  266. {
  267. DWORD dwLastError = ERROR_SUCCESS;
  268. BOOL fStartedKeyService = FALSE;
  269. BOOL bListConstruct = FALSE;
  270. LONG lRes = ERROR_SUCCESS;
  271. RPC_STATUS status;
  272. dwLastError = RtlInitializeCriticalSection(&g_csCredHistoryCache);
  273. if(!NT_SUCCESS(dwLastError))
  274. {
  275. goto cleanup;
  276. }
  277. DPAPIInitializeDebugging(TRUE);
  278. // Initialize stuff necessary to create tokens etc, just as if
  279. // we're a security package.
  280. g_pSecpkgTable = pSecpkgTable;
  281. CopyMemory( DPAPITokenSource.SourceName, DPAPI_PACKAGE_NAME_A, strlen(DPAPI_PACKAGE_NAME_A) );
  282. AllocateLocallyUniqueId( &DPAPITokenSource.SourceIdentifier );
  283. g_pCProvList = new CCryptProvList;
  284. if(g_pCProvList)
  285. {
  286. if(!g_pCProvList->Initialize())
  287. {
  288. delete g_pCProvList;
  289. g_pCProvList = NULL;
  290. }
  291. }
  292. IntializeGlobals();
  293. if(!InitializeKeyManagement())
  294. {
  295. dwLastError = STATUS_NO_MEMORY;
  296. goto cleanup;
  297. }
  298. status = RpcServerUseProtseqEpW(DPAPI_LOCAL_PROT_SEQ, //ncalrpc
  299. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  300. DPAPI_LOCAL_ENDPOINT, //protected_storage
  301. NULL); //Security Descriptor
  302. if(RPC_S_DUPLICATE_ENDPOINT == status)
  303. {
  304. status = RPC_S_OK;
  305. }
  306. if (status)
  307. {
  308. dwLastError = status;
  309. goto cleanup;
  310. }
  311. status = RpcServerUseProtseqEpW(DPAPI_BACKUP_PROT_SEQ, //ncacn_np
  312. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  313. DPAPI_BACKUP_ENDPOINT, //protected_storage
  314. NULL); //Security Descriptor
  315. if(RPC_S_DUPLICATE_ENDPOINT == status)
  316. {
  317. status = RPC_S_OK;
  318. }
  319. if (status)
  320. {
  321. dwLastError = status;
  322. goto cleanup;
  323. }
  324. status = RpcServerRegisterIfEx(s_ICryptProtect_v1_0_s_ifspec,
  325. NULL,
  326. NULL,
  327. RPC_IF_AUTOLISTEN,
  328. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  329. ProtectCallback);
  330. if (status)
  331. {
  332. dwLastError = status;
  333. goto cleanup;
  334. }
  335. status = RpcServerRegisterIfEx(s_PasswordRecovery_v1_0_s_ifspec,
  336. NULL,
  337. NULL,
  338. RPC_IF_AUTOLISTEN,
  339. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  340. ProtectCallback);
  341. if (status)
  342. {
  343. dwLastError = status;
  344. goto cleanup;
  345. }
  346. //
  347. // Start the Backup Key server
  348. // note: it only starts when the current machine is an domain controller.
  349. //
  350. dwLastError = StartBackupKeyServer();
  351. if(dwLastError != ERROR_SUCCESS) {
  352. goto cleanup;
  353. }
  354. return dwLastError;
  355. cleanup:
  356. DPAPIShutdown();
  357. return dwLastError;
  358. }
  359. DWORD
  360. NTAPI
  361. DPAPIShutdown( )
  362. {
  363. //
  364. // ignore errors because we are shutting down
  365. //
  366. (void)RpcServerUnregisterIf(s_ICryptProtect_v1_0_s_ifspec, 0, 0);
  367. //
  368. // stop backup key server
  369. // Note: this function knows internally whether the backup key server
  370. // really started or not.
  371. //
  372. StopBackupKeyServer();
  373. if(g_pCProvList)
  374. {
  375. delete g_pCProvList;
  376. g_pCProvList = NULL;
  377. }
  378. TeardownKeyManagement();
  379. ShutdownGlobals();
  380. return ERROR_SUCCESS;
  381. }
  382. #ifdef RETAIL_LOG_SUPPORT
  383. VOID
  384. DPAPIDumpHexData(
  385. DWORD LogLevel,
  386. PSTR pszPrefix,
  387. PBYTE pbData,
  388. DWORD cbData)
  389. {
  390. DWORD i,count;
  391. CHAR digits[]="0123456789abcdef";
  392. CHAR pbLine[MAX_PATH];
  393. DWORD cbLine;
  394. DWORD cbHeader;
  395. DWORD_PTR address;
  396. if((DPAPIInfoLevel & LogLevel) == 0)
  397. {
  398. return;
  399. }
  400. if(pbData == NULL || cbData == 0)
  401. {
  402. return;
  403. }
  404. if(pszPrefix)
  405. {
  406. strcpy(pbLine, pszPrefix);
  407. cbHeader = strlen(pszPrefix);
  408. }
  409. else
  410. {
  411. pbLine[0] = '\0';
  412. cbHeader = 0;
  413. }
  414. for(; cbData ; cbData -= count, pbData += count)
  415. {
  416. count = (cbData > 16) ? 16:cbData;
  417. cbLine = cbHeader;
  418. address = (DWORD_PTR)pbData;
  419. #if defined(_WIN64)
  420. pbLine[cbLine++] = digits[(address >> 0x3c) & 0x0f];
  421. pbLine[cbLine++] = digits[(address >> 0x38) & 0x0f];
  422. pbLine[cbLine++] = digits[(address >> 0x34) & 0x0f];
  423. pbLine[cbLine++] = digits[(address >> 0x30) & 0x0f];
  424. pbLine[cbLine++] = digits[(address >> 0x2c) & 0x0f];
  425. pbLine[cbLine++] = digits[(address >> 0x28) & 0x0f];
  426. pbLine[cbLine++] = digits[(address >> 0x24) & 0x0f];
  427. pbLine[cbLine++] = digits[(address >> 0x20) & 0x0f];
  428. #endif
  429. pbLine[cbLine++] = digits[(address >> 0x1c) & 0x0f];
  430. pbLine[cbLine++] = digits[(address >> 0x18) & 0x0f];
  431. pbLine[cbLine++] = digits[(address >> 0x14) & 0x0f];
  432. pbLine[cbLine++] = digits[(address >> 0x10) & 0x0f];
  433. pbLine[cbLine++] = digits[(address >> 0x0c) & 0x0f];
  434. pbLine[cbLine++] = digits[(address >> 0x08) & 0x0f];
  435. pbLine[cbLine++] = digits[(address >> 0x04) & 0x0f];
  436. pbLine[cbLine++] = digits[(address ) & 0x0f];
  437. pbLine[cbLine++] = ' ';
  438. pbLine[cbLine++] = ' ';
  439. for(i = 0; i < count; i++)
  440. {
  441. pbLine[cbLine++] = digits[pbData[i]>>4];
  442. pbLine[cbLine++] = digits[pbData[i]&0x0f];
  443. if(i == 7)
  444. {
  445. pbLine[cbLine++] = ':';
  446. }
  447. else
  448. {
  449. pbLine[cbLine++] = ' ';
  450. }
  451. }
  452. for(; i < 16; i++)
  453. {
  454. pbLine[cbLine++] = ' ';
  455. pbLine[cbLine++] = ' ';
  456. pbLine[cbLine++] = ' ';
  457. }
  458. pbLine[cbLine++] = ' ';
  459. for(i = 0; i < count; i++)
  460. {
  461. //
  462. // 37 is for %
  463. //
  464. if(pbData[i] < 32 || pbData[i] > 126 || pbData[i] == 37)
  465. {
  466. pbLine[cbLine++] = '.';
  467. }
  468. else
  469. {
  470. pbLine[cbLine++] = pbData[i];
  471. }
  472. }
  473. pbLine[cbLine++] = '\n';
  474. pbLine[cbLine++] = 0;
  475. D_DebugLog((LogLevel, pbLine));
  476. }
  477. }
  478. #endif