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.

2511 lines
69 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. #include "multisz.h"
  29. #define __dwFILE__ __dwFILE_CERTCLI_VROOT_CPP__
  30. #undef DEFINE_GUID
  31. #define INITGUID
  32. #ifndef INITGUID
  33. #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
  34. EXTERN_C const GUID FAR name
  35. #else
  36. #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
  37. EXTERN_C const GUID name \
  38. = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
  39. #endif // INITGUID
  40. #include <iwamreg.h>
  41. #include <iadmw.h>
  42. #include <iiscnfg.h>
  43. extern HINSTANCE g_hInstance;
  44. #define MAX_METABASE_ATTEMPTS 10 // Times to bang head on wall
  45. #define METABASE_PAUSE 500 // Time to pause in msec
  46. #define VRE_DELETEONLY 0x00000001 // Obsolete VRoot -- delete
  47. #define VRE_SCRIPTMAP 0x00000002 // Add additional associations to the script map
  48. #define VRE_ALLOWNTLM 0x00000004 // Alloc NTLM authentication
  49. #define VRE_CREATEAPP 0x00000008 // Create an in-process Web application
  50. typedef struct _VROOTENTRY
  51. {
  52. WCHAR *pwszVRootName;
  53. WCHAR *pwszDirectory; // relative to System32 directory
  54. DWORD Flags;
  55. } VROOTENTRY;
  56. VROOTENTRY g_avr[] = {
  57. // pwszVRootName pwszDirectory Flags
  58. { L"CertSrv", L"\\CertSrv", VRE_ALLOWNTLM | VRE_SCRIPTMAP | VRE_CREATEAPP},
  59. { L"CertControl", L"\\CertSrv\\CertControl", VRE_ALLOWNTLM },
  60. { L"CertEnroll", L"\\" wszCERTENROLLSHAREPATH, 0 },
  61. { L"CertQue", L"\\CertSrv\\CertQue", VRE_DELETEONLY },
  62. { L"CertAdm", L"\\CertSrv\\CertAdm", VRE_DELETEONLY },
  63. { NULL }
  64. };
  65. typedef struct _VRFSPARMS
  66. {
  67. IN DWORD Flags; // VFF_*
  68. IN ENUM_CATYPES CAType; // CAType
  69. IN BOOL fAsynchronous;
  70. IN DWORD csecTimeOut;
  71. OUT DWORD *pVRootDisposition; // VFD_*
  72. OUT DWORD *pShareDisposition; // VFD_*
  73. } VRFSPARMS;
  74. // Globals
  75. WCHAR const g_wszBaseRoot[] = L"/LM/W3svc/1/ROOT";
  76. WCHAR const g_wszCertCliDotDll[] = L"certcli.dll";
  77. WCHAR const g_wszDotAsp[] = L".asp";
  78. WCHAR const g_wszDotCer[] = L".cer";
  79. WCHAR const g_wszDotP7b[] = L".p7b";
  80. WCHAR const g_wszDotCrl[] = L".crl";
  81. WCHAR const g_wszW3SVC[] = L"/LM/W3SVC";
  82. WCHAR const g_wszMSCEP[] = L"mscep.dll";
  83. WCHAR const g_wszMSCEPID[] = L"MSCEPGroup";
  84. // caller must have CoInitialize()'d
  85. BOOL
  86. IsIISInstalled(
  87. OUT HRESULT *phr)
  88. {
  89. IMSAdminBase *pIMeta = NULL;
  90. *phr = CoCreateInstance(
  91. CLSID_MSAdminBase,
  92. NULL,
  93. CLSCTX_ALL,
  94. IID_IMSAdminBase,
  95. (VOID **) &pIMeta);
  96. _JumpIfError2(*phr, error, "CoCreateInstance(CLSID_MSAdminBase)", *phr);
  97. error:
  98. if (NULL != pIMeta)
  99. {
  100. pIMeta->Release();
  101. }
  102. return(S_OK == *phr);
  103. }
  104. HRESULT
  105. vrOpenRoot(
  106. IN IMSAdminBase *pIMeta,
  107. IN BOOL fReadOnly,
  108. OUT METADATA_HANDLE *phMetaRoot)
  109. {
  110. HRESULT hr;
  111. DWORD i;
  112. hr = S_OK;
  113. __try
  114. {
  115. // Re-try a few times to see if we can get past the block
  116. for (i = 0; i < MAX_METABASE_ATTEMPTS; i++)
  117. {
  118. if (0 != i)
  119. {
  120. Sleep(METABASE_PAUSE); // Pause and try again
  121. }
  122. // Make an attempt to open the root
  123. hr = pIMeta->OpenKey(
  124. METADATA_MASTER_ROOT_HANDLE,
  125. g_wszBaseRoot,
  126. fReadOnly?
  127. METADATA_PERMISSION_READ :
  128. (METADATA_PERMISSION_READ |
  129. METADATA_PERMISSION_WRITE),
  130. 1000,
  131. phMetaRoot);
  132. if (S_OK == hr)
  133. {
  134. break; // Success -- we're done!
  135. }
  136. // See if a previous call has things tied up
  137. if (HRESULT_FROM_WIN32(ERROR_PATH_BUSY) != hr)
  138. {
  139. _LeaveIfError(hr, "OpenKey"); // Detected some other error
  140. }
  141. }
  142. _LeaveIfError(hr, "OpenKey(timeout)"); // Detected some other error
  143. }
  144. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  145. {
  146. }
  147. //error:
  148. return(hr);
  149. }
  150. HRESULT
  151. vrCloseKey(
  152. IN IMSAdminBase *pIMeta,
  153. IN METADATA_HANDLE hMeta,
  154. IN HRESULT hr)
  155. {
  156. HRESULT hr2;
  157. hr2 = S_OK;
  158. __try
  159. {
  160. hr2 = pIMeta->CloseKey(hMeta);
  161. _LeaveIfError(hr2, "CloseKey");
  162. }
  163. __except(hr2 = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  164. {
  165. }
  166. if (S_OK != hr2)
  167. {
  168. if (S_OK == hr)
  169. {
  170. hr = hr2;
  171. }
  172. _PrintError(hr2, "CloseKey");
  173. }
  174. return(hr);
  175. }
  176. //+----------------------------------------------------------------------------
  177. //
  178. // Function: AddNewVDir(. . . .)
  179. //
  180. // Synopsis: Creates a new virtual root using the K2 metabase.
  181. //
  182. // Arguments: [pwszVRootName] Name to give to the virtual root
  183. // [pwszDirectory] Path for the directory to use as the root.
  184. //
  185. // Returns: HRESULT status code regurgitated from metabase COM interfaces
  186. //
  187. //
  188. // History: 05/16/97 JerryK Put in this file
  189. // 05/22/97 JerryK Made OCM setup build with this stuff
  190. // in place.
  191. //
  192. // Notes: Originally derived from sample code provided by MikeHow;
  193. // hacked up a lot in between.
  194. //
  195. // We do a try, fail, pause, retry loop on our attempts to open
  196. // the metabase master key to get around a K2 bug that can result
  197. // in it being left busy if this function is called too many
  198. // times successively.
  199. //
  200. // TO DO: COME BACK AND PUT SEMIREADABLE GUI LEVEL MESSAGEBOX REPORTING
  201. // THAT THE VROOTS IN QUESTION DIDN'T SET UP CORRECTLY.
  202. //
  203. //-----------------------------------------------------------------------------
  204. HRESULT
  205. AddNewVDir(
  206. IN LPWSTR pwszVRootName,
  207. IN LPWSTR pwszDirectory,
  208. IN BOOL fScriptMap,
  209. IN BOOL fNTLM,
  210. IN BOOL fCreateApp,
  211. OUT BOOL *pfExists)
  212. {
  213. HRESULT hr;
  214. METADATA_RECORD mr;
  215. IMSAdminBase *pIMeta = NULL;
  216. IWamAdmin *pIWam = NULL;
  217. WCHAR *pwszNewPath = NULL;
  218. WCHAR *pwszCurrentScriptMap=NULL;
  219. WCHAR *pwszNewScriptMap=NULL;
  220. WCHAR wszKeyType[] = TEXT(IIS_CLASS_WEB_VDIR);
  221. METADATA_HANDLE hMetaRoot = NULL; // Open key to ROOT (where VDirs live)
  222. METADATA_HANDLE hMetaKey = NULL;
  223. DWORD dwMDData = MD_LOGON_NETWORK; // Create network token when logging on anonymous account
  224. METADATA_RECORD MDData =
  225. {
  226. MD_LOGON_METHOD,
  227. METADATA_INHERIT,
  228. IIS_MD_UT_FILE,
  229. DWORD_METADATA,
  230. sizeof(dwMDData),
  231. (unsigned char*)&dwMDData,
  232. 0
  233. };
  234. *pfExists = FALSE;
  235. DBGPRINT((
  236. DBG_SS_CERTLIBI,
  237. "AddNewVDir(%ws, %ws, fScriptMap=%d, fNTLM=%d, fCreateApp=%d)\n",
  238. pwszVRootName,
  239. pwszDirectory,
  240. fScriptMap,
  241. fNTLM,
  242. fCreateApp));
  243. // Create an instance of the metabase object
  244. hr = CoCreateInstance(
  245. CLSID_MSAdminBase,
  246. NULL,
  247. CLSCTX_ALL,
  248. IID_IMSAdminBase,
  249. (void **) &pIMeta);
  250. _JumpIfError(hr, error, "CoCreateInstance");
  251. __try
  252. {
  253. hr = vrOpenRoot(pIMeta, FALSE, &hMetaRoot);
  254. _LeaveIfError(hr, "vrOpenRoot");
  255. // Add new VDir called pwszVRootName
  256. hr = pIMeta->AddKey(hMetaRoot, pwszVRootName);
  257. DBGPRINT((
  258. DBG_SS_CERTLIBI,
  259. "AddNewVDir: AddKey(%ws) --> %x\n",
  260. pwszVRootName,
  261. hr));
  262. if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) == hr)
  263. {
  264. *pfExists = TRUE;
  265. }
  266. else
  267. {
  268. _LeaveIfError(hr, "AddKey");
  269. }
  270. if (fScriptMap) {
  271. // get the current script map
  272. DWORD dwDataSize;
  273. mr.dwMDIdentifier=MD_SCRIPT_MAPS;
  274. mr.dwMDAttributes=METADATA_INHERIT;
  275. mr.dwMDUserType=IIS_MD_UT_FILE;
  276. mr.dwMDDataType=MULTISZ_METADATA;
  277. mr.dwMDDataLen=0;
  278. mr.pbMDData=NULL;
  279. hr=pIMeta->GetData(hMetaRoot, L"", &mr, &dwDataSize);
  280. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)!=hr) {
  281. _LeaveError(hr, "GetData");
  282. }
  283. pwszCurrentScriptMap=reinterpret_cast<WCHAR *>(new unsigned char[dwDataSize]);
  284. if (NULL==pwszCurrentScriptMap) {
  285. hr=E_OUTOFMEMORY;
  286. _LeaveError(hr, "new");
  287. }
  288. mr.pbMDData=reinterpret_cast<unsigned char *>(pwszCurrentScriptMap);
  289. mr.dwMDDataLen=dwDataSize;
  290. hr=pIMeta->GetData(hMetaRoot, L"", &mr, &dwDataSize);
  291. _LeaveIfError(hr, "GetData");
  292. }
  293. hr = pIMeta->SetData(hMetaRoot, pwszVRootName, &MDData);
  294. _LeaveIfError(hr, "CloseKey");
  295. hr = pIMeta->CloseKey(hMetaRoot);
  296. _LeaveIfError(hr, "CloseKey");
  297. hMetaRoot = NULL;
  298. // Build the name of the new VDir
  299. pwszNewPath = new WCHAR[wcslen(g_wszBaseRoot) + 1 + wcslen(pwszVRootName) + 1];
  300. if (NULL == pwszNewPath)
  301. {
  302. hr = E_OUTOFMEMORY;
  303. _LeaveError(hr, "new");
  304. }
  305. wcscpy(pwszNewPath, g_wszBaseRoot);
  306. wcscat(pwszNewPath, L"/");
  307. wcscat(pwszNewPath, pwszVRootName);
  308. // Open the new VDir
  309. hr = pIMeta->OpenKey(
  310. METADATA_MASTER_ROOT_HANDLE,
  311. pwszNewPath,
  312. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  313. 1000,
  314. &hMetaKey);
  315. _LeaveIfErrorStr(hr, "OpenKey", pwszNewPath);
  316. // Set the physical path for this VDir
  317. // virtual root path
  318. mr.dwMDIdentifier = MD_VR_PATH;
  319. mr.dwMDAttributes = METADATA_INHERIT;
  320. mr.dwMDUserType = IIS_MD_UT_FILE;
  321. mr.dwMDDataType = STRING_METADATA;
  322. mr.dwMDDataLen = (wcslen(pwszDirectory) + 1) * sizeof(WCHAR);
  323. mr.pbMDData = reinterpret_cast<unsigned char *>(pwszDirectory);
  324. hr = pIMeta->SetData(hMetaKey, L"", &mr);
  325. _LeaveIfError(hr, "SetData");
  326. // access permissions on VRoots: read & execute scripts only
  327. DWORD dwAccessPerms = MD_ACCESS_SCRIPT | MD_ACCESS_READ;
  328. mr.dwMDIdentifier = MD_ACCESS_PERM;
  329. mr.dwMDAttributes = METADATA_INHERIT;
  330. mr.dwMDUserType = IIS_MD_UT_FILE;
  331. mr.dwMDDataType = DWORD_METADATA;
  332. mr.dwMDDataLen = sizeof(dwAccessPerms);
  333. mr.pbMDData = reinterpret_cast<unsigned char *>(&dwAccessPerms);
  334. hr = pIMeta->SetData(hMetaKey, L"", &mr);
  335. _LeaveIfError(hr, "SetData");
  336. // key type
  337. mr.dwMDIdentifier = MD_KEY_TYPE;
  338. mr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  339. mr.dwMDUserType = IIS_MD_UT_SERVER;
  340. mr.dwMDDataType = STRING_METADATA;
  341. mr.dwMDDataLen = (wcslen(wszKeyType) + 1) * sizeof(WCHAR);
  342. mr.pbMDData = reinterpret_cast<unsigned char *>(wszKeyType);
  343. hr = pIMeta->SetData(hMetaKey, L"", &mr);
  344. _LeaveIfError(hr, "SetData");
  345. // set authentication to be anonymous
  346. DWORD dwAuthenticationType = MD_AUTH_ANONYMOUS;
  347. // chg to Basic/NTLM if we're told to
  348. if (fNTLM)
  349. dwAuthenticationType = MD_AUTH_NT;
  350. mr.dwMDIdentifier = MD_AUTHORIZATION;
  351. mr.dwMDAttributes = METADATA_INHERIT;
  352. mr.dwMDUserType = IIS_MD_UT_FILE;
  353. mr.dwMDDataType = DWORD_METADATA;
  354. mr.dwMDDataLen = sizeof(dwAuthenticationType);
  355. mr.pbMDData = reinterpret_cast<unsigned char *>(&dwAuthenticationType);
  356. hr = pIMeta->SetData(hMetaKey, L"", &mr);
  357. _LeaveIfError(hr, "SetData");
  358. if (fScriptMap) {
  359. // already have current script map.
  360. // walk through the script map and find .asp
  361. WCHAR * pwszCurAssoc=pwszCurrentScriptMap;
  362. do {
  363. if (L'\0'==pwszCurAssoc[0]) {
  364. hr=HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  365. _LeaveError(hr, ".asp association not found");
  366. } else if (0==_wcsnicmp(pwszCurAssoc, g_wszDotAsp, 4)) {
  367. break;
  368. } else {
  369. pwszCurAssoc+=wcslen(pwszCurAssoc)+1;
  370. }
  371. } while (TRUE);
  372. // Walk through the script map and find the last association.
  373. // We can't just subtract one from the total length
  374. // because there is a bug in IIS where sometimes it has a
  375. // triple terminator instead of a double terminator. <Sigh>
  376. unsigned int cchCurScriptMap=0;
  377. while(L'\0'!=pwszCurrentScriptMap[cchCurScriptMap]) {
  378. cchCurScriptMap+=wcslen(pwszCurrentScriptMap+cchCurScriptMap)+1;
  379. }
  380. // create a new script map that has .crl, .cer, and .p7b in it.
  381. // allocate enough space for the existing map, the three new associations, and the terminating \0.
  382. unsigned int cchAssocLen=wcslen(pwszCurAssoc)+1;
  383. pwszNewScriptMap=new WCHAR[cchCurScriptMap+cchAssocLen*3+1];
  384. if (NULL==pwszNewScriptMap) {
  385. hr=E_OUTOFMEMORY;
  386. _LeaveError(hr, "new");
  387. }
  388. // build the map
  389. WCHAR * pwszTravel=pwszNewScriptMap;
  390. // copy the existing map
  391. CopyMemory(pwszTravel, pwszCurrentScriptMap, cchCurScriptMap*sizeof(WCHAR));
  392. pwszTravel+=cchCurScriptMap;
  393. // add the .cer association
  394. wcscpy(pwszTravel, pwszCurAssoc);
  395. wcsncpy(pwszTravel, g_wszDotCer, 4);
  396. pwszTravel+=cchAssocLen;
  397. // add the .p7b association
  398. wcscpy(pwszTravel, pwszCurAssoc);
  399. wcsncpy(pwszTravel, g_wszDotP7b, 4);
  400. pwszTravel+=cchAssocLen;
  401. // add the .crl association
  402. wcscpy(pwszTravel, pwszCurAssoc);
  403. wcsncpy(pwszTravel, g_wszDotCrl, 4);
  404. pwszTravel+=cchAssocLen;
  405. // add the terminator
  406. pwszTravel[0]=L'\0';
  407. // set the new script map
  408. mr.dwMDIdentifier=MD_SCRIPT_MAPS;
  409. mr.dwMDAttributes=METADATA_INHERIT;
  410. mr.dwMDUserType=IIS_MD_UT_FILE;
  411. mr.dwMDDataType=MULTISZ_METADATA;
  412. mr.dwMDDataLen=(cchCurScriptMap+cchAssocLen*3+1) * sizeof(WCHAR);
  413. mr.pbMDData=reinterpret_cast<unsigned char *>(pwszNewScriptMap);
  414. hr=pIMeta->SetData(hMetaKey, L"", &mr);
  415. _LeaveIfError(hr, "SetData");
  416. }
  417. hr = pIMeta->CloseKey(hMetaKey);
  418. _LeaveIfError(hr, "CloseKey");
  419. hMetaKey = NULL;
  420. // Flush out the changes and close
  421. hr = pIMeta->SaveData();
  422. // Note: W2k used to swallow this error
  423. _LeaveIfError(hr, "SaveData");
  424. // _PrintIfError(hr, "SaveData");
  425. // hr = S_OK;
  426. // Create a 'web application' so that scrdenrl.dll runs in-process
  427. if (fCreateApp)
  428. {
  429. // Create an instance of the metabase object
  430. hr = CoCreateInstance(
  431. CLSID_WamAdmin,
  432. NULL,
  433. CLSCTX_ALL,
  434. IID_IWamAdmin,
  435. (void **) &pIWam);
  436. _LeaveIfError(hr, "CoCreateInstance");
  437. // Create the application running in-process
  438. hr = pIWam->AppCreate(pwszNewPath, TRUE);
  439. _LeaveIfError(hr, "AppCreate");
  440. }
  441. }
  442. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  443. {
  444. }
  445. error:
  446. if (NULL != pwszCurrentScriptMap)
  447. {
  448. delete [] pwszCurrentScriptMap;
  449. }
  450. if (NULL != pwszNewScriptMap)
  451. {
  452. delete [] pwszNewScriptMap;
  453. }
  454. if (NULL != pwszNewPath)
  455. {
  456. delete [] pwszNewPath;
  457. }
  458. if (pIMeta && NULL != hMetaKey)
  459. {
  460. pIMeta->CloseKey(hMetaKey);
  461. }
  462. if (NULL != hMetaRoot)
  463. {
  464. hr = vrCloseKey(pIMeta, hMetaRoot, hr);
  465. }
  466. if (NULL != pIWam)
  467. {
  468. pIWam->Release();
  469. }
  470. if (NULL != pIMeta)
  471. {
  472. pIMeta->Release();
  473. }
  474. return(hr);
  475. }
  476. BOOL
  477. TestForVDir(
  478. IN WCHAR *pwszVRootName)
  479. {
  480. HRESULT hr;
  481. IMSAdminBase *pIMeta = NULL;
  482. BOOL fExists = FALSE;
  483. BOOL fCoInit = FALSE;
  484. METADATA_HANDLE hMetaRoot = NULL; // Open key to ROOT (where VDirs live)
  485. METADATA_HANDLE hTestHandle = NULL;
  486. hr = CoInitialize(NULL);
  487. if (S_OK != hr && S_FALSE != hr)
  488. {
  489. _JumpError(hr, error, "CoInitialize");
  490. }
  491. fCoInit = TRUE;
  492. if (!IsIISInstalled(&hr))
  493. {
  494. goto error; // Ignore if IIS is not functioning or not installed
  495. }
  496. // Create an instance of the metabase object
  497. hr = CoCreateInstance(
  498. CLSID_MSAdminBase,
  499. NULL,
  500. CLSCTX_ALL,
  501. IID_IMSAdminBase,
  502. (void **) &pIMeta);
  503. _JumpIfError(hr, error, "CoCreateInstance");
  504. __try
  505. {
  506. hr = vrOpenRoot(pIMeta, TRUE, &hMetaRoot);
  507. _LeaveIfError(hr, "vrOpenRoot");
  508. // If we got here, we must have the master root handle
  509. // look for VDir
  510. hr = pIMeta->OpenKey(
  511. hMetaRoot,
  512. pwszVRootName,
  513. METADATA_PERMISSION_READ,
  514. 1000,
  515. &hTestHandle);
  516. DBGPRINT((
  517. DBG_SS_CERTLIBI,
  518. "TestForVDir: OpenKey(%ws) --> %x\n",
  519. pwszVRootName,
  520. hr));
  521. if (S_OK != hr)
  522. {
  523. hr = S_OK;
  524. __leave;
  525. }
  526. fExists = TRUE;
  527. hr = pIMeta->CloseKey(hTestHandle);
  528. _LeaveIfError(hr, "CloseKey");
  529. }
  530. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  531. {
  532. }
  533. error:
  534. if (NULL != hMetaRoot)
  535. {
  536. hr = vrCloseKey(pIMeta, hMetaRoot, hr);
  537. }
  538. if (NULL != pIMeta)
  539. {
  540. pIMeta->Release();
  541. }
  542. if (fCoInit)
  543. {
  544. CoUninitialize();
  545. }
  546. return(fExists);
  547. }
  548. #define SZ_HKEY_IIS_REGVROOT L"SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters\\Virtual Roots"
  549. HRESULT
  550. RemoveVDir(
  551. IN WCHAR *pwszVRootName,
  552. OUT BOOL *pfExisted)
  553. {
  554. HRESULT hr;
  555. HRESULT hr2;
  556. BOOL fCoInit = FALSE;
  557. IMSAdminBase *pIMeta = NULL;
  558. METADATA_HANDLE hMetaRoot = NULL; // Open key to ROOT (where VDirs live)
  559. *pfExisted = FALSE;
  560. hr = CoInitialize(NULL);
  561. if (S_OK != hr && S_FALSE != hr)
  562. {
  563. _JumpError(hr, error, "CoInitialize");
  564. }
  565. fCoInit = TRUE;
  566. // Create an instance of the metabase object
  567. hr = CoCreateInstance(
  568. CLSID_MSAdminBase,
  569. NULL,
  570. CLSCTX_ALL,
  571. IID_IMSAdminBase,
  572. (void **) &pIMeta);
  573. _JumpIfError(hr, error, "CoCreateInstance");
  574. __try
  575. {
  576. hr = vrOpenRoot(pIMeta, FALSE, &hMetaRoot);
  577. _LeaveIfError(hr, "vrOpenRoot");
  578. // If we got to here, we must have the master root handle
  579. // remove VDir
  580. hr2 = pIMeta->DeleteAllData(
  581. hMetaRoot,
  582. pwszVRootName,
  583. ALL_METADATA,
  584. ALL_METADATA);
  585. if (S_OK != hr2 && HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) != hr2)
  586. {
  587. hr = hr2;
  588. _PrintError(hr2, "DeleteAllData");
  589. }
  590. if (S_OK == hr2)
  591. {
  592. *pfExisted = TRUE;
  593. }
  594. hr2 = pIMeta->DeleteKey(hMetaRoot, pwszVRootName);
  595. if (S_OK != hr2 && HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) != hr2)
  596. {
  597. if (S_OK == hr)
  598. {
  599. hr = hr2;
  600. }
  601. _PrintError(hr2, "DeleteKey");
  602. }
  603. // HACKHACK: IIS reports S_OK in all cases above. However, if IIS is
  604. // stopped, it will recreate vroots when restarted. We have to delete
  605. // them from the registry manually (bleah!).
  606. {
  607. HKEY hKey;
  608. hr2 = RegOpenKeyEx(
  609. HKEY_LOCAL_MACHINE,
  610. SZ_HKEY_IIS_REGVROOT,
  611. 0,
  612. KEY_SET_VALUE,
  613. &hKey);
  614. _PrintIfError2(hr2, "RegDeleteValue", ERROR_FILE_NOT_FOUND);
  615. if (hr2 == S_OK)
  616. {
  617. WCHAR wsz[MAX_PATH + 1];
  618. if (wcslen(pwszVRootName) + 2 > ARRAYSIZE(wsz))
  619. {
  620. CSASSERT(!"pwszVRootName too long!");
  621. }
  622. else
  623. {
  624. wsz[0] = L'/';
  625. wcscpy(&wsz[1], pwszVRootName);
  626. hr2 = RegDeleteValue(hKey, wsz);
  627. _PrintIfError2(
  628. hr2,
  629. "RegDeleteValue (manual deletion of IIS VRoot)",
  630. ERROR_FILE_NOT_FOUND);
  631. }
  632. RegCloseKey(hKey);
  633. }
  634. // ignore missing vroot entries
  635. if (S_OK == hr && (HRESULT) ERROR_FILE_NOT_FOUND != hr2)
  636. {
  637. hr = hr2;
  638. }
  639. }
  640. }
  641. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  642. {
  643. }
  644. error:
  645. if (NULL != hMetaRoot)
  646. {
  647. hr = vrCloseKey(pIMeta, hMetaRoot, hr);
  648. }
  649. if (NULL != pIMeta)
  650. {
  651. pIMeta->Release();
  652. }
  653. if (fCoInit)
  654. {
  655. CoUninitialize();
  656. }
  657. return(hr);
  658. }
  659. //+------------------------------------------------------------------------
  660. // Function: vrModifyVirtualRoots()
  661. //
  662. // Synopsis: Creates the virtual roots needed for cert server web pages.
  663. //
  664. // Effects: Creates IIS Virtual Roots
  665. //
  666. // Arguments: None.
  667. //-------------------------------------------------------------------------
  668. HRESULT
  669. vrModifyVirtualRoots(
  670. IN BOOL fCreate, // else Delete
  671. IN BOOL fNTLM,
  672. OPTIONAL OUT DWORD *pDisposition)
  673. {
  674. HRESULT hr;
  675. HRESULT hr2;
  676. WCHAR wszSystem32Path[MAX_PATH];
  677. WCHAR wszVRootPathTemp[MAX_PATH];
  678. BOOL fCoInit = FALSE;
  679. VROOTENTRY *pavr;
  680. BOOL fExist;
  681. DWORD Disposition = 0;
  682. if (NULL != pDisposition)
  683. {
  684. *pDisposition = 0;
  685. }
  686. hr = CoInitialize(NULL);
  687. if (S_OK != hr && S_FALSE != hr)
  688. {
  689. _JumpError(hr, error, "CoInitialize");
  690. }
  691. fCoInit = TRUE;
  692. DBGPRINT((
  693. DBG_SS_CERTLIBI,
  694. "vrModifyVirtualRoots(tid=%x, fCreate=%d, fNTLM=%d)\n",
  695. GetCurrentThreadId(),
  696. fCreate,
  697. fNTLM));
  698. if (!IsIISInstalled(&hr))
  699. {
  700. // IIS is not functioning or not installed
  701. _PrintError2(hr, "IsIISInstalled", hr);
  702. hr = S_OK;
  703. Disposition = VFD_NOTSUPPORTED;
  704. goto error;
  705. }
  706. // Create path for SYSTEM32 directory
  707. if (0 == GetSystemDirectory(wszSystem32Path, ARRAYSIZE(wszSystem32Path)))
  708. {
  709. hr = myHLastError();
  710. _JumpError(hr, error, "GetSystemDirectory");
  711. }
  712. // Create virtual roots
  713. for (pavr = g_avr; NULL != pavr->pwszVRootName; pavr++)
  714. {
  715. CSASSERT(ARRAYSIZE(wszVRootPathTemp) >
  716. wcslen(wszSystem32Path) + wcslen(pavr->pwszDirectory));
  717. wcscpy(wszVRootPathTemp, wszSystem32Path);
  718. wcscat(wszVRootPathTemp, pavr->pwszDirectory);
  719. if (fCreate)
  720. {
  721. if (0 == (VRE_DELETEONLY & pavr->Flags)) // if not obsolete
  722. {
  723. hr = AddNewVDir(
  724. pavr->pwszVRootName,
  725. wszVRootPathTemp,
  726. (VRE_SCRIPTMAP & pavr->Flags)? TRUE : FALSE,
  727. (fNTLM && (VRE_ALLOWNTLM & pavr->Flags))? TRUE : FALSE,
  728. (VRE_CREATEAPP & pavr->Flags)? TRUE : FALSE,
  729. &fExist);
  730. if (S_OK != hr)
  731. {
  732. Disposition = VFD_CREATEERROR;
  733. _JumpErrorStr(hr, error, "AddNewVDir", pavr->pwszVRootName);
  734. }
  735. Disposition = fExist? VFD_EXISTS : VFD_CREATED;
  736. }
  737. }
  738. else // else Delete
  739. {
  740. hr2 = RemoveVDir(pavr->pwszVRootName, &fExist);
  741. if (0 == (VRE_DELETEONLY & pavr->Flags)) // if not obsolete
  742. {
  743. if (S_OK != hr2)
  744. {
  745. if (S_OK == hr)
  746. {
  747. hr = hr2;
  748. }
  749. Disposition = VFD_DELETEERROR;
  750. _PrintError(hr2, "RemoveVDir");
  751. }
  752. else
  753. {
  754. Disposition = fExist? VFD_DELETED : VFD_NOTFOUND;
  755. }
  756. }
  757. }
  758. }
  759. error:
  760. if (NULL != pDisposition)
  761. {
  762. *pDisposition = Disposition;
  763. }
  764. if (fCoInit)
  765. {
  766. CoUninitialize();
  767. }
  768. DBGPRINT((
  769. DBG_SS_CERTLIBI,
  770. "vrModifyVirtualRoots(tid=%x, hr=%x, disp=%d)\n",
  771. GetCurrentThreadId(),
  772. hr,
  773. Disposition));
  774. return(hr);
  775. }
  776. // myAddShare: create and test new net share
  777. HRESULT
  778. myAddShare(
  779. LPCWSTR szShareName,
  780. LPCWSTR szShareDescr,
  781. LPCWSTR szSharePath,
  782. BOOL fOverwrite,
  783. OPTIONAL BOOL *pfCreated)
  784. {
  785. HRESULT hr;
  786. BOOL fCreated = FALSE;
  787. HANDLE hTestFile = INVALID_HANDLE_VALUE;
  788. LPWSTR pwszTestComputerName = NULL;
  789. LPWSTR pwszTestUNCPath = NULL;
  790. // Share local path
  791. SHARE_INFO_502 shareStruct;
  792. ZeroMemory(&shareStruct, sizeof(shareStruct));
  793. shareStruct.shi502_netname = const_cast<WCHAR *>(szShareName);
  794. shareStruct.shi502_type = STYPE_DISKTREE;
  795. shareStruct.shi502_remark = const_cast<WCHAR *>(szShareDescr);
  796. shareStruct.shi502_max_uses = MAXDWORD;
  797. shareStruct.shi502_path = const_cast<WCHAR *>(szSharePath);
  798. hr = myGetSDFromTemplate(WSZ_DEFAULT_SHARE_SECURITY,
  799. NULL,
  800. &shareStruct.shi502_security_descriptor);
  801. _JumpIfError(hr, error, "myGetSDFromTemplate");
  802. hr = NetShareAdd(
  803. NULL, // this computer
  804. 502, // SHARE_LEVEL_502 struct
  805. (BYTE *) &shareStruct,
  806. NULL);
  807. fCreated = (S_OK == hr);
  808. if (hr == (HRESULT) NERR_DuplicateShare)
  809. {
  810. SHARE_INFO_2* pstructDupShare = NULL;
  811. hr = NetShareGetInfo(
  812. NULL,
  813. const_cast<WCHAR *>(szShareName),
  814. 2,
  815. (BYTE **) &pstructDupShare);
  816. _JumpIfError(hr, error, "NetShareGetInfo");
  817. if (0 == wcscmp(pstructDupShare->shi2_path, szSharePath))
  818. {
  819. // they're the same path, so we're okay!
  820. hr = S_OK;
  821. }
  822. else if (fOverwrite)
  823. {
  824. // not the same path, but we've been instructed to bash existing
  825. // remove offending share
  826. hr = NetShareDel(
  827. NULL,
  828. const_cast<WCHAR *>(szShareName),
  829. 0);
  830. if (S_OK == hr)
  831. {
  832. // try again
  833. hr = NetShareAdd(
  834. NULL, // this computer
  835. 502, // SHARE_LEVEL_502 struct
  836. (BYTE *) &shareStruct,
  837. NULL);
  838. fCreated = (S_OK == hr);
  839. }
  840. }
  841. if (NULL != pstructDupShare)
  842. {
  843. NetApiBufferFree(pstructDupShare);
  844. }
  845. }
  846. // if share does not exist by this time, we bail
  847. _JumpIfError(hr, error, "NetShareAdd");
  848. // TEST: is writable?
  849. #define UNCPATH_TEMPLATE L"\\\\%ws\\%ws\\write.tmp"
  850. hr = myGetMachineDnsName(&pwszTestComputerName);
  851. _JumpIfError(hr, error, "myGetMachineDnsName");
  852. // get the local machine name
  853. pwszTestUNCPath = (LPWSTR)LocalAlloc(LMEM_FIXED,
  854. (UINT)(( ARRAYSIZE(UNCPATH_TEMPLATE) +
  855. wcslen(pwszTestComputerName) +
  856. wcslen(szShareName) )
  857. *sizeof(WCHAR)));
  858. if (NULL == pwszTestUNCPath)
  859. {
  860. hr = E_OUTOFMEMORY;
  861. _JumpError(hr, error, "LocalAlloc");
  862. }
  863. // create UNC path
  864. swprintf(pwszTestUNCPath, UNCPATH_TEMPLATE, pwszTestComputerName, szShareName);
  865. hTestFile = CreateFile(
  866. pwszTestUNCPath,
  867. GENERIC_WRITE,
  868. FILE_SHARE_WRITE,
  869. NULL,
  870. CREATE_ALWAYS,
  871. FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
  872. NULL);
  873. if (hTestFile == INVALID_HANDLE_VALUE)
  874. {
  875. hr = myHLastError();
  876. _JumpErrorStr(hr, error, "CreateFile (test for UNC translation)", pwszTestUNCPath);
  877. }
  878. // if we got this far, our test went well
  879. hr = S_OK;
  880. error:
  881. // if created and then something went wrong, clean up
  882. if (fCreated && (hr != S_OK))
  883. {
  884. // don't mash hr
  885. HRESULT hr2;
  886. hr2 = NetShareDel(
  887. NULL,
  888. const_cast<WCHAR *>(szShareName),
  889. 0);
  890. // ignore NetShareDel hr
  891. _PrintIfError(hr2, "NetShareDel"); // not fatal, might already be shared
  892. }
  893. if (INVALID_HANDLE_VALUE != hTestFile)
  894. CloseHandle(hTestFile);
  895. if (NULL != pwszTestComputerName)
  896. LocalFree(pwszTestComputerName);
  897. if (NULL != pwszTestUNCPath)
  898. LocalFree(pwszTestUNCPath);
  899. if(shareStruct.shi502_security_descriptor)
  900. {
  901. LocalFree(shareStruct.shi502_security_descriptor);
  902. }
  903. if(pfCreated)
  904. *pfCreated = fCreated;
  905. return hr;
  906. }
  907. HRESULT
  908. vrModifyFileShares(
  909. IN BOOL fCreate, // else Delete
  910. OPTIONAL OUT DWORD *pDisposition)
  911. {
  912. HRESULT hr;
  913. WCHAR wszSystem32Dir[MAX_PATH];
  914. WCHAR wszRemark[512];
  915. WCHAR *pwszDirectory = NULL;
  916. DWORD Disposition = 0;
  917. BOOL fCreated = FALSE;
  918. if (NULL != pDisposition)
  919. {
  920. *pDisposition = 0;
  921. }
  922. if (fCreate)
  923. {
  924. if (0 == GetSystemDirectory(wszSystem32Dir, ARRAYSIZE(wszSystem32Dir)))
  925. {
  926. hr = myHLastError();
  927. _JumpError(hr, error, "GetSystemDirectory");
  928. }
  929. hr = myBuildPathAndExt(
  930. wszSystem32Dir,
  931. wszCERTENROLLSHAREPATH,
  932. NULL,
  933. &pwszDirectory);
  934. _JumpIfError(hr, error, "myBuildPathAndExt");
  935. if (!LoadString(
  936. g_hInstance,
  937. IDS_FILESHARE_REMARK,
  938. wszRemark,
  939. ARRAYSIZE(wszRemark)))
  940. {
  941. hr = myHLastError();
  942. CSASSERT(S_OK != hr);
  943. _JumpError(hr, error, "LoadString");
  944. }
  945. hr = myAddShare(wszCERTENROLLSHARENAME,
  946. wszRemark,
  947. pwszDirectory,
  948. TRUE,
  949. &fCreated);
  950. if (S_OK == hr)
  951. {
  952. Disposition = fCreated? VFD_CREATED : VFD_EXISTS;
  953. }
  954. else if(HRESULT_FROM_WIN32(ERROR_NETWORK_UNREACHABLE) == hr)
  955. {
  956. // Could not validate the share. Can happen if net cable is disconnected.
  957. // Put a warning message and ignore the error.
  958. Disposition = VFD_VERIFYERROR;
  959. hr = S_OK;
  960. }
  961. else
  962. {
  963. Disposition = VFD_CREATEERROR;
  964. _JumpErrorStr(hr, error, "NetShareAdd", wszCERTENROLLSHARENAME);
  965. }
  966. }
  967. else
  968. {
  969. hr = NetShareDel(NULL, wszCERTENROLLSHARENAME, NULL);
  970. CSASSERT(NERR_Success == S_OK);
  971. if (S_OK == hr)
  972. {
  973. Disposition = VFD_DELETED;
  974. }
  975. else if ((HRESULT) NERR_NetNameNotFound == hr)
  976. {
  977. Disposition = VFD_NOTFOUND;
  978. hr = S_OK;
  979. }
  980. else
  981. {
  982. Disposition = VFD_DELETEERROR;
  983. _JumpErrorStr(hr, error, "NetShareDel", wszCERTENROLLSHARENAME);
  984. }
  985. }
  986. NetShareDel(NULL, L"CertSrv", NULL); // delete old share name
  987. error:
  988. if (NULL != pDisposition)
  989. {
  990. *pDisposition = Disposition;
  991. }
  992. if (NULL != pwszDirectory)
  993. {
  994. LocalFree(pwszDirectory);
  995. }
  996. return(myHError(hr));
  997. }
  998. // For now, this writes the entry "CertUtil -vroot", and is not generalized
  999. HRESULT
  1000. myWriteRunOnceEntry(
  1001. IN BOOL fAdd // Add or Remove entry?
  1002. )
  1003. {
  1004. DWORD err;
  1005. // Add certutil -vroot to runonce commands
  1006. WCHAR szRunOnceCommand[] = L"certutil -vroot";
  1007. HKEY hkeyRunOnce = NULL;
  1008. DWORD dwDisposition;
  1009. err = RegCreateKeyEx(
  1010. HKEY_LOCAL_MACHINE,
  1011. L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce", // address of subkey name
  1012. 0,
  1013. NULL,
  1014. 0,
  1015. KEY_SET_VALUE,
  1016. NULL,
  1017. &hkeyRunOnce,
  1018. &dwDisposition);
  1019. _JumpIfError(err, error, "RegCreateKeyEx");
  1020. // add or remove entry?
  1021. if (fAdd)
  1022. {
  1023. err = RegSetValueEx(
  1024. hkeyRunOnce,
  1025. L"Certificate Services",
  1026. 0,
  1027. REG_SZ,
  1028. (BYTE *) szRunOnceCommand,
  1029. sizeof(szRunOnceCommand));
  1030. _JumpIfError(err, error, "RegSetValueEx");
  1031. }
  1032. else
  1033. {
  1034. err = RegDeleteValue(hkeyRunOnce, L"Certificate Services");
  1035. _PrintIfError2(err, "RegDeleteValue", ERROR_FILE_NOT_FOUND);
  1036. if (ERROR_FILE_NOT_FOUND == err)
  1037. {
  1038. err = ERROR_SUCCESS;
  1039. }
  1040. _JumpIfError(err, error, "RegDeleteValue");
  1041. }
  1042. error:
  1043. if (hkeyRunOnce)
  1044. RegCloseKey(hkeyRunOnce);
  1045. return (myHError(err));
  1046. }
  1047. DWORD
  1048. vrWorkerThread(
  1049. OPTIONAL IN OUT VOID *pvparms)
  1050. {
  1051. HRESULT hr = S_OK;
  1052. HRESULT hr2;
  1053. VRFSPARMS *pparms = (VRFSPARMS *) pvparms;
  1054. DWORD Disposition;
  1055. BOOL fFailed = FALSE;
  1056. CSASSERT(NULL != pparms);
  1057. if ((VFF_CREATEFILESHARES | VFF_DELETEFILESHARES) & pparms->Flags)
  1058. {
  1059. hr = vrModifyFileShares(
  1060. (VFF_CREATEFILESHARES & pparms->Flags)? TRUE : FALSE,
  1061. &Disposition);
  1062. _PrintIfError(hr, "vrModifyFileShares");
  1063. if (NULL != pparms->pShareDisposition)
  1064. {
  1065. *pparms->pShareDisposition = Disposition;
  1066. }
  1067. if (VFD_CREATEERROR == Disposition || VFD_DELETEERROR == Disposition)
  1068. {
  1069. fFailed = TRUE;
  1070. }
  1071. }
  1072. if ((VFF_CREATEVROOTS | VFF_DELETEVROOTS) & pparms->Flags)
  1073. {
  1074. BOOL fNTLM = FALSE; // set fNTLM iff Enterprise CA
  1075. if (IsEnterpriseCA(pparms->CAType))
  1076. {
  1077. fNTLM = TRUE;
  1078. }
  1079. hr2 = vrModifyVirtualRoots(
  1080. (VFF_CREATEVROOTS & pparms->Flags)? TRUE : FALSE,
  1081. fNTLM,
  1082. &Disposition);
  1083. _PrintIfError2(hr2, "vrModifyVirtualRoots", S_FALSE);
  1084. if (S_OK == hr)
  1085. {
  1086. hr = hr2;
  1087. }
  1088. if (NULL != pparms->pVRootDisposition)
  1089. {
  1090. *pparms->pVRootDisposition = Disposition;
  1091. }
  1092. if (VFD_CREATEERROR == Disposition || VFD_DELETEERROR == Disposition)
  1093. {
  1094. fFailed = TRUE;
  1095. }
  1096. if (S_OK == hr)
  1097. {
  1098. if (VFF_CREATEVROOTS & pparms->Flags)
  1099. {
  1100. DWORD ASPDisposition;
  1101. BOOL fEnabledASP;
  1102. hr2 = EnableASPInIIS(&fEnabledASP);
  1103. _PrintIfError(hr2, "EnableASPInIIS");
  1104. ASPDisposition = VFD_NOACTION;
  1105. hr2 = SetCertSrvASPDependency();
  1106. _PrintIfError(hr2, "SetCertSrvASPDependency");
  1107. if (S_OK != hr2)
  1108. {
  1109. ASPDisposition = VFD_CREATEERROR;
  1110. }
  1111. // enable ASP processing in IIS
  1112. if (VFF_ENABLEASP & pparms->Flags)
  1113. {
  1114. hr2 = EnableASPInIIS_New(&fEnabledASP);
  1115. _PrintIfError(hr2, "EnableASPInIIS_New");
  1116. if (S_OK == hr2)
  1117. {
  1118. ASPDisposition = fEnabledASP? VFD_CREATED : VFD_EXISTS;
  1119. }
  1120. }
  1121. if (NULL != pparms->pVRootDisposition)
  1122. {
  1123. *pparms->pVRootDisposition |= (ASPDisposition << 16);
  1124. }
  1125. if (VFD_CREATEERROR == ASPDisposition)
  1126. {
  1127. fFailed = TRUE;
  1128. }
  1129. }
  1130. }
  1131. }
  1132. if ((S_OK == hr && !fFailed) || ((VFF_DELETEVROOTS) & pparms->Flags)) // on success or removal
  1133. {
  1134. // remove "attempt vroot" flag so we don't try again
  1135. if (VFF_CLEARREGFLAGIFOK & pparms->Flags)
  1136. {
  1137. DBGPRINT((DBG_SS_CERTLIBI, "clearing registry\n"));
  1138. hr = SetSetupStatus(NULL, SETUP_ATTEMPT_VROOT_CREATE, FALSE);
  1139. _JumpIfError(hr, error, "SetSetupStatus");
  1140. }
  1141. hr = myWriteRunOnceEntry(FALSE); // worker thread deletes on success
  1142. _JumpIfError(hr, error, "myWriteRunOnceEntry");
  1143. }
  1144. error:
  1145. LocalFree(pparms);
  1146. DBGPRINT((DBG_SS_CERTLIBI, "vrWorkerThread returns %x\n", hr));
  1147. return(myHError(hr));
  1148. }
  1149. //+------------------------------------------------------------------------
  1150. // Function: myModifyVirtualRootsAndFileShares
  1151. //
  1152. // Synopsis: Creates the virtual roots needed for cert server web pages.
  1153. //
  1154. // Effects: Creates IIS Virtual Roots
  1155. //
  1156. // Arguments: None.
  1157. //-------------------------------------------------------------------------
  1158. HRESULT
  1159. myModifyVirtualRootsAndFileShares(
  1160. IN DWORD Flags, // VFF_*: Create/Delete VRoots and/or Shares
  1161. IN ENUM_CATYPES CAType,
  1162. IN BOOL fAsynchronous,
  1163. IN DWORD csecTimeOut,
  1164. OPTIONAL OUT DWORD *pVRootDisposition, // VFD_*
  1165. OPTIONAL OUT DWORD *pShareDisposition) // VFD_*
  1166. {
  1167. HRESULT hr;
  1168. HANDLE hThread = NULL;
  1169. HMODULE hMod = NULL;
  1170. DWORD ThreadId;
  1171. DWORD dw;
  1172. BOOL fEnable = TRUE;
  1173. DWORD SetupStatus;
  1174. VRFSPARMS *pparms = NULL;
  1175. if (NULL != pVRootDisposition)
  1176. {
  1177. *pVRootDisposition = 0;
  1178. }
  1179. if (NULL != pShareDisposition)
  1180. {
  1181. *pShareDisposition = 0;
  1182. }
  1183. dw = (VFF_DELETEVROOTS | VFF_DELETEFILESHARES) & Flags;
  1184. if (0 != dw && dw != Flags)
  1185. {
  1186. hr = E_INVALIDARG;
  1187. _JumpError(hr, error, "Mixed VFF_DELETE* and create flags");
  1188. }
  1189. if (((VFF_CHECKREGFLAGFIRST | VFF_CLEARREGFLAGFIRST) & Flags) &&
  1190. (VFF_SETREGFLAGFIRST & Flags))
  1191. {
  1192. hr = E_INVALIDARG;
  1193. _JumpError(hr, error, "Mixed VFF_SETREGFLAGFIRST & VFF_*REGFLAGFIRST");
  1194. }
  1195. hr = GetSetupStatus(NULL, &SetupStatus);
  1196. if (S_OK != hr)
  1197. {
  1198. _PrintError(hr, "GetSetupStatus(ignored)");
  1199. hr = S_OK;
  1200. SetupStatus = 0;
  1201. }
  1202. if (VFF_CHECKREGFLAGFIRST & Flags)
  1203. {
  1204. if (0 == (SETUP_ATTEMPT_VROOT_CREATE & SetupStatus))
  1205. {
  1206. fEnable = FALSE;
  1207. }
  1208. }
  1209. if (VFF_CLEARREGFLAGFIRST & Flags)
  1210. {
  1211. // remove "attempt vroot" flag so we don't try again
  1212. if (SETUP_ATTEMPT_VROOT_CREATE & SetupStatus)
  1213. {
  1214. hr = SetSetupStatus(NULL, SETUP_ATTEMPT_VROOT_CREATE, FALSE);
  1215. _JumpIfError(hr, error, "SetSetupStatus");
  1216. }
  1217. }
  1218. if (VFF_SETREGFLAGFIRST & Flags)
  1219. {
  1220. // set "attempt vroot" flag so we'll try again if necessary
  1221. if (0 == (SETUP_ATTEMPT_VROOT_CREATE & SetupStatus))
  1222. {
  1223. hr = SetSetupStatus(NULL, SETUP_ATTEMPT_VROOT_CREATE, TRUE);
  1224. _JumpIfError(hr, error, "SetSetupStatus");
  1225. }
  1226. }
  1227. hr = S_OK;
  1228. if (fEnable)
  1229. {
  1230. // only set RunOnce on a real attempt (worker thread clears this)
  1231. if (VFF_SETRUNONCEIFERROR & Flags)
  1232. {
  1233. hr = myWriteRunOnceEntry(TRUE);
  1234. _JumpIfError(hr, error, "myWriteRunOnceEntry");
  1235. }
  1236. pparms = (VRFSPARMS *) LocalAlloc(
  1237. LMEM_FIXED | LMEM_ZEROINIT,
  1238. sizeof(*pparms));
  1239. if (NULL == pparms)
  1240. {
  1241. hr = E_OUTOFMEMORY;
  1242. _JumpError(hr, error, "LocalAlloc");
  1243. }
  1244. pparms->Flags = Flags;
  1245. pparms->CAType = CAType;
  1246. pparms->csecTimeOut = csecTimeOut;
  1247. pparms->fAsynchronous = fAsynchronous;
  1248. if (!fAsynchronous)
  1249. {
  1250. pparms->pVRootDisposition = pVRootDisposition;
  1251. pparms->pShareDisposition = pShareDisposition;
  1252. }
  1253. else
  1254. {
  1255. hMod = LoadLibrary(g_wszCertCliDotDll);
  1256. if (NULL == hMod)
  1257. {
  1258. hr = myHLastError();
  1259. _JumpError(hr, error, "LoadLibrary");
  1260. }
  1261. }
  1262. hThread = CreateThread(
  1263. NULL, // lpThreadAttributes (Security Attr)
  1264. 0, // dwStackSize
  1265. vrWorkerThread,
  1266. pparms, // lpParameter
  1267. 0, // dwCreationFlags
  1268. &ThreadId);
  1269. if (NULL == hThread)
  1270. {
  1271. hr = myHLastError();
  1272. _JumpError(hr, error, "CreateThread");
  1273. }
  1274. pparms = NULL; // freed by the new thread
  1275. DBGPRINT((DBG_SS_CERTLIBI, "VRoot Worker Thread = %x\n", ThreadId));
  1276. // asynch? proper thread creation is all we do
  1277. if (fAsynchronous)
  1278. {
  1279. hr = S_OK;
  1280. goto error;
  1281. }
  1282. // Wait for the worker thread to exit
  1283. hr = WaitForSingleObject(
  1284. hThread,
  1285. (INFINITE == csecTimeOut) ? INFINITE : csecTimeOut * 1000 );
  1286. DBGPRINT((DBG_SS_CERTLIBI, "Wait for worker thread returns %x\n", hr));
  1287. if ((HRESULT) WAIT_OBJECT_0 == hr)
  1288. {
  1289. // worker thread returned.
  1290. if (!GetExitCodeThread(hThread, (DWORD *) &hr))
  1291. {
  1292. hr = myHLastError();
  1293. _JumpError(hr, error, "GetExitCodeThread");
  1294. }
  1295. DBGPRINT((DBG_SS_CERTLIBI, "worker thread exit: %x\n", hr));
  1296. if (S_OK != hr)
  1297. {
  1298. // If not synchronous, leave DLL loaded...
  1299. hMod = NULL;
  1300. _JumpError(hr, error, "vrWorkerThread");
  1301. }
  1302. }
  1303. else
  1304. {
  1305. // timeout: abandoning thread, leave the dll loaded
  1306. hMod = NULL;
  1307. _PrintError(hr, "WaitForSingleObject (ignored)");
  1308. // whack error
  1309. hr = S_OK;
  1310. }
  1311. }
  1312. error:
  1313. if (NULL != pparms)
  1314. {
  1315. LocalFree(pparms);
  1316. }
  1317. if (NULL != hThread)
  1318. {
  1319. CloseHandle(hThread);
  1320. }
  1321. if (NULL != hMod)
  1322. {
  1323. FreeLibrary(hMod);
  1324. }
  1325. DBGPRINT((DBG_SS_CERTLIBI, "myModifyVirtualRootsAndFileShares returns %x\n", hr));
  1326. return(myHError(hr));
  1327. }
  1328. //-------------------------------------------------------------------------
  1329. //
  1330. // ASP/IIS related functions
  1331. //
  1332. //-------------------------------------------------------------------------
  1333. #define MD_ISAPI_RESTRICTION_LIST_OBSOLETE (IIS_MD_HTTP_BASE+163)
  1334. METADATA_RECORD ASPRestrictionsMDData =
  1335. {
  1336. MD_ISAPI_RESTRICTION_LIST_OBSOLETE,
  1337. 0,
  1338. IIS_MD_UT_SERVER,
  1339. MULTISZ_METADATA,
  1340. 0,
  1341. NULL,
  1342. 0
  1343. };
  1344. METADATA_RECORD ApplicationDependenciesMDData =
  1345. {
  1346. MD_APP_DEPENDENCIES,
  1347. 0,
  1348. IIS_MD_UT_SERVER,
  1349. MULTISZ_METADATA,
  1350. 0,
  1351. NULL,
  1352. 0
  1353. };
  1354. METADATA_RECORD WebSvcExtRestrictionsMDData =
  1355. {
  1356. MD_WEB_SVC_EXT_RESTRICTION_LIST,
  1357. 0,
  1358. IIS_MD_UT_SERVER,
  1359. MULTISZ_METADATA,
  1360. 0,
  1361. NULL,
  1362. 0
  1363. };
  1364. const WCHAR g_wchExtensionOff = L'0';
  1365. const WCHAR g_wchExtensionOn = L'1';
  1366. LPCWSTR g_pcwszAspDll = L"asp.dll";
  1367. //+------------------------------------------------------------------------
  1368. // Builds the full path to asp.dll
  1369. //-------------------------------------------------------------------------
  1370. HRESULT BuildASPDllFullPath(LPWSTR &rpwszAspPath)
  1371. {
  1372. HRESULT hr;
  1373. WCHAR wszAsp[MAX_PATH];
  1374. LPCWSTR pcwszAsp = L"\\inetsrv\\asp.dll";
  1375. if (0 == GetSystemDirectory(wszAsp, MAX_PATH))
  1376. {
  1377. hr = myHLastError();
  1378. _JumpError(hr, error, "GetSystemDirectory");
  1379. }
  1380. rpwszAspPath = (LPWSTR)LocalAlloc(LMEM_FIXED,
  1381. sizeof(WCHAR)*(wcslen(wszAsp)+wcslen(pcwszAsp)+1));
  1382. _JumpIfAllocFailed(rpwszAspPath, error);
  1383. wcscpy(rpwszAspPath, wszAsp);
  1384. wcscat(rpwszAspPath, pcwszAsp);
  1385. hr = S_OK;
  1386. error:
  1387. return hr;
  1388. }
  1389. //+------------------------------------------------------------------------
  1390. // Saves the list of ASP restrictions to IIS metabase. IIS restriction
  1391. // list it's a multisz that looks like this:
  1392. //
  1393. // "1","DLL1","DLL2"...
  1394. // or
  1395. // "0","DLL1","DLL2"...
  1396. //
  1397. // When list starts with "1", the meaning is "enable all ASP DLLs
  1398. // excluding the list that follows". When it begins with "0", it means
  1399. // "disable all except the list".
  1400. //-------------------------------------------------------------------------
  1401. HRESULT SetASPRestrictions(CMultiSz& ASPRestrictionList)
  1402. {
  1403. HRESULT hr;
  1404. IMSAdminBase *pIMeta = NULL;
  1405. METADATA_HANDLE hMetaRoot = NULL;
  1406. void * pBuffer = NULL;
  1407. DWORD cBuffer;
  1408. bool fCoInit = false;
  1409. hr = CoInitialize(NULL);
  1410. if (S_OK != hr && S_FALSE != hr)
  1411. {
  1412. _JumpError(hr, error, "CoInitialize");
  1413. }
  1414. fCoInit = true;
  1415. hr = ASPRestrictionList.Marshal(pBuffer, cBuffer);
  1416. _JumpIfError(hr, error, "CMultiSz::Marshal");
  1417. ASPRestrictionsMDData.pbMDData = (unsigned char *)pBuffer;
  1418. ASPRestrictionsMDData.dwMDDataLen = cBuffer;
  1419. hr = CoCreateInstance(
  1420. CLSID_MSAdminBase,
  1421. NULL,
  1422. CLSCTX_ALL,
  1423. IID_IMSAdminBase,
  1424. (void **) &pIMeta);
  1425. _JumpIfError(hr, error, "CoCreateInstance");
  1426. hr = pIMeta->OpenKey(
  1427. METADATA_MASTER_ROOT_HANDLE,
  1428. g_wszW3SVC,
  1429. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  1430. 1000,
  1431. &hMetaRoot);
  1432. _JumpIfErrorStr(hr, error, "OpenKey", g_wszW3SVC);
  1433. hr = pIMeta->SetData(hMetaRoot, L"", &ASPRestrictionsMDData);
  1434. _JumpIfError(hr, error, "SetData");
  1435. hr = pIMeta->CloseKey(hMetaRoot);
  1436. _JumpIfError(hr, error, "CloseKey");
  1437. hMetaRoot = NULL;
  1438. hr = pIMeta->SaveData();
  1439. _JumpIfError(hr, error, "SaveData");
  1440. error:
  1441. LOCAL_FREE(pBuffer);
  1442. ASPRestrictionsMDData.pbMDData = NULL;
  1443. ASPRestrictionsMDData.dwMDDataLen = 0;
  1444. if (NULL != hMetaRoot)
  1445. {
  1446. pIMeta->CloseKey(hMetaRoot);
  1447. }
  1448. if(pIMeta)
  1449. {
  1450. pIMeta->Release();
  1451. }
  1452. if (fCoInit)
  1453. {
  1454. CoUninitialize();
  1455. }
  1456. return hr;
  1457. }
  1458. //+------------------------------------------------------------------------
  1459. // Loads the list of ASP restrictions from IIS metabase.
  1460. //-------------------------------------------------------------------------
  1461. HRESULT GetASPRestrictions(CMultiSz& ASPRestrictionList)
  1462. {
  1463. HRESULT hr;
  1464. IMSAdminBase *pIMeta = NULL;
  1465. METADATA_HANDLE hMetaRoot = NULL;
  1466. DWORD dwSize;
  1467. bool fCoInit = false;
  1468. hr = CoInitialize(NULL);
  1469. if (S_OK != hr && S_FALSE != hr)
  1470. {
  1471. _JumpError(hr, error, "CoInitialize");
  1472. }
  1473. fCoInit = true;
  1474. hr = CoCreateInstance(
  1475. CLSID_MSAdminBase,
  1476. NULL,
  1477. CLSCTX_ALL,
  1478. IID_IMSAdminBase,
  1479. (void **) &pIMeta);
  1480. _JumpIfError(hr, error, "CoCreateInstance");
  1481. hr = pIMeta->OpenKey(
  1482. METADATA_MASTER_ROOT_HANDLE,
  1483. g_wszW3SVC,
  1484. METADATA_PERMISSION_READ,
  1485. 1000,
  1486. &hMetaRoot);
  1487. _JumpIfErrorStr(hr, error, "OpenKey", g_wszW3SVC);
  1488. hr = pIMeta->GetData(hMetaRoot, L"", &ASPRestrictionsMDData, &dwSize);
  1489. if(MD_ERROR_DATA_NOT_FOUND==hr)
  1490. {
  1491. // value not set means ASP not enabled, return empty list
  1492. hr = S_OK;
  1493. }
  1494. else
  1495. {
  1496. if(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  1497. {
  1498. _JumpErrorStr(hr, error, "GetData", g_wszW3SVC);
  1499. }
  1500. hr = S_OK;
  1501. ASPRestrictionsMDData.pbMDData = (unsigned char*) LocalAlloc(LMEM_FIXED, dwSize);
  1502. _JumpIfAllocFailed(ASPRestrictionsMDData.pbMDData, error);
  1503. ASPRestrictionsMDData.dwMDDataLen = dwSize;
  1504. hr = pIMeta->GetData(hMetaRoot, L"", &ASPRestrictionsMDData, &dwSize);
  1505. _JumpIfErrorStr(hr, error, "OpenKey", g_wszW3SVC);
  1506. hr = ASPRestrictionList.Unmarshal(ASPRestrictionsMDData.pbMDData);
  1507. _JumpIfError(hr, error, "Unmarshal");
  1508. }
  1509. error:
  1510. LOCAL_FREE(ASPRestrictionsMDData.pbMDData);
  1511. ASPRestrictionsMDData.pbMDData = NULL;
  1512. ASPRestrictionsMDData.dwMDDataLen = 0;
  1513. if (NULL != hMetaRoot)
  1514. {
  1515. pIMeta->CloseKey(hMetaRoot);
  1516. }
  1517. if(pIMeta)
  1518. {
  1519. pIMeta->Release();
  1520. }
  1521. if (fCoInit)
  1522. {
  1523. CoUninitialize();
  1524. }
  1525. return hr;
  1526. }
  1527. //+------------------------------------------------------------------------
  1528. //
  1529. // Verify if this is MSCEP setup specific
  1530. //
  1531. //
  1532. //+------------------------------------------------------------------------
  1533. HRESULT SetupMSCEPForIIS(LPCWSTR pcwszExtension);
  1534. BOOL IsMSCEPSetup(LPCWSTR pwsz, LPCWSTR pwszDLL)
  1535. {
  1536. BOOL fResult=FALSE;
  1537. LPWSTR pwchar=NULL;
  1538. if((NULL == pwsz) || (NULL == pwszDLL))
  1539. goto error;
  1540. pwchar=wcsrchr(pwsz, L'\\');
  1541. if(NULL == pwchar)
  1542. goto error;
  1543. pwchar++;
  1544. if(0 != _wcsicmp(pwchar, pwszDLL))
  1545. goto error;
  1546. fResult=TRUE;
  1547. error:
  1548. return fResult;
  1549. }
  1550. //+------------------------------------------------------------------------
  1551. // Tests if this ISAPI extension is enabled in IIS.
  1552. // If IIS restriction starts with a "1":
  1553. // "1", "DLL1", "DLL2" ...
  1554. // it means run all but specified DLLs; if we find the extension
  1555. // in the list then it's disabled
  1556. //
  1557. // If IIS restriction starts with a "0":
  1558. // "0", "DLL1", "DLL2" ...
  1559. // the meaning is disable all but specified DLLs; if we find
  1560. // the extension then it's enabled
  1561. //-------------------------------------------------------------------------
  1562. HRESULT IsISAPIExtensionEnabled(
  1563. LPCWSTR pcwszExtension,
  1564. bool& rfEnabled)
  1565. {
  1566. HRESULT hr;
  1567. CMultiSz ASPRestrictionList;
  1568. CMultiSzEnum ASPRestrictionListEnum;
  1569. rfEnabled = false;
  1570. //special case for mscep.dll. Always return FALSE to
  1571. //proceed with the installation
  1572. if(IsMSCEPSetup(pcwszExtension, g_wszMSCEP))
  1573. {
  1574. rfEnabled=FALSE;
  1575. return S_OK;
  1576. }
  1577. hr = GetASPRestrictions(ASPRestrictionList);
  1578. _JumpIfError(hr, error, "GetASPRestrictionList");
  1579. if(!ASPRestrictionList.IsEmpty())
  1580. {
  1581. ASPRestrictionListEnum.Set(ASPRestrictionList);
  1582. const CString *pStr = ASPRestrictionListEnum.Next();
  1583. bool fRunAllExceptTheseDlls = false;
  1584. if(0 == wcscmp(*pStr, L"1"))
  1585. {
  1586. fRunAllExceptTheseDlls = true;
  1587. }
  1588. for(pStr = ASPRestrictionListEnum.Next();
  1589. pStr;
  1590. pStr = ASPRestrictionListEnum.Next())
  1591. {
  1592. if(0 == _wcsicmp(pcwszExtension, *pStr))
  1593. break;
  1594. }
  1595. // XOR: Enable if "1" is found but asp.dll not present or "0" (!"1")
  1596. // is found but asp.dll present
  1597. rfEnabled = fRunAllExceptTheseDlls ^ (NULL != pStr);
  1598. }
  1599. hr = S_OK;
  1600. error:
  1601. return hr;
  1602. }
  1603. //+------------------------------------------------------------------------
  1604. // Tests if ASP processing is enabled in IIS.
  1605. //-------------------------------------------------------------------------
  1606. HRESULT IsASPEnabledInIIS(
  1607. bool& rfEnabled)
  1608. {
  1609. HRESULT hr;
  1610. LPWSTR pwszAsp = NULL;
  1611. hr = BuildASPDllFullPath(pwszAsp);
  1612. _JumpIfError(hr, error, "GetASPDllFullPath");
  1613. hr = IsISAPIExtensionEnabled(
  1614. pwszAsp,
  1615. rfEnabled);
  1616. _JumpIfErrorStr(hr, error, "GetASPDllFullPath", pwszAsp);
  1617. error:
  1618. LOCAL_FREE(pwszAsp);
  1619. return hr;
  1620. }
  1621. //+------------------------------------------------------------------------
  1622. // Enables ISAPI extension in IIS.
  1623. //
  1624. // - if list is empty/not found, set it to "0","extension", ie only enable
  1625. // this extension
  1626. // - if list starts with "1", remove extension if found
  1627. // - if list starts with "0", add extension if not already present
  1628. //-------------------------------------------------------------------------
  1629. #pragma warning(push) // BUGBUG: nonstandard extension used : 'argument' : conversion from 'CString' to 'C &'
  1630. #pragma warning(disable: 4239) // BUGBUG: nonstandard extension used : 'argument' : conversion from 'CString' to 'C &'
  1631. HRESULT
  1632. EnableISAPIExtension(
  1633. IN LPCWSTR pcwszExtension,
  1634. OUT BOOL *pfEnabledASP)
  1635. {
  1636. HRESULT hr;
  1637. CMultiSz ASPRestrictionList;
  1638. CMultiSzEnum ASPRestrictionListEnum;
  1639. CString *pStr;
  1640. DWORD dwIndex;
  1641. bool fUpdateIt = false;
  1642. *pfEnabledASP = FALSE;
  1643. //special case for mscep.dll.
  1644. if(IsMSCEPSetup(pcwszExtension, g_wszMSCEP))
  1645. {
  1646. hr=SetupMSCEPForIIS(pcwszExtension);
  1647. _JumpIfError(hr, error, "SetupMSCEPForIIS");
  1648. }
  1649. hr = GetASPRestrictions(ASPRestrictionList);
  1650. _JumpIfError(hr, error, "GetASPRestrictions");
  1651. ASPRestrictionListEnum.Set(ASPRestrictionList);
  1652. pStr = ASPRestrictionListEnum.Next();
  1653. if(!pStr)
  1654. {
  1655. // list is empty, add "0"
  1656. pStr = new CString(L"0");
  1657. if(!pStr || pStr->IsEmpty())
  1658. {
  1659. hr = E_OUTOFMEMORY;
  1660. _JumpError(hr, error, "new");
  1661. }
  1662. ASPRestrictionList.AddTail(pStr);
  1663. }
  1664. dwIndex = ASPRestrictionList.FindIndex(CString(pcwszExtension));
  1665. if(0 == wcscmp(*pStr, L"0"))
  1666. {
  1667. // List means "disable all but the following DLLs".
  1668. // To enable it add ASP dll if not already there.
  1669. if(DWORD_MAX == dwIndex)
  1670. {
  1671. CString * pAsp = new CString(pcwszExtension);
  1672. if(!pAsp || pAsp->IsEmpty())
  1673. {
  1674. hr = E_OUTOFMEMORY;
  1675. _JumpError(hr, error, "new");
  1676. }
  1677. ASPRestrictionList.AddTail(pAsp);
  1678. fUpdateIt = true;
  1679. }
  1680. }
  1681. else
  1682. {
  1683. // List means "enable all but the following DLLs", to enable it
  1684. // remove extension if found
  1685. dwIndex = ASPRestrictionList.FindIndex(CString(pcwszExtension));
  1686. if(DWORD_MAX != dwIndex)
  1687. {
  1688. ASPRestrictionList.RemoveAt(dwIndex);
  1689. fUpdateIt = true;
  1690. }
  1691. }
  1692. if (fUpdateIt)
  1693. {
  1694. hr = SetASPRestrictions(ASPRestrictionList);
  1695. _JumpIfError(hr, error, "SetASPRestrictions");
  1696. *pfEnabledASP = TRUE;
  1697. }
  1698. error:
  1699. return S_OK;
  1700. }
  1701. #pragma warning(pop) // BUGBUG: nonstandard extension used : 'argument' : conversion from 'CString' to 'C &'
  1702. //+------------------------------------------------------------------------
  1703. // Enables ASP processing in IIS.
  1704. //-------------------------------------------------------------------------
  1705. HRESULT
  1706. EnableASPInIIS(
  1707. OUT BOOL *pfEnabledASP)
  1708. {
  1709. HRESULT hr;
  1710. LPWSTR pwszAsp = NULL;
  1711. *pfEnabledASP = FALSE;
  1712. hr = BuildASPDllFullPath(pwszAsp);
  1713. _JumpIfError(hr, error, "GetASPDllFullPath");
  1714. hr = EnableISAPIExtension(pwszAsp, pfEnabledASP);
  1715. _JumpIfErrorStr(hr, error, "GetASPDllFullPath", pwszAsp);
  1716. error:
  1717. LOCAL_FREE(pwszAsp);
  1718. return S_OK;
  1719. }
  1720. //+------------------------------------------------------------------------
  1721. // New APIs after IIS redesigning of enabling/disabling extensions
  1722. //-------------------------------------------------------------------------
  1723. HRESULT
  1724. SetMultiSzIISMetadata(
  1725. METADATA_RECORD& MDRecord,
  1726. CMultiSz& MultiSz);
  1727. HRESULT
  1728. GetMultiSzIISMetadata(
  1729. METADATA_RECORD& MDRecord,
  1730. CMultiSz& MultiSz);
  1731. //+------------------------------------------------------------------------
  1732. // Searches for the websvc specified extension and turns it on if needed
  1733. //-------------------------------------------------------------------------
  1734. HRESULT
  1735. EnableWebSvcExtension(
  1736. IN LPCWSTR pcwszExtDll, // e.g. "asp.dll"
  1737. OUT BOOL *pfEnabled)
  1738. {
  1739. HRESULT hr = S_OK;
  1740. CMultiSz WebSvcExtRestrictions;
  1741. CMultiSzEnum WebSvcExtRestrictionsEnum;
  1742. CString *pstr;
  1743. CString strTmp;
  1744. CString strExtDll = pcwszExtDll;
  1745. *pfEnabled = FALSE;
  1746. _wcslwr(strExtDll.GetBuffer()); // we need to find case insensitive, we'll
  1747. // also wcslwr the strings from list
  1748. hr = GetMultiSzIISMetadata(WebSvcExtRestrictionsMDData, WebSvcExtRestrictions);
  1749. _JumpIfError(hr, error, "GetMultiSzIISMetadata");
  1750. WebSvcExtRestrictionsEnum.Set(WebSvcExtRestrictions);
  1751. for(pstr = WebSvcExtRestrictionsEnum.Next();
  1752. pstr;
  1753. pstr = WebSvcExtRestrictionsEnum.Next())
  1754. {
  1755. // create a copy so we don't modify the original string
  1756. strTmp = *pstr;
  1757. _wcslwr(strTmp.GetBuffer());
  1758. if(NULL != wcsstr(strTmp, strExtDll))
  1759. {
  1760. if(g_wchExtensionOff == *(pstr->GetBuffer()))
  1761. {
  1762. *(pstr->GetBuffer()) = g_wchExtensionOn;
  1763. *pfEnabled = TRUE;
  1764. }
  1765. break;
  1766. }
  1767. }
  1768. if(!pstr)
  1769. {
  1770. hr = ERROR_NOT_FOUND;
  1771. _JumpErrorStr(hr, error, "extension was not found in WebSvcExtRestrictions", pcwszExtDll);
  1772. }
  1773. if(TRUE == *pfEnabled)
  1774. {
  1775. hr = SetMultiSzIISMetadata(WebSvcExtRestrictionsMDData, WebSvcExtRestrictions);
  1776. _JumpIfError(hr, error, "GetISAPIRestrictions");
  1777. }
  1778. error:
  1779. return hr;
  1780. }
  1781. //+------------------------------------------------------------------------
  1782. // Enable ASP processing in IIS
  1783. //-------------------------------------------------------------------------
  1784. HRESULT
  1785. EnableASPInIIS_New(
  1786. OUT BOOL *pfEnabledASP)
  1787. {
  1788. HRESULT hr;
  1789. LPWSTR pwszAsp = NULL;
  1790. *pfEnabledASP = FALSE;
  1791. hr = EnableWebSvcExtension(g_pcwszAspDll, pfEnabledASP);
  1792. _JumpIfErrorStr(hr, error, "GetASPDllFullPath", pwszAsp);
  1793. error:
  1794. LOCAL_FREE(pwszAsp);
  1795. return S_OK;
  1796. }
  1797. //+------------------------------------------------------------------------
  1798. // Stores a multisz property to IIS metabase root
  1799. //-------------------------------------------------------------------------
  1800. HRESULT
  1801. SetMultiSzIISMetadata(
  1802. METADATA_RECORD& MDRecord,
  1803. CMultiSz& MultiSz)
  1804. {
  1805. HRESULT hr;
  1806. IMSAdminBase *pIMeta = NULL;
  1807. METADATA_HANDLE hMetaRoot = NULL;
  1808. void * pBuffer = NULL;
  1809. DWORD cBuffer;
  1810. bool fCoInit = false;
  1811. CSASSERT(MULTISZ_METADATA == MDRecord.dwMDDataType);
  1812. hr = CoInitialize(NULL);
  1813. if (S_OK != hr && S_FALSE != hr)
  1814. {
  1815. _JumpError(hr, error, "CoInitialize");
  1816. }
  1817. fCoInit = true;
  1818. hr = MultiSz.Marshal(pBuffer, cBuffer);
  1819. _JumpIfError(hr, error, "CMultiSz::Marshal");
  1820. CSASSERT(NULL == MDRecord.pbMDData);
  1821. MDRecord.pbMDData = (unsigned char *)pBuffer;
  1822. MDRecord.dwMDDataLen = cBuffer;
  1823. hr = CoCreateInstance(
  1824. CLSID_MSAdminBase,
  1825. NULL,
  1826. CLSCTX_ALL,
  1827. IID_IMSAdminBase,
  1828. (void **) &pIMeta);
  1829. _JumpIfError(hr, error, "CoCreateInstance");
  1830. hr = pIMeta->OpenKey(
  1831. METADATA_MASTER_ROOT_HANDLE,
  1832. g_wszW3SVC,
  1833. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  1834. 1000,
  1835. &hMetaRoot);
  1836. _JumpIfErrorStr(hr, error, "OpenKey", g_wszW3SVC);
  1837. hr = pIMeta->SetData(hMetaRoot, L"", &MDRecord);
  1838. _JumpIfError(hr, error, "SetData");
  1839. hr = pIMeta->CloseKey(hMetaRoot);
  1840. _JumpIfError(hr, error, "CloseKey");
  1841. hMetaRoot = NULL;
  1842. hr = pIMeta->SaveData();
  1843. _JumpIfError(hr, error, "SaveData");
  1844. error:
  1845. LOCAL_FREE(pBuffer);
  1846. MDRecord.pbMDData = NULL;
  1847. MDRecord.dwMDDataLen = 0;
  1848. if (NULL != hMetaRoot)
  1849. {
  1850. pIMeta->CloseKey(hMetaRoot);
  1851. }
  1852. if(pIMeta)
  1853. {
  1854. pIMeta->Release();
  1855. }
  1856. if (fCoInit)
  1857. {
  1858. CoUninitialize();
  1859. }
  1860. return hr;
  1861. }
  1862. //+------------------------------------------------------------------------
  1863. // Retrieves a multisz property IIS metabase root
  1864. //-------------------------------------------------------------------------
  1865. HRESULT
  1866. GetMultiSzIISMetadata(
  1867. METADATA_RECORD& MDRecord,
  1868. CMultiSz& MultiSz)
  1869. {
  1870. HRESULT hr;
  1871. IMSAdminBase *pIMeta = NULL;
  1872. METADATA_HANDLE hMetaRoot = NULL;
  1873. DWORD dwSize = 0;
  1874. bool fCoInit = false;
  1875. CSASSERT(MULTISZ_METADATA == MDRecord.dwMDDataType);
  1876. hr = CoInitialize(NULL);
  1877. if (S_OK != hr && S_FALSE != hr)
  1878. {
  1879. _JumpError(hr, error, "CoInitialize");
  1880. }
  1881. fCoInit = true;
  1882. hr = CoCreateInstance(
  1883. CLSID_MSAdminBase,
  1884. NULL,
  1885. CLSCTX_ALL,
  1886. IID_IMSAdminBase,
  1887. (void **) &pIMeta);
  1888. _JumpIfError(hr, error, "CoCreateInstance");
  1889. hr = pIMeta->OpenKey(
  1890. METADATA_MASTER_ROOT_HANDLE,
  1891. g_wszW3SVC,
  1892. METADATA_PERMISSION_READ,
  1893. 1000,
  1894. &hMetaRoot);
  1895. _JumpIfErrorStr(hr, error, "OpenKey", g_wszW3SVC);
  1896. CSASSERT(NULL == MDRecord.pbMDData);
  1897. CSASSERT(0 == MDRecord.dwMDDataLen);
  1898. hr = pIMeta->GetData(hMetaRoot, L"", &MDRecord, &dwSize);
  1899. if(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  1900. {
  1901. _JumpErrorStr(hr, error, "GetData", g_wszW3SVC);
  1902. }
  1903. hr = S_OK;
  1904. MDRecord.pbMDData = (unsigned char*) LocalAlloc(LMEM_FIXED, dwSize);
  1905. _JumpIfAllocFailed(MDRecord.pbMDData, error);
  1906. MDRecord.dwMDDataLen = dwSize;
  1907. hr = pIMeta->GetData(hMetaRoot, L"", &MDRecord, &dwSize);
  1908. _JumpIfErrorStr(hr, error, "OpenKey", g_wszW3SVC);
  1909. hr = MultiSz.Unmarshal(MDRecord.pbMDData);
  1910. _JumpIfError(hr, error, "Unmarshal");
  1911. error:
  1912. LOCAL_FREE(MDRecord.pbMDData);
  1913. MDRecord.pbMDData = NULL;
  1914. MDRecord.dwMDDataLen = 0;
  1915. if (NULL != hMetaRoot)
  1916. {
  1917. pIMeta->CloseKey(hMetaRoot);
  1918. }
  1919. if(pIMeta)
  1920. {
  1921. pIMeta->Release();
  1922. }
  1923. if (fCoInit)
  1924. {
  1925. CoUninitialize();
  1926. }
  1927. return hr;
  1928. }
  1929. //+------------------------------------------------------------------------
  1930. // Check if an ISAPI dependency is present in the list
  1931. //-------------------------------------------------------------------------
  1932. bool IsISAPIDependencySet(CMultiSz& ISAPIDependList, LPCWSTR pcwszDependency)
  1933. {
  1934. return ISAPIDependList.Find(pcwszDependency, false); // false == case insensitive
  1935. }
  1936. //+------------------------------------------------------------------------
  1937. // Add an ISAPI dependency to the list
  1938. //-------------------------------------------------------------------------
  1939. HRESULT AddISAPIDependency(CMultiSz& ISAPIDependList, LPCWSTR pcwszDependency)
  1940. {
  1941. HRESULT hr = S_OK;
  1942. CString *pStr;
  1943. pStr = new CString(pcwszDependency);
  1944. if(!pStr || pStr->IsEmpty())
  1945. {
  1946. hr = E_OUTOFMEMORY;
  1947. _JumpError(hr, error, "new");
  1948. }
  1949. if(!ISAPIDependList.AddTail(pStr))
  1950. {
  1951. hr = E_OUTOFMEMORY;
  1952. _JumpError(hr, error, "CMultiSz::AddTail");
  1953. }
  1954. error:
  1955. if(S_OK != hr)
  1956. {
  1957. delete pStr;
  1958. }
  1959. return hr;
  1960. }
  1961. //+------------------------------------------------------------------------
  1962. // Set an application dependency in IIS metabase
  1963. //-------------------------------------------------------------------------
  1964. HRESULT
  1965. SetApplicationDependency(LPCWSTR pcwszDependencyString)
  1966. {
  1967. HRESULT hr;
  1968. CMultiSz AppDependList;
  1969. hr = GetMultiSzIISMetadata(ApplicationDependenciesMDData, AppDependList);
  1970. _JumpIfError(hr, error, "GetISAPIRestrictions");
  1971. if(!IsISAPIDependencySet(AppDependList, pcwszDependencyString))
  1972. {
  1973. hr = AddISAPIDependency(AppDependList, pcwszDependencyString);
  1974. _JumpIfError(hr, error, "AddISAPIDependency");
  1975. }
  1976. hr = SetMultiSzIISMetadata(ApplicationDependenciesMDData, AppDependList);
  1977. _JumpIfError(hr, error, "SetISAPIRestrictions");
  1978. error:
  1979. return S_OK;
  1980. }
  1981. //+------------------------------------------------------------------------
  1982. // Set CertSrv dependency on ASP in IIS metabase
  1983. //-------------------------------------------------------------------------
  1984. HRESULT
  1985. SetCertSrvASPDependency()
  1986. {
  1987. HRESULT hr;
  1988. CString strCertSrvASPDepend;
  1989. LPCSTR pcwszASP = ";ASP";
  1990. if(!strCertSrvASPDepend.LoadString(IDS_CERTIFICATE_SERVICES))
  1991. {
  1992. hr = E_OUTOFMEMORY;
  1993. _JumpError(hr, error, "LoadString(IDS_CERTIFICATE_SERVICES)");
  1994. }
  1995. // build the dependency string "Certificate Services;ASP"
  1996. strCertSrvASPDepend += pcwszASP;
  1997. hr = SetApplicationDependency(strCertSrvASPDepend);
  1998. _JumpIfError(hr, error, "SetApplicationDependency");
  1999. error:
  2000. return S_OK;
  2001. }
  2002. //+------------------------------------------------------------------------
  2003. // Tests if ASP processing is enabled in IIS.
  2004. //-------------------------------------------------------------------------
  2005. HRESULT IsASPEnabledInIIS_New(
  2006. bool& rfEnabled)
  2007. {
  2008. HRESULT hr;
  2009. CMultiSz WebSvcExtRestrictions;
  2010. CMultiSzEnum WebSvcExtRestrictionsEnum;
  2011. CString *pstr;
  2012. CString strTmp;
  2013. rfEnabled = false;
  2014. hr = GetMultiSzIISMetadata(WebSvcExtRestrictionsMDData, WebSvcExtRestrictions);
  2015. _JumpIfError(hr, error, "GetMultiSzIISMetadata");
  2016. WebSvcExtRestrictionsEnum.Set(WebSvcExtRestrictions);
  2017. for(pstr = WebSvcExtRestrictionsEnum.Next();
  2018. pstr;
  2019. pstr = WebSvcExtRestrictionsEnum.Next())
  2020. {
  2021. // create a copy so we don't modify the original string
  2022. strTmp = *pstr;
  2023. _wcslwr(strTmp.GetBuffer());
  2024. if(NULL != wcsstr(strTmp, g_pcwszAspDll))
  2025. {
  2026. if(g_wchExtensionOn == *(pstr->GetBuffer())) // string format is "1,"path\asp.dll,..." if
  2027. // asp is enabled
  2028. {
  2029. rfEnabled = true;
  2030. }
  2031. break;
  2032. }
  2033. }
  2034. error:
  2035. return hr;
  2036. }
  2037. //+------------------------------------------------------------------------
  2038. //
  2039. //
  2040. // SetupMSCEPForIIS
  2041. //
  2042. //-------------------------------------------------------------------------
  2043. HRESULT SetupMSCEPForIIS(LPCWSTR pcwszExtension)
  2044. {
  2045. HRESULT hr=E_FAIL;
  2046. CString strMSCEPAppDepend;
  2047. BOOL fEnabled=FALSE;
  2048. CMultiSz WebSvcExtList;
  2049. WCHAR wszDescription[255];
  2050. LPWSTR pwszWebSvcExt=NULL;
  2051. CString *pstrWebSvcExt=NULL;
  2052. if(NULL == pcwszExtension)
  2053. {
  2054. hr = E_INVALIDARG;
  2055. _JumpError(hr, error, "CheckForInput");
  2056. }
  2057. //*******************************************************
  2058. // set up the ApplicationDepedencies in the format of
  2059. // "ApplicationName";"GroupID"
  2060. if(!strMSCEPAppDepend.LoadString(IDS_MSCEP))
  2061. {
  2062. hr = E_OUTOFMEMORY;
  2063. _JumpError(hr, error, "LoadString(IDS_MSCEP)");
  2064. }
  2065. // build the dependency string "Certificate Services;ASP"
  2066. strMSCEPAppDepend += L";";
  2067. strMSCEPAppDepend += g_wszMSCEPID;
  2068. // add to the metadata if it does not exist
  2069. hr = SetApplicationDependency(strMSCEPAppDepend);
  2070. _JumpIfError(hr, error, "SetApplicationDependency");
  2071. //*******************************************************
  2072. // set up the WebSvcExtRestrictionList in the format of
  2073. // 1,d:\windows\system32\certsrv\mscep\mscep.dll,0,GroupID,Description
  2074. // turn on the enable bit if there exists an entry
  2075. if(S_OK == (hr=EnableWebSvcExtension(g_wszMSCEP, &fEnabled)))
  2076. goto error;
  2077. // we have to add a new entry
  2078. if(!LoadString(g_hInstance,
  2079. IDS_MSCEP_DES,
  2080. wszDescription,
  2081. ARRAYSIZE(wszDescription)))
  2082. {
  2083. hr = myHLastError();
  2084. _JumpError(hr, error, "LoadString");
  2085. }
  2086. pwszWebSvcExt=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*
  2087. (wcslen(pcwszExtension) + wcslen(g_wszMSCEPID) + wcslen(wszDescription) + 7));
  2088. if(NULL == pwszWebSvcExt)
  2089. {
  2090. hr=E_OUTOFMEMORY;
  2091. _JumpError(hr, error, "LocalAlloc");
  2092. }
  2093. wcscpy(pwszWebSvcExt, L"1,");
  2094. wcscat(pwszWebSvcExt, pcwszExtension);
  2095. wcscat(pwszWebSvcExt, L",0,");
  2096. wcscat(pwszWebSvcExt, g_wszMSCEPID);
  2097. wcscat(pwszWebSvcExt, L",");
  2098. wcscat(pwszWebSvcExt, wszDescription);
  2099. hr = GetMultiSzIISMetadata(WebSvcExtRestrictionsMDData, WebSvcExtList);
  2100. _JumpIfError(hr, error, "GetMultiSzIISMetadata");
  2101. pstrWebSvcExt=new CString(pwszWebSvcExt);
  2102. if((NULL == pstrWebSvcExt) || (pstrWebSvcExt->IsEmpty()))
  2103. {
  2104. hr=E_OUTOFMEMORY;
  2105. _JumpError(hr, error, "new");
  2106. }
  2107. if(!WebSvcExtList.AddTail(pstrWebSvcExt))
  2108. {
  2109. hr = E_OUTOFMEMORY;
  2110. _JumpError(hr, error, "CMultiSz::AddTail");
  2111. }
  2112. hr = SetMultiSzIISMetadata(WebSvcExtRestrictionsMDData, WebSvcExtList);
  2113. _JumpIfError(hr, error, "SetISAPIRestrictions");
  2114. hr=S_OK;
  2115. error:
  2116. if(pwszWebSvcExt)
  2117. LocalFree(pwszWebSvcExt);
  2118. if(S_OK != hr)
  2119. {
  2120. if(pstrWebSvcExt)
  2121. delete pstrWebSvcExt;
  2122. }
  2123. return hr;
  2124. }