//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 2001 // // File: cainfo.cpp // // Contents: // //--------------------------------------------------------------------------- #include "pch.cpp" #pragma hdrstop #include #include #include #include #include #include "certacl.h" #include "accctrl.h" #include #define __dwFILE__ __dwFILE_CERTCLIB_CAINFO_CPP__ typedef struct _CA_DEFAULT_PROVIDER { DWORD dwFlags; LPWSTR wszName; } CA_DEFAULT_PROVIDER; CA_DEFAULT_PROVIDER g_DefaultProviders[] = { {0, MS_DEF_PROV_W}, {0, MS_ENHANCED_PROV_W}, {0, MS_DEF_RSA_SIG_PROV_W}, {0, MS_DEF_RSA_SCHANNEL_PROV_W}, {0, MS_DEF_DSS_PROV_W}, {0, MS_DEF_DSS_DH_PROV_W}, {0, MS_ENH_DSS_DH_PROV_W}, {0, MS_DEF_DH_SCHANNEL_PROV_W}, {0, MS_SCARD_PROV_W} }; DWORD g_cDefaultProviders = sizeof(g_DefaultProviders)/sizeof(g_DefaultProviders[0]); LPCWSTR CAGetDN( IN HCAINFO hCAInfo ) { CSASSERT(hCAInfo); return ((CCAInfo*)hCAInfo)->GetDN(); } HRESULT CAFindByName( IN LPCWSTR wszCAName, IN LPCWSTR wszScope, IN DWORD fFlags, OUT HCAINFO * phCAInfo ) { HRESULT hr = S_OK; WCHAR *wszQueryBase = L"(cn="; WCHAR *wszQuery = NULL; DWORD cQuery; if((wszCAName == NULL) || (phCAInfo == NULL)) { return E_POINTER; } // Generate Query cQuery = wcslen(wszQueryBase) + wcslen(wszCAName) + 2; // 2 for ending paren and null wszQuery = (WCHAR *)LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*cQuery); if(wszQuery == NULL) { hr = E_OUTOFMEMORY; goto error; } wcscpy(wszQuery, wszQueryBase); wcscat(wszQuery, wszCAName); wcscat(wszQuery, L")"); if(fFlags & CA_FLAG_SCOPE_DNS) { hr = CCAInfo::FindDnsDomain(wszQuery, wszScope, fFlags, (CCAInfo **)phCAInfo); } else { hr = CCAInfo::Find(wszQuery, wszScope, fFlags, (CCAInfo **)phCAInfo); } if((hr == S_OK) && (*phCAInfo == NULL)) { hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); } error: if(wszQuery) { LocalFree(wszQuery); } return hr; } HRESULT CAFindByCertType( IN LPCWSTR wszCertType, IN LPCWSTR wszScope, IN DWORD fFlags, OUT HCAINFO * phCAInfo ) { HRESULT hr = S_OK; WCHAR *wszQueryBase = L"(" CA_PROP_CERT_TYPES L"="; WCHAR *wszQuery = NULL; DWORD cQuery; if((wszCertType == NULL) || (phCAInfo == NULL)) { return E_POINTER; } // Generate Query cQuery = wcslen(wszQueryBase) + wcslen(wszCertType) + 2; // 2 for ending paren and null wszQuery = (WCHAR *)LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*cQuery); if(wszQuery == NULL) { hr = E_OUTOFMEMORY; goto error; } wcscpy(wszQuery, wszQueryBase); wcscat(wszQuery, wszCertType); wcscat(wszQuery, L")"); if(fFlags & CA_FLAG_SCOPE_DNS) { hr = CCAInfo::FindDnsDomain(wszQuery, wszScope, fFlags, (CCAInfo **)phCAInfo); } else { hr = CCAInfo::Find(wszQuery, wszScope, fFlags, (CCAInfo **)phCAInfo); } if(*phCAInfo == NULL) { hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); } error: if(wszQuery) { LocalFree(wszQuery); } return hr; } HRESULT CAFindByIssuerDN( IN CERT_NAME_BLOB const * pIssuerDN, IN LPCWSTR wszScope, IN DWORD fFlags, OUT HCAINFO * phCAInfo ) { HRESULT hr = S_OK; WCHAR *wszQueryBase = wszLPAREN L"cACertificateDN="; WCHAR *wszQuery = NULL; WCHAR *wszNameStr = NULL; DWORD cQuery; if((pIssuerDN == NULL) || (phCAInfo == NULL)) { return E_POINTER; } // Generate Query // Convert the CAPI2 name to a string hr = myCertNameToStr( X509_ASN_ENCODING, pIssuerDN, CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_NO_QUOTING_FLAG, &wszNameStr); _JumpIfError(hr, error, "myCertNameToStr"); // Now quote that string with double quotes // two for ending paren and null, two for the double quotes cQuery = wcslen(wszQueryBase) + wcslen(wszNameStr) + 4; wszQuery = (WCHAR *)LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*cQuery); if(wszQuery == NULL) { hr = E_OUTOFMEMORY; goto error; } wcscpy(wszQuery, wszQueryBase); //wcscat(wszQuery, L"\""); wcscat(wszQuery, wszNameStr); //wcscat(wszQuery, L"\"" wszRPAREN); wcscat(wszQuery, wszRPAREN); CSASSERT(cQuery - 1 == wcslen(wszQuery)); if(fFlags & CA_FLAG_SCOPE_DNS) { hr = CCAInfo::FindDnsDomain(wszQuery, wszScope, fFlags, (CCAInfo **)phCAInfo); } else { hr = CCAInfo::Find(wszQuery, wszScope, fFlags, (CCAInfo **)phCAInfo); } error: if(wszNameStr) { LocalFree(wszNameStr); } if(wszQuery) { LocalFree(wszQuery); } return hr; } HRESULT CAEnumFirstCA( IN LPCWSTR wszScope, IN DWORD fFlags, OUT HCAINFO * phCAInfo ) { HRESULT hr = S_OK; if(fFlags & CA_FLAG_SCOPE_DNS) { hr = CCAInfo::FindDnsDomain(NULL, wszScope, fFlags, (CCAInfo **)phCAInfo); } else { hr = CCAInfo::Find(NULL, wszScope, fFlags, (CCAInfo **)phCAInfo); } if (S_OK != hr) { if (HRESULT_FROM_WIN32(ERROR_NETWORK_UNREACHABLE) != hr && HRESULT_FROM_WIN32(ERROR_WRONG_PASSWORD) != hr) { _PrintError3( hr, "FindDnsDomain/Find", HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED), HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN)); } goto error; } error: return(hr); } HRESULT CAEnumNextCA( IN HCAINFO hPrevCA, OUT HCAINFO * phCAInfo ) { CCAInfo *pInfo; if(hPrevCA == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hPrevCA; return pInfo->Next((CCAInfo **)phCAInfo); } HRESULT CACreateNewCA( IN LPCWSTR wszCAName, IN LPCWSTR wszScope, IN DWORD fFlags, OUT HCAINFO * phCAInfo ) { HRESULT hr = S_OK; if((wszCAName == NULL) || (phCAInfo == NULL)) { return E_POINTER; } // Generate Query if(CA_FLAG_SCOPE_DNS & fFlags) { hr = CCAInfo::CreateDnsDomain(wszCAName, wszScope, (CCAInfo **)phCAInfo); } else { hr = CCAInfo::Create(wszCAName, wszScope, (CCAInfo **)phCAInfo); } return hr; } HRESULT CAUpdateCA( IN HCAINFO hCAInfo ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->Update(); } HRESULT CADeleteCA( IN HCAINFO hCAInfo ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->Delete(); } DWORD CACountCAs(IN HCAINFO hCAInfo) { CCAInfo *pInfo; if(hCAInfo == NULL) { return 0; } pInfo = (CCAInfo *)hCAInfo; return pInfo->Count(); } HRESULT CACloseCA(IN HCAINFO hCAInfo) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->Release(); } HRESULT CAGetCAProperty( IN HCAINFO hCAInfo, IN LPCWSTR wszPropertyName, OUT LPWSTR ** pawszPropertyValue) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->GetProperty(wszPropertyName, pawszPropertyValue); } HRESULT CAFreeCAProperty( IN HCAINFO hCAInfo, IN LPWSTR * awszPropertyValue ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->FreeProperty(awszPropertyValue); } HRESULT CASetCAProperty( IN HCAINFO hCAInfo, IN LPCWSTR wszPropertyName, IN LPWSTR * awszPropertyValue) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->SetProperty(wszPropertyName, awszPropertyValue); } HRESULT CAGetCAFlags( IN HCAINFO hCAInfo, OUT DWORD * pdwFlags ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } if(pdwFlags == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; *pdwFlags = pInfo->GetFlags(); return S_OK; } HRESULT CASetCAFlags( IN HCAINFO hCAInfo, IN DWORD dwFlags ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; pInfo->SetFlags(dwFlags); return S_OK; } HRESULT CAGetCACertificate( IN HCAINFO hCAInfo, OUT PCCERT_CONTEXT *ppCert) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->GetCertificate(ppCert); } HRESULT CASetCACertificate( IN HCAINFO hCAInfo, IN PCCERT_CONTEXT pCert) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->SetCertificate(pCert); } HRESULT CAGetCAExpiration( HCAINFO hCAInfo, DWORD * pdwExpiration, DWORD * pdwUnits ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->GetExpiration(pdwExpiration, pdwUnits); } HRESULT CASetCAExpiration( HCAINFO hCAInfo, DWORD dwExpiration, DWORD dwUnits ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->SetExpiration(dwExpiration, dwUnits); } HRESULT CASetCASecurity( IN HCAINFO hCAInfo, IN PSECURITY_DESCRIPTOR pSD ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->SetSecurity( pSD ); } HRESULT CAGetCASecurity( IN HCAINFO hCAInfo, OUT PSECURITY_DESCRIPTOR * ppSD ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->GetSecurity( ppSD ) ; } CERTCLIAPI HRESULT WINAPI CAAccessCheck( IN HCAINFO hCAInfo, IN HANDLE ClientToken ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->AccessCheck(ClientToken,CERTTYPE_ACCESS_CHECK_ENROLL); } CERTCLIAPI HRESULT WINAPI CAAccessCheckEx( IN HCAINFO hCAInfo, IN HANDLE ClientToken, IN DWORD dwOption ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->AccessCheck(ClientToken,dwOption); } HRESULT CAEnumCertTypesForCAEx( IN HCAINFO hCAInfo, IN LPCWSTR wszScope, IN DWORD dwFlags, OUT HCERTTYPE * phCertType ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; if(dwFlags & CA_FLAG_ENUM_ALL_TYPES) { return CCertTypeInfo::Enum(wszScope, dwFlags, (CCertTypeInfo **)phCertType); } return pInfo->EnumSupportedCertTypesEx(wszScope, dwFlags, (CCertTypeInfo **)phCertType); } HRESULT CAEnumCertTypesForCA( IN HCAINFO hCAInfo, IN DWORD dwFlags, OUT HCERTTYPE * phCertType ) { return CAEnumCertTypesForCAEx(hCAInfo, NULL, dwFlags, phCertType); } HRESULT CAAddCACertificateType( HCAINFO hCAInfo, HCERTTYPE hCertType ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->AddCertType((CCertTypeInfo *)hCertType); } HRESULT CARemoveCACertificateType( HCAINFO hCAInfo, HCERTTYPE hCertType ) { CCAInfo *pInfo; if(hCAInfo == NULL) { return E_POINTER; } pInfo = (CCAInfo *)hCAInfo; return pInfo->RemoveCertType((CCertTypeInfo *)hCertType); } // // Certificate Type API's // HRESULT CAEnumCertTypes( IN DWORD dwFlags, OUT HCERTTYPE * phCertType ) { HRESULT hr; hr = CCertTypeInfo::Enum(NULL, dwFlags, (CCertTypeInfo **)phCertType); return hr; } HRESULT CAEnumCertTypesEx( IN LPCWSTR wszScope, IN DWORD dwFlags, OUT HCERTTYPE * phCertType ) { HRESULT hr; hr = CCertTypeInfo::Enum(wszScope, dwFlags, (CCertTypeInfo **)phCertType); return hr; } HRESULT CAFindCertTypeByName( IN LPCWSTR wszCertType, IN HCAINFO hCAInfo, IN DWORD dwFlags, OUT HCERTTYPE * phCertType ) { HRESULT hr = S_OK; LPCWSTR awszTypes[2]; if((wszCertType == NULL) || (phCertType == NULL)) { return E_POINTER; } awszTypes[0] = wszCertType; awszTypes[1] = NULL; hr = CCertTypeInfo::FindByNames(awszTypes, ((CT_FLAG_SCOPE_IS_LDAP_HANDLE & dwFlags)?(LPWSTR)hCAInfo:NULL), dwFlags, (CCertTypeInfo **)phCertType); if((hr == S_OK) && (*phCertType == NULL)) { hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); } return hr; } HRESULT CACreateCertType( IN LPCWSTR wszCertType, IN LPCWSTR wszScope, IN DWORD, // fFlags OUT HCERTTYPE * phCertType ) { HRESULT hr = S_OK; if((wszCertType == NULL) || (phCertType == NULL)) { return E_POINTER; } hr = CCertTypeInfo::Create(wszCertType, wszScope, (CCertTypeInfo **)phCertType); return hr; } HRESULT CAUpdateCertType( IN HCERTTYPE hCertType ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->Update(); } HRESULT CADeleteCertType( IN HCERTTYPE hCertType ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->Delete(); } //-------------------------------------------------------------------- // // CertTypeRetrieveClientToken // //-------------------------------------------------------------------- BOOL CertTypeRetrieveClientToken(HANDLE *phToken) { HRESULT hr = S_OK; HANDLE hHandle = NULL; HANDLE hClientToken = NULL; hHandle = GetCurrentThread(); if (NULL == hHandle) { hr = myHLastError(); } else { if (!OpenThreadToken(hHandle, TOKEN_QUERY, TRUE, // open as self &hClientToken)) { hr = myHLastError(); CloseHandle(hHandle); hHandle = NULL; } } if(hr != S_OK) { hHandle = GetCurrentProcess(); if (NULL == hHandle) { hr = myHLastError(); } else { HANDLE hProcessToken = NULL; hr = S_OK; if (!OpenProcessToken(hHandle, TOKEN_DUPLICATE, &hProcessToken)) { hr = myHLastError(); CloseHandle(hHandle); hHandle = NULL; } else { if(!DuplicateToken(hProcessToken, SecurityImpersonation, &hClientToken)) { hr = myHLastError(); CloseHandle(hHandle); hHandle = NULL; } CloseHandle(hProcessToken); } } } if(S_OK == hr) *phToken = hClientToken; if(hHandle) CloseHandle(hHandle); return (S_OK == hr); } HRESULT CACloneCertType( IN HCERTTYPE hCertType, IN LPCWSTR wszCertType, IN LPCWSTR wszFriendlyName, IN LPVOID pvldap, IN DWORD dwFlags, OUT HCERTTYPE * phCertType ) { HRESULT hr=E_INVALIDARG; DWORD dwFindCT=CT_FLAG_NO_CACHE_LOOKUP | CT_ENUM_MACHINE_TYPES | CT_ENUM_USER_TYPES; LPWSTR awszProp[2]; DWORD dwEnrollmentFlag=0; DWORD dwSubjectNameFlag=0; DWORD dwGeneralFlag=0; DWORD dwSubjectRequirement=CT_FLAG_SUBJECT_REQUIRE_DIRECTORY_PATH | CT_FLAG_SUBJECT_REQUIRE_COMMON_NAME | CT_FLAG_SUBJECT_REQUIRE_EMAIL | CT_FLAG_SUBJECT_REQUIRE_DNS_AS_CN; DWORD dwTokenUserSize=0; DWORD dwAbsSDSize=0; DWORD dwDaclSize=0; DWORD dwSaclSize=0; DWORD dwOwnerSize=0; DWORD dwPriGrpSize=0; DWORD dwRelSDSize=0; ACL_SIZE_INFORMATION aclsizeinfo; DWORD dwNewAclSize=0; ACE_HEADER *pFirstAce=NULL; PACL pAcl=NULL; BOOL bAclPresent=FALSE; BOOL bDefaultAcl=FALSE; DWORD nIndex=0; BOOL fAddAce=TRUE; DWORD dwCount=0; HANDLE hToken=NULL; TOKEN_USER *pTokenUser=NULL; PSECURITY_DESCRIPTOR pSID=NULL; PSECURITY_DESCRIPTOR pAbsSD=NULL; ACL * pAbsDacl=NULL; ACL * pAbsSacl=NULL; SID * pAbsOwner=NULL; SID * pAbsPriGrp=NULL; PSECURITY_DESCRIPTOR pNewSD=NULL; LPWSTR * awszCN=NULL; HCERTTYPE hNewCertType=NULL; ACL *pNewDacl=NULL; DWORD *pdwIndex=NULL; if((NULL==hCertType) || (NULL==wszCertType) || (NULL==phCertType)) goto error; *phCertType=NULL; if(pvldap) dwFindCT |= CT_FLAG_SCOPE_IS_LDAP_HANDLE; //make sure the new name does not exit if(S_OK == CAFindCertTypeByName( wszCertType, (HCAINFO)pvldap, dwFindCT, &hNewCertType)) { hr=CRYPT_E_EXISTS; goto error; } //get a new cert type handle if(S_OK != (hr = CAGetCertTypePropertyEx(hCertType, CERTTYPE_PROP_CN, &awszCN))) goto error; if((NULL==awszCN) || (NULL==awszCN[0])) { hr=HRESULT_FROM_WIN32(ERROR_NOT_FOUND); goto error; } if(S_OK != (hr = CAFindCertTypeByName( (LPCWSTR)awszCN[0], (HCAINFO)pvldap, dwFindCT, &hNewCertType))) goto error; if(NULL==hNewCertType) { hr=HRESULT_FROM_WIN32(ERROR_NOT_FOUND); goto error; } //clone by setting the CN awszProp[0]=(LPWSTR)wszCertType; awszProp[1]=NULL; if(S_OK != (hr=CASetCertTypePropertyEx( hNewCertType, CERTTYPE_PROP_CN, awszProp))) goto error; //set the friendly name if(wszFriendlyName) { awszProp[0]=(LPWSTR)wszFriendlyName; awszProp[1]=NULL; if(S_OK != (hr=CASetCertTypePropertyEx( hNewCertType, CERTTYPE_PROP_FRIENDLY_NAME, awszProp))) goto error; } //turn off autoenrollment bit if(0 == (CT_CLONE_KEEP_AUTOENROLLMENT_SETTING & dwFlags)) { if(S_OK != (hr=CAGetCertTypeFlagsEx( hNewCertType, CERTTYPE_ENROLLMENT_FLAG, &dwEnrollmentFlag))) goto error; dwEnrollmentFlag &= (~CT_FLAG_AUTO_ENROLLMENT); if(S_OK != (hr=CASetCertTypeFlagsEx( hNewCertType, CERTTYPE_ENROLLMENT_FLAG, dwEnrollmentFlag))) goto error; } //turn off the subject name requirement for machien template if(0 == (CT_CLONE_KEEP_SUBJECT_NAME_SETTING & dwFlags)) { if(S_OK != (hr=CAGetCertTypeFlagsEx( hNewCertType, CERTTYPE_GENERAL_FLAG, &dwGeneralFlag))) goto error; if(CT_FLAG_MACHINE_TYPE & dwGeneralFlag) { if(S_OK != (hr=CAGetCertTypeFlagsEx( hNewCertType, CERTTYPE_SUBJECT_NAME_FLAG, &dwSubjectNameFlag))) goto error; dwSubjectNameFlag &= (~dwSubjectRequirement); if(S_OK != (hr=CASetCertTypeFlagsEx( hNewCertType, CERTTYPE_SUBJECT_NAME_FLAG, dwSubjectNameFlag))) goto error; } } //get the client token if(!CertTypeRetrieveClientToken(&hToken)) { hr = myHLastError(); goto error; } //get the client sid dwTokenUserSize=0; if(!GetTokenInformation( hToken, // handle to access token TokenUser, // token type NULL, // buffer 0, // size of buffer &dwTokenUserSize)) // required buffer size { if (ERROR_INSUFFICIENT_BUFFER!=GetLastError()) { hr = myHLastError(); goto error; } } if(NULL==(pTokenUser=(TOKEN_USER *)LocalAlloc(LPTR, dwTokenUserSize))) { hr=E_OUTOFMEMORY; goto error; } if(!GetTokenInformation( hToken, // handle to access token TokenUser, // token type pTokenUser, // buffer dwTokenUserSize, // size of buffer &dwTokenUserSize)) // required buffer size { hr = myHLastError(); goto error; } //update the ACLs of the template to have the caller as the owner //of the ACL if(S_OK != (hr=CACertTypeGetSecurity( hNewCertType, &pSID))) goto error; //we will delete all ACCESS_DENIED ACEs for the caller // get the (D)ACL from the security descriptor if (!GetSecurityDescriptorDacl(pSID, &bAclPresent, &pAcl, &bDefaultAcl)) { hr = myHLastError(); _JumpError(hr, error, "GetSecurityDescriptorDacl"); } if(FALSE == bAclPresent) { hr=HRESULT_FROM_WIN32(ERROR_INVALID_SECURITY_DESCR); _JumpError(hr, error, "IsValidSecurityDescriptor"); } // NULL acl -> allow all access if (NULL != pAcl) { // find out how many ACEs memset(&aclsizeinfo, 0, sizeof(aclsizeinfo)); if (!GetAclInformation(pAcl, &aclsizeinfo, sizeof(aclsizeinfo), AclSizeInformation)) { hr = myHLastError(); _JumpError(hr, error, "GetAclInformation"); } pdwIndex=(DWORD *)LocalAlloc(LPTR, sizeof(DWORD) * (aclsizeinfo.AceCount)); if(NULL==pdwIndex) { hr=E_OUTOFMEMORY; goto error; } memset(pdwIndex, 0, sizeof(DWORD) * (aclsizeinfo.AceCount)); dwCount=0; for (nIndex=0; nIndex < aclsizeinfo.AceCount; nIndex++) { ACE_HEADER * pAceHeader=NULL; ACCESS_ALLOWED_ACE * pAccessAce=NULL; PSID pSid=NULL; if (!GetAce(pAcl, nIndex, (void**)&pAceHeader)) { hr = myHLastError(); _JumpError(hr, error, "GetAce"); } // find the sid for this ACE if ((ACCESS_ALLOWED_ACE_TYPE != pAceHeader->AceType) && (ACCESS_DENIED_ACE_TYPE != pAceHeader->AceType)) { // we are only interested in ace types continue; } // note that ACCESS_ALLOWED_ACE and ACCESS_DENIED_ACE are the same structurally. pAccessAce=(ACCESS_ALLOWED_ACE *)pAceHeader; pSid=((BYTE *)&(pAccessAce->SidStart)); // make sure this is the sid we are looking for if (!EqualSid(pSid, (pTokenUser->User).Sid)) { continue; } if(ACCESS_ALLOWED_ACE_TYPE == pAceHeader->AceType) { //change it to allowed for everything fAddAce=FALSE; pAceHeader->AceType=ACCESS_ALLOWED_ACE_TYPE; pAccessAce->Mask=(pAccessAce->Mask) | (ACTRL_CERTSRV_MANAGE_LESS_CONTROL_ACCESS); } else { //delete the denied ace if(ACCESS_DENIED_ACE_TYPE == pAceHeader->AceType) { pdwIndex[dwCount]=nIndex; dwCount++; } } } if(!MakeAbsoluteSD(pSID, NULL, &dwAbsSDSize, NULL, &dwDaclSize, NULL, &dwSaclSize, NULL, &dwOwnerSize, NULL, &dwPriGrpSize)) { if (ERROR_INSUFFICIENT_BUFFER!=GetLastError()) { hr = myHLastError(); goto error; } } // allocate memory if(NULL==(pAbsSD=(PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwAbsSDSize))) { hr=E_OUTOFMEMORY; goto error; } if(NULL==(pAbsDacl=(ACL * )LocalAlloc(LPTR, dwDaclSize))) { hr=E_OUTOFMEMORY; goto error; } if(NULL==(pAbsSacl=(ACL * )LocalAlloc(LPTR, dwSaclSize))) { hr=E_OUTOFMEMORY; goto error; } if(NULL==(pAbsOwner=(SID *)LocalAlloc(LPTR, dwOwnerSize))) { hr=E_OUTOFMEMORY; goto error; } if(NULL==(pAbsPriGrp=(SID *)LocalAlloc(LPTR, dwPriGrpSize))) { hr=E_OUTOFMEMORY; goto error; } // copy the SD to the memory buffers if(!MakeAbsoluteSD(pSID, pAbsSD, &dwAbsSDSize, pAbsDacl, &dwDaclSize, pAbsSacl, &dwSaclSize, pAbsOwner, &dwOwnerSize, pAbsPriGrp, &dwPriGrpSize)) { hr = myHLastError(); goto error; } // get the current size info for the dacl memset(&aclsizeinfo, 0, sizeof(aclsizeinfo)); if(!GetAclInformation(pAbsDacl, &aclsizeinfo, sizeof(aclsizeinfo), AclSizeInformation)) { hr = myHLastError(); _JumpError(hr, error, "GetAclInformation"); } // figure out the new size dwNewAclSize=aclsizeinfo.AclBytesInUse +sizeof(ACCESS_ALLOWED_ACE) -sizeof(DWORD) //ACCESS_ALLOWED_ACE::SidStart +GetLengthSid((pTokenUser->User).Sid); // allocate memory pNewDacl=(ACL *)LocalAlloc(LPTR, dwNewAclSize); if(NULL == pNewDacl) { hr=E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } // init the header if(!InitializeAcl(pNewDacl, dwNewAclSize, ACL_REVISION_DS)) { hr = myHLastError(); _JumpError(hr, error, "InitializeAcl"); } // find the first ace in the dacl if(!GetAce(pAbsDacl, 0, (void **)&pFirstAce)) { hr = myHLastError(); _JumpError(hr, error, "GetAce"); } // add all the old aces if(!AddAce(pNewDacl, ACL_REVISION_DS, 0, pFirstAce, aclsizeinfo.AclBytesInUse-sizeof(ACL))) { hr = myHLastError(); _JumpError(hr, error, "AddAce"); } //delete ACEs for(nIndex=0; nIndex < dwCount; nIndex++) { //the ACEs in pNewDacl is repacked after each deletion. //the pdwIndex[] has to be adjusted if(!DeleteAce(pNewDacl, (pdwIndex[nIndex]-nIndex))) { hr = myHLastError(); _JumpError(hr, error, "DeleteAce"); } } // add the new ace for caller to allow FULL control other than DS_CONTROL if(TRUE == fAddAce) { if(!AddAccessAllowedAce(pNewDacl, ACL_REVISION_DS, ACTRL_CERTSRV_MANAGE_LESS_CONTROL_ACCESS, (pTokenUser->User).Sid)) { hr = myHLastError(); _JumpError(hr, error, "AddAccessDeniedAce"); } } // stick the new dacl in the sd if(!SetSecurityDescriptorDacl(pAbsSD, TRUE, pNewDacl, FALSE)) { hr = myHLastError(); _JumpError(hr, error, "SetSecurityDescriptorDacl"); } // set the owner of the security descriptor as the caller if(!SetSecurityDescriptorOwner( pAbsSD, // SD (pTokenUser->User).Sid, // SID for owner FALSE)) // flag for default { hr = myHLastError(); goto error; } //convert the absolute SD to its relative form if(!MakeSelfRelativeSD(pAbsSD, NULL, &dwRelSDSize)) { if (ERROR_INSUFFICIENT_BUFFER!=GetLastError()) { hr = myHLastError(); goto error; } } // allocate memory if(NULL==(pNewSD=(PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwRelSDSize))) { hr=E_OUTOFMEMORY; goto error; } // copy the SD to the new memory buffer if (!MakeSelfRelativeSD(pAbsSD, pNewSD, &dwRelSDSize)) { hr = myHLastError(); goto error; } //set the relative SID if(S_OK != (hr=CACertTypeSetSecurity( hNewCertType, pNewSD))) goto error; } *phCertType=hNewCertType; hNewCertType=NULL; hr=S_OK; error: if(pdwIndex) LocalFree(pdwIndex); if (pNewDacl) LocalFree(pNewDacl); if(hToken) CloseHandle(hToken); if(pTokenUser) LocalFree(pTokenUser); if(pSID) LocalFree(pSID); 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); if (NULL!=pNewSD) LocalFree(pNewSD); if(awszCN) CAFreeCertTypeProperty(hCertType, awszCN); if(hNewCertType) CACloseCertType(hNewCertType); return hr; } HRESULT CAEnumNextCertType( IN HCERTTYPE hPrevCertType, OUT HCERTTYPE * phCertTypeInfo ) { CCertTypeInfo *pInfo; if(hPrevCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hPrevCertType; return pInfo->Next((CCertTypeInfo **)phCertTypeInfo); } DWORD CACountCertTypes(IN HCERTTYPE hCertType) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return 0; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->Count(); } HRESULT CACloseCertType(IN HCERTTYPE hCertTypeInfo) { CCertTypeInfo *pInfo; if(hCertTypeInfo == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertTypeInfo; return pInfo->Release(); } HRESULT CAGetCertTypeProperty( IN HCERTTYPE hCertType, IN LPCWSTR wszPropertyName, OUT LPWSTR ** pawszPropertyValue) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->GetProperty(wszPropertyName, pawszPropertyValue); } HRESULT CAGetCertTypePropertyEx( IN HCERTTYPE hCertType, IN LPCWSTR wszPropertyName, OUT LPVOID pPropertyValue) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->GetPropertyEx(wszPropertyName, pPropertyValue); } HRESULT CASetCertTypeProperty( IN HCERTTYPE hCertType, IN LPCWSTR wszPropertyName, IN LPWSTR * awszPropertyValue) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->SetProperty(wszPropertyName, awszPropertyValue) ; } HRESULT CASetCertTypePropertyEx( IN HCERTTYPE hCertType, IN LPCWSTR wszPropertyName, IN LPVOID pPropertyValue) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->SetPropertyEx(wszPropertyName, pPropertyValue) ; } HRESULT CAFreeCertTypeProperty( IN HCERTTYPE hCertType, LPWSTR * awszPropertyValue ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->FreeProperty(awszPropertyValue) ; } HRESULT CAGetCertTypeExtensions( IN HCERTTYPE hCertType, OUT PCERT_EXTENSIONS * ppCertExtensions ) { return CAGetCertTypeExtensionsEx(hCertType, 0, NULL, ppCertExtensions); } HRESULT CAGetCertTypeExtensionsEx( IN HCERTTYPE hCertType, IN DWORD dwFlags, IN LPVOID, // pParam OUT PCERT_EXTENSIONS * ppCertExtensions ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->GetExtensions(dwFlags, ppCertExtensions); } HRESULT CAFreeCertTypeExtensions( IN HCERTTYPE, // hCertType IN PCERT_EXTENSIONS pCertExtensions ) { //should alreays free via LocalFree since CryptUIWizCertRequest freed //it via LocalFree if(pCertExtensions) { LocalFree(pCertExtensions); } return S_OK; #if 0 CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->FreeExtensions(pCertExtensions) ; #endif } HRESULT CASetCertTypeExtension( IN HCERTTYPE hCertType, IN LPCWSTR wszExtensionName, IN DWORD dwFlags, IN LPVOID pExtension ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->SetExtension(wszExtensionName, pExtension, dwFlags); } HRESULT CAGetCertTypeFlags( IN HCERTTYPE hCertType, OUT DWORD * pdwFlags ) { return CAGetCertTypeFlagsEx(hCertType, CERTTYPE_GENERAL_FLAG, pdwFlags); } HRESULT CAGetCertTypeFlagsEx( IN HCERTTYPE hCertType, IN DWORD dwOption, OUT DWORD * pdwFlags ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } if(pdwFlags == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; *pdwFlags = pInfo->GetFlags(dwOption); return S_OK; } HRESULT CASetCertTypeFlags( IN HCERTTYPE hCertType, IN DWORD dwFlags ) { return CASetCertTypeFlagsEx(hCertType, CERTTYPE_GENERAL_FLAG, dwFlags); } HRESULT CASetCertTypeFlagsEx( IN HCERTTYPE hCertType, IN DWORD dwOption, IN DWORD dwFlags ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->SetFlags(dwOption, dwFlags); } HRESULT CAGetCertTypeKeySpec( IN HCERTTYPE hCertType, OUT DWORD * pdwKeySpec ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } if(pdwKeySpec == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; *pdwKeySpec = pInfo->GetKeySpec(); return S_OK; } HRESULT CASetCertTypeKeySpec( IN HCERTTYPE hCertType, IN DWORD dwKeySpec ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; pInfo->SetKeySpec(dwKeySpec); return S_OK; } HRESULT CAGetCertTypeExpiration( IN HCERTTYPE hCertType, OUT OPTIONAL FILETIME * pftExpiration, OUT OPTIONAL FILETIME * pftOverlap ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->GetExpiration(pftExpiration, pftOverlap); } HRESULT CASetCertTypeExpiration( IN HCERTTYPE hCertType, IN OPTIONAL FILETIME * pftExpiration, IN OPTIONAL FILETIME * pftOverlap ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->SetExpiration(pftExpiration, pftOverlap); } HRESULT CACertTypeSetSecurity( IN HCERTTYPE hCertType, IN PSECURITY_DESCRIPTOR pSD ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->SetSecurity( pSD ); } HRESULT CACertTypeGetSecurity( IN HCERTTYPE hCertType, OUT PSECURITY_DESCRIPTOR * ppSD ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->GetSecurity( ppSD ) ; } HRESULT CACertTypeAccessCheck( IN HCERTTYPE hCertType, IN HANDLE ClientToken ) { return CACertTypeAccessCheckEx(hCertType, ClientToken, CERTTYPE_ACCESS_CHECK_ENROLL); } CERTCLIAPI HRESULT WINAPI CACertTypeAccessCheckEx( IN HCERTTYPE hCertType, IN HANDLE ClientToken, IN DWORD dwOption ) { CCertTypeInfo *pInfo; if(hCertType == NULL) { return E_POINTER; } pInfo = (CCertTypeInfo *)hCertType; return pInfo->AccessCheck(ClientToken, dwOption); } CERTCLIAPI HRESULT WINAPI CAInstallDefaultCertType( IN DWORD // dwFlags ) { return CCertTypeInfo::InstallDefaultTypes(); } CERTCLIAPI BOOL WINAPI CAIsCertTypeCurrent( IN DWORD, // dwFlags IN LPWSTR wszCertType ) { BOOL fCurrent=FALSE; HRESULT hr=E_FAIL; DWORD dwCT=0; DWORD dwDefault=0; DWORD dwCount=0; BOOL fFound=FALSE; DWORD dwFound=0; DWORD dwVersion=0; CCertTypeInfo *pInfo=NULL; HCERTTYPE hNewCertType=NULL; HCERTTYPE hCurCertType=NULL; LPWSTR *awszCertTypeName=NULL; //get all the templates on the directory hr = CAEnumCertTypesEx( NULL, CT_ENUM_USER_TYPES | CT_ENUM_MACHINE_TYPES | CT_FLAG_NO_CACHE_LOOKUP, &hCurCertType); if((S_OK != hr) || (NULL==hCurCertType)) goto error; dwCount = CACountCertTypes(hCurCertType); if(0 == dwCount) goto error; //enumrating all templates on the directory for(dwCT = 0; dwCT < dwCount; dwCT++ ) { if(awszCertTypeName) { CAFreeCertTypeProperty(hCurCertType, awszCertTypeName); awszCertTypeName=NULL; } //check if we have a new certificate template if(dwCT > 0) { hr = CAEnumNextCertType(hCurCertType, &hNewCertType); if((S_OK != hr) || (NULL == hNewCertType)) { break; } CACloseCertType(hCurCertType); hCurCertType=hNewCertType; } //get the template name hr = CAGetCertTypePropertyEx( hCurCertType, CERTTYPE_PROP_DN, &awszCertTypeName); if((S_OK != hr) || (NULL == awszCertTypeName) || (NULL == awszCertTypeName[0]) ) { goto error; } //for all templates requested, verify against the default list if((NULL == wszCertType) || (0 == mylstrcmpiL(awszCertTypeName[0], wszCertType))) { if(wszCertType) fFound=TRUE; for(dwDefault=0; dwDefault < g_cDefaultCertTypes; dwDefault++) { if(0==mylstrcmpiL(awszCertTypeName[0], g_aDefaultCertTypes[dwDefault].wszName)) { break; } } //match the default name list if(dwDefault < g_cDefaultCertTypes) { hr=CAGetCertTypePropertyEx( hCurCertType, CERTTYPE_PROP_REVISION, &dwVersion); if(S_OK != hr) goto error; if (dwVersion < g_aDefaultCertTypes[dwDefault].dwRevision) goto error; pInfo = (CCertTypeInfo *)hCurCertType; if(!(pInfo->IsValidSecurityOwner())) goto error; //mark that we found a good default template dwFound++; } } } //all requested template has to be checked if(wszCertType) { if(FALSE == fFound) goto error; } else { if(dwFound != g_cDefaultCertTypes) goto error; } fCurrent=TRUE; error: if(awszCertTypeName) { if(hCurCertType) { CAFreeCertTypeProperty(hCurCertType, awszCertTypeName); } } if(hCurCertType) { CACloseCertType(hCurCertType); } return fCurrent; } HANDLE myEnterCriticalPolicySection( IN BOOL bMachine) { HANDLE hPolicy = NULL; HRESULT hr = S_OK; // ?CriticalPolicySection calls are delay loaded. Protect with try/except __try { hPolicy = EnterCriticalPolicySection(bMachine); // Delayload wrapped } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { } // (S_OK == hr) does not mean EnterCriticalPolicySection succeeded. // It just means no exception was raised. if (myIsDelayLoadHResult(hr)) { hPolicy = (HANDLE) (ULONG_PTR) (bMachine? 37 : 49); hr = S_OK; } return(hPolicy); } BOOL myLeaveCriticalPolicySection( IN HANDLE hSection) { HRESULT hr = S_OK; BOOL fOk = FALSE; // ?CriticalPolicySection calls are delay loaded. Protect with try/except __try { fOk = LeaveCriticalPolicySection(hSection); // Delayload wrapped } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { } // (S_OK == hr) does not mean LeaveCriticalPolicySection succeeded. // It just means no exception was raised. if (myIsDelayLoadHResult(hr)) { fOk = (HANDLE) (ULONG_PTR) 37 == hSection || (HANDLE) (ULONG_PTR) 49 == hSection; hr = S_OK; } return(fOk); }