//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997 - 2001. // // File: CertMgr.cpp // // Contents: Implementation of DLL Exports // //---------------------------------------------------------------------------- #include "stdafx.h" #include #include #include "CertMgr_i.c" #include "about.h" // CCertMgrAbout #include "compdata.h" // CCertMgrSnapin, CCertMgrExtension #pragma warning(push, 3) #include // UUIDs for Computer Management #include "uuids.h" #include #include // For Security Configuratino Editor snapin #include // VER_PRODUCTVERSION_STR, VERS_COMPANYNAME_STR #include #pragma warning(pop) #ifdef _DEBUG #ifndef ALPHA #define new DEBUG_NEW #endif #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif bool g_bSchemaIsW2K = false; USE_HANDLE_MACROS ("CERTMGR (CertMgr.cpp)") LPCWSTR CM_HELP_TOPIC = L"sag_CMtopNode.htm"; LPCWSTR CM_HELP_FILE = L"certmgr.chm"; LPCWSTR CM_LINKED_HELP_FILE = L"CMconcepts.chm"; LPCWSTR PKP_LINKED_HELP_FILE = L"SecSetConcepts.chm"; LPCWSTR PKP_HELP_FILE = L"secsettings.chm"; LPCWSTR PKP_HELP_TOPIC = L"sag_secsettopnode.htm"; LPCWSTR SAFER_WINDOWS_HELP_FILE = L"SAFER.chm"; LPCWSTR SAFER_WINDOWS_LINKED_HELP_FILE = L"SAFERconcepts.chm"; LPCWSTR SAFER_HELP_TOPIC = L"SAFER_topnode.htm"; LPCWSTR CM_CONTEXT_HELP = L"\\help\\certmgr.hlp"; LPCWSTR WINDOWS_HELP = L"windows.hlp"; // // This is used by the nodetype utility routines in stdutils.cpp // const struct NODETYPE_GUID_ARRAYSTRUCT g_NodetypeGuids[CERTMGR_NUMTYPES] = { { // CERTMGR_SNAPIN structuuidNodetypeSnapin, lstruuidNodetypeSnapin }, { // CERTMGR_CERTIFICATE structuuidNodetypeCertificate, lstruuidNodetypeCertificate }, { // CERTMGR_LOG_STORE structuuidNodetypeLogStore, lstruuidNodetypeLogStore }, { // CERTMGR_PHYS_STORE structuuidNodetypePhysStore, lstruuidNodetypePhysStore }, { // CERTMGR_USAGE structuuidNodetypeUsage, lstruuidNodetypeUsage }, { // CERTMGR_CRL_CONTAINER structuuidNodetypeCRLContainer, lstruuidNodetypeCRLContainer }, { // CERTMGR_CTL_CONTAINER structuuidNodetypeCTLContainer, lstruuidNodetypeCTLContainer }, { // CERTMGR_CERT_CONTAINER structuuidNodetypeCertContainer, lstruuidNodetypeCertContainer }, { // CERTMGR_CRL structuuidNodetypeCRL, lstruuidNodetypeCRL }, { // CERTMGR_CTL structuuidNodetypeCTL, lstruuidNodetypeCTL }, { // CERTMGR_AUTO_CERT_REQUEST structuuidNodetypeAutoCertRequest, lstruuidNodetypeAutoCertRequest }, { // CERTMGR_CERT_POLICIES_USER, structuuidNodetypeCertPoliciesUser, lstruiidNodetypeCertPoliciesUser }, { // CERTMGR_CERT_POLICIES_COMPUTER, structuuidNodetypeCertPoliciesComputer, lstruiidNodetypeCertPoliciesComputer }, { // CERTMGR_LOG_STORE_GPE structuuidNodetypeLogStore, lstruuidNodetypeLogStore }, { // CERTMGR_LOG_STORE_RSOP structuuidNodetypeLogStore, lstruuidNodetypeLogStore }, { // CERTMGR_PKP_AUTOENROLLMENT_COMPUTER_SETTINGS structuuidNodetypePKPAutoenrollmentSettings, lstruiidNodetypePKPAutoenrollmentSettings }, { // CERTMGR_PKP_AUTOENROLLMENT_USER_SETTINGS 0, 0 }, { // CERTMGR_SAFER_COMPUTER_ROOT structuuidNodetypeSaferComputerRoot, lstruiidNodetypeSaferComputerRoot }, { // CERTMGR_SAFER_COMPUTER_LEVELS structuuidNodetypeSaferComputerLevels, lstruiidNodetypeSaferComputerLevels }, { // CERTMGR_SAFER_COMPUTER_ENTRIES structuuidNodetypeSaferComputerEntries, lstruiidNodetypeSaferComputerEntries }, { // CERTMGR_SAFER_USER_ROOT structuuidNodetypeSaferUserRoot, lstruiidNodetypeSaferUserRoot }, { // CERTMGR_SAFER_USER_ENTRIES structuuidNodetypeSaferUserEntries, lstruiidNodetypeSaferUserEntries }, { // CERTMGR_SAFER_USER_LEVELS structuuidNodetypeSaferUserLevels, lstruiidNodetypeSaferUserLevels }, { // CERTMGR_SAFER_COMPUTER_LEVEL structuuidNodetypeSaferComputerLevel, lstruiidNodetypeSaferComputerLevel }, { // CERTMGR_SAFER_USER_LEVEL structuuidNodetypeSaferUserLevel, lstruiidNodetypeSaferUserLevel }, { // CERTMGR_SAFER_COMPUTER_ENTRY structuuidNodetypeSaferComputerEntry, lstruiidNodetypeSaferComputerEntry }, { // CERTMGR_SAFER_USER_ENTRY structuuidNodetypeSaferUserEntry, lstruiidNodetypeSaferUserEntry }, { // CERTMGR_SAFER_COMPUTER_TRUSTED_PUBLISHERS structuuidNodetypeSaferTrustedPublishers, lstruiidNodetypeSaferTrustedPublisher }, { // CERTMGR_SAFER_USER_TRUSTED_PUBLISHERS 0, 0 }, { // CERTMGR_SAFER_COMPUTER_DEFINED_FILE_TYPES structuuidNodetypeSaferDefinedFileTypes, lstruiidNodetypeSaferDefinedFileTypes }, { // CERTMGR_SAFER_USER_DEFINED_FILE_TYPES 0, 0 }, { // CERTMGR_SAFER_USER_ENFORCEMENT structuuidNodetypeSaferEnforcement, lstruiidNodetypeSaferEnforcement }, { // CERTMGR_SAFER_COMPUTER_ENFORCEMENT 0, 0 } }; const struct NODETYPE_GUID_ARRAYSTRUCT* g_aNodetypeGuids = g_NodetypeGuids; const int g_cNumNodetypeGuids = CERTMGR_NUMTYPES; HINSTANCE g_hInstance = 0; CString g_szFileName; CComModule _Module; BEGIN_OBJECT_MAP (ObjectMap) OBJECT_ENTRY (CLSID_CertificateManager, CCertMgrSnapin) OBJECT_ENTRY (CLSID_CertificateManagerPKPOLExt, CCertMgrPKPolExtension) OBJECT_ENTRY (CLSID_CertificateManagerAbout, CCertMgrAbout) OBJECT_ENTRY (CLSID_PublicKeyPoliciesAbout, CPublicKeyPoliciesAbout) OBJECT_ENTRY (CLSID_SaferWindowsExtension, CSaferWindowsExtension) OBJECT_ENTRY (CLSID_SaferWindowsAbout, CSaferWindowsAbout) END_OBJECT_MAP () class CCertMgrApp : public CWinApp { public: CCertMgrApp (); virtual BOOL InitInstance (); virtual int ExitInstance (); private: }; CCertMgrApp theApp; CCertMgrApp::CCertMgrApp () { LPWSTR pszCommandLine = _wcsupr (::GetCommandLine ()); LPWSTR pszParam = L"/CERTMGR:FILENAME="; size_t len = wcslen (pszParam); LPWSTR pszArg = wcsstr (pszCommandLine, pszParam); if ( !pszArg ) pszParam = L"-CERTMGR:FILENAME="; if ( pszArg ) { LPWSTR pszDelimiters = 0; // jump past the name of the arg to get the value pszArg += len; // Is the file name delimited by double quotes? This could indicate // the presence of spaces in the name. If so, skip the quote // and look for the closing quote. Otherwise, look for the next // space, tab or NULL terminator. if ( L'\"' == pszArg[0] ) { pszDelimiters = L"\""; pszArg++; } else pszDelimiters = L" \t\0"; len = wcscspn (pszArg, pszDelimiters); * (pszArg + len) = 0; g_szFileName = pszArg; } } BOOL CCertMgrApp::InitInstance () { #ifdef _MERGE_PROXYSTUB hProxyDll = m_hInstance; #endif g_hInstance = m_hInstance; AfxSetResourceHandle (m_hInstance); _Module.Init (ObjectMap, m_hInstance); #if DBG == 1 CheckDebugOutputLevel (); #endif SHFusionInitializeFromModuleID (m_hInstance, 2); return CWinApp::InitInstance (); } int CCertMgrApp::ExitInstance () { SHFusionUninitialize(); SetRegistryScope (0, false); _Module.Term (); return CWinApp::ExitInstance (); } ///////////////////////////////////////////////////////////////////////////// // Used to determine whether the DLL can be unloaded by OLE STDAPI DllCanUnloadNow (void) { AFX_MANAGE_STATE (AfxGetStaticModuleState ()); return (AfxDllCanUnloadNow ()==S_OK && _Module.GetLockCount ()==0) ? S_OK : S_FALSE; } ///////////////////////////////////////////////////////////////////////////// // Returns a class factory to create an object of the requested type STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, LPVOID* ppv) { return _Module.GetClassObject (rclsid, riid, ppv); } ///////////////////////////////////////////////////////////////////////////// // DllRegisterServer - Adds entries to the system registry //const WCHAR g_szNameString[] = TEXT ("NameString"); //const WCHAR g_szNodeType[] = TEXT ("NodeType"); STDAPI DllRegisterServer (void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // NTRAID# 88502 intlext: mui: me common: crypto: certificate 's // intended purpose string unlocalized // Unregister szOID_EFS_RECOVERY CRYPT_OID_INFO oid; ::ZeroMemory (&oid, sizeof (CRYPT_OID_INFO)); oid.cbSize = sizeof (CRYPT_OID_INFO); oid.pszOID = szOID_EFS_RECOVERY; oid.dwGroupId = CRYPT_ENHKEY_USAGE_OID_GROUP_ID; CryptUnregisterOIDInfo (&oid); // registers object, typelib and all interfaces in typelib HRESULT hr = _Module.RegisterServer (TRUE); ASSERT (SUCCEEDED (hr)); if ( E_ACCESSDENIED == hr ) { CString caption; CString text; CThemeContextActivator activator; VERIFY (caption.LoadString (IDS_REGISTER_CERTMGR)); VERIFY (text.LoadString (IDS_INSUFFICIENT_RIGHTS_TO_REGISTER_CERTMGR)); MessageBox (NULL, text, caption, MB_OK); return hr; } try { CString strGUID; CString snapinName; CString verProviderStr, verVersionStr; AMC::CRegKey rkSnapins; BOOL fFound = rkSnapins.OpenKeyEx (HKEY_LOCAL_MACHINE, SNAPINS_KEY); ASSERT (fFound); if ( fFound ) { { AMC::CRegKey rkCertMgrSnapin; hr = GuidToCString (&strGUID, CLSID_CertificateManager); if ( FAILED (hr) ) { ASSERT (FALSE); return SELFREG_E_CLASS; } rkCertMgrSnapin.CreateKeyEx (rkSnapins, strGUID); ASSERT (rkCertMgrSnapin.GetLastError () == ERROR_SUCCESS); rkCertMgrSnapin.SetString (g_szNodeType, g_aNodetypeGuids[CERTMGR_SNAPIN].bstr); VERIFY (snapinName.LoadString (IDS_CERTIFICATE_MANAGER_REGISTRY)); rkCertMgrSnapin.SetString (g_szNameString, (LPCWSTR) snapinName); hr = GuidToCString (&strGUID, CLSID_CertificateManagerAbout); if ( FAILED (hr) ) { ASSERT (FALSE); return SELFREG_E_CLASS; } rkCertMgrSnapin.SetString (L"About", strGUID); size_t len = strlen (VER_COMPANYNAME_STR); len = mbstowcs (verProviderStr.GetBufferSetLength ((int) len), VER_COMPANYNAME_STR, len); rkCertMgrSnapin.SetString (L"Provider", verProviderStr); len = strlen (VER_PRODUCTVERSION_STR); len = mbstowcs (verVersionStr.GetBufferSetLength ((int)len), VER_PRODUCTVERSION_STR, len); rkCertMgrSnapin.SetString (L"Version", verVersionStr); AMC::CRegKey rkCertMgrStandalone; rkCertMgrStandalone.CreateKeyEx (rkCertMgrSnapin, g_szStandAlone); ASSERT (rkCertMgrStandalone.GetLastError () == ERROR_SUCCESS); AMC::CRegKey rkMyNodeTypes; rkMyNodeTypes.CreateKeyEx (rkCertMgrSnapin, g_szNodeTypes); ASSERT (rkMyNodeTypes.GetLastError () == ERROR_SUCCESS); AMC::CRegKey rkMyNodeType; for (int i = CERTMGR_SNAPIN; i < CERTMGR_NUMTYPES; i++) { switch (i) { case CERTMGR_LOG_STORE_GPE: case CERTMGR_LOG_STORE_RSOP: case CERTMGR_AUTO_CERT_REQUEST: case CERTMGR_CERT_POLICIES_USER: case CERTMGR_CERT_POLICIES_COMPUTER: case CERTMGR_PKP_AUTOENROLLMENT_USER_SETTINGS: // not necessary - just another kind of the same node break; // TODO: What to do with these? case CERTMGR_SAFER_COMPUTER_ROOT: case CERTMGR_SAFER_USER_ROOT: case CERTMGR_SAFER_COMPUTER_LEVELS: case CERTMGR_SAFER_USER_LEVELS: case CERTMGR_SAFER_COMPUTER_ENTRIES: case CERTMGR_SAFER_USER_ENTRIES: case CERTMGR_SAFER_COMPUTER_LEVEL: case CERTMGR_SAFER_USER_LEVEL: case CERTMGR_SAFER_COMPUTER_ENTRY: case CERTMGR_SAFER_USER_ENTRY: case CERTMGR_SAFER_COMPUTER_TRUSTED_PUBLISHERS: case CERTMGR_SAFER_USER_TRUSTED_PUBLISHERS: case CERTMGR_SAFER_COMPUTER_DEFINED_FILE_TYPES: case CERTMGR_SAFER_USER_DEFINED_FILE_TYPES: case CERTMGR_SAFER_USER_ENFORCEMENT: case CERTMGR_SAFER_COMPUTER_ENFORCEMENT: break; case CERTMGR_PKP_AUTOENROLLMENT_COMPUTER_SETTINGS: default: if ( wcslen (g_aNodetypeGuids[i].bstr) ) { rkMyNodeType.CreateKeyEx (rkMyNodeTypes, g_aNodetypeGuids[i].bstr); ASSERT (rkMyNodeType.GetLastError () == ERROR_SUCCESS); rkMyNodeType.CloseKey (); } break; } } // // BryanWal 5/18/00 // 94793: MUI: MMC: Certificates snap-in stores its display // information in the registry // // MMC now supports NameStringIndirect // TCHAR achModuleFileName[MAX_PATH+20]; if (0 < ::GetModuleFileName( AfxGetInstanceHandle(), achModuleFileName, sizeof(achModuleFileName)/sizeof(TCHAR) )) { CString strNameIndirect; strNameIndirect.Format(L"@%s,-%d", achModuleFileName, IDS_CERTIFICATE_MANAGER_REGISTRY ); rkCertMgrSnapin.SetString(L"NameStringIndirect", strNameIndirect ); } rkCertMgrSnapin.CloseKey (); } AMC::CRegKey rkNodeTypes; fFound = rkNodeTypes.OpenKeyEx (HKEY_LOCAL_MACHINE, NODE_TYPES_KEY); ASSERT (fFound); if ( fFound ) { AMC::CRegKey rkNodeType; for (int i = CERTMGR_SNAPIN; i < CERTMGR_NUMTYPES; i++) { switch (i) { // these types are not used in the primary snapin case CERTMGR_LOG_STORE_GPE: case CERTMGR_LOG_STORE_RSOP: case CERTMGR_AUTO_CERT_REQUEST: case CERTMGR_CERT_POLICIES_USER: case CERTMGR_CERT_POLICIES_COMPUTER: case CERTMGR_PKP_AUTOENROLLMENT_COMPUTER_SETTINGS: case CERTMGR_PKP_AUTOENROLLMENT_USER_SETTINGS: case CERTMGR_SAFER_COMPUTER_ROOT: case CERTMGR_SAFER_USER_ROOT: case CERTMGR_SAFER_COMPUTER_LEVELS: case CERTMGR_SAFER_USER_LEVELS: case CERTMGR_SAFER_COMPUTER_ENTRIES: case CERTMGR_SAFER_USER_ENTRIES: case CERTMGR_SAFER_COMPUTER_LEVEL: case CERTMGR_SAFER_USER_LEVEL: case CERTMGR_SAFER_COMPUTER_ENTRY: case CERTMGR_SAFER_USER_ENTRY: case CERTMGR_SAFER_COMPUTER_TRUSTED_PUBLISHERS: case CERTMGR_SAFER_USER_TRUSTED_PUBLISHERS: case CERTMGR_SAFER_COMPUTER_DEFINED_FILE_TYPES: case CERTMGR_SAFER_USER_DEFINED_FILE_TYPES: case CERTMGR_SAFER_USER_ENFORCEMENT: case CERTMGR_SAFER_COMPUTER_ENFORCEMENT: break; default: if ( wcslen (g_aNodetypeGuids[i].bstr) ) { rkNodeType.CreateKeyEx (rkNodeTypes, g_aNodetypeGuids[i].bstr); ASSERT (rkNodeType.GetLastError () == ERROR_SUCCESS); rkNodeType.CloseKey (); } break; } } if ( IsWindowsNT () ) { { // Public Key PoliciesSnap-in under Security Configuration Editor (SCE) // Certificate Manager extends "Computer Settings" and // "User Settings" node CString strCertMgrExtPKPolGUID; hr = GuidToCString (&strCertMgrExtPKPolGUID, CLSID_CertificateManagerPKPOLExt); if ( FAILED (hr) ) { ASSERT (FALSE); return SELFREG_E_CLASS; } VERIFY (snapinName.LoadString (IDS_CERT_MGR_SCE_EXTENSION_REGISTRY)); { AMC::CRegKey rkCertMgrExtension; rkCertMgrExtension.CreateKeyEx (rkSnapins, strCertMgrExtPKPolGUID); ASSERT (rkCertMgrExtension.GetLastError () == ERROR_SUCCESS); rkCertMgrExtension.SetString (g_szNameString, (LPCWSTR) snapinName); hr = GuidToCString (&strGUID, CLSID_PublicKeyPoliciesAbout); if ( FAILED (hr) ) { ASSERT (FALSE); return SELFREG_E_CLASS; } rkCertMgrExtension.SetString (L"About", strGUID); rkCertMgrExtension.SetString (L"Provider", verProviderStr); rkCertMgrExtension.SetString (L"Version", verVersionStr); // Register the node types of the extension AMC::CRegKey rkMyNodeTypes; rkMyNodeTypes.CreateKeyEx (rkCertMgrExtension, g_szNodeTypes); ASSERT (rkMyNodeTypes.GetLastError () == ERROR_SUCCESS); AMC::CRegKey rkMyNodeType; for (int i = CERTMGR_SNAPIN; i < CERTMGR_NUMTYPES; i++) { switch (i) { // None of these are used in the Public Key Policy extension case CERTMGR_USAGE: case CERTMGR_PHYS_STORE: case CERTMGR_LOG_STORE: case CERTMGR_CRL_CONTAINER: case CERTMGR_CTL_CONTAINER: case CERTMGR_CERT_CONTAINER: case CERTMGR_CRL: case CERTMGR_SAFER_COMPUTER_ROOT: case CERTMGR_SAFER_USER_ROOT: case CERTMGR_SAFER_COMPUTER_LEVELS: case CERTMGR_SAFER_USER_LEVELS: case CERTMGR_SAFER_COMPUTER_ENTRIES: case CERTMGR_SAFER_USER_ENTRIES: case CERTMGR_SAFER_COMPUTER_LEVEL: case CERTMGR_SAFER_USER_LEVEL: case CERTMGR_SAFER_COMPUTER_ENTRY: case CERTMGR_SAFER_USER_ENTRY: case CERTMGR_SAFER_COMPUTER_TRUSTED_PUBLISHERS: case CERTMGR_SAFER_USER_TRUSTED_PUBLISHERS: case CERTMGR_SAFER_COMPUTER_DEFINED_FILE_TYPES: case CERTMGR_SAFER_USER_DEFINED_FILE_TYPES: case CERTMGR_SAFER_USER_ENFORCEMENT: case CERTMGR_SAFER_COMPUTER_ENFORCEMENT: // not necessary - just another kind of the same node case CERTMGR_PKP_AUTOENROLLMENT_USER_SETTINGS: break; default: if ( wcslen (g_aNodetypeGuids[i].bstr) ) { rkMyNodeType.CreateKeyEx (rkMyNodeTypes, g_aNodetypeGuids[i].bstr); ASSERT (rkMyNodeType.GetLastError () == ERROR_SUCCESS); rkMyNodeType.CloseKey (); } break; } } // // BryanWal 5/18/00 // 94793: MUI: MMC: Certificates snap-in stores its display // information in the registry // // MMC now supports NameStringIndirect // TCHAR achModuleFileName[MAX_PATH+20]; if (0 < ::GetModuleFileName( AfxGetInstanceHandle(), achModuleFileName, sizeof(achModuleFileName)/sizeof(TCHAR) )) { CString strNameIndirect; strNameIndirect.Format(L"@%s,-%d", achModuleFileName, IDS_CERT_MGR_SCE_EXTENSION_REGISTRY ); rkCertMgrExtension.SetString( L"NameStringIndirect", strNameIndirect ); } rkCertMgrExtension.CloseKey (); } hr = GuidToCString (&strGUID, cNodetypeSceTemplate); if ( FAILED (hr) ) { ASSERT (FALSE); return SELFREG_E_CLASS; } rkNodeType.CreateKeyEx (rkNodeTypes, strGUID); ASSERT (rkNodeType.GetLastError () == ERROR_SUCCESS); if ( rkNodeType.GetLastError () == ERROR_SUCCESS ) { AMC::CRegKey rkExtensions; ASSERT (rkExtensions.GetLastError () == ERROR_SUCCESS); rkExtensions.CreateKeyEx (rkNodeType, g_szExtensions); AMC::CRegKey rkNameSpace; rkNameSpace.CreateKeyEx (rkExtensions, g_szNameSpace); ASSERT (rkNameSpace.GetLastError () == ERROR_SUCCESS); rkNameSpace.SetString (strCertMgrExtPKPolGUID, (LPCWSTR) snapinName); rkNodeType.CloseKey (); } else return SELFREG_E_CLASS; } { // SAFER Windows Snap-in under Security Configuration Editor (SCE) // Certificate Manager extends "Computer Settings" and // "User Settings" node CString strSaferWindowsExtensionGUID; hr = GuidToCString (&strSaferWindowsExtensionGUID, CLSID_SaferWindowsExtension); if ( FAILED (hr) ) { ASSERT (FALSE); return SELFREG_E_CLASS; } VERIFY (snapinName.LoadString (IDS_SAFER_WINDOWS_EXTENSION_REGISTRY)); { AMC::CRegKey rkCertMgrExtension; rkCertMgrExtension.CreateKeyEx (rkSnapins, strSaferWindowsExtensionGUID); ASSERT (rkCertMgrExtension.GetLastError () == ERROR_SUCCESS); rkCertMgrExtension.SetString (g_szNameString, (LPCWSTR) snapinName); hr = GuidToCString (&strGUID, CLSID_SaferWindowsAbout); if ( FAILED (hr) ) { ASSERT (FALSE); return SELFREG_E_CLASS; } rkCertMgrExtension.SetString (L"About", strGUID); rkCertMgrExtension.SetString (L"Provider", verProviderStr); rkCertMgrExtension.SetString (L"Version", verVersionStr); // Register the node types of the extension AMC::CRegKey rkMyNodeTypes; rkMyNodeTypes.CreateKeyEx (rkCertMgrExtension, g_szNodeTypes); ASSERT (rkMyNodeTypes.GetLastError () == ERROR_SUCCESS); AMC::CRegKey rkMyNodeType; for (int i = CERTMGR_SNAPIN; i < CERTMGR_NUMTYPES; i++) { switch (i) { case CERTMGR_CERTIFICATE: case CERTMGR_LOG_STORE: case CERTMGR_PHYS_STORE: case CERTMGR_USAGE: case CERTMGR_CRL_CONTAINER: case CERTMGR_CTL_CONTAINER: case CERTMGR_CERT_CONTAINER: case CERTMGR_CRL: case CERTMGR_CTL: case CERTMGR_AUTO_CERT_REQUEST: case CERTMGR_CERT_POLICIES_USER: case CERTMGR_CERT_POLICIES_COMPUTER: case CERTMGR_LOG_STORE_GPE: case CERTMGR_LOG_STORE_RSOP: case CERTMGR_PKP_AUTOENROLLMENT_USER_SETTINGS: case CERTMGR_PKP_AUTOENROLLMENT_COMPUTER_SETTINGS: // None of these are used in the Software Restriction Policies extension break; case CERTMGR_SAFER_COMPUTER_ROOT: case CERTMGR_SAFER_USER_ROOT: case CERTMGR_SAFER_COMPUTER_LEVELS: case CERTMGR_SAFER_USER_LEVELS: case CERTMGR_SAFER_COMPUTER_ENTRIES: case CERTMGR_SAFER_USER_ENTRIES: case CERTMGR_SAFER_COMPUTER_LEVEL: case CERTMGR_SAFER_USER_LEVEL: case CERTMGR_SAFER_COMPUTER_ENTRY: case CERTMGR_SAFER_USER_ENTRY: case CERTMGR_SAFER_COMPUTER_TRUSTED_PUBLISHERS: case CERTMGR_SAFER_USER_TRUSTED_PUBLISHERS: case CERTMGR_SAFER_COMPUTER_DEFINED_FILE_TYPES: case CERTMGR_SAFER_USER_DEFINED_FILE_TYPES: case CERTMGR_SAFER_USER_ENFORCEMENT: case CERTMGR_SAFER_COMPUTER_ENFORCEMENT: default: if ( g_aNodetypeGuids[i].bstr && wcslen (g_aNodetypeGuids[i].bstr) ) { rkMyNodeType.CreateKeyEx (rkMyNodeTypes, g_aNodetypeGuids[i].bstr); ASSERT (rkMyNodeType.GetLastError () == ERROR_SUCCESS); rkMyNodeType.CloseKey (); } break; } } TCHAR achModuleFileName[MAX_PATH+20]; if (0 < ::GetModuleFileName( AfxGetInstanceHandle(), achModuleFileName, sizeof(achModuleFileName)/sizeof(TCHAR) )) { CString strNameIndirect; strNameIndirect.Format( L"@%s,-%d", achModuleFileName, IDS_SAFER_WINDOWS_EXTENSION_REGISTRY ); rkCertMgrExtension.SetString( L"NameStringIndirect", strNameIndirect ); } rkCertMgrExtension.CloseKey (); } hr = GuidToCString (&strGUID, cNodetypeSceTemplate); if ( FAILED (hr) ) { ASSERT (FALSE); return SELFREG_E_CLASS; } rkNodeType.CreateKeyEx (rkNodeTypes, strGUID); ASSERT (rkNodeType.GetLastError () == ERROR_SUCCESS); if ( rkNodeType.GetLastError () == ERROR_SUCCESS ) { AMC::CRegKey rkExtensions; ASSERT (rkExtensions.GetLastError () == ERROR_SUCCESS); rkExtensions.CreateKeyEx (rkNodeType, g_szExtensions); AMC::CRegKey rkNameSpace; rkNameSpace.CreateKeyEx (rkExtensions, g_szNameSpace); ASSERT (rkNameSpace.GetLastError () == ERROR_SUCCESS); rkNameSpace.SetString (strSaferWindowsExtensionGUID, (LPCWSTR) snapinName); rkNodeType.CloseKey (); } else return SELFREG_E_CLASS; } // Deregister as extension to My Computer System Tools node // CODEWORK It would be good if we deregistered the server too // JonN 12/14/98 try { fFound = rkNodeType.OpenKeyEx (rkNodeTypes, TEXT(struuidNodetypeSystemTools)); // if this fails just carry on if ( fFound ) { AMC::CRegKey rkExtensions; ASSERT (rkExtensions.GetLastError () == ERROR_SUCCESS); fFound = rkExtensions.OpenKeyEx (rkNodeType, g_szExtensions); // if this fails just carry on if ( fFound ) { AMC::CRegKey rkNameSpace; ASSERT (rkNameSpace.GetLastError () == ERROR_SUCCESS); fFound = rkNameSpace.OpenKeyEx (rkExtensions, g_szNameSpace); // if this fails just carry on if ( fFound ) { rkNameSpace.DeleteValue( L"{9C7910D2-4C01-11D1-856B-00C04FB94F17}" ); } } } } catch (COleException* /*e*/) { // don't do anything } } // endif IsWindowsNT () rkNodeTypes.CloseKey (); } else return SELFREG_E_CLASS; } else return SELFREG_E_CLASS; } catch (COleException* e) { ASSERT (FALSE); e->Delete (); return SELFREG_E_CLASS; } ASSERT (SUCCEEDED (hr)); return hr; } ///////////////////////////////////////////////////////////////////////////// // DllUnregisterServer - Removes entries from the system registry STDAPI DllUnregisterServer (void) { _Module.UnregisterServer (); return S_OK; } STDAPI DllInstall(BOOL /*bInstall*/, LPCWSTR pszCmdLine) { LPCWSTR wszCurrentCmd = pszCmdLine; AFX_MANAGE_STATE(AfxGetStaticModuleState()); // parse the cmd line while(wszCurrentCmd && *wszCurrentCmd) { while(*wszCurrentCmd == L' ') wszCurrentCmd++; if(*wszCurrentCmd == 0) break; switch(*wszCurrentCmd++) { case L'?': return S_OK; } } return S_OK; } /////////////////////////////////////////////////////////////////////////// // ConvertNameBlobToString () // // nameBlob (IN) - Contains a CERT_NAME_BLOB to be decoded // pszName (OUT) - The decoded contents of the name blob // /////////////////////////////////////////////////////////////////////////// HRESULT ConvertNameBlobToString (CERT_NAME_BLOB nameBlob, CString & pszName) { HRESULT hr = S_OK; DWORD dwSize = 0; // Call CertNameToStr to get returned the string length. dwSize = CertNameToStr ( MY_ENCODING_TYPE, // Encoding type &nameBlob, // CERT_NAME_BLOB CERT_SIMPLE_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, // Type NULL, // Place to return string dwSize); // Size of string (chars), // including zero terminator. ASSERT (dwSize > 1); if ( dwSize > 1 ) // This function always returns a null char // (0), so the minimum count returned will // be 1, even if nothing got converted. { // Call CertNameToStr to get the string. dwSize = CertNameToStr ( MY_ENCODING_TYPE, // Encoding type &nameBlob, // CERT_NAME_BLOB CERT_SIMPLE_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, // Type pszName.GetBufferSetLength (dwSize), // Place to return string dwSize); // Size of string (chars) ASSERT (dwSize > 1); pszName.ReleaseBuffer (); if ( dwSize <= 1 ) { hr = E_UNEXPECTED; } } return hr; } /////////////////////////////////////////////////////////////////////////////// // FormatDate () // // utcDateTime (IN) - A FILETIME in UTC format. // pszDateTime (OUT) - A string containing the local date and time // formatted by locale and user preference // /////////////////////////////////////////////////////////////////////////////// HRESULT FormatDate (FILETIME utcDateTime, CString & pszDateTime, DWORD dwDateFlags, bool bGetTime) { // Time is returned as UTC, will be displayed as local. // Use FileTimeToLocalFileTime () to make it local, // then call FileTimeToSystemTime () to convert to system time, then // format with GetDateFormat () and GetTimeFormat () to display // according to user and locale preferences HRESULT hr = S_OK; FILETIME localDateTime; BOOL bResult = FileTimeToLocalFileTime (&utcDateTime, // pointer to UTC file time to convert &localDateTime); // pointer to converted file time ASSERT (bResult); if ( bResult ) { SYSTEMTIME sysTime; bResult = FileTimeToSystemTime ( &localDateTime, // pointer to file time to convert &sysTime); // pointer to structure to receive system time if ( bResult ) { CString date; CString time; // Get date // Get length to allocate buffer of sufficient size int iLen = GetDateFormat ( LOCALE_USER_DEFAULT, // locale for which date is to be formatted dwDateFlags, // flags specifying function options &sysTime, // date to be formatted 0, // date format string 0, // buffer for storing formatted string 0); // size of buffer ASSERT (iLen > 0); if ( iLen > 0 ) { int iResult = GetDateFormat ( LOCALE_USER_DEFAULT, // locale for which date is to be formatted dwDateFlags, // flags specifying function options &sysTime, // date to be formatted 0, // date format string date.GetBufferSetLength (iLen), // buffer for storing formatted string iLen); // size of buffer ASSERT (iResult); date.ReleaseBuffer (); if ( iResult ) pszDateTime = date; else hr = HRESULT_FROM_WIN32 (GetLastError ()); if ( iResult && bGetTime ) { // Get time // Get length to allocate buffer of sufficient size iLen = GetTimeFormat ( LOCALE_USER_DEFAULT, // locale for which date is to be formatted 0, // flags specifying function options &sysTime, // date to be formatted 0, // date format string 0, // buffer for storing formatted string 0); // size of buffer ASSERT (iLen > 0); if ( iLen > 0 ) { iResult = GetTimeFormat ( LOCALE_USER_DEFAULT, // locale for which date is to be formatted 0, // flags specifying function options &sysTime, // date to be formatted 0, // date format string time.GetBufferSetLength (iLen), // buffer for storing formatted string iLen); // size of buffer ASSERT (iResult); time.ReleaseBuffer (); if ( iResult ) { pszDateTime = date + L" " + time; } else hr = E_UNEXPECTED; } else hr = E_UNEXPECTED; } } else { hr = HRESULT_FROM_WIN32 (GetLastError ()); } } else { hr = HRESULT_FROM_WIN32 (GetLastError ()); } } else { hr = HRESULT_FROM_WIN32 (GetLastError ()); } return hr; } void DisplaySystemError (HWND hParent, DWORD dwErr) { AFX_MANAGE_STATE (AfxGetStaticModuleState ()); LPVOID lpMsgBuf; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPWSTR) &lpMsgBuf, 0, NULL); // Display the string. CString caption; VERIFY (caption.LoadString (IDS_CERTIFICATE_MANAGER)); CThemeContextActivator activator; ::MessageBox (hParent, (LPWSTR) lpMsgBuf, (LPCWSTR) caption, MB_OK); // Free the buffer. LocalFree (lpMsgBuf); } CString GetSystemMessage (DWORD dwErr) { AFX_MANAGE_STATE (AfxGetStaticModuleState ()); CString message; LPVOID lpMsgBuf; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPWSTR) &lpMsgBuf, 0, NULL ); message = (LPWSTR) lpMsgBuf; // Free the buffer. LocalFree (lpMsgBuf); return message; } bool MyGetOIDInfo (CString & string, LPCSTR pszObjId) { ASSERT (pszObjId); PCCRYPT_OID_INFO pOIDInfo; // This points to a constant data structure and must not be freed. bool bResult = true; pOIDInfo = ::CryptFindOIDInfo (CRYPT_OID_INFO_OID_KEY, (void *) pszObjId, 0); if ( pOIDInfo ) { string = pOIDInfo->pwszName; } else { int nLen = ::MultiByteToWideChar (CP_ACP, 0, pszObjId, -1, NULL, 0); ASSERT (nLen); if ( nLen ) { nLen = ::MultiByteToWideChar (CP_ACP, 0, pszObjId, -1, string.GetBufferSetLength (nLen), nLen); ASSERT (nLen); string.ReleaseBuffer (); } bResult = (nLen > 0) ? true : false; } return bResult; } bool IsWindowsNT() { OSVERSIONINFO versionInfo; ::ZeroMemory (&versionInfo, sizeof (OSVERSIONINFO)); versionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); BOOL bResult = ::GetVersionEx (&versionInfo); ASSERT (bResult); if ( bResult ) { if ( VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId ) bResult = TRUE; } return bResult ? true : false; } bool GetNameStringByType ( PCCERT_CONTEXT pCertContext, DWORD dwFlag, DWORD dwType, CString& szNameString) { bool bResult = false; DWORD dwTypePara = CERT_SIMPLE_NAME_STR | CERT_NAME_STR_REVERSE_FLAG; DWORD cchNameString = 0; DWORD dwResult = ::CertGetNameString (pCertContext, dwType, dwFlag, &dwTypePara, NULL, cchNameString); if ( dwResult > 1 ) { cchNameString = dwResult; LPWSTR pszNameString = new WCHAR[cchNameString]; if ( pszNameString ) { ::ZeroMemory (pszNameString, cchNameString*sizeof (WCHAR)); dwResult = ::CertGetNameString (pCertContext, dwType, dwFlag, &dwTypePara, pszNameString, cchNameString); ASSERT (dwResult > 1); if ( dwResult > 1 ) { szNameString = pszNameString; bResult = true; } delete [] pszNameString; } } return bResult; } CString GetNameString (PCCERT_CONTEXT pCertContext, DWORD dwFlag) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CString szNameString; DWORD dwTypes[] = {CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_EMAIL_TYPE, CERT_NAME_UPN_TYPE, CERT_NAME_DNS_TYPE, CERT_NAME_URL_TYPE, (DWORD) -1}; int nIndex = 0; while ( -1 != dwTypes[nIndex]) { if ( GetNameStringByType ( pCertContext, dwFlag, dwTypes[nIndex], szNameString) ) { break; } nIndex++; } if ( szNameString.IsEmpty () ) szNameString.FormatMessage (IDS_NOT_AVAILABLE); return szNameString; } bool CertHasEFSKeyUsage(PCCERT_CONTEXT pCertContext) { bool bFound = false; BOOL bResult = FALSE; DWORD cbUsage = 0; bResult = ::CertGetEnhancedKeyUsage (pCertContext, 0, // get extension and property NULL, &cbUsage); if ( bResult ) { PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE) new BYTE[cbUsage]; if ( pUsage ) { bResult = ::CertGetEnhancedKeyUsage (pCertContext, 0, // get extension and property pUsage, &cbUsage); if ( bResult ) { for (DWORD dwIndex = 0; dwIndex < pUsage->cUsageIdentifier; dwIndex++) { if ( !_stricmp (szOID_EFS_RECOVERY, pUsage->rgpszUsageIdentifier[dwIndex]) ) { bFound = true; break; } } } else { ASSERT (GetLastError () == CRYPT_E_NOT_FOUND); } delete [] pUsage; } } else { ASSERT (GetLastError () == CRYPT_E_NOT_FOUND); } return bFound; } ////// This stuff was stolen from windows\gina\snapins\gpedit (eric flo's stuff) ////// //************************************************************* // // CheckSlash() // // Purpose: Checks for an ending slash and adds one if // it is missing. // // Parameters: lpDir - directory // // Return: Pointer to the end of the string // // Comments: // // History: Date Author Comment // 6/19/95 ericflo Created // //************************************************************* LPWSTR CheckSlash (LPWSTR lpDir) { LPWSTR lpEnd = lpDir + lstrlen(lpDir); if (*(lpEnd - 1) != TEXT('\\')) { *lpEnd = TEXT('\\'); lpEnd++; *lpEnd = TEXT('\0'); } return lpEnd; } //************************************************************* // // RegDelnodeRecurse() // // Purpose: Deletes a registry key and all it's subkeys / values. // Called by RegDelnode // // Parameters: hKeyRoot - Root key // lpSubKey - SubKey to delete // // Return: ERROR_SUCCESS if successful // something else if an error occurs // // Comments: // // History: Date Author Comment // 10/3/95 ericflo Created // 5/13/98 BryanWal Modified to return LRESULT // //************************************************************* LRESULT RegDelnodeRecurse (HKEY hKeyRoot, LPWSTR lpSubKey) { // // First, see if we can delete the key without having // to recurse. // LONG lResult = RegDeleteKey(hKeyRoot, lpSubKey); if (lResult == ERROR_SUCCESS) { return lResult; } HKEY hKey = 0; lResult = RegOpenKeyEx (hKeyRoot, lpSubKey, 0, KEY_READ, &hKey); if (lResult != ERROR_SUCCESS) { return lResult; } LPWSTR lpEnd = CheckSlash(lpSubKey); // // Enumerate the keys // DWORD dwSize = MAX_PATH; FILETIME ftWrite; WCHAR szName[MAX_PATH]; lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite); if (lResult == ERROR_SUCCESS) { do { lstrcpy (lpEnd, szName); if ( ERROR_SUCCESS != RegDelnodeRecurse(hKeyRoot, lpSubKey) ) { break; } // // Enumerate again // dwSize = MAX_PATH; lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite); } while (lResult == ERROR_SUCCESS); } lpEnd--; *lpEnd = TEXT('\0'); RegCloseKey (hKey); // // Try again to delete the key // lResult = RegDeleteKey(hKeyRoot, lpSubKey); if (lResult == ERROR_SUCCESS) { return lResult; } return lResult; } //************************************************************* // // RegDelnode() // // Purpose: Deletes a registry key and all it's subkeys / values // // Parameters: hKeyRoot - Root key // lpSubKey - SubKey to delete // // Return: ERROR_SUCCESS if successful // something else if an error occurs // // Comments: // // History: Date Author Comment // 10/3/95 ericflo Created // 5/13/98 BryanWal Modified to return LRESULT // //************************************************************* LRESULT RegDelnode (HKEY hKeyRoot, LPWSTR lpSubKey) { const size_t BUF_LEN = 2 * MAX_PATH; WCHAR szDelKey[BUF_LEN]; ::ZeroMemory (szDelKey, BUF_LEN * sizeof (WCHAR)); wcsncpy (szDelKey, lpSubKey, BUF_LEN - 1); return RegDelnodeRecurse(hKeyRoot, szDelKey); } HRESULT DisplayCertificateCountByStore(LPCONSOLE pConsole, CCertStore* pCertStore, bool bIsGPE) { if ( !pConsole || !pCertStore ) return E_POINTER; _TRACE (1, L"Entering DisplayCertificateCountByStore- %s \n", (LPCWSTR) pCertStore->GetStoreName ()); AFX_MANAGE_STATE (AfxGetStaticModuleState ( )); IConsole2* pConsole2 = 0; HRESULT hr = pConsole->QueryInterface (IID_PPV_ARG (IConsole2, &pConsole2)); if (SUCCEEDED (hr)) { CString statusText; int nCertCount = 0; switch (pCertStore->GetStoreType ()) { case ACRS_STORE: nCertCount = pCertStore->GetCTLCount (); break; case TRUST_STORE: if ( bIsGPE ) { nCertCount = pCertStore->GetCTLCount (); } else nCertCount = pCertStore->GetCertCount (); break; default: nCertCount = pCertStore->GetCertCount (); break; } switch (nCertCount) { case 0: { UINT formatID = 0; switch (pCertStore->GetStoreType ()) { case ACRS_STORE: formatID = IDS_STATUS_NO_AUTOENROLLMENT_OBJECTS; break; case TRUST_STORE: if ( bIsGPE ) { formatID = IDS_STATUS_NO_CTLS; } else formatID = IDS_STATUS_NO_CERTS; break; default: formatID = IDS_STATUS_NO_CERTS; break; } statusText.FormatMessage (formatID, pCertStore->GetLocalizedName ()); } break; case 1: { UINT formatID = 0; switch (pCertStore->GetStoreType ()) { case ACRS_STORE: formatID = IDS_STATUS_ONE_AUTOENROLLMENT_OBJECT; break; case TRUST_STORE: if ( bIsGPE ) { formatID = IDS_STATUS_ONE_CTL; } else formatID = IDS_STATUS_ONE_CERT; break; default: formatID = IDS_STATUS_ONE_CERT; break; } statusText.FormatMessage (formatID, pCertStore->GetLocalizedName ()); } break; default: { UINT formatID = 0; switch (pCertStore->GetStoreType ()) { case ACRS_STORE: formatID = IDS_STATUS_X_AUTOENROLLMENT_OBJECTS; break; case TRUST_STORE: if ( bIsGPE ) { formatID = IDS_STATUS_X_CTLS; } else formatID = IDS_STATUS_X_CERTS; break; default: formatID = IDS_STATUS_X_CERTS; break; } statusText.FormatMessage (formatID, (LPCWSTR) pCertStore->GetLocalizedName (), nCertCount); } break; } hr = pConsole2->SetStatusText ((LPWSTR)(LPCWSTR) statusText); pConsole2->Release (); } _TRACE (-1, L"Leaving DisplayCertificateCountByStore- %s \n", (LPCWSTR) pCertStore->GetStoreName ()); return hr; } CString GetF1HelpFilename() { static CString helpFileName; if ( helpFileName.IsEmpty () ) { UINT result = ::GetSystemWindowsDirectory ( helpFileName.GetBufferSetLength (MAX_PATH+1), MAX_PATH); ASSERT(result != 0 && result <= MAX_PATH); helpFileName.ReleaseBuffer (); if ( result != 0 && result <= MAX_PATH ) helpFileName += CM_CONTEXT_HELP; } return helpFileName; } //+--------------------------------------------------------------------------- // // Function: LocaleStrCmp // // Synopsis: Do a case insensitive string compare that is safe for any // locale. // // Arguments: [ptsz1] - strings to compare // [ptsz2] // // Returns: -1, 0, or 1 just like lstrcmpi // // History: 10-28-96 DavidMun Created // // Notes: This is slower than lstrcmpi, but will work when sorting // strings even in Japanese. // //---------------------------------------------------------------------------- int LocaleStrCmp(LPCWSTR ptsz1, LPCWSTR ptsz2) { int iRet = 0; iRet = CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH, ptsz1, -1, ptsz2, -1); if (iRet) { iRet -= 2; // convert to lstrcmpi-style return -1, 0, or 1 if ( 0 == iRet ) { UNICODE_STRING unistr1; unistr1.Length = (USHORT) (wcslen(ptsz1) * sizeof(WCHAR)); unistr1.MaximumLength = unistr1.Length; unistr1.Buffer = (LPWSTR)ptsz1; UNICODE_STRING unistr2; unistr2.Length = (USHORT) (wcslen(ptsz2) * sizeof(WCHAR)); unistr2.MaximumLength = unistr2.Length; unistr2.Buffer = (LPWSTR)ptsz2; iRet = ::RtlCompareUnicodeString( &unistr1, &unistr2, FALSE ); } } else { _TRACE (0, L"CompareString (%s, %s) failed: 0x%x\n", ptsz1, ptsz2, GetLastError ()); } return iRet; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// HPROPSHEETPAGE MyCreatePropertySheetPage(AFX_OLDPROPSHEETPAGE* psp) { PROPSHEETPAGE_V3 sp_v3 = {0}; CopyMemory (&sp_v3, psp, psp->dwSize); sp_v3.dwSize = sizeof(sp_v3); return (::CreatePropertySheetPage (&sp_v3)); } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include //-------------------------------------------------------------------------- // // Defines // //-------------------------------------------------------------------------- #define DS_RETEST_SECONDS 3 #define CVT_BASE (1000 * 1000 * 10) #define CVT_SECONDS (1) #define CERTTYPE_SECURITY_DESCRIPTOR_NAME L"NTSecurityDescriptor" #define TEMPLATE_CONTAINER_NAME L"CN=Certificate Templates,CN=Public Key Services,CN=Services," #define SCHEMA_CONTAINER_NAME L"CN=Schema," HRESULT myHError(HRESULT hr) { if (S_OK != hr && S_FALSE != hr && !FAILED(hr)) { hr = HRESULT_FROM_WIN32(hr); if ( SUCCEEDED (hr) ) { // A call failed without properly setting an error condition! hr = E_UNEXPECTED; } } return(hr); } HRESULT myDupString( IN WCHAR const *pwszIn, IN WCHAR **ppwszOut) { HRESULT hr = S_OK; size_t cb = (wcslen(pwszIn) + 1) * sizeof(WCHAR); *ppwszOut = (WCHAR *) LocalAlloc(LMEM_FIXED, cb); if (NULL == *ppwszOut) { hr = E_OUTOFMEMORY; goto error; } CopyMemory(*ppwszOut, pwszIn, cb); hr = S_OK; error: return(hr); } DWORD CAGetAuthoritativeDomainDn( IN LDAP* LdapHandle, OUT CString* pszDomainDn, OUT CString* pszConfigDn ) /*++ Routine Description: This routine simply queries the operational attributes for the domaindn and configdn. The strings returned by this routine must be freed by the caller using RtlFreeHeap() using the process heap. Parameters: LdapHandle : a valid handle to an ldap session pszDomainDn : a pointer to a string to be allocated in this routine pszConfigDn : a pointer to a string to be allocated in this routine Return Values: An error from the win32 error space. ERROR_SUCCESS and Other operation errors. --*/ { DWORD WinError = ERROR_SUCCESS; ULONG LdapError; LDAPMessage *SearchResult = NULL; LDAPMessage *Entry = NULL; WCHAR *Attr = NULL; BerElement *BerElement; WCHAR **Values = NULL; WCHAR *AttrArray[3]; WCHAR *DefaultNamingContext = L"defaultNamingContext"; WCHAR *ConfigNamingContext = L"configurationNamingContext"; WCHAR *ObjectClassFilter = L"objectClass=*"; // // These must be present // // // Set the out parameters to null // if ( pszDomainDn ) *pszDomainDn = L""; if ( pszConfigDn ) *pszConfigDn = L""; // // Query for the ldap server oerational attributes to obtain the default // naming context. // AttrArray[0] = DefaultNamingContext; AttrArray[1] = ConfigNamingContext; // this is the sentinel AttrArray[2] = NULL; // this is the sentinel __try { LdapError = ldap_search_sW(LdapHandle, NULL, LDAP_SCOPE_BASE, ObjectClassFilter, AttrArray, FALSE, &SearchResult); WinError = LdapMapErrorToWin32(LdapError); if (ERROR_SUCCESS == WinError) { Entry = ldap_first_entry(LdapHandle, SearchResult); if (Entry) { Attr = ldap_first_attributeW(LdapHandle, Entry, &BerElement); while (Attr) { if (!_wcsicmp(Attr, DefaultNamingContext)) { if ( pszDomainDn ) { Values = ldap_get_values(LdapHandle, Entry, Attr); if (Values && Values[0]) { *pszDomainDn = Values[0]; } ldap_value_free(Values); } } else if (!_wcsicmp(Attr, ConfigNamingContext)) { if ( pszConfigDn ) { Values = ldap_get_values(LdapHandle, Entry, Attr); if (Values && Values[0]) { *pszConfigDn = Values[0]; } ldap_value_free(Values); } } Attr = ldap_next_attribute(LdapHandle, Entry, BerElement); } } if ( pszDomainDn && pszDomainDn->IsEmpty () ) { // // We could get the default domain - bail out // WinError = ERROR_CANT_ACCESS_DOMAIN_INFO; } else if ( pszConfigDn && pszConfigDn->IsEmpty () ) { // // We could get the default domain - bail out // WinError = ERROR_CANT_ACCESS_DOMAIN_INFO; } } } __except(WinError = GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER) { } // make sure we free this if (SearchResult) ldap_msgfree( SearchResult ); return WinError; } HRESULT myDoesDSExist(IN BOOL fRetry) { HRESULT hr = S_OK; static BOOL s_fKnowDSExists = FALSE; static HRESULT s_hrDSExists = HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN); static FILETIME s_ftNextTest = {0,0}; if (s_fKnowDSExists && (s_hrDSExists != S_OK) && fRetry) // s_fKnowDSExists = FALSE; // force a retry { FILETIME ftCurrent; GetSystemTimeAsFileTime(&ftCurrent); // if Compare is < 0 (next < current), force retest if (0 > CompareFileTime(&s_ftNextTest, &ftCurrent)) s_fKnowDSExists = FALSE; } if (!s_fKnowDSExists) { GetSystemTimeAsFileTime(&s_ftNextTest); // set NEXT in 100ns increments ((LARGE_INTEGER *) &s_ftNextTest)->QuadPart += (__int64) (CVT_BASE * CVT_SECONDS * 60) * DS_RETEST_SECONDS; // NetApi32 is delay loaded, so wrap to catch problems when it's not available __try { DOMAIN_CONTROLLER_INFO *pDCI; DSROLE_PRIMARY_DOMAIN_INFO_BASIC *pDsRole; // ensure we're not standalone pDsRole = NULL; hr = DsRoleGetPrimaryDomainInformation( // Delayload wrapped NULL, DsRolePrimaryDomainInfoBasic, (BYTE **) &pDsRole); if (S_OK == hr && (pDsRole->MachineRole == DsRole_RoleStandaloneServer || pDsRole->MachineRole == DsRole_RoleStandaloneWorkstation)) { hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN); } if (NULL != pDsRole) { DsRoleFreeMemory(pDsRole); // Delayload wrapped } if (S_OK == hr) { // not standalone; return info on our DS pDCI = NULL; hr = DsGetDcName( // Delayload wrapped NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_PREFERRED, &pDCI); if (S_OK == hr && 0 == (pDCI->Flags & DS_DS_FLAG)) { hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO); } if (NULL != pDCI) { NetApiBufferFree(pDCI); // Delayload wrapped } } s_fKnowDSExists = TRUE; } __except(hr = GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER) { } // else just allow users without netapi flounder with timeouts // if ds not available... s_hrDSExists = myHError(hr); } return(s_hrDSExists); } HRESULT myRobustLdapBindEx( OUT LDAP ** ppldap, OPTIONAL OUT LPWSTR* ppszForestDNSName, IN BOOL fGC) { HRESULT hr = S_OK; BOOL fForceRediscovery = FALSE; DWORD dwGetDCFlags = DS_RETURN_DNS_NAME; PDOMAIN_CONTROLLER_INFO pDomainInfo = NULL; LDAP *pld = NULL; WCHAR const *pwszDomainControllerName = NULL; ULONG ldaperr = 0; if (fGC) { dwGetDCFlags |= DS_GC_SERVER_REQUIRED; } do { if (fForceRediscovery) { dwGetDCFlags |= DS_FORCE_REDISCOVERY; } ldaperr = LDAP_SERVER_DOWN; // netapi32!DsGetDcName is delay loaded, so wrap __try { // Get the GC location hr = DsGetDcName( NULL, // Delayload wrapped NULL, NULL, NULL, dwGetDCFlags, &pDomainInfo); } __except(hr = GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER) { } if (S_OK != hr) { hr = HRESULT_FROM_WIN32(hr); if (fForceRediscovery) { goto error; } fForceRediscovery = TRUE; continue; } if (NULL == pDomainInfo || (fGC && 0 == (DS_GC_FLAG & pDomainInfo->Flags)) || 0 == (DS_DNS_CONTROLLER_FLAG & pDomainInfo->Flags) || NULL == pDomainInfo->DomainControllerName) { if (!fForceRediscovery) { fForceRediscovery = TRUE; continue; } hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO); goto error; } pwszDomainControllerName = pDomainInfo->DomainControllerName; // skip past forward slashes (why are they there?) while (L'\\' == *pwszDomainControllerName) { pwszDomainControllerName++; } // bind to ds pld = ldap_init( const_cast(pwszDomainControllerName), fGC? LDAP_GC_PORT : LDAP_PORT); if (NULL == pld) { ldaperr = LdapGetLastError(); } else { // do this because we're explicitly setting DC name ldaperr = ldap_set_option(pld, LDAP_OPT_AREC_EXCLUSIVE, LDAP_OPT_ON); ldaperr = ldap_bind_s(pld, NULL, NULL, LDAP_AUTH_NEGOTIATE); } hr = myHError(LdapMapErrorToWin32(ldaperr)); if (fForceRediscovery) { break; } fForceRediscovery = TRUE; } while (LDAP_SERVER_DOWN == ldaperr); // everything's cool, party down if (S_OK == hr) { if (NULL != ppszForestDNSName) { hr = myDupString( pDomainInfo->DomainControllerName, ppszForestDNSName); if(S_OK != hr) goto error; } *ppldap = pld; pld = NULL; } error: if (NULL != pld) { ldap_unbind(pld); } // we know netapi32 was already loaded safely (that's where we got // pDomainInfo), so no need to wrap if (NULL != pDomainInfo) { NetApiBufferFree(pDomainInfo); // Delayload wrapped } return(hr); } HRESULT myRobustLdapBind( OUT LDAP ** ppldap, IN BOOL fGC) { return(myRobustLdapBindEx(ppldap, NULL, fGC)); } void CheckDomainVersion () { _TRACE (1, L"Entering CheckDomainVersion()\n"); AFX_MANAGE_STATE (AfxGetStaticModuleState ()); HRESULT hr=S_OK; DWORD dwErr=0; ULONG ldaperr=0; struct l_timeval timeout; LPWSTR awszAttr[2]; LDAP *pld = NULL; CString szConfig; CString szDN; LDAPMessage *SearchResult = NULL; //************************************************************* // // check the schema version // _TRACE (0, L"Checking the schema version...\n"); //retrieve the ldap handle and the config string if(S_OK != myDoesDSExist(TRUE)) { _TRACE (0, L"No DS exists.\n"); goto error; } if(S_OK != (hr = myRobustLdapBind(&pld, FALSE))) { _TRACE (0, L"Error: Failed to bind to the DS.\n"); goto error; } dwErr = CAGetAuthoritativeDomainDn(pld, NULL, &szConfig); if(ERROR_SUCCESS != dwErr) { _TRACE (0, L"Error: Failed to get the domain name.\n"); hr = HRESULT_FROM_WIN32(dwErr); goto error; } szDN = SCHEMA_CONTAINER_NAME; szDN += szConfig; timeout.tv_sec = 300; timeout.tv_usec = 0; awszAttr[0]=L"cn"; awszAttr[1]=NULL; ldaperr = ldap_search_stW( pld, const_cast ((PCWSTR) szDN), LDAP_SCOPE_ONELEVEL, L"(cn=ms-PKI-Enrollment-Flag)", awszAttr, 0, &timeout, &SearchResult); if ( LDAP_SUCCESS != ldaperr ) { _TRACE (0, L"We have W2K Schema. Exit\n"); g_bSchemaIsW2K = true; hr = S_OK; goto error; } error: if(SearchResult) ldap_msgfree(SearchResult); if (pld) ldap_unbind(pld); _TRACE (1, L"Entering CheckDomainVersion ()\n"); }