2078 lines
52 KiB
C
2078 lines
52 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991-1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
wsdevice.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the support routines for the APIs that call
|
|||
|
into the redirector or the datagram receiver.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Rita Wong (ritaw) 20-Feb-1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "wsutil.h"
|
|||
|
#include "wsconfig.h"
|
|||
|
#include "wsdevice.h"
|
|||
|
#include "wsbind.h"
|
|||
|
#include <lmerrlog.h> // Eventlog message IDs
|
|||
|
#include "winreg.h" // registry API's
|
|||
|
#include <prefix.h> // PREFIX_ equates.
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Buffer allocation size for enumeration output buffer.
|
|||
|
//
|
|||
|
#define INITIAL_ALLOCATION_SIZE 4096 // First attempt size
|
|||
|
#define FUDGE_FACTOR_SIZE 1024 // Second try TotalBytesNeeded
|
|||
|
// plus this amount
|
|||
|
#define CSC_WAIT_TIME 15 * 1000 // give agent 15 seconds to stop CSC
|
|||
|
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
// //
|
|||
|
// Local Function Prototypes //
|
|||
|
// //
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
|
|||
|
STATIC
|
|||
|
NET_API_STATUS
|
|||
|
WsOpenRedirector(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
STATIC
|
|||
|
NET_API_STATUS
|
|||
|
WsOpenDgReceiver (
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
HANDLE
|
|||
|
CreateNamedEvent(
|
|||
|
LPWSTR lpwEventName
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
AgentIsAlive(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
// //
|
|||
|
// Global variables //
|
|||
|
// //
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
|
|||
|
//
|
|||
|
// Handle to the Redirector FSD
|
|||
|
//
|
|||
|
HANDLE WsRedirDeviceHandle = NULL;
|
|||
|
HANDLE WsRedirAsyncDeviceHandle = NULL;
|
|||
|
|
|||
|
BOOLEAN LoadedMRxSmbInsteadOfRdr = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Handle to the Datagram Receiver DD
|
|||
|
//
|
|||
|
HANDLE WsDgReceiverDeviceHandle = NULL;
|
|||
|
HANDLE WsDgrecAsyncDeviceHandle = NULL;
|
|||
|
|
|||
|
HANDLE heventWkssvcToAgentStart = NULL;
|
|||
|
HANDLE heventWkssvcToAgentStop = NULL;
|
|||
|
HANDLE heventAgentToWkssvc = NULL;
|
|||
|
|
|||
|
BOOL vfRedirStarted = FALSE;
|
|||
|
|
|||
|
static WCHAR wszWkssvcToAgentStartEvent[] = L"WkssvcToAgentStartEvent";
|
|||
|
static WCHAR wszWkssvcToAgentStopEvent[] = L"WkssvcToAgentStopEvent";
|
|||
|
static WCHAR wszAgentToWkssvcEvent[] = L"AgentToWkssvcEvent";
|
|||
|
static WCHAR wzAgentExistsEvent[] = L"AgentExistsEvent"; // used to detect if agent exists
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsDeviceControlGetInfo(
|
|||
|
IN DDTYPE DeviceDriverType,
|
|||
|
IN HANDLE FileHandle,
|
|||
|
IN ULONG DeviceControlCode,
|
|||
|
IN PVOID RequestPacket,
|
|||
|
IN ULONG RequestPacketLength,
|
|||
|
OUT LPBYTE *OutputBuffer,
|
|||
|
IN ULONG PreferedMaximumLength,
|
|||
|
IN ULONG BufferHintSize,
|
|||
|
OUT PULONG_PTR Information OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function allocates the buffer and fill it with the information
|
|||
|
that is retrieved from the redirector or datagram receiver.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceDriverType - Supplies the value which indicates whether to call
|
|||
|
the redirector or the datagram receiver.
|
|||
|
|
|||
|
FileHandle - Supplies a handle to the file or device of which to get
|
|||
|
information about.
|
|||
|
|
|||
|
DeviceControlCode - Supplies the NtFsControlFile or NtIoDeviceControlFile
|
|||
|
function control code.
|
|||
|
|
|||
|
RequestPacket - Supplies a pointer to the device request packet.
|
|||
|
|
|||
|
RrequestPacketLength - Supplies the length of the device request packet.
|
|||
|
|
|||
|
OutputBuffer - Returns a pointer to the buffer allocated by this routine
|
|||
|
which contains the use information requested. This pointer is set to
|
|||
|
NULL if return code is not NERR_Success.
|
|||
|
|
|||
|
PreferedMaximumLength - Supplies the number of bytes of information to
|
|||
|
return in the buffer. If this value is MAXULONG, we will try to
|
|||
|
return all available information if there is enough memory resource.
|
|||
|
|
|||
|
BufferHintSize - Supplies the hint size of the output buffer so that the
|
|||
|
memory allocated for the initial buffer will most likely be large
|
|||
|
enough to hold all requested data.
|
|||
|
|
|||
|
Information - Returns the information code from the NtFsControlFile or
|
|||
|
NtIoDeviceControlFile call.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
DWORD OutputBufferLength;
|
|||
|
DWORD TotalBytesNeeded = 1;
|
|||
|
ULONG OriginalResumeKey;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If PreferedMaximumLength is MAXULONG, then we are supposed to get all
|
|||
|
// the information, regardless of size. Allocate the output buffer of a
|
|||
|
// reasonable size and try to use it. If this fails, the Redirector FSD
|
|||
|
// will say how much we need to allocate.
|
|||
|
//
|
|||
|
if (PreferedMaximumLength == MAXULONG) {
|
|||
|
OutputBufferLength = (BufferHintSize) ?
|
|||
|
BufferHintSize :
|
|||
|
INITIAL_ALLOCATION_SIZE;
|
|||
|
}
|
|||
|
else {
|
|||
|
OutputBufferLength = PreferedMaximumLength;
|
|||
|
}
|
|||
|
|
|||
|
OutputBufferLength = ROUND_UP_COUNT(OutputBufferLength, ALIGN_WCHAR);
|
|||
|
|
|||
|
if ((*OutputBuffer = MIDL_user_allocate(OutputBufferLength)) == NULL) {
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
RtlZeroMemory((PVOID) *OutputBuffer, OutputBufferLength);
|
|||
|
|
|||
|
if (DeviceDriverType == Redirector) {
|
|||
|
PLMR_REQUEST_PACKET Rrp = (PLMR_REQUEST_PACKET) RequestPacket;
|
|||
|
|
|||
|
OriginalResumeKey = Rrp->Parameters.Get.ResumeHandle;
|
|||
|
|
|||
|
//
|
|||
|
// Make the request of the Redirector
|
|||
|
//
|
|||
|
|
|||
|
status = WsRedirFsControl(
|
|||
|
FileHandle,
|
|||
|
DeviceControlCode,
|
|||
|
Rrp,
|
|||
|
RequestPacketLength,
|
|||
|
*OutputBuffer,
|
|||
|
OutputBufferLength,
|
|||
|
Information
|
|||
|
);
|
|||
|
|
|||
|
if (status == ERROR_MORE_DATA) {
|
|||
|
TotalBytesNeeded = Rrp->Parameters.Get.TotalBytesNeeded;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else {
|
|||
|
PLMDR_REQUEST_PACKET Drrp = (PLMDR_REQUEST_PACKET) RequestPacket;
|
|||
|
|
|||
|
OriginalResumeKey = Drrp->Parameters.EnumerateNames.ResumeHandle;
|
|||
|
|
|||
|
//
|
|||
|
// Make the request of the Datagram Receiver
|
|||
|
//
|
|||
|
status = WsDgReceiverIoControl(
|
|||
|
FileHandle,
|
|||
|
DeviceControlCode,
|
|||
|
Drrp,
|
|||
|
RequestPacketLength,
|
|||
|
*OutputBuffer,
|
|||
|
OutputBufferLength,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (status == ERROR_MORE_DATA) {
|
|||
|
|
|||
|
NetpAssert(
|
|||
|
FIELD_OFFSET(
|
|||
|
LMDR_REQUEST_PACKET,
|
|||
|
Parameters.EnumerateNames.TotalBytesNeeded
|
|||
|
) ==
|
|||
|
FIELD_OFFSET(
|
|||
|
LMDR_REQUEST_PACKET,
|
|||
|
Parameters.EnumerateServers.TotalBytesNeeded
|
|||
|
)
|
|||
|
);
|
|||
|
|
|||
|
TotalBytesNeeded = Drrp->Parameters.EnumerateNames.TotalBytesNeeded;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((TotalBytesNeeded > OutputBufferLength) &&
|
|||
|
(PreferedMaximumLength == MAXULONG)) {
|
|||
|
|
|||
|
//
|
|||
|
// Initial output buffer allocated was too small and we need to return
|
|||
|
// all data. First free the output buffer before allocating the
|
|||
|
// required size plus a fudge factor just in case the amount of data
|
|||
|
// grew.
|
|||
|
//
|
|||
|
|
|||
|
MIDL_user_free(*OutputBuffer);
|
|||
|
|
|||
|
OutputBufferLength =
|
|||
|
ROUND_UP_COUNT((TotalBytesNeeded + FUDGE_FACTOR_SIZE),
|
|||
|
ALIGN_WCHAR);
|
|||
|
|
|||
|
if ((*OutputBuffer = MIDL_user_allocate(OutputBufferLength)) == NULL) {
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
RtlZeroMemory((PVOID) *OutputBuffer, OutputBufferLength);
|
|||
|
|
|||
|
//
|
|||
|
// Try again to get the information from the redirector or datagram
|
|||
|
// receiver
|
|||
|
//
|
|||
|
if (DeviceDriverType == Redirector) {
|
|||
|
PLMR_REQUEST_PACKET Rrp = (PLMR_REQUEST_PACKET) RequestPacket;
|
|||
|
|
|||
|
Rrp->Parameters.Get.ResumeHandle = OriginalResumeKey;
|
|||
|
|
|||
|
//
|
|||
|
// Make the request of the Redirector
|
|||
|
//
|
|||
|
status = WsRedirFsControl(
|
|||
|
FileHandle,
|
|||
|
DeviceControlCode,
|
|||
|
Rrp,
|
|||
|
RequestPacketLength,
|
|||
|
*OutputBuffer,
|
|||
|
OutputBufferLength,
|
|||
|
Information
|
|||
|
);
|
|||
|
}
|
|||
|
else {
|
|||
|
PLMDR_REQUEST_PACKET Drrp = (PLMDR_REQUEST_PACKET) RequestPacket;
|
|||
|
|
|||
|
NetpAssert(
|
|||
|
FIELD_OFFSET(
|
|||
|
LMDR_REQUEST_PACKET,
|
|||
|
Parameters.EnumerateNames.ResumeHandle
|
|||
|
) ==
|
|||
|
FIELD_OFFSET(
|
|||
|
LMDR_REQUEST_PACKET,
|
|||
|
Parameters.EnumerateServers.ResumeHandle
|
|||
|
)
|
|||
|
);
|
|||
|
|
|||
|
Drrp->Parameters.EnumerateNames.ResumeHandle = OriginalResumeKey;
|
|||
|
|
|||
|
//
|
|||
|
// Make the request of the Datagram Receiver
|
|||
|
//
|
|||
|
|
|||
|
status = WsDgReceiverIoControl(
|
|||
|
FileHandle,
|
|||
|
DeviceControlCode,
|
|||
|
Drrp,
|
|||
|
RequestPacketLength,
|
|||
|
*OutputBuffer,
|
|||
|
OutputBufferLength,
|
|||
|
NULL
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If not successful in getting any data, or if the caller asked for
|
|||
|
// all available data with PreferedMaximumLength == MAXULONG and
|
|||
|
// our buffer overflowed, free the output buffer and set its pointer
|
|||
|
// to NULL.
|
|||
|
//
|
|||
|
if ((status != NERR_Success && status != ERROR_MORE_DATA) ||
|
|||
|
(TotalBytesNeeded == 0) ||
|
|||
|
(PreferedMaximumLength == MAXULONG && status == ERROR_MORE_DATA)) {
|
|||
|
|
|||
|
MIDL_user_free(*OutputBuffer);
|
|||
|
*OutputBuffer = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// PreferedMaximumLength == MAXULONG and buffer overflowed means
|
|||
|
// we do not have enough memory to satisfy the request.
|
|||
|
//
|
|||
|
if (status == ERROR_MORE_DATA) {
|
|||
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsInitializeRedirector(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine opens the NT LAN Man redirector. It then reads in
|
|||
|
the configuration information and initializes to redirector.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
|
|||
|
|
|||
|
status = WsLoadRedirector();
|
|||
|
|
|||
|
if (status != NERR_Success && status != ERROR_SERVICE_ALREADY_RUNNING) {
|
|||
|
DbgPrint("WKSSVC Load redirector returned %lx\n", status);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Open redirector FSD to get handle to it
|
|||
|
//
|
|||
|
|
|||
|
if ((status = WsOpenRedirector()) != NERR_Success) {
|
|||
|
DbgPrint("WKSSVC Open redirector returned %lx\n", status);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
// if ((status = WsLoadDriver(L"DGRcvr")) != NERR_Success) {
|
|||
|
// return status;
|
|||
|
// }
|
|||
|
|
|||
|
//
|
|||
|
// Open datagram receiver FSD to get handle to it.
|
|||
|
//
|
|||
|
if ((status = WsOpenDgReceiver()) != NERR_Success) {
|
|||
|
DbgPrint("WKSSVC Open datagram receiver returned %lx\n", status);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Load redirector and datagram receiver configuration
|
|||
|
//
|
|||
|
if ((status = WsGetWorkstationConfiguration()) != NERR_Success) {
|
|||
|
|
|||
|
DbgPrint("WKSSVC Get workstation configuration returned %lx\n", status);
|
|||
|
DbgPrint("WKSSVC Shut down the redirector\n");
|
|||
|
|
|||
|
(void) WsShutdownRedirector();
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
IF_DEBUG(START) {
|
|||
|
DbgPrint("WKSSVC Get workstation configuration returned %lx\n", status);
|
|||
|
}
|
|||
|
|
|||
|
return NERR_Success;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
STATIC
|
|||
|
NET_API_STATUS
|
|||
|
WsOpenRedirector(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine opens the NT LAN Man redirector FSD.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS ntstatus;
|
|||
|
UNICODE_STRING DeviceName;
|
|||
|
IO_STATUS_BLOCK IoStatusBlock;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
|
|||
|
//
|
|||
|
// Open the redirector device.
|
|||
|
//
|
|||
|
RtlInitUnicodeString(&DeviceName,DD_NFS_DEVICE_NAME_U);
|
|||
|
|
|||
|
InitializeObjectAttributes(
|
|||
|
&ObjectAttributes,
|
|||
|
&DeviceName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
ntstatus = NtOpenFile(
|
|||
|
&WsRedirDeviceHandle,
|
|||
|
SYNCHRONIZE,
|
|||
|
&ObjectAttributes,
|
|||
|
&IoStatusBlock,
|
|||
|
FILE_SHARE_VALID_FLAGS,
|
|||
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(ntstatus)) {
|
|||
|
ntstatus = IoStatusBlock.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (! NT_SUCCESS(ntstatus)) {
|
|||
|
NetpKdPrint(("[Wksta] NtOpenFile redirector failed: 0x%08lx\n",
|
|||
|
ntstatus));
|
|||
|
WsRedirDeviceHandle = NULL;
|
|||
|
return NetpNtStatusToApiStatus( ntstatus);
|
|||
|
}
|
|||
|
|
|||
|
ntstatus = NtOpenFile(
|
|||
|
&WsRedirAsyncDeviceHandle,
|
|||
|
FILE_READ_DATA | FILE_WRITE_DATA,
|
|||
|
&ObjectAttributes,
|
|||
|
&IoStatusBlock,
|
|||
|
FILE_SHARE_VALID_FLAGS,
|
|||
|
0L
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(ntstatus)) {
|
|||
|
ntstatus = IoStatusBlock.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (! NT_SUCCESS(ntstatus)) {
|
|||
|
NetpKdPrint(("[Wksta] NtOpenFile redirector ASYNC failed: 0x%08lx\n",
|
|||
|
ntstatus));
|
|||
|
WsRedirAsyncDeviceHandle = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return NetpNtStatusToApiStatus(ntstatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
STATIC
|
|||
|
NET_API_STATUS
|
|||
|
WsOpenDgReceiver(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine opens the NT LAN Man Datagram Receiver driver.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS ntstatus;
|
|||
|
UNICODE_STRING DeviceName;
|
|||
|
IO_STATUS_BLOCK IoStatusBlock;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
|
|||
|
RtlInitUnicodeString( &DeviceName, DD_BROWSER_DEVICE_NAME_U);
|
|||
|
|
|||
|
InitializeObjectAttributes(
|
|||
|
&ObjectAttributes,
|
|||
|
&DeviceName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (WsDgReceiverDeviceHandle == NULL) {
|
|||
|
//
|
|||
|
// Open the BOSWER device. The check is based on the fact that Services process
|
|||
|
// does not actually unload the driver when the service is stopped.
|
|||
|
//
|
|||
|
|
|||
|
ntstatus = NtOpenFile(
|
|||
|
&WsDgReceiverDeviceHandle,
|
|||
|
SYNCHRONIZE,
|
|||
|
&ObjectAttributes,
|
|||
|
&IoStatusBlock,
|
|||
|
FILE_SHARE_VALID_FLAGS,
|
|||
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(ntstatus)) {
|
|||
|
ntstatus = IoStatusBlock.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (! NT_SUCCESS(ntstatus)) {
|
|||
|
NetpKdPrint(("[Wksta] NtOpenFile datagram receiver failed: 0x%08lx\n",
|
|||
|
ntstatus));
|
|||
|
|
|||
|
WsDgReceiverDeviceHandle = NULL;
|
|||
|
return NetpNtStatusToApiStatus(ntstatus);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ntstatus = NtOpenFile(
|
|||
|
&WsDgrecAsyncDeviceHandle,
|
|||
|
FILE_READ_DATA | FILE_WRITE_DATA,
|
|||
|
&ObjectAttributes,
|
|||
|
&IoStatusBlock,
|
|||
|
FILE_SHARE_VALID_FLAGS,
|
|||
|
0L
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(ntstatus)) {
|
|||
|
ntstatus = IoStatusBlock.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (! NT_SUCCESS(ntstatus)) {
|
|||
|
NetpKdPrint(("[Wksta] NtOpenFile datagram receiver ASYNC failed: 0x%08lx\n",
|
|||
|
ntstatus));
|
|||
|
|
|||
|
WsDgrecAsyncDeviceHandle = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return NetpNtStatusToApiStatus(ntstatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsUnloadDriver(
|
|||
|
IN LPWSTR DriverNameString
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG Privileges[1];
|
|||
|
LPWSTR DriverRegistryName;
|
|||
|
UNICODE_STRING DriverRegistryString;
|
|||
|
NET_API_STATUS Status;
|
|||
|
NTSTATUS ntstatus;
|
|||
|
|
|||
|
|
|||
|
DriverRegistryName = (LPWSTR) LocalAlloc(
|
|||
|
LMEM_FIXED,
|
|||
|
(UINT) (sizeof(SERVICE_REGISTRY_KEY) +
|
|||
|
(wcslen(DriverNameString) *
|
|||
|
sizeof(WCHAR)))
|
|||
|
);
|
|||
|
|
|||
|
if (DriverRegistryName == NULL) {
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Privileges[0] = SE_LOAD_DRIVER_PRIVILEGE;
|
|||
|
|
|||
|
Status = NetpGetPrivilege(1, Privileges);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
LocalFree(DriverRegistryName);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
wcscpy(DriverRegistryName, SERVICE_REGISTRY_KEY);
|
|||
|
wcscat(DriverRegistryName, DriverNameString);
|
|||
|
|
|||
|
RtlInitUnicodeString(&DriverRegistryString, DriverRegistryName);
|
|||
|
|
|||
|
ntstatus = NtUnloadDriver(&DriverRegistryString);
|
|||
|
|
|||
|
LocalFree(DriverRegistryName);
|
|||
|
|
|||
|
NetpReleasePrivilege();
|
|||
|
|
|||
|
return(WsMapStatus(ntstatus));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsLoadDriver(
|
|||
|
IN LPWSTR DriverNameString
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG Privileges[1];
|
|||
|
LPWSTR DriverRegistryName;
|
|||
|
UNICODE_STRING DriverRegistryString;
|
|||
|
NET_API_STATUS Status;
|
|||
|
NTSTATUS ntstatus;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DriverRegistryName = (LPWSTR) LocalAlloc(
|
|||
|
LMEM_FIXED,
|
|||
|
(UINT) (sizeof(SERVICE_REGISTRY_KEY) +
|
|||
|
(wcslen(DriverNameString) *
|
|||
|
sizeof(WCHAR)))
|
|||
|
);
|
|||
|
|
|||
|
if (DriverRegistryName == NULL) {
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
Privileges[0] = SE_LOAD_DRIVER_PRIVILEGE;
|
|||
|
|
|||
|
Status = NetpGetPrivilege(1, Privileges);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
LocalFree(DriverRegistryName);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
wcscpy(DriverRegistryName, SERVICE_REGISTRY_KEY);
|
|||
|
wcscat(DriverRegistryName, DriverNameString);
|
|||
|
|
|||
|
RtlInitUnicodeString(&DriverRegistryString, DriverRegistryName);
|
|||
|
|
|||
|
ntstatus = NtLoadDriver(&DriverRegistryString);
|
|||
|
|
|||
|
NetpReleasePrivilege();
|
|||
|
|
|||
|
LocalFree(DriverRegistryName);
|
|||
|
|
|||
|
if (ntstatus != STATUS_SUCCESS && ntstatus != STATUS_IMAGE_ALREADY_LOADED) {
|
|||
|
|
|||
|
LPWSTR subString[1];
|
|||
|
|
|||
|
|
|||
|
subString[0] = DriverNameString;
|
|||
|
|
|||
|
WsLogEvent(
|
|||
|
NELOG_DriverNotLoaded,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
1,
|
|||
|
subString,
|
|||
|
ntstatus
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
return(WsMapStatus(ntstatus));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsShutdownRedirector(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine close the LAN Man Redirector device.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LMR_REQUEST_PACKET Rrp;
|
|||
|
LMDR_REQUEST_PACKET Drp;
|
|||
|
NET_API_STATUS Status;
|
|||
|
|
|||
|
// tell csc to stop doing stuff
|
|||
|
if ((Status = WsCSCWantToStopRedir()) != ERROR_SUCCESS)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
Rrp.Version = REQUEST_PACKET_VERSION;
|
|||
|
|
|||
|
Status = WsRedirFsControl(
|
|||
|
WsRedirDeviceHandle,
|
|||
|
FSCTL_LMR_STOP,
|
|||
|
&Rrp,
|
|||
|
sizeof(LMR_REQUEST_PACKET),
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
(void) NtClose(WsRedirDeviceHandle);
|
|||
|
WsRedirDeviceHandle = NULL;
|
|||
|
|
|||
|
|
|||
|
if (Status != ERROR_REDIRECTOR_HAS_OPEN_HANDLES) {
|
|||
|
//
|
|||
|
// After the workstation has been stopped, we want to unload our
|
|||
|
// dependant drivers (the RDR and BOWSER).
|
|||
|
//
|
|||
|
|
|||
|
if (WsDgReceiverDeviceHandle != NULL) {
|
|||
|
|
|||
|
Drp.Version = LMDR_REQUEST_PACKET_VERSION;
|
|||
|
|
|||
|
(void) WsDgReceiverIoControl(
|
|||
|
WsDgReceiverDeviceHandle,
|
|||
|
IOCTL_LMDR_STOP,
|
|||
|
&Drp,
|
|||
|
sizeof(LMDR_REQUEST_PACKET),
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
(void) NtClose(WsDgReceiverDeviceHandle);
|
|||
|
WsDgReceiverDeviceHandle = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// WsUnloadDriver(L"DGRcvr");
|
|||
|
//
|
|||
|
}
|
|||
|
|
|||
|
WsUnloadRedirector();
|
|||
|
} else {
|
|||
|
NET_API_STATUS TempStatus;
|
|||
|
HKEY hRedirectorKey;
|
|||
|
DWORD FinalStatus;
|
|||
|
|
|||
|
TempStatus = RegOpenKeyEx(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
MRXSMB_REGISTRY_KEY,
|
|||
|
0,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
&hRedirectorKey);
|
|||
|
|
|||
|
if (TempStatus == ERROR_SUCCESS) {
|
|||
|
// if this is a controlled shutdown and the driver could not be
|
|||
|
// unloaded mark the status in the registry for resumption
|
|||
|
|
|||
|
FinalStatus = ERROR_SUCCESS;
|
|||
|
TempStatus = RegSetValueEx(
|
|||
|
hRedirectorKey,
|
|||
|
LAST_LOAD_STATUS,
|
|||
|
0,
|
|||
|
REG_DWORD,
|
|||
|
(PCHAR)&FinalStatus,
|
|||
|
sizeof(DWORD));
|
|||
|
|
|||
|
if (TempStatus == ERROR_SUCCESS) {
|
|||
|
NetpKdPrint((PREFIX_WKSTA "New RDR will be loaded on restart\n"));
|
|||
|
}
|
|||
|
|
|||
|
RegCloseKey(hRedirectorKey);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (Status != NERR_Success)
|
|||
|
{
|
|||
|
// NetpAssert(vfRedirStarted == 0);
|
|||
|
|
|||
|
WsCSCReportStartRedir();
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsRedirFsControl(
|
|||
|
IN HANDLE FileHandle,
|
|||
|
IN ULONG RedirControlCode,
|
|||
|
IN PLMR_REQUEST_PACKET Rrp,
|
|||
|
IN ULONG RrpLength,
|
|||
|
IN PVOID SecondBuffer OPTIONAL,
|
|||
|
IN ULONG SecondBufferLength,
|
|||
|
OUT PULONG_PTR Information OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
FileHandle - Supplies a handle to the file or device on which the service
|
|||
|
is being performed.
|
|||
|
|
|||
|
RedirControlCode - Supplies the NtFsControlFile function code given to
|
|||
|
the redirector.
|
|||
|
|
|||
|
Rrp - Supplies the redirector request packet.
|
|||
|
|
|||
|
RrpLength - Supplies the length of the redirector request packet.
|
|||
|
|
|||
|
SecondBuffer - Supplies the second buffer in call to NtFsControlFile.
|
|||
|
|
|||
|
SecondBufferLength - Supplies the length of the second buffer.
|
|||
|
|
|||
|
Information - Returns the information field of the I/O status block.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS ntstatus;
|
|||
|
IO_STATUS_BLOCK IoStatusBlock;
|
|||
|
|
|||
|
//
|
|||
|
// Send the request to the Redirector FSD.
|
|||
|
//
|
|||
|
ntstatus = NtFsControlFile(
|
|||
|
FileHandle,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&IoStatusBlock,
|
|||
|
RedirControlCode,
|
|||
|
Rrp,
|
|||
|
RrpLength,
|
|||
|
SecondBuffer,
|
|||
|
SecondBufferLength
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(ntstatus)) {
|
|||
|
ntstatus = IoStatusBlock.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(Information)) {
|
|||
|
*Information = IoStatusBlock.Information;
|
|||
|
}
|
|||
|
|
|||
|
IF_DEBUG(UTIL) {
|
|||
|
if (! NT_SUCCESS(ntstatus)) {
|
|||
|
NetpKdPrint(("[Wksta] fsctl to redir returns %08lx\n", ntstatus));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return WsMapStatus(ntstatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsDgReceiverIoControl(
|
|||
|
IN HANDLE FileHandle,
|
|||
|
IN ULONG DgReceiverControlCode,
|
|||
|
IN PLMDR_REQUEST_PACKET Drp,
|
|||
|
IN ULONG DrpSize,
|
|||
|
IN PVOID SecondBuffer OPTIONAL,
|
|||
|
IN ULONG SecondBufferLength,
|
|||
|
OUT PULONG_PTR Information OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
FileHandle - Supplies a handle to the file or device on which the service
|
|||
|
is being performed.
|
|||
|
|
|||
|
DgReceiverControlCode - Supplies the NtDeviceIoControlFile function code
|
|||
|
given to the datagram receiver.
|
|||
|
|
|||
|
Drp - Supplies the datagram receiver request packet.
|
|||
|
|
|||
|
DrpSize - Supplies the length of the datagram receiver request packet.
|
|||
|
|
|||
|
SecondBuffer - Supplies the second buffer in call to NtDeviceIoControlFile.
|
|||
|
|
|||
|
SecondBufferLength - Supplies the length of the second buffer.
|
|||
|
|
|||
|
Information - Returns the information field of the I/O status block.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS ntstatus;
|
|||
|
IO_STATUS_BLOCK IoStatusBlock;
|
|||
|
|
|||
|
|
|||
|
if (FileHandle == NULL) {
|
|||
|
IF_DEBUG(UTIL) {
|
|||
|
NetpKdPrint(("[Wksta] Datagram receiver not implemented\n"));
|
|||
|
}
|
|||
|
return ERROR_NOT_SUPPORTED;
|
|||
|
}
|
|||
|
|
|||
|
Drp->TransportName.Length = 0;
|
|||
|
#ifdef _CAIRO_
|
|||
|
RtlInitUnicodeString( &Drp->EmulatedDomainName, NULL );
|
|||
|
#endif // _CAIRO_
|
|||
|
|
|||
|
//
|
|||
|
// Send the request to the Datagram Receiver DD.
|
|||
|
//
|
|||
|
ntstatus = NtDeviceIoControlFile(
|
|||
|
FileHandle,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&IoStatusBlock,
|
|||
|
DgReceiverControlCode,
|
|||
|
Drp,
|
|||
|
DrpSize,
|
|||
|
SecondBuffer,
|
|||
|
SecondBufferLength
|
|||
|
);
|
|||
|
|
|||
|
// as our handles are always async, only if the driver returned pending
|
|||
|
// do we copy the status from the iostatusblock
|
|||
|
if (ntstatus==STATUS_PENDING) {
|
|||
|
ntstatus = IoStatusBlock.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(Information)) {
|
|||
|
if (NT_SUCCESS(ntstatus))
|
|||
|
{
|
|||
|
*Information = IoStatusBlock.Information;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
IF_DEBUG(UTIL) {
|
|||
|
if (! NT_SUCCESS(ntstatus)) {
|
|||
|
NetpKdPrint(("[Wksta] fsctl to dgreceiver returns %08lx\n", ntstatus));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ntstatus == STATUS_TIMEOUT) {
|
|||
|
return ERROR_TIMEOUT;
|
|||
|
} else {
|
|||
|
return WsMapStatus(ntstatus);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsAsyncBindTransport(
|
|||
|
IN LPWSTR transportName,
|
|||
|
IN DWORD qualityOfService,
|
|||
|
IN PLIST_ENTRY pHeader
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function async binds the specified transport to the redirector
|
|||
|
and the datagram receiver.
|
|||
|
|
|||
|
NOTE: The transport name length pass to the redirector and
|
|||
|
datagram receiver is the number of bytes.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
transportName - Supplies the name of the transport to bind to.
|
|||
|
|
|||
|
qualityOfService - Supplies a value which specifies the search
|
|||
|
order of the transport with respect to other transports. The
|
|||
|
highest value is searched first.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS ntStatus;
|
|||
|
NET_API_STATUS status;
|
|||
|
DWORD size;
|
|||
|
DWORD redirSize;
|
|||
|
DWORD dgrecSize;
|
|||
|
DWORD nameLength;
|
|||
|
PWS_BIND pBind;
|
|||
|
PWS_BIND_REDIR pBindRedir;
|
|||
|
PWS_BIND_DGREC pBindDgrec;
|
|||
|
DWORD variablePart;
|
|||
|
#ifdef _CAIRO_
|
|||
|
LPBYTE Where;
|
|||
|
#endif // _CAIRO_
|
|||
|
|
|||
|
nameLength = STRLEN( transportName);
|
|||
|
|
|||
|
//
|
|||
|
// Make sure *Size-s are PVOID aligned.
|
|||
|
//
|
|||
|
|
|||
|
variablePart = nameLength * sizeof( WCHAR );
|
|||
|
variablePart = (variablePart + sizeof(PVOID) - 1) & ~(sizeof(PVOID) - 1);
|
|||
|
|
|||
|
//
|
|||
|
// Then add the fixed part to *Size-s.
|
|||
|
//
|
|||
|
|
|||
|
size = sizeof( WS_BIND) + variablePart;
|
|||
|
redirSize = sizeof( WS_BIND_REDIR) + variablePart;
|
|||
|
dgrecSize = sizeof( WS_BIND_DGREC) + variablePart
|
|||
|
#ifdef _CAIRO_
|
|||
|
+ WsInfo.WsPrimaryDomainNameLength * sizeof(WCHAR) + sizeof(WCHAR)
|
|||
|
#endif // _CAIRO_
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
pBind = (PVOID) LocalAlloc(
|
|||
|
LMEM_ZEROINIT,
|
|||
|
(UINT) (size + redirSize + dgrecSize)
|
|||
|
);
|
|||
|
|
|||
|
if ( pBind == NULL) {
|
|||
|
NetpKdPrint(( "[Wksta] Failed to allocate pBind memory\n"));
|
|||
|
return GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
pBind->TransportNameLength = nameLength * sizeof( WCHAR);
|
|||
|
STRCPY( pBind->TransportName, transportName);
|
|||
|
pBind->Redir = pBindRedir = (PWS_BIND_REDIR)( (PCHAR)pBind + size);
|
|||
|
pBind->Dgrec = pBindDgrec = (PWS_BIND_DGREC)( (PCHAR)pBindRedir + redirSize);
|
|||
|
|
|||
|
pBindRedir->EventHandle = INVALID_HANDLE_VALUE;
|
|||
|
pBindRedir->Bound = FALSE;
|
|||
|
pBindRedir->Packet.Version = REQUEST_PACKET_VERSION;
|
|||
|
pBindRedir->Packet.Parameters.Bind.QualityOfService = qualityOfService;
|
|||
|
pBindRedir->Packet.Parameters.Bind.TransportNameLength =
|
|||
|
nameLength * sizeof( WCHAR);
|
|||
|
STRCPY( pBindRedir->Packet.Parameters.Bind.TransportName, transportName);
|
|||
|
|
|||
|
pBindDgrec->EventHandle = INVALID_HANDLE_VALUE;
|
|||
|
pBindDgrec->Bound = FALSE;
|
|||
|
pBindDgrec->Packet.Version = LMDR_REQUEST_PACKET_VERSION;
|
|||
|
pBindDgrec->Packet.Level = 0; // Indicate computername doesn't follow transport name
|
|||
|
pBindDgrec->Packet.Parameters.Bind.TransportNameLength =
|
|||
|
nameLength * sizeof( WCHAR);
|
|||
|
STRCPY( pBindDgrec->Packet.Parameters.Bind.TransportName, transportName);
|
|||
|
|
|||
|
#ifdef _CAIRO_
|
|||
|
Where = ((LPBYTE)&pBindDgrec->Packet.Parameters.Bind.TransportName) +
|
|||
|
pBindDgrec->Packet.Parameters.Bind.TransportNameLength;
|
|||
|
wcscpy( (LPWSTR) Where, WsInfo.WsPrimaryDomainName);
|
|||
|
RtlInitUnicodeString( &pBindDgrec->Packet.EmulatedDomainName, (LPWSTR) Where );
|
|||
|
#endif // _CAIRO_
|
|||
|
|
|||
|
|
|||
|
pBindRedir->EventHandle = CreateEvent(
|
|||
|
NULL,
|
|||
|
TRUE,
|
|||
|
FALSE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ( pBindRedir->EventHandle == NULL) {
|
|||
|
NetpKdPrint(( "[Wksta] Failed to allocate event handle\n"));
|
|||
|
status = GetLastError();
|
|||
|
goto tail_exit;
|
|||
|
}
|
|||
|
|
|||
|
ntStatus = NtFsControlFile(
|
|||
|
WsRedirAsyncDeviceHandle,
|
|||
|
pBindRedir->EventHandle,
|
|||
|
NULL, // apc routine
|
|||
|
NULL, // apc context
|
|||
|
&pBindRedir->IoStatusBlock,
|
|||
|
FSCTL_LMR_BIND_TO_TRANSPORT, // control code
|
|||
|
&pBindRedir->Packet,
|
|||
|
sizeof( LMR_REQUEST_PACKET) +
|
|||
|
pBindRedir->Packet.Parameters.Bind.TransportNameLength,
|
|||
|
NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
|
|||
|
if ( ntStatus != STATUS_PENDING) {
|
|||
|
CloseHandle( pBindRedir->EventHandle);
|
|||
|
pBindRedir->EventHandle = INVALID_HANDLE_VALUE;
|
|||
|
pBindRedir->Bound = NT_SUCCESS( ntStatus );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
pBindDgrec->EventHandle = CreateEvent(
|
|||
|
NULL,
|
|||
|
TRUE,
|
|||
|
FALSE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ( pBindDgrec->EventHandle == NULL) {
|
|||
|
status = GetLastError();
|
|||
|
goto tail_exit;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef RDR_PNP_POWER
|
|||
|
ntStatus = STATUS_SUCCESS;
|
|||
|
#else
|
|||
|
ntStatus = NtDeviceIoControlFile(
|
|||
|
WsDgrecAsyncDeviceHandle,
|
|||
|
pBindDgrec->EventHandle,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&pBindDgrec->IoStatusBlock,
|
|||
|
IOCTL_LMDR_BIND_TO_TRANSPORT,
|
|||
|
&pBindDgrec->Packet,
|
|||
|
dgrecSize - FIELD_OFFSET( WS_BIND_DGREC, Packet ),
|
|||
|
NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
#endif
|
|||
|
|
|||
|
if ( ntStatus != STATUS_PENDING) {
|
|||
|
CloseHandle( pBindDgrec->EventHandle);
|
|||
|
pBindDgrec->EventHandle = INVALID_HANDLE_VALUE;
|
|||
|
pBindDgrec->Bound = NT_SUCCESS( ntStatus );
|
|||
|
}
|
|||
|
|
|||
|
tail_exit:
|
|||
|
InsertTailList( pHeader, &pBind->ListEntry);
|
|||
|
return NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsBindTransport(
|
|||
|
IN LPTSTR TransportName,
|
|||
|
IN DWORD QualityOfService,
|
|||
|
OUT LPDWORD ErrorParameter OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function binds the specified transport to the redirector
|
|||
|
and the datagram receiver.
|
|||
|
|
|||
|
NOTE: The transport name length pass to the redirector and
|
|||
|
datagram receiver is the number of bytes.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TransportName - Supplies the name of the transport to bind to.
|
|||
|
|
|||
|
QualityOfService - Supplies a value which specifies the search
|
|||
|
order of the transport with respect to other transports. The
|
|||
|
highest value is searched first.
|
|||
|
|
|||
|
ErrorParameter - Returns the identifier to the invalid parameter if
|
|||
|
this function returns ERROR_INVALID_PARAMETER.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
DWORD RequestPacketSize;
|
|||
|
DWORD TransportNameSize = STRLEN(TransportName) * sizeof(TCHAR);
|
|||
|
|
|||
|
PLMR_REQUEST_PACKET Rrp;
|
|||
|
PLMDR_REQUEST_PACKET Drrp;
|
|||
|
#ifdef _CAIRO_
|
|||
|
LPBYTE Where;
|
|||
|
#endif // _CAIRO_
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Size of request packet buffer
|
|||
|
//
|
|||
|
RequestPacketSize = STRLEN(TransportName) * sizeof(WCHAR) +
|
|||
|
#ifdef _CAIRO_
|
|||
|
WsInfo.WsPrimaryDomainNameLength*sizeof(WCHAR)+sizeof(WCHAR)+
|
|||
|
#endif // _CAIRO_
|
|||
|
max(sizeof(LMR_REQUEST_PACKET),
|
|||
|
sizeof(LMDR_REQUEST_PACKET));
|
|||
|
|
|||
|
//
|
|||
|
// Allocate memory for redirector/datagram receiver request packet
|
|||
|
//
|
|||
|
if ((Rrp = (PVOID) LocalAlloc(LMEM_ZEROINIT, (UINT) RequestPacketSize)) == NULL) {
|
|||
|
return GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get redirector to bind to transport
|
|||
|
//
|
|||
|
Rrp->Version = REQUEST_PACKET_VERSION;
|
|||
|
Rrp->Parameters.Bind.QualityOfService = QualityOfService;
|
|||
|
|
|||
|
Rrp->Parameters.Bind.TransportNameLength = TransportNameSize;
|
|||
|
STRCPY(Rrp->Parameters.Bind.TransportName, TransportName);
|
|||
|
|
|||
|
if ((status = WsRedirFsControl(
|
|||
|
WsRedirDeviceHandle,
|
|||
|
FSCTL_LMR_BIND_TO_TRANSPORT,
|
|||
|
Rrp,
|
|||
|
sizeof(LMR_REQUEST_PACKET) +
|
|||
|
Rrp->Parameters.Bind.TransportNameLength,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
)) != NERR_Success) {
|
|||
|
|
|||
|
if (status == ERROR_INVALID_PARAMETER &&
|
|||
|
ARGUMENT_PRESENT(ErrorParameter)) {
|
|||
|
|
|||
|
IF_DEBUG(INFO) {
|
|||
|
NetpKdPrint((
|
|||
|
"[Wksta] NetrWkstaTransportAdd: invalid parameter is %lu\n",
|
|||
|
Rrp->Parameters.Bind.WkstaParameter));
|
|||
|
}
|
|||
|
|
|||
|
*ErrorParameter = Rrp->Parameters.Bind.WkstaParameter;
|
|||
|
}
|
|||
|
|
|||
|
(void) LocalFree(Rrp);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Get dgrec to bind to transport
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Make use of the same request packet buffer as FSCtl to
|
|||
|
// redirector.
|
|||
|
//
|
|||
|
Drrp = (PLMDR_REQUEST_PACKET) Rrp;
|
|||
|
|
|||
|
Drrp->Version = LMDR_REQUEST_PACKET_VERSION;
|
|||
|
|
|||
|
Drrp->Parameters.Bind.TransportNameLength = TransportNameSize;
|
|||
|
STRCPY(Drrp->Parameters.Bind.TransportName, TransportName);
|
|||
|
|
|||
|
#ifdef _CAIRO_
|
|||
|
Where = ((LPBYTE)&Drrp->Parameters.Bind.TransportName) +
|
|||
|
Drrp->Parameters.Bind.TransportNameLength;
|
|||
|
wcscpy( (LPWSTR) Where, WsInfo.WsPrimaryDomainName);
|
|||
|
RtlInitUnicodeString( &Drrp->EmulatedDomainName, (LPWSTR) Where );
|
|||
|
#endif // _CAIRO_
|
|||
|
|
|||
|
status = WsDgReceiverIoControl(
|
|||
|
WsDgReceiverDeviceHandle,
|
|||
|
IOCTL_LMDR_BIND_TO_TRANSPORT,
|
|||
|
Drrp,
|
|||
|
RequestPacketSize,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
(void) LocalFree(Rrp);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
WsUnbindTransport2(
|
|||
|
IN PWS_BIND pBind
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function unbinds the specified transport from the redirector
|
|||
|
and the datagram receiver.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pBind - structure constructed via WsAsyncBindTransport()
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
// NET_API_STATUS status;
|
|||
|
PWS_BIND_REDIR pBindRedir = pBind->Redir;
|
|||
|
PWS_BIND_DGREC pBindDgrec = pBind->Dgrec;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Get redirector to unbind from transport
|
|||
|
//
|
|||
|
|
|||
|
if ( pBindRedir->Bound == TRUE) {
|
|||
|
pBindRedir->Packet.Parameters.Unbind.TransportNameLength
|
|||
|
= pBind->TransportNameLength;
|
|||
|
memcpy(
|
|||
|
pBindRedir->Packet.Parameters.Unbind.TransportName,
|
|||
|
pBind->TransportName,
|
|||
|
pBind->TransportNameLength
|
|||
|
);
|
|||
|
|
|||
|
(VOID)NtFsControlFile(
|
|||
|
WsRedirDeviceHandle,
|
|||
|
NULL,
|
|||
|
NULL, // apc routine
|
|||
|
NULL, // apc context
|
|||
|
&pBindRedir->IoStatusBlock,
|
|||
|
FSCTL_LMR_UNBIND_FROM_TRANSPORT, // control code
|
|||
|
&pBindRedir->Packet,
|
|||
|
sizeof( LMR_REQUEST_PACKET) +
|
|||
|
pBindRedir->Packet.Parameters.Unbind.TransportNameLength,
|
|||
|
NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
pBindRedir->Bound = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get datagram receiver to unbind from transport
|
|||
|
//
|
|||
|
|
|||
|
if ( pBindDgrec->Bound == TRUE) {
|
|||
|
|
|||
|
pBindDgrec->Packet.Parameters.Unbind.TransportNameLength
|
|||
|
= pBind->TransportNameLength;
|
|||
|
memcpy(
|
|||
|
pBindDgrec->Packet.Parameters.Unbind.TransportName,
|
|||
|
pBind->TransportName,
|
|||
|
pBind->TransportNameLength
|
|||
|
);
|
|||
|
|
|||
|
(VOID)NtDeviceIoControlFile(
|
|||
|
WsDgReceiverDeviceHandle,
|
|||
|
NULL,
|
|||
|
NULL, // apc routine
|
|||
|
NULL, // apc context
|
|||
|
&pBindDgrec->IoStatusBlock,
|
|||
|
FSCTL_LMR_UNBIND_FROM_TRANSPORT, // control code
|
|||
|
&pBindDgrec->Packet,
|
|||
|
sizeof( LMR_REQUEST_PACKET) +
|
|||
|
pBindDgrec->Packet.Parameters.Unbind.TransportNameLength,
|
|||
|
NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
pBindDgrec->Bound = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsUnbindTransport(
|
|||
|
IN LPTSTR TransportName,
|
|||
|
IN DWORD ForceLevel
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function unbinds the specified transport from the redirector
|
|||
|
and the datagram receiver.
|
|||
|
|
|||
|
NOTE: The transport name length pass to the redirector and
|
|||
|
datagram receiver is the number of bytes.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TransportName - Supplies the name of the transport to bind to.
|
|||
|
|
|||
|
ForceLevel - Supplies the force level to delete active connections
|
|||
|
on the specified transport.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
DWORD RequestPacketSize;
|
|||
|
DWORD TransportNameSize = STRLEN(TransportName) * sizeof(TCHAR);
|
|||
|
|
|||
|
PLMR_REQUEST_PACKET Rrp;
|
|||
|
PLMDR_REQUEST_PACKET Drrp;
|
|||
|
#ifdef _CAIRO_
|
|||
|
LPBYTE Where;
|
|||
|
#endif // _CAIRO_
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Size of request packet buffer
|
|||
|
//
|
|||
|
RequestPacketSize = STRLEN(TransportName) * sizeof(WCHAR) +
|
|||
|
#ifdef _CAIRO_
|
|||
|
WsInfo.WsPrimaryDomainNameLength*sizeof(WCHAR)+sizeof(WCHAR)+
|
|||
|
#endif // _CAIRO_
|
|||
|
max(sizeof(LMR_REQUEST_PACKET),
|
|||
|
sizeof(LMDR_REQUEST_PACKET));
|
|||
|
|
|||
|
//
|
|||
|
// Allocate memory for redirector/datagram receiver request packet
|
|||
|
//
|
|||
|
if ((Rrp = (PVOID) LocalAlloc(LMEM_ZEROINIT, (UINT) RequestPacketSize)) == NULL) {
|
|||
|
return GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Get redirector to unbind from transport
|
|||
|
//
|
|||
|
Rrp->Version = REQUEST_PACKET_VERSION;
|
|||
|
Rrp->Level = ForceLevel;
|
|||
|
|
|||
|
Rrp->Parameters.Unbind.TransportNameLength = TransportNameSize;
|
|||
|
STRCPY(Rrp->Parameters.Unbind.TransportName, TransportName);
|
|||
|
|
|||
|
if ((status = WsRedirFsControl(
|
|||
|
WsRedirDeviceHandle,
|
|||
|
FSCTL_LMR_UNBIND_FROM_TRANSPORT,
|
|||
|
Rrp,
|
|||
|
sizeof(LMR_REQUEST_PACKET) +
|
|||
|
Rrp->Parameters.Unbind.TransportNameLength,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
)) != NERR_Success) {
|
|||
|
(void) LocalFree(Rrp);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get datagram receiver to unbind from transport
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Make use of the same request packet buffer as FSCtl to
|
|||
|
// redirector.
|
|||
|
//
|
|||
|
Drrp = (PLMDR_REQUEST_PACKET) Rrp;
|
|||
|
|
|||
|
Drrp->Version = LMDR_REQUEST_PACKET_VERSION;
|
|||
|
Drrp->Level = ForceLevel;
|
|||
|
|
|||
|
Drrp->Parameters.Unbind.TransportNameLength = TransportNameSize;
|
|||
|
STRCPY(Drrp->Parameters.Unbind.TransportName, TransportName);
|
|||
|
|
|||
|
#ifdef _CAIRO_
|
|||
|
Where = ((LPBYTE)&Drrp->Parameters.Unbind.TransportName) +
|
|||
|
Drrp->Parameters.Unbind.TransportNameLength;
|
|||
|
wcscpy( (LPWSTR) Where, WsInfo.WsPrimaryDomainName);
|
|||
|
RtlInitUnicodeString( &Drrp->EmulatedDomainName, (LPWSTR) Where );
|
|||
|
#endif // _CAIRO_
|
|||
|
|
|||
|
if ((status = WsDgReceiverIoControl(
|
|||
|
WsDgReceiverDeviceHandle,
|
|||
|
IOCTL_LMDR_UNBIND_FROM_TRANSPORT,
|
|||
|
Drrp,
|
|||
|
RequestPacketSize,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
)) != NERR_Success) {
|
|||
|
|
|||
|
// NTRAID-70693-2/6/2000 davey This is a hack until the bowser supports XNS and LOOP.
|
|||
|
|
|||
|
if (status == NERR_UseNotFound) {
|
|||
|
status = NERR_Success;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
(void) LocalFree(Rrp);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsDeleteDomainName(
|
|||
|
IN PLMDR_REQUEST_PACKET Drp,
|
|||
|
IN DWORD DrpSize,
|
|||
|
IN LPTSTR DomainName,
|
|||
|
IN DWORD DomainNameSize
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function deletes a domain name from the datagram receiver for
|
|||
|
the current user. It assumes that enough memory is allocate for the
|
|||
|
request packet that is passed in.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Drp - Pointer to a datagram receiver request packet with the
|
|||
|
request packet version, and name type initialized.
|
|||
|
|
|||
|
DrpSize - Length of datagram receiver request packet in bytes.
|
|||
|
|
|||
|
DomainName - Pointer to the domain name to delete.
|
|||
|
|
|||
|
DomainNameSize - Length of the domain name in bytes.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
Drp->Parameters.AddDelName.DgReceiverNameLength = DomainNameSize;
|
|||
|
|
|||
|
memcpy(
|
|||
|
(LPBYTE) Drp->Parameters.AddDelName.Name,
|
|||
|
(LPBYTE) DomainName,
|
|||
|
DomainNameSize
|
|||
|
);
|
|||
|
|
|||
|
return WsDgReceiverIoControl(
|
|||
|
WsDgReceiverDeviceHandle,
|
|||
|
IOCTL_LMDR_DELETE_NAME,
|
|||
|
Drp,
|
|||
|
DrpSize,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsAddDomainName(
|
|||
|
IN PLMDR_REQUEST_PACKET Drp,
|
|||
|
IN DWORD DrpSize,
|
|||
|
IN LPTSTR DomainName,
|
|||
|
IN DWORD DomainNameSize
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function adds a domain name to the datagram receiver for the
|
|||
|
current user. It assumes that enough memory is allocate for the
|
|||
|
request packet that is passed in.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Drp - Pointer to a datagram receiver request packet with the
|
|||
|
request packet version, and name type initialized.
|
|||
|
|
|||
|
DrpSize - Length of datagram receiver request packet in bytes.
|
|||
|
|
|||
|
DomainName - Pointer to the domain name to delete.
|
|||
|
|
|||
|
DomainNameSize - Length of the domain name in bytes.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
Drp->Parameters.AddDelName.DgReceiverNameLength = DomainNameSize;
|
|||
|
|
|||
|
memcpy(
|
|||
|
(LPBYTE) Drp->Parameters.AddDelName.Name,
|
|||
|
(LPBYTE) DomainName,
|
|||
|
DomainNameSize
|
|||
|
);
|
|||
|
|
|||
|
return WsDgReceiverIoControl(
|
|||
|
WsDgReceiverDeviceHandle,
|
|||
|
IOCTL_LMDR_ADD_NAME,
|
|||
|
Drp,
|
|||
|
DrpSize,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsTryToLoadSmbMiniRedirector(
|
|||
|
VOID
|
|||
|
);
|
|||
|
NET_API_STATUS
|
|||
|
WsLoadRedirector(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine loads rdr.sys or mrxsmb.sys et al depending on whether
|
|||
|
the conditions for loading mrxsmb.sys are met.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
The new redirector consists of two parts -- the RDBSS (redirected drive buffering
|
|||
|
subsystem ) and the corresponding smb mini redirectors. Only the minirdr is loaded here;
|
|||
|
the minirdr loads the RDBSS itself.
|
|||
|
|
|||
|
As a stopgap measure the old redirector is loaded in the event of any problem
|
|||
|
associated with loading the new redirector.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
|
|||
|
status = WsTryToLoadSmbMiniRedirector();
|
|||
|
if ((status != ERROR_SUCCESS) &&
|
|||
|
(status != ERROR_SERVICE_ALREADY_RUNNING)) {
|
|||
|
// Either the new redirector load did not succeed or it does not exist.
|
|||
|
// Load the old redirector.
|
|||
|
|
|||
|
LoadedMRxSmbInsteadOfRdr = FALSE;
|
|||
|
status = WsLoadDriver(REDIRECTOR);
|
|||
|
}
|
|||
|
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
WsUnloadRedirector(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine unloads the drivers that we loaded above.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
DWORD NameLength,NameOffset;
|
|||
|
HKEY hRedirectorKey;
|
|||
|
DWORD FinalStatus;
|
|||
|
|
|||
|
if (!LoadedMRxSmbInsteadOfRdr) {
|
|||
|
WsUnloadDriver(REDIRECTOR);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
status = WsUnloadDriver(SMB_MINIRDR);
|
|||
|
|
|||
|
if (status == ERROR_SUCCESS) {
|
|||
|
WsUnloadDriver(RDBSS);
|
|||
|
}
|
|||
|
|
|||
|
status = RegOpenKeyEx(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
MRXSMB_REGISTRY_KEY,
|
|||
|
0,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
&hRedirectorKey);
|
|||
|
|
|||
|
if (status == ERROR_SUCCESS) {
|
|||
|
// if the unloading was successful, reset the LastLoadStatus so that
|
|||
|
// the new redirector will be loaded on the next attempt as well.
|
|||
|
FinalStatus = ERROR_SUCCESS;
|
|||
|
status = RegSetValueEx(
|
|||
|
hRedirectorKey,
|
|||
|
LAST_LOAD_STATUS,
|
|||
|
0,
|
|||
|
REG_DWORD,
|
|||
|
(PCHAR)&FinalStatus,
|
|||
|
sizeof(DWORD));
|
|||
|
|
|||
|
if (status == ERROR_SUCCESS) {
|
|||
|
NetpKdPrint((PREFIX_WKSTA "New RDR will be loaded on restart\n"));
|
|||
|
}
|
|||
|
|
|||
|
RegCloseKey(hRedirectorKey);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
////////////////////// minirdr stuff
|
|||
|
NET_API_STATUS
|
|||
|
WsTryToLoadSmbMiniRedirector(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine loads rdr.sys or mrxsmb.sys et al depending on whether
|
|||
|
the conditions for loading mrxsmb.sys are met.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
The new redirector consists of two parts -- the RDBSS (redirected drive buffering
|
|||
|
subsystem ) and the corresponding smb mini redirectors. Only the minirdr is loaded here;
|
|||
|
the minirdr loads the RDBSS itself.
|
|||
|
|
|||
|
As a stopgap measure the old redirector is loaded in the event of any problem
|
|||
|
associated with loading the new redirector.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
ULONG Attributes;
|
|||
|
DWORD ValueType;
|
|||
|
DWORD ValueSize;
|
|||
|
DWORD NameLength,NameOffset;
|
|||
|
HKEY hRedirectorKey;
|
|||
|
|
|||
|
DWORD FinalStatus; // Temporary till the new rdr is the default
|
|||
|
DWORD LastLoadStatus;
|
|||
|
|
|||
|
//try to open the minirdr's registry key....if fails GET OUT IMMEDIATELY!!!!
|
|||
|
status = RegOpenKeyEx(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
MRXSMB_REGISTRY_KEY,
|
|||
|
0,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
&hRedirectorKey);
|
|||
|
|
|||
|
if (status != ERROR_SUCCESS) {
|
|||
|
return(status);
|
|||
|
} else {
|
|||
|
status = WsLoadDriver(RDBSS);
|
|||
|
|
|||
|
if ((status == ERROR_SUCCESS) || (status == ERROR_SERVICE_ALREADY_RUNNING)) {
|
|||
|
|
|||
|
status = WsLoadDriver(SMB_MINIRDR);
|
|||
|
|
|||
|
if (status == ERROR_SUCCESS) {
|
|||
|
LoadedMRxSmbInsteadOfRdr = TRUE;
|
|||
|
} else if (status == ERROR_SERVICE_ALREADY_RUNNING) {
|
|||
|
NetpKdPrint((PREFIX_WKSTA "Reactivating Previously Loaded Service\n"));
|
|||
|
LoadedMRxSmbInsteadOfRdr = TRUE;
|
|||
|
status = ERROR_SUCCESS;
|
|||
|
} else {
|
|||
|
// error loading the minirdr
|
|||
|
//WsUnloadDriver(RDBSS);
|
|||
|
NetpKdPrint((PREFIX_WKSTA "Error Loading MRxSmb\n"));
|
|||
|
}
|
|||
|
}
|
|||
|
// NetpKdPrint((PREFIX_WKSTA "New redirector(RDR2) load status %lx\n",status));
|
|||
|
}
|
|||
|
|
|||
|
// Close the handle to the registry key irrespective of the result.
|
|||
|
RegCloseKey(hRedirectorKey);
|
|||
|
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsCSCReportStartRedir(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status = ERROR_SUCCESS;
|
|||
|
DWORD dwError = ERROR_GEN_FAILURE;
|
|||
|
|
|||
|
|
|||
|
// NetpKdPrint(("Wkssvc: Reporting redir start \n"));
|
|||
|
|
|||
|
// ensure that there are named autoreset events
|
|||
|
if (!heventWkssvcToAgentStart)
|
|||
|
{
|
|||
|
NetpAssert(!heventAgentToWkssvc);
|
|||
|
|
|||
|
heventWkssvcToAgentStart = CreateNamedEvent(wszWkssvcToAgentStartEvent);
|
|||
|
|
|||
|
if (!heventWkssvcToAgentStart)
|
|||
|
{
|
|||
|
dwError = GetLastError();
|
|||
|
NetpKdPrint(("Wkssvc: Failed to create heventWkssvcToAgentStart, error = %d\n", dwError));
|
|||
|
goto bailout;
|
|||
|
}
|
|||
|
|
|||
|
heventWkssvcToAgentStop = CreateNamedEvent(wszWkssvcToAgentStopEvent);
|
|||
|
|
|||
|
if (!heventWkssvcToAgentStop)
|
|||
|
{
|
|||
|
dwError = GetLastError();
|
|||
|
NetpKdPrint(("Wkssvc: Failed to create heventWkssvcToAgentStop, error = %d\n", dwError));
|
|||
|
goto bailout;
|
|||
|
}
|
|||
|
|
|||
|
heventAgentToWkssvc = CreateNamedEvent(wszAgentToWkssvcEvent);
|
|||
|
|
|||
|
if (!heventAgentToWkssvc)
|
|||
|
{
|
|||
|
dwError = GetLastError();
|
|||
|
NetpKdPrint(("Wkssvc: Failed to create heventAgentToWkssvc, error = %d\n", dwError));
|
|||
|
goto bailout;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// NetpAssert(!vfRedirStarted);
|
|||
|
|
|||
|
if (!vfRedirStarted)
|
|||
|
{
|
|||
|
SetEvent(heventWkssvcToAgentStart);
|
|||
|
|
|||
|
vfRedirStarted = TRUE;
|
|||
|
|
|||
|
// NetpKdPrint(("Wkssvc: Reported redir start \n"));
|
|||
|
}
|
|||
|
|
|||
|
dwError = ERROR_SUCCESS;
|
|||
|
|
|||
|
bailout:
|
|||
|
if (dwError != ERROR_SUCCESS)
|
|||
|
{
|
|||
|
if (heventWkssvcToAgentStart)
|
|||
|
{
|
|||
|
CloseHandle(heventWkssvcToAgentStart);
|
|||
|
heventWkssvcToAgentStart = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (heventWkssvcToAgentStop)
|
|||
|
{
|
|||
|
CloseHandle(heventWkssvcToAgentStop);
|
|||
|
heventWkssvcToAgentStop = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (heventAgentToWkssvc)
|
|||
|
{
|
|||
|
CloseHandle(heventAgentToWkssvc);
|
|||
|
heventAgentToWkssvc = NULL;
|
|||
|
}
|
|||
|
|
|||
|
NetpKdPrint(("Wkssvc: Failed to report redir start error code=%d\n", dwError));
|
|||
|
}
|
|||
|
|
|||
|
return (dwError);
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsCSCWantToStopRedir(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status = ERROR_SUCCESS;
|
|||
|
DWORD dwError;
|
|||
|
|
|||
|
// NetpKdPrint(("Wkssvc: Asking agent to stop, so the redir can be stopped\n"));
|
|||
|
|
|||
|
if (!vfRedirStarted)
|
|||
|
{
|
|||
|
NetpKdPrint(("Wkssvc: getting a stop without a start\n"));
|
|||
|
return ERROR_GEN_FAILURE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (!heventWkssvcToAgentStop)
|
|||
|
{
|
|||
|
NetpAssert(!heventWkssvcToAgentStart && !heventAgentToWkssvc);
|
|||
|
|
|||
|
NetpKdPrint(("Wkssvc: Need events for redir stop\n"));
|
|||
|
return ERROR_GEN_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
// Bleed the event
|
|||
|
WaitForSingleObject(heventAgentToWkssvc, 0);
|
|||
|
|
|||
|
if (!AgentIsAlive())
|
|||
|
{
|
|||
|
// the agent isn't up
|
|||
|
// no need to issue stop
|
|||
|
NetpKdPrint(("Wkssvc: Agent not alive\n"));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// NetpKdPrint(("Wkssvc: Agent Alive\n"));
|
|||
|
|
|||
|
// agent is up
|
|||
|
|
|||
|
// tell him to stop
|
|||
|
SetEvent(heventWkssvcToAgentStop);
|
|||
|
|
|||
|
// Wait some reasonable time to see if he stops
|
|||
|
dwError = WaitForSingleObject(heventAgentToWkssvc, CSC_WAIT_TIME);
|
|||
|
|
|||
|
if (dwError!=WAIT_OBJECT_0)
|
|||
|
{
|
|||
|
HANDLE hT[2];
|
|||
|
|
|||
|
NetpKdPrint(("Wkssvc: Agent didn't disbale CSC in %d milli-seconds\n", CSC_WAIT_TIME));
|
|||
|
|
|||
|
// let us try to reset our event in a way that we don't just miss the agent
|
|||
|
hT[0] = heventWkssvcToAgentStop;
|
|||
|
hT[1] = heventAgentToWkssvc;
|
|||
|
|
|||
|
dwError = WaitForMultipleObjects(2, hT, FALSE, 0);
|
|||
|
|
|||
|
// if we fired because of 1, then the agent gave us an ack
|
|||
|
// otherwise the stop event would be reset and the agent won't get confused
|
|||
|
|
|||
|
if (dwError == WAIT_OBJECT_0+1)
|
|||
|
{
|
|||
|
// NetpKdPrint(("Wkssvc: Agent disabled CSC\n"));
|
|||
|
vfRedirStarted = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
ResetEvent(heventWkssvcToAgentStop);
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// NetpKdPrint(("Wkssvc: Agent disabled CSC\n"));
|
|||
|
vfRedirStarted = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
HANDLE
|
|||
|
CreateNamedEvent(
|
|||
|
LPWSTR lpwEventName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
lpwEventName Name of the event to create.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HANDLE hevent = NULL;
|
|||
|
|
|||
|
hevent = CreateEvent(NULL, FALSE, FALSE, lpwEventName);
|
|||
|
|
|||
|
return hevent;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
AgentIsAlive(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if agent is alive, FALSE otherwise
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
The named event is created by the agent thread when it comes up.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HANDLE hT;
|
|||
|
BOOL fRet = FALSE;
|
|||
|
|
|||
|
// see whether the agent has already created the event
|
|||
|
hT = OpenEvent(SYNCHRONIZE, FALSE, wzAgentExistsEvent);
|
|||
|
|
|||
|
if (hT != NULL)
|
|||
|
{
|
|||
|
CloseHandle(hT);
|
|||
|
fRet = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
NetpKdPrint(("Wkssvc: Agent error = %d\n", GetLastError()));
|
|||
|
}
|
|||
|
return (fRet);
|
|||
|
}
|