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.

1658 lines
50 KiB

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