windows-nt/Source/XPSP1/NT/admin/snapin/certmgr/certmgr.cpp
2020-09-26 16:20:57 +08:00

2100 lines
61 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997 - 2001.
//
// File: CertMgr.cpp
//
// Contents: Implementation of DLL Exports
//
//----------------------------------------------------------------------------
#include "stdafx.h"
#include <initguid.h>
#include <gpedit.h>
#include "CertMgr_i.c"
#include "about.h" // CCertMgrAbout
#include "compdata.h" // CCertMgrSnapin, CCertMgrExtension
#pragma warning(push, 3)
#include <compuuid.h> // UUIDs for Computer Management
#include "uuids.h"
#include <efsstruc.h>
#include <sceattch.h> // For Security Configuratino Editor snapin
#include <ntverp.h> // VER_PRODUCTVERSION_STR, VERS_COMPANYNAME_STR
#include <typeinfo.h>
#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 <winldap.h>
#include <ntldap.h>
#include <dsrole.h>
#include <dsgetdc.h>
#include <accctrl.h>
#include <lmaccess.h>
#include <lmapibuf.h>
#include <lmerr.h>
//--------------------------------------------------------------------------
//
// 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<WCHAR *>(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 <PWCHAR>((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");
}