1659 lines
50 KiB
C++
1659 lines
50 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997-2001.
|
|
//
|
|
// 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");
|
|
size_t len = strlen (VER_PRODUCTVERSION_STR);
|
|
PWSTR pszVer = new WCHAR[(len+1) * sizeof (WCHAR)];
|
|
if ( pszVer )
|
|
{
|
|
::ZeroMemory (pszVer, (len+1) * sizeof (WCHAR));
|
|
len = mbstowcs (pszVer, VER_PRODUCTVERSION_STR, len);
|
|
|
|
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
|
|
//
|
|
TCHAR achModuleFileName[MAX_PATH+20];
|
|
if (0 < ::GetModuleFileName(
|
|
AfxGetInstanceHandle(),
|
|
achModuleFileName,
|
|
sizeof(achModuleFileName)/sizeof(TCHAR) ))
|
|
{
|
|
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)
|
|
{
|
|
try
|
|
{
|
|
LRESULT lResult = 0;
|
|
CString strGUID;
|
|
CString snapinName;
|
|
AMC::CRegKey rkSnapins;
|
|
BOOL 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);
|
|
return SELFREG_E_CLASS;
|
|
}
|
|
|
|
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
|
|
return SELFREG_E_CLASS;
|
|
}
|
|
else
|
|
return SELFREG_E_CLASS;
|
|
}
|
|
catch (COleException* e)
|
|
{
|
|
ASSERT (FALSE);
|
|
e->Delete ();
|
|
return SELFREG_E_CLASS;
|
|
}
|
|
|
|
_Module.UnregisterServer ();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
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;
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
void TraceSystemError (DWORD dwErr)
|
|
{
|
|
//#ifdef _DEBUG
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
LPVOID lpMsgBuf = 0;
|
|
|
|
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.
|
|
AfxTrace ((PCWSTR) lpMsgBuf);
|
|
|
|
// Free the buffer.
|
|
LocalFree (lpMsgBuf);
|
|
//#endif // _DEBUG
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////// 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
|
|
//
|
|
//*************************************************************
|
|
PWSTR CheckSlash (PWSTR lpDir)
|
|
{
|
|
PWSTR 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, PWSTR 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;
|
|
}
|
|
|
|
|
|
PWSTR 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, PCWSTR 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);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// 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];
|
|
|
|
ZeroMemory(aScopeInit, sizeof(DSOP_SCOPE_INIT_INFO) * SCOPE_INIT_COUNT);
|
|
|
|
//
|
|
// 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;
|
|
/*
|
|
| DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN
|
|
| DSOP_SCOPE_TYPE_GLOBAL_CATALOG
|
|
| DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN
|
|
| DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN
|
|
| DSOP_SCOPE_TYPE_WORKGROUP
|
|
| DSOP_SCOPE_TYPE_USER_ENTERED_UPLEVEL_SCOPE
|
|
| DSOP_SCOPE_TYPE_USER_ENTERED_DOWNLEVEL_SCOPE;
|
|
*/
|
|
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;
|
|
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;
|
|
|
|
LPVOID lpMsgBuf;
|
|
|
|
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)
|
|
{
|
|
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 = (PWSTR)ptsz1;
|
|
UNICODE_STRING unistr2;
|
|
unistr2.Length = (USHORT)(::wcslen(ptsz2)*sizeof(WCHAR));
|
|
unistr2.MaximumLength = unistr2.Length;
|
|
unistr2.Buffer = (PWSTR)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 )
|
|
{
|
|
statusText.FormatMessage (formatID, dwCnt);
|
|
}
|
|
|
|
hr = spConsole2->SetStatusText ((PWSTR)(PCWSTR) statusText);
|
|
}
|
|
|
|
_TRACE (-1, L"Leaving DisplayObjectCountInStatusBar: 0x%x\n", hr);
|
|
return hr;
|
|
}
|
|
|
|
const int MAX_PASSWORD_LENGTH = 256;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// CCredentialObject
|
|
|
|
CCredentialObject::CCredentialObject(CCredentialObject* pCredObject)
|
|
{
|
|
m_sUsername = pCredObject->m_sUsername;
|
|
if (pCredObject->m_pszPassword != NULL)
|
|
{
|
|
m_pszPassword = (PWSTR)malloc(sizeof(WCHAR[MAX_PASSWORD_LENGTH + 1]));
|
|
wcscpy(m_pszPassword, pCredObject->m_pszPassword);
|
|
}
|
|
else
|
|
{
|
|
m_pszPassword = NULL;
|
|
}
|
|
|
|
m_bUseCredentials = pCredObject->m_bUseCredentials;
|
|
}
|
|
|
|
// A prime number used to seed the encoding and decoding
|
|
//
|
|
#define NW_ENCODE_SEED3 0x83
|
|
|
|
HRESULT CCredentialObject::SetPasswordFromHwnd(HWND hWnd)
|
|
{
|
|
UNICODE_STRING Password;
|
|
|
|
if (m_pszPassword)
|
|
{
|
|
free(m_pszPassword);
|
|
m_pszPassword = NULL;
|
|
}
|
|
|
|
UCHAR Seed = NW_ENCODE_SEED3;
|
|
Password.Length = 0;
|
|
|
|
WCHAR szBuffer[MAX_PASSWORD_LENGTH + 1];
|
|
::GetWindowText(hWnd, szBuffer, MAX_PASSWORD_LENGTH + 1);
|
|
if (!szBuffer)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
RtlInitUnicodeString(&Password, szBuffer);
|
|
RtlRunEncodeUnicodeString(&Seed, &Password);
|
|
|
|
m_pszPassword = (PWSTR)malloc(sizeof(WCHAR[MAX_PASSWORD_LENGTH + 1]));
|
|
if(!m_pszPassword)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
wcscpy(m_pszPassword, szBuffer);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CCredentialObject::GetPassword(PWSTR pszBuffer, int bufLen) const
|
|
{
|
|
UNICODE_STRING Password;
|
|
UCHAR Seed = NW_ENCODE_SEED3;
|
|
|
|
Password.Length = 0;
|
|
|
|
if (!pszBuffer)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (!m_pszPassword)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
wcsncpy(pszBuffer, m_pszPassword, bufLen);
|
|
|
|
RtlInitUnicodeString(&Password, pszBuffer);
|
|
RtlRunDecodeUnicodeString(Seed, &Password);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
PCCRYPT_OID_INFO pOIDInfo; // This points to a constant data structure and must not be freed.
|
|
bool bResult = false;
|
|
|
|
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 )
|
|
{
|
|
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;
|
|
}
|
|
|
|
#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)
|
|
{
|
|
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 )
|
|
{
|
|
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
|
|
//
|
|
hr = CoCreateInstance(
|
|
CLSID_Pathname,
|
|
NULL,
|
|
CLSCTX_ALL,
|
|
IID_PPV_ARG (IADsPathname, &spPathname));
|
|
if ( SUCCEEDED (hr) )
|
|
{
|
|
ASSERT (!!spPathname);
|
|
hr = spPathname->Set(const_cast <PWSTR> (CERTTMPL_LDAP),
|
|
ADS_SETTYPE_PROVIDER);
|
|
if ( SUCCEEDED (hr) )
|
|
{
|
|
//
|
|
// Open the root DSE object
|
|
//
|
|
hr = spPathname->AddLeafElement(const_cast <PWSTR> (CERTTMPL_ROOTDSE));
|
|
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
|
|
//
|
|
hr = spRootDSEObject->Get(const_cast <PWSTR> (CERTTMPL_CONFIG_NAMING_CONTEXT),
|
|
&varNamingContext);
|
|
if ( SUCCEEDED (hr) )
|
|
{
|
|
hr = spPathname->Set(V_BSTR(&varNamingContext),
|
|
ADS_SETTYPE_DN);
|
|
if ( SUCCEEDED (hr) )
|
|
{
|
|
hr = spPathname->AddLeafElement (L"CN=Services");
|
|
if ( SUCCEEDED (hr) )
|
|
{
|
|
hr = spPathname->AddLeafElement (L"CN=Public Key Services");
|
|
if ( SUCCEEDED (hr) )
|
|
{
|
|
hr = spPathname->AddLeafElement (L"CN=OID");
|
|
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)
|
|
{
|
|
_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
|
|
(int) wcslen (pszOidValue), // number of chars in string
|
|
0, // buffer for new string
|
|
0, // size of buffer
|
|
0, // default for unmappable chars
|
|
0); // set when default char used
|
|
if ( nLen > 0 )
|
|
{
|
|
nLen++; // account for Null terminator
|
|
PSTR pszAnsiBuf = new CHAR[nLen];
|
|
if ( pszAnsiBuf )
|
|
{
|
|
ZeroMemory (pszAnsiBuf, nLen*sizeof(CHAR));
|
|
nLen = WideCharToMultiByte(
|
|
CP_ACP, // code page
|
|
0, // performance and mapping flags
|
|
pszOidValue, // wide-character string
|
|
(int) wcslen (pszOidValue), // number of chars in string
|
|
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;
|
|
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
|
|
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;
|
|
::ZeroMemory (&cryptAttr, sizeof (CRYPT_ATTRIBUTE));
|
|
|
|
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)
|
|
{
|
|
PROPSHEETPAGE_V3 sp_v3 = {0};
|
|
CopyMemory (&sp_v3, psp, psp->dwSize);
|
|
sp_v3.dwSize = sizeof(sp_v3);
|
|
|
|
return (::CreatePropertySheetPage (&sp_v3));
|
|
}
|