|
|
//+----------------------------------------------------------------------------
//
// Copyright (C) 1992, Microsoft Corporation.
//
// File: PKTFSCTL.C
//
// Contents: This module contains the implementation for FS controls
// which manipulate the PKT.
//
// Functions: PktFsctrlUpdateDomainKnowledge -
// PktFsctrlGetRelationInfo -
// PktFsctrlSetRelationInfo -
// PktFsctrlIsChildnameLegal -
// PktFsctrlCreateEntry -
// PktFsctrlCreateSubordinateEntry -
// PktFsctrlDestroyEntry -
// PktFsctrlUpdateSiteCosts -
// DfsFsctrlSetDCName -
// DfsAgePktEntries - Flush PKT entries periodically
//
// Private Functions
//
// DfsCreateExitPathOnRoot
// PktpHashSiteCostList
// PktpLookupSiteCost
// PktpUpdateSiteCosts
// PktpSetActiveSpcService
//
// Debug Only Functions
//
// PktFsctrlFlushCache - Flush PKT entries on command
// PktFsctrlFlushSpcCache - Flush SPC entries on command
// PktFsctrlGetFirstSvc - Test hooks for testing replica
// PktFsctrlGetNextSvc - selection.
//
// History: 12 Jul 1993 Alanw Created from localvol.c.
//
//-----------------------------------------------------------------------------
#include "dfsprocs.h"
#include "dfserr.h"
#include "fsctrl.h"
#include "log.h"
#include "dnr.h"
#include "know.h"
#include <stdlib.h>
//
// The local debug trace level
//
#define Dbg (DEBUG_TRACE_LOCALVOL)
//
// Local function prototypes
//
NTSTATUS DfspProtocolToService( IN PDS_TRANSPORT pdsTransport, IN PWSTR pwszPrincipalName, IN PWSTR pwszShareName, IN BOOLEAN fIsDfs, IN OUT PDFS_SERVICE pService);
NTSTATUS PktFsctrlFlushCache( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PVOID InputBuffer, IN ULONG InputBufferLength );
NTSTATUS PktFsctrlFlushSpcCache( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PVOID InputBuffer, IN ULONG InputBufferLength );
VOID PktFlushChildren( PDFS_PKT_ENTRY pEntry );
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, DfsAgePktEntries )
#pragma alloc_text( PAGE, DfspProtocolToService )
#pragma alloc_text( PAGE, DfsFsctrlSetDCName )
#pragma alloc_text( PAGE, PktpSetActiveSpcService )
#pragma alloc_text( PAGE, PktFlushChildren )
#pragma alloc_text( PAGE, PktFsctrlFlushCache )
#pragma alloc_text( PAGE, PktFsctrlFlushSpcCache )
#endif // ALLOC_PRAGMA
//+----------------------------------------------------------------------
//
// Function: DfsAgePktEntries, public
//
// Synopsis: This function gets called in the FSP to step through the PKT
// entries and delete those entries which are old.
//
// Arguments: [TimerContext] -- This context block contains a busy flag
// and a count of the number of ticks that
// have elapsed.
//
// Returns: Nothing.
//
// Notes: In case the PKT cannot be acquired exclusive, the
// routine just returns without doing anything. We
// will have missed an aging interval, but aging is
// a non-critical activity.
//
// History: 04/23/93 SudK Created.
//
//-----------------------------------------------------------------------
VOID DfsAgePktEntries(PDFS_TIMER_CONTEXT DfsTimerContext) {
PDFS_PKT pkt = _GetPkt(); PDFS_PKT_ENTRY entry, nextEntry; PDFS_SPECIAL_ENTRY sentry, snextEntry; PLIST_ENTRY link; PDFS_CREDENTIALS creds; BOOLEAN pktLocked = FALSE; PDFS_SPECIAL_TABLE pSpecialTable;
DfsDbgTrace(+1, Dbg, "DfsAgePktEntries called\n", 0);
pSpecialTable = &pkt->SpecialTable;
//
// First we need to acquire a lock on the PKT and step through the PKT
//
//
// If we can't get to the resource then let us return right away.
// This is really not that critical. We can always try again.
//
PktAcquireExclusive(FALSE, &pktLocked);
if (pktLocked == FALSE) {
DfsTimerContext->TickCount = 0;
DfsTimerContext->InUse = FALSE;
DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit (no scan)\n", 0);
return;
}
if (ExAcquireResourceExclusiveLite(&DfsData.Resource, FALSE) == FALSE) {
PktRelease();
DfsTimerContext->TickCount = 0;
DfsTimerContext->InUse = FALSE;
DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit (no scan 2)\n", 0);
return;
}
//
// Age all the Pkt entries
//
entry = PktFirstEntry(pkt);
while (entry != NULL) {
DfsDbgTrace(0, Dbg, "DfsAgePktEntries: Scanning %wZ\n", &entry->Id.Prefix);
nextEntry = PktNextEntry(pkt, entry);
if (entry->ExpireTime < DfsTimerContext->TickCount) { #if DBG
if (MupVerbose) DbgPrint("DfsAgePktEntries:Setting expiretime on %wZ to 0\n", &entry->Id.Prefix); #endif
entry->ExpireTime = 0; } else { entry->ExpireTime -= DfsTimerContext->TickCount; }
entry = nextEntry;
}
//
// Age the special table
//
if (pkt->SpecialTable.SpecialEntryCount > 0) {
if (pkt->SpecialTable.TimeToLive >= DfsTimerContext->TickCount) {
pkt->SpecialTable.TimeToLive -= DfsTimerContext->TickCount;
} else { // make it zero
pkt->SpecialTable.TimeToLive = 0;
}
} //
// Check the deleted credentials queue...
//
for (link = DfsData.DeletedCredentials.Flink; link != &DfsData.DeletedCredentials; NOTHING) {
creds = CONTAINING_RECORD(link, DFS_CREDENTIALS, Link);
link = link->Flink;
if (creds->RefCount == 0) {
RemoveEntryList( &creds->Link );
ExFreePool( creds );
}
}
ExReleaseResourceLite( &DfsData.Resource );
PktRelease();
//
// Finally we need to reset the count so that the Timer Routine can
// work fine. We also release the context block by resetting the InUse
// boolean. This will make sure that the next count towards the PKT
// aging will start again.
//
DfsTimerContext->TickCount = 0;
DfsTimerContext->InUse = FALSE;
DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit\n", 0); }
//+----------------------------------------------------------------------------
//
// Function: DfspProtocolToService
//
// Synopsis: Given a NetBIOS protocol definition in a DS_PROTOCOL structure
// this function creates a corresponding DFS_SERVICE structure.
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS DfspProtocolToService( IN PDS_TRANSPORT pdsTransport, IN PWSTR pwszPrincipalName, IN PWSTR pwszShareName, IN BOOLEAN fIsDfs, IN OUT PDFS_SERVICE pService) { NTSTATUS status = STATUS_SUCCESS; PTA_ADDRESS pTaddr = &pdsTransport->taddr; PTDI_ADDRESS_NETBIOS pNBAddress; USHORT i; WCHAR NetBiosAddress[ TDI_ADDRESS_LENGTH_NETBIOS + 1]; ULONG cbUnused; PUNICODE_STRING pServiceAddr; ULONG AllocLen;
DfsDbgTrace(+1, Dbg, "DfspProtocolToService - entered\n", 0);
//
// Initialize the service to nulls
//
RtlZeroMemory(pService, sizeof(DFS_SERVICE));
ASSERT(pTaddr->AddressType == TDI_ADDRESS_TYPE_NETBIOS);
pNBAddress = (PTDI_ADDRESS_NETBIOS) pTaddr->Address; ASSERT(pTaddr->AddressLength == sizeof(TDI_ADDRESS_NETBIOS));
RtlMultiByteToUnicodeN( NetBiosAddress, sizeof(NetBiosAddress), &cbUnused, pNBAddress->NetbiosName, 16);
//
// Process a NetBIOS name. Throw away char 16, then ignore the trailing
// spaces
//
for (i = 14; i >= 0 && NetBiosAddress[i] == L' '; i--) { NOTHING; } NetBiosAddress[i+1] = UNICODE_NULL;
DfsDbgTrace(0, Dbg, "NetBIOS address is %ws\n", NetBiosAddress);
pService->Name.Length = wcslen(pwszPrincipalName) * sizeof(WCHAR); pService->Name.MaximumLength = pService->Name.Length + sizeof(UNICODE_NULL); pService->Name.Buffer = ExAllocatePoolWithTag( PagedPool, pService->Name.MaximumLength, ' puM');
if (!pService->Name.Buffer) { DfsDbgTrace(0, Dbg, "Unable to create principal name!\n", 0); status = STATUS_INSUFFICIENT_RESOURCES; DfsDbgTrace(-1, Dbg, "DfsProtocolToService returning %08lx\n", ULongToPtr(status) ); return(status); }
RtlCopyMemory(pService->Name.Buffer, pwszPrincipalName, pService->Name.Length);
AllocLen = sizeof(UNICODE_PATH_SEP) + pService->Name.Length + sizeof(UNICODE_PATH_SEP) + wcslen(pwszShareName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
if (AllocLen <= MAXUSHORT) { pService->Address.MaximumLength = (USHORT) AllocLen; } else { DfsDbgTrace(0, Dbg, "Address too long!\n", 0); ExFreePool(pService->Name.Buffer); status = STATUS_NAME_TOO_LONG; DfsDbgTrace(-1, Dbg, "DfsProtocolToService returning %08lx\n", ULongToPtr(status) ); return(status); }
pService->Address.Buffer = ExAllocatePoolWithTag( PagedPool, pService->Address.MaximumLength, ' puM');
if (!pService->Address.Buffer) { DfsDbgTrace(0, Dbg, "Unable to create address!\n", 0); ExFreePool(pService->Name.Buffer); pService->Name.Buffer = NULL; status = STATUS_INSUFFICIENT_RESOURCES; DfsDbgTrace(-1, Dbg, "DfsProtocolToService returning %08lx\n", ULongToPtr(status) ); return(status); }
pService->Address.Length = sizeof(UNICODE_PATH_SEP);
pService->Address.Buffer[0] = UNICODE_PATH_SEP;
DnrConcatenateFilePath( &pService->Address, pService->Name.Buffer, pService->Name.Length);
DnrConcatenateFilePath( &pService->Address, pwszShareName, (USHORT) (wcslen(pwszShareName) * sizeof(WCHAR)));
DfsDbgTrace(0, Dbg, "Server Name is %wZ\n", &pService->Name);
DfsDbgTrace(0, Dbg, "Address is %wZ\n", &pService->Address);
pService->Type = DFS_SERVICE_TYPE_MASTER;
if (fIsDfs) { pService->Capability = PROV_DFS_RDR; pService->ProviderId = PROV_ID_DFS_RDR; } else { pService->Capability = PROV_STRIP_PREFIX; pService->ProviderId = PROV_ID_MUP_RDR; } pService->pProvider = NULL;
DfsDbgTrace(-1, Dbg, "DfsProtocolToService returning %08lx\n", ULongToPtr(status) ); return(status); }
//+----------------------------------------------------------------------------
//
// Function: DfsFsctrlSetDCName
//
// Synopsis: Sets the DC to use for special referrals,
// also tries for more referrals if the table is emty or old,
// and also sets the preferred DC if a new DC is passed in.
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS DfsFsctrlSetDCName( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PVOID InputBuffer, IN ULONG InputBufferLength ) { NTSTATUS Status = STATUS_SUCCESS; PDFS_PKT Pkt = _GetPkt(); BOOLEAN GotPkt = FALSE; BOOLEAN GotNewDc = FALSE; ULONG i; WCHAR *DCNameArg; UNICODE_STRING DomainNameDns; UNICODE_STRING DomainNameFlat; UNICODE_STRING DCNameFlat; UNICODE_STRING DCName;
STD_FSCTRL_PROLOGUE(DfsFsctrlSetDCName, TRUE, FALSE, FALSE);
DfsDbgTrace(+1, Dbg, "DfsFsctrlSetDCName()\n", 0);
RtlZeroMemory(&DomainNameDns, sizeof(UNICODE_STRING)); RtlZeroMemory(&DomainNameFlat, sizeof(UNICODE_STRING)); RtlZeroMemory(&DCName, sizeof(UNICODE_STRING)); RtlZeroMemory(&DCNameFlat, sizeof(UNICODE_STRING));
DCNameArg = (WCHAR *)InputBuffer;
//
// We expect a the buffer to be unicode, so it had better be
// of even length
//
if ((InputBufferLength & 0x1) != 0) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; }
//
// Verify there's a null someplace in the buffer
//
for (i = 0; i < InputBufferLength/sizeof(WCHAR) && DCNameArg[i]; i++) NOTHING;
if (i >= InputBufferLength/sizeof(WCHAR)) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; }
//
// Verify that the name given (with an added NULL) will fit
// into a USHORT
//
if ((wcslen(DCNameArg) * sizeof(WCHAR)) > MAXUSHORT - sizeof(WCHAR)) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; }
GotNewDc = (i > 0) ? TRUE : FALSE;
//
// If we have a new DC name, switch to it
//
if (GotNewDc == TRUE) {
UNICODE_STRING NewDCName;
DfsDbgTrace(0, Dbg, "DCNameArg=%ws\n", DCNameArg);
NewDCName.Length = wcslen(DCNameArg) * sizeof(WCHAR); NewDCName.MaximumLength = NewDCName.Length + sizeof(UNICODE_NULL);
NewDCName.Buffer = ExAllocatePoolWithTag(PagedPool, NewDCName.MaximumLength, ' puM');
if (NewDCName.Buffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; }
PktAcquireExclusive(TRUE, &GotPkt);
RtlCopyMemory(NewDCName.Buffer, DCNameArg, NewDCName.MaximumLength);
if (Pkt->DCName.Buffer != NULL) { ExFreePool(Pkt->DCName.Buffer); } Pkt->DCName = NewDCName;
}
//
// We need to reference the DCName in the Pkt even without the Pkt locked,
// so we make a copy.
//
if (GotPkt == FALSE) {
PktAcquireExclusive(TRUE, &GotPkt);
}
if (Pkt->DCName.Length > 0) {
DFS_DUPLICATE_STRING(DCName,Pkt->DCName.Buffer, Status);
if (!NT_SUCCESS(Status)) { goto Cleanup; }
}
if (GotNewDc == TRUE) {
if (Pkt->DomainNameDns.Length > 0) {
DFS_DUPLICATE_STRING(DomainNameDns,Pkt->DomainNameDns.Buffer, Status);
if (!NT_SUCCESS(Status)) { goto CheckSpcTable; }
}
if (Pkt->DomainNameFlat.Length > 0) {
DFS_DUPLICATE_STRING(DomainNameFlat,Pkt->DomainNameFlat.Buffer, Status);
if (!NT_SUCCESS(Status)) { goto CheckSpcTable; }
}
PktRelease(); GotPkt = FALSE; if (DCName.Length > 0 && DomainNameDns.Length > 0) {
PktpSetActiveSpcService( &DomainNameDns, &DCName, FALSE);
DCNameFlat = DCName;
for (i = 0; i < DCNameFlat.Length / sizeof(WCHAR) && DCNameFlat.Buffer[i] != L'.'; i++ ) { NOTHING; }
DCNameFlat.Length = (USHORT) (i * sizeof(WCHAR));
if (DCNameFlat.Length > Pkt->DCName.Length) DCNameFlat.Length = Pkt->DCName.Length;
}
if (DCNameFlat.Length > 0 && DomainNameFlat.Length > 0) {
PktpSetActiveSpcService( &DomainNameFlat, &DCNameFlat, FALSE);
}
}
if (GotPkt == TRUE) {
PktRelease(); GotPkt = FALSE;
}
CheckSpcTable:
if (NT_SUCCESS(Status) && (Pkt->SpecialTable.SpecialEntryCount == 0 || Pkt->SpecialTable.TimeToLive == 0)) {
if (DCName.Length > 0) {
Status = PktGetSpecialReferralTable(&DCName, TRUE);
} else {
Status = STATUS_BAD_NETWORK_PATH;
}
}
Cleanup:
//
// Free the local copies
//
if (DomainNameDns.Buffer != NULL) ExFreePool(DomainNameDns.Buffer);
if (DomainNameFlat.Buffer != NULL) ExFreePool(DomainNameFlat.Buffer);
if (DCName.Buffer != NULL) ExFreePool(DCName.Buffer);
if (GotPkt == TRUE) {
PktRelease(); GotPkt = FALSE;
}
DfsCompleteRequest(IrpContext, Irp, Status); DfsDbgTrace(+1, Dbg, "DfsFsctrlSetDCName exit 0x%x\n", ULongToPtr(Status) );
return (Status); }
//+----------------------------------------------------------------------------
//
// Function: DfsFsctrlSetDomainNameFlat
//
// Synopsis: Sets the DomainName (flat)
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS DfsFsctrlSetDomainNameFlat( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PVOID InputBuffer, IN ULONG InputBufferLength ) { NTSTATUS Status = STATUS_SUCCESS; PDFS_PKT Pkt = _GetPkt(); BOOLEAN GotPkt; ULONG i; WCHAR *DomainNameFlat;
STD_FSCTRL_PROLOGUE(DfsFsctrlSetDomainNameFlat, TRUE, FALSE, FALSE);
DfsDbgTrace(+1, Dbg, "DfsFsctrlSetDomainNameFlat()\n", 0);
DomainNameFlat = (WCHAR *)InputBuffer;
//
// Verify there's a null someplace in the buffer
//
for (i = 0; i < InputBufferLength/sizeof(WCHAR) && DomainNameFlat[i]; i++) NOTHING;
//
// Zero-len is as bad as no terminating NULL
//
if (i == 0 || i >= InputBufferLength/sizeof(WCHAR)) { DfsCompleteRequest(IrpContext, Irp, Status); return STATUS_INVALID_PARAMETER; }
//
// Verify that the name given (with an added NULL) will fit
// into a USHORT
//
if ((wcslen(DomainNameFlat) * sizeof(WCHAR)) > MAXUSHORT - sizeof(WCHAR)) { Status = STATUS_INVALID_PARAMETER; DfsCompleteRequest(IrpContext, Irp, Status); return STATUS_INVALID_PARAMETER; }
PktAcquireExclusive(TRUE, &GotPkt);
DfsDbgTrace(0, Dbg, "DomainNameFlat=%ws\n", DomainNameFlat);
//
// Replace old
//
if (Pkt->DomainNameFlat.Buffer) { ExFreePool(Pkt->DomainNameFlat.Buffer); } Pkt->DomainNameFlat.Length = wcslen(DomainNameFlat) * sizeof(WCHAR); Pkt->DomainNameFlat.MaximumLength = Pkt->DomainNameFlat.Length + sizeof(UNICODE_NULL);
Pkt->DomainNameFlat.Buffer = ExAllocatePoolWithTag( PagedPool, Pkt->DomainNameFlat.MaximumLength, ' puM');
if (Pkt->DomainNameFlat.Buffer != NULL) { RtlCopyMemory( Pkt->DomainNameFlat.Buffer, DomainNameFlat, Pkt->DomainNameFlat.MaximumLength); } else { Pkt->DomainNameFlat.Length = Pkt->DomainNameFlat.MaximumLength = 0; Status = STATUS_INSUFFICIENT_RESOURCES; }
PktRelease();
DfsCompleteRequest(IrpContext, Irp, Status); DfsDbgTrace(+1, Dbg, "DfsFsctrlSetDomainNameFlat exit 0x%x\n", ULongToPtr(Status) );
return (Status); }
//+----------------------------------------------------------------------------
//
// Function: DfsFsctrlSetDomainNameDns
//
// Synopsis: Sets the DomainName (flat)
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS DfsFsctrlSetDomainNameDns( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PVOID InputBuffer, IN ULONG InputBufferLength ) { NTSTATUS Status = STATUS_SUCCESS; PDFS_PKT Pkt = _GetPkt(); BOOLEAN GotPkt; ULONG i; WCHAR *DomainNameDns;
STD_FSCTRL_PROLOGUE(DfsFsctrlSetDomainNameDns, TRUE, FALSE, FALSE);
DfsDbgTrace(+1, Dbg, "DfsFsctrlSetDomainNameDns()\n", 0);
DomainNameDns = (WCHAR *)InputBuffer;
//
// Verify there's a null someplace in the buffer
//
for (i = 0; i < InputBufferLength/sizeof(WCHAR) && DomainNameDns[i]; i++) NOTHING;
//
// Zero-len is as bad as no terminating NULL
//
if (i == 0 || i >= InputBufferLength/sizeof(WCHAR)) { DfsCompleteRequest(IrpContext, Irp, Status); return STATUS_INVALID_PARAMETER; }
//
// Verify that the name given (with an added NULL) will fit
// into a USHORT
//
if ((wcslen(DomainNameDns) * sizeof(WCHAR)) > MAXUSHORT - sizeof(WCHAR)) { Status = STATUS_INVALID_PARAMETER; DfsCompleteRequest(IrpContext, Irp, Status); return STATUS_INVALID_PARAMETER; }
PktAcquireExclusive(TRUE, &GotPkt);
DfsDbgTrace(0, Dbg, "DomainNameDns=%ws\n", DomainNameDns);
//
// Replace old
//
if (Pkt->DomainNameDns.Buffer) { ExFreePool(Pkt->DomainNameDns.Buffer); } Pkt->DomainNameDns.Length = wcslen(DomainNameDns) * sizeof(WCHAR); Pkt->DomainNameDns.MaximumLength = Pkt->DomainNameDns.Length + sizeof(UNICODE_NULL);
Pkt->DomainNameDns.Buffer = ExAllocatePoolWithTag( PagedPool, Pkt->DomainNameDns.MaximumLength, ' puM');
if (Pkt->DomainNameDns.Buffer != NULL) { RtlCopyMemory( Pkt->DomainNameDns.Buffer, DomainNameDns, Pkt->DomainNameDns.MaximumLength); } else { Pkt->DomainNameDns.Length = Pkt->DomainNameDns.MaximumLength = 0; Status = STATUS_INSUFFICIENT_RESOURCES; }
PktRelease();
DfsCompleteRequest(IrpContext, Irp, Status); DfsDbgTrace(+1, Dbg, "DfsFsctrlSetDomainNameDns exit 0x%x\n", ULongToPtr(Status) );
return (Status); }
//+-------------------------------------------------------------------------
//
// Function: PktFsctrlFlushCache, public
//
// Synopsis: This function will flush all entries which match the specified
// input path.
// However, this function will refuse to delete any Permanent
// entries of the PKT.
//
// Arguments:
//
// Returns:
//
//--------------------------------------------------------------------------
NTSTATUS PktFsctrlFlushCache( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PVOID InputBuffer, IN ULONG InputBufferLength ) { NTSTATUS status = STATUS_SUCCESS; PDFS_PKT Pkt; PDFS_PKT_ENTRY curEntry; PDFS_PKT_ENTRY nextEntry; PDFS_PKT_ENTRY pEntry; BOOLEAN pktLocked; UNICODE_STRING ustrPrefix, RemainingPath; PWCHAR wCp = (PWCHAR) InputBuffer;
STD_FSCTRL_PROLOGUE(PktFsctrlFlushCache, TRUE, FALSE, FALSE);
DfsDbgTrace(+1,Dbg, "PktFsctrlFlushCache()\n", 0);
//
// If InputBufferLength == 2 and InputBuffer == '*', flush all entries
//
if (InputBufferLength == sizeof(WCHAR) && wCp[0] == L'*') {
Pkt = _GetPkt(); PktAcquireExclusive(TRUE, &pktLocked); ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE); curEntry = PktFirstEntry(Pkt);
while (curEntry!=NULL) {
nextEntry = PktNextEntry(Pkt, curEntry);
if ( !(curEntry->Type & PKT_ENTRY_TYPE_PERMANENT) ) {
if (curEntry->UseCount == 0) {
PktEntryDestroy(curEntry, Pkt, (BOOLEAN) TRUE);
} else if ( !(curEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC) ) {
//
// We can't delete this entry because it is in use, so
// mark it DELETE_PENDING, set its timeout to zero
// and remove from the prefix tables
//
curEntry->Type |= PKT_ENTRY_TYPE_DELETE_PENDING; curEntry->ExpireTime = 0; curEntry->USN++; DfsRemoveUnicodePrefix(&Pkt->PrefixTable, &(curEntry->Id.Prefix)); DfsRemoveUnicodePrefix(&Pkt->ShortPrefixTable, &(curEntry->Id.ShortPrefix));
}
}
curEntry = nextEntry; }
PktRelease(); ExReleaseResourceLite( &DfsData.Resource );
DfsCompleteRequest( IrpContext, Irp, status ); DfsDbgTrace(-1,Dbg, "PktFsctrlFlushCache: Exit -> %08lx\n", ULongToPtr(status) ); return(status);
}
//
// Verify the buffer contains at least a '\' and is of even length
//
if (InputBufferLength < sizeof(WCHAR) || (InputBufferLength & 0x1) != 0 || wCp[0] != UNICODE_PATH_SEP) {
status = STATUS_INVALID_PARAMETER; DfsCompleteRequest( IrpContext, Irp, status ); return status;
}
//
// Flush one entry
//
ustrPrefix.Length = (USHORT) InputBufferLength; ustrPrefix.MaximumLength = (USHORT) InputBufferLength; ustrPrefix.Buffer = (PWCHAR) InputBuffer;
if (ustrPrefix.Length >= sizeof(WCHAR) * 2 && ustrPrefix.Buffer[0] == UNICODE_PATH_SEP && ustrPrefix.Buffer[1] == UNICODE_PATH_SEP ) { ustrPrefix.Buffer++; ustrPrefix.Length -= sizeof(WCHAR); }
if (ustrPrefix.Buffer[ustrPrefix.Length/sizeof(WCHAR)-1] == UNICODE_NULL) { ustrPrefix.Length -= sizeof(WCHAR); }
Pkt = _GetPkt();
PktAcquireExclusive(TRUE, &pktLocked); ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
pEntry = PktLookupEntryByPrefix(Pkt, &ustrPrefix, &RemainingPath);
if (pEntry == NULL || RemainingPath.Length != 0) {
status = STATUS_OBJECT_NAME_NOT_FOUND;
} else {
if ( !(pEntry->Type & PKT_ENTRY_TYPE_PERMANENT) ) { if (pEntry->UseCount == 0) {
PktEntryDestroy(pEntry, Pkt, (BOOLEAN) TRUE);
} else if ( !(pEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC) ) {
//
// We can't delete this entry because it is in use, so
// mark it DELETE_PENDING, set its timeout to zero
// and remove from the prefix tables
//
pEntry->Type |= PKT_ENTRY_TYPE_DELETE_PENDING; pEntry->ExpireTime = 0; DfsRemoveUnicodePrefix(&Pkt->PrefixTable, &(pEntry->Id.Prefix)); DfsRemoveUnicodePrefix(&Pkt->ShortPrefixTable, &(pEntry->Id.ShortPrefix));
}
} else {
status = STATUS_INVALID_PARAMETER;
}
}
PktRelease(); ExReleaseResourceLite( &DfsData.Resource );
DfsCompleteRequest( IrpContext, Irp, status ); DfsDbgTrace(-1,Dbg, "PktFsctrlFlushCache: Exit -> %08lx\n", ULongToPtr(status) ); return status;
}
//+-------------------------------------------------------------------------
//
// Function: PktFsctrlFlushSpcCache, public
//
// Synopsis: This function will flush all entries which match the specified
// input path.
// However, this function will refuse to delete any Permanent
// entries of the PKT.
//
// Arguments:
//
// Returns:
//
//--------------------------------------------------------------------------
NTSTATUS PktFsctrlFlushSpcCache( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PVOID InputBuffer, IN ULONG InputBufferLength ) { NTSTATUS status = STATUS_INVALID_PARAMETER; PDFS_PKT Pkt; BOOLEAN pktLocked; PDFS_SPECIAL_ENTRY pSpecialEntry; PDFS_SPECIAL_TABLE pSpecialTable; PWCHAR wCp = (PWCHAR) InputBuffer; ULONG i;
STD_FSCTRL_PROLOGUE(PktFsctrlFlushSpcCache, TRUE, FALSE, FALSE);
DfsDbgTrace(+1,Dbg, "PktFsctrlFlushSpcCache()\n", 0);
//
// InputBufferLength == 2 and InputBuffer == '*'
//
if (InputBufferLength == sizeof(WCHAR) && wCp[0] == L'*') {
Pkt = _GetPkt(); PktAcquireExclusive(TRUE, &pktLocked); pSpecialTable = &Pkt->SpecialTable;
pSpecialTable->TimeToLive = 0;
pSpecialEntry = CONTAINING_RECORD( pSpecialTable->SpecialEntryList.Flink, DFS_SPECIAL_ENTRY, Link);
for (i = 0; i < pSpecialTable->SpecialEntryCount; i++) {
pSpecialEntry->Stale = TRUE;
pSpecialEntry = CONTAINING_RECORD( pSpecialEntry->Link.Flink, DFS_SPECIAL_ENTRY, Link); }
PktRelease();
status = STATUS_SUCCESS;
} else {
status = STATUS_INVALID_PARAMETER;
}
DfsCompleteRequest( IrpContext, Irp, status ); DfsDbgTrace(-1,Dbg, "PktFsctrlFlushSpcCache: Exit -> %08lx\n", ULongToPtr(status) ); return status;
}
//+-------------------------------------------------------------------------
//
// Function: PktFlushChildren
//
// Synopsis: This function will flush all entries which are children
// of the entry passed in.
// However, this function will refuse to delete any Permanent
// entries of the PKT.
//
// Arguments:
//
// Returns:
//
//--------------------------------------------------------------------------
VOID PktFlushChildren( PDFS_PKT_ENTRY pEntry ) { NTSTATUS status = STATUS_SUCCESS; PDFS_PKT Pkt; PDFS_PKT_ENTRY curEntry; PDFS_PKT_ENTRY nextEntry; BOOLEAN pktLocked;
DfsDbgTrace(+1,Dbg, "PktFlushChildren(%wZ)\n", &pEntry->Id.Prefix);
#if DBG
if (MupVerbose) DbgPrint("PktFlushChildren(%wZ)\n", &pEntry->Id.Prefix); #endif
PktAcquireExclusive(TRUE, &pktLocked); ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
Pkt = _GetPkt();
curEntry = PktEntryFirstChild(pEntry);
while (curEntry != NULL) {
DfsDbgTrace(0, Dbg, "PktFlushChildren: examining %wZ\n", &curEntry->Id.Prefix); //
// We may lose this entry due to deletion. Let us get the Next
// entry before we go into the next stage.
//
nextEntry = PktEntryNextChild(pEntry,curEntry);
//
// Try to delete the entry.
//
if ( !(curEntry->Type & PKT_ENTRY_TYPE_PERMANENT) ) { if (curEntry->UseCount == 0) {
PktEntryDestroy(curEntry, Pkt, (BOOLEAN) TRUE);
} else if ( !(curEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC) ) {
//
// We can't delete this entry because it is in use, so
// mark it DELETE_PENDING, set its timeout to zero
// and remove from the prefix tables
//
curEntry->Type |= PKT_ENTRY_TYPE_DELETE_PENDING; curEntry->ExpireTime = 0; DfsRemoveUnicodePrefix(&Pkt->PrefixTable, &(curEntry->Id.Prefix)); DfsRemoveUnicodePrefix(&Pkt->ShortPrefixTable, &(curEntry->Id.ShortPrefix));
}
}
curEntry = nextEntry;
}
PktRelease(); ExReleaseResourceLite( &DfsData.Resource );
#if DBG
if (MupVerbose) DbgPrint("PktFlushChildren returning VOID\n"); #endif
DfsDbgTrace(-1,Dbg, "PktFlushChildren returning VOID\n", 0);
}
//+-------------------------------------------------------------------------
//
// Function: PktpSetActiveSpcService
//
// Synopsis: This function will attempt to set the 'active' DC in the specified
// domain
//
// Arguments:
//
// Returns: STATUS_SUCCESS or STATUS_NOT_FOUND
//
//--------------------------------------------------------------------------
NTSTATUS PktpSetActiveSpcService( PUNICODE_STRING DomainName, PUNICODE_STRING DcName, BOOLEAN ResetTimeout) { NTSTATUS status = STATUS_NOT_FOUND; ULONG EntryIdx; USHORT i; PDFS_SPECIAL_ENTRY pSpecialEntry; UNICODE_STRING DcNameFlat; BOOLEAN pktLocked;
if (DomainName != NULL && DomainName->Length > 0) {
status = PktExpandSpecialName(DomainName, &pSpecialEntry);
if (NT_SUCCESS(status)) {
for (EntryIdx = 0; EntryIdx < pSpecialEntry->ExpandedCount; EntryIdx++) {
if (RtlCompareUnicodeString( DcName, &pSpecialEntry->ExpandedNames[EntryIdx].ExpandedName, TRUE) == 0) {
pSpecialEntry->Active = EntryIdx; //
// Keep the spc table around for a while longer
//
if (ResetTimeout == TRUE) { PktAcquireExclusive(TRUE, &pktLocked); if (DfsData.Pkt.SpecialTable.TimeToLive < 60 * 15) { DfsData.Pkt.SpecialTable.TimeToLive += 60 * 15; // 15 min
} PktRelease(); } status = STATUS_SUCCESS; break;
}
status = STATUS_NOT_FOUND;
}
InterlockedDecrement(&pSpecialEntry->UseCount);
} else {
status = STATUS_NOT_FOUND;
}
}
return status;
}
|