500 lines
12 KiB
C++
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|