2025-04-27 07:49:33 -04:00

500 lines
12 KiB
C++

//+----------------------------------------------------------------------------
//
// Copyright (C) 2000, Microsoft Corporation
//
// File: DfsAdsiApi.cxx
//
// Contents: Contains APIs to communicate with the DS
//
// Classes: none.
//
// History: March. 13 2001, Author: Rohanp
//
//-----------------------------------------------------------------------------
#include "DfsAdsiAPi.hxx"
#include "DfsError.hxx"
#include "dfsgeneric.hxx"
#include "dfsinit.hxx"
#include "lm.h"
#include "lmdfs.h"
//
// dfsdev: comment this properly.
//
LPWSTR RootDseString=L"LDAP://RootDSE";
//
// dfscreatedn take a pathstring and fills it with the information
// necessary for the path to be used as a Distinguished Name.
// It starts the string with LDAP://, follows that with a DCName
// if supplied, and then adds the array of CNNames passed in
// one after the other , each one followed by a ,
// the final outcome is something like:
// LDAP://ntdev-dc-01/CN=Dfs-Configuration, CN=System, Dc=Ntdev, etc
//
//dfsdev: this function should take a path len and return overflow
// if we overrun the buffer!!!
VOID
DfsCreateDN(
LPWSTR PathString,
LPWSTR DCName,
LPWSTR *CNNames )
{
LPWSTR *InArray = CNNames;
LPWSTR CNName;
wcscpy(PathString, L"LDAP://");
//
// if the dc name is specified, we want to go to a specific dc
// add that in.
//
if ((DCName != NULL) && (wcslen(DCName) > 0))
{
wcscat(PathString, DCName);
wcscat(PathString, L"/");
}
//
// Now treat the CNNames as an array of LPWSTR and add each one of
// the lpwstr to our path.
//
if (CNNames != NULL)
{
while ((CNName = *InArray++) != NULL)
{
wcscat(PathString, CNName);
if (*InArray != NULL)
{
wcscat(PathString,L",");
}
}
}
return NOTHING;
}
DFSSTATUS
DfsGenerateDfsAdNameContext(
PUNICODE_STRING pString )
{
IADs *pRootDseObject;
HRESULT HResult;
VARIANT VarDSRoot;
DFSSTATUS Status;
HResult = ADsGetObject( RootDseString,
IID_IADs,
(void **)&pRootDseObject );
if (SUCCEEDED(HResult))
{
VariantInit( &VarDSRoot );
// Get the Directory Object on the root DSE, to get to the server configuration
HResult = pRootDseObject->Get(L"defaultNamingContext",&VarDSRoot);
if (SUCCEEDED(HResult))
{
DfsCreateUnicodeStringFromString( pString,
(LPWSTR)V_BSTR(&VarDSRoot) );
}
VariantClear(&VarDSRoot);
pRootDseObject->Release();
}
Status = DfsGetErrorFromHr(HResult);
return Status;
}
#if 0
HRESULT
DfsGetADObject(
LPWSTR DCName,
REFIID Id,
LPWSTR ObjectName,
PVOID *ppObject )
{
HRESULT HResult;
LPOLESTR PathString;
VARIANT VarDSRoot;
LPWSTR CNNames[4];
LPWSTR DCNameToUse;
UNICODE_STRING GotDCName;
IADs *pRootDseObject;
ULONG Index;
PathString = new OLECHAR[MAX_PATH];
if (PathString == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
RtlInitUnicodeString( &GotDCName, NULL );
DCNameToUse = DCName;
if (IsEmptyString(DCNameToUse))
{
DfsGetBlobDCName( &GotDCName );
DCNameToUse = GotDCName.Buffer;
}
CNNames[0] = RootDseString;
CNNames[1] = NULL;
DfsCreateDN( PathString,
DCNameToUse,
CNNames );
//
// contact the rootdse (local domain), and get the default
// naming context. Use that to get to the dfs configuration
// object.
//
HResult = ADsGetObject(PathString,
IID_IADs,
(void**)&pRootDseObject);
if (SUCCEEDED(HResult))
{
VariantInit( &VarDSRoot );
// Get the Directory Object on the root DSE, to get to the server configuration
HResult = pRootDseObject->Get(L"defaultNamingContext",&VarDSRoot);
if (SUCCEEDED(HResult))
{
Index = 0;
if (ObjectName != NULL)
{
CNNames[Index++] = ObjectName;
}
CNNames[Index++] = DFS_AD_CONFIG_DATA;
CNNames[Index++] = (LPWSTR)V_BSTR(&VarDSRoot);
CNNames[Index++] = NULL;
DfsCreateDN( PathString, DCNameToUse, CNNames);
VariantClear(&VarDSRoot);
}
pRootDseObject->Release();
}
//
// open dfs configuration container for enumeration.
//
if (SUCCEEDED(HResult))
{
HResult = ADsGetObject(PathString,
Id,
ppObject );
}
//
// Since we initialized DCName with empty string, it is benign
// to call this, even if we did not call GetBlobDCName above.
//
DfsReleaseBlobDCName( &GotDCName );
delete [] PathString;
return HResult;
}
#endif
HRESULT
DfsGetADObject(
LPWSTR DCName,
REFIID Id,
LPWSTR ObjectName,
PVOID *ppObject )
{
HRESULT HResult;
LPOLESTR PathString;
LPWSTR CNNames[4];
LPWSTR DCNameToUse;
UNICODE_STRING GotDCName;
ULONG Index;
PathString = new OLECHAR[MAX_PATH];
if (PathString == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
RtlInitUnicodeString( &GotDCName, NULL );
DCNameToUse = DCName;
if (IsEmptyString(DCNameToUse))
{
DfsGetBlobDCName( &GotDCName );
DCNameToUse = GotDCName.Buffer;
}
Index = 0;
if (ObjectName != NULL)
{
CNNames[Index++] = ObjectName;
}
CNNames[Index++] = DFS_AD_CONFIG_DATA;
CNNames[Index++] = DfsGetDfsAdNameContextString();
CNNames[Index++] = NULL;
DfsCreateDN( PathString, DCNameToUse, CNNames);
//
// open dfs configuration container for enumeration.
//
HResult = ADsOpenObject(PathString,
NULL,
NULL,
ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND | ADS_SERVER_BIND,
Id,
ppObject );
//
// Since we initialized DCName with empty string, it is benign
// to call this, even if we did not call GetBlobDCName above.
//
DfsReleaseBlobDCName( &GotDCName );
delete [] PathString;
return HResult;
}
//
// Given the root share name, get the root object.
//
DFSSTATUS
DfsGetDfsRootADObject(
LPWSTR DCName,
LPWSTR RootName,
IADs **ppRootObject )
{
HRESULT HResult;
LPWSTR RootCNName;
DFSSTATUS Status = ERROR_SUCCESS;
RootCNName = new WCHAR[MAX_PATH];
if (RootCNName == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
wcscpy(RootCNName, L"CN=");
wcscat(RootCNName, RootName);
HResult = DfsGetADObject( DCName,
IID_IADs,
RootCNName,
(PVOID *)ppRootObject );
delete [] RootCNName;
Status = DfsGetErrorFromHr(HResult);
return Status;
}
DFSSTATUS
PackRootName(
LPWSTR Name,
PDFS_INFO_200 pDfsInfo200,
PULONG pBufferSize,
PULONG pTotalSize )
{
ULONG BufferLen = (wcslen(Name) + 1) * sizeof(WCHAR);
ULONG NeedSize = sizeof(DFS_INFO_200) + BufferLen;
DFSSTATUS Status = ERROR_SUCCESS;
*pTotalSize += NeedSize;
if (*pBufferSize >= NeedSize)
{
ULONG_PTR pStringBuffer;
pStringBuffer = (ULONG_PTR)(pDfsInfo200) + *pBufferSize - BufferLen;
wcscpy( (LPWSTR)pStringBuffer, &Name[3] );
pDfsInfo200->FtDfsName = (LPWSTR)pStringBuffer;
*pBufferSize -= NeedSize;
}
else
{
Status = ERROR_BUFFER_OVERFLOW;
*pBufferSize = 0;
}
return Status;
}
HRESULT
DfsGetDfsConfigurationObject(
LPWSTR DCName,
IADsContainer **ppDfsConfiguration )
{
HRESULT HResult;
HResult = DfsGetADObject( DCName,
IID_IADsContainer,
NULL,
(PVOID *)ppDfsConfiguration );
return HResult;
}
DFSSTATUS
DfsDeleteDfsRootObject(
LPWSTR DCName,
LPWSTR RootName )
{
BSTR ObjectName, ObjectClass;
DFSSTATUS Status;
HRESULT HResult;
IADsContainer *pDfsConfiguration;
IADs *pRootObject;
Status = DfsGetDfsRootADObject( DCName,
RootName,
&pRootObject );
if (Status == ERROR_SUCCESS)
{
HResult = DfsGetDfsConfigurationObject( DCName,
&pDfsConfiguration );
if (SUCCEEDED(HResult))
{
HResult = pRootObject->get_Name(&ObjectName);
if (SUCCEEDED(HResult))
{
HResult = pRootObject->get_Class(&ObjectClass);
if (SUCCEEDED(HResult))
{
HResult = pDfsConfiguration->Delete( ObjectClass,
ObjectName );
SysFreeString(ObjectClass);
}
SysFreeString(ObjectName);
}
pDfsConfiguration->Release();
}
pRootObject->Release();
Status = DfsGetErrorFromHr(HResult);
}
return Status;
}
DFSSTATUS
DfsEnumerateDfsADRoots(
LPWSTR DCName,
PULONG_PTR pBuffer,
PULONG pBufferSize,
PULONG pEntriesRead,
PULONG pSizeRequired )
{
HRESULT HResult;
IADsContainer *pDfsConfiguration;
IEnumVARIANT *pEnum;
ULONG TotalSize = 0;
ULONG TotalEntries = 0;
PDFS_INFO_200 pDfsInfo200;
ULONG BufferSize = *pBufferSize;
DFSSTATUS Status;
//
// point the dfsinfo200 structure to the start of buffer passed in
// we will use this as an array of info200 buffers.
//
pDfsInfo200 = (PDFS_INFO_200)*pBuffer;
HResult = DfsGetDfsConfigurationObject( DCName,
&pDfsConfiguration );
if (SUCCEEDED(HResult))
{
HResult = ADsBuildEnumerator( pDfsConfiguration,
&pEnum );
if (SUCCEEDED(HResult))
{
VARIANT Variant;
ULONG Fetched;
BSTR BString;
IADs *pRootObject;
VariantInit(&Variant);
while ((HResult = ADsEnumerateNext(pEnum,
1,
&Variant,
&Fetched)) == S_OK)
{
IDispatch *pDisp;
pDisp = V_DISPATCH(&Variant);
pDisp->QueryInterface(IID_IADs, (void **)&pRootObject);
pDisp->Release();
pRootObject->get_Name(&BString);
Status = PackRootName( BString, pDfsInfo200, &BufferSize, &TotalSize );
pRootObject->Release();
// DfsDev: investigate. this causes an av.
// VariantClear(&Variant);
if (Status == ERROR_SUCCESS)
{
TotalEntries++;
pDfsInfo200++;
}
}
if (HResult == S_FALSE)
{
HResult = S_OK;
}
ADsFreeEnumerator( pEnum );
}
pDfsConfiguration->Release();
}
Status = DfsGetErrorFromHr(HResult);
if (Status == ERROR_SUCCESS)
{
*pSizeRequired = TotalSize;
if (TotalSize > *pBufferSize)
{
Status = ERROR_BUFFER_OVERFLOW;
}
else
{
*pEntriesRead = TotalEntries;
}
}
return Status;
}