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.

3397 lines
90 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. recovery.cpp
  5. Abstract:
  6. This module implements the callout from winlogon to set
  7. recovery policy.
  8. Author:
  9. Robert Reichel (RobertRe)
  10. Revision History:
  11. --*/
  12. //
  13. // Turn off lean and mean so we get wincrypt.h and winefs.h included
  14. //
  15. #undef WIN32_LEAN_AND_MEAN
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <ntlsa.h>
  20. #include <windows.h>
  21. #include <stdio.h>
  22. #include <lmcons.h>
  23. #include <cryptui.h>
  24. #include <winwlx.h>
  25. #include <malloc.h>
  26. #include <feclient.h>
  27. #include <efsstruc.h>
  28. #include <netlib.h>
  29. #include <secobj.h>
  30. #include <initguid.h>
  31. #include <gpedit.h>
  32. #include <wincrypt.h>
  33. #include <winreg.h>
  34. #include <dsrole.h>
  35. #include <winldap.h>
  36. #include <dsgetdc.h>
  37. #include <ntdsapi.h>
  38. #include "sclgntfy.hxx"
  39. #define YEARCOUNT (LONGLONG) 10000000*3600*24*365 // One Year's tick count
  40. typedef BOOL (WINAPI *PFREFRESHPOLICY)(BOOL);
  41. extern HINSTANCE g_hDllInstance;
  42. HANDLE hEventLog = NULL;
  43. TCHAR EventSourceName[] = TEXT("SclgNtfy");
  44. TCHAR MS[] = TEXT("\\Microsoft");
  45. TCHAR REMOTEINSTALL[] = TEXT("\\RemoteInstall");
  46. TCHAR FILTERNAME[] = TEXT("\\oscfilter.ini");
  47. GUID guidExtension = { 0xb1be8d72, 0x6eac, 0x11d2, {0xa4, 0xea, 0x00, 0xc0, 0x4f, 0x79, 0xf8, 0x3a }};
  48. GUID guidRegExt = REGISTRY_EXTENSION_GUID;
  49. GUID guidSnapin = {0x53D6AB1B,0x2488,0x11d1,{0xA2,0x8C,0x00,0xC0,0x4F,0xB9,0x4F,0x17}}; // CLSID_CertificateManager
  50. //
  51. // Event handle
  52. //
  53. PTOKEN_USER
  54. GetTokenUser(
  55. HANDLE TokenHandle
  56. );
  57. BOOLEAN
  58. CreateSelfSignedRecoveryCertificate(
  59. IN BOOL bIsDC,
  60. OUT PCCERT_CONTEXT * pCertContext
  61. );
  62. BOOL
  63. EncodeAndAlloc(
  64. DWORD dwEncodingType,
  65. LPCSTR lpszStructType,
  66. const void * pvStructInfo,
  67. PBYTE * pbEncoded,
  68. PDWORD pcbEncoded
  69. );
  70. LPWSTR
  71. MakeDNName(
  72. VOID
  73. );
  74. DWORD
  75. CreatePublicKeyInformationCertificate(
  76. IN PSID pUserSid OPTIONAL,
  77. PBYTE pbCert,
  78. DWORD cbCert,
  79. OUT PEFS_PUBLIC_KEY_INFO * PublicKeyInformation
  80. );
  81. DWORD
  82. GetDefaultRecoveryPolicy(
  83. IN HANDLE hToken,
  84. IN BOOL bIsDC,
  85. OUT PUCHAR *pRecoveryPolicyBlob,
  86. OUT ULONG *PolicySize,
  87. OUT PCCERT_CONTEXT *ppCertContext
  88. );
  89. HRESULT
  90. CreateLocalMachinePolicy(
  91. IN PWLX_NOTIFICATION_INFO pInfo,
  92. IN BOOL bIsDC,
  93. OUT PUCHAR *pEfsBlob,
  94. OUT ULONG *pEfsSize,
  95. OUT PCCERT_CONTEXT *ppCertContext
  96. );
  97. typedef DWORD (WINAPI *PFNDSGETDCNAME)(LPCTSTR, LPCTSTR, GUID *, LPCTSTR, ULONG, PDOMAIN_CONTROLLER_INFO *);
  98. HRESULT
  99. CreateEFSDefaultPolicy(
  100. IN HANDLE hToken,
  101. IN PUCHAR *pEfsBlob,
  102. IN DWORD *pEfsSize,
  103. IN PCCERT_CONTEXT *ppCertContext,
  104. IN LPTSTR DomainName
  105. );
  106. DWORD
  107. MyLdapOpen(
  108. OUT PLDAP *pLdap
  109. );
  110. DWORD
  111. MyGetDsObjectRoot(
  112. IN PLDAP pLdap,
  113. OUT PWSTR *pDsRootName
  114. );
  115. HRESULT
  116. CreateGroupPolicyObjectInDomain(
  117. IN HANDLE hToken,
  118. IN PWSTR DomainNCName,
  119. IN PWSTR GPObjectName,
  120. IN PUCHAR EfsBlob,
  121. IN ULONG EfsSize,
  122. IN PCCERT_CONTEXT pCertContext,
  123. OUT LPGROUPPOLICYOBJECT *ppObject
  124. );
  125. BOOL
  126. MyIsAdmin(
  127. IN HANDLE hToken
  128. );
  129. DWORD
  130. CheckExistingEFSPolicy(
  131. IN PLDAP phLdap,
  132. IN LPTSTR DomainNCName,
  133. OUT BOOL *bExist
  134. );
  135. DWORD
  136. MyLdapClose(
  137. IN PLDAP *pLdap
  138. );
  139. LPWSTR
  140. GetCertDisplayInformation(
  141. IN PCCERT_CONTEXT pCertContext
  142. );
  143. BOOLEAN
  144. IsSelfSignedPolicyExpired(
  145. IN PRECOVERY_POLICY_1_1 RecoveryPolicy OPTIONAL
  146. );
  147. #define EFS_NOTIFY_PATH TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify\\EFS")
  148. extern "C"
  149. BOOL
  150. EfsRecInit(
  151. IN PVOID hmod,
  152. IN ULONG Reason,
  153. IN PCONTEXT Context
  154. )
  155. {
  156. return( TRUE );
  157. UNREFERENCED_PARAMETER(hmod);
  158. UNREFERENCED_PARAMETER(Reason);
  159. UNREFERENCED_PARAMETER(Context);
  160. }
  161. /////////////////////////////////////////////////////////////////////////////
  162. // DllRegisterServer - Adds entries to the system registry
  163. STDAPI DllRegisterServerEFS(void)
  164. {
  165. HKEY hKey;
  166. LONG lResult;
  167. DWORD dwDisp;
  168. lResult = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  169. EFS_NOTIFY_PATH,
  170. 0,
  171. NULL,
  172. REG_OPTION_NON_VOLATILE,
  173. KEY_WRITE,
  174. NULL,
  175. &hKey,
  176. &dwDisp
  177. );
  178. if (lResult != ERROR_SUCCESS)
  179. {
  180. return lResult;
  181. }
  182. lResult = RegSetValueEx( hKey,
  183. TEXT("Logon"),
  184. 0,
  185. REG_SZ,
  186. (LPBYTE)TEXT("WLEventLogon"),
  187. (lstrlen(TEXT("WLEventLogon")) + 1) * sizeof(TCHAR)
  188. );
  189. if (lResult == ERROR_SUCCESS) {
  190. lResult = RegSetValueEx( hKey,
  191. TEXT("DllName"),
  192. 0,
  193. REG_EXPAND_SZ,
  194. (LPBYTE)TEXT("sclgntfy.dll"),
  195. (lstrlen(TEXT("sclgntfy.dll")) + 1) * sizeof(TCHAR)
  196. );
  197. if (lResult == ERROR_SUCCESS) {
  198. //
  199. // increase the wait limit to 5 minutes
  200. //
  201. DWORD dwValue = 300;
  202. lResult = RegSetValueEx( hKey,
  203. TEXT("MaxWait"),
  204. 0,
  205. REG_DWORD,
  206. (LPBYTE)&dwValue,
  207. sizeof(DWORD)
  208. );
  209. }
  210. }
  211. RegCloseKey (hKey);
  212. return lResult;
  213. }
  214. /////////////////////////////////////////////////////////////////////////////
  215. // DllUnregisterServer - Removes entries from the system registry
  216. STDAPI DllUnregisterServerEFS(void)
  217. {
  218. RegDeleteKey (HKEY_LOCAL_MACHINE, EFS_NOTIFY_PATH);
  219. return S_OK;
  220. }
  221. DWORD WINAPI
  222. EFSRecPolicyPostProcess(
  223. IN LPVOID Param
  224. )
  225. /*++
  226. Routine Description:
  227. Enumerate the volumes and do the possible recovery jobs caused by
  228. power outage or crash during encryption or decryption.
  229. Arguments:
  230. Param -- Standard parameter for thread. Not used.
  231. Return Value:
  232. Operation result.
  233. --*/
  234. {
  235. PEFS_POLICY_POST_PROCESS pPcType = (PEFS_POLICY_POST_PROCESS) Param;
  236. LPWSTR objName = NULL;
  237. LPWSTR popUpMsg = NULL;
  238. LPWSTR popUpTitle = NULL;
  239. DWORD dRet;
  240. DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1;
  241. if ( pPcType == NULL ) {
  242. return(ERROR_INVALID_PARAMETER);
  243. }
  244. if (!SetThreadDesktop( pPcType->ShellWnd )){
  245. return GetLastError();
  246. }
  247. if (!(pPcType->PCIsDC)) {
  248. //
  249. // Get the PC name
  250. //
  251. BOOL b = GetComputerName ( pPcType->ObjName, &nSize );
  252. if (b) {
  253. objName = pPcType->ObjName;
  254. }
  255. } else {
  256. objName = pPcType->ObjName;
  257. }
  258. dRet = FormatMessage(
  259. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  260. g_hDllInstance,
  261. EFS_POLICY_WARNING,
  262. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  263. (LPTSTR) &popUpMsg,
  264. 0,
  265. (va_list *)&objName
  266. );
  267. if (dRet) {
  268. dRet = FormatMessage(
  269. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY | 80,
  270. g_hDllInstance,
  271. EFS_POLICY_WARNING_TITLE,
  272. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  273. (LPTSTR) &popUpTitle,
  274. 0,
  275. NULL
  276. );
  277. if (dRet) {
  278. MessageBox(NULL, popUpMsg, popUpTitle, MB_OK | MB_ICONINFORMATION);
  279. LocalFree( popUpTitle );
  280. }
  281. LocalFree( popUpMsg );
  282. }
  283. //
  284. // free the buffer allocated
  285. //
  286. LocalFree(pPcType);
  287. return 0;
  288. }
  289. #if 0
  290. DWORD
  291. EFSRecPolicyPopup(
  292. IN DSROLE_MACHINE_ROLE MachineRole,
  293. IN LPTSTR DomainNameFlat OPTIONAL
  294. )
  295. {
  296. DWORD EFSRecPolicyThreadID;
  297. HANDLE EfsWarningThread;
  298. PEFS_POLICY_POST_PROCESS PcType = NULL;
  299. //
  300. // Pop the dialog warning the user that the recovery policy has been created.
  301. //
  302. PcType = (PEFS_POLICY_POST_PROCESS)LocalAlloc(LPTR, sizeof(EFS_POLICY_POST_PROCESS));
  303. if ( PcType == NULL ) {
  304. return(ERROR_NOT_ENOUGH_MEMORY);
  305. }
  306. if (MachineRole == DsRole_RolePrimaryDomainController ||
  307. MachineRole == DsRole_RoleBackupDomainController ) {
  308. //
  309. // The PC is a DC.
  310. //
  311. PcType->PCIsDC = TRUE;
  312. if ( DomainNameFlat) {
  313. wcscpy(PcType->ObjName,DomainNameFlat);
  314. } else {
  315. PcType->ObjName[0] = L'\0';
  316. }
  317. } else {
  318. PcType->PCIsDC = FALSE;
  319. PcType->ObjName[0] = L'\0';
  320. }
  321. DWORD rc=ERROR_SUCCESS;
  322. PcType->ShellWnd = GetThreadDesktop( GetCurrentThreadId() );
  323. if (PcType->ShellWnd) {
  324. EfsWarningThread = CreateThread( NULL,
  325. 0,
  326. EFSRecPolicyPostProcess,
  327. PcType,
  328. 0,
  329. &EFSRecPolicyThreadID
  330. );
  331. if (EfsWarningThread) {
  332. CloseHandle(EfsWarningThread);
  333. } else {
  334. //
  335. // free the buffer allocated
  336. //
  337. LocalFree(PcType);
  338. rc = GetLastError();
  339. }
  340. } else {
  341. //
  342. // free the buffer allocated
  343. //
  344. LocalFree(PcType);
  345. rc = GetLastError();
  346. }
  347. return rc;
  348. }
  349. #endif
  350. VOID WLEventLogon(
  351. PWLX_NOTIFICATION_INFO pInfo
  352. )
  353. {
  354. //
  355. // First, local EFS policy is always created on all products (wks, srv, DC)
  356. //
  357. DWORD rc;
  358. LONG lResult;
  359. HKEY hKey;
  360. DWORD IsCreated=0;
  361. //
  362. // even if we were unregistered, without a reboot, we still get this event.
  363. // use the EFS... key to see if we were deregistered, and if so, leave.
  364. //
  365. lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  366. EFS_NOTIFY_PATH,
  367. 0,
  368. MAXIMUM_ALLOWED,
  369. &hKey
  370. );
  371. if (lResult != ERROR_SUCCESS) {
  372. return;
  373. } else {
  374. //
  375. // query if a domain EFS policy was created before
  376. //
  377. DWORD RegType;
  378. DWORD nSize=sizeof(DWORD);
  379. RegQueryValueEx(
  380. hKey,
  381. L"EFSDomainGPOCreated",
  382. 0,
  383. &RegType,
  384. (LPBYTE)&IsCreated,
  385. &nSize
  386. );
  387. RegCloseKey( hKey );
  388. }
  389. if (IsCreated != 0) {
  390. //
  391. // The DC recovery policy is already set
  392. //
  393. DllUnregisterServerEFS();
  394. return;
  395. }
  396. //
  397. // check the current logon user. If not a member of administrators, quit
  398. //
  399. if ( !MyIsAdmin(pInfo->hToken) ) {
  400. //
  401. // if it's not admin logon, or for some reason token membership can't
  402. // be checked, quit ???
  403. //
  404. return;
  405. }
  406. //
  407. // impersonate the token
  408. //
  409. if ( FALSE == ImpersonateLoggedOnUser(pInfo->hToken) ) {
  410. return;
  411. }
  412. //
  413. // initialize event log. If failed, will try later for each LogEvent call.
  414. //
  415. (void) InitializeEvents();
  416. //
  417. // check the machine role
  418. //
  419. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole;
  420. rc = DsRoleGetPrimaryDomainInformation(
  421. NULL,
  422. DsRolePrimaryDomainInfoBasic,
  423. (PBYTE *)&pDsRole
  424. );
  425. if (rc != ERROR_SUCCESS) {
  426. //
  427. // Try again some other time? Deregister?
  428. // This isn't supposed to happen.
  429. //
  430. LogEvent(STATUS_SEVERITY_ERROR,
  431. GPOEVENT_ERROR_DSROLE,
  432. IDS_FAILED_GET_DSROLE,
  433. GetLastError()
  434. );
  435. (void) ShutdownEvents();
  436. RevertToSelf();
  437. return;
  438. }
  439. DSROLE_MACHINE_ROLE MachineRole = pDsRole->MachineRole;
  440. if (MachineRole != DsRole_RolePrimaryDomainController) {
  441. //
  442. // We don't create EFS recovery policy on non-PDC
  443. //
  444. (void) ShutdownEvents();
  445. DsRoleFreeMemory( pDsRole );
  446. RevertToSelf();
  447. DllUnregisterServerEFS();
  448. return;
  449. }
  450. //
  451. // create the EFS local policy if not exist
  452. //
  453. CoInitialize(NULL);
  454. HRESULT hr = ERROR_SUCCESS;
  455. PUCHAR EfsBlob=NULL;
  456. ULONG EfsSize=0;
  457. PCCERT_CONTEXT pCertContext=NULL;
  458. /*
  459. //
  460. // check/create EFS policy in the local machine object
  461. //
  462. hr = CreateLocalMachinePolicy(
  463. pInfo,
  464. ( MachineRole == DsRole_RolePrimaryDomainController ) ? TRUE : FALSE,
  465. &EfsBlob,
  466. &EfsSize,
  467. &pCertContext
  468. );
  469. if ( SUCCEEDED(hr) ) {
  470. //
  471. // local machine policy has been successfully created
  472. // delete the SystemClone flag if it exists (or set it to 0 if it can't be deleted)
  473. //
  474. lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  475. EFS_NOTIFY_PATH,
  476. 0,
  477. MAXIMUM_ALLOWED,
  478. &hKey
  479. );
  480. if (lResult == ERROR_SUCCESS) {
  481. lResult = RegDeleteValue (hKey, TEXT("SystemCloned") );
  482. if ( lResult == ERROR_ACCESS_DENIED ) {
  483. //
  484. // can't delete it, now set it to 0
  485. //
  486. DWORD dwClone = 0;
  487. RegSetValueEx( hKey,
  488. TEXT("SystemCloned"),
  489. 0,
  490. REG_DWORD,
  491. (LPBYTE)&dwClone,
  492. sizeof(DWORD)
  493. );
  494. }
  495. RegCloseKey( hKey );
  496. }
  497. //
  498. // detect the role of this computer and create the default EFS group
  499. // policies for domain controllers
  500. //
  501. // this code is also executed for replicas because if the user logs on
  502. // to replica first (before logging onto the PDC), we still want to
  503. // have EFS recovery policy created.
  504. //
  505. // if the replica is a READ ONLY replica (BDC), this call will fail
  506. //
  507. if ( (MachineRole == DsRole_RolePrimaryDomainController) &&
  508. ( IsCreated == 0) ) {
  509. //
  510. // Create the default group policy object and add it to the gPLink list.
  511. //
  512. if ( EfsBlob == NULL ) {
  513. EfsSize = 0;
  514. if ( pCertContext ) {
  515. //
  516. // free it first
  517. //
  518. CertFreeCertificateContext( pCertContext );
  519. pCertContext = NULL;
  520. }
  521. }
  522. */
  523. //
  524. // create both EFS default policy and domain account policy objects.
  525. //
  526. hr = CreateEFSDefaultPolicy(pInfo->hToken,
  527. &EfsBlob,
  528. &EfsSize,
  529. &pCertContext,
  530. pDsRole->DomainNameFlat);
  531. if ( SUCCEEDED(hr) ) {
  532. //
  533. // update the registry value EFSDomainGPOCreated
  534. //
  535. lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  536. EFS_NOTIFY_PATH,
  537. 0,
  538. MAXIMUM_ALLOWED,
  539. &hKey
  540. );
  541. if (lResult == ERROR_SUCCESS) {
  542. //
  543. // set the flag
  544. //
  545. IsCreated = 1;
  546. RegSetValueEx( hKey,
  547. L"EFSDomainGPOCreated",
  548. 0,
  549. REG_DWORD,
  550. (LPBYTE)&IsCreated,
  551. sizeof(DWORD)
  552. );
  553. RegCloseKey( hKey );
  554. }
  555. }
  556. /*
  557. } else {
  558. //
  559. // the domain GPO is already created, or
  560. //
  561. // If it's workstation or server (either standalone or member), local policy
  562. // (existing or just created) is enough.
  563. //
  564. //
  565. // If it's a backup domain controller (replica), no need to create any
  566. // default ( because either the one replicated from the primary domain
  567. // or the one created by server setup will take effect );
  568. //
  569. // !!! do nothing !!!
  570. }
  571. */
  572. if ( SUCCEEDED(hr) ) {
  573. DllUnregisterServerEFS();
  574. HINSTANCE hUserEnvDll = LoadLibrary(TEXT("userenv.dll"));
  575. PFREFRESHPOLICY pfRefreshPolicy=NULL;
  576. if ( hUserEnvDll) {
  577. pfRefreshPolicy = (PFREFRESHPOLICY)GetProcAddress(
  578. hUserEnvDll,
  579. "RefreshPolicy");
  580. if ( pfRefreshPolicy ) {
  581. //
  582. // do not care errors
  583. //
  584. (void) (*pfRefreshPolicy)(TRUE);
  585. } else {
  586. LogEvent(STATUS_SEVERITY_WARNING,
  587. GPOEVENT_WARNING_NOT_REFRESH,
  588. IDS_ERROR_GET_PROC_ADDR,
  589. GetLastError()
  590. );
  591. }
  592. FreeLibrary(hUserEnvDll);
  593. } else {
  594. LogEvent(STATUS_SEVERITY_WARNING,
  595. GPOEVENT_WARNING_NOT_REFRESH,
  596. IDS_ERROR_LOAD_USERENV,
  597. GetLastError()
  598. );
  599. }
  600. }
  601. // }
  602. if (pDsRole) {
  603. DsRoleFreeMemory( pDsRole );
  604. }
  605. (void) ShutdownEvents();
  606. //
  607. // uninitialize OLE
  608. //
  609. CoUninitialize();
  610. RevertToSelf();
  611. //
  612. // clean up buffers
  613. //
  614. if ( EfsBlob ) {
  615. free(EfsBlob);
  616. }
  617. if ( pCertContext ) {
  618. CertFreeCertificateContext( pCertContext );
  619. }
  620. }
  621. #if 0
  622. HRESULT
  623. CreateLocalMachinePolicy(
  624. IN PWLX_NOTIFICATION_INFO pInfo,
  625. IN BOOL bIsDC,
  626. OUT PUCHAR *pEfsBlob,
  627. OUT ULONG *pEfsSize,
  628. OUT PCCERT_CONTEXT *ppCertContext
  629. )
  630. {
  631. LPGROUPPOLICYOBJECT pGPO = NULL;
  632. HRESULT hr;
  633. HKEY hKeyPolicyRoot;
  634. HKEY hKey;
  635. DWORD rc=ERROR_SUCCESS;
  636. //
  637. // create Policy Object instance
  638. //
  639. hr = CoCreateInstance( CLSID_GroupPolicyObject,
  640. NULL,
  641. CLSCTX_SERVER,
  642. IID_IGroupPolicyObject,
  643. (PVOID *)&pGPO
  644. );
  645. if (SUCCEEDED(hr) && pGPO) {
  646. //
  647. // open LPO and load policy into registry
  648. // if LPO does not exist, create it (under system context now)
  649. //
  650. hr = pGPO->OpenLocalMachineGPO( TRUE );
  651. if (SUCCEEDED(hr)) {
  652. //
  653. // get the registry key for the root of machine policy object
  654. //
  655. hr = pGPO->GetRegistryKey( GPO_SECTION_MACHINE,
  656. &hKeyPolicyRoot
  657. );
  658. if (SUCCEEDED(hr)) {
  659. //
  660. // open EFS recovery policy base key in the registry
  661. //
  662. BOOL fContinue = TRUE;
  663. DWORD dwDisposition;
  664. if ( (rc = RegCreateKeyEx(
  665. hKeyPolicyRoot,
  666. CERT_EFSBLOB_REGPATH,
  667. 0,
  668. TEXT("REG_SZ"),
  669. REG_OPTION_NON_VOLATILE,
  670. KEY_ALL_ACCESS,
  671. NULL,
  672. &hKey,
  673. &dwDisposition
  674. )) == ERROR_SUCCESS ) {
  675. //
  676. // check to see if there is EFS blob
  677. // if not, create it.
  678. //
  679. DWORD RegType;
  680. DWORD EfsSize;
  681. PUCHAR pEfsOldBlob=NULL;
  682. BOOL bIsExpired=FALSE;
  683. rc = RegQueryValueEx(
  684. hKey,
  685. CERT_EFSBLOB_VALUE_NAME,
  686. 0,
  687. &RegType,
  688. NULL,
  689. &EfsSize
  690. );
  691. if ( rc == ERROR_SUCCESS && EfsSize > 0 ) {
  692. //
  693. // query if this machine is cloned
  694. //
  695. HKEY hKeyClone;
  696. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  697. EFS_NOTIFY_PATH,
  698. 0,
  699. MAXIMUM_ALLOWED,
  700. &hKeyClone
  701. );
  702. if (rc == ERROR_SUCCESS) {
  703. DWORD nSize=sizeof(DWORD);
  704. DWORD dwClone=0;
  705. RegQueryValueEx(
  706. hKeyClone,
  707. L"SystemCloned",
  708. 0,
  709. &RegType,
  710. (LPBYTE)&dwClone,
  711. &nSize
  712. );
  713. RegCloseKey( hKeyClone );
  714. if ( dwClone > 0 ) {
  715. bIsExpired = TRUE;
  716. }
  717. }
  718. if ( !bIsExpired ) {
  719. //
  720. // EFS recovery policy already exists
  721. // query the blob and check if this policy needs to be
  722. // upgraded (change expiration date)
  723. //
  724. pEfsOldBlob = (PUCHAR)LocalAlloc(LPTR, EfsSize+1);
  725. if ( pEfsOldBlob ) {
  726. rc = RegQueryValueEx(
  727. hKey,
  728. CERT_EFSBLOB_VALUE_NAME,
  729. 0,
  730. &RegType,
  731. pEfsOldBlob,
  732. &EfsSize
  733. );
  734. if ( rc == ERROR_SUCCESS ) {
  735. //
  736. // check if the policy should be recreated.
  737. //
  738. bIsExpired = IsSelfSignedPolicyExpired((PRECOVERY_POLICY_1_1)pEfsOldBlob);
  739. }
  740. LocalFree(pEfsOldBlob);
  741. pEfsOldBlob = NULL;
  742. } else {
  743. rc = ERROR_NOT_ENOUGH_MEMORY;
  744. }
  745. }
  746. }
  747. if ( rc != ERROR_SUCCESS || EfsSize == 0 || bIsExpired ) {
  748. //
  749. // the EFSBlob registry value does not exis
  750. // this means that local EFS policy should be created
  751. //
  752. *pEfsSize = 0;
  753. rc = GetDefaultRecoveryPolicy(pInfo->hToken,
  754. bIsDC,
  755. pEfsBlob,
  756. pEfsSize,
  757. ppCertContext
  758. );
  759. if ( ERROR_SUCCESS == rc && *ppCertContext ) {
  760. //
  761. // add to the cert store of this GPO first
  762. //
  763. CERT_SYSTEM_STORE_RELOCATE_PARA paraRelocate;
  764. paraRelocate.hKeyBase = hKeyPolicyRoot;
  765. paraRelocate.pwszSystemStore = L"EFS";
  766. HCERTSTORE hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
  767. 0,
  768. NULL,
  769. CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY |
  770. CERT_SYSTEM_STORE_RELOCATE_FLAG,
  771. (void *)&paraRelocate
  772. );
  773. if ( hCertStore ) {
  774. if ( bIsExpired ) {
  775. //
  776. // delete all old certs from the store first
  777. //
  778. PCCERT_CONTEXT pEnumCertContext = CertEnumCertificatesInStore(
  779. hCertStore,
  780. NULL
  781. );
  782. PCCERT_CONTEXT pCertContextDelete=NULL;
  783. while ( pEnumCertContext ) {
  784. //
  785. // duplicate the cert context
  786. //
  787. pCertContextDelete = CertDuplicateCertificateContext( pEnumCertContext );
  788. //
  789. // enumerate the next certificate context
  790. //
  791. pEnumCertContext = CertEnumCertificatesInStore(
  792. hCertStore,
  793. pEnumCertContext
  794. );
  795. if ( pCertContextDelete ) {
  796. //
  797. // delete the cert from store
  798. //
  799. CertDeleteCertificateFromStore( pCertContextDelete );
  800. //
  801. // no need to free the cert context
  802. // because it's freed by the previous call (even under error case)
  803. //
  804. pCertContextDelete = NULL;
  805. }
  806. }
  807. }
  808. if ( !CertAddCertificateContextToStore(
  809. hCertStore,
  810. *ppCertContext,
  811. CERT_STORE_ADD_ALWAYS,
  812. NULL
  813. ) ) {
  814. rc = GetLastError();
  815. }
  816. //
  817. // close the store
  818. //
  819. CertCloseStore(hCertStore, 0);
  820. hCertStore = NULL;
  821. } else {
  822. rc = GetLastError();
  823. }
  824. if ( ERROR_SUCCESS == rc ) {
  825. rc = RegSetValueEx(
  826. hKey,
  827. CERT_EFSBLOB_VALUE_NAME,
  828. 0,
  829. REG_BINARY,
  830. (PBYTE)(*pEfsBlob),
  831. *pEfsSize
  832. );
  833. if (rc == ERROR_SUCCESS) {
  834. hr = pGPO->Save(TRUE, TRUE, &guidExtension, &guidSnapin );
  835. hr = pGPO->Save(TRUE, TRUE, &guidRegExt, &guidSnapin );
  836. if ( FAILED(hr) ) {
  837. LogEvent(STATUS_SEVERITY_ERROR,
  838. GPOEVENT_ERROR_CREATE_LPO,
  839. IDS_ERROR_SAVE_LPO,
  840. hr
  841. );
  842. } else {
  843. /* comment out due to PM request
  844. //
  845. // popup a message to warn user
  846. //
  847. EFSRecPolicyPopup(
  848. DsRole_RoleStandaloneWorkstation, // this value doesn't matter
  849. NULL
  850. );
  851. */
  852. }
  853. } else {
  854. LogEvent(STATUS_SEVERITY_ERROR,
  855. GPOEVENT_ERROR_CREATE_LPO,
  856. IDS_ERROR_SAVE_EFSBLOB,
  857. rc
  858. );
  859. }
  860. } else {
  861. LogEvent(STATUS_SEVERITY_ERROR,
  862. GPOEVENT_ERROR_CREATE_LPO,
  863. IDS_ERROR_ADD_CERTIFICATE,
  864. rc
  865. );
  866. }
  867. } else {
  868. LogEvent(STATUS_SEVERITY_ERROR,
  869. GPOEVENT_ERROR_CREATE_LPO,
  870. IDS_ERROR_CREATE_EFSBLOB,
  871. rc
  872. );
  873. }
  874. }
  875. //
  876. // close the registry key
  877. //
  878. RegCloseKey(hKey);
  879. } else {
  880. LogEvent(STATUS_SEVERITY_ERROR,
  881. GPOEVENT_ERROR_CREATE_LPO,
  882. IDS_ERROR_OPEN_EFSKEY,
  883. rc
  884. );
  885. }
  886. if ( rc != ERROR_SUCCESS ) {
  887. hr = HRESULT_FROM_WIN32(rc);
  888. }
  889. RegCloseKey(hKeyPolicyRoot);
  890. } else {
  891. LogEvent(STATUS_SEVERITY_ERROR,
  892. GPOEVENT_ERROR_CREATE_LPO,
  893. IDS_ERROR_GET_REGISTRY_KEY,
  894. hr
  895. );
  896. }
  897. } else {
  898. LogEvent(STATUS_SEVERITY_ERROR,
  899. GPOEVENT_ERROR_CREATE_LPO,
  900. IDS_ERROR_OPEN_LPO,
  901. hr
  902. );
  903. }
  904. //
  905. // release the policy object instance
  906. //
  907. pGPO->Release();
  908. } else {
  909. LogEvent(STATUS_SEVERITY_ERROR,
  910. GPOEVENT_ERROR_CREATE_LPO,
  911. IDS_ERROR_CREATE_GPO_INSTANCE,
  912. hr
  913. );
  914. }
  915. return hr;
  916. }
  917. #endif
  918. DWORD
  919. GetDefaultRecoveryPolicy(
  920. IN HANDLE hToken,
  921. IN BOOL bIsDC,
  922. OUT PUCHAR *pRecoveryPolicyBlob,
  923. OUT ULONG *BlobSize,
  924. OUT PCCERT_CONTEXT *ppCertContext
  925. )
  926. /*++
  927. Routine Description:
  928. This routine creates the default recovery policy for the current system.
  929. It does this by auto-generating a recovery key based on the name of the
  930. machine.
  931. Arguments:
  932. hToken - the token of current user
  933. pRecoveryPolicyBlob - the output buffer to hold EFSBlob
  934. BlobSize - the size of EFSBlob
  935. Return Value:
  936. --*/
  937. {
  938. DWORD rc = ERROR_SUCCESS;
  939. PCCERT_CONTEXT pCertContext;
  940. *pRecoveryPolicyBlob = NULL;
  941. *BlobSize = 0;
  942. *ppCertContext = NULL;
  943. if (CreateSelfSignedRecoveryCertificate(
  944. bIsDC,
  945. &pCertContext
  946. )) {
  947. PEFS_PUBLIC_KEY_INFO PublicKeyInformation;
  948. PBYTE pbCert = pCertContext->pbCertEncoded;
  949. DWORD cbCert = pCertContext->cbCertEncoded;
  950. PTOKEN_USER pTokenUser = GetTokenUser( hToken );
  951. if (pTokenUser) {
  952. rc = CreatePublicKeyInformationCertificate(
  953. pTokenUser->User.Sid,
  954. pbCert,
  955. cbCert,
  956. &PublicKeyInformation
  957. );
  958. if (rc == ERROR_SUCCESS) {
  959. //
  960. // Compute the total size of the RECOVERY_POLICY_1_1 structure, which
  961. // is the size of the structure minus the size of the EFS_PUBLIC_KEY_INFO
  962. // plus the size of the thing we just created above.
  963. //
  964. ULONG RecoveryKeySize = sizeof( RECOVERY_KEY_1_1 ) - sizeof( EFS_PUBLIC_KEY_INFO ) + PublicKeyInformation->Length;
  965. ULONG PolicySize = sizeof( RECOVERY_POLICY_1_1 ) + RecoveryKeySize - sizeof( RECOVERY_KEY_1_1 );
  966. //
  967. // Allocate the policy block
  968. //
  969. PRECOVERY_POLICY_1_1 RecoveryPolicy = (PRECOVERY_POLICY_1_1)malloc( PolicySize );
  970. if (RecoveryPolicy != NULL) {
  971. RecoveryPolicy->RecoveryPolicyHeader.MajorRevision = EFS_RECOVERY_POLICY_MAJOR_REVISION_1;
  972. RecoveryPolicy->RecoveryPolicyHeader.MinorRevision = EFS_RECOVERY_POLICY_MINOR_REVISION_1;
  973. RecoveryPolicy->RecoveryPolicyHeader.RecoveryKeyCount = 1;
  974. PRECOVERY_KEY_1_1 RecoveryKey = (PRECOVERY_KEY_1_1) &(RecoveryPolicy->RecoveryKeyList[0]);
  975. memcpy( &RecoveryKey->PublicKeyInfo, PublicKeyInformation, PublicKeyInformation->Length );
  976. RecoveryKey->TotalLength = sizeof( RECOVERY_KEY_1_1 ) + PublicKeyInformation->Length - sizeof( EFS_PUBLIC_KEY_INFO );
  977. *pRecoveryPolicyBlob = (PUCHAR)RecoveryPolicy;
  978. *BlobSize = PolicySize;
  979. *ppCertContext = pCertContext;
  980. //
  981. // will free this outside this function
  982. //
  983. pCertContext = NULL;
  984. } else {
  985. rc = ERROR_NOT_ENOUGH_MEMORY;
  986. }
  987. free( PublicKeyInformation );
  988. }
  989. free( pTokenUser );
  990. } else {
  991. rc = GetLastError();
  992. }
  993. //
  994. // free the certificate context if not outputted
  995. //
  996. if ( pCertContext ) {
  997. CertFreeCertificateContext( pCertContext );
  998. }
  999. } else {
  1000. rc = GetLastError();
  1001. }
  1002. return( rc );
  1003. }
  1004. BOOLEAN
  1005. CreateSelfSignedRecoveryCertificate(
  1006. IN BOOL bIsDC,
  1007. OUT PCCERT_CONTEXT * pCertContext
  1008. )
  1009. /*++
  1010. Routine Description:
  1011. This routine sets up and creates a self-signed certificate.
  1012. Arguments:
  1013. Return Value:
  1014. TRUE on success, FALSE on failure. Call GetLastError() for more details.
  1015. --*/
  1016. {
  1017. BOOLEAN fReturn = FALSE;
  1018. DWORD rc = ERROR_SUCCESS;
  1019. LPWSTR lpContainerName = NULL;
  1020. LPWSTR lpProviderName = NULL;
  1021. LPWSTR lpDisplayInfo = NULL;
  1022. HCRYPTKEY hKey = NULL;
  1023. HCRYPTPROV hProv = NULL;
  1024. *pCertContext = NULL;
  1025. //
  1026. // Croft up a key pair
  1027. //
  1028. //
  1029. // Container name
  1030. //
  1031. GUID guidContainerName;
  1032. if ( ERROR_SUCCESS != UuidCreate(&guidContainerName) ) {
  1033. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1034. return(fReturn);
  1035. }
  1036. if (ERROR_SUCCESS == UuidToStringW(&guidContainerName, (unsigned short **)&lpContainerName )) {
  1037. //
  1038. // Copy the container name into LSA heap memory
  1039. //
  1040. lpProviderName = MS_DEF_PROV;
  1041. //
  1042. // Create the key container
  1043. //
  1044. if (CryptAcquireContext(&hProv, lpContainerName, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET )) {
  1045. if (CryptGenKey(hProv, AT_KEYEXCHANGE, RSA1024BIT_KEY | CRYPT_EXPORTABLE, &hKey)) {
  1046. DWORD NameLength = 64;
  1047. LPWSTR AgentName = NULL;
  1048. //
  1049. // Construct the subject name information
  1050. //
  1051. //lpDisplayInfo = MakeDNName();
  1052. AgentName = (LPWSTR)malloc(NameLength * sizeof(WCHAR));
  1053. if (AgentName){
  1054. if (!GetUserName(AgentName, &NameLength)){
  1055. free(AgentName);
  1056. AgentName = (LPWSTR)malloc(NameLength * sizeof(WCHAR));
  1057. //
  1058. // Try again with big buffer
  1059. //
  1060. if ( AgentName ){
  1061. if (!GetUserName(AgentName, &NameLength)){
  1062. rc = GetLastError();
  1063. free(AgentName);
  1064. AgentName = NULL;
  1065. }
  1066. } else {
  1067. rc = ERROR_NOT_ENOUGH_MEMORY;
  1068. }
  1069. }
  1070. } else {
  1071. rc = ERROR_NOT_ENOUGH_MEMORY;
  1072. }
  1073. if (AgentName) {
  1074. LPCWSTR DNNameTemplate = L"CN=%ws,L=EFS,OU=EFS File Encryption Certificate";
  1075. DWORD cbDNName = 0;
  1076. cbDNName = (DWORD)((wcslen( DNNameTemplate ) + 1) * sizeof( WCHAR ) + (wcslen( AgentName ) + 1) * sizeof( WCHAR ));
  1077. lpDisplayInfo = (LPWSTR)malloc( cbDNName );
  1078. if (lpDisplayInfo) {
  1079. swprintf( lpDisplayInfo, DNNameTemplate, AgentName );
  1080. } else {
  1081. rc = ERROR_NOT_ENOUGH_MEMORY;
  1082. }
  1083. free(AgentName);
  1084. AgentName = NULL;
  1085. }
  1086. if (lpDisplayInfo) {
  1087. //
  1088. // Use this piece of code to create the PCERT_NAME_BLOB going into CertCreateSelfSignCertificate()
  1089. //
  1090. CERT_NAME_BLOB SubjectName;
  1091. SubjectName.cbData = 0;
  1092. if(CertStrToNameW(
  1093. CRYPT_ASN_ENCODING,
  1094. lpDisplayInfo,
  1095. 0,
  1096. NULL,
  1097. NULL,
  1098. &SubjectName.cbData,
  1099. NULL)) {
  1100. SubjectName.pbData = (BYTE *) malloc(SubjectName.cbData);
  1101. if (SubjectName.pbData) {
  1102. if (CertStrToNameW(
  1103. CRYPT_ASN_ENCODING,
  1104. lpDisplayInfo,
  1105. 0,
  1106. NULL,
  1107. SubjectName.pbData,
  1108. &SubjectName.cbData,
  1109. NULL) ) {
  1110. //
  1111. // Make the enhanced key usage
  1112. //
  1113. CERT_ENHKEY_USAGE certEnhKeyUsage;
  1114. LPSTR lpstr;
  1115. CERT_EXTENSION certExt;
  1116. lpstr = szOID_EFS_RECOVERY;
  1117. certEnhKeyUsage.cUsageIdentifier = 1;
  1118. certEnhKeyUsage.rgpszUsageIdentifier = &lpstr;
  1119. // now call CryptEncodeObject to encode the enhanced key usage into the extension struct
  1120. certExt.Value.cbData = 0;
  1121. certExt.Value.pbData = NULL;
  1122. certExt.fCritical = FALSE;
  1123. certExt.pszObjId = szOID_ENHANCED_KEY_USAGE;
  1124. //
  1125. // Encode it
  1126. //
  1127. if (EncodeAndAlloc(
  1128. CRYPT_ASN_ENCODING,
  1129. X509_ENHANCED_KEY_USAGE,
  1130. &certEnhKeyUsage,
  1131. &certExt.Value.pbData,
  1132. &certExt.Value.cbData
  1133. )) {
  1134. //
  1135. // finally, set up the array of extensions in the certInfo struct
  1136. // any further extensions need to be added to this array.
  1137. //
  1138. CERT_EXTENSIONS certExts;
  1139. certExts.cExtension = 1;
  1140. certExts.rgExtension = &certExt;
  1141. CRYPT_KEY_PROV_INFO KeyProvInfo;
  1142. memset( &KeyProvInfo, 0, sizeof( CRYPT_KEY_PROV_INFO ));
  1143. KeyProvInfo.pwszContainerName = lpContainerName;
  1144. KeyProvInfo.pwszProvName = lpProviderName;
  1145. KeyProvInfo.dwProvType = PROV_RSA_FULL;
  1146. KeyProvInfo.dwKeySpec = AT_KEYEXCHANGE;
  1147. SYSTEMTIME StartTime;
  1148. FILETIME FileTime;
  1149. LARGE_INTEGER TimeData;
  1150. SYSTEMTIME EndTime;
  1151. GetSystemTime(&StartTime);
  1152. SystemTimeToFileTime(&StartTime, &FileTime);
  1153. TimeData.LowPart = FileTime.dwLowDateTime;
  1154. TimeData.HighPart = (LONG) FileTime.dwHighDateTime;
  1155. if ( bIsDC ) {
  1156. TimeData.QuadPart += YEARCOUNT * 3;
  1157. } else {
  1158. TimeData.QuadPart += YEARCOUNT * 100;
  1159. }
  1160. FileTime.dwLowDateTime = TimeData.LowPart;
  1161. FileTime.dwHighDateTime = (DWORD) TimeData.HighPart;
  1162. FileTimeToSystemTime(&FileTime, &EndTime);
  1163. *pCertContext = CertCreateSelfSignCertificate(
  1164. hProv,
  1165. &SubjectName,
  1166. 0,
  1167. &KeyProvInfo,
  1168. NULL,
  1169. &StartTime,
  1170. &EndTime,
  1171. &certExts
  1172. );
  1173. if (*pCertContext) {
  1174. HCERTSTORE hStore;
  1175. hStore = CertOpenSystemStoreW( NULL, L"MY" );
  1176. if (hStore) {
  1177. //
  1178. // save the temp cert
  1179. //
  1180. if(CertAddCertificateContextToStore(
  1181. hStore,
  1182. *pCertContext,
  1183. CERT_STORE_ADD_NEW,
  1184. NULL) ) {
  1185. fReturn = TRUE;
  1186. } else {
  1187. rc = GetLastError();
  1188. }
  1189. CertCloseStore( hStore, 0 );
  1190. } else {
  1191. rc = GetLastError();
  1192. }
  1193. } else {
  1194. rc = GetLastError();
  1195. }
  1196. free( certExt.Value.pbData );
  1197. } else {
  1198. rc = GetLastError();
  1199. }
  1200. } else {
  1201. rc = GetLastError();
  1202. }
  1203. free( SubjectName.pbData );
  1204. } else {
  1205. rc = ERROR_NOT_ENOUGH_MEMORY;
  1206. }
  1207. } else {
  1208. rc = GetLastError();
  1209. }
  1210. free( lpDisplayInfo );
  1211. } else {
  1212. rc = ERROR_NOT_ENOUGH_MEMORY;
  1213. }
  1214. CryptDestroyKey( hKey );
  1215. } else {
  1216. rc = GetLastError();
  1217. }
  1218. CryptReleaseContext( hProv, 0 );
  1219. } else {
  1220. rc = GetLastError();
  1221. }
  1222. RpcStringFree( (unsigned short **)&lpContainerName );
  1223. } else {
  1224. rc = ERROR_NOT_ENOUGH_MEMORY;
  1225. }
  1226. SetLastError( rc );
  1227. if (!fReturn) {
  1228. if (*pCertContext) {
  1229. CertFreeCertificateContext( *pCertContext );
  1230. *pCertContext = NULL;
  1231. }
  1232. }
  1233. return( fReturn );
  1234. }
  1235. BOOL
  1236. EncodeAndAlloc(
  1237. DWORD dwEncodingType,
  1238. LPCSTR lpszStructType,
  1239. const void * pvStructInfo,
  1240. PBYTE * pbEncoded,
  1241. PDWORD pcbEncoded
  1242. )
  1243. {
  1244. BOOL b = FALSE;
  1245. if (CryptEncodeObject(
  1246. dwEncodingType,
  1247. lpszStructType,
  1248. pvStructInfo,
  1249. NULL,
  1250. pcbEncoded )) {
  1251. *pbEncoded = (PBYTE)malloc( *pcbEncoded );
  1252. if (*pbEncoded) {
  1253. if (CryptEncodeObject(
  1254. dwEncodingType,
  1255. lpszStructType,
  1256. pvStructInfo,
  1257. *pbEncoded,
  1258. pcbEncoded )) {
  1259. b = TRUE;
  1260. } else {
  1261. free( *pbEncoded );
  1262. *pbEncoded = NULL;
  1263. }
  1264. } else {
  1265. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1266. }
  1267. }
  1268. return( b );
  1269. }
  1270. LPWSTR
  1271. MakeDNName(
  1272. VOID
  1273. )
  1274. /*++
  1275. Routine Description:
  1276. Fabricates a display name for a locally built self-signed cert
  1277. Arguments:
  1278. RecoveryKey - Specifies if this is a recovery key or not.
  1279. Return Value:
  1280. Returns a string containing a display name, or NULL.
  1281. --*/
  1282. {
  1283. LPWSTR DNName = NULL;
  1284. LPCWSTR DNNameTemplate = L"CN=%ws,L=EFS,OU=EFS File Encryption Certificate";
  1285. DWORD cbDNName = 0;
  1286. DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1;
  1287. WCHAR lpComputerName[(MAX_COMPUTERNAME_LENGTH + 1) * sizeof( WCHAR )];
  1288. BOOL b = GetComputerName ( lpComputerName, &nSize );
  1289. if (b) {
  1290. cbDNName = (DWORD)((wcslen( DNNameTemplate ) + 1) * sizeof( WCHAR ) + (wcslen( lpComputerName ) + 1) * sizeof( WCHAR ));
  1291. DNName = (LPWSTR)malloc( cbDNName );
  1292. if (DNName) {
  1293. swprintf( DNName, DNNameTemplate, lpComputerName );
  1294. } else {
  1295. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1296. }
  1297. }
  1298. return( DNName );
  1299. }
  1300. DWORD
  1301. CreatePublicKeyInformationCertificate(
  1302. IN PSID pUserSid OPTIONAL,
  1303. PBYTE pbCert,
  1304. DWORD cbCert,
  1305. OUT PEFS_PUBLIC_KEY_INFO * PublicKeyInformation
  1306. )
  1307. {
  1308. DWORD PublicKeyInformationLength = 0;
  1309. DWORD UserSidLength = 0;
  1310. PWCHAR Base;
  1311. if (pUserSid != NULL) {
  1312. UserSidLength = GetLengthSid( pUserSid );
  1313. }
  1314. //
  1315. // Total size is the size of the public key info structure, the size of the
  1316. // cert hash data structure, the length of the thumbprint, and the lengths of the
  1317. // container name and provider name if they were passed.
  1318. //
  1319. PublicKeyInformationLength = sizeof( EFS_PUBLIC_KEY_INFO ) + UserSidLength + cbCert;
  1320. //
  1321. // Allocate and fill in the PublicKeyInformation structure
  1322. //
  1323. *PublicKeyInformation = (PEFS_PUBLIC_KEY_INFO)malloc( PublicKeyInformationLength );
  1324. if (*PublicKeyInformation == NULL) {
  1325. return( ERROR_NOT_ENOUGH_MEMORY );
  1326. }
  1327. (*PublicKeyInformation)->Length = PublicKeyInformationLength;
  1328. (*PublicKeyInformation)->KeySourceTag = (ULONG)EfsCertificate;
  1329. //
  1330. // Copy the string and SID data to the end of the structure.
  1331. //
  1332. Base = (PWCHAR)(*PublicKeyInformation);
  1333. Base = (PWCHAR)((PBYTE)Base + sizeof( EFS_PUBLIC_KEY_INFO ));
  1334. if (pUserSid != NULL) {
  1335. (*PublicKeyInformation)->PossibleKeyOwner = (ULONG)POINTER_TO_OFFSET( Base, *PublicKeyInformation );
  1336. CopySid( UserSidLength, (PSID)Base, pUserSid );
  1337. } else {
  1338. (*PublicKeyInformation)->PossibleKeyOwner = (ULONG)0;
  1339. }
  1340. Base = (PWCHAR)((PBYTE)Base + UserSidLength);
  1341. (*PublicKeyInformation)->CertificateInfo.CertificateLength = cbCert;
  1342. (*PublicKeyInformation)->CertificateInfo.Certificate = (ULONG)POINTER_TO_OFFSET( Base, *PublicKeyInformation );
  1343. memcpy( (PBYTE)Base, pbCert, cbCert );
  1344. return( ERROR_SUCCESS );
  1345. }
  1346. #if 0
  1347. BOOLEAN
  1348. Admin(
  1349. IN LSA_HANDLE LsaPolicyHandle,
  1350. IN HANDLE hToken,
  1351. OUT PSID * Sid
  1352. )
  1353. /*++
  1354. Routine Description:
  1355. This routine determines if the passed token belongs to an administrator.
  1356. If we are in a domain, the user must be a domain admin for this to succeed.
  1357. If we are standalne, the user must be in the local administrator's group.
  1358. Arguments:
  1359. hToken - Supplies the token of the user to be examined.
  1360. bDomain - Returns TRUE if the caller is a domain administrator.
  1361. Sid - Returns the Sid of the user.
  1362. Return Value:
  1363. TRUE if the user is an administrator of the type we need, FALSE otherwise.
  1364. Note that this routine does not attempt to set last error, it either works
  1365. or it doesn't.
  1366. --*/
  1367. {
  1368. NET_API_STATUS NetStatus;
  1369. PSID DomainId;
  1370. NTSTATUS Status;
  1371. BOOLEAN fReturn = FALSE;
  1372. DWORD ReturnLength;
  1373. PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo;
  1374. //
  1375. // Initialize OUT parameters
  1376. //
  1377. *Sid = NULL;
  1378. Status = NtQueryInformationToken (
  1379. hToken,
  1380. TokenGroups,
  1381. NULL,
  1382. 0,
  1383. &ReturnLength
  1384. );
  1385. if (STATUS_BUFFER_TOO_SMALL == Status) {
  1386. PTOKEN_GROUPS Groups = (PTOKEN_GROUPS)malloc( ReturnLength );
  1387. if (Groups) {
  1388. Status = NtQueryInformationToken (
  1389. hToken,
  1390. TokenGroups,
  1391. Groups,
  1392. ReturnLength,
  1393. &ReturnLength
  1394. );
  1395. if (NT_SUCCESS( Status )) {
  1396. //
  1397. // We've got the groups, build the SIDs and see if
  1398. // they're in the token.
  1399. //
  1400. //
  1401. // We're standalone
  1402. //
  1403. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1404. PSID AdminAccountSid;
  1405. Status = RtlAllocateAndInitializeSid(
  1406. &NtAuthority,
  1407. 2,
  1408. SECURITY_BUILTIN_DOMAIN_RID,
  1409. DOMAIN_ALIAS_RID_ADMINS,
  1410. 0, 0, 0, 0, 0, 0,
  1411. &AdminAccountSid
  1412. );
  1413. if (NT_SUCCESS( Status )) {
  1414. DWORD i;
  1415. for (i=0; i<Groups->GroupCount; i++) {
  1416. if (RtlEqualSid(Groups->Groups[i].Sid, AdminAccountSid)) {
  1417. *Sid = AdminAccountSid;
  1418. fReturn = TRUE;
  1419. break;
  1420. }
  1421. }
  1422. }
  1423. }
  1424. free( Groups );
  1425. }
  1426. if (!fReturn) {
  1427. //
  1428. // Something failed, clean up any allocated OUT parameters
  1429. //
  1430. if (*Sid) {
  1431. if (*bDomain == FALSE) {
  1432. FreeSid( *Sid );
  1433. } else {
  1434. free( *Sid );
  1435. }
  1436. *Sid = NULL;
  1437. }
  1438. }
  1439. }
  1440. return( fReturn );
  1441. }
  1442. #endif
  1443. PTOKEN_USER
  1444. GetTokenUser(
  1445. HANDLE TokenHandle
  1446. )
  1447. /*++
  1448. Routine Description:
  1449. This routine returns the TOKEN_USER structure for the
  1450. current user, and optionally, the AuthenticationId from his
  1451. token.
  1452. Arguments:
  1453. AuthenticationId - Supplies an optional pointer to return the
  1454. AuthenticationId.
  1455. Return Value:
  1456. On success, returns a pointer to a TOKEN_USER structure.
  1457. On failure, returns NULL. Call GetLastError() for more
  1458. detailed error information.
  1459. --*/
  1460. {
  1461. NTSTATUS Status;
  1462. ULONG ReturnLength;
  1463. PTOKEN_USER pTokenUser = NULL;
  1464. BOOLEAN b = FALSE;
  1465. Status = NtQueryInformationToken (
  1466. TokenHandle,
  1467. TokenUser,
  1468. NULL,
  1469. 0,
  1470. &ReturnLength
  1471. );
  1472. if (Status == STATUS_BUFFER_TOO_SMALL) {
  1473. pTokenUser = (PTOKEN_USER)malloc( ReturnLength );
  1474. if (pTokenUser) {
  1475. Status = NtQueryInformationToken (
  1476. TokenHandle,
  1477. TokenUser,
  1478. pTokenUser,
  1479. ReturnLength,
  1480. &ReturnLength
  1481. );
  1482. if ( NT_SUCCESS( Status )) {
  1483. //
  1484. // We're done, mark that everything worked
  1485. //
  1486. b = TRUE;
  1487. } else {
  1488. SetLastError( RtlNtStatusToDosError( Status ));
  1489. }
  1490. if (!b) {
  1491. //
  1492. // Something failed, clean up what we were going to return
  1493. //
  1494. free( pTokenUser );
  1495. pTokenUser = NULL;
  1496. }
  1497. } else {
  1498. SetLastError( RtlNtStatusToDosError( STATUS_INSUFFICIENT_RESOURCES ));
  1499. }
  1500. } else {
  1501. SetLastError( RtlNtStatusToDosError( Status ));
  1502. }
  1503. return( pTokenUser );
  1504. }
  1505. VOID
  1506. InitializeOtherPolicies(LPGROUPPOLICYOBJECT pGPO, HKEY hKeyRoot)
  1507. {
  1508. TCHAR szPath[2*MAX_PATH];
  1509. TCHAR *dirPath;
  1510. GUID guidRIClient = {0x3060e8d0, 0x7020, 0x11d2, 0x84, 0x2d, 0x0, 0xc0, 0x4f, 0xa3, 0x72, 0xd4};
  1511. GUID guidRISnap = {0x3060e8ce, 0x7020, 0x11d2, 0x84, 0x2d, 0x0, 0xc0, 0x4f, 0xa3, 0x72, 0xd4};
  1512. //
  1513. // Initialize Remote Install settings
  1514. //
  1515. if (SUCCEEDED(pGPO->GetFileSysPath (GPO_SECTION_USER, szPath, 2*MAX_PATH)))
  1516. {
  1517. DWORD KeyLength = (sizeof(MS) + sizeof(REMOTEINSTALL) + sizeof(FILTERNAME))/sizeof(TCHAR);
  1518. KeyLength += lstrlen(szPath) + 1;
  1519. if (KeyLength > 2*MAX_PATH) {
  1520. //
  1521. // Allocate more memory for this.
  1522. //
  1523. dirPath = (TCHAR*) malloc( KeyLength * sizeof (TCHAR) );
  1524. if (NULL == dirPath) {
  1525. return;
  1526. }
  1527. } else {
  1528. dirPath = szPath;
  1529. }
  1530. lstrcat (dirPath, MS);
  1531. if (!CreateDirectory(dirPath, NULL)) {
  1532. return;
  1533. }
  1534. lstrcat (dirPath, REMOTEINSTALL);
  1535. if (!CreateDirectory(dirPath, NULL)) {
  1536. return;
  1537. }
  1538. lstrcat (dirPath, FILTERNAME);
  1539. WritePrivateProfileString(TEXT("choice"), TEXT("custom"), TEXT("0"), dirPath);
  1540. WritePrivateProfileString(TEXT("choice"), TEXT("tools"), TEXT("0"), dirPath);
  1541. WritePrivateProfileString(TEXT("choice"), TEXT("restart"), TEXT("0"), dirPath);
  1542. if (dirPath != szPath) {
  1543. free(dirPath);
  1544. }
  1545. pGPO->Save(FALSE, TRUE, &guidRIClient, &guidRISnap);
  1546. }
  1547. UNREFERENCED_PARAMETER(hKeyRoot);
  1548. }
  1549. HRESULT
  1550. CreateEFSDefaultPolicy(
  1551. IN HANDLE hToken,
  1552. IN PUCHAR *pEfsBlob,
  1553. IN DWORD *pEfsSize,
  1554. IN PCCERT_CONTEXT *ppCertContext,
  1555. IN LPTSTR DomainName
  1556. )
  1557. /*++
  1558. Routine Description:
  1559. Creates the default domain-wide EFS recovery policy object.
  1560. Arguments:
  1561. hToken - the current logged on user's token
  1562. EfsBlob - EFS recovery policy blob
  1563. EfsSize - the size of the blob ( in bytes)
  1564. Return:
  1565. HRESULT
  1566. --*/
  1567. {
  1568. //
  1569. // bind to DS to find the domain DNS name
  1570. //
  1571. DWORD rc;
  1572. PLDAP phLdap=NULL;
  1573. PWSTR DsRootName=NULL;
  1574. rc = MyLdapOpen(&phLdap);
  1575. if ( ERROR_SUCCESS == rc ) {
  1576. rc = MyGetDsObjectRoot(
  1577. phLdap,
  1578. &DsRootName
  1579. );
  1580. if ( ERROR_SUCCESS != rc ) {
  1581. LogEvent(STATUS_SEVERITY_ERROR,
  1582. GPOEVENT_ERROR_CREATE_GPO,
  1583. IDS_ERROR_GET_DSROOT,
  1584. rc
  1585. );
  1586. }
  1587. } else {
  1588. LogEvent(STATUS_SEVERITY_ERROR,
  1589. GPOEVENT_ERROR_CREATE_GPO,
  1590. IDS_ERROR_BIND_DS,
  1591. rc
  1592. );
  1593. }
  1594. HRESULT hr = HRESULT_FROM_WIN32(rc);
  1595. // if ( SUCCEEDED(hr) && DsRootName ) {
  1596. /* Get the default recovery policy only when there is no existing one
  1597. if ( *pEfsBlob == NULL ) {
  1598. rc = GetDefaultRecoveryPolicy(hToken,
  1599. TRUE,
  1600. pEfsBlob,
  1601. pEfsSize,
  1602. ppCertContext);
  1603. if ( ERROR_SUCCESS != rc ) {
  1604. LogEvent(STATUS_SEVERITY_ERROR,
  1605. GPOEVENT_ERROR_CREATE_GPO,
  1606. IDS_ERROR_CREATE_EFSBLOB,
  1607. rc
  1608. );
  1609. }
  1610. hr = HRESULT_FROM_WIN32(rc);
  1611. }
  1612. */
  1613. // }
  1614. if ( SUCCEEDED(hr) && DsRootName) {
  1615. LPGROUPPOLICYOBJECT pEfsGPO = NULL;
  1616. //
  1617. // OLE is already initialized before this call
  1618. // create Policy Object instances
  1619. //
  1620. TCHAR szPolicyName[MAX_PATH];
  1621. pLoadResourceString(IDS_DEFAULT_EFS_POLICY,
  1622. szPolicyName,
  1623. MAX_PATH,
  1624. L"Domain EFS Recovery Policy"
  1625. );
  1626. hr = CreateGroupPolicyObjectInDomain(hToken,
  1627. DsRootName,
  1628. szPolicyName,
  1629. *pEfsBlob,
  1630. *pEfsSize,
  1631. *ppCertContext,
  1632. &pEfsGPO);
  1633. if ( FAILED(hr) ) {
  1634. //
  1635. // if any of the creation failed, delet both objects
  1636. //
  1637. if ( pEfsGPO ) {
  1638. pEfsGPO->Delete();
  1639. }
  1640. }
  1641. //
  1642. // release the instances
  1643. //
  1644. if ( pEfsGPO ) {
  1645. pEfsGPO->Release();
  1646. }
  1647. }
  1648. //
  1649. // close LDAP port
  1650. //
  1651. if ( phLdap ) {
  1652. MyLdapClose(&phLdap);
  1653. }
  1654. if ( DsRootName ) {
  1655. LocalFree(DsRootName);
  1656. }
  1657. return hr;
  1658. UNREFERENCED_PARAMETER(DomainName);
  1659. }
  1660. HRESULT
  1661. CreateGroupPolicyObjectInDomain(
  1662. IN HANDLE hToken,
  1663. IN PWSTR DomainNCName,
  1664. IN PWSTR GPObjectName,
  1665. IN PUCHAR EfsBlob,
  1666. IN ULONG EfsSize,
  1667. IN PCCERT_CONTEXT pCertContext,
  1668. OUT LPGROUPPOLICYOBJECT *ppObject
  1669. )
  1670. /*++
  1671. Routine Description:
  1672. Creates a group policy object in DS (and sysvol).
  1673. Arguments:
  1674. DomainNCName - The DS domain's ADSI name
  1675. GPObjectName - the display name for the group policy object to create
  1676. EfsBlob - The EFS recovery policy blob (ignored if to create default
  1677. domain policy)
  1678. EfsSize - the size of EfsBlob (in bytes)
  1679. ppObject - the created group policy object instance. This will be
  1680. released by the caller.
  1681. Return:
  1682. HRESULT
  1683. --*/
  1684. {
  1685. LPGROUPPOLICYOBJECT pGPO;
  1686. HRESULT hr = CoCreateInstance( CLSID_GroupPolicyObject,
  1687. NULL,
  1688. CLSCTX_SERVER,
  1689. IID_IGroupPolicyObject,
  1690. (PVOID *)&pGPO
  1691. );
  1692. if (SUCCEEDED(hr) && pGPO) {
  1693. LPWSTR lpPath;
  1694. //
  1695. // Build the path to the default GPO
  1696. //
  1697. lpPath = (LPWSTR) LocalAlloc (LPTR, (lstrlen(DomainNCName) + 100) * sizeof(WCHAR));
  1698. if (lpPath) {
  1699. lstrcpy (lpPath, TEXT("LDAP://CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,"));
  1700. lstrcat (lpPath, (DomainNCName+7));
  1701. //
  1702. // Open the default GPO
  1703. //
  1704. hr = pGPO->OpenDSGPO(lpPath, GPO_OPEN_LOAD_REGISTRY);
  1705. LocalFree (lpPath);
  1706. if ( SUCCEEDED(hr) ) {
  1707. //
  1708. // save EFS blob into the object
  1709. //
  1710. HKEY hKeyPolicyRoot;
  1711. hr = pGPO->GetRegistryKey( GPO_SECTION_MACHINE,
  1712. &hKeyPolicyRoot
  1713. );
  1714. if (SUCCEEDED(hr)) {
  1715. //
  1716. // create EFS recovery policy in the registry
  1717. // open reg key CERT_EFSBLOB_REGPATH defined in wincrypt.h
  1718. //
  1719. DWORD dwDisposition;
  1720. HKEY hKey;
  1721. DWORD Win32rc;
  1722. if ( (Win32rc = RegCreateKeyEx(
  1723. hKeyPolicyRoot,
  1724. CERT_EFSBLOB_REGPATH,
  1725. 0,
  1726. TEXT("REG_SZ"),
  1727. REG_OPTION_NON_VOLATILE,
  1728. KEY_ALL_ACCESS,
  1729. NULL,
  1730. &hKey,
  1731. &dwDisposition
  1732. ) ) == ERROR_SUCCESS ) {
  1733. //
  1734. // check to see if there is EFS blob
  1735. // if not, create it.
  1736. //
  1737. DWORD RegType;
  1738. DWORD BlobSize;
  1739. PUCHAR pNewBlob=NULL;
  1740. PCCERT_CONTEXT pNewCert=NULL;
  1741. Win32rc = RegQueryValueEx(
  1742. hKey,
  1743. CERT_EFSBLOB_VALUE_NAME,
  1744. 0,
  1745. &RegType,
  1746. NULL,
  1747. &BlobSize
  1748. );
  1749. if ( Win32rc != ERROR_SUCCESS || BlobSize == 0 ) {
  1750. if ( EfsBlob == NULL ) {
  1751. Win32rc = GetDefaultRecoveryPolicy(hToken,
  1752. TRUE,
  1753. &pNewBlob,
  1754. &BlobSize,
  1755. &pNewCert);
  1756. if ( ERROR_SUCCESS != Win32rc ) {
  1757. LogEvent(STATUS_SEVERITY_ERROR,
  1758. GPOEVENT_ERROR_CREATE_GPO,
  1759. IDS_ERROR_CREATE_EFSBLOB,
  1760. Win32rc
  1761. );
  1762. }
  1763. } else {
  1764. //
  1765. // EFS blob is already created, just use it
  1766. //
  1767. pNewBlob = EfsBlob;
  1768. BlobSize = EfsSize;
  1769. pNewCert = pCertContext;
  1770. Win32rc = ERROR_SUCCESS;
  1771. }
  1772. if ( ERROR_SUCCESS == Win32rc ) {
  1773. //
  1774. // add to the cert store of this GPO first
  1775. //
  1776. CERT_SYSTEM_STORE_RELOCATE_PARA paraRelocate;
  1777. paraRelocate.hKeyBase = hKeyPolicyRoot;
  1778. paraRelocate.pwszSystemStore = L"EFS";
  1779. HCERTSTORE hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
  1780. 0,
  1781. NULL,
  1782. CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY |
  1783. CERT_SYSTEM_STORE_RELOCATE_FLAG,
  1784. (void *)&paraRelocate
  1785. );
  1786. if ( hCertStore ) {
  1787. if ( !CertAddCertificateContextToStore(
  1788. hCertStore,
  1789. pNewCert, // pCertContext,
  1790. CERT_STORE_ADD_ALWAYS,
  1791. NULL
  1792. ) ) {
  1793. Win32rc = GetLastError();
  1794. }
  1795. //
  1796. // close the store
  1797. //
  1798. CertCloseStore(hCertStore, 0);
  1799. hCertStore = NULL;
  1800. } else {
  1801. Win32rc = GetLastError();
  1802. }
  1803. if ( ERROR_SUCCESS == Win32rc ) {
  1804. //
  1805. // set EFS recovery policy binary data to registry
  1806. // open reg key CERT_EFSBLOB_REGPATH defined in wincrypt.h
  1807. //
  1808. Win32rc = RegSetValueEx(
  1809. hKey,
  1810. CERT_EFSBLOB_VALUE_NAME,
  1811. 0,
  1812. REG_BINARY,
  1813. (PBYTE)pNewBlob, // EfsBlob
  1814. BlobSize // EfsSize
  1815. );
  1816. if (Win32rc == ERROR_SUCCESS) {
  1817. hr = pGPO->Save(TRUE, TRUE, &guidExtension, &guidSnapin);
  1818. hr = pGPO->Save(TRUE, TRUE, &guidRegExt, &guidSnapin );
  1819. if ( FAILED(hr) ) {
  1820. LogEvent(STATUS_SEVERITY_ERROR,
  1821. GPOEVENT_ERROR_CREATE_GPO,
  1822. IDS_ERROR_SAVE_GPO,
  1823. hr,
  1824. GPObjectName
  1825. );
  1826. }
  1827. } else {
  1828. LogEvent(STATUS_SEVERITY_ERROR,
  1829. GPOEVENT_ERROR_CREATE_GPO,
  1830. IDS_ERROR_SAVE_EFSBLOB,
  1831. Win32rc
  1832. );
  1833. }
  1834. } else {
  1835. LogEvent(STATUS_SEVERITY_ERROR,
  1836. GPOEVENT_ERROR_CREATE_GPO,
  1837. IDS_ERROR_ADD_CERTIFICATE,
  1838. Win32rc
  1839. );
  1840. }
  1841. //
  1842. // free allocated blob and certificate
  1843. //
  1844. if ( pNewBlob != EfsBlob ) {
  1845. if ( pNewBlob ) {
  1846. free(pNewBlob);
  1847. }
  1848. if ( pNewCert ) {
  1849. CertFreeCertificateContext( pNewCert );
  1850. }
  1851. }
  1852. } else {
  1853. LogEvent(STATUS_SEVERITY_ERROR,
  1854. GPOEVENT_ERROR_CREATE_GPO,
  1855. IDS_ERROR_CREATE_EFSBLOB,
  1856. Win32rc
  1857. );
  1858. }
  1859. }
  1860. //
  1861. // close the registry key
  1862. //
  1863. RegCloseKey(hKey);
  1864. } else {
  1865. LogEvent(STATUS_SEVERITY_ERROR,
  1866. GPOEVENT_ERROR_CREATE_GPO,
  1867. IDS_ERROR_OPEN_EFSKEY,
  1868. Win32rc
  1869. );
  1870. }
  1871. if ( Win32rc != ERROR_SUCCESS ) {
  1872. hr = HRESULT_FROM_WIN32(Win32rc);
  1873. }
  1874. InitializeOtherPolicies(pGPO, hKeyPolicyRoot);
  1875. RegCloseKey(hKeyPolicyRoot);
  1876. } else {
  1877. LogEvent(STATUS_SEVERITY_ERROR,
  1878. GPOEVENT_ERROR_CREATE_GPO,
  1879. IDS_ERROR_GETGPO_REGKEY,
  1880. hr,
  1881. GPObjectName
  1882. );
  1883. }
  1884. } else {
  1885. LogEvent(STATUS_SEVERITY_ERROR,
  1886. GPOEVENT_ERROR_CREATE_GPO,
  1887. IDS_ERROR_NEW_GPO,
  1888. hr,
  1889. GPObjectName,
  1890. DomainNCName
  1891. );
  1892. }
  1893. }
  1894. } else {
  1895. LogEvent(STATUS_SEVERITY_ERROR,
  1896. GPOEVENT_ERROR_CREATE_GPO,
  1897. IDS_ERROR_CREATE_GPO_INSTANCE,
  1898. hr
  1899. );
  1900. }
  1901. if ( SUCCEEDED(hr) ) {
  1902. *ppObject = pGPO;
  1903. } else if ( pGPO ) {
  1904. //
  1905. // failed, release the instance
  1906. //
  1907. pGPO->Release();
  1908. }
  1909. return hr;
  1910. }
  1911. DWORD
  1912. MyGetDsObjectRoot(
  1913. IN PLDAP pLdap,
  1914. OUT PWSTR *pDsRootName
  1915. )
  1916. /*++
  1917. Routine Description:
  1918. Get the root domain name of the current domain. The returned domain's
  1919. name is in ADSI format, for example,
  1920. LDAP://DC=test_dom,DC=ntdev,DC=microsoft,DC=com
  1921. Arguments:
  1922. pLdap - the ldap handle
  1923. pDsRootName - the domain's ADSI name to output
  1924. Return:
  1925. Win32 error
  1926. --*/
  1927. {
  1928. DWORD retErr;
  1929. LDAPMessage *Message = NULL; // for LDAP calls.
  1930. PWSTR Attribs[2]; // for LDAP calls.
  1931. if ( pLdap == NULL || pDsRootName == NULL ) {
  1932. return(ERROR_INVALID_PARAMETER);
  1933. }
  1934. Attribs[0] = L"defaultNamingContext";
  1935. Attribs[1] = NULL;
  1936. retErr = ldap_search_s(pLdap,
  1937. L"",
  1938. LDAP_SCOPE_BASE,
  1939. L"(objectClass=*)",
  1940. Attribs,
  1941. 0,
  1942. &Message);
  1943. if( Message ) { // should not check for error code
  1944. retErr = ERROR_SUCCESS;
  1945. LDAPMessage *Entry = NULL;
  1946. //
  1947. // read the first entry.
  1948. // we did base level search, we have only one entry.
  1949. // Entry does not need to be freed (it is freed with the message)
  1950. //
  1951. Entry = ldap_first_entry(pLdap, Message);
  1952. if(Entry != NULL) {
  1953. PWSTR *Values = ldap_get_values(pLdap, Entry, Attribs[0]);
  1954. if(Values != NULL) {
  1955. //
  1956. // should only get one value for the default naming context
  1957. // Values[0] here is the DN.
  1958. //
  1959. *pDsRootName = (PWSTR)LocalAlloc(0, (wcslen(Values[0])+1+7)*sizeof(WCHAR));
  1960. if ( *pDsRootName ) {
  1961. swprintf(*pDsRootName, L"LDAP://%s\0", Values[0]);
  1962. } else {
  1963. retErr = ERROR_NOT_ENOUGH_MEMORY;
  1964. }
  1965. ldap_value_free(Values);
  1966. } else
  1967. retErr = LdapMapErrorToWin32(pLdap->ld_errno);
  1968. } else
  1969. retErr = LdapMapErrorToWin32(pLdap->ld_errno);
  1970. ldap_msgfree(Message);
  1971. Message = NULL;
  1972. }
  1973. return(retErr);
  1974. }
  1975. DWORD
  1976. MyLdapOpen(
  1977. OUT PLDAP *pLdap
  1978. )
  1979. /*++
  1980. Routine Description:
  1981. Open a LDAP port and bind to it.
  1982. Arguments:
  1983. pLdap - the ldap handle to output
  1984. Return:
  1985. Win32 error
  1986. --*/
  1987. {
  1988. DWORD Win32rc;
  1989. WCHAR sysName[256];
  1990. DWORD dSize = (sizeof(sysName) / sizeof(sysName[0]));
  1991. if ( pLdap == NULL ) {
  1992. return(ERROR_INVALID_PARAMETER);
  1993. }
  1994. //
  1995. // get current computer and IP address
  1996. //
  1997. if ( !GetComputerName(sysName, &dSize) ) {
  1998. Win32rc = GetLastError();
  1999. } else {
  2000. PDOMAIN_CONTROLLER_INFOW DCInfo = NULL; // for DsGetDcName
  2001. HINSTANCE hDsGetDcDll = LoadLibrary(TEXT("netapi32.dll"));
  2002. PFNDSGETDCNAME pfnDsGetDcName=NULL;
  2003. if ( hDsGetDcDll) {
  2004. #if defined(UNICODE)
  2005. pfnDsGetDcName = (PFNDSGETDCNAME)GetProcAddress(hDsGetDcDll,
  2006. "DsGetDcNameW");
  2007. #else
  2008. pfnDsGetDcName = (PFNDSGETDCNAME)GetProcAddress(hDsGetDcDll,
  2009. "DsGetDcNameA");
  2010. #endif
  2011. }
  2012. if ( pfnDsGetDcName ) {
  2013. Win32rc = (*pfnDsGetDcName)(sysName,
  2014. NULL,
  2015. NULL,
  2016. NULL,
  2017. DS_IP_REQUIRED,
  2018. &DCInfo
  2019. );
  2020. } else {
  2021. Win32rc = ERROR_PROC_NOT_FOUND;
  2022. }
  2023. if ( hDsGetDcDll ) {
  2024. FreeLibrary(hDsGetDcDll);
  2025. }
  2026. if (NULL == DCInfo && ERROR_SUCCESS != Win32rc) {
  2027. Win32rc = ERROR_INVALID_DATA;
  2028. }
  2029. if(Win32rc == ERROR_SUCCESS) {
  2030. PWSTR pwszAddress = DCInfo[0].DomainControllerAddress;
  2031. if(*pwszAddress == L'\\') {
  2032. pwszAddress += 2;
  2033. }
  2034. //
  2035. // bind to ldap
  2036. //
  2037. *pLdap = ldap_open(pwszAddress, LDAP_PORT);
  2038. if ( *pLdap == NULL ) {
  2039. Win32rc = ERROR_FILE_NOT_FOUND;
  2040. } else {
  2041. Win32rc = ldap_bind_s(*pLdap,
  2042. NULL,
  2043. NULL,
  2044. LDAP_AUTH_SSPI);
  2045. }
  2046. //
  2047. // free DCInfo
  2048. //
  2049. LocalFree(DCInfo);
  2050. }
  2051. }
  2052. return(Win32rc);
  2053. }
  2054. DWORD
  2055. MyLdapClose(
  2056. IN PLDAP *pLdap
  2057. )
  2058. /*++
  2059. Routine Description:
  2060. Close the LDAP bind.
  2061. Arguments:
  2062. pLdap - the ldap handle
  2063. Return:
  2064. Win32 error
  2065. --*/
  2066. {
  2067. if ( pLdap != NULL ) {
  2068. //
  2069. // unbind pLDAP
  2070. //
  2071. if ( *pLdap != NULL )
  2072. ldap_unbind(*pLdap);
  2073. *pLdap = NULL;
  2074. }
  2075. return(ERROR_SUCCESS);
  2076. }
  2077. BOOL
  2078. MyIsAdmin(
  2079. IN HANDLE hToken
  2080. )
  2081. {
  2082. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  2083. PSID AdminAccountSid;
  2084. BOOL bIsMemberOfAdmins = FALSE;
  2085. if ( NT_SUCCESS( RtlAllocateAndInitializeSid(
  2086. &NtAuthority,
  2087. 2,
  2088. SECURITY_BUILTIN_DOMAIN_RID,
  2089. DOMAIN_ALIAS_RID_ADMINS,
  2090. 0, 0, 0, 0, 0, 0,
  2091. &AdminAccountSid
  2092. ) ) ) {
  2093. HANDLE NewToken;
  2094. if ( DuplicateToken( hToken, SecurityImpersonation, &NewToken )) {
  2095. if ( FALSE == CheckTokenMembership(
  2096. NewToken,
  2097. AdminAccountSid,
  2098. &bIsMemberOfAdmins
  2099. ) ) {
  2100. //
  2101. // error occured when checking membership, assume it is not a member
  2102. //
  2103. bIsMemberOfAdmins = FALSE;
  2104. }
  2105. CloseHandle(NewToken);
  2106. }
  2107. RtlFreeSid( AdminAccountSid);
  2108. }
  2109. return bIsMemberOfAdmins;
  2110. }
  2111. EXTERN_C
  2112. DWORD
  2113. APIENTRY
  2114. GenerateDefaultEFSRecoveryPolicy(
  2115. OUT PUCHAR *pRecoveryPolicyBlob,
  2116. OUT ULONG *pBlobSize,
  2117. OUT PCCERT_CONTEXT *ppCertContext
  2118. )
  2119. /*++
  2120. Routine Description:
  2121. This function exports GetDefaultRecoveryPolicy(). It checks
  2122. that the caller is an admin and it's running on a DC.
  2123. see GetDefaultRecoveryPolicy()
  2124. Arguments:
  2125. pRecoveryPolicyBlob - the output buffer to hold EFSBlob
  2126. pBlobSize - the size of EFSBlob
  2127. Return Value:
  2128. Win32 error
  2129. --*/
  2130. {
  2131. DWORD rc = ERROR_SUCCESS;
  2132. HANDLE hToken = NULL;
  2133. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
  2134. if(NULL == pRecoveryPolicyBlob ||
  2135. NULL == pBlobSize ||
  2136. NULL == ppCertContext){
  2137. return ERROR_INVALID_PARAMETER;
  2138. }
  2139. //
  2140. // check if the token belong to an admin, otherwise quit
  2141. //
  2142. if(!OpenThreadToken( GetCurrentThread(),
  2143. TOKEN_QUERY | TOKEN_DUPLICATE,
  2144. TRUE,
  2145. &hToken
  2146. ) ){
  2147. if(ERROR_NO_TOKEN == GetLastError()){
  2148. if(!OpenProcessToken( GetCurrentProcess(),
  2149. TOKEN_QUERY | TOKEN_DUPLICATE,
  2150. &hToken
  2151. ) ){
  2152. rc = GetLastError();
  2153. goto ExitHandler;
  2154. }
  2155. }
  2156. else{
  2157. rc = GetLastError();
  2158. goto ExitHandler;
  2159. }
  2160. }
  2161. if(!MyIsAdmin(hToken)){
  2162. rc = ERROR_ACCESS_DENIED;
  2163. goto ExitHandler;
  2164. }
  2165. //
  2166. // Check if we are running on a DC
  2167. //
  2168. rc = DsRoleGetPrimaryDomainInformation(
  2169. NULL,
  2170. DsRolePrimaryDomainInfoBasic,
  2171. (PBYTE *)&pDsRole
  2172. );
  2173. if (rc != ERROR_SUCCESS) {
  2174. goto ExitHandler;
  2175. }
  2176. DSROLE_MACHINE_ROLE MachineRole = pDsRole->MachineRole;
  2177. if ((MachineRole != DsRole_RolePrimaryDomainController) &&
  2178. (MachineRole != DsRole_RoleBackupDomainController)) {
  2179. rc = ERROR_INVALID_DOMAIN_ROLE;
  2180. goto ExitHandler;
  2181. }
  2182. rc = GetDefaultRecoveryPolicy(hToken,
  2183. TRUE,
  2184. pRecoveryPolicyBlob,
  2185. pBlobSize,
  2186. ppCertContext
  2187. );
  2188. ExitHandler:
  2189. //
  2190. // cleanup
  2191. //
  2192. if(hToken){
  2193. CloseHandle(hToken);
  2194. }
  2195. if (pDsRole) {
  2196. DsRoleFreeMemory( pDsRole );
  2197. }
  2198. return rc;
  2199. }
  2200. //*************************************************************
  2201. // Routines to handle events
  2202. //*************************************************************
  2203. BOOL InitializeEvents (void)
  2204. /*++
  2205. Routine Description:
  2206. Opens the event log
  2207. Arguments:
  2208. None
  2209. Return:
  2210. TRUE if successful
  2211. FALSE if an error occurs
  2212. --*/
  2213. {
  2214. //
  2215. // Open the event source
  2216. //
  2217. hEventLog = RegisterEventSource(NULL, EventSourceName);
  2218. if (hEventLog) {
  2219. return TRUE;
  2220. }
  2221. return FALSE;
  2222. }
  2223. int
  2224. LogEvent(
  2225. IN DWORD LogLevel,
  2226. IN DWORD dwEventID,
  2227. IN UINT idMsg,
  2228. ...)
  2229. /*++
  2230. Routine Description:
  2231. Logs a verbose event to the event log
  2232. Arguments:
  2233. bLogLevel - the severity level of the log
  2234. STATUS_SEVERITY_SUCCESS
  2235. STATUS_SEVERITY_INFORMATIONAL
  2236. STATUS_SEVERITY_WARNING
  2237. STATUS_SEVERITY_ERROR
  2238. dwEventID - the event ID (defined in uevents.mc)
  2239. idMsg - Message id
  2240. Return:
  2241. TRUE if successful
  2242. FALSE if an error occurs
  2243. --*/
  2244. {
  2245. TCHAR szMsg[MAX_PATH];
  2246. TCHAR szErrorMsg[2*MAX_PATH+40];
  2247. LPTSTR aStrings[2];
  2248. WORD wType;
  2249. va_list marker;
  2250. //
  2251. // Load the message
  2252. //
  2253. if (idMsg != 0) {
  2254. pLoadResourceString(idMsg, szMsg, MAX_PATH,
  2255. TEXT("Error loading resource string. Params : %x"));
  2256. } else {
  2257. lstrcpy (szMsg, TEXT("%s"));
  2258. }
  2259. //
  2260. // Plug in the arguments
  2261. //
  2262. szErrorMsg[0] = L'\0';
  2263. va_start(marker, idMsg);
  2264. __try {
  2265. wvsprintf(szErrorMsg, szMsg, marker);
  2266. } __except(EXCEPTION_EXECUTE_HANDLER) {
  2267. }
  2268. va_end(marker);
  2269. //
  2270. // Check for the event log being open.
  2271. //
  2272. if (!hEventLog) {
  2273. if (!InitializeEvents()) {
  2274. return -1;
  2275. }
  2276. }
  2277. //
  2278. // Report the event to the eventlog
  2279. //
  2280. aStrings[0] = szErrorMsg;
  2281. switch (LogLevel) {
  2282. case STATUS_SEVERITY_WARNING:
  2283. wType = EVENTLOG_WARNING_TYPE;
  2284. break;
  2285. case STATUS_SEVERITY_SUCCESS:
  2286. wType = EVENTLOG_SUCCESS;
  2287. break;
  2288. case STATUS_SEVERITY_ERROR:
  2289. wType = EVENTLOG_ERROR_TYPE;
  2290. break;
  2291. default:
  2292. wType = EVENTLOG_INFORMATION_TYPE;
  2293. break;
  2294. }
  2295. if (!ReportEvent(hEventLog,
  2296. wType,
  2297. 0,
  2298. dwEventID,
  2299. NULL,
  2300. 1,
  2301. 0,
  2302. (LPCTSTR *)aStrings,
  2303. NULL) ) {
  2304. return 1;
  2305. }
  2306. return 0;
  2307. }
  2308. BOOL
  2309. ShutdownEvents (void)
  2310. /*++
  2311. Routine Description:
  2312. Stops the event log
  2313. Arguments:
  2314. None
  2315. Return:
  2316. TRUE if successful
  2317. FALSE if an error occurs
  2318. --*/
  2319. {
  2320. BOOL bRetVal = TRUE;
  2321. if (hEventLog) {
  2322. bRetVal = DeregisterEventSource(hEventLog);
  2323. hEventLog = NULL;
  2324. }
  2325. return bRetVal;
  2326. }
  2327. LPWSTR
  2328. GetCertDisplayInformation(
  2329. IN PCCERT_CONTEXT pCertContext
  2330. )
  2331. /*++
  2332. Routine Description:
  2333. Returns the display string from the passed certificate context.
  2334. Arguments:
  2335. pCertContext - Supplies a pointer to an open certificate context.
  2336. Return Value:
  2337. On success, pointer to display string. Caller must call
  2338. free() to free.
  2339. NULL on failure.
  2340. --*/
  2341. {
  2342. DWORD Format = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
  2343. //
  2344. // First, try to get the email name
  2345. //
  2346. DWORD cchNameString;
  2347. LPWSTR wszNameString = NULL;
  2348. cchNameString = CertGetNameString(
  2349. pCertContext,
  2350. CERT_NAME_RDN_TYPE,
  2351. 0,
  2352. &Format,
  2353. NULL,
  2354. 0
  2355. );
  2356. if (cchNameString != 1) {
  2357. //
  2358. // String was found
  2359. //
  2360. wszNameString = (LPWSTR)malloc( cchNameString * sizeof( WCHAR ));
  2361. if (wszNameString) {
  2362. cchNameString = CertGetNameString(
  2363. pCertContext,
  2364. CERT_NAME_RDN_TYPE,
  2365. 0,
  2366. &Format,
  2367. wszNameString,
  2368. cchNameString
  2369. );
  2370. } else {
  2371. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  2372. }
  2373. } else {
  2374. //
  2375. // This shouldn't happen. If it does, we'll return NULL.
  2376. // Try to complain about it.
  2377. //
  2378. ASSERT( FALSE );
  2379. }
  2380. return( wszNameString );
  2381. }
  2382. BOOLEAN
  2383. IsSelfSignedPolicyExpired(
  2384. IN PRECOVERY_POLICY_1_1 RecoveryPolicy OPTIONAL
  2385. )
  2386. /*++
  2387. Routine Description:
  2388. This routine checks if the existing recovery cert expiring within one year
  2389. Arguments:
  2390. PolicyEfsInfo - Supplies a pointer to the current EFS recovery policy.
  2391. Return Value:
  2392. return-value - TRUE if it is within one year
  2393. --*/
  2394. {
  2395. BOOLEAN GetNewCert = TRUE;
  2396. if (RecoveryPolicy == NULL) {
  2397. //
  2398. // We need to create a new one if none exists.
  2399. //
  2400. return TRUE;
  2401. }
  2402. if (RecoveryPolicy->RecoveryPolicyHeader.RecoveryKeyCount > 1){
  2403. //
  2404. // Default recovery policy changed.
  2405. //
  2406. return FALSE;
  2407. }
  2408. __try {
  2409. //
  2410. // Scan the recovery data looking for recovery keys in a format we understand
  2411. //
  2412. PEFS_PUBLIC_KEY_INFO PublicKeyInfo = &((PRECOVERY_KEY_1_1) &(RecoveryPolicy->RecoveryKeyList[0]))->PublicKeyInfo;
  2413. if (PublicKeyInfo->KeySourceTag != EfsCertificate) {
  2414. //
  2415. // Out dated recovery cert. Get a new one
  2416. //
  2417. return TRUE;
  2418. }
  2419. PBYTE pbCert = (PBYTE)OFFSET_TO_POINTER(CertificateInfo.Certificate, PublicKeyInfo);
  2420. DWORD cbCert = PublicKeyInfo->CertificateInfo.CertificateLength;
  2421. PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(
  2422. CRYPT_ASN_ENCODING,
  2423. (const PBYTE)pbCert,
  2424. cbCert);
  2425. if (pCertContext) {
  2426. SYSTEMTIME CertTime;
  2427. SYSTEMTIME CrntTime;
  2428. if (FileTimeToSystemTime(&(pCertContext->pCertInfo->NotAfter), &CertTime)){
  2429. GetSystemTime( &CrntTime);
  2430. if ( CertTime.wYear <= CrntTime.wYear + 1) {
  2431. //
  2432. // Get the display information
  2433. //
  2434. LPWSTR lpDisplayInfo = GetCertDisplayInformation( pCertContext );
  2435. if (lpDisplayInfo ) {
  2436. if (!wcstok( lpDisplayInfo, L"OU=EFS File Encryption Certificate" )){
  2437. GetNewCert = FALSE;
  2438. }
  2439. free(lpDisplayInfo);
  2440. }
  2441. } else {
  2442. GetNewCert = FALSE;
  2443. }
  2444. }
  2445. CertFreeCertificateContext( pCertContext );
  2446. }
  2447. } __except (EXCEPTION_EXECUTE_HANDLER) {
  2448. //
  2449. // There was something wrong with the recovery policy.
  2450. // Get a new recovery cert.
  2451. //
  2452. }
  2453. return GetNewCert;
  2454. }