mirror of https://github.com/lianthony/NT4.0
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.
1276 lines
31 KiB
1276 lines
31 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
redir.c
|
|
|
|
Abstract:
|
|
|
|
Redirector thread for USRV.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 20-Oct-1989
|
|
Chuck Lenzmeier (chuckl)
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "usrv.h"
|
|
|
|
//
|
|
// Forward declarations
|
|
//
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
CreateEndpoint (
|
|
IN OUT PDESCRIPTOR Redir,
|
|
IN CLONG RedirNumber,
|
|
IN PSZ DebugName
|
|
);
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
CreateEvents (
|
|
IN OUT PDESCRIPTOR Redir,
|
|
IN PSZ DebugName
|
|
);
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
ExecuteBatchFile(
|
|
IN PSZ Name,
|
|
IN PDESCRIPTOR Redir,
|
|
IN PSZ Prompt
|
|
);
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
ExecuteCommand(
|
|
IN PSZ Command,
|
|
IN PDESCRIPTOR Redir,
|
|
IN PSZ Prompt
|
|
);
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
Negotiate (
|
|
IN OUT PDESCRIPTOR Redir
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
ParseCommand(
|
|
IN PSZ CommandLine,
|
|
OUT PSZ Argv[],
|
|
OUT PSHORT Argc,
|
|
IN SHORT MaxArgc
|
|
);
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
StartAssociate (
|
|
IN HANDLE ConnectionFileHandle,
|
|
IN HANDLE AddressFileHandle,
|
|
IN HANDLE EventHandle,
|
|
IN PIO_STATUS_BLOCK Iosb,
|
|
IN PSZ DebugString
|
|
);
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
StartConnect (
|
|
IN PSTRING RemoteAddress,
|
|
IN PVOID Buffer,
|
|
IN HANDLE FileHandle,
|
|
IN HANDLE EventHandle,
|
|
IN PIO_STATUS_BLOCK Iosb,
|
|
IN PSZ DebugString
|
|
);
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
WaitForAssociate (
|
|
IN PSZ Operation,
|
|
IN PDESCRIPTOR Redir,
|
|
IN UCHAR EventNumber
|
|
);
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
WaitForConnect (
|
|
IN PSZ Operation,
|
|
IN PDESCRIPTOR Redir,
|
|
IN UCHAR EventNumber
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
RedirThreadWrapper(
|
|
IN PVOID Dummy
|
|
)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = RedirThread( (PDESCRIPTOR)Dummy );
|
|
|
|
NtTerminateThread( NtCurrentThread(), status );
|
|
|
|
return status; // shouldn't get here
|
|
|
|
} // RedirThreadWrapper
|
|
|
|
|
|
NTSTATUS
|
|
RedirThread(
|
|
IN PDESCRIPTOR Redir
|
|
)
|
|
|
|
{
|
|
#define MAX_ARGC 20
|
|
|
|
NTSTATUS status;
|
|
UCHAR i;
|
|
STRING remoteAddress;
|
|
CLONG redirNumber;
|
|
CHAR prompt[11];
|
|
|
|
redirNumber = Redir->RedirNumber;
|
|
IF_DEBUG(1) printf( "****Entered redir thread %ld.\n", redirNumber );
|
|
|
|
//
|
|
// Allocate data buffers.
|
|
//
|
|
|
|
for( i = 0; i < NUMBER_OF_EVENTS; i++ ) {
|
|
Redir->Data[i] = malloc( Redir->MaxBufferSize );
|
|
if ( Redir->Data[i] == NULL ) {
|
|
printf( "malloc (redir data buffer) failed\n" );
|
|
DbgBreakPoint( );
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
IF_DEBUG(2) printf( "Redir data buffer address: 0x%lx\n", Redir->Data[i] );
|
|
}
|
|
|
|
Redir->RawBuffer = NULL;
|
|
|
|
//
|
|
// Create redir events.
|
|
//
|
|
|
|
status = CreateEvents(
|
|
Redir,
|
|
"Redir"
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Create endpoint for Redir.
|
|
//
|
|
|
|
status = CreateEndpoint(
|
|
Redir,
|
|
redirNumber,
|
|
"Redir"
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Connect redir to server (must be started after server listen).
|
|
//
|
|
|
|
RtlInitString( &remoteAddress, ServerName+1 ); // skip comma in server name
|
|
IF_DEBUG(2) printf( "Server name \"%Z\"\n", &remoteAddress );
|
|
|
|
status = StartConnect(
|
|
&remoteAddress,
|
|
Redir->Data[0],
|
|
Redir->FileHandle,
|
|
Redir->EventHandle[0],
|
|
&Redir->Iosb[0],
|
|
"Connect"
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
|
|
status = WaitForConnect(
|
|
"Connect",
|
|
Redir,
|
|
0
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
|
|
if ( DefaultNegotiate ) {
|
|
status = Negotiate( Redir );
|
|
if ( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
IF_DEBUG(1) {
|
|
printf( "****Redir thread %ld initialization complete.\n",
|
|
redirNumber );
|
|
}
|
|
|
|
RtlMoveMemory( prompt, "Redir_", 6 );
|
|
prompt[6] = (CHAR)( redirNumber / 10 + '0' );
|
|
prompt[7] = (CHAR)( redirNumber % 10 + '0' );
|
|
prompt[8] = '>';
|
|
prompt[9] = ' ';
|
|
prompt[10] = 0;
|
|
|
|
if ( !NoUsrvInit ) {
|
|
ExecuteBatchFile( "usrvinit", Redir, prompt );
|
|
}
|
|
|
|
ExecuteCommand( NULL, Redir, prompt );
|
|
|
|
printf( "****Redir thread %ld exiting: %X\n",
|
|
redirNumber, STATUS_SUCCESS );
|
|
return STATUS_SUCCESS;
|
|
|
|
} // RedirThread
|
|
|
|
|
|
NTSTATUS
|
|
CreateEndpoint (
|
|
PDESCRIPTOR Redir,
|
|
CLONG RedirNumber,
|
|
PSZ DebugName
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
CHAR transportName[128];
|
|
CHAR redirName[17];
|
|
CLONG baseNameLength;
|
|
STRING nameString;
|
|
UNICODE_STRING unicodeNameString;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
LARGE_INTEGER allocationSize = { 0, 0 };
|
|
CHAR eaBuffer[sizeof(FILE_FULL_EA_INFORMATION) - 1 +
|
|
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
|
sizeof(TA_NETBIOS_ADDRESS)];
|
|
PFILE_FULL_EA_INFORMATION ea;
|
|
CONNECTION_CONTEXT ctx;
|
|
CONNECTION_CONTEXT *pctx;
|
|
|
|
//
|
|
// Create the transport and redir names.
|
|
//
|
|
|
|
baseNameLength = strlen( REDIR_ADDRESS_PART1 );
|
|
RtlMoveMemory(
|
|
transportName,
|
|
REDIR_ADDRESS_PART1,
|
|
baseNameLength
|
|
);
|
|
RtlMoveMemory(
|
|
transportName + baseNameLength,
|
|
Transport,
|
|
strlen( Transport ) + 1
|
|
);
|
|
IF_DEBUG(1) printf( "Using transport name %s\n", transportName );
|
|
|
|
RtlMoveMemory( redirName, "Redir_", 6 );
|
|
redirName[6] = (CHAR)( RedirNumber / 10 + '0' );
|
|
redirName[7] = (CHAR)( RedirNumber % 10 + '0' );
|
|
RtlMoveMemory( redirName+8, " ", 7 );
|
|
redirName[15] = 0;
|
|
redirName[16] = 0;
|
|
|
|
IF_DEBUG(1) printf( "Using redir name \"%s\"\n", redirName );
|
|
|
|
//
|
|
// Open the address.
|
|
//
|
|
|
|
RtlInitString( &nameString, transportName );
|
|
status = RtlAnsiStringToUnicodeString(
|
|
&unicodeNameString,
|
|
&nameString,
|
|
TRUE
|
|
);
|
|
ASSERT( NT_SUCCESS(status) );
|
|
|
|
IF_DEBUG(2) printf( "Creating %s endpoint\n", DebugName );
|
|
status = TdiOpenNetbiosAddress(
|
|
&Redir->EndpointFileHandle,
|
|
eaBuffer,
|
|
&unicodeNameString,
|
|
redirName
|
|
);
|
|
|
|
RtlFreeUnicodeString( &unicodeNameString );
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "TdiOpenNetbiosAddress (%s) failed: %X\n",
|
|
DebugName, status );
|
|
DbgBreakPoint( );
|
|
return status;
|
|
}
|
|
|
|
IF_DEBUG(2) printf( " %s Address file handle 0x%lx\n",
|
|
DebugName, Redir->EndpointFileHandle );
|
|
|
|
//
|
|
// Create a connection.
|
|
//
|
|
// Create the EA for the connection context.
|
|
//
|
|
|
|
ASSERT( TDI_CONNECTION_CONTEXT_LENGTH + sizeof(CONNECTION_CONTEXT) <=
|
|
TDI_TRANSPORT_ADDRESS_LENGTH + sizeof(TA_NETBIOS_ADDRESS) );
|
|
|
|
ea = (PFILE_FULL_EA_INFORMATION)eaBuffer;
|
|
ea->NextEntryOffset = 0;
|
|
ea->Flags = 0;
|
|
ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
|
|
ea->EaValueLength = sizeof( CONNECTION_CONTEXT );
|
|
|
|
RtlMoveMemory( ea->EaName, TdiConnectionContext, ea->EaNameLength + 1 );
|
|
|
|
ctx = (PVOID)0x22222222;
|
|
pctx = (CONNECTION_CONTEXT *)&ea->EaName[ea->EaNameLength + 1];
|
|
RtlMoveMemory( pctx, &ctx, sizeof(CONNECTION_CONTEXT) );
|
|
|
|
//
|
|
// Create the connection file object.
|
|
//
|
|
|
|
RtlInitString( &nameString, transportName );
|
|
status = RtlAnsiStringToUnicodeString(
|
|
&unicodeNameString,
|
|
&nameString,
|
|
TRUE
|
|
);
|
|
ASSERT( NT_SUCCESS(status) );
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
&unicodeNameString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
status = NtCreateFile(
|
|
&Redir->FileHandle,
|
|
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
|
|
&objectAttributes,
|
|
&Redir->Iosb[0],
|
|
&allocationSize,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
eaBuffer,
|
|
FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
|
|
ea->EaNameLength + 1 + ea->EaValueLength
|
|
);
|
|
|
|
RtlFreeUnicodeString( &unicodeNameString );
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "NtCreateFile (%s) service failed: %X\n", DebugName, status );
|
|
DbgBreakPoint( );
|
|
NtClose( Redir->EndpointFileHandle );
|
|
return status;
|
|
}
|
|
|
|
status = Redir->Iosb[0].Status;
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "NtCreateFile (%s) I/O failed: %X\n", DebugName, status );
|
|
DbgBreakPoint( );
|
|
NtClose( Redir->EndpointFileHandle );
|
|
return status;
|
|
}
|
|
|
|
IF_DEBUG(2) printf( " %s Connection File handle 0x%lx\n",
|
|
DebugName, Redir->FileHandle );
|
|
|
|
//
|
|
// Associate the connection with the address.
|
|
//
|
|
|
|
status = StartAssociate(
|
|
Redir->FileHandle,
|
|
Redir->EndpointFileHandle,
|
|
Redir->EventHandle[0],
|
|
&Redir->Iosb[0],
|
|
DebugName
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
NtClose( Redir->FileHandle );
|
|
NtClose( Redir->EndpointFileHandle );
|
|
return status;
|
|
}
|
|
|
|
status = WaitForAssociate(
|
|
DebugName,
|
|
Redir,
|
|
0
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
NtClose( Redir->FileHandle );
|
|
NtClose( Redir->EndpointFileHandle );
|
|
return status;
|
|
}
|
|
|
|
IF_DEBUG(2) printf( " connection 0x%lx associated with address 0x%lx\n",
|
|
Redir->FileHandle, Redir->EndpointFileHandle );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // CreateEndpoint
|
|
|
|
|
|
NTSTATUS
|
|
CreateEvents (
|
|
PDESCRIPTOR Redir,
|
|
PSZ DebugName
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
UCHAR i;
|
|
|
|
//
|
|
// Create redir events.
|
|
//
|
|
|
|
for( i = 0; i < NUMBER_OF_EVENTS; i++ ) {
|
|
status = NtCreateEvent(
|
|
&Redir->EventHandle[i],
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "NtCreateEvent (%s) failed: %X\n", DebugName, status );
|
|
DbgBreakPoint( );
|
|
return status;
|
|
}
|
|
|
|
IF_DEBUG(2) printf( " %s Event handle 0x%lx\n",
|
|
DebugName, Redir->EventHandle[i] );
|
|
|
|
} // loop on NUMBER_OF_EVENTS
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // CreateEvents
|
|
|
|
|
|
NTSTATUS
|
|
Negotiate(
|
|
IN OUT PDESCRIPTOR Redir
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
ID_SELECTIONS idSelections;
|
|
ULONG smbSize;
|
|
|
|
//
|
|
// Create dummy IdSelections. Required to be present, but not used
|
|
// by Negotiate request/response.
|
|
//
|
|
|
|
idSelections.Uid = 0;
|
|
idSelections.Tid = 0;
|
|
idSelections.Fid = 0;
|
|
|
|
//
|
|
// Format the Negotiate request.
|
|
//
|
|
|
|
status = MakeNegotiateSmb(
|
|
Redir,
|
|
Redir->Data[0],
|
|
NULL,
|
|
SMB_COM_NO_ANDX_COMMAND,
|
|
&idSelections,
|
|
&Redir->IdValues,
|
|
&smbSize
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Send the request and receive a response.
|
|
//
|
|
|
|
status = SendAndReceiveSmb( Redir, "Negotiate", smbSize, 0, 1 );
|
|
if ( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Verify the response.
|
|
//
|
|
|
|
status = VerifyNegotiate(
|
|
Redir,
|
|
NULL,
|
|
SMB_COM_NEGOTIATE,
|
|
&idSelections,
|
|
&Redir->IdValues,
|
|
&smbSize,
|
|
Redir->Data[1]
|
|
);
|
|
if ( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // Negotiate
|
|
|
|
|
|
VOID
|
|
ParseCommand(
|
|
IN PSZ CommandLine,
|
|
OUT PSZ Argv[],
|
|
OUT PSHORT Argc,
|
|
IN SHORT MaxArgc
|
|
)
|
|
{
|
|
PSZ cl = CommandLine;
|
|
SHORT ac = 0;
|
|
|
|
while ( *cl && (ac < MaxArgc) ) {
|
|
|
|
while ( *cl && (*cl <= ' ') ) { // ignore leading blanks
|
|
cl++;
|
|
}
|
|
|
|
if ( !*cl ) break;
|
|
|
|
*Argv++ = cl;
|
|
++ac;
|
|
|
|
while (*cl > ' ') {
|
|
cl++;
|
|
}
|
|
|
|
if ( *cl ) {
|
|
*cl++ = '\0';
|
|
}
|
|
}
|
|
|
|
if ( ac < MaxArgc ) {
|
|
*Argv++ = NULL;
|
|
} else if ( *cl ) {
|
|
printf( "Too many tokens in command; \"%s\" ignored\n", cl );
|
|
}
|
|
|
|
*Argc = ac;
|
|
|
|
return;
|
|
|
|
} // ParseCommand
|
|
|
|
|
|
NTSTATUS
|
|
StartConnect (
|
|
IN PSTRING RemoteAddress,
|
|
IN PVOID Buffer,
|
|
IN HANDLE FileHandle,
|
|
IN HANDLE EventHandle,
|
|
IN PIO_STATUS_BLOCK Iosb,
|
|
IN PSZ DebugString
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PTDI_REQUEST_CONNECT request;
|
|
PTDI_CONNECTION_INFORMATION conninfo;
|
|
PTA_NETBIOS_ADDRESS address;
|
|
ULONG i;
|
|
SHORT length;
|
|
PSZ remoteAddress;
|
|
|
|
remoteAddress = RemoteAddress->Buffer;
|
|
length = RemoteAddress->Length;
|
|
|
|
//
|
|
// Inside of Buffer, initialize the TDI_REQUEST_CONNECT,
|
|
// followed immediately by the TDI_CONNECTION_INFORMATION,
|
|
// followed by the TA_NETBIOS_ADDRESS.
|
|
//
|
|
|
|
request = (PTDI_REQUEST_CONNECT)Buffer;
|
|
request->RequestConnectionInformation = (PTDI_CONNECTION_INFORMATION)(request + 1);
|
|
|
|
conninfo = request->RequestConnectionInformation;
|
|
conninfo->UserDataLength = 0;
|
|
conninfo->OptionsLength = 0;
|
|
conninfo->RemoteAddressLength = sizeof(TA_NETBIOS_ADDRESS);
|
|
conninfo->RemoteAddress = (PTA_NETBIOS_ADDRESS)(conninfo + 1);
|
|
|
|
address = conninfo->RemoteAddress;
|
|
address->TAAddressCount = 1;
|
|
address->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
|
address->Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
|
|
address->Address[0].Address[0].NetbiosNameType =
|
|
TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
|
RtlMoveMemory(
|
|
address->Address[0].Address[0].NetbiosName,
|
|
remoteAddress,
|
|
MIN( length, 16 )
|
|
);
|
|
for ( i = length; i < 16; i++ ) {
|
|
address->Address[0].Address[0].NetbiosName[i] = 0;
|
|
}
|
|
|
|
IF_DEBUG(2) printf( "Starting %s\n", DebugString );
|
|
status = NtDeviceIoControlFile(
|
|
FileHandle,
|
|
EventHandle,
|
|
NULL,
|
|
NULL,
|
|
Iosb,
|
|
IOCTL_TDI_CONNECT,
|
|
(PVOID)Buffer,
|
|
sizeof(*request) + sizeof(*conninfo) + sizeof(*address),
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "NtDeviceIoControlFile (%s) service failed: %X\n",
|
|
DebugString, status );
|
|
DbgBreakPoint( );
|
|
return status;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // StartConnect
|
|
|
|
|
|
NTSTATUS
|
|
WaitForConnect(
|
|
IN PSZ Operation,
|
|
IN PDESCRIPTOR Redir,
|
|
IN UCHAR EventNumber
|
|
)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
IF_DEBUG(2) printf( "Waiting for %s\n", Operation );
|
|
status = NtWaitForSingleObject(
|
|
Redir->EventHandle[EventNumber],
|
|
FALSE,
|
|
NULL
|
|
);
|
|
IF_DEBUG(2) printf( "%s complete\n", Operation );
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "NtWaitForSingleObject (%s) failed: %X\n", Operation, status );
|
|
DbgBreakPoint( );
|
|
return status;
|
|
}
|
|
|
|
status = Redir->Iosb[EventNumber].Status;
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "%s I/O failed: %X\n", Operation, status );
|
|
DbgBreakPoint( );
|
|
return status;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // WaitForConnect
|
|
|
|
|
|
NTSTATUS
|
|
StartAssociate (
|
|
IN HANDLE ConnectionFileHandle,
|
|
IN HANDLE AddressFileHandle,
|
|
IN HANDLE EventHandle,
|
|
IN PIO_STATUS_BLOCK Iosb,
|
|
IN PSZ DebugString
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
TDI_REQUEST_ASSOCIATE_ADDRESS request;
|
|
|
|
request.AddressHandle = AddressFileHandle;
|
|
|
|
IF_DEBUG(2) printf( "Starting %s Associate\n", DebugString );
|
|
status = NtDeviceIoControlFile(
|
|
ConnectionFileHandle,
|
|
EventHandle,
|
|
NULL,
|
|
NULL,
|
|
Iosb,
|
|
IOCTL_TDI_ASSOCIATE_ADDRESS,
|
|
(PVOID)&request,
|
|
sizeof(request),
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "NtDeviceIoControlFile (%s Associate) service failed: %X\n",
|
|
DebugString, status );
|
|
DbgBreakPoint( );
|
|
return status;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // StartAssociate
|
|
|
|
|
|
NTSTATUS
|
|
WaitForAssociate(
|
|
IN PSZ Operation,
|
|
IN PDESCRIPTOR Redir,
|
|
IN UCHAR EventNumber
|
|
)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
IF_DEBUG(2) printf( "Waiting for %s Associate\n", Operation );
|
|
status = NtWaitForSingleObject(
|
|
Redir->EventHandle[EventNumber],
|
|
FALSE,
|
|
NULL
|
|
);
|
|
IF_DEBUG(2) printf( "%s Associate complete\n", Operation );
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "NtWaitForSingleObject (%s Associate) failed: %X\n",
|
|
Operation, status );
|
|
DbgBreakPoint( );
|
|
return status;
|
|
}
|
|
|
|
status = Redir->Iosb[EventNumber].Status;
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "%s Associate I/O failed: %X\n", Operation, status );
|
|
DbgBreakPoint( );
|
|
return status;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // WaitForAssociate
|
|
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
ReadWithPrompt(
|
|
PSZ Prompt,
|
|
PSZ Buffer,
|
|
ULONG BufferLength
|
|
)
|
|
{
|
|
ULONG length;
|
|
CHAR c;
|
|
PSZ dest;
|
|
|
|
ASSERT( BufferLength > 0 );
|
|
|
|
printf( Prompt );
|
|
|
|
c = 0;
|
|
length = 0;
|
|
dest = Buffer;
|
|
|
|
while ( length < BufferLength ) {
|
|
|
|
c = (CHAR)getchar( );
|
|
if ( c == EOF ) break;
|
|
if ( c == '\n' ) break;
|
|
|
|
*dest++ = c;
|
|
length++;
|
|
|
|
}
|
|
|
|
*dest = 0;
|
|
|
|
return (BOOLEAN)(c == EOF);
|
|
|
|
} // ReadWithPrompt
|
|
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
ExecuteCommand(
|
|
IN PSZ Command OPTIONAL,
|
|
IN PDESCRIPTOR Redir,
|
|
IN PSZ Prompt
|
|
)
|
|
|
|
{
|
|
BOOLEAN done = FALSE;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
UCHAR i;
|
|
ULONG SmbSize;
|
|
PREDIR_TEST LocalRedirTest;
|
|
PSMB_TEST smbTest;
|
|
CLONG redirNumber;
|
|
LONG testNumber;
|
|
CHAR debugString[128];
|
|
CLONG testNameLength;
|
|
|
|
BOOLEAN again = TRUE;
|
|
|
|
#define COMMAND_LINE_LENGTH 128
|
|
CHAR commandLineBuffer[COMMAND_LINE_LENGTH];
|
|
PSZ commandLine;
|
|
PSZ localArgv[MAX_ARGC];
|
|
|
|
|
|
while ( !done ) {
|
|
|
|
testNumber = Redir->TestNumber;
|
|
|
|
if ( (testNumber < 0) && again ) {
|
|
|
|
while ( !done ) {
|
|
|
|
if ( Command == NULL ) {
|
|
|
|
done = ReadWithPrompt(
|
|
Prompt,
|
|
commandLineBuffer,
|
|
COMMAND_LINE_LENGTH
|
|
);
|
|
commandLine = (PSZ)commandLineBuffer;
|
|
|
|
} else {
|
|
|
|
done = TRUE;
|
|
printf( "%s%s\n", Prompt, Command );
|
|
commandLine = Command;
|
|
|
|
}
|
|
|
|
ParseCommand(
|
|
commandLine,
|
|
localArgv,
|
|
&Redir->argc,
|
|
MAX_ARGC
|
|
);
|
|
if ( Redir->argc <= 0 ) {
|
|
continue;
|
|
}
|
|
|
|
if ( *localArgv[0] == '@' ) {
|
|
ExecuteBatchFile( localArgv[0]+1, Redir, Prompt );
|
|
continue;
|
|
}
|
|
|
|
if ( _stricmp( localArgv[0], "break" ) == 0 ) {
|
|
DbgBreakPoint( );
|
|
continue;
|
|
}
|
|
|
|
if ( _stricmp( localArgv[0], "exit" ) == 0 ) {
|
|
break;
|
|
}
|
|
|
|
if ( _stricmp( localArgv[0], "debug" ) == 0 ) {
|
|
if ( Redir->argc > 1 ) {
|
|
DebugParameter = atolx( localArgv[1] );
|
|
} else {
|
|
printf( "USRV: Missing argument\n" );
|
|
}
|
|
continue;
|
|
}
|
|
|
|
#if 0
|
|
if ( _stricmp( localArgv[0], "dbg" ) == 0 ) {
|
|
NTSTATUS netStatus;
|
|
netStatus = NetLocalSetServerDebug(
|
|
(SHORT)(Redir->argc - 1),
|
|
&localArgv[1],
|
|
NULL,
|
|
NULL
|
|
);
|
|
if ( NT_SUCCESS(status) ) {
|
|
printf( "The command completed successfully\n" );
|
|
}
|
|
continue;
|
|
}
|
|
#endif
|
|
if ( _stricmp( localArgv[0], "delay" ) == 0 ) {
|
|
ULONG ms = 1000;
|
|
LARGE_INTEGER delayTime;
|
|
if ( Redir->argc > 1 ) {
|
|
ms = atol( localArgv[1] );
|
|
}
|
|
printf( "Delaying for %lu milliseconds\n", ms );
|
|
delayTime.QuadPart = Int32x32To64( ms, -10000 );
|
|
NtDelayExecution( TRUE, (PLARGE_INTEGER)&delayTime );
|
|
continue;
|
|
}
|
|
|
|
Redir->argv = localArgv;
|
|
testNumber = MatchTestName( localArgv[0] );
|
|
|
|
switch( testNumber ) {
|
|
case (LONG)-1:
|
|
printf( "Unknown test specified: %s\n", localArgv[0] );
|
|
continue;
|
|
case (LONG)-2:
|
|
printf( "Test name ambiguous: %s\n", localArgv[0] );
|
|
continue;
|
|
}
|
|
|
|
Redir->TestNumber = testNumber;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( testNumber < 0 ) {
|
|
break;
|
|
}
|
|
|
|
LocalRedirTest = &RedirTests[testNumber];
|
|
testNameLength = strlen( LocalRedirTest->RedirName );
|
|
RtlMoveMemory( debugString, LocalRedirTest->RedirName, testNameLength );
|
|
debugString[testNameLength] = ' ';
|
|
|
|
for( i = 0, smbTest = LocalRedirTest->SmbTests;
|
|
smbTest->SmbMaker != NULL;
|
|
i++, smbTest++ ) {
|
|
|
|
RtlMoveMemory(
|
|
debugString + testNameLength + 1,
|
|
smbTest->DebugString,
|
|
strlen( smbTest->DebugString ) + 1
|
|
);
|
|
IF_DEBUG(1) printf( "Starting test #%ld.%ld.%ld - %s\n",
|
|
redirNumber, testNumber, i, debugString );
|
|
|
|
Redir->ErrorInhibit = smbTest->ErrorInhibit;
|
|
|
|
if ( smbTest->SmbVerifier == NULL ) {
|
|
|
|
status = smbTest->SmbMaker(
|
|
Redir,
|
|
debugString,
|
|
NULL,
|
|
smbTest->Command,
|
|
&smbTest->IdSelections,
|
|
&Redir->IdValues,
|
|
NULL
|
|
);
|
|
|
|
} else {
|
|
|
|
status = smbTest->SmbMaker(
|
|
Redir,
|
|
Redir->Data[0],
|
|
NULL,
|
|
(UCHAR)(smbTest->SmbMaker == MakeAndXChain ?
|
|
smbTest->Command : 0xFF),
|
|
&smbTest->IdSelections,
|
|
&Redir->IdValues,
|
|
&SmbSize
|
|
);
|
|
|
|
if ( NT_SUCCESS(status) && (status != STATUS_PENDING) ) {
|
|
|
|
status = SendAndReceiveSmb(
|
|
Redir,
|
|
debugString,
|
|
SmbSize,
|
|
0,
|
|
1
|
|
);
|
|
|
|
if ( NT_SUCCESS(status) ) {
|
|
|
|
status = smbTest->SmbVerifier(
|
|
Redir,
|
|
NULL,
|
|
smbTest->Command,
|
|
&smbTest->IdSelections,
|
|
&Redir->IdValues,
|
|
&SmbSize,
|
|
Redir->Data[1]
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // if ( smbTest->SmbVerifier == NULL )
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
IF_SMB_ERROR_QUIT_TEST {
|
|
break;
|
|
}
|
|
}
|
|
|
|
} // for( i = 0, smbTest = LocalRedirTest->SmbTests; ...
|
|
|
|
Redir->TestNumber = -4;
|
|
again = PromptForNextTest;
|
|
|
|
} // while ( TRUE )
|
|
|
|
return status;
|
|
|
|
} // ExecuteCommand
|
|
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
ExecuteBatchFile(
|
|
IN PSZ Name,
|
|
IN PDESCRIPTOR Redir,
|
|
IN PSZ Prompt
|
|
)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
CHAR nameBuffer[32];
|
|
CHAR commandBuffer[128];
|
|
PCHAR commandBufferPtr;
|
|
STRING fileName;
|
|
UNICODE_STRING unicodeFileName;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
HANDLE fileHandle;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
PCHAR readBuffer;
|
|
ULONG readBufferIndex;
|
|
|
|
RtlMoveMemory( nameBuffer, "\\SystemRoot\\", 12 );
|
|
RtlMoveMemory( nameBuffer + 15, Name, strlen( Name ) );
|
|
RtlMoveMemory( nameBuffer + 15 + strlen( Name ), ".CMD", 5 );
|
|
|
|
fileName.Buffer = nameBuffer;
|
|
fileName.Length = (SHORT)strlen( nameBuffer );
|
|
|
|
status = RtlAnsiStringToUnicodeString(
|
|
&unicodeFileName,
|
|
&fileName,
|
|
TRUE
|
|
);
|
|
ASSERT( NT_SUCCESS(status) );
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
&unicodeFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
status = NtOpenFile(
|
|
&fileHandle,
|
|
FILE_READ_DATA | SYNCHRONIZE,
|
|
&objectAttributes,
|
|
&ioStatusBlock,
|
|
FILE_SHARE_READ,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
|
|
RtlFreeUnicodeString( &unicodeFileName );
|
|
if ( !NT_SUCCESS(status) ) {
|
|
if ( status == STATUS_OBJECT_NAME_NOT_FOUND ) {
|
|
printf( "Batch file %Z not found\n", &fileName );
|
|
} else {
|
|
printf( "Error opening batch file %Z: %X\n",
|
|
&fileName, status );
|
|
}
|
|
return status;
|
|
}
|
|
|
|
readBuffer = malloc( 4096 );
|
|
if ( readBuffer == NULL ) {
|
|
NtClose( fileHandle );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
status = NtReadFile(
|
|
fileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ioStatusBlock,
|
|
readBuffer,
|
|
4096,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
printf( "Error reading batch file %Z: %X\n", &fileName, status );
|
|
ioStatusBlock.Information = 0;
|
|
}
|
|
|
|
for ( readBufferIndex = 0, commandBufferPtr = commandBuffer;
|
|
readBufferIndex < ioStatusBlock.Information;
|
|
readBufferIndex++ ) {
|
|
|
|
if ( readBuffer[readBufferIndex] == '\n' ) {
|
|
*commandBufferPtr = '\0';
|
|
(VOID)ExecuteCommand( commandBuffer, Redir, Prompt );
|
|
commandBufferPtr = commandBuffer;
|
|
continue;
|
|
}
|
|
|
|
*commandBufferPtr++ = readBuffer[readBufferIndex];
|
|
}
|
|
|
|
NtClose( fileHandle );
|
|
free( readBuffer );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // ExecuteBatchFile
|
|
|
|
|
|
NTSTATUS
|
|
TdiOpenNetbiosAddress (
|
|
IN OUT PHANDLE FileHandle,
|
|
IN PUCHAR Buffer,
|
|
IN PVOID DeviceName,
|
|
IN PVOID Address)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens an address on the given file handle and device.
|
|
|
|
Arguments:
|
|
|
|
FileHandle - the returned handle to the file object that is opened.
|
|
|
|
Buffer - pointer to a buffer that the ea is to be built in. This buffer
|
|
must be at least 40 bytes long.
|
|
|
|
DeviceName - the Unicode string that points to the device object.
|
|
|
|
Name - the address to be registered. If this pointer is NULL, the routine
|
|
will attempt to open a "control channel" to the device; that is, it
|
|
will attempt to open the file object with a null ea pointer, and if the
|
|
transport provider allows for that, will return that handle.
|
|
|
|
Return Value:
|
|
|
|
An informative error code if something goes wrong. STATUS_SUCCESS if the
|
|
returned file handle is valid.
|
|
|
|
--*/
|
|
{
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
PFILE_FULL_EA_INFORMATION EaBuffer;
|
|
TA_NETBIOS_ADDRESS NetbiosAddress;
|
|
PSZ Name;
|
|
ULONG Length;
|
|
|
|
if (Address != NULL) {
|
|
Name = (PSZ)Address;
|
|
try {
|
|
Length = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
|
|
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
|
sizeof(TA_NETBIOS_ADDRESS);
|
|
EaBuffer = (PFILE_FULL_EA_INFORMATION)Buffer;
|
|
|
|
if (EaBuffer == NULL) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
EaBuffer->NextEntryOffset = 0;
|
|
EaBuffer->Flags = 0;
|
|
EaBuffer->EaNameLength = (UCHAR)TDI_TRANSPORT_ADDRESS_LENGTH;
|
|
EaBuffer->EaValueLength = sizeof (TA_NETBIOS_ADDRESS);
|
|
|
|
RtlMoveMemory(
|
|
EaBuffer->EaName,
|
|
TdiTransportAddress,
|
|
EaBuffer->EaNameLength + 1
|
|
);
|
|
|
|
//
|
|
// Create a copy of the NETBIOS address descriptor in a local
|
|
// first, in order to avoid alignment problems.
|
|
//
|
|
|
|
NetbiosAddress.TAAddressCount = 1;
|
|
NetbiosAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
|
NetbiosAddress.Address[0].AddressLength =
|
|
sizeof (TDI_ADDRESS_NETBIOS);
|
|
NetbiosAddress.Address[0].Address[0].NetbiosNameType =
|
|
TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
|
RtlMoveMemory(
|
|
NetbiosAddress.Address[0].Address[0].NetbiosName,
|
|
Name,
|
|
16
|
|
);
|
|
|
|
RtlMoveMemory (
|
|
&EaBuffer->EaName[EaBuffer->EaNameLength + 1],
|
|
&NetbiosAddress,
|
|
sizeof(TA_NETBIOS_ADDRESS)
|
|
);
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
//
|
|
// Couldn't touch the passed parameters; just return an error
|
|
// status.
|
|
//
|
|
|
|
return GetExceptionCode();
|
|
}
|
|
} else {
|
|
EaBuffer = NULL;
|
|
Length = 0;
|
|
}
|
|
|
|
InitializeObjectAttributes (
|
|
&ObjectAttributes,
|
|
DeviceName,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtCreateFile (
|
|
FileHandle,
|
|
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, // desired access.
|
|
&ObjectAttributes, // object attributes.
|
|
&IoStatusBlock, // returned status information.
|
|
0, // block size (unused).
|
|
0, // file attributes.
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, // share access.
|
|
FILE_CREATE, // create disposition.
|
|
0, // create options.
|
|
EaBuffer, // EA buffer.
|
|
Length); // EA length.
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
return Status;
|
|
}
|
|
|
|
Status = IoStatusBlock.Status;
|
|
|
|
return Status;
|
|
|
|
} // TdiOpenNetbiosAddress
|
|
|