|
|
//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 2000
//
// File: request.cpp
//
// Contents: Cert Server Policy Module implementation
//
//---------------------------------------------------------------------------
#include "pch.cpp"
#pragma hdrstop
#include <ntdsapi.h>
#include <lm.h>
#include <winldap.h>
#include <security.h>
#include "cspelog.h"
#include "pollog.h"
#include "csprop.h"
#include "csldap.h"
#include "csdisp.h"
#include "policy.h"
#include "cainfop.h"
#define __dwFILE__ __dwFILE_POLICY_DEFAULT_REQUEST_CPP__
LDAP **g_rgGCCache = NULL; LONG g_cGCCacheCur; LONG g_cGCCacheMax; CRITICAL_SECTION g_GCCacheCriticalSection; BOOL g_fGCCacheCriticalSection = FALSE;
VOID myLdapUnbind( IN OUT LDAP **ppld) { if (NULL != *ppld) { ldap_unbind(*ppld); *ppld = NULL; } }
HRESULT myLdapBind( IN DWORD Flags, OPTIONAL IN WCHAR const *pwszClientDC, // require GC unless non-NULL
IN OUT LDAP **ppld) { HRESULT hr; ULONG ldaperr; DWORD GetDSNameFlags; WCHAR *pwszDomainControllerName; BOOL fGC = NULL == pwszClientDC; BOOL fRediscover = FALSE; LDAP *pld = *ppld;
GetDSNameFlags = DS_RETURN_DNS_NAME; if (fGC) { // We want to talk to a GC, so grab the GC name. Get the GC location.
GetDSNameFlags |= DS_GC_SERVER_REQUIRED; }
while (TRUE) { if (NULL != *ppld) { break; }
// Clean up from previous loop execution
if (NULL != pld) { ldap_unbind(pld); pld = NULL; }
// Grab an LDAP handle for use during this instantiation
pld = ldap_init( const_cast<WCHAR *>(pwszClientDC), fGC? LDAP_GC_PORT : LDAP_PORT); if (NULL == pld) { hr = myHLdapLastError(NULL, NULL); if (!fRediscover) { _PrintError2(hr, "Policy:ldap_init", hr); fRediscover = TRUE; continue; } _JumpError(hr, error, "Policy:ldap_init"); } if (fRediscover && NULL == pwszClientDC) { GetDSNameFlags |= DS_FORCE_REDISCOVERY; }
ldaperr = ldap_set_option( pld, LDAP_OPT_GETDSNAME_FLAGS, (VOID *) &GetDSNameFlags); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(pld, ldaperr, NULL); if (!fRediscover) { _PrintError2(hr, "Policy:ldap_set_option", hr); fRediscover = TRUE; continue; } _JumpError(hr, error, "Policy:ldap_set_option"); }
if (NULL != pwszClientDC) { DWORD SSPIFlags;
// Turn on mutual authentication -- just to make sure we can trust
// the client-supplied DC name.
ldaperr = ldap_get_option( pld, LDAP_OPT_SSPI_FLAGS, (VOID *) &SSPIFlags); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(pld, ldaperr, NULL); if (!fRediscover) { _PrintError2(hr, "Policy:ldap_get_option", hr); fRediscover = TRUE; continue; } _JumpError(hr, error, "Policy:ldap_get_option"); }
SSPIFlags |= ISC_REQ_MUTUAL_AUTH;
ldaperr = ldap_set_option( pld, LDAP_OPT_SSPI_FLAGS, (VOID *) &GetDSNameFlags); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(pld, 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(pld, LDAP_OPT_SIGN, LDAP_OPT_ON); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(pld, ldaperr, NULL); if (!fRediscover) { _PrintError2(hr, "Policy:ldap_set_option", hr); fRediscover = TRUE; continue; } _JumpError(hr, error, "Policy:ldap_set_option"); }
if (0 == (EDITF_ENABLELDAPREFERRALS & Flags) || NULL != pwszClientDC) { ldaperr = ldap_set_option(pld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(pld, ldaperr, NULL); if (!fRediscover) { _PrintError2(hr, "Policy:ldap_set_option LDAP_OPT_REFERRALS", hr); fRediscover = TRUE; continue; } _JumpError(hr, error, "Policy:ldap_set_option LDAP_OPT_REFERRALS"); } }
ldaperr = ldap_bind_s(pld, NULL, NULL, LDAP_AUTH_NEGOTIATE); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(pld, ldaperr, NULL); if (!fRediscover) { _PrintError2(hr, "Policy:ldap_bind_s", hr); fRediscover = TRUE; continue; } _JumpError(hr, error, "Policy:ldap_bind_s"); }
hr = myLdapGetDSHostName(pld, &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: if (S_OK != hr) { myLdapUnbind(&pld); } *ppld = pld; return(hr); }
HRESULT reqGetLdapGC( IN DWORD Flags, OUT LDAP **ppldGC, OUT BOOL *pfCached) { HRESULT hr; LDAP *pldGC;
*pfCached = TRUE; myLdapUnbind(ppldGC);
if (!g_fGCCacheCriticalSection || NULL == g_rgGCCache) { hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED); _JumpError(hr, error, "InitializeCriticalSection"); } pldGC = NULL;
EnterCriticalSection(&g_GCCacheCriticalSection); if (0 != g_cGCCacheCur) { pldGC = g_rgGCCache[--g_cGCCacheCur]; } LeaveCriticalSection(&g_GCCacheCriticalSection);
if (NULL == pldGC) { hr = myLdapBind(Flags, NULL, &pldGC); _JumpIfError(hr, error, "myLdapBind");
*pfCached = FALSE; } *ppldGC = pldGC; hr = S_OK;
error: return(hr); }
VOID reqReleaseLdapGC( IN OUT LDAP **ppldGC) { LDAP *pldGC = *ppldGC;
if (NULL != pldGC) { *ppldGC = NULL; EnterCriticalSection(&g_GCCacheCriticalSection); CSASSERT(0 != g_cGCCacheMax); if (g_cGCCacheCur < g_cGCCacheMax) { g_rgGCCache[g_cGCCacheCur++] = pldGC; pldGC = NULL; } LeaveCriticalSection(&g_GCCacheCriticalSection); myLdapUnbind(&pldGC); } }
WCHAR * reqCombineTemplates( OPTIONAL IN WCHAR const *pwszTemplateName, OPTIONAL IN WCHAR const *pwszTemplateObjId, OPTIONAL IN WCHAR const *pwszTemplateRA) { HRESULT hr; WCHAR const *apwszTemplate[3]; WCHAR const *apwszDisplayName[3]; DWORD i; DWORD cwc; WCHAR *pwszList = NULL;
apwszTemplate[0] = pwszTemplateName; apwszTemplate[1] = pwszTemplateObjId; apwszTemplate[2] = pwszTemplateRA; ZeroMemory(apwszDisplayName, sizeof(apwszDisplayName));
cwc = 0; for (i = 0; i < ARRAYSIZE(apwszTemplate); i++) { if (NULL != apwszTemplate[i]) { if (0 != cwc) { cwc++; } cwc += wcslen(apwszTemplate[i]); hr = myVerifyObjId(apwszTemplate[i]); if (S_OK == hr) { WCHAR const *pwszDisplay = NULL;
pwszDisplay = myGetOIDName(apwszTemplate[i]); // Static: do not free!
if (NULL != pwszDisplay && L'\0' != *pwszDisplay) { apwszDisplayName[i] = pwszDisplay; cwc += 2 + wcslen(pwszDisplay); } } } } if (0 != cwc) { pwszList = (WCHAR *) LocalAlloc(LMEM_FIXED, (1 + cwc) * sizeof(WCHAR)); if (NULL == pwszList) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:LocalAlloc"); } pwszList[0] = L'\0'; for (i = 0; i < ARRAYSIZE(apwszTemplate); i++) { if (NULL != apwszTemplate[i]) { if (L'\0' != pwszList[0]) { wcscat(pwszList, L"/"); } wcscat(pwszList, apwszTemplate[i]); if (NULL != apwszDisplayName[i]) { wcscat(pwszList, wszLPAREN); wcscat(pwszList, apwszDisplayName[i]); wcscat(pwszList, wszRPAREN); } } } CSASSERT(wcslen(pwszList) == cwc); }
error: return(pwszList); }
// begin_sdksample
HRESULT ReqInitialize( IN ICertServerPolicy *pServer) { HRESULT hr; // end_sdksample
hr = S_OK; __try { InitializeCriticalSection(&g_GCCacheCriticalSection); g_fGCCacheCriticalSection = TRUE; } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { } _JumpIfError(hr, error, "InitializeCriticalSection");
hr = polGetCertificateLongProperty( pServer, wszPROPSESSIONCOUNT, &g_cGCCacheMax); if (S_OK != hr) { g_cGCCacheMax = DBSESSIONCOUNTDEFAULT; } g_rgGCCache = (LDAP **) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, g_cGCCacheMax * sizeof(g_rgGCCache[0])); if (NULL == g_rgGCCache) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:LocalAlloc"); } g_cGCCacheCur = 0; // begin_sdksample
hr = S_OK;
error: // no_sdksample
return(hr); }
VOID ReqCleanup() { // end_sdksample
if (g_fGCCacheCriticalSection) { EnterCriticalSection(&g_GCCacheCriticalSection); if (NULL != g_rgGCCache) { while (0 != g_cGCCacheCur) { myLdapUnbind(&g_rgGCCache[--g_cGCCacheCur]); } LocalFree(g_rgGCCache); } LeaveCriticalSection(&g_GCCacheCriticalSection); DeleteCriticalSection(&g_GCCacheCriticalSection); } // begin_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
//+--------------------------------------
_ReleasePrincipalObject(); 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; } delete m_pTemplate; m_pTemplate = NULL;
if (NULL != m_pCreateErrorInfo) { m_pCreateErrorInfo->Release(); m_pCreateErrorInfo = NULL; }
//+--------------------------------------
// begin_sdksample
}
// end_sdksample
VOID CRequestInstance::SaveErrorInfo( OPTIONAL IN ICreateErrorInfo *pCreateErrorInfo) { if (NULL != pCreateErrorInfo) { if (NULL != m_pCreateErrorInfo) { m_pCreateErrorInfo->Release(); } m_pCreateErrorInfo = pCreateErrorInfo; } }
HRESULT CRequestInstance::SetErrorInfo() { HRESULT hr; if (NULL != m_pCreateErrorInfo) { hr = SetModuleErrorInfo(m_pCreateErrorInfo); _JumpIfError(hr, error, "Policy:SetErrorInfo"); } hr = S_OK;
error: return(hr); }
HRESULT CRequestInstance::BuildErrorInfo( IN HRESULT hrLog, IN DWORD dwLogId, OPTIONAL IN WCHAR const * const *ppwszInsert) { HRESULT hr;
hr = polBuildErrorInfo( hrLog, dwLogId, m_pPolicy->GetPolicyDescription(), ppwszInsert, &m_pCreateErrorInfo); _JumpIfError(hr, error, "polBuildErrorInfo");
error: return(hr); } // 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, OUT BOOL *pfEnableEnrolleeExtensions) { 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; WCHAR const *pwszV1TemplateClass; VARIANT varValue; DWORD cbType; DWORD i; BOOL fConflict; BOOL f; BOOL fTemplateMissing; BOOL fRAObjId = FALSE; CTemplatePolicy *ptp = NULL; // no_sdksample
WCHAR *pwszTemplateList = NULL; // no_sdksample
VariantInit(&varValue); *pfEnableEnrolleeExtensions = TRUE && !fEnterpriseCA // no_sdksample
;
m_pPolicy = pPolicy; m_fCA = FALSE; m_fNewRequest = bNewRequest; // no_sdksample
// 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 = polGetCertificateExtension( pServer, TEXT(szOID_CERTIFICATE_TEMPLATE), PROPTYPE_BINARY, &varValue); _PrintIfErrorStr2( hr, "Policy:polGetCertificateExtension", TEXT(szOID_CERTIFICATE_TEMPLATE), CERTSRV_E_PROPERTY_EMPTY); 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 = polGetCertificateExtension( pServer, TEXT(szOID_ENROLL_CERTTYPE_EXTENSION), PROPTYPE_BINARY, &varValue); _PrintIfErrorStr2( hr, "Policy:polGetCertificateExtension", TEXT(szOID_ENROLL_CERTTYPE_EXTENSION), CERTSRV_E_PROPERTY_EMPTY); 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 = SysAllocString((WCHAR *) pName->Value.pbData); if (NULL == strTemplateName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:SysAllocString"); } 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) { _PrintErrorStr2( hr, "Policy:polGetRequestAttribute", wszPROPCERTTEMPLATE, CERTSRV_E_PROPERTY_EMPTY); 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) { 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 | CT_FLAG_IS_CROSS_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 == mylstrcmpiL(s_apwszCATypes[i], pwszTemplateName)) { m_fCA = TRUE; break; } } } } hr = SetTemplateName(pServer, pwszTemplateName, pwszTemplateObjId); _JumpIfError(hr, error, "Policy:SetTemplateName");
pwszV1TemplateClass = pwszTemplateName;
// end_sdksample
if (NULL != ptp) { DWORD dwSubjectNameFlags;
// on resubmitted requests we don't have the requester's token
if (bNewRequest) { CSASSERT(NULL != m_hToken);
hr = ptp->AccessCheck(m_hToken); _JumpIfError(hr, error, "Policy:AccessCheck"); } hr = ptp->GetV1TemplateClass(&pwszV1TemplateClass); _JumpIfError(hr, error, "AddTemplateNameExtension");
hr = ptp->GetFlags(CERTTYPE_SUBJECT_NAME_FLAG, &dwSubjectNameFlags); _JumpIfError(hr, error, "GetFlags");
if (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT & dwSubjectNameFlags) { *pfEnableEnrolleeExtensions = TRUE; }
hr = ptp->Clone(&m_pTemplate); _JumpIfError(hr, error, "Clone"); }
// begin_sdksample
hr = pPolicy->AddV1TemplateNameExtension(pServer, pwszV1TemplateClass); _JumpIfError(hr, error, "AddTemplateNameExtension");
error: if (S_OK != hrTemplate) { hr = hrTemplate; // override secondary errors
// end_sdksample
WCHAR const *apwsz[2]; DWORD cpwsz = 0; DWORD LogMsg;
switch (hrTemplate) { default: case CERTSRV_E_NO_CERT_TYPE: LogMsg = MSG_MISSING_CERT_TYPE; apwsz[cpwsz++] = wszPROPCERTTEMPLATE; break;
// The request specifies conflicting certificate templates: %1.
case CERTSRV_E_TEMPLATE_CONFLICT: LogMsg = MSG_CONFLICTING_CERT_TYPE; break;
// The request was for a certificate template that is not
// supported by the Certificate Services policy: %1.
case CERTSRV_E_UNSUPPORTED_CERT_TYPE: LogMsg = MSG_UNSUPPORTED_CERT_TYPE; break; } if (0 == cpwsz) { WCHAR const *pwsz; pwszTemplateList = reqCombineTemplates( strTemplateName, strTemplateObjId, strTemplateRA); pwsz = pwszTemplateList; if (NULL == pwsz) { pwsz = strTemplateName; if (NULL == pwsz) { pwsz = strTemplateObjId; if (NULL == pwsz) { pwsz = strTemplateRA; if (NULL == pwsz) { pwsz = L"???"; } } } } apwsz[cpwsz++] = pwsz; } CSASSERT(ARRAYSIZE(apwsz) > cpwsz); apwsz[cpwsz] = NULL;
BuildErrorInfo(hr, LogMsg, apwsz); // begin_sdksample
} VariantClear(&varValue);
// end_sdksample
if (NULL != pwszTemplateList) { LocalFree(pwszTemplateList); } // begin_sdksample
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); }
// end_sdksample
//+--------------------------------------------------------------------------
// CRequestInstance::ApplyTemplate
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT CRequestInstance::ApplyTemplate( IN ICertServerPolicy *pServer, OUT BOOL *pfReenroll, OUT DWORD *pdwEnrollmentFlags, OUT DWORD *pcCriticalExtensions, OUT WCHAR const * const **papwszCriticalExtensions) { HRESULT hr;
*pdwEnrollmentFlags = 0; *pfReenroll = FALSE; *pcCriticalExtensions = 0; *papwszCriticalExtensions = NULL; if (NULL == m_pTemplate) { hr = CERTSRV_E_UNSUPPORTED_CERT_TYPE; _JumpErrorStr( hr, error, "Policy:ApplyTemplate:no cert template", m_strTemplateName); } hr = m_pTemplate->Apply(pServer, this, pfReenroll); _JumpIfError(hr, error, "Apply");
hr = m_pTemplate->GetFlags(CERTTYPE_ENROLLMENT_FLAG, pdwEnrollmentFlags); _JumpIfError(hr, error, "GetFlags");
hr = m_pTemplate->GetCriticalExtensions( pcCriticalExtensions, papwszCriticalExtensions); _JumpIfError(hr, error, "GetCriticalExtension");
error: DBGPRINT((DBG_SS_CERTPOLI, "Policy:_ApplyTemplate: %x\n", hr)); return(hr); }
// begin_sdksample
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 == mylstrcmpiL(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; HANDLE hToken;
VariantInit(&varValue);
hr = polGetProperty( pServer, FALSE, // fRequest
wszPROPREQUESTERTOKEN, PROPTYPE_BINARY, &varValue); if(CERTSRV_E_PROPERTY_EMPTY == hr) { _PrintIfError(hr, "polGetProperty(PROPREQUESTERTOKEN)"); hr = S_OK; } _JumpIfError(hr, error, "polGetProperty(PROPREQUESTERTOKEN)"); // Got a token value
if (sizeof(hToken) != SysStringByteLen(varValue.bstrVal) || NULL == *(HANDLE *) varValue.bstrVal) { hr = E_HANDLE; BuildErrorInfo(hr, MSG_NO_REQUESTER_TOKEN, NULL); _JumpError(hr, error, "Policy:Token/Length"); }
hToken = *(HANDLE *) varValue.bstrVal;
if (!DuplicateToken(hToken, SecurityIdentification, &m_hToken)) { hr = myHLastError(); BuildErrorInfo(hr, MSG_NO_REQUESTER_TOKEN, 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, IN BOOL fDNSNameRequired) { HRESULT hr; BSTR strProp = NULL; LPWSTR *awszUPN = NULL; BSTR strSamName = NULL; BSTR strClientDC = 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)) { pwszUserName = wcschr(wszDN, L'\\'); if (NULL != pwszUserName) { BSTR strT; DWORD cwcT; pwszUserName[1] = L'\0';
cwcT = wcslen(wszDN) + wcslen(strSamName); strT = SysAllocStringLen(NULL, cwcT); if (NULL == strT) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:SysAllocString"); } wcscpy(strT, wszDN); wcscat(strT, strSamName); CSASSERT(wcslen(strT) == cwcT); CSASSERT(SysStringLen(strT) == cwcT); SysFreeString(strSamName); strSamName = strT; } } }
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(pServer, fDNSNameRequired, NULL);
// If we couldn't find the DS object or the DNS name is missing or out of
// date, it is a machine object and the client specified his DC name, chase
// the client supplied DC in hopes of finding more current information.
if ((CERTSRV_E_SUBJECT_DNS_REQUIRED == hr || HRESULT_FROM_WIN32(DNS_ERROR_NAME_DOES_NOT_EXIST) == hr || (HRESULT) ERROR_DS_OBJ_NOT_FOUND == hr || HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND) == hr) && fDNSNameRequired && (EDITF_ENABLECHASECLIENTDC & m_pPolicy->GetEditFlags()) && !m_fUser) { HRESULT hr2; _PrintError(hr, "_GetDSObject");
hr2 = polGetRequestAttribute(pServer, wszPROPCLIENTDCDNS, &strClientDC); _PrintIfErrorStr( hr2, "Policy:polGetRequestAttribute", wszPROPCLIENTDCDNS); if (S_OK == hr2 && NULL != strClientDC) { _PrintErrorStr(hr, "_GetDSObject", strClientDC); hr = _GetDSObject(pServer, TRUE, strClientDC); _JumpIfErrorStr(hr, error, "_GetDSObject", strClientDC); } } _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; DWORD cwcT;
// Build a UPN from the username -- without the SAM domain.
// Get a buffer that will be big enough.
cwcT = wcslen(pwszUserName) + 1 + wcslen(m_strUserDN); m_pwszUPN = (WCHAR *) LocalAlloc( LMEM_FIXED, (1 + cwcT) * sizeof(WCHAR)); if (NULL == m_pwszUPN) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Policy:LocalAlloc"); }
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 == LSTRCMPIS(wszDC, L"DC=")) { wcscat( m_pwszUPN, (*ppwszCurrent) + ARRAYSIZE(wszDC) - 1); wcscat(m_pwszUPN, L"."); CSASSERT(wcslen(m_pwszUPN) < cwcT); } }
// 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 { if (CERTSRV_E_PROPERTY_EMPTY == hr || S_OK == hr) { hr = CERTSRV_E_SUBJECT_DNS_REQUIRED; } BuildErrorInfo(hr, MSG_NO_DNS_NAME, &m_strUserDN); _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 != strClientDC) { SysFreeString(strClientDC); } if (NULL != strSamName) { SysFreeString(strSamName); } if (NULL != awszUPN) { _FreeValues(awszUPN); } if (NULL != strProp) { SysFreeString(strProp); } VariantClear(&var); return(hr); }
VOID CRequestInstance::_ReleasePrincipalObject() { if (NULL != m_pldGC) { if (NULL != m_SearchResult) { ldap_msgfree(m_SearchResult); m_SearchResult = NULL; } reqReleaseLdapGC(&m_pldGC); myLdapUnbind(&m_pldClientDC); } }
#define wszHOSTPREFIX L"HOST/"
#define DS_ATTR_SPN L"servicePrincipalName"
#define DS_ATTR_BACKLINK L"serverReferenceBL"
#define wszSEARCHUSER L"(objectCategory=user)"
#define wszSEARCHCOMPUTER L"(objectCategory=computer)"
#define wszSEARCHNTDSDSA L"(objectCategory=nTDSDSA)"
#define wszSEARCHUSERCOMPUTER L"(|" wszSEARCHUSER wszSEARCHCOMPUTER L")"
#define wszSEARCHSPN L"(" DS_ATTR_SPN L"=" wszHOSTPREFIX L"%ws)"
#define wszSEARCHCOMPUTERSPN L"(&" wszSEARCHCOMPUTER wszSEARCHSPN L")"
#define wszDSOBJECTCATEGORYATTRIBUTE L"objectCategory"
WCHAR *s_apwszAttrsClientDC[] = { DS_ATTR_DNS_NAME, DS_ATTR_SPN, DS_ATTR_BACKLINK, NULL, };
// Use the ldap GC handle to verify the client-supplied DC DNS name is a valid
// DC in our forest. If it is, bind to the client supplied DC.
HRESULT reqFindClientDC( IN LDAP *pldGC, IN WCHAR const *pwszClientDC, OUT LDAP **ppldClientDC) { HRESULT hr; ULONG ldaperr; struct l_timeval timeout; WCHAR *pwszSearch = NULL; DWORD cwc; WCHAR *pwszError = NULL; LDAPMessage *pSearchResult = NULL; LDAPMessage *pEntry = NULL; WCHAR **ppwszValues = NULL; WCHAR *pwszServiceDN = NULL;
myLdapUnbind(ppldClientDC);
cwc = WSZARRAYSIZE(wszSEARCHCOMPUTERSPN) + wcslen(pwszClientDC); pwszSearch = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == pwszSearch) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocStringByteLen"); } wsprintf(pwszSearch, wszSEARCHCOMPUTERSPN, pwszClientDC); CSASSERT(wcslen(pwszSearch) <= cwc);
timeout.tv_sec = csecLDAPTIMEOUT; timeout.tv_usec = 0;
// ldap_search the GC for a Computer object with matching SPN.
// Fetch the service object back link attribute from the Computer object.
// Make sure the service object has a child object of class NTDSDSA
ldaperr = ldap_search_ext_s( pldGC, NULL, LDAP_SCOPE_SUBTREE, pwszSearch, s_apwszAttrsClientDC, 0, NULL, NULL, &timeout, 10000, &pSearchResult); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(pldGC, ldaperr, &pwszError); _PrintErrorStr(hr, "Policy:ldap_search_ext_s", pwszError); _JumpErrorStr(hr, error, "Policy:ldap_search_ext_s", pwszSearch); } if (0 == ldap_count_entries(pldGC, pSearchResult)) { hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER); _JumpError(hr, error, "Policy:ldap_count_entries"); } pEntry = ldap_first_entry(pldGC, pSearchResult); if (NULL == pEntry) { hr = myHLdapLastError(pldGC, NULL); _JumpError(hr, error, "Policy:ldap_first_entry"); } ppwszValues = ldap_get_values(pldGC, pEntry, DS_ATTR_BACKLINK); if (NULL == ppwszValues || NULL == ppwszValues[0]) { hr = CERTSRV_E_PROPERTY_EMPTY; _JumpErrorStr(hr, error, "Policy:ldap_get_values", DS_ATTR_BACKLINK); } hr = myDupString(ppwszValues[0], &pwszServiceDN); _JumpIfError(hr, error, "myDupString");
if (NULL != ppwszValues) { ldap_value_free(ppwszValues); ppwszValues = NULL; } if (NULL != pSearchResult) { ldap_msgfree(pSearchResult); pSearchResult = NULL; } if (NULL != pwszError) { LocalFree(pwszError); pwszError = NULL; }
// ldap_search the GC for a child of the Service object with class NTDSDSA.
ldaperr = ldap_search_ext_s( pldGC, pwszServiceDN, LDAP_SCOPE_ONELEVEL, wszSEARCHNTDSDSA, NULL, 0, NULL, NULL, &timeout, 10000, &pSearchResult); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(pldGC, ldaperr, &pwszError); _PrintErrorStr(hr, "Policy:ldap_search_ext_s", pwszError); _JumpErrorStr(hr, error, "Policy:ldap_search_ext_s", pwszServiceDN); } if (0 == ldap_count_entries(pldGC, pSearchResult)) { hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER); _JumpError(hr, error, "Policy:ldap_count_entries"); }
hr = myLdapBind(0, pwszClientDC, ppldClientDC); _JumpIfError(hr, error, "myLdapBind");
error: if (NULL != ppwszValues) { ldap_value_free(ppwszValues); } if (NULL != pSearchResult) { ldap_msgfree(pSearchResult); } if (NULL != pwszError) { LocalFree(pwszError); } if (NULL != pwszServiceDN) { LocalFree(pwszServiceDN); } if (NULL != pwszSearch) { LocalFree(pwszSearch); } return(hr); }
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( IN ICertServerPolicy *pServer, IN BOOL fDNSNameRequired, OPTIONAL IN WCHAR const *pwszClientDC) { HRESULT hr; ULONG ldaperr; struct l_timeval timeout; WCHAR **ppwszValues = NULL; BOOL fUser; LONG cRetry; WCHAR *pwszError = NULL; BSTR strDNS = NULL;
timeout.tv_sec = csecLDAPTIMEOUT; timeout.tv_usec = 0;
cRetry = 0; while (TRUE) { BOOL fCached;
if (NULL != m_SearchResult) { ldap_msgfree(m_SearchResult); m_SearchResult = NULL; } hr = reqGetLdapGC(m_pPolicy->GetEditFlags(), &m_pldGC, &fCached); _JumpIfError(hr, error, "reqGetLdapGC");
m_pldT = m_pldGC;
if (NULL != pwszClientDC) { hr = reqFindClientDC(m_pldGC, pwszClientDC, &m_pldClientDC); _JumpIfError(hr, error, "reqFindClientDC");
m_pldT = m_pldClientDC; }
ldaperr = ldap_search_ext_s( m_pldT, m_strUserDN, LDAP_SCOPE_BASE, wszSEARCHUSERCOMPUTER, s_apwszAttrs, 0, NULL, NULL, &timeout, 10000, &m_SearchResult); if (LDAP_SUCCESS != ldaperr) { if (NULL != pwszError) { LocalFree(pwszError); pwszError = NULL; } hr = myHLdapError(m_pldT, ldaperr, &pwszError);
// only retry for cached GC handle & when hr != object not found
if (fCached && (HRESULT) ERROR_DS_OBJ_NOT_FOUND != hr && NULL == pwszClientDC && cRetry++ < g_cGCCacheMax) { // get rid of GC handle we have, it might be stale
_PrintError2(hr, "Policy:ldap_search_ext_s", hr); myLdapUnbind(&m_pldGC); myLdapUnbind(&m_pldClientDC); continue; } _JumpErrorStr(hr, error, "Policy:ldap_search_ext_s", m_strUserDN); } break; } if (0 == ldap_count_entries(m_pldT, m_SearchResult)) { hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER); _JumpError(hr, error, "Policy:ldap_count_entries"); }
m_PrincipalAttributes = ldap_first_entry(m_pldT, m_SearchResult); if (NULL == m_PrincipalAttributes) { hr = myHLdapLastError(m_pldT, NULL); _JumpError(hr, error, "Policy:ldap_first_entry"); } #if DBG_CERTSRV
{ DWORD i;
for (i = 0; NULL != s_apwszAttrs[i]; i++) { if (0 == LSTRCMPIS(s_apwszAttrs[i], DS_ATTR_OBJECT_GUID)) { 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, "%ws[%u] = %ws\n", wszDSOBJECTCLASSATTRIBUTE, i, ppwszValues[i])); if (0 == LSTRCMPIS(ppwszValues[i], L"computer")) { 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; }
if (!m_fUser && fDNSNameRequired) { if (NULL != ppwszValues) { _FreeValues(ppwszValues); ppwszValues = NULL; } hr = _GetValues(DS_ATTR_DNS_NAME, &ppwszValues); if (S_OK != hr || NULL == ppwszValues || NULL == ppwszValues[0]) { _PrintIfError(hr, "Policy:_GetValues"); hr = CERTSRV_E_SUBJECT_DNS_REQUIRED; } _JumpIfErrorStr(hr, error, "Policy:_GetValues", DS_ATTR_DNS_NAME);
hr = polGetRequestAttribute(pServer, wszPROPREQUESTMACHINEDNS, &strDNS); _PrintIfErrorStr( hr, "Policy:polGetRequestAttribute", wszPROPREQUESTMACHINEDNS); if (S_OK == hr && NULL != strDNS && 0 != mylstrcmpiL(ppwszValues[0], strDNS)) { hr = HRESULT_FROM_WIN32(DNS_ERROR_NAME_DOES_NOT_EXIST); _PrintErrorStr(hr, "Policy:DNS name changed", ppwszValues[0]); _JumpErrorStr(hr, error, "Policy:DNS name changed", strDNS); } } hr = S_OK;
error: if (S_OK != hr && NULL != pwszError) { WCHAR *apwsz[2];
apwsz[0] = m_strUserDN; apwsz[1] = pwszError; BuildErrorInfo( hr, HRESULT_FROM_WIN32(ERROR_DS_REFERRAL) == hr? MSG_DS_REFERRAL : MSG_DS_SEARCH_ERROR, apwsz); } if (NULL != strDNS) { SysFreeString(strDNS); } if (NULL != pwszError) { LocalFree(pwszError); } 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( m_pldT, m_PrincipalAttributes, const_cast<WCHAR *>(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( m_pldT, 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, ~(sizeof(WCHAR) - 1) & 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); }
|