netroot.c revision 78a072e1b56619e3230735ae073668311232ec94
/*++
Copyright (c) 1989 - 1999 Microsoft Corporation
Module Name:
netroot.c
Abstract:
This module implements the routines for creating the net root.
--*/
#include "precomp.h"
#pragma hdrstop
//
// Forward declarations ...
//
NTSTATUS VBoxMRxUpdateNetRootState (IN OUT PMRX_NET_ROOT pNetRoot)
/*++
Routine Description:
This routine updates the mini redirector state associated with a net root.
Arguments:
pNetRoot - the net root instance.
Return Value:
NTSTATUS - The return status for the operation
Notes:
By diffrentiating the mini redirector state from the net root condition it is possible
to permit a variety of reconnect strategies. It is conceivable that the RDBSS considers
a net root to be good while the underlying mini redirector might mark it as invalid
and reconnect on the fly.
--*/
{
NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
Log(("VBOXSF: VBoxMRxUpdateNetRootState: Called.\n"));
return (Status);
}
NTSTATUS VBoxMRxInitializeNetRootEntry (IN PMRX_NET_ROOT pNetRoot)
/*++
Routine Description:
This routine initializes a new net root.
It also validates rootnames. Eg: attempts to create a
file in a root that has not been created will fail.
Arguments:
pNetRoot - the net root
Return Value:
NTSTATUS - The return status for the operation
Notes:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = (PMRX_VBOX_NETROOT_EXTENSION)pNetRoot->Context;
Log(("VBOXSF: VBoxMRxInitializeNetRootEntry: Called.\n"));
return Status;
}
NTSTATUS VBoxUpdateNetRoot (PMRX_NET_ROOT pNetRoot)
/*++
Routine Description:
This routine initializes the wrapper data structure corresponding to a
given net root entry.
Arguments:
pNetRootEntry - the server entry
Return Value:
STATUS_SUCCESS if successful
--*/
{
PAGED_CODE();
Log(("VBOXSF: VBoxUpdateNetRoot: NetRoot = 0x%x Type = 0x%x\n", pNetRoot, pNetRoot->Type));
switch (pNetRoot->Type)
{
case NET_ROOT_DISK:
pNetRoot->DeviceType = RxDeviceType(DISK);
break;
case NET_ROOT_PIPE:
pNetRoot->DeviceType = RxDeviceType(NAMED_PIPE);
break;
case NET_ROOT_COMM:
pNetRoot->DeviceType = RxDeviceType(SERIAL_PORT);
break;
case NET_ROOT_PRINT:
pNetRoot->DeviceType = RxDeviceType(PRINTER);
break;
case NET_ROOT_MAILSLOT:
pNetRoot->DeviceType = RxDeviceType(MAILSLOT);
break;
case NET_ROOT_WILD:
/* We get this type when for example Windows Media player opens an MP3 file.
* This NetRoot has the same remote path (\\vboxsrv\dir) as other NetRoots,
* which were created earlier and which were NET_ROOT_DISK.
*
* In the beginning of the function (UpdateNetRoot) the DDK sample sets
* pNetRoot->Type of newly created NetRoots using a value previously
* pstored in a NetRootExtension. One NetRootExtensions is used for a single
* remote path and reused by a few NetRoots, if they point to the same path.
*
* To simplify things we just set the type to DISK here (we do not support
* anything else anyway), and update the DeviceType correspondingly.
*/
pNetRoot->Type = NET_ROOT_DISK;
pNetRoot->DeviceType = RxDeviceType(DISK);
break;
default:
AssertMsgFailed(("VBOXSF: VBoxUpdateNetRoot: Invalid net root type! Type = 0x%x\n", pNetRoot->Type));
break;
}
Log(("VBOXSF: VBoxUpdateNetRoot: leaving pNetRoot->DeviceType = 0x%x\n", pNetRoot->DeviceType));
return STATUS_SUCCESS;
}
NTSTATUS VBoxMRxCreateVNetRoot (IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
/*++
Routine Description:
This routine patches the RDBSS created net root instance with the information required
by the mini redirector.
Arguments:
pVNetRoot - the virtual net root instance.
pCreateNetRootContext - the net root context for calling back
Return Value:
NTSTATUS - The return status for the operation
Notes:
--*/
{
NTSTATUS Status;
PRX_CONTEXT pRxContext = pCreateNetRootContext->RxContext;
PMRX_V_NET_ROOT pVNetRoot = (PMRX_V_NET_ROOT)pCreateNetRootContext->pVNetRoot;
VBoxMRxGetDeviceExtension(pRxContext, pDeviceExtension);
VBoxMRxGetNetRootExtension(pVNetRoot->pNetRoot, pNetRootExtension);
PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot;
PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
BOOLEAN fTreeConnectOpen = TRUE; // RxContext->Create.ThisIsATreeConnectOpen;
BOOLEAN fInitializeNetRoot;
Log(("VBOXSF: VBoxMRxCreateVNetRoot: pNetRoot = %p, fTreeConnectOpen = %d\n", pNetRoot, pRxContext->Create.ThisIsATreeConnectOpen));
/* IMPORTANT:
*
* This function must always call 'pCreateNetRootContext->Callback(pCreateNetRootContext)' before
* returning and then return STATUS_PENDING. Otherwise Win64 will hang.
*/
if (pNetRoot->Type == NET_ROOT_MAILSLOT || pNetRoot->Type == NET_ROOT_PIPE)
{
/* DDK sample returns this status code. And our driver does get such NetRoots. */
Log(("VBOXSF: VBoxMRxCreateVNetRoot: Mailslot or Pipe open (%d) not supported!\n", pNetRoot->Type));
pVNetRoot->Context = NULL;
Status = STATUS_NOT_SUPPORTED;
goto l_Exit;
}
// The V_NET_ROOT is associated with a NET_ROOT. The two cases of interest are as
// follows
// 1) the V_NET_ROOT and the associated NET_ROOT are being newly created.
// 2) a new V_NET_ROOT associated with an existing NET_ROOT is being created.
//
// These two cases can be distinguished by checking if the context associated with
// NET_ROOT is NULL. Since the construction of NET_ROOT's/V_NET_ROOT's are serialized
// by the wrapper this is a safe check.
// ( The wrapper cannot have more then one thread tryingto initialize the same
// NET_ROOT).
//
// The above is not really true in our case. Since we have asked the wrapper,
// to manage our netroot extension, the netroot context will always be non-NULL.
// We will distinguish the cases by checking our root state in the context...
//
if (pNetRoot->Context == NULL)
{
fInitializeNetRoot = TRUE;
}
else
{
VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension);
/* Detect an already initialized NetRoot.
* pNetRootExtension is actually the pNetRoot->Context and it is not null.
*/
fInitializeNetRoot = pNetRootExtension->phgcmClient == NULL;
}
Assert((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) && (NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL));
Status = STATUS_SUCCESS;
// update the net root state to be good.
if (fInitializeNetRoot)
{
PWCHAR pRootName;
ULONG RootNameLength;
int vboxRC;
PSHFLSTRING ParsedPath = 0;
ULONG ParsedPathSize;
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
// validate the fixed netroot name
RootNameLength = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length;
if (!RootNameLength)
{
/* Refuse a netroot path with an empty shared folder name */
Log(("VBOXSF: VBoxMRxCreateVNetRoot: Invalid shared folder name! (length=0)\n"));
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
Status = STATUS_BAD_NETWORK_NAME;
goto l_Exit;
}
RootNameLength -= 2; /* remove leading backslash */
pRootName = (PWCHAR)(pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR)));
pRootName++; /* remove leading backslash */
if (pNetRootExtension->phgcmClient == NULL)
{
Log(("VBOXSF: VBoxMRxCreateVNetRoot: Initialize netroot length = %d, name = %.*ls\n", RootNameLength, RootNameLength / sizeof(WCHAR), pRootName));
/* Calculate length required for parsed path.
*/
ParsedPathSize = sizeof(*ParsedPath) + RootNameLength + sizeof(WCHAR);
ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize);
if (!ParsedPath)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto l_Exit;
}
memset(ParsedPath, 0, ParsedPathSize);
ShflStringInitBuffer(ParsedPath, ParsedPathSize - sizeof(SHFLSTRING));
ParsedPath->u16Size = (uint16_t)RootNameLength + sizeof(WCHAR);
ParsedPath->u16Length = ParsedPath->u16Size - sizeof(WCHAR); /* without terminating null */
RtlCopyMemory(ParsedPath->String.ucs2, pRootName, ParsedPath->u16Length);
vboxRC = vboxCallMapFolder(&pDeviceExtension->hgcmClient, ParsedPath, &pNetRootExtension->map);
vbsfFreeNonPagedMem(ParsedPath);
if (vboxRC != VINF_SUCCESS)
{
Log(("VBOXSF: VBoxMRxCreateVNetRoot: vboxCallMapFolder failed with %d\n", vboxRC));
Status = STATUS_BAD_NETWORK_NAME;
}
else
{
Status = STATUS_SUCCESS;
pNetRootExtension->phgcmClient = &pDeviceExtension->hgcmClient;
}
}
}
else Log(("VBOXSF: VBoxMRxCreateVNetRoot: Creating V_NET_ROOT on existing NET_ROOT!\n"));
if ((Status == STATUS_SUCCESS) && fInitializeNetRoot)
{
//
// A new NET_ROOT and associated V_NET_ROOT are being created !
//
Status = VBoxMRxInitializeNetRootEntry(pNetRoot);
Log(("VBOXSF: VBoxMRxCreateVNetRoot: NulMRXInitializeNetRootEntry called, Status = 0x%lx\n", Status));
}
VBoxUpdateNetRoot(pNetRoot);
l_Exit:
if (Status != STATUS_PENDING)
{
Log(("VBOXSF: VBoxMRxCreateVNetRoot: Returning 0x%lx\n", Status));
pCreateNetRootContext->VirtualNetRootStatus = Status;
if (fInitializeNetRoot)
pCreateNetRootContext->NetRootStatus = Status;
else pCreateNetRootContext->NetRootStatus = Status;
// Callback the RDBSS for resumption.
pCreateNetRootContext->Callback(pCreateNetRootContext);
// Map the error code to STATUS_PENDING since this triggers
// the synchronization mechanism in the RDBSS.
Status = STATUS_PENDING;
}
Log(("VBOXSF: VBoxMRxCreateVNetRoot: Returned STATUS_PENDING\n"));
return Status;
}
NTSTATUS VBoxMRxFinalizeVNetRoot (IN PMRX_V_NET_ROOT pVNetRoot, IN PBOOLEAN ForceDisconnect)
/*++
Routine Description:
Arguments:
pVNetRoot - the virtual net root
ForceDisconnect - disconnect is forced
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot;
VBoxMRxGetNetRootExtension(pVNetRoot->pNetRoot, pNetRootExtension);
int vboxRC;
Log(("VBOXSF: VBoxMRxFinalizeVNetRoot: Address = 0x%lx\n", pVNetRoot));
if (pNetRootExtension->phgcmClient)
{
vboxRC = vboxCallUnmapFolder(pNetRootExtension->phgcmClient, &pNetRootExtension->map);
if (vboxRC != VINF_SUCCESS)
{
Log(("VBOXSF: VBoxMRxFinalizeVNetRoot: vboxCallMapFolder failed with %d\n", vboxRC));
}
pNetRootExtension->phgcmClient = NULL;
}
//
// This is called when all outstanding handles on this
// root have been cleaned up ! We can now zap the netroot
// extension...
//
return Status;
}
NTSTATUS VBoxMRxFinalizeNetRoot (IN PMRX_NET_ROOT pNetRoot, IN PBOOLEAN ForceDisconnect)
/*++
Routine Description:
Arguments:
pVirtualNetRoot - the virtual net root
ForceDisconnect - disconnect is forced
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
Log(("VBOXSF: VBoxMRxFinalizeNetRoot: Called.\n"));
//
// This is called when all outstanding handles on this
// root have been cleaned up ! We can now zap the netroot
// extension...
//
return (Status);
}
VOID VBoxMRxExtractNetRootName (IN PUNICODE_STRING FilePathName, IN PMRX_SRV_CALL SrvCall, OUT PUNICODE_STRING NetRootName, OUT PUNICODE_STRING RestOfName OPTIONAL
)
/*++
Routine Description:
This routine parses the input name into srv, netroot, and the
rest.
Arguments:
--*/
{
UNICODE_STRING xRestOfName;
ULONG length = FilePathName->Length;
PWCH w = FilePathName->Buffer;
PWCH wlimit = (PWCH)(((PCHAR)w) + length);
PWCH wlow;
Log(("VBOXSF: VBoxMRxExtractNetRootName: Called.\n"));
w += (SrvCall->pSrvCallName->Length / sizeof(WCHAR));
NetRootName->Buffer = wlow = w;
for (;;)
{
if (w >= wlimit)
break;
if ((*w == OBJ_NAME_PATH_SEPARATOR) && (w != wlow))
{
break;
}
w++;
}
NetRootName->Length = NetRootName->MaximumLength = (USHORT)((PCHAR)w - (PCHAR)wlow);
//w = FilePathName->Buffer;
//NetRootName->Buffer = w++;
if (!RestOfName)
RestOfName = &xRestOfName;
RestOfName->Buffer = w;
RestOfName->Length = (USHORT)RestOfName->MaximumLength = (USHORT)((PCHAR)wlimit - (PCHAR)w);
Log(("VBOXSF: VBoxMRxExtractNetRootName: FilePath = %.*ls\n", FilePathName->Length / sizeof(WCHAR), FilePathName->Buffer));
Log(("VBOXSF: VBoxMRxExtractNetRootName: Srv = %.*ls, Root = %.*ls, Rest = %.*ls\n", SrvCall->pSrvCallName->Length / sizeof(WCHAR), SrvCall->pSrvCallName->Buffer, NetRootName->Length
/ sizeof(WCHAR), NetRootName->Buffer, RestOfName->Length / sizeof(WCHAR), RestOfName->Buffer));
return;
}