//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 2000 // // File: request.cpp // // Contents: Cert Server Policy Module implementation // //--------------------------------------------------------------------------- #include "pch.cpp" #pragma hdrstop #include #include #include #include #include "cspelog.h" #include "pollog.h" #include "csprop.h" #include "csldap.h" #include "csdisp.h" #include "policy.h" #include "cainfop.h" LDAP *g_pldGC = NULL; HRESULT myLdapGCBind( IN OUT LDAP **ppldGC) { HRESULT hr; ULONG ldaperr; DWORD GetDSNameFlags; WCHAR *pwszDomainControllerName; BOOL fRediscover = FALSE; LDAP *pldGC = *ppldGC; // We want to talk to a GC, so grab the GC name. Get the GC location. GetDSNameFlags = DS_RETURN_DNS_NAME | DS_GC_SERVER_REQUIRED; if (fRediscover) { GetDSNameFlags |= DS_FORCE_REDISCOVERY; } while (TRUE) { if (NULL != *ppldGC) { break; } // Clean up from previous loop execution if (NULL != pldGC) { ldap_unbind(pldGC); pldGC = NULL; } // Grab an LDAP handle for use during this instantiation pldGC = ldap_init(NULL, LDAP_GC_PORT); if (NULL == pldGC) { hr = myHLdapLastError(NULL, NULL); if (!fRediscover) { _PrintError2(hr, "Policy:ldap_init", hr); fRediscover = TRUE; continue; } _JumpError(hr, error, "Policy:ldap_init"); } ldaperr = ldap_set_option( pldGC, LDAP_OPT_GETDSNAME_FLAGS, (VOID *) &GetDSNameFlags); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(pldGC, ldaperr, NULL); if (!fRediscover) { _PrintError2(hr, "Policy:ldap_set_option", hr); fRediscover = TRUE; continue; } _JumpError(hr, error, "Policy:ldap_set_option"); } ldaperr = ldap_set_option(pldGC, LDAP_OPT_SIGN, LDAP_OPT_ON); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(pldGC, ldaperr, NULL); if (!fRediscover) { _PrintError2(hr, "Policy:ldap_set_option", hr); fRediscover = TRUE; continue; } _JumpError(hr, error, "Policy:ldap_set_option"); } ldaperr = ldap_bind_s(pldGC, NULL, NULL, LDAP_AUTH_NEGOTIATE); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(pldGC, ldaperr, NULL); if (!fRediscover) { _PrintError2(hr, "Policy:ldap_bind_s", hr); fRediscover = TRUE; continue; } _JumpError(hr, error, "Policy:ldap_bind_s"); } hr = myLdapGetDSHostName(pldGC, &pwszDomainControllerName); if (S_OK != hr) { if (!fRediscover) { _PrintError2(hr, "Policy:myLdapGetDSHostName", hr); fRediscover = TRUE; continue; } _JumpError(hr, error, "Policy:myLdapGetDSHostName"); } DBGPRINT(( DBG_SS_CERTPOLI, "DC name = %ws\n", pwszDomainControllerName)); break; } hr = S_OK; error: *ppldGC = pldGC; return(hr); } VOID myLdapGCUnBind( IN OUT LDAP **ppldGC) { if (NULL != *ppldGC) { ldap_unbind(*ppldGC); *ppldGC = NULL; } } // begin_sdksample VOID reqCleanup() { myLdapGCUnBind(&g_pldGC); // no_sdksample } CRequestInstance::~CRequestInstance() { _Cleanup(); } VOID CRequestInstance::_Cleanup() { if (NULL != m_strTemplateName) { SysFreeString(m_strTemplateName); m_strTemplateName = NULL; } if (NULL != m_strTemplateObjId) { SysFreeString(m_strTemplateObjId); m_strTemplateObjId = NULL; } // end_sdksample //+-------------------------------------- if (NULL != m_hToken) { CloseHandle(m_hToken); m_hToken = NULL; } if (NULL != m_strUserDN) { SysFreeString(m_strUserDN); m_strUserDN = NULL; } if (NULL != m_pwszUPN) { LocalFree(m_pwszUPN); m_pwszUPN = NULL; } if (NULL != m_SearchResult) { ldap_msgfree(m_SearchResult); m_SearchResult = NULL; } //+-------------------------------------- // begin_sdksample } static WCHAR const *s_apwszCATypes[] = { wszCERTTYPE_SUBORDINATE_CA, wszCERTTYPE_CROSS_CA, }; //+-------------------------------------------------------------------------- // CRequestInstance::Initialize // // Returns S_OK on success. //+-------------------------------------------------------------------------- HRESULT CRequestInstance::Initialize( IN CCertPolicyEnterprise *pPolicy, IN BOOL fEnterpriseCA, // no_sdksample IN BOOL bNewRequest, // no_sdksample IN ICertServerPolicy *pServer) { HRESULT hr; HRESULT hrTemplate = S_OK; CERT_TEMPLATE_EXT *pTemplate = NULL; CERT_NAME_VALUE *pName = NULL; BSTR strTemplateObjId = NULL; // from V2 template extension BSTR strTemplateName = NULL; // from V1 template extension BSTR strTemplateRA = NULL; // from request attributes WCHAR const *pwszTemplateName; WCHAR const *pwszTemplateObjId; VARIANT varValue; DWORD cbType; DWORD i; BOOL fConflict; BOOL f; BOOL fTemplateMissing; BOOL fRAObjId = FALSE; VariantInit(&varValue); m_pPolicy = pPolicy; m_fCA = FALSE; m_fNewRequest = bNewRequest; // end_sdksample //+-------------------------------------- m_fUser = TRUE; m_fEnterpriseCA = fEnterpriseCA; if (m_fEnterpriseCA && bNewRequest) { hr = _InitToken(pServer); _JumpIfError(hr, error, "Policy:_InitToken"); } hr = _InitClientOSVersionInfo(pServer); _JumpIfError(hr, error, "Policy:_InitClientOSVersionInfo"); //+-------------------------------------- // begin_sdksample // Retrieve the template ObjId from the V2 cert template info extension m_dwTemplateMajorVersion = 0; m_dwTemplateMinorVersion = 0; hr = pServer->GetCertificateExtension( TEXT(szOID_CERTIFICATE_TEMPLATE), PROPTYPE_BINARY, &varValue); _PrintIfErrorStr( hr, "Policy:GetCertificateExtension", TEXT(szOID_CERTIFICATE_TEMPLATE)); if (S_OK == hr) { // There was a cert type indicator. // varValue points to an encoded string if (VT_BSTR != varValue.vt) { hr = E_INVALIDARG; _JumpError(hr, error, "Policy:varValue.vt"); } if (!myDecodeObject( X509_ASN_ENCODING, X509_CERTIFICATE_TEMPLATE, (BYTE *) varValue.bstrVal, SysStringByteLen(varValue.bstrVal), CERTLIB_USE_LOCALALLOC, (VOID **) &pTemplate, &cbType)) { hr = myHLastError(); _JumpError(hr, error, "Policy:myDecodeObject"); } if (!myConvertSzToBstr(&strTemplateObjId, pTemplate->pszObjId, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:myConvertSzToBstr"); } m_dwTemplateMajorVersion = pTemplate->dwMajorVersion; m_dwTemplateMinorVersion = pTemplate->dwMinorVersion; DBGPRINT(( DBG_SS_CERTPOL, pTemplate->fMinorVersion? "Extension Template Info: %ws V%u.%u\n" : "Extension Template Info: %ws V%u%\n", strTemplateObjId, m_dwTemplateMajorVersion, m_dwTemplateMinorVersion)); } VariantClear(&varValue); // Retrieve template Name from the V1 cert template name extension hr = pServer->GetCertificateExtension( TEXT(szOID_ENROLL_CERTTYPE_EXTENSION), PROPTYPE_BINARY, &varValue); _PrintIfErrorStr( hr, "Policy:GetCertificateExtension", TEXT(szOID_ENROLL_CERTTYPE_EXTENSION)); if (S_OK == hr) { // There was a cert type indicator. // varValue points to an encoded string if (VT_BSTR != varValue.vt) { hr = E_INVALIDARG; _JumpError(hr, error, "Policy:varValue.vt"); } if (!myDecodeObject( X509_ASN_ENCODING, X509_UNICODE_ANY_STRING, (BYTE *) varValue.bstrVal, SysStringByteLen(varValue.bstrVal), CERTLIB_USE_LOCALALLOC, (VOID **) &pName, &cbType)) { hr = myHLastError(); _JumpError(hr, error, "Policy:myDecodeObject"); } strTemplateName = SysAllocStringByteLen( (char *) pName->Value.pbData, pName->Value.cbData); if (NULL == strTemplateName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:SysAllocStringByteLen"); } DBGPRINT((DBG_SS_CERTPOL, "Extension Template: %ws\n", strTemplateName)); } fConflict = FALSE; fTemplateMissing = FALSE; // Retrieve the template from the request attributes hr = polGetRequestAttribute(pServer, wszPROPCERTTEMPLATE, &strTemplateRA); if (S_OK != hr) { _PrintErrorStr(hr, "Policy:polGetRequestAttribute", wszPROPCERTTEMPLATE); hr = S_OK; // end_sdksample if (m_fEnterpriseCA && NULL == strTemplateObjId && NULL == strTemplateName) { hrTemplate = CERTSRV_E_NO_CERT_TYPE; _PrintError(hrTemplate, "Policy:Request contains no template name"); } // begin_sdksample } else { DBGPRINT((DBG_SS_CERTPOL, "Attribute Template: %ws\n", strTemplateRA)); if (NULL != strTemplateObjId && !_TemplateNamesMatch(strTemplateObjId, strTemplateRA, &f)) { fConflict = TRUE; if (f) { fTemplateMissing = TRUE; } } if (NULL != strTemplateName && !_TemplateNamesMatch(strTemplateName, strTemplateRA, &f)) { fConflict = TRUE; if (f) { fTemplateMissing = TRUE; } } hr = myVerifyObjId(strTemplateRA); fRAObjId = S_OK == hr; } if (NULL != strTemplateObjId && NULL != strTemplateName && !_TemplateNamesMatch(strTemplateObjId, strTemplateName, &f)) { fConflict = TRUE; if (f) { fTemplateMissing = TRUE; } } if (fConflict) { hrTemplate = CERTSRV_E_TEMPLATE_CONFLICT; if (NULL != strTemplateObjId) { _PrintErrorStr( hrTemplate, "Policy:Extension Template ObjId", strTemplateObjId); } if (NULL != strTemplateName) { _PrintErrorStr( hrTemplate, "Policy:Extension Template Name", strTemplateName); } if (NULL != strTemplateRA) { _PrintErrorStr( hrTemplate, "Policy:Attribute Template", strTemplateRA); } } pwszTemplateName = strTemplateName; pwszTemplateObjId = strTemplateObjId; if (fRAObjId) { if (NULL == pwszTemplateObjId) { pwszTemplateObjId = strTemplateRA; } } else { if (NULL == pwszTemplateName) { pwszTemplateName = strTemplateRA; } } // end_sdksample if (m_fEnterpriseCA) { CTemplatePolicy *ptp; DWORD dwFlags; hr = m_pPolicy->FindTemplate( pwszTemplateName, pwszTemplateObjId, &ptp); if (S_OK != hr) { _PrintErrorStr( hr, "FindTemplate", NULL != pwszTemplateName? pwszTemplateName : pwszTemplateObjId); if (S_OK == hrTemplate || fTemplateMissing) { hrTemplate = hr; } } else { hr = ptp->GetFlags(CERTTYPE_GENERAL_FLAG, &dwFlags); _JumpIfError(hr, error, "Policy:GetFlags"); if (CT_FLAG_IS_CA & dwFlags) { m_fCA = TRUE; } hr = ptp->GetFlags(CERTTYPE_ENROLLMENT_FLAG, &dwFlags); _JumpIfError(hr, error, "Policy:GetFlags"); hr = _SetFlagsProperty( pServer, wszPROPCERTIFICATEENROLLMENTFLAGS, dwFlags); _JumpIfError(hr, error, "Policy:_SetFlagsProperty"); hr = ptp->GetFlags(CERTTYPE_GENERAL_FLAG, &dwFlags); _JumpIfError(hr, error, "Policy:GetFlags"); hr = _SetFlagsProperty( pServer, wszPROPCERTIFICATEGENERALFLAGS, dwFlags); _JumpIfError(hr, error, "Policy:_SetFlagsProperty"); if (CT_FLAG_MACHINE_TYPE & dwFlags) { m_fUser = FALSE; } pwszTemplateName = ptp->GetTemplateName(); pwszTemplateObjId = ptp->GetTemplateObjId(); } } else // begin_sdksample { if (NULL != pwszTemplateName) { for (i = 0; i < ARRAYSIZE(s_apwszCATypes); i++) { if (0 == lstrcmpi(s_apwszCATypes[i], pwszTemplateName)) { m_fCA = TRUE; break; } } } } hr = SetTemplateName(pServer, pwszTemplateName, pwszTemplateObjId); _JumpIfError(hr, error, "Policy:SetTemplateName"); error: if (S_OK != hrTemplate) { hr = hrTemplate; // override secondary errors // end_sdksample WCHAR const *apwsz[4]; DWORD cpwsz = 0; DWORD LogMsg; switch (hrTemplate) { default: case CERTSRV_E_NO_CERT_TYPE: LogMsg = MSG_MISSING_CERT_TYPE; apwsz[cpwsz++] = wszPROPCERTTEMPLATE; break; case CERTSRV_E_TEMPLATE_CONFLICT: LogMsg = MSG_CONFLICTING_CERT_TYPE; break; case CERTSRV_E_UNSUPPORTED_CERT_TYPE: LogMsg = MSG_UNSUPPORTED_CERT_TYPE; break; } if (0 == cpwsz) { if (NULL != strTemplateName) { apwsz[cpwsz++] = strTemplateName; } if (NULL != strTemplateObjId) { apwsz[cpwsz++] = strTemplateObjId; } if (NULL != strTemplateRA) { apwsz[cpwsz++] = strTemplateRA; } } apwsz[cpwsz] = NULL; LogModuleStatus( g_hInstance, LogMsg, TRUE, m_pPolicy->GetPolicyDescription(), apwsz); // begin_sdksample } VariantClear(&varValue); if (NULL != pName) { LocalFree(pName); } if (NULL != pTemplate) { LocalFree(pTemplate); } if (NULL != strTemplateObjId) { SysFreeString(strTemplateObjId); } if (NULL != strTemplateName) { SysFreeString(strTemplateName); } if (NULL != strTemplateRA) { SysFreeString(strTemplateRA); } return(hr); } BOOL CRequestInstance::_TemplateNamesMatch( IN WCHAR const *pwszTemplateName1, IN WCHAR const *pwszTemplateName2, OUT BOOL *pfTemplateMissing) { HRESULT hr1; HRESULT hr2; BOOL fMatch = TRUE; *pfTemplateMissing = FALSE; if (0 == lstrcmpi(pwszTemplateName1, pwszTemplateName2)) { goto done; // identical names } // end_sdksample if (m_fEnterpriseCA) { CTemplatePolicy *pTemplate1; CTemplatePolicy *pTemplate2; hr1 = m_pPolicy->FindTemplate(pwszTemplateName1, NULL, &pTemplate1); hr2 = m_pPolicy->FindTemplate(pwszTemplateName2, NULL, &pTemplate2); if (S_OK == hr1 && S_OK == hr2) { if (pTemplate1 == pTemplate2) { goto done; } } else { *pfTemplateMissing = TRUE; } } else // begin_sdksample { hr1 = myVerifyObjId(pwszTemplateName1); hr2 = myVerifyObjId(pwszTemplateName2); if ((S_OK == hr1) ^ (S_OK == hr2)) { goto done; } } fMatch = FALSE; done: return(fMatch); } //+-------------------------------------------------------------------------- // CRequestInstance::SetTemplateName // // Returns S_OK on success. //+-------------------------------------------------------------------------- HRESULT CRequestInstance::SetTemplateName( IN ICertServerPolicy *pServer, IN OPTIONAL WCHAR const *pwszTemplateName, IN OPTIONAL WCHAR const *pwszTemplateObjId) { HRESULT hr; BSTR strProp = NULL; BSTR strTemplateName = NULL; if (NULL != pwszTemplateName) { m_strTemplateName = SysAllocString(pwszTemplateName); if (NULL == m_strTemplateName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:SysAllocString"); } strTemplateName = m_strTemplateName; } if (NULL != pwszTemplateObjId) { m_strTemplateObjId = SysAllocString(pwszTemplateObjId); if (NULL == m_strTemplateObjId) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:SysAllocString"); } strTemplateName = m_strTemplateObjId; } if (NULL != strTemplateName) { VARIANT var; strProp = SysAllocString(wszPROPCERTIFICATETEMPLATE); if (NULL == strProp) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:SysAllocString"); } var.vt = VT_BSTR; var.bstrVal = strTemplateName; hr = pServer->SetCertificateProperty(strProp, PROPTYPE_STRING, &var); _JumpIfError(hr, error, "Policy:SetCertificateProperty"); } hr = S_OK; error: if (NULL != strProp) { SysFreeString(strProp); } return(hr); } // end_sdksample HRESULT CRequestInstance::_SetFlagsProperty( IN ICertServerPolicy *pServer, IN WCHAR const *pwszPropName, IN DWORD dwFlags) { HRESULT hr; BSTR strPropName = NULL; VARIANT var; strPropName = SysAllocString(pwszPropName); if (NULL == strPropName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:SysAllocString"); } var.vt = VT_I4; var.lVal = dwFlags; hr = pServer->SetCertificateProperty(strPropName, PROPTYPE_LONG, &var); _JumpIfError(hr, error, "Policy:SetCertificateProperty"); error: if (NULL != strPropName) { SysFreeString(strPropName); } return(hr); } VOID CRequestInstance::GetTemplateVersion( OUT DWORD *pdwTemplateMajorVersion, OUT DWORD *pdwTemplateMinorVersion) { *pdwTemplateMajorVersion = m_dwTemplateMajorVersion; *pdwTemplateMinorVersion = m_dwTemplateMinorVersion; } //+-------------------------------------------------------------------------- // CRequestInstance::_InitToken // // Returns S_OK on success. //+-------------------------------------------------------------------------- HRESULT CRequestInstance::_InitToken( IN ICertServerPolicy *pServer) { HRESULT hr; VARIANT varValue; VariantInit(&varValue); hr = pServer->GetCertificateProperty( wszPROPREQUESTERTOKEN, PROPTYPE_BINARY, &varValue); if (S_OK == hr) { HANDLE hToken; // Got a token value if (sizeof(hToken) != SysStringByteLen(varValue.bstrVal)) { hr = E_HANDLE; ::LogModuleStatus( g_hInstance, MSG_NO_REQUESTER_TOKEN, TRUE, m_pPolicy->GetPolicyDescription(), NULL); _JumpError(hr, error, "Policy:Token Length"); } hToken = *(HANDLE *) varValue.bstrVal; if (!DuplicateToken(hToken, SecurityIdentification, &m_hToken)) { hr = myHLastError(); ::LogModuleStatus( g_hInstance, MSG_NO_REQUESTER_TOKEN, TRUE, m_pPolicy->GetPolicyDescription(), NULL); _JumpError(hr, error, "Policy:DuplicateToken"); } } hr = S_OK; error: VariantClear(&varValue); return(hr); } //+-------------------------------------------------------------------------- // CRequestInstance::_InitClientOSVersionInfo // // Returns S_OK on success. //+-------------------------------------------------------------------------- HRESULT CRequestInstance::_InitClientOSVersionInfo( IN ICertServerPolicy *pServer) { HRESULT hr; VARIANT varValue; DWORD dwFormat = 0; LONG l; BSTR strVersionInfo = NULL; BSTR strCSPProvider = NULL; VariantInit(&varValue); // In the following code, we also attempt to determine if the // request came from an xenroll.dll, so we know whether to put // the UPN in the subject name. We put the UPN in the subject name // for old xenroll requests, as we know that autoenrollment on those // machines will need it to prevent enrollment loops. // Get the optional OS version information. Ignore failure. hr = polGetRequestAttribute(pServer, wszPROPREQUESTOSVERSION, &strVersionInfo); if (S_OK == hr && NULL != strVersionInfo) { DWORD dwMajor, dwMinor, dwBuild, dwPlatform; if (4 == swscanf( strVersionInfo, L"%d.%d.%d.%d", &dwMajor, &dwMinor, &dwBuild, &dwPlatform)) { m_RequestOsVersion.dwMajorVersion = dwMajor; m_RequestOsVersion.dwMinorVersion = dwMinor; m_RequestOsVersion.dwBuildNumber = dwBuild; m_RequestOsVersion.dwPlatformId = dwPlatform; } // We know this is an xenroll request, // as it has a OSVERSIONINFO property m_fIsXenrollRequest = TRUE; m_fClientVersionSpecified = TRUE; } hr = polGetRequestLongProperty(pServer, wszPROPREQUESTTYPE, &l); if (S_OK == hr) { dwFormat = CR_IN_FORMATMASK & l; } if (dwFormat == CR_IN_KEYGEN) { // KEYGEN requests only come from netscape, not xenroll, // so we know it's not an xenroll request. m_fIsXenrollRequest = FALSE; } else if (!m_fIsXenrollRequest) { hr = polGetRequestAttribute( pServer, wszPROPREQUESTCSPPROVIDER, &strCSPProvider); if (S_OK == hr && NULL != strCSPProvider) { // xenroll includes a CSPPROVIDER attribute m_fIsXenrollRequest = TRUE; } } hr = S_OK; //error: if (NULL != strVersionInfo) { SysFreeString(strVersionInfo); } if (NULL != strCSPProvider) { SysFreeString(strCSPProvider); } VariantClear(&varValue); return(hr); } //+-------------------------------------------------------------------------- // CRequestInstance::_LoadPrincipalObject // // Returns S_OK on success. //+-------------------------------------------------------------------------- HRESULT CRequestInstance::_LoadPrincipalObject( IN ICertServerPolicy *pServer, IN CTemplatePolicy *pTemplate) { HRESULT hr; BSTR strProp = NULL; LPWSTR *awszUPN = NULL; BSTR strSamName = NULL; WCHAR *pwszUserName; DWORD dwFlags; VARIANT var; VariantInit(&var); // Get the name of the user or machine hr = polGetRequestStringProperty( pServer, wszPROPREQUESTERNAME, &strSamName); _JumpIfErrorStr( hr, error, "Policy:polGetRequestStringProperty", wszPROPREQUESTERNAME); if (L'\0' == *strSamName) { // can't have a zero length name hr = E_ACCESSDENIED; _JumpError(hr, error, "Policy:zero length name"); } // See if there's a domain, as well pwszUserName = wcschr(strSamName, L'\\'); if (NULL == pwszUserName) { WCHAR wszDN[MAX_PATH]; DWORD cwc = ARRAYSIZE(wszDN); // No domain portion, so assume part of the current domain. if (GetUserNameEx(NameSamCompatible, wszDN, &cwc)) { // Fix NULL termination bug if (0 < cwc) { wszDN[cwc - 1] = L'\0'; } pwszUserName = wcschr(wszDN, L'\\'); if (NULL != pwszUserName) { pwszUserName++; wcsncpy(pwszUserName, strSamName, ARRAYSIZE(wszDN) - (cwc - 1)); SysFreeString(strSamName); strSamName = SysAllocString(wszDN); if (NULL == strSamName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:SysAllocString"); } } } } pwszUserName = wcschr(strSamName, L'\\'); if (NULL == pwszUserName) { pwszUserName = strSamName; } else { pwszUserName++; } DBGPRINT((DBG_SS_CERTPOL, "pwszUserName = %ws\n", pwszUserName)); DBGPRINT((DBG_SS_CERTPOL, "strSamName = %ws\n", strSamName)); // If the user name ends in $, it's a hint that this is a machine account. if (pwszUserName[wcslen(pwszUserName) - 1] == L'$') { if (m_fUser) { DBGPRINT(( DBG_SS_CERTPOL, "USER TEMPLATE w/ '$': %ws\n", pwszUserName)); } } else { if (!m_fUser) { DBGPRINT(( DBG_SS_CERTPOL, "MACHINE TEMPLATE w/o '$': %ws\n", pwszUserName)); } } hr = polGetCertificateStringProperty(pServer, wszPROPUSERDN, &m_strUserDN); _JumpIfErrorStr( hr, error, "Policy:polGetCertificateStringProperty", wszPROPUSERDN); hr = _GetDSObject(); _JumpIfError(hr, error, "_GetDSObject"); hr = pTemplate->GetFlags(CERTTYPE_GENERAL_FLAG, &dwFlags); _JumpIfError(hr, error, "Policy:GetFlags"); if (!m_fUser ^ (0 != (CT_FLAG_MACHINE_TYPE & dwFlags))) { // if m_fUser state no longer agrees with the template machine flag, // toggle the flag and store the corrected value in the database. dwFlags ^= CT_FLAG_MACHINE_TYPE; hr = _SetFlagsProperty( pServer, wszPROPCERTIFICATEGENERALFLAGS, dwFlags); _JumpIfError(hr, error, "Policy:_SetFlagsProperty"); } // Build the UPN value. // If a machine, the UPN must be the DNS name. hr = _GetValues(m_fUser? DS_ATTR_UPN : DS_ATTR_DNS_NAME, &awszUPN); if (S_OK == hr && NULL != awszUPN && NULL != awszUPN[0]) { hr = myDupString(awszUPN[0], &m_pwszUPN); _JumpIfError(hr, error, "myDupString"); } else { if (m_fUser) { WCHAR **awszExplodedDN; WCHAR **ppwszCurrent; // Build a UPN from the username -- without the SAM domain. // Get a buffer that will be big enough. hr = myDupString(m_strUserDN, &m_pwszUPN); _JumpIfError(hr, error, "myDupString"); wcscpy(m_pwszUPN, pwszUserName); awszExplodedDN = ldap_explode_dn(m_strUserDN, 0); if (NULL != awszExplodedDN) { wcscat(m_pwszUPN, L"@"); for (ppwszCurrent = awszExplodedDN; NULL != *ppwszCurrent; ppwszCurrent++) { WCHAR wszDC[4]; wcsncpy(wszDC, *ppwszCurrent, ARRAYSIZE(wszDC) - 1); wszDC[ARRAYSIZE(wszDC) - 1] = L'\0'; if (0 == lstrcmpi(wszDC, L"DC=")) { wcscat( m_pwszUPN, (*ppwszCurrent) + ARRAYSIZE(wszDC) - 1); wcscat(m_pwszUPN, L"."); } } // remove the trailing '.' or "@" if there was no DC= m_pwszUPN[wcslen(m_pwszUPN) - 1] = L'\0'; // We're done referencing awszExplodedDN, so free it. // ldap_value_free frees the ldap_explode_dn return value ldap_value_free(awszExplodedDN); } } else { LPCWSTR wszStrings[1]; wszStrings[0] = m_strUserDN; ::LogModuleStatus( g_hInstance, MSG_NO_DNS_NAME, TRUE, m_pPolicy->GetPolicyDescription(), wszStrings); if (hr == S_OK) { hr = CERTSRV_E_SUBJECT_DNS_REQUIRED; } _JumpErrorStr(hr, error, "No DNS Name", m_strUserDN); } } DBGPRINT((DBG_SS_CERTPOL, "m_pwszUPN = %ws\n", m_pwszUPN)); strProp = SysAllocString(wszPROPCERTIFICATEUPN); if (NULL == strProp) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:SysAllocString"); } var.bstrVal = NULL; if (!myConvertWszToBstr(&var.bstrVal, m_pwszUPN, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:myConvertWszToBstr"); } var.vt = VT_BSTR; hr = pServer->SetCertificateProperty(strProp, PROPTYPE_STRING, &var); _JumpIfError(hr, error, "Policy:SetCertificateProperty"); error: if (NULL != strSamName) { SysFreeString(strSamName); } if (NULL != awszUPN) { _FreeValues(awszUPN); } if (NULL != strProp) { SysFreeString(strProp); } VariantClear(&var); return(hr); } #define wszSEARCHUSER L"(objectCategory=user)" #define wszSEARCHCOMPUTER L"(objectCategory=computer)" #define wszSEARCHUSERCOMPUTER L"(|" wszSEARCHUSER wszSEARCHCOMPUTER L")" #define wszDSOBJECTCATEGORYATTRIBUTE L"objectCategory" WCHAR *s_apwszAttrs[] = { wszDSOBJECTCLASSATTRIBUTE, //wszDSOBJECTCATEGORYATTRIBUTE, DS_ATTR_COMMON_NAME, DS_ATTR_DNS_NAME, DS_ATTR_EMAIL_ADDR, DS_ATTR_OBJECT_GUID, DS_ATTR_UPN, NULL, }; HRESULT CRequestInstance::_GetDSObject() { HRESULT hr; ULONG ldaperr; struct l_timeval timeout; WCHAR **ppwszValues = NULL; BOOL fRediscover = FALSE; BOOL fUser; timeout.tv_sec = csecLDAPTIMEOUT; timeout.tv_usec = 0; while (TRUE) { if (NULL != m_SearchResult) { ldap_msgfree(m_SearchResult); m_SearchResult = NULL; } hr = myLdapGCBind(&g_pldGC); _JumpIfError(hr, error, "myLdapGCBind"); ldaperr = ldap_search_ext_s( g_pldGC, m_strUserDN, LDAP_SCOPE_BASE, wszSEARCHUSERCOMPUTER, s_apwszAttrs, 0, NULL, NULL, &timeout, 10000, &m_SearchResult); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(g_pldGC, ldaperr, NULL); if (!fRediscover) // only do this once { // get rid of GC we have, handle might be stale _PrintError2(hr, "Policy:ldap_search_ext_s", hr); myLdapGCUnBind(&g_pldGC); fRediscover = TRUE; continue; } _JumpError(hr, error, "Policy:ldap_search_ext_s"); } break; } if (0 == ldap_count_entries(g_pldGC, m_SearchResult)) { hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER); _JumpError(hr, error, "Policy:ldap_count_entries"); } m_PrincipalAttributes = ldap_first_entry(g_pldGC, m_SearchResult); if (NULL == m_PrincipalAttributes) { hr = myHLdapLastError(g_pldGC, NULL); _JumpError(hr, error, "Policy:ldap_first_entry"); } #if DBG_CERTSRV { DWORD i; for (i = 0; NULL != s_apwszAttrs[i]; i++) { if (0 == lstrcmpi(DS_ATTR_OBJECT_GUID, s_apwszAttrs[i])) { BSTR strGuid = NULL; hr = _GetObjectGUID(&strGuid); if (S_OK == hr) { WCHAR *pwsz; hr = myCLSIDToWsz((CLSID const *) strGuid, &pwsz); if (S_OK == hr) { DBGPRINT(( DBG_SS_CERTPOL, "%ws = %ws\n", s_apwszAttrs[i], pwsz)); LocalFree(pwsz); } SysFreeString(strGuid); } } else { hr = _GetValues(s_apwszAttrs[i], &ppwszValues); if (S_OK == hr) { DWORD j; for (j = 0; NULL != ppwszValues[j]; j++) { DBGPRINT(( DBG_SS_CERTPOL, "%ws[%u] = %ws\n", s_apwszAttrs[i], j, ppwszValues[j])); } _FreeValues(ppwszValues); ppwszValues = NULL; } } if (S_OK != hr) { DBGPRINT((DBG_SS_CERTPOL, "%ws = NULL\n", s_apwszAttrs[i])); } } } #endif hr = _GetValues(wszDSOBJECTCLASSATTRIBUTE, &ppwszValues); _JumpIfErrorStr(hr, error, "Policy:_GetValues", wszDSOBJECTCLASSATTRIBUTE); fUser = TRUE; if (NULL != ppwszValues) { DWORD i; for (i = 0; NULL != ppwszValues[i]; i++) { DBGPRINT(( DBG_SS_CERTPOLI, "Class[%u] = %ws\n", i, ppwszValues[i])); if (0 == lstrcmpi(L"computer", ppwszValues[i])) { fUser = FALSE; break; } } } if (fUser != m_fUser) { DBGPRINT(( DBG_SS_CERTPOL, fUser? "MACHINE -> USER: %ws\n" : "USER -> MACHINE: %ws\n", m_strUserDN)); m_fUser = fUser; } hr = S_OK; error: if (NULL != ppwszValues) { _FreeValues(ppwszValues); } return(hr); } HRESULT CRequestInstance::_GetValues( IN WCHAR const *pwszName, OUT WCHAR ***pppwszValues) { HRESULT hr; WCHAR **ppwszValues = NULL; ppwszValues = ldap_get_values( g_pldGC, m_PrincipalAttributes, const_cast(pwszName)); if (NULL == ppwszValues || NULL == ppwszValues[0]) { hr = CERTSRV_E_PROPERTY_EMPTY; _JumpErrorStr2(hr, error, "Policy:ldap_get_values", pwszName, hr); } *pppwszValues = ppwszValues; ppwszValues = NULL; hr = S_OK; error: if (NULL != ppwszValues) { ldap_value_free(ppwszValues); } return(hr); } HRESULT CRequestInstance::_GetObjectGUID( OUT BSTR *pstrGuid) { struct berval **pGuidVal = NULL; HRESULT hr; *pstrGuid = NULL; pGuidVal = ldap_get_values_len( g_pldGC, m_PrincipalAttributes, DS_ATTR_OBJECT_GUID); if (NULL == pGuidVal || NULL == pGuidVal[0]) { hr = CERTSRV_E_PROPERTY_EMPTY; _JumpError2(hr, error, "Policy:ldap_get_values_len", hr); } *pstrGuid = SysAllocStringByteLen(pGuidVal[0]->bv_val, pGuidVal[0]->bv_len); if (NULL == *pstrGuid) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocStringByteLen"); } hr = S_OK; error: if (NULL != pGuidVal) { ldap_value_free_len(pGuidVal); } return(hr); } HRESULT CRequestInstance::_FreeValues( IN WCHAR **ppwszValues) { if (NULL != ppwszValues) { ldap_value_free(ppwszValues); } return(S_OK); } HRESULT CRequestInstance::_GetValueString( IN WCHAR const *pwszName, OUT BSTRC *pstrValue) { HRESULT hr; WCHAR **ppwszValues = NULL; BSTR strReturn; DWORD i; DWORD cwc; *pstrValue = NULL; hr = _GetValues(pwszName, &ppwszValues); _JumpIfErrorStr(hr, error, "Policy:_GetValues", pwszName); if (NULL == ppwszValues || NULL == ppwszValues[0]) { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); _JumpErrorStr(hr, error, "Policy:ppwszValues", pwszName); } cwc = 0; for (i = 0; NULL != ppwszValues[i]; i++) { if (0 != i) { cwc++; } cwc += wcslen(ppwszValues[i]); } strReturn = SysAllocStringLen(NULL, cwc); if (NULL == strReturn) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:SysAllocStringLen"); } strReturn[0] = L'\0'; for (i = 0; NULL != ppwszValues[i]; i++) { if (0 != i) { wcscat(strReturn, L","); } wcscat(strReturn, ppwszValues[i]); } CSASSERT(SysStringByteLen(strReturn) == cwc * sizeof(WCHAR)); CSASSERT(wcslen(strReturn) == cwc); *pstrValue = strReturn; error: if (NULL != ppwszValues) { _FreeValues(ppwszValues); } return(hr); }