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.
 
 
 
 
 
 

2698 lines
82 KiB

//--------------------------------------------------------------------
// SetupUtil - implementation
// Copyright (C) Microsoft Corporation, 1999
//
// Created by: Louis Thomas (louisth), 8-10-99
//
// Functions needed to set up CEP
//
//--------------------------------------------------------------------
// includes
#include "global.hxx"
#include <xenroll.h>
#include <dbgdef.h>
#include "ErrorHandling.h"
#include "SetupUtil.h"
//--------------------------------------------------------------------
// Constants
static const WCHAR gc_wszRegKeyServices[]=L"System\\CurrentControlSet\\Services";
static const WCHAR gc_wszCertSrvDir[]=L"CertSrv";
// from <wincrypt.h>
static const WCHAR gc_wszEnrollmentAgentOid[]=L"1.3.6.1.4.1.311.20.2.1"; //szOID_ENROLLMENT_AGENT
// from ca\include\certlib.h; ca\certlib\acl.cpp
const GUID GUID_ENROLL={0x0e10c968, 0x78fb, 0x11d2, {0x90, 0xd4, 0x00, 0xc0, 0x4f, 0x79, 0xdc, 0x55}};
//--------------------------------------------------------------------
// IIS magic
#undef DEFINE_GUID
#define INITGUID
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
EXTERN_C const GUID name \
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
#include <iwamreg.h>
#include <iadmw.h>
#include <iiscnfg.h>
//--------------------------------------------------------------------
// constants
#include "..\common.h"
#define MAX_METABASE_ATTEMPTS 10 // Times to bang head on wall
#define METABASE_PAUSE 500 // Time to pause in msec
static const WCHAR gc_wszBaseRoot[]=L"/LM/W3svc/1/ROOT";
static const WCHAR gc_wszCepDllName[]=CEP_DLL_NAME;
static const WCHAR gc_wszCepStoreName[]=CEP_STORE_NAME;
static const WCHAR gc_wszAppPoolBase[]=L"/LM/W3svc/APPPOOLS";
//---------------------------------------------------------------------
// function prototypes
HRESULT
EnableISAPIExtension(
IN LPCWSTR pcwszExtension,
OUT BOOL *pfEnabledASP);
HRESULT IsISAPIExtensionEnabled(
LPCWSTR pcwszExtension,
bool& rfEnabled);
//####################################################################
// module local functions
//--------------------------------------------------------------------
static HRESULT myHExceptionCode(EXCEPTION_POINTERS * pep)
{
HRESULT hr=pep->ExceptionRecord->ExceptionCode;
if (!FAILED(hr)) {
hr=HRESULT_FROM_WIN32(hr);
}
return hr;
}
//--------------------------------------------------------------------
static HRESULT
vrOpenRoot(
IN IMSAdminBase *pIMeta,
IN BOOL fReadOnly,
IN const WCHAR * wszBaseRoot,
OUT METADATA_HANDLE *phMetaRoot)
{
HRESULT hr;
unsigned int nAttempts;
// Re-try a few times to see if we can get past the block
nAttempts=0;
do {
// Pause on retry
if (0!=nAttempts) {
Sleep(METABASE_PAUSE);
}
// Make an attempt to open the root
__try {
hr=pIMeta->OpenKey(
METADATA_MASTER_ROOT_HANDLE,
wszBaseRoot,
fReadOnly?
METADATA_PERMISSION_READ :
(METADATA_PERMISSION_READ |
METADATA_PERMISSION_WRITE),
1000,
phMetaRoot);
} _TrapException(hr);
nAttempts++;
} while (HRESULT_FROM_WIN32(ERROR_PATH_BUSY)==hr && nAttempts<MAX_METABASE_ATTEMPTS);
_JumpIfError(hr, error, "OpenKey");
error:
return hr;
}
//--------------------------------------------------------------------
static HRESULT GetRegString(IN HKEY hKey, IN const WCHAR * wszValue, OUT WCHAR ** pwszString)
{
HRESULT hr;
DWORD dwDataSize;
DWORD dwType;
DWORD dwError;
// must be cleaned up
WCHAR * wszString=NULL;
// init out params
*pwszString=NULL;
// get value
dwDataSize=0;
dwError=RegQueryValueExW(hKey, wszValue, NULL, &dwType, NULL, &dwDataSize);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegQueryValueExW", wszValue);
}
_Verify(REG_SZ==dwType, hr, error);
wszString=(WCHAR *)LocalAlloc(LPTR, dwDataSize);
_JumpIfOutOfMemory(hr, error, pwszString);
dwError=RegQueryValueExW(hKey, wszValue, NULL, &dwType, (BYTE *)wszString, &dwDataSize);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegQueryValueExW", wszValue);
}
_Verify(REG_SZ==dwType, hr, error);
// it worked
hr=S_OK;
*pwszString=wszString;
wszString=NULL;
error:
if (NULL!=wszString) {
LocalFree(wszString);
}
return hr;
}
//--------------------------------------------------------------------
static HRESULT OpenCertSrvConfig(HKEY * phkey)
{
HRESULT hr;
DWORD dwError;
DWORD dwType;
DWORD dwDataSize;
// must be cleaned up
HKEY hServices=NULL;
HKEY hCertSvc=NULL;
HKEY hConfig=NULL;
// initialize out params
*phkey=NULL;
// Open HKLM\System\CurrentControlSet\Services
dwError=RegOpenKeyExW(HKEY_LOCAL_MACHINE, gc_wszRegKeyServices, 0, KEY_READ, &hServices);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegOpenKeyEx", gc_wszRegKeyServices);
}
// open CertSvc\Configuration
dwError=RegOpenKeyExW(hServices, wszSERVICE_NAME, 0, KEY_READ, &hCertSvc);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegOpenKeyEx", wszSERVICE_NAME);
}
dwError=RegOpenKeyExW(hCertSvc, wszREGKEYCONFIG, 0, KEY_READ, &hConfig);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegOpenKeyEx", wszREGKEYCONFIG);
}
// we were successfull
hr=S_OK;
*phkey=hConfig;
hConfig=0;
error:
if (NULL!=hConfig) {
RegCloseKey(hConfig);
}
if (NULL!=hCertSvc) {
RegCloseKey(hCertSvc);
}
if (NULL!=hServices) {
RegCloseKey(hServices);
}
return hr;
}
//--------------------------------------------------------------------
static HRESULT OpenCurrentCAConfig(HKEY * phkey)
{
HRESULT hr;
DWORD dwError;
DWORD dwType;
DWORD dwDataSize;
// must be cleaned up
HKEY hConfig=NULL;
HKEY hCurConfig=NULL;
WCHAR * wszActiveConfig=NULL;
// initialize out params
*phkey=NULL;
// Open HKLM\System\CurrentControlSet\Services\CertSvc\Configuration
hr=OpenCertSrvConfig(&hConfig);
_JumpIfError(hr, error, "OpenCertSrvConfig");
// get value "active"
hr=GetRegString(hConfig, wszREGACTIVE, &wszActiveConfig);
_JumpIfErrorStr(hr, error, "GetRegString", wszREGACTIVE);
// and open <active>
dwError=RegOpenKeyExW(hConfig, wszActiveConfig, 0, KEY_ALL_ACCESS, &hCurConfig);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegOpenKeyEx", wszActiveConfig);
}
// we were successfull
hr=S_OK;
*phkey=hCurConfig;
hCurConfig=0;
error:
if (NULL!=hCurConfig) {
RegCloseKey(hCurConfig);
}
if (NULL!=wszActiveConfig) {
LocalFree(wszActiveConfig);
}
if (NULL!=hConfig) {
RegCloseKey(hConfig);
}
return hr;
}
//--------------------------------------------------------------------
// stolen from certlib.cpp. use this until Pete fixes the api.
static HRESULT GetCADsName(OUT WCHAR **pwszName)
{
#define cwcCNMAX 64 // 64 chars max for CN
#define cwcCHOPHASHMAX (1+5) // "-%05hu" decimal USHORT hash digits
#define cwcSUFFIXMAX (1 + 5 + 1) // five decimal digits plus parentheses
#define cwcCHOPBASE (cwcCNMAX-(cwcCHOPHASHMAX+cwcSUFFIXMAX))
HRESULT hr;
DWORD cwc;
DWORD cwcCopy;
WCHAR wszDSName[cwcCHOPBASE+cwcCHOPHASHMAX+1];
// must be cleaned up
HKEY hConfig=NULL;
WCHAR * wszSanitizedName=NULL;
// initialize out params
*pwszName=NULL;
// Open HKLM\System\CurrentControlSet\Services\CertSvc\Configuration
hr=OpenCertSrvConfig(&hConfig);
_JumpIfError(hr, error, "OpenCertSrvConfig");
// get value "active" - this is the sanitized name
hr=GetRegString(hConfig, wszREGACTIVE, &wszSanitizedName);
_JumpIfErrorStr(hr, error, "GetRegString", wszREGACTIVE);
// ----- begin stolen code -----
cwc = wcslen(wszSanitizedName);
cwcCopy = cwc;
if (cwcCHOPBASE < cwcCopy)
{
cwcCopy = cwcCHOPBASE;
}
CopyMemory(wszDSName, wszSanitizedName, cwcCopy * sizeof(WCHAR));
wszDSName[cwcCopy] = L'\0';
if (cwcCHOPBASE < cwc)
{
// Hash the rest of the name into a USHORT
USHORT usHash = 0;
DWORD i;
WCHAR *pwsz;
// Truncate an incomplete sanitized Unicode character
pwsz = wcsrchr(wszDSName, L'!');
if (NULL != pwsz && wcslen(pwsz) < 5)
{
cwcCopy -= wcslen(pwsz);
*pwsz = L'\0';
}
for (i = cwcCopy; i < cwc; i++)
{
USHORT usLowBit = (0x8000 & usHash)? 1 : 0;
usHash = ((usHash << 1) | usLowBit) + wszSanitizedName[i];
}
wsprintf(&wszDSName[cwcCopy], L"-%05hu", usHash);
//CSASSERT(wcslen(wszDSName) < ARRAYSIZE(wszDSName));
}
// ----- end stolen code -----
*pwszName=(WCHAR *)LocalAlloc(LPTR, (wcslen(wszDSName)+1)*sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, *pwszName);
wcscpy(*pwszName, wszDSName);
hr=S_OK;
error:
if (NULL!=wszSanitizedName) {
LocalFree(wszSanitizedName);
}
if (NULL!=hConfig) {
RegCloseKey(hConfig);
}
return hr;
}
//--------------------------------------------------------------------
HRESULT SetSDOnCEPCertificate(BSTR bstrCertificate, SID * psidAccount)
{
HRESULT hr=E_FAIL;
DWORD dwKeySpec=0;
BOOL fFreeProv=FALSE;
CERT_BLOB blobCert;
DWORD dwSD=0;
PACL pAcl=NULL;
BOOL fDacl = TRUE;
BOOL fDef = FALSE;
ACL_SIZE_INFORMATION AclInfo;
DWORD dwAccess=ACTRL_FILE_READ | ACTRL_FILE_READ_PROP | ACTRL_FILE_READ_ATTRIB;
ACE_HEADER *pFirstAce=NULL;
PSECURITY_DESCRIPTOR pNewSD = NULL;
PACL pNewAcl = NULL;
PSECURITY_DESCRIPTOR pSID=NULL;
HCERTSTORE hCEPStore=NULL;
PCERT_CONTEXT pCertContext=NULL;
PCCERT_CONTEXT pCEPCert=NULL;
HCRYPTPROV hProv=NULL;
//open the CEP store
if(NULL == (hCEPStore=CertOpenStore(
CERT_STORE_PROV_SYSTEM_W,
ENCODE_TYPE,
NULL,
CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG,
CEP_STORE_NAME)))
{
hr=E_UNEXPECTED;
_JumpError(hr, error, "CertOpenStore");
}
//get the certificate context
memset(&blobCert, 0, sizeof(blobCert));
blobCert.cbData = (DWORD)SysStringByteLen(bstrCertificate);
blobCert.pbData = (BYTE *)bstrCertificate;
if(!CryptQueryObject(
CERT_QUERY_OBJECT_BLOB,
&blobCert,
CERT_QUERY_CONTENT_FLAG_CERT,
CERT_QUERY_FORMAT_FLAG_ALL,
0,
NULL,
NULL,
NULL,
NULL,
NULL,
(const void **)&pCertContext))
{
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "CryptQueryObject");
}
if(NULL == pCertContext)
{
hr=E_UNEXPECTED;
_JumpError(hr, error, "CryptQueryObject");
}
//find the certificate in CEP store
if(NULL == (pCEPCert=CertFindCertificateInStore(
hCEPStore,
X509_ASN_ENCODING,
0,
CERT_FIND_EXISTING,
pCertContext,
NULL)))
{
hr=E_UNEXPECTED;
_JumpError(hr, error, "CertFindCertificateInStore");
}
//set the SD on the private key
if(!CryptAcquireCertificatePrivateKey(pCEPCert,
CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
NULL,
&hProv,
&dwKeySpec,
&fFreeProv))
{
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "CryptAcquireCertificatePrivateKey");
}
if(!CryptGetProvParam(
hProv,
PP_KEYSET_SEC_DESCR,
NULL,
&dwSD,
DACL_SECURITY_INFORMATION))
{
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "CryptAcquireCertificatePrivateKey");
}
pSID = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwSD);
if (NULL == pSID)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if(!CryptGetProvParam(
hProv,
PP_KEYSET_SEC_DESCR,
(BYTE *)pSID,
&dwSD,
DACL_SECURITY_INFORMATION))
{
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "CryptGetProvParam");
}
//get acl from sd
if(!GetSecurityDescriptorDacl(
pSID,
&fDacl,
&pAcl,
&fDef))
{
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetSecurityDescriptorDacl");
}
//if no dacl or everyone access, quit
if((NULL==pAcl) || (FALSE == fDacl))
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
_JumpError(hr, error, "GetSecurityDescriptorDacl");
}
//get acl info
if(!GetAclInformation(
pAcl,
&AclInfo,
sizeof(AclInfo),
AclSizeInformation))
{
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetAclInformation");
}
//allocate enough for new dacl since we might add a new ACE
dwSD=AclInfo.AclBytesInUse
+sizeof(ACCESS_ALLOWED_ACE)
-sizeof(DWORD) //ACCESS_ALLOWED_ACE::SidStart
+GetLengthSid(psidAccount);
pNewAcl = (PACL)LocalAlloc(LPTR, dwSD);
if(NULL == pNewAcl)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if(!InitializeAcl(pNewAcl, dwSD, ACL_REVISION_DS))
{
hr = HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "InitializeAcl");
}
// find the first ace in the dacl
if (!GetAce(pAcl, 0, (void **)&pFirstAce))
{
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetAce");
}
// add all the old aces
if (!AddAce(pNewAcl, ACL_REVISION_DS, 0, pFirstAce, AclInfo.AclBytesInUse-sizeof(ACL)))
{
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "AddAce");
}
//add the access allowed ACE
if(!AddAccessAllowedAce(pNewAcl, ACL_REVISION, dwAccess, psidAccount))
{
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "AddAccessAllowedAce");
}
// initialize a security descriptor.
pNewSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (pNewSD == NULL)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if(!InitializeSecurityDescriptor(pNewSD, SECURITY_DESCRIPTOR_REVISION))
{
hr = HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "InitializeSecurityDescriptor");
}
// add the ACL to the security descriptor.
if(!SetSecurityDescriptorDacl(
pNewSD,
TRUE, // fDaclPresent flag
pNewAcl,
FALSE)) // not a default DACL
{
hr = HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "SetSecurityDescriptorDacl");
}
//set sd to be protected
if(!SetSecurityDescriptorControl(
pNewSD,
SE_DACL_PROTECTED,
SE_DACL_PROTECTED))
{
hr = HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "SetSecurityDescriptorControl");
}
if(!IsValidSecurityDescriptor(pNewSD))
{
hr = HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "IsValidSecurityDescriptor");
}
//we just set it back to the privaet key
if(!CryptSetProvParam(
hProv,
PP_KEYSET_SEC_DESCR,
(BYTE*)pNewSD,
DACL_SECURITY_INFORMATION))
{
hr = HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "CryptSetProvParam");
}
hr=S_OK;
error:
if(pNewSD)
{
LocalFree(pNewSD);
}
if(pSID)
{
LocalFree(pSID);
}
if(pNewAcl)
{
LocalFree(pNewAcl);
}
if(fFreeProv)
{
if(hProv)
CryptReleaseContext(hProv, 0);
}
if(pCEPCert)
{
CertFreeCertificateContext(pCEPCert);
}
if(pCertContext)
{
CertFreeCertificateContext(pCertContext);
}
if(hCEPStore)
{
CertCloseStore(hCEPStore, 0);
}
return hr;
}
//--------------------------------------------------------------------
static HRESULT EnrollForRACert(
IN const WCHAR * wszDistinguishedName,
IN const WCHAR * wszCSPName,
IN DWORD dwCSPType,
IN DWORD dwKeySize,
IN DWORD dwKeySpec,
IN const WCHAR * wszTemplate,
IN SID *psidAccount
)
{
HRESULT hr;
LONG nDisposition;
LONG nRequestID;
// must be cleaned up
ICEnroll3 * pXEnroll=NULL;
BSTR bszConfigString=NULL;
BSTR bszRequest=NULL;
ICertConfig * pICertConfig=NULL;
ICertRequest * pICertRequest=NULL;
ICertAdmin * pICertAdmin=NULL;
BSTR bszCertificate=NULL;
// get the config string
hr=CoCreateInstance(
CLSID_CCertConfig,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICertConfig,
(void **)&pICertConfig);
_JumpIfError(hr, error, "CoCreateInstance(CLSID_CCertConfig)");
hr = pICertConfig->GetConfig(CC_LOCALCONFIG, &bszConfigString);
_JumpIfError(hr, error, "GetConfig");
// create XEnroll
hr=CoCreateInstance(
CLSID_CEnroll,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICEnroll3,
(void **)&pXEnroll);
_JumpIfError(hr, error, "CoCreateInstance(CLSID_CEnroll)");
// build the Offline enrollment agent cert.
hr=pXEnroll->put_ProviderName((WCHAR *)wszCSPName);
_JumpIfError(hr, error, "put_ProviderName");
hr=pXEnroll->put_ProviderType(dwCSPType);
_JumpIfError(hr, error, "put_ProviderType");
hr=pXEnroll->put_ProviderFlags(CRYPT_MACHINE_KEYSET); // used in CryptAcquireContext
_JumpIfError(hr, error, "put_ProviderFlags");
hr=pXEnroll->put_GenKeyFlags(dwKeySize<<16);
_JumpIfError(hr, error, "put_GenKeyFlags");
hr=pXEnroll->put_KeySpec(dwKeySpec);
_JumpIfError(hr, error, "put_KeySpec");
hr=pXEnroll->put_LimitExchangeKeyToEncipherment(AT_KEYEXCHANGE==dwKeySpec);
_JumpIfError(hr, error, "put_LimitExchangeKeyToEncipherment");
hr=pXEnroll->put_UseExistingKeySet(FALSE);
_JumpIfError(hr, error, "put_UseExistingKeySet");
hr=pXEnroll->put_RequestStoreFlags(CERT_SYSTEM_STORE_LOCAL_MACHINE); // the keys attached to the dummy request cert go in the local machine store
_JumpIfError(hr, error, "put_RequestStoreFlags");
hr=pXEnroll->addCertTypeToRequest((WCHAR *)wszTemplate);
_JumpIfErrorStr(hr, error, "addCertTypeToRequest", wszTemplate);
hr=pXEnroll->createPKCS10((WCHAR *)wszDistinguishedName, (WCHAR *)gc_wszEnrollmentAgentOid, &bszRequest);
_JumpIfError(hr, error, "CreatePKCS10");
// create ICertRequest
hr=CoCreateInstance(
CLSID_CCertRequest,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICertRequest,
(void **)&pICertRequest);
_JumpIfError(hr, error, "CoCreateInstance(CLSID_CCertRequest)");
// request the cert
hr=pICertRequest->Submit(CR_IN_BASE64, bszRequest, NULL, bszConfigString, &nDisposition);
_JumpIfError(hr, error, "Submit");
// did we get it?
if (CR_DISP_UNDER_SUBMISSION==nDisposition) {
// we need to approve it. No problem!
hr=pICertRequest->GetRequestId(&nRequestID);
_JumpIfError(hr, error, "GetRequestId");
// create ICertAdmin
hr=CoCreateInstance(
CLSID_CCertAdmin,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICertAdmin,
(void **)&pICertAdmin);
_JumpIfError(hr, error, "CoCreateInstance(CLSID_CCertAdmin)");
// resubmit it
hr=pICertAdmin->ResubmitRequest(bszConfigString, nRequestID, &nDisposition);
_JumpIfError(hr, error, "ResubmitRequest");
// This should have worked, but we're going to ignore the
// returned disposition and use the one from the next call.
// now, get the cert that we just approved
hr=pICertRequest->RetrievePending(nRequestID, bszConfigString, &nDisposition);
_JumpIfError(hr, error, "RetrievePending");
}
// We should have it by now.
_Verify(CR_DISP_ISSUED==nDisposition, hr, error);
// grab the cert from the CA
hr=pICertRequest->GetCertificate(CR_OUT_BASE64, &bszCertificate);
_JumpIfError(hr, error, "GetCertificate");
// install the cert
hr=pXEnroll->put_MyStoreName((WCHAR *)gc_wszCepStoreName); // We have to use our special store
_JumpIfError(hr, error, "put_MyStoreName");
hr=pXEnroll->put_MyStoreFlags(CERT_SYSTEM_STORE_LOCAL_MACHINE); // the keys attached to the final cert also go in the local machine store
_JumpIfError(hr, error, "put_MyStoreFlags");
hr=pXEnroll->put_RootStoreFlags(CERT_SYSTEM_STORE_LOCAL_MACHINE);
_JumpIfError(hr, error, "put_RootStoreFlags");
hr=pXEnroll->put_CAStoreFlags(CERT_SYSTEM_STORE_LOCAL_MACHINE);
_JumpIfError(hr, error, "put_CAStoreFlags");
hr=pXEnroll->put_SPCFileName(L"");
_JumpIfError(hr, error, "put_MyStoreName");
hr=pXEnroll->acceptPKCS7(bszCertificate);
_JumpIfError(hr, error, "acceptPKCS7");
//set the SD on the private key of the enrolled certificate
if(psidAccount)
{
hr=SetSDOnCEPCertificate(bszCertificate, psidAccount);
_JumpIfError(hr, error, "acceptPKCS7");
}
// all done
hr=S_OK;
error:
if(NULL!=pICertConfig){
pICertConfig->Release();
}
if (NULL!=bszCertificate) {
SysFreeString(bszCertificate);
}
if (NULL!=pICertAdmin) {
pICertAdmin->Release();
}
if (NULL!=pICertRequest) {
pICertRequest->Release();
}
if (NULL!=bszRequest) {
SysFreeString(bszRequest);
}
if (NULL!=bszConfigString) {
SysFreeString(bszConfigString);
}
if (NULL!=pXEnroll) {
pXEnroll->Release();
}
return hr;
}
//--------------------------------------------------------------------
// DEBUG, not used
static BOOL DumpTokenGroups(void)
{
#define MAX_NAME 256
DWORD i, dwSize = 0, dwResult = 0;
HANDLE hToken;
PTOKEN_GROUPS pGroupInfo;
SID_NAME_USE SidType;
char lpName[MAX_NAME];
char lpDomain[MAX_NAME];
SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
// Open a handle to the access token for the calling process.
if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken )) {
wprintf( L"OpenProcessToken Error %u\n", GetLastError() );
return FALSE;
}
// Call GetTokenInformation to get the buffer size.
if(!GetTokenInformation(hToken, TokenGroups, NULL, dwSize, &dwSize)) {
dwResult = GetLastError();
if( dwResult != ERROR_INSUFFICIENT_BUFFER ) {
wprintf( L"GetTokenInformation Error %u\n", dwResult );
return FALSE;
}
}
// Allocate the buffer.
pGroupInfo = (PTOKEN_GROUPS) GlobalAlloc( GPTR, dwSize );
// Call GetTokenInformation again to get the group information.
if(! GetTokenInformation(hToken, TokenGroups, pGroupInfo,
dwSize, &dwSize ) ) {
wprintf( L"GetTokenInformation Error %u\n", GetLastError() );
return FALSE;
}
// Loop through the group SIDs looking for the administrator SID.
for(i=0; i<pGroupInfo->GroupCount; i++) {
// Lookup the account name and print it.
dwSize = MAX_NAME;
if( !LookupAccountSidA( NULL, pGroupInfo->Groups[i].Sid,
lpName, &dwSize, lpDomain,
&dwSize, &SidType ) ) {
dwResult = GetLastError();
if( dwResult == ERROR_NONE_MAPPED )
strcpy( lpName, "NONE_MAPPED" );
else {
wprintf(L"LookupAccountSid Error %u\n", GetLastError());
return FALSE;
}
}
char * szSid=NULL;
if (!ConvertSidToStringSidA(pGroupInfo->Groups[i].Sid, &szSid)) {
wprintf(L"ConvertSidToStringSid Error %u\n", GetLastError());
return FALSE;
}
// Find out if the SID is enabled in the token
char * szEnable;
if (pGroupInfo->Groups[i].Attributes & SE_GROUP_ENABLED) {
szEnable="enabled";
} else if (pGroupInfo->Groups[i].Attributes & SE_GROUP_USE_FOR_DENY_ONLY) {
szEnable="deny-only";
} else {
szEnable="not enabled";
}
wprintf( L"Member of %hs\\%hs (%hs) (%hs)\n",
lpDomain, lpName, szSid, szEnable );
LocalFree(szSid);
}
if ( pGroupInfo )
GlobalFree( pGroupInfo );
return TRUE;
}
//--------------------------------------------------------------------
// DEBUG, not used
static void DumpAcl(PACL pAcl, ACL_SIZE_INFORMATION aclsizeinfo)
{
HRESULT hr;
unsigned int nIndex;
DWORD dwError;
wprintf(L"/-- begin ACL ---\n");
for (nIndex=0; nIndex<aclsizeinfo.AceCount; nIndex++) {
ACE_HEADER * pAceHeader;
PSID pSid=NULL;
wprintf(L"| ");
if (!GetAce(pAcl, nIndex, (void**)&pAceHeader)) {
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf(L" (GetAce failed:0x%08X)\n", hr);
continue;
}
wprintf(L"[");
if (ACCESS_ALLOWED_ACE_TYPE==pAceHeader->AceType) {
wprintf(L"aA_");
pSid=&((ACCESS_ALLOWED_ACE *)pAceHeader)->SidStart;
} else if (ACCESS_DENIED_ACE_TYPE==pAceHeader->AceType) {
wprintf(L"aD_");
pSid=&((ACCESS_DENIED_ACE *)pAceHeader)->SidStart;
} else if (ACCESS_ALLOWED_OBJECT_ACE_TYPE==pAceHeader->AceType) {
wprintf(L"aAo");
pSid=&((ACCESS_ALLOWED_OBJECT_ACE *)pAceHeader)->SidStart;
if (((ACCESS_ALLOWED_OBJECT_ACE *)pAceHeader)->Flags!=(ACE_OBJECT_TYPE_PRESENT|ACE_INHERITED_OBJECT_TYPE_PRESENT)) {
pSid=((BYTE *)pSid)-sizeof(GUID);
}
} else if (ACCESS_DENIED_OBJECT_ACE_TYPE==pAceHeader->AceType) {
wprintf(L"aDo");
pSid=&((ACCESS_DENIED_OBJECT_ACE *)pAceHeader)->SidStart;
if (((ACCESS_DENIED_OBJECT_ACE *)pAceHeader)->Flags!=(ACE_OBJECT_TYPE_PRESENT|ACE_INHERITED_OBJECT_TYPE_PRESENT)) {
pSid=((BYTE *)pSid)-sizeof(GUID);
}
} else {
wprintf(L"sa?");
}
wprintf(L"] ");
if (NULL!=pSid) {
// print the sid
{
WCHAR wszName[MAX_NAME];
WCHAR wszDomain[MAX_NAME];
DWORD dwSize=MAX_NAME;
SID_NAME_USE SidType;
if(!LookupAccountSidW(
NULL, pSid,
wszName, &dwSize, wszDomain,
&dwSize, &SidType))
{
dwError=GetLastError();
if (dwError==ERROR_NONE_MAPPED) {
wprintf(L"(Unknown)");
} else {
hr=HRESULT_FROM_WIN32(dwError);
wprintf(L"(Error 0x%08X)", hr);
}
} else {
wprintf(L"%ws\\%ws", wszDomain, wszName);
}
}
{
WCHAR * wszSid=NULL;
if (!ConvertSidToStringSidW(pSid, &wszSid)) {
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf(L"(Error 0x%08X)", hr);
} else {
wprintf(L" %ws", wszSid);
LocalFree(wszSid);
}
}
}
wprintf(L"\n");
}
wprintf(L"\\-- end ACL ---\n");
}
//--------------------------------------------------------------------
static HRESULT GetRootDomEntitySid(SID ** ppSid, DWORD dwEntityRid)
{
HRESULT hr;
NET_API_STATUS nasError;
unsigned int nSubAuthorities;
unsigned int nSubAuthIndex;
// must be cleaned up
SID * psidRootDomEntity=NULL;
USER_MODALS_INFO_2 * pumi2=NULL;
DOMAIN_CONTROLLER_INFOW * pdci=NULL;
DOMAIN_CONTROLLER_INFOW * pdciForest=NULL;
// initialize out params
*ppSid=NULL;
// get the forest name
nasError=DsGetDcNameW(NULL, NULL, NULL, NULL, 0, &pdciForest);
if (NERR_Success!=nasError) {
hr=HRESULT_FROM_WIN32(nasError);
_JumpError(hr, error, "DsGetDcNameW");
}
// get the top level DC name
nasError=DsGetDcNameW(NULL, pdciForest->DnsForestName, NULL, NULL, 0, &pdci);
if (NERR_Success!=nasError) {
hr=HRESULT_FROM_WIN32(nasError);
_JumpError(hr, error, "DsGetDcNameW");
}
// get the domain Sid on the top level DC.
nasError=NetUserModalsGet(pdci->DomainControllerName, 2, (LPBYTE *)&pumi2);
if(NERR_Success!=nasError) {
hr=HRESULT_FROM_WIN32(nasError);
_JumpError(hr, error, "NetUserModalsGet");
}
nSubAuthorities=*GetSidSubAuthorityCount(pumi2->usrmod2_domain_id);
// allocate storage for new Sid. account domain Sid + account Rid
psidRootDomEntity=(SID *)LocalAlloc(LPTR, GetSidLengthRequired((UCHAR)(nSubAuthorities+1)));
_JumpIfOutOfMemory(hr, error, psidRootDomEntity);
// copy the first few peices into the SID
if (!InitializeSid(psidRootDomEntity,
GetSidIdentifierAuthority(pumi2->usrmod2_domain_id),
(BYTE)(nSubAuthorities+1)))
{
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "InitializeSid");
}
// copy existing subauthorities from account domain Sid into new Sid
for (nSubAuthIndex=0; nSubAuthIndex < nSubAuthorities ; nSubAuthIndex++) {
*GetSidSubAuthority(psidRootDomEntity, nSubAuthIndex)=
*GetSidSubAuthority(pumi2->usrmod2_domain_id, nSubAuthIndex);
}
// append Rid to new Sid
*GetSidSubAuthority(psidRootDomEntity, nSubAuthorities)=dwEntityRid;
*ppSid=psidRootDomEntity;
psidRootDomEntity=NULL;
hr=S_OK;
error:
if (NULL!=psidRootDomEntity) {
LocalFree(psidRootDomEntity);
}
if (NULL!=pdci) {
NetApiBufferFree(pdci);
}
if (NULL!=pdci) {
NetApiBufferFree(pdciForest);
}
if (NULL!=pumi2) {
NetApiBufferFree(pumi2);
}
return hr;
}
//--------------------------------------------------------------------
static HRESULT GetEntAdminSid(SID ** ppSid)
{
return GetRootDomEntitySid(ppSid, DOMAIN_GROUP_RID_ENTERPRISE_ADMINS);
}
//--------------------------------------------------------------------
static HRESULT GetRootDomAdminSid(SID ** ppSid)
{
return GetRootDomEntitySid(ppSid, DOMAIN_GROUP_RID_ADMINS);
}
//--------------------------------------------------------------------
static HRESULT GetThisComputerSid(SID ** ppSid)
{
HRESULT hr;
DWORD cchSize;
DWORD dwSidSize;
DWORD dwDomainSize;
SID_NAME_USE snu;
// must be cleaned up
SID * psidThisComputer=NULL;
WCHAR * wszName=NULL;
WCHAR * wszDomain=NULL;
// initialize out params
*ppSid=NULL;
// get the size of the computer's name
cchSize=0;
_Verify(!GetComputerObjectNameW(NameSamCompatible, NULL, &cchSize), hr, error);
if (ERROR_INSUFFICIENT_BUFFER!=GetLastError()) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetComputerObjectNameW");
}
// bug in GetComputerObjectNameW
cchSize++;
// allocate memory
wszName=(WCHAR *)LocalAlloc(LPTR, cchSize*sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, wszName);
// get the computer's name
if (!GetComputerObjectNameW(NameSamCompatible, wszName, &cchSize)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetComputerObjectNameW");
}
// get the size of the sid
dwSidSize=0;
dwDomainSize=0;
_Verify(!LookupAccountNameW(NULL, wszName, NULL, &dwSidSize, NULL, &dwDomainSize, &snu), hr, error);
if (ERROR_INSUFFICIENT_BUFFER!=GetLastError()) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "LookupAccountNameW");
}
// allocate memory
wszDomain=(WCHAR *)LocalAlloc(LPTR, dwDomainSize*sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, wszDomain);
psidThisComputer=(SID *)LocalAlloc(LPTR, dwSidSize);
_JumpIfOutOfMemory(hr, error, psidThisComputer);
// get the sid
if (!LookupAccountNameW(NULL, wszName, psidThisComputer, &dwSidSize, wszDomain, &dwDomainSize, &snu)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "LookupAccountNameW");
}
// success!
*ppSid=psidThisComputer;
psidThisComputer=NULL;
hr=S_OK;
error:
if (NULL!=psidThisComputer) {
LocalFree(psidThisComputer);
}
if (NULL!=wszName) {
LocalFree(wszName);
}
if (NULL!=wszDomain) {
LocalFree(wszDomain);
}
return hr;
}
//--------------------------------------------------------------------
static HRESULT ConfirmAccess(PSECURITY_DESCRIPTOR * ppSD, SID * pTrustworthySid, BOOL * pbSDChanged)
{
//define ENROLL_ACCESS_MASK (0x130)
HRESULT hr;
PACL pAcl;
BOOL bAclPresent;
BOOL bDefaultAcl;
unsigned int nIndex;
ACL_SIZE_INFORMATION aclsizeinfo;
bool bSidInAcl;
// must be cleaned up
PSECURITY_DESCRIPTOR pAbsSD=NULL;
ACL * pAbsDacl=NULL;
ACL * pAbsSacl=NULL;
SID * pAbsOwner=NULL;
SID * pAbsPriGrp=NULL;
ACL * pNewDacl=NULL;
PSECURITY_DESCRIPTOR pNewSD=NULL;
// initialize out params
*pbSDChanged=FALSE;
// get the (D)ACL from the security descriptor
if (!GetSecurityDescriptorDacl(*ppSD, &bAclPresent, &pAcl, &bDefaultAcl)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetSecurityDescriptorDacl");
}
_Verify(bAclPresent, hr, error);
if (NULL==pAcl) {
hr=E_FAIL;
_JumpError(hr, error, "GetSecurityDescriptorDacl");
}
// find out how many ACEs
if (!GetAclInformation(pAcl, &aclsizeinfo, sizeof(aclsizeinfo), AclSizeInformation)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetAclInformation");
}
//DumpAcl(pAcl,aclsizeinfo);
// find our sid in the acl
bSidInAcl=false;
for (nIndex=0; nIndex<aclsizeinfo.AceCount; nIndex++) {
ACE_HEADER * pAceHeader;
ACCESS_ALLOWED_OBJECT_ACE * pAccessAce;
PSID pSid=NULL;
if (!GetAce(pAcl, nIndex, (void**)&pAceHeader)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetAce");
}
// find the sid for this ACE
if (ACCESS_ALLOWED_OBJECT_ACE_TYPE!=pAceHeader->AceType && ACCESS_DENIED_OBJECT_ACE_TYPE!=pAceHeader->AceType) {
// we are only interested in OBJECT ace types
continue;
}
// note that ACCESS_ALLOWED_OBJECT_ACE and ACCESS_DENIED_OBJECT_ACE are the same structurally.
pAccessAce=(ACCESS_ALLOWED_OBJECT_ACE *)pAceHeader;
_Verify(ACE_OBJECT_TYPE_PRESENT==pAccessAce->Flags, hr, error);
pSid=((BYTE *)&pAccessAce->SidStart)-sizeof(GUID);
// confirm the GUID
if (!IsEqualGUID(pAccessAce->ObjectType, GUID_ENROLL)) {
continue;
}
// make sure this is the sid we are looking for
if (!EqualSid(pSid, pTrustworthySid)) {
continue;
}
// Was this a denial?
if (ACCESS_DENIED_OBJECT_ACE_TYPE==pAceHeader->AceType) {
// It's not anymore!
pAceHeader->AceType=ACCESS_ALLOWED_OBJECT_ACE_TYPE;
*pbSDChanged=TRUE;
}
// is the mask wrong?
if (0==(pAccessAce->Mask&ACTRL_DS_CONTROL_ACCESS)) {
// It's not anymore!
pAccessAce->Mask|=ACTRL_DS_CONTROL_ACCESS;
*pbSDChanged=TRUE;
}
// The sid is now in the acl and set to allow access.
bSidInAcl=true;
break;
}
// Was the sid in the acl?
if (false==bSidInAcl) {
SECURITY_DESCRIPTOR_CONTROL sdcon;
DWORD dwRevision;
DWORD dwNewAclSize;
DWORD dwAbsSDSize=0;
DWORD dwDaclSize=0;
DWORD dwSaclSize=0;
DWORD dwOwnerSize=0;
DWORD dwPriGrpSize=0;
ACE_HEADER * pFirstAce;
DWORD dwRelSDSize=0;
// we have to be self-relative
if (!GetSecurityDescriptorControl(*ppSD, &sdcon, &dwRevision)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetSecurityDescriptorControl");
}
_Verify(sdcon&SE_SELF_RELATIVE, hr, error);
// get the sizes
_Verify(!MakeAbsoluteSD(*ppSD, NULL, &dwAbsSDSize, NULL, &dwDaclSize, NULL, &dwSaclSize, NULL, &dwOwnerSize, NULL, &dwPriGrpSize), hr, error);
if (ERROR_INSUFFICIENT_BUFFER!=GetLastError()) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "MakeAbsoluteSD");
}
// allocate memory
pAbsSD=(PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwAbsSDSize);
_JumpIfOutOfMemory(hr, error, pAbsSD);
pAbsDacl=(ACL * )LocalAlloc(LPTR, dwDaclSize);
_JumpIfOutOfMemory(hr, error, pAbsDacl);
pAbsSacl=(ACL * )LocalAlloc(LPTR, dwSaclSize);
_JumpIfOutOfMemory(hr, error, pAbsSacl);
pAbsOwner=(SID *)LocalAlloc(LPTR, dwOwnerSize);
_JumpIfOutOfMemory(hr, error, pAbsOwner);
pAbsPriGrp=(SID *)LocalAlloc(LPTR, dwPriGrpSize);
_JumpIfOutOfMemory(hr, error, pAbsPriGrp);
// copy the SD to the memory buffers
if (!MakeAbsoluteSD(*ppSD, pAbsSD, &dwAbsSDSize, pAbsDacl, &dwDaclSize, pAbsSacl, &dwSaclSize, pAbsOwner, &dwOwnerSize, pAbsPriGrp, &dwPriGrpSize)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "MakeAbsoluteSD");
}
// get the current size info for the dacl
if (!GetAclInformation(pAbsDacl, &aclsizeinfo, sizeof(aclsizeinfo), AclSizeInformation)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetAclInformation");
}
// figure out the new size
dwNewAclSize=aclsizeinfo.AclBytesInUse+sizeof(_ACCESS_ALLOWED_OBJECT_ACE)
-sizeof(GUID) //ACCESS_ALLOWED_OBJECT_ACE::InheritedObjectType
-sizeof(DWORD) //ACCESS_ALLOWED_OBJECT_ACE::SidStart
+GetLengthSid(pTrustworthySid);
// allocate memory
pNewDacl=(ACL *)LocalAlloc(LPTR, dwNewAclSize);
_JumpIfOutOfMemory(hr, error, pNewDacl);
// init the header
if (!InitializeAcl(pNewDacl, dwNewAclSize, ACL_REVISION_DS)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "InitializeAcl");
}
// find the first ace in the dacl
if (!GetAce(pAbsDacl, 0, (void **)&pFirstAce)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetAce");
}
// add all the old aces
if (!AddAce(pNewDacl, ACL_REVISION_DS, 0, pFirstAce, aclsizeinfo.AclBytesInUse-sizeof(ACL))) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "AddAce");
}
// finally, add the new acl
if (!AddAccessAllowedObjectAce(pNewDacl, ACL_REVISION_DS, OBJECT_INHERIT_ACE, ACTRL_DS_CONTROL_ACCESS, (GUID *)&GUID_ENROLL, NULL, pTrustworthySid)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "AddAccessAllowedObjectAce");
}
// stick the new dacl in the sd
if (!SetSecurityDescriptorDacl(pAbsSD, TRUE, pNewDacl, FALSE)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "SetSecurityDescriptorDacl");
}
// compact everything back together
// get the size
_Verify(!MakeSelfRelativeSD(pAbsSD, NULL, &dwRelSDSize), hr, error);
if (ERROR_INSUFFICIENT_BUFFER!=GetLastError()) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "MakeSelfRelativeSD");
}
// allocate memory
pNewSD=(PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwRelSDSize);
_JumpIfOutOfMemory(hr, error, pNewSD);
// copy the SD to the new memory buffer
if (!MakeSelfRelativeSD(pAbsSD, pNewSD, &dwRelSDSize)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "MakeSelfRelativeSD");
}
// Whew! We made it!
LocalFree(*ppSD);
*ppSD=pNewSD;
pNewSD=NULL;
*pbSDChanged=TRUE;
} // <- end if sid not in acl
_Verify(IsValidSecurityDescriptor(*ppSD), hr, error);
hr=S_OK;
error:
if (NULL!=pNewSD) {
LocalFree(pNewSD);
}
if (NULL!=pNewDacl) {
LocalFree(pNewDacl);
}
if (NULL!=pAbsSD) {
LocalFree(pAbsSD);
}
if (NULL!=pAbsDacl) {
LocalFree(pAbsDacl);
}
if (NULL!=pAbsSacl) {
LocalFree(pAbsSacl);
}
if (NULL!=pAbsOwner) {
LocalFree(pAbsOwner);
}
if (NULL!=pAbsPriGrp) {
LocalFree(pAbsPriGrp);
}
return hr;
}
//####################################################################
// public functions
//--------------------------------------------------------------------
BOOL IsNT5(void)
{
HRESULT hr;
OSVERSIONINFO ovi;
static BOOL s_fDone=FALSE;
static BOOL s_fNT5=FALSE;
if (!s_fDone) {
s_fDone=TRUE;
// get and confirm platform info
ovi.dwOSVersionInfoSize = sizeof(ovi);
if (!GetVersionEx(&ovi)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetVersionEx");
}
if (VER_PLATFORM_WIN32_NT!=ovi.dwPlatformId) {
hr=ERROR_CANCELLED;
_JumpError(hr, error, "Not a supported OS");
}
if ((5 <= ovi.dwMajorVersion) && (1 <= ovi.dwMinorVersion)){
s_fNT5=TRUE;
}
}
error:
return s_fNT5;
}
//--------------------------------------------------------------------
BOOL IsIISInstalled(void)
{
HRESULT hr;
// must be cleaned up
IMSAdminBase * pIMeta=NULL;
hr=CoCreateInstance(
CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(VOID **) &pIMeta);
if (FAILED(hr)) {
_IgnoreError(hr, "CoCreateInstance(CLSID_MSAdminBase)");
}
//error:
if (NULL!=pIMeta) {
pIMeta->Release();
}
return (S_OK==hr);
}
//--------------------------------------------------------------------
HRESULT CEPUpdateApplicationPool(BOOL fDC, const WCHAR * pwszApplicationPool, BOOL fLocalSystem, const WCHAR * pwszUserName, const WCHAR * pwszPassword)
{
HRESULT hr=E_FAIL;
METADATA_RECORD mr;
DWORD dwLogonMethod=MD_LOGON_INTERACTIVE;
DWORD dwAppPoolID=MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER;
DWORD dwTimeout=0;
// must be cleaned up
WCHAR * wszFullAppPath=NULL; // "/lm/w3svc/apppools/SCEP"
IMSAdminBase * pIMeta=NULL;
METADATA_HANDLE hMetaRoot=NULL;
METADATA_HANDLE hMetaKey=NULL;
//check input parameter
if(NULL==pwszApplicationPool)
{
hr=E_INVALIDARG;
_JumpIfError(hr, error, "paramCheck");
}
//change the logon type to network logon on the DC so that the domain account does not have
//to have the local logon provilege to the DC; NETWORK logon does not have the correct token
//to validate user on the network; since we are running the DC, we should be validate locally
//and everything should just work.
if(fDC)
dwLogonMethod=MD_LOGON_NETWORK;
if(fLocalSystem)
{
dwAppPoolID=MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM;
}
else
{
dwAppPoolID=MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER;
if((NULL==pwszUserName) || (NULL==pwszPassword))
{
hr=E_INVALIDARG;
_JumpIfError(hr, error, "paramCheck");
}
}
wszFullAppPath=(WCHAR *)LocalAlloc(LPTR, (wcslen(gc_wszAppPoolBase)+1+wcslen(pwszApplicationPool)+1)*sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, wszFullAppPath);
wcscpy(wszFullAppPath, gc_wszAppPoolBase);
wcscat(wszFullAppPath, L"/");
wcscat(wszFullAppPath, pwszApplicationPool);
// Create an instance of the metabase object
hr=CoCreateInstance(
CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(void **) &pIMeta);
_JumpIfError(hr, error, "CoCreateInstance(CLSID_MSAdminBase)");
// open the top level
hr=vrOpenRoot(pIMeta, FALSE, gc_wszAppPoolBase, &hMetaRoot);
_JumpIfError(hr, error, "vrOpenRoot");
// Add new VDir called "SCEP"
hr=pIMeta->AddKey(hMetaRoot, pwszApplicationPool);
if(HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)==hr)
{
// That's fine.
_IgnoreError(hr, "AddKey");
}
else
{
_JumpIfErrorStr(hr, error, "AddKey", pwszApplicationPool);
}
// close the root key
hr=pIMeta->CloseKey(hMetaRoot);
hMetaRoot=NULL;
_JumpIfError(hr, error, "CloseKey");
// Open the new VDir at /lm/w3svc/apppools/SCEP
hr=pIMeta->OpenKey(
METADATA_MASTER_ROOT_HANDLE,
wszFullAppPath,
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
1000,
&hMetaKey);
_JumpIfErrorStr(hr, error, "OpenKey", wszFullAppPath);
//set properties on this application
if(FALSE == fLocalSystem)
{
//set the UserName
memset(&mr, 0, sizeof(METADATA_RECORD));
mr.dwMDIdentifier=MD_WAM_USER_NAME;
mr.dwMDAttributes=METADATA_INHERIT;
mr.dwMDUserType=IIS_MD_UT_FILE;
mr.dwMDDataType=STRING_METADATA;
mr.dwMDDataLen=(wcslen(pwszUserName)+1)*sizeof(WCHAR);
mr.pbMDData=(BYTE *)(pwszUserName);
hr=pIMeta->SetData(hMetaKey, L"", &mr);
_JumpIfError(hr, error, "SetData");
//set the password
memset(&mr, 0, sizeof(METADATA_RECORD));
mr.dwMDIdentifier=MD_WAM_PWD;
mr.dwMDAttributes=METADATA_INHERIT | METADATA_SECURE;
mr.dwMDUserType=IIS_MD_UT_FILE;
mr.dwMDDataType=STRING_METADATA;
mr.dwMDDataLen=(wcslen(pwszPassword)+1)*sizeof(WCHAR);
mr.pbMDData=(BYTE *)(pwszPassword);
hr=pIMeta->SetData(hMetaKey, L"", &mr);
_JumpIfError(hr, error, "SetData");
//set the logon method
memset(&mr, 0, sizeof(METADATA_RECORD));
mr.dwMDIdentifier=MD_LOGON_METHOD;
mr.dwMDAttributes=METADATA_INHERIT;
mr.dwMDUserType=IIS_MD_UT_FILE;
mr.dwMDDataType=DWORD_METADATA;
mr.dwMDDataLen=sizeof(dwLogonMethod);
mr.pbMDData=(BYTE *)(&dwLogonMethod);
hr=pIMeta->SetData(hMetaKey, L"", &mr);
_JumpIfError(hr, error, "SetData");
}
//set the application identity
memset(&mr, 0, sizeof(METADATA_RECORD));
mr.dwMDIdentifier=MD_APPPOOL_IDENTITY_TYPE;
mr.dwMDAttributes=METADATA_INHERIT;
mr.dwMDUserType=IIS_MD_UT_SERVER;
mr.dwMDDataType=DWORD_METADATA;
mr.dwMDDataLen=sizeof(dwAppPoolID);
mr.pbMDData=(BYTE *)(&dwAppPoolID);
hr=pIMeta->SetData(hMetaKey, L"", &mr);
_JumpIfError(hr, error, "SetData");
#ifdef MD_APPPOOL_FRIENDLY_NAME
//set the application pool friendly name
memset(&mr, 0, sizeof(METADATA_RECORD));
mr.dwMDIdentifier=MD_APPPOOL_FRIENDLY_NAME;
mr.dwMDAttributes=METADATA_NO_ATTRIBUTES;
mr.dwMDUserType=IIS_MD_UT_SERVER;
mr.dwMDDataType=STRING_METADATA;
mr.dwMDDataLen=(wcslen(pwszApplicationPool)+1)*sizeof(WCHAR);
mr.pbMDData=(BYTE *)(pwszApplicationPool);
hr=pIMeta->SetData(hMetaKey, L"", &mr);
_JumpIfError(hr, error, "SetData");
#endif
//set the PeriodicRestartTime to 0
memset(&mr, 0, sizeof(METADATA_RECORD));
mr.dwMDIdentifier=MD_APPPOOL_PERIODIC_RESTART_TIME;
mr.dwMDAttributes=METADATA_INHERIT;
mr.dwMDUserType=IIS_MD_UT_SERVER;
mr.dwMDDataType=DWORD_METADATA;
mr.dwMDDataLen=sizeof(dwTimeout);
mr.pbMDData=(BYTE *)(&dwTimeout);
hr=pIMeta->SetData(hMetaKey, L"", &mr);
_JumpIfError(hr, error, "SetData");
//set the IDleTimeOut to 0
memset(&mr, 0, sizeof(METADATA_RECORD));
mr.dwMDIdentifier=MD_APPPOOL_IDLE_TIMEOUT;
mr.dwMDAttributes=METADATA_INHERIT;
mr.dwMDUserType=IIS_MD_UT_SERVER;
mr.dwMDDataType=DWORD_METADATA;
mr.dwMDDataLen=sizeof(dwTimeout);
mr.pbMDData=(BYTE *)(&dwTimeout);
hr=pIMeta->SetData(hMetaKey, L"", &mr);
_JumpIfError(hr, error, "SetData");
// done with this key.
hr=pIMeta->CloseKey(hMetaKey);
hMetaKey=NULL;
_JumpIfError(hr, error, "CloseKey");
// Flush out the changes and close
pIMeta->SaveData();
hr=S_OK;
error:
if (NULL!=wszFullAppPath)
{
LocalFree(wszFullAppPath);
}
if (NULL!=hMetaKey)
{
pIMeta->CloseKey(hMetaKey);
}
if (NULL!=hMetaRoot)
{
pIMeta->CloseKey(hMetaRoot);
}
if (NULL!=pIMeta)
{
pIMeta->Release();
}
return hr;
}
//--------------------------------------------------------------------
HRESULT AddVDir(IN BOOL fDC,
IN const WCHAR * wszDirectory,
IN const WCHAR * wszApplicationPool,
IN BOOL fLocalSystem,
IN const WCHAR * wszUserName,
IN const WCHAR * wszPassword)
{
HRESULT hr;
METADATA_RECORD mr;
DWORD dwAccessPerms;
DWORD dwAuthenticationType;
const WCHAR * wszKeyType=IIS_CLASS_WEB_VDIR_W;
WCHAR wszSysDirBuf[MAX_PATH + 2];
bool fISAPIEnabled=false;
BOOL fEnabled=FALSE;
// must be cleaned up
IMSAdminBase * pIMeta=NULL;
IWamAdmin * pIWam=NULL;
IIISApplicationAdmin *pIIISAppAdmin=NULL;
METADATA_HANDLE hMetaRoot=NULL;
METADATA_HANDLE hMetaKey=NULL;
WCHAR * wszPhysicalPath=NULL; // "c:\winnt\system32\certsrv\mscep"
WCHAR * wszRelativeVirtualPath=NULL; // "certsrv/mscep"
WCHAR * wszFullVirtualPath=NULL; // "/LM/W3svc/1/ROOT/certsrv/mscep"
WCHAR * wszFullPhysicalPath=NULL; // "c:\winnt\system32\certsrv\mscep\mscep.dll"
// build the directories
if (FALSE==GetSystemDirectoryW(wszSysDirBuf, MAX_PATH + 2)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetSystemDirectory");
}
wszPhysicalPath=(WCHAR *)LocalAlloc(LPTR, (wcslen(wszSysDirBuf)+1+wcslen(gc_wszCertSrvDir)+1+wcslen(wszDirectory)+1)*sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, wszPhysicalPath);
wcscpy(wszPhysicalPath, wszSysDirBuf);
wcscat(wszPhysicalPath, L"\\");
wcscat(wszPhysicalPath, gc_wszCertSrvDir);
wcscat(wszPhysicalPath, L"\\");
wcscat(wszPhysicalPath, wszDirectory);
wszRelativeVirtualPath=(WCHAR *)LocalAlloc(LPTR, (wcslen(gc_wszCertSrvDir)+1+wcslen(wszDirectory)+1)*sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, wszRelativeVirtualPath);
wcscpy(wszRelativeVirtualPath, gc_wszCertSrvDir);
wcscat(wszRelativeVirtualPath, L"/");
wcscat(wszRelativeVirtualPath, wszDirectory);
wszFullVirtualPath=(WCHAR *)LocalAlloc(LPTR, (wcslen(gc_wszBaseRoot)+1+wcslen(wszRelativeVirtualPath)+1)*sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, wszFullVirtualPath);
wcscpy(wszFullVirtualPath, gc_wszBaseRoot);
wcscat(wszFullVirtualPath, L"/");
wcscat(wszFullVirtualPath, wszRelativeVirtualPath);
wszFullPhysicalPath=(WCHAR *)LocalAlloc(LPTR, (wcslen(wszPhysicalPath)+1+wcslen(L"\\")+wcslen(CEP_DLL_NAME)) * sizeof(WCHAR));
_JumpIfOutOfMemory(hr, error, wszFullPhysicalPath);
wcscpy(wszFullPhysicalPath, wszPhysicalPath);
wcscat(wszFullPhysicalPath, L"\\");
wcscat(wszFullPhysicalPath, CEP_DLL_NAME);
//enable the ISAPI Extension on IIS
hr=IsISAPIExtensionEnabled(wszFullPhysicalPath, fISAPIEnabled);
//do not respond to error for backward compatibility of previous IDS build
if((S_OK == hr) && (!fISAPIEnabled))
{
hr=EnableISAPIExtension(wszFullPhysicalPath, &fEnabled);
_JumpIfError(hr, error, "EnableISAPIExtension");
}
// Create an instance of the metabase object
hr=CoCreateInstance(
CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(void **) &pIMeta);
_JumpIfError(hr, error, "CoCreateInstance(CLSID_MSAdminBase)");
// open the top level
hr=vrOpenRoot(pIMeta, FALSE/*not read-only*/, gc_wszBaseRoot, &hMetaRoot);
_JumpIfError(hr, error, "vrOpenRoot");
// Add new VDir called gc_wszVRootName
__try {
hr=pIMeta->AddKey(hMetaRoot, wszRelativeVirtualPath);
} _TrapException(hr);
if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)==hr) {
// That's fine.
_IgnoreError(hr, "AddKey");
} else {
_JumpIfErrorStr(hr, error, "AddKey", wszRelativeVirtualPath);
}
// close the root key
__try {
hr=pIMeta->CloseKey(hMetaRoot);
} _TrapException(hr);
hMetaRoot=NULL;
_JumpIfError(hr, error, "CloseKey");
// Open the new VDir
__try {
hr=pIMeta->OpenKey(
METADATA_MASTER_ROOT_HANDLE,
wszFullVirtualPath,
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
1000,
&hMetaKey);
} _TrapException(hr);
_JumpIfErrorStr(hr, error, "OpenKey", wszFullVirtualPath);
// Set the physical path for this VDir
// virtual root path
mr.dwMDIdentifier=MD_VR_PATH;
mr.dwMDAttributes=METADATA_INHERIT;
mr.dwMDUserType=IIS_MD_UT_FILE;
mr.dwMDDataType=STRING_METADATA;
mr.dwMDDataLen=(wcslen(wszPhysicalPath)+1)*sizeof(WCHAR);
mr.pbMDData=(BYTE *)(wszPhysicalPath);
__try {
hr=pIMeta->SetData(hMetaKey, L"", &mr);
} _TrapException(hr);
_JumpIfError(hr, error, "SetData");
// access permissions on VRoots: read & execute
dwAccessPerms=MD_ACCESS_EXECUTE | MD_ACCESS_READ;
mr.dwMDIdentifier=MD_ACCESS_PERM;
mr.dwMDAttributes=METADATA_INHERIT;
mr.dwMDUserType=IIS_MD_UT_FILE;
mr.dwMDDataType=DWORD_METADATA;
mr.dwMDDataLen=sizeof(dwAccessPerms);
mr.pbMDData=(BYTE *)(&dwAccessPerms);
__try {
hr=pIMeta->SetData(hMetaKey, L"", &mr);
} _TrapException(hr);
_JumpIfError(hr, error, "SetData");
// indicate that what we created is a vroot - set the key type
mr.dwMDIdentifier=MD_KEY_TYPE;
mr.dwMDAttributes=METADATA_NO_ATTRIBUTES;
mr.dwMDUserType=IIS_MD_UT_SERVER;
mr.dwMDDataType=STRING_METADATA;
mr.dwMDDataLen=(wcslen(wszKeyType)+1)*sizeof(WCHAR);
mr.pbMDData=(BYTE *)(wszKeyType);
__try {
hr=pIMeta->SetData(hMetaKey, L"", &mr);
} _TrapException(hr);
_JumpIfError(hr, error, "SetData");
// set authentication to be anonymous or NTLM
dwAuthenticationType=MD_AUTH_ANONYMOUS|MD_AUTH_NT;
mr.dwMDIdentifier=MD_AUTHORIZATION;
mr.dwMDAttributes=METADATA_INHERIT;
mr.dwMDUserType=IIS_MD_UT_FILE;
mr.dwMDDataType=DWORD_METADATA;
mr.dwMDDataLen=sizeof(dwAuthenticationType);
mr.pbMDData=reinterpret_cast<BYTE *>(&dwAuthenticationType);
__try {
hr=pIMeta->SetData(hMetaKey, L"", &mr);
} _TrapException(hr);
_JumpIfError(hr, error, "SetData");
// set the default document
mr.dwMDIdentifier=MD_DEFAULT_LOAD_FILE;
mr.dwMDAttributes=METADATA_NO_ATTRIBUTES;
mr.dwMDUserType=IIS_MD_UT_FILE;
mr.dwMDDataType=STRING_METADATA;
mr.dwMDDataLen=(wcslen(gc_wszCepDllName)+1)*sizeof(WCHAR);
mr.pbMDData=(BYTE *)(gc_wszCepDllName);
__try {
hr=pIMeta->SetData(hMetaKey, L"", &mr);
} _TrapException(hr);
_JumpIfError(hr, error, "SetData");
// done with this key.
__try {
hr=pIMeta->CloseKey(hMetaKey);
} _TrapException(hr);
hMetaKey=NULL;
_JumpIfError(hr, error, "CloseKey");
// Flush out the changes and close
__try {
hr=pIMeta->SaveData();
} _TrapException(hr);
// _JumpIfError(hr, "SaveData");
if (FAILED(hr)) {
_IgnoreError(hr, "SaveData");
}
hr=S_OK;
// Create a 'web application' so that scrdenrl.dll runs in-process
// Create an instance of the metabase object
hr=CoCreateInstance(
CLSID_WamAdmin,
NULL,
CLSCTX_ALL,
IID_IWamAdmin,
(void **) &pIWam);
_JumpIfError(hr, error, "CoCreateInstance(CLSID_WamAdmin)");
// Create the application running in-process
__try {
hr=pIWam->AppCreate(wszFullVirtualPath, TRUE);
} _TrapException(hr);
_JumpIfError(hr, error, "AppCreate");
//create an application pool
hr=CoCreateInstance(
CLSID_WamAdmin,
NULL,
CLSCTX_ALL,
IID_IIISApplicationAdmin,
(void **) &pIIISAppAdmin);
_JumpIfError(hr, error, "CoCreateInstance(IID_IIISApplicationAdmin)");
hr=pIIISAppAdmin->CreateApplication(wszFullVirtualPath, eAppRunInProc, wszApplicationPool, TRUE);
if(hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
{
// That's fine since installation can be run multiple times
_IgnoreError(hr, "CreateApplication");
}
else
{
_JumpIfErrorStr(hr, error, "CreateApplication", wszFullVirtualPath);
}
//update an application pool
hr=CEPUpdateApplicationPool(fDC, wszApplicationPool, fLocalSystem, wszUserName, wszPassword);
_JumpIfError(hr, error, "CEPCreateApplicationPool");
hr=S_OK;
error:
if (NULL!=wszFullVirtualPath) {
LocalFree(wszFullVirtualPath);
}
if (NULL!=wszRelativeVirtualPath) {
LocalFree(wszRelativeVirtualPath);
}
if (NULL!=wszPhysicalPath) {
LocalFree(wszPhysicalPath);
}
if (NULL!=wszFullPhysicalPath)
{
LocalFree(wszFullPhysicalPath);
}
if (NULL!=hMetaKey) {
HRESULT hr2;
__try {
hr2=pIMeta->CloseKey(hMetaKey);
} _TrapException(hr2);
_TeardownError(hr, hr2, "CloseKey");
}
if (NULL!=hMetaRoot) {
HRESULT hr2;
__try {
hr2=pIMeta->CloseKey(hMetaRoot);
} _TrapException(hr2);
_TeardownError(hr, hr2, "CloseKey");
}
if (NULL!=pIIISAppAdmin) {
pIIISAppAdmin->Release();
}
if (NULL!=pIWam) {
pIWam->Release();
}
if (NULL!=pIMeta) {
pIMeta->Release();
}
return hr;
}
//--------------------------------------------------------------------
HRESULT CepStopService(IN DWORD dwServicePeriod, const WCHAR * wszServiceName, BOOL * pbWasRunning)
{
HRESULT hr;
SERVICE_STATUS ss;
unsigned int nAttempts;
// must be cleaned up
SC_HANDLE hSCManager=NULL;
SC_HANDLE hService=NULL;
// initialize out parameters
*pbWasRunning=FALSE;
// talk to the service manager
hSCManager=OpenSCManagerW(NULL/*machine*/, NULL/*db*/, SC_MANAGER_ALL_ACCESS);
if (NULL==hSCManager) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "OpenSCManager");
}
// get to the service
hService=OpenServiceW(hSCManager, wszServiceName, SERVICE_ALL_ACCESS);
if (NULL==hService) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpErrorStr(hr, error, "OpenService", wszServiceName);
}
// see if the service is running
if (FALSE==QueryServiceStatus(hService, &ss)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpErrorStr(hr, error, "QueryServiceStatus", wszServiceName);
}
if (SERVICE_STOPPED!=ss.dwCurrentState && SERVICE_STOP_PENDING!=ss.dwCurrentState) {
*pbWasRunning=TRUE;
}
// begin the service stopping loop
for (nAttempts=0; SERVICE_STOPPED!=ss.dwCurrentState && nAttempts<dwServicePeriod; nAttempts++) {
// service is running, must stop it.
if (SERVICE_STOP_PENDING!=ss.dwCurrentState) {
if (!ControlService(hService, SERVICE_CONTROL_STOP, &ss)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpErrorStr(hr, error, "ControlService(Stop)", wszServiceName);
}
}
// wait a little while
Sleep(1000);
// see if the service is running
if (FALSE==QueryServiceStatus(hService, &ss)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpErrorStr(hr, error, "QueryServiceStatus", wszServiceName);
}
}
if (nAttempts>=dwServicePeriod) {
// it never stopped
hr=HRESULT_FROM_WIN32(ERROR_SERVICE_REQUEST_TIMEOUT);
_JumpErrorStr(hr, error, "Stopping service", wszServiceName);
}
hr=S_OK;
error:
if (NULL!=hService) {
CloseServiceHandle(hService);
}
if (NULL!=hSCManager) {
CloseServiceHandle(hSCManager);
}
return hr;
}
//--------------------------------------------------------------------
HRESULT CepStartService(const WCHAR * wszServiceName)
{
HRESULT hr;
SERVICE_STATUS ss;
// must be cleaned up
SC_HANDLE hSCManager=NULL;
SC_HANDLE hService=NULL;
// talk to the service manager
hSCManager=OpenSCManagerW(NULL/*machine*/, NULL/*db*/, SC_MANAGER_ALL_ACCESS);
if (NULL==hSCManager) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "OpenSCManager");
}
// get to the service
hService=OpenServiceW(hSCManager, wszServiceName, SERVICE_ALL_ACCESS);
if (NULL==hService) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpErrorStr(hr, error, "OpenService", wszServiceName);
}
// now, start the service.
if (FALSE==StartServiceW(hService, 0 /*num args*/, NULL /*args*/)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "OpenSCManager");
}
hr=S_OK;
error:
if (NULL!=hService) {
CloseServiceHandle(hService);
}
if (NULL!=hSCManager) {
CloseServiceHandle(hSCManager);
}
return hr;
}
//--------------------------------------------------------------------
BOOL IsGoodCaInstalled(void)
{
HRESULT hr;
DWORD dwError;
DWORD dwType;
DWORD dwDataSize;
DWORD dwSetupStatus;
BOOL bResult=FALSE;
DWORD dwCAType;
// must be cleaned up
HKEY hCurConfig=NULL;
// get the current configuration
hr=OpenCurrentCAConfig(&hCurConfig);
_JumpIfError(hr, error, "OpenCurrentCAConfig");
// get value SetupStatus
dwDataSize=sizeof(dwSetupStatus);
dwError=RegQueryValueExW(hCurConfig, wszREGSETUPSTATUS, NULL, &dwType, (BYTE *)&dwSetupStatus, &dwDataSize);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegQueryValueExW", wszREGSETUPSTATUS);
}
_Verify(REG_DWORD==dwType, hr, error);
_Verify(sizeof(dwSetupStatus)==dwDataSize, hr, error);
// make sure we have all the needed components set up
_Verify(0!=(dwSetupStatus&SETUP_SERVER_FLAG), hr, error);
_Verify(0!=(dwSetupStatus&SETUP_CLIENT_FLAG), hr, error);
_Verify(0==(dwSetupStatus&SETUP_SUSPEND_FLAG), hr, error);
// Check the CA Type too
dwDataSize=sizeof(dwCAType);
dwError=RegQueryValueExW(hCurConfig, wszREGCATYPE, NULL, &dwType, (BYTE *)&dwCAType, &dwDataSize);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegQueryValueExW", wszREGCATYPE);
}
_Verify(REG_DWORD==dwType, hr, error);
_Verify(sizeof(dwCAType)==dwDataSize, hr, error);
_Verify(dwCAType<=ENUM_UNKNOWN_CA, hr, error);
bResult=TRUE;
error:
if (NULL!=hCurConfig) {
RegCloseKey(hCurConfig);
}
return bResult;
}
//--------------------------------------------------------------------
BOOL IsServiceRunning(IN const WCHAR * wszServiceName)
{
HRESULT hr;
SERVICE_STATUS ss;
BOOL bResult=FALSE;
// must be cleaned up
SC_HANDLE hSCManager=NULL;
SC_HANDLE hService=NULL;
// talk to the service manager
hSCManager=OpenSCManagerW(NULL/*machine*/, NULL/*db*/, SC_MANAGER_ALL_ACCESS);
if (NULL==hSCManager) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "OpenSCManager");
}
// get to the service
hService=OpenServiceW(hSCManager, wszServiceName, SERVICE_ALL_ACCESS);
if (NULL==hService) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpErrorStr(hr, error, "OpenService", wszSERVICE_NAME);
}
// see if the service is running
if (FALSE==QueryServiceStatus(hService, &ss)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpErrorStr(hr, error, "QueryServiceStatus", wszSERVICE_NAME);
}
_Verify(SERVICE_RUNNING==ss.dwCurrentState, hr, error)
_Verify(0!=(SERVICE_ACCEPT_PAUSE_CONTINUE&ss.dwControlsAccepted), hr, error);
// looks like it is
bResult=TRUE;
error:
if (NULL!=hService) {
CloseServiceHandle(hService);
}
if (NULL!=hSCManager) {
CloseServiceHandle(hSCManager);
}
return bResult;
}
//--------------------------------------------------------------------
BOOL IsCaRunning(void)
{
return IsServiceRunning(wszSERVICE_NAME);
}
//--------------------------------------------------------------------
HRESULT EnrollForRACertificates(
IN const WCHAR * wszDistinguishedName,
IN const WCHAR * wszSignCSPName,
IN DWORD dwSignCSPType,
IN DWORD dwSignKeySize,
IN const WCHAR * wszEncryptCSPName,
IN DWORD dwEncryptCSPType,
IN DWORD dwEncryptKeySize,
IN SID *psidAccount)
{
HRESULT hr;
hr=EnrollForRACert(
wszDistinguishedName,
wszSignCSPName,
dwSignCSPType,
dwSignKeySize,
AT_SIGNATURE,
wszCERTTYPE_ENROLLMENT_AGENT_OFFLINE,
psidAccount);
_JumpIfError(hr, error, "EnrollForRACert(OfflineEnrollmentAgent)");
hr=EnrollForRACert(
wszDistinguishedName,
wszEncryptCSPName,
dwEncryptCSPType,
dwEncryptKeySize,
AT_KEYEXCHANGE,
wszCERTTYPE_CEP_ENCRYPTION,
psidAccount);
_JumpIfError(hr, error, "EnrollForRACert(CepEncryption)");
// all done
hr=S_OK;
error:
return hr;
}
//--------------------------------------------------------------------
HRESULT DoCertSrvRegChanges(IN BOOL bDisablePendingFirst)
{
HRESULT hr;
DWORD dwDataSize;
DWORD dwType;
DWORD dwError;
WCHAR * wszTravel;
DWORD dwNewDataSize;
DWORD dwRequestDisposition;
bool bSubjectTemplateAlreadyModified=false;
// must be cleaned up
HKEY hCaConfig=NULL;
WCHAR * mwszSubjectTemplate=NULL;
HKEY hPolicyModules=NULL;
HKEY hCurPolicy=NULL;
WCHAR * wszCurPolicy=NULL;
// get the current CA config key
hr=OpenCurrentCAConfig(&hCaConfig);
_JumpIfError(hr, error, "OpenCurrentCAConfig");
//
// add strings to the SubjectTemplate value
//
// get the size of the Multi_SZ
dwDataSize=0;
dwError=RegQueryValueExW(hCaConfig, wszREGSUBJECTTEMPLATE, NULL, &dwType, NULL, &dwDataSize);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegQueryValueExW", wszREGSUBJECTTEMPLATE);
}
_Verify(REG_MULTI_SZ==dwType, hr, error);
// add exra space for the strings we want to add
dwDataSize+=(wcslen(wszPROPUNSTRUCTUREDNAME)+1)*sizeof(WCHAR);
dwDataSize+=(wcslen(wszPROPUNSTRUCTUREDADDRESS)+1)*sizeof(WCHAR);
dwDataSize+=(wcslen(wszPROPDEVICESERIALNUMBER)+1)*sizeof(WCHAR);
dwNewDataSize=dwDataSize;
mwszSubjectTemplate=(WCHAR *)LocalAlloc(LPTR, dwDataSize);
_JumpIfOutOfMemory(hr, error, mwszSubjectTemplate);
// get the Multi_SZ
dwError=RegQueryValueExW(hCaConfig, wszREGSUBJECTTEMPLATE, NULL, &dwType, (BYTE *)mwszSubjectTemplate, &dwDataSize);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegQueryValueExW", wszREGSUBJECTTEMPLATE);
}
_Verify(REG_MULTI_SZ==dwType, hr, error);
// walk to the end
for (wszTravel=mwszSubjectTemplate; 0!=wcslen(wszTravel); wszTravel+=wcslen(wszTravel)+1) {
// while walking, make sure we haven't added these strings already
if (0==wcscmp(wszTravel, wszPROPUNSTRUCTUREDNAME)) {
bSubjectTemplateAlreadyModified=true;
break;
}
}
// we are now pointing at the last '\0' in the string, which we will overwrite
// did we do this already? If so, don't do it again.
if (false==bSubjectTemplateAlreadyModified) {
// add the strings
wcscpy(wszTravel, wszPROPUNSTRUCTUREDNAME);
wszTravel+=wcslen(wszTravel)+1;
wcscpy(wszTravel, wszPROPUNSTRUCTUREDADDRESS);
wszTravel+=wcslen(wszTravel)+1;
wcscpy(wszTravel, wszPROPDEVICESERIALNUMBER);
wszTravel+=wcslen(wszTravel)+1;
// add extra terminator
wszTravel[0]='\0';
// save the Multi_SZ
dwError=RegSetValueExW(hCaConfig, wszREGSUBJECTTEMPLATE, NULL, dwType, (BYTE *)mwszSubjectTemplate, dwNewDataSize);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegSetValueExW", wszREGSUBJECTTEMPLATE);
}
}
//
// remove the Pending First flag from the current policy settings
//
if (FALSE!=bDisablePendingFirst) {
// open the current policy
dwError=RegOpenKeyExW(hCaConfig, wszREGKEYPOLICYMODULES, NULL, KEY_READ, &hPolicyModules);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegOpenKeyExW", wszREGKEYPOLICYMODULES);
}
hr=GetRegString(hPolicyModules, wszREGACTIVE, &wszCurPolicy);
_JumpIfErrorStr(hr, error, "GetRegString", wszREGACTIVE);
dwError=RegOpenKeyExW(hPolicyModules, wszCurPolicy, NULL, KEY_ALL_ACCESS, &hCurPolicy);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegOpenKeyExW", wszCurPolicy);
}
// read the value
dwDataSize=sizeof(dwRequestDisposition);
dwError=RegQueryValueExW(hCurPolicy, wszREGREQUESTDISPOSITION, NULL, &dwType, (BYTE *)&dwRequestDisposition, &dwDataSize);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegQueryValueExW", wszREGREQUESTDISPOSITION);
}
_Verify(REG_DWORD==dwType, hr, error);
_Verify(sizeof(dwRequestDisposition)==dwDataSize, hr, error);
// clear the pending-first flag
dwRequestDisposition&=~REQDISP_PENDINGFIRST;
// save the vale
dwError=RegSetValueExW(hCurPolicy, wszREGREQUESTDISPOSITION, NULL, dwType, (BYTE *)&dwRequestDisposition, dwDataSize);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegSetValueExW", wszREGREQUESTDISPOSITION);
}
}
// all done
hr=S_OK;
error:
if (NULL!=wszCurPolicy) {
LocalFree(wszCurPolicy);
}
if (NULL!=hCurPolicy) {
RegCloseKey(hCurPolicy);
}
if (NULL!=hPolicyModules) {
RegCloseKey(hPolicyModules);
}
if (NULL!=mwszSubjectTemplate) {
LocalFree(mwszSubjectTemplate);
}
if (NULL!=hCaConfig) {
RegCloseKey(hCaConfig);
}
return hr;
}
//--------------------------------------------------------------------
HRESULT GetCaType(OUT ENUM_CATYPES * pCAType)
{
HRESULT hr;
DWORD dwDataSize;
DWORD dwCAType;
DWORD dwType;
DWORD dwError;
// must be cleaned up
HKEY hCaConfig=NULL;
// init out params
*pCAType=ENUM_UNKNOWN_CA;
// get the current CA config key
hr=OpenCurrentCAConfig(&hCaConfig);
_JumpIfError(hr, error, "OpenCurrentCAConfig");
// read the CA Type
dwDataSize=sizeof(dwCAType);
dwError=RegQueryValueExW(hCaConfig, wszREGCATYPE, NULL, &dwType, (BYTE *)&dwCAType, &dwDataSize);
if (ERROR_SUCCESS!=dwError) {
hr=HRESULT_FROM_WIN32(dwError);
_JumpErrorStr(hr, error, "RegQueryValueExW", wszREGCATYPE);
}
_Verify(REG_DWORD==dwType, hr, error);
_Verify(sizeof(dwCAType)==dwDataSize, hr, error);
_Verify(dwCAType<=ENUM_UNKNOWN_CA, hr, error);
// all done
hr=S_OK;
*pCAType=(ENUM_CATYPES)dwCAType;
error:
if (NULL!=hCaConfig) {
RegCloseKey(hCaConfig);
}
return hr;
}
//--------------------------------------------------------------------
BOOL IsUserInAdminGroup(IN BOOL bEnterprise)
{
BOOL bIsMember=FALSE;
HRESULT hr;
SID_IDENTIFIER_AUTHORITY siaNtAuthority=SECURITY_NT_AUTHORITY;
// must be cleaned up
HANDLE hAccessToken=NULL;
HANDLE hDupToken=NULL;
SID * psidLocalAdmins=NULL;
SID * psidEntAdmins=NULL;
SID * psidRootDomAdmins=NULL;
// Get the access token for this process
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, &hAccessToken)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "OpenProcessToken");
}
// CheckTokenMembership must operate on impersonation token, so make one
if (!DuplicateToken(hAccessToken, SecurityIdentification, &hDupToken)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "DuplicateToken");
}
if (bEnterprise) {
// see if the user is a member of the [domain]\Enmterprised Administrators group
BOOL bIsEntAdmin=FALSE;
BOOL bIsRootDomAdmin=FALSE;
// get the Enterpise Admin SID
hr=GetEntAdminSid(&psidEntAdmins);
_JumpIfError(hr, error, "GetEntAdminSid");
// check for membership
if (!CheckTokenMembership(hDupToken, psidEntAdmins, &bIsEntAdmin)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "CheckTokenMembership");
}
// get the root Domain Admin SID
hr=GetRootDomAdminSid(&psidRootDomAdmins);
_JumpIfError(hr, error, "GetRootDomAdminSid");
// check for membership
if (!CheckTokenMembership(hDupToken, psidRootDomAdmins, &bIsRootDomAdmin)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "CheckTokenMembership");
}
// either one will do
bIsMember=(bIsEntAdmin || bIsRootDomAdmin);
} else {
// see if the user is a member of the BUILTIN\Administrators group
// get the well-known SID
if (!AllocateAndInitializeSid(&siaNtAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, (void **)&psidLocalAdmins))
{
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "AllocateAndInitializeSid");
}
// check for membership
if (!CheckTokenMembership(hDupToken, psidLocalAdmins, &bIsMember)) {
hr=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "CheckTokenMembership");
}
}
error:
if (NULL!=hAccessToken) {
CloseHandle(hAccessToken);
}
if (NULL!=hDupToken) {
CloseHandle(hDupToken);
}
if (NULL!=psidLocalAdmins) {
FreeSid(psidLocalAdmins);
}
if (NULL!=psidEntAdmins) {
LocalFree(psidEntAdmins);
}
if (NULL!=psidRootDomAdmins) {
LocalFree(psidRootDomAdmins);
}
return bIsMember;
}
//--------------------------------------------------------------------
HRESULT DoCertSrvEnterpriseChanges(SID * psidAccount)
{
HRESULT hr;
DWORD dwFlags;
BOOL bSDChanged1;
BOOL bSDChanged2;
BOOL bSDChanged3;
BOOL bSDChanged4;
// must be cleaned up
HCERTTYPE hEAOTemplate=NULL;
HCERTTYPE hCETemplate=NULL;
HCERTTYPE hIIOTemplate=NULL;
PSECURITY_DESCRIPTOR pSD=NULL;
WCHAR * wszCAName=NULL;
HCAINFO hCA=NULL;
SID * psidEntAdmins=NULL;
SID * psidRootDomAdmins=NULL;
SID * psidThisComputer=NULL;
//
// first, make sure the CA will issue the cert templates we want
//
// get the sanitized CA name
hr=GetCADsName(&wszCAName);
_JumpIfError(hr, error, "GetCADsName");
// get the CA (in the DS)
hr=CAFindByName(wszCAName, NULL, 0, &hCA);
_JumpIfErrorStr(hr, error, "CAFindCaByName", wszCAName);
// check the flags to confirm it supports templates
hr=CAGetCAFlags(hCA, &dwFlags);
_JumpIfError(hr, error, "CAGetCAFlags");
_Verify(0==(dwFlags&CA_FLAG_NO_TEMPLATE_SUPPORT), hr, error);
// get the enrollment agent offline template
hr=CAFindCertTypeByName(wszCERTTYPE_ENROLLMENT_AGENT_OFFLINE, NULL, CT_ENUM_USER_TYPES, &hEAOTemplate);
_JumpIfErrorStr(hr, error, "CAFindCertTypeByName", wszCERTTYPE_ENROLLMENT_AGENT_OFFLINE);
// make sure that the CA will issue this template
hr=CAAddCACertificateType(hCA, hEAOTemplate);
_JumpIfErrorStr(hr, error, "CAAddCACertificateType", wszCERTTYPE_ENROLLMENT_AGENT_OFFLINE);
// get the CEP encryption template
hr=CAFindCertTypeByName(wszCERTTYPE_CEP_ENCRYPTION, NULL, CT_ENUM_MACHINE_TYPES, &hCETemplate);
_JumpIfErrorStr(hr, error, "CAFindCertTypeByName", wszCERTTYPE_CEP_ENCRYPTION);
// make sure that the CA will issue this template
hr=CAAddCACertificateType(hCA, hCETemplate);
_JumpIfErrorStr(hr, error, "CAAddCACertificateType", wszCERTTYPE_CEP_ENCRYPTION);
// get the IPSEC Intermediate offline template
hr=CAFindCertTypeByName(wszCERTTYPE_IPSEC_INTERMEDIATE_OFFLINE, NULL, CT_ENUM_MACHINE_TYPES, &hIIOTemplate);
_JumpIfErrorStr(hr, error, "CAFindCertTypeByName", wszCERTTYPE_IPSEC_INTERMEDIATE_OFFLINE);
// make sure that the CA will issue this template
hr=CAAddCACertificateType(hCA, hIIOTemplate);
_JumpIfErrorStr(hr, error, "CAAddCACertificateType", wszCERTTYPE_IPSEC_INTERMEDIATE_OFFLINE);
// make sure that all gets written.
hr=CAUpdateCA(hCA);
_JumpIfError(hr, error, "CAUpdateCA");
//
// now, check the ACLs
//
// get the Enterpise Admin SID
hr=GetEntAdminSid(&psidEntAdmins);
_JumpIfError(hr, error, "GetEntAdminSid");
// get the root Domain Admin SID
hr=GetRootDomAdminSid(&psidRootDomAdmins);
_JumpIfError(hr, error, "GetRootDomAdminSid");
// get this computer's SID
hr=GetThisComputerSid(&psidThisComputer);
_JumpIfError(hr, error, "GetThisComputerSid");
// enrollment agent offline template needs Enterprise Admins and root Domain Admins
hr=CACertTypeGetSecurity(hEAOTemplate, &pSD);
_JumpIfError(hr, error, "CACertTypeGetSecurity");
hr=ConfirmAccess(&pSD, psidEntAdmins, &bSDChanged1);
_JumpIfError(hr, error, "ConfirmAccess");
hr=ConfirmAccess(&pSD, psidRootDomAdmins, &bSDChanged2);
_JumpIfError(hr, error, "ConfirmAccess");
if (bSDChanged1 || bSDChanged2) {
hr=CACertTypeSetSecurity(hEAOTemplate, pSD);
_JumpIfError(hr, error, "CACertTypeSetSecurity");
hr=CAUpdateCertType(hEAOTemplate);
_JumpIfError(hr, error, "CAUpdateCertType");
}
LocalFree(pSD);
pSD=NULL;
// CEP encryption template needs Enterprise Admins and root Domain Admins
hr=CACertTypeGetSecurity(hCETemplate, &pSD);
_JumpIfError(hr, error, "CACertTypeGetSecurity");
hr=ConfirmAccess(&pSD, psidEntAdmins, &bSDChanged1);
_JumpIfError(hr, error, "ConfirmAccess");
hr=ConfirmAccess(&pSD, psidRootDomAdmins, &bSDChanged2);
_JumpIfError(hr, error, "ConfirmAccess");
if (bSDChanged1 || bSDChanged2) {
hr=CACertTypeSetSecurity(hCETemplate, pSD);
_JumpIfError(hr, error, "CACertTypeSetSecurity");
hr=CAUpdateCertType(hCETemplate);
_JumpIfError(hr, error, "CAUpdateCertType");
}
LocalFree(pSD);
pSD=NULL;
// IPSEC Intermediate offline template needs Enterprise Admins and root Domain Admins and the current machine
hr=CACertTypeGetSecurity(hIIOTemplate, &pSD);
_JumpIfError(hr, error, "CACertTypeGetSecurity");
hr=ConfirmAccess(&pSD, psidEntAdmins, &bSDChanged1);
_JumpIfError(hr, error, "ConfirmAccess");
hr=ConfirmAccess(&pSD, psidRootDomAdmins, &bSDChanged2);
_JumpIfError(hr, error, "ConfirmAccess");
hr=ConfirmAccess(&pSD, psidThisComputer, &bSDChanged3);
_JumpIfError(hr, error, "ConfirmAccess");
//if a service account if used, add the account to the template
if(psidAccount)
{
hr=ConfirmAccess(&pSD, psidAccount, &bSDChanged4);
_JumpIfError(hr, error, "ConfirmAccess");
}
else
{
bSDChanged4=FALSE;
}
if (bSDChanged1 || bSDChanged2 || bSDChanged3 || bSDChanged4) {
hr=CACertTypeSetSecurity(hIIOTemplate, pSD);
_JumpIfError(hr, error, "CACertTypeSetSecurity");
hr=CAUpdateCertType(hIIOTemplate);
_JumpIfError(hr, error, "CAUpdateCertType");
}
hr=S_OK;
error:
if (NULL!=psidThisComputer) {
LocalFree(psidThisComputer);
}
if (NULL!=psidEntAdmins) {
LocalFree(psidEntAdmins);
}
if (NULL!=psidRootDomAdmins) {
LocalFree(psidRootDomAdmins);
}
if (NULL!=pSD) {
LocalFree(pSD);
}
if (NULL!=hEAOTemplate) {
CACloseCertType(hEAOTemplate);
}
if (NULL!=hCETemplate) {
CACloseCertType(hCETemplate);
}
if (NULL!=hIIOTemplate) {
CACloseCertType(hIIOTemplate);
}
if (NULL!=wszCAName) {
LocalFree(wszCAName);
}
if (NULL!=hCA) {
CACloseCA(hCA);
}
return hr;
}