Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1617 lines
54 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997-2002.
//
// File: CertTmpl.cpp
//
// Contents: Implementation of DLL Exports
//
//----------------------------------------------------------------------------
#include "stdafx.h"
#define INITGUID
#pragma warning(push,3)
#include <initguid.h>
#pragma warning(pop)
#include "CertTmpl_i.c"
#include "about.h" // CCertTemplatesAbout
#include "compdata.h" // CCertTmplSnapin
#include "uuids.h"
#pragma warning(push,3)
#include <ntverp.h> // VER_PRODUCTVERSION_STR
#include <typeinfo.h>
#define INCL_WINSOCK_API_TYPEDEFS 1
#include <winsock2.h>
#include <svcguid.h>
#include <winldap.h>
#pragma warning(pop)
#include "chooser.cpp"
#include "ShellExt.h"
#include "PolicyOID.h"
extern POLICY_OID_LIST g_policyOIDList;
USE_HANDLE_MACROS ("CERTTMPL (CertTmpl.cpp)")
//
// This is used by the nodetype utility routines in stdutils.cpp
//
const struct NODETYPE_GUID_ARRAYSTRUCT g_NodetypeGuids[CERTTMPL_NUMTYPES] =
{
{ // CERTTMPL_SNAPIN
structuuidNodetypeSnapin,
lstruuidNodetypeSnapin },
{ // CERT_TEMPLATE
structuuidNodetypeCertTemplate,
lstruuidNodetypeCertTemplate }
};
const struct NODETYPE_GUID_ARRAYSTRUCT* g_aNodetypeGuids = g_NodetypeGuids;
const int g_cNumNodetypeGuids = CERTTMPL_NUMTYPES;
const CLSID CLSID_CertTemplateShellExt = /* {11BDCE06-D55C-44e9-BC0B-8655F89E8CC5} */
{ 0x11bdce06, 0xd55c, 0x44e9, { 0xbc, 0xb, 0x86, 0x55, 0xf8, 0x9e, 0x8c, 0xc5 } };
HINSTANCE g_hInstance = 0;
CComModule _Module;
BEGIN_OBJECT_MAP (ObjectMap)
OBJECT_ENTRY (CLSID_CertTemplatesSnapin, CCertTmplSnapin)
OBJECT_ENTRY (CLSID_CertTemplatesAbout, CCertTemplatesAbout)
OBJECT_ENTRY(CLSID_CertTemplateShellExt, CCertTemplateShellExt)
END_OBJECT_MAP ()
class CCertTmplApp : public CWinApp
{
public:
CCertTmplApp ();
virtual ~CCertTmplApp ();
virtual BOOL InitInstance ();
virtual int ExitInstance ();
private:
};
CCertTmplApp theApp;
CCertTmplApp::CCertTmplApp ()
{
}
CCertTmplApp::~CCertTmplApp ()
{
}
BOOL CCertTmplApp::InitInstance ()
{
#ifdef _MERGE_PROXYSTUB
hProxyDll = m_hInstance;
#endif
g_hInstance = m_hInstance;
AfxSetResourceHandle (m_hInstance);
_Module.Init (ObjectMap, m_hInstance);
AfxInitRichEdit();
#if DBG
CheckDebugOutputLevel ();
#endif
SHFusionInitializeFromModuleID (m_hInstance, 2);
return CWinApp::InitInstance ();
}
int CCertTmplApp::ExitInstance ()
{
SHFusionUninitialize();
while ( !g_policyOIDList.IsEmpty () )
{
CPolicyOID* pPolicyOID = g_policyOIDList.RemoveHead ();
if ( pPolicyOID )
delete pPolicyOID;
}
_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
STDAPI DllRegisterServer (void)
{
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
// 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_CERTTMPL));
VERIFY (text.LoadString (IDS_INSUFFICIENT_RIGHTS_TO_REGISTER_CERTTMPL));
MessageBox (NULL, text, caption, MB_OK);
return hr;
}
try
{
CString strGUID;
CString snapinName;
AMC::CRegKey rkSnapins;
BOOL fFound = rkSnapins.OpenKeyEx (HKEY_LOCAL_MACHINE, SNAPINS_KEY);
ASSERT (fFound);
if ( fFound )
{
{
AMC::CRegKey rkCertTmplSnapin;
hr = GuidToCString (&strGUID, CLSID_CertTemplatesSnapin);
if ( FAILED (hr) )
{
ASSERT (FALSE);
return SELFREG_E_CLASS;
}
rkCertTmplSnapin.CreateKeyEx (rkSnapins, strGUID);
ASSERT (rkCertTmplSnapin.GetLastError () == ERROR_SUCCESS);
rkCertTmplSnapin.SetString (g_szNodeType, g_aNodetypeGuids[CERTTMPL_SNAPIN].bstr);
VERIFY (snapinName.LoadString (IDS_CERTTMPL_REGISTRY));
rkCertTmplSnapin.SetString (g_szNameString, (PCWSTR) snapinName);
hr = GuidToCString (&strGUID, CLSID_CertTemplatesAbout);
if ( FAILED (hr) )
{
ASSERT (FALSE);
return SELFREG_E_CLASS;
}
rkCertTmplSnapin.SetString (L"About", strGUID);
rkCertTmplSnapin.SetString (L"Provider", L"Microsoft");
// security review 2/20/2002 BryanWal ok
size_t len = strlen (VER_PRODUCTVERSION_STR);
PWSTR pszVer = new WCHAR[len+1];
if ( pszVer )
{
// security review BryanWal 02/20/2002 ok
::ZeroMemory (pszVer, (len+1) * sizeof (WCHAR));
// security review BryanWal 02/20/2002 cnt should be len+1
// to include conversion of NULL char
len = ::mbstowcs (pszVer, VER_PRODUCTVERSION_STR, len+1);
rkCertTmplSnapin.SetString (L"Version", pszVer);
delete [] pszVer;
}
AMC::CRegKey rkCertTmplMgrStandalone;
rkCertTmplMgrStandalone.CreateKeyEx (rkCertTmplSnapin, g_szStandAlone);
ASSERT (rkCertTmplMgrStandalone.GetLastError () == ERROR_SUCCESS);
AMC::CRegKey rkMyNodeTypes;
rkMyNodeTypes.CreateKeyEx (rkCertTmplSnapin, g_szNodeTypes);
ASSERT (rkMyNodeTypes.GetLastError () == ERROR_SUCCESS);
AMC::CRegKey rkMyNodeType;
for (int i = CERTTMPL_SNAPIN; i < CERTTMPL_NUMTYPES; i++)
{
rkMyNodeType.CreateKeyEx (rkMyNodeTypes, g_aNodetypeGuids[i].bstr);
ASSERT (rkMyNodeType.GetLastError () == ERROR_SUCCESS);
rkMyNodeType.CloseKey ();
}
//
// BryanWal 5/18/00
// 94793: MUI: MMC: Certificates snap-in stores its display
// information in the registry
//
// MMC now supports NameStringIndirect
//
// NTRAID# Bug9 611500 prefast: certtmpl: certtmpl.cpp(247) :
// warning 53: Call to 'GetModuleFileNameW' may not
// zero-terminate string 'achModuleFileName'.
// Fix by zero'ing out the buffer and passing in 1 less than
// the buffer size to GetModuleFileName
WCHAR achModuleFileName[MAX_PATH+20];
::ZeroMemory (achModuleFileName, sizeof(achModuleFileName)/sizeof(WCHAR));
if (0 != ::GetModuleFileName(
AfxGetInstanceHandle(),
achModuleFileName,
sizeof(achModuleFileName)/sizeof(WCHAR) - 1))
{
CString strNameIndirect;
strNameIndirect.Format (L"@%s,-%d",
achModuleFileName,
IDS_CERTTMPL_REGISTRY);
rkCertTmplSnapin.SetString (L"NameStringIndirect",
strNameIndirect );
}
rkCertTmplSnapin.CloseKey ();
}
AMC::CRegKey rkNodeTypes;
fFound = rkNodeTypes.OpenKeyEx (HKEY_LOCAL_MACHINE, NODE_TYPES_KEY);
ASSERT (fFound);
if ( fFound )
{
AMC::CRegKey rkNodeType;
for (int i = CERTTMPL_SNAPIN; i < CERTTMPL_NUMTYPES; i++)
{
rkNodeType.CreateKeyEx (rkNodeTypes, g_aNodetypeGuids[i].bstr);
ASSERT (rkNodeType.GetLastError () == ERROR_SUCCESS);
rkNodeType.CloseKey ();
}
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)
{
LRESULT lResult = 0;
try
{
AMC::CRegKey rkSnapins;
BOOL fFound = FALSE;
do
{
CString strGUID;
CString snapinName;
fFound = rkSnapins.OpenKeyEx (HKEY_LOCAL_MACHINE, SNAPINS_KEY);
ASSERT (fFound);
if ( fFound )
{
{
AMC::CRegKey rkCertTmplSnapin;
HRESULT hr = GuidToCString (&strGUID, CLSID_CertTemplatesSnapin);
if ( FAILED (hr) )
{
ASSERT (FALSE);
lResult = SELFREG_E_CLASS;
break;
}
lResult = RegDelnode (rkSnapins, (PCWSTR) strGUID);
}
AMC::CRegKey rkNodeTypes;
fFound = rkNodeTypes.OpenKeyEx (HKEY_LOCAL_MACHINE, NODE_TYPES_KEY);
ASSERT (fFound);
if ( fFound )
{
for (int i = CERTTMPL_SNAPIN; i < CERTTMPL_NUMTYPES; i++)
{
lResult = RegDelnode (rkNodeTypes, g_aNodetypeGuids[i].bstr);
}
rkNodeTypes.CloseKey ();
}
else
{
lResult = SELFREG_E_CLASS;
break;
}
}
else
{
lResult = SELFREG_E_CLASS;
break;
}
} while (0);
if ( fFound )
rkSnapins.CloseKey ();
}
catch (COleException* e)
{
ASSERT (FALSE);
e->Delete ();
lResult = SELFREG_E_CLASS;
}
if ( SELFREG_E_CLASS != lResult )
_Module.UnregisterServer ();
return HRESULT_FROM_WIN32 (lResult);
}
STDAPI DllInstall(BOOL /*bInstall*/, PCWSTR /*pszCmdLine*/)
{
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
// 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)
{
// 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
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 )
{
int iResult = GetDateFormat (
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
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 )
{
// 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 = 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;
// security review BryanWal 2/20/2002 ok because message is from system
FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwErr,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(PWSTR) &lpMsgBuf, 0, NULL);
// Display the string.
CThemeContextActivator activator;
CString caption;
VERIFY (caption.LoadString (IDS_CERTTMPL));
::MessageBox (hParent, (PWSTR) lpMsgBuf, (PCWSTR) caption, MB_OK);
// Free the buffer.
LocalFree (lpMsgBuf);
}
bool IsWindowsNT()
{
OSVERSIONINFO versionInfo;
// security review BryanWal 2/20/2002 ok
::ZeroMemory (&versionInfo, sizeof (versionInfo));
versionInfo.dwOSVersionInfoSize = sizeof (versionInfo);
BOOL bResult = ::GetVersionEx (&versionInfo);
ASSERT (bResult);
if ( bResult )
{
if ( VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId )
bResult = TRUE;
}
return bResult ? true : false;
}
////// This stuff was stolen from windows\gina\snapins\gpedit (eric flo's stuff) //////
//*************************************************************
//
// RegDelnodeRecurse()
//
// Purpose: Deletes a registry key and all it's subkeys / values.
// Called by RegDelnode
//
// Parameters: hKeyRoot - Root key
// pwszSubKey - 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, CString szSubKey)
{
ASSERT (hKeyRoot && !szSubKey.IsEmpty ());
if ( !hKeyRoot || szSubKey.IsEmpty () )
return ERROR_INVALID_PARAMETER;
//
// First, see if we can delete the key without having
// to recurse.
//
LONG lResult = ::RegDeleteKey(hKeyRoot, szSubKey);
if (lResult == ERROR_SUCCESS)
{
return lResult;
}
HKEY hKey = 0;
lResult = ::RegOpenKeyEx (hKeyRoot, szSubKey, 0, KEY_READ, &hKey);
if (lResult == ERROR_SUCCESS)
{
// ensure szSubKey ends with a slash
if ( L'\\' != szSubKey.GetAt (szSubKey.GetLength () - 1) )
{
szSubKey += L"\\";
}
//
// Enumerate the keys
//
DWORD dwSize = MAX_PATH;
FILETIME ftWrite;
WCHAR szName[MAX_PATH];
lResult = ::RegEnumKeyEx(hKey, 0,
szName,
&dwSize, // size in TCHARS of szName, including terminating NULL (on input)
NULL,
NULL, NULL, &ftWrite);
if (lResult == ERROR_SUCCESS)
{
do {
if ( ERROR_SUCCESS != RegDelnodeRecurse (hKeyRoot, szSubKey + szName) )
{
break;
}
//
// Enumerate again
//
dwSize = MAX_PATH;
lResult = ::RegEnumKeyEx(hKey, 0,
szName,
&dwSize, // size in TCHARS of szName, including terminating NULL (on input)
NULL,
NULL, NULL, &ftWrite);
} while (lResult == ERROR_SUCCESS);
}
::RegCloseKey (hKey);
}
// remove slash from szSubKey
szSubKey.Delete (szSubKey.GetLength () - 1, 1);
//
// Try again to delete the key
//
lResult = ::RegDeleteKey(hKeyRoot, szSubKey);
if (lResult == ERROR_SUCCESS)
{
return lResult;
}
return lResult;
}
//*************************************************************
//
// RegDelnode()
//
// Purpose: Deletes a registry key and all it's subkeys / values
//
// Parameters: hKeyRoot - Root key
// pwszSubKey - 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, CString szSubKey)
{
ASSERT (hKeyRoot && !szSubKey.IsEmpty ());
if ( !hKeyRoot || szSubKey.IsEmpty () )
return ERROR_INVALID_PARAMETER;
return RegDelnodeRecurse (hKeyRoot, szSubKey);
}
//+--------------------------------------------------------------------------
//
// Function: InitObjectPickerForDomainComputers
//
// Synopsis: Call IDsObjectPicker::Initialize with arguments that will
// set it to allow the user to pick a single computer object.
//
// Arguments: [pDsObjectPicker] - object picker interface instance
//
// Returns: Result of calling IDsObjectPicker::Initialize.
//
// History: 10-14-1998 DavidMun Created
//
//---------------------------------------------------------------------------
HRESULT InitObjectPickerForDomainComputers(IDsObjectPicker *pDsObjectPicker)
{
//
// Prepare to initialize the object picker.
// Set up the array of scope initializer structures.
//
static const int SCOPE_INIT_COUNT = 1;
DSOP_SCOPE_INIT_INFO aScopeInit[SCOPE_INIT_COUNT];
// security review BryanWal 02/02/2002 ok
::ZeroMemory(aScopeInit, sizeof(aScopeInit));
//
// Since we just want computer objects from every scope, combine them
// all in a single scope initializer.
//
aScopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
aScopeInit[0].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN
| DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN;
aScopeInit[0].FilterFlags.Uplevel.flBothModes =
DSOP_FILTER_COMPUTERS;
aScopeInit[0].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS;
//
// Put the scope init array into the object picker init array
//
DSOP_INIT_INFO InitInfo;
// security review BryanWal 02/02/2002 ok
::ZeroMemory(&InitInfo, sizeof(InitInfo));
InitInfo.cbSize = sizeof(InitInfo);
InitInfo.pwzTargetComputer = NULL; // NULL == local machine
InitInfo.cDsScopeInfos = SCOPE_INIT_COUNT;
InitInfo.aDsScopeInfos = aScopeInit;
//
// Note object picker makes its own copy of InitInfo. Also note
// that Initialize may be called multiple times, last call wins.
//
return pDsObjectPicker->Initialize(&InitInfo);
}
CString GetSystemMessage (DWORD dwErr)
{
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
CString message;
if ( HRESULT_FROM_WIN32 (ERROR_NO_SUCH_DOMAIN) == dwErr )
{
VERIFY (message.LoadString (IDS_ERROR_NO_SUCH_DOMAIN));
}
else
{
LPVOID lpMsgBuf = 0;
// security review BryanWal 02/02/2002 ok because message is from system
FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwErr,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(PWSTR) &lpMsgBuf, 0, NULL );
message = (PWSTR) lpMsgBuf;
// Remove white space (including new line characters)
message.TrimRight ();
// Free the buffer.
LocalFree (lpMsgBuf);
}
return message;
}
//+---------------------------------------------------------------------------
//
// 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)
{
ASSERT (ptsz1 && ptsz2);
if ( !ptsz1 || !ptsz2 )
return 0;
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;
UNICODE_STRING unistr2;
// security review 2/20/2002 BryanWal ok - Length is length in BYTES
::RtlInitUnicodeString (&unistr1, ptsz1);
// security review 2/20/2002 BryanWal ok - Length is length in BYTES
::RtlInitUnicodeString (&unistr2, ptsz2);
iRet = ::RtlCompareUnicodeString(
&unistr1,
&unistr2,
FALSE );
}
}
else
{
DWORD dwErr = GetLastError ();
_TRACE (0, L"CompareString (%s, %s) failed: 0x%x\n", ptsz1, ptsz2, dwErr);
}
return iRet;
}
void FreeStringArray (PWSTR* rgpszStrings, DWORD dwAddCount)
{
if ( rgpszStrings )
{
for (DWORD dwIndex = 0; dwIndex < dwAddCount; dwIndex++)
{
if ( rgpszStrings[dwIndex] )
CoTaskMemFree (rgpszStrings[dwIndex]);
}
CoTaskMemFree (rgpszStrings);
}
}
HRESULT DisplayRootNodeStatusBarText (LPCONSOLE pConsole)
{
if ( !pConsole )
return E_POINTER;
_TRACE (1, L"Entering DisplayRootNodeStatusBarText\n");
AFX_MANAGE_STATE (AfxGetStaticModuleState ( ));
CComPtr<IConsole2> spConsole2;
HRESULT hr = pConsole->QueryInterface (IID_PPV_ARG (IConsole2, &spConsole2));
if (SUCCEEDED (hr))
{
CString statusText;
VERIFY (statusText.LoadString (IDS_ROOTNODE_STATUSBAR_TEXT));
hr = spConsole2->SetStatusText ((PWSTR)(PCWSTR) statusText);
}
_TRACE (-1, L"Leaving DisplayRootNodeStatusBarText: 0x%x\n", hr);
return hr;
}
HRESULT DisplayObjectCountInStatusBar (LPCONSOLE pConsole, DWORD dwCnt)
{
if ( !pConsole )
return E_POINTER;
_TRACE (1, L"Entering DisplayObjectCountInStatusBar- %d, %s\n",
dwCnt, L"Certificate Templates");
AFX_MANAGE_STATE (AfxGetStaticModuleState ( ));
CComPtr<IConsole2> spConsole2;
HRESULT hr = pConsole->QueryInterface (IID_PPV_ARG (IConsole2, &spConsole2));
if (SUCCEEDED (hr))
{
CString statusText;
UINT formatID = 0;
switch (dwCnt)
{
case -1:
statusText = L"";
break;
case 1:
VERIFY (statusText.LoadString (IDS_CERT_TEMPLATE_COUNT_SINGLE));
break;
default:
formatID = IDS_CERT_TEMPLATE_COUNT;
break;
}
if ( formatID )
{
// security review BryanWal 02/02/2002 ok
statusText.FormatMessage (formatID, dwCnt);
}
hr = spConsole2->SetStatusText ((PWSTR)(PCWSTR) statusText);
}
_TRACE (-1, L"Leaving DisplayObjectCountInStatusBar: 0x%x\n", hr);
return hr;
}
PCWSTR GetContextHelpFile ()
{
static CString strHelpTopic;
if ( strHelpTopic.IsEmpty () )
{
UINT nLen = ::GetSystemWindowsDirectory (strHelpTopic.GetBufferSetLength(2 * MAX_PATH), 2 * MAX_PATH);
strHelpTopic.ReleaseBuffer();
if (0 == nLen)
{
ASSERT(FALSE);
return 0;
}
strHelpTopic += CERTTMPL_HELP_PATH;
strHelpTopic += CERTTMPL_CONTEXT_HELP_FILE;
}
return (PCWSTR) strHelpTopic;
}
bool MyGetOIDInfoA (CString & string, LPCSTR pszObjId)
{
ASSERT (pszObjId);
if ( !pszObjId )
return false;
PCCRYPT_OID_INFO pOIDInfo; // This points to a constant data structure and must not be freed.
bool bResult = false;
// NTRAID# 479067 Certtmpl UI: Title bar and descriptive text incorrect
if ( !strcmp (szOID_CERT_POLICIES, pszObjId) )
{
VERIFY (string.LoadString (IDS_ISSUANCE_POLICIES));
bResult = true;
}
else
{
string = L"";
pOIDInfo = ::CryptFindOIDInfo (CRYPT_OID_INFO_OID_KEY, (void *) pszObjId, 0);
if ( pOIDInfo )
{
string = pOIDInfo->pwszName;
bResult = true;
}
else
{
for (POSITION nextPos = g_policyOIDList.GetHeadPosition (); nextPos; )
{
CPolicyOID* pPolicyOID = g_policyOIDList.GetNext (nextPos);
if ( pPolicyOID )
{
if ( !strcmp (pPolicyOID->GetOIDA (), pszObjId) )
{
string = pPolicyOID->GetDisplayName ();
bResult = true;
break;
}
}
}
if ( !bResult )
{
// security review BryanWal 02/02/2002 ok
int nLen = ::MultiByteToWideChar (CP_ACP, 0, pszObjId, -1, NULL, 0);
ASSERT (nLen > 0);
if ( nLen > 0)
{
// security review BryanWal 02/02/2002 ok
// NOTICE: GetBufferSetLength () takes len not including trailing NULL,
// returns NULL on failure. MultiByteToWideChar () handles NULL arg.
nLen = ::MultiByteToWideChar (CP_ACP, 0, pszObjId, -1,
string.GetBufferSetLength (nLen), nLen);
ASSERT (nLen > 0);
string.ReleaseBuffer ();
}
bResult = (nLen > 0) ? true : false;
}
}
}
return bResult;
}
#define REGSZ_ENABLE_CERTTYPE_EDITING L"EnableCertTypeEditing"
bool IsCerttypeEditingAllowed()
{
DWORD lResult;
HKEY hKey = NULL;
DWORD dwType;
DWORD dwEnabled = 0;
DWORD cbEnabled = sizeof(dwEnabled);
lResult = RegOpenKeyEx (HKEY_CURRENT_USER,
L"Software\\Microsoft\\Cryptography\\CertificateTemplateCache",
0,
KEY_READ,
&hKey);
if (lResult == ERROR_SUCCESS)
{
// security review BryanWal 02/02/2002 ok
lResult = RegQueryValueEx(hKey,
REGSZ_ENABLE_CERTTYPE_EDITING,
NULL,
&dwType,
(PBYTE)&dwEnabled,
&cbEnabled);
if(lResult == ERROR_SUCCESS)
{
if(dwType != REG_DWORD)
{
dwEnabled = 0;
}
}
RegCloseKey (hKey);
}
return (dwEnabled != 0);
}
BOOL EnumOIDInfo (PCCRYPT_OID_INFO pInfo, void* /*pvArg*/)
{
BOOL bRVal = TRUE;
if ( pInfo && pInfo->pszOID )
{
// NTRAID# 463344 Certtmpl.msc: Remove "All Application Policies" from
// Extensions selection list in Certtmpl.msc -- break Enrollment
if ( !strcmp (szOID_ANY_APPLICATION_POLICY, pInfo->pszOID) )
return TRUE;
for (POSITION nextPos = g_policyOIDList.GetHeadPosition (); nextPos; )
{
CPolicyOID* pPolicyOID = g_policyOIDList.GetNext (nextPos);
if ( pPolicyOID )
{
if ( !strcmp (pPolicyOID->GetOIDA (), pInfo->pszOID) )
return TRUE; // duplicate found, get next
}
}
int flags = 0;
if ( CRYPT_ENHKEY_USAGE_OID_GROUP_ID == pInfo->dwGroupId )
flags = CERT_OID_TYPE_APPLICATION_POLICY;
else if ( CRYPT_POLICY_OID_GROUP_ID == pInfo->dwGroupId )
flags = CERT_OID_TYPE_ISSUER_POLICY;
else
{
ASSERT (0);
return TRUE;
}
CPolicyOID* pPolicyOID = new CPolicyOID (pInfo->pszOID, pInfo->pwszName,
flags, false);
if ( pPolicyOID )
{
g_policyOIDList.AddTail (pPolicyOID);
}
else
bRVal = FALSE;
}
else
bRVal = FALSE;
return bRVal;
}
HRESULT GetBuiltInOIDs ()
{
HRESULT hr = S_OK;
CryptEnumOIDInfo (
CRYPT_ENHKEY_USAGE_OID_GROUP_ID,
0,
0,
EnumOIDInfo);
CryptEnumOIDInfo (
CRYPT_POLICY_OID_GROUP_ID,
0,
0,
EnumOIDInfo);
return hr;
}
HRESULT EnumerateOIDs (
IDirectoryObject* pOIDContObj)
{
_TRACE (1, L"Entering EnumerateOIDs\n");
CComPtr<IDirectorySearch> spDsSearch;
HRESULT hr = pOIDContObj->QueryInterface (IID_PPV_ARG(IDirectorySearch, &spDsSearch));
if ( SUCCEEDED (hr) )
{
ASSERT (!!spDsSearch);
ADS_SEARCHPREF_INFO pSearchPref[1];
DWORD dwNumPref = 1;
pSearchPref[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
pSearchPref[0].vValue.dwType = ADSTYPE_INTEGER;
pSearchPref[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
hr = spDsSearch->SetSearchPreference(
pSearchPref,
dwNumPref
);
if ( SUCCEEDED (hr) )
{
static const DWORD cAttrs = 3;
static PWSTR rgszAttrList[cAttrs] = {OID_PROP_DISPLAY_NAME, OID_PROP_OID, OID_PROP_TYPE};
ADS_SEARCH_HANDLE hSearchHandle = 0;
wstring strQuery;
ADS_SEARCH_COLUMN Column;
Column.pszAttrName = 0;
strQuery = L"objectClass=msPKI-Enterprise-Oid";
hr = spDsSearch->ExecuteSearch(
const_cast <PWSTR>(strQuery.c_str ()),
rgszAttrList,
cAttrs,
&hSearchHandle
);
if ( SUCCEEDED (hr) )
{
while ((hr = spDsSearch->GetNextRow (hSearchHandle)) != S_ADS_NOMORE_ROWS )
{
if (FAILED(hr))
continue;
//
// Getting current row's information
//
hr = spDsSearch->GetColumn(
hSearchHandle,
rgszAttrList[0],
&Column
);
if ( SUCCEEDED (hr) )
{
CString strDisplayName = Column.pADsValues->CaseIgnoreString;
spDsSearch->FreeColumn (&Column);
Column.pszAttrName = NULL;
hr = spDsSearch->GetColumn(
hSearchHandle,
rgszAttrList[1],
&Column
);
if ( SUCCEEDED (hr) )
{
bool bOIDFound = false;
CString strOID = Column.pADsValues->CaseIgnoreString;
spDsSearch->FreeColumn (&Column);
for (POSITION nextPos = g_policyOIDList.GetHeadPosition (); nextPos; )
{
CPolicyOID* pPolicyOID = g_policyOIDList.GetNext (nextPos);
if ( pPolicyOID )
{
if ( pPolicyOID->GetOIDW () == strOID )
{
bOIDFound = true;
break;
}
}
}
if ( !bOIDFound )
{
Column.pszAttrName = NULL;
hr = spDsSearch->GetColumn(
hSearchHandle,
rgszAttrList[2],
&Column
);
if ( SUCCEEDED (hr) )
{
ADS_INTEGER flags = Column.pADsValues->Integer;
spDsSearch->FreeColumn (&Column);
Column.pszAttrName = NULL;
// Only add issuance and application OIDs to the list
if ( CERT_OID_TYPE_ISSUER_POLICY == flags ||
CERT_OID_TYPE_APPLICATION_POLICY == flags )
{
CPolicyOID* pPolicyOID = new CPolicyOID (strOID, strDisplayName, flags);
if ( pPolicyOID )
{
g_policyOIDList.AddTail (pPolicyOID);
}
else
break;
}
}
}
}
}
else if ( hr != E_ADS_COLUMN_NOT_SET )
{
break;
}
else
{
_TRACE (0, L"IDirectorySearch::GetColumn () failed: 0x%x\n", hr);
}
}
}
else
{
_TRACE (0, L"IDirectorySearch::ExecuteSearch () failed: 0x%x\n", hr);
}
spDsSearch->CloseSearchHandle(hSearchHandle);
}
else
{
_TRACE (0, L"IDirectorySearch::SetSearchPreference () failed: 0x%x\n", hr);
}
}
else
{
_TRACE (0, L"IDirectoryObject::QueryInterface (IDirectorySearch) failed: 0x%x\n", hr);
}
_TRACE (-1, L"Leaving EnumerateOIDs: 0x%x\n", hr);
return hr;
}
HRESULT GetEnterpriseOIDs ()
{
_TRACE (1, L"Entering GetEnterpriseOIDs\n");
AFX_MANAGE_STATE(AfxGetStaticModuleState());
HRESULT hr = S_OK;
// Empty the list first
while ( !g_policyOIDList.IsEmpty () )
{
CPolicyOID* pPolicyOID = g_policyOIDList.RemoveHead ();
if ( pPolicyOID )
delete pPolicyOID;
}
hr = GetBuiltInOIDs ();
if ( SUCCEEDED (hr) )
{
CComPtr<IADsPathname> spPathname;
//
// Constructing the directory paths
//
// security review BryanWal 02/02/2002 ok
hr = CoCreateInstance(
CLSID_Pathname,
NULL,
CLSCTX_ALL,
IID_PPV_ARG (IADsPathname, &spPathname));
if ( SUCCEEDED (hr) )
{
CComBSTR bstrPathElement;
ASSERT (!!spPathname);
bstrPathElement = CERTTMPL_LDAP;
hr = spPathname->Set(bstrPathElement, ADS_SETTYPE_PROVIDER);
if ( SUCCEEDED (hr) )
{
//
// Open the root DSE object
//
bstrPathElement = CERTTMPL_ROOTDSE;
hr = spPathname->AddLeafElement(bstrPathElement);
if ( SUCCEEDED (hr) )
{
BSTR bstrFullPath = 0;
hr = spPathname->Retrieve(ADS_FORMAT_X500, &bstrFullPath);
if ( SUCCEEDED (hr) )
{
CComPtr<IADs> spRootDSEObject;
VARIANT varNamingContext;
hr = ADsGetObject (
bstrFullPath,
IID_PPV_ARG (IADs, &spRootDSEObject));
if ( SUCCEEDED (hr) )
{
ASSERT (!!spRootDSEObject);
//
// Get the configuration naming context from the root DSE
//
bstrPathElement = CERTTMPL_CONFIG_NAMING_CONTEXT;
hr = spRootDSEObject->Get(bstrPathElement,
&varNamingContext);
if ( SUCCEEDED (hr) )
{
hr = spPathname->Set(V_BSTR(&varNamingContext),
ADS_SETTYPE_DN);
if ( SUCCEEDED (hr) )
{
bstrPathElement = L"CN=Services";
hr = spPathname->AddLeafElement (bstrPathElement);
if ( SUCCEEDED (hr) )
{
bstrPathElement = L"CN=Public Key Services";
hr = spPathname->AddLeafElement (bstrPathElement);
if ( SUCCEEDED (hr) )
{
bstrPathElement = L"CN=OID";
hr = spPathname->AddLeafElement (bstrPathElement);
if ( SUCCEEDED (hr) )
{
BSTR bstrOIDPath = 0;
hr = spPathname->Retrieve(ADS_FORMAT_X500, &bstrOIDPath);
if ( SUCCEEDED (hr) )
{
CComPtr<IDirectoryObject> spOIDContObj;
hr = ADsGetObject (
bstrOIDPath,
IID_PPV_ARG (IDirectoryObject, &spOIDContObj));
if ( SUCCEEDED (hr) )
{
hr = EnumerateOIDs (spOIDContObj);
}
else
{
_TRACE (0, L"ADsGetObject (%s) failed: 0x%x\n", bstrOIDPath, hr);
}
SysFreeString (bstrOIDPath);
}
}
}
}
}
}
else
{
_TRACE (0, L"IADs::Get (%s) failed: 0x%x\n", CERTTMPL_CONFIG_NAMING_CONTEXT, hr);
}
}
else
{
_TRACE (0, L"ADsGetObject (%s) failed: 0x%x\n", bstrFullPath, hr);
}
}
}
}
}
else
hr = E_POINTER;
}
_TRACE (-1, L"Leaving GetEnterpriseOIDs: 0x%x\n", hr);
return hr;
}
bool OIDHasValidFormat (PCWSTR pszOidValue, int& rErrorTypeStrID)
{
ASSERT (pszOidValue);
if ( !pszOidValue )
return false;
_TRACE (1, L"Entering OIDHasValidFormat (%s)\n", pszOidValue);
rErrorTypeStrID = 0;
bool bFormatIsValid = false;
int nLen = WideCharToMultiByte(
CP_ACP, // code page
0, // performance and mapping flags
pszOidValue, // wide-character string
-1, // -1 - calculate length of null-terminated string automatically
0, // buffer for new string
0, // size of buffer - 0 causes API to return length including null terminator
0, // default for unmappable chars
0); // set when default char used
if ( nLen > 0 )
{
PSTR pszAnsiBuf = new char[nLen];
if ( pszAnsiBuf )
{
// security review BryanWal 02/02/2002 ok
ZeroMemory (pszAnsiBuf, nLen*sizeof(char));
// security review BryanWal 02/02/2002 ok
nLen = WideCharToMultiByte(
CP_ACP, // code page
0, // performance and mapping flags
pszOidValue, // wide-character string
-1, // -1 - calculate length of null-terminated string automatically
pszAnsiBuf, // buffer for new string
nLen, // size of buffer
0, // default for unmappable chars
0); // set when default char used
if ( nLen )
{
// According to PhilH:
// The first number is limited to
// 0,1 or 2. The second number is
// limited to 0 - 39 when the first
// number is 0 or 1. Otherwise, any
// number.
// Also, according to X.208, there
// must be at least 2 numbers.
bFormatIsValid = true;
// security review 2/20/2002 BryanWal ok
size_t cbAnsiBufLen = strlen (pszAnsiBuf);
// check for only digits and "."
size_t nIdx = strspn (pszAnsiBuf, "0123456789.\0");
if ( nIdx > 0 && nIdx < cbAnsiBufLen )
{
bFormatIsValid = false;
rErrorTypeStrID = IDS_OID_CONTAINS_NON_DIGITS;
}
// check for consecutive "."s - string not valid if present
if ( bFormatIsValid && strstr (pszAnsiBuf, "..") )
{
bFormatIsValid = false;
rErrorTypeStrID = IDS_OID_CONTAINS_CONSECUTIVE_DOTS;
}
// must begin with "0." or "1." or "2."
bool bFirstNumberIs0 = false;
bool bFirstNumberIs1 = false;
bool bFirstNumberIs2 = false;
if ( bFormatIsValid )
{
if ( !strncmp (pszAnsiBuf, "0.", 2) )
bFirstNumberIs0 = true;
else if ( !strncmp (pszAnsiBuf, "1.", 2) )
bFirstNumberIs1 = true;
else if ( !strncmp (pszAnsiBuf, "2.", 2) )
bFirstNumberIs2 = true;
if ( !bFirstNumberIs0 && !bFirstNumberIs1 && !bFirstNumberIs2 )
{
bFormatIsValid = false;
rErrorTypeStrID = IDS_OID_MUST_START_WITH_0_1_2;
}
}
if ( bFormatIsValid && ( bFirstNumberIs0 || bFirstNumberIs1 ) )
{
PSTR pszBuf = pszAnsiBuf;
pszBuf += 2;
// there must be a number after the dot
// security review 2/20/2002 BryanWal ok
if ( strlen (pszBuf) )
{
// truncate the string at the next dot, if any
PSTR pszDot = strstr (pszBuf, ".");
if ( pszDot )
pszDot[0] = 0;
// convert the string to a number and check for range 0-39
int nValue = atoi (pszBuf);
if ( nValue < 0 || nValue > 39 )
{
bFormatIsValid = false;
rErrorTypeStrID = IDS_OID_0_1_MUST_BE_0_TO_39;
}
}
else
{
bFormatIsValid = false;
rErrorTypeStrID = IDS_OID_MUST_HAVE_TWO_NUMBERS;
}
}
// ensure no trailing "."
if ( bFormatIsValid )
{
if ( '.' == pszAnsiBuf[cbAnsiBufLen - 1] )
{
bFormatIsValid = false;
rErrorTypeStrID = IDS_OID_CANNOT_END_WITH_DOT;
}
}
if ( bFormatIsValid )
{
bFormatIsValid = false;
CRYPT_ATTRIBUTE cryptAttr;
// security review BryanWal 02/02/2002 ok
::ZeroMemory (&cryptAttr, sizeof (cryptAttr));
cryptAttr.cValue = 0;
cryptAttr.pszObjId = pszAnsiBuf;
cryptAttr.rgValue = 0;
DWORD cbEncoded = 0;
BOOL bResult = CryptEncodeObject (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
PKCS_ATTRIBUTE,
&cryptAttr,
NULL,
&cbEncoded);
if ( cbEncoded > 0 )
{
BYTE* pBuffer = new BYTE[cbEncoded];
if ( pBuffer )
{
bResult = CryptEncodeObject (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
PKCS_ATTRIBUTE,
&cryptAttr,
pBuffer,
&cbEncoded);
if ( bResult )
{
DWORD cbStructInfo = 0;
bResult = CryptDecodeObject (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
PKCS_ATTRIBUTE,
pBuffer,
cbEncoded,
0,
0,
&cbStructInfo);
if ( cbStructInfo > 0 )
{
BYTE* pStructBuf = new BYTE[cbStructInfo];
if ( pStructBuf )
{
bResult = CryptDecodeObject (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
PKCS_ATTRIBUTE,
pBuffer,
cbEncoded,
0,
pStructBuf,
&cbStructInfo);
if ( bResult )
{
CRYPT_ATTRIBUTE* pCryptAttr = (CRYPT_ATTRIBUTE*) pStructBuf;
if ( !strcmp (pszAnsiBuf, pCryptAttr->pszObjId) )
{
bFormatIsValid = true;
}
}
delete [] pStructBuf;
}
}
}
delete [] pBuffer;
}
}
}
}
else
{
_TRACE (0, L"WideCharToMultiByte (%s) failed: 0x%x\n", pszOidValue,
GetLastError ());
}
delete [] pszAnsiBuf;
}
}
else
{
_TRACE (0, L"WideCharToMultiByte (%s) failed: 0x%x\n", pszOidValue,
GetLastError ());
}
_TRACE (-1, L"Leaving EnumerateOIDs: %s\n", bFormatIsValid ? L"true" : L"false");
return bFormatIsValid;
}
HPROPSHEETPAGE MyCreatePropertySheetPage(AFX_OLDPROPSHEETPAGE* psp)
{
ASSERT (psp);
if ( !psp )
return 0;
PROPSHEETPAGE_V3 sp_v3 = {0};
// security review 2/20/2002 BryanWal ok
ASSERT (sizeof (sp_v3) >= psp->dwSize);
if ( sizeof (sp_v3) >= psp->dwSize )
{
CopyMemory (&sp_v3, psp, psp->dwSize);
sp_v3.dwSize = sizeof(sp_v3);
}
else
return 0;
return (::CreatePropertySheetPage (&sp_v3));
}