//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: prop.cpp // // Contents: Cert Server Property interface implementation // // History: 31-Jul-96 vich created // //--------------------------------------------------------------------------- #include #pragma hdrstop #include "csprop.h" #include "cscom.h" #include "csdisp.h" #include "com.h" #include "certlog.h" #include "certsrvd.h" #include "dbtable.h" #include "elog.h" #define __dwFILE__ __dwFILE_CERTSRV_PROP_CPP__ #ifndef DBG_PROP # define DBG_PROP 0 #endif HRESULT PropSetRequestTimeProperty( IN ICertDBRow *prow, IN WCHAR const *pwszProp) { HRESULT hr; SYSTEMTIME st; FILETIME ft; GetSystemTime(&st); if (!SystemTimeToFileTime(&st, &ft)) { hr = myHLastError(); _JumpError(hr, error, "SystemTimeToFileTime"); } hr = prow->SetProperty( pwszProp, PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_REQUEST, sizeof(ft), (BYTE *) &ft); _JumpIfError(hr, error, "SetProperty"); error: return(hr); } HRESULT PropParseRequest( IN ICertDBRow *prow, IN DWORD dwFlags, IN DWORD cbRequest, IN BYTE const *pbRequest, IN OUT CERTSRV_RESULT_CONTEXT *pResult) { HRESULT hr; pResult->dwFlagsTop = dwFlags; hr = PKCSParseRequest( dwFlags, prow, cbRequest, pbRequest, NULL, NULL, pResult); _JumpIfError(hr, error, "PKCSParseRequest"); error: return(hr); } HRESULT propVerifyDateRange( IN ICertDBRow *prow, IN DWORD Flags, IN WCHAR const *pwszPropertyName, IN FILETIME const *pft) { HRESULT hr; DWORD cbProp; FILETIME ftNotBefore; FILETIME ftNotAfter; hr = E_INVALIDARG; CSASSERT((PROPTYPE_MASK & Flags) == PROPTYPE_DATE); if ((PROPTABLE_MASK & Flags) != PROPTABLE_CERTIFICATE) { _JumpError(hr, error, "Flags: Invalid table"); } if (0 != mylstrcmpiS(pwszPropertyName, g_wszPropCertificateNotBeforeDate) && 0 != mylstrcmpiS(pwszPropertyName, g_wszPropCertificateNotAfterDate)) { _JumpError(hr, error, "pwszPropertyName: Invalid date property"); } cbProp = sizeof(ftNotBefore); hr = prow->GetProperty( g_wszPropCertificateNotBeforeDate, Flags, NULL, &cbProp, (BYTE *) &ftNotBefore); _JumpIfError(hr, error, "GetProperty"); cbProp = sizeof(ftNotAfter); hr = prow->GetProperty( g_wszPropCertificateNotAfterDate, Flags, NULL, &cbProp, (BYTE *) &ftNotAfter); _JumpIfError(hr, error, "GetProperty"); if (0 > CompareFileTime(pft, &ftNotBefore) || 0 < CompareFileTime(pft, &ftNotAfter)) { CERTSRVDBGPRINTTIME("Old Not Before", &ftNotBefore); CERTSRVDBGPRINTTIME(" Old Not After", &ftNotAfter); CERTSRVDBGPRINTTIME( 0 == mylstrcmpiS( pwszPropertyName, g_wszPropCertificateNotBeforeDate)? "New Not Before" : " New Not After", pft); hr = E_INVALIDARG; _JumpErrorStr(hr, error, "FILETIME out of range", pwszPropertyName); } error: return(myHError(hr)); } // Returns TRUE if names match! #define PROPNAMEMATCH(cwcNameVariable, pwszNameVariable, wszNameLiteral) \ (WSZARRAYSIZE((wszNameLiteral)) == (cwcNameVariable) && \ 0 == LSTRCMPIS((pwszNameVariable), (wszNameLiteral))) HRESULT propGetSystemProperty( IN WCHAR const *pwszPropName, IN DWORD Flags, IN LONG Context, OUT BOOL *pfSystemProperty, OUT VARIANT *pvarPropertyValue) { HRESULT hr = S_OK; BYTE *pbFree = NULL; DWORD cwcPropName; DWORD cwcBaseName; WCHAR wszBaseName[32]; WCHAR const *pwszIndex; WCHAR wszRenewalSuffix[cwcFILENAMESUFFIXMAX]; DWORD iCert = MAXDWORD; DWORD iCRL; DWORD iDummy; DWORD State; DWORD PropType; DWORD cbCopy; DWORD cbOut; BYTE const *pbOut = NULL; // PROPTYPE_LONG or PROPTYPE_BINARY WCHAR const *pwszOut = NULL; // PROPTYPE_STRING CRL_CONTEXT const *pCRL = NULL; CERTSRV_COM_CONTEXT *pComContext; BOOL fT; *pfSystemProperty = FALSE; wszRenewalSuffix[0] = L'\0'; cbOut = 0; // Allow "PropName.#" // Copy the base part of the property name to a local buffer, so we can do // case ignore string compares. cwcPropName = wcslen(pwszPropName); cwcBaseName = wcscspn(pwszPropName, L"."); if (ARRAYSIZE(wszBaseName) - 1 < cwcBaseName) { cwcBaseName = ARRAYSIZE(wszBaseName) - 1; } CopyMemory(wszBaseName, pwszPropName, cwcBaseName * sizeof(WCHAR)); wszBaseName[cwcBaseName] = L'\0'; pwszIndex = &pwszPropName[cwcBaseName]; if (L'.' == *pwszIndex) { pwszIndex++; iCert = _wtol(pwszIndex); for ( ; L'\0' != *pwszIndex; pwszIndex++) { if (!iswdigit(*pwszIndex)) { CSASSERT(S_OK == hr); // Not a system property, return S_OK goto error; } } } // Assume property type is a long: PropType = PROPTYPE_LONG; *pfSystemProperty = TRUE; if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPCATYPE)) { pbOut = (BYTE const *) &g_CAType; cbOut = sizeof(g_CAType); } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPUSEDS)) { pbOut = (BYTE const *) &g_fUseDS; cbOut = sizeof(g_fUseDS); } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPDELTACRLSDISABLED)) { pbOut = (BYTE const *) &g_fDeltaCRLPublishDisabled; cbOut = sizeof(g_fDeltaCRLPublishDisabled); } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPSERVERUPGRADED)) { pbOut = (BYTE const *) &g_fServerUpgraded; cbOut = sizeof(g_fServerUpgraded); } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPLOGLEVEL)) { pbOut = (BYTE const *) &g_dwLogLevel; cbOut = sizeof(g_dwLogLevel); } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPSESSIONCOUNT)) { pbOut = (BYTE const *) &g_dwSessionCount; cbOut = sizeof(g_dwSessionCount); } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPREQUESTERTOKEN)) { hr = ComGetClientInfo(Context, MAXDWORD, &pComContext); _JumpIfError(hr, error, "ComGetClientInfo"); if (NULL == pComContext->hAccessToken || INVALID_HANDLE_VALUE == pComContext->hAccessToken) { hr = CERTSRV_E_PROPERTY_EMPTY; _JumpError(hr, error, "ComGetClientInfo(bad hAccessToken)"); } pbOut = (BYTE const *) &pComContext->hAccessToken; cbOut = sizeof(pComContext->hAccessToken); PropType = PROPTYPE_BINARY; } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPREQUESTERCAACCESS)) { hr = ComGetClientInfo(Context, MAXDWORD, &pComContext); _JumpIfError(hr, error, "ComGetClientInfo"); if (0 == (CCCF_INREQUESTGROUPSET & pComContext->dwFlags)) { hr = CERTSRV_E_PROPERTY_EMPTY; _JumpError(hr, error, "ComGetClientInfo(fInRequestGroup not set)"); } fT = (CCCF_INREQUESTGROUP & pComContext->dwFlags)? TRUE : FALSE; pbOut = (BYTE const *) &fT; cbOut = sizeof(fT); } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPKEYARCHIVED)) { hr = ComGetClientInfo(Context, MAXDWORD, &pComContext); _JumpIfError(hr, error, "ComGetClientInfo"); if (0 == (CCCF_KEYARCHIVEDSET & pComContext->dwFlags)) { hr = CoreSetArchivedKey(pComContext); _JumpIfError(hr, error, "CoreSetArchivedKey"); CSASSERT(CCCF_KEYARCHIVEDSET & pComContext->dwFlags); } fT = (CCCF_KEYARCHIVED & pComContext->dwFlags)? TRUE : FALSE; pbOut = (BYTE const *) &fT; cbOut = sizeof(fT); } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPUSERDN)) { hr = ComGetClientInfo(Context, MAXDWORD, &pComContext); _JumpIfError(hr, error, "ComGetClientInfo"); if (NULL == pComContext->pwszUserDN) { if (!g_fUseDS) { hr = CERTSRV_E_PROPERTY_EMPTY; _JumpError(hr, error, "ComGetClientInfo(bad pwszUserDN)"); } hr = CoreSetComContextUserDN( pComContext->RequestId, Context, MAXDWORD, &pwszOut); _JumpIfError(hr, error, "CoreSetComContextUserDN"); } pwszOut = pComContext->pwszUserDN; } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPCERTCOUNT)) { pbOut = (BYTE const *) &g_cCACerts; cbOut = sizeof(g_cCACerts); } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPSANITIZEDCANAME)) { pwszOut = g_wszSanitizedName; } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPSANITIZEDSHORTNAME)) { pwszOut = g_pwszSanitizedDSName; } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPMACHINEDNSNAME)) { pwszOut = g_pwszServerName; } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPCONFIGDN)) { pwszOut = g_strConfigDN; } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPDOMAINDN)) { pwszOut = g_strDomainDN; } else if (PROPNAMEMATCH(cwcPropName, pwszPropName, wszPROPMODULEREGLOC)) { // future: cache storage location once it is built WCHAR *pwszQuasiPath; DWORD cwcQuasiPath; WCHAR const *pwszPrefix; MarshalInterface *pIF; if ((PROPCALLER_MASK & Flags) == PROPCALLER_POLICY) { pIF = &g_miPolicy; cwcQuasiPath = ARRAYSIZE(L"Policy\\"); // includes L'\0' pwszPrefix = L"Policy\\"; } else { hr = ExitGetActiveModule(Context, &pIF); _JumpIfError(hr, error, "ExitGetActiveModule"); cwcQuasiPath = ARRAYSIZE(L"Exit\\"); // includes L'\0' pwszPrefix = L"Exit\\"; } cwcQuasiPath += wcslen(pIF->GetProgID()); pwszQuasiPath = (WCHAR *) LocalAlloc( LMEM_FIXED, cwcQuasiPath * sizeof(WCHAR)); if (NULL == pwszQuasiPath) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pwszQuasiPath, pwszPrefix); wcscat(pwszQuasiPath, pIF->GetProgID()); hr = myRegOpenRelativeKey( pIF->GetConfig(), pwszQuasiPath, RORKF_FULLPATH | RORKF_CREATESUBKEYS, (WCHAR **) &pwszOut, NULL, NULL); LocalFree(pwszQuasiPath); _JumpIfError(hr, error, "myRegOpenRelativeKey"); CSASSERT(NULL != pwszOut); pbFree = (BYTE *) pwszOut; } else if (PROPNAMEMATCH(cwcBaseName, wszBaseName, wszPROPRAWCACERTIFICATE)) { hr = PKCSGetCACert( CR_PROP_CASIGCERT, iCert, const_cast(&pbOut), &cbOut); // not alloc'd _JumpIfError(hr, error, "PKCSGetCACert"); PropType = PROPTYPE_BINARY; } else if (PROPNAMEMATCH(cwcBaseName, wszBaseName, wszPROPRAWCRL)) { hr = CRLGetCRL(iCert, FALSE, &pCRL, NULL); _JumpIfError(hr, error, "CRLGetCRL"); cbOut = pCRL->cbCrlEncoded; pbOut = pCRL->pbCrlEncoded; PropType = PROPTYPE_BINARY; } else if (PROPNAMEMATCH(cwcBaseName, wszBaseName, wszPROPRAWDELTACRL)) { hr = CRLGetCRL(iCert, TRUE, &pCRL, NULL); _JumpIfError2( hr, error, "CRLGetCRL", HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); cbOut = pCRL->cbCrlEncoded; pbOut = pCRL->pbCrlEncoded; PropType = PROPTYPE_BINARY; } else if (PROPNAMEMATCH(cwcBaseName, wszBaseName, wszPROPCERTSTATE)) { hr = PKCSMapCertIndex(iCert, &iCert, &State); _JumpIfError(hr, error, "PKCSMapCertIndex"); pbOut = (BYTE *) &State; cbOut = sizeof(State); } else if (PROPNAMEMATCH(cwcBaseName, wszBaseName, wszPROPCERTSUFFIX)) { hr = PKCSMapCertIndex(iCert, &iCert, &State); _JumpIfError(hr, error, "PKCSMapCertIndex"); pwszOut = wszRenewalSuffix; } else if (PROPNAMEMATCH(cwcBaseName, wszBaseName, wszPROPCRLINDEX)) { hr = PKCSMapCRLIndex(iCert, &iCert, &iCRL, &State); _JumpIfError(hr, error, "PKCSMapCRLIndex"); pbOut = (BYTE *) &iCRL; cbOut = sizeof(iCRL); } else if (PROPNAMEMATCH(cwcBaseName, wszBaseName, wszPROPCRLSTATE)) { hr = PKCSMapCRLIndex(iCert, &iCert, &iCRL, &State); _JumpIfError(hr, error, "PKCSMapCRLIndex"); pbOut = (BYTE *) &State; cbOut = sizeof(State); } else if (PROPNAMEMATCH(cwcBaseName, wszBaseName, wszPROPCRLSUFFIX)) { hr = PKCSMapCRLIndex(iCert, &iDummy, &iCert, &State); _JumpIfError(hr, error, "PKCSMapCRLIndex"); pwszOut = wszRenewalSuffix; } else if(PROPNAMEMATCH(cwcBaseName, wszBaseName, wszPROPTEMPLATECHANGESEQUENCENUMBER)) { pbOut = (BYTE const *) &g_cTemplateUpdateSequenceNum; cbOut = sizeof(g_cTemplateUpdateSequenceNum); } else { CSASSERT(S_OK == hr); // Not a system property, return S_OK *pfSystemProperty = FALSE; goto error; } CSASSERT((NULL != pbOut) ^ (NULL != pwszOut)); // exactly 1 must be set cbCopy = cbOut; if (NULL != pwszOut) { if (wszRenewalSuffix == pwszOut && 0 != iCert) { wsprintf(wszRenewalSuffix, L"(%u)", iCert); } PropType = PROPTYPE_STRING; cbOut = wcslen(pwszOut) * sizeof(WCHAR); cbCopy = cbOut + sizeof(WCHAR); pbOut = (BYTE *) pwszOut; } if ((PROPTYPE_MASK & Flags) != PropType) { hr = E_INVALIDARG; _JumpError2(hr, error, "bad PropType", hr); } hr = myUnmarshalVariant( PROPMARSHAL_LOCALSTRING | Flags, cbOut, pbOut, pvarPropertyValue); _JumpIfError(hr, error, "myUnmarshalVariant"); error: if (NULL != pCRL) { CertFreeCRLContext(pCRL); } if (NULL != pbFree) { LocalFree(pbFree); } return(hr); } class CComputedProperty : public ICertDBComputedColumn { public: CComputedProperty(); ~CComputedProperty(); // IUnknown STDMETHODIMP QueryInterface(const IID& iid, void **ppv); ULONG STDMETHODCALLTYPE AddRef(); ULONG STDMETHODCALLTYPE Release(); STDMETHOD(GetAlternateColumnId)( IN DWORD ComputedColumnId, OUT DWORD *pAlternateColumnId, OUT DWORD *pPropType); STDMETHOD(ComputeColumnValue)( IN DWORD ComputedColumnId, IN DWORD AlternateColumnId, IN DWORD PropType, IN DWORD cbProp, IN BYTE const *pbProp, OUT DWORD *pdwValue); HRESULT SavePropertyArgument( IN WCHAR const *pwszPropIn, OUT WCHAR **ppwszPropOut); private: WCHAR *m_pwszArg; // Reference count long m_cRef; }; CComputedProperty::CComputedProperty() { m_pwszArg = NULL; m_cRef = 1; } CComputedProperty::~CComputedProperty() { if (NULL != m_pwszArg) { LocalFree(m_pwszArg); } } STDMETHODIMP CComputedProperty::QueryInterface( const IID& iid, void **ppv) { HRESULT hr; if (NULL == ppv) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } if (iid == IID_IUnknown) { *ppv = static_cast(this); } else if (iid == IID_ICertDBComputedColumn) { *ppv = static_cast(this); } else { *ppv = NULL; hr = E_NOINTERFACE; _JumpError(hr, error, "IID"); } reinterpret_cast(*ppv)->AddRef(); hr = S_OK; error: return(hr); } ULONG STDMETHODCALLTYPE CComputedProperty::AddRef() { return(InterlockedIncrement(&m_cRef)); } ULONG STDMETHODCALLTYPE CComputedProperty::Release() { ULONG cRef = InterlockedDecrement(&m_cRef); if (0 == cRef) { delete this; } return(cRef); } STDMETHODIMP CComputedProperty::ComputeColumnValue( IN DWORD ComputedColumnId, IN DWORD AlternateColumnId, IN DWORD PropType, IN DWORD cbProp, IN BYTE const *pbProp, OUT DWORD *pdwValue) { HRESULT hr; WCHAR const *pwszRequesterName; *pdwValue = 0; if (NULL == m_pwszArg) { hr = CERTSRV_E_PROPERTY_EMPTY; _JumpError(hr, error, "m_pwszArg NULL"); } if ((DTI_REQUESTTABLE | DTR_OFFICER) != ComputedColumnId || (DTI_REQUESTTABLE | DTR_REQUESTERNAME) != AlternateColumnId || PROPTYPE_STRING != PropType || 0 == cbProp || ((sizeof(WCHAR) - 1) & cbProp)) { hr = CERTSRV_E_PROPERTY_EMPTY; _JumpError(hr, error, "ComputedColumnId"); } pwszRequesterName = (WCHAR const *) pbProp; CSASSERT(L'\0' == pwszRequesterName[cbProp / sizeof(WCHAR)]); CSASSERT(sizeof(WCHAR) * wcslen(pwszRequesterName) == cbProp); hr = CheckOfficerRightsFromOfficerName(m_pwszArg, pwszRequesterName); if (S_OK == hr) { *pdwValue = 1; } else if (CERTSRV_E_RESTRICTEDOFFICER == hr) { hr = S_OK; } _JumpIfError(hr, error, "CheckOfficerRightsFromOfficerName"); error: DBGPRINT(( DBG_SS_CERTSRV, "ComputeColumnValue(%ws) = %u hr=%x\n", (WCHAR const *) pbProp, *pdwValue, hr)); return(hr); } HRESULT CComputedProperty::SavePropertyArgument( IN WCHAR const *pwszPropIn, OUT WCHAR **ppwszPropOut) { HRESULT hr; WCHAR *pwszT; CSASSERT(NULL == m_pwszArg); hr = myDupString(pwszPropIn, ppwszPropOut); _JumpIfError(hr, error, "myDupString"); pwszT = wcschr(*ppwszPropOut, wcLPAREN); if (NULL != pwszT) { WCHAR *pwsz2 = pwszT; while (--pwsz2 >= *ppwszPropOut && L' ' == *pwsz2) { *pwsz2 = L'\0'; } *pwszT++ = L'\0'; while (L' ' == *pwszT) { pwszT++; } hr = myDupString(pwszT, &m_pwszArg); _JumpIfError(hr, error, "myDupString"); pwszT = wcschr(m_pwszArg, wcRPAREN); if (NULL == pwszT) { hr = E_INVALIDARG; _JumpErrorStr(hr, error, "SavePropertyArgument", pwszPropIn); } do { *pwszT-- = L'\0'; } while (pwszT >= m_pwszArg && L' ' == *pwszT); } hr = S_OK; error: return(hr); } STDMETHODIMP CComputedProperty::GetAlternateColumnId( IN DWORD ComputedColumnId, OUT DWORD *pAlternateColumnId, OUT DWORD *pPropType) { HRESULT hr; *pAlternateColumnId = 0; if ((DTI_REQUESTTABLE | DTR_OFFICER) != ComputedColumnId) { hr = CERTSRV_E_PROPERTY_EMPTY; _JumpError(hr, error, "ComputedColumnId"); } *pAlternateColumnId = DTI_REQUESTTABLE | DTR_REQUESTERNAME; *pPropType = PROPTYPE_STRING; hr = S_OK; error: return(hr); } FNCIGETPROPERTY PropCIGetProperty; HRESULT PropCIGetProperty( IN LONG Context, IN DWORD Flags, IN WCHAR const *pwszPropertyName, OUT VARIANT *pvarPropertyValue) { HRESULT hr; DWORD RequestId; DWORD cbprop; BYTE *pbprop = NULL; ICertDBRow *prow = NULL; BYTE rgbFastBuf[128]; // many properties are small (128) BOOL fSystemProperty; CComputedProperty ccp; WCHAR *pwszPropAlloc = NULL; if (NULL != pvarPropertyValue) { VariantInit(pvarPropertyValue); } if (NULL == pwszPropertyName || NULL == pvarPropertyValue) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } hr = E_INVALIDARG; if ((PROPCALLER_MASK & Flags) != PROPCALLER_POLICY && (PROPCALLER_MASK & Flags) != PROPCALLER_EXIT && (PROPCALLER_MASK & Flags) != PROPCALLER_SERVER) { _JumpError(hr, error, "Flags: Invalid caller"); } if ((PROPTABLE_MASK & Flags) != PROPTABLE_REQUEST && (PROPTABLE_MASK & Flags) != PROPTABLE_CERTIFICATE && (PROPTABLE_MASK & Flags) != PROPTABLE_ATTRIBUTE) { _JumpError(hr, error, "Flags: Invalid table"); } fSystemProperty = FALSE; if ((PROPTABLE_MASK & Flags) == PROPTABLE_CERTIFICATE) { hr = ComVerifyRequestContext(TRUE, Flags, Context, &RequestId); _JumpIfError(hr, error, "ComVerifyRequestContext"); // Check for special, hard-coded properties first hr = propGetSystemProperty( pwszPropertyName, Flags, Context, &fSystemProperty, pvarPropertyValue); _JumpIfErrorStr2( hr, error, "propGetSystemProperty", pwszPropertyName, E_INVALIDARG); } if (!fSystemProperty) { DWORD VerifyFlags = Flags; if (((PROPCALLER_MASK | PROPTABLE_MASK | PROPTYPE_MASK) & Flags) == (PROPCALLER_SERVER | PROPTABLE_REQUEST | PROPTYPE_LONG) && 0 == LSTRCMPIS(pwszPropertyName, wszPROPREQUESTREQUESTID)) { VerifyFlags = PROPCALLER_EXIT | (~PROPCALLER_MASK & VerifyFlags); } hr = ComVerifyRequestContext(FALSE, VerifyFlags, Context, &RequestId); _JumpIfError(hr, error, "ComVerifyRequestContext"); pbprop = rgbFastBuf; cbprop = sizeof(rgbFastBuf); // PROPCALLER_SERVER indicates this call is only for Context validation // -- return a zero RequestId. This keeps CRL publication exit module // notification from failing. if (0 == RequestId && ((PROPCALLER_MASK | PROPTABLE_MASK | PROPTYPE_MASK) & Flags) == (PROPCALLER_SERVER | PROPTABLE_REQUEST | PROPTYPE_LONG) && 0 == LSTRCMPIS(pwszPropertyName, wszPROPREQUESTREQUESTID)) { *(DWORD *) pbprop = 0; cbprop = sizeof(DWORD); } else { WCHAR const *pwszPropT; if (PROPTYPE_STRING == (PROPTYPE_MASK & Flags) && PROPTABLE_CERTIFICATE == (PROPTABLE_MASK & Flags)) { BOOL fSubjectDot; hr = PKCSVerifySubjectRDN( NULL, // prow &pwszPropertyName, NULL, // pwszPropertyValue &fSubjectDot); _JumpIfError(hr, error, "PKCSVerifySubjectRDN"); } hr = g_pCertDB->OpenRow( PROPOPEN_READONLY | PROPTABLE_REQCERT, RequestId, NULL, &prow); _JumpIfError(hr, error, "OpenRow"); if ((PROPTABLE_MASK & Flags) == PROPTABLE_REQUEST || (PROPTABLE_MASK & Flags) == PROPTABLE_CERTIFICATE) { hr = ccp.SavePropertyArgument(pwszPropertyName, &pwszPropAlloc); _JumpIfError(hr, error, "SavePropertyArgument"); pwszPropT = pwszPropAlloc; } else { pwszPropT = pwszPropertyName; } hr = prow->GetProperty( pwszPropT, Flags, g_OfficerRightsSD.IsEnabled()? &ccp : NULL, &cbprop, pbprop); if (S_OK != hr) { if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr) { _JumpIfError3( hr, error, "GetProperty", CERTSRV_E_PROPERTY_EMPTY, E_INVALIDARG); } CSASSERT(ARRAYSIZE(rgbFastBuf) < cbprop); DBGPRINT(( DBG_SS_CERTSRVI, "FastBuf miss: PropCIGetProperty - pbprop %i bytes\n", cbprop)); pbprop = (BYTE *) LocalAlloc(LMEM_FIXED, cbprop); if (NULL == pbprop) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } hr = prow->GetProperty( pwszPropT, Flags, g_OfficerRightsSD.IsEnabled()? &ccp : NULL, &cbprop, pbprop); _JumpIfError(hr, error, "GetProperty"); } } // property is in-hand if ((((PROPTABLE_MASK | PROPTYPE_MASK) & Flags) == (PROPTABLE_REQUEST | PROPTYPE_BINARY)) && (0 == LSTRCMPIS(pwszPropertyName, wszPROPREQUESTRAWARCHIVEDKEY) || 0 == LSTRCMPIS(pwszPropertyName, wszPROPREQUESTDOT wszPROPREQUESTRAWARCHIVEDKEY))) { *pbprop = 0; cbprop = sizeof(*pbprop); } hr = myUnmarshalVariant( PROPMARSHAL_LOCALSTRING | Flags, cbprop, pbprop, pvarPropertyValue); _JumpIfError(hr, error, "myUnmarshalVariant"); } error: if (NULL != prow) { prow->Release(); } if (NULL != pbprop && pbprop != rgbFastBuf) { LocalFree(pbprop); } if (NULL != pwszPropAlloc) { LocalFree(pwszPropAlloc); } return(myHError(hr)); } HRESULT propSetSystemProperty( IN WCHAR const *pwszPropName, IN DWORD Flags, OUT BOOL *pfSystemProperty, IN VARIANT const *pvarPropertyValue) { HRESULT hr = S_OK; DWORD LogLevel = MAXDWORD; DWORD infotype = EVENTLOG_INFORMATION_TYPE; DWORD LogMsg = MSG_POLICY_LOG_INFORMATION; WCHAR *pwsz = NULL; DWORD cwcMax; *pfSystemProperty = FALSE; cwcMax = 1; if (0 == LSTRCMPIS(pwszPropName, wszPROPEVENTLOGTERSE)) { LogLevel = CERTLOG_TERSE; } else if (0 == LSTRCMPIS(pwszPropName, wszPROPEVENTLOGERROR)) { LogLevel = CERTLOG_ERROR; infotype = EVENTLOG_ERROR_TYPE; LogMsg = MSG_POLICY_LOG_ERROR; } else if (0 == LSTRCMPIS(pwszPropName, wszPROPEVENTLOGWARNING)) { LogLevel = CERTLOG_WARNING; infotype = EVENTLOG_WARNING_TYPE; LogMsg = MSG_POLICY_LOG_WARNING; } else if (0 == LSTRCMPIS(pwszPropName, wszPROPEVENTLOGVERBOSE)) { LogLevel = CERTLOG_VERBOSE; } else if (0 == LSTRCMPIS(pwszPropName, wszPROPDCNAME)) { pwsz = g_wszPolicyDCName; cwcMax = g_cwcPolicyDCName; } else { CSASSERT(S_OK == hr); // Not a system property, return S_OK goto error; } *pfSystemProperty = TRUE; if (PROPTYPE_STRING != (PROPTYPE_MASK & Flags) || VT_BSTR != pvarPropertyValue->vt || NULL == pvarPropertyValue->bstrVal) { hr = E_INVALIDARG; _JumpErrorStr(hr, error, "string property value/type", pwszPropName); } if (NULL != pwsz) { // Terminate first to avoid problems with multi-threaded access. pwsz[cwcMax - 1] = L'\0'; wcsncpy(pwsz, pvarPropertyValue->bstrVal, cwcMax - 1); } else { CSASSERT(MAXDWORD != LogLevel); if (LogLevel <= g_dwLogLevel) { WCHAR const *apwsz[2]; WCHAR const *pwszMessage = pvarPropertyValue->bstrVal; HRESULT hrPrefix; if (ComParseErrorPrefix( pvarPropertyValue->bstrVal, &hrPrefix, &pwszMessage)) { } else { pwszMessage = pvarPropertyValue->bstrVal; } apwsz[0] = g_strPolicyDescription; apwsz[1] = pwszMessage; hr = LogEvent(infotype, LogMsg, ARRAYSIZE(apwsz), apwsz); _JumpIfError(hr, error, "LogEvent"); } } hr = S_OK; error: return(myHError(hr)); } FNCISETPROPERTY PropCISetProperty; HRESULT PropCISetProperty( IN LONG Context, IN DWORD Flags, IN WCHAR const *pwszPropertyName, IN VARIANT const *pvarPropertyValue) { HRESULT hr; DWORD RequestId; DWORD cbprop; BYTE *pbprop = NULL; ICertDBRow *prow = NULL; BOOL fSubjectDot = FALSE; BOOL fSystemProperty; BOOL fCommitted = FALSE; if (NULL == pwszPropertyName || NULL == pvarPropertyValue) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } hr = E_INVALIDARG; if ((PROPCALLER_MASK & Flags) != PROPCALLER_POLICY) { _JumpError(hr, error, "Flags: Invalid caller"); } if ((PROPTABLE_MASK & Flags) != PROPTABLE_CERTIFICATE) { _JumpError(hr, error, "Flags: Invalid table"); } hr = ComVerifyRequestContext(TRUE, Flags, Context, &RequestId); _JumpIfError(hr, error, "ComVerifyRequestContext"); // Check for special, hard-coded properties first fSystemProperty = FALSE; hr = propSetSystemProperty( pwszPropertyName, Flags, &fSystemProperty, pvarPropertyValue); _JumpIfError(hr, error, "propSetSystemProperty"); if (!fSystemProperty) { hr = ComVerifyRequestContext(FALSE, Flags, Context, &RequestId); _JumpIfError(hr, error, "ComVerifyRequestContext"); hr = myMarshalVariant( pvarPropertyValue, PROPMARSHAL_NULLBSTROK | PROPMARSHAL_LOCALSTRING | Flags, &cbprop, &pbprop); _JumpIfError(hr, error, "myMarshalVariant"); hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, RequestId, NULL, &prow); _JumpIfError(hr, error, "OpenRow"); if (PROPTYPE_DATE == (PROPTYPE_MASK & Flags)) { hr = propVerifyDateRange( prow, Flags, pwszPropertyName, (FILETIME *) pbprop); _JumpIfError(hr, error, "propVerifyDateRange"); } else if (PROPTYPE_STRING == (PROPTYPE_MASK & Flags) && PROPTABLE_CERTIFICATE == (PROPTABLE_MASK & Flags)) { hr = PKCSVerifySubjectRDN( prow, &pwszPropertyName, (WCHAR const *) pbprop, &fSubjectDot); _JumpIfError(hr, error, "PKCSVerifySubjectRDN"); } if (NULL == pbprop && fSubjectDot) { hr = PKCSDeleteAllSubjectRDNs(prow, Flags); _JumpIfError(hr, error, "PKCSDeleteAllSubjectRDNs"); } else { hr = prow->SetProperty(pwszPropertyName, Flags, cbprop, pbprop); _JumpIfError(hr, error, "SetProperty"); } hr = prow->CommitTransaction(CDBROW_COMMIT_SOFTCOMMIT); // not critical to flush _JumpIfError(hr, error, "CommitTransaction"); fCommitted = TRUE; } hr = S_OK; error: if (NULL != prow) { if (S_OK != hr && !fCommitted) { HRESULT hr2 = prow->CommitTransaction(CDBROW_COMMIT_ROLLBACK); _PrintIfError(hr2, "CommitTransaction"); } prow->Release(); } if (NULL != pbprop) { LocalFree(pbprop); } return(myHError(hr)); } HRESULT PropGetExtension( IN ICertDBRow *prow, IN DWORD Flags, IN WCHAR const *pwszExtensionName, OUT DWORD *pdwExtFlags, OUT DWORD *pcbValue, OUT BYTE **ppbValue) // LocalAlloc { HRESULT hr; DWORD cbprop; BYTE *pbprop = NULL; CSASSERT( PROPCALLER_EXIT == (PROPCALLER_MASK & Flags) || PROPCALLER_POLICY == (PROPCALLER_MASK & Flags) || PROPCALLER_SERVER == (PROPCALLER_MASK & Flags)); CSASSERT(0 == (~(PROPMARSHAL_LOCALSTRING | PROPCALLER_MASK | PROPTYPE_MASK) & Flags)); hr = myVerifyObjId(pwszExtensionName); _JumpIfError(hr, error, "myVerifyObjId"); cbprop = 0; hr = prow->GetExtension(pwszExtensionName, pdwExtFlags, &cbprop, NULL); _JumpIfError2(hr, error, "GetExtension(NULL)", CERTSRV_E_PROPERTY_EMPTY); pbprop = (BYTE *) LocalAlloc(LMEM_FIXED, cbprop); if (NULL == pbprop) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc(ExtValue)"); } hr = prow->GetExtension(pwszExtensionName, pdwExtFlags, &cbprop, pbprop); _JumpIfError(hr, error, "GetExtension"); if (PROPTYPE_BINARY == (PROPTYPE_MASK & Flags)) { *pcbValue = cbprop; *ppbValue = pbprop; pbprop = NULL; } else { hr = myDecodeExtension(Flags, pbprop, cbprop, ppbValue, pcbValue); _JumpIfError(hr, error, "myDecodeExtension"); } error: if (NULL != pbprop) { LocalFree(pbprop); } return(myHError(hr)); } HRESULT PropSetExtension( IN ICertDBRow *prow, IN DWORD Flags, IN WCHAR const *pwszExtensionName, IN DWORD ExtFlags, IN DWORD cbValue, IN BYTE const *pbValue) { HRESULT hr; DWORD cbprop; BYTE *pbprop = NULL; CSASSERT( PROPCALLER_ADMIN == (PROPCALLER_MASK & Flags) || PROPCALLER_POLICY == (PROPCALLER_MASK & Flags) || PROPCALLER_SERVER == (PROPCALLER_MASK & Flags) || PROPCALLER_REQUEST == (PROPCALLER_MASK & Flags)); CSASSERT(0 == (~(PROPMARSHAL_LOCALSTRING | PROPCALLER_MASK | PROPTYPE_MASK) & Flags)); hr = myVerifyObjId(pwszExtensionName); _JumpIfError(hr, error, "myVerifyObjId"); if (PROPTYPE_BINARY == (PROPTYPE_MASK & Flags)) { cbprop = cbValue; pbprop = (BYTE *) pbValue; } else { hr = myEncodeExtension(Flags, pbValue, cbValue, &pbprop, &cbprop); _JumpIfError(hr, error, "myEncodeExtension"); } hr = prow->SetExtension(pwszExtensionName, ExtFlags, cbprop, pbprop); _JumpIfError(hr, error, "SetExtension"); error: if (NULL != pbprop && pbprop != pbValue) { LocalFree(pbprop); } return(hr); } FNCIGETEXTENSION PropCIGetExtension; HRESULT PropCIGetExtension( IN LONG Context, IN DWORD Flags, IN WCHAR const *pwszExtensionName, OUT DWORD *pdwExtFlags, OUT VARIANT *pvarValue) { HRESULT hr; DWORD RequestId; BYTE *pbValue = NULL; DWORD cbValue; ICertDBRow *prow = NULL; if (NULL != pvarValue) { VariantInit(pvarValue); } if (NULL == pwszExtensionName || NULL == pdwExtFlags || NULL == pvarValue) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } hr = ComVerifyRequestContext(FALSE, Flags, Context, &RequestId); _JumpIfError(hr, error, "ComVerifyRequestContext"); hr = g_pCertDB->OpenRow(PROPOPEN_READONLY | PROPTABLE_REQCERT, RequestId, NULL, &prow); _JumpIfError(hr, error, "OpenRow"); hr = PropGetExtension( prow, PROPMARSHAL_LOCALSTRING | Flags, pwszExtensionName, pdwExtFlags, &cbValue, &pbValue); _JumpIfError2(hr, error, "PropGetExtension", CERTSRV_E_PROPERTY_EMPTY); hr = myUnmarshalVariant( PROPMARSHAL_LOCALSTRING | Flags, cbValue, pbValue, pvarValue); _JumpIfError(hr, error, "myUnmarshalVariant"); error: if (NULL != prow) { prow->Release(); } if (NULL != pbValue) { LocalFree(pbValue); } return(hr); } FNCISETPROPERTY PropCISetExtension; HRESULT PropCISetExtension( IN LONG Context, IN DWORD Flags, IN WCHAR const *pwszExtensionName, IN DWORD ExtFlags, IN VARIANT const *pvarValue) { HRESULT hr; DWORD RequestId; DWORD cbprop; BYTE *pbprop = NULL; ICertDBRow *prow = NULL; BOOL fCommitted = FALSE; if (NULL == pwszExtensionName || NULL == pvarValue) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } if ((PROPCALLER_MASK & Flags) != PROPCALLER_POLICY) { hr = E_INVALIDARG; _JumpError(hr, error, "Flags: Invalid caller"); } hr = ComVerifyRequestContext(FALSE, Flags, Context, &RequestId); _JumpIfError(hr, error, "ComVerifyRequestContext"); hr = myMarshalVariant( pvarValue, PROPMARSHAL_LOCALSTRING | Flags, &cbprop, &pbprop); _JumpIfError(hr, error, "myMarshalVariant"); hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, RequestId, NULL, &prow); _JumpIfError(hr, error, "OpenRow"); hr = PropSetExtension( prow, PROPMARSHAL_LOCALSTRING | Flags, pwszExtensionName, ExtFlags, cbprop, pbprop); _JumpIfError(hr, error, "PropSetExtension"); hr = prow->CommitTransaction(CDBROW_COMMIT_SOFTCOMMIT); // not critical to flush _JumpIfError(hr, error, "CommitTransaction"); fCommitted = TRUE; error: if (NULL != prow) { if (S_OK != hr && !fCommitted) { HRESULT hr2 = prow->CommitTransaction(CDBROW_COMMIT_ROLLBACK); _PrintIfError(hr2, "CommitTransaction"); } prow->Release(); } if (NULL != pbprop) { LocalFree(pbprop); } return(myHError(hr)); } FNCIENUMSETUP PropCIEnumSetup; HRESULT PropCIEnumSetup( IN LONG Context, IN LONG Flags, IN OUT CIENUM *pciEnum) { HRESULT hr; DWORD RequestId; CSASSERT(CSExpr(CIE_CALLER_POLICY == PROPCALLER_POLICY)); CSASSERT(CSExpr(CIE_CALLER_EXIT == PROPCALLER_EXIT)); CSASSERT(CSExpr(CIE_CALLER_MASK == PROPCALLER_MASK)); hr = ComVerifyRequestContext(FALSE, Flags, Context, &RequestId); _JumpIfError(hr, error, "ComVerifyRequestContext"); hr = pciEnum->EnumSetup(RequestId, Context, Flags); _JumpIfError(hr, error, "EnumSetup"); error: return(hr); } FNCIENUMNEXT PropCIEnumNext; HRESULT PropCIEnumNext( IN OUT CIENUM *pciEnum, OUT BSTR *pstrPropertyName) { HRESULT hr; DWORD RequestId; CSASSERT(CSExpr(CIE_CALLER_POLICY == PROPCALLER_POLICY)); CSASSERT(CSExpr(CIE_CALLER_EXIT == PROPCALLER_EXIT)); CSASSERT(CSExpr(CIE_CALLER_MASK == PROPCALLER_MASK)); hr = ComVerifyRequestContext( FALSE, pciEnum->GetFlags(), pciEnum->GetContext(), &RequestId); _JumpIfError(hr, error, "ComVerifyRequestContext"); hr = pciEnum->EnumNext(pstrPropertyName); _JumpIfError2(hr, error, "EnumNext", S_FALSE); error: return(hr); } FNCIENUMCLOSE PropCIEnumClose; HRESULT PropCIEnumClose( IN OUT CIENUM *pciEnum) { HRESULT hr; hr = pciEnum->EnumClose(); _JumpIfError(hr, error, "EnumClose"); error: return(hr); } HRESULT PropSetAttributeProperty( IN ICertDBRow *prow, IN BOOL fConcatenateRDNs, IN BOOL fPrependNewValue, IN DWORD dwTable, IN DWORD cwcNameMax, OPTIONAL IN WCHAR const *pwszSuffix, IN WCHAR const *pwszName, IN WCHAR const *pwszValue) { HRESULT hr = S_OK; WCHAR *pwszTemp = NULL; WCHAR const *pwszValue2 = pwszValue; DWORD cbProp; DWORD dwFlags = dwTable | PROPTYPE_STRING | PROPCALLER_SERVER; CSASSERT( PROPTABLE_ATTRIBUTE == dwTable || PROPTABLE_REQUEST == dwTable || PROPTABLE_CERTIFICATE == dwTable); // if the name and value are both non-empty ... if (NULL != pwszName && L'\0' != *pwszName && NULL != pwszValue && L'\0' != *pwszValue) { if (PROPTABLE_ATTRIBUTE != dwTable) { if (g_fEnforceRDNNameLengths && wcslen(pwszValue) > cwcNameMax) { hr = CERTSRV_E_BAD_REQUESTSUBJECT; DBGPRINT(( DBG_SS_CERTSRV, "RDN component too long: %u/%u: %ws=\"%ws\"\n", wcslen(pwszValue), cwcNameMax, pwszName, pwszValue)); _JumpErrorStr(hr, error, "RDN component too long", pwszValue); } if (fConcatenateRDNs) { cbProp = 0; hr = prow->GetProperty(pwszName, dwFlags, NULL, &cbProp, NULL); if (CERTSRV_E_PROPERTY_EMPTY != hr) { DWORD cwcAdd; _JumpIfError(hr, error, "GetProperty"); cwcAdd = 1 + wcslen(pwszValue); // cbProp includes trailing L'\0' when out buffer is NULL pwszTemp = (WCHAR *) LocalAlloc( LMEM_FIXED, cbProp + sizeof(WCHAR) * cwcAdd); if (NULL == pwszTemp) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } // If there are multiple RDN components for the same DB // column, concatenate them. if (fPrependNewValue) { wcscpy(pwszTemp, pwszValue); wcscat(pwszTemp, wszNAMESEPARATORDEFAULT); CSASSERT(wcslen(pwszTemp) == cwcAdd); } hr = prow->GetProperty( pwszName, dwFlags, NULL, &cbProp, (BYTE *) &pwszTemp[fPrependNewValue? cwcAdd : 0]); _JumpIfError(hr, error, "GetProperty"); // If there are multiple RDN components for the same DB // column, concatenate them. if (!fPrependNewValue) { wcscat(pwszTemp, wszNAMESEPARATORDEFAULT); wcscat(pwszTemp, pwszValue); } pwszValue2 = pwszTemp; // cbProp now does NOT include trailing L'\0' CSASSERT( sizeof(WCHAR) * wcslen(pwszTemp) == cbProp + sizeof(WCHAR) * cwcAdd); } } else if (NULL != pwszSuffix) { hr = myAddNameSuffix( pwszValue, pwszSuffix, cwcNameMax, &pwszTemp); _JumpIfError(hr, error, "myAddNameSuffix"); pwszValue2 = pwszTemp; } } hr = prow->SetProperty( pwszName, dwFlags, MAXDWORD, (BYTE const *) pwszValue2); _JumpIfError(hr, error, "SetProperty"); } error: if (NULL != pwszTemp) { LocalFree(pwszTemp); } return(hr); }