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.

1617 lines
54 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997-2002.
  5. //
  6. // File: CertTmpl.cpp
  7. //
  8. // Contents: Implementation of DLL Exports
  9. //
  10. //----------------------------------------------------------------------------
  11. #include "stdafx.h"
  12. #define INITGUID
  13. #pragma warning(push,3)
  14. #include <initguid.h>
  15. #pragma warning(pop)
  16. #include "CertTmpl_i.c"
  17. #include "about.h" // CCertTemplatesAbout
  18. #include "compdata.h" // CCertTmplSnapin
  19. #include "uuids.h"
  20. #pragma warning(push,3)
  21. #include <ntverp.h> // VER_PRODUCTVERSION_STR
  22. #include <typeinfo.h>
  23. #define INCL_WINSOCK_API_TYPEDEFS 1
  24. #include <winsock2.h>
  25. #include <svcguid.h>
  26. #include <winldap.h>
  27. #pragma warning(pop)
  28. #include "chooser.cpp"
  29. #include "ShellExt.h"
  30. #include "PolicyOID.h"
  31. extern POLICY_OID_LIST g_policyOIDList;
  32. USE_HANDLE_MACROS ("CERTTMPL (CertTmpl.cpp)")
  33. //
  34. // This is used by the nodetype utility routines in stdutils.cpp
  35. //
  36. const struct NODETYPE_GUID_ARRAYSTRUCT g_NodetypeGuids[CERTTMPL_NUMTYPES] =
  37. {
  38. { // CERTTMPL_SNAPIN
  39. structuuidNodetypeSnapin,
  40. lstruuidNodetypeSnapin },
  41. { // CERT_TEMPLATE
  42. structuuidNodetypeCertTemplate,
  43. lstruuidNodetypeCertTemplate }
  44. };
  45. const struct NODETYPE_GUID_ARRAYSTRUCT* g_aNodetypeGuids = g_NodetypeGuids;
  46. const int g_cNumNodetypeGuids = CERTTMPL_NUMTYPES;
  47. const CLSID CLSID_CertTemplateShellExt = /* {11BDCE06-D55C-44e9-BC0B-8655F89E8CC5} */
  48. { 0x11bdce06, 0xd55c, 0x44e9, { 0xbc, 0xb, 0x86, 0x55, 0xf8, 0x9e, 0x8c, 0xc5 } };
  49. HINSTANCE g_hInstance = 0;
  50. CComModule _Module;
  51. BEGIN_OBJECT_MAP (ObjectMap)
  52. OBJECT_ENTRY (CLSID_CertTemplatesSnapin, CCertTmplSnapin)
  53. OBJECT_ENTRY (CLSID_CertTemplatesAbout, CCertTemplatesAbout)
  54. OBJECT_ENTRY(CLSID_CertTemplateShellExt, CCertTemplateShellExt)
  55. END_OBJECT_MAP ()
  56. class CCertTmplApp : public CWinApp
  57. {
  58. public:
  59. CCertTmplApp ();
  60. virtual ~CCertTmplApp ();
  61. virtual BOOL InitInstance ();
  62. virtual int ExitInstance ();
  63. private:
  64. };
  65. CCertTmplApp theApp;
  66. CCertTmplApp::CCertTmplApp ()
  67. {
  68. }
  69. CCertTmplApp::~CCertTmplApp ()
  70. {
  71. }
  72. BOOL CCertTmplApp::InitInstance ()
  73. {
  74. #ifdef _MERGE_PROXYSTUB
  75. hProxyDll = m_hInstance;
  76. #endif
  77. g_hInstance = m_hInstance;
  78. AfxSetResourceHandle (m_hInstance);
  79. _Module.Init (ObjectMap, m_hInstance);
  80. AfxInitRichEdit();
  81. #if DBG
  82. CheckDebugOutputLevel ();
  83. #endif
  84. SHFusionInitializeFromModuleID (m_hInstance, 2);
  85. return CWinApp::InitInstance ();
  86. }
  87. int CCertTmplApp::ExitInstance ()
  88. {
  89. SHFusionUninitialize();
  90. while ( !g_policyOIDList.IsEmpty () )
  91. {
  92. CPolicyOID* pPolicyOID = g_policyOIDList.RemoveHead ();
  93. if ( pPolicyOID )
  94. delete pPolicyOID;
  95. }
  96. _Module.Term ();
  97. return CWinApp::ExitInstance ();
  98. }
  99. /////////////////////////////////////////////////////////////////////////////
  100. // Used to determine whether the DLL can be unloaded by OLE
  101. STDAPI DllCanUnloadNow (void)
  102. {
  103. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  104. return (AfxDllCanUnloadNow ()==S_OK && _Module.GetLockCount ()==0) ? S_OK : S_FALSE;
  105. }
  106. /////////////////////////////////////////////////////////////////////////////
  107. // Returns a class factory to create an object of the requested type
  108. STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, LPVOID* ppv)
  109. {
  110. return _Module.GetClassObject (rclsid, riid, ppv);
  111. }
  112. /////////////////////////////////////////////////////////////////////////////
  113. // DllRegisterServer - Adds entries to the system registry
  114. STDAPI DllRegisterServer (void)
  115. {
  116. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  117. // registers object, typelib and all interfaces in typelib
  118. HRESULT hr = _Module.RegisterServer (TRUE);
  119. ASSERT (SUCCEEDED (hr));
  120. if ( E_ACCESSDENIED == hr )
  121. {
  122. CString caption;
  123. CString text;
  124. CThemeContextActivator activator;
  125. VERIFY (caption.LoadString (IDS_REGISTER_CERTTMPL));
  126. VERIFY (text.LoadString (IDS_INSUFFICIENT_RIGHTS_TO_REGISTER_CERTTMPL));
  127. MessageBox (NULL, text, caption, MB_OK);
  128. return hr;
  129. }
  130. try
  131. {
  132. CString strGUID;
  133. CString snapinName;
  134. AMC::CRegKey rkSnapins;
  135. BOOL fFound = rkSnapins.OpenKeyEx (HKEY_LOCAL_MACHINE, SNAPINS_KEY);
  136. ASSERT (fFound);
  137. if ( fFound )
  138. {
  139. {
  140. AMC::CRegKey rkCertTmplSnapin;
  141. hr = GuidToCString (&strGUID, CLSID_CertTemplatesSnapin);
  142. if ( FAILED (hr) )
  143. {
  144. ASSERT (FALSE);
  145. return SELFREG_E_CLASS;
  146. }
  147. rkCertTmplSnapin.CreateKeyEx (rkSnapins, strGUID);
  148. ASSERT (rkCertTmplSnapin.GetLastError () == ERROR_SUCCESS);
  149. rkCertTmplSnapin.SetString (g_szNodeType, g_aNodetypeGuids[CERTTMPL_SNAPIN].bstr);
  150. VERIFY (snapinName.LoadString (IDS_CERTTMPL_REGISTRY));
  151. rkCertTmplSnapin.SetString (g_szNameString, (PCWSTR) snapinName);
  152. hr = GuidToCString (&strGUID, CLSID_CertTemplatesAbout);
  153. if ( FAILED (hr) )
  154. {
  155. ASSERT (FALSE);
  156. return SELFREG_E_CLASS;
  157. }
  158. rkCertTmplSnapin.SetString (L"About", strGUID);
  159. rkCertTmplSnapin.SetString (L"Provider", L"Microsoft");
  160. // security review 2/20/2002 BryanWal ok
  161. size_t len = strlen (VER_PRODUCTVERSION_STR);
  162. PWSTR pszVer = new WCHAR[len+1];
  163. if ( pszVer )
  164. {
  165. // security review BryanWal 02/20/2002 ok
  166. ::ZeroMemory (pszVer, (len+1) * sizeof (WCHAR));
  167. // security review BryanWal 02/20/2002 cnt should be len+1
  168. // to include conversion of NULL char
  169. len = ::mbstowcs (pszVer, VER_PRODUCTVERSION_STR, len+1);
  170. rkCertTmplSnapin.SetString (L"Version", pszVer);
  171. delete [] pszVer;
  172. }
  173. AMC::CRegKey rkCertTmplMgrStandalone;
  174. rkCertTmplMgrStandalone.CreateKeyEx (rkCertTmplSnapin, g_szStandAlone);
  175. ASSERT (rkCertTmplMgrStandalone.GetLastError () == ERROR_SUCCESS);
  176. AMC::CRegKey rkMyNodeTypes;
  177. rkMyNodeTypes.CreateKeyEx (rkCertTmplSnapin, g_szNodeTypes);
  178. ASSERT (rkMyNodeTypes.GetLastError () == ERROR_SUCCESS);
  179. AMC::CRegKey rkMyNodeType;
  180. for (int i = CERTTMPL_SNAPIN; i < CERTTMPL_NUMTYPES; i++)
  181. {
  182. rkMyNodeType.CreateKeyEx (rkMyNodeTypes, g_aNodetypeGuids[i].bstr);
  183. ASSERT (rkMyNodeType.GetLastError () == ERROR_SUCCESS);
  184. rkMyNodeType.CloseKey ();
  185. }
  186. //
  187. // BryanWal 5/18/00
  188. // 94793: MUI: MMC: Certificates snap-in stores its display
  189. // information in the registry
  190. //
  191. // MMC now supports NameStringIndirect
  192. //
  193. // NTRAID# Bug9 611500 prefast: certtmpl: certtmpl.cpp(247) :
  194. // warning 53: Call to 'GetModuleFileNameW' may not
  195. // zero-terminate string 'achModuleFileName'.
  196. // Fix by zero'ing out the buffer and passing in 1 less than
  197. // the buffer size to GetModuleFileName
  198. WCHAR achModuleFileName[MAX_PATH+20];
  199. ::ZeroMemory (achModuleFileName, sizeof(achModuleFileName)/sizeof(WCHAR));
  200. if (0 != ::GetModuleFileName(
  201. AfxGetInstanceHandle(),
  202. achModuleFileName,
  203. sizeof(achModuleFileName)/sizeof(WCHAR) - 1))
  204. {
  205. CString strNameIndirect;
  206. strNameIndirect.Format (L"@%s,-%d",
  207. achModuleFileName,
  208. IDS_CERTTMPL_REGISTRY);
  209. rkCertTmplSnapin.SetString (L"NameStringIndirect",
  210. strNameIndirect );
  211. }
  212. rkCertTmplSnapin.CloseKey ();
  213. }
  214. AMC::CRegKey rkNodeTypes;
  215. fFound = rkNodeTypes.OpenKeyEx (HKEY_LOCAL_MACHINE, NODE_TYPES_KEY);
  216. ASSERT (fFound);
  217. if ( fFound )
  218. {
  219. AMC::CRegKey rkNodeType;
  220. for (int i = CERTTMPL_SNAPIN; i < CERTTMPL_NUMTYPES; i++)
  221. {
  222. rkNodeType.CreateKeyEx (rkNodeTypes, g_aNodetypeGuids[i].bstr);
  223. ASSERT (rkNodeType.GetLastError () == ERROR_SUCCESS);
  224. rkNodeType.CloseKey ();
  225. }
  226. rkNodeTypes.CloseKey ();
  227. }
  228. else
  229. return SELFREG_E_CLASS;
  230. }
  231. else
  232. return SELFREG_E_CLASS;
  233. }
  234. catch (COleException* e)
  235. {
  236. ASSERT (FALSE);
  237. e->Delete ();
  238. return SELFREG_E_CLASS;
  239. }
  240. ASSERT (SUCCEEDED (hr));
  241. return hr;
  242. }
  243. /////////////////////////////////////////////////////////////////////////////
  244. // DllUnregisterServer - Removes entries from the system registry
  245. STDAPI DllUnregisterServer (void)
  246. {
  247. LRESULT lResult = 0;
  248. try
  249. {
  250. AMC::CRegKey rkSnapins;
  251. BOOL fFound = FALSE;
  252. do
  253. {
  254. CString strGUID;
  255. CString snapinName;
  256. fFound = rkSnapins.OpenKeyEx (HKEY_LOCAL_MACHINE, SNAPINS_KEY);
  257. ASSERT (fFound);
  258. if ( fFound )
  259. {
  260. {
  261. AMC::CRegKey rkCertTmplSnapin;
  262. HRESULT hr = GuidToCString (&strGUID, CLSID_CertTemplatesSnapin);
  263. if ( FAILED (hr) )
  264. {
  265. ASSERT (FALSE);
  266. lResult = SELFREG_E_CLASS;
  267. break;
  268. }
  269. lResult = RegDelnode (rkSnapins, (PCWSTR) strGUID);
  270. }
  271. AMC::CRegKey rkNodeTypes;
  272. fFound = rkNodeTypes.OpenKeyEx (HKEY_LOCAL_MACHINE, NODE_TYPES_KEY);
  273. ASSERT (fFound);
  274. if ( fFound )
  275. {
  276. for (int i = CERTTMPL_SNAPIN; i < CERTTMPL_NUMTYPES; i++)
  277. {
  278. lResult = RegDelnode (rkNodeTypes, g_aNodetypeGuids[i].bstr);
  279. }
  280. rkNodeTypes.CloseKey ();
  281. }
  282. else
  283. {
  284. lResult = SELFREG_E_CLASS;
  285. break;
  286. }
  287. }
  288. else
  289. {
  290. lResult = SELFREG_E_CLASS;
  291. break;
  292. }
  293. } while (0);
  294. if ( fFound )
  295. rkSnapins.CloseKey ();
  296. }
  297. catch (COleException* e)
  298. {
  299. ASSERT (FALSE);
  300. e->Delete ();
  301. lResult = SELFREG_E_CLASS;
  302. }
  303. if ( SELFREG_E_CLASS != lResult )
  304. _Module.UnregisterServer ();
  305. return HRESULT_FROM_WIN32 (lResult);
  306. }
  307. STDAPI DllInstall(BOOL /*bInstall*/, PCWSTR /*pszCmdLine*/)
  308. {
  309. return S_OK;
  310. }
  311. ///////////////////////////////////////////////////////////////////////////////
  312. // FormatDate ()
  313. //
  314. // utcDateTime (IN) - A FILETIME in UTC format.
  315. // pszDateTime (OUT) - A string containing the local date and time
  316. // formatted by locale and user preference
  317. //
  318. ///////////////////////////////////////////////////////////////////////////////
  319. HRESULT FormatDate (FILETIME utcDateTime, CString & pszDateTime)
  320. {
  321. // Time is returned as UTC, will be displayed as local.
  322. // Use FileTimeToLocalFileTime () to make it local,
  323. // then call FileTimeToSystemTime () to convert to system time, then
  324. // format with GetDateFormat () and GetTimeFormat () to display
  325. // according to user and locale preferences
  326. HRESULT hr = S_OK;
  327. FILETIME localDateTime;
  328. BOOL bResult = FileTimeToLocalFileTime (&utcDateTime, // pointer to UTC file time to convert
  329. &localDateTime); // pointer to converted file time
  330. ASSERT (bResult);
  331. if ( bResult )
  332. {
  333. SYSTEMTIME sysTime;
  334. bResult = FileTimeToSystemTime (
  335. &localDateTime, // pointer to file time to convert
  336. &sysTime); // pointer to structure to receive system time
  337. if ( bResult )
  338. {
  339. CString date;
  340. CString time;
  341. // Get date
  342. // Get length to allocate buffer of sufficient size
  343. int iLen = GetDateFormat (
  344. LOCALE_USER_DEFAULT, // locale for which date is to be formatted
  345. 0, // flags specifying function options
  346. &sysTime, // date to be formatted
  347. 0, // date format string
  348. 0, // buffer for storing formatted string
  349. 0); // size of buffer
  350. ASSERT (iLen > 0);
  351. if ( iLen > 0 )
  352. {
  353. int iResult = GetDateFormat (
  354. LOCALE_USER_DEFAULT, // locale for which date is to be formatted
  355. 0, // flags specifying function options
  356. &sysTime, // date to be formatted
  357. 0, // date format string
  358. date.GetBufferSetLength (iLen), // buffer for storing formatted string
  359. iLen); // size of buffer
  360. ASSERT (iResult);
  361. date.ReleaseBuffer ();
  362. if ( iResult )
  363. pszDateTime = date;
  364. else
  365. hr = HRESULT_FROM_WIN32 (GetLastError ());
  366. if ( iResult )
  367. {
  368. // Get time
  369. // Get length to allocate buffer of sufficient size
  370. iLen = GetTimeFormat (
  371. LOCALE_USER_DEFAULT, // locale for which date is to be formatted
  372. 0, // flags specifying function options
  373. &sysTime, // date to be formatted
  374. 0, // date format string
  375. 0, // buffer for storing formatted string
  376. 0); // size of buffer
  377. ASSERT (iLen > 0);
  378. if ( iLen > 0 )
  379. {
  380. iResult = GetTimeFormat (
  381. LOCALE_USER_DEFAULT, // locale for which date is to be formatted
  382. 0, // flags specifying function options
  383. &sysTime, // date to be formatted
  384. 0, // date format string
  385. time.GetBufferSetLength (iLen), // buffer for storing formatted string
  386. iLen); // size of buffer
  387. ASSERT (iResult);
  388. time.ReleaseBuffer ();
  389. if ( iResult )
  390. {
  391. pszDateTime = date + L" " + time;
  392. }
  393. else
  394. hr = E_UNEXPECTED;
  395. }
  396. else
  397. hr = E_UNEXPECTED;
  398. }
  399. else
  400. hr = E_UNEXPECTED;
  401. }
  402. else
  403. {
  404. hr = HRESULT_FROM_WIN32 (GetLastError ());
  405. }
  406. }
  407. else
  408. {
  409. hr = HRESULT_FROM_WIN32 (GetLastError ());
  410. }
  411. }
  412. else
  413. {
  414. hr = HRESULT_FROM_WIN32 (GetLastError ());
  415. }
  416. return hr;
  417. }
  418. void DisplaySystemError (HWND hParent, DWORD dwErr)
  419. {
  420. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  421. LPVOID lpMsgBuf;
  422. // security review BryanWal 2/20/2002 ok because message is from system
  423. FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  424. NULL,
  425. dwErr,
  426. MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  427. (PWSTR) &lpMsgBuf, 0, NULL);
  428. // Display the string.
  429. CThemeContextActivator activator;
  430. CString caption;
  431. VERIFY (caption.LoadString (IDS_CERTTMPL));
  432. ::MessageBox (hParent, (PWSTR) lpMsgBuf, (PCWSTR) caption, MB_OK);
  433. // Free the buffer.
  434. LocalFree (lpMsgBuf);
  435. }
  436. bool IsWindowsNT()
  437. {
  438. OSVERSIONINFO versionInfo;
  439. // security review BryanWal 2/20/2002 ok
  440. ::ZeroMemory (&versionInfo, sizeof (versionInfo));
  441. versionInfo.dwOSVersionInfoSize = sizeof (versionInfo);
  442. BOOL bResult = ::GetVersionEx (&versionInfo);
  443. ASSERT (bResult);
  444. if ( bResult )
  445. {
  446. if ( VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId )
  447. bResult = TRUE;
  448. }
  449. return bResult ? true : false;
  450. }
  451. ////// This stuff was stolen from windows\gina\snapins\gpedit (eric flo's stuff) //////
  452. //*************************************************************
  453. //
  454. // RegDelnodeRecurse()
  455. //
  456. // Purpose: Deletes a registry key and all it's subkeys / values.
  457. // Called by RegDelnode
  458. //
  459. // Parameters: hKeyRoot - Root key
  460. // pwszSubKey - SubKey to delete
  461. //
  462. // Return: ERROR_SUCCESS if successful
  463. // something else if an error occurs
  464. //
  465. // Comments:
  466. //
  467. // History: Date Author Comment
  468. // 10/3/95 ericflo Created
  469. // 5/13/98 BryanWal Modified to return LRESULT
  470. //
  471. //*************************************************************
  472. LRESULT RegDelnodeRecurse (HKEY hKeyRoot, CString szSubKey)
  473. {
  474. ASSERT (hKeyRoot && !szSubKey.IsEmpty ());
  475. if ( !hKeyRoot || szSubKey.IsEmpty () )
  476. return ERROR_INVALID_PARAMETER;
  477. //
  478. // First, see if we can delete the key without having
  479. // to recurse.
  480. //
  481. LONG lResult = ::RegDeleteKey(hKeyRoot, szSubKey);
  482. if (lResult == ERROR_SUCCESS)
  483. {
  484. return lResult;
  485. }
  486. HKEY hKey = 0;
  487. lResult = ::RegOpenKeyEx (hKeyRoot, szSubKey, 0, KEY_READ, &hKey);
  488. if (lResult == ERROR_SUCCESS)
  489. {
  490. // ensure szSubKey ends with a slash
  491. if ( L'\\' != szSubKey.GetAt (szSubKey.GetLength () - 1) )
  492. {
  493. szSubKey += L"\\";
  494. }
  495. //
  496. // Enumerate the keys
  497. //
  498. DWORD dwSize = MAX_PATH;
  499. FILETIME ftWrite;
  500. WCHAR szName[MAX_PATH];
  501. lResult = ::RegEnumKeyEx(hKey, 0,
  502. szName,
  503. &dwSize, // size in TCHARS of szName, including terminating NULL (on input)
  504. NULL,
  505. NULL, NULL, &ftWrite);
  506. if (lResult == ERROR_SUCCESS)
  507. {
  508. do {
  509. if ( ERROR_SUCCESS != RegDelnodeRecurse (hKeyRoot, szSubKey + szName) )
  510. {
  511. break;
  512. }
  513. //
  514. // Enumerate again
  515. //
  516. dwSize = MAX_PATH;
  517. lResult = ::RegEnumKeyEx(hKey, 0,
  518. szName,
  519. &dwSize, // size in TCHARS of szName, including terminating NULL (on input)
  520. NULL,
  521. NULL, NULL, &ftWrite);
  522. } while (lResult == ERROR_SUCCESS);
  523. }
  524. ::RegCloseKey (hKey);
  525. }
  526. // remove slash from szSubKey
  527. szSubKey.Delete (szSubKey.GetLength () - 1, 1);
  528. //
  529. // Try again to delete the key
  530. //
  531. lResult = ::RegDeleteKey(hKeyRoot, szSubKey);
  532. if (lResult == ERROR_SUCCESS)
  533. {
  534. return lResult;
  535. }
  536. return lResult;
  537. }
  538. //*************************************************************
  539. //
  540. // RegDelnode()
  541. //
  542. // Purpose: Deletes a registry key and all it's subkeys / values
  543. //
  544. // Parameters: hKeyRoot - Root key
  545. // pwszSubKey - SubKey to delete
  546. //
  547. // Return: ERROR_SUCCESS if successful
  548. // something else if an error occurs
  549. //
  550. // Comments:
  551. //
  552. // History: Date Author Comment
  553. // 10/3/95 ericflo Created
  554. // 5/13/98 BryanWal Modified to return LRESULT
  555. //
  556. //*************************************************************
  557. LRESULT RegDelnode (HKEY hKeyRoot, CString szSubKey)
  558. {
  559. ASSERT (hKeyRoot && !szSubKey.IsEmpty ());
  560. if ( !hKeyRoot || szSubKey.IsEmpty () )
  561. return ERROR_INVALID_PARAMETER;
  562. return RegDelnodeRecurse (hKeyRoot, szSubKey);
  563. }
  564. //+--------------------------------------------------------------------------
  565. //
  566. // Function: InitObjectPickerForDomainComputers
  567. //
  568. // Synopsis: Call IDsObjectPicker::Initialize with arguments that will
  569. // set it to allow the user to pick a single computer object.
  570. //
  571. // Arguments: [pDsObjectPicker] - object picker interface instance
  572. //
  573. // Returns: Result of calling IDsObjectPicker::Initialize.
  574. //
  575. // History: 10-14-1998 DavidMun Created
  576. //
  577. //---------------------------------------------------------------------------
  578. HRESULT InitObjectPickerForDomainComputers(IDsObjectPicker *pDsObjectPicker)
  579. {
  580. //
  581. // Prepare to initialize the object picker.
  582. // Set up the array of scope initializer structures.
  583. //
  584. static const int SCOPE_INIT_COUNT = 1;
  585. DSOP_SCOPE_INIT_INFO aScopeInit[SCOPE_INIT_COUNT];
  586. // security review BryanWal 02/02/2002 ok
  587. ::ZeroMemory(aScopeInit, sizeof(aScopeInit));
  588. //
  589. // Since we just want computer objects from every scope, combine them
  590. // all in a single scope initializer.
  591. //
  592. aScopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
  593. aScopeInit[0].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN
  594. | DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN;
  595. aScopeInit[0].FilterFlags.Uplevel.flBothModes =
  596. DSOP_FILTER_COMPUTERS;
  597. aScopeInit[0].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS;
  598. //
  599. // Put the scope init array into the object picker init array
  600. //
  601. DSOP_INIT_INFO InitInfo;
  602. // security review BryanWal 02/02/2002 ok
  603. ::ZeroMemory(&InitInfo, sizeof(InitInfo));
  604. InitInfo.cbSize = sizeof(InitInfo);
  605. InitInfo.pwzTargetComputer = NULL; // NULL == local machine
  606. InitInfo.cDsScopeInfos = SCOPE_INIT_COUNT;
  607. InitInfo.aDsScopeInfos = aScopeInit;
  608. //
  609. // Note object picker makes its own copy of InitInfo. Also note
  610. // that Initialize may be called multiple times, last call wins.
  611. //
  612. return pDsObjectPicker->Initialize(&InitInfo);
  613. }
  614. CString GetSystemMessage (DWORD dwErr)
  615. {
  616. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  617. CString message;
  618. if ( HRESULT_FROM_WIN32 (ERROR_NO_SUCH_DOMAIN) == dwErr )
  619. {
  620. VERIFY (message.LoadString (IDS_ERROR_NO_SUCH_DOMAIN));
  621. }
  622. else
  623. {
  624. LPVOID lpMsgBuf = 0;
  625. // security review BryanWal 02/02/2002 ok because message is from system
  626. FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  627. NULL,
  628. dwErr,
  629. MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  630. (PWSTR) &lpMsgBuf, 0, NULL );
  631. message = (PWSTR) lpMsgBuf;
  632. // Remove white space (including new line characters)
  633. message.TrimRight ();
  634. // Free the buffer.
  635. LocalFree (lpMsgBuf);
  636. }
  637. return message;
  638. }
  639. //+---------------------------------------------------------------------------
  640. //
  641. // Function: LocaleStrCmp
  642. //
  643. // Synopsis: Do a case insensitive string compare that is safe for any
  644. // locale.
  645. //
  646. // Arguments: [ptsz1] - strings to compare
  647. // [ptsz2]
  648. //
  649. // Returns: -1, 0, or 1 just like lstrcmpi
  650. //
  651. // History: 10-28-96 DavidMun Created
  652. //
  653. // Notes: This is slower than lstrcmpi, but will work when sorting
  654. // strings even in Japanese.
  655. //
  656. //----------------------------------------------------------------------------
  657. int LocaleStrCmp(LPCWSTR ptsz1, LPCWSTR ptsz2)
  658. {
  659. ASSERT (ptsz1 && ptsz2);
  660. if ( !ptsz1 || !ptsz2 )
  661. return 0;
  662. int iRet = 0;
  663. iRet = CompareString(LOCALE_USER_DEFAULT,
  664. NORM_IGNORECASE |
  665. NORM_IGNOREKANATYPE |
  666. NORM_IGNOREWIDTH,
  667. ptsz1,
  668. -1,
  669. ptsz2,
  670. -1);
  671. if (iRet)
  672. {
  673. iRet -= 2; // convert to lstrcmpi-style return -1, 0, or 1
  674. if ( 0 == iRet )
  675. {
  676. UNICODE_STRING unistr1;
  677. UNICODE_STRING unistr2;
  678. // security review 2/20/2002 BryanWal ok - Length is length in BYTES
  679. ::RtlInitUnicodeString (&unistr1, ptsz1);
  680. // security review 2/20/2002 BryanWal ok - Length is length in BYTES
  681. ::RtlInitUnicodeString (&unistr2, ptsz2);
  682. iRet = ::RtlCompareUnicodeString(
  683. &unistr1,
  684. &unistr2,
  685. FALSE );
  686. }
  687. }
  688. else
  689. {
  690. DWORD dwErr = GetLastError ();
  691. _TRACE (0, L"CompareString (%s, %s) failed: 0x%x\n", ptsz1, ptsz2, dwErr);
  692. }
  693. return iRet;
  694. }
  695. void FreeStringArray (PWSTR* rgpszStrings, DWORD dwAddCount)
  696. {
  697. if ( rgpszStrings )
  698. {
  699. for (DWORD dwIndex = 0; dwIndex < dwAddCount; dwIndex++)
  700. {
  701. if ( rgpszStrings[dwIndex] )
  702. CoTaskMemFree (rgpszStrings[dwIndex]);
  703. }
  704. CoTaskMemFree (rgpszStrings);
  705. }
  706. }
  707. HRESULT DisplayRootNodeStatusBarText (LPCONSOLE pConsole)
  708. {
  709. if ( !pConsole )
  710. return E_POINTER;
  711. _TRACE (1, L"Entering DisplayRootNodeStatusBarText\n");
  712. AFX_MANAGE_STATE (AfxGetStaticModuleState ( ));
  713. CComPtr<IConsole2> spConsole2;
  714. HRESULT hr = pConsole->QueryInterface (IID_PPV_ARG (IConsole2, &spConsole2));
  715. if (SUCCEEDED (hr))
  716. {
  717. CString statusText;
  718. VERIFY (statusText.LoadString (IDS_ROOTNODE_STATUSBAR_TEXT));
  719. hr = spConsole2->SetStatusText ((PWSTR)(PCWSTR) statusText);
  720. }
  721. _TRACE (-1, L"Leaving DisplayRootNodeStatusBarText: 0x%x\n", hr);
  722. return hr;
  723. }
  724. HRESULT DisplayObjectCountInStatusBar (LPCONSOLE pConsole, DWORD dwCnt)
  725. {
  726. if ( !pConsole )
  727. return E_POINTER;
  728. _TRACE (1, L"Entering DisplayObjectCountInStatusBar- %d, %s\n",
  729. dwCnt, L"Certificate Templates");
  730. AFX_MANAGE_STATE (AfxGetStaticModuleState ( ));
  731. CComPtr<IConsole2> spConsole2;
  732. HRESULT hr = pConsole->QueryInterface (IID_PPV_ARG (IConsole2, &spConsole2));
  733. if (SUCCEEDED (hr))
  734. {
  735. CString statusText;
  736. UINT formatID = 0;
  737. switch (dwCnt)
  738. {
  739. case -1:
  740. statusText = L"";
  741. break;
  742. case 1:
  743. VERIFY (statusText.LoadString (IDS_CERT_TEMPLATE_COUNT_SINGLE));
  744. break;
  745. default:
  746. formatID = IDS_CERT_TEMPLATE_COUNT;
  747. break;
  748. }
  749. if ( formatID )
  750. {
  751. // security review BryanWal 02/02/2002 ok
  752. statusText.FormatMessage (formatID, dwCnt);
  753. }
  754. hr = spConsole2->SetStatusText ((PWSTR)(PCWSTR) statusText);
  755. }
  756. _TRACE (-1, L"Leaving DisplayObjectCountInStatusBar: 0x%x\n", hr);
  757. return hr;
  758. }
  759. PCWSTR GetContextHelpFile ()
  760. {
  761. static CString strHelpTopic;
  762. if ( strHelpTopic.IsEmpty () )
  763. {
  764. UINT nLen = ::GetSystemWindowsDirectory (strHelpTopic.GetBufferSetLength(2 * MAX_PATH), 2 * MAX_PATH);
  765. strHelpTopic.ReleaseBuffer();
  766. if (0 == nLen)
  767. {
  768. ASSERT(FALSE);
  769. return 0;
  770. }
  771. strHelpTopic += CERTTMPL_HELP_PATH;
  772. strHelpTopic += CERTTMPL_CONTEXT_HELP_FILE;
  773. }
  774. return (PCWSTR) strHelpTopic;
  775. }
  776. bool MyGetOIDInfoA (CString & string, LPCSTR pszObjId)
  777. {
  778. ASSERT (pszObjId);
  779. if ( !pszObjId )
  780. return false;
  781. PCCRYPT_OID_INFO pOIDInfo; // This points to a constant data structure and must not be freed.
  782. bool bResult = false;
  783. // NTRAID# 479067 Certtmpl UI: Title bar and descriptive text incorrect
  784. if ( !strcmp (szOID_CERT_POLICIES, pszObjId) )
  785. {
  786. VERIFY (string.LoadString (IDS_ISSUANCE_POLICIES));
  787. bResult = true;
  788. }
  789. else
  790. {
  791. string = L"";
  792. pOIDInfo = ::CryptFindOIDInfo (CRYPT_OID_INFO_OID_KEY, (void *) pszObjId, 0);
  793. if ( pOIDInfo )
  794. {
  795. string = pOIDInfo->pwszName;
  796. bResult = true;
  797. }
  798. else
  799. {
  800. for (POSITION nextPos = g_policyOIDList.GetHeadPosition (); nextPos; )
  801. {
  802. CPolicyOID* pPolicyOID = g_policyOIDList.GetNext (nextPos);
  803. if ( pPolicyOID )
  804. {
  805. if ( !strcmp (pPolicyOID->GetOIDA (), pszObjId) )
  806. {
  807. string = pPolicyOID->GetDisplayName ();
  808. bResult = true;
  809. break;
  810. }
  811. }
  812. }
  813. if ( !bResult )
  814. {
  815. // security review BryanWal 02/02/2002 ok
  816. int nLen = ::MultiByteToWideChar (CP_ACP, 0, pszObjId, -1, NULL, 0);
  817. ASSERT (nLen > 0);
  818. if ( nLen > 0)
  819. {
  820. // security review BryanWal 02/02/2002 ok
  821. // NOTICE: GetBufferSetLength () takes len not including trailing NULL,
  822. // returns NULL on failure. MultiByteToWideChar () handles NULL arg.
  823. nLen = ::MultiByteToWideChar (CP_ACP, 0, pszObjId, -1,
  824. string.GetBufferSetLength (nLen), nLen);
  825. ASSERT (nLen > 0);
  826. string.ReleaseBuffer ();
  827. }
  828. bResult = (nLen > 0) ? true : false;
  829. }
  830. }
  831. }
  832. return bResult;
  833. }
  834. #define REGSZ_ENABLE_CERTTYPE_EDITING L"EnableCertTypeEditing"
  835. bool IsCerttypeEditingAllowed()
  836. {
  837. DWORD lResult;
  838. HKEY hKey = NULL;
  839. DWORD dwType;
  840. DWORD dwEnabled = 0;
  841. DWORD cbEnabled = sizeof(dwEnabled);
  842. lResult = RegOpenKeyEx (HKEY_CURRENT_USER,
  843. L"Software\\Microsoft\\Cryptography\\CertificateTemplateCache",
  844. 0,
  845. KEY_READ,
  846. &hKey);
  847. if (lResult == ERROR_SUCCESS)
  848. {
  849. // security review BryanWal 02/02/2002 ok
  850. lResult = RegQueryValueEx(hKey,
  851. REGSZ_ENABLE_CERTTYPE_EDITING,
  852. NULL,
  853. &dwType,
  854. (PBYTE)&dwEnabled,
  855. &cbEnabled);
  856. if(lResult == ERROR_SUCCESS)
  857. {
  858. if(dwType != REG_DWORD)
  859. {
  860. dwEnabled = 0;
  861. }
  862. }
  863. RegCloseKey (hKey);
  864. }
  865. return (dwEnabled != 0);
  866. }
  867. BOOL EnumOIDInfo (PCCRYPT_OID_INFO pInfo, void* /*pvArg*/)
  868. {
  869. BOOL bRVal = TRUE;
  870. if ( pInfo && pInfo->pszOID )
  871. {
  872. // NTRAID# 463344 Certtmpl.msc: Remove "All Application Policies" from
  873. // Extensions selection list in Certtmpl.msc -- break Enrollment
  874. if ( !strcmp (szOID_ANY_APPLICATION_POLICY, pInfo->pszOID) )
  875. return TRUE;
  876. for (POSITION nextPos = g_policyOIDList.GetHeadPosition (); nextPos; )
  877. {
  878. CPolicyOID* pPolicyOID = g_policyOIDList.GetNext (nextPos);
  879. if ( pPolicyOID )
  880. {
  881. if ( !strcmp (pPolicyOID->GetOIDA (), pInfo->pszOID) )
  882. return TRUE; // duplicate found, get next
  883. }
  884. }
  885. int flags = 0;
  886. if ( CRYPT_ENHKEY_USAGE_OID_GROUP_ID == pInfo->dwGroupId )
  887. flags = CERT_OID_TYPE_APPLICATION_POLICY;
  888. else if ( CRYPT_POLICY_OID_GROUP_ID == pInfo->dwGroupId )
  889. flags = CERT_OID_TYPE_ISSUER_POLICY;
  890. else
  891. {
  892. ASSERT (0);
  893. return TRUE;
  894. }
  895. CPolicyOID* pPolicyOID = new CPolicyOID (pInfo->pszOID, pInfo->pwszName,
  896. flags, false);
  897. if ( pPolicyOID )
  898. {
  899. g_policyOIDList.AddTail (pPolicyOID);
  900. }
  901. else
  902. bRVal = FALSE;
  903. }
  904. else
  905. bRVal = FALSE;
  906. return bRVal;
  907. }
  908. HRESULT GetBuiltInOIDs ()
  909. {
  910. HRESULT hr = S_OK;
  911. CryptEnumOIDInfo (
  912. CRYPT_ENHKEY_USAGE_OID_GROUP_ID,
  913. 0,
  914. 0,
  915. EnumOIDInfo);
  916. CryptEnumOIDInfo (
  917. CRYPT_POLICY_OID_GROUP_ID,
  918. 0,
  919. 0,
  920. EnumOIDInfo);
  921. return hr;
  922. }
  923. HRESULT EnumerateOIDs (
  924. IDirectoryObject* pOIDContObj)
  925. {
  926. _TRACE (1, L"Entering EnumerateOIDs\n");
  927. CComPtr<IDirectorySearch> spDsSearch;
  928. HRESULT hr = pOIDContObj->QueryInterface (IID_PPV_ARG(IDirectorySearch, &spDsSearch));
  929. if ( SUCCEEDED (hr) )
  930. {
  931. ASSERT (!!spDsSearch);
  932. ADS_SEARCHPREF_INFO pSearchPref[1];
  933. DWORD dwNumPref = 1;
  934. pSearchPref[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  935. pSearchPref[0].vValue.dwType = ADSTYPE_INTEGER;
  936. pSearchPref[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
  937. hr = spDsSearch->SetSearchPreference(
  938. pSearchPref,
  939. dwNumPref
  940. );
  941. if ( SUCCEEDED (hr) )
  942. {
  943. static const DWORD cAttrs = 3;
  944. static PWSTR rgszAttrList[cAttrs] = {OID_PROP_DISPLAY_NAME, OID_PROP_OID, OID_PROP_TYPE};
  945. ADS_SEARCH_HANDLE hSearchHandle = 0;
  946. wstring strQuery;
  947. ADS_SEARCH_COLUMN Column;
  948. Column.pszAttrName = 0;
  949. strQuery = L"objectClass=msPKI-Enterprise-Oid";
  950. hr = spDsSearch->ExecuteSearch(
  951. const_cast <PWSTR>(strQuery.c_str ()),
  952. rgszAttrList,
  953. cAttrs,
  954. &hSearchHandle
  955. );
  956. if ( SUCCEEDED (hr) )
  957. {
  958. while ((hr = spDsSearch->GetNextRow (hSearchHandle)) != S_ADS_NOMORE_ROWS )
  959. {
  960. if (FAILED(hr))
  961. continue;
  962. //
  963. // Getting current row's information
  964. //
  965. hr = spDsSearch->GetColumn(
  966. hSearchHandle,
  967. rgszAttrList[0],
  968. &Column
  969. );
  970. if ( SUCCEEDED (hr) )
  971. {
  972. CString strDisplayName = Column.pADsValues->CaseIgnoreString;
  973. spDsSearch->FreeColumn (&Column);
  974. Column.pszAttrName = NULL;
  975. hr = spDsSearch->GetColumn(
  976. hSearchHandle,
  977. rgszAttrList[1],
  978. &Column
  979. );
  980. if ( SUCCEEDED (hr) )
  981. {
  982. bool bOIDFound = false;
  983. CString strOID = Column.pADsValues->CaseIgnoreString;
  984. spDsSearch->FreeColumn (&Column);
  985. for (POSITION nextPos = g_policyOIDList.GetHeadPosition (); nextPos; )
  986. {
  987. CPolicyOID* pPolicyOID = g_policyOIDList.GetNext (nextPos);
  988. if ( pPolicyOID )
  989. {
  990. if ( pPolicyOID->GetOIDW () == strOID )
  991. {
  992. bOIDFound = true;
  993. break;
  994. }
  995. }
  996. }
  997. if ( !bOIDFound )
  998. {
  999. Column.pszAttrName = NULL;
  1000. hr = spDsSearch->GetColumn(
  1001. hSearchHandle,
  1002. rgszAttrList[2],
  1003. &Column
  1004. );
  1005. if ( SUCCEEDED (hr) )
  1006. {
  1007. ADS_INTEGER flags = Column.pADsValues->Integer;
  1008. spDsSearch->FreeColumn (&Column);
  1009. Column.pszAttrName = NULL;
  1010. // Only add issuance and application OIDs to the list
  1011. if ( CERT_OID_TYPE_ISSUER_POLICY == flags ||
  1012. CERT_OID_TYPE_APPLICATION_POLICY == flags )
  1013. {
  1014. CPolicyOID* pPolicyOID = new CPolicyOID (strOID, strDisplayName, flags);
  1015. if ( pPolicyOID )
  1016. {
  1017. g_policyOIDList.AddTail (pPolicyOID);
  1018. }
  1019. else
  1020. break;
  1021. }
  1022. }
  1023. }
  1024. }
  1025. }
  1026. else if ( hr != E_ADS_COLUMN_NOT_SET )
  1027. {
  1028. break;
  1029. }
  1030. else
  1031. {
  1032. _TRACE (0, L"IDirectorySearch::GetColumn () failed: 0x%x\n", hr);
  1033. }
  1034. }
  1035. }
  1036. else
  1037. {
  1038. _TRACE (0, L"IDirectorySearch::ExecuteSearch () failed: 0x%x\n", hr);
  1039. }
  1040. spDsSearch->CloseSearchHandle(hSearchHandle);
  1041. }
  1042. else
  1043. {
  1044. _TRACE (0, L"IDirectorySearch::SetSearchPreference () failed: 0x%x\n", hr);
  1045. }
  1046. }
  1047. else
  1048. {
  1049. _TRACE (0, L"IDirectoryObject::QueryInterface (IDirectorySearch) failed: 0x%x\n", hr);
  1050. }
  1051. _TRACE (-1, L"Leaving EnumerateOIDs: 0x%x\n", hr);
  1052. return hr;
  1053. }
  1054. HRESULT GetEnterpriseOIDs ()
  1055. {
  1056. _TRACE (1, L"Entering GetEnterpriseOIDs\n");
  1057. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1058. HRESULT hr = S_OK;
  1059. // Empty the list first
  1060. while ( !g_policyOIDList.IsEmpty () )
  1061. {
  1062. CPolicyOID* pPolicyOID = g_policyOIDList.RemoveHead ();
  1063. if ( pPolicyOID )
  1064. delete pPolicyOID;
  1065. }
  1066. hr = GetBuiltInOIDs ();
  1067. if ( SUCCEEDED (hr) )
  1068. {
  1069. CComPtr<IADsPathname> spPathname;
  1070. //
  1071. // Constructing the directory paths
  1072. //
  1073. // security review BryanWal 02/02/2002 ok
  1074. hr = CoCreateInstance(
  1075. CLSID_Pathname,
  1076. NULL,
  1077. CLSCTX_ALL,
  1078. IID_PPV_ARG (IADsPathname, &spPathname));
  1079. if ( SUCCEEDED (hr) )
  1080. {
  1081. CComBSTR bstrPathElement;
  1082. ASSERT (!!spPathname);
  1083. bstrPathElement = CERTTMPL_LDAP;
  1084. hr = spPathname->Set(bstrPathElement, ADS_SETTYPE_PROVIDER);
  1085. if ( SUCCEEDED (hr) )
  1086. {
  1087. //
  1088. // Open the root DSE object
  1089. //
  1090. bstrPathElement = CERTTMPL_ROOTDSE;
  1091. hr = spPathname->AddLeafElement(bstrPathElement);
  1092. if ( SUCCEEDED (hr) )
  1093. {
  1094. BSTR bstrFullPath = 0;
  1095. hr = spPathname->Retrieve(ADS_FORMAT_X500, &bstrFullPath);
  1096. if ( SUCCEEDED (hr) )
  1097. {
  1098. CComPtr<IADs> spRootDSEObject;
  1099. VARIANT varNamingContext;
  1100. hr = ADsGetObject (
  1101. bstrFullPath,
  1102. IID_PPV_ARG (IADs, &spRootDSEObject));
  1103. if ( SUCCEEDED (hr) )
  1104. {
  1105. ASSERT (!!spRootDSEObject);
  1106. //
  1107. // Get the configuration naming context from the root DSE
  1108. //
  1109. bstrPathElement = CERTTMPL_CONFIG_NAMING_CONTEXT;
  1110. hr = spRootDSEObject->Get(bstrPathElement,
  1111. &varNamingContext);
  1112. if ( SUCCEEDED (hr) )
  1113. {
  1114. hr = spPathname->Set(V_BSTR(&varNamingContext),
  1115. ADS_SETTYPE_DN);
  1116. if ( SUCCEEDED (hr) )
  1117. {
  1118. bstrPathElement = L"CN=Services";
  1119. hr = spPathname->AddLeafElement (bstrPathElement);
  1120. if ( SUCCEEDED (hr) )
  1121. {
  1122. bstrPathElement = L"CN=Public Key Services";
  1123. hr = spPathname->AddLeafElement (bstrPathElement);
  1124. if ( SUCCEEDED (hr) )
  1125. {
  1126. bstrPathElement = L"CN=OID";
  1127. hr = spPathname->AddLeafElement (bstrPathElement);
  1128. if ( SUCCEEDED (hr) )
  1129. {
  1130. BSTR bstrOIDPath = 0;
  1131. hr = spPathname->Retrieve(ADS_FORMAT_X500, &bstrOIDPath);
  1132. if ( SUCCEEDED (hr) )
  1133. {
  1134. CComPtr<IDirectoryObject> spOIDContObj;
  1135. hr = ADsGetObject (
  1136. bstrOIDPath,
  1137. IID_PPV_ARG (IDirectoryObject, &spOIDContObj));
  1138. if ( SUCCEEDED (hr) )
  1139. {
  1140. hr = EnumerateOIDs (spOIDContObj);
  1141. }
  1142. else
  1143. {
  1144. _TRACE (0, L"ADsGetObject (%s) failed: 0x%x\n", bstrOIDPath, hr);
  1145. }
  1146. SysFreeString (bstrOIDPath);
  1147. }
  1148. }
  1149. }
  1150. }
  1151. }
  1152. }
  1153. else
  1154. {
  1155. _TRACE (0, L"IADs::Get (%s) failed: 0x%x\n", CERTTMPL_CONFIG_NAMING_CONTEXT, hr);
  1156. }
  1157. }
  1158. else
  1159. {
  1160. _TRACE (0, L"ADsGetObject (%s) failed: 0x%x\n", bstrFullPath, hr);
  1161. }
  1162. }
  1163. }
  1164. }
  1165. }
  1166. else
  1167. hr = E_POINTER;
  1168. }
  1169. _TRACE (-1, L"Leaving GetEnterpriseOIDs: 0x%x\n", hr);
  1170. return hr;
  1171. }
  1172. bool OIDHasValidFormat (PCWSTR pszOidValue, int& rErrorTypeStrID)
  1173. {
  1174. ASSERT (pszOidValue);
  1175. if ( !pszOidValue )
  1176. return false;
  1177. _TRACE (1, L"Entering OIDHasValidFormat (%s)\n", pszOidValue);
  1178. rErrorTypeStrID = 0;
  1179. bool bFormatIsValid = false;
  1180. int nLen = WideCharToMultiByte(
  1181. CP_ACP, // code page
  1182. 0, // performance and mapping flags
  1183. pszOidValue, // wide-character string
  1184. -1, // -1 - calculate length of null-terminated string automatically
  1185. 0, // buffer for new string
  1186. 0, // size of buffer - 0 causes API to return length including null terminator
  1187. 0, // default for unmappable chars
  1188. 0); // set when default char used
  1189. if ( nLen > 0 )
  1190. {
  1191. PSTR pszAnsiBuf = new char[nLen];
  1192. if ( pszAnsiBuf )
  1193. {
  1194. // security review BryanWal 02/02/2002 ok
  1195. ZeroMemory (pszAnsiBuf, nLen*sizeof(char));
  1196. // security review BryanWal 02/02/2002 ok
  1197. nLen = WideCharToMultiByte(
  1198. CP_ACP, // code page
  1199. 0, // performance and mapping flags
  1200. pszOidValue, // wide-character string
  1201. -1, // -1 - calculate length of null-terminated string automatically
  1202. pszAnsiBuf, // buffer for new string
  1203. nLen, // size of buffer
  1204. 0, // default for unmappable chars
  1205. 0); // set when default char used
  1206. if ( nLen )
  1207. {
  1208. // According to PhilH:
  1209. // The first number is limited to
  1210. // 0,1 or 2. The second number is
  1211. // limited to 0 - 39 when the first
  1212. // number is 0 or 1. Otherwise, any
  1213. // number.
  1214. // Also, according to X.208, there
  1215. // must be at least 2 numbers.
  1216. bFormatIsValid = true;
  1217. // security review 2/20/2002 BryanWal ok
  1218. size_t cbAnsiBufLen = strlen (pszAnsiBuf);
  1219. // check for only digits and "."
  1220. size_t nIdx = strspn (pszAnsiBuf, "0123456789.\0");
  1221. if ( nIdx > 0 && nIdx < cbAnsiBufLen )
  1222. {
  1223. bFormatIsValid = false;
  1224. rErrorTypeStrID = IDS_OID_CONTAINS_NON_DIGITS;
  1225. }
  1226. // check for consecutive "."s - string not valid if present
  1227. if ( bFormatIsValid && strstr (pszAnsiBuf, "..") )
  1228. {
  1229. bFormatIsValid = false;
  1230. rErrorTypeStrID = IDS_OID_CONTAINS_CONSECUTIVE_DOTS;
  1231. }
  1232. // must begin with "0." or "1." or "2."
  1233. bool bFirstNumberIs0 = false;
  1234. bool bFirstNumberIs1 = false;
  1235. bool bFirstNumberIs2 = false;
  1236. if ( bFormatIsValid )
  1237. {
  1238. if ( !strncmp (pszAnsiBuf, "0.", 2) )
  1239. bFirstNumberIs0 = true;
  1240. else if ( !strncmp (pszAnsiBuf, "1.", 2) )
  1241. bFirstNumberIs1 = true;
  1242. else if ( !strncmp (pszAnsiBuf, "2.", 2) )
  1243. bFirstNumberIs2 = true;
  1244. if ( !bFirstNumberIs0 && !bFirstNumberIs1 && !bFirstNumberIs2 )
  1245. {
  1246. bFormatIsValid = false;
  1247. rErrorTypeStrID = IDS_OID_MUST_START_WITH_0_1_2;
  1248. }
  1249. }
  1250. if ( bFormatIsValid && ( bFirstNumberIs0 || bFirstNumberIs1 ) )
  1251. {
  1252. PSTR pszBuf = pszAnsiBuf;
  1253. pszBuf += 2;
  1254. // there must be a number after the dot
  1255. // security review 2/20/2002 BryanWal ok
  1256. if ( strlen (pszBuf) )
  1257. {
  1258. // truncate the string at the next dot, if any
  1259. PSTR pszDot = strstr (pszBuf, ".");
  1260. if ( pszDot )
  1261. pszDot[0] = 0;
  1262. // convert the string to a number and check for range 0-39
  1263. int nValue = atoi (pszBuf);
  1264. if ( nValue < 0 || nValue > 39 )
  1265. {
  1266. bFormatIsValid = false;
  1267. rErrorTypeStrID = IDS_OID_0_1_MUST_BE_0_TO_39;
  1268. }
  1269. }
  1270. else
  1271. {
  1272. bFormatIsValid = false;
  1273. rErrorTypeStrID = IDS_OID_MUST_HAVE_TWO_NUMBERS;
  1274. }
  1275. }
  1276. // ensure no trailing "."
  1277. if ( bFormatIsValid )
  1278. {
  1279. if ( '.' == pszAnsiBuf[cbAnsiBufLen - 1] )
  1280. {
  1281. bFormatIsValid = false;
  1282. rErrorTypeStrID = IDS_OID_CANNOT_END_WITH_DOT;
  1283. }
  1284. }
  1285. if ( bFormatIsValid )
  1286. {
  1287. bFormatIsValid = false;
  1288. CRYPT_ATTRIBUTE cryptAttr;
  1289. // security review BryanWal 02/02/2002 ok
  1290. ::ZeroMemory (&cryptAttr, sizeof (cryptAttr));
  1291. cryptAttr.cValue = 0;
  1292. cryptAttr.pszObjId = pszAnsiBuf;
  1293. cryptAttr.rgValue = 0;
  1294. DWORD cbEncoded = 0;
  1295. BOOL bResult = CryptEncodeObject (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1296. PKCS_ATTRIBUTE,
  1297. &cryptAttr,
  1298. NULL,
  1299. &cbEncoded);
  1300. if ( cbEncoded > 0 )
  1301. {
  1302. BYTE* pBuffer = new BYTE[cbEncoded];
  1303. if ( pBuffer )
  1304. {
  1305. bResult = CryptEncodeObject (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1306. PKCS_ATTRIBUTE,
  1307. &cryptAttr,
  1308. pBuffer,
  1309. &cbEncoded);
  1310. if ( bResult )
  1311. {
  1312. DWORD cbStructInfo = 0;
  1313. bResult = CryptDecodeObject (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1314. PKCS_ATTRIBUTE,
  1315. pBuffer,
  1316. cbEncoded,
  1317. 0,
  1318. 0,
  1319. &cbStructInfo);
  1320. if ( cbStructInfo > 0 )
  1321. {
  1322. BYTE* pStructBuf = new BYTE[cbStructInfo];
  1323. if ( pStructBuf )
  1324. {
  1325. bResult = CryptDecodeObject (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1326. PKCS_ATTRIBUTE,
  1327. pBuffer,
  1328. cbEncoded,
  1329. 0,
  1330. pStructBuf,
  1331. &cbStructInfo);
  1332. if ( bResult )
  1333. {
  1334. CRYPT_ATTRIBUTE* pCryptAttr = (CRYPT_ATTRIBUTE*) pStructBuf;
  1335. if ( !strcmp (pszAnsiBuf, pCryptAttr->pszObjId) )
  1336. {
  1337. bFormatIsValid = true;
  1338. }
  1339. }
  1340. delete [] pStructBuf;
  1341. }
  1342. }
  1343. }
  1344. delete [] pBuffer;
  1345. }
  1346. }
  1347. }
  1348. }
  1349. else
  1350. {
  1351. _TRACE (0, L"WideCharToMultiByte (%s) failed: 0x%x\n", pszOidValue,
  1352. GetLastError ());
  1353. }
  1354. delete [] pszAnsiBuf;
  1355. }
  1356. }
  1357. else
  1358. {
  1359. _TRACE (0, L"WideCharToMultiByte (%s) failed: 0x%x\n", pszOidValue,
  1360. GetLastError ());
  1361. }
  1362. _TRACE (-1, L"Leaving EnumerateOIDs: %s\n", bFormatIsValid ? L"true" : L"false");
  1363. return bFormatIsValid;
  1364. }
  1365. HPROPSHEETPAGE MyCreatePropertySheetPage(AFX_OLDPROPSHEETPAGE* psp)
  1366. {
  1367. ASSERT (psp);
  1368. if ( !psp )
  1369. return 0;
  1370. PROPSHEETPAGE_V3 sp_v3 = {0};
  1371. // security review 2/20/2002 BryanWal ok
  1372. ASSERT (sizeof (sp_v3) >= psp->dwSize);
  1373. if ( sizeof (sp_v3) >= psp->dwSize )
  1374. {
  1375. CopyMemory (&sp_v3, psp, psp->dwSize);
  1376. sp_v3.dwSize = sizeof(sp_v3);
  1377. }
  1378. else
  1379. return 0;
  1380. return (::CreatePropertySheetPage (&sp_v3));
  1381. }