Windows-Server-2003/base/fs/mup/creds.c

1239 lines
32 KiB
C

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