Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1249 lines
32 KiB

//+----------------------------------------------------------------------------
//
// 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;
}