windows-nt/Source/XPSP1/NT/ds/adsi/ldap/cnamesp.cxx
2020-09-26 16:20:57 +08:00

1329 lines
34 KiB
C++

//---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996
//
// File: cnamesp.cxx
//
// Contents: LDAP Namespace Object
//
//
// History: 06-15-96 yihsins Created.
//
//----------------------------------------------------------------------------
#include "LDAP.hxx"
#pragma hdrstop
#include <ntdsapi.h>
DEFINE_IDispatch_Implementation(CLDAPNamespace)
DEFINE_IADs_Implementation(CLDAPNamespace)
DEFINE_IADsPutGet_UnImplementation(CLDAPNamespace)
// Class CLDAPNamespace
CLDAPNamespace::CLDAPNamespace()
{
VariantInit(&_vFilter);
ENLIST_TRACKING(CLDAPNamespace);
_pObjectInfo = NULL;
}
HRESULT
CLDAPNamespace::CreateNamespace(
BSTR Parent,
BSTR NamespaceName,
CCredentials& Credentials,
DWORD dwObjectState,
REFIID riid,
void **ppvObj
)
{
CLDAPNamespace FAR * pNamespace = NULL;
HRESULT hr = S_OK;
hr = AllocateNamespaceObject(
Credentials,
&pNamespace
);
BAIL_ON_FAILURE(hr);
hr = pNamespace->InitializeCoreObject(
Parent,
NamespaceName,
NAMESPACE_CLASS_NAME,
CLSID_LDAPNamespace,
dwObjectState
);
BAIL_ON_FAILURE(hr);
if (Credentials.GetAuthFlags() & ADS_AUTH_RESERVED) {
//
// Umi Object is going to be the owner, so we need to
// initilaize the umi object and return.
//
hr = ((CCoreADsObject*)pNamespace)->InitUmiObject(
IntfPropsSchema,
NULL,
(IADs *) pNamespace,
(IADs *) pNamespace,
riid,
ppvObj,
&(pNamespace->_Credentials)
);
BAIL_ON_FAILURE(hr);
RRETURN(S_OK);
}
hr = pNamespace->QueryInterface(riid, ppvObj);
BAIL_ON_FAILURE(hr);
pNamespace->Release();
RRETURN(hr);
error:
*ppvObj = NULL;
delete pNamespace;
RRETURN_EXP_IF_ERR(hr);
}
CLDAPNamespace::~CLDAPNamespace( )
{
VariantClear(&_vFilter);
delete _pDispMgr;
}
STDMETHODIMP
CLDAPNamespace::QueryInterface(REFIID iid, LPVOID FAR* ppv)
{
if (ppv == NULL) {
RRETURN(E_POINTER);
}
if (IsEqualIID(iid, IID_IUnknown))
{
*ppv = (IADs FAR *)this;
}else if (IsEqualIID(iid, IID_IDispatch))
{
*ppv = (IADs FAR *)this;
}
else if (IsEqualIID(iid, IID_IADsContainer))
{
*ppv = (IADsContainer FAR *) this;
}
else if (IsEqualIID(iid, IID_IADs))
{
*ppv = (IADs FAR *) this;
}
else if (IsEqualIID(iid, IID_IADsOpenDSObject))
{
*ppv = (IADsOpenDSObject FAR *) this;
}
else if (IsEqualIID(iid, IID_ISupportErrorInfo))
{
*ppv = (ISupportErrorInfo FAR *) this;
}
else if (IsEqualIID(iid, IID_IADsPathnameProvider))
{
*ppv = (IADsPathnameProvider FAR *) this;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return NOERROR;
}
/* ISupportErrorInfo method */
STDMETHODIMP
CLDAPNamespace::InterfaceSupportsErrorInfo(THIS_ REFIID riid)
{
if (IsEqualIID(riid, IID_IADs) ||
IsEqualIID(riid, IID_IADsContainer) ||
IsEqualIID(riid, IID_IADsOpenDSObject)) {
RRETURN(S_OK);
} else {
RRETURN(S_FALSE);
}
}
STDMETHODIMP
CLDAPNamespace::SetInfo(THIS)
{
RRETURN_EXP_IF_ERR(E_NOTIMPL);
}
STDMETHODIMP
CLDAPNamespace::GetInfo(THIS)
{
RRETURN_EXP_IF_ERR(E_NOTIMPL);
}
STDMETHODIMP
CLDAPNamespace::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved)
{
RRETURN_EXP_IF_ERR(E_NOTIMPL);
}
/* IADsContainer methods */
STDMETHODIMP
CLDAPNamespace::get_Count(long FAR* retval)
{
RRETURN(E_NOTIMPL);
}
STDMETHODIMP
CLDAPNamespace::get_Filter(THIS_ VARIANT FAR* pVar)
{
HRESULT hr;
VariantInit(pVar);
hr = VariantCopy(pVar, &_vFilter);
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CLDAPNamespace::put_Filter(THIS_ VARIANT Var)
{
HRESULT hr;
hr = VariantCopy(&_vFilter, &Var);
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CLDAPNamespace::get_Hints(THIS_ VARIANT FAR* pVar)
{
RRETURN_EXP_IF_ERR(E_NOTIMPL);
}
STDMETHODIMP
CLDAPNamespace::put_Hints(THIS_ VARIANT Var)
{
RRETURN_EXP_IF_ERR(E_NOTIMPL);
}
STDMETHODIMP
CLDAPNamespace::GetObject(
THIS_ BSTR ClassName,
BSTR RelativeName,
IDispatch * FAR* ppObject
)
{
DWORD dwBufferSize = 0;
TCHAR *pszBuffer = NULL;
HRESULT hr = S_OK;
if (!RelativeName || !*RelativeName) {
RRETURN_EXP_IF_ERR(E_ADS_UNKNOWN_OBJECT);
}
dwBufferSize = ( _tcslen(_ADsPath) + _tcslen(RelativeName)
+ 3 ) * sizeof(TCHAR); // includes "//"
pszBuffer = (LPTSTR) AllocADsMem( dwBufferSize );
if ( pszBuffer == NULL )
{
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
_tcscpy(pszBuffer, _ADsPath);
_tcscat(pszBuffer, TEXT("//"));
_tcscat(pszBuffer, RelativeName);
hr = ::GetObject(
pszBuffer,
_Credentials,
(LPVOID *)ppObject
);
BAIL_ON_FAILURE(hr);
error:
if ( pszBuffer )
FreeADsStr( pszBuffer );
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CLDAPNamespace::get__NewEnum(THIS_ IUnknown * FAR* retval)
{
HRESULT hr;
IUnknown FAR* punkEnum=NULL;
IEnumVARIANT * penum = NULL;
*retval = NULL;
//
// Create new enumerator for items currently
// in collection and QI for IUnknown
//
hr = CLDAPNamespaceEnum::Create(
(CLDAPNamespaceEnum **)&penum,
_vFilter,
_Credentials,
_ADsPath
);
if (FAILED(hr)){
goto error;
}
hr = penum->QueryInterface(
IID_IUnknown,
(VOID FAR* FAR*)retval
);
if (FAILED(hr)){
goto error;
}
if (penum) {
penum->Release();
}
return NOERROR;
error:
if (penum) {
delete penum;
}
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CLDAPNamespace::Create(THIS_ BSTR ClassName, BSTR RelativeName, IDispatch * FAR* ppObject)
{
RRETURN_EXP_IF_ERR(E_NOTIMPL);
}
STDMETHODIMP
CLDAPNamespace::Delete(THIS_ BSTR SourceName, BSTR Type)
{
RRETURN_EXP_IF_ERR(E_NOTIMPL);
}
STDMETHODIMP
CLDAPNamespace::CopyHere(THIS_ BSTR SourceName, BSTR NewName, IDispatch * FAR* ppObject)
{
RRETURN_EXP_IF_ERR(E_NOTIMPL);
}
STDMETHODIMP
CLDAPNamespace::MoveHere(THIS_ BSTR SourceName, BSTR NewName, IDispatch * FAR* ppObject)
{
RRETURN_EXP_IF_ERR(E_NOTIMPL);
}
HRESULT
CLDAPNamespace::AllocateNamespaceObject(
CCredentials& Credentials,
CLDAPNamespace ** ppNamespace
)
{
CLDAPNamespace FAR * pNamespace = NULL;
CAggregatorDispMgr FAR * pDispMgr = NULL;
HRESULT hr = S_OK;
pNamespace = new CLDAPNamespace();
if (pNamespace == NULL) {
hr = E_OUTOFMEMORY;
}
BAIL_ON_FAILURE(hr);
pDispMgr = new CAggregatorDispMgr(Credentials);
if (pDispMgr == NULL) {
hr = E_OUTOFMEMORY;
}
BAIL_ON_FAILURE(hr);
hr = LoadTypeInfoEntry(pDispMgr,
LIBID_ADs,
IID_IADs,
(IADs *)pNamespace,
DISPID_REGULAR
);
BAIL_ON_FAILURE(hr);
hr = LoadTypeInfoEntry(pDispMgr,
LIBID_ADs,
IID_IADsOpenDSObject,
(IADsOpenDSObject *)pNamespace,
DISPID_REGULAR
);
BAIL_ON_FAILURE(hr);
hr = LoadTypeInfoEntry(pDispMgr,
LIBID_ADs,
IID_IADsContainer,
(IADsContainer *)pNamespace,
DISPID_NEWENUM
);
BAIL_ON_FAILURE(hr);
pNamespace->_Credentials = Credentials;
pNamespace->_pDispMgr = pDispMgr;
*ppNamespace = pNamespace;
RRETURN(hr);
error:
delete pDispMgr;
RRETURN(hr);
}
STDMETHODIMP
CLDAPNamespace::OpenDSObject(
BSTR lpszDNName,
BSTR lpszUserName,
BSTR lpszPassword,
LONG lnReserved,
IDispatch FAR * * ppADsObj
)
{
HRESULT hr = S_OK;
IUnknown * pObject = NULL;
CCredentials Credentials(lpszUserName, lpszPassword, lnReserved);
hr = ::GetObject(
lpszDNName,
Credentials,
(LPVOID *)&pObject
);
BAIL_ON_FAILURE(hr);
hr = pObject->QueryInterface(
IID_IDispatch,
(void **)ppADsObj
);
BAIL_ON_FAILURE(hr);
error:
if (pObject) {
pObject->Release();
}
RRETURN_EXP_IF_ERR(hr);
}
HRESULT
CLDAPNamespace::ParsePath(
BSTR bstrADsPath,
DWORD dwType,
PPATH_OBJECTINFO pObjectInfo
)
/*++
Routine Description:
Parse a path based on the type and return the information in pObjectInfo
Arguments:
bstrADsPath - ads path to be parsed
dwType - the type of path to be parsed:
ADS_PARSE_FULL
ADS_PARSE_DN
ADS_PARSE_COMPONENT
pObjectInfo - The place where the parsed object is stored.
It assumes that this structure is valid and empty, and will
overwrite anything that is in there already.
Return Value:
S_OK on success, error code otherwise.
--*/
{
HRESULT hr = S_OK;
OBJECTINFO ObjInfo;
POBJECTINFO pObjInfo = &ObjInfo;
LPWSTR szPath = NULL;
memset(pObjInfo, 0, sizeof(OBJECTINFO));
switch (dwType) {
case ADS_PARSE_FULL:
{
hr = ADsObject(bstrADsPath, pObjInfo);
BAIL_ON_FAILURE(hr);
break;
}
case ADS_PARSE_DN:
{
WCHAR szToken[MAX_TOKEN_LENGTH];
DWORD dwToken;
hr = GetDisplayName(bstrADsPath, &szPath);
BAIL_ON_FAILURE(hr);
hr = InitObjectInfo(szPath,
pObjInfo);
BAIL_ON_FAILURE(hr);
CLexer Lexer(szPath);
Lexer.SetAtDisabler(TRUE);
hr = PathName(&Lexer,
pObjInfo);
BAIL_ON_FAILURE(hr);
hr = Lexer.GetNextToken(szToken,
&dwToken);
BAIL_ON_FAILURE(hr);
if (dwToken != TOKEN_END) {
hr = E_ADS_BAD_PATHNAME;
goto error;
}
break;
}
case ADS_PARSE_COMPONENT:
{
hr = GetDisplayName(bstrADsPath, &szPath);
BAIL_ON_FAILURE(hr);
CLexer Lexer(szPath);
hr = InitObjectInfo(szPath, pObjInfo);
BAIL_ON_FAILURE(hr);
Lexer.SetAtDisabler(TRUE);
hr = Component(&Lexer,
pObjInfo);
BAIL_ON_FAILURE(hr);
break;
}
default:
break;
}
//
// Setting new info
//
if (pObjInfo->ProviderName) {
pObjectInfo->ProviderName = AllocADsStr(pObjInfo->NamespaceName);
if (!pObjectInfo->ProviderName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
}
if (pObjInfo->TreeName) {
pObjectInfo->ServerName = AllocADsStr(pObjInfo->TreeName);
if (!pObjectInfo->ServerName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
}
if (pObjInfo->DisplayTreeName) {
pObjectInfo->DisplayServerName = AllocADsStr(pObjInfo->DisplayTreeName);
if (!pObjectInfo->DisplayServerName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
}
hr = SetObjInfoComponents(pObjInfo,
pObjectInfo);
BAIL_ON_FAILURE(hr);
pObjectInfo->NumComponents = pObjInfo->NumComponents;
pObjectInfo->dwPathType = (pObjInfo->dwPathType == PATHTYPE_X500) ?
ADS_PATHTYPE_LEAFFIRST : ADS_PATHTYPE_ROOTFIRST;
error:
if (szPath != NULL) {
FreeADsStr(szPath);
}
FreeObjectInfo(pObjInfo);
return (hr);
}
HRESULT
CLDAPNamespace::SetObjInfoComponents(
OBJECTINFO *pObjectInfo,
PATH_OBJECTINFO *pObjectInfoTarget
)
/*++
Routine Description:
Set all the compoents in an objinfo from another objinfo. Assumes that the
components in the target objinfo is empty. Users of this function can call
FreeObjInfo to free that data prior to this function call.
Arguments:
Return Value:
S_OK on success, error code otherwise.
--*/
{
DWORD NumComponents;
HRESULT hr = S_OK;
PWSTR pszPath = NULL;
NumComponents = 0;
while (NumComponents < pObjectInfo->NumComponents) {
if (pObjectInfo->ComponentArray[NumComponents].szComponent) {
pObjectInfoTarget->ComponentArray[NumComponents].szComponent =
AllocADsStr(pObjectInfo->ComponentArray[NumComponents].szComponent);
if (pObjectInfoTarget->ComponentArray[NumComponents].szComponent == NULL) {
pObjectInfoTarget->NumComponents = NumComponents;
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
pObjectInfoTarget->ProvSpecComponentArray[NumComponents].szComponent =
AllocADsStr(pObjectInfo->ComponentArray[NumComponents].szComponent);
if (pObjectInfoTarget->ProvSpecComponentArray[NumComponents].szComponent == NULL) {
pObjectInfoTarget->NumComponents = NumComponents;
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
}
if (pObjectInfo->ComponentArray[NumComponents].szValue) {
DWORD dwResult;
DWORD dwSize = 0;
pObjectInfoTarget->ComponentArray[NumComponents].szValue =
AllocADsStr(pObjectInfo->ComponentArray[NumComponents].szValue);
if (pObjectInfoTarget->ComponentArray[NumComponents].szValue == NULL) {
pObjectInfoTarget->NumComponents = NumComponents;
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
dwSize = wcslen(pObjectInfo->ComponentArray[NumComponents].szValue) + 1;
pszPath = (PWSTR)AllocADsMem(dwSize * sizeof(WCHAR));
if (pszPath == NULL) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
dwResult = DsUnquoteRdnValueWrapper(
wcslen(pObjectInfo->ComponentArray[NumComponents].szValue),
pObjectInfo->ComponentArray[NumComponents].szValue,
&dwSize,
pszPath);
if (dwResult == NO_ERROR) {
pszPath[dwSize] = NULL;
pObjectInfoTarget->ProvSpecComponentArray[NumComponents].szValue =
AllocADsStr(pszPath);
if (pObjectInfoTarget->ProvSpecComponentArray[NumComponents].szValue == NULL) {
pObjectInfoTarget->NumComponents = NumComponents;
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
}
if (pszPath) {
FreeADsMem(pszPath);
pszPath = NULL;
}
}
if (pObjectInfo->DisplayComponentArray[NumComponents].szComponent) {
pObjectInfoTarget->DisplayComponentArray[NumComponents].szComponent =
AllocADsStr(pObjectInfo->DisplayComponentArray[NumComponents].szComponent);
if (pObjectInfoTarget->DisplayComponentArray[NumComponents].szComponent == NULL) {
pObjectInfoTarget->NumComponents = NumComponents;
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
}
if (pObjectInfo->DisplayComponentArray[NumComponents].szValue) {
pObjectInfoTarget->DisplayComponentArray[NumComponents].szValue =
AllocADsStr(pObjectInfo->DisplayComponentArray[NumComponents].szValue);
if (pObjectInfoTarget->DisplayComponentArray[NumComponents].szValue == NULL) {
pObjectInfoTarget->NumComponents = NumComponents;
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
}
NumComponents++;
}
pObjectInfoTarget->NumComponents = pObjectInfo->NumComponents;
return hr;
error:
FreeObjInfoComponents(pObjectInfoTarget);
if (pszPath) {
FreeADsMem(pszPath);
}
RRETURN_EXP_IF_ERR(hr);
}
void
CLDAPNamespace::FreeObjInfoComponents(
PATH_OBJECTINFO *pObjectInfo
)
/*++
Routine Description:
Free all the compoents in an objinfo
Arguments:
Return Value:
S_OK on success, error code otherwise.
--*/
{
DWORD NumComponents;
while (pObjectInfo->NumComponents > 0) {
pObjectInfo->NumComponents--;
NumComponents = pObjectInfo->NumComponents;
if (pObjectInfo->ComponentArray[NumComponents].szComponent) {
FreeADsStr(
pObjectInfo->ComponentArray[NumComponents].szComponent);
pObjectInfo->ComponentArray[NumComponents].szComponent = NULL;
}
if (pObjectInfo->ComponentArray[NumComponents].szValue) {
FreeADsStr(
pObjectInfo->ComponentArray[NumComponents].szValue);
pObjectInfo->ComponentArray[NumComponents].szValue = NULL;
}
if (pObjectInfo->DisplayComponentArray[NumComponents].szComponent) {
FreeADsStr(
pObjectInfo->DisplayComponentArray[NumComponents].szComponent);
pObjectInfo->DisplayComponentArray[NumComponents].szComponent = NULL;
}
if (pObjectInfo->DisplayComponentArray[NumComponents].szValue) {
FreeADsStr(
pObjectInfo->DisplayComponentArray[NumComponents].szValue);
pObjectInfo->DisplayComponentArray[NumComponents].szValue = NULL;
}
if (pObjectInfo->ProvSpecComponentArray[NumComponents].szComponent) {
FreeADsStr(
pObjectInfo->ProvSpecComponentArray[NumComponents].szComponent);
pObjectInfo->ProvSpecComponentArray[NumComponents].szComponent = NULL;
}
if (pObjectInfo->ProvSpecComponentArray[NumComponents].szValue) {
FreeADsStr(
pObjectInfo->ProvSpecComponentArray[NumComponents].szValue);
pObjectInfo->ProvSpecComponentArray[NumComponents].szValue = NULL;
}
}
}
void
CLDAPNamespace::SetComponent(
LPWSTR szReturn,
DWORD cComponents,
DWORD dwEscapedMode
)
/*++
Routine Description:
Set an individual component in the pathname. For internal use only.
Not exposed.
Arguments:
szReturn - the buffer to store the return value
cComponents - the component number to be set
Return Value:
S_OK on success, error code otherwise.
--*/
{
PATH_COMPONENT* pComponent = NULL;
ASSERT(dwEscapedMode != ADS_ESCAPEDMODE_DEFAULT);
if (dwEscapedMode == ADS_ESCAPEDMODE_OFF){
pComponent = _pObjectInfo->ComponentArray;
}
else if (dwEscapedMode == ADS_ESCAPEDMODE_OFF_EX){
pComponent = _pObjectInfo->ProvSpecComponentArray;
}
else if (dwEscapedMode == ADS_ESCAPEDMODE_ON) {
pComponent = _pObjectInfo->DisplayComponentArray;
}
if (_fNamingAttribute) {
wcscat(szReturn, pComponent[cComponents].szComponent);
if (pComponent[cComponents].szValue) {
wcscat(szReturn,
TEXT("="));
wcscat(szReturn,
pComponent[cComponents].szValue);
}
}
else {
if (pComponent[cComponents].szValue) {
//
// If value exist, only show display value
//
wcscat(szReturn,
pComponent[cComponents].szValue);
}
else {
//
// else value is only stored in Component
//
wcscat(szReturn,
pComponent[cComponents].szComponent);
}
}
}
HRESULT
CLDAPNamespace::SetComponents(
LPWSTR szReturn,
BOOLEAN bIsWindowsPath,
LPWSTR chSeparator,
DWORD dwType,
DWORD dwEscapedMode
)
/*++
Routine Description:
Set components in the pathname. For internal use only. Not exposed.
Arguments:
szReturn - the buffer to store the return value
bIsWindowsPath - whether a windows path is to be returned
chSeparator - separator to be used
dwType - the type to be set
ADS_COMPONENT_LEAF
ADS_COMPONENT_DN
ADS_COMPONENT_PARENT
Return Value:
S_OK on success, error code otherwise.
--*/
{
HRESULT hr = S_OK;
BOOL bReverse;
long cComponents;
long dwLimit;
long dwOtherLimit = 0;
if (dwType == ADS_COMPONENT_LEAF) {
//
// Only returns the leaf component
//
if (_pObjectInfo->dwPathType == ADS_PATHTYPE_ROOTFIRST) {
if (_pObjectInfo->NumComponents > 0) {
SetComponent(szReturn,
_pObjectInfo->NumComponents - 1,
dwEscapedMode);
}
else {
hr = E_ADS_BAD_PATHNAME;
}
}
else {
if (_pObjectInfo->NumComponents != 0) {
SetComponent(szReturn,
0,
dwEscapedMode);
}
else {
hr = E_ADS_BAD_PATHNAME;
}
}
RRETURN(hr);
}
if (_pObjectInfo->dwPathType == ADS_PATHTYPE_ROOTFIRST) {
bReverse = !bIsWindowsPath;
}
else {
bReverse = bIsWindowsPath;
}
if (!bReverse) {
dwLimit = _pObjectInfo->NumComponents;
if (dwType == ADS_COMPONENT_PARENT) {
if (_pObjectInfo->dwPathType == ADS_PATHTYPE_ROOTFIRST)
dwLimit--;
else
dwOtherLimit++;
}
if (dwOtherLimit >= dwLimit) {
hr = E_ADS_BAD_PATHNAME;
goto error;
}
for (cComponents = dwOtherLimit; cComponents < dwLimit; cComponents++) {
SetComponent(szReturn,
cComponents,
dwEscapedMode);
if (cComponents != dwLimit - 1) {
wcscat(szReturn,
chSeparator);
}
}
}
else {
dwLimit = _pObjectInfo->NumComponents-1;
if (dwType == ADS_COMPONENT_PARENT) {
if (_pObjectInfo->dwPathType == ADS_PATHTYPE_ROOTFIRST)
dwLimit--;
else
dwOtherLimit++;
}
if (dwLimit < dwOtherLimit) {
hr = E_ADS_BAD_PATHNAME;
goto error;
}
for (cComponents = dwLimit ; (long)cComponents >= dwOtherLimit; cComponents--) {
SetComponent(szReturn,
cComponents,
dwEscapedMode);
if (cComponents != dwOtherLimit) {
wcscat(szReturn, chSeparator);
}
}
}
error:
RRETURN(S_OK);
}
DWORD CountPath(
PPATH_OBJECTINFO pObjectInfo
)
{
DWORD dwPath = 4; // Basic needs '://' and '/' for servername
DWORD i;
if (pObjectInfo->ProviderName) {
dwPath += wcslen(pObjectInfo->ProviderName);
}
if (pObjectInfo->DisplayServerName) {
dwPath += wcslen(pObjectInfo->DisplayServerName);
}
for (i=0;i<pObjectInfo->NumComponents;i++) {
if (pObjectInfo->DisplayComponentArray[i].szComponent) {
dwPath += wcslen(pObjectInfo->DisplayComponentArray[i].szComponent);
}
if (pObjectInfo->DisplayComponentArray[i].szValue) {
dwPath += wcslen(pObjectInfo->DisplayComponentArray[i].szValue);
}
//
// Add one for comma separator, one for equal sign
//
dwPath+=2;
}
return dwPath;
}
STDMETHODIMP
CLDAPNamespace::ConstructPath(
PPATH_OBJECTINFO pObjectInfo,
DWORD dwFormatType,
DWORD dwFlag,
DWORD dwEscapedMode,
BSTR *pbstrADsPath
)
/*++
Routine Description:
Given an objectinfo structure, and the settings required, this function
assembles the path and returns it in pbstrADsPath
Arguments:
pObjectInfo - the input object info structure
dwFormatType- The format type passed in from Retrieve.
dwFlag - the flag to be set
ADS_CONSTRUCT_ESCAPED
ADS_CONSTRUCT_NAMINGATTRIBUTE
pbstrADsPath - the returned path
Return Value:
S_OK on success, error code otherwise.
--*/
{
HRESULT hr = S_OK;
PWSTR szReturn = NULL;
long cComponents;
DWORD dwPath = 0;
DWORD dwEscapedInternal;
dwEscapedInternal = dwEscapedMode;
if (dwEscapedMode == ADS_ESCAPEDMODE_DEFAULT) {
dwEscapedInternal = ADS_ESCAPEDMODE_OFF;
}
if (!pbstrADsPath) {
hr = E_INVALIDARG;
goto error;
}
dwPath = CountPath(pObjectInfo);
szReturn = (PWSTR)AllocADsMem((dwPath + 1)* sizeof(WCHAR));
if (szReturn == NULL) {
hr = E_OUTOFMEMORY;
goto error;
}
_fNamingAttribute = (BOOLEAN)(dwFlag & ADS_CONSTRUCT_NAMINGATTRIBUTE);
_pObjectInfo = pObjectInfo; // useful in SetComponet() and SetComponents()
wcscpy(szReturn,TEXT(""));
switch (dwFormatType) {
case ADS_FORMAT_WINDOWS:
case ADS_FORMAT_WINDOWS_NO_SERVER:
if (dwEscapedMode == ADS_ESCAPEDMODE_DEFAULT) {
dwEscapedInternal = ADS_ESCAPEDMODE_ON;
}
if (!pObjectInfo->ProviderName) {
hr = E_FAIL; // Need Error Code
goto error;
}
wcscat(szReturn,pObjectInfo->ProviderName);
wcscat(szReturn,TEXT("://"));
if (dwFormatType == ADS_FORMAT_WINDOWS) {
if (dwEscapedInternal == ADS_ESCAPEDMODE_ON) {
if (pObjectInfo->DisplayServerName && (*(pObjectInfo->DisplayServerName))) {
wcscat(szReturn,pObjectInfo->DisplayServerName);
if (pObjectInfo->NumComponents>0) {
wcscat(szReturn,TEXT("/"));
}
}
}
else {
if (pObjectInfo->ServerName && (*(pObjectInfo->ServerName))) {
wcscat(szReturn,pObjectInfo->ServerName);
if (pObjectInfo->NumComponents>0) {
wcscat(szReturn,TEXT("/"));
}
}
}
}
hr = SetComponents(szReturn,
TRUE,
TEXT("/"),
ADS_COMPONENT_DN,
dwEscapedInternal);
BAIL_ON_FAILURE(hr);
break;
case ADS_FORMAT_WINDOWS_DN:
hr = SetComponents(szReturn,
TRUE,
TEXT("/"),
ADS_COMPONENT_DN,
dwEscapedInternal);
BAIL_ON_FAILURE(hr);
break;
case ADS_FORMAT_WINDOWS_PARENT:
hr = SetComponents(szReturn,
TRUE,
TEXT("/"),
ADS_COMPONENT_PARENT,
dwEscapedInternal);
BAIL_ON_FAILURE(hr);
break;
case ADS_FORMAT_X500:
case ADS_FORMAT_X500_NO_SERVER:
if (dwEscapedMode == ADS_ESCAPEDMODE_DEFAULT) {
dwEscapedInternal = ADS_ESCAPEDMODE_ON;
}
if (!pObjectInfo->ProviderName) {
hr = E_FAIL; // Need Error Code
goto error;
}
wcscat(szReturn,pObjectInfo->ProviderName);
wcscat(szReturn,TEXT("://"));
if (dwFormatType == ADS_FORMAT_X500) {
if (dwEscapedInternal == ADS_ESCAPEDMODE_ON) {
if (pObjectInfo->DisplayServerName && (*(pObjectInfo->DisplayServerName))) {
wcscat(szReturn,pObjectInfo->DisplayServerName);
if (pObjectInfo->NumComponents>0) {
wcscat(szReturn,TEXT("/"));
}
}
}
else {
if (pObjectInfo->ServerName && (*(pObjectInfo->ServerName))) {
wcscat(szReturn,pObjectInfo->ServerName);
if (pObjectInfo->NumComponents>0) {
wcscat(szReturn,TEXT("/"));
}
}
}
}
hr = SetComponents(szReturn,
FALSE,
TEXT(","),
ADS_COMPONENT_DN,
dwEscapedInternal);
BAIL_ON_FAILURE(hr);
break;
case ADS_FORMAT_X500_DN:
hr = SetComponents(szReturn,
FALSE,
TEXT(","),
ADS_COMPONENT_DN,
dwEscapedInternal);
BAIL_ON_FAILURE(hr);
break;
case ADS_FORMAT_X500_PARENT:
hr = SetComponents(szReturn,
FALSE,
TEXT(","),
ADS_COMPONENT_PARENT,
dwEscapedInternal);
BAIL_ON_FAILURE(hr);
break;
case ADS_FORMAT_LEAF:
//
// Reverse only if pathtype is X500. In that case, we need to get
// the first element but not the last
//
hr = SetComponents(szReturn,
NULL,
NULL,
ADS_COMPONENT_LEAF,
dwEscapedInternal);
BAIL_ON_FAILURE(hr);
break;
default:
hr = E_INVALIDARG;
goto error;
}
hr = ADsAllocString(szReturn, pbstrADsPath);
error:
if (szReturn) {
FreeADsMem(szReturn);
}
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CLDAPNamespace::GetEscapedElement(
LONG lnReserved,
BSTR bstrInStr,
BSTR* pbstrOutStr
)
{
HRESULT hr = S_OK;
if (FAILED(hr = ValidateOutParameter(pbstrOutStr))){
RRETURN_EXP_IF_ERR(hr);
}
if (!bstrInStr) {
RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
}
hr = HelperEscapeRDN(bstrInStr, pbstrOutStr);
RRETURN(hr);
}
/////////////////////////////////////////////////////////////////////
// escape.cpp
//
// routine to escape special characters in an RDN
//
// ASSUMPTIONS/RESTRICTIONS:
// - we assume that the input string is un-escaped in any way
// - we assume that the input string is a correctly attributed
// RDN, and we directly copy everything up to and including
// the first '='
//
// HISTORY
// 3-dec-98 jimharr Creation.
/////////////////////////////////////////////////////////////////////
static WCHAR specialChars[] = L",=\r\n+<>#;\"\\/";
HRESULT
HelperEscapeRDN (
IN BSTR bstrIn,
OUT BSTR * pbstrOut
)
{
//
// algorithm:
// create temporary buffer to hold escaped RDN
// skip up to first '=', to skip attributeType
// examine each character, if it needs escaping
// put a '\' in the dest.
// copy the character
// continue until done
//
// alloc BSTR of correct size to return
// copy string, delete temp buffer
//
HRESULT hr = S_OK;
WCHAR *pchSource = NULL;
WCHAR *pchDest = NULL;
WCHAR *pBuffer = NULL;
WCHAR *pTmp;
pBuffer = (WCHAR* ) AllocADsMem((wcslen(bstrIn) * 3 + 1) * sizeof(WCHAR));
if (pBuffer == NULL)
BAIL_ON_FAILURE(hr=E_OUTOFMEMORY);
pchDest = pBuffer;
pchSource = (WCHAR *)bstrIn;
// copy up to the equals sign
do {
*pchDest = *pchSource;
pchSource++;
pchDest++;
} while ((*pchSource != L'=') && (*pchSource != L'\0'));
// if we didn't find an '=', bail
if (*pchSource == L'\0') {
BAIL_ON_FAILURE(hr=E_INVALIDARG);
}
// copy the '='
*pchDest = *pchSource;
pchSource++;
pchDest++;
//
// If the first character after the '=' is a space, we'll escape it.
// According to LDAP, if the value starts with a space, it has to be escaped
// or else it will be trimmed.
//
if (*pchSource == L' ') {
*pchDest = L'\\';
pchDest++;
*pchDest = *pchSource;
pchDest++;
pchSource++;
}
while (*pchSource != L'\0') {
//
// If we have reached the last character and it is a space, we'll escape
// it
//
if ( (*(pchSource+1) == L'\0') &&
((*pchSource) == L' ') ) {
*pchDest = L'\\';
pchDest++;
*pchDest = *pchSource;
pchDest++;
break;
}
if (NeedsEscaping(*pchSource)) {
*pchDest = L'\\';
pchDest++;
}
pTmp = EscapedVersion(*pchSource);
if (pTmp != NULL) {
wcscpy (pchDest, pTmp);
pchDest += wcslen(pTmp);
} else {
*pchDest = *pchSource;
pchDest++;
}
pchSource++;
}
*pchDest = L'\0';
*pbstrOut = SysAllocString (pBuffer);
error:
if (pBuffer) {
FreeADsMem(pBuffer);
}
return (hr);
}
BOOL
NeedsEscaping (WCHAR c)
{
WCHAR * pSpecial = specialChars;
while (*pSpecial != L'\0'){
if (*pSpecial == c) return TRUE;
pSpecial++;
}
return FALSE;
}
WCHAR *
EscapedVersion (WCHAR c)
{
if (c == L'\r')
return L"0D";
if (c == L'\n')
return L"0A";
return NULL;
}