3612 lines
94 KiB
C++
3612 lines
94 KiB
C++
//+----------------------------------------------------------------------------
|
||
//
|
||
// Copyright (C) 1995, Microsoft Corporation
|
||
//
|
||
// File: CLdpStor.hxx
|
||
//
|
||
// Contents: Implementation of classes derived from CStorage and
|
||
// CEnumStorage that use an LDAP DS for persistent storage.
|
||
//
|
||
// In addition to providing this, this class
|
||
// maintains a global mapping from the Prefix property to
|
||
// "object name" in an instance of CStorageDirectory. Thus, given
|
||
// a Prefix, one can find the object path.
|
||
//
|
||
// Note that this map from Prefix to object path has the
|
||
// following restrictions:
|
||
//
|
||
// o At process start time, all objects are "read in" and their
|
||
// ReadIdProps() method called. This is needed to populate the
|
||
// map.
|
||
//
|
||
// o When a new object is created, its SetIdProps() method must
|
||
// be called before it can be located via the map.
|
||
//
|
||
// o Maps are many to 1 - many EntryPaths may map to the same
|
||
// object. At no point in time can one try to map the same
|
||
// EntryPath to many objects.
|
||
//
|
||
// Classes: CLdap
|
||
// CLdapStorage
|
||
// CLdapEnumDirectory
|
||
//
|
||
// Functions:
|
||
//
|
||
// History: 12-19-95 Milans created
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
#include "headers.hxx"
|
||
#pragma hdrstop
|
||
|
||
#include <ntldap.h>
|
||
|
||
#include "marshal.hxx"
|
||
#include "winldap.h"
|
||
#include "dsgetdc.h"
|
||
#include "setup.hxx"
|
||
#include "ftsup.hxx"
|
||
#include "dfsmwml.h"
|
||
#include "cldap.hxx"
|
||
|
||
//
|
||
// Helper function prototypes
|
||
//
|
||
|
||
DWORD
|
||
GetDcName(
|
||
IN LPCSTR DomainName OPTIONAL,
|
||
IN DWORD RetryCount,
|
||
OUT LPWSTR *DCName);
|
||
|
||
DWORD
|
||
GetConfigurationDN(
|
||
LPWSTR *pwszDN);
|
||
|
||
DWORD
|
||
InitializeVolumeObject(
|
||
PWSTR pwszVolName,
|
||
BOOLEAN bInitVol,
|
||
BOOLEAN SyncRemoteServerName=FALSE);
|
||
|
||
|
||
INIT_LDAP_OBJECT_MARSHAL_INFO();
|
||
INIT_LDAP_PKT_MARSHAL_INFO();
|
||
INIT_LDAP_DFS_VOLUME_PROPERTIES_MARSHAL_INFO();
|
||
|
||
DWORD
|
||
ProcessSiteTable(
|
||
PBYTE pData,
|
||
ULONG cbData,
|
||
ULONG Count,
|
||
PUNICODE_STRING pustr);
|
||
|
||
extern PLDAP pLdapConnection;
|
||
|
||
extern HANDLE hSyncEvent;
|
||
|
||
|
||
extern "C"
|
||
DWORD
|
||
DfsGetFtServersFromDs(
|
||
PLDAP pLDAP,
|
||
LPWSTR wszDomainName,
|
||
LPWSTR wszDfsName,
|
||
LPWSTR **List
|
||
);
|
||
|
||
|
||
//
|
||
// The global instance of CLdap
|
||
//
|
||
|
||
CLdap *pDfsmLdap = NULL;
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::CLdap
|
||
//
|
||
// Synopsis: Constructor for CLdap - Initializes the private Object table.
|
||
//
|
||
// Arguments: [wszDfsName] -- Name of the fault tolerant Dfs. Looks like
|
||
// "NtBuilds".
|
||
// [pdwErr] -- On return, the result of initializing the instance
|
||
//
|
||
// Returns: Result returned in pdwErr argument:
|
||
//
|
||
// [ERROR_SUCCESS] -- Successfully initialized
|
||
//
|
||
// [ERROR_INSUFFICIENT_RESOURCES] -- Out of memory.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
CLdap::CLdap(
|
||
IN LPWSTR wszDfsName,
|
||
OUT LPDWORD pdwErr)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
|
||
IDfsVolInlineDebOut((
|
||
DEB_TRACE, "CLdap::+CLdap(0x%x)\n",
|
||
this));
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::CLdap()\n");
|
||
#endif
|
||
|
||
_fDirty = FALSE;
|
||
_cEntries = 0;
|
||
_cRef = 0;
|
||
ZeroMemory( &_ObjectTableId, sizeof(GUID) );
|
||
_wszDfsName = NULL;
|
||
_wszObjectDN = NULL;
|
||
_cEntriesAllocated = 0;
|
||
_ldapPkt.cLdapObjects = 0;
|
||
_ldapPkt.rgldapObjects = NULL;
|
||
_pBuffer = NULL;
|
||
_RemoteServerList = NULL;
|
||
|
||
if (pLdapConnection != NULL) {
|
||
if (DfsSvcLdap)
|
||
DbgPrint("CLdap::Cldap:ldap_unbind(pLdapConnection)\n");
|
||
ldap_unbind(pLdapConnection);
|
||
}
|
||
pLdapConnection = NULL;
|
||
|
||
if (!DfsInitializeUnicodePrefix(&_ObjectTable))
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
_wszDfsName = new WCHAR [ wcslen(wszDfsName) + 1 ];
|
||
|
||
if (_wszDfsName != NULL)
|
||
wcscpy(_wszDfsName, wszDfsName);
|
||
else
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS)
|
||
dwErr = GetConfigurationDN( &_wszObjectDN);
|
||
|
||
*pdwErr = dwErr;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::~CLdap
|
||
//
|
||
// Synopsis: Destructor for CLdap - Deallocates the Object table and
|
||
// deletes all the Object entries.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
CLdap::~CLdap()
|
||
{
|
||
PLDAP_OBJECT p;
|
||
PNAME_PAGE pNamePage;
|
||
PNAME_PAGE pNextPage;
|
||
|
||
IDfsVolInlineDebOut((
|
||
DEB_TRACE, "CLdap::~CLdap(0x%x)\n",
|
||
this));
|
||
|
||
ASSERT( _cRef == 0 );
|
||
|
||
_DestroyObjectTable();
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::~CLdap()\n");
|
||
#endif
|
||
|
||
//
|
||
// We destroy pages as we walk the list, so
|
||
// we need to save the pNextPage before the deallocation.
|
||
//
|
||
for (pNamePage = _ObjectTable.NamePageList.pFirstPage;
|
||
pNamePage != NULL;
|
||
pNamePage = pNextPage
|
||
) {
|
||
pNextPage = pNamePage->pNextPage;
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::~CLdap:Releasing NamePage@0x%x\n", pNamePage);
|
||
#endif
|
||
free(pNamePage);
|
||
}
|
||
|
||
if (_ldapPkt.rgldapObjects != NULL)
|
||
delete [] _ldapPkt.rgldapObjects;
|
||
|
||
if (_pBuffer != NULL)
|
||
delete [] _pBuffer;
|
||
|
||
if (_wszDfsName != NULL)
|
||
delete [] _wszDfsName;
|
||
|
||
if (_wszObjectDN != NULL)
|
||
delete [] _wszObjectDN;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::AddRef
|
||
//
|
||
// Synopsis: Increases the ref count on the in-memory Pkt. If the
|
||
// refcount is going from 0 to 1, an attempt is made to refresh
|
||
// the in-memory Pkt from the Ldap server.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns:
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
|
||
DWORD
|
||
CLdap::AddRef(BOOLEAN SyncRemoteServerName=FALSE)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::AddRef()\n"));
|
||
|
||
_cRef++;
|
||
|
||
if (DfsSvcVerbose & 0x80000000)
|
||
DbgPrint("CLdap::AddRef: %d\n", _cRef);
|
||
|
||
if (_cRef == 1) {
|
||
dwErr = DfspConnectToLdapServer();
|
||
if (dwErr == ERROR_SUCCESS && !_IsObjectTableUpToDate()) {
|
||
dwErr = _ReadObjectTable();
|
||
if (pDfsmStorageDirectory != NULL)
|
||
delete pDfsmStorageDirectory;
|
||
if (pDfsmSites != NULL)
|
||
delete pDfsmSites;
|
||
pDfsmSites = new CSites(LDAP_VOLUMES_DIR SITE_ROOT, &dwErr);
|
||
pDfsmStorageDirectory = new CStorageDirectory( &dwErr );
|
||
DfsmMarkStalePktEntries();
|
||
DfsmInitLocalPartitions();
|
||
InitializeVolumeObject( DOMAIN_ROOT_VOL, TRUE, SyncRemoteServerName);
|
||
DfsmFlushStalePktEntries();
|
||
DfsmPktFlushCache();
|
||
}
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::AddRef() exit %d\n", dwErr));
|
||
|
||
return dwErr;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::Release
|
||
//
|
||
// Synopsis: Decrease the ref count on the in-memory Pkt. If the
|
||
// refcount is going from 1 to 0, then attempt to flush the
|
||
// Pkt to the ldap server, if something has changed.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdap::Release()
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::Release()\n"));
|
||
|
||
if (_cRef > 0)
|
||
_cRef--;
|
||
|
||
if (DfsSvcVerbose & 0x80000000)
|
||
DbgPrint("CLdap::Release: %d\n", _cRef);
|
||
|
||
if (_cRef == 0)
|
||
dwErr = Flush();
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::Release() exit\n"));
|
||
|
||
return dwErr;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::Flush
|
||
//
|
||
// Synopsis: Flush the Pkt to the ldap server, if something has changed
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdap::Flush()
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::Flush()\n"));
|
||
|
||
if (_fDirty) {
|
||
dwErr = DfspConnectToLdapServer();
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
dwErr = _FlushObjectTable();
|
||
if (dwErr == ERROR_SUCCESS)
|
||
_fDirty = FALSE;
|
||
}
|
||
|
||
if(dwErr != ERROR_SUCCESS) {
|
||
//
|
||
// Reset dfs
|
||
//
|
||
|
||
SetEvent(hSyncEvent);
|
||
|
||
}
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::Flush() exit\n"));
|
||
|
||
return dwErr;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::CreateObject
|
||
//
|
||
// Synopsis: Creates a new object in the in-memory Pkt.
|
||
//
|
||
// Arguments: [wszObjectName] -- Name of object to create.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully created the object.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory condition.
|
||
//
|
||
// [ERROR_ALREADY_EXISTS] -- An object with the given name
|
||
// already exists
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD CLdap::CreateObject(
|
||
IN LPCWSTR wszObjectName)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
PLDAP_OBJECT p;
|
||
UNICODE_STRING ustrObject, ustrRemaining;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::CreateObject(%ws)\n", wszObjectName);
|
||
#endif
|
||
|
||
RtlInitUnicodeString( &ustrObject, wszObjectName );
|
||
|
||
p = (PLDAP_OBJECT) DfsFindUnicodePrefix(
|
||
&_ObjectTable,
|
||
&ustrObject,
|
||
&ustrRemaining );
|
||
|
||
if (p == NULL || ustrRemaining.Length != 0) {
|
||
|
||
p = (PLDAP_OBJECT) new BYTE [ sizeof(LDAP_OBJECT) +
|
||
(wcslen(wszObjectName) + 1) *
|
||
sizeof(WCHAR) ];
|
||
|
||
if (p != NULL) {
|
||
|
||
UNICODE_STRING ustrObjectName;
|
||
|
||
RtlInitUnicodeString(&ustrObjectName, wszObjectName);
|
||
|
||
p->wszObjectName = (PWCHAR) (p+1);
|
||
|
||
wcscpy(p->wszObjectName, wszObjectName);
|
||
|
||
p->cbObjectData = 0;
|
||
|
||
p->pObjectData = NULL;
|
||
|
||
if (DfsInsertUnicodePrefix(&_ObjectTable, &ustrObjectName, p)) {
|
||
|
||
_cEntries++;
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
delete p;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_ALREADY_EXISTS;
|
||
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::CreateObject returning %d\n", dwErr);
|
||
#endif
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::DeleteObject
|
||
//
|
||
// Synopsis: Deletes an object from the in-memory Pkt.
|
||
//
|
||
// Arguments: [wszObjectName] -- Name of object to delete.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully created the object.
|
||
//
|
||
// [ERROR_FILE_NOT_FOUND] -- Object not found in the Object Table
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdap::DeleteObject(
|
||
IN LPWSTR wszObjectName)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
PLDAP_OBJECT p;
|
||
UNICODE_STRING ustrObject, ustrRemaining;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::DeleteObject(%ws)\n", wszObjectName);
|
||
#endif
|
||
|
||
RtlInitUnicodeString( &ustrObject, wszObjectName );
|
||
|
||
p = (PLDAP_OBJECT) DfsFindUnicodePrefix(
|
||
&_ObjectTable,
|
||
&ustrObject,
|
||
&ustrRemaining );
|
||
|
||
if (p != NULL && ustrRemaining.Length == 0) {
|
||
|
||
DfsRemoveUnicodePrefix( &_ObjectTable, &ustrObject );
|
||
|
||
if (p->pObjectData != NULL)
|
||
delete p->pObjectData;
|
||
|
||
delete p;
|
||
|
||
_cEntries--;
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_FILE_NOT_FOUND;
|
||
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::DeleteObject returning %d\n", dwErr);
|
||
#endif
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::GetData
|
||
//
|
||
// Synopsis: Reads the data associated with an Object.
|
||
//
|
||
// Arguments: [wszObjectName] -- Name of Object.
|
||
// [pcbObjectSize] -- Size of object data
|
||
// [ppObjectData] -- On successful return, points to a newly
|
||
// allocated buffer containing the object data. Caller
|
||
// must free with the delete operator.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully returning object.
|
||
//
|
||
// [ERROR_FILE_NOT_FOUND] -- Unable to find the named object.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory condition
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD CLdap::GetData(
|
||
IN LPCWSTR wszObjectName,
|
||
OUT LPDWORD pcbObjectSize,
|
||
OUT PCHAR *ppObjectData)
|
||
{
|
||
DWORD dwErr;
|
||
PLDAP_OBJECT p;
|
||
UNICODE_STRING ustrObject, ustrRemaining;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::GetData(%ws,%d)\n", wszObjectName, *pcbObjectSize);
|
||
#endif
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::GetData(%ws)\n", wszObjectName));
|
||
|
||
RtlInitUnicodeString( &ustrObject, wszObjectName );
|
||
|
||
p = (PLDAP_OBJECT) DfsFindUnicodePrefix(
|
||
&_ObjectTable,
|
||
&ustrObject,
|
||
&ustrRemaining);
|
||
|
||
if (p != NULL && ustrRemaining.Length == 0) {
|
||
|
||
if (p->cbObjectData != 0) {
|
||
|
||
*ppObjectData = new CHAR [p->cbObjectData];
|
||
|
||
if (*ppObjectData != NULL) {
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint(" CopyMemory(%d bytes)\n", p->cbObjectData);
|
||
#endif
|
||
|
||
CopyMemory( *ppObjectData, p->pObjectData, p->cbObjectData );
|
||
|
||
*pcbObjectSize = p->cbObjectData;
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
} else {
|
||
|
||
*pcbObjectSize = 0;
|
||
|
||
*ppObjectData = NULL;
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_FILE_NOT_FOUND;
|
||
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::GetData exit %d\n", dwErr));
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::GetData returning %d\n", dwErr);
|
||
#endif
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::PutData
|
||
//
|
||
// Synopsis: Updates the data associated with an object.
|
||
//
|
||
// Arguments: [wszObjectName] -- Name of Object.
|
||
// [cbObjectSize] -- Size of object data
|
||
// [pObjectData] -- Points to the buffer allocated for the
|
||
// object data.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully returning object.
|
||
//
|
||
// [ERROR_FILE_NOT_FOUND] -- Unable to find the named object.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory condition
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD CLdap::PutData(
|
||
IN LPWSTR wszObjectName,
|
||
IN DWORD cbObjectSize,
|
||
IN PCHAR pObjectData)
|
||
{
|
||
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
PLDAP_OBJECT p;
|
||
UNICODE_STRING ustrObject, ustrRemaining;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::PutData(%ws,%d)\n", wszObjectName, cbObjectSize);
|
||
#endif
|
||
|
||
RtlInitUnicodeString( &ustrObject, wszObjectName );
|
||
|
||
p = (PLDAP_OBJECT) DfsFindUnicodePrefix(
|
||
&_ObjectTable,
|
||
&ustrObject,
|
||
&ustrRemaining);
|
||
|
||
if (p != NULL && ustrRemaining.Length == 0) {
|
||
|
||
if (p->cbObjectData >= cbObjectSize) {
|
||
|
||
CopyMemory( p->pObjectData, pObjectData, cbObjectSize );
|
||
|
||
p->cbObjectData = cbObjectSize;
|
||
|
||
} else {
|
||
|
||
if (p->pObjectData != NULL) {
|
||
|
||
delete p->pObjectData;
|
||
|
||
p->pObjectData = NULL;
|
||
|
||
p->cbObjectData = 0;
|
||
|
||
}
|
||
|
||
p->pObjectData = new CHAR [cbObjectSize];
|
||
|
||
if (p->pObjectData != NULL) {
|
||
|
||
p->cbObjectData = cbObjectSize;
|
||
|
||
CopyMemory( p->pObjectData, pObjectData, cbObjectSize );
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_FILE_NOT_FOUND;
|
||
|
||
}
|
||
|
||
if (!_fDirty && dwErr == ERROR_SUCCESS)
|
||
_fDirty = TRUE;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::PutData returning %d\n", dwErr);
|
||
#endif
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::NextChild
|
||
//
|
||
// Synopsis: Given the name of an object, this method can be used to
|
||
// enumerate the children of the object.
|
||
//
|
||
// Arguments: [wszObjectName] -- Name of child to enumerate
|
||
// [ppCookie] -- On first call, *ppCookie should be NULL. On
|
||
// subsequent calls, call with the value returned by
|
||
// the previous call.
|
||
//
|
||
// Returns: Pointer to name of child if successful, NULL otherwise.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
LPWSTR
|
||
CLdap::NextChild(
|
||
IN LPWSTR wszObjectName,
|
||
OUT PVOID *ppCookie)
|
||
{
|
||
PLDAP_OBJECT pldapObject;
|
||
UNICODE_STRING ustrObjectName;
|
||
|
||
RtlInitUnicodeString(&ustrObjectName, wszObjectName);
|
||
|
||
pldapObject = (PLDAP_OBJECT) DfsNextUnicodePrefixChild(
|
||
&_ObjectTable,
|
||
&ustrObjectName,
|
||
ppCookie);
|
||
|
||
if (pldapObject != NULL) {
|
||
|
||
return( pldapObject->wszObjectName );
|
||
|
||
} else {
|
||
|
||
return( NULL );
|
||
}
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfspConnectToLdapServer
|
||
//
|
||
// Synopsis: Connects to an Ldap server for the domain.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Win32 result of attempt to connect
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
DfspConnectToLdapServer()
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
DWORD cConnectRetry;
|
||
LPWSTR ObjName = NULL;
|
||
LPWSTR DcName = NULL;
|
||
|
||
if (pLdapConnection != NULL)
|
||
return dwErr;
|
||
|
||
//
|
||
// pLdapConnection is NULL
|
||
//
|
||
|
||
if (pwszDSMachineName != NULL) {
|
||
dwErr = DfspLdapOpen(pwszDSMachineName, &pLdapConnection, &ObjName);
|
||
DFSM_TRACE_ERROR_HIGH(dwErr, ALL_ERROR,
|
||
DfspConnectToLdapServer_ERROR_DfspLdapOpen,
|
||
LOGSTATUS(dwErr));
|
||
if (dwErr == ERROR_SUCCESS)
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// pLdapConnection is NULL
|
||
// AND we have no preconceived idea of a DC to go to.
|
||
//
|
||
for (cConnectRetry = 0;
|
||
(cConnectRetry < 5) && (pLdapConnection == NULL);
|
||
cConnectRetry++) {
|
||
|
||
if (ObjName != NULL) {
|
||
free(ObjName);
|
||
ObjName = NULL;
|
||
}
|
||
if (DcName != NULL) {
|
||
delete [] DcName;
|
||
DcName = NULL;
|
||
}
|
||
|
||
dwErr = GetDcName( NULL, cConnectRetry, &DcName );
|
||
|
||
|
||
if (DfsSvcLdap)
|
||
DbgPrint("DfspConnectToLdapServer:%ws\n", &DcName[2]);
|
||
|
||
if (dwErr == ERROR_SUCCESS)
|
||
dwErr = DfspLdapOpen(&DcName[2], &pLdapConnection, &ObjName);
|
||
|
||
if (DfsSvcLdap)
|
||
DbgPrint("DfspConnectToLdapServer returned %d\n", dwErr);
|
||
|
||
if (pLdapConnection == NULL) {
|
||
if (DfsSvcLdap)
|
||
DbgPrint("DfspConnectToLdapServer:sleep 15s\n");
|
||
Sleep( 15 * 1000 );
|
||
}
|
||
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
if (ObjName != NULL)
|
||
free(ObjName);
|
||
|
||
if (DcName != NULL)
|
||
delete [] DcName;
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::_IsObjectTableUpToDate
|
||
//
|
||
// Synopsis: Returns true if the in-memory copy of the Pkt is the same as
|
||
// the one on the DS.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: TRUE if we are up-to-date with the DS, FALSE otherwise
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
BOOLEAN
|
||
CLdap::_IsObjectTableUpToDate()
|
||
{
|
||
DWORD ldapErr;
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
PLDAPMessage pldapMsg = NULL;
|
||
PLDAPMessage pldapEntry;
|
||
LPWSTR rgszAttr[2];
|
||
PLDAP_BERVAL *rgldapPktId;
|
||
BOOLEAN fEqual = FALSE;
|
||
int i;
|
||
LPWSTR *newRemoteServerList = NULL;
|
||
BOOLEAN ListsMatch = TRUE;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::_IsObjectTableUpToDate()\n"));
|
||
|
||
|
||
dwErr = DfsGetFtServersFromDs(pLdapConnection, NULL, _wszDfsName, &newRemoteServerList);
|
||
|
||
if(dwErr != ERROR_SUCCESS) {
|
||
goto exit;
|
||
}
|
||
|
||
if(_RemoteServerList) {
|
||
i = 0;
|
||
while(newRemoteServerList[i]) {
|
||
if(!_RemoteServerList[i]) {
|
||
ListsMatch = FALSE;
|
||
break; //we've reached the end of one list
|
||
} else if(wcscmp(newRemoteServerList[i], _RemoteServerList[i]) != 0) {
|
||
ListsMatch = FALSE;
|
||
}
|
||
i++;
|
||
}
|
||
NetApiBufferFree(_RemoteServerList);
|
||
}
|
||
_RemoteServerList = newRemoteServerList;
|
||
|
||
if(!ListsMatch) {
|
||
goto exit;
|
||
}
|
||
|
||
rgszAttr[0] = L"pKTGuid";
|
||
rgszAttr[1] = NULL;
|
||
|
||
if (DfsSvcLdap)
|
||
DbgPrint("CLdap::_IsObjectTableUpToDate:ldap_search(%ws)\n", rgszAttr[0]);
|
||
|
||
ldapErr = ldap_search_sW(
|
||
pLdapConnection, // LDAP connection
|
||
_wszObjectDN, // search DN
|
||
LDAP_SCOPE_BASE, // search base
|
||
L"(objectClass=*)", // Filter
|
||
rgszAttr, // Attributes
|
||
0, // Read Attributes and Value
|
||
&pldapMsg); // LDAP message
|
||
|
||
DFSM_TRACE_ERROR_HIGH(ldapErr, ALL_ERROR,
|
||
_IsObjectTableUpToDate_Error_ldap_search_sW,
|
||
LOGULONG(ldapErr));
|
||
|
||
if (ldapErr == LDAP_SUCCESS) {
|
||
|
||
pldapEntry = ldap_first_entry(
|
||
pLdapConnection,
|
||
pldapMsg);
|
||
|
||
if (pldapEntry != NULL) {
|
||
|
||
rgldapPktId = ldap_get_values_len(
|
||
pLdapConnection,
|
||
pldapEntry,
|
||
"pKTGuid");
|
||
|
||
if (rgldapPktId != NULL) {
|
||
|
||
if ((rgldapPktId[0]->bv_len == sizeof(GUID)) &&
|
||
RtlCompareMemory(
|
||
rgldapPktId[0]->bv_val,
|
||
&_ObjectTableId,
|
||
sizeof(GUID)) == sizeof(GUID)) {
|
||
|
||
//
|
||
// We have an up-to-date Pkt
|
||
//
|
||
|
||
fEqual = TRUE;
|
||
|
||
}
|
||
|
||
ldap_value_free_len( rgldapPktId );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
exit:
|
||
if (pldapMsg != NULL)
|
||
ldap_msgfree(pldapMsg);
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::_IsObjectTableUpToDate() exit %d\n", fEqual));
|
||
|
||
return( fEqual );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::_ReadObjectTable
|
||
//
|
||
// Synopsis: Reads the entire table of object data from the DS sever and
|
||
// populates the in-memory prefix table with it.
|
||
//
|
||
// Assumes that we have already connected to the DS server.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Win32 error from reading DS data
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdap::_ReadObjectTable()
|
||
{
|
||
|
||
DWORD ldapErr;
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
NTSTATUS status;
|
||
PLDAPMessage pldapMsg = NULL;
|
||
PLDAPMessage pldapEntry;
|
||
LPWSTR rgszAttr[3];
|
||
PLDAP_BERVAL *rgldapPktBlob, pldapPktBlob;
|
||
MARSHAL_BUFFER marshalBuffer;
|
||
LDAP_PKT ldapPkt;
|
||
ULONG i;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::_ReadObjectTable()\n"));
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::_ReadObjectTable()\n");
|
||
#endif
|
||
|
||
rgszAttr[0] = L"pKT";
|
||
rgszAttr[1] = L"pKTGuid";
|
||
rgszAttr[2] = NULL;
|
||
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("Reading BLOB...\n");
|
||
#endif
|
||
|
||
if (DfsSvcLdap)
|
||
DbgPrint("CLdap::_ReadObjectTable:ldap_search(%ws and %ws)]\n", rgszAttr[0], rgszAttr[1]);
|
||
|
||
ldapErr = ldap_search_sW(
|
||
pLdapConnection, // LDAP connection
|
||
_wszObjectDN, // search DN
|
||
LDAP_SCOPE_BASE, // search base
|
||
L"(objectClass=*)", // Filter
|
||
rgszAttr, // Attributes
|
||
0, // Read Attributes and Value
|
||
&pldapMsg); // LDAP message
|
||
|
||
DFSM_TRACE_ERROR_HIGH(ldapErr, ALL_ERROR,
|
||
_ReadObjectTable_Error_ldap_search_sW,
|
||
LOGULONG(ldapErr));
|
||
|
||
if (ldapErr == LDAP_SUCCESS) {
|
||
|
||
pldapEntry = ldap_first_entry(
|
||
pLdapConnection,
|
||
pldapMsg);
|
||
|
||
if (pldapEntry != NULL) {
|
||
|
||
rgldapPktBlob = ldap_get_values_len(
|
||
pLdapConnection,
|
||
pldapEntry,
|
||
"pKT");
|
||
|
||
if (rgldapPktBlob != NULL) {
|
||
|
||
pldapPktBlob = rgldapPktBlob[0];
|
||
|
||
if (pldapPktBlob->bv_len > sizeof(DWORD)) {
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("Got BLOB of %d bytes\n", pldapPktBlob->bv_len);
|
||
#endif
|
||
|
||
MarshalBufferInitialize(
|
||
&marshalBuffer,
|
||
pldapPktBlob->bv_len - sizeof(DWORD),
|
||
pldapPktBlob->bv_val + sizeof(DWORD));
|
||
|
||
status = DfsRtlGet(&marshalBuffer, &MiLdapPkt, &ldapPkt);
|
||
|
||
//
|
||
// Cool, we now have a list of all the LDAP_OBJECT records. Go
|
||
// through each and insert it into the prefix table. Clean
|
||
// up the current _ObjectTable if needed
|
||
//
|
||
|
||
_DestroyObjectTable();
|
||
if (pDfsmStorageDirectory != NULL) {
|
||
delete pDfsmStorageDirectory;
|
||
pDfsmStorageDirectory = NULL;
|
||
}
|
||
if (pDfsmSites != NULL) {
|
||
delete pDfsmSites;
|
||
pDfsmSites = NULL;
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
for (i = 0;
|
||
(i < ldapPkt.cLdapObjects) &&
|
||
(dwErr == ERROR_SUCCESS);
|
||
i++) {
|
||
|
||
dwErr = _InsertLdapObject(&ldapPkt.rgldapObjects[i]);
|
||
|
||
MarshalBufferFree(ldapPkt.rgldapObjects[i].wszObjectName);
|
||
|
||
MarshalBufferFree(ldapPkt.rgldapObjects[i].pObjectData);
|
||
|
||
}
|
||
|
||
//
|
||
// In case we errored out of the loop above, clean up the
|
||
// rest of the unmarshalled ldap objects
|
||
//
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
_cEntries = ldapPkt.cLdapObjects;
|
||
|
||
_fDirty = FALSE;
|
||
|
||
} else {
|
||
|
||
for (; i < ldapPkt.cLdapObjects; i++) {
|
||
|
||
MarshalBufferFree(ldapPkt.rgldapObjects[i].wszObjectName);
|
||
|
||
MarshalBufferFree(ldapPkt.rgldapObjects[i].pObjectData);
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// Free up the enclosing ldapPkt that we unmarshalled
|
||
//
|
||
|
||
MarshalBufferFree(ldapPkt.rgldapObjects);
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_INTERNAL_DB_CORRUPTION;
|
||
|
||
}
|
||
|
||
} else if (pldapPktBlob->bv_len != sizeof(DWORD)) {
|
||
|
||
dwErr = ERROR_INTERNAL_DB_CORRUPTION;
|
||
}
|
||
|
||
//
|
||
// Free up the ldap buffers used to retrieve the pkt
|
||
//
|
||
|
||
ldap_value_free_len( rgldapPktBlob );
|
||
|
||
//
|
||
// If successful so far, retrieve the pkt id
|
||
//
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
rgldapPktBlob = ldap_get_values_len(
|
||
pLdapConnection,
|
||
pldapEntry,
|
||
"pKTGuid");
|
||
|
||
if (rgldapPktBlob != NULL) {
|
||
|
||
pldapPktBlob = rgldapPktBlob[0];
|
||
|
||
if (pldapPktBlob->bv_len == sizeof(GUID)) {
|
||
|
||
CopyMemory(
|
||
&_ObjectTableId,
|
||
pldapPktBlob->bv_val,
|
||
sizeof(GUID));
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_INTERNAL_DB_CORRUPTION;
|
||
|
||
}
|
||
|
||
ldap_value_free_len( rgldapPktBlob );
|
||
|
||
} else {
|
||
|
||
//
|
||
// why would ldap fail the ldap_get_values_len call?
|
||
//
|
||
|
||
IDfsVolInlineDebOut((
|
||
DEB_ERROR,
|
||
"ldap_get_values_len for %ws:%ws failed\n",
|
||
_wszObjectDN,
|
||
L"pKTGuid",
|
||
ldapErr));
|
||
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// why would ldap fail the ldap_get_values_len call?
|
||
//
|
||
|
||
IDfsVolInlineDebOut((
|
||
DEB_ERROR,
|
||
"ldap_get_values_len for %ws:%ws failed\n",
|
||
_wszObjectDN,
|
||
L"pKT",
|
||
ldapErr));
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// why would ldap fail the ldap_first_entry call?
|
||
//
|
||
|
||
IDfsVolInlineDebOut((
|
||
DEB_ERROR,
|
||
"ldap_first_entry for %ws:%ws failed\n",
|
||
_wszObjectDN,
|
||
L"pKT",
|
||
ldapErr));
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
IDfsVolInlineDebOut((
|
||
DEB_ERROR,
|
||
"ldap_search_s for %ws failed with ldap error %x\n",
|
||
_wszObjectDN,
|
||
ldapErr));
|
||
|
||
dwErr = LdapMapErrorToWin32(ldapErr);
|
||
|
||
}
|
||
|
||
if (pldapMsg != NULL)
|
||
ldap_msgfree( pldapMsg );
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::_ReadObjectTable() exit\n"));
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::_ReadObjectTable exit %d\n", dwErr);
|
||
#endif
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::_FlushObjectTable
|
||
//
|
||
// Synopsis: Routine to marshall all the LDAP_OBJECTS resident in the
|
||
// in-memory prefix table into a single blob and store it in
|
||
// the DS.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully flushed Pkt to DS.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory condition
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdap::_FlushObjectTable()
|
||
{
|
||
|
||
DWORD ldapErr;
|
||
DWORD dwErr = ERROR_SUCCESS, i, cbPkt;
|
||
NTSTATUS NtStatus = STATUS_SUCCESS;
|
||
MARSHAL_BUFFER marshalBuffer;
|
||
|
||
GUID idNewPkt;
|
||
LDAP_BERVAL ldapVal, ldapIdVal;
|
||
PLDAP_BERVAL rgldapVals[2], rgldapIdVals[2];
|
||
LDAPModW ldapMod, ldapIdMod;
|
||
PLDAPModW rgldapMods[3];
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::_FlushObjectTable()\n"));
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::_FlushObjectTable()\n");
|
||
#endif
|
||
|
||
LDAPControlW LazyCommitControl =
|
||
{
|
||
LDAP_SERVER_LAZY_COMMIT_OID_W, // the control
|
||
{ 0, NULL}, // no associated data
|
||
FALSE // control isn't mandatory
|
||
};
|
||
|
||
PLDAPControlW ServerControls[2] =
|
||
{
|
||
&LazyCommitControl,
|
||
NULL
|
||
};
|
||
//
|
||
// No one should call _FlushObjectTable if the _ObjectTable is empty!
|
||
//
|
||
if( _cEntries == 0 )
|
||
return ERROR_INVALID_PARAMETER;
|
||
|
||
//
|
||
// Allocate array of pointers to ldap objects if needed, or the current
|
||
// one is too small.
|
||
//
|
||
if (_cEntries >= _cEntriesAllocated) {
|
||
if (_ldapPkt.rgldapObjects != NULL)
|
||
delete [] _ldapPkt.rgldapObjects;
|
||
_ldapPkt.rgldapObjects = NULL;
|
||
_cEntriesAllocated = 0;
|
||
}
|
||
if (_ldapPkt.rgldapObjects == NULL) {
|
||
_ldapPkt.rgldapObjects = new LDAP_OBJECT [(_cEntries + 1) * 2];
|
||
if (_ldapPkt.rgldapObjects == NULL) {
|
||
_ldapPkt.rgldapObjects = new LDAP_OBJECT [_cEntries + 1];
|
||
if (_ldapPkt.rgldapObjects == NULL) {
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
goto Cleanup;
|
||
} else {
|
||
_cEntriesAllocated = _cEntries + 1;
|
||
}
|
||
} else {
|
||
_cEntriesAllocated = (_cEntries + 1) * 2;
|
||
}
|
||
}
|
||
_ldapPkt.cLdapObjects = _cEntries;
|
||
_ldapPkt.rgldapObjects[0] =
|
||
*((PLDAP_OBJECT) DfsNextUnicodePrefix(&_ObjectTable, TRUE));
|
||
for (i = 1; i < _cEntries; i++) {
|
||
_ldapPkt.rgldapObjects[i] =
|
||
*((PLDAP_OBJECT) DfsNextUnicodePrefix(&_ObjectTable, FALSE));
|
||
}
|
||
//
|
||
// We now have an LDAP_PKT structure, lets marshal it and store
|
||
// it in the DS.
|
||
//
|
||
cbPkt = 0;
|
||
DoMarshall:
|
||
if (_pBuffer == NULL) {
|
||
NtStatus = DfsRtlSize(&MiLdapPkt, &_ldapPkt, &cbPkt);
|
||
if (cbPkt == 0 || !NT_SUCCESS(NtStatus)) {
|
||
dwErr = RtlNtStatusToDosError(NtStatus);
|
||
goto Cleanup;
|
||
}
|
||
_pBuffer = new BYTE [ sizeof(DWORD) + (2 * cbPkt) ];
|
||
if (_pBuffer == NULL) {
|
||
_pBuffer = new BYTE [ sizeof(DWORD) + cbPkt ];
|
||
if (_pBuffer == NULL) {
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
}
|
||
*((LPDWORD) _pBuffer) = 1;
|
||
MarshalBufferInitialize(
|
||
&marshalBuffer,
|
||
cbPkt,
|
||
_pBuffer + sizeof(DWORD));
|
||
NtStatus = DfsRtlPut(&marshalBuffer, &MiLdapPkt, &_ldapPkt);
|
||
if (!NT_SUCCESS(NtStatus) && cbPkt == 0) {
|
||
if (_pBuffer != NULL)
|
||
delete [] _pBuffer;
|
||
_pBuffer = NULL;
|
||
goto DoMarshall;
|
||
}
|
||
//
|
||
// We have a serialized blob to put into the DS.
|
||
//
|
||
UuidCreate( &idNewPkt );
|
||
|
||
ldapIdVal.bv_len = sizeof(GUID);
|
||
ldapIdVal.bv_val = (PCHAR) &idNewPkt;
|
||
rgldapIdVals[0] = &ldapIdVal;
|
||
rgldapIdVals[1] = NULL;
|
||
|
||
ldapIdMod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
|
||
ldapIdMod.mod_type = L"pKTGuid";
|
||
ldapIdMod.mod_vals.modv_bvals = rgldapIdVals;
|
||
|
||
ldapVal.bv_len = cbPkt + sizeof(DWORD);
|
||
ldapVal.bv_val = (PCHAR) _pBuffer;
|
||
rgldapVals[0] = &ldapVal;
|
||
rgldapVals[1] = NULL;
|
||
|
||
ldapMod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
|
||
ldapMod.mod_type = L"pKT";
|
||
ldapMod.mod_vals.modv_bvals = rgldapVals;
|
||
|
||
rgldapMods[0] = &ldapMod;
|
||
rgldapMods[1] = &ldapIdMod;
|
||
rgldapMods[2] = NULL;
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("Writing BLOB of %d bytes\n", cbPkt);
|
||
#endif
|
||
if (DfsSvcLdap)
|
||
DbgPrint("FlushObjectTable:ldap_modify(%ws) using 0x%x\n",
|
||
L"pKTGuid and pKT",
|
||
pLdapConnection);
|
||
|
||
ldapErr = ldap_modify_ext_sW(
|
||
pLdapConnection,
|
||
_wszObjectDN,
|
||
rgldapMods,
|
||
(PLDAPControlW *) &ServerControls,
|
||
NULL);
|
||
DFSM_TRACE_ERROR_HIGH(ldapErr, ALL_ERROR,
|
||
_FlushObjectTable_Error_ldap_modify_ext_sW,
|
||
LOGULONG(ldapErr));
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("ldap_modify_sW returned 0x%x(%d)\n", ldapErr, ldapErr);
|
||
#endif
|
||
|
||
CopyMemory( &_ObjectTableId, &idNewPkt, sizeof(GUID) );
|
||
if (ldapErr != LDAP_SUCCESS) {
|
||
dwErr = LdapMapErrorToWin32(ldapErr);
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdap::_FlushObjectTable() exit\n"));
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::_FlushObjectTable() exit %d\n", dwErr);
|
||
#endif
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::_InsertLdapObject
|
||
//
|
||
// Synopsis: Helper routine for _ReadObjectTable(). This routine inserts
|
||
// a single LDAP_OBJECT into the internal prefix table, so that
|
||
// it can be looked up etc.
|
||
//
|
||
// This routine duplicates the passed in LDAP_OBJECT.
|
||
//
|
||
// Arguments: [pldapObject] -- The object to duplicate and insert into the
|
||
// prefix table.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully inserted object.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory error.
|
||
//
|
||
// [ERROR_ALREADY_EXISTS] -- The LDAP_OBJECT to be inserted
|
||
// already exists in the prefix table.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdap::_InsertLdapObject(
|
||
PLDAP_OBJECT pldapObject)
|
||
{
|
||
DWORD dwErr;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::InsertLdapObject(%ws)\n", pldapObject->wszObjectName);
|
||
#endif
|
||
|
||
dwErr = CreateObject( pldapObject->wszObjectName );
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
dwErr = PutData(
|
||
pldapObject->wszObjectName,
|
||
pldapObject->cbObjectData,
|
||
pldapObject->pObjectData);
|
||
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::InsertLdapObject returning %d\n", dwErr);
|
||
#endif
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdap::_DestroyObjectTable
|
||
//
|
||
// Synopsis: Destroys all the entries in the _ObjectTable
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
VOID
|
||
CLdap::_DestroyObjectTable()
|
||
{
|
||
|
||
PLDAP_OBJECT p;
|
||
BOOLEAN Restart, Success;
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CLdap::_DestroyObjectTable()\n");
|
||
#endif
|
||
|
||
p = (PLDAP_OBJECT) DfsNextUnicodePrefix( &_ObjectTable, TRUE );
|
||
|
||
while (p != NULL) {
|
||
|
||
UNICODE_STRING ustrObjectName;
|
||
|
||
RtlInitUnicodeString(&ustrObjectName, p->wszObjectName);
|
||
Success = DfsRemoveUnicodePrefix( &_ObjectTable, &ustrObjectName );
|
||
if (Success == TRUE) {
|
||
Restart = TRUE;
|
||
delete p->pObjectData;
|
||
delete p;
|
||
}
|
||
else {
|
||
Restart = FALSE;
|
||
}
|
||
|
||
p = (PLDAP_OBJECT) DfsNextUnicodePrefix( &_ObjectTable, Restart );
|
||
}
|
||
|
||
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: InitializeLdapStorage
|
||
//
|
||
// Synopsis: Initializes a global CLdap object, pDfsmLdap, that is used
|
||
// by the CLdapStorage instances to store and retrieve properties
|
||
//
|
||
// Arguments: [wszDfsName] -- Name of the Dfs to initialize
|
||
//
|
||
// Notes: NOTE THAT THE ABOVE TWO STRINGS ARE ASCII STRINGS, NOT
|
||
// UNICODE.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully initialized Ldap storage.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory situation
|
||
//
|
||
// [ERROR_ALREADY_INITIALIZED] -- Ldap storage is already
|
||
// initialized
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
InitializeLdapStorage(
|
||
LPWSTR wszDfsName)
|
||
{
|
||
DWORD dwErr;
|
||
|
||
if (pDfsmLdap == NULL) {
|
||
|
||
pDfsmLdap = new CLdap( wszDfsName, &dwErr );
|
||
|
||
if (pDfsmLdap != NULL) {
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
|
||
delete pDfsmLdap;
|
||
|
||
pDfsmLdap = NULL;
|
||
|
||
} else {
|
||
|
||
pDfsmLdap->AddRef();
|
||
pDfsmLdap->Release();
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_ALREADY_INITIALIZED;
|
||
|
||
}
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: UnInitializeLdapStorage
|
||
//
|
||
// Synopsis: UnInitializes a global CLdap object, pDfsmLdap, that is used
|
||
// by the CLdapStorage instances to store and retrieve properties
|
||
//
|
||
// Arguments: None
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
VOID
|
||
UnInitializeLdapStorage(
|
||
void )
|
||
{
|
||
|
||
if (pDfsmLdap != NULL) {
|
||
|
||
pDfsmLdap->Release();
|
||
delete pDfsmLdap;
|
||
pDfsmLdap = NULL;
|
||
if (pLdapConnection != NULL) {
|
||
if (DfsSvcLdap)
|
||
DbgPrint("UnitializeLdapStorage:ldap_unbind()\n");
|
||
ldap_unbind(pLdapConnection);
|
||
pLdapConnection = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapStorage::CLdapStorage
|
||
//
|
||
// Synopsis: Constructor for a CLdapStorage object.
|
||
//
|
||
// Arguments: [lpwszFileName] -- Full Name of "storage object".
|
||
//
|
||
// [pdwErr] -- If the constructor fails, this variable is set to
|
||
// an appropriate error.
|
||
//
|
||
// Returns: Nothing, but note the error return in pdwErr out parameter.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
CLdapStorage::CLdapStorage(
|
||
LPCWSTR lpwszFileName,
|
||
LPDWORD pdwErr) :
|
||
CStorage(lpwszFileName)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
NTSTATUS status;
|
||
DWORD cbDataBuffer;
|
||
PCHAR pDataBuffer;
|
||
MARSHAL_BUFFER marshalBuffer;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdapStorage::CLdapStorage(%ws)\n", lpwszFileName));
|
||
IDfsVolInlineDebOut((
|
||
DEB_TRACE, "CLdapStorage::+CLdapStorage(0x%x)\n",
|
||
this));
|
||
|
||
ZeroMemory(&_VolProps, sizeof(_VolProps));
|
||
|
||
_wszFileName = NULL;
|
||
|
||
//
|
||
// Add a reference to the global CLdap object. Do this first so it can
|
||
// initialize anything it needs to satisfy read/write requests.
|
||
//
|
||
|
||
pDfsmLdap->AddRef();
|
||
|
||
//
|
||
// Get the data from the Dfsm Ldap layer.
|
||
//
|
||
|
||
dwErr = pDfsmLdap->GetData(lpwszFileName, &cbDataBuffer, &pDataBuffer);
|
||
|
||
if (dwErr == ERROR_SUCCESS && cbDataBuffer > 0) {
|
||
|
||
MarshalBufferInitialize(&marshalBuffer, cbDataBuffer, pDataBuffer);
|
||
|
||
status = DfsRtlGet(&marshalBuffer, &MiVolumeProperties, &_VolProps);
|
||
|
||
_VolProps.dwTimeout = GTimeout;
|
||
|
||
if (
|
||
(marshalBuffer.Current < marshalBuffer.Last)
|
||
&&
|
||
(marshalBuffer.Last - marshalBuffer.Current) == sizeof(ULONG)
|
||
) {
|
||
|
||
DfsRtlGetUlong(&marshalBuffer, &_VolProps.dwTimeout);
|
||
|
||
}
|
||
|
||
|
||
delete [] pDataBuffer;
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
dwErr = ERROR_INTERNAL_DB_CORRUPTION;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
_wszFileName = new WCHAR [wcslen(lpwszFileName) + 1];
|
||
|
||
if (_wszFileName != NULL)
|
||
wcscpy(_wszFileName, lpwszFileName);
|
||
else
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS && _VolProps.wszPrefix != NULL) {
|
||
|
||
dwErr = pDfsmStorageDirectory->_InsertIfNeeded(
|
||
_VolProps.wszPrefix,
|
||
_wszFileName);
|
||
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdapStorage::CLdapStorage exit %d\n", dwErr));
|
||
|
||
*pdwErr = dwErr;
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapStorage::~CLdapStorage
|
||
//
|
||
// Synopsis: Destructor for CLdapStorage object
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
CLdapStorage::~CLdapStorage()
|
||
{
|
||
|
||
IDfsVolInlineDebOut((
|
||
DEB_TRACE, "CLdapStorage::~CLdapStorage(0x%x)\n",
|
||
this));
|
||
|
||
if (_wszFileName != NULL)
|
||
delete [] _wszFileName;
|
||
|
||
if (_VolProps.wszPrefix != NULL)
|
||
MarshalBufferFree( _VolProps.wszPrefix );
|
||
|
||
if (_VolProps.wszShortPrefix != NULL)
|
||
MarshalBufferFree( _VolProps.wszShortPrefix );
|
||
|
||
if (_VolProps.wszComment != NULL)
|
||
MarshalBufferFree( _VolProps.wszComment );
|
||
|
||
if (_VolProps.pSvc != NULL)
|
||
MarshalBufferFree( _VolProps.pSvc );
|
||
|
||
if (_VolProps.pRecovery != NULL)
|
||
MarshalBufferFree( _VolProps.pRecovery );
|
||
|
||
pDfsmLdap->Release();
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapStorage::DestroyElement
|
||
//
|
||
// Synopsis: Destroys a CLdapStorage *child* of this object.
|
||
//
|
||
// Arguments: [lpwszChildName] -- Name of child to delete, relative to
|
||
// this object's name.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully deleted child
|
||
//
|
||
// [ERROR_FILE_NOT_FOUND] -- No child found with given name.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdapStorage::DestroyElement(
|
||
LPCWSTR lpwszChildName)
|
||
{
|
||
DWORD dwErr;
|
||
PWCHAR pwszFullChildName;
|
||
|
||
pwszFullChildName = new WCHAR [
|
||
wcslen(_wszFileName) +
|
||
1 +
|
||
wcslen(lpwszChildName) +
|
||
1 ];
|
||
|
||
if (pwszFullChildName != NULL) {
|
||
|
||
wcscpy(pwszFullChildName, _wszFileName);
|
||
wcscat(pwszFullChildName, UNICODE_PATH_SEP_STR);
|
||
wcscat(pwszFullChildName, lpwszChildName);
|
||
|
||
dwErr = pDfsmLdap->DeleteObject( pwszFullChildName );
|
||
|
||
delete [] pwszFullChildName;
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
return(dwErr);
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapStorage::GetEnumDirectory
|
||
//
|
||
// Synopsis: Returns an enumerator for the children of this ldap storage
|
||
// structure.
|
||
//
|
||
// Arguments: [ppRegDir] -- On successful return, pointer to a
|
||
// CEnumDirectory instance.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully returning CEnumDirectory
|
||
// instance.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory situation
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdapStorage::GetEnumDirectory(
|
||
CEnumDirectory **ppRegDir)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
CLdapEnumDirectory *pLdapRegDir;
|
||
|
||
*ppRegDir = NULL;
|
||
|
||
pLdapRegDir = new CLdapEnumDirectory( _wszFileName, &dwErr );
|
||
|
||
if (pLdapRegDir != NULL) {
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
|
||
delete pLdapRegDir;
|
||
|
||
} else {
|
||
|
||
*ppRegDir = (CEnumDirectory *) pLdapRegDir;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
return(dwErr);
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapStorage::SetVersionProps
|
||
//
|
||
// Synopsis: Sets the version property set of this object
|
||
//
|
||
// Arguments: [ulVersion] -- The version to set.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- If successfully set the property.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdapStorage::SetVersionProps(
|
||
ULONG ulVersion)
|
||
{
|
||
DWORD dwErr;
|
||
|
||
_VolProps.dwVersion = ulVersion;
|
||
|
||
dwErr = _FlushProperties();
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapStorage::GetVersionProps
|
||
//
|
||
// Synopsis: Returns the stored version property
|
||
//
|
||
// Arguments: [pulVersion] -- Holds the current version property.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Always succeeds.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdapStorage::GetVersionProps(
|
||
PULONG pulVersion)
|
||
{
|
||
*pulVersion = _VolProps.dwVersion;
|
||
|
||
return( ERROR_SUCCESS );
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapStorage::SetIdProps
|
||
//
|
||
// Synopsis: Sets the ID properties
|
||
//
|
||
// Arguments: [dwType] -- The volume Type
|
||
// [dwState] -- The volume State
|
||
// [pwszPrefix] -- The volume prefix
|
||
// [pwszShortPath] -- The volume 8.3 prefix
|
||
// [idVolume] -- The volume guid
|
||
// [pwszComment] -- The volume comment
|
||
// [dwTimeout] -- The volume timeout
|
||
// [ftPrefix] -- The modification time of prefix
|
||
// [ftState] -- The modification time of state
|
||
// [ftComment] -- The modification time of comment
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully modified properties
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory condition
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdapStorage::SetIdProps(
|
||
ULONG dwType,
|
||
ULONG dwState,
|
||
LPWSTR pwszPrefix,
|
||
LPWSTR pwszShortPath,
|
||
GUID idVolume,
|
||
LPWSTR pwszComment,
|
||
ULONG dwTimeout,
|
||
FILETIME ftPrefix,
|
||
FILETIME ftState,
|
||
FILETIME ftComment)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
DFS_VOLUME_PROPERTIES newProps;
|
||
|
||
newProps = _VolProps;
|
||
|
||
newProps.idVolume = idVolume;
|
||
newProps.dwType = dwType;
|
||
newProps.dwState = dwState;
|
||
newProps.ftPrefix = ftPrefix;
|
||
newProps.ftState = ftState;
|
||
newProps.ftComment = ftComment;
|
||
|
||
newProps.wszPrefix = NULL;
|
||
newProps.wszShortPrefix = NULL;
|
||
newProps.wszComment = NULL;
|
||
|
||
newProps.dwTimeout = dwTimeout;
|
||
|
||
newProps.wszPrefix = (PWCHAR) MarshalBufferAllocate(
|
||
(wcslen(pwszPrefix) + 1) *
|
||
sizeof(WCHAR));
|
||
if (newProps.wszPrefix != NULL) {
|
||
wcscpy(newProps.wszPrefix, pwszPrefix);
|
||
} else {
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
newProps.wszShortPrefix =
|
||
(PWCHAR) MarshalBufferAllocate(
|
||
(wcslen(pwszShortPath) + 1) * sizeof(WCHAR));
|
||
if (newProps.wszShortPrefix != NULL)
|
||
wcscpy(newProps.wszShortPrefix, pwszShortPath);
|
||
else
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
newProps.wszComment =
|
||
(PWCHAR) MarshalBufferAllocate(
|
||
(wcslen(pwszComment) + 1) * sizeof(WCHAR));
|
||
if (newProps.wszComment != NULL)
|
||
wcscpy(newProps.wszComment, pwszComment);
|
||
else
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
//
|
||
// The prefix might have changed; update the Prefix->ObjectName map if
|
||
// necessary.
|
||
//
|
||
|
||
if (dwErr == ERROR_SUCCESS &&
|
||
((_VolProps.wszPrefix == NULL) ||
|
||
(_wcsicmp(newProps.wszPrefix, _VolProps.wszPrefix) != 0)) ) {
|
||
|
||
dwErr = pDfsmStorageDirectory->_InsertIfNeeded(
|
||
newProps.wszPrefix,
|
||
_wszFileName);
|
||
|
||
if (dwErr == ERROR_SUCCESS && _VolProps.wszPrefix != NULL) {
|
||
|
||
pDfsmStorageDirectory->_Delete( _VolProps.wszPrefix );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
if (_VolProps.wszPrefix)
|
||
MarshalBufferFree(_VolProps.wszPrefix);
|
||
|
||
if (_VolProps.wszShortPrefix)
|
||
MarshalBufferFree(_VolProps.wszShortPrefix);
|
||
|
||
if (_VolProps.wszComment)
|
||
MarshalBufferFree(_VolProps.wszComment);
|
||
|
||
_VolProps = newProps;
|
||
|
||
dwErr = _FlushProperties();
|
||
|
||
} else {
|
||
|
||
//
|
||
// Cleanup as much as we allocated for the new props
|
||
//
|
||
|
||
if (newProps.wszPrefix)
|
||
MarshalBufferFree(newProps.wszPrefix);
|
||
|
||
if (newProps.wszShortPrefix)
|
||
MarshalBufferFree(newProps.wszShortPrefix);
|
||
|
||
if (newProps.wszComment)
|
||
MarshalBufferFree(newProps.wszComment);
|
||
|
||
}
|
||
|
||
return(dwErr);
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapStorage::GetIdProps
|
||
//
|
||
// Synopsis: Retrieves the ID properties
|
||
//
|
||
// Arguments: [pdwType] -- Type of Volume
|
||
// [pdwState] -- State of Volume
|
||
// [ppwszPrefix] -- Prefix of volume
|
||
// [ppwszShortPath] -- Short prefix of volume
|
||
// [pidVolume] -- Guid of volume.
|
||
// [ppwszComment] -- Comment associated with volume
|
||
// [pdwTimeout] -- Timeout of volume
|
||
// [pftPrefix] -- Modification time of prefix
|
||
// [pftState] -- Modification time of state
|
||
// [pftComment] -- Modification time of comment
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully returning ID properties.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory situation.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdapStorage::GetIdProps(
|
||
LPDWORD pdwType,
|
||
LPDWORD pdwState,
|
||
LPWSTR *ppwszPrefix,
|
||
LPWSTR *ppwszShortPath,
|
||
GUID *pidVolume,
|
||
LPWSTR *ppwszComment,
|
||
LPDWORD pdwTimeout,
|
||
FILETIME *pftPrefix,
|
||
FILETIME *pftState,
|
||
FILETIME *pftComment)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdapStorage::GetIdProps()\n"));
|
||
|
||
#define GIP_DUPLICATE_STRING(dwErr, src, dest) \
|
||
if ((src) != NULL) \
|
||
(*(dest)) = new WCHAR [ wcslen(src) + 1 ]; \
|
||
else \
|
||
(*(dest)) = new WCHAR [1]; \
|
||
\
|
||
if (*(dest) != NULL) \
|
||
if ((src) != NULL) \
|
||
wcscpy( *(dest), (src) ); \
|
||
else \
|
||
(*(dest))[0] = UNICODE_NULL; \
|
||
else \
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
GIP_DUPLICATE_STRING(dwErr, _VolProps.wszPrefix, ppwszPrefix);
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
GIP_DUPLICATE_STRING(dwErr, _VolProps.wszShortPrefix, ppwszShortPath);
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
GIP_DUPLICATE_STRING(dwErr, _VolProps.wszComment, ppwszComment);
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
*pdwType = _VolProps.dwType;
|
||
*pdwState = _VolProps.dwState;
|
||
*pidVolume = _VolProps.idVolume;
|
||
*pdwTimeout = _VolProps.dwTimeout;
|
||
|
||
*pftPrefix = _VolProps.ftPrefix;
|
||
*pftState = _VolProps.ftState;
|
||
*pftComment = _VolProps.ftComment;
|
||
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CLdapStorage::GetIdProps() exit\n"));
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapStorage::SetSvcProps
|
||
//
|
||
// Synopsis: Sets the service property of the volume object
|
||
//
|
||
// Arguments: [pSvc] -- The service property
|
||
// [cbSvc] -- Length in bytes of the service property
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully set the service property
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory situation
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdapStorage::SetSvcProps(
|
||
PBYTE pSvc,
|
||
ULONG cbSvc)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
PBYTE pNewBuffer;
|
||
|
||
pNewBuffer = (PBYTE) MarshalBufferAllocate( cbSvc );
|
||
|
||
if (pNewBuffer != NULL) {
|
||
|
||
CopyMemory( pNewBuffer, pSvc, cbSvc );
|
||
|
||
if (_VolProps.pSvc != NULL)
|
||
MarshalBufferFree( _VolProps.pSvc );
|
||
|
||
_VolProps.pSvc = pNewBuffer;
|
||
|
||
_VolProps.cbSvc = cbSvc;
|
||
|
||
dwErr = _FlushProperties();
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapStorage::GetSvcProps
|
||
//
|
||
// Synopsis: Retrieves the service property from this volume object
|
||
//
|
||
// Arguments: [ppSvc] -- On successful return, points to allocated svc buffer
|
||
// [pcbSvc] -- On successful return, size in bytes of *ppSvc
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully returning svc property.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory situation.
|
||
//
|
||
// [ERROR_FILE_NOT_FOUND] -- Svc property not set.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdapStorage::GetSvcProps(
|
||
PBYTE *ppSvc,
|
||
LPDWORD pcbSvc)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
PBYTE pNewBuffer;
|
||
|
||
if (_VolProps.cbSvc != 0) {
|
||
|
||
pNewBuffer = new BYTE [_VolProps.cbSvc];
|
||
|
||
if (pNewBuffer != NULL) {
|
||
|
||
CopyMemory( pNewBuffer, _VolProps.pSvc, _VolProps.cbSvc );
|
||
|
||
*ppSvc = pNewBuffer;
|
||
|
||
*pcbSvc = _VolProps.cbSvc;
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
} else {
|
||
|
||
*ppSvc = NULL;
|
||
|
||
*pcbSvc = 0;
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_FILE_NOT_FOUND;
|
||
}
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapStorage::SetRecoveryProps
|
||
//
|
||
// Synopsis: Sets the recovery property of the volume object
|
||
//
|
||
// Arguments: [pRecovery] -- The recovery property
|
||
// [cbRecovery] -- Length in bytes of the recovery property
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully set the recovery property
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory situation
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdapStorage::SetRecoveryProps(
|
||
PBYTE pRecovery,
|
||
ULONG cbRecovery)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
PBYTE pNewBuffer;
|
||
|
||
pNewBuffer = (PBYTE) MarshalBufferAllocate( cbRecovery );
|
||
|
||
if (pNewBuffer != NULL) {
|
||
|
||
CopyMemory( pNewBuffer, pRecovery, cbRecovery );
|
||
|
||
if (_VolProps.pRecovery != NULL)
|
||
MarshalBufferFree( _VolProps.pRecovery );
|
||
|
||
_VolProps.pRecovery = pNewBuffer;
|
||
|
||
_VolProps.cbRecovery = cbRecovery;
|
||
|
||
dwErr = _FlushProperties();
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapStorage::GetRecoveryProps
|
||
//
|
||
// Synopsis: Retrieves the recovery property from this volume object
|
||
//
|
||
// Arguments: [ppRecovery] -- On successful return, points to allocated Recovery buffer
|
||
// [pcbRecovery] -- On successful return, size in bytes of *ppRecovery
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully returning Recovery property.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory situation.
|
||
//
|
||
// [ERROR_FILE_NOT_FOUND] -- Recovery property not set.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdapStorage::GetRecoveryProps(
|
||
PBYTE *ppRecovery,
|
||
LPDWORD pcbRecovery)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
PBYTE pNewBuffer;
|
||
|
||
if (_VolProps.cbRecovery != 0) {
|
||
|
||
pNewBuffer = new BYTE [_VolProps.cbRecovery];
|
||
|
||
if (pNewBuffer != NULL) {
|
||
|
||
CopyMemory( pNewBuffer, _VolProps.pRecovery, _VolProps.cbRecovery );
|
||
|
||
*ppRecovery = pNewBuffer;
|
||
|
||
*pcbRecovery = _VolProps.cbRecovery;
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
} else {
|
||
|
||
*ppRecovery = NULL;
|
||
|
||
*pcbRecovery = 0;
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_FILE_NOT_FOUND;
|
||
}
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapStorage::_FlushProperties
|
||
//
|
||
// Synopsis: Helper function to marshal the volume properties and store
|
||
// them in the LDAP agent.
|
||
//
|
||
// Arguments: None - uses the member _VolProps.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully flushed properties.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory situation.
|
||
//
|
||
// Error from CLdap::PutData()
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdapStorage::_FlushProperties()
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
NTSTATUS status;
|
||
MARSHAL_BUFFER marshalBuffer;
|
||
ULONG cbBuffer;
|
||
PCHAR pBuffer;
|
||
|
||
cbBuffer = 0;
|
||
|
||
status = DfsRtlSize(&MiVolumeProperties, &_VolProps, &cbBuffer);
|
||
|
||
ASSERT(NT_SUCCESS(status));
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
dwErr = ERROR_INVALID_DATA;
|
||
|
||
goto exit_with_error;
|
||
|
||
}
|
||
|
||
cbBuffer += sizeof(ULONG);
|
||
|
||
pBuffer = new CHAR [cbBuffer];
|
||
|
||
if (pBuffer != NULL) {
|
||
|
||
MarshalBufferInitialize(
|
||
&marshalBuffer,
|
||
cbBuffer,
|
||
pBuffer);
|
||
|
||
status = DfsRtlPut(&marshalBuffer, &MiVolumeProperties, &_VolProps);
|
||
|
||
DfsRtlPutUlong(&marshalBuffer, &_VolProps.dwTimeout);
|
||
|
||
ASSERT(NT_SUCCESS(status));
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
dwErr = ERROR_INVALID_DATA;
|
||
|
||
delete [] pBuffer;
|
||
|
||
goto exit_with_error;
|
||
}
|
||
|
||
dwErr = pDfsmLdap->PutData(_wszFileName, cbBuffer, pBuffer);
|
||
|
||
delete [] pBuffer;
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
exit_with_error:
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapEnumDirectory::CLdapEnumDirectory
|
||
//
|
||
// Synopsis: Enumerator over ldap objects in the global CLdap object
|
||
//
|
||
// Arguments: [wszFileName] -- The ldap object whose children we are to
|
||
// enumerate.
|
||
//
|
||
// [pdwErr] -- Result of construction
|
||
//
|
||
// Returns: Nothing, but note the result code returned in the pdwErr
|
||
// parameter.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
CLdapEnumDirectory::CLdapEnumDirectory(
|
||
LPWSTR wszFileName,
|
||
LPDWORD pdwErr)
|
||
{
|
||
IDfsVolInlineDebOut((
|
||
DEB_TRACE, "CLdapEnumDirectory::+CLdapEnumDirectory(0x%x)\n",
|
||
this));
|
||
|
||
_pCookie = NULL;
|
||
|
||
_wszFileName = new WCHAR [ wcslen(wszFileName) + 1 ];
|
||
|
||
if (_wszFileName != NULL) {
|
||
|
||
wcscpy( _wszFileName, wszFileName );
|
||
|
||
*pdwErr = ERROR_SUCCESS;
|
||
|
||
} else {
|
||
|
||
*pdwErr = ERROR_OUTOFMEMORY;
|
||
}
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapEnumDirectory::~CLdapEnumDirectory
|
||
//
|
||
// Synopsis: Destructor for ldap object directory enumerator
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
CLdapEnumDirectory::~CLdapEnumDirectory()
|
||
{
|
||
IDfsVolInlineDebOut((
|
||
DEB_TRACE, "CLdapEnumDirectory::~CLdapEnumDirectory(0x%x)\n",
|
||
this));
|
||
|
||
if (_wszFileName != NULL)
|
||
delete [] _wszFileName;
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CLdapEnumDirectory::Next
|
||
//
|
||
// Synopsis: Enumerates the next child of _wszFileName
|
||
//
|
||
// Arguments: [rgelt] -- Pointer to STATDIR structure. Only the name
|
||
// of the child relative to this storage is returned.
|
||
// [pcFetched] -- Set to 1 if a child name is successfully
|
||
// retrieved, 0 if an error occurs or if no more
|
||
// children.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Operation succeeded. If no more children
|
||
// are available, ERROR_SUCCESS is returned and
|
||
// *pcFetched is set to 0.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Unable to allocate room for child name.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CLdapEnumDirectory::Next(
|
||
DFSMSTATDIR *rgelt,
|
||
PULONG pcFetched)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
LPWSTR wszFullChildName;
|
||
|
||
wszFullChildName = pDfsmLdap->NextChild( _wszFileName, &_pCookie );
|
||
|
||
if (wszFullChildName != NULL) {
|
||
|
||
rgelt->pwcsName = new WCHAR [wcslen(wszFullChildName) + 1];
|
||
|
||
if (rgelt->pwcsName != NULL) {
|
||
|
||
wcscpy(
|
||
rgelt->pwcsName,
|
||
&wszFullChildName[ wcslen(_wszFileName) + 1 ]);
|
||
|
||
*pcFetched = 1;
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
*pcFetched = 0;
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
}
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsmCreateLdapStorage
|
||
//
|
||
// Synopsis: Given a "file name", creates and returns a CLdapStorage over
|
||
// it.
|
||
//
|
||
// Arguments: [lpwszFileName] -- Name of file to create.
|
||
// [ppDfsmStorage] -- On successful return, holds pointer to
|
||
// new CLdapStorage object. This object must be deleted
|
||
// by calling its Release() method.
|
||
//
|
||
// Returns: S_OK if successful.
|
||
//
|
||
// E_OUTOFMEMORY if unable to allocate memory.
|
||
//
|
||
// DWORD_FROM_WIN32 of Win32 error returned by RegCreateKey()
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
DfsmCreateLdapStorage(
|
||
IN LPCWSTR lpwszFileName,
|
||
OUT CStorage **ppDfsmStorage)
|
||
{
|
||
DWORD dwErr;
|
||
HKEY hkey;
|
||
|
||
dwErr = pDfsmLdap->CreateObject(lpwszFileName);
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
dwErr = DfsmOpenLdapStorage( lpwszFileName, ppDfsmStorage );
|
||
|
||
}
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
static DWORD GetDCFlags[] = {
|
||
DS_DIRECTORY_SERVICE_REQUIRED |
|
||
DS_IP_REQUIRED,
|
||
|
||
DS_DIRECTORY_SERVICE_REQUIRED |
|
||
DS_IP_REQUIRED |
|
||
DS_FORCE_REDISCOVERY
|
||
};
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: GetDCName
|
||
//
|
||
// Synopsis: Stub function that returns the "address" of a DC.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Returns:
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
GetDcName(
|
||
IN LPCSTR DomainName OPTIONAL,
|
||
IN DWORD RetryCount,
|
||
OUT LPWSTR *DCName)
|
||
{
|
||
DWORD dwErr, cRetryCount;
|
||
PDOMAIN_CONTROLLER_INFO pDCInfo;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("DsGetDcName(%d)\n", RetryCount);
|
||
#endif
|
||
|
||
cRetryCount = RetryCount % (sizeof(GetDCFlags) / sizeof(GetDCFlags[1]));
|
||
|
||
dwErr = DsGetDcName(
|
||
NULL, // Computer to remote to
|
||
NULL, // Domain - use local domain
|
||
NULL, // Domain Guid
|
||
NULL, // Site Guid
|
||
GetDCFlags[cRetryCount], // Flags
|
||
&pDCInfo);
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("DsGetDcName returned %d\n", dwErr);
|
||
#endif
|
||
|
||
DFSM_TRACE_ERROR_HIGH(dwErr, ALL_ERROR, GetDcName_Error_GetDcName,
|
||
LOGULONG(dwErr)
|
||
);
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
(*DCName) = new WCHAR [ wcslen(pDCInfo->DomainControllerName) + 1 ];
|
||
|
||
if ((*DCName) != NULL) {
|
||
wcscpy(*DCName, pDCInfo->DomainControllerName);
|
||
} else {
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
NetApiBufferFree( pDCInfo );
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("DsGetDcName DC [%ws]\n", *DCName);
|
||
#endif
|
||
|
||
} else {
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "DsGetDcName failed %d\n", dwErr));
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("GetDcName returning %d\n", dwErr);
|
||
#endif
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: GetConfigurationDN
|
||
//
|
||
// Synopsis: This routine computes the DN of the metadata container object in the DS
|
||
//
|
||
// Arguments: [pwszDN] -- On return, points to allocated string containing
|
||
// DN of megadata container. Caller should free using
|
||
// delete
|
||
//
|
||
// Returns: Win32 error from ldap or memory allocation functions.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
GetConfigurationDN(
|
||
LPWSTR *pwszDN)
|
||
{
|
||
DWORD dwErr;
|
||
HKEY hkey;
|
||
WCHAR wszConfigDN[ MAX_PATH ];
|
||
DWORD dwType, cbConfigDN;
|
||
|
||
dwErr = RegOpenKey( HKEY_LOCAL_MACHINE, VOLUMES_DIR, &hkey );
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
cbConfigDN = sizeof(wszConfigDN);
|
||
|
||
dwErr = RegQueryValueEx(
|
||
hkey,
|
||
FTDFS_DN_VALUE_NAME,
|
||
NULL,
|
||
&dwType,
|
||
(PBYTE) wszConfigDN,
|
||
&cbConfigDN);
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
*pwszDN = new WCHAR [ wcslen(wszConfigDN) + 1 ];
|
||
|
||
if ((*pwszDN) != NULL) {
|
||
|
||
wcscpy( (*pwszDN), wszConfigDN);
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
RegCloseKey( hkey );
|
||
|
||
}
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
DWORD
|
||
LdapCreateObject(
|
||
LPWSTR ObjectName)
|
||
{
|
||
DWORD dwErr;
|
||
|
||
pDfsmLdap->AddRef();
|
||
|
||
dwErr = pDfsmLdap->CreateObject(ObjectName);
|
||
|
||
pDfsmLdap->Release();
|
||
|
||
return dwErr;
|
||
}
|
||
|
||
DWORD
|
||
LdapGetData(
|
||
LPWSTR ObjectName,
|
||
PULONG pcBytes,
|
||
PCHAR *ppData)
|
||
{
|
||
DWORD dwErr;
|
||
|
||
pDfsmLdap->AddRef();
|
||
|
||
dwErr = pDfsmLdap->GetData(
|
||
ObjectName,
|
||
pcBytes,
|
||
ppData);
|
||
|
||
pDfsmLdap->Release();
|
||
|
||
return dwErr;
|
||
}
|
||
|
||
DWORD
|
||
LdapPutData(
|
||
LPWSTR ObjectName,
|
||
ULONG cBytes,
|
||
PCHAR pData)
|
||
{
|
||
DWORD dwErr;
|
||
|
||
pDfsmLdap->AddRef();
|
||
|
||
dwErr = pDfsmLdap->PutData(
|
||
ObjectName,
|
||
cBytes,
|
||
pData);
|
||
|
||
pDfsmLdap->Release();
|
||
|
||
return dwErr;
|
||
}
|
||
|
||
DWORD
|
||
LdapFlushTable(void)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("LdapFlushTable()\n");
|
||
#endif
|
||
if (pDfsmLdap != NULL) {
|
||
dwErr = pDfsmLdap->Flush();
|
||
}
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("LdapFlushTable returning %d\n", dwErr);
|
||
#endif
|
||
return dwErr;
|
||
}
|
||
|
||
DWORD
|
||
LdapIncrementBlob(BOOLEAN SyncRemoteServerName)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("LdapIncrementBlob()\n");
|
||
#endif
|
||
if (pDfsmLdap != NULL) {
|
||
dwErr = pDfsmLdap->AddRef(SyncRemoteServerName);
|
||
}
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("LdapIncrementBlob returning %d\n", dwErr);
|
||
#endif
|
||
return dwErr;
|
||
}
|
||
|
||
DWORD
|
||
LdapDecrementBlob(void)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("LdapDecrementBlob()\n");
|
||
#endif
|
||
if (pDfsmLdap != NULL) {
|
||
dwErr = pDfsmLdap->Release();
|
||
}
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("LdapDecrementBlob returning %d\n", dwErr);
|
||
#endif
|
||
return dwErr;
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsLoadSiteTableFromDs
|
||
//
|
||
// Synopsis: Given the name of an FTDfs and a list of servers, this routine
|
||
// goes throught the FtDFS blob and primes the dfs site table with
|
||
// the site information for each servername passed in.
|
||
//
|
||
// Arguments: [pldap] -- ldap to use
|
||
// [wszFTDfsName] -- Name of FTDfs
|
||
// [Count] -- number of server names in pustr
|
||
// [pustr] -- pointer to array of UNICODE_STRINGS, each a server we
|
||
// want site information on.
|
||
//
|
||
// Returns: Win32 error from ldap or memory allocation functions.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" DWORD
|
||
DfsLoadSiteTableFromDs(
|
||
PLDAP pldap,
|
||
LPWSTR wszFTDfsName,
|
||
ULONG Count,
|
||
PUNICODE_STRING pustr)
|
||
{
|
||
NTSTATUS NtStatus;
|
||
DWORD dwErr;
|
||
DWORD i, j;
|
||
DWORD cObj;
|
||
|
||
PLDAPMessage pMsg = NULL;
|
||
MARSHAL_BUFFER marshalBuffer;
|
||
LDAP_PKT ldapPkt;
|
||
PLDAP_OBJECT pldapObject;
|
||
|
||
WCHAR wszFtDfsConfigDN[MAX_PATH+1];
|
||
LPWSTR wszDCName = NULL;
|
||
LPWSTR wszDfsConfigDN = NULL;
|
||
|
||
BOOLEAN bUnbindNeeded = FALSE;
|
||
|
||
LPWSTR rgAttrs[5];
|
||
|
||
if (pldap == NULL) {
|
||
|
||
if (pwszDSMachineName != NULL) {
|
||
|
||
dwErr = DfspLdapOpen(pwszDSMachineName, &pldap, &wszDfsConfigDN);
|
||
|
||
} else {
|
||
|
||
dwErr = GetDcName( NULL, 1, &wszDCName );
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
dwErr = DfspLdapOpen(&wszDCName[2], &pldap, &wszDfsConfigDN);
|
||
delete [] wszDCName;
|
||
}
|
||
|
||
}
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
bUnbindNeeded = TRUE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// We've been given the ldap connection, just need the name of the dfs
|
||
// configuration obj.
|
||
//
|
||
|
||
dwErr = DfspLdapOpen(NULL, &pldap, &wszDfsConfigDN);
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
|
||
IDfsVolInlineDebOut((DEB_ERROR, "Unable to find Configuration naming context\n", 0));
|
||
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
wsprintf(
|
||
wszFtDfsConfigDN,
|
||
L"CN=%ws,%ws",
|
||
wszFTDfsName,
|
||
wszDfsConfigDN);
|
||
|
||
rgAttrs[0] = L"pKT";
|
||
rgAttrs[1] = NULL;
|
||
|
||
if (DfsSvcLdap)
|
||
DbgPrint("CLdap::DfsLoadSiteTableFromDs:ldap_search(%ws)\n", rgAttrs[0]);
|
||
|
||
dwErr = ldap_search_sW(
|
||
pldap,
|
||
wszFtDfsConfigDN,
|
||
LDAP_SCOPE_BASE,
|
||
L"(objectClass=*)",
|
||
rgAttrs,
|
||
0,
|
||
&pMsg);
|
||
|
||
DFSM_TRACE_ERROR_HIGH(dwErr, ALL_ERROR,
|
||
DfsLoadSiteTableFromDs_Error_ldap_search_sW,
|
||
LOGULONG(dwErr));
|
||
|
||
if (dwErr == LDAP_SUCCESS) {
|
||
|
||
PLDAP_BERVAL *rgldapPktBlob, pldapPktBlob;
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
rgldapPktBlob = ldap_get_values_lenW(
|
||
pldap,
|
||
pMsg,
|
||
L"pKT");
|
||
|
||
if((rgldapPktBlob != NULL) && (*rgldapPktBlob != NULL)) {
|
||
|
||
pldapPktBlob = rgldapPktBlob[0];
|
||
|
||
if (pldapPktBlob->bv_len > sizeof(DWORD)) {
|
||
|
||
MarshalBufferInitialize(
|
||
&marshalBuffer,
|
||
pldapPktBlob->bv_len - sizeof(DWORD),
|
||
pldapPktBlob->bv_val + sizeof(DWORD));
|
||
|
||
NtStatus = DfsRtlGet(&marshalBuffer, &MiLdapPkt, &ldapPkt);
|
||
|
||
if (NT_SUCCESS(NtStatus)) {
|
||
|
||
for (cObj = 0; cObj < ldapPkt.cLdapObjects; cObj++) {
|
||
|
||
pldapObject = &ldapPkt.rgldapObjects[cObj];
|
||
|
||
if (wcscmp(pldapObject->wszObjectName, L"\\siteroot") == 0) {
|
||
ProcessSiteTable(
|
||
(PBYTE)pldapObject->pObjectData,
|
||
pldapObject->cbObjectData,
|
||
Count,
|
||
pustr);
|
||
}
|
||
|
||
MarshalBufferFree(pldapObject->wszObjectName);
|
||
MarshalBufferFree(pldapObject->pObjectData);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
MarshalBufferFree(ldapPkt.rgldapObjects);
|
||
|
||
}
|
||
|
||
ldap_value_free_len(rgldapPktBlob);
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_UNEXP_NET_ERR;
|
||
|
||
}
|
||
|
||
ldap_msgfree(pMsg);
|
||
|
||
} else {
|
||
|
||
dwErr = LdapMapErrorToWin32(dwErr);
|
||
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
if( pldap != NULL && bUnbindNeeded == TRUE && pldap != pLdapConnection) {
|
||
if (DfsSvcLdap)
|
||
DbgPrint("DfsLoadSiteTableFromDs:ldap_unbind\n");
|
||
ldap_unbind(pldap);
|
||
}
|
||
|
||
if (wszDfsConfigDN != NULL) {
|
||
free(wszDfsConfigDN);
|
||
}
|
||
|
||
return dwErr;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: ProcessSiteTable
|
||
//
|
||
// Synopsis: Unmarshalls a site table and uses a list of servers to prime the
|
||
// site table.
|
||
//
|
||
// Arguments: [pBuffer] -- Buffer with site table
|
||
// [cbBuffer] -- size of the buffer
|
||
// [cServers] -- number of names in the pustrServers array
|
||
// [pustrServers] -- pointer to array of UNICODE_STRING server names.
|
||
//
|
||
// Returns: Win32 error from ldap or memory allocation functions.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
ProcessSiteTable(
|
||
PBYTE pBuffer,
|
||
ULONG cbBuffer,
|
||
ULONG cServers,
|
||
PUNICODE_STRING pustrServers)
|
||
{
|
||
NTSTATUS NtStatus;
|
||
DWORD dwErr;
|
||
ULONG cObjects = 0;
|
||
ULONG cbThisObj;
|
||
ULONG i;
|
||
ULONG j;
|
||
PDFSM_SITE_ENTRY pSiteInfo;
|
||
MARSHAL_BUFFER marshalBuffer;
|
||
UNICODE_STRING ServerName1;
|
||
UNICODE_STRING ServerName2;
|
||
GUID guid;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "ProcessSiteTable()\n", 0));
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
|
||
if (dwErr == ERROR_SUCCESS && cbBuffer >= sizeof(ULONG)) {
|
||
|
||
//
|
||
// Unmarshall all the objects (NET_DFS_SITENAME_INFO's) in the buffer
|
||
//
|
||
|
||
MarshalBufferInitialize(
|
||
&marshalBuffer,
|
||
cbBuffer,
|
||
pBuffer);
|
||
|
||
DfsRtlGetGuid(&marshalBuffer, &guid);
|
||
DfsRtlGetUlong(&marshalBuffer, &cObjects);
|
||
|
||
//
|
||
// Examine each object (a DFSM_SITE_ENTRY)
|
||
//
|
||
|
||
for (i = 0; i < cObjects; i++) {
|
||
|
||
pSiteInfo = (PDFSM_SITE_ENTRY) new BYTE [cbBuffer-sizeof(ULONG)];
|
||
|
||
if (pSiteInfo != NULL) {
|
||
|
||
NtStatus = DfsRtlGet(&marshalBuffer,&MiDfsmSiteEntry, pSiteInfo);
|
||
|
||
if (NT_SUCCESS(NtStatus)) {
|
||
|
||
RtlInitUnicodeString(&ServerName1, pSiteInfo->ServerName);
|
||
|
||
//
|
||
// Compare the ServerName of this Site entry with the list of
|
||
// servers passed in. If we match, prime the dfs driver with
|
||
// the site info for this server.
|
||
//
|
||
|
||
for (j = 0; j < cServers; j++) {
|
||
|
||
//
|
||
// Get the server from \\server\share
|
||
//
|
||
|
||
DfsServerFromPath(&pustrServers[j], &ServerName2);
|
||
|
||
if (RtlCompareUnicodeString(&ServerName1,&ServerName2,TRUE) == 0) {
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE,
|
||
"DfsSentUpDate(%ws,%d)\n",
|
||
pSiteInfo->ServerName,
|
||
pSiteInfo->Info.cSites));
|
||
|
||
DfsSendUpdate(
|
||
pSiteInfo->ServerName,
|
||
pSiteInfo->Info.cSites,
|
||
&pSiteInfo->Info.Site[0]);
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// The unmarshalling routines allocate buffers; we need to
|
||
// free them.
|
||
//
|
||
|
||
for (j = 0; j < pSiteInfo->Info.cSites; j++) {
|
||
MarshalBufferFree(pSiteInfo->Info.Site[j].SiteName);
|
||
}
|
||
|
||
MarshalBufferFree(pSiteInfo->ServerName);
|
||
|
||
}
|
||
|
||
delete [] pSiteInfo;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "ProcessSiteTable exit dwErr=%d\n", dwErr));
|
||
|
||
return dwErr;
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsServerFromPath
|
||
//
|
||
// Synopsis: Helper routine to extract the servername from a pathname.
|
||
// ex: \microsoft\dfs will return 'microsoft'.
|
||
//
|
||
// Arguments: [PathName] -- PathName to search
|
||
// [ServerName] -- Name of server in that pathname
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
VOID
|
||
DfsServerFromPath(
|
||
PUNICODE_STRING PathName,
|
||
PUNICODE_STRING ServerName)
|
||
{
|
||
ULONG i;
|
||
|
||
*ServerName = *PathName;
|
||
|
||
while (ServerName->Buffer[0] == L'\\' && ServerName->Length > 0) {
|
||
|
||
ServerName->Buffer++;
|
||
ServerName->Length -= sizeof(WCHAR);
|
||
ServerName->MaximumLength -= sizeof(WCHAR);
|
||
|
||
}
|
||
|
||
for (i = 0;
|
||
ServerName->Buffer[i] != L'\\' && i < ServerName->Length/sizeof(WCHAR);
|
||
i++
|
||
) {
|
||
|
||
/* NOTHING */
|
||
|
||
}
|
||
|
||
if (i < ServerName->Length/sizeof(WCHAR)) {
|
||
|
||
ServerName->Length = (USHORT) (i * sizeof(WCHAR));
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsGetFtServersFromDs
|
||
//
|
||
// Synopsis: This API returns a vector of \\server\share combinations which
|
||
// form the root of a Fault Tolerant DFS. This null-terminated vector should be
|
||
// freed by the caller with NetApiBufferFree().
|
||
//
|
||
// If pLDAP is supplied, we assume that this is the handle to the DS server
|
||
// holding the configuration data. Else, we use wszDomainName to locate the
|
||
// proper DS server.
|
||
//
|
||
// wszDfsName is the name of the fault tolerant DFS for which individual servers
|
||
// are to be discovered.
|
||
//
|
||
//+----------------------------------------------------------------------------
|
||
extern "C"
|
||
DWORD
|
||
DfsGetFtServersFromDs(
|
||
PLDAP pLDAP,
|
||
LPWSTR wszDomainName,
|
||
LPWSTR wszDfsName,
|
||
LPWSTR **List
|
||
)
|
||
{
|
||
BOOLEAN bUnbindNeeded = FALSE;
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
NTSTATUS status;
|
||
PWCHAR attrs[2];
|
||
LDAPMessage *pMsg = NULL;
|
||
LDAPMessage *pEntry = NULL;
|
||
WCHAR *pAttr = NULL;
|
||
WCHAR **rpValues = NULL;
|
||
WCHAR **allValues = NULL;
|
||
WCHAR ***rpValuesToFree = NULL;
|
||
INT cValues = 0;
|
||
INT i;
|
||
LPWSTR FtDfsDN = NULL;
|
||
LPWSTR DfsConfigDN = NULL;
|
||
DWORD len;
|
||
USHORT cChar;
|
||
PWCHAR *resultVector;
|
||
ULONG cBytes;
|
||
BOOLEAN GettingNames = FALSE;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("DfsGetFtServersFromDs(0x%x,%ws,%ws)\n",
|
||
pLDAP,
|
||
wszDomainName,
|
||
wszDfsName);
|
||
#endif
|
||
|
||
if (List == NULL) {
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto AllDone;
|
||
}
|
||
|
||
*List = NULL;
|
||
|
||
if (!ARGUMENT_PRESENT(pLDAP)) {
|
||
|
||
DOMAIN_CONTROLLER_INFO *pInfo = NULL;
|
||
ULONG dsAdditionalFlags = 0;
|
||
ULONG retry;
|
||
|
||
for (retry = 0; pLDAP == NULL && retry < 2; retry++) {
|
||
|
||
//
|
||
// Find a DC for the given domain.
|
||
//
|
||
dwErr = DsGetDcName(
|
||
NULL, // computer name
|
||
wszDomainName, // DNS domain name
|
||
NULL, // domain guid
|
||
NULL, // site guid
|
||
DS_DIRECTORY_SERVICE_REQUIRED |
|
||
DS_IP_REQUIRED |
|
||
dsAdditionalFlags,
|
||
&pInfo);
|
||
|
||
DFSM_TRACE_ERROR_HIGH(dwErr, ALL_ERROR, DfsGetFtServersFromDs_Error_DsGetDcName,
|
||
LOGWSTR(wszDomainName)
|
||
LOGULONG(dwErr)
|
||
);
|
||
|
||
if (dwErr != ERROR_SUCCESS)
|
||
goto AllDone;
|
||
|
||
//
|
||
// DomainControllerName is prefixed with "\\" so
|
||
// aditionally ensure there's some useful data there.
|
||
//
|
||
|
||
if (DS_INET_ADDRESS != pInfo->DomainControllerAddressType ||
|
||
(cChar = (USHORT)wcslen(pInfo->DomainName)) < 3) {
|
||
|
||
NetApiBufferFree(pInfo);
|
||
dwErr = ERROR_NO_SUCH_DOMAIN;
|
||
goto AllDone;
|
||
}
|
||
|
||
//
|
||
// Try to connect to the DS server on the DC
|
||
//
|
||
|
||
dwErr = DfspLdapOpen(&pInfo->DomainControllerName[2], &pLDAP, &DfsConfigDN);
|
||
|
||
NetApiBufferFree(pInfo);
|
||
|
||
}
|
||
|
||
if (dwErr != ERROR_SUCCESS)
|
||
goto AllDone;
|
||
|
||
bUnbindNeeded = TRUE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// We've been given an ldap connection, just need the name of the dfs
|
||
// configuration object
|
||
//
|
||
|
||
dwErr = DfspLdapOpen(NULL, &pLDAP, &DfsConfigDN);
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(wszDfsName)) {
|
||
|
||
//
|
||
// Looks good. Allocate enough memory to hold the DN of the
|
||
// DFS configuration data for the fault tolerant DFS in question
|
||
//
|
||
|
||
len = (DWORD)(3 * sizeof(WCHAR) +
|
||
(wcslen(wszDfsName) + 1) * sizeof(WCHAR) +
|
||
(wcslen(DfsConfigDN) + 1) * sizeof(WCHAR));
|
||
|
||
dwErr = NetApiBufferAllocate(len, (PVOID *)&FtDfsDN);
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Construct the DN for the FtDfs obj
|
||
//
|
||
|
||
RtlZeroMemory(FtDfsDN, len);
|
||
wcscpy(FtDfsDN, L"CN=");
|
||
wcscat(FtDfsDN, wszDfsName);
|
||
wcscat(FtDfsDN, L",");
|
||
wcscat(FtDfsDN, DfsConfigDN);
|
||
|
||
//
|
||
// Now see if we can get at the 'remoteServerName' property of this object.
|
||
// This property holds the names of the servers hosting this DFS
|
||
//
|
||
|
||
pLDAP->ld_sizelimit = 0;
|
||
pLDAP->ld_timelimit= 0;
|
||
pLDAP->ld_deref = LDAP_DEREF_NEVER;
|
||
|
||
ldap_msgfree(pMsg);
|
||
pMsg = NULL;
|
||
|
||
attrs[0] = L"remoteServerName";
|
||
attrs[1] = NULL;
|
||
|
||
if (DfsSvcLdap)
|
||
DbgPrint("DfsGetFtServersFromDs:ldap_search(%ws)\n", attrs[0]);
|
||
|
||
dwErr = ldap_search_sW(
|
||
pLDAP,
|
||
FtDfsDN,
|
||
LDAP_SCOPE_BASE,
|
||
L"(objectClass=*)",
|
||
attrs,
|
||
0,
|
||
&pMsg);
|
||
|
||
DFSM_TRACE_ERROR_HIGH(dwErr, ALL_ERROR,
|
||
DfsGetFtServersFromDs_Error_ldap_search_sW,
|
||
LOGULONG(dwErr));
|
||
|
||
if (dwErr != LDAP_SUCCESS) {
|
||
|
||
dwErr = LdapMapErrorToWin32(dwErr);
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
//
|
||
// Make sure the result is reasonable
|
||
//
|
||
if (ldap_count_entries(pLDAP, pMsg) == 0 ||
|
||
(pEntry = ldap_first_entry(pLDAP, pMsg)) == NULL ||
|
||
(rpValues = ldap_get_valuesW(pLDAP, pEntry, attrs[0])) == NULL ||
|
||
rpValues[0][0] == L'\0'
|
||
) {
|
||
|
||
dwErr = ERROR_UNEXP_NET_ERR;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// The result is reasonable, just point allValues to rpValues
|
||
//
|
||
|
||
allValues = rpValues;
|
||
|
||
} else {
|
||
|
||
//
|
||
// The caller is trying to retrieve the names of all the FT DFSs in the domain
|
||
//
|
||
|
||
GettingNames = TRUE;
|
||
|
||
//
|
||
// Now see if we can enumerate the objects below this one. The names
|
||
// of these objects will be the different FT dfs's available
|
||
//
|
||
pLDAP->ld_sizelimit = 0;
|
||
pLDAP->ld_timelimit= 0;
|
||
pLDAP->ld_deref = LDAP_DEREF_NEVER;
|
||
|
||
attrs[0] = L"CN";
|
||
attrs[1] = NULL;
|
||
|
||
if (DfsSvcLdap)
|
||
DbgPrint("DfsGetFtServersFromDs:ldap_search(%ws)\n", attrs[0]);
|
||
|
||
dwErr = ldap_search_sW(
|
||
pLDAP,
|
||
DfsConfigDN,
|
||
LDAP_SCOPE_ONELEVEL,
|
||
L"(objectClass=fTDfs)",
|
||
attrs,
|
||
0,
|
||
&pMsg);
|
||
|
||
DFSM_TRACE_ERROR_HIGH(dwErr, ALL_ERROR,
|
||
DfsGetFtServersFromDs_Error_ldap_search_sW_2,
|
||
LOGULONG(dwErr));
|
||
|
||
if (dwErr != LDAP_SUCCESS) {
|
||
|
||
dwErr = LdapMapErrorToWin32(dwErr);
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
//
|
||
// Make sure the result is reasonable
|
||
//
|
||
if (
|
||
((cValues = ldap_count_entries(pLDAP, pMsg)) == 0) ||
|
||
(pEntry = ldap_first_entry(pLDAP, pMsg)) == NULL
|
||
) {
|
||
dwErr = ERROR_UNEXP_NET_ERR;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// The search for all FTDfs's returns multiple entries, each with
|
||
// one value for the object's CN. Coalesce these into a single array.
|
||
//
|
||
|
||
dwErr = NetApiBufferAllocate(2 * (cValues + 1) * sizeof(PWSTR), (PVOID *)&allValues);
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
rpValuesToFree = (WCHAR ***) &allValues[cValues + 1];
|
||
|
||
for (i = 0; (i < cValues) && (dwErr == ERROR_SUCCESS); i++) {
|
||
|
||
rpValues = ldap_get_valuesW(pLDAP, pEntry, attrs[0]);
|
||
rpValuesToFree[i] = rpValues;
|
||
//
|
||
// Sanity check
|
||
//
|
||
if (ldap_count_valuesW(rpValues) == 0 || rpValues[0][0] == L'\0') {
|
||
dwErr = ERROR_UNEXP_NET_ERR;
|
||
} else {
|
||
allValues[i] = rpValues[0];
|
||
pEntry = ldap_next_entry(pLDAP, pEntry);
|
||
}
|
||
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
allValues[i] = NULL;
|
||
rpValuesToFree[i] = NULL;
|
||
} else {
|
||
goto Cleanup;
|
||
}
|
||
|
||
}
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Now we need to allocate the memory to hold this vector and return the results.
|
||
//
|
||
// First see how much space we need
|
||
//
|
||
|
||
for (i = len = cValues = 0; allValues[i]; i++) {
|
||
if (*allValues[i] == UNICODE_PATH_SEP || GettingNames == TRUE) {
|
||
len += sizeof(LPWSTR) + (wcslen(allValues[i]) + 1) * sizeof(WCHAR);
|
||
cValues++;
|
||
}
|
||
}
|
||
len += sizeof(LPWSTR);
|
||
|
||
dwErr = NetApiBufferAllocate(len, (PVOID *)&resultVector);
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
LPWSTR pstr = (LPWSTR)((PCHAR)resultVector + (cValues + 1) * sizeof(LPWSTR));
|
||
ULONG slen;
|
||
|
||
RtlZeroMemory(resultVector, len);
|
||
|
||
len -= (cValues+1) * sizeof(LPWSTR);
|
||
|
||
for (i = cValues = 0; allValues[i] && len >= sizeof(WCHAR); i++) {
|
||
if (*allValues[i] == UNICODE_PATH_SEP || GettingNames == TRUE) {
|
||
resultVector[cValues] = pstr;
|
||
wcscpy(pstr, allValues[i]);
|
||
slen = wcslen(allValues[i]);
|
||
pstr += slen + 1;
|
||
len -= (slen + 1) * sizeof(WCHAR);
|
||
cValues++;
|
||
}
|
||
}
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
*List = resultVector;
|
||
|
||
Cleanup:
|
||
|
||
if (ARGUMENT_PRESENT(wszDfsName)) {
|
||
if (rpValues != NULL) {
|
||
ldap_value_freeW(rpValues);
|
||
}
|
||
} else {
|
||
if (rpValuesToFree != NULL) {
|
||
for (i = 0; rpValuesToFree[i] != NULL; i++) {
|
||
ldap_value_freeW(rpValuesToFree[i]);
|
||
}
|
||
}
|
||
if (allValues != NULL) {
|
||
NetApiBufferFree(allValues);
|
||
}
|
||
}
|
||
|
||
if (pMsg != NULL) {
|
||
ldap_msgfree(pMsg);
|
||
}
|
||
|
||
if (FtDfsDN != NULL) {
|
||
NetApiBufferFree(FtDfsDN);
|
||
}
|
||
|
||
if (DfsConfigDN != NULL) {
|
||
free(DfsConfigDN);
|
||
}
|
||
|
||
if (pLDAP != NULL && bUnbindNeeded == TRUE && pLDAP != pLdapConnection) {
|
||
if (DfsSvcLdap)
|
||
DbgPrint("DfsGetFtServersFromDs:ldap_unbind\n");
|
||
ldap_unbind(pLDAP);
|
||
}
|
||
|
||
AllDone:
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("DfsGetFtServersFromDs returning %d\n", dwErr);
|
||
#endif
|
||
|
||
return dwErr;
|
||
}
|