|
|
//+----------------------------------------------------------------------------
//
// Copyright (C) 1992, Microsoft Corporation.
//
// File: logroot.c
//
// Contents: This module implements the logical root handling functions.
//
// Functions: DfsInitializeLogicalRoot -
// DfsDeleteLogicalRoot -
// DfspLogRootNameToPath -
//
// History: 14-June-1994 SudK Created (Most stuff moved from Dsinit.c)
//
//-----------------------------------------------------------------------------
#include "dfsprocs.h"
#include "creds.h"
#include "dnr.h"
#include "fcbsup.h"
#include <stdio.h>
#define Dbg DEBUG_TRACE_LOGROOT
NTSTATUS DfsDefineDosDevice( IN WCHAR Device, IN PUNICODE_STRING Target);
NTSTATUS DfsUndefineDosDevice( IN WCHAR Device);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, DfsFindLogicalRoot )
#pragma alloc_text( PAGE, DfsInitializeLogicalRoot )
#pragma alloc_text( PAGE, DfsDeleteLogicalRoot )
#pragma alloc_text( PAGE, DfspLogRootNameToPath )
#pragma alloc_text( PAGE, DfsGetResourceFromVcb )
#pragma alloc_text( PAGE, DfsGetResourceFromDevlessRoot )
#pragma alloc_text( PAGE, DfsLogicalRootExists )
#endif
#ifdef TERMSRV
//
// Maximum character string length of a session Id (decimal)
//
#define SESSIONID_MAX_LEN 10
//
// Maximum characters string length of a session ID [10] (decimal) or
// logon ID [16] (hex, base 16)
//
#define ID_MAX_LEN 16
#endif // TERMSRV
//
// Global that denotes whether LUID device maps are enabled
// TRUE - LUID device maps are enabled
// FALSE - LUID device maps are not enabled
// Defined in nt\base\fs\mup\dfsinit.c
//
extern BOOL DfsLUIDDeviceMapsEnabled;
//+-------------------------------------------------------------------------
//
// Function: DfsFindLogicalRoot, local
//
// Synopsis: DfsFindLogicalRoot takes as input a DS path name in
// the standard form (root:\file\path\name), looks up
// the DFS_VCB associated with the logical root, and returns
// a string pointing to beyond the logical root part
// of the input string.
//
// Arguments: [PrefixPath] -- Input path name
// [Vcb] -- Returns DFS_VCB which corresponds to logical root
// in PrefixPath
// [RemainingPath] -- Returns with portion of PrefixPath
// after the logical root name and colon
//
// Returns: NTSTATUS:
// STATUS_SUCCESS if Vcb found
// STATUS_OBJECT_PATH_SYNTAX_BAD - no logical root name
// STATUS_NO_SUCH_DEVICE - logical root name not found
//
//--------------------------------------------------------------------------
#ifdef TERMSRV
NTSTATUS DfsFindLogicalRoot( IN PUNICODE_STRING PrefixPath, IN ULONG SessionID, IN PLUID LogonID, OUT PDFS_VCB *Vcb, OUT PUNICODE_STRING RemainingPath )
#else // TERMSRV
NTSTATUS DfsFindLogicalRoot( IN PUNICODE_STRING PrefixPath, IN PLUID LogonID, OUT PDFS_VCB *Vcb, OUT PUNICODE_STRING RemainingPath )
#endif // TERMSRV
{ PLIST_ENTRY Link; unsigned int i; NTSTATUS Status = STATUS_SUCCESS; NETRESOURCE testnt;
DfsDbgTrace(+1, Dbg, "DfsFindLogicalRoot...\n", 0);
*RemainingPath = *PrefixPath;
for (i = 0; i < RemainingPath->Length/sizeof(WCHAR); i++) { if ((RemainingPath->Buffer[i] == (WCHAR)':') || (RemainingPath->Buffer[i] == UNICODE_PATH_SEP)) break; }
if ((i*sizeof(WCHAR) >= RemainingPath->Length) || (RemainingPath->Buffer[i] == UNICODE_PATH_SEP)) { Status = STATUS_OBJECT_PATH_SYNTAX_BAD; DfsDbgTrace(-1, Dbg, "DfsFindLogicalRoot -> %08lx\n", ULongToPtr(Status) ); return(Status); }
RemainingPath->Length = (USHORT)(i * sizeof (WCHAR));
//
// Search for the logical root in all known DFS_VCBs
//
ExAcquireResourceSharedLite(&DfsData.Resource, TRUE); for ( Link = DfsData.VcbQueue.Flink; Link != &DfsData.VcbQueue; Link = Link->Flink ) {
*Vcb = CONTAINING_RECORD( Link, DFS_VCB, VcbLinks );
#ifdef TERMSRV
if ((SessionID == INVALID_SESSIONID) || (SessionID == (*Vcb)->SessionID)) { #endif
if ( RtlEqualLuid(LogonID, &(*Vcb)->LogonID) ) { if (RtlEqualString( (PSTRING)&(*Vcb)->LogicalRoot, (PSTRING)RemainingPath, (BOOLEAN)TRUE) ) { break; } } #ifdef TERMSRV
} #endif // TERMSRV
} if (Link == &DfsData.VcbQueue) { Status = STATUS_NO_SUCH_DEVICE; ExReleaseResourceLite(&DfsData.Resource); DfsDbgTrace(-1, Dbg, "DfsFindLogicalRoot -> %08lx\n", ULongToPtr(Status) ); return(Status); }
//
// Adjust remaining path to point beyond the logical root name
//
RemainingPath->Buffer = (WCHAR*)((char*) (RemainingPath->Buffer) + RemainingPath->Length + sizeof (WCHAR) ); RemainingPath->Length = PrefixPath->Length - (RemainingPath->Length + sizeof (WCHAR));
if (RemainingPath->Length <= 0 || RemainingPath->Buffer[0] != UNICODE_PATH_SEP) { Status = STATUS_OBJECT_PATH_SYNTAX_BAD; ExReleaseResourceLite(&DfsData.Resource); DfsDbgTrace(-1, Dbg, "DfsFindLogicalRoot -> %08lx\n", ULongToPtr(Status) ); return(Status); }
ExReleaseResourceLite(&DfsData.Resource); DfsDbgTrace(-1, Dbg, "DfsFindLogicalRoot -> %08lx\n", ULongToPtr(Status) ); return(Status); }
//+-------------------------------------------------------------------------
//
// Function: DfsInitializeLogicalRoot, public
//
// Synopsis: Allocate and initialize storage for a logical root.
// This includes creating a device object and DFS_VCB for it.
//
// Effects: A logical root device object is created. A corresponding
// DFS_VCB is also created and linked into the list of known
// DFS_VCBs.
//
// Arguments: [Name] -- name of logical root.
// [Prefix] -- Prefix to be prepended to file names opened
// via the logical root being created before
// they can be resolved in the DFS name space.
// [Credentials] -- The credentials to use when accessing files
// via this logical root.
// [VcbFlags] -- To be OR'd into the VcbState field of the
// DFS_VCB of the newly created logical root device.
//
// Requires: DfsData must first be set up. Also an EXCLUSIVE LOCK on
// DfsData.Resource must be acquired.
//
// Returns: NTSTATUS - STATUS_SUCCESS unless there is some problem.
//
// History: 25 Jan 1992 alanw created
//
//--------------------------------------------------------------------------
#ifdef TERMSRV
NTSTATUS DfsInitializeLogicalRoot( IN LPCWSTR Name, IN PUNICODE_STRING Prefix OPTIONAL, IN PDFS_CREDENTIALS Credentials OPTIONAL, IN USHORT VcbFlags, IN ULONG SessionID, IN PLUID LogonID )
#else // TERMSRV
NTSTATUS DfsInitializeLogicalRoot( IN LPCWSTR Name, IN PUNICODE_STRING Prefix OPTIONAL, IN PDFS_CREDENTIALS Credentials OPTIONAL, IN USHORT VcbFlags, IN PLUID LogonID )
#endif // TERMSRV
{ UNICODE_STRING UnicodeString = DfsData.LogRootDevName; UNICODE_STRING LogRootPrefix; UNICODE_STRING RootName, RemainingPath; UNICODE_STRING LogicalRoot;
#ifdef TERMSRV
//
// The SessionID suffix is :SessionID where SessionID is 10 digits max.
//
UNICODE_STRING DeviceString; WCHAR DeviceBuffer[MAX_LOGICAL_ROOT_LEN + ID_MAX_LEN + sizeof(WCHAR)]; UNICODE_STRING IDString; WCHAR IDBuffer[ID_MAX_LEN + 1]; // +1 for UNICODE_NULL
#endif // TERMSRV
WCHAR *TmpBuf; PDFS_VCB Vcb; WCHAR RootBuffer[MAX_LOGICAL_ROOT_LEN]; PDFS_PKT_ENTRY pktEntry = NULL;
LPCWSTR pstr = Name; PWSTR pdst; PLOGICAL_ROOT_DEVICE_OBJECT DeviceObject = NULL; NTSTATUS Status;
DfsDbgTrace(0, Dbg, "DfsInitializeLogicalRoot -> %ws\n", Name); DfsDbgTrace(0, Dbg, "DfsInitializeLogicalRoot -> %wZ\n", Prefix);
//
// First, see if a logical root by the given name already exists
//
ASSERT(ARGUMENT_PRESENT(Name)); RootName.Buffer = RootBuffer; RootName.MaximumLength = sizeof(RootBuffer); Status = DfspLogRootNameToPath(Name, &RootName); if (!NT_SUCCESS(Status)) { return(Status); }
#ifdef TERMSRV
Status = DfsFindLogicalRoot(&RootName, SessionID, LogonID, &Vcb, &RemainingPath); #else
Status = DfsFindLogicalRoot(&RootName, &Vcb, LogonID, &RemainingPath); #endif
ASSERT(Status != STATUS_OBJECT_PATH_SYNTAX_BAD); if (Status != STATUS_NO_SUCH_DEVICE) { return(STATUS_OBJECT_NAME_COLLISION); }
#ifdef TERMSRV
//
// For multiuser,
// If LUID device maps are enabled,
// then we add the LogonID to the devicename - e.g.
// net use f: to a DFS share for logon ID 0x000000000003a3f0 will create
// a symbolic link with the following format:
// \??\f: -> \Device\WinDfs\f:000000000003a3f0
//
// If LUID device maps are not enabled,
// then we add the SessionID to the devicename - e.g.
// net use f: to a DFS share for session ID 3 will create a symbolic link
// \DosDevices\f::3 -> \device\WinDfs\f:3
// In the VCB we store the SessionID for matching purposes.
// Both the symbolic link and the object name shall contain the SessionID
// in the name. However, in deviceObject->Vcb.LogicalRoot.Buffer, the
// name does not contain the SessionID. To find a matching VCB, both the name
// and SessionID must match.
//
DeviceString.Buffer = DeviceBuffer; DeviceString.MaximumLength = sizeof(DeviceBuffer); DeviceString.Length = 0;
//
// Build the UnicodeString without the SessionID or LogonID
//
RtlAppendUnicodeToString(&UnicodeString, (LPWSTR)Name);
if( SessionID != INVALID_SESSIONID) {
if( (DfsLUIDDeviceMapsEnabled == TRUE) && (LogonID != NULL) && (sizeof(*LogonID) == sizeof(LUID)) ) { //
// Build the DeviceString with the LogonID
//
_snwprintf( IDBuffer, sizeof(IDBuffer)/sizeof(WCHAR), L"%08x%08x", LogonID->HighPart, LogonID->LowPart );
IDBuffer[ID_MAX_LEN] = UNICODE_NULL;
RtlInitUnicodeString( &IDString, IDBuffer ); } else { //
// Build the DeviceString with the SessionID
//
IDString.Buffer = IDBuffer; IDString.MaximumLength = sizeof(IDBuffer); IDString.Length = 0;
RtlIntegerToUnicodeString(SessionID, 10, &IDString); } RtlCopyUnicodeString(&DeviceString, &DfsData.LogRootDevName); RtlAppendUnicodeToString(&DeviceString, (LPWSTR)Name); RtlAppendUnicodeToString(&DeviceString,L":"); RtlAppendUnicodeStringToString(&DeviceString, &IDString); DeviceString.MaximumLength = DeviceString.Length;
//
// Next, try to setup the Dos Device link
//
if (Prefix) { Status = DfsDefineDosDevice( Name[0], &DeviceString ); if (!NT_SUCCESS(Status)) { return( Status ); } } } else {
ASSERT( Prefix == FALSE ); }
#else // TERMSRV
//
// DfsData.LogRootDevName is initialized to be L"\Device\WinDfs\"
// Here, we tack on the name of the Logical root we are creating
// to the above string, so that the string becomes, for example,
// L"\Device\WinDfs\Root". Note that at this point, we are scribbling
// into the buffer belonging to DfsData.LogRootDevName, but this
// should be ok, since we are not changing the Length field of that
// Unicode string! BTW, we need a string of this form to create the
// device object.
//
pdst = &UnicodeString.Buffer[UnicodeString.Length/sizeof (WCHAR)]; while (*pstr != UNICODE_NULL) { *pdst++ = *pstr++; UnicodeString.Length += sizeof (WCHAR); }
//
// Next, try to setup the Dos Device link
//
if (Prefix) { Status = DfsDefineDosDevice( Name[0], &UnicodeString ); if (!NT_SUCCESS(Status)) { return( Status ); } }
#endif // TERMSRV
//
// Before we initialize the Vcb, we need to allocate space for the
// Prefix. PagedPool should be fine here. We need to reallocate because
// we will store this permanently in the DFS_VCB.
//
LogRootPrefix.Buffer = NULL;
if (Prefix && Prefix->Length > 0) { LogRootPrefix.Length = Prefix->Length; LogRootPrefix.MaximumLength = LogRootPrefix.Length + sizeof(WCHAR); LogRootPrefix.Buffer = ExAllocatePoolWithTag( PagedPool, LogRootPrefix.MaximumLength, ' puM');
if (LogRootPrefix.Buffer != NULL) { RtlMoveMemory(LogRootPrefix.Buffer, Prefix->Buffer, Prefix->MaximumLength);
LogRootPrefix.Buffer[Prefix->Length/sizeof(WCHAR)] = UNICODE_NULL;
} else {
//
// Couldn't allocate memory! Ok to return with error code, since
// we haven't changed the state of the IO subsystem yet.
//
if (Prefix) { NTSTATUS DeleteStatus;
DeleteStatus = DfsUndefineDosDevice( Name[0] );
ASSERT(NT_SUCCESS(DeleteStatus)); }
return(STATUS_INSUFFICIENT_RESOURCES); } } else { RtlInitUnicodeString(&LogRootPrefix, NULL); }
//
// Save the logical root name for the DFS_VCB structure. Remember, above
// we had UnicodeString to be of the form L"\Device\WinDfs\org". Now,
// we copy UnicodeString, then adjust the buffer and length fields so that
// the Buffer points to the beginning of the L"org"; Then, we allocate
// space for LogicalRootBuffer, and copy the name to it!
//
LogicalRoot = UnicodeString;
LogicalRoot.Buffer = &LogicalRoot.Buffer[ DfsData.LogRootDevName.Length/sizeof (WCHAR) ]; LogicalRoot.Length -= DfsData.LogRootDevName.Length; LogicalRoot.MaximumLength -= DfsData.LogRootDevName.Length;
//
// Now dup the buffer that LogicalRoot uses
//
TmpBuf = ExAllocatePoolWithTag( PagedPool, LogicalRoot.Length, ' puM');
if (TmpBuf == NULL) {
//
// Couldn't allocate memory! Ok to return with error code, since
// we still haven't changed the state of the IO subsystem yet.
//
if (LogRootPrefix.Buffer != NULL) {
ExFreePool(LogRootPrefix.Buffer);
}
if (Prefix) { NTSTATUS DeleteStatus;
DeleteStatus = DfsUndefineDosDevice( Name[0] );
ASSERT(NT_SUCCESS(DeleteStatus)); }
return(STATUS_INSUFFICIENT_RESOURCES);
} else {
RtlMoveMemory( TmpBuf, LogicalRoot.Buffer, LogicalRoot.Length );
LogicalRoot.Buffer = TmpBuf;
}
//
// Create the device object for the logical root.
//
#ifdef TERMSRV
Status = IoCreateDevice( DfsData.DriverObject, sizeof( LOGICAL_ROOT_DEVICE_OBJECT ) - sizeof( DEVICE_OBJECT ), (SessionID != INVALID_SESSIONID) ? &DeviceString : &UnicodeString, FILE_DEVICE_DFS, FILE_REMOTE_DEVICE, FALSE, (PDEVICE_OBJECT *) &DeviceObject );
#else // TERMSRV
Status = IoCreateDevice( DfsData.DriverObject, sizeof( LOGICAL_ROOT_DEVICE_OBJECT ) - sizeof( DEVICE_OBJECT ), &UnicodeString, FILE_DEVICE_DFS, FILE_REMOTE_DEVICE, FALSE, (PDEVICE_OBJECT *) &DeviceObject );
#endif // TERMSRV
if ( !NT_SUCCESS( Status ) ) { if (LogRootPrefix.Buffer) { ExFreePool(LogRootPrefix.Buffer); ExFreePool(LogicalRoot.Buffer); } if (Prefix) { NTSTATUS DeleteStatus;
DeleteStatus = DfsUndefineDosDevice( Name[0] );
ASSERT(NT_SUCCESS(DeleteStatus)); } return Status; }
//
// Pin the pkt entry in the cache by incrementing the Usecount
//
if (LogRootPrefix.Buffer != NULL && LogRootPrefix.Length > 0) {
UNICODE_STRING prefix = LogRootPrefix; USHORT i, j;
//
// We want to work with the \server\share part of the prefix only,
// so count up to 3 backslashes, then stop.
//
for (i = j = 0; i < prefix.Length/sizeof(WCHAR) && j < 3; i++) {
if (prefix.Buffer[i] == UNICODE_PATH_SEP) {
j++;
}
}
prefix.Length = (j >= 3) ? (i-1) * sizeof(WCHAR) : i * sizeof(WCHAR);
pktEntry = PktLookupEntryByPrefix(&DfsData.Pkt, &prefix, &RemainingPath);
if (pktEntry != NULL && RemainingPath.Length == 0) {
InterlockedIncrement(&pktEntry->UseCount);
} else { pktEntry = NULL; } }
DeviceObject->DeviceObject.StackSize = 5;
DfsInitializeVcb ( NULL, &DeviceObject->Vcb, &LogRootPrefix, Credentials, (PDEVICE_OBJECT)DeviceObject );
DeviceObject->Vcb.VcbState |= VcbFlags;
#ifdef TERMSRV
DeviceObject->Vcb.SessionID = SessionID; #endif
DeviceObject->Vcb.pktEntry = pktEntry;
RtlCopyLuid(&DeviceObject->Vcb.LogonID, LogonID);
//
// Above we preallocated the buffer we need here. So just use it.
//
DeviceObject->Vcb.LogicalRoot = LogicalRoot;
//
// This is not documented anywhere, but calling IoCreateDevice has set
// the DO_DEVICE_INITIALIZING flag in DeviceObject->Flags. Normally,
// device objects are created only at driver init time, and IoLoadDriver
// will clear this bit for all device objects created at init time.
// Since in Dfs, we need to create and delete devices on the fly (ie,
// via FsCtl), we need to manually clear this bit.
//
DeviceObject->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS; }
//+----------------------------------------------------------------------------
//
// Function: DfsDeleteLogicalRoot
//
// Synopsis: Removes a logical root if found and possible.
//
// Arguments: [Name] -- Name of the Logical Root
// [fForce] -- Whether to Forcibly delete logical root inspite of
// open files.
//
// Returns: STATUS_SUCCESS -- If successfully deleted logical root
//
// STATUS_NO_SUCH_DEVICE -- If there is no logical root to
// delete.
//
// STATUS_DEVICE_BUSY -- If fForce is false and there are open
// files via this logical root.
//
//-----------------------------------------------------------------------------
#ifdef TERMSRV
NTSTATUS DfsDeleteLogicalRoot( IN PWSTR Name, IN BOOLEAN fForce, IN ULONG SessionID, IN PLUID LogonID )
#else // TERMSRV
NTSTATUS DfsDeleteLogicalRoot( IN PWSTR Name, IN BOOLEAN fForce, IN PLUID LogonID )
#endif // TERMSRV
{ UNICODE_STRING RootName; UNICODE_STRING RemainingPath; WCHAR RootBuffer[MAX_LOGICAL_ROOT_LEN + 2]; PDFS_PKT_ENTRY PktEntry; PDFS_VCB Vcb; NTSTATUS Status; PLOGICAL_ROOT_DEVICE_OBJECT DeviceObject; BOOLEAN pktLocked; PDFS_PKT_ENTRY pktEntry;
//
// The 2 extra spots are for holding :\ to form a path out of a
// root name; ie, to go from root to a root:\ form.
//
DfsDbgTrace(0, Dbg, "DfsDeleteLogicalRoot -> %ws\n", Name); DfsDbgTrace(0, Dbg, "DfsDeleteLogicalRoot -> %s\n", fForce ? "TRUE":"FALSE");
//
// First see if the logical root even exists.
//
ASSERT(ARGUMENT_PRESENT(Name));
RootName.Buffer = RootBuffer; RootName.MaximumLength = sizeof(RootBuffer);
Status = DfspLogRootNameToPath(Name, &RootName);
if (!NT_SUCCESS(Status)) return(Status);
//
// Acquire Pkt and DfsData, wait till we do so.
//
PktAcquireExclusive(TRUE, &pktLocked);
ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
#ifdef TERMSRV
Status = DfsFindLogicalRoot(&RootName, SessionID, LogonID, &Vcb, &RemainingPath); #else // TERMSRV
Status = DfsFindLogicalRoot(&RootName, LogonID, &Vcb, &RemainingPath); #endif // TERMSRV
if (!NT_SUCCESS(Status)) {
goto Cleanup; }
//
// Check to see if there are open files via this volume.
//
if (!fForce && ((Vcb->DirectAccessOpenCount != 0) || (Vcb->OpenFileCount != 0))) {
Status = STATUS_DEVICE_BUSY;
goto Cleanup;
}
//
// Delete the credentials used by this connection
//
if (Vcb->Credentials != NULL) { DfsDeleteCredentials( Vcb->Credentials ); }
//
// Get rid of the Dos Device
//
DfsUndefineDosDevice( Name[0] );
//
// Dec ref count on pkt entry
//
if (Vcb->pktEntry != NULL) { InterlockedDecrement(&Vcb->pktEntry->UseCount);
Vcb->pktEntry = NULL; }
//
// Now, get rid of the Device itself. This is a bit tricky, because there
// might be files open on this device. So, we reference the device and
// call ObMakeTemporaryObject. This causes the object to be removed from
// the NT Object table, but, since atleast our reference is active,
// prevents the object from being freed. Then, we insert this object into
// our DeletedVcb list. The timer routine will periodically wake up and
// see if all references to this device have been released, at which
// point the device will be finally freed.
//
RemoveEntryList(&Vcb->VcbLinks);
InsertTailList( &DfsData.DeletedVcbQueue, &Vcb->VcbLinks );
DeviceObject = CONTAINING_RECORD( Vcb, LOGICAL_ROOT_DEVICE_OBJECT, Vcb);
ObReferenceObjectByPointer( DeviceObject, 0, NULL, KernelMode );
ObMakeTemporaryObject((PVOID) DeviceObject);
DeviceObject->DeviceObject.Flags &= ~DO_DEVICE_HAS_NAME;
Cleanup:
ExReleaseResourceLite(&DfsData.Resource);
PktRelease();
return(Status); }
//+----------------------------------------------------------------------------
//
// Function: DfspLogRootNameToPath
//
// Synopsis: Amazingly enough, all it does it takes a PWSTR, copies it into
// a Unicode string's buffer, and appends a \ to the tail of the
// buffer, thus making a path out of a Logical root name.
//
// Arguments: [Name] -- Name of logical root, like L"org"
// [RootName] -- Destination for L"org\\"
//
// Returns: STATUS_BUFFER_OVERFLOW, STATUS_SUCCESS
//
//-----------------------------------------------------------------------------
NTSTATUS DfspLogRootNameToPath( IN LPCWSTR Name, OUT PUNICODE_STRING RootName ) { unsigned short i, nMaxNameLen;
//
// The two extra spots are required to append a ":\" after the root name.
//
nMaxNameLen = (RootName->MaximumLength/sizeof(WCHAR)) - 2;
//
// Copy the name
//
for (i = 0; Name[i] != UNICODE_NULL && i < nMaxNameLen; i++) { RootName->Buffer[i] = Name[i]; }
//
// Make sure entire name was copied before we ran out of space
//
if (Name[i] != UNICODE_NULL) { //
// Someone sent in a name bigger than allowed.
//
return(STATUS_BUFFER_OVERFLOW); }
//
// Append the ":\" to form a path
//
RootName->Length = i * sizeof(WCHAR); return(RtlAppendUnicodeToString(RootName, L":\\")); }
#define PackMem(buf, str, len, pulen) { \
ASSERT(*(pulen) >= (len)); \ RtlMoveMemory((buf) + *(pulen) - (len), (str), (len)); \ *(pulen) -= (len); \ }
//+----------------------------------------------------------------------------
//
// Function: DfsGetResourceFromVcb
//
// Synopsis: Given a DFS_VCB it constructs a NETRESOURCE struct into the buffer
// passed in. At the same time it uses the end of the buffer to
// fill in a string. If the buffer is insufficient in size the
// required size is returned in "pulen". If everything succeeds
// then the pulen arg is decremented to indicate remaining size
// of buffer.
//
// Arguments: [Vcb] -- The source DFS_VCB
// [ProviderName] -- Provider Name to stuff in the NETRESOURCE
// [BufBegin] -- Start of actual buffer for computing offsets
// [Buf] -- The NETRESOURCE structure to fill
// [BufSize] -- On entry, size of buf. On return, contains
// remaining size of buf.
//
// Returns: [STATUS_SUCCESS] -- Operation completed successfully.
// [STATUS_BUFFER_OVERFLOW] -- buf is not big enough.
//
// Notes: This routine fills in a NETRESOURCE structure starting at
// Buf. The strings in the NETRESOURCE are filled in starting
// from the *end* (ie, starting at Buf + *BufSize)
//
//-----------------------------------------------------------------------------
#if defined (_WIN64)
typedef struct _DFS_NETRESOURCE32 { DWORD dwScope; DWORD dwType; DWORD dwDisplayType; DWORD dwUsage; ULONG lpLocalName; ULONG lpRemoteName; ULONG lpComment ; ULONG lpProvider; }DFS_NETRESOURCE32, *PDFS_NETRESOURCE32;
#endif
NTSTATUS DfsGetResourceFromVcb( PIRP pIrp, PDFS_VCB Vcb, PUNICODE_STRING ProviderName, PUCHAR BufBegin, PUCHAR Buf, PULONG BufSize, PULONG pResourceSize
) { LPNETRESOURCE netResource = (LPNETRESOURCE) Buf; ULONG sizeRequired = 0, ResourceSize; WCHAR localDrive[ 3 ]; ULONG32 CommentOffset, ProviderOffset, LocalNameOffset, RemoteNameOffset;
#if defined (_WIN64)
if (IoIs32bitProcess(pIrp)) { ResourceSize = sizeof(DFS_NETRESOURCE32); } else #endif
ResourceSize = sizeof(NETRESOURCE);
*pResourceSize = ResourceSize;
sizeRequired = ResourceSize + ProviderName->Length + sizeof(UNICODE_NULL) + 3 * sizeof(WCHAR) + // lpLocalName D: etc.
sizeof(UNICODE_PATH_SEP) + Vcb->LogRootPrefix.Length + sizeof(UNICODE_NULL);
if (*BufSize < sizeRequired) { *BufSize = sizeRequired; return(STATUS_BUFFER_OVERFLOW); }
//
// Buffer is big enough, fill in the NETRESOURCE structure
//
Buf += ResourceSize; *BufSize -= ResourceSize;
netResource->dwScope = RESOURCE_CONNECTED; netResource->dwType = RESOURCETYPE_DISK; netResource->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC; netResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
CommentOffset = 0; //
// Fill in the provider name
//
PackMem(Buf, L"", sizeof(L""), BufSize); PackMem(Buf, ProviderName->Buffer, ProviderName->Length, BufSize); ProviderOffset = (ULONG32)(Buf + *BufSize - BufBegin);
//
// Fill in the local name next
//
localDrive[0] = Vcb->LogicalRoot.Buffer[0]; localDrive[1] = UNICODE_DRIVE_SEP; localDrive[2] = UNICODE_NULL;
PackMem(Buf, localDrive, sizeof(localDrive), BufSize); LocalNameOffset = (ULONG32)(Buf + *BufSize - BufBegin);
//
// Fill in the remote name last
//
PackMem(Buf, L"", sizeof(L""), BufSize); PackMem(Buf, Vcb->LogRootPrefix.Buffer, Vcb->LogRootPrefix.Length, BufSize); PackMem(Buf, UNICODE_PATH_SEP_STR, sizeof(UNICODE_PATH_SEP), BufSize); RemoteNameOffset = (ULONG32)(Buf + *BufSize - BufBegin);
#if defined (_WIN64)
if (IoIs32bitProcess(pIrp)) { PDFS_NETRESOURCE32 pNetResource32 = (PDFS_NETRESOURCE32)netResource;
pNetResource32->lpComment = CommentOffset; pNetResource32->lpProvider = ProviderOffset; pNetResource32->lpLocalName = LocalNameOffset; pNetResource32->lpRemoteName = RemoteNameOffset; } else { #endif
netResource->lpComment = (LPWSTR)UIntToPtr( CommentOffset ); netResource->lpProvider = (LPWSTR)UIntToPtr( ProviderOffset ); netResource->lpLocalName = (LPWSTR)UIntToPtr( LocalNameOffset ); netResource->lpRemoteName = (LPWSTR)UIntToPtr( RemoteNameOffset ); #if defined (_WIN64)
} #endif
return(STATUS_SUCCESS); }
//+----------------------------------------------------------------------------
//
// Function: DfsGetResourceFromDevlessRoot
//
// Synopsis: Builds a NETRESOURCE structure for a device-less connection.
// The LPWSTR members of NETRESOURCE actually contain offsets
// from the BufBegin parameter.
//
// Arguments: [Drt] -- The DevicelessRoot structure
// [ProviderName] -- Provider Name to stuff in the NETRESOURCE
// [BufBegin] -- Start of actual buffer for computing offsets
// [Buf] -- The NETRESOURCE structure to fill
// [BufSize] -- On entry, size of buf. On return, contains
// remaining size of buf.
//
// Returns: [STATUS_SUCCESS] -- Operation completed successfully.
// [STATUS_BUFFER_OVERFLOW] -- buf is not big enough.
//
// Notes: This routine fills in a NETRESOURCE structure starting at
// Buf. The strings in the NETRESOURCE are filled in starting
// from the *end* (ie, starting at Buf + *BufSize)
//
//-----------------------------------------------------------------------------
NTSTATUS DfsGetResourceFromDevlessRoot( PIRP pIrp, PDFS_DEVLESS_ROOT pDrt, PUNICODE_STRING ProviderName, PUCHAR BufBegin, PUCHAR Buf, PULONG BufSize, PULONG pResourceSize) { LPNETRESOURCE netResource = (LPNETRESOURCE) Buf; ULONG sizeRequired = 0, ResourceSize; WCHAR localDrive[ 3 ]; ULONG32 CommentOffset, ProviderOffset, LocalNameOffset, RemoteNameOffset; #if defined (_WIN64)
if (IoIs32bitProcess(pIrp)) { ResourceSize = sizeof(DFS_NETRESOURCE32); } else #endif
ResourceSize = sizeof(NETRESOURCE);
*pResourceSize = ResourceSize;
sizeRequired = ResourceSize + ProviderName->Length + sizeof(UNICODE_NULL) + 2 * sizeof(UNICODE_PATH_SEP) + pDrt->DevlessPath.Length + sizeof(UNICODE_NULL);
if (*BufSize < sizeRequired) { *BufSize = sizeRequired; return(STATUS_BUFFER_OVERFLOW); }
//
// Buffer is big enough, fill in the NETRESOURCE structure
//
Buf += ResourceSize; *BufSize -= ResourceSize;
netResource->dwScope = RESOURCE_CONNECTED; netResource->dwType = RESOURCETYPE_DISK; netResource->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC; netResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
CommentOffset = 0; LocalNameOffset = 0;
//
// Fill in the provider name
//
PackMem(Buf, L"", sizeof(L""), BufSize); PackMem(Buf, ProviderName->Buffer, ProviderName->Length, BufSize); ProviderOffset = (ULONG32)(Buf + *BufSize - BufBegin);
//
// Fill in the remote name last
//
PackMem(Buf, L"", sizeof(L""), BufSize); PackMem(Buf, pDrt->DevlessPath.Buffer, pDrt->DevlessPath.Length, BufSize);
PackMem(Buf, UNICODE_PATH_SEP_STR, sizeof(UNICODE_PATH_SEP), BufSize);
RemoteNameOffset = (ULONG32)(Buf + *BufSize - BufBegin);
#if defined (_WIN64)
if (IoIs32bitProcess(pIrp)) { PDFS_NETRESOURCE32 pNetResource32 = (PDFS_NETRESOURCE32)netResource;
pNetResource32->lpComment = CommentOffset; pNetResource32->lpProvider = ProviderOffset; pNetResource32->lpLocalName = LocalNameOffset; pNetResource32->lpRemoteName = RemoteNameOffset; } else { #endif
netResource->lpComment = (LPWSTR)UIntToPtr( CommentOffset ); netResource->lpProvider = (LPWSTR)UIntToPtr( ProviderOffset ); netResource->lpLocalName = (LPWSTR)UIntToPtr( LocalNameOffset ); netResource->lpRemoteName = (LPWSTR)UIntToPtr( RemoteNameOffset ); #if defined (_WIN64)
} #endif
return(STATUS_SUCCESS);
}
#ifdef TERMSRV
BOOLEAN DfsLogicalRootExists( IN PWSTR pwszName, IN ULONG SessionID, IN PLUID LogonID )
#else // TERMSRV
BOOLEAN DfsLogicalRootExists( IN PWSTR pwszName, IN PLUID LogonID )
#endif // TERMSRV
{
UNICODE_STRING RootName; UNICODE_STRING RemainingPath; WCHAR RootBuffer[MAX_LOGICAL_ROOT_LEN + 2]; PDFS_VCB Vcb; NTSTATUS Status;
ASSERT(ARGUMENT_PRESENT(pwszName)); RootName.Buffer = RootBuffer; RootName.MaximumLength = sizeof(RootBuffer);
Status = DfspLogRootNameToPath(pwszName, &RootName); if (!NT_SUCCESS(Status)) { return(FALSE); }
#ifdef TERMSRV
Status = DfsFindLogicalRoot(&RootName, SessionID, LogonID, &Vcb, &RemainingPath); #else // TERMSRV
Status = DfsFindLogicalRoot(&RootName, LogonId, &Vcb, &RemainingPath); #endif // TERMSRV
if (!NT_SUCCESS(Status)) {
//
// If this asserts, we need to fix the code above that creates the
// Logical Root name, or fix DfsFindLogicalRoot.
//
ASSERT(Status != STATUS_OBJECT_PATH_SYNTAX_BAD); return(FALSE); } else { return(TRUE); }
}
//+----------------------------------------------------------------------------
//
// Function: DfsDefineDosDevice
//
// Synopsis: Creates a dos device to a logical root
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS DfsDefineDosDevice( IN WCHAR Device, IN PUNICODE_STRING Target) { NTSTATUS status; HANDLE device; OBJECT_ATTRIBUTES ob; UNICODE_STRING deviceName; WCHAR Buf[25];
wcscpy(Buf, L"\\??\\X:"); RtlInitUnicodeString( &deviceName, Buf); deviceName.Buffer[ deviceName.Length/sizeof(WCHAR) - 2] = Device;
InitializeObjectAttributes( &ob, &deviceName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwCreateSymbolicLinkObject( &device, SYMBOLIC_LINK_ALL_ACCESS, &ob, Target);
if (NT_SUCCESS(status)) ZwClose( device );
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: DfsUndefineDosDevice
//
// Synopsis: Undefines a dos device
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS DfsUndefineDosDevice( IN WCHAR Device ) {
NTSTATUS status; HANDLE device; OBJECT_ATTRIBUTES ob; UNICODE_STRING deviceName; WCHAR Buf[25];
wcscpy(Buf, L"\\??\\X:"); RtlInitUnicodeString( &deviceName, Buf); deviceName.Buffer[ deviceName.Length/sizeof(WCHAR) - 2] = Device;
InitializeObjectAttributes( &ob, &deviceName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwOpenSymbolicLinkObject( &device, SYMBOLIC_LINK_QUERY | DELETE, &ob);
if (NT_SUCCESS(status)) {
status = ZwMakeTemporaryObject( device );
ZwClose( device );
}
return( status );
}
//+-------------------------------------------------------------------------
//
// Function: DfsFindDevlessRoot, local
//
// Synopsis: DfsFindDevlessRoot takes as input a UNC name
// looks up the DFS_DEVLESS_ROOT associated with the root,
// and returns the DevlessRoot
//
// Arguments: [Path] -- Input path name
// [Drt] -- Returns DFS_DEVLESS_ROOT which corresponds to
// the root for the Path
//
// Returns: NTSTATUS:
// STATUS_SUCCESS if Drt found
// STATUS_NO_SUCH_DEVICE - root name not found
//
//--------------------------------------------------------------------------
#ifdef TERMSRV
NTSTATUS DfsFindDevlessRoot( IN PUNICODE_STRING Path, IN ULONG SessionID, IN PLUID LogonID, OUT PDFS_DEVLESS_ROOT *Drt )
#else // TERMSRV
NTSTATUS DfsFindDevlessRoot( IN PUNICODE_STRING Path, IN PLUID LogonID, OUT PDFS_DEVLESS_ROOT *Drt, )
#endif // TERMSRV
{ PLIST_ENTRY Link; NTSTATUS Status = STATUS_SUCCESS;
DfsDbgTrace(+1, Dbg, "DfsFindDevlessRoot...%wZ\n", Path);
//
// Search for the devless ROOT.
//
ExAcquireResourceSharedLite(&DfsData.Resource, TRUE);
for ( Link = DfsData.DrtQueue.Flink; Link != &DfsData.DrtQueue; Link = Link->Flink ) {
*Drt = CONTAINING_RECORD( Link, DFS_DEVLESS_ROOT, DrtLinks );
#ifdef TERMSRV
if ((SessionID == INVALID_SESSIONID) || (SessionID == (*Drt)->SessionID)) { #endif
if ( RtlEqualLuid(LogonID, &(*Drt)->LogonID) ) { if (RtlEqualString( (PSTRING)&(*Drt)->DevlessPath, (PSTRING)Path, (BOOLEAN)TRUE) ) { break; } } #ifdef TERMSRV
} #endif // TERMSRV
} if (Link == &DfsData.DrtQueue) { Status = STATUS_NO_SUCH_DEVICE; ExReleaseResourceLite(&DfsData.Resource); DfsDbgTrace(-1, Dbg, "DfsFindDevlessRoot -> %08lx\n", ULongToPtr(Status) ); return(Status); }
ExReleaseResourceLite(&DfsData.Resource); DfsDbgTrace(-1, Dbg, "DfsFindLogicalRoot -> %08lx\n", ULongToPtr(Status) ); return(Status); }
//+-------------------------------------------------------------------------
//
// Function: DfsInitializeDevlessRoot, public
//
// Synopsis: Allocate and initialize storage for a Deviceless root.
//
// Effects: A DFS_DEVLESS_ROOT structure is created.
//
// Arguments: [Name] -- Pathname that is the deviceless root.
// [Credentials] -- The credentials to use when accessing files
// via this logical root.
//
// Requires: DfsData must first be set up. Also an EXCLUSIVE LOCK on
// DfsData.Resource must be acquired.
//
// Returns: NTSTATUS - STATUS_SUCCESS unless there is some problem.
//
//--------------------------------------------------------------------------
#ifdef TERMSRV
NTSTATUS DfsInitializeDevlessRoot( IN PUNICODE_STRING Name, IN PDFS_CREDENTIALS Credentials OPTIONAL, IN ULONG SessionID, IN PLUID LogonID )
#else // TERMSRV
NTSTATUS DfsInitializeDevlessRoot( IN PUNICODE_STRING Name, IN PDFS_CREDENTIALS Credentials OPTIONAL, IN PLUID LogonID )
#endif // TERMSRV
{
PDFS_DEVLESS_ROOT Drt; PDFS_PKT_ENTRY pktEntry = NULL; UNICODE_STRING DevlessRootName; NTSTATUS Status;
DfsDbgTrace(0, Dbg, "DfsInitializeDevlessRoot -> %wZ\n", Name);
#ifdef TERMSRV
Status = DfsFindDevlessRoot(Name, SessionID, LogonID, &Drt); #else
Status = DfsFindDevlessRoot(Name, LogonID, &Drt); #endif
if (Status != STATUS_NO_SUCH_DEVICE) { //
// this means we found a device. In the devless Root case, this means
// we dont have to do any more work. Just return a success response.
// However, we still have the credentials which the caller assumes
// we will be using. Get rid of it here and return success.
//
DfsDeleteCredentials(Credentials); return(STATUS_SUCCESS); }
Drt = ExAllocatePoolWithTag( PagedPool, sizeof(DFS_DEVLESS_ROOT), ' puM'); if (Drt == NULL) { return(STATUS_INSUFFICIENT_RESOURCES); }
//
// Before we initialize the Drt, we need to allocate space for the
// Prefix. PagedPool should be fine here. We need to reallocate because
// we will store this permanently in the DFS_DEVLESS_ROOT.
//
DevlessRootName.Length = Name->Length; DevlessRootName.MaximumLength = DevlessRootName.Length + sizeof(WCHAR); DevlessRootName.Buffer = ExAllocatePoolWithTag( PagedPool, DevlessRootName.MaximumLength, ' puM');
if (DevlessRootName.Buffer != NULL) { RtlMoveMemory(DevlessRootName.Buffer, Name->Buffer, Name->MaximumLength); DevlessRootName.Buffer[Name->Length/sizeof(WCHAR)] = UNICODE_NULL; } else { ExFreePool(Drt); return(STATUS_INSUFFICIENT_RESOURCES); }
//
// Pin the pkt entry in the cache by incrementing the Usecount
//
if (DevlessRootName.Buffer != NULL && DevlessRootName.Length > 0) {
UNICODE_STRING prefix = DevlessRootName; USHORT i, j; UNICODE_STRING RemainingPath;
//
// We want to work with the \server\share part of the prefix only,
// so count up to 3 backslashes, then stop.
//
for (i = j = 0; i < prefix.Length/sizeof(WCHAR) && j < 3; i++) { if (prefix.Buffer[i] == UNICODE_PATH_SEP) { j++; } }
prefix.Length = (j >= 3) ? (i-1) * sizeof(WCHAR) : i * sizeof(WCHAR);
pktEntry = PktLookupEntryByPrefix(&DfsData.Pkt, &prefix, &RemainingPath);
if (pktEntry != NULL && RemainingPath.Length == 0) {
InterlockedIncrement(&pktEntry->UseCount);
} else { pktEntry = NULL; }
}
DfsInitializeDrt ( Drt, &DevlessRootName, Credentials);
#ifdef TERMSRV
Drt->SessionID = SessionID; #endif
Drt->pktEntry = pktEntry; RtlCopyLuid(&Drt->LogonID, LogonID);
return STATUS_SUCCESS; }
//+----------------------------------------------------------------------------
//
// Function: DfsDeleteDevlessRoot
//
// Synopsis: Removes a Devless root if found and possible.
//
// Arguments: [Name] -- Name of the Logical Root
//
// Returns: STATUS_SUCCESS -- If successfully deleted logical root
//
// STATUS_NO_SUCH_DEVICE -- If there is no logical root to
// delete.
//
//
//-----------------------------------------------------------------------------
#ifdef TERMSRV
NTSTATUS DfsDeleteDevlessRoot( IN PUNICODE_STRING Name, IN ULONG SessionID, IN PLUID LogonID )
#else // TERMSRV
NTSTATUS DfsDeleteDevlessRoot( IN PUNICODE_STRING Name, IN PLUID LogonID )
#endif // TERMSRV
{ PDFS_PKT_ENTRY PktEntry; PDFS_DEVLESS_ROOT Drt; NTSTATUS Status; BOOLEAN pktLocked; PDFS_PKT_ENTRY pktEntry;
DfsDbgTrace(0, Dbg, "DfsDeleteDevlessRoot -> %wZ\n", Name);
//
// Acquire Pkt and DfsData, wait till we do so.
//
PktAcquireExclusive(TRUE, &pktLocked);
ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
#ifdef TERMSRV
Status = DfsFindDevlessRoot(Name, SessionID, LogonID, &Drt); #else // TERMSRV
Status = DfsFindDevlessRoot(Name, LogonID, &Drt); #endif // TERMSRV
if (!NT_SUCCESS(Status)) { goto Cleanup; }
//
// Delete the credentials used by this connection
//
DfsDeleteCredentials( Drt->Credentials );
if (Drt->pktEntry != NULL) { InterlockedDecrement(&Drt->pktEntry->UseCount); Drt->pktEntry = NULL; }
RemoveEntryList(&Drt->DrtLinks);
if (Drt->DevlessPath.Buffer) { ExFreePool(Drt->DevlessPath.Buffer); } ExFreePool(Drt);
Cleanup:
ExReleaseResourceLite(&DfsData.Resource);
PktRelease();
return(Status); }
|