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.

644 lines
17 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1998
  6. //
  7. // File: simutil.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. /////////////////////////////////////////////////////////////////////
  11. // SimUtil.cpp
  12. //
  13. // Utilities routines specific to the Security Identity Mapping project.
  14. //
  15. // HISTORY
  16. // 25-Jun-97 t-danm Creation.
  17. /////////////////////////////////////////////////////////////////////
  18. #include "stdafx.h"
  19. #include "common.h"
  20. const TCHAR szDefaultCertificateExtension[] = _T("cer"); // Not subject to localization
  21. /////////////////////////////////////////////////////////////////////
  22. // UiGetCertificateFile()
  23. //
  24. // Invoke the common dialog to get a certificate file.
  25. //
  26. // Return FALSE if the user clicked on cancel button.
  27. //
  28. BOOL
  29. UiGetCertificateFile(
  30. CString * pstrCertificateFilename) // OUT: Name of the certificate file
  31. {
  32. ASSERT(pstrCertificateFilename != NULL);
  33. BOOL bResult = FALSE;
  34. CString strFilter;
  35. VERIFY( strFilter.LoadString(IDS_SIM_CERTIFICATE_FILTER) );
  36. CFileDialog* pDlg = new CFileDialog (
  37. TRUE, // Open File
  38. szDefaultCertificateExtension, // lpszDefExt
  39. NULL, // lpszFileName
  40. OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST,
  41. strFilter); // lpszFilter
  42. if ( pDlg )
  43. {
  44. CString strCaption;
  45. VERIFY( strCaption.LoadString(IDS_SIM_ADD_CERTIFICATE) );
  46. pDlg->m_ofn.lpstrTitle = (LPCTSTR)strCaption;
  47. if (pDlg->DoModal() == IDOK)
  48. {
  49. // Copy the string
  50. *pstrCertificateFilename = pDlg->GetPathName();
  51. bResult = TRUE;
  52. }
  53. delete pDlg;
  54. }
  55. return bResult;
  56. } // UiGetCertificateFile()
  57. /////////////////////////////////////////////////////////////////////
  58. // strSimToUi()
  59. //
  60. // Convert a SIM string into a format the user understand.
  61. //
  62. // The routine will remove any quotes and expand any escape characters
  63. // to a format friendly to the user.
  64. //
  65. void strSimToUi(
  66. LPCTSTR pszSIM, // IN:
  67. CString * pstrUI) // OUT:
  68. {
  69. ASSERT(pszSIM != NULL);
  70. ASSERT(pstrUI != NULL);
  71. // Find out if the string contains a quote
  72. if (!wcschr(pszSIM, '"'))
  73. {
  74. // No quote found, so return the original string
  75. *pstrUI = pszSIM;
  76. return;
  77. }
  78. pstrUI->Empty();
  79. while (TRUE)
  80. {
  81. if (*pszSIM == '"')
  82. {
  83. pszSIM++;
  84. }
  85. if (*pszSIM == '\0')
  86. break;
  87. *pstrUI += *pszSIM++;
  88. } // while
  89. } // strSimToUi()
  90. /////////////////////////////////////////////////////////////////////
  91. // strUiToSim()
  92. //
  93. // Convert a string typed by the user to a valid SIM format.
  94. //
  95. // If the UI string contains special characters, the routine
  96. // will add quotes and other escape characters wherever necessary.
  97. //
  98. // BACKGROUND INFORMATION
  99. // From the CryptoAPI SDK
  100. // Quote the RDN value if it contains leading or trailing
  101. // white space or one of the following characters:
  102. // ",", "+", "=", """, "\n", "<", ">", "#" or ";".
  103. // The quoting character is ". If the RDN Value contains a " it is double quoted ("").
  104. //
  105. void strUiToSim(
  106. LPCTSTR pszUI, // IN:
  107. CString * pstrSIM) // OUT:
  108. {
  109. ASSERT(pszUI != NULL);
  110. ASSERT(pstrSIM != NULL);
  111. //
  112. // String containing special characters
  113. //
  114. static const TCHAR szSpecialCharacters[] = _T(",+=<>#;\"\n");
  115. //
  116. // Skip the leading spaces
  117. //
  118. while (*pszUI == _T(' '))
  119. {
  120. pszUI++;
  121. }
  122. const TCHAR * pszDataString = pszUI;
  123. //
  124. // Find out wherever the string needs to be surrounded by quotes
  125. //
  126. const TCHAR * pchFirstSpecialToken = wcspbrk(pszUI, szSpecialCharacters);
  127. if (pchFirstSpecialToken != NULL && *pchFirstSpecialToken == '=')
  128. {
  129. pszDataString = pchFirstSpecialToken;
  130. pchFirstSpecialToken = wcspbrk(pchFirstSpecialToken + 1, szSpecialCharacters);
  131. }
  132. BOOL fNeedQuotes = (pchFirstSpecialToken != NULL) ||
  133. (pszDataString[0] == _T(' ')) ||
  134. (pszDataString[lstrlen(pszDataString)] == _T(' '));
  135. if (!fNeedQuotes)
  136. {
  137. *pstrSIM = pszUI;
  138. return;
  139. }
  140. pstrSIM->Empty();
  141. const TCHAR * pchSrc = pszUI;
  142. ASSERT(pszDataString != NULL);
  143. if (*pszDataString == '=')
  144. {
  145. // Copy string until the equal '=' sign
  146. ASSERT(pszDataString >= pchSrc);
  147. for (int cch = (int)((pszDataString - pchSrc) + 1); cch > 0; cch--)
  148. {
  149. ASSERT(*pchSrc != '\0' && "Unexpected end of string");
  150. *pstrSIM += *pchSrc++;
  151. }
  152. } // if
  153. // Add the openning quote
  154. *pstrSIM += '"';
  155. for ( ; *pchSrc != '\0'; pchSrc++)
  156. {
  157. if (*pchSrc == '"')
  158. *pstrSIM += '"'; // Add one more quote for each quote
  159. *pstrSIM += *pchSrc;
  160. } // while
  161. // Add the tailing quote
  162. *pstrSIM += '"';
  163. } // strUiToSim()
  164. // Macro to make pointer 'DWORD aligned'
  165. #define ALIGN_NEXT_DWORD_PTR(pv) (( ((INT_PTR)(pv)) + 3) & ~3)
  166. /////////////////////////////////////////////////////////////////////
  167. // ParseSimString()
  168. //
  169. // Parse a SIM string into an array of zero-terminated string.
  170. //
  171. // RETURN
  172. // Return a pointer to an allocated array of pointers to strings.
  173. // The array of pointers allocated with the new() operator,
  174. // therefore the caller must call ONCE delete() to free the memory.
  175. // The routine may return NULL if the input string has a syntax error.
  176. //
  177. // INTERFACE NOTES
  178. // The format returned is the same as the API CommandLineToArgvW()
  179. // which is the same as main(int argc, char * argv[]).
  180. // - This routine will handle special characters such as quotes and
  181. // commas that are embedded into strings.
  182. //
  183. // EXTRA INFO
  184. // See strSimToUi() and strUiToSim().
  185. //
  186. // EXAMPLE
  187. // LPTSTR * pargzpsz; // Pointer to allocated array of pointer to strings
  188. // pargzpsz = ParseSimString("X509:<I>L=Internet<S>C=US, O=Microsoft, OU=DBSD, CN=Bob Bitter");
  189. // ... The output will be
  190. // "X509:"
  191. // "<I>"
  192. // "L=Internet"
  193. // "<S>"
  194. // "C=US"
  195. // "O=Microsoft"
  196. // "OU=DBSD"
  197. // "CN=Bob Bitter"
  198. // delete pargzpsz;
  199. //
  200. LPTSTR *
  201. ParseSimString(
  202. LPCTSTR szSimString, // IN: String to parse
  203. int * pArgc) // OUT: OPTIONAL: Argument count
  204. {
  205. ASSERT(szSimString != NULL);
  206. Endorse(pArgc == NULL);
  207. // Compute how much memory is needed for allocation.
  208. // The computation may allocate more memory than necessary depending
  209. // on the input string.
  210. CONST TCHAR * pchSrc;
  211. int cch = 0;
  212. int cStringCount = 2; // Estimate of the number of strings
  213. for (pchSrc = szSimString; *pchSrc != _T('\0'); pchSrc++, cch++)
  214. {
  215. // Search for any character that will make a new string
  216. switch (*pchSrc)
  217. {
  218. case _T(':'): // Colon
  219. case _T('<'): // Angle bracket
  220. case _T('>'): // Angle bracket
  221. case _T(','): // Comma
  222. cStringCount++;
  223. break;
  224. } // switch
  225. } // for
  226. // Extra space for pointers and DWORD alignment
  227. cch += cStringCount * (2 * sizeof(TCHAR *)) + 16;
  228. // Allocate a single block of memory for all the data
  229. LPTSTR * pargzpsz = (LPTSTR *)new TCHAR[cch];
  230. ASSERT(pargzpsz != NULL && "new() should throw");
  231. TCHAR * pchDst = (TCHAR *)&pargzpsz[cStringCount+1];
  232. #ifdef DEBUG
  233. DebugCode( int cStringCountT = cStringCount; )
  234. #endif
  235. pargzpsz[0] = pchDst;
  236. pchSrc = szSimString;
  237. cStringCount = 0;
  238. int cchString = 0;
  239. // Scan the rest of the string
  240. TCHAR chSpecial = 0;
  241. while (TRUE)
  242. {
  243. // Make a new string
  244. *pchDst = '\0';
  245. if (cchString > 0)
  246. {
  247. pchDst++;
  248. pchDst = (TCHAR *)ALIGN_NEXT_DWORD_PTR(pchDst);
  249. pargzpsz[++cStringCount] = pchDst;
  250. cchString = 0;
  251. }
  252. *pchDst = '\0';
  253. if (chSpecial)
  254. {
  255. switch (chSpecial)
  256. {
  257. case _T('<'):
  258. for ( ; ; pchSrc++)
  259. {
  260. if (*pchSrc == '\0')
  261. goto Error; // Unexpected end of string
  262. *pchDst++ = *pchSrc;
  263. cchString++;
  264. if (*pchSrc == _T('>'))
  265. {
  266. pchSrc++;
  267. break;
  268. }
  269. } // for
  270. break;
  271. case _T(','):
  272. while (*++pchSrc == _T(' '))
  273. ; // Skip the blanks
  274. break; // Make a new string
  275. } // switch
  276. chSpecial = 0;
  277. continue;
  278. } // if
  279. while (chSpecial == '\0')
  280. {
  281. switch (*pchSrc)
  282. {
  283. case _T('\0'):
  284. goto Done;
  285. case _T('<'):
  286. case _T(','):
  287. chSpecial = *pchSrc;
  288. break;
  289. case _T(':'):
  290. *pchDst++ = *pchSrc++;
  291. cchString++;
  292. if (cStringCount == 0)
  293. chSpecial = _T(':');
  294. break;
  295. case _T('"'): // The string contains quotes
  296. cchString++;
  297. *pchDst++ = *pchSrc++; // Copy the first quiote
  298. if (*pchDst == _T('"'))
  299. {
  300. // Two consecutive quotes
  301. *pchDst++ = *pchSrc++;
  302. break;
  303. }
  304. // Skip until the next quote
  305. while (TRUE)
  306. {
  307. if (*pchSrc == _T('\0'))
  308. goto Error; // Unexpected end of string
  309. if (*pchSrc == _T('"'))
  310. {
  311. *pchDst++ = *pchSrc++;
  312. break;
  313. }
  314. *pchDst++ = *pchSrc++;
  315. }
  316. break;
  317. default:
  318. *pchDst++ = *pchSrc++;
  319. cchString++;
  320. } // switch
  321. } // while
  322. } // while
  323. Done:
  324. *pchDst = '\0';
  325. if (cchString > 0)
  326. cStringCount++;
  327. #ifdef DEBUG
  328. ASSERT(cStringCount <= cStringCountT);
  329. #endif
  330. pargzpsz[cStringCount] = NULL;
  331. if (pArgc != NULL)
  332. *pArgc = cStringCount;
  333. return pargzpsz;
  334. Error:
  335. TRACE1("ParseSimString() - Error parsing string %s.\n", szSimString);
  336. delete pargzpsz;
  337. return NULL;
  338. } // ParseSimString()
  339. /////////////////////////////////////////////////////////////////////
  340. // UnparseSimString()
  341. //
  342. // This is the opposite of ParseSimString(). This routine
  343. // will concacenate an array of strings to produce
  344. // a single long SIM string.
  345. //
  346. // INTERFACE NOTES
  347. // This toutine will concatenate the array of strings to the
  348. // existing CString object.
  349. //
  350. void
  351. UnparseSimString(
  352. CString * pstrOut, // INOUT: Pointer to concatenated string
  353. const LPCTSTR rgzpsz[]) // IN: Array of pointer to strings
  354. {
  355. ASSERT(rgzpsz != NULL);
  356. ASSERT(pstrOut != NULL);
  357. for (int i = 0; rgzpsz[i] != NULL; i++)
  358. {
  359. if (i > 0)
  360. *pstrOut += ",";
  361. *pstrOut += rgzpsz[i];
  362. } // for
  363. } // UnparseSimString()
  364. /////////////////////////////////////////////////////////////////////
  365. // ParseSimSeparators()
  366. //
  367. // Break up an array of pointer to string to sub-array
  368. // of pointer to string for Issuer, Subject and AltSubject.
  369. //
  370. // INTERFACE NOTES
  371. // The output parameters must have enough storage to hold
  372. // the substrings.
  373. //
  374. void
  375. ParseSimSeparators(
  376. const LPCTSTR rgzpszIn[], // IN: Array of pointer to string
  377. LPCTSTR rgzpszIssuer[], // OUT: Substrings for Issuer
  378. LPCTSTR rgzpszSubject[], // OUT: Substrings for Subject
  379. LPCTSTR rgzpszAltSubject[]) // OUT: Substrings for AltSubject
  380. {
  381. ASSERT(rgzpszIn != NULL);
  382. Endorse(rgzpszIssuer == NULL);
  383. Endorse(rgzpszSubject == NULL);
  384. Endorse(rgzpszAltSubject == NULL);
  385. if (rgzpszIssuer != NULL)
  386. {
  387. // Get the substrings for Issuer
  388. (void)FindSimAttributes(szSimIssuer, IN rgzpszIn, OUT rgzpszIssuer);
  389. }
  390. if (rgzpszSubject != NULL)
  391. {
  392. // Get the substrings for Subject
  393. (void)FindSimAttributes(szSimSubject, IN rgzpszIn, OUT rgzpszSubject);
  394. }
  395. if (rgzpszAltSubject != NULL)
  396. {
  397. // Get the substrings for AltSubject
  398. (void)FindSimAttributes(szSimAltSubject, IN rgzpszIn, OUT rgzpszAltSubject);
  399. }
  400. } // ParseSimSeparators()
  401. /////////////////////////////////////////////////////////////////////
  402. // UnparseSimSeparators()
  403. //
  404. // Append the strings for Issuer, Subject and AltSubject into
  405. // a single string.
  406. //
  407. // INTERFACE NOTES
  408. // The routine will append to the existing CString object.
  409. //
  410. int
  411. UnparseSimSeparators(
  412. CString * pstrOut, // INOUT: Pointer to contatenated string
  413. const LPCTSTR rgzpszIssuer[],
  414. const LPCTSTR rgzpszSubject[],
  415. const LPCTSTR rgzpszAltSubject[])
  416. {
  417. ASSERT(pstrOut != NULL);
  418. int cSeparators = 0; // Number of separators added to the contatenated string
  419. if (rgzpszIssuer != NULL && rgzpszIssuer[0] != NULL)
  420. {
  421. cSeparators++;
  422. *pstrOut += szSimIssuer;
  423. UnparseSimString(OUT pstrOut, rgzpszIssuer);
  424. }
  425. if (rgzpszSubject != NULL && rgzpszSubject[0] != NULL)
  426. {
  427. cSeparators++;
  428. *pstrOut += szSimSubject;
  429. UnparseSimString(OUT pstrOut, rgzpszSubject);
  430. }
  431. if (rgzpszAltSubject != NULL && rgzpszAltSubject[0] != NULL)
  432. {
  433. cSeparators++;
  434. *pstrOut += szSimAltSubject;
  435. UnparseSimString(OUT pstrOut, rgzpszAltSubject);
  436. }
  437. return cSeparators;
  438. } // UnparseSimSeparators()
  439. /////////////////////////////////////////////////////////////////////
  440. // PchFindSimAttribute()
  441. //
  442. // Search an array of strings for a given tag and an attribute.
  443. //
  444. // Return pointer to string containing the attribute. Routine
  445. // may return NULL if attribute is not found within the tags.
  446. //
  447. // INTERFACE NOTES
  448. // The routine assumes that all tags start with an openning bracket '<'.
  449. //
  450. // EXAMPLE
  451. // LPCTSTR pszIssuer = PchFindSimAttribute(pargzpsz, "<I>", "OU=");
  452. //
  453. LPCTSTR PchFindSimAttribute(
  454. const LPCTSTR rgzpsz[], // IN: Array of pointer to strings
  455. LPCTSTR pszSeparatorTag, // IN: Tag to search. eg: "<I>", "<S>" and "<AS>"
  456. LPCTSTR pszAttributeTag) // IN: Attribute to searc for. eg: "CN=", "OU="
  457. {
  458. ASSERT(rgzpsz != NULL);
  459. ASSERT(pszSeparatorTag != NULL);
  460. ASSERT(pszAttributeTag != NULL);
  461. size_t nLenAttrTag = wcslen (pszAttributeTag);
  462. for (int i = 0; rgzpsz[i] != NULL; i++)
  463. {
  464. if (_wcsicmp(pszSeparatorTag, rgzpsz[i]) != 0)
  465. continue;
  466. for (++i; ; i++)
  467. {
  468. if (rgzpsz[i] == NULL)
  469. return NULL;
  470. if (rgzpsz[i][0] == _T('<'))
  471. {
  472. // We have found another separator tag
  473. break;
  474. }
  475. if (_wcsnicmp(pszAttributeTag, rgzpsz[i], nLenAttrTag) == 0)
  476. {
  477. return rgzpsz[i];
  478. }
  479. } // for
  480. } // for
  481. return NULL;
  482. } // PchFindSimAttribute()
  483. /////////////////////////////////////////////////////////////////////
  484. // FindSimAttributes()
  485. //
  486. // Search an array of strings for a given tag. Fill an array of
  487. // strings that belongs to the tag.
  488. //
  489. // Return number of strings belonging to the tab (which is
  490. // the length of rgzpszOut).
  491. //
  492. // INTERFACE NOTES
  493. // This routine assumes parameter rgzpszOut has enough storage
  494. // to hold all the strings for the tag. It is recommended to make
  495. // rgzpszOut the same length as rgzpszIn (for safety).
  496. // - The output array does not include the tag.
  497. //
  498. int FindSimAttributes(
  499. LPCTSTR pszSeparatorTag, // IN: Tag to search. eg: "<I>", "<S>" and "<AS>"
  500. const LPCTSTR rgzpszIn[], // IN: Array of pointer to strings
  501. LPCTSTR rgzpszOut[]) // OUT: Output array of pointer to strings for tag
  502. {
  503. ASSERT(pszSeparatorTag != NULL);
  504. ASSERT(rgzpszIn != NULL);
  505. ASSERT(rgzpszOut != NULL);
  506. BOOL fTagFound = FALSE;
  507. int iOut = 0; // Index for the output array
  508. for (int iIn = 0; rgzpszIn[iIn] != NULL; iIn++)
  509. {
  510. const LPCTSTR pszT = rgzpszIn[iIn];
  511. if (pszT[0] == '<')
  512. {
  513. fTagFound = (_wcsicmp(pszSeparatorTag, pszT) == 0) ? TRUE : FALSE;
  514. }
  515. else if (fTagFound)
  516. {
  517. rgzpszOut[iOut++] = pszT;
  518. }
  519. } // for
  520. rgzpszOut[iOut] = NULL;
  521. return iOut;
  522. } // FindSimAttributes()
  523. /////////////////////////////////////////////////////////////////////
  524. // SplitX509String()
  525. //
  526. // Split a X509 string into its Issuer, Subject and AltSubject.
  527. //
  528. // Return a pointer to an allocated array of pointers to strings allocated
  529. // by ParseSimString().
  530. //
  531. // INTERFACE NOTES
  532. // As the hungarian name implies, the output parameters
  533. // are pointers to allcated arrays of substrings for the
  534. // Issuer, Subject and AltSubject respectively.
  535. // - The caller is responsible of freeing the memory for
  536. // both the return value and all the output parameters.
  537. //
  538. //
  539. LPTSTR *
  540. SplitX509String(
  541. LPCTSTR pszX509, // IN: String to split
  542. LPCTSTR * ppargzpszIssuer[], // OUT: Pointer to allocated array of Substrings for Issuer
  543. LPCTSTR * ppargzpszSubject[], // OUT: Pointer to allocated array of Substrings for Subject
  544. LPCTSTR * ppargzpszAltSubject[]) // OUT: Pointer to allocated array of Substrings for AltSubject
  545. {
  546. ASSERT(pszX509 != NULL);
  547. Endorse(ppargzpszIssuer == NULL);
  548. Endorse(ppargzpszSubject == NULL);
  549. Endorse(ppargzpszAltSubject == NULL);
  550. LPTSTR * pargzpsz; // Pointer to allocated array of pointer to strings
  551. int cNumStr; // Number of strings
  552. pargzpsz = ParseSimString(IN pszX509, OUT &cNumStr);
  553. if (pargzpsz == NULL)
  554. {
  555. TRACE1("SplitX509String() - Error parsing string %s.\n", pszX509);
  556. return NULL;
  557. }
  558. ASSERT(cNumStr > 0);
  559. if (ppargzpszIssuer != NULL)
  560. {
  561. *ppargzpszIssuer = new LPCTSTR[cNumStr];
  562. // Get the substrings for Issuer
  563. (void)FindSimAttributes(szSimIssuer, IN pargzpsz, OUT *ppargzpszIssuer);
  564. }
  565. if (ppargzpszSubject != NULL)
  566. {
  567. *ppargzpszSubject = new LPCTSTR[cNumStr];
  568. // Get the substrings for Subject
  569. (void)FindSimAttributes(szSimSubject, IN pargzpsz, OUT *ppargzpszSubject);
  570. }
  571. if (ppargzpszAltSubject != NULL)
  572. {
  573. *ppargzpszAltSubject = new LPCTSTR[cNumStr];
  574. // Get the substrings for AltSubject
  575. (void)FindSimAttributes(szSimAltSubject, IN pargzpsz, OUT *ppargzpszAltSubject);
  576. }
  577. return pargzpsz;
  578. } // SplitX509String()
  579. /////////////////////////////////////////////////////////////////////
  580. int
  581. UnsplitX509String(
  582. CString * pstrX509, // OUT: Concatenated string
  583. const LPCTSTR rgzpszIssuer[], // IN:
  584. const LPCTSTR rgzpszSubject[], // IN:
  585. const LPCTSTR rgzpszAltSubject[]) // IN:
  586. {
  587. ASSERT(pstrX509 != NULL);
  588. *pstrX509 = szX509;
  589. return UnparseSimSeparators(
  590. INOUT pstrX509,
  591. IN rgzpszIssuer,
  592. IN rgzpszSubject,
  593. IN rgzpszAltSubject);
  594. } // UnsplitX509String()