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.

1981 lines
56 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1999 - 1999
  3. Module Name:
  4. pwdui.c
  5. Abstract:
  6. This module contains routines for displaying Data Protection API
  7. related UI, originating from client process address space.
  8. For the future, there is support planned for causing UI to originate
  9. from the secure desktop, via Secure Authentication Sequence (SAS).
  10. Author:
  11. Scott Field (sfield) 12-May-99
  12. --*/
  13. #define UNICODE
  14. #define _UNICODE
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <windows.h>
  19. #include <wincrypt.h>
  20. #include <sha.h>
  21. #include <unicode5.h>
  22. #include "resource.h"
  23. #include "pwdui.h"
  24. typedef struct {
  25. DATA_BLOB *pDataIn; // input DATA_BLOB* to CryptProtect or CryptUnprotect
  26. CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct; // PromptStruct describing UI operations to perform
  27. LPWSTR szDataDescription; // Application supplied data descr
  28. PBYTE rgbPasswordHash; // resultant passwordhash for strong security
  29. BOOL fCachedPassword; // did we find password in cache?
  30. BOOL fProtect; // protect or unprotect?
  31. BOOL fValidPassword; // does rgbPasswordHash contain a valid value?
  32. } DIALOGARGS, *PDIALOGARGS, *LPDIALOGARGS;
  33. typedef struct {
  34. LIST_ENTRY Next;
  35. LUID LogonId;
  36. FILETIME ftLastAccess;
  37. BYTE rgbDataInHash[A_SHA_DIGEST_LEN];
  38. BYTE rgbPasswordHash[A_SHA_DIGEST_LEN];
  39. } PASSWORD_CACHE_ENTRY, *PPASSWORD_CACHE_ENTRY, *LPPASSWORD_CACHE_ENTRY;
  40. DWORD
  41. ProtectUIConfirm(
  42. IN DIALOGARGS *pDialogArgs
  43. );
  44. DWORD
  45. UnprotectUIConfirm(
  46. IN DIALOGARGS *pDialogArgs
  47. );
  48. BOOL
  49. ChooseSecurityLevel(
  50. IN HWND hWndParent,
  51. IN DIALOGARGS *pDialogArgs
  52. );
  53. VOID
  54. AdvancedSecurityDetails(
  55. IN HWND hWndParent,
  56. IN DIALOGARGS *pDialogArgs
  57. );
  58. //
  59. // dialog box handling routines.
  60. //
  61. INT_PTR
  62. CALLBACK
  63. DialogConfirmProtect(
  64. HWND hDlg, // handle to dialog box
  65. UINT message, // message
  66. WPARAM wParam, // first message parameter
  67. LPARAM lParam // second message parameter
  68. );
  69. INT_PTR
  70. CALLBACK
  71. DialogConfirmAccess(
  72. HWND hDlg, // handle to dialog box
  73. UINT message, // message
  74. WPARAM wParam, // first message parameter
  75. LPARAM lParam // second message parameter
  76. );
  77. INT_PTR
  78. CALLBACK
  79. DialogChooseSecurityLevel(
  80. HWND hDlg, // handle to dialog box
  81. UINT message, // message
  82. WPARAM wParam, // first message parameter
  83. LPARAM lParam // second message parameter
  84. );
  85. INT_PTR
  86. CALLBACK
  87. DialogChooseSecurityLevelMedium(
  88. HWND hDlg, // handle to dialog box
  89. UINT message, // message
  90. WPARAM wParam, // first message parameter
  91. LPARAM lParam // second message parameter
  92. );
  93. INT_PTR
  94. CALLBACK
  95. DialogChooseSecurityLevelHigh(
  96. HWND hDlg, // handle to dialog box
  97. UINT message, // message
  98. WPARAM wParam, // first message parameter
  99. LPARAM lParam // second message parameter
  100. );
  101. INT_PTR
  102. CALLBACK
  103. DialogAdvancedSecurityDetails(
  104. HWND hDlg, // handle to dialog box
  105. UINT message, // message
  106. WPARAM wParam, // first message parameter
  107. LPARAM lParam // second message parameter
  108. );
  109. //
  110. // helper routines.
  111. //
  112. #ifndef SSAlloc
  113. #define SSAlloc(x) LocalAlloc(LMEM_FIXED, x)
  114. #endif
  115. #ifndef SSFree
  116. #define SSFree(x) LocalFree(x)
  117. #endif
  118. VOID
  119. ComputePasswordHash(
  120. IN PVOID pvPassword,
  121. IN DWORD cbPassword,
  122. IN OUT BYTE rgbPasswordHash[A_SHA_DIGEST_LEN]
  123. );
  124. BOOL
  125. GetEffectiveLogonId(
  126. IN OUT LUID *pLogonId
  127. );
  128. BOOL
  129. InitializeDetailGlobals(
  130. VOID
  131. );
  132. //
  133. // password cache related routines.
  134. //
  135. BOOL
  136. InitializeProtectPasswordCache(
  137. VOID
  138. );
  139. VOID
  140. DeleteProtectPasswordCache(
  141. VOID
  142. );
  143. BOOL
  144. AddProtectPasswordCache(
  145. IN DATA_BLOB* pDataIn,
  146. IN BYTE rgbPassword[A_SHA_DIGEST_LEN]
  147. );
  148. BOOL
  149. SearchProtectPasswordCache(
  150. IN DATA_BLOB* pDataIn,
  151. IN OUT BYTE rgbPassword[A_SHA_DIGEST_LEN],
  152. IN BOOL fDeleteFoundEntry
  153. );
  154. VOID
  155. PurgeProtectPasswordCache(
  156. VOID
  157. );
  158. BOOL
  159. IsCachePWAllowed(
  160. VOID
  161. );
  162. //
  163. // global variables.
  164. //
  165. HINSTANCE g_hInstProtectUI;
  166. CRITICAL_SECTION g_csProtectPasswordCache;
  167. LIST_ENTRY g_ProtectPasswordCache;
  168. #define ALLOW_CACHE_UNKNOWN 0
  169. #define ALLOW_CACHE_NO 1
  170. #define ALLOW_CACHE_YES 2
  171. DWORD g_dwAllowCachePW = 0;
  172. WCHAR g_szGooPassword[] = L"(*&#$(^(#%^))(*&(^(*{}_SAF^^%";
  173. BOOL g_fDetailGlobalsInitialized = FALSE;
  174. LPWSTR g_szDetailApplicationName = NULL;
  175. LPWSTR g_szDetailApplicationPath = NULL;
  176. BOOL
  177. WINAPI
  178. ProtectUI_DllMain(
  179. HINSTANCE hinstDLL, // handle to DLL module
  180. DWORD fdwReason, // reason for calling function
  181. LPVOID lpvReserved // reserved
  182. )
  183. {
  184. BOOL fRet = TRUE;
  185. if( fdwReason == DLL_PROCESS_ATTACH ) {
  186. g_hInstProtectUI = hinstDLL;
  187. fRet = InitializeProtectPasswordCache();
  188. } else if ( fdwReason == DLL_PROCESS_DETACH ) {
  189. DeleteProtectPasswordCache();
  190. }
  191. return fRet;
  192. }
  193. DWORD
  194. WINAPI
  195. I_CryptUIProtect(
  196. IN PVOID pvReserved1,
  197. IN PVOID pvReserved2,
  198. IN DWORD dwReserved3,
  199. IN PVOID *pvReserved4,
  200. IN BOOL fReserved5,
  201. IN PVOID pvReserved6
  202. )
  203. {
  204. DIALOGARGS DialogArgs;
  205. DWORD dwLastError = ERROR_SUCCESS;
  206. DATA_BLOB* pDataIn = (DATA_BLOB*)pvReserved1;
  207. CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct = (CRYPTPROTECT_PROMPTSTRUCT*)pvReserved2;
  208. DWORD dwFlags = (DWORD)dwReserved3;
  209. LPCWSTR szDescription = (LPCWSTR)*pvReserved4;
  210. BOOL fProtectOperation = (BOOL)fReserved5;
  211. PBYTE rgbPasswordHash = (PBYTE)pvReserved6;
  212. BOOL fEmptyDescription;
  213. //
  214. // for protect:
  215. // szDescription, if NULL or empty, get from user
  216. // if PROMPT_STRONG is set, grey out medium security.
  217. //
  218. // for unprotect:
  219. // szDescription, get from datablob.
  220. // pPromptStruct->dwPromptFlags from datablob.
  221. // if PROMPT_STRONG is set, enable password field and
  222. //
  223. if( pPromptStruct == NULL )
  224. return ERROR_INVALID_PARAMETER;
  225. if( pPromptStruct->cbSize != sizeof( CRYPTPROTECT_PROMPTSTRUCT) )
  226. return ERROR_INVALID_PARAMETER;
  227. if( fProtectOperation ) {
  228. //
  229. // if unprotect was specified, protect is implicitly specified.
  230. // vice-versa is true, too.
  231. //
  232. if ( ((pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_PROTECT) == 0) &&
  233. ((pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_UNPROTECT) == 0)
  234. )
  235. {
  236. //
  237. // nothing to do, bail out.
  238. //
  239. return ERROR_SUCCESS;
  240. }
  241. pPromptStruct->dwPromptFlags |= CRYPTPROTECT_PROMPT_ON_PROTECT;
  242. pPromptStruct->dwPromptFlags |= CRYPTPROTECT_PROMPT_ON_UNPROTECT;
  243. }
  244. if ( dwFlags & CRYPTPROTECT_UI_FORBIDDEN ) {
  245. return ERROR_PASSWORD_RESTRICTION;
  246. }
  247. //
  248. // build dialog box arguments block.
  249. //
  250. DialogArgs.pDataIn = pDataIn;
  251. DialogArgs.pPromptStruct = pPromptStruct;
  252. if( szDescription != NULL && szDescription[0] != L'\0' ) {
  253. DialogArgs.szDataDescription = (LPWSTR)szDescription;
  254. fEmptyDescription = FALSE;
  255. } else {
  256. DialogArgs.szDataDescription = NULL;
  257. fEmptyDescription = TRUE;
  258. }
  259. DialogArgs.rgbPasswordHash = rgbPasswordHash;
  260. DialogArgs.fCachedPassword = FALSE;
  261. DialogArgs.fProtect = fProtectOperation;
  262. DialogArgs.fValidPassword = FALSE;
  263. if( fProtectOperation ) {
  264. //
  265. // now, throw the UI for the protect operation.
  266. //
  267. dwLastError = ProtectUIConfirm( &DialogArgs );
  268. if( dwLastError == ERROR_SUCCESS && fEmptyDescription &&
  269. DialogArgs.szDataDescription ) {
  270. //
  271. // output modified data description to caller.
  272. //
  273. *pvReserved4 = DialogArgs.szDataDescription;
  274. }
  275. } else {
  276. //
  277. // now, throw the UI for the unprotect operation.
  278. //
  279. dwLastError = UnprotectUIConfirm( &DialogArgs );
  280. }
  281. if( fEmptyDescription && dwLastError != ERROR_SUCCESS &&
  282. DialogArgs.szDataDescription ) {
  283. SSFree( DialogArgs.szDataDescription );
  284. }
  285. return dwLastError;
  286. }
  287. DWORD
  288. WINAPI
  289. I_CryptUIProtectFailure(
  290. IN PVOID pvReserved1,
  291. IN DWORD dwReserved2,
  292. IN PVOID *pvReserved3)
  293. {
  294. CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct = (CRYPTPROTECT_PROMPTSTRUCT*)pvReserved1;
  295. DWORD dwFlags = (DWORD)dwReserved2;
  296. LPCWSTR szDescription = (LPCWSTR)*pvReserved3;
  297. WCHAR szTitle[512];
  298. WCHAR szText[512];
  299. if((pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_UNPROTECT) == 0)
  300. {
  301. return ERROR_SUCCESS;
  302. }
  303. if(dwFlags & CRYPTPROTECT_UI_FORBIDDEN)
  304. {
  305. return ERROR_PASSWORD_RESTRICTION;
  306. }
  307. LoadStringU(g_hInstProtectUI, IDS_PROTECT_DECRYPTION_ERROR, szTitle, sizeof(szTitle)/sizeof(WCHAR));
  308. LoadStringU(g_hInstProtectUI, IDS_PROTECT_CANNOT_DECRYPT, szText, sizeof(szText)/sizeof(WCHAR));
  309. MessageBoxU(pPromptStruct->hwndApp, szText, szTitle, MB_OK | MB_ICONWARNING);
  310. return ERROR_SUCCESS;
  311. }
  312. DWORD
  313. ProtectUIConfirm(
  314. IN DIALOGARGS *pDialogArgs
  315. )
  316. {
  317. INT_PTR iRet;
  318. iRet = DialogBoxParamU(
  319. g_hInstProtectUI,
  320. MAKEINTRESOURCE(IDD_PROTECT_CONFIRM_PROTECT),
  321. pDialogArgs->pPromptStruct->hwndApp,
  322. DialogConfirmProtect,
  323. (LPARAM)pDialogArgs
  324. );
  325. return (DWORD)iRet;
  326. }
  327. DWORD
  328. UnprotectUIConfirm(
  329. IN DIALOGARGS *pDialogArgs
  330. )
  331. {
  332. INT_PTR iRet;
  333. iRet = DialogBoxParamU(
  334. g_hInstProtectUI,
  335. MAKEINTRESOURCE(IDD_PROTECT_CONFIRM_SECURITY),
  336. pDialogArgs->pPromptStruct->hwndApp,
  337. DialogConfirmAccess,
  338. (LPARAM)pDialogArgs
  339. );
  340. return (DWORD)iRet;
  341. }
  342. INT_PTR
  343. CALLBACK
  344. DialogConfirmProtect(
  345. HWND hDlg, // handle to dialog box
  346. UINT message, // message
  347. WPARAM wParam, // first message parameter
  348. LPARAM lParam // second message parameter
  349. )
  350. {
  351. DIALOGARGS *pDialogArgs;
  352. CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
  353. switch (message)
  354. {
  355. case WM_INITDIALOG:
  356. {
  357. SetLastError( 0 ); // as per win32 documentation
  358. if(SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)lParam) == 0) {
  359. if(GetLastError() != ERROR_SUCCESS) {
  360. EndDialog(hDlg, GetLastError());
  361. return FALSE;
  362. }
  363. }
  364. // lParam is DIALOGARGS *
  365. pDialogArgs = (DIALOGARGS*)lParam;
  366. pPromptStruct = pDialogArgs->pPromptStruct;
  367. //
  368. // set the dialog title
  369. //
  370. if (pPromptStruct->szPrompt)
  371. SetWindowTextU(hDlg, pPromptStruct->szPrompt);
  372. //
  373. // display dynamic stuff.
  374. //
  375. SendMessage( hDlg, WM_COMMAND, IDC_PROTECT_UPDATE_DYNAMIC, 0 );
  376. return FALSE; // don't default the Focus..
  377. } // WM_INITDIALOG
  378. case WM_COMMAND:
  379. {
  380. switch(LOWORD(wParam))
  381. {
  382. case IDOK:
  383. {
  384. EndDialog(hDlg, ERROR_SUCCESS);
  385. return TRUE;
  386. }
  387. case IDCANCEL:
  388. {
  389. EndDialog(hDlg, ERROR_CANCELLED);
  390. return TRUE;
  391. }
  392. case IDC_PROTECT_ADVANCED:
  393. {
  394. pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
  395. hDlg,
  396. GWLP_USERDATA
  397. );
  398. if(pDialogArgs == NULL)
  399. break; // TODO: bail out
  400. //
  401. // show details dialog.
  402. //
  403. AdvancedSecurityDetails(
  404. hDlg,
  405. pDialogArgs
  406. );
  407. return FALSE;
  408. }
  409. case IDC_PROTECT_UPDATE_DYNAMIC:
  410. {
  411. WCHAR szResource[ 256 ] = L"";
  412. int cchResource = sizeof(szResource) / sizeof(WCHAR);
  413. UINT ResourceId;
  414. pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
  415. hDlg,
  416. GWLP_USERDATA
  417. );
  418. if(pDialogArgs == NULL)
  419. break; // TODO: bail out
  420. pPromptStruct = pDialogArgs->pPromptStruct;
  421. //
  422. // description.
  423. //
  424. if (pDialogArgs->szDataDescription)
  425. SetWindowTextU(GetDlgItem(hDlg, IDC_PROTECT_LABEL_EDIT1), pDialogArgs->szDataDescription);
  426. // Disable the OK button if we're defaulting to strong protection,
  427. // unless a password has already been set.
  428. if((pPromptStruct->dwPromptFlags & (CRYPTPROTECT_PROMPT_STRONG |
  429. CRYPTPROTECT_PROMPT_REQUIRE_STRONG)) &&
  430. (pDialogArgs->fValidPassword == FALSE))
  431. {
  432. EnableWindow( GetDlgItem(hDlg, IDOK), FALSE );
  433. SendMessage(hDlg, DM_SETDEFID, IDC_PROTECT_CHANGE_SECURITY, 0);
  434. SetFocus(GetDlgItem(hDlg, IDC_PROTECT_CHANGE_SECURITY));
  435. }
  436. else
  437. {
  438. EnableWindow( GetDlgItem(hDlg, IDOK), TRUE );
  439. SendMessage(hDlg, DM_SETDEFID, IDOK,0);
  440. SetFocus(GetDlgItem(hDlg, IDOK));
  441. }
  442. //
  443. // security level.
  444. //
  445. if( pPromptStruct->dwPromptFlags & (CRYPTPROTECT_PROMPT_STRONG |
  446. CRYPTPROTECT_PROMPT_REQUIRE_STRONG))
  447. {
  448. ResourceId = IDS_PROTECT_SECURITY_LEVEL_SET_HIGH;
  449. } else {
  450. ResourceId = IDS_PROTECT_SECURITY_LEVEL_SET_MEDIUM;
  451. }
  452. cchResource = LoadStringU(g_hInstProtectUI,
  453. ResourceId,
  454. szResource,
  455. cchResource
  456. );
  457. SetWindowTextU( GetDlgItem(hDlg,IDC_PROTECT_SECURITY_LEVEL),
  458. szResource
  459. );
  460. return FALSE;
  461. }
  462. case IDC_PROTECT_CHANGE_SECURITY:
  463. {
  464. pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
  465. hDlg,
  466. GWLP_USERDATA
  467. );
  468. if(pDialogArgs == NULL)
  469. break; // TODO: bail out
  470. //
  471. // spawn child dialog to handle prompting for security level.
  472. //
  473. if(!ChooseSecurityLevel( hDlg, pDialogArgs )) {
  474. EndDialog(hDlg, ERROR_CANCELLED);
  475. return TRUE;
  476. }
  477. //
  478. // display dynamic stuff that may have changed.
  479. //
  480. SendMessage( hDlg, WM_COMMAND, IDC_PROTECT_UPDATE_DYNAMIC, 0 );
  481. break;
  482. }
  483. default:
  484. {
  485. return FALSE;
  486. }
  487. }
  488. } // WM_COMMAND
  489. default:
  490. {
  491. return FALSE;
  492. }
  493. } // message
  494. }
  495. INT_PTR
  496. CALLBACK
  497. DialogConfirmAccess(
  498. HWND hDlg, // handle to dialog box
  499. UINT message, // message
  500. WPARAM wParam, // first message parameter
  501. LPARAM lParam // second message parameter
  502. )
  503. {
  504. DIALOGARGS *pDialogArgs;
  505. CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
  506. switch (message)
  507. {
  508. case WM_INITDIALOG:
  509. {
  510. SetLastError( 0 ); // as per win32 documentation
  511. if(SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)lParam) == 0) {
  512. if(GetLastError() != ERROR_SUCCESS) {
  513. EndDialog(hDlg, GetLastError());
  514. return FALSE;
  515. }
  516. }
  517. // lParam is DIALOGARGS *
  518. pDialogArgs = (DIALOGARGS*)lParam;
  519. pPromptStruct = pDialogArgs->pPromptStruct;
  520. //
  521. // set the dialog title
  522. //
  523. if (pPromptStruct->szPrompt)
  524. SetWindowTextU(hDlg, pPromptStruct->szPrompt);
  525. //
  526. // description.
  527. //
  528. if (pDialogArgs->szDataDescription)
  529. SetWindowTextU(GetDlgItem(hDlg, IDC_PROTECT_LABEL_EDIT1), pDialogArgs->szDataDescription);
  530. if( pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG ) {
  531. //
  532. // If policy doesn't allow, disable caching of password.
  533. //
  534. // Otherwise, search password cache to see if user cached password
  535. // for this item.
  536. //
  537. if( g_dwAllowCachePW == ALLOW_CACHE_UNKNOWN )
  538. {
  539. if(!IsCachePWAllowed()) {
  540. g_dwAllowCachePW = ALLOW_CACHE_NO;
  541. } else {
  542. g_dwAllowCachePW = ALLOW_CACHE_YES;
  543. }
  544. }
  545. if((g_dwAllowCachePW == ALLOW_CACHE_NO) ||
  546. (pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_REQUIRE_STRONG))
  547. {
  548. ShowWindow( GetDlgItem(hDlg, IDC_PROTECT_CACHEPW), SW_HIDE );
  549. EnableWindow( GetDlgItem(hDlg, IDC_PROTECT_CACHEPW), FALSE );
  550. } else if(SearchProtectPasswordCache( pDialogArgs->pDataIn, pDialogArgs->rgbPasswordHash, FALSE ))
  551. {
  552. //
  553. // enable checkbox for cached password, fill edit control
  554. // with password.
  555. //
  556. SetWindowTextU(GetDlgItem(hDlg,IDC_PROTECT_PASSWORD1),
  557. g_szGooPassword
  558. );
  559. SendMessage(GetDlgItem(hDlg, IDC_PROTECT_CACHEPW), BM_SETCHECK, BST_CHECKED, 0);
  560. pDialogArgs->fCachedPassword = TRUE;
  561. pDialogArgs->fValidPassword = TRUE;
  562. }
  563. } else {
  564. //
  565. // disable irrelevant fields in dialog.
  566. //
  567. ShowWindow( GetDlgItem(hDlg, IDC_PROTECT_CACHEPW), SW_HIDE );
  568. EnableWindow( GetDlgItem(hDlg, IDC_PROTECT_CACHEPW), FALSE );
  569. ShowWindow( GetDlgItem(hDlg, IDC_PROTECT_PASSWORD1), SW_HIDE );
  570. EnableWindow( GetDlgItem(hDlg, IDC_PROTECT_PASSWORD1), FALSE );
  571. }
  572. return TRUE;
  573. } // WM_INITDIALOG
  574. case WM_COMMAND:
  575. {
  576. switch(LOWORD(wParam))
  577. {
  578. case IDOK:
  579. {
  580. pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
  581. hDlg,
  582. GWLP_USERDATA
  583. );
  584. if(pDialogArgs == NULL)
  585. break; // TODO: bail out
  586. pPromptStruct = pDialogArgs->pPromptStruct;
  587. if( pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
  588. {
  589. WCHAR szPassword[ 256 ];
  590. int cchPassword = sizeof(szPassword) / sizeof(WCHAR);
  591. BOOL fCachePassword;
  592. //
  593. // check if remember password is checked.
  594. // if so, check if password is untypable goo.
  595. //
  596. if( g_dwAllowCachePW != ALLOW_CACHE_NO &&
  597. (BST_CHECKED == SendMessage(GetDlgItem(hDlg, IDC_PROTECT_CACHEPW), BM_GETCHECK, 0, 0))
  598. )
  599. {
  600. fCachePassword = TRUE;
  601. } else {
  602. fCachePassword = FALSE;
  603. }
  604. cchPassword = GetWindowTextU(
  605. GetDlgItem(hDlg,IDC_PROTECT_PASSWORD1),
  606. szPassword,
  607. cchPassword
  608. );
  609. if( !fCachePassword && pDialogArgs->fCachedPassword ) {
  610. //
  611. // user un-checked cachePW button, and item was cached.
  612. // remove it from cache.
  613. //
  614. SearchProtectPasswordCache(
  615. pDialogArgs->pDataIn,
  616. pDialogArgs->rgbPasswordHash,
  617. TRUE
  618. );
  619. }
  620. if(
  621. pDialogArgs->fCachedPassword &&
  622. (cchPassword*sizeof(WCHAR) == sizeof(g_szGooPassword)-sizeof(WCHAR)) &&
  623. (memcmp(szPassword, g_szGooPassword, cchPassword*sizeof(WCHAR)) == 0)
  624. )
  625. {
  626. //
  627. // nothing to do, rgbPasswordHash was updated by
  628. // cache search...
  629. //
  630. } else {
  631. ComputePasswordHash(
  632. szPassword,
  633. (DWORD)(cchPassword * sizeof(WCHAR)),
  634. pDialogArgs->rgbPasswordHash
  635. );
  636. pDialogArgs->fValidPassword = TRUE;
  637. //
  638. // if user chose to cache password, add it.
  639. //
  640. if( fCachePassword )
  641. {
  642. AddProtectPasswordCache(
  643. pDialogArgs->pDataIn,
  644. pDialogArgs->rgbPasswordHash
  645. );
  646. }
  647. }
  648. SecureZeroMemory(szPassword, sizeof(szPassword));
  649. }
  650. EndDialog(hDlg, ERROR_SUCCESS);
  651. return TRUE;
  652. }
  653. case IDCANCEL:
  654. {
  655. EndDialog(hDlg, ERROR_CANCELLED);
  656. return TRUE;
  657. }
  658. case IDC_PROTECT_ADVANCED:
  659. {
  660. pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
  661. hDlg,
  662. GWLP_USERDATA
  663. );
  664. if(pDialogArgs == NULL)
  665. break; // TODO: bail out
  666. //
  667. // show details dialog.
  668. //
  669. AdvancedSecurityDetails(
  670. hDlg,
  671. pDialogArgs
  672. );
  673. return FALSE;
  674. }
  675. default:
  676. {
  677. return FALSE;
  678. }
  679. }
  680. } // WM_COMMAND
  681. default:
  682. {
  683. return FALSE;
  684. }
  685. } // message
  686. }
  687. //
  688. // security level chooser routines.
  689. //
  690. BOOL
  691. ChooseSecurityLevel(
  692. IN HWND hWndParent,
  693. IN DIALOGARGS *pDialogArgs
  694. )
  695. {
  696. CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
  697. DWORD dwOriginalPromptFlags;
  698. BOOL fEmptyDescription;
  699. INT_PTR iRet;
  700. pPromptStruct = pDialogArgs->pPromptStruct;
  701. dwOriginalPromptFlags = pPromptStruct->dwPromptFlags;
  702. fEmptyDescription = (pDialogArgs->szDataDescription == NULL);
  703. Step1:
  704. if(pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_REQUIRE_STRONG)
  705. {
  706. //
  707. // Force strong protection.
  708. //
  709. pPromptStruct->dwPromptFlags |= CRYPTPROTECT_PROMPT_STRONG;
  710. }
  711. else
  712. {
  713. //
  714. // The "require strong" flag is not set, so allow the user to select
  715. // between medium and strong protection.
  716. //
  717. iRet = DialogBoxParamU(
  718. g_hInstProtectUI,
  719. MAKEINTRESOURCE(IDD_PROTECT_CHOOSE_SECURITY),
  720. hWndParent,
  721. DialogChooseSecurityLevel,
  722. (LPARAM)pDialogArgs
  723. );
  724. // if user decides not to choose, bail
  725. if( iRet == IDCANCEL )
  726. return TRUE;
  727. if( iRet != IDOK )
  728. return FALSE;
  729. }
  730. if( pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG ) {
  731. //
  732. // display dialog 'page' confirming high security.
  733. //
  734. iRet = DialogBoxParamU(
  735. g_hInstProtectUI,
  736. MAKEINTRESOURCE(IDD_PROTECT_CHOOSE_SECURITY_H),
  737. hWndParent,
  738. DialogChooseSecurityLevelHigh,
  739. (LPARAM)pDialogArgs
  740. );
  741. } else {
  742. //
  743. // display dialog 'page' confirming medium security.
  744. //
  745. iRet = DialogBoxParamU(
  746. g_hInstProtectUI,
  747. MAKEINTRESOURCE(IDD_PROTECT_CHOOSE_SECURITY_M),
  748. hWndParent,
  749. DialogChooseSecurityLevelMedium,
  750. (LPARAM)pDialogArgs
  751. );
  752. }
  753. if( iRet == IDC_PROTECT_BACK ) {
  754. //
  755. // put original prompt flags back so we don't end up with undefined
  756. // pwd at high-security level.
  757. // free allocated description if that happened, too.
  758. //
  759. pPromptStruct->dwPromptFlags = dwOriginalPromptFlags;
  760. if( fEmptyDescription && pDialogArgs->szDataDescription ) {
  761. SSFree( pDialogArgs->szDataDescription );
  762. pDialogArgs->szDataDescription = NULL;
  763. }
  764. goto Step1;
  765. }
  766. if( iRet != IDOK )
  767. return FALSE;
  768. return TRUE;
  769. }
  770. INT_PTR
  771. CALLBACK
  772. DialogChooseSecurityLevel(
  773. HWND hDlg, // handle to dialog box
  774. UINT message, // message
  775. WPARAM wParam, // first message parameter
  776. LPARAM lParam // second message parameter
  777. )
  778. {
  779. switch (message)
  780. {
  781. CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
  782. DIALOGARGS *pDialogArgs;
  783. case WM_INITDIALOG:
  784. {
  785. SetLastError( 0 ); // as per win32 documentation
  786. if(SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)lParam) == 0) {
  787. if(GetLastError() != ERROR_SUCCESS) {
  788. EndDialog(hDlg, IDCANCEL);
  789. return FALSE;
  790. }
  791. }
  792. // lParam is DIALOGARGS*
  793. pDialogArgs = (DIALOGARGS*)lParam;
  794. pPromptStruct = pDialogArgs->pPromptStruct;
  795. // set the dialog title
  796. if (pPromptStruct->szPrompt)
  797. SetWindowTextU(hDlg, pPromptStruct->szPrompt);
  798. if( pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG ) {
  799. SendDlgItemMessage(hDlg, IDC_PROTECT_RADIO_HIGH, BM_SETCHECK, BST_CHECKED, 0);
  800. SendMessage(hDlg, WM_COMMAND, (WORD)IDC_PROTECT_RADIO_HIGH, 0);
  801. } else {
  802. SendDlgItemMessage(hDlg, IDC_PROTECT_RADIO_MEDIUM, BM_SETCHECK, BST_CHECKED, 0);
  803. SendMessage(hDlg, WM_COMMAND, (WORD)IDC_PROTECT_RADIO_MEDIUM, 0);
  804. }
  805. return TRUE;
  806. } // WM_INITDIALOG
  807. case WM_COMMAND:
  808. {
  809. switch (LOWORD(wParam))
  810. {
  811. case IDC_PROTECT_NEXT:
  812. case IDOK:
  813. {
  814. pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
  815. hDlg,
  816. GWLP_USERDATA
  817. );
  818. if(pDialogArgs == NULL)
  819. break; // TODO: bail out
  820. pPromptStruct = pDialogArgs->pPromptStruct;
  821. if (BST_CHECKED == SendDlgItemMessageW(
  822. hDlg,
  823. IDC_PROTECT_RADIO_HIGH,
  824. BM_GETCHECK,
  825. 0,
  826. 0
  827. ))
  828. {
  829. pPromptStruct->dwPromptFlags |= CRYPTPROTECT_PROMPT_STRONG;
  830. } else {
  831. pPromptStruct->dwPromptFlags &= ~(CRYPTPROTECT_PROMPT_STRONG);
  832. }
  833. break;
  834. }
  835. default:
  836. {
  837. break;
  838. }
  839. }
  840. if (
  841. (LOWORD(wParam) == IDOK) ||
  842. (LOWORD(wParam) == IDCANCEL) ||
  843. (LOWORD(wParam) == IDC_PROTECT_NEXT)
  844. )
  845. {
  846. EndDialog(hDlg, LOWORD(wParam));
  847. return TRUE;
  848. }
  849. } // WM_COMMAND
  850. default:
  851. {
  852. return FALSE;
  853. }
  854. } // message
  855. }
  856. INT_PTR
  857. CALLBACK
  858. DialogChooseSecurityLevelMedium(
  859. HWND hDlg, // handle to dialog box
  860. UINT message, // message
  861. WPARAM wParam, // first message parameter
  862. LPARAM lParam // second message parameter
  863. )
  864. {
  865. switch (message)
  866. {
  867. case WM_INITDIALOG:
  868. {
  869. DIALOGARGS *pDialogArgs;
  870. CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
  871. // lParam is DIALOGARGS*
  872. pDialogArgs = (DIALOGARGS*)lParam;
  873. pPromptStruct = pDialogArgs->pPromptStruct;
  874. // set the dialog title
  875. if (pPromptStruct->szPrompt)
  876. SetWindowTextU(hDlg, pPromptStruct->szPrompt);
  877. return TRUE;
  878. } // WM_INITDIALOG
  879. case WM_COMMAND:
  880. {
  881. if (
  882. (LOWORD(wParam) == IDOK) ||
  883. (LOWORD(wParam) == IDCANCEL) ||
  884. (LOWORD(wParam) == IDC_PROTECT_BACK)
  885. )
  886. {
  887. EndDialog(hDlg, LOWORD(wParam));
  888. return TRUE;
  889. }
  890. } // WM_COMMAND
  891. default:
  892. {
  893. return FALSE;
  894. }
  895. } // message
  896. }
  897. INT_PTR
  898. CALLBACK
  899. DialogChooseSecurityLevelHigh(
  900. HWND hDlg, // handle to dialog box
  901. UINT message, // message
  902. WPARAM wParam, // first message parameter
  903. LPARAM lParam // second message parameter
  904. )
  905. {
  906. switch (message)
  907. {
  908. DIALOGARGS *pDialogArgs;
  909. CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
  910. case WM_INITDIALOG:
  911. {
  912. SetLastError( 0 ); // as per win32 documentation
  913. if(SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)lParam) == 0) {
  914. if(GetLastError() != ERROR_SUCCESS) {
  915. EndDialog(hDlg, IDCANCEL);
  916. return FALSE;
  917. }
  918. }
  919. // lParam is DIALOGARGS*
  920. pDialogArgs = (DIALOGARGS*)lParam;
  921. pPromptStruct = pDialogArgs->pPromptStruct;
  922. // set the dialog title
  923. if (pPromptStruct->szPrompt)
  924. SetWindowTextU(hDlg, pPromptStruct->szPrompt);
  925. // Disable <Back and Finished buttons
  926. if(pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_REQUIRE_STRONG)
  927. {
  928. EnableWindow( GetDlgItem(hDlg, IDC_PROTECT_BACK), FALSE );
  929. EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  930. }
  931. //
  932. // description.
  933. //
  934. if( pDialogArgs->szDataDescription ) {
  935. HWND hwndProtectEdit1 = GetDlgItem( hDlg, IDC_PROTECT_PASSWORD1 );
  936. SetWindowTextU(GetDlgItem(hDlg, IDC_PROTECT_PW_NEWNAME), pDialogArgs->szDataDescription);
  937. //
  938. // set focus to Password entry box.
  939. //
  940. EnableWindow(hwndProtectEdit1, TRUE);
  941. SetFocus(hwndProtectEdit1);
  942. //
  943. // default dialog template disabled input.
  944. //
  945. } else {
  946. HWND hwndProtectPWNew = GetDlgItem( hDlg, IDC_PROTECT_PW_NEWNAME );
  947. //
  948. // enable edit box entry.
  949. //
  950. EnableWindow(hwndProtectPWNew, TRUE);
  951. //
  952. // set focus to description box
  953. //
  954. SetFocus(hwndProtectPWNew);
  955. }
  956. return FALSE;
  957. } // WM_INITDIALOG
  958. case WM_COMMAND:
  959. {
  960. switch(LOWORD(wParam))
  961. {
  962. case IDOK:
  963. {
  964. WCHAR szPassword[ 256 ];
  965. int cchPassword;
  966. BYTE rgbPasswordHashConfirm[A_SHA_DIGEST_LEN];
  967. BOOL fPasswordsMatch = TRUE; // assume passwords match.
  968. pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
  969. hDlg,
  970. GWLP_USERDATA
  971. );
  972. if(pDialogArgs == NULL)
  973. break; // TODO: bail out
  974. pPromptStruct = pDialogArgs->pPromptStruct;
  975. //
  976. // nothing more to do if not STRONG
  977. //
  978. if( (pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG) == 0 ) {
  979. EndDialog( hDlg, IDOK );
  980. }
  981. cchPassword = sizeof(szPassword) / sizeof(WCHAR);
  982. cchPassword = GetWindowTextU(
  983. GetDlgItem(hDlg,IDC_PROTECT_PASSWORD1),
  984. szPassword,
  985. cchPassword
  986. );
  987. ComputePasswordHash(
  988. szPassword,
  989. cchPassword * sizeof(WCHAR),
  990. pDialogArgs->rgbPasswordHash
  991. );
  992. SecureZeroMemory( szPassword, cchPassword*sizeof(WCHAR) );
  993. cchPassword = sizeof(szPassword) / sizeof(WCHAR);
  994. cchPassword = GetWindowTextU(
  995. GetDlgItem(hDlg,IDC_PROTECT_EDIT2),
  996. szPassword,
  997. cchPassword
  998. );
  999. ComputePasswordHash(
  1000. szPassword,
  1001. cchPassword * sizeof(WCHAR),
  1002. rgbPasswordHashConfirm
  1003. );
  1004. SecureZeroMemory( szPassword, cchPassword*sizeof(WCHAR) );
  1005. //
  1006. // check if both passwords entered by user match.
  1007. //
  1008. if( memcmp(rgbPasswordHashConfirm, pDialogArgs->rgbPasswordHash, sizeof(rgbPasswordHashConfirm)) != 0 )
  1009. {
  1010. fPasswordsMatch = FALSE;
  1011. }
  1012. SecureZeroMemory( rgbPasswordHashConfirm, sizeof(rgbPasswordHashConfirm) );
  1013. if( !fPasswordsMatch )
  1014. {
  1015. WCHAR szText[256];
  1016. WCHAR szCaption[256];
  1017. //
  1018. // passwords must match: tell user.
  1019. //
  1020. LoadStringU(g_hInstProtectUI,
  1021. IDS_PROTECT_PASSWORD_NOMATCH,
  1022. szText,
  1023. sizeof(szText) / sizeof(WCHAR)
  1024. );
  1025. LoadStringU(g_hInstProtectUI,
  1026. IDS_PROTECT_PASSWORD_ERROR_DLGTITLE,
  1027. szCaption,
  1028. sizeof(szCaption) / sizeof(WCHAR)
  1029. );
  1030. MessageBoxW(hDlg,
  1031. szText,
  1032. szCaption,
  1033. MB_OK | MB_ICONEXCLAMATION
  1034. );
  1035. return FALSE;
  1036. }
  1037. //
  1038. // if no description provided, make sure user entered one,
  1039. // and grab it..
  1040. //
  1041. if( pDialogArgs->szDataDescription == NULL ) {
  1042. cchPassword = sizeof(szPassword) / sizeof(WCHAR);
  1043. cchPassword = GetWindowTextU(
  1044. GetDlgItem(hDlg,IDC_PROTECT_PW_NEWNAME),
  1045. szPassword,
  1046. cchPassword
  1047. );
  1048. if( cchPassword == 0 ) {
  1049. WCHAR szText[256];
  1050. WCHAR szCaption[256];
  1051. //
  1052. // password must be named: tell user.
  1053. //
  1054. LoadStringU(g_hInstProtectUI,
  1055. IDS_PROTECT_PASSWORD_MUSTNAME,
  1056. szText,
  1057. sizeof(szText) / sizeof(WCHAR)
  1058. );
  1059. LoadStringU(g_hInstProtectUI,
  1060. IDS_PROTECT_PASSWORD_ERROR_DLGTITLE,
  1061. szCaption,
  1062. sizeof(szCaption) / sizeof(WCHAR)
  1063. );
  1064. MessageBoxW(hDlg,
  1065. szText,
  1066. szCaption,
  1067. MB_OK | MB_ICONEXCLAMATION
  1068. );
  1069. return FALSE;
  1070. }
  1071. pDialogArgs->szDataDescription = (LPWSTR)SSAlloc( (cchPassword+1) * sizeof(WCHAR) );
  1072. if( pDialogArgs->szDataDescription == NULL )
  1073. return FALSE;
  1074. CopyMemory( pDialogArgs->szDataDescription, szPassword, cchPassword*sizeof(WCHAR) );
  1075. (pDialogArgs->szDataDescription)[cchPassword] = L'\0';
  1076. }
  1077. pDialogArgs->fValidPassword = TRUE;
  1078. EndDialog(hDlg, IDOK);
  1079. return TRUE;
  1080. }
  1081. case IDC_PROTECT_PASSWORD1:
  1082. {
  1083. pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
  1084. hDlg,
  1085. GWLP_USERDATA
  1086. );
  1087. if(pDialogArgs == NULL)
  1088. break; // TODO: bail out
  1089. pPromptStruct = pDialogArgs->pPromptStruct;
  1090. if(pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_REQUIRE_STRONG)
  1091. {
  1092. WCHAR szPassword[ 256 ];
  1093. int cchPassword;
  1094. //
  1095. // Disable the Finish button until a password has been entered.
  1096. //
  1097. cchPassword = sizeof(szPassword) / sizeof(WCHAR);
  1098. cchPassword = GetWindowTextU(
  1099. GetDlgItem(hDlg,IDC_PROTECT_PASSWORD1),
  1100. szPassword,
  1101. cchPassword
  1102. );
  1103. if(cchPassword)
  1104. {
  1105. RtlSecureZeroMemory(szPassword, cchPassword * sizeof(WCHAR));
  1106. EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
  1107. }
  1108. else
  1109. {
  1110. EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  1111. }
  1112. }
  1113. break;
  1114. }
  1115. case IDC_PROTECT_BACK:
  1116. case IDCANCEL:
  1117. {
  1118. EndDialog(hDlg, LOWORD(wParam));
  1119. return TRUE;
  1120. }
  1121. default:
  1122. {
  1123. break;
  1124. }
  1125. }
  1126. } // WM_COMMAND
  1127. default:
  1128. {
  1129. return FALSE;
  1130. }
  1131. } // message
  1132. }
  1133. VOID
  1134. AdvancedSecurityDetails(
  1135. IN HWND hWndParent,
  1136. IN DIALOGARGS *pDialogArgs
  1137. )
  1138. {
  1139. DialogBoxParamU(
  1140. g_hInstProtectUI,
  1141. MAKEINTRESOURCE(IDD_PROTECT_SECURITY_DETAILS),
  1142. hWndParent,
  1143. DialogAdvancedSecurityDetails,
  1144. (LPARAM)pDialogArgs
  1145. );
  1146. }
  1147. INT_PTR
  1148. CALLBACK
  1149. DialogAdvancedSecurityDetails(
  1150. HWND hDlg, // handle to dialog box
  1151. UINT message, // message
  1152. WPARAM wParam, // first message parameter
  1153. LPARAM lParam // second message parameter
  1154. )
  1155. {
  1156. switch (message) {
  1157. DIALOGARGS *pDialogArgs;
  1158. CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
  1159. case WM_INITDIALOG:
  1160. {
  1161. WCHAR szResource[ 256 ] = L"";
  1162. UINT ResourceId;
  1163. SetLastError( 0 ); // as per win32 documentation
  1164. if(SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)lParam) == 0) {
  1165. if(GetLastError() != ERROR_SUCCESS) {
  1166. EndDialog(hDlg, IDCANCEL);
  1167. return FALSE;
  1168. }
  1169. }
  1170. // lParam is DIALOGARGS*
  1171. pDialogArgs = (DIALOGARGS*)lParam;
  1172. pPromptStruct = pDialogArgs->pPromptStruct;
  1173. // set the dialog title
  1174. if (pPromptStruct->szPrompt)
  1175. SetWindowTextU(hDlg, pPromptStruct->szPrompt);
  1176. InitializeDetailGlobals();
  1177. if(g_szDetailApplicationPath)
  1178. {
  1179. SetWindowTextU(GetDlgItem(hDlg, IDC_PROTECT_APP_PATH), g_szDetailApplicationPath);
  1180. }
  1181. if( pDialogArgs->fProtect ) {
  1182. ResourceId = IDS_PROTECT_OPERATION_PROTECT;
  1183. } else {
  1184. ResourceId = IDS_PROTECT_OPERATION_UNPROTECT;
  1185. }
  1186. LoadStringU(g_hInstProtectUI,
  1187. ResourceId,
  1188. szResource,
  1189. sizeof(szResource) / sizeof(WCHAR)
  1190. );
  1191. SetWindowTextU(GetDlgItem(hDlg, IDC_PROTECT_OPERATION_TYPE), szResource);
  1192. if( pDialogArgs->szDataDescription ) {
  1193. SetWindowTextU(GetDlgItem(hDlg, IDC_PROTECT_APP_DESCRIPTION), pDialogArgs->szDataDescription);
  1194. }
  1195. return FALSE;
  1196. } // WM_INITDIALOG
  1197. case WM_COMMAND:
  1198. {
  1199. switch(LOWORD(wParam))
  1200. {
  1201. case IDOK:
  1202. case IDCANCEL:
  1203. {
  1204. EndDialog(hDlg, LOWORD(wParam));
  1205. return TRUE;
  1206. }
  1207. default:
  1208. {
  1209. break;
  1210. }
  1211. }
  1212. } // WM_COMMAND
  1213. default:
  1214. {
  1215. return FALSE;
  1216. }
  1217. } // switch
  1218. return FALSE;
  1219. }
  1220. VOID
  1221. ComputePasswordHash(
  1222. IN PVOID pvPassword,
  1223. IN DWORD cbPassword,
  1224. IN OUT BYTE rgbPasswordHash[A_SHA_DIGEST_LEN]
  1225. )
  1226. /*++
  1227. Compute SHA-1 hash of supplied pvPassword of size cbPassword, returning
  1228. resultant hash in rgbPasswordHash buffer.
  1229. --*/
  1230. {
  1231. A_SHA_CTX shaCtx;
  1232. if( pvPassword == NULL )
  1233. return;
  1234. A_SHAInit( &shaCtx );
  1235. A_SHAUpdate( &shaCtx, (unsigned char*)pvPassword, (unsigned int)cbPassword );
  1236. A_SHAFinal( &shaCtx, rgbPasswordHash );
  1237. SecureZeroMemory( &shaCtx, sizeof(shaCtx) );
  1238. return;
  1239. }
  1240. BOOL
  1241. GetEffectiveLogonId(
  1242. IN OUT LUID *pLogonId
  1243. )
  1244. {
  1245. HANDLE hToken;
  1246. TOKEN_STATISTICS TokenInformation;
  1247. DWORD cbTokenInformation;
  1248. BOOL fSuccess;
  1249. if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken)) {
  1250. if(GetLastError() != ERROR_NO_TOKEN)
  1251. return FALSE;
  1252. if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
  1253. return FALSE;
  1254. }
  1255. fSuccess = GetTokenInformation(
  1256. hToken,
  1257. TokenStatistics,
  1258. &TokenInformation,
  1259. sizeof(TokenInformation),
  1260. &cbTokenInformation
  1261. );
  1262. CloseHandle( hToken );
  1263. if( fSuccess ) {
  1264. CopyMemory( pLogonId, &TokenInformation.AuthenticationId, sizeof(*pLogonId) );
  1265. }
  1266. return fSuccess;
  1267. }
  1268. BOOL
  1269. InitializeDetailGlobals(
  1270. VOID
  1271. )
  1272. {
  1273. WCHAR szStackBuffer[ 256 ];
  1274. DWORD cchStackBuffer;
  1275. LPWSTR szDetailApplicationName = NULL;
  1276. LPWSTR szDetailApplicationPath = NULL;
  1277. if( g_fDetailGlobalsInitialized )
  1278. return TRUE;
  1279. cchStackBuffer = sizeof(szStackBuffer) / sizeof(WCHAR);
  1280. cchStackBuffer = GetModuleFileNameU( NULL, szStackBuffer, cchStackBuffer );
  1281. if( cchStackBuffer ) {
  1282. cchStackBuffer++; // include terminal NULL.
  1283. szDetailApplicationPath = (LPWSTR)SSAlloc( cchStackBuffer * sizeof(WCHAR) );
  1284. if( szDetailApplicationPath ) {
  1285. CopyMemory( szDetailApplicationPath, szStackBuffer, cchStackBuffer*sizeof(WCHAR) );
  1286. }
  1287. }
  1288. EnterCriticalSection( &g_csProtectPasswordCache );
  1289. if( !g_fDetailGlobalsInitialized ) {
  1290. g_szDetailApplicationName = szDetailApplicationName;
  1291. g_szDetailApplicationPath = szDetailApplicationPath;
  1292. g_fDetailGlobalsInitialized = TRUE;
  1293. szDetailApplicationName = NULL;
  1294. szDetailApplicationPath = NULL;
  1295. }
  1296. LeaveCriticalSection( &g_csProtectPasswordCache );
  1297. if( szDetailApplicationName )
  1298. SSFree( szDetailApplicationName );
  1299. if( szDetailApplicationPath )
  1300. SSFree( szDetailApplicationPath );
  1301. return TRUE;
  1302. }
  1303. BOOL
  1304. InitializeProtectPasswordCache(
  1305. VOID
  1306. )
  1307. {
  1308. __try
  1309. {
  1310. InitializeCriticalSection( &g_csProtectPasswordCache );
  1311. }
  1312. __except(EXCEPTION_EXECUTE_HANDLER)
  1313. {
  1314. SecureZeroMemory(&g_csProtectPasswordCache, sizeof(g_csProtectPasswordCache));
  1315. SetLastError(GetExceptionCode());
  1316. return FALSE;
  1317. }
  1318. InitializeListHead( &g_ProtectPasswordCache );
  1319. g_fDetailGlobalsInitialized = FALSE;
  1320. g_szDetailApplicationName = NULL;
  1321. g_szDetailApplicationPath = NULL;
  1322. return TRUE;
  1323. }
  1324. VOID
  1325. DeleteProtectPasswordCache(
  1326. VOID
  1327. )
  1328. {
  1329. if( g_szDetailApplicationName )
  1330. {
  1331. SSFree(g_szDetailApplicationName);
  1332. g_szDetailApplicationName = NULL;
  1333. }
  1334. if( g_szDetailApplicationPath )
  1335. {
  1336. SSFree(g_szDetailApplicationPath);
  1337. g_szDetailApplicationPath = NULL;
  1338. }
  1339. g_fDetailGlobalsInitialized = FALSE;
  1340. EnterCriticalSection( &g_csProtectPasswordCache );
  1341. while ( !IsListEmpty( &g_ProtectPasswordCache ) ) {
  1342. PPASSWORD_CACHE_ENTRY pCacheEntry;
  1343. pCacheEntry = CONTAINING_RECORD(
  1344. g_ProtectPasswordCache.Flink,
  1345. PASSWORD_CACHE_ENTRY,
  1346. Next
  1347. );
  1348. RemoveEntryList( &pCacheEntry->Next );
  1349. SecureZeroMemory( pCacheEntry, sizeof(*pCacheEntry) );
  1350. SSFree( pCacheEntry );
  1351. }
  1352. LeaveCriticalSection( &g_csProtectPasswordCache );
  1353. DeleteCriticalSection( &g_csProtectPasswordCache );
  1354. }
  1355. BOOL
  1356. AddProtectPasswordCache(
  1357. IN DATA_BLOB* pDataIn,
  1358. IN BYTE rgbPassword[A_SHA_DIGEST_LEN]
  1359. )
  1360. {
  1361. PPASSWORD_CACHE_ENTRY pCacheEntry = NULL;
  1362. A_SHA_CTX shaCtx;
  1363. pCacheEntry = (PPASSWORD_CACHE_ENTRY)SSAlloc( sizeof(PASSWORD_CACHE_ENTRY) );
  1364. if( pCacheEntry == NULL )
  1365. return FALSE;
  1366. GetEffectiveLogonId( &pCacheEntry->LogonId );
  1367. GetSystemTimeAsFileTime( &pCacheEntry->ftLastAccess );
  1368. A_SHAInit( &shaCtx );
  1369. A_SHAUpdate( &shaCtx, (unsigned char*)pDataIn->pbData, pDataIn->cbData );
  1370. A_SHAFinal( &shaCtx, pCacheEntry->rgbDataInHash );
  1371. SecureZeroMemory( &shaCtx, sizeof(shaCtx) );
  1372. CopyMemory( pCacheEntry->rgbPasswordHash, rgbPassword, A_SHA_DIGEST_LEN );
  1373. EnterCriticalSection( &g_csProtectPasswordCache );
  1374. InsertHeadList( &g_ProtectPasswordCache, &pCacheEntry->Next );
  1375. LeaveCriticalSection( &g_csProtectPasswordCache );
  1376. return TRUE;
  1377. }
  1378. BOOL
  1379. SearchProtectPasswordCache(
  1380. IN DATA_BLOB* pDataIn,
  1381. IN OUT BYTE rgbPassword[A_SHA_DIGEST_LEN],
  1382. IN BOOL fDeleteFoundEntry
  1383. )
  1384. {
  1385. A_SHA_CTX shaCtx;
  1386. BYTE rgbDataInHashCandidate[A_SHA_DIGEST_LEN];
  1387. LUID LogonIdCandidate;
  1388. PLIST_ENTRY ListEntry;
  1389. PLIST_ENTRY ListHead;
  1390. BOOL fFoundMatch = FALSE;
  1391. if(!GetEffectiveLogonId( &LogonIdCandidate ))
  1392. return FALSE;
  1393. A_SHAInit( &shaCtx );
  1394. A_SHAUpdate( &shaCtx, (unsigned char*)pDataIn->pbData, pDataIn->cbData );
  1395. A_SHAFinal( &shaCtx, rgbDataInHashCandidate );
  1396. EnterCriticalSection( &g_csProtectPasswordCache );
  1397. ListHead = &g_ProtectPasswordCache;
  1398. for( ListEntry = ListHead->Flink;
  1399. ListEntry != ListHead;
  1400. ListEntry = ListEntry->Flink ) {
  1401. PPASSWORD_CACHE_ENTRY pCacheEntry;
  1402. signed int comparator;
  1403. pCacheEntry = CONTAINING_RECORD( ListEntry, PASSWORD_CACHE_ENTRY, Next );
  1404. //
  1405. // search by hash, then LogonId
  1406. // note that most usage scenarios, all cache entries will correspond
  1407. // to same LogonId.
  1408. //
  1409. comparator = memcmp( rgbDataInHashCandidate, pCacheEntry->rgbDataInHash, sizeof(rgbDataInHashCandidate) );
  1410. if( comparator != 0 )
  1411. continue;
  1412. comparator = memcmp(&LogonIdCandidate, &pCacheEntry->LogonId, sizeof(LUID));
  1413. if( comparator != 0 )
  1414. continue;
  1415. //
  1416. // match found.
  1417. //
  1418. fFoundMatch = TRUE;
  1419. if( fDeleteFoundEntry ) {
  1420. RemoveEntryList( &pCacheEntry->Next );
  1421. SecureZeroMemory( pCacheEntry, sizeof(*pCacheEntry) );
  1422. SSFree( pCacheEntry );
  1423. } else {
  1424. CopyMemory( rgbPassword, pCacheEntry->rgbPasswordHash, A_SHA_DIGEST_LEN );
  1425. //
  1426. // update last access time.
  1427. //
  1428. GetSystemTimeAsFileTime( &pCacheEntry->ftLastAccess );
  1429. }
  1430. break;
  1431. }
  1432. LeaveCriticalSection( &g_csProtectPasswordCache );
  1433. PurgeProtectPasswordCache();
  1434. return fFoundMatch;
  1435. }
  1436. VOID
  1437. PurgeProtectPasswordCache(
  1438. VOID
  1439. )
  1440. /*++
  1441. This routine purges entries in the password cache that are greater than
  1442. 1 hour in age, via the ftLastAccess time.
  1443. --*/
  1444. {
  1445. // static FILETIME ftLastPurge = {0xffffffff,0xffffffff};
  1446. static FILETIME ftLastPurge;
  1447. FILETIME ftStaleEntry;
  1448. PLIST_ENTRY ListEntry;
  1449. PLIST_ENTRY ListHead;
  1450. unsigned __int64 ui64;
  1451. //
  1452. // get current time, and subtract an hour off it.
  1453. //
  1454. GetSystemTimeAsFileTime( &ftStaleEntry );
  1455. ui64 = ftStaleEntry.dwHighDateTime;
  1456. ui64 <<= 32;
  1457. ui64 |= ftStaleEntry.dwLowDateTime;
  1458. // ui64 -= (600000000*60);
  1459. ui64 -= 0x861c46800;
  1460. ftStaleEntry.dwLowDateTime = (DWORD)(ui64 & 0xffffffff);
  1461. ftStaleEntry.dwHighDateTime = (DWORD)(ui64 >> 32);
  1462. //
  1463. // only purge list once per hour.
  1464. //
  1465. if( CompareFileTime( &ftStaleEntry, &ftLastPurge ) < 0 ) {
  1466. return;
  1467. }
  1468. //
  1469. // update last purge time.
  1470. //
  1471. GetSystemTimeAsFileTime( &ftLastPurge );
  1472. EnterCriticalSection( &g_csProtectPasswordCache );
  1473. ListHead = &g_ProtectPasswordCache;
  1474. for( ListEntry = ListHead->Flink;
  1475. ListEntry != ListHead;
  1476. ListEntry = ListEntry->Flink ) {
  1477. PPASSWORD_CACHE_ENTRY pCacheEntry;
  1478. signed int comparator;
  1479. pCacheEntry = CONTAINING_RECORD( ListEntry, PASSWORD_CACHE_ENTRY, Next );
  1480. if( CompareFileTime( &ftStaleEntry, &pCacheEntry->ftLastAccess ) > 0 )
  1481. {
  1482. ListEntry = ListEntry->Blink;
  1483. RemoveEntryList( &pCacheEntry->Next );
  1484. SecureZeroMemory( pCacheEntry, sizeof(*pCacheEntry) );
  1485. SSFree( pCacheEntry );
  1486. }
  1487. }
  1488. LeaveCriticalSection( &g_csProtectPasswordCache );
  1489. return;
  1490. }
  1491. BOOL
  1492. IsCachePWAllowed(
  1493. VOID
  1494. )
  1495. {
  1496. HKEY hKeyProtect;
  1497. DWORD dwType;
  1498. DWORD dwValue;
  1499. DWORD cbValue;
  1500. LONG lRet;
  1501. lRet = RegOpenKeyExU(
  1502. HKEY_LOCAL_MACHINE,
  1503. L"SOFTWARE\\Policies\\Microsoft\\Cryptography\\Protect",
  1504. 0,
  1505. KEY_QUERY_VALUE,
  1506. &hKeyProtect
  1507. );
  1508. if( lRet != ERROR_SUCCESS )
  1509. return TRUE;
  1510. cbValue = sizeof(dwValue);
  1511. lRet = RegQueryValueExU(
  1512. hKeyProtect,
  1513. L"AllowCachePW",
  1514. NULL,
  1515. &dwType,
  1516. (PBYTE)&dwValue,
  1517. &cbValue
  1518. );
  1519. RegCloseKey( hKeyProtect );
  1520. if( lRet == ERROR_SUCCESS && dwType == REG_DWORD && dwValue == 0 ) {
  1521. return FALSE;
  1522. }
  1523. return TRUE;
  1524. }