Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

619 lines
19 KiB

/****************************************************************************/
// namespc.c
//
// Redirector namespace code
//
// Copyright (C) 1998-2000 Microsoft Corp.
/****************************************************************************/
#include "precomp.hxx"
#define TRC_FILE "namespc"
#include "trc.h"
NTSTATUS
DrCreateSrvCall(
IN OUT PMRX_SRV_CALL pSrvCall,
IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
/*++
Routine Description:
This routine patches the RDBSS created srv call instance with the information required
by the mini redirector.
Arguments:
CallBackContext - the call back context in RDBSS for continuation.
Return Value:
RXSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;
PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = pCallbackContext;
PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(SCCBC->SrvCalldownStructure);
SmartPtr<DrSession> Session;
PWCHAR ClientName;
BEGIN_FN("DrCreateSrvCall");
TRC_NRM((TB, "SrvCallName %wZ", pSrvCall->pSrvCallName));
ASSERT(pSrvCall);
ASSERT(NodeType(pSrvCall) == RDBSS_NTC_SRVCALL);
ASSERT(pSrvCall->pSrvCallName);
ASSERT(pSrvCall->pSrvCallName->Buffer);
//
// Actually do the work of setting up our stuff for this "server" (client)
// Smb would attempt to contact the server now, but since our stuff
// is client initiated, we already know if we have a connection
//
// Status = DrInitializeServerEntry(pSrvCall,pCallbackContext);
//
// Our SrvCalls look like \clientName
//
ClientName = pSrvCall->pSrvCallName->Buffer;
if (ClientName[0] == OBJ_NAME_PATH_SEPARATOR) {
ClientName++;
}
#if 0
if (Sessions->FindSessionByClientName(ClientName, Session)) {
TRC_NRM((TB, "Recognize SrvCall %wZ", pSrvCall->pSrvCallName));
Status = STATUS_SUCCESS;
}
else {
TRC_NRM((TB, "Unrecognize SrvCall %wZ", pSrvCall->pSrvCallName));
Status = STATUS_BAD_NETWORK_NAME;
}
#endif
if (_wcsicmp(ClientName, DRUNCSERVERNAME_U) == 0) {
TRC_NRM((TB, "Recognize SrvCall %wZ", pSrvCall->pSrvCallName));
Status = STATUS_SUCCESS;
}
else {
TRC_NRM((TB, "Unrecognize SrvCall %wZ", pSrvCall->pSrvCallName));
Status = STATUS_BAD_NETWORK_NAME;
}
SCCBC->RecommunicateContext = NULL;
SCCBC->Status = Status;
SrvCalldownStructure->CallBack(SCCBC);
//
// The CreateSrvCall callback is supposed to return STATUS_PENDING, the
// real result goes in the ServCallbackContext thing
//
return STATUS_PENDING;
}
NTSTATUS
DrSrvCallWinnerNotify(
IN OUT PMRX_SRV_CALL SrvCall,
IN BOOLEAN ThisMinirdrIsTheWinner,
IN OUT PVOID RecommunicateContext
)
/*++
Routine Description:
This routine is called by RDBSS to notify the mini redirector whether the
previous SrvCall is actually going to be processed by this redir.
Arguments:
SrvCall - the SrvCall in question
ThisMinirdrIsTheWinner - True if we will be processing files on this SrvCall
RecommunicateContext - the context we specificed in DrCreateSrvCall
Return Value:
NTSTATUS - The return status for the operation
--*/
{
BEGIN_FN("DrSrvCallWinnerNotify");
PAGED_CODE();
if (!ThisMinirdrIsTheWinner) {
TRC_NRM((TB, "This minirdr is not the winner"));
//
// Some other mini rdr has been choosen to connect. Destroy
// the data structures created for this mini redirector.
//
return STATUS_SUCCESS;
} else {
TRC_NRM((TB, "This minirdr is the winner"));
}
SrvCall->Context = NULL;
SrvCall->Flags |= SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS |
SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES;
return STATUS_SUCCESS;
}
NTSTATUS
DrFinalizeSrvCall(
PMRX_SRV_CALL pSrvCall,
BOOLEAN Force
)
/*++
Routine Description:
This routine is called by RDBSS to notify the mini redirector when the
SrvCall structure is being released.
Arguments:
SrvCall - the SrvCall in question
Force - I don't know, there's no documentation on any of this stuff
Return Value:
NTSTATUS - The return status for the operation
--*/
{
BEGIN_FN("DrFinalizeSrvCall");
PAGED_CODE();
//
// We seem to get called with this even if we weren't the "winner"
// Check to make sure this was filled in before we mess with it
//
return STATUS_SUCCESS;
}
NTSTATUS
DrUpdateNetRootState(
IN PMRX_NET_ROOT pNetRoot
)
{
BEGIN_FN("DrUpdateNetRootState");
return STATUS_SUCCESS;
}
VOID
DrExtractNetRootName(
IN PUNICODE_STRING FilePathName,
IN PMRX_SRV_CALL SrvCall,
OUT PUNICODE_STRING NetRootName,
OUT PUNICODE_STRING RestOfName OPTIONAL
)
/*++
Routine Description:
This routine is called by RDBSS to get a NetRoot (share) name parsed out
of the path. The SrvCall already has part parsed out.
Arguments:
FilePathName - The full path, including the SrvCall
SrvCall - relevant SrvCall structure
NetRootName - The place to put the NetRoot name
RestOfName - What's self of the path afterwards
Return Value:
NTSTATUS - The return status for the operation
--*/
{
UNICODE_STRING xRestOfName;
ULONG length = FilePathName->Length;
PWCH w = FilePathName->Buffer;
PWCH wlimit = (PWCH)(((PCHAR)w)+length);
PWCH wlow;
BEGIN_FN("DrExtractNetRootName");
PAGED_CODE();
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++;
}
// Polish of the NetRootName UNICODE_STRING
NetRootName->Length = NetRootName->MaximumLength
= (USHORT) ((PCHAR)w - (PCHAR)wlow);
if (!RestOfName) RestOfName = &xRestOfName;
RestOfName->Buffer = w;
RestOfName->Length = RestOfName->MaximumLength
= (USHORT) ((PCHAR)wlimit - (PCHAR)w);
TRC_NRM((TB, "DrExtractNetRootName FilePath=%wZ",FilePathName));
TRC_NRM((TB, " Srv=%wZ,Root=%wZ,Rest=%wZ",
SrvCall->pSrvCallName, NetRootName,
RestOfName));
return;
}
NTSTATUS
DrFinalizeNetRoot(
IN OUT PMRX_NET_ROOT pNetRoot,
IN PBOOLEAN ForceDisconnect
)
{
BEGIN_FN("DrFinalizeNetRoot");
return STATUS_SUCCESS;
}
NTSTATUS
DrCreateSCardDevice(SmartPtr<DrSession> &Session, PV_NET_ROOT pVNetRoot,
SmartPtr<DrDevice> &Device)
{
NTSTATUS Status;
PMRX_NET_ROOT pNetRoot = NULL;
BEGIN_FN("DrCreateDevice");
Status = STATUS_BAD_NETWORK_NAME;
if (pVNetRoot != NULL) {
pNetRoot = pVNetRoot->pNetRoot;
}
// We also need to create the smart card subsystem at this point
// even a session may not exist and/or the client smartcard subsystem
// is not connected
Device = new(NonPagedPool) DrSmartCard(Session, RDPDR_DTYP_SMARTCARD,
RDPDR_INVALIDDEVICEID, (PUCHAR)DR_SMARTCARD_SUBSYSTEM);
if (Device != NULL) {
//
// Give the specific device a chance to initialize based on the data
//
TRC_DBG((TB, "Created new device"));
Status = Device->Initialize(NULL, 0);
if (NT_SUCCESS(Status)) {
TRC_DBG((TB, "Device initialized, adding"));
Device->SetDeviceStatus(dsAvailable);
if (Session->GetDevMgr().AddDevice(Device)) {
TRC_DBG((TB, "Added device"));
}
else {
Device = NULL;
if (!Session->FindDeviceByDosName((UCHAR *)DR_SMARTCARD_SUBSYSTEM,
Device, TRUE)) {
TRC_ERR((TB, "Failed to add device to devicelist"));
goto EXIT_POINT;
}
}
}
else {
TRC_ERR((TB, "Failed to initialize device"));
Device = NULL;
goto EXIT_POINT;
}
} else {
TRC_ERR((TB, "Error creating new device: 0x%08lx", Status));
goto EXIT_POINT;
}
if (pVNetRoot != NULL) {
Device->AddRef();
pVNetRoot->Context = (DrDevice *)Device;
pNetRoot->DeviceType = RxDeviceType(DISK);
pNetRoot->Type = NET_ROOT_DISK;
#if DBG
Device->_VNetRoot = (PVOID)pVNetRoot;
#endif
}
Status = STATUS_SUCCESS;
EXIT_POINT:
return Status;
}
NTSTATUS
DrCreateSession(ULONG SessionId, PV_NET_ROOT pVNetRoot, SmartPtr<DrSession> &Session)
{
NTSTATUS Status;
BEGIN_FN("DrCreateSession");
Status = STATUS_BAD_NETWORK_NAME;
// For smart card subsystem, we'll need to create session and
// smart card subsystem objects early before client connect
Session = new(NonPagedPool) DrSession;
if (Session != NULL) {
TRC_DBG((TB, "Created new session"));
if (Session->Initialize()) {
TRC_DBG((TB, "Session connected, adding"));
if (Sessions->AddSession(Session)) {
TRC_DBG((TB, "Added session"));
}
else {
Session = NULL;
if (!Sessions->FindSessionById(SessionId, Session)) {
TRC_DBG((TB, "Session couldn't be added to session list"));
goto EXIT_POINT;
}
}
}
else {
TRC_DBG((TB, "Session couldn't initialize"));
Session = NULL;
goto EXIT_POINT;
}
}
else {
TRC_ERR((TB, "Failed to allocate new session"));
goto EXIT_POINT;
}
Session->SetSessionId(SessionId);
Session->GetExchangeManager().Start();
Status = STATUS_SUCCESS;
EXIT_POINT:
return Status;
}
NTSTATUS
DrCreateVNetRoot(
IN OUT PMRX_CREATENETROOT_CONTEXT CreateNetRootContext
)
{
NTSTATUS Status;
PRX_CONTEXT pRxContext = CreateNetRootContext->RxContext;
ULONG DeviceId;
PMRX_SRV_CALL pSrvCall;
PMRX_NET_ROOT pNetRoot;
SmartPtr<DrSession> Session;
SmartPtr<DrDevice> Device;
PUNICODE_STRING pNetRootName, pSrvCallName;
WCHAR NetRootBuffer[64];
UNICODE_STRING NetRoot = {0, sizeof(NetRootBuffer), NetRootBuffer};
PV_NET_ROOT pVNetRoot;
UCHAR DeviceDosName[MAX_PATH];
PWCHAR token;
ULONG SessionId = -1;
UNICODE_STRING SessionIdString;
USHORT OemCodePage, AnsiCodePage;
INT len;
BEGIN_FN("DrCreateVNetRoot");
pVNetRoot = CreateNetRootContext->pVNetRoot;
pNetRoot = pVNetRoot->pNetRoot;
pSrvCall = pNetRoot->pSrvCall;
ASSERT(NodeType(pNetRoot) == RDBSS_NTC_NETROOT);
ASSERT(NodeType(pSrvCall) == RDBSS_NTC_SRVCALL);
token = &pRxContext->CurrentIrpSp->FileObject->FileName.Buffer[0];
//
// Get the sessionId from the IRP fileName
// File name in the format of:
// \;<DosDeviceName>:<SessionId>\ClientName\DosDeviveName
//
for (unsigned i = 0; i < pRxContext->CurrentIrpSp->FileObject->FileName.Length / sizeof(WCHAR); i++) {
if (*token == L':') {
token++;
SessionIdString.Length = pRxContext->CurrentIrpSp->FileObject->FileName.Length -
(i+1) * sizeof(WCHAR);
SessionIdString.MaximumLength = pRxContext->CurrentIrpSp->FileObject->FileName.MaximumLength -
(i+1) * sizeof(WCHAR);
SessionIdString.Buffer = token;
RtlUnicodeStringToInteger(&SessionIdString, 0, &SessionId);
break;
}
token++;
}
TRC_NRM((TB, "pVNetRoot->SessionId: %d", pVNetRoot->SessionId));
TRC_NRM((TB, "SessionId from FileObject: %d", SessionId));
//
// We first try to get the session id from the FileObject name. If not,
// then it's because we get called directly from a UNC name, in this case
// we have to base on if the UNC is called from the session context and use that
// as the session id.
//
if (SessionId == -1) {
SessionId = pVNetRoot->SessionId;
}
//
// Get the NetRoot name as the DeviceDosName
//
DrExtractNetRootName(pNetRoot->pNetRootName, pSrvCall, &NetRoot, NULL);
if (NetRoot.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) {
NetRoot.Buffer++;
NetRoot.Length -= sizeof(WCHAR);
NetRoot.MaximumLength -= sizeof(WCHAR);
}
TRC_NRM((TB, "Name of NetRoot: %wZ", &NetRoot));
RtlGetDefaultCodePage(&AnsiCodePage,&OemCodePage);
len = ConvertToAndFromWideChar(AnsiCodePage, NetRoot.Buffer,
NetRoot.MaximumLength, (char *)DeviceDosName,
MAX_PATH - 1, FALSE);
if (len != -1) {
DeviceDosName[len] = '\0';
TRC_NRM((TB, "DeviceDosName=%s", DeviceDosName));
}
if (Sessions->FindSessionById(SessionId, Session)) {
// 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).
if (pVNetRoot->Context == NULL) {
if (len != -1) {
if (Session->FindDeviceByDosName(DeviceDosName, Device, TRUE)) {
Device->AddRef();
pVNetRoot->Context = (DrDevice *)Device;
Status = STATUS_SUCCESS;
TRC_NRM((TB, "Successfully recognized VNetRoot"));
// Set the Device type to DISK if this is file system or
// smartcard subsystem,
// set it to COMM if it is serial port.
// otherwise, treated it as printer device.
if (Device->GetDeviceType() == RDPDR_DTYP_FILESYSTEM) {
if (Device->ShouldCreateDevice()) {
pNetRoot->DeviceType = RxDeviceType(DISK);
pNetRoot->Type = NET_ROOT_DISK;
}
else {
Device->Release();
pVNetRoot->Context = NULL;
Status = STATUS_BAD_NETWORK_NAME;
TRC_NRM((TB, "We have disabled drive mapping"));
}
}
else if (Device->GetDeviceType() == RDPDR_DTYP_SERIAL) {
pNetRoot->DeviceType = RxDeviceType(SERIAL_PORT);
pNetRoot->Type = NET_ROOT_COMM;
}
else if (Device->GetDeviceType() == RDPDR_DTYP_SMARTCARD) {
pNetRoot->DeviceType = RxDeviceType(DISK);
pNetRoot->Type = NET_ROOT_DISK;
#if DBG
Device->_VNetRoot = (PVOID)pVNetRoot;
#endif
}
else {
pNetRoot->Type = NET_ROOT_PRINT;
pNetRoot->DeviceType = RxDeviceType(PRINTER);
}
} else {
//
// check to see if this is a smartcard subsystem request
//
if (_stricmp((CHAR *)DeviceDosName, (CHAR *)DR_SMARTCARD_SUBSYSTEM) == 0) {
Status = DrCreateSCardDevice(Session, pVNetRoot, Device);
goto EXIT_POINT;
}
else {
TRC_NRM((TB, "Unrecognized VNetRoot"));
Status = STATUS_BAD_NETWORK_NAME;
}
}
} else {
Status = STATUS_BAD_NETWORK_NAME;
TRC_NRM((TB, "Couldn't find VNetRoot"));
}
} else {
// It already has a happy context
// BUGBUG: What if this is a crusty old out of date
// DeviceEntry from before a disconnect? isn't this our big chance
// to look for and swap in a better one?
Status = STATUS_SUCCESS;
}
}
else {
// Check if this is a smartcard subsystem request
if (_stricmp((CHAR *)DeviceDosName, (CHAR *)DR_SMARTCARD_SUBSYSTEM) != 0) {
TRC_NRM((TB, "Unrecognized VNetRoot"));
Status = STATUS_BAD_NETWORK_NAME;
}
else {
Status = DrCreateSession(SessionId, pVNetRoot, Session);
if (Status == STATUS_SUCCESS) {
Status = DrCreateSCardDevice(Session, pVNetRoot, Device);
}
}
}
EXIT_POINT:
CreateNetRootContext->NetRootStatus = STATUS_SUCCESS;
CreateNetRootContext->VirtualNetRootStatus = Status;
CreateNetRootContext->Callback(CreateNetRootContext);
ASSERT((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) &&
(NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL));
return STATUS_PENDING;
}
NTSTATUS
DrFinalizeVNetRoot(
IN OUT PMRX_V_NET_ROOT pVirtualNetRoot,
IN PBOOLEAN ForceDisconnect
)
{
DrDevice *Device = (DrDevice *)pVirtualNetRoot->Context;
BEGIN_FN("DrFinalizeVNetRoot");
if (Device != NULL) {
TRC_NRM((TB, "Releasing device entry in FinalizeNetRoot "
"Context"));
#if DBG
Device->_VNetRootFinalized = TRUE;
#endif
Device->Release();
pVirtualNetRoot->Context = NULL;
}
return STATUS_SUCCESS;
}