windows-nt/Source/XPSP1/NT/ds/adsi/ldap/cpropmgr.cxx

3562 lines
92 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: cpropmgr.cxx
//
// Contents: Property manager - object that implements/helps implement
// IUMIPropList functions.
// The property manager needs to be initialized in one of 2 modes
// 1) PropertyCache mode in which case it uses the objects existing
// to provide IUMIPropList support and
// 2) Interface property mode in which case ???
//
// Functions: TBD.
//
// History: 02-07-00 AjayR Created.
//
//----------------------------------------------------------------------------
#include "ldap.hxx"
//
// These are global utility fucntions. Might be worth moving to a
// better location subsequently.
//
//+---------------------------------------------------------------------------
// Function: FreeOneUmiProperty -- Global scope.
//
// Synopsis: Walk through and free all information being pointed to
// including the values.
//
// Arguments: self explanatory
//
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
HRESULT FreeOneUmiProperty(UMI_PROPERTY umiProperty)
{
//
// Free the name now if we can
//
if (umiProperty.pszPropertyName) {
FreeADsStr(umiProperty.pszPropertyName);
umiProperty.pszPropertyName = NULL;
}
if (!umiProperty.pUmiValue) {
//
// We are done if count is 0
//
if (umiProperty.uCount == 0) {
RRETURN(S_OK);
}
else {
RRETURN(E_ADS_BAD_PARAMETER);
}
}
//
// Must have valid umiValues at this point.
//
for (ULONG ulCtr = 0; ulCtr < umiProperty.uCount; ulCtr++) {
switch (umiProperty.uType) {
case UMI_TYPE_LPWSTR:
//
// Go through and free each of the values.
//
if (umiProperty.pUmiValue->pszStrValue[ulCtr]) {
FreeADsStr(umiProperty.pUmiValue->pszStrValue[ulCtr]);
umiProperty.pUmiValue->pszStrValue[ulCtr] = NULL;
}
break;
case UMI_TYPE_BOOL:
case UMI_TYPE_I4:
case UMI_TYPE_FILETIME:
case UMI_TYPE_SYSTEMTIME:
case UMI_TYPE_I8:
//
// In all these cases nothing much to free except the value array
//
break;
case UMI_TYPE_OCTETSTRING:
//
// Go through and free each of the values.
//
if (umiProperty.pUmiValue->octetStr[ulCtr].lpValue) {
FreeADsMem(umiProperty.pUmiValue->octetStr[ulCtr].lpValue);
umiProperty.pUmiValue->octetStr[ulCtr].lpValue = NULL;
}
break;
case UMI_TYPE_IUNKNOWN:
//
// Need to release the ptr and Free the riid.
//
UMI_COM_OBJECT ComObject;
if (umiProperty.pUmiValue->comObject) {
ComObject = umiProperty.pUmiValue->comObject[ulCtr];
if (ComObject.pInterface) {
((IUnknown*)ComObject.pInterface)->Release();
ComObject.pInterface = NULL;
}
if (ComObject.priid) {
FreeADsMem((void *)ComObject.priid);
ComObject.priid = NULL;
}
}
break;
default:
//
// UmiType that we do not know anything about ??
//
ADsAssert(!"Unknown umitype in free memory");
RRETURN(E_ADS_BAD_PARAMETER);
break;
} // end of case
} // end of for
//
// Free the array of values now
//
if (umiProperty.pUmiValue) {
FreeADsMem( (void *)umiProperty.pUmiValue);
umiProperty.pUmiValue = NULL;
}
RRETURN(S_OK);
}
//+---------------------------------------------------------------------------
// Function: FreeUmiPropertyValues -- Global scope.
//
// Synopsis: Walk through and free all information being pointed to
// including the values.
//
// Arguments: self explanatory
//
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
HRESULT FreeUmiPropertyValues(UMI_PROPERTY_VALUES *pUmiProps)
{
HRESULT hr = S_OK;
if (pUmiProps) {
__try {
//
// Go through and free each property in the list
//
for (ULONG ulCtr = 0; ulCtr < pUmiProps->uCount; ulCtr++) {
hr = FreeOneUmiProperty(pUmiProps->pPropArray[ulCtr]);
}
//
// Free the inner array.
//
if (pUmiProps->pPropArray) {
FreeADsMem(pUmiProps->pPropArray);
}
//
// Free the array itself.
//
FreeADsMem( (LPVOID) pUmiProps);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
hr = E_INVALIDARG;
}
}
else {
hr = E_INVALIDARG;
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: ConvertUmiPropCodeToLdapCode -- Global scope.
//
// Synopsis: Convert the property code appropriately.
//
// Arguments: umiFlags - the umiPropCode,
// dwLdapOpCode& - byRef return value.
//
// Returns: HRESULT - S_OK or E_ADS_BAD_PARAMETER
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
HRESULT ConvertUmiPropCodeToLdapCode(ULONG umiFlags, DWORD& dwLdapOpCode)
{
HRESULT hr = S_OK;
switch (umiFlags) {
case UMI_OPERATION_APPEND:
dwLdapOpCode = PROPERTY_ADD;
break;
case UMI_OPERATION_UPDATE:
dwLdapOpCode = PROPERTY_UPDATE;
break;
case UMI_OPERATION_EMPTY:
dwLdapOpCode = PROPERTY_DELETE;
break;
case UMI_OPERATION_DELETE_ALL_MATCHES:
dwLdapOpCode = PROPERTY_DELETE_VALUE;
break;
default:
//
// we do not handle these values.
// UMI_OPERATION_INSERT_AT
// UMI_OPERATION_REMOVE_AT
// UMI_OPERATION_DELETE_AT
// UMI_OPERATION_DELETE_FIRST_MATCH
// UMI_OPERATION_DELETE_ALL_MATCHES
//
hr = UMI_E_UNSUPPORTED_OPERATION;
break;
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: ConvertLdapCodeToUmiPropCode -- Global scope.
//
// Synopsis: Convert the property code appropriately.
//
// Arguments: dwLdapOpCode& - property cache operation code.
// umiFlags& - byRef return value.
//
// Returns: HRESULT - S_OK or E_ADS_BAD_PARAMETER
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
HRESULT
ConvertLdapCodeToUmiPropCode(
DWORD dwLdapCode,
ULONG &uUmiFlags
)
{
HRESULT hr = S_OK;
switch (dwLdapCode) {
case PROPERTY_ADD:
uUmiFlags = UMI_OPERATION_APPEND;
break;
case PROPERTY_UPDATE:
uUmiFlags = UMI_OPERATION_UPDATE;
break;
case PROPERTY_DELETE:
uUmiFlags = UMI_OPERATION_EMPTY;
break;
case PROPERTY_DELETE_VALUE:
uUmiFlags = UMI_OPERATION_DELETE_ALL_MATCHES;
break;
case 0:
//
// special case values that are just in the cache.
//
uUmiFlags = 0;
break;
default:
hr = E_ADS_BAD_PARAMETER;
break;
}
RRETURN(hr);
}
//****************************************************************************
//
//Internal helpers - restricted scope
//
//****************************************************************************
//+---------------------------------------------------------------------------
// Function: ConvertVariantLongToUmiProp.
//
// Synopsis: Convert the variant to a corresponding UmiProp.
//
// Arguments: vVariant - variant containg long val to convert.
// ppProp - Output UmiPropertyValues.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: *pProp to point to valid UMI_PROPERTY_VALUES.
//
//----------------------------------------------------------------------------
HRESULT
ConvertVariantLongToUmiProp(
VARIANT vVariant,
UMI_PROPERTY_VALUES **ppProp
)
{
HRESULT hr = S_OK;
LONG *pLArray = NULL;
*ppProp = (PUMI_PROPERTY_VALUES) AllocADsMem(sizeof(UMI_PROPERTY_VALUES));
if (!*ppProp) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
(*ppProp)->pPropArray =
(UMI_PROPERTY *) AllocADsMem(sizeof(UMI_PROPERTY));
if (!((*ppProp)->pPropArray)) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
(*ppProp)->uCount = 1;
(*ppProp)->pPropArray[0].uType = UMI_TYPE_I4;
(*ppProp)->pPropArray[0].uCount = 1;
pLArray = (LONG *) AllocADsMem(sizeof(LONG) * 1);
if (!pLArray) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
pLArray[0] = vVariant.lVal;
(*ppProp)->pPropArray[0].pUmiValue = (UMI_VALUE *)(void *)pLArray;
error :
if (FAILED(hr)) {
if (pLArray) {
FreeADsMem( (void*) pLArray);
}
FreeUmiPropertyValues(*ppProp);
}
RRETURN(hr);
}
HRESULT
GetEmptyLPWSTRProp(UMI_PROPERTY_VALUES **ppProp)
{
HRESULT hr = S_OK;
*ppProp = (PUMI_PROPERTY_VALUES) AllocADsMem(sizeof(UMI_PROPERTY_VALUES));
if (!*ppProp) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
(*ppProp)->pPropArray =
(UMI_PROPERTY *) AllocADsMem(sizeof(UMI_PROPERTY));
if (!((*ppProp)->pPropArray)) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
(*ppProp)->uCount = 1;
(*ppProp)->pPropArray[0].uType = UMI_TYPE_LPWSTR;
(*ppProp)->pPropArray[0].uCount = 0;
(*ppProp)->pPropArray[0].pUmiValue = NULL;
error :
if (FAILED(hr)) {
FreeUmiPropertyValues(*ppProp);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: ConvertBSTRToUmiProp.
//
// Synopsis: Convert the bstr to a corresponding UmiProp.
//
// Arguments: bstrStringVal - String to convert to umi values.
// ppProp - Output UmiPropertyValues.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: *pProp to point to valid UMI_PROPERTY_VALUES.
//
//----------------------------------------------------------------------------
HRESULT
ConvertBSTRToUmiProp(
BSTR bstrStringVal,
UMI_PROPERTY_VALUES **ppProp
)
{
HRESULT hr = S_OK;
LPWSTR * pszStrArray = NULL;
LPWSTR pszTmpStr = NULL;
*ppProp = (PUMI_PROPERTY_VALUES) AllocADsMem(sizeof(UMI_PROPERTY_VALUES));
if (!*ppProp) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
(*ppProp)->pPropArray =
(UMI_PROPERTY *) AllocADsMem(sizeof(UMI_PROPERTY));
if (!((*ppProp)->pPropArray)) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
(*ppProp)->uCount = 1;
(*ppProp)->pPropArray[0].uType = UMI_TYPE_LPWSTR;
(*ppProp)->pPropArray[0].uCount = 1;
pszStrArray = (LPWSTR *) AllocADsMem(sizeof(LPWSTR) * 1);
if (!pszStrArray) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// If the value is NULL, then we return an array with a NULL
// value as the result.
//
if (bstrStringVal) {
pszStrArray[0] = AllocADsStr(bstrStringVal);
if (!pszStrArray[0]) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
}
(*ppProp)->pPropArray[0].pUmiValue = (UMI_VALUE *)(void *)pszStrArray;
error :
if (FAILED(hr)) {
if (pszStrArray) {
FreeADsMem( (void*) pszStrArray);
}
FreeUmiPropertyValues(*ppProp);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: ConvertIUnkToUmiProp.
//
// Synopsis: Convert the IUnk to a corresponding UmiProp.
//
// Arguments: pUnk - IUnk ptr.
// iid - iid of the ptr.
// ppProp - Output UmiPropertyValues.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: *pProp to point to valid UMI_PROPERTY_VALUES.
//
//----------------------------------------------------------------------------
HRESULT
ConvertIUnkToUmiProp(
IUnknown * pUnk,
IID iid,
UMI_PROPERTY_VALUES **ppProp
)
{
HRESULT hr = S_OK;
PUMI_COM_OBJECT pComObjArray = NULL;
*ppProp = (PUMI_PROPERTY_VALUES) AllocADsMem(sizeof(UMI_PROPERTY_VALUES));
if (!*ppProp) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
(*ppProp)->pPropArray =
(UMI_PROPERTY *) AllocADsMem(sizeof(UMI_PROPERTY));
if (!((*ppProp)->pPropArray)) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
(*ppProp)->uCount = 1;
(*ppProp)->pPropArray[0].uType = UMI_TYPE_IUNKNOWN;
(*ppProp)->pPropArray[0].uCount = 1;
pComObjArray = (PUMI_COM_OBJECT) AllocADsMem(sizeof(UMI_COM_OBJECT) * 1);
if (!pComObjArray) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
hr = pUnk->QueryInterface(
iid,
(void **) &(pComObjArray[0].pInterface)
);
BAIL_ON_FAILURE(hr);
pComObjArray[0].priid = (IID *) AllocADsMem(sizeof(IID));
if (!pComObjArray[0].priid) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
memcpy(pComObjArray[0].priid, &iid, sizeof(IID));
(*ppProp)->pPropArray[0].pUmiValue = (UMI_VALUE *)(void *)pComObjArray;
error :
if (FAILED(hr)) {
if (pComObjArray) {
if (pComObjArray[0].pInterface) {
((IUnknown *)pComObjArray[0].pInterface)->Release();
}
FreeADsMem( (void*) pComObjArray);
}
FreeUmiPropertyValues(*ppProp);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: HelperGetUmiRelUrl.
//
// Synopsis: Gets the __RELURL property for the object. This routine
// combines the IADs::get_Name and IADs::get_Class
//
// Arguments: pIADs - Pointer to obj implementing IADs.
// bstrRetVal - Pointer for retrun bstr value.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: *pProp to point to valid UMI_PROPERTY_VALUES.
//
//----------------------------------------------------------------------------
HRESULT
HelperGetUmiRelUrl(
IADs * pIADs,
BSTR * bstrRetVal
)
{
HRESULT hr = S_OK;
BSTR bstrName = NULL, bstrClass = NULL;
LPWSTR pszTempVal = NULL;
BOOL fSchemaObject = FALSE;
hr = pIADs->get_Name(&bstrName);
BAIL_ON_FAILURE(hr);
hr = pIADs->get_Class(&bstrClass);
BAIL_ON_FAILURE(hr);
//
// See if this is a schema object.
//
if (!_wcsicmp(bstrClass, L"Schema")
|| !_wcsicmp(bstrClass, L"Class")
|| !_wcsicmp(bstrClass, L"Property")
)
{
LPWSTR pszTemp;
//
// If this is indeed a schema object then the name
// wont have any = sign in it. Equal is not allowed
// in the names of schema objects.
//
if ((pszTemp = wcschr(bstrName, L'=')) == NULL)
fSchemaObject = TRUE;
}
//
// Add 2 as we need 1 for the \0 and the other for the .
// in class.name
//
DWORD dwLen;
dwLen = wcslen(bstrName) + wcslen(bstrClass) + 2;
if (fSchemaObject) {
//
// Need to add space for .Name
//
dwLen = dwLen + 6;
}
pszTempVal = (LPWSTR) AllocADsMem(dwLen * sizeof(WCHAR));
if (!pszTempVal) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
if (!fSchemaObject) {
wsprintf(pszTempVal, L"%s.%s", bstrClass, bstrName);
}
else {
wsprintf(pszTempVal, L"%s.Name=%s", bstrClass, bstrName);
}
hr = ADsAllocString(pszTempVal, bstrRetVal);
BAIL_ON_FAILURE(hr);
error:
if (bstrName) {
SysFreeString(bstrName);
}
if (bstrClass) {
SysFreeString(bstrClass);
}
if (pszTempVal) {
FreeADsStr(pszTempVal);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: HelperGetUmiSchemaContainerPath.
//
// Synopsis: Gets the Umi path to the schema container for this object.
//
// Arguments: pIADs - Pointer to obj implementing IADs.
// bstrRetVal - Pointer for retrun bstr value.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: *bstrRetVal points to the correct schema path.
//
//----------------------------------------------------------------------------
HRESULT
HelperGetUmiSchemaContainerPath(
IADs * pIADs,
BSTR * bstrRetVal
)
{
HRESULT hr = S_OK;
BSTR bstrSchema = NULL;
LPWSTR pszParent = NULL, pszCN = NULL, pszUmiSchema = NULL;
//
// First we need the path of the schema object itslef.
//
hr = pIADs->get_Schema(&bstrSchema);
BAIL_ON_FAILURE(hr);
//
// Now we can build the path to the schema container from the path.
//
hr = BuildADsParentPath(
bstrSchema,
&pszParent,
&pszCN
);
BAIL_ON_FAILURE(hr);
hr = ADsPathToUmiURL(pszParent, &pszUmiSchema);
BAIL_ON_FAILURE(hr);
hr = ADsAllocString(pszUmiSchema, bstrRetVal);
BAIL_ON_FAILURE(hr);
error:
if (bstrSchema) {
SysFreeString(bstrSchema);
}
if (pszCN) {
FreeADsStr(pszCN);
}
if (pszParent) {
FreeADsStr(pszParent);
}
if (pszUmiSchema) {
FreeADsStr(pszUmiSchema);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: HelperGetUmiDerivedFrom.
//
// Synopsis: Gets the value of the class that the current class object
// is derived from.
//
// Arguments: pIADs - Pointer to obj implementing IADs.
// bstrRetVal - Pointer for retrun bstr value.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: *bstrRetVal points to the correct schema path.
//
//----------------------------------------------------------------------------
HRESULT
HelperGetUmiDerivedFrom(
IADs * pIADs,
BSTR * pbstrRetVal
)
{
HRESULT hr = S_OK;
IADsClass *pClass = NULL;
BSTR bstrName = NULL;
VARIANT vVariant;
VariantInit(&vVariant);
*pbstrRetVal = NULL;
hr = pIADs->get_Name(&bstrName);
BAIL_ON_FAILURE(hr);
//
// If the class is Top then we just return NULL.
//
if (_wcsicmp(bstrName, L"Top")) {
//
// Get the IADsClass interface, this is done because IADs::Get
// will need to ask for different attributes based on the server.
// IADsClass encapsulates this difference for us.
//
hr = pIADs->QueryInterface(IID_IADsClass, (void **) &pClass);
if (FAILED(hr)) {
BAIL_ON_FAILURE(hr = E_FAIL);
}
hr = pClass->get_DerivedFrom(&vVariant);
BAIL_ON_FAILURE(hr);
ADsAssert(vVariant.vt == VT_BSTR);
hr = ADsAllocString(vVariant.bstrVal, pbstrRetVal);
}
BAIL_ON_FAILURE(hr);
error:
VariantClear(&vVariant);
if (bstrName) {
SysFreeString(bstrName);
}
if (pClass) {
pClass->Release();
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: HelperConvertNameToKey.
//
// Synopsis: Converts the value of the BSTR (of the form cn=test) to cn
// as required by UMI.
//
// Arguments: bstrName - Value to get the key from.
// pszUmiKey - Return value for the key.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: *pszUmiUrl points to the key.
//
//----------------------------------------------------------------------------
HRESULT
HelperConvertNameToKey(
BSTR bstrName,
LPWSTR * pszUmiUrl
)
{
HRESULT hr = S_OK;
LPWSTR pszTemp = bstrName;
BOOL fEqualFound = FALSE;
DWORD dwCount = 0;
ADsAssert(bstrName && pszTemp && *pszTemp);
while (pszTemp
&& *pszTemp
&& (!fEqualFound)
) {
if (*pszTemp == L'=') {
fEqualFound = TRUE;
}
dwCount++;
pszTemp++;
}
if (!fEqualFound) {
BAIL_ON_FAILURE(hr = E_ADS_PROPERTY_NOT_FOUND);
}
*pszUmiUrl = (LPWSTR) AllocADsMem(dwCount * sizeof(WCHAR));
if (!*pszUmiUrl) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
wcsncpy(*pszUmiUrl, bstrName, (dwCount-1));
error:
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: HelperUpdateSDFlags.
//
// Synopsis: On put/get calls updates the security flags appropriately.
//
// Arguments: pIADs - IADs pointer to use to update sd.
// uFlags - Flags to use for getting SD.
// pfUpdated - Return boolean value.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: Underlying property cache and pfUpdated to TRUE if the
// flags on the object had to be changed and FALSE otherwise.
//
//----------------------------------------------------------------------------
HRESULT
HelperUpdateSDFlags(
IADs *pIADs,
ULONG uFlags,
BOOL *pfUpdated = NULL
)
{
HRESULT hr = S_OK;
IADsObjOptPrivate *pPrivOpt = NULL;
SECURITY_INFORMATION secInfo;
ADsAssert(pIADs);
if (pfUpdated) {
*pfUpdated = FALSE;
}
//
// Get the objOpt intf and make sure the flags are right.
//
hr = pIADs->QueryInterface(IID_IADsObjOptPrivate, (void **) &pPrivOpt);
BAIL_ON_FAILURE(hr);
hr = pPrivOpt->GetOption(
LDAP_SECURITY_MASK,
(void *) &secInfo
);
BAIL_ON_FAILURE(hr);
if (secInfo != uFlags) {
//
// We need to update the security mask on the object.
//
hr = pPrivOpt->SetOption(
LDAP_SECURITY_MASK,
(void **) &uFlags
);
BAIL_ON_FAILURE(hr);
//
// Need to let caller know that the flags have changed.
//
if (pfUpdated) {
*pfUpdated = TRUE;
}
}
error:
if (pPrivOpt) {
pPrivOpt->Release();
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: HelperGetSDIntoCache.
//
// Synopsis: Reads the sd into the property cache using the appropriate
// flags as needed.
//
// Arguments: pIADs - IADs pointer to use to update sd.
// uFlags - Flags to use for getting SD.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: Underlying property cache.
//
//----------------------------------------------------------------------------
HRESULT HelperGetSDIntoCache(
IADs * pIADs,
ULONG uFlags
)
{
HRESULT hr = S_OK;
VARIANT vVar;
BOOL fUpdated = FALSE;
LPWSTR szSecDesc[] = {L"ntSecurityDescriptor"};
VariantInit(&vVar);
hr = HelperUpdateSDFlags(
pIADs,
(uFlags & UMI_SECURITY_MASK),
&fUpdated
);
BAIL_ON_FAILURE(hr);
if (fUpdated) {
//
// Update just the SD by calling GetInfoEx.
//
hr = ADsBuildVarArrayStr(
szSecDesc,
1,
&vVar
);
BAIL_ON_FAILURE(hr);
hr = pIADs->GetInfoEx(vVar, 0);
BAIL_ON_FAILURE(hr);
}
error :
VariantClear(&vVar);
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: HelperGetOrigin.
//
// Synopsis: Gets the originating class for the property in question.
//
// Arguments: pIADs - IADs pointer to backing object.
// pszName - Name of the property whose origin is needed.
// ppProp - Return value.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
HRESULT
HelperGetOrigin(
IADs *pIADs,
LPCWSTR pszName,
UMI_PROPERTY_VALUES **ppProp
)
{
HRESULT hr = S_OK;
IADsUmiHelperPrivate *pHelper = NULL;
BSTR bstrVal = NULL;
hr = pIADs->QueryInterface(
IID_IADsUmiHelperPrivate,
(void **) &pHelper
);
if (FAILED(hr)) {
//
// This object does not support this property as it is not
// a class object.
//
BAIL_ON_FAILURE(hr = E_ADS_PROPERTY_NOT_FOUND);
}
hr = pHelper->GetOriginHelper(
pszName,
&bstrVal
);
BAIL_ON_FAILURE(hr);
hr = ConvertBSTRToUmiProp(
bstrVal,
ppProp
);
error:
if (bstrVal) {
SysFreeString(bstrVal);
}
if (pHelper) {
pHelper->Release();
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CopyUmiProperty.
//
// Synopsis: Copy the input value into a newly allocated output buffer.
// Note that since this is an internal routine assumptions are made
// as to the data. Currently handles only UMI_TYPE_LPWSTR,
// UMI_TYPE_I4 and UMI_TYPE_BOOL. If multivalued, we can only copy
// strings (things like filter on enum can be multi-valued).
//
// Arguments: umiProp - Umi property value to copy.
// ppUmiProp - Return value for new umi property.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: *ppUmiProp to point to valid UMI_PROPERTY.
//
//----------------------------------------------------------------------------
HRESULT
CopyUmiProperty(
UMI_PROPERTY umiProp,
PUMI_PROPERTY *ppUmiProp
)
{
HRESULT hr = S_OK;
UMI_PROPERTY *pUmiPropLocal = NULL;
ULONG ulUmiType = umiProp.uType;
ULONG ulPropCount = umiProp.uCount;
*ppUmiProp = NULL;
//
// Multi valued has to be string.
//
if ((ulPropCount > 1) && (ulUmiType != UMI_TYPE_LPWSTR)) {
BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
}
pUmiPropLocal = (UMI_PROPERTY *) AllocADsMem(sizeof(UMI_PROPERTY));
if (!pUmiPropLocal) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
pUmiPropLocal->pszPropertyName = AllocADsStr(umiProp.pszPropertyName);
if (!pUmiPropLocal->pszPropertyName) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
pUmiPropLocal->uOperationType = umiProp.uOperationType;
pUmiPropLocal->uType = umiProp.uType;
switch (umiProp.uType) {
case UMI_TYPE_LPWSTR :
LPWSTR *pszTmpArray;
pszTmpArray = (LPWSTR *) AllocADsMem(sizeof(LPWSTR) * ulPropCount);
if (!pszTmpArray) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
for (DWORD dwCtr = 0; dwCtr < ulPropCount; dwCtr++) {
pszTmpArray[dwCtr] = AllocADsStr(
umiProp.pUmiValue->pszStrValue[dwCtr]
);
if (!pszTmpArray[dwCtr]) {
//
// NULL is allowed as a value only if it is the
// only value being set.
//
if (ulPropCount != 1
|| umiProp.pUmiValue->pszStrValue[dwCtr]
) {
//
// Cleanup and exit.
//
for (DWORD dwCtr2 = 0; dwCtr2 < dwCtr; dwCtr2++) {
if (pszTmpArray[dwCtr2]) {
FreeADsStr(pszTmpArray[dwCtr2]);
pszTmpArray[dwCtr2] = NULL;
}
}
FreeADsMem(pszTmpArray);
pszTmpArray = NULL;
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
} // if alloc failed in middle of array.
}
pUmiPropLocal->pUmiValue = (PUMI_VALUE) (void *) pszTmpArray;
break;
case UMI_TYPE_I4:
LONG *pLongArray;
pLongArray = (LONG *) AllocADsMem(sizeof(LONG) * 1);
if (!pLongArray) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
pLongArray[0] = umiProp.pUmiValue->lValue[0];
pUmiPropLocal->pUmiValue = (PUMI_VALUE) (void *) pLongArray;
break;
case UMI_TYPE_BOOL:
BOOL *pBoolArray;
pBoolArray = (BOOL *) AllocADsMem(sizeof(BOOL) * 1);
if (!pBoolArray) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
pBoolArray[0] = umiProp.pUmiValue->bValue[0];
pUmiPropLocal->pUmiValue = (PUMI_VALUE) (void *) pBoolArray;
break;
default:
BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
break;
}
pUmiPropLocal->uCount = ulPropCount;
*ppUmiProp = pUmiPropLocal;
RRETURN(hr);
error:
//
// Cleanup cause we hit an error.
//
if (pUmiPropLocal) {
FreeOneUmiProperty(*pUmiPropLocal);
FreeADsMem( (void*) pUmiPropLocal);
}
RRETURN(hr);
}
//****************************************************************************
//
//CPropertyManager Methods.
//
//****************************************************************************
//+---------------------------------------------------------------------------
// Function: CPropertyManager::CPropertyManager
//
// Synopsis: Constructor
//
// Arguments: None
//
// Returns: N/A
//
// Modifies: N/A
//
//----------------------------------------------------------------------------
CPropertyManager::CPropertyManager():
_dwMaxProperties(0),
_pPropCache(NULL),
_pIntfProperties(NULL),
_dwMaxLimit(0),
_fPropCacheMode(TRUE),
_pStaticPropData(NULL),
_ulStatus(0),
_pIADs(NULL),
_pUnk(NULL),
_pCreds(NULL),
_pszServerName(NULL)
{
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::~CPropertyManager
//
// Synopsis: Destructor
//
// Arguments: None
//
// Returns: N/A
//
// Modifies: N/A
//
//----------------------------------------------------------------------------
CPropertyManager::~CPropertyManager()
{
//
// Need to cleanup inftProps table
//
if (_pIntfProperties) {
DWORD dwCtr;
for (dwCtr = 0; dwCtr < _dwMaxProperties; dwCtr++) {
//
// Free each of the entries and their contents.
//
PINTF_PROPERTY pIntfProp = &(_pIntfProperties[dwCtr]);
if (pIntfProp->pszPropertyName) {
FreeADsStr(pIntfProp->pszPropertyName);
pIntfProp->pszPropertyName = NULL;
}
if (pIntfProp->pUmiProperty) {
FreeOneUmiProperty(*(pIntfProp->pUmiProperty));
FreeADsMem(pIntfProp->pUmiProperty);
pIntfProp->pUmiProperty = NULL;
}
}
FreeADsMem(_pIntfProperties);
}
_pIntfProperties = NULL;
//
// The rest of the stuff is taken care of when the
// destructor to the IADs obj is called. This object
// itself will be released only in the destructor of the
// IADs object is called.
//
_pPropCache = NULL;
if (_pIADs) {
_pIADs->Release();
}
_pIADs = NULL;
_dwMaxProperties = 0;
//
// Do not free as these are owned by the owning object.
//
_pszServerName = NULL;
_pCreds = NULL;
_pUnk = NULL;
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::CreatePropertyManager (overloaded)
//
// Synopsis: Static allocation routine (property cache mode).
//
// Arguments: IADs* - pointer to IADs implementor object.
// pUnk - owning object unknown.
// pPropCache - pointer to propertyCache used by object.
// pCredentials - pointer to credentials.
// pszServerName - pointer to servername.
// ppPropertyManager - return ptr for new prop mgr.
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: CPropertyManager ** - ptr to newly created object.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::CreatePropertyManager(
IADs *pADsObj,
IUnknown *pUnk,
CPropertyCache *pPropCache,
CCredentials *pCredentials,
LPWSTR pszServerName,
CPropertyManager FAR * FAR * ppPropertyManager
)
{
CPropertyManager FAR * pPropMgr = NULL;
pPropMgr = new CPropertyManager();
if (!pPropMgr) {
RRETURN_EXP_IF_ERR(E_OUTOFMEMORY);
}
if (pADsObj) {
pADsObj->QueryInterface(IID_IADs, (void**) &(pPropMgr->_pIADs));
}
pPropMgr->_pUnk = pUnk;
pPropMgr->_pPropCache = pPropCache;
pPropMgr->_fPropCacheMode = TRUE;
pPropMgr->_pIntfProperties = NULL;
pPropMgr->_pszServerName = pszServerName;
pPropMgr->_pCreds = pCredentials;
*ppPropertyManager = pPropMgr;
RRETURN(S_OK);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::CreatePropertyManager (overloaded)
//
// Synopsis: Static allocation routine (interface properties mode).
//
// Arguments: pUnk - pointer to owner (umi) object.
// pIADs - pointer to IADs implementor.
// pCredentials - pointer to credentials.
// pTable - property table.
// ppPropertyManager - return value for new prop mgr.
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: CPropertyManager ** - ptr to newly created object.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::CreatePropertyManager(
IUnknown *pUnk,
IUnknown *pIADs,
CCredentials *pCredentials,
INTF_PROP_DATA pTable[],
CPropertyManager FAR * FAR * ppPropertyManager
)
{
CPropertyManager FAR * pPropMgr = NULL;
pPropMgr = new CPropertyManager();
if (!pPropMgr) {
RRETURN_EXP_IF_ERR(E_OUTOFMEMORY);
}
pPropMgr->_pUnk = pUnk;
//
// We can ignore any failures here.
//
if (pIADs) {
pIADs->QueryInterface(IID_IADs, (void**) &(pPropMgr->_pIADs));
}
pPropMgr->_pPropCache = NULL;
pPropMgr->_fPropCacheMode = FALSE;
pPropMgr->_pIntfProperties = NULL;
pPropMgr->_pCreds = pCredentials;
pPropMgr->_pStaticPropData = pTable;
*ppPropertyManager = pPropMgr;
RRETURN(S_OK);
}
STDMETHODIMP
CPropertyManager::QueryInterface(REFIID iid, LPVOID FAR* ppv)
{
HRESULT hr = S_OK;
SetLastStatus(0);
if (ppv == NULL) {
RRETURN(E_POINTER);
}
if (IsEqualIID(iid, IID_IUnknown)){
*ppv = (IUnknown FAR *) this;
}
else if (IsEqualIID(iid, IID_IUmiPropList)) {
*ppv = (IUmiPropList FAR *) this;
}
else {
*ppv = NULL;
SetLastStatus(E_NOINTERFACE);
return E_NOINTERFACE;
}
AddRef();
return NOERROR;
}
//
// Methods defined on the proplist interface.
//
//+---------------------------------------------------------------------------
// Function: CPropertyManager::Put (IUmiPropList support).
//
// Synopsis: Sets the value for the attribute in the cache.
//
// Arguments: self explanatory
//
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: PropertyCache or internal interface property list.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CPropertyManager::Put(
IN LPCWSTR pszName,
IN ULONG uFlags,
IN UMI_PROPERTY_VALUES *pProp
)
{
HRESULT hr = S_OK;
LDAPOBJECTARRAY ldapDestObjects;
DWORD dwOperationFlags = 0;
BOOL fSecurityFlags = FALSE;
IUmiObject *pUmiObj = NULL;
BOOL fInternalPut = FALSE;
SetLastStatus(0);
//
// Initialize so that we are not trying to free junk.
//
if (_fPropCacheMode) {
LDAPOBJECTARRAY_INIT(ldapDestObjects);
}
//
// Pre process and pull out the highest flag, all these
// because we are not allowed to support Put with 0.
//
if (uFlags & 0x8000000) {
uFlags &= 0x4000000;
fInternalPut = TRUE;
}
if (uFlags > UMI_SECURITY_MASK) {
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
}
if (!pProp || !pszName) {
BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
}
if (uFlags & UMI_SECURITY_MASK) {
fSecurityFlags = TRUE;
}
//
// We support only putting one property at a time.
//
if (pProp->uCount != 1) {
BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
}
//
// Make sure that the data passed in is correct.
//
if (!pProp->pPropArray
|| !pProp->pPropArray[0].pszPropertyName) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
if (_fPropCacheMode) {
DWORD dwLdapSyntaxId = 1;
if (fInternalPut
&& pProp->pPropArray[0].uOperationType == 0) {
dwOperationFlags = 0;
}
else {
//
// Verify that the operationType is something we support.
//
hr = ConvertUmiPropCodeToLdapCode(
pProp->pPropArray[0].uOperationType,
dwOperationFlags
);
BAIL_ON_FAILURE(hr);
}
if (fSecurityFlags) {
//
// Only this ntSecurityDescriptor can use the security flags.
//
if (_wcsicmp(L"ntSecurityDescriptor", pszName)) {
BAIL_ON_FAILURE(hr = E_FAIL);
}
hr = HelperUpdateSDFlags(
_pIADs,
uFlags & UMI_SECURITY_MASK
);
BAIL_ON_FAILURE(hr);
}
//
// In this case we need to convert data to ldap values and
// store in cache.
//
hr = UmiTypeToLdapTypeCopy(
*pProp,
uFlags,
&ldapDestObjects,
dwLdapSyntaxId, // byRef
_pCreds,
_pszServerName
);
BAIL_ON_FAILURE(hr);
//
// PutpropertyExt will add to the cache if needed.
//
hr = _pPropCache->putpropertyext(
(LPWSTR)pszName,
dwOperationFlags,
dwLdapSyntaxId,
ldapDestObjects
);
BAIL_ON_FAILURE(hr);
}
else {
//
// Local cache for interface properties. Verify property is
// legal and update the local information accordingly.
//
if (VerifyIfValidProperty(
pProp->pPropArray[0].pszPropertyName,
pProp->pPropArray[0]
)
) {
if (fSecurityFlags
|| !_wcsicmp(pszName, L"__SECURITY_DESCRIPTOR")
) {
//
// Make sure name is correct.
//
if (_wcsicmp(L"__SECURITY_DESCRIPTOR", pszName)) {
BAIL_ON_FAILURE(hr = E_FAIL);
}
//
// We need turn around and call put on the owning object.
// This means we need to package the UMI_PROPERTY_VALUES
// accordingly.
//
UMI_PROPERTY pUmiProperty[] = {
pProp->pPropArray[0].uType,
pProp->pPropArray[0].uCount,
pProp->pPropArray[0].uOperationType,
L"ntSecurityDescriptor",
pProp->pPropArray[0].pUmiValue
};
UMI_PROPERTY_VALUES pUmiProp[] = {1, pUmiProperty};
hr = _pUnk->QueryInterface(
IID_IUmiObject,
(void **) &pUmiObj
);
BAIL_ON_FAILURE(hr);
hr = pUmiObj->Put(
L"ntSecurityDescriptor",
uFlags,
pUmiProp
);
BAIL_ON_FAILURE(hr);
}
else {
//
// We need to update this value in our cache
//
hr = AddProperty(
pszName,
pProp->pPropArray[0]
);
BAIL_ON_FAILURE(hr);
}
} // not valid property.
else {
BAIL_ON_FAILURE(hr = E_FAIL);
}
}
error :
//
// Free ldapDestObjects if applicable.
//
if (_fPropCacheMode) {
LdapTypeFreeLdapObjects( &ldapDestObjects );
}
if (pUmiObj) {
pUmiObj->Release();
}
if (FAILED(hr)) {
SetLastStatus(hr);
hr = MapHrToUmiError(hr);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::Get (IUmiPropList support).
//
// Synopsis: Gets the value for the attribute. This will read data
// from the server as needed.
//
// Arguments: self explanatory
//
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: UMI_PROPERTY_VALUES* has the values of the attribute.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CPropertyManager::Get(
IN LPCWSTR pszName,
IN ULONG uFlags,
OUT UMI_PROPERTY_VALUES **pProp
)
{
HRESULT hr = S_OK;
ULONG uUmiFlag;
LDAPOBJECTARRAY ldapSrcObjects;
BOOL fSecurityFlag = FALSE;
BOOL fSchemaFlag = FALSE;
IADsObjOptPrivate *pPrivOpt = NULL;
SetLastStatus(0);
LDAPOBJECTARRAY_INIT(ldapSrcObjects);
if (!pProp) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
*pProp = NULL;
//
// Currently this is the highest flag we support.
//
if (uFlags > UMI_FLAG_PROPERTY_ORIGIN) {
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
}
else if (uFlags & UMI_SECURITY_MASK) {
fSecurityFlag = TRUE;
}
else if (uFlags == UMI_FLAG_PROPERTY_ORIGIN) {
fSchemaFlag = TRUE;
}
if (fSchemaFlag && fSecurityFlag) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
//
// Name cannot be NULL.
//
if (!pszName) {
BAIL_ON_FAILURE(hr = E_INVALIDARG)
}
//
// If this is Property Manager is for server properties.
//
if (_fPropCacheMode) {
DWORD dwSyntaxId;
DWORD dwStatus;
DWORD dwSecOptions;
if (fSchemaFlag) {
BAIL_ON_FAILURE(hr = UMI_E_UNSUPPORTED_FLAGS);
}
if (fSecurityFlag) {
if (_wcsicmp(L"ntSecurityDescriptor", pszName)) {
//
// Security flag used and attrib not securityDescriptor.
//
BAIL_ON_FAILURE(hr = E_FAIL);
}
else {
//
// Valid flag we need to process the flags.
//
hr = HelperGetSDIntoCache(
_pIADs,
uFlags
);
BAIL_ON_FAILURE(hr);
}
}
//
// Object maybe unbound, so we should return no such prop if
// we get back E_ADS_OBJECT_UNBOUND.
//
hr = _pPropCache->getproperty(
(LPWSTR)pszName,
&dwSyntaxId,
&dwStatus,
&ldapSrcObjects
);
if (hr == E_ADS_OBJECT_UNBOUND) {
hr = E_ADS_PROPERTY_NOT_FOUND;
}
BAIL_ON_FAILURE(hr);
hr = ConvertLdapCodeToUmiPropCode(dwStatus, uUmiFlag);
BAIL_ON_FAILURE(hr);
//
// Return error if provider cache is not set and
// the cache is dirty.
//
if (uUmiFlag && !(uFlags & UMI_FLAG_PROVIDER_CACHE)) {
BAIL_ON_FAILURE(hr = UMI_E_SYNCHRONIZATION_REQUIRED);
}
//
// At this point we might have ldapSrcObjects.pLdapObjects == NULL.
// Typically that would be for property delete operations.
//
hr = LdapTypeToUmiTypeCopy(
ldapSrcObjects,
pProp,
dwStatus,
dwSyntaxId,
_pCreds,
_pszServerName,
uUmiFlag
);
}
else {
//
// Property Manager is for interface properties.
//
DWORD dwIndex;
//
// If the schema flag is set then we need to get the origin
// and not the property itself.
//
if (fSchemaFlag) {
hr = HelperGetOrigin(
_pIADs,
pszName,
pProp
);
}
else {
//
// Make sure this property is valid.
//
hr = GetIndexInStaticTable(pszName, dwIndex); // dwIndex is byRef
BAIL_ON_FAILURE(hr);
hr = GetInterfaceProperty(
pszName,
uFlags,
pProp,
dwIndex
);
}
}
BAIL_ON_FAILURE(hr);
//
// Stuff the name in the return value.
//
if (pProp && *pProp) {
(*pProp)->pPropArray[0].pszPropertyName = AllocADsStr(pszName);
if (!(*pProp)->pPropArray[0].pszPropertyName) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
}
error:
if (_fPropCacheMode) {
LdapTypeFreeLdapObjects(&ldapSrcObjects);
}
if (FAILED(hr)) {
SetLastStatus(hr);
hr = MapHrToUmiError(hr);
if (pProp && *pProp) {
this->FreeMemory(0, (void *) *pProp);
*pProp = NULL;
}
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::GetAt (IUmiPropList support).
//
// Synopsis: Used to get the value by index ???
//
// Arguments: Not implemented
//
//
// Returns: E_NOTIMPL
//
// Modifies: Not implemented
//
//----------------------------------------------------------------------------
STDMETHODIMP
CPropertyManager::GetAt(
IN LPCWSTR pszName,
IN ULONG uFlags,
IN ULONG uBufferLength,
OUT LPVOID pExisitingMem
)
{
SetLastStatus(E_NOTIMPL);
RRETURN(E_NOTIMPL);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::GetAs (IUmiPropList support).
//
// Synopsis: Gets the value for the attribute in the specified format.
//
// Arguments: self explanatory
//
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: UMI_PROPERTY_VALUES* has the values of the attribute.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CPropertyManager::GetAs(
IN LPCWSTR pszName,
IN ULONG uFlags,
IN ULONG uCoercionType,
IN OUT UMI_PROPERTY_VALUES **pProp
)
{
HRESULT hr = S_OK;
LDAPOBJECTARRAY ldapSrcObjects;
LDAPOBJECTARRAY ldapSrcObjectsTmp;
LDAPOBJECTARRAY * pldapObjects = NULL;
ULONG uUmiFlag;
DWORD dwSyntaxId, dwStatus, dwRequestedSyntax;
DWORD dwCachedSyntax, dwUserSyntax;
SetLastStatus(0);
LDAPOBJECTARRAY_INIT(ldapSrcObjects);
LDAPOBJECTARRAY_INIT(ldapSrcObjectsTmp);
if (!pszName || !pProp) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
//
// Has to be in prop cache mode.
//
if (!_fPropCacheMode || !_pPropCache) {
BAIL_ON_FAILURE(hr = E_NOTIMPL);
}
if (uFlags > UMI_SECURITY_MASK) {
BAIL_ON_FAILURE(hr = UMI_E_UNSUPPORTED_FLAGS);
}
if (uFlags & UMI_SECURITY_MASK) {
//
// Make sure it is the SD they are interested in.
//
if (_wcsicmp(L"ntSecurityDescriptor", pszName)) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
//
// At this point we need to get the SD in the cache.
//
hr = HelperGetSDIntoCache(_pIADs, uFlags);
BAIL_ON_FAILURE(hr);
}
//
// Object maybe unbound, so we should return no such prop if
// we get back E_ADS_OBJECT_UNBOUND.
//
hr = _pPropCache->getproperty(
(LPWSTR)pszName,
&dwSyntaxId,
&dwStatus,
&ldapSrcObjects
);
if (hr == E_ADS_OBJECT_UNBOUND) {
hr = E_ADS_PROPERTY_NOT_FOUND;
}
BAIL_ON_FAILURE(hr);
//
// Get the appropriate umi code for the status.
//
hr = ConvertLdapCodeToUmiPropCode(dwStatus, uUmiFlag);
BAIL_ON_FAILURE(hr);
//
// At this point we need to see if we can convert the data
// to the format requested. This code is similar to that in
// proplist.cxx GetPropertyItem but there appears to be no
// easy way to avoid this duplication.
//
dwCachedSyntax = dwSyntaxId;
//
// Need to take the requested type to ADs types and from there to
// ldap types.
//
hr = UmiTypeToLdapTypeEnum(uCoercionType, &dwUserSyntax);
BAIL_ON_FAILURE(hr);
//
// We can convert to any requested type only if it is unknown.
//
if (dwCachedSyntax == LDAPTYPE_UNKNOWN) {
dwRequestedSyntax = dwUserSyntax;
}
else if (dwCachedSyntax == dwUserSyntax) {
//
// Easy one !
//
dwRequestedSyntax = dwCachedSyntax;
}
else {
//
// This means we already have a type. In this case the only
// coercion we allows is SD to binary blob and vice-versa.
//
if ((dwCachedSyntax == LDAPTYPE_SECURITY_DESCRIPTOR)
&& (dwUserSyntax == LDAPTYPE_OCTETSTRING)
) {
dwRequestedSyntax = dwUserSyntax;
}
else if ((dwCachedSyntax == LDAPTYPE_OCTETSTRING)
&& (dwUserSyntax == LDAPTYPE_SECURITY_DESCRIPTOR)
) {
dwRequestedSyntax = dwUserSyntax;
}
else {
BAIL_ON_FAILURE(hr = E_FAIL);
}
}
//
// If the data is in a state that needs conversion the fn will
// take care - note that if the source is already in the correct
// format then the HR will S_FALSE.
//
hr = LdapTypeBinaryToString(
dwRequestedSyntax,
&ldapSrcObjects,
&ldapSrcObjectsTmp
);
BAIL_ON_FAILURE(hr);
if (hr == S_OK) {
pldapObjects = &ldapSrcObjectsTmp;
}
else {
//
// We already have the data in the right format.
//
pldapObjects = &ldapSrcObjects;
hr = S_OK;
}
//
// Now that we have the correct data in pLdapObjects, we need
// to convert that to Umi Properties.
//
hr = LdapTypeToUmiTypeCopy(
*pldapObjects,
pProp,
dwStatus,
dwRequestedSyntax,
_pCreds,
_pszServerName,
uUmiFlag
);
BAIL_ON_FAILURE(hr);
//
// Stuff the name in the return value.
//
if (pProp) {
(*pProp)->pPropArray[0].pszPropertyName = AllocADsStr(pszName);
if (!(*pProp)->pPropArray[0].pszPropertyName) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
}
error:
if (_fPropCacheMode) {
LdapTypeFreeLdapObjects(&ldapSrcObjects);
LdapTypeFreeLdapObjects(&ldapSrcObjectsTmp);
}
if (FAILED(hr)) {
SetLastStatus(hr);
hr = MapHrToUmiError(hr);
if (pProp) {
this->FreeMemory(0, (void *)*pProp);
*pProp = NULL;
}
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::FreeMemory (IUmiPropList support).
//
// Synopsis: Free memory pointed to. Note that the pointer should have
// originally come from a Get/GetAs call.
//
// Arguments: Ptr to data to be freed.
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: *pMem is of course freed.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CPropertyManager::FreeMemory(
ULONG uReserved,
LPVOID pMem
)
{
HRESULT hr = S_OK;
SetLastStatus(0);
if (uReserved) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
if (pMem) {
//
// At this time this has to be a pUmiProperty. Ideally we should
// tag this in some way so that we can check to make sure.
//
hr = FreeUmiPropertyValues((UMI_PROPERTY_VALUES *)pMem);
}
else {
hr = E_INVALIDARG;
}
error:
if (FAILED(hr)) {
SetLastStatus(hr);
hr = MapHrToUmiError(hr);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::Delete (IUmiPropList support).
//
// Synopsis: Delete the named property from the cache.
//
// Arguments: pszName - Name of property to delete.
// uFlags - Standard flags parameter.
//
// Returns: E_NOTIMPL.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CPropertyManager::Delete(
IN LPCWSTR pszName,
IN ULONG uFlags
)
{
SetLastStatus(E_NOTIMPL);
RRETURN(E_NOTIMPL);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::GetProps (IUmiPropList support).
//
// Synopsis: Gets the values for the attributes. This will read data
// from the server as needed.
//
// Arguments: self explanatory
//
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: UMI_PROPERTY_VALUES* has the an array of values for the
// attributes. Note that there is no ordering specified
// for the return values.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CPropertyManager::GetProps(
IN LPCWSTR* pszNames,
IN ULONG uNameCount,
IN ULONG uFlags,
OUT UMI_PROPERTY_VALUES **pProps
)
{
HRESULT hr = S_OK;
if ((uFlags != UMI_FLAG_GETPROPS_NAMES)
&& (uFlags != UMI_FLAG_GETPROPS_SCHEMA)
) {
BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
}
//
// Currently we support only getting the names of all the properties.
//
if (pszNames
|| uNameCount
|| !pProps
) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
*pProps = NULL;
if (_fPropCacheMode) {
//
// Only UMI_FLAG_GETPROPS_NAMES is valid in this case.
//
if (uFlags != UMI_FLAG_GETPROPS_NAMES) {
BAIL_ON_FAILURE(hr = UMI_E_UNSUPPORTED_FLAGS);
}
hr = _pPropCache->GetPropertyNames(pProps);
}
else {
//
// Need to see what type of flag it is and extra check needed,
// if this is UMI_FLAGS_GETPROPS_SCHEMA.
//
if (uFlags == UMI_FLAG_GETPROPS_SCHEMA) {
LONG lVal;
hr = GetLongProperty(L"__GENUS", &lVal);
BAIL_ON_FAILURE(hr);
if (lVal != UMI_GENUS_CLASS) {
BAIL_ON_FAILURE(hr = UMI_E_UNSUPPORTED_FLAGS);
}
hr = GetPropertyNamesSchema(pProps);
}
else {
//
// Need to do get our static list.
//
hr = this->GetPropertyNames(pProps);
}
} // else for !propertyCacheMode.
error:
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::PutProps (IUmiPropList support).
//
// Synopsis: Puts the value for the attributes in the cache.
//
// Arguments: self explanatory
//
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: Property cache for the object.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::PutProps(
IN LPCWSTR* pszNames,
IN ULONG uNameCount,
IN ULONG uFlags,
IN UMI_PROPERTY_VALUES *pProps
)
{
HRESULT hr = S_OK;
//
// When done - should get and put multiple work directly of the server ?
// That would take care off problems like 5 can be put in the cache
// but sixth cannot ...
//
SetLastStatus(E_NOTIMPL);
RRETURN(E_NOTIMPL);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::PutFrom (IUmiPropList support).
//
// Synopsis: Clarify exactly what this is supposed to do ?
//
// Arguments: self explanatory
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: Property cache for the object.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CPropertyManager::PutFrom(
IN LPCWSTR pszName,
IN ULONG uFlags,
IN ULONG uBufferLength,
IN LPVOID pExistingMem
)
{
SetLastStatus(E_NOTIMPL);
RRETURN(E_NOTIMPL);
}
//
// PropertyManager methods that are not part of the IUmiPropList interface.
//
//+---------------------------------------------------------------------------
// Function: CPropertyManager::GetLastStatus
//
// Synopsis: Returns the error from the last operation on this object.
// For now only the status code is supported.
//
// Arguments: uFlags - Must be 0 for now.
// puSpecificStatus - Status is returned in this value.
// riid - IID requested on status obj.
// pStatusObj - Must be NULL for now.
//
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: *puSpecificStatus with last status code.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::GetLastStatus(
ULONG uFlags,
ULONG *puSpecificStatus,
REFIID riid,
LPVOID *pStatusObj
)
{
if (!puSpecificStatus || pStatusObj) {
RRETURN(E_INVALIDARG);
}
if (uFlags) {
RRETURN(UMI_E_INVALID_FLAGS);
}
*puSpecificStatus = _ulStatus;
RRETURN(S_OK);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::AddProperty.
//
// Synopsis: Updates the value of the property to the interface
// property cache. This fn is called only in interface mode.
// If necessary the property will be added to the cache.
//
// Arguments: self explanatory
//
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: Changes the internal property table.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::AddProperty(
LPCWSTR szPropertyName,
UMI_PROPERTY umiProperty
)
{
HRESULT hr = S_OK;
DWORD dwIndex = (DWORD) -1;
BOOL fAddedName = FALSE;
//
// Make sure we do not have property in the cache.
//
hr = FindProperty(szPropertyName, &dwIndex);
if (FAILED(hr)) {
//
// We actually need to add this property in our list.
//
hr = AddToTable(szPropertyName, &dwIndex);
fAddedName = TRUE;
}
BAIL_ON_FAILURE(hr);
//
// At this point we can just dump the value into the cache.
//
hr = UpdateProperty(
dwIndex,
umiProperty
);
BAIL_ON_FAILURE(hr);
error:
if (FAILED(hr) && fAddedName) {
//
// Do we delete the name from the cache.
//
DeleteProperty(dwIndex);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::UpdateProperty.
//
// Synopsis: Updates the value of an interface property in the local cache.
// The assumption is that this function is only called with from
// AddProperty (or anywhere else where we have the correct index).
//
// Arguments: dwIndex - index in our table of the property to update
// UMI_PROPERTY - the value to add to our table, note that
// if the operation is delete we should remove the element
// from our table (value returned if any will be default value
// for subsequent get calls).
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: Underlying data in the cache is changed
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::UpdateProperty(
DWORD dwIndex,
UMI_PROPERTY umiProp
)
{
HRESULT hr = E_NOTIMPL;
DWORD dwFlags, dwCacheSyntaxId, dwNumElements;
PUMI_PROPERTY pUmiProperty = NULL;
if (!_pIntfProperties) {
//
// Should we check the index ? It is after all an internal
// value, so it should not be wrong.
//
BAIL_ON_FAILURE(hr = E_FAIL);
}
//
// Only update and delete are really supported.
//
if ((umiProp.uOperationType != UMI_OPERATION_UPDATE)
&& (umiProp.uOperationType != UMI_OPERATION_DELETE_ALL_MATCHES)) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
if (_pIntfProperties[dwIndex].pUmiProperty) {
//
// Free the current data in the table and set initial values.
//
hr = FreeOneUmiProperty(*(_pIntfProperties[dwIndex].pUmiProperty));
BAIL_ON_FAILURE(hr);
FreeADsMem(_pIntfProperties[dwIndex].pUmiProperty);
_pIntfProperties[dwIndex].pUmiProperty = NULL;
_pIntfProperties[dwIndex].dwFlags = 0;
_pIntfProperties[dwIndex].dwSyntaxId = 0;
}
//
// Copy the value to temp variable, so we can handle failures gracefully.
//
hr = CopyUmiProperty(
umiProp,
&pUmiProperty
);
BAIL_ON_FAILURE(hr);
_pIntfProperties[dwIndex].pUmiProperty = pUmiProperty;
error:
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::FindProperty.
//
// Synopsis: Searches for the specified property in the local cache.
//
// Arguments: szPropertyName, name of property.
// pdwIndex - pointer to DWORD with index in table.
//
// Returns: HRESULT - S_OK or E_ADS_PROPERTY_NOT_FOUND.
//
// Modifies: *pdwIndex to.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::FindProperty(
LPCWSTR szPropertyName,
PDWORD pdwIndex
)
{
DWORD dwIndex;
if (!_pIntfProperties) {
RRETURN(E_ADS_PROPERTY_NOT_FOUND);
}
for (dwIndex = 0; dwIndex < _dwMaxProperties; dwIndex++) {
if (_wcsicmp(
_pIntfProperties[dwIndex].pszPropertyName,
szPropertyName
) == 0) {
*pdwIndex = dwIndex;
RRETURN(S_OK);
}
}
RRETURN(E_ADS_PROPERTY_NOT_FOUND);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::DeleteProperty.
//
// Synopsis: Deletes the property specified from the cahce.
//
// Arguments: Index to element to delete.
//
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: Underlying data in the cache is changed.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::DeleteProperty(
DWORD dwIndex
)
{
HRESULT hr = S_OK;
INTF_PROPERTY* pIntfProp = NULL;
if (_pIntfProperties && ((_dwMaxProperties-1) < dwIndex)) {
//
// Valid property in cache.
//
pIntfProp = _pIntfProperties + dwIndex;
ADsAssert(pIntfProp);
if (pIntfProp->pszPropertyName) {
FreeADsStr(pIntfProp->pszPropertyName);
pIntfProp->pszPropertyName = NULL;
}
//
// Now Copy over the rest of the data here.
//
}
else {
hr = E_FAIL;
}
RRETURN (hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::FlushPropertyCache.
//
// Synopsis: Clear all internal data in the property cache.
//
// Arguments:
//
// Returns: N/A
//
// Modifies: Underlying data in the cache is changed
//
//----------------------------------------------------------------------------
VOID
CPropertyManager::flushpropertycache()
{
//
// Free any data in our table
if (_pIntfProperties) {
for (DWORD dwCtr = 0; (dwCtr < _dwMaxProperties); dwCtr++) {
INTF_PROPERTY *pIntfProp = (PINTF_PROPERTY)_pIntfProperties+ dwCtr;
if (pIntfProp) {
if (pIntfProp->pszPropertyName) {
FreeADsStr(pIntfProp->pszPropertyName);
pIntfProp->pszPropertyName = NULL;
}
}
}
//
// Now free the array of pointers.
//
FreeADsMem((void *) _pIntfProperties);
_pIntfProperties = NULL;
}
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::ClearAllPropertyFlags.
//
// Synopsis: Resets all property flags to zero.
//
// Arguments: None.
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: Underlying data in the cache is changed.
//
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::ClearAllPropertyFlags(
VOID
)
{
RRETURN(E_NOTIMPL);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::GetPropertyNames.
//
// Synopsis: Returns list of names of interface properties available.
//
// Arguments: out params only
//
// Returns: HRESULT - S_OK or any failure error code
//
// Modifies: ppStringsNames to point to valid array of strings.
// pUlCount to point to number of strings in the array.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::GetPropertyNames(
PUMI_PROPERTY_VALUES *pUmiProps
)
{
HRESULT hr = S_OK;
PUMI_PROPERTY_VALUES pUmiPropVals = NULL;
PUMI_PROPERTY pUmiProperties = NULL;
DWORD dwCtr, dwPropCount = 0;
pUmiPropVals = (PUMI_PROPERTY_VALUES) AllocADsMem(
sizeof(UMI_PROPERTY_VALUES)
);
if (!pUmiPropVals) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// Need to count the properties.
//
while (_pStaticPropData[dwPropCount].pszPropertyName) {
dwPropCount++;
}
if (!dwPropCount) {
*pUmiProps = pUmiPropVals;
RRETURN(S_OK);
}
pUmiProperties = (PUMI_PROPERTY) AllocADsMem(
sizeof(UMI_PROPERTY) * dwPropCount
);
if (!pUmiProperties) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// Need to go through the table and alloc the values.
//
for (dwCtr = 0; dwCtr < dwPropCount; dwCtr++) {
pUmiProperties[dwCtr].pszPropertyName =
AllocADsStr(_pStaticPropData[dwCtr].pszPropertyName);
if (!pUmiProperties[dwCtr].pszPropertyName) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
pUmiProperties[dwCtr].uType = UMI_TYPE_NULL;
}
pUmiPropVals->pPropArray = pUmiProperties;
pUmiPropVals->uCount = dwPropCount;
*pUmiProps = pUmiPropVals;
RRETURN(S_OK);
error :
if (pUmiProperties) {
for (dwCtr = 0; dwCtr < dwPropCount; dwCtr++) {
if (pUmiProperties[dwCtr].pszPropertyName) {
FreeADsStr(pUmiProperties[dwCtr].pszPropertyName);
}
}
FreeADsMem(pUmiProperties);
}
if (pUmiPropVals) {
FreeADsMem(pUmiPropVals);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::GetPropertyNamesSchema
//
// Synopsis: Returns list of the names and types of the properties this
// object can contain. Note that this method is valid only if the
// underlying object is an instance of class Class (schema class).
//
// Arguments: out params only
//
// Returns: HRESULT - S_OK or any failure error code
//
// Modifies:
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::GetPropertyNamesSchema(
PUMI_PROPERTY_VALUES *pUmiProps
)
{
HRESULT hr = S_OK;
IADsUmiHelperPrivate *pIADsUmiPriv = NULL;
// Array of ptr to PROPERTYINFO
PPROPERTYINFO *pPropArray = NULL;
DWORD dwPropCount = 0;
PUMI_PROPERTY_VALUES pUmiPropVals = NULL;
PUMI_PROPERTY pUmiProperties = NULL;
//
// Need a ptr to the helper routine.
//
hr = this->_pIADs->QueryInterface(
IID_IADsUmiHelperPrivate,
(void **) &pIADsUmiPriv
);
if (hr == E_NOINTERFACE) {
BAIL_ON_FAILURE(hr = UMI_E_UNSUPPORTED_FLAGS);
}
hr = pIADsUmiPriv->GetPropertiesHelper(
(void**) &pPropArray,
&dwPropCount
);
BAIL_ON_FAILURE(hr);
//
// Need to prepare the return values.
//
pUmiPropVals = (PUMI_PROPERTY_VALUES) AllocADsMem(
sizeof(UMI_PROPERTY_VALUES)
);
if (!pUmiPropVals) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
if (!dwPropCount) {
*pUmiProps = pUmiPropVals;
RRETURN(S_OK);
}
pUmiProperties = (PUMI_PROPERTY) AllocADsMem(
sizeof(UMI_PROPERTY) * dwPropCount
);
if (!pUmiProperties) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
for (DWORD dwCtr = 0; dwCtr < dwPropCount; dwCtr++) {
DWORD dwSyntaxId = 0;
pUmiProperties[dwCtr].pszPropertyName =
AllocADsStr(pPropArray[dwCtr]->pszPropertyName);
if (!pUmiProperties[dwCtr].pszPropertyName) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// Need to update the type with the type from the schema.
//
dwSyntaxId = LdapGetSyntaxIdOfAttribute(
pPropArray[dwCtr]->pszSyntax
);
//
// If we get dwSyntaxId == -1 we could not find the entry in
// our table.
//
if (dwSyntaxId == -1) {
pUmiProperties[dwCtr].uType = UMI_TYPE_UNDEFINED;
}
else {
hr = ConvertLdapSyntaxIdToUmiType(
dwSyntaxId,
(pUmiProperties[dwCtr].uType)
);
if (FAILED(hr)) {
hr = S_OK;
//
// Cannot do anything about this.
//
pUmiProperties[dwCtr].uType = UMI_TYPE_UNDEFINED;
}
//
// If this property is multivalued.
//
if (!pPropArray[dwCtr]->fSingleValued) {
pUmiProperties[dwCtr].uType |= UMI_TYPE_ARRAY_FLAG;
}
}
} // for each property.
pUmiPropVals->pPropArray = pUmiProperties;
pUmiPropVals->uCount = dwPropCount;
*pUmiProps = pUmiPropVals;
error:
if (pIADsUmiPriv) {
pIADsUmiPriv->Release();
}
//
// Need to free the array not the elements which are ptrs into
// the global parsed schema's we hold.
//
if (pPropArray) {
FreeADsMem(pPropArray);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::GetInterfaceProperty
//
// Synopsis: Gets the interface property from the owning object or the
// default value and packages the value as an UMI_PROPERTY_VALUE.
//
// Arguments: pszName - name of property to get.
// uFlags - flags has to be zero for now.
// ppProp - value is returned in this ptr.
// dwTableIndex - index to entry in table describing this item.
//
// Returns: HRESULT - S_OK or any failure error code
//
// Modifies: ppProp which will point to return value if the fn succeeds.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::GetInterfaceProperty(
LPCWSTR pszName,
ULONG uFlags,
UMI_PROPERTY_VALUES **ppProp,
DWORD dwTableIndex
)
{
HRESULT hr;
ULONG ulOperationAllowed = _pStaticPropData[dwTableIndex].ulOpCode;
ULONG ulVal;
LONG lGenus;
LPWSTR pszStringVal = NULL;
BSTR bstrRetVal = NULL, bstrTempVal = NULL;
LPWSTR pszUmiUrl = NULL;
IADsObjectOptions *pObjOpt = NULL;
VARIANT vVariant;
DWORD dwIndex;
PUMI_PROPERTY pUmiPropLocal = NULL;
IUnknown *pUnk = NULL;
IUmiObject *pUmiObj = NULL;
BOOL fUnkPtr = FALSE;
BOOL fClassInstance = FALSE;
VariantInit(&vVariant);
if (!_pUnk) {
BAIL_ON_FAILURE(hr = E_FAIL);
}
//
// If the property is READ/WRITE, we need to see if there is a value
// in the propCache. If yes, return that. If not return the default
// value.
//
if (ulOperationAllowed == OPERATION_CODE_READWRITE) {
hr = FindProperty(pszName, &dwIndex);
//
// If it succeeded it was updated in the cache.
//
if (SUCCEEDED(hr)) {
hr = CopyUmiProperty(
*(_pIntfProperties[dwIndex].pUmiProperty),
&pUmiPropLocal
);
BAIL_ON_FAILURE(hr);
//
// We need to free the name of the first property cause
// that is allocated again by the Get call.
//
if (pUmiPropLocal && pUmiPropLocal->pszPropertyName) {
FreeADsStr(pUmiPropLocal->pszPropertyName);
pUmiPropLocal->pszPropertyName = NULL;
}
//
// Got the property need to package in umi property values.
//
*ppProp = (PUMI_PROPERTY_VALUES) AllocADsMem(
sizeof(UMI_PROPERTY_VALUES)
);
if (!*ppProp) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
(*ppProp)->pPropArray = pUmiPropLocal;
(*ppProp)->uCount = 1;
RRETURN(hr);
} // value found in cache
else {
//
// Setting this should trigger a read of the default
// value for this property.
//
ulOperationAllowed = OPERATION_CODE_READABLE;
}
}
//
// We need to check for the securityDescriptor as that needs
// some special handling.
//
if (!_wcsicmp(pszName, L"__SECURITY_DESCRIPTOR")) {
//
// Need to read this from the actual object.
//
hr = _pUnk->QueryInterface(IID_IUmiObject, (void **) &pUmiObj);
BAIL_ON_FAILURE(hr);
hr = pUmiObj->GetAs(
L"ntSecurityDescriptor",
uFlags,
UMI_TYPE_OCTETSTRING,
ppProp
);
if (SUCCEEDED(hr)) {
//
// Need to make sure that we do not set name twice.
//
if (*ppProp
&& (*ppProp)[0].pPropArray
&& (*ppProp)[0].pPropArray[0].pszPropertyName
) {
FreeADsStr((*ppProp)[0].pPropArray[0].pszPropertyName);
(*ppProp)[0].pPropArray[0].pszPropertyName = NULL;
}
}
//
// This seems the cleanest ...
//
goto error;
}
//
// If the property is only readable, then get it from owning object.
// If not get the value from cache or use defualt value as appropriate.
//
if (ulOperationAllowed == OPERATION_CODE_READABLE) {
hr = GetLongProperty(L"__GENUS", &lGenus);
if (FAILED(hr)) {
//
// There was no genus property = connection for example.
//
fClassInstance = FALSE;
}
else if (lGenus == UMI_GENUS_CLASS) {
fClassInstance = TRUE;
}
//
// The value can be a string/long for now and it has to
// be either the default value or the value from the owning object.
//
switch (_pStaticPropData[dwTableIndex].ulDataType) {
case UMI_TYPE_I4:
//
// Use default value from the static table.
//
vVariant.lVal = _pStaticPropData[dwTableIndex].umiVal.lValue[0];
hr = ConvertVariantLongToUmiProp(vVariant, ppProp);
break;
case UMI_TYPE_BOOL:
//
// Use default value from table.
//
vVariant.lVal = _pStaticPropData[dwTableIndex].umiVal.bValue[0];
hr = ConvertVariantLongToUmiProp(vVariant, ppProp);
(*ppProp)[0].pPropArray[0].uType = UMI_TYPE_BOOL;
break;
case UMI_TYPE_LPWSTR:
//
// In this case it has to be NULL.
//
hr = GetEmptyLPWSTRProp(ppProp);
break;
case 9999:
if (!_pIADs) {
//
// Nothing we can do here !
//
BAIL_ON_FAILURE(hr = E_FAIL);
}
if (!_wcsicmp(pszName, L"__Path")) {
hr = _pIADs->get_ADsPath(&bstrRetVal);
}
else if (!_wcsicmp(pszName, L"__Class")) {
if (fClassInstance) {
//
// For classes, the class is the name,
// not "class" itself.
//
hr = _pIADs->get_Name(&bstrRetVal);
}
else {
hr = _pIADs->get_Class(&bstrRetVal);
}
}
else if (!_wcsicmp(pszName, L"__KEY")) {
hr = _pIADs->get_Name(&bstrRetVal);
BAIL_ON_FAILURE(hr);
if (SUCCEEDED(hr)) {
hr = HelperConvertNameToKey(bstrRetVal, &pszUmiUrl);
}
}
else if (!_wcsicmp(pszName, L"__GUID")) {
hr = _pIADs->get_GUID(&bstrRetVal);
}
else if (!_wcsicmp(pszName, L"__Parent")) {
hr = _pIADs->get_Parent(&bstrRetVal);
if (SUCCEEDED(hr)) {
hr = ADsPathToUmiURL(bstrRetVal, &pszUmiUrl);
}
}
else if (!_wcsicmp(pszName, L"__Schema")) {
hr = _pIADs->get_Schema(&bstrRetVal);
//
// Now need to bind to this object.
//
if (SUCCEEDED(hr)) {
hr = GetObject(
bstrRetVal,
*_pCreds,
(void **) &pUnk
);
BAIL_ON_FAILURE(hr);
fUnkPtr = TRUE;
}
}
else if (!_wcsicmp(pszName, L"__URL")) {
hr = _pIADs->get_ADsPath(&bstrTempVal);
if (SUCCEEDED(hr)) {
hr = ADsPathToUmiURL(bstrTempVal, &pszUmiUrl);
}
}
else if (!_wcsicmp(pszName, L"__Name")) {
if (fClassInstance) {
hr = _pIADs->get_Name(&bstrRetVal);
} else {
hr = HelperGetUmiRelUrl(_pIADs, &bstrRetVal);
}
}
else if (!_wcsicmp(pszName, L"__RELURL")) {
hr = HelperGetUmiRelUrl(_pIADs, &bstrRetVal);
}
else if (!_wcsicmp(pszName, L"__RELPATH")) {
hr = HelperGetUmiRelUrl(_pIADs, &bstrRetVal);
}
else if (!_wcsicmp(pszName, L"__FULLRELURL")) {
//
// Same as __RELURL, __NAME and __RELPATH
//
hr = HelperGetUmiRelUrl(_pIADs, &bstrRetVal);
}
else if (!_wcsicmp(pszName, L"__PADS_SCHEMA_CONTAINER_PATH")) {
hr = HelperGetUmiSchemaContainerPath(_pIADs, &bstrRetVal);
}
else if (!_wcsicmp(pszName, L"__SUPERCLASS")) {
if (!fClassInstance) {
//
// Only supported if this is a class.
//
hr = E_FAIL;
}
else {
hr = HelperGetUmiDerivedFrom(_pIADs, &bstrRetVal);
}
}
else {
hr = E_FAIL;
}
BAIL_ON_FAILURE(hr);
//
// If not schema then it has to be a string.
//
if (!fUnkPtr) {
hr = ConvertBSTRToUmiProp(
pszUmiUrl ? pszUmiUrl:bstrRetVal,
ppProp
);
}
else {
hr = ConvertIUnkToUmiProp(
pUnk,
IID_IUmiObject,
ppProp
);
}
break;
default:
hr = E_FAIL;
} // end of switch
BAIL_ON_FAILURE(hr);
} // opeartion code is READABLE.
else {
hr = E_FAIL;
}
error:
if (pObjOpt) {
pObjOpt->Release();
}
VariantClear(&vVariant);
if (bstrRetVal) {
SysFreeString(bstrRetVal);
}
if (bstrTempVal) {
SysFreeString(bstrTempVal);
}
if (pszUmiUrl) {
FreeADsStr(pszUmiUrl);
}
if (pUnk) {
pUnk->Release();
}
if (pUmiObj) {
pUmiObj->Release();
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::DeleteSDIfPresent --- Helper method.
//
// Synopsis: Helps remove the SD from the property cache so that we do not
// set it when we Commit the changes.
//
// Arguments: N/A.
//
// Returns: HRESULT - S_OK or any failure error code
//
// Modifies: Underlying property cache.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::DeleteSDIfPresent()
{
HRESULT hr = S_OK;
DWORD dwIndex = 0;
if (!_fPropCacheMode) {
//
// Sanity check, should never be here.
//
RRETURN(S_OK);
}
if (!_pPropCache) {
//
// Want to delete SD when we do not have a cache - weird.
//
RRETURN(S_OK);
}
hr = _pPropCache->findproperty(L"ntSecurityDescriptor", &dwIndex);
if (FAILED(hr)) {
RRETURN(S_OK);
}
else {
//
// Get rid of this from the cache.
//
_pPropCache->deleteproperty(dwIndex);
}
RRETURN(S_OK);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::GetIndexInStaticTable
//
// Synopsis: Verifies that the named property can be found in the list of
// valid properties and returns the index.
//
// Arguments: Self explanatory.
//
// Returns: S_OK or E_ADS_PROPERTY_NOT_FOUND as appropriate.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::GetIndexInStaticTable(
LPCWSTR pszName,
DWORD &dwIndex
)
{
for (DWORD dwCtr = 0;
_pStaticPropData[dwCtr].pszPropertyName;
dwCtr++ ) {
if (!_wcsicmp(
pszName,
_pStaticPropData[dwCtr].pszPropertyName
)) {
dwIndex = dwCtr;
RRETURN(S_OK);
}
}
RRETURN(E_ADS_PROPERTY_NOT_FOUND);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::VerifyIfValidProperty.
//
// Synopsis: Makes sure that a valid interface property is being set. This
// function is called internally if we know we are not in the
// property cache mode. The internal static table pointer is used to
// verify the property.
//
// Arguments: Self explanatory.
//
// Returns: Bool - True or False as appropriate.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
BOOL
CPropertyManager::VerifyIfValidProperty(
LPCWSTR pszPropertyName,
UMI_PROPERTY umiProperty
)
{
DWORD dwIndex;
//
// if _pStaticPropData is NULL then there are no interface properties.
// If the count is zero, then the only operation is delete.
//
if ((!_pStaticPropData)
|| ((umiProperty.uCount == 0)
&& (umiProperty.uOperationType != UMI_OPERATION_DELETE_ALL_MATCHES)
)
)
{
return FALSE;
}
if (SUCCEEDED(GetIndexInStaticTable(
pszPropertyName,
dwIndex
))
) {
//
// Verify type and if property can be changed.
// If the types do not match we should still allow 9999 for
// things like __SECURITY_DESCRIPTOR that can be changed.
// If the attribute cannot be written, then the next part of
// the check will fail, so you still wont be able to write
// things the __URL property.
//
if (((_pStaticPropData[dwIndex].ulDataType == umiProperty.uType)
|| (_pStaticPropData[dwIndex].ulDataType == 9999))
&& (_pStaticPropData[dwIndex].ulOpCode
!= OPERATION_CODE_READABLE)
) {
//
// Need to make sure count is correct.
//
if ((umiProperty.uCount > 1)
&& (!_pStaticPropData[dwIndex].fMultiValued)
) {
return FALSE;
}
return TRUE;
}
}
//
// Either we did not satisfy requirements or not found
//
return FALSE;
}
HRESULT
CPropertyManager::AddToTable(
LPCWSTR pszPropertyName,
PDWORD pdwIndex
)
{
HRESULT hr = S_OK;
PINTF_PROPERTY pNewProperty = NULL;
//
// Check to see if the table is already there. If not create
// the table with potential to store upto 10 entries. This should
// suffice unless we have more properties. Set the current pointer
// and current top appropriately.
//
if (!_pIntfProperties) {
_pIntfProperties = (PINTF_PROPERTY) AllocADsMem(
sizeof(INTF_PROPERTY) * MAX_PROPMGR_PROP_COUNT
);
if (!_pIntfProperties) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
_dwMaxProperties = 0;
_dwMaxLimit = MAX_PROPMGR_PROP_COUNT;
}
if ((_dwMaxProperties+1) < _dwMaxLimit) {
//
// We can add this property to the table.
//
DWORD dwTop;
dwTop = _dwMaxProperties++;
_pIntfProperties[dwTop].pszPropertyName =
AllocADsStr(pszPropertyName);
if (!_pIntfProperties[dwTop].pszPropertyName) {
//
// Reset the count.
//
_dwMaxProperties--;
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
*pdwIndex = dwTop;
}
else {
//
// We do not have space in the table - return an error.
//
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
error:
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::GetStringProperty.
//
// Synopsis: Retrieves the string property if one is set in the cache or
// returns NULL if the property is not in the cache. The assumption
// here is that string properties are defaulted to NULL always.
//
// Arguments: Self explanatory.
//
// Returns: S_OK, UMI_E_NOT_FOUND, E_FAIL.
//
// Modifies: pszRetVal to point to the appropriate value.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::GetStringProperty(
LPCWSTR pszPropName,
LPWSTR *ppszRetStrVal
)
{
DWORD dwIndex;
HRESULT hr = FindProperty(pszPropName, &dwIndex);
PUMI_PROPERTY pUmiProp;
if (FAILED(hr)) {
//
// Do we lookup the static table ? The table wont have strings in
// it though cause the union assumes chars.
//
*ppszRetStrVal = NULL;
RRETURN(S_OK);
}
pUmiProp = _pIntfProperties[dwIndex].pUmiProperty;
//
// Make sure that this is a string.
//
if (pUmiProp->uType != UMI_TYPE_LPWSTR) {
BAIL_ON_FAILURE(hr = E_FAIL);
}
if (pUmiProp->pUmiValue
&& pUmiProp->pUmiValue->pszStrValue[0]) {
*ppszRetStrVal = AllocADsStr(pUmiProp->pUmiValue->pszStrValue[0]);
if (!*ppszRetStrVal) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
}
error:
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::GetLongProperty - Helper method.
//
// Synopsis: Retrieves the long property if one is set in the cache or
// returns the defaulted value if the property is not in the cache.
//
// Arguments: pszPropName --- Name of property being retrieved.
// plVal --- Ptr for return value.
//
// Returns: S_OK, UMI_E_NOT_FOUND or E_FAIL.
//
// Modifies: *plVal with appropriate value.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::GetLongProperty(
LPCWSTR pszPropName,
LONG *plVal
)
{
DWORD dwIndex;
HRESULT hr = FindProperty(pszPropName, &dwIndex);
PUMI_PROPERTY pUmiProp;
*plVal = 0;
if (FAILED(hr)) {
//
// We need to look for the property in the static table.
//
hr = GetIndexInStaticTable(pszPropName, dwIndex);
if (SUCCEEDED(hr)
&& (_pStaticPropData[dwIndex].ulDataType == UMI_TYPE_I4)
) {
//
// Get the correct value from the table.
//
*plVal = _pStaticPropData[dwIndex].umiVal.lValue[0];
}
else {
hr = UMI_E_NOT_FOUND;
}
RRETURN(hr);
}
pUmiProp = _pIntfProperties[dwIndex].pUmiProperty;
//
// Make sure that this is a long.
//
if (pUmiProp->uType != UMI_TYPE_I4) {
BAIL_ON_FAILURE(hr = E_FAIL);
}
if (pUmiProp->pUmiValue) {
*plVal = pUmiProp->pUmiValue->lValue[0];
}
error:
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CPropertyManager::GetBoolProperty - Helper method.
//
// Synopsis: Retrieves the bool property if one is set in the cache or
// returns the defaulted value if the property is not in the cache.
//
// Arguments: pszPropName --- Name of property being retrieved.
// pfFlag --- Ptr for return value.
//
// Returns: S_OK, UMI_E_NOT_FOUND or E_FAIL.
//
// Modifies: ofFlag with appropriate value of the property.
//
//----------------------------------------------------------------------------
HRESULT
CPropertyManager::GetBoolProperty(
LPCWSTR pszPropName,
BOOL *pfFlag
)
{
DWORD dwIndex;
HRESULT hr = FindProperty(pszPropName, &dwIndex);
PUMI_PROPERTY pUmiProp;
*pfFlag = FALSE;
if (FAILED(hr)) {
//
// We need to look for the property in the static table.
//
hr = GetIndexInStaticTable(pszPropName, dwIndex);
if (SUCCEEDED(hr)
&& (_pStaticPropData[dwIndex].ulDataType == UMI_TYPE_BOOL)
) {
//
// Get the correct value from the table.
//
*pfFlag = _pStaticPropData[dwIndex].umiVal.bValue[0];
}
else {
hr = E_FAIL;
}
RRETURN(hr);
}
pUmiProp = _pIntfProperties[dwIndex].pUmiProperty;
//
// Make sure that this is a long.
//
if (pUmiProp->uType != UMI_TYPE_BOOL) {
BAIL_ON_FAILURE(hr = E_FAIL);
}
if (pUmiProp->pUmiValue) {
*pfFlag = pUmiProp->pUmiValue->bValue[0];
}
error:
RRETURN(hr);
}