You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
643 lines
20 KiB
643 lines
20 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 2001, Microsoft Corporation
|
|
//
|
|
// File: DfsXForest.cxx
|
|
//
|
|
// Contents: the Dfs xforest info class
|
|
//
|
|
// Classes: DfsXForest, DfsDomainNameTable
|
|
//
|
|
// History: Nov, 15 2002, Author: udayh
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "dfsxforest.hxx"
|
|
#include "lm.h"
|
|
|
|
#include "dfsxforest.tmh"
|
|
|
|
//
|
|
// This file implements DfsXForest class. This class enumerates all
|
|
// local domains and cross forest domains, and builds a table of uniqye
|
|
// domain names.
|
|
//
|
|
// Ideally this should be an API such as DsEnumerateDomainTrusts, but
|
|
// lacking that we are putting this support here.
|
|
//
|
|
// Since this is happening so close to RTM, there is minimal code change
|
|
// in the original path, and all functionality has been implemented in
|
|
// this new class. This is called from DfsDomainInformation, where
|
|
// instead of enumerating domains by calling DsEnumerateDomainTrusts we
|
|
// enumerate domains by building the DfsXForest instance.
|
|
//
|
|
// DfsDomainInformation gets the DfsXForest instance, reads all the domains
|
|
// from the DfsXForest and destroys the DfsXForest.
|
|
//
|
|
//
|
|
// In future, we may either want to get an API for this. If that does
|
|
// not happen, it may be worthwhile changing the DfsDomainInformation
|
|
// code to use the DfsXForest instance all the time instead of
|
|
// building an array of domain names enumerated using this class.
|
|
// That would be a more performance optimal solution.
|
|
//
|
|
//
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsXForest::Initialize( DFSSTATUS *pXforestInitStatus )
|
|
{
|
|
DFSSTATUS Status;
|
|
|
|
Status = _DomainTable.Initialize();
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = DfsAddLocalDomainsToDomainTable();
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
DFSSTATUS DfsCrossForestDomainStatus;
|
|
|
|
DfsCrossForestDomainStatus = InitializeForestRootName();
|
|
DFS_TRACE_ERROR_NORM(DfsCrossForestDomainStatus, REFERRAL_SERVER,
|
|
"DfsXForest::InitializeForestRootName, Status 0x%x\n",
|
|
DfsCrossForestDomainStatus);
|
|
//
|
|
// If we cannot get cross forest domain information,
|
|
// we continue with just the local information.
|
|
//
|
|
if (DfsCrossForestDomainStatus == ERROR_SUCCESS)
|
|
{
|
|
DfsCrossForestDomainStatus = DfsAddCrossForestDomainsToDomainTable();
|
|
DFS_TRACE_ERROR_NORM(DfsCrossForestDomainStatus, REFERRAL_SERVER,
|
|
"DfsXForest::DfsAddCrossForestDomainsToDomainTable, Status 0x%x\n",
|
|
DfsCrossForestDomainStatus);
|
|
}
|
|
|
|
*pXforestInitStatus = DfsCrossForestDomainStatus;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// InitializeForestRootName: Get the Root Forest name and store it
|
|
// in our private member _ForestRootName.
|
|
//
|
|
//
|
|
DFSSTATUS
|
|
DfsXForest::InitializeForestRootName()
|
|
{
|
|
|
|
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS NtStatus = 0;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
LSA_HANDLE hPolicy;
|
|
|
|
//attempt to open the policy.
|
|
RtlInitUnicodeString(&_ForestRootName, NULL);
|
|
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));//object attributes are reserved, so initalize to zeroes.
|
|
|
|
NtStatus = LsaOpenPolicy( NULL,
|
|
&ObjectAttributes,
|
|
POLICY_VIEW_LOCAL_INFORMATION,
|
|
&hPolicy); //recieves the policy handle
|
|
|
|
DFS_TRACE_ERROR_HIGH( NtStatus, REFERRAL_SERVER, "LsaOpenPolicy, NtStatus 0x%x\n", NtStatus );
|
|
|
|
if (NT_SUCCESS(NtStatus))
|
|
{
|
|
//ask for audit event policy information
|
|
PPOLICY_DNS_DOMAIN_INFO info;
|
|
NtStatus = LsaQueryInformationPolicy(hPolicy,
|
|
PolicyDnsDomainInformation,
|
|
(PVOID *)&info);
|
|
DFS_TRACE_ERROR_HIGH( NtStatus, REFERRAL_SERVER, "LsaQueryInformationPolicy, NtStatus 0x%x\n", NtStatus );
|
|
|
|
if (NT_SUCCESS(NtStatus))
|
|
{
|
|
//
|
|
// convert LSA_UNICODE_STRING to normal UNICODE_STRING.
|
|
// not that it matters now, but if things should change,
|
|
// we will be in trouble.
|
|
// Save the forest name and we are done.
|
|
//
|
|
UNICODE_STRING TempForestName;
|
|
|
|
TempForestName.Buffer = info->DnsForestName.Buffer;
|
|
TempForestName.Length = info->DnsForestName.Length;
|
|
TempForestName.MaximumLength = info->DnsForestName.MaximumLength;
|
|
|
|
Status = DfsCreateUnicodeString( &_ForestRootName,
|
|
&TempForestName);
|
|
|
|
|
|
//free policy info structure
|
|
LsaFreeMemory((PVOID) info);
|
|
}
|
|
|
|
//Freeing the policy object handle
|
|
LsaClose(hPolicy);
|
|
}
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
Status = RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// DfsAddLocalDomainsToDomainTable: enumerate all the local domain
|
|
// trusts and add this to the domain table.
|
|
//
|
|
|
|
DFSSTATUS
|
|
DfsXForest::DfsAddLocalDomainsToDomainTable()
|
|
{
|
|
DFSSTATUS Status;
|
|
ULONG DsDomainCount = 0;
|
|
PDS_DOMAIN_TRUSTS pDsDomainTrusts = NULL;
|
|
ULONG Index;
|
|
|
|
Status = DsEnumerateDomainTrusts( NULL,
|
|
DS_DOMAIN_VALID_FLAGS,
|
|
&pDsDomainTrusts,
|
|
&DsDomainCount );
|
|
|
|
DFS_TRACE_ERROR_NORM( Status, REFERRAL_SERVER, "DsEnumerateDomainTrusts, Status 0x%x\n", Status );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
for (Index = 0; (Status == ERROR_SUCCESS) && (Index < DsDomainCount); Index++)
|
|
{
|
|
if (pDsDomainTrusts[Index].TrustType == TRUST_TYPE_DOWNLEVEL)
|
|
continue;
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
if (IsEmptyString(pDsDomainTrusts[Index].NetbiosDomainName) == FALSE)
|
|
{
|
|
Status = AddDomainToDomainTable(pDsDomainTrusts[Index].NetbiosDomainName, NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
if (IsEmptyString(pDsDomainTrusts[Index].DnsDomainName) == FALSE)
|
|
{
|
|
Status = AddDomainToDomainTable(pDsDomainTrusts[Index].DnsDomainName, NULL, FALSE);
|
|
}
|
|
}
|
|
}
|
|
NetApiBufferFree(pDsDomainTrusts);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// DfsAddForestDomainsToDomainTable: enumerate all the domains in a forest
|
|
// and add that to our table.
|
|
//
|
|
//
|
|
DFSSTATUS
|
|
DfsXForest::DfsAddForestDomainsToDomainTable( LSA_HANDLE hPolicy,
|
|
LPWSTR RootNameString)
|
|
{
|
|
DFSSTATUS Status;
|
|
NTSTATUS NtStatus;
|
|
ULONG j;
|
|
|
|
LSA_UNICODE_STRING LsaRootName;
|
|
UNICODE_STRING RootName;
|
|
|
|
PLSA_FOREST_TRUST_INFORMATION pForestTrustInfo = NULL;
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&RootName, RootNameString);
|
|
LsaRootName.Length = RootName.Length;
|
|
LsaRootName.MaximumLength = RootName.MaximumLength;
|
|
LsaRootName.Buffer = RootName.Buffer;
|
|
|
|
NtStatus = LsaQueryForestTrustInformation( hPolicy,
|
|
&LsaRootName,
|
|
&pForestTrustInfo);
|
|
|
|
Status = RtlNtStatusToDosError(NtStatus);
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
|
|
for (j = 0; (Status == ERROR_SUCCESS) && (j < pForestTrustInfo->RecordCount); j++ )
|
|
{
|
|
PLSA_FOREST_TRUST_DOMAIN_INFO pDomainInfo;
|
|
|
|
if (pForestTrustInfo->Entries[j]->ForestTrustType == ForestTrustDomainInfo)
|
|
{
|
|
pDomainInfo = &pForestTrustInfo->Entries[j]->ForestTrustData.DomainInfo;
|
|
|
|
|
|
//
|
|
// If only the DnsDomainName is empty, add both the dns and
|
|
// netbios domain names.
|
|
// The reason is: we cannot resolve netbios domain names
|
|
// to DCs. We bind to the DNS domain name to resolve netbios
|
|
// domains, so we add both netbios and dns names in
|
|
// the add domain to table for netbios names.
|
|
//
|
|
if (IsEmptyUnicodeString((PUNICODE_STRING)&pDomainInfo->DnsName) == FALSE)
|
|
{
|
|
|
|
Status = AddDomainToDomainTable((PUNICODE_STRING)&pDomainInfo->DnsName, NULL, FALSE);
|
|
|
|
if ((Status == ERROR_SUCCESS) && (IsEmptyUnicodeString((PUNICODE_STRING)&pDomainInfo->NetbiosName) == FALSE))
|
|
{
|
|
Status = AddDomainToDomainTable((PUNICODE_STRING)&pDomainInfo->NetbiosName,
|
|
(PUNICODE_STRING)&pDomainInfo->DnsName,
|
|
TRUE);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
LsaFreeMemory(pForestTrustInfo);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// Magic trust flags: KahrenT indicates this is what we need.
|
|
//
|
|
#define DOMAIN_TRUST_FLAGS DS_DOMAIN_DIRECT_INBOUND
|
|
|
|
//
|
|
// DfsAddCrossForestDomainsToDomainTable: Enumerate each forest that we have
|
|
// a trust to, and add that to our table.
|
|
//
|
|
//
|
|
DFSSTATUS
|
|
DfsXForest::DfsAddCrossForestDomainsToDomainTable()
|
|
{
|
|
DFSSTATUS Status;
|
|
NTSTATUS NtStatus;
|
|
|
|
ULONG DsDomainCount = 0;
|
|
PDS_DOMAIN_TRUSTS pDsDomainTrusts = NULL;
|
|
|
|
PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
|
|
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
|
|
LSA_HANDLE hPolicy;
|
|
|
|
ULONG Index;
|
|
|
|
//object attributes are reserved, so initalize to zeroes.
|
|
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
|
|
|
|
Status = DsGetDcName( NULL, //computer name
|
|
_ForestRootName.Buffer,
|
|
NULL, // domain guid
|
|
NULL, // site name
|
|
DS_DIRECTORY_SERVICE_REQUIRED | DS_FORCE_REDISCOVERY,
|
|
&pDomainControllerInfo );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = DsEnumerateDomainTrusts( pDomainControllerInfo->DomainControllerName,
|
|
DOMAIN_TRUST_FLAGS,
|
|
&pDsDomainTrusts,
|
|
&DsDomainCount );
|
|
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
LSA_UNICODE_STRING LsaDCName;
|
|
|
|
RtlInitUnicodeString(&LsaDCName,
|
|
pDomainControllerInfo->DomainControllerName);
|
|
|
|
NtStatus = LsaOpenPolicy(&LsaDCName,
|
|
&ObjectAttributes,
|
|
POLICY_VIEW_LOCAL_INFORMATION,
|
|
&hPolicy);
|
|
|
|
Status = RtlNtStatusToDosError(NtStatus);
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
for (Index = 0; Index < DsDomainCount; Index++)
|
|
{
|
|
PDS_DOMAIN_TRUSTS pDomainTrust;
|
|
DFSSTATUS ForestTrustStatus;
|
|
|
|
pDomainTrust = &pDsDomainTrusts[Index];
|
|
|
|
//
|
|
// If the domain is not in our forest, and it is
|
|
// not MIT kerberos and it has transitive trust,
|
|
// we have found a match. Add that forest and its
|
|
// domains to our list.
|
|
//
|
|
if (!(pDomainTrust->Flags & DS_DOMAIN_IN_FOREST) &&
|
|
(pDomainTrust->TrustType != TRUST_TYPE_MIT) &&
|
|
(pDomainTrust->TrustAttributes & TRUST_ATTRIBUTE_FOREST_TRANSITIVE))
|
|
{
|
|
|
|
//
|
|
// Ignore status return.
|
|
//
|
|
// If any one of the domain enumeration fails,
|
|
// we dont want to fail the entire domain
|
|
// table creation.
|
|
//
|
|
ForestTrustStatus = DfsAddForestDomainsToDomainTable( hPolicy,
|
|
pDomainTrust->DnsDomainName);
|
|
}
|
|
|
|
}
|
|
LsaClose(hPolicy);
|
|
}
|
|
|
|
NetApiBufferFree(pDsDomainTrusts);
|
|
}
|
|
|
|
NetApiBufferFree(pDomainControllerInfo);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
//AddDomainToDomainTable: given a domain name add it to our table
|
|
//
|
|
DFSSTATUS
|
|
DfsXForest::AddDomainToDomainTable(LPWSTR DomainName,
|
|
LPWSTR BindDomainName,
|
|
BOOLEAN Netbios)
|
|
{
|
|
UNICODE_STRING DomainNameUnicode;
|
|
UNICODE_STRING BindDomainNameUnicode;
|
|
DFSSTATUS Status;
|
|
|
|
RtlInitUnicodeString(&DomainNameUnicode, DomainName);
|
|
if (BindDomainName != NULL)
|
|
{
|
|
RtlInitUnicodeString(&BindDomainNameUnicode, BindDomainName);
|
|
}
|
|
|
|
Status = AddDomainToDomainTable( &DomainNameUnicode,
|
|
BindDomainName ? &BindDomainNameUnicode : NULL,
|
|
Netbios);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
//AddDomainToDomainTable: given a domain name add it to our table
|
|
//
|
|
|
|
DFSSTATUS
|
|
DfsXForest::AddDomainToDomainTable(PUNICODE_STRING DomainName,
|
|
PUNICODE_STRING BindDomainName,
|
|
BOOLEAN Netbios)
|
|
{
|
|
DFSSTATUS Status;
|
|
|
|
Status = _DomainTable.AddDomain(DomainName, BindDomainName, Netbios);
|
|
|
|
//
|
|
// Buffer overflow indicates that we went over the hash table limit.
|
|
// However, we keep adding so that we have a count of how many we
|
|
// missed.
|
|
//
|
|
if (Status == ERROR_BUFFER_OVERFLOW)
|
|
{
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// AddDomain: Insert the domain name in our hash table.
|
|
//
|
|
DFSSTATUS
|
|
DfsDomainNameTable::AddDomain(PUNICODE_STRING DomainName,
|
|
PUNICODE_STRING BindDomainName,
|
|
BOOLEAN Netbios)
|
|
{
|
|
PDFS_DOMAIN_NAME_DATA pDomainData = NULL;
|
|
ULONG DomainDataLength;
|
|
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
USHORT DomainNameLength = DomainName->Length;
|
|
USHORT MaxDomainNameLength = DomainNameLength + sizeof(WCHAR);
|
|
|
|
USHORT BindDomainNameLength = 0;
|
|
USHORT MaxBindDomainNameLength = 0;
|
|
|
|
NTSTATUS NtStatus;
|
|
ULONG CurrentSize = 0;
|
|
|
|
if (_DomainReferralSize > MAX_REFERRAL_SIZE)
|
|
{
|
|
_DomainsSkipped++;
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
|
|
CurrentSize = sizeof(DFS_REFERRAL_V3) + sizeof(UNICODE_PATH_SEP)
|
|
+ DomainName->Length + sizeof(UNICODE_NULL);
|
|
|
|
if (BindDomainName != NULL)
|
|
{
|
|
BindDomainNameLength = BindDomainName->Length;
|
|
MaxBindDomainNameLength = BindDomainNameLength + sizeof(WCHAR);
|
|
}
|
|
|
|
DomainDataLength = sizeof(DFS_DOMAIN_NAME_DATA) + MaxDomainNameLength + MaxBindDomainNameLength;
|
|
pDomainData = (PDFS_DOMAIN_NAME_DATA) DfsAllocateForDomainTable(DomainDataLength);
|
|
|
|
if (pDomainData != NULL)
|
|
{
|
|
RtlZeroMemory(pDomainData, DomainDataLength);
|
|
|
|
pDomainData->Header.RefCount = 1;
|
|
pDomainData->Header.pvKey = (PVOID)&pDomainData->DomainInfo.DomainName;
|
|
pDomainData->Header.pData = (PVOID)pDomainData;
|
|
|
|
pDomainData->DomainInfo.Netbios = Netbios;
|
|
RtlInitUnicodeString(&pDomainData->DomainInfo.DomainName, NULL);
|
|
|
|
pDomainData->DomainInfo.DomainName.Buffer = (LPWSTR)(pDomainData + 1);
|
|
pDomainData->DomainInfo.DomainName.MaximumLength = MaxDomainNameLength;
|
|
pDomainData->DomainInfo.DomainName.Length = DomainNameLength;
|
|
|
|
RtlCopyMemory(pDomainData->DomainInfo.DomainName.Buffer,
|
|
DomainName->Buffer,
|
|
DomainNameLength);
|
|
pDomainData->DomainInfo.DomainName.Buffer[DomainNameLength/sizeof(WCHAR)] = 0;
|
|
|
|
if (BindDomainName)
|
|
{
|
|
pDomainData->DomainInfo.BindDomainName.Buffer = (LPWSTR)(((ULONG_PTR)(pDomainData + 1)) + MaxDomainNameLength);
|
|
pDomainData->DomainInfo.BindDomainName.MaximumLength = MaxBindDomainNameLength;
|
|
pDomainData->DomainInfo.BindDomainName.Length = BindDomainNameLength;
|
|
|
|
RtlCopyMemory(pDomainData->DomainInfo.BindDomainName.Buffer,
|
|
BindDomainName->Buffer,
|
|
BindDomainNameLength);
|
|
pDomainData->DomainInfo.BindDomainName.Buffer[BindDomainNameLength/sizeof(WCHAR)] = 0;
|
|
|
|
pDomainData->DomainInfo.UseBindDomain = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
NtStatus = SHashInsertKey(_pDomainNameTable,
|
|
pDomainData,
|
|
&pDomainData->DomainInfo.DomainName,
|
|
SHASH_FAIL_IFFOUND);
|
|
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
DfsDeallocateForDomainTable( pDomainData );
|
|
//
|
|
// if we have collision, we already know this name and
|
|
// we can ignore this error.
|
|
//
|
|
if (NtStatus != STATUS_OBJECT_NAME_COLLISION)
|
|
{
|
|
Status = RtlNtStatusToDosError( NtStatus );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we successfully added to the table, bump up our
|
|
// DomainReferralSize.
|
|
//
|
|
InterlockedDecrement(&pDomainData->Header.RefCount);
|
|
_DomainReferralSize += CurrentSize;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// InvalidateDomainTable: Run through the hash and throw out all our
|
|
// entries.
|
|
//
|
|
//
|
|
VOID
|
|
DfsDomainNameTable::InvalidateDomainTable(VOID)
|
|
{
|
|
SHASH_ITERATOR Iter;
|
|
PDFS_DOMAIN_NAME_DATA pExistingData = NULL;
|
|
NTSTATUS NtStatus;
|
|
|
|
pExistingData = (PDFS_DOMAIN_NAME_DATA) SHashStartEnumerate(&Iter, _pDomainNameTable);
|
|
while (pExistingData != NULL)
|
|
{
|
|
//
|
|
// Remove this item. There's nothing we can do if we hit errors
|
|
// except to keep going.
|
|
//
|
|
|
|
NtStatus = SHashRemoveKey(_pDomainNameTable,
|
|
&pExistingData->DomainInfo.DomainName,
|
|
NULL );
|
|
|
|
//
|
|
// ignore status here, since we want to keep going.
|
|
//
|
|
pExistingData = (PDFS_DOMAIN_NAME_DATA) SHashNextEnumerate(&Iter, _pDomainNameTable);
|
|
}
|
|
SHashFinishEnumerate(&Iter, _pDomainNameTable);
|
|
}
|
|
|
|
|
|
//
|
|
// GetCount: Run through our hash and get a count of the number of
|
|
// items. I wish we could ask the hash table for the count.
|
|
//
|
|
|
|
ULONG
|
|
DfsDomainNameTable::GetCount(VOID)
|
|
{
|
|
SHASH_ITERATOR Iter;
|
|
PDFS_DOMAIN_NAME_DATA pExistingData = NULL;
|
|
ULONG nEntries = 0;
|
|
|
|
pExistingData = (PDFS_DOMAIN_NAME_DATA) SHashStartEnumerate(&Iter, _pDomainNameTable);
|
|
while (pExistingData != NULL)
|
|
{
|
|
nEntries++;
|
|
pExistingData = (PDFS_DOMAIN_NAME_DATA) SHashNextEnumerate(&Iter, _pDomainNameTable);
|
|
}
|
|
SHashFinishEnumerate(&Iter, _pDomainNameTable);
|
|
|
|
return nEntries;
|
|
}
|
|
|
|
//
|
|
// FinishDomainNameEnumerate
|
|
//
|
|
VOID
|
|
DfsDomainNameTable::FinishDomainNameEnumerate( SHASH_ITERATOR *pIter )
|
|
{
|
|
SHashFinishEnumerate( pIter, _pDomainNameTable);
|
|
}
|
|
|
|
|
|
// Allocate and deallocate the cache data entry
|
|
PVOID
|
|
DfsAllocateForDomainTable(ULONG Size )
|
|
{
|
|
PVOID RetValue = NULL;
|
|
|
|
if (Size)
|
|
{
|
|
RetValue = (PVOID) new BYTE[Size];
|
|
if (RetValue != NULL)
|
|
{
|
|
RtlZeroMemory( RetValue, Size );
|
|
}
|
|
}
|
|
|
|
return RetValue;
|
|
}
|
|
|
|
VOID
|
|
DfsDeallocateForDomainTable(PVOID pPointer )
|
|
{
|
|
|
|
if (pPointer)
|
|
{
|
|
delete [] (PBYTE)pPointer;
|
|
}
|
|
}
|
|
|