|
|
//--------------------------------------------------------------------
// 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; }
|