Source code of Windows XP (NT5)
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.

1473 lines
40 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: vroot.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. //+------------------------------------------------------------------------
  11. //
  12. // File: vroot.cpp
  13. //
  14. // Contents: Code for creating IIS web server virtual roots under K2.
  15. //
  16. // Functions: AddNewVDir()
  17. //
  18. // History: 5/16/97 JerryK Created
  19. //
  20. //-------------------------------------------------------------------------
  21. // Include File Voodoo
  22. #include "pch.cpp"
  23. #pragma hdrstop
  24. #include <lm.h>
  25. #include <sddl.h>
  26. #include "resource.h"
  27. #include "certacl.h"
  28. #define __dwFILE__ __dwFILE_CERTCLI_VROOT_CPP__
  29. #undef DEFINE_GUID
  30. #define INITGUID
  31. #ifndef INITGUID
  32. #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
  33. EXTERN_C const GUID FAR name
  34. #else
  35. #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
  36. EXTERN_C const GUID name \
  37. = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
  38. #endif // INITGUID
  39. #include <iwamreg.h>
  40. #include <iadmw.h>
  41. #include <iiscnfg.h>
  42. extern HINSTANCE g_hInstance;
  43. #define MAX_METABASE_ATTEMPTS 10 // Times to bang head on wall
  44. #define METABASE_PAUSE 500 // Time to pause in msec
  45. #define VRE_DELETEONLY 0x00000001 // Obsolete VRoot -- delete
  46. #define VRE_SCRIPTMAP 0x00000002 // Add additional associations to the script map
  47. #define VRE_ALLOWNTLM 0x00000004 // Alloc NTLM authentication
  48. #define VRE_CREATEAPP 0x00000008 // Create an in-process Web application
  49. typedef struct _VROOTENTRY
  50. {
  51. WCHAR *pwszVRootName;
  52. WCHAR *pwszDirectory; // relative to System32 directory
  53. DWORD Flags;
  54. } VROOTENTRY;
  55. VROOTENTRY g_avr[] = {
  56. // pwszVRootName pwszDirectory Flags
  57. { L"CertSrv", L"\\CertSrv", VRE_ALLOWNTLM | VRE_SCRIPTMAP | VRE_CREATEAPP},
  58. { L"CertControl", L"\\CertSrv\\CertControl", VRE_ALLOWNTLM },
  59. { L"CertEnroll", L"\\" wszCERTENROLLSHAREPATH, 0 },
  60. { L"CertQue", L"\\CertSrv\\CertQue", VRE_DELETEONLY },
  61. { L"CertAdm", L"\\CertSrv\\CertAdm", VRE_DELETEONLY },
  62. { NULL }
  63. };
  64. typedef struct _VRFSPARMS
  65. {
  66. IN DWORD Flags; // VFF_*
  67. IN ENUM_CATYPES CAType; // CAType
  68. IN BOOL fAsynchronous;
  69. IN DWORD csecTimeOut;
  70. OUT DWORD *pVRootDisposition; // VFD_*
  71. OUT DWORD *pShareDisposition; // VFD_*
  72. } VRFSPARMS;
  73. // Globals
  74. WCHAR const g_wszBaseRoot[] = L"/LM/W3svc/1/ROOT";
  75. WCHAR const g_wszCertCliDotDll[] = L"certcli.dll";
  76. WCHAR const g_wszDotAsp[] = L".asp";
  77. WCHAR const g_wszDotCer[] = L".cer";
  78. WCHAR const g_wszDotP7b[] = L".p7b";
  79. WCHAR const g_wszDotCrl[] = L".crl";
  80. // caller must have CoInitialize()'d
  81. BOOL
  82. IsIISInstalled(
  83. OUT HRESULT *phr)
  84. {
  85. IMSAdminBase *pIMeta = NULL;
  86. *phr = CoCreateInstance(
  87. CLSID_MSAdminBase,
  88. NULL,
  89. CLSCTX_ALL,
  90. IID_IMSAdminBase,
  91. (VOID **) &pIMeta);
  92. _JumpIfError2(*phr, error, "CoCreateInstance(CLSID_MSAdminBase)", *phr);
  93. error:
  94. if (NULL != pIMeta)
  95. {
  96. pIMeta->Release();
  97. }
  98. return(S_OK == *phr);
  99. }
  100. HRESULT
  101. vrOpenRoot(
  102. IN IMSAdminBase *pIMeta,
  103. IN BOOL fReadOnly,
  104. OUT METADATA_HANDLE *phMetaRoot)
  105. {
  106. HRESULT hr;
  107. DWORD i;
  108. __try
  109. {
  110. // Re-try a few times to see if we can get past the block
  111. for (i = 0; i < MAX_METABASE_ATTEMPTS; i++)
  112. {
  113. if (0 != i)
  114. {
  115. Sleep(METABASE_PAUSE); // Pause and try again
  116. }
  117. // Make an attempt to open the root
  118. hr = pIMeta->OpenKey(
  119. METADATA_MASTER_ROOT_HANDLE,
  120. g_wszBaseRoot,
  121. fReadOnly?
  122. METADATA_PERMISSION_READ :
  123. (METADATA_PERMISSION_READ |
  124. METADATA_PERMISSION_WRITE),
  125. 1000,
  126. phMetaRoot);
  127. if (S_OK == hr)
  128. {
  129. break; // Success -- we're done!
  130. }
  131. // See if a previous call has things tied up
  132. if (HRESULT_FROM_WIN32(ERROR_PATH_BUSY) != hr)
  133. {
  134. _LeaveIfError(hr, "OpenKey"); // Detected some other error
  135. }
  136. }
  137. _LeaveIfError(hr, "OpenKey(timeout)"); // Detected some other error
  138. }
  139. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  140. {
  141. }
  142. //error:
  143. return(hr);
  144. }
  145. HRESULT
  146. vrCloseKey(
  147. IN IMSAdminBase *pIMeta,
  148. IN METADATA_HANDLE hMeta,
  149. IN HRESULT hr)
  150. {
  151. HRESULT hr2;
  152. __try
  153. {
  154. hr2 = pIMeta->CloseKey(hMeta);
  155. _LeaveIfError(hr2, "CloseKey");
  156. }
  157. __except(hr2 = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  158. {
  159. }
  160. if (S_OK != hr2)
  161. {
  162. if (S_OK == hr)
  163. {
  164. hr = hr2;
  165. }
  166. _PrintError(hr2, "CloseKey");
  167. }
  168. return(hr);
  169. }
  170. //+----------------------------------------------------------------------------
  171. //
  172. // Function: AddNewVDir(. . . .)
  173. //
  174. // Synopsis: Creates a new virtual root using the K2 metabase.
  175. //
  176. // Arguments: [pwszVRootName] Name to give to the virtual root
  177. // [pwszDirectory] Path for the directory to use as the root.
  178. //
  179. // Returns: HRESULT status code regurgitated from metabase COM interfaces
  180. //
  181. //
  182. // History: 05/16/97 JerryK Put in this file
  183. // 05/22/97 JerryK Made OCM setup build with this stuff
  184. // in place.
  185. //
  186. // Notes: Originally derived from sample code provided by MikeHow;
  187. // hacked up a lot in between.
  188. //
  189. // We do a try, fail, pause, retry loop on our attempts to open
  190. // the metabase master key to get around a K2 bug that can result
  191. // in it being left busy if this function is called too many
  192. // times successively.
  193. //
  194. // TO DO: COME BACK AND PUT SEMIREADABLE GUI LEVEL MESSAGEBOX REPORTING
  195. // THAT THE VROOTS IN QUESTION DIDN'T SET UP CORRECTLY.
  196. //
  197. //-----------------------------------------------------------------------------
  198. HRESULT
  199. AddNewVDir(
  200. IN LPWSTR pwszVRootName,
  201. IN LPWSTR pwszDirectory,
  202. IN BOOL fScriptMap,
  203. IN BOOL fNTLM,
  204. IN BOOL fCreateApp,
  205. OUT BOOL *pfExists)
  206. {
  207. HRESULT hr;
  208. METADATA_RECORD mr;
  209. IMSAdminBase *pIMeta = NULL;
  210. IWamAdmin *pIWam = NULL;
  211. WCHAR *pwszNewPath = NULL;
  212. WCHAR *pwszCurrentScriptMap=NULL;
  213. WCHAR *pwszNewScriptMap=NULL;
  214. WCHAR wszKeyType[] = TEXT(IIS_CLASS_WEB_VDIR);
  215. METADATA_HANDLE hMetaRoot = NULL; // Open key to ROOT (where VDirs live)
  216. DWORD dwMDData = MD_LOGON_NETWORK; // Create network token when logging on anonymous account
  217. METADATA_RECORD MDData =
  218. {
  219. MD_LOGON_METHOD,
  220. 0,
  221. IIS_MD_UT_SERVER,
  222. DWORD_METADATA,
  223. sizeof(dwMDData),
  224. (unsigned char*)&dwMDData,
  225. 0
  226. };
  227. *pfExists = FALSE;
  228. DBGPRINT((
  229. DBG_SS_CERTLIBI,
  230. "AddNewVDir(%ws, %ws, fScriptMap=%d, fNTLM=%d, fCreateApp=%d)\n",
  231. pwszVRootName,
  232. pwszDirectory,
  233. fScriptMap,
  234. fNTLM,
  235. fCreateApp));
  236. // Create an instance of the metabase object
  237. hr = CoCreateInstance(
  238. CLSID_MSAdminBase,
  239. NULL,
  240. CLSCTX_ALL,
  241. IID_IMSAdminBase,
  242. (void **) &pIMeta);
  243. _JumpIfError(hr, error, "CoCreateInstance");
  244. __try
  245. {
  246. hr = vrOpenRoot(pIMeta, FALSE, &hMetaRoot);
  247. _JumpIfError(hr, error, "vrOpenRoot");
  248. // Add new VDir called pwszVRootName
  249. hr = pIMeta->AddKey(hMetaRoot, pwszVRootName);
  250. DBGPRINT((
  251. DBG_SS_CERTLIBI,
  252. "AddNewVDir: AddKey(%ws) --> %x\n",
  253. pwszVRootName,
  254. hr));
  255. if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) == hr)
  256. {
  257. *pfExists = TRUE;
  258. }
  259. else
  260. {
  261. _LeaveIfError(hr, "AddKey");
  262. }
  263. if (fScriptMap) {
  264. // get the current script map
  265. DWORD dwDataSize;
  266. mr.dwMDIdentifier=MD_SCRIPT_MAPS;
  267. mr.dwMDAttributes=METADATA_INHERIT;
  268. mr.dwMDUserType=IIS_MD_UT_FILE;
  269. mr.dwMDDataType=MULTISZ_METADATA;
  270. mr.dwMDDataLen=0;
  271. mr.pbMDData=NULL;
  272. hr=pIMeta->GetData(hMetaRoot, L"", &mr, &dwDataSize);
  273. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)!=hr) {
  274. _LeaveError(hr, "GetData");
  275. }
  276. pwszCurrentScriptMap=reinterpret_cast<WCHAR *>(new unsigned char[dwDataSize]);
  277. if (NULL==pwszCurrentScriptMap) {
  278. hr=E_OUTOFMEMORY;
  279. _LeaveError(hr, "new");
  280. }
  281. mr.pbMDData=reinterpret_cast<unsigned char *>(pwszCurrentScriptMap);
  282. mr.dwMDDataLen=dwDataSize;
  283. hr=pIMeta->GetData(hMetaRoot, L"", &mr, &dwDataSize);
  284. _LeaveIfError(hr, "GetData");
  285. }
  286. hr = pIMeta->SetData(hMetaRoot, pwszVRootName, &MDData);
  287. _LeaveIfError(hr, "CloseKey");
  288. hr = pIMeta->CloseKey(hMetaRoot);
  289. _LeaveIfError(hr, "CloseKey");
  290. hMetaRoot = NULL;
  291. // Build the name of the new VDir
  292. pwszNewPath = new WCHAR[wcslen(g_wszBaseRoot) + 1 + wcslen(pwszVRootName) + 1];
  293. if (NULL == pwszNewPath)
  294. {
  295. hr = E_OUTOFMEMORY;
  296. _LeaveError(hr, "new");
  297. }
  298. wcscpy(pwszNewPath, g_wszBaseRoot);
  299. wcscat(pwszNewPath, L"/");
  300. wcscat(pwszNewPath, pwszVRootName);
  301. // Open the new VDir
  302. METADATA_HANDLE hMetaKey = NULL;
  303. hr = pIMeta->OpenKey(
  304. METADATA_MASTER_ROOT_HANDLE,
  305. pwszNewPath,
  306. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  307. 1000,
  308. &hMetaKey);
  309. _LeaveIfErrorStr(hr, "OpenKey", pwszNewPath);
  310. // Set the physical path for this VDir
  311. // virtual root path
  312. mr.dwMDIdentifier = MD_VR_PATH;
  313. mr.dwMDAttributes = METADATA_INHERIT;
  314. mr.dwMDUserType = IIS_MD_UT_FILE;
  315. mr.dwMDDataType = STRING_METADATA;
  316. mr.dwMDDataLen = (wcslen(pwszDirectory) + 1) * sizeof(WCHAR);
  317. mr.pbMDData = reinterpret_cast<unsigned char *>(pwszDirectory);
  318. hr = pIMeta->SetData(hMetaKey, L"", &mr);
  319. _LeaveIfError(hr, "SetData");
  320. // access permissions on VRoots: read & execute scripts only
  321. DWORD dwAccessPerms = MD_ACCESS_SCRIPT | MD_ACCESS_READ;
  322. mr.dwMDIdentifier = MD_ACCESS_PERM;
  323. mr.dwMDAttributes = METADATA_INHERIT;
  324. mr.dwMDUserType = IIS_MD_UT_FILE;
  325. mr.dwMDDataType = DWORD_METADATA;
  326. mr.dwMDDataLen = sizeof(dwAccessPerms);
  327. mr.pbMDData = reinterpret_cast<unsigned char *>(&dwAccessPerms);
  328. hr = pIMeta->SetData(hMetaKey, L"", &mr);
  329. _LeaveIfError(hr, "SetData");
  330. // key type
  331. mr.dwMDIdentifier = MD_KEY_TYPE;
  332. mr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  333. mr.dwMDUserType = IIS_MD_UT_SERVER;
  334. mr.dwMDDataType = STRING_METADATA;
  335. mr.dwMDDataLen = (wcslen(wszKeyType) + 1) * sizeof(WCHAR);
  336. mr.pbMDData = reinterpret_cast<unsigned char *>(wszKeyType);
  337. hr = pIMeta->SetData(hMetaKey, L"", &mr);
  338. _LeaveIfError(hr, "SetData");
  339. // set authentication to be anonymous
  340. DWORD dwAuthenticationType = MD_AUTH_ANONYMOUS;
  341. // chg to Basic/NTLM if we're told to
  342. if (fNTLM)
  343. dwAuthenticationType = MD_AUTH_BASIC | MD_AUTH_NT;
  344. mr.dwMDIdentifier = MD_AUTHORIZATION;
  345. mr.dwMDAttributes = METADATA_INHERIT;
  346. mr.dwMDUserType = IIS_MD_UT_FILE;
  347. mr.dwMDDataType = DWORD_METADATA;
  348. mr.dwMDDataLen = sizeof(dwAuthenticationType);
  349. mr.pbMDData = reinterpret_cast<unsigned char *>(&dwAuthenticationType);
  350. hr = pIMeta->SetData(hMetaKey, L"", &mr);
  351. _LeaveIfError(hr, "SetData");
  352. if (fScriptMap) {
  353. // already have current script map.
  354. // walk through the script map and find .asp
  355. WCHAR * pwszCurAssoc=pwszCurrentScriptMap;
  356. do {
  357. if (L'\0'==pwszCurAssoc[0]) {
  358. hr=HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  359. _LeaveError(hr, ".asp association not found");
  360. } else if (0==_wcsnicmp(pwszCurAssoc, g_wszDotAsp, 4)) {
  361. break;
  362. } else {
  363. pwszCurAssoc+=wcslen(pwszCurAssoc)+1;
  364. }
  365. } while (TRUE);
  366. // Walk through the script map and find the last association.
  367. // We can't just subtract one from the total length
  368. // because there is a bug in IIS where sometimes it has a
  369. // triple terminator instead of a double terminator. <Sigh>
  370. unsigned int cchCurScriptMap=0;
  371. while(L'\0'!=pwszCurrentScriptMap[cchCurScriptMap]) {
  372. cchCurScriptMap+=wcslen(pwszCurrentScriptMap+cchCurScriptMap)+1;
  373. }
  374. // create a new script map that has .crl, .cer, and .p7b in it.
  375. // allocate enough space for the existing map, the three new associations, and the terminating \0.
  376. unsigned int cchAssocLen=wcslen(pwszCurAssoc)+1;
  377. pwszNewScriptMap=new WCHAR[cchCurScriptMap+cchAssocLen*3+1];
  378. if (NULL==pwszNewScriptMap) {
  379. hr=E_OUTOFMEMORY;
  380. _LeaveError(hr, "new");
  381. }
  382. // build the map
  383. WCHAR * pwszTravel=pwszNewScriptMap;
  384. // copy the existing map
  385. CopyMemory(pwszTravel, pwszCurrentScriptMap, cchCurScriptMap*sizeof(WCHAR));
  386. pwszTravel+=cchCurScriptMap;
  387. // add the .cer association
  388. wcscpy(pwszTravel, pwszCurAssoc);
  389. wcsncpy(pwszTravel, g_wszDotCer, 4);
  390. pwszTravel+=cchAssocLen;
  391. // add the .p7b association
  392. wcscpy(pwszTravel, pwszCurAssoc);
  393. wcsncpy(pwszTravel, g_wszDotP7b, 4);
  394. pwszTravel+=cchAssocLen;
  395. // add the .crl association
  396. wcscpy(pwszTravel, pwszCurAssoc);
  397. wcsncpy(pwszTravel, g_wszDotCrl, 4);
  398. pwszTravel+=cchAssocLen;
  399. // add the terminator
  400. pwszTravel[0]=L'\0';
  401. // set the new script map
  402. mr.dwMDIdentifier=MD_SCRIPT_MAPS;
  403. mr.dwMDAttributes=METADATA_INHERIT;
  404. mr.dwMDUserType=IIS_MD_UT_FILE;
  405. mr.dwMDDataType=MULTISZ_METADATA;
  406. mr.dwMDDataLen=(cchCurScriptMap+cchAssocLen*3+1) * sizeof(WCHAR);
  407. mr.pbMDData=reinterpret_cast<unsigned char *>(pwszNewScriptMap);
  408. hr=pIMeta->SetData(hMetaKey, L"", &mr);
  409. _LeaveIfError(hr, "SetData");
  410. }
  411. hr = pIMeta->CloseKey(hMetaKey);
  412. _LeaveIfError(hr, "CloseKey");
  413. // Flush out the changes and close
  414. hr = pIMeta->SaveData();
  415. // Note: W2k used to swallow this error
  416. _LeaveIfError(hr, "SaveData");
  417. // _PrintIfError(hr, "SaveData");
  418. // hr = S_OK;
  419. // Create a 'web application' so that scrdenrl.dll runs in-process
  420. if (fCreateApp)
  421. {
  422. // Create an instance of the metabase object
  423. hr = CoCreateInstance(
  424. CLSID_WamAdmin,
  425. NULL,
  426. CLSCTX_ALL,
  427. IID_IWamAdmin,
  428. (void **) &pIWam);
  429. _LeaveIfError(hr, "CoCreateInstance");
  430. // Create the application running in-process
  431. hr = pIWam->AppCreate(pwszNewPath, TRUE);
  432. _LeaveIfError(hr, "AppCreate");
  433. }
  434. }
  435. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  436. {
  437. }
  438. error:
  439. if (NULL != pwszCurrentScriptMap)
  440. {
  441. delete [] pwszCurrentScriptMap;
  442. }
  443. if (NULL != pwszNewScriptMap)
  444. {
  445. delete [] pwszNewScriptMap;
  446. }
  447. if (NULL != pwszNewPath)
  448. {
  449. delete [] pwszNewPath;
  450. }
  451. if (NULL != hMetaRoot)
  452. {
  453. hr = vrCloseKey(pIMeta, hMetaRoot, hr);
  454. }
  455. if (NULL != pIWam)
  456. {
  457. pIWam->Release();
  458. }
  459. if (NULL != pIMeta)
  460. {
  461. pIMeta->Release();
  462. }
  463. return(hr);
  464. }
  465. BOOL
  466. TestForVDir(
  467. IN WCHAR *pwszVRootName)
  468. {
  469. HRESULT hr;
  470. IMSAdminBase *pIMeta = NULL;
  471. BOOL fExists = FALSE;
  472. BOOL fCoInit = FALSE;
  473. METADATA_HANDLE hMetaRoot = NULL; // Open key to ROOT (where VDirs live)
  474. METADATA_HANDLE hTestHandle = NULL;
  475. hr = CoInitialize(NULL);
  476. if (S_OK != hr && S_FALSE != hr)
  477. {
  478. _JumpError(hr, error, "CoInitialize");
  479. }
  480. fCoInit = TRUE;
  481. if (!IsIISInstalled(&hr))
  482. {
  483. goto error; // Ignore if IIS is not functioning or not installed
  484. }
  485. // Create an instance of the metabase object
  486. hr = CoCreateInstance(
  487. CLSID_MSAdminBase,
  488. NULL,
  489. CLSCTX_ALL,
  490. IID_IMSAdminBase,
  491. (void **) &pIMeta);
  492. _JumpIfError(hr, error, "CoCreateInstance");
  493. __try
  494. {
  495. hr = vrOpenRoot(pIMeta, TRUE, &hMetaRoot);
  496. _LeaveIfError(hr, "vrOpenRoot");
  497. // If we got here, we must have the master root handle
  498. // look for VDir
  499. hr = pIMeta->OpenKey(
  500. hMetaRoot,
  501. pwszVRootName,
  502. METADATA_PERMISSION_READ,
  503. 1000,
  504. &hTestHandle);
  505. DBGPRINT((
  506. DBG_SS_CERTLIBI,
  507. "TestForVDir: OpenKey(%ws) --> %x\n",
  508. pwszVRootName,
  509. hr));
  510. if (S_OK != hr)
  511. {
  512. hr = S_OK;
  513. __leave;
  514. }
  515. fExists = TRUE;
  516. hr = pIMeta->CloseKey(hTestHandle);
  517. _LeaveIfError(hr, "CloseKey");
  518. }
  519. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  520. {
  521. }
  522. error:
  523. if (NULL != hMetaRoot)
  524. {
  525. hr = vrCloseKey(pIMeta, hMetaRoot, hr);
  526. }
  527. if (NULL != pIMeta)
  528. {
  529. pIMeta->Release();
  530. }
  531. if (fCoInit)
  532. {
  533. CoUninitialize();
  534. }
  535. return(fExists);
  536. }
  537. #define SZ_HKEY_IIS_REGVROOT L"SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters\\Virtual Roots"
  538. HRESULT
  539. RemoveVDir(
  540. IN WCHAR *pwszVRootName,
  541. OUT BOOL *pfExisted)
  542. {
  543. HRESULT hr;
  544. HRESULT hr2;
  545. BOOL fCoInit = FALSE;
  546. IMSAdminBase *pIMeta = NULL;
  547. METADATA_HANDLE hMetaRoot = NULL; // Open key to ROOT (where VDirs live)
  548. *pfExisted = FALSE;
  549. hr = CoInitialize(NULL);
  550. if (S_OK != hr && S_FALSE != hr)
  551. {
  552. _JumpError(hr, error, "CoInitialize");
  553. }
  554. fCoInit = TRUE;
  555. // Create an instance of the metabase object
  556. hr = CoCreateInstance(
  557. CLSID_MSAdminBase,
  558. NULL,
  559. CLSCTX_ALL,
  560. IID_IMSAdminBase,
  561. (void **) &pIMeta);
  562. _JumpIfError(hr, error, "CoCreateInstance");
  563. __try
  564. {
  565. hr = vrOpenRoot(pIMeta, FALSE, &hMetaRoot);
  566. _LeaveIfError(hr, "vrOpenRoot");
  567. // If we got to here, we must have the master root handle
  568. // remove VDir
  569. hr2 = pIMeta->DeleteAllData(
  570. hMetaRoot,
  571. pwszVRootName,
  572. ALL_METADATA,
  573. ALL_METADATA);
  574. if (S_OK != hr2 && HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) != hr2)
  575. {
  576. hr = hr2;
  577. _PrintError(hr2, "DeleteAllData");
  578. }
  579. if (S_OK == hr2)
  580. {
  581. *pfExisted = TRUE;
  582. }
  583. hr2 = pIMeta->DeleteKey(hMetaRoot, pwszVRootName);
  584. if (S_OK != hr2 && HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) != hr2)
  585. {
  586. if (S_OK == hr)
  587. {
  588. hr = hr2;
  589. }
  590. _PrintError(hr2, "DeleteKey");
  591. }
  592. // HACKHACK: IIS reports S_OK in all cases above. However, if IIS is
  593. // stopped, it will recreate vroots when restarted. We have to delete
  594. // them from the registry manually (bleah!).
  595. {
  596. HKEY hKey;
  597. hr2 = RegOpenKeyEx(
  598. HKEY_LOCAL_MACHINE,
  599. SZ_HKEY_IIS_REGVROOT,
  600. 0,
  601. KEY_SET_VALUE,
  602. &hKey);
  603. _PrintIfError2(hr2, "RegDeleteValue", ERROR_FILE_NOT_FOUND);
  604. if (hr2 == S_OK)
  605. {
  606. WCHAR wsz[MAX_PATH + 1];
  607. if (wcslen(pwszVRootName) + 2 > ARRAYSIZE(wsz))
  608. {
  609. CSASSERT(!"pwszVRootName too long!");
  610. }
  611. else
  612. {
  613. wsz[0] = L'/';
  614. wcscpy(&wsz[1], pwszVRootName);
  615. hr2 = RegDeleteValue(hKey, wsz);
  616. _PrintIfError2(
  617. hr2,
  618. "RegDeleteValue (manual deletion of IIS VRoot)",
  619. ERROR_FILE_NOT_FOUND);
  620. }
  621. RegCloseKey(hKey);
  622. }
  623. // ignore missing vroot entries
  624. if (S_OK == hr && ERROR_FILE_NOT_FOUND != hr2)
  625. {
  626. hr = hr2;
  627. }
  628. }
  629. }
  630. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  631. {
  632. }
  633. error:
  634. if (NULL != hMetaRoot)
  635. {
  636. hr = vrCloseKey(pIMeta, hMetaRoot, hr);
  637. }
  638. if (NULL != pIMeta)
  639. {
  640. pIMeta->Release();
  641. }
  642. if (fCoInit)
  643. {
  644. CoUninitialize();
  645. }
  646. return(hr);
  647. }
  648. //+------------------------------------------------------------------------
  649. // Function: vrModifyVirtualRoots()
  650. //
  651. // Synopsis: Creates the virtual roots needed for cert server web pages.
  652. //
  653. // Effects: Creates IIS Virtual Roots
  654. //
  655. // Arguments: None.
  656. //-------------------------------------------------------------------------
  657. HRESULT
  658. vrModifyVirtualRoots(
  659. IN BOOL fCreate, // else Delete
  660. IN BOOL fNTLM,
  661. OPTIONAL OUT DWORD *pDisposition)
  662. {
  663. HRESULT hr;
  664. HRESULT hr2;
  665. WCHAR wszSystem32Path[MAX_PATH];
  666. WCHAR wszVRootPathTemp[MAX_PATH];
  667. BOOL fCoInit = FALSE;
  668. IMSAdminBase *pIMeta = NULL;
  669. METADATA_HANDLE hMetaRoot = NULL; // Open key to ROOT (where VDirs live)
  670. VROOTENTRY *pavr;
  671. BOOL fExist;
  672. DWORD Disposition = 0;
  673. if (NULL != pDisposition)
  674. {
  675. *pDisposition = 0;
  676. }
  677. hr = CoInitialize(NULL);
  678. if (S_OK != hr && S_FALSE != hr)
  679. {
  680. _JumpError(hr, error, "CoInitialize");
  681. }
  682. fCoInit = TRUE;
  683. DBGPRINT((
  684. DBG_SS_CERTLIBI,
  685. "vrModifyVirtualRoots(tid=%x, fCreate=%d, fNTLM=%d)\n",
  686. GetCurrentThreadId(),
  687. fCreate,
  688. fNTLM));
  689. if (!IsIISInstalled(&hr))
  690. {
  691. // IIS is not functioning or not installed
  692. _PrintError2(hr, "IsIISInstalled", hr);
  693. hr = S_OK;
  694. Disposition = VFD_NOTSUPPORTED;
  695. goto error;
  696. }
  697. // Create path for SYSTEM32 directory
  698. if (0 == GetSystemDirectory(wszSystem32Path, ARRAYSIZE(wszSystem32Path)))
  699. {
  700. hr = myHLastError();
  701. _JumpError(hr, error, "GetSystemDirectory");
  702. }
  703. // Create virtual roots
  704. for (pavr = g_avr; NULL != pavr->pwszVRootName; pavr++)
  705. {
  706. CSASSERT(ARRAYSIZE(wszVRootPathTemp) >
  707. wcslen(wszSystem32Path) + wcslen(pavr->pwszDirectory));
  708. wcscpy(wszVRootPathTemp, wszSystem32Path);
  709. wcscat(wszVRootPathTemp, pavr->pwszDirectory);
  710. if (fCreate)
  711. {
  712. if (0 == (VRE_DELETEONLY & pavr->Flags)) // if not obsolete
  713. {
  714. hr = AddNewVDir(
  715. pavr->pwszVRootName,
  716. wszVRootPathTemp,
  717. (VRE_SCRIPTMAP & pavr->Flags)? TRUE : FALSE,
  718. (fNTLM && (VRE_ALLOWNTLM & pavr->Flags))? TRUE : FALSE,
  719. (VRE_CREATEAPP & pavr->Flags)? TRUE : FALSE,
  720. &fExist);
  721. if (S_OK != hr)
  722. {
  723. Disposition = VFD_CREATEERROR;
  724. _JumpErrorStr(hr, error, "AddNewVDir", pavr->pwszVRootName);
  725. }
  726. Disposition = fExist? VFD_EXISTS : VFD_CREATED;
  727. }
  728. }
  729. else // else Delete
  730. {
  731. hr2 = RemoveVDir(pavr->pwszVRootName, &fExist);
  732. if (0 == (VRE_DELETEONLY & pavr->Flags)) // if not obsolete
  733. {
  734. if (S_OK != hr2)
  735. {
  736. if (S_OK == hr)
  737. {
  738. hr = hr2;
  739. }
  740. Disposition = VFD_DELETEERROR;
  741. _PrintError(hr2, "RemoveVDir");
  742. }
  743. else
  744. {
  745. Disposition = fExist? VFD_DELETED : VFD_NOTFOUND;
  746. }
  747. }
  748. }
  749. }
  750. error:
  751. if (NULL != pDisposition)
  752. {
  753. *pDisposition = Disposition;
  754. }
  755. if (fCoInit)
  756. {
  757. CoUninitialize();
  758. }
  759. DBGPRINT((
  760. DBG_SS_CERTLIBI,
  761. "vrModifyVirtualRoots(tid=%x, hr=%x, disp=%d)\n",
  762. GetCurrentThreadId(),
  763. hr,
  764. Disposition));
  765. return(hr);
  766. }
  767. // myAddShare: create and test new net share
  768. HRESULT
  769. myAddShare(
  770. LPCWSTR szShareName,
  771. LPCWSTR szShareDescr,
  772. LPCWSTR szSharePath,
  773. BOOL fOverwrite,
  774. OPTIONAL BOOL *pfCreated)
  775. {
  776. HRESULT hr;
  777. BOOL fCreated = FALSE;
  778. HANDLE hTestFile = INVALID_HANDLE_VALUE;
  779. LPWSTR pwszTestComputerName = NULL;
  780. LPWSTR pwszTestUNCPath = NULL;
  781. // Share local path
  782. SHARE_INFO_502 shareStruct;
  783. ZeroMemory(&shareStruct, sizeof(shareStruct));
  784. shareStruct.shi502_netname = const_cast<WCHAR *>(szShareName);
  785. shareStruct.shi502_type = STYPE_DISKTREE;
  786. shareStruct.shi502_remark = const_cast<WCHAR *>(szShareDescr);
  787. shareStruct.shi502_max_uses = -1;
  788. shareStruct.shi502_path = const_cast<WCHAR *>(szSharePath);
  789. hr = myGetSDFromTemplate(WSZ_DEFAULT_SHARE_SECURITY,
  790. NULL,
  791. &shareStruct.shi502_security_descriptor);
  792. _JumpIfError(hr, error, "myGetSDFromTemplate");
  793. hr = NetShareAdd(
  794. NULL, // this computer
  795. 502, // SHARE_LEVEL_502 struct
  796. (BYTE *) &shareStruct,
  797. NULL);
  798. fCreated = (S_OK == hr);
  799. if (hr == (HRESULT) NERR_DuplicateShare)
  800. {
  801. SHARE_INFO_2* pstructDupShare = NULL;
  802. hr = NetShareGetInfo(
  803. NULL,
  804. const_cast<WCHAR *>(szShareName),
  805. 2,
  806. (BYTE **) &pstructDupShare);
  807. _JumpIfError(hr, error, "NetShareGetInfo");
  808. if (0 == wcscmp(pstructDupShare->shi2_path, szSharePath))
  809. {
  810. // they're the same path, so we're okay!
  811. hr = S_OK;
  812. }
  813. else if (fOverwrite)
  814. {
  815. // not the same path, but we've been instructed to bash existing
  816. // remove offending share
  817. hr = NetShareDel(
  818. NULL,
  819. const_cast<WCHAR *>(szShareName),
  820. 0);
  821. if (S_OK == hr)
  822. {
  823. // try again
  824. hr = NetShareAdd(
  825. NULL, // this computer
  826. 502, // SHARE_LEVEL_502 struct
  827. (BYTE *) &shareStruct,
  828. NULL);
  829. fCreated = (S_OK == hr);
  830. }
  831. }
  832. if (NULL != pstructDupShare)
  833. {
  834. NetApiBufferFree(pstructDupShare);
  835. }
  836. }
  837. // if share does not exist by this time, we bail
  838. _JumpIfError(hr, error, "NetShareAdd");
  839. // TEST: is writable?
  840. #define UNCPATH_TEMPLATE L"\\\\%ws\\%ws\\write.tmp"
  841. hr = myGetMachineDnsName(&pwszTestComputerName);
  842. _JumpIfError(hr, error, "myGetMachineDnsName");
  843. // get the local machine name
  844. pwszTestUNCPath = (LPWSTR)LocalAlloc(LMEM_FIXED,
  845. (UINT)(( ARRAYSIZE(UNCPATH_TEMPLATE) +
  846. wcslen(pwszTestComputerName) +
  847. wcslen(szShareName) )
  848. *sizeof(WCHAR)));
  849. if (NULL == pwszTestUNCPath)
  850. {
  851. hr = E_OUTOFMEMORY;
  852. _JumpError(hr, error, "LocalAlloc");
  853. }
  854. // create UNC path
  855. swprintf(pwszTestUNCPath, UNCPATH_TEMPLATE, pwszTestComputerName, szShareName);
  856. hTestFile = CreateFile(
  857. pwszTestUNCPath,
  858. GENERIC_WRITE,
  859. FILE_SHARE_WRITE,
  860. NULL,
  861. CREATE_ALWAYS,
  862. FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
  863. NULL);
  864. if (hTestFile == INVALID_HANDLE_VALUE)
  865. {
  866. hr = myHLastError();
  867. _JumpErrorStr(hr, error, "CreateFile (test for UNC translation)", pwszTestUNCPath);
  868. }
  869. // if we got this far, our test went well
  870. hr = S_OK;
  871. error:
  872. // if created and then something went wrong, clean up
  873. if (fCreated && (hr != S_OK))
  874. {
  875. // don't mash hr
  876. HRESULT hr2;
  877. hr2 = NetShareDel(
  878. NULL,
  879. const_cast<WCHAR *>(szShareName),
  880. 0);
  881. // ignore NetShareDel hr
  882. _PrintIfError(hr2, "NetShareDel"); // not fatal, might already be shared
  883. }
  884. if (INVALID_HANDLE_VALUE != hTestFile)
  885. CloseHandle(hTestFile);
  886. if (NULL != pwszTestComputerName)
  887. LocalFree(pwszTestComputerName);
  888. if (NULL != pwszTestUNCPath)
  889. LocalFree(pwszTestUNCPath);
  890. if(shareStruct.shi502_security_descriptor)
  891. {
  892. LocalFree(shareStruct.shi502_security_descriptor);
  893. }
  894. if(pfCreated)
  895. *pfCreated = fCreated;
  896. return hr;
  897. }
  898. HRESULT
  899. vrModifyFileShares(
  900. IN BOOL fCreate, // else Delete
  901. OPTIONAL OUT DWORD *pDisposition)
  902. {
  903. HRESULT hr;
  904. WCHAR wszSystem32Dir[MAX_PATH];
  905. WCHAR wszRemark[512];
  906. WCHAR *pwszDirectory = NULL;
  907. DWORD Disposition = 0;
  908. BOOL fCreated = FALSE;
  909. if (NULL != pDisposition)
  910. {
  911. *pDisposition = 0;
  912. }
  913. if (fCreate)
  914. {
  915. if (0 == GetSystemDirectory(wszSystem32Dir, ARRAYSIZE(wszSystem32Dir)))
  916. {
  917. hr = myHLastError();
  918. _JumpError(hr, error, "GetSystemDirectory");
  919. }
  920. hr = myBuildPathAndExt(
  921. wszSystem32Dir,
  922. wszCERTENROLLSHAREPATH,
  923. NULL,
  924. &pwszDirectory);
  925. _JumpIfError(hr, error, "myBuildPathAndExt");
  926. if (!LoadString(
  927. g_hInstance,
  928. IDS_FILESHARE_REMARK,
  929. wszRemark,
  930. ARRAYSIZE(wszRemark)))
  931. {
  932. hr = myHLastError();
  933. CSASSERT(S_OK != hr);
  934. _JumpError(hr, error, "LoadString");
  935. }
  936. hr = myAddShare(wszCERTENROLLSHARENAME,
  937. wszRemark,
  938. pwszDirectory,
  939. TRUE,
  940. &fCreated);
  941. if (S_OK == hr)
  942. {
  943. Disposition = fCreated?VFD_CREATED:VFD_EXISTS;
  944. }
  945. else
  946. {
  947. Disposition = VFD_CREATEERROR;
  948. _JumpErrorStr(hr, error, "NetShareAdd", wszCERTENROLLSHARENAME);
  949. }
  950. }
  951. else
  952. {
  953. hr = NetShareDel(NULL, wszCERTENROLLSHARENAME, NULL);
  954. CSASSERT(NERR_Success == S_OK);
  955. if (S_OK == hr)
  956. {
  957. Disposition = VFD_DELETED;
  958. }
  959. else if ((HRESULT) NERR_NetNameNotFound == hr)
  960. {
  961. Disposition = VFD_NOTFOUND;
  962. hr = S_OK;
  963. }
  964. else
  965. {
  966. Disposition = VFD_DELETEERROR;
  967. _JumpErrorStr(hr, error, "NetShareDel", wszCERTENROLLSHARENAME);
  968. }
  969. }
  970. NetShareDel(NULL, L"CertSrv", NULL); // delete old share name
  971. error:
  972. if (NULL != pDisposition)
  973. {
  974. *pDisposition = Disposition;
  975. }
  976. if (NULL != pwszDirectory)
  977. {
  978. LocalFree(pwszDirectory);
  979. }
  980. return(myHError(hr));
  981. }
  982. // For now, this writes the entry "CertUtil -vroot", and is not generalized
  983. HRESULT
  984. myWriteRunOnceEntry(
  985. IN BOOL fAdd // Add or Remove entry?
  986. )
  987. {
  988. DWORD err;
  989. // Add certutil -vroot to runonce commands
  990. WCHAR szRunOnceCommand[] = L"certutil -vroot";
  991. HKEY hkeyRunOnce = NULL;
  992. DWORD dwDisposition;
  993. err = RegCreateKeyEx(
  994. HKEY_LOCAL_MACHINE,
  995. L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce", // address of subkey name
  996. 0,
  997. NULL,
  998. 0,
  999. KEY_SET_VALUE,
  1000. NULL,
  1001. &hkeyRunOnce,
  1002. &dwDisposition);
  1003. _JumpIfError(err, error, "RegCreateKeyEx");
  1004. // add or remove entry?
  1005. if (fAdd)
  1006. {
  1007. err = RegSetValueEx(
  1008. hkeyRunOnce,
  1009. L"Certificate Services",
  1010. 0,
  1011. REG_SZ,
  1012. (BYTE *) szRunOnceCommand,
  1013. sizeof(szRunOnceCommand));
  1014. _JumpIfError(err, error, "RegSetValueEx");
  1015. }
  1016. else
  1017. {
  1018. err = RegDeleteValue(hkeyRunOnce, L"Certificate Services");
  1019. _PrintIfError2(err, "RegDeleteValue", ERROR_FILE_NOT_FOUND);
  1020. if (ERROR_FILE_NOT_FOUND == err)
  1021. {
  1022. err = ERROR_SUCCESS;
  1023. }
  1024. _JumpIfError(err, error, "RegDeleteValue");
  1025. }
  1026. error:
  1027. if (hkeyRunOnce)
  1028. RegCloseKey(hkeyRunOnce);
  1029. return (myHError(err));
  1030. }
  1031. DWORD
  1032. vrWorkerThread(
  1033. OPTIONAL IN OUT VOID *pvparms)
  1034. {
  1035. HRESULT hr = S_OK;
  1036. HRESULT hr2;
  1037. VRFSPARMS *pparms = (VRFSPARMS *) pvparms;
  1038. DWORD Disposition;
  1039. BOOL fFailed = FALSE;
  1040. CSASSERT(NULL != pparms);
  1041. if ((VFF_CREATEFILESHARES | VFF_DELETEFILESHARES) & pparms->Flags)
  1042. {
  1043. hr = vrModifyFileShares(
  1044. (VFF_CREATEFILESHARES & pparms->Flags)? TRUE : FALSE,
  1045. &Disposition);
  1046. _PrintIfError(hr, "vrModifyFileShares");
  1047. if (NULL != pparms->pShareDisposition)
  1048. {
  1049. *pparms->pShareDisposition = Disposition;
  1050. }
  1051. if (VFD_CREATEERROR == Disposition || VFD_DELETEERROR == Disposition)
  1052. {
  1053. fFailed = TRUE;
  1054. }
  1055. }
  1056. if ((VFF_CREATEVROOTS | VFF_DELETEVROOTS) & pparms->Flags)
  1057. {
  1058. BOOL fNTLM = FALSE; // set fNTLM iff Enterprise CA
  1059. if (IsEnterpriseCA(pparms->CAType))
  1060. {
  1061. fNTLM = TRUE;
  1062. }
  1063. hr2 = vrModifyVirtualRoots(
  1064. (VFF_CREATEVROOTS & pparms->Flags)? TRUE : FALSE,
  1065. fNTLM,
  1066. &Disposition);
  1067. _PrintIfError2(hr2, "vrModifyVirtualRoots", S_FALSE);
  1068. if (S_OK == hr)
  1069. {
  1070. hr = hr2;
  1071. }
  1072. if (NULL != pparms->pVRootDisposition)
  1073. {
  1074. *pparms->pVRootDisposition = Disposition;
  1075. }
  1076. if (VFD_CREATEERROR == Disposition || VFD_DELETEERROR == Disposition)
  1077. {
  1078. fFailed = TRUE;
  1079. }
  1080. }
  1081. if ((S_OK == hr && !fFailed) || ((VFF_DELETEVROOTS) & pparms->Flags)) // on success or removal
  1082. {
  1083. // remove "attempt vroot" flag so we don't try again
  1084. if (VFF_CLEARREGFLAGIFOK & pparms->Flags)
  1085. {
  1086. DBGPRINT((DBG_SS_CERTLIBI, "clearing registry\n"));
  1087. hr = SetSetupStatus(NULL, SETUP_ATTEMPT_VROOT_CREATE, FALSE);
  1088. _JumpIfError(hr, error, "SetSetupStatus");
  1089. }
  1090. hr = myWriteRunOnceEntry(FALSE); // worker thread deletes on success
  1091. _JumpIfError(hr, error, "myWriteRunOnceEntry");
  1092. }
  1093. error:
  1094. LocalFree(pparms);
  1095. DBGPRINT((DBG_SS_CERTLIBI, "vrWorkerThread returns %x\n", hr));
  1096. return(myHError(hr));
  1097. }
  1098. //+------------------------------------------------------------------------
  1099. // Function: myModifyVirtualRootsAndFileShares
  1100. //
  1101. // Synopsis: Creates the virtual roots needed for cert server web pages.
  1102. //
  1103. // Effects: Creates IIS Virtual Roots
  1104. //
  1105. // Arguments: None.
  1106. //-------------------------------------------------------------------------
  1107. HRESULT
  1108. myModifyVirtualRootsAndFileShares(
  1109. IN DWORD Flags, // VFF_*: Create/Delete VRoots and/or Shares
  1110. IN ENUM_CATYPES CAType,
  1111. IN BOOL fAsynchronous,
  1112. IN DWORD csecTimeOut,
  1113. OPTIONAL OUT DWORD *pVRootDisposition, // VFD_*
  1114. OPTIONAL OUT DWORD *pShareDisposition) // VFD_*
  1115. {
  1116. HRESULT hr;
  1117. HANDLE hThread = NULL;
  1118. HMODULE hMod = NULL;
  1119. DWORD ThreadId;
  1120. DWORD dw;
  1121. BOOL fEnable = TRUE;
  1122. DWORD SetupStatus;
  1123. VRFSPARMS *pparms = NULL;
  1124. if (NULL != pVRootDisposition)
  1125. {
  1126. *pVRootDisposition = 0;
  1127. }
  1128. if (NULL != pShareDisposition)
  1129. {
  1130. *pShareDisposition = 0;
  1131. }
  1132. dw = (VFF_DELETEVROOTS | VFF_DELETEFILESHARES) & Flags;
  1133. if (0 != dw && dw != Flags)
  1134. {
  1135. hr = E_INVALIDARG;
  1136. _JumpError(hr, error, "Mixed VFF_DELETE* and create flags");
  1137. }
  1138. if (((VFF_CHECKREGFLAGFIRST | VFF_CLEARREGFLAGFIRST) & Flags) &&
  1139. (VFF_SETREGFLAGFIRST & Flags))
  1140. {
  1141. hr = E_INVALIDARG;
  1142. _JumpError(hr, error, "Mixed VFF_SETREGFLAGFIRST & VFF_*REGFLAGFIRST");
  1143. }
  1144. hr = GetSetupStatus(NULL, &SetupStatus);
  1145. if (S_OK != hr)
  1146. {
  1147. _PrintError(hr, "GetSetupStatus(ignored)");
  1148. hr = S_OK;
  1149. SetupStatus = 0;
  1150. }
  1151. if (VFF_CHECKREGFLAGFIRST & Flags)
  1152. {
  1153. if (0 == (SETUP_ATTEMPT_VROOT_CREATE & SetupStatus))
  1154. {
  1155. fEnable = FALSE;
  1156. }
  1157. }
  1158. if (VFF_CLEARREGFLAGFIRST & Flags)
  1159. {
  1160. // remove "attempt vroot" flag so we don't try again
  1161. if (SETUP_ATTEMPT_VROOT_CREATE & SetupStatus)
  1162. {
  1163. hr = SetSetupStatus(NULL, SETUP_ATTEMPT_VROOT_CREATE, FALSE);
  1164. _JumpIfError(hr, error, "SetSetupStatus");
  1165. }
  1166. }
  1167. if (VFF_SETREGFLAGFIRST & Flags)
  1168. {
  1169. // set "attempt vroot" flag so we'll try again if necessary
  1170. if (0 == (SETUP_ATTEMPT_VROOT_CREATE & SetupStatus))
  1171. {
  1172. hr = SetSetupStatus(NULL, SETUP_ATTEMPT_VROOT_CREATE, TRUE);
  1173. _JumpIfError(hr, error, "SetSetupStatus");
  1174. }
  1175. }
  1176. hr = S_OK;
  1177. if (fEnable)
  1178. {
  1179. // only set RunOnce on a real attempt (worker thread clears this)
  1180. if (VFF_SETRUNONCEIFERROR & Flags)
  1181. {
  1182. hr = myWriteRunOnceEntry(TRUE);
  1183. _JumpIfError(hr, error, "myWriteRunOnceEntry");
  1184. }
  1185. pparms = (VRFSPARMS *) LocalAlloc(
  1186. LMEM_FIXED | LMEM_ZEROINIT,
  1187. sizeof(*pparms));
  1188. if (NULL == pparms)
  1189. {
  1190. hr = E_OUTOFMEMORY;
  1191. _JumpError(hr, error, "LocalAlloc");
  1192. }
  1193. pparms->Flags = Flags;
  1194. pparms->CAType = CAType;
  1195. pparms->csecTimeOut = csecTimeOut;
  1196. pparms->fAsynchronous = fAsynchronous;
  1197. if (!fAsynchronous)
  1198. {
  1199. pparms->pVRootDisposition = pVRootDisposition;
  1200. pparms->pShareDisposition = pShareDisposition;
  1201. }
  1202. else
  1203. {
  1204. hMod = LoadLibrary(g_wszCertCliDotDll);
  1205. if (NULL == hMod)
  1206. {
  1207. hr = myHLastError();
  1208. _JumpError(hr, error, "LoadLibrary");
  1209. }
  1210. }
  1211. hThread = CreateThread(
  1212. NULL, // lpThreadAttributes (Security Attr)
  1213. 0, // dwStackSize
  1214. vrWorkerThread,
  1215. pparms, // lpParameter
  1216. 0, // dwCreationFlags
  1217. &ThreadId);
  1218. if (NULL == hThread)
  1219. {
  1220. hr = myHLastError();
  1221. _JumpError(hr, error, "CreateThread");
  1222. }
  1223. pparms = NULL; // freed by the new thread
  1224. DBGPRINT((DBG_SS_CERTLIBI, "VRoot Worker Thread = %x\n", ThreadId));
  1225. // asynch? proper thread creation is all we do
  1226. if (fAsynchronous)
  1227. {
  1228. hr = S_OK;
  1229. goto error;
  1230. }
  1231. // Wait for the worker thread to exit
  1232. hr = WaitForSingleObject(
  1233. hThread,
  1234. (INFINITE == csecTimeOut) ? INFINITE : csecTimeOut * 1000 );
  1235. DBGPRINT((DBG_SS_CERTLIBI, "Wait for worker thread returns %x\n", hr));
  1236. if ((HRESULT) WAIT_OBJECT_0 == hr)
  1237. {
  1238. // worker thread returned.
  1239. if (!GetExitCodeThread(hThread, (DWORD *) &hr))
  1240. {
  1241. hr = myHLastError();
  1242. _JumpError(hr, error, "GetExitCodeThread");
  1243. }
  1244. DBGPRINT((DBG_SS_CERTLIBI, "worker thread exit: %x\n", hr));
  1245. if (S_OK != hr)
  1246. {
  1247. // If not synchronous, leave DLL loaded...
  1248. hMod = NULL;
  1249. _JumpError(hr, error, "vrWorkerThread");
  1250. }
  1251. }
  1252. else
  1253. {
  1254. // timeout: abandoning thread, leave the dll loaded
  1255. hMod = NULL;
  1256. _PrintError(hr, "WaitForSingleObject (ignored)");
  1257. // whack error
  1258. hr = S_OK;
  1259. }
  1260. }
  1261. error:
  1262. if (NULL != pparms)
  1263. {
  1264. LocalFree(pparms);
  1265. }
  1266. if (NULL != hThread)
  1267. {
  1268. CloseHandle(hThread);
  1269. }
  1270. if (NULL != hMod)
  1271. {
  1272. FreeLibrary(hMod);
  1273. }
  1274. DBGPRINT((DBG_SS_CERTLIBI, "myModifyVirtualRootsAndFileShares returns %x\n", hr));
  1275. return(myHError(hr));
  1276. }