//-------------------------------------------------------------------- // 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 #include #include "ErrorHandling.h" #include "SetupUtil.h" //-------------------------------------------------------------------- // Constants static const WCHAR gc_wszRegKeyServices[]=L"System\\CurrentControlSet\\Services"; static const WCHAR gc_wszCertSrvDir[]=L"CertSrv"; // from 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 #include #include //-------------------------------------------------------------------- // 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 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; iGroupCount; 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; nIndexAceType) { 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; nIndexAceType && 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(&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) { // 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; }