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.

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