Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

781 lines
22 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 -
// DfsAgePktEntries - Flush PKT entries periodically
//
// Private Functions
//
// DfsCreateExitPathOnRoot
// PktpHashSiteCostList
// PktpLookupSiteCost
// PktpUpdateSiteCosts
//
// Debug Only Functions
//
// PktFsctrlFlushCache - Flush PKT 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 OUT PDFS_SERVICE pService);
VOID
DfspFreeGluon(
IN PDS_GLUON pGluon);
VOID
DfspSvcListFromGluon(
PDFS_PKT_ENTRY_INFO pServiceInfo,
PDFS_SERVICE *ppActiveService,
PDS_GLUON pGluon);
#if DBG
NTSTATUS
PktFsctrlFlushCache(
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength
);
#endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, DfsAgePktEntries )
#pragma alloc_text( PAGE, DfspProtocolToService )
#pragma alloc_text( PAGE, DfspFreeGluon )
#pragma alloc_text( PAGE, DfspSvcListFromGluon )
#pragma alloc_text( PAGE, DfsFsctrlSetDomainGluon )
#if DBG
#pragma alloc_text( PAGE, PktFsctrlFlushCache )
#endif // DBG
#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;
PLIST_ENTRY link;
PDFS_CREDENTIALS creds;
BOOLEAN pktLocked = FALSE;
DfsDbgTrace(+1, Dbg, "DfsAgePktEntries called\n", 0);
//
// 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 (ExAcquireResourceExclusive(&DfsData.Resource, FALSE) == FALSE) {
PktRelease();
DfsTimerContext->TickCount = 0;
DfsTimerContext->InUse = FALSE;
DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit (no scan 2)\n", 0);
return;
}
entry = PktFirstEntry(pkt);
while (entry != NULL) {
DfsDbgTrace(0, Dbg, "DfsAgePktEntries: Scanning %wZ\n",
&entry->Id.Prefix);
//
// We may lose this entry due to deletion. Let us get the Next
// entry before we go into the next stage.
//
nextEntry = PktNextEntry(pkt, entry);
//
// For each entry if it is not permanent and its expire time is
// less than DFS_MAX_TICKS then we can delete it else we just
// update its expire time and go on to the next entry.
//
if ( !(entry->Type & PKT_ENTRY_TYPE_PERMANENT)
&&
(entry->UseCount == 0)
&&
IsListEmpty(&entry->ChildList)) {
if (entry->ExpireTime < DfsTimerContext->TickCount) {
DfsDbgTrace(0, Dbg, "DfsAgePktEntries: Deleted: %wZ\n",
&entry->Id.Prefix);
PktEntryDestroy(entry, pkt, (BOOLEAN) TRUE);
} else {
entry->ExpireTime -= DfsTimerContext->TickCount;
}
}
entry = nextEntry;
}
//
// 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 );
}
}
ExReleaseResource( &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 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;
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; 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 = ExAllocatePool(
PagedPool,
pService->Name.MaximumLength);
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", status);
return(status);
}
RtlCopyMemory(pService->Name.Buffer, pwszPrincipalName, pService->Name.Length);
pService->Address.MaximumLength =
sizeof(UNICODE_PATH_SEP) +
pService->Name.Length +
sizeof(UNICODE_PATH_SEP) +
wcslen(pwszShareName) * sizeof(WCHAR) +
sizeof(UNICODE_NULL);
pService->Address.Buffer = ExAllocatePool(
PagedPool,
pService->Address.MaximumLength);
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", 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 | DFS_SERVICE_TYPE_REFERRAL;
pService->Capability = PROV_DFS_RDR;
pService->ProviderId = PROV_ID_DFS_RDR;
pService->pProvider = NULL;
DfsDbgTrace(-1, Dbg, "DfsProtocolToService returning %08lx\n", status);
return(status);
}
//+----------------------------------------------------------------------------
//
// Function: DfspFreeGluon
//
// Synopsis: Frees an unmarshalled gluon
//
// Arguments: [pGluon] -- pointer to gluon data structure
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
VOID
DfspFreeGluon(
IN PDS_GLUON pGluon)
{
ULONG i, j, k;
if (pGluon->cMachines) {
for (i = pGluon->cMachines; i > 0; i--) {
PDS_MACHINE pMachine = pGluon->rpMachines[i-1];
if (pMachine) {
MarshalBufferFree(pMachine->pwszShareName);
if (pMachine->cPrincipals) {
for (j = pMachine->cPrincipals; j > 0; j--) {
MarshalBufferFree(pMachine->prgpwszPrincipals[j-1]);
}
}
MarshalBufferFree(pMachine->prgpwszPrincipals);
if (pMachine->cTransports) {
for (j = pMachine->cTransports; j > 0; j--) {
MarshalBufferFree(pMachine->rpTrans[j-1]);
}
}
MarshalBufferFree(pMachine);
}
}
}
MarshalBufferFree(pGluon);
}
//+----------------------------------------------------------------------------
//
// Function: DfspSvcListFromGluon
//
// Synopsis: Creates a service list corresponding to the list of DS_MACHINEs
// in a gluon. For each Service that this function creates it will
// strip the relevant DS_MACHINE structure from the gluon.
//
// Arguments:
//
// Returns: No error code. But if for some reason one of the services is
// not created then there can be less SERVICES than the DS_MACHINEs
// passed in.
//
//-----------------------------------------------------------------------------
VOID
DfspSvcListFromGluon(
PDFS_PKT_ENTRY_INFO pServiceInfo,
PDFS_SERVICE *ppActiveService,
PDS_GLUON pGluon
)
{
ULONG i, j, k;
NTSTATUS status;
*ppActiveService = NULL;
//
// We'll traverse through each machine and each transport, and wean
// out the netbios names to create DFS_SERVICE structures.
//
for (i=0, j=0; i < pGluon->cMachines; i++) {
PDS_MACHINE pdsMachine;
pdsMachine = pGluon->rpMachines[i];
for (k=0; k < pdsMachine->cTransports; k++) {
PDS_TRANSPORT pdsTransport;
pdsTransport = pdsMachine->rpTrans[k];
//
// Support only SMB redir with NetBIOS addresses for now.
//
if ( pdsTransport->usFileProtocol == FSP_SMB
&&
pdsTransport->taddr.AddressType == TDI_ADDRESS_TYPE_NETBIOS) {
ASSERT(j <= pGluon->cMachines);
status = DfspProtocolToService(
pdsTransport,
pdsMachine->prgpwszPrincipals[pdsTransport->iPrincipal],
pdsMachine->pwszShareName,
&pServiceInfo->ServiceList[j]);
if (NT_SUCCESS(status)) {
pServiceInfo->ServiceList[j].pMachEntry =
ExAllocatePool( PagedPool, sizeof(DFS_MACHINE_ENTRY) );
if (pServiceInfo->ServiceList[j].pMachEntry == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
} else {
RtlZeroMemory(
(PVOID) pServiceInfo->ServiceList[j].pMachEntry,
sizeof(DFS_MACHINE_ENTRY));
}
}
if (NT_SUCCESS(status)) {
DfsDbgTrace(0, Dbg, "Added service # %d\n", j);
DfsDbgTrace(0, Dbg, "Name = %wZ\n",
&pServiceInfo->ServiceList[j].Name);
DfsDbgTrace(0, Dbg, "Address = %wZ\n",
&pServiceInfo->ServiceList[j].Address);
pServiceInfo->ServiceList[j].pMachEntry->pMachine = pdsMachine;
pServiceInfo->ServiceList[j].pMachEntry->UseCount = 1;
//
// Now strip the pdsMachine Structure from Gluon.
//
pGluon->rpMachines[i] = NULL;
//
// DfsSetDomainInfo in api\gluonapi.c sets the grfFlags
// field of the gluon to the index of the active service.
//
if (pGluon->grfFlags == i) {
*ppActiveService = &pServiceInfo->ServiceList[j];
}
j++;
} else {
DfsDbgTrace(0, 1, "Error %08lx creating service\n",
status);
}
break; // Get out of the loop for transports.
} // end if transport is SMB/NetBIOS
} // end for each transport
} // end for each machine
DfsDbgTrace(0, Dbg, "%d services found\n", j);
pServiceInfo->ServiceCount = j;
}
//+----------------------------------------------------------------------------
//
// Function: DfsFsctrlSetDomainGluon
//
// Synopsis: Inserts a pkt entry corresponding to the domain gluon.
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS
DfsFsctrlSetDomainGluon(
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength
)
{
NTSTATUS status = STATUS_SUCCESS;
MARSHAL_BUFFER marshalBuffer;
DS_GLUON_P domainGluonP;
PDS_GLUON pDomainGluon;
DFS_PKT_ENTRY_ID domainId;
DFS_PKT_ENTRY_INFO domainInfo;
PDFS_SERVICE pActiveService;
PDFS_PKT_ENTRY pDCEntry;
PDFS_PKT pkt;
ULONG j;
BOOLEAN pktLocked;
STD_FSCTRL_PROLOGUE(DfsFsctrlSetDomainGluon, TRUE, FALSE, FALSE);
//
// Unmarshal the gluon.
//
MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
status = DfsRtlGet(&marshalBuffer, &MiDSGluonP, &domainGluonP);
if (!NT_SUCCESS(status)) {
DfsDbgTrace(0, Dbg, "Unmarshalling of gluon failed %08lx\n", status);
DfsCompleteRequest( IrpContext, Irp, status );
DfsDbgTrace(-1, Dbg, "DfsFsctrlSetDomainGluon: Exited %08lx\n", status);
return(status);
}
pDomainGluon = domainGluonP.pDSGluon;
DfsDbgTrace(0, Dbg, "Unmarshalled gluon @ %08lx\n", pDomainGluon);
DfsDbgTrace(0, Dbg, "Name is %ws\n", pDomainGluon->pwszName);
DfsDbgTrace(0, Dbg, "# of services is %d\n", pDomainGluon->cMachines);
DfsDbgTrace(0, Dbg, "Unpacking gluon...\n", 0);
//
// Initialize the entry id for the domain service.
//
domainId.Prefix.Length = wcslen(pDomainGluon->pwszName)*sizeof(WCHAR);
domainId.Prefix.MaximumLength = domainId.Prefix.Length + sizeof(WCHAR);
domainId.Prefix.Buffer = ExAllocatePool(PagedPool, domainId.Prefix.MaximumLength);
if (domainId.Prefix.Buffer == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
DfsDbgTrace(0, Dbg, "Unable to convert name to prefix %08lx\n", status);
DfspFreeGluon(pDomainGluon);
DfsCompleteRequest( IrpContext, Irp, status );
DfsDbgTrace(-1, Dbg, "DfsFsctrlSetDomainGluon: Exit -> %08lx\n", status);
return status;
}
domainId.ShortPrefix.Length = domainId.Prefix.Length;
domainId.ShortPrefix.MaximumLength = domainId.Prefix.MaximumLength;
domainId.ShortPrefix.Buffer = ExAllocatePool(PagedPool, domainId.ShortPrefix.MaximumLength);
if (domainId.ShortPrefix.Buffer == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
DfsDbgTrace(0, Dbg, "Unable to convert name to short prefix %08lx\n", status);
ExFreePool(domainId.Prefix.Buffer);
DfspFreeGluon(pDomainGluon);
DfsCompleteRequest( IrpContext, Irp, status );
DfsDbgTrace(-1, Dbg, "DfsFsctrlSetDomainGluon: Exit -> %08lx\n", status);
return status;
}
wcscpy(domainId.Prefix.Buffer, pDomainGluon->pwszName);
wcscpy(domainId.ShortPrefix.Buffer, pDomainGluon->pwszName);
DfsDbgTrace(0, Dbg, "Prefix is %wZ\n", &domainId.Prefix);
RtlCopyMemory(&domainId.Uid, &pDomainGluon->guidThis, sizeof(GUID));
//
// Create a new info structure by disassembling the gluon
//
// BUGBUG - temporary code till we move to using DS_MACHINES entirely
//
domainInfo.ServiceList = ExAllocatePool(PagedPool,
pDomainGluon->cMachines * sizeof(DFS_SERVICE));
if (domainInfo.ServiceList == NULL) {
DfsDbgTrace(0, Dbg, "Unable to allocated %d bytes\n",
(pDomainGluon->cMachines * sizeof(DFS_SERVICE)));
DfspFreeGluon(pDomainGluon);
status = STATUS_INSUFFICIENT_RESOURCES;
DfsCompleteRequest( IrpContext, Irp, status );
DfsDbgTrace(-1, Dbg, "DfsFsctrlSetDomainGluon: Exit -> %08lx\n", status);
return status;
}
DfspSvcListFromGluon(&domainInfo, &pActiveService, pDomainGluon);
//
// Now, lets acquire the Pkt and insert the domain pkt entry. That's
// all it takes!
//
pkt = _GetPkt();
PktAcquireExclusive(TRUE, &pktLocked);
status = PktCreateEntry(
pkt,
PKT_ENTRY_TYPE_REFERRAL_SVC,
&domainId,
&domainInfo,
PKT_ENTRY_SUPERSEDE,
&pDCEntry);
if (NT_SUCCESS(status)) {
DfsDbgTrace(0, Dbg, "Created domain pkt entry @ %08lx\n", pDCEntry);
pDCEntry->ActiveService = pActiveService;
} else {
DfsDbgTrace(0, Dbg, "Error %08lx creating domain pkt entry\n", status);
status = DFS_STATUS_INCONSISTENT;
//
// Do some cleanup.
//
ExFreePool(domainId.Prefix.Buffer);
for (j = 0; j < domainInfo.ServiceCount; j++) {
PktServiceDestroy(&domainInfo.ServiceList[j], FALSE);
}
ExFreePool(domainInfo.ServiceList);
}
PktRelease();
DfspFreeGluon(pDomainGluon);
DfsDbgTrace(-1, Dbg, "DfsFsctrlSetDomainGluon: exited %08lx\n", status);
DfsCompleteRequest( IrpContext, Irp, status );
return(status);
}
#if DBG
//+-------------------------------------------------------------------------
//
// Function: PktFsctrlFlushCache, public
//
// Synopsis: This function will flush all entries which have all the
// bits specified in the TYPE vairable set in their own Type field.
// However, this function will refuse to delete and Permanent
// entries of the PKT.
//
// Arguments: Type - Specifies which entries to delete.
//
// Returns:
//
// Notes: We only process this FSCTRL from the file system process,
// never from the driver.
//
//--------------------------------------------------------------------------
NTSTATUS
PktFsctrlFlushCache(
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG Type;
PDFS_PKT Pkt;
PDFS_PKT_ENTRY curEntry, nextEntry;
BOOLEAN pktLocked;
STD_FSCTRL_PROLOGUE(PktFsctrlFlushCache, TRUE, FALSE, TRUE);
//
// Unmarshalling is very simple here. We only expect a ULONG.
//
Type = (*((ULONG *)InputBuffer));
Pkt = _GetPkt();
PktAcquireExclusive(TRUE, &pktLocked);
curEntry = PktFirstEntry(Pkt);
while (curEntry!=NULL) {
nextEntry = PktNextEntry(Pkt, curEntry);
if (((curEntry->Type & Type) == Type) &&
!(curEntry->Type & PKT_ENTRY_TYPE_LOCAL) &&
!(curEntry->Type & PKT_ENTRY_TYPE_LOCAL_XPOINT)) {
//
// Entry has all the Type bits specified in variable
// "Type" set and hence we can destroy this entry.
//
PktEntryDestroy(curEntry, Pkt, (BOOLEAN) TRUE);
}
curEntry = nextEntry;
}
PktRelease();
DfsCompleteRequest( IrpContext, Irp, status );
DfsDbgTrace(-1,Dbg, "PktFsctrlFlushCache: Exit -> %08lx\n", status);
return(status);
}
#endif // DBG