|
|
//+----------------------------------------------------------------------------
//
// Copyright (C) 1996, Microsoft Corporation
//
// File: creds.c
//
// Contents: Code to handle user-defined credentials
//
// Classes: None
//
// Functions: DfsCreateCredentials --
// DfsFreeCredentials --
// DfsInsertCredentials --
// DfsDeleteCredentials --
// DfsLookupCredentials --
//
// History: March 18, 1996 Milans Created
//
//-----------------------------------------------------------------------------
#include "dfsprocs.h"
#include <align.h>
#include <ntddnfs.h>
#include "dnr.h"
#include "rpselect.h"
#include "creds.h"
VOID DfspFillEa( OUT PFILE_FULL_EA_INFORMATION EA, IN LPSTR EaName, IN PUNICODE_STRING EaValue);
NTSTATUS DfspTreeConnectToService( IN PDFS_SERVICE Service, IN PDFS_CREDENTIALS Creds);
VOID DfspDeleteAllAuthenticatedConnections( IN PDFS_CREDENTIALS Creds);
NTSTATUS DfsCompleteDeleteTreeConnection( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Ctx);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,DfsCreateCredentials)
#pragma alloc_text(PAGE,DfsVerifyCredentials)
#pragma alloc_text(PAGE,DfspFillEa)
#pragma alloc_text(PAGE,DfsFreeCredentials)
#pragma alloc_text(PAGE,DfsInsertCredentials)
#pragma alloc_text(PAGE,DfsDeleteCredentials)
#pragma alloc_text(PAGE,DfsLookupCredentials)
#pragma alloc_text(PAGE,DfsLookupCredentialsByServerShare)
#pragma alloc_text(PAGE,DfspTreeConnectToService)
#pragma alloc_text(PAGE,DfspDeleteAllAuthenticatedConnections)
#pragma alloc_text(PAGE,DfsDeleteTreeConnection)
#endif // ALLOC_PRAGMA
//+----------------------------------------------------------------------------
//
// Function: DfsCreateCredentials
//
// Synopsis: Creates a DFS_CREDENTIALS structure from a
// FILE_DFS_DEF_ROOT_CREDENTIALS structure.
//
// Arguments: [CredDef] -- The input PFILE_DFS_DEF_ROOT_CREDENTIALS.
// [CredDefSize] -- Size in bytes of *CredDef.
// [Creds] -- On successful return, contains a pointer to the
// allocated PDFS_CREDENTIALS structure.
//
// Returns: [STATUS_SUCCESS] -- Allocated credentials
//
// [STATUS_INVALID_PARAMETER] -- CredDef didn't pass mustard.
//
// [STATUS_INSUFFICIENT_RESOURCES] -- Unable to allocate pool.
//
//-----------------------------------------------------------------------------
#define DEF_NAME_TO_UNICODE_STRING(srcLength, dest, srcBuf, destBuf) \
if ((srcLength)) { \ (dest)->Length = (dest)->MaximumLength = srcLength; \ (dest)->Buffer = (destBuf); \ RtlMoveMemory((dest)->Buffer, (srcBuf), (dest)->Length); \ srcBuf += ((dest)->Length / sizeof(WCHAR)); \ destBuf += ((dest)->Length / sizeof(WCHAR)); \ }
#ifdef TERMSRV
NTSTATUS DfsCreateCredentials( IN PFILE_DFS_DEF_ROOT_CREDENTIALS CredDef, IN ULONG CredDefSize, IN ULONG SessionID, IN PLUID LogonID, OUT PDFS_CREDENTIALS *Creds )
#else // TERMSRV
NTSTATUS DfsCreateCredentials( IN PFILE_DFS_DEF_ROOT_CREDENTIALS CredDef, IN ULONG CredDefSize, IN PLUID LogonID, OUT PDFS_CREDENTIALS *Creds)
#endif // TERMSRV
{ NTSTATUS status = STATUS_SUCCESS; ULONG totalSize; PDFS_CREDENTIALS creds; PWCHAR nameSrc, nameBuf; PFILE_FULL_EA_INFORMATION ea; ULONG eaLength;
totalSize = CredDef->DomainNameLen + CredDef->UserNameLen + CredDef->PasswordLen + CredDef->ServerNameLen + CredDef->ShareNameLen;
//
// Validate the CredDef buffer
//
if ((totalSize + sizeof(FILE_DFS_DEF_ROOT_CREDENTIALS) - sizeof(WCHAR)) > CredDefSize) status = STATUS_INVALID_PARAMETER; else if (CredDef->ServerNameLen == 0) status = STATUS_INVALID_PARAMETER; else if (CredDef->ShareNameLen == 0) status = STATUS_INVALID_PARAMETER;
//
// Allocate the new DFS_CREDENTIALS structure
//
if (NT_SUCCESS(status)) {
//
// Add in the size of the DFS_CREDENTIALS_STRUCTURE itself.
//
totalSize += sizeof(DFS_CREDENTIALS);
//
// Add in the size of the EA_BUFFER that we will create. The
// eaLength has room for 4 FILE_FULL_EA_INFORMATION structures,
// the names and values of the four EAs we will use, and, since each
// EA structure has to be long-word aligned, 4 ULONGs.
//
eaLength = 4 * sizeof(FILE_FULL_EA_INFORMATION) + sizeof(EA_NAME_DOMAIN) + sizeof(EA_NAME_USERNAME) + sizeof(EA_NAME_PASSWORD) + sizeof(EA_NAME_CSCAGENT) + CredDef->DomainNameLen + CredDef->UserNameLen + CredDef->PasswordLen + 4 * sizeof(ULONG);
if (CredDef->Flags & DFS_USE_NULL_PASSWORD) { eaLength += sizeof(UNICODE_NULL); totalSize += sizeof(UNICODE_NULL); }
//
// The buffers for DomainName, UserName etc. will start right after
// the EaBuffer of DFS_CREDENTIALS. So, EaLength has to be WCHAR
// aligned.
//
eaLength = ROUND_UP_COUNT(eaLength, ALIGN_WCHAR);
//
// Now, allocate the pool
//
creds = (PDFS_CREDENTIALS) ExAllocatePoolWithTag( NonPagedPool, totalSize + eaLength, ' puM');
if (creds == NULL) status = STATUS_INSUFFICIENT_RESOURCES;
}
//
// Fill up the DFS_CREDENTIALS structure.
//
if (NT_SUCCESS(status)) {
nameSrc = CredDef->Buffer;
nameBuf = (PWCHAR) ((PUCHAR) creds + sizeof(DFS_CREDENTIALS) + eaLength);
RtlZeroMemory( creds, sizeof(DFS_CREDENTIALS) );
DEF_NAME_TO_UNICODE_STRING( CredDef->DomainNameLen, &creds->DomainName, nameSrc, nameBuf);
DEF_NAME_TO_UNICODE_STRING( CredDef->UserNameLen, &creds->UserName, nameSrc, nameBuf);
if (CredDef->Flags & DFS_USE_NULL_PASSWORD) {
LPWSTR nullPassword = L"";
DEF_NAME_TO_UNICODE_STRING( sizeof(UNICODE_NULL), &creds->Password, nullPassword, nameBuf);
} else {
DEF_NAME_TO_UNICODE_STRING( CredDef->PasswordLen, &creds->Password, nameSrc, nameBuf);
}
DEF_NAME_TO_UNICODE_STRING( CredDef->ServerNameLen, &creds->ServerName, nameSrc, nameBuf);
DEF_NAME_TO_UNICODE_STRING( CredDef->ShareNameLen, &creds->ShareName, nameSrc, nameBuf);
creds->RefCount = 0;
creds->NetUseCount = 0;
eaLength = 0;
ea = (PFILE_FULL_EA_INFORMATION) &creds->EaBuffer[0];
if (creds->DomainName.Length != 0) {
DfspFillEa(ea, EA_NAME_DOMAIN, &creds->DomainName);
eaLength += ea->NextEntryOffset;
}
if (creds->UserName.Length != 0) {
ea = (PFILE_FULL_EA_INFORMATION) ((PUCHAR) ea + ea->NextEntryOffset);
DfspFillEa(ea, EA_NAME_USERNAME, &creds->UserName);
eaLength += ea->NextEntryOffset;
}
if (CredDef->Flags & DFS_USE_NULL_PASSWORD) {
UNICODE_STRING nullPassword;
RtlInitUnicodeString(&nullPassword, L"");
ea = (PFILE_FULL_EA_INFORMATION) ((PUCHAR) ea + ea->NextEntryOffset);
DfspFillEa(ea, EA_NAME_PASSWORD, &nullPassword);
eaLength += ea->NextEntryOffset;
} else if (creds->Password.Length != 0) {
ea = (PFILE_FULL_EA_INFORMATION) ((PUCHAR) ea + ea->NextEntryOffset);
DfspFillEa(ea, EA_NAME_PASSWORD, &creds->Password);
eaLength += ea->NextEntryOffset;
}
if (CredDef->CSCAgentCreate == TRUE) {
UNICODE_STRING EmptyUniString;
RtlInitUnicodeString(&EmptyUniString, NULL);
ea = (PFILE_FULL_EA_INFORMATION) ((PUCHAR) ea + ea->NextEntryOffset);
DfspFillEa(ea, EA_NAME_CSCAGENT, &EmptyUniString);
eaLength += ea->NextEntryOffset;
}
ea->NextEntryOffset = 0;
creds->EaLength = eaLength;
#ifdef TERMSRV
creds->SessionID = SessionID; #endif // TERMSRV
RtlCopyLuid(&creds->LogonID, LogonID);
*Creds = creds;
}
//
// Done...
//
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: DfspFillEa
//
// Synopsis: Helper routine to fill up an EA Buffer
//
// Arguments: [EA] -- Pointer to FILE_FULL_EA_INFORMATION to fill
//
// [EaName] -- Name of Ea
//
// [EaValue] -- Value (UNICODE_STRING) of Ea
//
// Returns:
//
//-----------------------------------------------------------------------------
VOID DfspFillEa( OUT PFILE_FULL_EA_INFORMATION EA, IN LPSTR EaName, IN PUNICODE_STRING EaValue) { ULONG nameLen;
nameLen = strlen(EaName) + sizeof(CHAR);
EA->Flags = 0;
EA->EaNameLength = (UCHAR) ROUND_UP_COUNT(nameLen, ALIGN_WCHAR) - sizeof(CHAR);
EA->EaValueLength = EaValue->Length;
//
// Set the last character of EaName to 0 - the IO subsystem checks for
// this
//
EA->EaName[ EA->EaNameLength ] = 0;
RtlMoveMemory(&EA->EaName[0], EaName, nameLen);
if (EaValue->Length > 0) {
RtlMoveMemory( &EA->EaName[ EA->EaNameLength + 1 ], EaValue->Buffer, EA->EaValueLength);
}
EA->NextEntryOffset = ROUND_UP_COUNT( FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) + EA->EaNameLength + EA->EaValueLength, ALIGN_DWORD);
}
//+----------------------------------------------------------------------------
//
// Function: DfsFreeCredentials
//
// Synopsis: Frees up the resources used by the DFS_CREDENTIALS structure.
// Dual of DfsCreateCredentials
//
// Arguments: [Creds] -- The credentials structure to free
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
VOID DfsFreeCredentials( PDFS_CREDENTIALS Creds) { ExFreePool( Creds ); }
//+----------------------------------------------------------------------------
//
// Function: DfsInsertCredentials
//
// Synopsis: Inserts a new user credential into DfsData.Credentials queue.
// Note that if this routine finds an existing credential
// record, it will free up the passed in one, bump up the ref
// count on the existing one, return a pointer to the
// existing one, and return STATUS_OBJECT_NAME_COLLISION.
//
// Arguments: [Creds] -- Pointer to DFS_CREDENTIALS structure to insert.
// [ForDevicelessConnection] -- If TRUE, the creds are being
// inserted because the caller wants to create a
// deviceless connection.
//
// Returns: [STATUS_SUCCESS] -- Successfully inserted structure
//
// [STATUS_NETWORK_CREDENTIAL_CONFLICT] -- There is already
// another set of credentials for the given server\share.
//
// [STATUS_OBJECT_NAME_COLLISION] -- There is already another
// net use to the same server\share with the same
// credentials.
//
//-----------------------------------------------------------------------------
NTSTATUS DfsInsertCredentials( IN OUT PDFS_CREDENTIALS *Creds, IN BOOLEAN ForDevicelessConnection) {
NTSTATUS status = STATUS_SUCCESS; PDFS_CREDENTIALS creds, existingCreds;
creds = *Creds;
ASSERT(creds->ServerName.Length != 0); ASSERT(creds->ShareName.Length != 0);
ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
#ifdef TERMSRV
existingCreds = DfsLookupCredentialsByServerShare( &creds->ServerName, &creds->ShareName, creds->SessionID, &creds->LogonID );
#else // TERMSRV
existingCreds = DfsLookupCredentialsByServerShare( &creds->ServerName, &creds->ShareName, &creds->LogonID );
#endif // TERMSRV
if (existingCreds != NULL) { if ( (creds->DomainName.Length > 0 && !RtlEqualUnicodeString( &existingCreds->DomainName, &creds->DomainName, TRUE)) || (creds->UserName.Length > 0 && !RtlEqualUnicodeString( &existingCreds->UserName, &creds->UserName, TRUE)) || //
// For compatibility reasons, check for password inconsistency ONLY
// if we have a previously setup credentials and the previous
// credentials had explicit password and the current request
// has explicitly specified password.
// rdr2\rdbss\rxconnct.c also has a similar check for the rdr.
//
(existingCreds->Password.Length > 0 && creds->Password.Length > 0 && !RtlEqualUnicodeString( &existingCreds->Password, &creds->Password, TRUE)) ) {
status = STATUS_NETWORK_CREDENTIAL_CONFLICT;
} else { //
// Do this for both deviceless and has device cases.
// With deep net uses of deviceless, multiple DevlessRoots
// may point to the same credentials.
//
existingCreds->NetUseCount++; existingCreds->RefCount++;
DfsFreeCredentials( *Creds );
*Creds = existingCreds;
status = STATUS_OBJECT_NAME_COLLISION; }
} else {
ASSERT(creds->RefCount == 0);
ASSERT(creds->NetUseCount == 0);
creds->RefCount = 1;
creds->NetUseCount = 1;
InsertTailList( &DfsData.Credentials, &creds->Link );
status = STATUS_SUCCESS;
}
if (status != STATUS_NETWORK_CREDENTIAL_CONFLICT) {
if (ForDevicelessConnection) (*Creds)->Flags |= CRED_IS_DEVICELESS; else (*Creds)->Flags |= CRED_HAS_DEVICE;
}
ExReleaseResourceLite( &DfsData.Resource );
return( status ); }
//+----------------------------------------------------------------------------
//
// Function: DfsDeleteCredentials
//
// Synopsis: Deletes a user credential record. This is the dual of
// DfsInsertCredentials, NOT DfsCreateCredentials.
//
// Arguments: [Creds] -- Pointer to DFS_CREDENTIALS record to delete.
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
VOID DfsDeleteCredentials( IN PDFS_CREDENTIALS Creds) { ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
Creds->NetUseCount--;
Creds->RefCount--;
if (Creds->NetUseCount == 0) {
DfspDeleteAllAuthenticatedConnections( Creds );
RemoveEntryList( &Creds->Link );
InsertTailList( &DfsData.DeletedCredentials, &Creds->Link );
}
ExReleaseResourceLite( &DfsData.Resource );
}
//+----------------------------------------------------------------------------
//
// Function: DfsLookupCredentials
//
// Synopsis: Looks up a credential, if any, associated with a file name.
//
// Arguments: [FileName] -- Name of file. Assumed to have atleast a
// \server\share part.
//
// Returns: Pointer to DFS_CREDENTIALS to use, NULL if not found.
//
//-----------------------------------------------------------------------------
#ifdef TERMSRV
PDFS_CREDENTIALS DfsLookupCredentials( IN PUNICODE_STRING FileName, IN ULONG SessionID, IN PLUID LogonID )
#else // TERMSRV
PDFS_CREDENTIALS DfsLookupCredentials( IN PUNICODE_STRING FileName, IN PLUID LogonID )
#endif // TERMSRV
{ UNICODE_STRING server, share; USHORT i;
//
// FileName has to be atleast \a\b
//
if (FileName->Length < 4 * sizeof(WCHAR)) return( NULL );
if (FileName->Buffer[0] != UNICODE_PATH_SEP) return( NULL );
server.Buffer = &FileName->Buffer[1];
for (i = 1, server.Length = 0; i < FileName->Length/sizeof(WCHAR) && FileName->Buffer[i] != UNICODE_PATH_SEP; i++, server.Length += sizeof(WCHAR)) { NOTHING; }
server.MaximumLength = server.Length;
i++; // Go past the backslash
share.Buffer = &FileName->Buffer[i];
for (share.Length = 0; i < FileName->Length/sizeof(WCHAR) && FileName->Buffer[i] != UNICODE_PATH_SEP; i++, share.Length += sizeof(WCHAR)) { NOTHING; }
share.MaximumLength = share.Length;
if ((server.Length == 0) || (share.Length == 0)) return( NULL );
#ifdef TERMSRV
return DfsLookupCredentialsByServerShare( &server, &share, SessionID, LogonID );
#else // TERMSRV
return DfsLookupCredentialsByServerShare( &server, &share, LogonID );
#endif // TERMSRV
}
//+----------------------------------------------------------------------------
//
// Function: DfsLookupCredentialsByServerShare
//
// Synopsis: Searches DfsData.Credentials for credentials given a server
// and share name.
//
// Arguments: [ServerName] -- Name of server to match.
// [ShareName] -- Name of share to match.
//
// Returns: Pointer to DFS_CREDENTIALS, NULL if not found.
//
//-----------------------------------------------------------------------------
#ifdef TERMSRV
PDFS_CREDENTIALS DfsLookupCredentialsByServerShare( IN PUNICODE_STRING ServerName, IN PUNICODE_STRING ShareName, IN ULONG SessionID, IN PLUID LogonID )
#else // TERMSRV
PDFS_CREDENTIALS DfsLookupCredentialsByServerShare( IN PUNICODE_STRING ServerName, IN PUNICODE_STRING ShareName, IN PLUID LogonID )
#endif // TERMSRV
{ PLIST_ENTRY link; PDFS_CREDENTIALS matchedCreds = NULL;
for (link = DfsData.Credentials.Flink; link != &DfsData.Credentials && matchedCreds == NULL; link = link->Flink) {
PDFS_CREDENTIALS creds;
creds = CONTAINING_RECORD(link, DFS_CREDENTIALS, Link);
if (RtlEqualUnicodeString(ServerName, &creds->ServerName, TRUE) && RtlEqualUnicodeString(ShareName, &creds->ShareName, TRUE)) { #ifdef TERMSRV
if( (creds->SessionID == SessionID) && RtlEqualLuid(&creds->LogonID, LogonID) ) { matchedCreds = creds; }
#else // TERMSRV
if( RtlEqualLuid(&creds->LogonID, LogonID) ) { matchedCreds = creds; }
#endif // TERMSRV
}
}
return( matchedCreds );
}
//+----------------------------------------------------------------------------
//
// Function: DfsVerifyCredentials
//
// Synopsis: Returns the result of trying to connect to a Dfs share using
// the supplied credentials
//
// Arguments: [Prefix] -- The Dfs Prefix to connect to.
// [Creds] -- The DFS_CREDENTIALS record to use for connecting.
//
// Returns: [STATUS_SUCCESS] -- Successfully connected.
//
// [STATUS_BAD_NETWORK_PATH] -- Unable to find Prefix
// in Pkt or a server for prefix could not be found.
//
// NT Status of Tree Connect attempt
//
//-----------------------------------------------------------------------------
NTSTATUS DfsVerifyCredentials( IN PUNICODE_STRING Prefix, IN PDFS_CREDENTIALS Creds) { NTSTATUS status; UNICODE_STRING remPath, shareName; PDFS_PKT pkt; PDFS_PKT_ENTRY pktEntry; PDFS_SERVICE service; ULONG i, USN; BOOLEAN pktLocked, fRetry; UNICODE_STRING UsePrefix;
DfsGetServerShare( &UsePrefix, Prefix );
pkt = _GetPkt();
//
// We acquire Pkt exclusive because we might tear down the IPC$ connection
// to a server while trying to establish a connection with supplied
// credentials.
//
PktAcquireExclusive( TRUE, &pktLocked );
do {
fRetry = FALSE;
pktEntry = PktLookupEntryByPrefix( pkt, &UsePrefix, &remPath );
if (pktEntry != NULL) {
InterlockedIncrement(&pktEntry->UseCount);
USN = pktEntry->USN;
status = STATUS_BAD_NETWORK_PATH;
for (i = 0; i < pktEntry->Info.ServiceCount; i++) {
service = &pktEntry->Info.ServiceList[i];
status = DfspTreeConnectToService(service, Creds);
//
// If tree connect succeeded, we are done.
//
if (NT_SUCCESS(status)) break;
//
// If tree connect failed with an "interesting error" like
// STATUS_ACCESS_DENIED, we are done.
//
if (!ReplIsRecoverableError(status)) break;
//
// Tree connect failed because of an error like host not
// reachable. In that case, we want to go on to the next
// server in the list. But before we do that, we have to see
// if the pkt changed on us while we were off doing the tree
// connect.
//
if (USN != pktEntry->USN) {
fRetry = TRUE;
break;
}
}
InterlockedDecrement(&pktEntry->UseCount);
} else {
status = STATUS_BAD_NETWORK_PATH;
}
} while ( fRetry );
PktRelease();
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: DfspTreeConnectToService
//
// Synopsis: Helper routine to tree connect to a DFS_SERVICE with supplied
// credentials.
//
// Arguments: [Service] -- The service to connect to
// [Creds] -- The credentials to use to tree connect
//
// Returns: NT Status of tree connect
//
// Notes: This routine assumes that the Pkt has been acquired before
// being called. This routine will release and reacquire the Pkt
// so the caller should be prepared for the event that the Pkt
// has changed after a call to this routine.
//
//-----------------------------------------------------------------------------
NTSTATUS DfspTreeConnectToService( IN PDFS_SERVICE Service, IN PDFS_CREDENTIALS Creds) { NTSTATUS status; UNICODE_STRING shareName; HANDLE treeHandle; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatusBlock; BOOLEAN pktLocked; USHORT i, k;
ASSERT( PKT_LOCKED_FOR_SHARED_ACCESS() );
//
// Compute the share name...
//
if (Service->pProvider != NULL && Service->pProvider->DeviceName.Buffer != NULL && Service->pProvider->DeviceName.Length > 0) {
//
// We have a provider already - use it
//
shareName.MaximumLength = Service->pProvider->DeviceName.Length + Service->Address.Length;
} else {
//
// We don't have a provider yet - give it to the mup to find one
//
shareName.MaximumLength = sizeof(DD_NFS_DEVICE_NAME_U) + Service->Address.Length;
}
shareName.Buffer = ExAllocatePoolWithTag(PagedPool, shareName.MaximumLength, ' puM');
if (shareName.Buffer != NULL) {
//
// If we have a cached connection to the IPC$ share of this server,
// close it or it might conflict with the credentials supplied here.
//
if (Service->ConnFile != NULL) {
ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
if (Service->ConnFile != NULL) DfsCloseConnection(Service);
ExReleaseResourceLite(&DfsData.Resource);
}
//
// Now, build the share name to tree connect to.
//
shareName.Length = 0;
if (Service->pProvider != NULL && Service->pProvider->DeviceName.Buffer != NULL && Service->pProvider->DeviceName.Length > 0) {
//
// We have a provider already - use it
//
RtlAppendUnicodeToString( &shareName, Service->pProvider->DeviceName.Buffer);
} else {
//
// We don't have a provider yet - give it to the mup to find one
//
RtlAppendUnicodeToString( &shareName, DD_NFS_DEVICE_NAME_U);
} RtlAppendUnicodeStringToString(&shareName, &Service->Address);
//
// One can only do tree connects to server\share. So, in case
// pService->Address refers to something deeper than the share,
// make sure we setup a tree-conn only to server\share. Note that
// by now, shareName is of the form
// \Device\LanmanRedirector\server\share<\path>. So, count up to
// 4 slashes and terminate the share name there.
//
for (i = 0, k = 0; i < shareName.Length/sizeof(WCHAR) && k < 5; i++) {
if (shareName.Buffer[i] == UNICODE_PATH_SEP) k++; }
shareName.Length = i * sizeof(WCHAR); if (k == 5) shareName.Length -= sizeof(WCHAR);
InitializeObjectAttributes( &objectAttributes, &shareName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
//
// Release the Pkt before going over the net...
//
PktRelease();
status = ZwCreateFile( &treeHandle, SYNCHRONIZE, &objectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, (PVOID) Creds->EaBuffer, Creds->EaLength);
if (NT_SUCCESS(status)) {
PFILE_OBJECT fileObject;
//
// 426184, need to check return code for errors.
//
status = ObReferenceObjectByHandle( treeHandle, 0, NULL, KernelMode, &fileObject, NULL);
ZwClose( treeHandle );
if (NT_SUCCESS(status)) { DfsDeleteTreeConnection( fileObject, USE_FORCE ); } }
ExFreePool( shareName.Buffer );
PktAcquireShared( TRUE, &pktLocked );
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: DfspDeleteAllAuthenticatedConnections
//
// Synopsis: Deletes all authenticated connections made using a particular
// set of credentials that we might have cached. Useful to
// implement net use /d
//
// Arguments: [Creds] -- The Credentials to match against authenticated
// connection
//
// Returns: Nothing
//
// Notes: Pkt and DfsData must have been acquired before calling!
//
//-----------------------------------------------------------------------------
VOID DfspDeleteAllAuthenticatedConnections( IN PDFS_CREDENTIALS Creds) { PDFS_PKT_ENTRY pktEntry; ULONG i; PDFS_MACHINE_ENTRY machine;
ASSERT( PKT_LOCKED_FOR_SHARED_ACCESS() || PKT_LOCKED_FOR_EXCLUSIVE_ACCESS() );
ASSERT( ExIsResourceAcquiredExclusiveLite( &DfsData.Resource ) );
for (pktEntry = PktFirstEntry(&DfsData.Pkt); pktEntry != NULL; pktEntry = PktNextEntry(&DfsData.Pkt, pktEntry)) {
for (i = 0; i < pktEntry->Info.ServiceCount; i++) {
//
// Tear down connection to IPC$ if we have one...
//
if (pktEntry->Info.ServiceList[i].ConnFile != NULL) DfsCloseConnection( &pktEntry->Info.ServiceList[i] );
machine = pktEntry->Info.ServiceList[i].pMachEntry;
if (machine->Credentials == Creds) {
DfsDeleteTreeConnection(machine->AuthConn, USE_LOTS_OF_FORCE);
machine->AuthConn = NULL;
machine->Credentials->RefCount--;
machine->Credentials = NULL;
}
}
}
}
//+----------------------------------------------------------------------------
//
// Function: DfsDeleteTreeConnection, public
//
// Synopsis: Tears down tree connections given the file object representing
// the tree connection.
//
// Arguments: [TreeConnFileObj] -- The tree connection to tear down.
// [ForceFilesClosed] -- If TRUE, the tree connection will be
// torn down even if files are open on the server
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
VOID DfsDeleteTreeConnection( IN PFILE_OBJECT TreeConnFileObj, IN ULONG Level) { PIRP irp; KEVENT event; static LMR_REQUEST_PACKET req;
KeInitializeEvent( &event, SynchronizationEvent, FALSE );
req.Version = REQUEST_PACKET_VERSION;
req.Level = Level;
irp = DnrBuildFsControlRequest( TreeConnFileObj, &event, FSCTL_LMR_DELETE_CONNECTION, &req, sizeof(req), NULL, 0, DfsCompleteDeleteTreeConnection);
if (irp != NULL) {
IoCallDriver( IoGetRelatedDeviceObject( TreeConnFileObj ), irp);
KeWaitForSingleObject( &event, UserRequest, KernelMode, FALSE, // Alertable
NULL); // Timeout
IoFreeIrp( irp );
ObDereferenceObject(TreeConnFileObj);
}
}
NTSTATUS DfsCompleteDeleteTreeConnection( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Ctx) {
KeSetEvent( (PKEVENT) Ctx, EVENT_INCREMENT, FALSE );
return( STATUS_MORE_PROCESSING_REQUIRED ); }
VOID DfsGetServerShare( PUNICODE_STRING pDest, PUNICODE_STRING pSrc) { ULONG i;
*pDest = *pSrc;
for (i = 0; ((i < pDest->Length/sizeof(WCHAR)) && (pDest->Buffer[i] == UNICODE_PATH_SEP)); i++) { NOTHING; } for (; ((i < pDest->Length/sizeof(WCHAR)) && (pDest->Buffer[i] != UNICODE_PATH_SEP)); i++) { NOTHING; } for (i = i + 1; ((i < pDest->Length/sizeof(WCHAR)) && (pDest->Buffer[i] != UNICODE_PATH_SEP)); i++) { NOTHING; }
if (i <= pDest->Length/sizeof(WCHAR)) { pDest->Length = (USHORT)i * sizeof(WCHAR); } }
|