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.

658 lines
20 KiB

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