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.

1064 lines
31 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: config.cpp
  8. //
  9. // Contents: OC Manager component DLL for running the Certificate
  10. // Server setup.
  11. //
  12. //--------------------------------------------------------------------------
  13. #include "pch.cpp"
  14. #pragma hdrstop
  15. #include <string.h>
  16. #include "csdisp.h"
  17. #include "csprop.h"
  18. #include "wizpage.h"
  19. #include "certmsg.h"
  20. #define __dwFILE__ __dwFILE_OCMSETUP_CONFIG_CPP__
  21. WCHAR const g_szCertSrvDotTxt[] = L"certsrv.txt";
  22. WCHAR const g_szCertSrvDotBak[] = L"certsrv.bak";
  23. WCHAR const g_szSlashCertSrvDotTmp[] = L"\\certsrv.tmp";
  24. #define wszXEnrollDllFileForVer L"CertSrv\\CertControl\\x86\\xenroll.dll"
  25. #define wszScrdEnrlDllFileForVer L"CertSrv\\CertControl\\x86\\scrdenrl.dll"
  26. //+-------------------------------------------------------------------------
  27. //
  28. // Function: GetBaseFileNameFromFullPath()
  29. //
  30. // Synopsis: Takes a string representing a path of the form
  31. // "\foo\bar\shrd\lu\basefilename"
  32. // and extracts the "basefilename" from the end.
  33. //
  34. // Effects: Modifies the pointer in the second argument;
  35. // allocates memory.
  36. //
  37. // Arguments: [pszFullPath] -- Path to operate on
  38. // [pszBaseFileName] -- Buffer to receive base name
  39. //
  40. // Returns: BOOL success/failure code.
  41. //
  42. // Requires: Assumes that pszBaseFileName is a pre-allocated buffer of
  43. // size sufficient to hold the filename extracted from
  44. // pszFullPath---NO ERROR CHECKING IS DONE ON THIS ARGUMENT;
  45. // IN THE CURRENT CODE BUFFERS GIVEN TO THIS ARGUMENT ARE
  46. // STATICALLY ALLOCATED OF SIZE MAX_PATH (OR EQUIVALENTLY
  47. // STRBUF_SIZE).
  48. //
  49. // Modifies: [ppszBaseFileName]
  50. //
  51. // History: 10/25/96 JerryK Created
  52. // 11/25/96 JerryK Code Cleanup
  53. //
  54. //--------------------------------------------------------------------------
  55. BOOL
  56. GetBaseFileNameFromFullPath(
  57. IN const LPTSTR pszFullPath,
  58. OUT LPTSTR pszBaseFileName)
  59. {
  60. LPTSTR pszBaseName;
  61. BOOL fRetVal;
  62. // Find the last '\' character in the full path string
  63. if (NULL == (pszBaseName = _tcsrchr(pszFullPath,TEXT('\\'))))
  64. {
  65. // Didn't find a '\' character at all so point to start of string
  66. pszBaseName = pszFullPath;
  67. }
  68. else
  69. {
  70. // Found the '\' character so move to point just past it
  71. pszBaseName++;
  72. }
  73. // Copy the base file name into the result buffer
  74. _tcscpy(pszBaseFileName,pszBaseName);
  75. // Set up return value
  76. fRetVal = TRUE;
  77. return fRetVal;
  78. }
  79. HRESULT myStringToAnsiFile(HANDLE hFile, LPCSTR psz, DWORD cch)
  80. {
  81. DWORD dwWritten;
  82. if (cch == -1)
  83. cch = lstrlenA(psz);
  84. if (!WriteFile(
  85. hFile,
  86. psz,
  87. cch,
  88. &dwWritten,
  89. NULL))
  90. return myHLastError();
  91. CSASSERT(dwWritten == cch);
  92. return S_OK;
  93. }
  94. HRESULT myStringToAnsiFile(HANDLE hFile, LPCWSTR pwsz, DWORD cch)
  95. {
  96. HRESULT hr;
  97. LPSTR psz = NULL;
  98. if (!ConvertWszToSz(&psz, pwsz, cch))
  99. {
  100. hr = myHLastError();
  101. goto Ret;
  102. }
  103. hr = myStringToAnsiFile(hFile, psz, cch);
  104. Ret:
  105. if (psz)
  106. LocalFree(psz);
  107. return hr;
  108. }
  109. HRESULT myStringToAnsiFile(HANDLE hFile, CHAR ch)
  110. {
  111. return myStringToAnsiFile(hFile, &ch, 1);
  112. }
  113. HRESULT
  114. WriteEscapedString(
  115. HANDLE hConfigFile,
  116. WCHAR const *pwszIn,
  117. IN BOOL fEol)
  118. {
  119. BOOL fQuote = FALSE;
  120. DWORD i;
  121. HRESULT hr;
  122. if (NULL == pwszIn)
  123. {
  124. hr = myStringToAnsiFile(hConfigFile, "\"\"", 2); // write ("")
  125. _JumpIfError(hr, error, "myStringToAnsiFile");
  126. }
  127. else
  128. {
  129. // Quote strings that have double quotes, commas, '#' or white space,
  130. // or that are empty.
  131. fQuote = L'\0' != pwszIn[wcscspn(pwszIn, L"\",# \t")] || L'\0' == *pwszIn;
  132. if (fQuote)
  133. {
  134. hr = myStringToAnsiFile(hConfigFile, '"');
  135. _JumpIfError(hr, error, "myStringToAnsiFile");
  136. }
  137. while (TRUE)
  138. {
  139. // Find a L'\0' or L'"', and print the string UP TO that character:
  140. i = wcscspn(pwszIn, L"\"");
  141. hr = myStringToAnsiFile(hConfigFile, pwszIn, i);
  142. _JumpIfError(hr, error, "myStringToAnsiFile");
  143. // Point to the L'\0' or L'"', and stop at the end of the string.
  144. pwszIn += i;
  145. if (L'\0' == *pwszIn)
  146. {
  147. break;
  148. }
  149. // Skip the L'"', and print two of them to escape the embedded quote.
  150. pwszIn++;
  151. hr = myStringToAnsiFile(hConfigFile, "\"\"", 2); // write ("")
  152. _JumpIfError(hr, error, "myStringToAnsiFile");
  153. }
  154. if (fQuote)
  155. {
  156. hr = myStringToAnsiFile(hConfigFile, '"');
  157. _JumpIfError(hr, error, "myStringToAnsiFile");
  158. }
  159. }
  160. hr = myStringToAnsiFile(hConfigFile, fEol ? "\r\n" : ", ", 2); // each insert string is 2 chars
  161. _JumpIfError(hr, error, "myStringToAnsiFile");
  162. error:
  163. return hr;
  164. }
  165. HRESULT
  166. WriteNewConfigEntry(
  167. HANDLE hConfigFile,
  168. IN PER_COMPONENT_DATA *pComp)
  169. {
  170. HRESULT hr;
  171. DWORD i;
  172. WCHAR wszSelfSignFName[MAX_PATH];
  173. WCHAR *pwszConfig = NULL;
  174. CASERVERSETUPINFO *pServer = (pComp->CA).pServer;
  175. hr = myFormConfigString(pComp->pwszServerName,
  176. pServer->pwszSanitizedName,
  177. &pwszConfig);
  178. _JumpIfError(hr, error, "myFormConfigString");
  179. // Yank out the base filenames for the exchange and self-signed certs
  180. GetBaseFileNameFromFullPath(pServer->pwszCACertFile, wszSelfSignFName);
  181. hr = WriteEscapedString(hConfigFile, pServer->pwszSanitizedName, FALSE);
  182. _JumpIfError(hr, error, "WriteEscapedString");
  183. // org, ou, country, state
  184. hr = WriteEscapedString(hConfigFile, L"", FALSE);
  185. _JumpIfError(hr, error, "WriteEscapedString");
  186. hr = WriteEscapedString(hConfigFile, L"", FALSE);
  187. _JumpIfError(hr, error, "WriteEscapedString");
  188. hr = WriteEscapedString(hConfigFile, L"", FALSE);
  189. _JumpIfError(hr, error, "WriteEscapedString");
  190. hr = WriteEscapedString(hConfigFile, L"", FALSE);
  191. _JumpIfError(hr, error, "WriteEscapedString");
  192. hr = WriteEscapedString(hConfigFile, L"", FALSE);
  193. _JumpIfError(hr, error, "WriteEscapedString");
  194. hr = WriteEscapedString(hConfigFile, pwszConfig, FALSE);
  195. _JumpIfError(hr, error, "WriteEscapedString");
  196. hr = WriteEscapedString(hConfigFile, L"", FALSE); // dummy wszExchangeFName
  197. _JumpIfError(hr, error, "WriteEscapedString");
  198. hr = WriteEscapedString(hConfigFile, wszSelfSignFName, FALSE);
  199. _JumpIfError(hr, error, "WriteEscapedString");
  200. // ca description
  201. hr = WriteEscapedString(hConfigFile, L"", TRUE);
  202. _JumpIfError(hr, error, "WriteEscapedString");
  203. error:
  204. if (NULL != pwszConfig)
  205. {
  206. LocalFree(pwszConfig);
  207. }
  208. return(hr);
  209. }
  210. WCHAR *apwszFieldNames[] = {
  211. wszCONFIG_COMMONNAME,
  212. wszCONFIG_ORGUNIT,
  213. wszCONFIG_ORGANIZATION,
  214. wszCONFIG_LOCALITY,
  215. wszCONFIG_STATE,
  216. wszCONFIG_COUNTRY,
  217. #define FN_CONFIG 6 // Index into apwszFieldNames & apstrFieldNames
  218. wszCONFIG_CONFIG,
  219. wszCONFIG_EXCHANGECERTIFICATE,
  220. #define FN_CERTNAME 8 // Index into apwszFieldNames & apstrFieldNames
  221. wszCONFIG_SIGNATURECERTIFICATE,
  222. #define FN_COMMENT 9 // Index into apwszFieldNames & apstrFieldNames
  223. wszCONFIG_DESCRIPTION,
  224. };
  225. #define CSTRING (sizeof(apwszFieldNames)/sizeof(apwszFieldNames[0]))
  226. BSTR apstrFieldNames[CSTRING];
  227. HRESULT
  228. CopyConfigEntry(
  229. IN HANDLE hConfigFile,
  230. IN BSTR const strConfig,
  231. IN ICertConfig *pConfig)
  232. {
  233. HRESULT hr;
  234. BSTR strFieldValue = NULL;
  235. BSTR strComment = NULL;
  236. BSTR strCertName = NULL;
  237. DWORD i;
  238. for (i = 0; i < CSTRING; i++)
  239. {
  240. CSASSERT(NULL != apstrFieldNames[i]);
  241. hr = pConfig->GetField(apstrFieldNames[i], &strFieldValue);
  242. _JumpIfErrorNotSpecific(
  243. hr,
  244. error,
  245. "ICertConfig::GetField",
  246. CERTSRV_E_PROPERTY_EMPTY);
  247. hr = WriteEscapedString(hConfigFile, strFieldValue, ((CSTRING - 1) == i) );
  248. _JumpIfError(hr, error, "WriteEscapedString");
  249. switch (i)
  250. {
  251. case FN_CERTNAME:
  252. strCertName = strFieldValue;
  253. strFieldValue = NULL;
  254. break;
  255. case FN_COMMENT:
  256. strComment = strFieldValue;
  257. strFieldValue = NULL;
  258. break;
  259. }
  260. }
  261. hr = S_OK;
  262. error:
  263. if (NULL != strFieldValue)
  264. {
  265. SysFreeString(strFieldValue);
  266. }
  267. if (NULL != strComment)
  268. {
  269. SysFreeString(strComment);
  270. }
  271. if (NULL != strCertName)
  272. {
  273. SysFreeString(strCertName);
  274. }
  275. return(hr);
  276. }
  277. HRESULT
  278. WriteFilteredConfigEntries(
  279. IN HANDLE hConfigFile,
  280. IN ICertConfig *pConfig,
  281. IN PER_COMPONENT_DATA *pComp)
  282. {
  283. HRESULT hr = S_OK;
  284. LONG Count;
  285. LONG Index;
  286. BSTR strConfig = NULL;
  287. BSTR strFlags = NULL;
  288. LONG lConfigFlags;
  289. WCHAR wszConfigComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  290. WCHAR *pwsz;
  291. WCHAR *pwszConfigServer = NULL;
  292. DWORD cwcConfigServer;
  293. DWORD cwc;
  294. DWORD i;
  295. BOOL fValidDigitString;
  296. for (i = 0; i < CSTRING; i++)
  297. {
  298. if (!ConvertWszToBstr(&apstrFieldNames[i], apwszFieldNames[i], -1))
  299. {
  300. hr = E_OUTOFMEMORY;
  301. _JumpError(hr, error, "ConvertWszToBstr");
  302. }
  303. }
  304. hr = pConfig->Reset(0, &Count);
  305. if (S_OK != hr)
  306. {
  307. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  308. {
  309. hr = S_OK;
  310. }
  311. _JumpError2(hr, error, "Reset", S_FALSE);
  312. }
  313. while (Count-- > 0)
  314. {
  315. hr = pConfig->Next(&Index);
  316. _JumpIfError(hr, error, "Next");
  317. hr = pConfig->GetField(apstrFieldNames[FN_CONFIG], &strConfig);
  318. _JumpIfError(hr, error, "GetField");
  319. pwsz = wcschr(strConfig, L'\\');
  320. if (NULL == pwsz)
  321. {
  322. cwc = wcslen(strConfig);
  323. }
  324. else
  325. {
  326. cwc = SAFE_SUBTRACT_POINTERS(pwsz, strConfig);
  327. }
  328. if (NULL == pwszConfigServer || cwc >= cwcConfigServer)
  329. {
  330. if (NULL != pwszConfigServer)
  331. {
  332. LocalFree(pwszConfigServer);
  333. pwszConfigServer = NULL;
  334. }
  335. cwcConfigServer = cwc + 1;
  336. if (2 * MAX_COMPUTERNAME_LENGTH > cwcConfigServer)
  337. {
  338. cwcConfigServer = 2 * MAX_COMPUTERNAME_LENGTH;
  339. }
  340. pwszConfigServer = (WCHAR *) LocalAlloc(
  341. LMEM_FIXED,
  342. cwcConfigServer * sizeof(WCHAR));
  343. _JumpIfOutOfMemory(hr, error, pwszConfigServer);
  344. }
  345. CSASSERT(cwc < cwcConfigServer);
  346. CopyMemory(pwszConfigServer, strConfig, cwc * sizeof(WCHAR));
  347. pwszConfigServer[cwc] = L'\0';
  348. hr = pConfig->GetField(wszCONFIG_FLAGS, &strFlags);
  349. _JumpIfError(hr, error, "GetField");
  350. lConfigFlags = myWtoI(strFlags, &fValidDigitString);
  351. // write everything _but_ current server
  352. if (0 != lstrcmpi(pwszConfigServer, pComp->pwszServerName) &&
  353. 0 != lstrcmpi(pwszConfigServer, pComp->pwszServerNameOld) &&
  354. 0 != (CAIF_SHAREDFOLDERENTRY & lConfigFlags) )
  355. {
  356. hr = CopyConfigEntry(
  357. hConfigFile,
  358. strConfig,
  359. pConfig);
  360. _JumpIfError(hr, error, "CopyConfigEntry");
  361. }
  362. }
  363. error:
  364. if (NULL != pwszConfigServer)
  365. {
  366. LocalFree(pwszConfigServer);
  367. }
  368. for (i = 0; i < CSTRING; i++)
  369. {
  370. if (NULL != apstrFieldNames[i])
  371. {
  372. SysFreeString(apstrFieldNames[i]);
  373. apstrFieldNames[i] = NULL;
  374. }
  375. }
  376. if (NULL != strConfig)
  377. {
  378. SysFreeString(strConfig);
  379. }
  380. if (NULL != strFlags)
  381. {
  382. SysFreeString(strFlags);
  383. }
  384. return(hr);
  385. }
  386. HRESULT
  387. CertReplaceFile(
  388. IN HINSTANCE hInstance,
  389. IN BOOL fUnattended,
  390. IN HWND hwnd,
  391. IN WCHAR const *pwszpath,
  392. IN WCHAR const *pwszFileNew,
  393. IN WCHAR const *pwszFileBackup)
  394. {
  395. HRESULT hr;
  396. WCHAR *pwsz;
  397. WCHAR wszpathNew[MAX_PATH] = L"";
  398. WCHAR wszpathBackup[MAX_PATH] = L"";
  399. wcscpy(wszpathNew, pwszpath);
  400. pwsz = wcsrchr(wszpathNew, L'\\');
  401. CSASSERT(NULL != pwsz);
  402. if (NULL == pwsz)
  403. return E_INVALIDARG;
  404. else
  405. pwsz[1] = L'\0';
  406. wcscpy(wszpathBackup, wszpathNew);
  407. wcscat(wszpathNew, pwszFileNew);
  408. wcscat(wszpathBackup, pwszFileBackup);
  409. if (!DeleteFile(wszpathBackup))
  410. {
  411. hr = myHLastError();
  412. _PrintErrorStr2(
  413. hr,
  414. "DeleteFile",
  415. wszpathBackup,
  416. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
  417. }
  418. if (!MoveFile(wszpathNew, wszpathBackup))
  419. {
  420. hr = myHLastError();
  421. _PrintErrorStr2(
  422. hr,
  423. "MoveFile",
  424. wszpathNew,
  425. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
  426. }
  427. if (!MoveFile(pwszpath, wszpathNew))
  428. {
  429. hr = myHLastError();
  430. _JumpErrorStr(hr, error, "MoveFile", pwszpath);
  431. }
  432. hr = S_OK;
  433. error:
  434. return(hr);
  435. }
  436. //--------------------------------------------------------------------
  437. // Perform search and replace on the source string, using multiple
  438. // replacee strings, and returns the result.
  439. // rgrgwszReplacement is an array of arrays of two strings:
  440. // rgrgwszReplacement[n][0] is the replacee,
  441. // rgrgwszReplacement[n][1] is the replacment.
  442. // No portion of any of the replacement strings is searched for a replacee string.
  443. // Replacement strings may be NULL.
  444. #define REPLACEE 0
  445. #define REPLACEMENT 1
  446. WCHAR * MultiStringReplace(const WCHAR * pwszSource, const WCHAR *(* rgrgpwszReplacements)[2] , unsigned int nReplacements) {
  447. // precondition
  448. CSASSERT(NULL!=pwszSource);
  449. CSASSERT(nReplacements>0);
  450. CSASSERT(NULL!=rgrgpwszReplacements);
  451. // common variables
  452. unsigned int nIndex;
  453. BOOL bSubstFound;
  454. unsigned int nChosenReplacement;
  455. const WCHAR * pwchSubstStart;
  456. const WCHAR * pwchSearchStart;
  457. WCHAR * pwszTarget=NULL;
  458. WCHAR * pwchTargetStart;
  459. // first, calculate the length of the result string
  460. unsigned int nFinalStringLen=wcslen(pwszSource)+1;
  461. pwchSearchStart=pwszSource;
  462. do {
  463. // find the next substitution
  464. bSubstFound=FALSE;
  465. for (nIndex=0; nIndex<nReplacements; nIndex++) {
  466. WCHAR * pwchTempSubstStart=wcsstr(pwchSearchStart, rgrgpwszReplacements[nIndex][REPLACEE]);
  467. if (NULL==pwchTempSubstStart) {
  468. // we didn't find this replacee in the target
  469. // so ignore it
  470. } else if (FALSE==bSubstFound) {
  471. // this is the first one we found
  472. pwchSubstStart=pwchTempSubstStart;
  473. bSubstFound=TRUE;
  474. nChosenReplacement=nIndex;
  475. } else if (pwchSubstStart>pwchTempSubstStart) {
  476. // this is one comes before the one we already found
  477. pwchSubstStart=pwchTempSubstStart;
  478. nChosenReplacement=nIndex;
  479. } else {
  480. // this is one comes after the one we already found
  481. // so ignore it
  482. }
  483. } // <- end substitution finding loop
  484. // if no substitution has been found, exit the loop
  485. if (FALSE==bSubstFound) {
  486. break;
  487. }
  488. // update the statistics
  489. nFinalStringLen=nFinalStringLen
  490. + (NULL != rgrgpwszReplacements[nChosenReplacement][REPLACEMENT] ?
  491. wcslen(rgrgpwszReplacements[nChosenReplacement][REPLACEMENT]) : 0)
  492. -wcslen(rgrgpwszReplacements[nChosenReplacement][REPLACEE]);
  493. pwchSearchStart=pwchSubstStart+wcslen(rgrgpwszReplacements[nChosenReplacement][REPLACEE]);
  494. } while (TRUE); // <- end length-calculating loop
  495. // allocate the new string
  496. pwszTarget=(WCHAR *)LocalAlloc(LMEM_FIXED, nFinalStringLen*sizeof(WCHAR));
  497. if (NULL==pwszTarget) {
  498. _JumpError(E_OUTOFMEMORY, error, "LocalAlloc");
  499. }
  500. // build the result
  501. pwchTargetStart=pwszTarget;
  502. pwchSearchStart=pwszSource;
  503. do {
  504. // find the next substitution
  505. bSubstFound=FALSE;
  506. for (nIndex=0; nIndex<nReplacements; nIndex++) {
  507. WCHAR * pwchTempSubstStart=wcsstr(pwchSearchStart, rgrgpwszReplacements[nIndex][REPLACEE]);
  508. if (NULL==pwchTempSubstStart) {
  509. // we didn't find this replacee in the target
  510. // so ignore it
  511. } else if (FALSE==bSubstFound) {
  512. // this is the first one we found
  513. pwchSubstStart=pwchTempSubstStart;
  514. bSubstFound=TRUE;
  515. nChosenReplacement=nIndex;
  516. } else if (pwchSubstStart>pwchTempSubstStart) {
  517. // this is one comes before the one we already found
  518. pwchSubstStart=pwchTempSubstStart;
  519. nChosenReplacement=nIndex;
  520. } else {
  521. // this is one comes after the one we already found
  522. // so ignore it
  523. }
  524. } // <- end substitution finding loop
  525. // if no substitution has been found, exit the loop
  526. if (FALSE==bSubstFound) {
  527. break;
  528. }
  529. // copy the source up to the replacee
  530. unsigned int nCopyLen=SAFE_SUBTRACT_POINTERS(pwchSubstStart, pwchSearchStart);
  531. wcsncpy(pwchTargetStart, pwchSearchStart, nCopyLen);
  532. pwchTargetStart+=nCopyLen;
  533. if (NULL != rgrgpwszReplacements[nChosenReplacement][REPLACEMENT])
  534. {
  535. // copy the replacement
  536. nCopyLen=wcslen(rgrgpwszReplacements[nChosenReplacement][REPLACEMENT]);
  537. wcsncpy(pwchTargetStart, rgrgpwszReplacements[nChosenReplacement][REPLACEMENT], nCopyLen);
  538. pwchTargetStart+=nCopyLen;
  539. }
  540. // skip over the replacee
  541. pwchSearchStart=pwchSubstStart+wcslen(rgrgpwszReplacements[nChosenReplacement][REPLACEE]);
  542. } while (TRUE); // <- end target string building loop
  543. // finish copying whatever's left, which may be just '\0'.
  544. wcscpy(pwchTargetStart, pwchSearchStart);
  545. // postcondition
  546. CSASSERT(wcslen(pwszTarget)+1==nFinalStringLen);
  547. // all done
  548. error:
  549. return pwszTarget;
  550. }
  551. //--------------------------------------------------------------------
  552. // Escapes any characters unsuitable for plain HTML (or VBScript)
  553. static const WCHAR * gc_rgrgpwszHTMLSafe[4][2]={
  554. {L"<", L"&lt;"}, {L">", L"&gt;"}, {L"\"", L"&quot;"}, {L"&", L"&amp;"}
  555. };
  556. WCHAR * MakeStringHTMLSafe(const WCHAR * pwszTarget) {
  557. return MultiStringReplace(pwszTarget, gc_rgrgpwszHTMLSafe, ARRAYSIZE(gc_rgrgpwszHTMLSafe));
  558. }
  559. //--------------------------------------------------------------------
  560. // Escapes any characters unsuitable for plain HTML (or VBScript)
  561. static const WCHAR * gc_rgrgpwszVBScriptSafe[2][2]={
  562. {L"\"", L"\"\""}, {L"%>", L"%\" & \">"}
  563. };
  564. WCHAR * MakeStringVBScriptSafe(const WCHAR * pwszTarget) {
  565. return MultiStringReplace(pwszTarget, gc_rgrgpwszVBScriptSafe, ARRAYSIZE(gc_rgrgpwszVBScriptSafe));
  566. }
  567. //--------------------------------------------------------------------
  568. // Perform search and replace on the source string and return the result
  569. // No portion of the replacement string is searched for the replacee string.
  570. // Simple adapter for MultiStringReplace
  571. WCHAR * SingleStringReplace(const WCHAR * pwszSource, const WCHAR * pwszReplacee, const WCHAR * pwszReplacement) {
  572. const WCHAR * rgrgpwszTemp[1][2]={{pwszReplacee, pwszReplacement}};
  573. return MultiStringReplace(pwszSource, rgrgpwszTemp, ARRAYSIZE(rgrgpwszTemp));
  574. }
  575. //--------------------------------------------------------------------
  576. // write a string to a file
  577. // Mostly, this is a wrapper to do UNICODE->UTF8 conversion.
  578. HRESULT WriteString(HANDLE hTarget, const WCHAR * pwszSource) {
  579. // precondition
  580. CSASSERT(NULL!=pwszSource);
  581. CSASSERT(NULL!=hTarget && INVALID_HANDLE_VALUE!=hTarget);
  582. // common variables
  583. HRESULT hr=S_OK;
  584. char * pszMbcsBuf=NULL;
  585. // perform UNICODE->MBCS
  586. // determine size of output buffer
  587. DWORD dwBufByteSize=WideCharToMultiByte(CP_UTF8/*code page*/, 0/*flags*/, pwszSource,
  588. -1/*null-terminated*/, NULL/*out-buf*/, 0/*size of out-buf, 0->calc*/,
  589. NULL/*default char*/, NULL/*used default char*/);
  590. if (0==dwBufByteSize) {
  591. hr=myHLastError();
  592. _JumpError(hr, error, "WideCharToMultiByte(calc)");
  593. }
  594. // allocate output buffer
  595. pszMbcsBuf=(char *)LocalAlloc(LMEM_FIXED, dwBufByteSize);
  596. _JumpIfOutOfMemory(hr, error, pszMbcsBuf);
  597. // do the conversion
  598. if (0==WideCharToMultiByte(CP_UTF8/*code page*/, 0/*flags*/, pwszSource,
  599. -1/*null-terminated*/, pszMbcsBuf, dwBufByteSize,
  600. NULL/*default char*/, NULL/*used default char*/)) {
  601. hr=myHLastError();
  602. _JumpError(hr, error, "WideCharToMultiByte(convert)");
  603. }
  604. // write to file and free the string
  605. dwBufByteSize--; // minus one so we don't write the terminating null
  606. DWORD dwBytesWritten;
  607. if (FALSE==WriteFile(hTarget, pszMbcsBuf, dwBufByteSize, &dwBytesWritten, NULL /*overlapped*/)) {
  608. hr=myHLastError();
  609. _JumpError(hr, error, "WriteFile");
  610. }
  611. // all done
  612. error:
  613. if (NULL!=pszMbcsBuf) {
  614. LocalFree(pszMbcsBuf);
  615. }
  616. return hr;
  617. }
  618. //--------------------------------------------------------------------
  619. // return the version string for a file in the format for a web page (comma separated)
  620. HRESULT
  621. GetFileWebVersionString(
  622. IN WCHAR const * pwszFileName,
  623. OUT WCHAR ** ppwszVersion)
  624. {
  625. // precondition
  626. CSASSERT(NULL!=pwszFileName);
  627. CSASSERT(NULL!=ppwszVersion);
  628. // common variables
  629. HRESULT hr;
  630. DWORD cbData;
  631. DWORD dwIgnored;
  632. UINT uLen;
  633. VS_FIXEDFILEINFO * pvs;
  634. WCHAR wszFileVersion[64];
  635. int cch;
  636. // variables that must be cleaned up
  637. VOID * pvData=NULL;
  638. // reset the output parameter
  639. *ppwszVersion=NULL;
  640. // determine the size of the memory block needed to store the version info
  641. cbData=GetFileVersionInfoSize(const_cast<WCHAR *>(pwszFileName), &dwIgnored);
  642. if (0==cbData) {
  643. hr=myHLastError();
  644. if (S_OK==hr) {
  645. hr=HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);
  646. }
  647. _JumpErrorStr(hr, error, "GetFileVersionInfoSize", pwszFileName);
  648. }
  649. // allocate the block
  650. pvData=LocalAlloc(LMEM_FIXED, cbData);
  651. _JumpIfOutOfMemory(hr, error, pvData);
  652. // load the file version info
  653. if (!GetFileVersionInfo(const_cast<WCHAR *>(pwszFileName), dwIgnored, cbData, pvData)) {
  654. hr=myHLastError();
  655. _JumpErrorStr(hr, error, "GetFileVersionInfo", pwszFileName);
  656. }
  657. // get a pointer to the root block
  658. if (!VerQueryValue(pvData, L"\\", (VOID **) &pvs, &uLen)) {
  659. hr=myHLastError();
  660. _JumpError(hr, error, "VerQueryValue");
  661. }
  662. cch = wsprintf(wszFileVersion, L"%d,%d,%d,%d",
  663. HIWORD(pvs->dwFileVersionMS),
  664. LOWORD(pvs->dwFileVersionMS),
  665. HIWORD(pvs->dwFileVersionLS),
  666. LOWORD(pvs->dwFileVersionLS));
  667. CSASSERT(cch < ARRAYSIZE(wszFileVersion));
  668. *ppwszVersion = (WCHAR*)LocalAlloc(LMEM_FIXED,
  669. (wcslen(wszFileVersion)+1) * sizeof(WCHAR));
  670. if (NULL == *ppwszVersion)
  671. {
  672. hr = E_OUTOFMEMORY;
  673. _JumpError(hr, error, "LocalAlloc");
  674. }
  675. wcscpy(*ppwszVersion, wszFileVersion);
  676. hr=S_OK;
  677. error:
  678. if (NULL != pvData) {
  679. LocalFree(pvData);
  680. }
  681. return hr;
  682. }
  683. //--------------------------------------------------------------------
  684. // create the .inc file that has the basic configuration data
  685. HRESULT CreateCertWebDatIncPage(IN PER_COMPONENT_DATA *pComp, IN BOOL bIsServer)
  686. {
  687. // precondition
  688. CSASSERT(NULL!=pComp);
  689. // common variables
  690. HRESULT hr=S_OK;
  691. HANDLE hTarget=INVALID_HANDLE_VALUE;
  692. const WCHAR * rgrgpwszSubst[12][2];
  693. WCHAR wszTargetFileName[MAX_PATH];
  694. wszTargetFileName[0] = L'\0';
  695. // variables that must be cleaned up
  696. WCHAR * pwszTempA=NULL;
  697. WCHAR * pwszTempB=NULL;
  698. WCHAR * pwszTempC=NULL;
  699. WCHAR * pwszTempD=NULL;
  700. WCHAR * pwszTempE=NULL;
  701. ENUM_CATYPES CAType;
  702. // create the target file name
  703. wcscpy(wszTargetFileName, pComp->pwszSystem32);
  704. wcscat(wszTargetFileName, L"CertSrv\\certdat.inc");
  705. // get html lines from resource
  706. // Note, we don't have to free these strings.
  707. WCHAR const * pwszCWDat=myLoadResourceString(IDS_HTML_CERTWEBDAT);
  708. if (NULL==pwszCWDat) {
  709. hr=myHLastError();
  710. _JumpError(hr, error, "myLoadResourceString");
  711. }
  712. // open the file
  713. hTarget=CreateFileW(wszTargetFileName, GENERIC_WRITE, 0/*no sharing*/, NULL/*security*/,
  714. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL/*template*/);
  715. if (INVALID_HANDLE_VALUE==hTarget) {
  716. hr=myHLastError();
  717. _JumpError(hr, error, "CreateFileW");
  718. }
  719. // prepare to write the file
  720. // %0 - default company
  721. // %1 - default OrgUnit
  722. // %2 - default locality
  723. // %3 - default state
  724. // %4 - default country
  725. // %5 - computer
  726. // %6 - CA name (unsanitized, for config)
  727. // %7 - server type
  728. // %8 - opposite of %7
  729. // %9 - XEnroll version
  730. // %A - ScrdEnrl version
  731. // %B - CA name (unsanitized, for display)
  732. rgrgpwszSubst[0][REPLACEE]=L"%0";
  733. rgrgpwszSubst[1][REPLACEE]=L"%1";
  734. rgrgpwszSubst[2][REPLACEE]=L"%2";
  735. rgrgpwszSubst[3][REPLACEE]=L"%3";
  736. rgrgpwszSubst[4][REPLACEE]=L"%4";
  737. rgrgpwszSubst[5][REPLACEE]=L"%5";
  738. rgrgpwszSubst[6][REPLACEE]=L"%6";
  739. rgrgpwszSubst[7][REPLACEE]=L"%7";
  740. rgrgpwszSubst[8][REPLACEE]=L"%8";
  741. rgrgpwszSubst[9][REPLACEE]=L"%9";
  742. rgrgpwszSubst[10][REPLACEE]=L"%A";
  743. rgrgpwszSubst[11][REPLACEE]=L"%B";
  744. rgrgpwszSubst[0][REPLACEMENT]=L""; // company/org
  745. rgrgpwszSubst[1][REPLACEMENT]=L""; // ou
  746. rgrgpwszSubst[2][REPLACEMENT]=L""; // locality
  747. rgrgpwszSubst[3][REPLACEMENT]=L""; // state
  748. rgrgpwszSubst[4][REPLACEMENT]=L""; // country
  749. if (FALSE==bIsServer) {
  750. // This is a web-client only setup
  751. CAWEBCLIENTSETUPINFO *pClient=pComp->CA.pClient;
  752. // set the identity of the CA
  753. rgrgpwszSubst[5][REPLACEMENT]=pClient->pwszWebCAMachine;
  754. pwszTempE=MakeStringVBScriptSafe(pClient->pwszWebCAName);
  755. _JumpIfOutOfMemory(hr, error, pwszTempE);
  756. rgrgpwszSubst[6][REPLACEMENT]=pwszTempE;
  757. pwszTempD=MakeStringHTMLSafe(pClient->pwszWebCAName);
  758. _JumpIfOutOfMemory(hr, error, pwszTempD);
  759. rgrgpwszSubst[11][REPLACEMENT]=pwszTempD;
  760. CAType = pClient->WebCAType;
  761. } else {
  762. // This is a server + web-client setup
  763. CASERVERSETUPINFO *pServer=pComp->CA.pServer;
  764. // set the identity of the CA
  765. rgrgpwszSubst[5][REPLACEMENT]=pComp->pwszServerName;
  766. pwszTempE=MakeStringVBScriptSafe(pServer->pwszCACommonName);
  767. _JumpIfOutOfMemory(hr, error, pwszTempE);
  768. rgrgpwszSubst[6][REPLACEMENT]=pwszTempE;
  769. pwszTempD=MakeStringHTMLSafe(pServer->pwszCACommonName);
  770. _JumpIfOutOfMemory(hr, error, pwszTempD);
  771. rgrgpwszSubst[11][REPLACEMENT]=pwszTempD;
  772. CAType = pServer->CAType;
  773. }
  774. // set the CA type
  775. if (IsStandaloneCA(CAType)) {
  776. rgrgpwszSubst[7][REPLACEMENT]=L"StandAlone";
  777. rgrgpwszSubst[8][REPLACEMENT]=L"Enterprise";
  778. } else {
  779. rgrgpwszSubst[7][REPLACEMENT]=L"Enterprise";
  780. rgrgpwszSubst[8][REPLACEMENT]=L"StandAlone";
  781. }
  782. // %9 - XEnroll version
  783. wcscpy(wszTargetFileName, pComp->pwszSystem32);
  784. wcscat(wszTargetFileName, wszXEnrollDllFileForVer);
  785. hr=GetFileWebVersionString(wszTargetFileName, &pwszTempB);
  786. _JumpIfError(hr, error, "GetFileWebVersionString");
  787. rgrgpwszSubst[9][REPLACEMENT]=pwszTempB;
  788. // %A - ScrdEnrl version
  789. wcscpy(wszTargetFileName, pComp->pwszSystem32);
  790. wcscat(wszTargetFileName, wszScrdEnrlDllFileForVer);
  791. hr=GetFileWebVersionString(wszTargetFileName, &pwszTempC);
  792. _JumpIfError(hr, error, "GetFileWebVersionString");
  793. rgrgpwszSubst[10][REPLACEMENT]=pwszTempC;
  794. // do the replacements
  795. pwszTempA=MultiStringReplace(pwszCWDat, rgrgpwszSubst, ARRAYSIZE(rgrgpwszSubst));
  796. _JumpIfOutOfMemory(hr, error, pwszTempA);
  797. // write the text
  798. hr=WriteString(hTarget, pwszTempA);
  799. _JumpIfError(hr, error, "WriteString");
  800. // all done
  801. error:
  802. if (INVALID_HANDLE_VALUE!=hTarget) {
  803. CloseHandle(hTarget);
  804. }
  805. if (NULL!=pwszTempA) {
  806. LocalFree(pwszTempA);
  807. }
  808. if (NULL!=pwszTempB) {
  809. LocalFree(pwszTempB);
  810. }
  811. if (NULL!=pwszTempC) {
  812. LocalFree(pwszTempC);
  813. }
  814. if (NULL!=pwszTempD) {
  815. LocalFree(pwszTempD);
  816. }
  817. if (NULL!=pwszTempE) {
  818. LocalFree(pwszTempE);
  819. }
  820. return hr;
  821. }
  822. HRESULT
  823. CreateConfigFiles(
  824. WCHAR *pwszDirectoryPath,
  825. PER_COMPONENT_DATA *pComp,
  826. BOOL fRemove,
  827. HWND hwnd)
  828. {
  829. WCHAR wszpathConfig[MAX_PATH];
  830. WCHAR wszCACertFileName[MAX_PATH];
  831. HANDLE hConfigFile;
  832. DISPATCHINTERFACE di;
  833. ICertConfig *pConfig = NULL;
  834. BOOL fMustRelease = FALSE;
  835. HRESULT hr = S_OK;
  836. CASERVERSETUPINFO *pServer = pComp->CA.pServer;
  837. hr = DispatchSetup(
  838. DISPSETUP_COM,
  839. CLSCTX_INPROC_SERVER,
  840. wszCLASS_CERTCONFIG,
  841. &CLSID_CCertConfig,
  842. &IID_ICertConfig,
  843. 0, // cDispatch
  844. NULL, // pDispatchTable
  845. &di);
  846. if (S_OK != hr)
  847. {
  848. pComp->iErrMsg = IDS_ERR_LOADICERTCONFIG;
  849. _JumpError(hr, error, "DispatchSetup");
  850. }
  851. fMustRelease = TRUE;
  852. pConfig = (ICertConfig *) di.pUnknown;
  853. wcscpy(wszpathConfig, pwszDirectoryPath);
  854. wcscat(wszpathConfig, g_szSlashCertSrvDotTmp);
  855. hConfigFile = CreateFile(
  856. wszpathConfig,
  857. GENERIC_WRITE,
  858. 0,
  859. NULL,
  860. CREATE_ALWAYS,
  861. 0,
  862. 0);
  863. if (INVALID_HANDLE_VALUE == hConfigFile)
  864. {
  865. hr = HRESULT_FROM_WIN32(ERROR_OPEN_FAILED);
  866. _JumpErrorStr2(
  867. hr,
  868. error,
  869. "CreateFile",
  870. wszpathConfig,
  871. fRemove? hr : S_OK);
  872. }
  873. if (!fRemove)
  874. {
  875. // if installing, write our config entry first
  876. hr = WriteNewConfigEntry(hConfigFile, pComp);
  877. _PrintIfError(hr, "WriteNewConfigEntry");
  878. }
  879. if (S_OK == hr)
  880. {
  881. hr = WriteFilteredConfigEntries(
  882. hConfigFile,
  883. pConfig,
  884. pComp);
  885. _PrintIfError2(hr, "WriteFilteredConfigEntries", S_FALSE);
  886. }
  887. // must close here because the following call will move it
  888. if (NULL != hConfigFile)
  889. {
  890. CloseHandle(hConfigFile);
  891. }
  892. hr = CertReplaceFile(pComp->hInstance,
  893. pComp->fUnattended,
  894. hwnd,
  895. wszpathConfig,
  896. g_szCertSrvDotTxt,
  897. g_szCertSrvDotBak);
  898. _JumpIfErrorStr(hr, error, "CertReplaceFile", g_szCertSrvDotTxt);
  899. hr = S_OK;
  900. error:
  901. if (S_OK != hr && 0 == pComp->iErrMsg)
  902. {
  903. pComp->iErrMsg = IDS_ERR_WRITECONFIGFILE;
  904. }
  905. if (fMustRelease)
  906. {
  907. Config_Release(&di);
  908. }
  909. return(hr);
  910. }