summaryrefslogtreecommitdiffstats
path: root/private/net/srvtest/subs.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/net/srvtest/subs.c')
-rw-r--r--private/net/srvtest/subs.c2417
1 files changed, 2417 insertions, 0 deletions
diff --git a/private/net/srvtest/subs.c b/private/net/srvtest/subs.c
new file mode 100644
index 000000000..fea02cacd
--- /dev/null
+++ b/private/net/srvtest/subs.c
@@ -0,0 +1,2417 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ subs.c
+
+Abstract:
+
+ Common subroutines for USRV.
+
+Author:
+
+ David Treadwell (davidtr) 20-Oct-1989
+ Chuck Lenzmeier (chuckl)
+
+Revision History:
+
+--*/
+
+#define INCLUDE_SMB_FILE_CONTROL
+#define INCLUDE_SMB_OPEN_CLOSE
+#define INCLUDE_SMB_READ_WRITE
+#define INCLUDE_SMB_TRANSACTION
+
+#include "usrv.h"
+
+
+NTSTATUS
+DoOpen(
+ IN PSZ Title,
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues,
+ IN CLONG Session,
+ IN USHORT Pid,
+ IN PSTRING File,
+ IN USHORT DesiredAccess,
+ IN USHORT OpenFunction,
+ OUT PUSHORT Fid,
+#ifdef DOSERROR
+ IN UCHAR ExpectedClass,
+ IN USHORT ExpectedError
+#else
+ IN NTSTATUS ExpectedStatus
+#endif
+ )
+
+{
+ NTSTATUS status;
+ CLONG smbSize;
+
+ PSMB_HEADER header;
+ PREQ_OPEN_ANDX request;
+ PRESP_OPEN_ANDX response;
+
+#ifdef DOSERROR
+ UCHAR class;
+ USHORT error;
+#endif
+
+ IF_DEBUG(3) printf( "'%s' start\n", Title );
+
+ header = (PSMB_HEADER)Redir->Data[0];
+ request = (PREQ_OPEN_ANDX)(header + 1);
+
+ IdSelections->Uid += Session;
+
+ (VOID)MakeSmbHeader(
+ Redir,
+ header,
+ SMB_COM_OPEN_ANDX,
+ IdSelections,
+ IdValues
+ );
+ SmbPutAlignedUshort( &header->Pid, Pid );
+
+ IdSelections->Uid -= Session;
+
+ request->WordCount = 15;
+ SmbPutUshort( &request->Flags, 0 );
+ SmbPutUshort( &request->DesiredAccess, DesiredAccess );
+ SmbPutUshort( &request->SearchAttributes, 0 );
+ SmbPutUshort( &request->FileAttributes, 0 );
+ SmbPutUshort( &request->OpenFunction, OpenFunction );
+ SmbPutUlong( &request->AllocationSize, 0 );
+ SmbPutUlong( &request->Timeout, 0 );
+ SmbPutUlong( &request->Reserved, 0 );
+ SmbPutUshort( &request->ByteCount, (USHORT)(File->Length+1) );
+
+ RtlMoveMemory( request->Buffer, File->Buffer, File->Length+1 );
+
+ request->AndXCommand = SMB_COM_NO_ANDX_COMMAND;
+
+ SmbPutUshort(
+ &request->AndXOffset,
+ GET_ANDX_OFFSET( header, request, REQ_OPEN_ANDX, File->Length+1 )
+ );
+
+ smbSize = SmbGetUshort( &request->AndXOffset );
+
+ status = SendAndReceiveSmb(
+ Redir,
+ DebugString,
+ smbSize,
+ 0,
+ 1
+ );
+ CHECK_STATUS( Title );
+
+ header = (PSMB_HEADER)Redir->Data[1];
+ response = (PRESP_OPEN_ANDX)(header + 1);
+
+#ifdef DOSERROR
+ class = header->ErrorClass;
+ error = SmbGetUshort( &header->Error );
+ CHECK_ERROR( Title, ExpectedClass, ExpectedError );
+#else
+ status = SmbGetUlong( (PULONG)&header->ErrorClass );
+ CHECK_ERROR( Title, status, ExpectedStatus );
+#endif
+
+ *Fid = SmbGetUshort( &response->Fid );
+
+#ifdef DOS_ERROR
+ IF_DEBUG(3) {
+ printf( "'%s' complete. Fid 0x%lx, Class %ld, Error %ld\n",
+ Title, *Fid, class, error );
+ }
+#else
+ IF_DEBUG(3) {
+ printf( "'%s' complete. Fid 0x%lx, Status %lx\n",
+ Title, *Fid, status);
+ }
+#endif
+
+ return STATUS_SUCCESS;
+
+} // DoOpen
+
+
+NTSTATUS
+DoClose(
+ IN PSZ Title,
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues,
+ IN CLONG Session,
+ IN USHORT Fid,
+#ifdef DOSERROR
+ IN UCHAR ExpectedClass,
+ IN USHORT ExpectedError
+#else
+ IN NTSTATUS ExpectedStatus
+#endif
+ )
+
+{
+ NTSTATUS status;
+ CLONG smbSize;
+
+ PSMB_HEADER header;
+ PREQ_CLOSE request;
+
+#ifdef DOSERROR
+ UCHAR class;
+ USHORT error;
+#else
+ NTSTATUS smbStatus;
+#endif
+
+ IF_DEBUG(3) printf( "'%s' start\n", Title );
+
+ header = (PSMB_HEADER)Redir->Data[0];
+ request = (PREQ_CLOSE)(header + 1);
+
+ IdSelections->Uid += Session;
+
+ (VOID)MakeSmbHeader(
+ Redir,
+ header,
+ SMB_COM_CLOSE,
+ IdSelections,
+ IdValues
+ );
+
+ IdSelections->Uid -= Session;
+
+ request->WordCount = 3;
+ SmbPutUshort( &request->Fid, Fid );
+ SmbPutUlong( &request->LastWriteTimeInSeconds, 0 );
+ SmbPutUshort( &request->ByteCount, 0 );
+
+ smbSize = GET_ANDX_OFFSET( header, request, REQ_CLOSE, 0 );
+
+ status = SendAndReceiveSmb(
+ Redir,
+ DebugString,
+ smbSize,
+ 0,
+ 1
+ );
+ CHECK_STATUS( Title );
+
+ header = (PSMB_HEADER)Redir->Data[1];
+
+#ifdef DOSERROR
+ class = header->ErrorClass;
+ error = SmbGetUshort( &header->Error );
+ CHECK_ERROR( Title, ExpectedClass, ExpectedError );
+
+ IF_DEBUG(3) {
+ printf( "'%s' complete. Class %ld, Error %ld\n",
+ Title, class, error );
+ }
+#else
+ smbStatus = SmbGetUlong( (PULONG)&header->ErrorClass );
+ CHECK_ERROR( Title, smbStatus, ExpectedStatus );
+
+ IF_DEBUG(3) {
+ printf( "'%s' complete. Status %lx\n",
+ Title, smbStatus );
+ }
+#endif
+
+
+ return STATUS_SUCCESS;
+
+} // DoClose
+
+
+NTSTATUS
+DoDelete(
+ IN PSZ Title,
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues,
+ IN CLONG Session,
+ IN PSTRING File,
+#ifdef DOSERROR
+ IN UCHAR ExpectedClass,
+ IN USHORT ExpectedError
+#else
+ IN NTSTATUS ExpectedStatus
+#endif
+ )
+
+{
+ NTSTATUS status;
+ CLONG smbSize;
+
+ PSMB_HEADER header;
+ PREQ_DELETE request;
+
+#ifdef DOSERROR
+ UCHAR class;
+ USHORT error;
+#else
+ NTSTATUS smbStatus;
+#endif
+
+ IF_DEBUG(3) printf( "'%s' start\n", Title );
+
+ header = (PSMB_HEADER)Redir->Data[0];
+ request = (PREQ_DELETE)(header + 1);
+
+ IdSelections->Uid += Session;
+
+ (VOID)MakeSmbHeader(
+ Redir,
+ header,
+ SMB_COM_DELETE,
+ IdSelections,
+ IdValues
+ );
+
+ IdSelections->Uid -= Session;
+
+ request->WordCount = 1;
+ SmbPutUshort( &request->SearchAttributes, 0 );
+ SmbPutUshort( &request->ByteCount, (USHORT)(File->Length + 2) );
+
+ request->Buffer[0] = SMB_FORMAT_ASCII;
+ RtlMoveMemory( request->Buffer+1, File->Buffer, File->Length+1 );
+
+ smbSize = GET_ANDX_OFFSET( header, request, REQ_DELETE, File->Length+2 );
+
+ status = SendAndReceiveSmb(
+ Redir,
+ DebugString,
+ smbSize,
+ 0,
+ 1
+ );
+ CHECK_STATUS( Title );
+
+ header = (PSMB_HEADER)Redir->Data[1];
+
+#ifdef DOSERROR
+ class = header->ErrorClass;
+ error = SmbGetUshort( &header->Error );
+ CHECK_ERROR( Title, ExpectedClass, ExpectedError );
+
+ IF_DEBUG(3) {
+ printf( "'%s' complete. Class %ld, Error %ld\n",
+ Title, class, error );
+ }
+
+#else
+ smbStatus = SmbGetUlong( (PULONG)&header->ErrorClass );
+
+ CHECK_ERROR( Title, smbStatus, ExpectedStatus );
+
+ IF_DEBUG(3) {
+ printf( "'%s' complete. Status %lx\n", Title, smbStatus );
+ }
+
+#endif
+ return STATUS_SUCCESS;
+
+} // DoDelete
+
+
+long
+atolx(
+ const char *String
+ )
+{
+ LONG result = 0;
+ CHAR c;
+
+ while ( (c = *String++) != 0 ) {
+ result = result * 16;
+ if ( c < '0' ) {
+ return 0;
+ }
+ if ( c <= '9' ) {
+ result += c - '0';
+ continue;
+ }
+ if ( c < 'A' ) {
+ return 0;
+ }
+ if ( c <= 'F' ) {
+ result += c - 'A' + 10;
+ continue;
+ }
+ if ( c < 'a' ) {
+ return 0;
+ }
+ if ( c > 'f' ) {
+ return 0;
+ }
+ result += c - 'a' + 10;
+ }
+
+ return result;
+
+} // atolx
+
+
+CCHAR
+GetTreeConnectIndex (
+ IN PSZ InputString
+ )
+
+{
+ if ( *(InputString+1) != ':' ) {
+ return 0;
+ }
+
+ if ( *InputString >= '0' && *InputString <= '9' ) {
+ return (CCHAR)( *InputString - '0' );
+ }
+
+ if ( *InputString >= 'a' && *InputString <= 'f' ) {
+ return (CCHAR)( *InputString - 'a' + 0xA );
+ }
+
+ if ( *InputString >= 'A' && *InputString <= 'F' ) {
+ return (CCHAR)( *InputString - 'F' + 0xA );
+ }
+
+ return 0;
+}
+
+
+NTSTATUS
+MakeSmbHeader(
+ IN OUT PDESCRIPTOR Redir,
+ IN PSMB_HEADER Header,
+ IN USHORT Command,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues
+ )
+
+{
+ Redir; // prevent compiler warnings
+
+ if ( Header == NULL ) {
+ return STATUS_SUCCESS;
+ }
+
+ Header->Protocol[0] = 0xFF;
+ Header->Protocol[1] = 'S';
+ Header->Protocol[2] = 'M';
+ Header->Protocol[3] = 'B';
+ Header->Command = (UCHAR)Command;
+ Header->ErrorClass = 0;
+ Header->Reserved = 0;
+ SmbPutUshort( &Header->Error, 0 );
+ Header->Flags = SMB_FLAGS_CASE_INSENSITIVE;
+ SmbPutAlignedUshort( &Header->Flags2, 0 );
+ RtlZeroMemory( &Header->Reserved2[0], sizeof(Header->Reserved2) );
+
+ if ( IdSelections->Tid == 0xF && Redir->argc > 1 ) {
+
+ SHORT i;
+ USHORT tid = 0;
+
+ //
+ // Find the first argument that starts with "X:". Use that to
+ // find the TID.
+ //
+
+ for ( i = 1; i < Redir->argc; i++ ) {
+ CHAR c = *Redir->argv[i];
+ CHAR d = *(Redir->argv[i]+1);
+
+ if ( d == ':' && ( (c >= '0' && c <= '9') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ) ) {
+ break;
+ }
+ }
+
+ if ( i != Redir->argc ) {
+ tid = IdValues->Tid[GetTreeConnectIndex( Redir->argv[i] )];
+ }
+
+ if ( (i == Redir->argc || tid == 0) &&
+ (Command != SMB_COM_NEGOTIATE &&
+ Command != SMB_COM_SESSION_SETUP_ANDX &&
+ Command != SMB_COM_TREE_CONNECT &&
+ Command != SMB_COM_TREE_CONNECT_ANDX) ) {
+
+ printf( "Bad virtual drive letter.\n" );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ SmbPutUshort( &Header->Tid, tid );
+
+ } else if ( IdSelections->Tid == 0xF ) {
+ SmbPutUshort( &Header->Tid, IdValues->Tid[0xA] );
+ } else {
+ SmbPutUshort( &Header->Tid, IdValues->Tid[IdSelections->Tid] );
+ }
+
+ SmbPutUshort( &Header->Pid, (USHORT)0xdead );
+ SmbPutUshort( &Header->Uid, IdValues->Uid[IdSelections->Uid] );
+ SmbPutUshort( &Header->Mid, 0 );
+
+ return STATUS_SUCCESS;
+
+} // MakeSmbHeader
+
+
+NTSTATUS
+VerifySmbHeader(
+ IN OUT PDESCRIPTOR Redir,
+ IN PID_SELECTIONS IdSelections,
+ IN OUT PID_VALUES IdValues,
+ IN PSMB_HEADER Header,
+ IN USHORT Command
+ )
+
+{
+ NTSTATUS status;
+
+ Redir, IdSelections, IdValues; // prevent compiler warnings
+
+ if ( Header->Command != (UCHAR)Command &&
+ Command != SMB_COM_NO_ANDX_COMMAND ) {
+ IF_SMB_ERROR_PRINT {
+ printf( "SMB Header error.\n" );
+ printf( "Expected command: 0x%lx; Received command: %lx\n",
+ Command, Header->Command );
+ }
+ SMB_ERROR_BREAK;
+ return STATUS_UNSUCCESSFUL;
+ }
+
+#ifdef DOSERROR
+
+ if ( Header->ErrorClass == SMB_ERR_CLASS_DOS &&
+ SmbGetUshort( &Header->Error ) == SMB_ERR_NO_FILES ) {
+
+ return STATUS_NO_MORE_FILES;
+ }
+
+ if ( Header->ErrorClass == SMB_ERR_CLASS_DOS &&
+ ( SmbGetUshort( &Header->Error ) == ERROR_EA_ACCESS_DENIED ||
+ SmbGetUshort( &Header->Error ) == ERROR_EAS_DIDNT_FIT ) ) {
+
+ return (NTSTATUS)(SRV_OS2_STATUS | SmbGetUshort( &Header->Error ));
+ }
+
+ if (Header->ErrorClass == SMB_ERR_CLASS_DOS &&
+ SmbGetUshort( &Header->Error ) == SMB_ERR_MORE_DATA ) {
+
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ if ( (Header->ErrorClass != 0) || (SmbGetUshort( &Header->Error ) != 0) ) {
+ IF_SMB_ERROR_PRINT {
+ printf( "SMB header error, command = 0x%lx\n", Header->Command );
+ PrintError( Header->ErrorClass, SmbGetUshort( &Header->Error ) );
+ }
+ SMB_ERROR_BREAK;
+
+ if ( StopOnSmbError ) {
+ return STATUS_UNSUCCESSFUL;
+ } else {
+ return STATUS_SUCCESS;
+ }
+ }
+
+#else
+
+ status = SmbGetUlong( (PULONG)&Header->ErrorClass );
+
+ if ( status == STATUS_NO_MORE_FILES
+ || status == STATUS_OS2_EA_ACCESS_DENIED
+ || status == STATUS_OS2_EAS_DIDNT_FIT
+ || status == STATUS_BUFFER_OVERFLOW ) {
+
+ return status;
+
+ }
+
+ if ( status != STATUS_SUCCESS ) {
+ IF_SMB_ERROR_PRINT {
+ printf( "SMB header error, command = 0x%lx\n", Header->Command );
+ printf( "Status = 0x%lx\n", status );
+ }
+ SMB_ERROR_BREAK;
+
+ if ( StopOnSmbError ) {
+ return STATUS_UNSUCCESSFUL;
+ } else {
+ return STATUS_SUCCESS;
+ }
+ }
+
+#endif
+
+ return STATUS_SUCCESS;
+
+} // VerifySmbHeader
+
+
+NTSTATUS
+MakeAndXChain(
+ IN OUT PDESCRIPTOR Redir,
+ IN OUT PVOID Buffer,
+ IN PVOID ForcedParams OPTIONAL,
+ IN UCHAR AndXCommand,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues,
+ OUT PULONG SmbSize
+ )
+
+{
+ NTSTATUS status;
+ CSHORT i;
+ UCHAR currentChain = AndXCommand;
+
+ IdSelections; // prevent compiler warnings
+
+ *SmbSize = 0;
+ ForcedParams = NULL;
+
+ for ( i = 0; AndXChains[currentChain][i].SmbMaker != NULL; i++ ) {
+
+ status = AndXChains[currentChain][i].SmbMaker(
+ Redir,
+ Buffer,
+ ForcedParams,
+ AndXChains[currentChain][i+1].Command,
+ &AndXChains[currentChain][i].IdSelections,
+ IdValues,
+ SmbSize
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ ForcedParams = (PVOID)( (PUCHAR)Buffer + *SmbSize);
+ }
+
+ return STATUS_SUCCESS;
+
+} // MakeAndXChain
+
+
+NTSTATUS
+VerifyAndXChain(
+ IN OUT PDESCRIPTOR Redir,
+ IN OUT PVOID ForcedParams OPTIONAL,
+ IN UCHAR AndXCommand,
+ IN PID_SELECTIONS IdSelections,
+ IN OUT PID_VALUES IdValues,
+ OUT PULONG SmbSize,
+ IN PVOID Buffer
+ )
+
+{
+ PSMB_HEADER Header;
+ NTSTATUS status;
+ SHORT i;
+ UCHAR currentChain = AndXCommand;
+
+ Header = (PSMB_HEADER)(Buffer);
+
+ *SmbSize = 0;
+
+ status = VerifySmbHeader(
+ Redir,
+ IdSelections,
+ IdValues,
+ Header,
+ AndXChains[currentChain][0].Command
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ for ( i = 0; AndXChains[currentChain][i].SmbVerifier != NULL; i++ ) {
+
+ status = AndXChains[currentChain][i].SmbVerifier(
+ Redir,
+ &ForcedParams,
+ AndXChains[currentChain][i+1].Command,
+ &AndXChains[currentChain][i].IdSelections,
+ IdValues,
+ SmbSize,
+ Buffer
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ ForcedParams = (PVOID)( (PUCHAR)Buffer + *SmbSize);
+ }
+
+ return STATUS_SUCCESS;
+
+} // VerifyAndXChain
+
+
+LONG
+MatchTestName(
+ IN PSZ GivenName
+ )
+{
+ ULONG i;
+ LONG foundIndex = -1;
+ CHAR redirName[64];
+ PSZ s,t;
+ LONG givenNameLength = strlen( GivenName );
+
+ for ( i = 0; i < NumberOfRedirs; i++ ) {
+
+ for ( s = redirName, t = RedirTests[i].RedirName;
+ *t != '\0';
+ s++, t++) {
+
+ *s = *t;
+
+ if ( *s >= 'a' && *s <= 'z' ) {
+ *s -= 'a' - 'A';
+ }
+ }
+
+ for ( s = GivenName; *s != '\0'; s++ ) {
+
+ if ( *s >= 'a' && *s <= 'z' ) {
+ *s -= 'a' - 'A';
+ }
+ }
+
+ if ( strncmp( redirName, GivenName, givenNameLength ) == 0) {
+
+ if ( foundIndex != -1 ) {
+ return -2;
+ }
+
+ foundIndex = (LONG)i;
+ }
+ }
+
+ return foundIndex;
+
+} // MatchTestName
+
+
+VOID
+PutNtDateAndTime(
+ IN PSZ Prefix,
+ IN LARGE_INTEGER Time
+ )
+{
+ TIME_FIELDS timeFields;
+
+ RtlTimeToTimeFields( &Time, &timeFields );
+
+ printf( "%s date %ld/%ld/%ld, time %ld:%ld:%ld\n",
+ Prefix,
+ timeFields.Month,
+ timeFields.Day,
+ timeFields.Year,
+ timeFields.Hour,
+ timeFields.Minute,
+ timeFields.Second
+ );
+ return;
+
+} // PutDateAndTime
+
+
+VOID
+PutDateAndTime(
+ IN PSZ Prefix,
+ IN SMB_DATE Date,
+ IN SMB_TIME Time
+ )
+{
+ printf( "%s date %ld/%ld/%ld, time %ld:%ld:%ld\n",
+ Prefix,
+ Date.Struct.Month,
+ Date.Struct.Day,
+ Date.Struct.Year + 80,
+ Time.Struct.Hours,
+ Time.Struct.Minutes,
+ Time.Struct.TwoSeconds*2
+ );
+ return;
+
+} // PutDateAndTime
+
+
+VOID
+PutDateAndTime2(
+ IN SMB_DATE Date,
+ IN SMB_TIME Time
+ )
+{
+ switch ( Date.Struct.Month ) {
+
+ case 1:
+ printf( "Jan " );
+ break;
+
+ case 2:
+ printf( "Feb " );
+ break;
+
+ case 3:
+ printf( "Mar " );
+ break;
+
+ case 4:
+ printf( "Apr " );
+ break;
+
+ case 5:
+ printf( "May " );
+ break;
+
+ case 6:
+ printf( "Jun " );
+ break;
+
+ case 7:
+ printf( "Jul " );
+ break;
+
+ case 8:
+ printf( "Aug " );
+ break;
+
+ case 9:
+ printf( "Sep " );
+ break;
+
+ case 10:
+ printf( "Oct " );
+ break;
+
+ case 11:
+ printf( "Nov " );
+ break;
+
+ case 12:
+ printf( "Dec " );
+ break;
+
+ default:
+ printf( "xxx " );
+
+ }
+
+ if ( Date.Struct.Day < 10 ) {
+ printf( "0%ld ", Date.Struct.Day );
+ } else {
+ printf( "%ld ", Date.Struct.Day );
+ }
+
+ if ( Time.Struct.Hours < 10 ) {
+ printf( "0%ld:", Time.Struct.Hours );
+ } else if ( Time.Struct.Hours < 100 ) {
+ printf( "%ld:", Time.Struct.Hours );
+ } else {
+ printf( "%ldx", Time.Struct.Hours % 100 );
+ }
+
+ if ( Time.Struct.Minutes < 10 ) {
+ printf( "0%ld:", Time.Struct.Minutes );
+ } else {
+ printf( "%ld:", Time.Struct.Minutes );
+ }
+
+ if ( Time.Struct.TwoSeconds*2 < 10 ) {
+ printf( "0%ld ", Time.Struct.TwoSeconds*2 );
+ } else {
+ printf( "%ld ", Time.Struct.TwoSeconds*2 );
+ }
+
+ printf( "%ld", Date.Struct.Year + 1980 );
+
+ return;
+
+} // PutDateAndTime2
+
+
+NTSTATUS
+ReceiveSmb(
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN UCHAR ReceiveBuffer
+ )
+
+{
+ NTSTATUS status;
+
+ status = StartReceive(
+ DebugString,
+ Redir->FileHandle,
+ Redir->EventHandle[ReceiveBuffer],
+ &Redir->Iosb[ReceiveBuffer],
+ Redir->Data[ReceiveBuffer],
+ Redir->MaxBufferSize
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ status = WaitForSendOrReceive(
+ DebugString,
+ Redir,
+ ReceiveBuffer,
+ "receive"
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ return STATUS_SUCCESS;
+
+} // ReceiveSmb
+
+
+NTSTATUS
+SendAndReceiveSmb(
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN ULONG SmbSize,
+ IN UCHAR SendBuffer,
+ IN UCHAR ReceiveBuffer
+ )
+
+{
+ NTSTATUS status;
+
+ if ( ( (DebugParameter & 0x80000000) >> 31) == 0 ) {
+ status = StartReceive(
+ DebugString,
+ Redir->FileHandle,
+ Redir->EventHandle[ReceiveBuffer],
+ &Redir->Iosb[ReceiveBuffer],
+ Redir->Data[ReceiveBuffer],
+ Redir->MaxBufferSize
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+ }
+
+ status = StartSend(
+ DebugString,
+ Redir->FileHandle,
+ Redir->EventHandle[SendBuffer],
+ &Redir->Iosb[SendBuffer],
+ Redir->Data[SendBuffer],
+ SmbSize
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ if ( ( (DebugParameter & 0xc0000000) >> 30) == 2 ) {
+ status = StartReceive(
+ DebugString,
+ Redir->FileHandle,
+ Redir->EventHandle[ReceiveBuffer],
+ &Redir->Iosb[ReceiveBuffer],
+ Redir->Data[ReceiveBuffer],
+ Redir->MaxBufferSize
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+ }
+
+ status = WaitForSendOrReceive(
+ DebugString,
+ Redir,
+ SendBuffer,
+ "send"
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ if ( ( (DebugParameter & 0xc0000000) >> 30) == 3 ) {
+ status = StartReceive(
+ DebugString,
+ Redir->FileHandle,
+ Redir->EventHandle[ReceiveBuffer],
+ &Redir->Iosb[ReceiveBuffer],
+ Redir->Data[ReceiveBuffer],
+ Redir->MaxBufferSize
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+ }
+
+ status = WaitForSendOrReceive(
+ DebugString,
+ Redir,
+ ReceiveBuffer,
+ "receive"
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ return STATUS_SUCCESS;
+
+} // SendAndReceiveSmb
+
+
+NTSTATUS
+SendAndReceiveTransaction(
+ IN OUT PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues,
+ IN UCHAR Command,
+ IN OUT PVOID Setup,
+ IN CLONG InSetupCount,
+ IN OUT PCLONG OutSetupCount,
+ IN PUCHAR Name,
+ IN USHORT Function,
+ IN OUT PVOID Parameters,
+ IN CLONG InParameterCount,
+ IN OUT PCLONG OutParameterCount,
+ IN OUT PVOID Data,
+ IN CLONG InDataCount,
+ IN OUT PCLONG OutDataCount
+ )
+
+{
+ PSMB_HEADER header;
+ PREQ_TRANSACTION request;
+ PREQ_NT_TRANSACTION ntRequest;
+
+ NTSTATUS status;
+ NTSTATUS initStatus;
+ CLONG smbSize;
+
+ PUSHORT pSetup;
+ PUSHORT pBcc;
+ PUCHAR pParam, pData, pName; // pointer to field
+ CLONG lParam, lData, lName; // length of field
+ CLONG oParam, oData; // offset of field in SMB
+ CLONG dParam, dData; // displacement of these bytes
+ CLONG rParam, rData; // remaining bytes to be sent
+
+ //
+ // Build the primary request.
+ //
+
+ header = (PSMB_HEADER)Redir->Data[0];
+
+ status = MakeSmbHeader(
+ Redir,
+ header,
+ Command,
+ IdSelections,
+ IdValues
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ request = (PREQ_TRANSACTION)(header + 1);
+ ntRequest = (PREQ_NT_TRANSACTION)(header + 1);
+
+ RtlZeroMemory(
+ request,
+ MAX( sizeof(REQ_TRANSACTION), sizeof(REQ_NT_TRANSACTION) )
+ );
+
+ if ( Command == SMB_COM_NT_TRANSACT ) {
+ ntRequest->WordCount = (UCHAR)(19 + InSetupCount);
+ SmbPutUshort( &ntRequest->TotalParameterCount, (USHORT)InParameterCount );
+ SmbPutUshort( &ntRequest->TotalDataCount, (USHORT)InDataCount );
+ SmbPutUshort( &ntRequest->MaxParameterCount, *(PUSHORT)OutParameterCount );
+ SmbPutUshort( &ntRequest->MaxDataCount, *(PUSHORT)OutDataCount );
+ ntRequest->MaxSetupCount = *(PUCHAR)OutSetupCount;
+ ntRequest->SetupCount = (UCHAR)InSetupCount;
+ ntRequest->Function = Function;
+
+ pSetup = (PUSHORT)ntRequest->Buffer;
+ } else {
+ request->WordCount = (UCHAR)(14 + InSetupCount);
+ SmbPutUshort( &request->TotalParameterCount, (USHORT)InParameterCount );
+ SmbPutUshort( &request->TotalDataCount, (USHORT)InDataCount );
+ SmbPutUshort( &request->MaxParameterCount, *(PUSHORT)OutParameterCount );
+ SmbPutUshort( &request->MaxDataCount, *(PUSHORT)OutDataCount );
+ request->MaxSetupCount = *(PUCHAR)OutSetupCount;
+ request->SetupCount = (UCHAR)InSetupCount;
+
+ pSetup = (PUSHORT)request->Buffer;
+ }
+
+ RtlMoveMemory( pSetup, Setup, InSetupCount * sizeof(USHORT) );
+
+ pBcc = pSetup + InSetupCount;
+// *(PUCHAR)(pBcc+1) = 0; // null transaction name
+
+ pName = (PUCHAR)(pBcc + 1);
+ lName = strlen(Name) + 1;
+
+ pParam = (PUCHAR)(pName + lName + 1);
+ oParam = (pParam - (PUCHAR)header + 3) & ~3;
+ pParam = (PUCHAR)header + oParam;
+ lParam = InParameterCount;
+ if ( oParam + lParam > (CLONG)Redir->MaxBufferSize ) {
+ lParam = (Redir->MaxBufferSize - oParam) & ~3;
+ pData = pParam + lParam;
+ oData = 0;
+ lData = 0;
+ } else {
+ pData = pParam + lParam;
+ oData = (pData - (PUCHAR)header + 3) & ~3;
+ pData = (PUCHAR)header + oData;
+ lData = InDataCount;
+ if ( oData + lData > (CLONG)Redir->MaxBufferSize ) {
+ lData = (Redir->MaxBufferSize - oData) & ~3;
+ }
+ }
+
+ if ( Command == SMB_COM_NT_TRANSACT ) {
+ SmbPutUlong( &ntRequest->ParameterCount, lParam );
+ SmbPutUlong( &ntRequest->ParameterOffset, oParam );
+ SmbPutUlong( &ntRequest->DataCount, lData );
+ SmbPutUlong( &ntRequest->DataOffset, oData );
+ } else {
+ SmbPutUshort( &request->ParameterCount, (USHORT)lParam );
+ SmbPutUshort( &request->ParameterOffset, (USHORT)oParam );
+ SmbPutUshort( &request->DataCount, (USHORT)lData );
+ SmbPutUshort( &request->DataOffset, (USHORT)oData );
+ }
+
+ SmbPutUshort( pBcc, (USHORT)(pData - (PUCHAR)(pBcc+1) + lData) );
+
+ if ( lName > 0 ) {
+ RtlMoveMemory( pName, Name, lName );
+ }
+ if ( lParam > 0 ) {
+ RtlMoveMemory( pParam, Parameters, lParam );
+ }
+ if ( lData > 0 ) {
+ RtlMoveMemory( pData, Data, lData );
+ }
+
+ dParam = lParam;
+ rParam = InParameterCount - lParam;
+ dData = lData;
+ rData = InDataCount - lData;
+
+ smbSize = pData - (PUCHAR)header + lData;
+
+ //
+ // Send the primary request, and receive either the interim response
+ // or the first (possibly only) secondary response.
+ //
+
+ status = SendAndReceiveSmb(
+ Redir,
+ DebugString,
+ smbSize,
+ 0,
+ 1
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ //
+ // If there's more data to send, then interpret the response as an
+ // interim one, and send the remaining request messages.
+ //
+
+ while ( rParam + rData > 0 ) {
+
+ PREQ_TRANSACTION_SECONDARY request; // overrides outer declaration
+ PREQ_NT_TRANSACTION_SECONDARY ntRequest; // overrides outer declaration
+
+ status = VerifySmbHeader(
+ Redir,
+ IdSelections,
+ IdValues,
+ (PSMB_HEADER)Redir->Data[1],
+ Command
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ //
+ // Build the secondary request.
+ //
+
+ if ( Command == SMB_COM_NT_TRANSACT ) {
+ header->Command = SMB_COM_NT_TRANSACT_SECONDARY;
+ } else {
+ header->Command = SMB_COM_TRANSACTION2_SECONDARY;
+ }
+
+ request = (PREQ_TRANSACTION_SECONDARY)(header + 1);
+ ntRequest = (PREQ_NT_TRANSACTION_SECONDARY)(header + 1);
+
+ RtlZeroMemory(
+ request,
+ MAX(
+ sizeof(REQ_TRANSACTION_SECONDARY),
+ sizeof(REQ_NT_TRANSACTION_SECONDARY)
+ )
+ );
+
+ if ( Command == SMB_COM_NT_TRANSACT ) {
+ ntRequest->WordCount = (UCHAR)18;
+ SmbPutUlong(
+ &ntRequest->TotalParameterCount,
+ InParameterCount
+ );
+ SmbPutUlong( &ntRequest->TotalDataCount, InDataCount );
+ pParam = request->Buffer;
+ } else {
+ request->WordCount = (UCHAR)9;
+ SmbPutUshort(
+ &request->TotalParameterCount,
+ (USHORT)InParameterCount
+ );
+ SmbPutUshort( &request->TotalDataCount, (USHORT)InDataCount );
+ pParam = request->Buffer + 2; // Leave space for 9th word (fid)
+ }
+
+ oParam = (pParam - (PUCHAR)header + 3) & ~3;
+ pParam = (PUCHAR)header + oParam;
+ lParam = rParam;
+ if ( oParam + lParam > (CLONG)Redir->MaxBufferSize ) {
+ lParam = (Redir->MaxBufferSize - oParam) & ~3;
+ pData = pParam + lParam;
+ oData = 0;
+ lData = 0;
+ } else {
+ pData = pParam + lParam;
+ oData = (pData - (PUCHAR)header + 3) & ~3;
+ pData = (PUCHAR)header + oData;
+ lData = rData;
+ if ( oData + lData > (CLONG)Redir->MaxBufferSize ) {
+ lData = (Redir->MaxBufferSize - oData) & ~3;
+ }
+ }
+
+ if ( Command == SMB_COM_NT_TRANSACT ) {
+ SmbPutUlong( &ntRequest->ParameterCount, lParam );
+ SmbPutUlong( &ntRequest->ParameterOffset, oParam );
+ SmbPutUlong( &ntRequest->ParameterDisplacement, dParam );
+ SmbPutUlong( &ntRequest->DataCount, lData );
+ SmbPutUlong( &ntRequest->DataOffset, oData );
+ SmbPutUlong( &ntRequest->DataDisplacement, dData );
+ SmbPutUshort(
+ &request->ByteCount,
+ (USHORT)(pData - (request->Buffer+2) + lData)
+ );
+ } else {
+ SmbPutUshort( &request->ParameterCount, (USHORT)lParam );
+ SmbPutUshort( &request->ParameterOffset, (USHORT)oParam );
+ SmbPutUshort( &request->ParameterDisplacement, (USHORT)dParam );
+ SmbPutUshort( &request->DataCount, (USHORT)lData );
+ SmbPutUshort( &request->DataOffset, (USHORT)oData );
+ SmbPutUshort( &request->DataDisplacement, (USHORT)dData );
+
+ //
+ // Since we are using the transaction response description,
+ // but this is a transaction2, put the ByteCount 2 bytes
+ // back so that it is in the right place.
+ //
+
+ SmbPutUshort(
+ &(request->ByteCount) + 1,
+ (USHORT)(pData - (request->Buffer+2) + lData)
+ );
+ }
+
+ if ( lParam > 0 ) {
+ RtlMoveMemory( pParam, (PUCHAR)Parameters+dParam, lParam );
+ }
+ if ( lData > 0 ) {
+ RtlMoveMemory( pData, (PUCHAR)Data+dData, lData );
+ }
+
+ dParam = lParam;
+ rParam = rParam - lParam;
+ dData = lData;
+ rData = rData - lData;
+
+ smbSize = pData - (PUCHAR)header + lData;
+
+ //
+ // If this isn't the last request message, just send it.
+ // Otherwise, send it and receive the first response.
+ //
+
+ if ( rParam + rData > 0 ) {
+ status = SendSmb(
+ Redir,
+ DebugString,
+ smbSize,
+ 0
+ );
+ } else {
+ status = SendAndReceiveSmb(
+ Redir,
+ DebugString,
+ smbSize,
+ 0,
+ 1
+ );
+ }
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ }
+
+ //
+ // All request messages have been sent, and the first response has
+ // been received.
+ //
+
+ lParam = 0;
+ lData = 0;
+
+ while ( TRUE ) {
+
+ PRESP_TRANSACTION response;
+ PRESP_NT_TRANSACTION ntResponse;
+
+ header = (PSMB_HEADER)Redir->Data[1];
+
+ status = VerifySmbHeader(
+ Redir,
+ IdSelections,
+ IdValues,
+ header,
+ Command
+ );
+ if ( !NT_SUCCESS(status) &&
+ status != STATUS_OS2_EA_ACCESS_DENIED &&
+ status != STATUS_OS2_EAS_DIDNT_FIT &&
+ status != STATUS_BUFFER_OVERFLOW ) {
+ return status;
+ }
+
+ initStatus = status;
+
+ response = (PRESP_TRANSACTION)(header + 1);
+ ntResponse = (PRESP_NT_TRANSACTION)(header + 1);
+
+ //
+ // Copy data from the response into output buffers.
+ //
+
+ if ( Command == SMB_COM_NT_TRANSACT ) {
+ if ( ntResponse->SetupCount != 0 ) {
+ RtlMoveMemory(
+ Setup,
+ ntResponse->Buffer,
+ ntResponse->SetupCount
+ );
+ *OutSetupCount = ntResponse->SetupCount;
+ }
+
+ if ( SmbGetUshort( &ntResponse->ParameterCount ) != 0 ) {
+ RtlMoveMemory(
+ (PUCHAR)Parameters +
+ SmbGetUshort( &ntResponse->ParameterDisplacement ),
+ (PUCHAR)header + SmbGetUshort( &ntResponse->ParameterOffset ),
+ SmbGetUshort( &ntResponse->ParameterCount )
+ );
+ lParam = lParam + SmbGetUshort( &ntResponse->ParameterCount );
+ }
+
+ if ( SmbGetUshort( &ntResponse->DataCount ) != 0 ) {
+ RtlMoveMemory(
+ (PUCHAR)Data + SmbGetUshort( &ntResponse->DataDisplacement ),
+ (PUCHAR)header + SmbGetUshort( &ntResponse->DataOffset ),
+ SmbGetUshort( &ntResponse->DataCount )
+ );
+ lData = lData + SmbGetUshort( &ntResponse->DataCount );
+ }
+
+ //
+ // If all data has been received, jump out.
+ //
+
+ if ( (lParam ==
+ SmbGetUlong( &ntResponse->TotalParameterCount )) &&
+ (lData == SmbGetUlong( &ntResponse->TotalDataCount )) ) {
+ *OutParameterCount = lParam;
+ *OutDataCount = lData;
+ return initStatus;
+ }
+
+ } else {
+ if ( response->SetupCount != 0 ) {
+ RtlMoveMemory(
+ Setup,
+ response->Buffer,
+ response->SetupCount
+ );
+ *OutSetupCount = response->SetupCount;
+ }
+
+ if ( SmbGetUshort( &response->ParameterCount ) != 0 ) {
+ RtlMoveMemory(
+ (PUCHAR)Parameters +
+ SmbGetUshort( &response->ParameterDisplacement ),
+ (PUCHAR)header + SmbGetUshort( &response->ParameterOffset ),
+ SmbGetUshort( &response->ParameterCount )
+ );
+ lParam = lParam + SmbGetUshort( &response->ParameterCount );
+ }
+
+ if ( SmbGetUshort( &response->DataCount ) != 0 ) {
+ RtlMoveMemory(
+ (PUCHAR)Data + SmbGetUshort( &response->DataDisplacement ),
+ (PUCHAR)header + SmbGetUshort( &response->DataOffset ),
+ SmbGetUshort( &response->DataCount )
+ );
+ lData = lData + SmbGetUshort( &response->DataCount );
+ }
+
+ //
+ // If all data has been received, jump out.
+ //
+
+ if ( ((USHORT)lParam ==
+ SmbGetUshort( &response->TotalParameterCount )) &&
+ ((USHORT)lData == SmbGetUshort( &response->TotalDataCount )) ) {
+ *OutParameterCount = lParam;
+ *OutDataCount = lData;
+ return initStatus;
+ }
+
+ }
+
+ //
+ // Receive another response message.
+ //
+
+ status = ReceiveSmb(
+ Redir,
+ DebugString,
+ 1
+ );
+ }
+
+} // SendAndReceiveTransaction
+
+
+NTSTATUS
+SendSmb(
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN ULONG SmbSize,
+ IN UCHAR SendBuffer
+ )
+
+{
+ NTSTATUS status;
+
+ status = StartSend(
+ DebugString,
+ Redir->FileHandle,
+ Redir->EventHandle[SendBuffer],
+ &Redir->Iosb[SendBuffer],
+ Redir->Data[SendBuffer],
+ SmbSize
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ status = WaitForSendOrReceive(
+ DebugString,
+ Redir,
+ SendBuffer,
+ "send"
+ );
+ if ( !NT_SUCCESS(status) ) {
+ return status;
+ }
+
+ return STATUS_SUCCESS;
+
+} // SendSmb
+
+
+NTSTATUS
+StartReceive (
+ IN PSZ Operation,
+ IN HANDLE FileHandle,
+ IN HANDLE EventHandle,
+ IN PIO_STATUS_BLOCK Iosb,
+ IN PVOID Buffer,
+ IN ULONG BufferLength
+ )
+{
+ NTSTATUS status;
+
+ IF_DEBUG(2) printf( "Starting %s receive\n", Operation );
+ status = NtDeviceIoControlFile(
+ FileHandle,
+ EventHandle,
+ NULL,
+ NULL,
+ Iosb,
+ IOCTL_TDI_RECEIVE,
+ NULL,
+ 0,
+ (PVOID)Buffer,
+ BufferLength
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ printf( "NtDeviceIoControlFile (%s) service failed: %X\n",
+ Operation, status );
+ return status;
+ }
+
+ return STATUS_SUCCESS;
+
+} // StartReceive
+
+
+NTSTATUS
+StartSend (
+ IN PSZ Operation,
+ IN HANDLE FileHandle,
+ IN HANDLE EventHandle,
+ IN PIO_STATUS_BLOCK Iosb,
+ IN PVOID Buffer,
+ IN ULONG BufferLength
+ )
+{
+ NTSTATUS status;
+
+ IF_DEBUG(2) printf( "Starting %s send\n", Operation );
+ status = NtDeviceIoControlFile(
+ FileHandle,
+ EventHandle,
+ NULL,
+ NULL,
+ Iosb,
+ IOCTL_TDI_SEND,
+ NULL,
+ 0,
+ (PVOID)Buffer,
+ BufferLength
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ printf( "NtDeviceIoControlFile (%s) service failed: %X\n",
+ Operation, status );
+ DbgBreakPoint( );
+ return status;
+ }
+
+ return STATUS_SUCCESS;
+
+} // StartSend
+
+
+NTSTATUS
+WaitForSendOrReceive (
+ IN PSZ Operation,
+ IN PDESCRIPTOR Redir,
+ IN UCHAR EventNumber,
+ IN PSZ SendOrReceive
+ )
+{
+ NTSTATUS status;
+
+ IF_DEBUG(2) printf( "Waiting for %s %s\n", Operation, SendOrReceive );
+ status = NtWaitForSingleObject(
+ Redir->EventHandle[EventNumber],
+ FALSE,
+ NULL
+ );
+ IF_DEBUG(2) printf( "%s %s complete\n", Operation, SendOrReceive );
+ if ( !NT_SUCCESS(status) ) {
+ printf( "KeWaitForSingleObject (%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;
+
+} // WaitForSendOrReceive
+
+
+VOID
+AllocateAndBuildFeaList (
+ IN PVOID *Information,
+ IN PULONG InformationLength,
+ IN PSZ argv[],
+ IN SHORT argc
+ )
+
+{
+ LONG i;
+ PFEA fea;
+
+ *InformationLength = 4;
+
+ for ( i = 1; i < argc-1; i++ ) {
+
+ if ( *argv[i+1] == '~' ) {
+ *argv[i+1] = '\0';
+ }
+
+ *InformationLength += sizeof(FEA) + strlen( argv[i++] ) + 1 +
+ strlen( argv[i] );
+ }
+
+ *Information = malloc( *InformationLength );
+
+ for ( i = 1, fea = (PFEA)((PCHAR)*Information + 4); i < argc-1; i++ ) {
+
+ //
+ // Set the flags field. If the first character is '!', then
+ // set FILE_NEED_EA.
+ //
+
+ fea->fEA = (UCHAR)( (*argv[i] == '!') ? FILE_NEED_EA : 0 );
+
+ fea->cbName = (UCHAR)strlen( argv[i] );
+ SmbPutUshort( &fea->cbValue, (USHORT)strlen( argv[i+1] ) );
+
+ RtlMoveMemory( fea+1, argv[i], fea->cbName+1 );
+ RtlMoveMemory(
+ (PCHAR)(fea+1) + fea->cbName + 1,
+ argv[++i],
+ SmbGetUshort( &fea->cbValue )
+ );
+
+ (PCHAR)fea += sizeof(FEA) + fea->cbName + 1 +
+ SmbGetUshort( &fea->cbValue );
+ }
+
+ SmbPutUlong( (PULONG)*Information, *InformationLength );
+ return;
+
+} // AllocateAndBuildFeaList
+
+
+VOID
+BuildGeaList (
+ IN PVOID Information,
+ IN PULONG InformationLength,
+ IN PSZ argv[],
+ IN SHORT argc
+ )
+
+{
+ SHORT i;
+ PGEA gea;
+
+ *InformationLength = 4;
+
+ for ( i = 1; i < argc; i++ ) {
+ *InformationLength += sizeof(GEA) + strlen( argv[i] );
+ }
+
+ for ( i = 1, gea = (PGEA)((PCHAR)Information + 4); i < argc; i++ ) {
+ gea->cbName = (UCHAR)strlen( argv[i] );
+ RtlMoveMemory( gea->szName, argv[i], gea->cbName+1 );
+ gea = (PGEA)((PCHAR)gea + sizeof(GEA) + gea->cbName);
+ }
+
+ SmbPutUlong( (PULONG)Information, *InformationLength );
+ return;
+
+} // BuildGeaList
+
+#ifdef DOSERROR
+
+VOID
+PrintError (
+ IN USHORT ErrorClass,
+ IN USHORT ErrorCode
+ )
+
+{
+ CSHORT i;
+
+ switch ( ErrorClass ) {
+
+ case SMB_ERR_CLASS_DOS:
+ printf( "Error Class: DOS " );
+ break;
+
+ case SMB_ERR_CLASS_SERVER:
+ printf( "Error Class: Server " );
+ break;
+
+ case SMB_ERR_CLASS_HARDWARE:
+ printf( "Error Class: Hardware " );
+ break;
+
+ default:
+ printf( "Unknown error class: %ld, error code %ld\n",
+ ErrorClass, ErrorCode );
+ return;
+ }
+
+ for ( i = 0; Errors[ErrorClass][i].ErrorValue != 0; i++ ) {
+ if ( Errors[ErrorClass][i].ErrorValue == ErrorCode ) {
+ printf( "Error Code: %s\n", Errors[ErrorClass][i].ErrorName );
+ return;
+ }
+ }
+
+ printf( "Unknown error code: %ld\n", ErrorCode );
+ return;
+}
+
+#else
+
+VOID
+PrintError (
+ IN NTSTATUS Status
+ )
+
+{
+ printf ("Status: %lx\n", Status );
+ return;
+}
+
+#endif
+
+
+VOID
+PrintFeaList (
+ IN PFEALIST FeaList
+ )
+
+{
+ PFEA fea, lastFeaStartLocation;
+
+ lastFeaStartLocation = (PFEA)( (PCHAR)FeaList +
+ SmbGetUlong( &FeaList->cbList ) - sizeof(FEA) );
+
+ if ( SmbGetUlong( &FeaList->cbList ) < sizeof(FEA) + 4) {
+ printf( "No EAs.\n" );
+ return;
+ }
+
+ for ( fea = FeaList->list;
+ fea <= lastFeaStartLocation;
+ (PCHAR)fea += sizeof(FEA) + fea->cbName + 1 +
+ SmbGetUshort( &fea->cbValue ) ) {
+
+ STRING eaValue;
+
+ eaValue.Length = SmbGetUshort( &fea->cbValue );
+ eaValue.Buffer = ((PCHAR)(fea+1) + fea->cbName + 1);
+
+ printf( "EA name: %s, ", fea+1 );
+ printf( "value length: %ld, ", SmbGetUshort( &fea->cbValue ) );
+ if ( eaValue.Length == 0 ) {
+ printf( "(no value)\n" );
+ } else {
+ printf( "Value: %Z\n", &eaValue );
+ }
+ }
+
+ return;
+
+} // PrintFeaList
+
+
+#if SMBDBG
+
+//
+// The following functions are defined in smbgtpt.h. When debug mode is
+// disabled (!DBG), these functions are instead defined as macros.
+//
+
+USHORT
+SmbGetUshort (
+ IN PUSHORT SrcAddress
+ )
+
+{
+ return (USHORT)(
+ ( ( (PUCHAR)(SrcAddress) )[0] ) |
+ ( ( (PUCHAR)(SrcAddress) )[1] << 8 )
+ );
+}
+
+USHORT
+SmbGetAlignedUshort (
+ IN PUSHORT SrcAddress
+ )
+
+{
+ return *(SrcAddress);
+}
+
+VOID
+SmbPutUshort (
+ OUT PUSHORT DestAddress,
+ IN USHORT Value
+ )
+
+{
+ ( (PUCHAR)(DestAddress) )[0] = BYTE_0(Value);
+ ( (PUCHAR)(DestAddress) )[1] = BYTE_1(Value);
+ return;
+}
+
+VOID
+SmbPutAlignedUshort (
+ OUT PUSHORT DestAddress,
+ IN USHORT Value
+ )
+
+{
+ *(DestAddress) = (Value);
+ return;
+}
+
+VOID
+SmbMoveUshort (
+ OUT PUSHORT DestAddress,
+ IN PUSHORT SrcAddress
+ )
+
+{
+ ( (PUCHAR)(DestAddress) )[0] = ( (PUCHAR)(SrcAddress) )[0];
+ ( (PUCHAR)(DestAddress) )[1] = ( (PUCHAR)(SrcAddress) )[1];
+ return;
+}
+
+ULONG
+SmbGetUlong (
+ IN PULONG SrcAddress
+ )
+
+{
+ return (ULONG)(
+ ( ( (PUCHAR)(SrcAddress) )[0] ) |
+ ( ( (PUCHAR)(SrcAddress) )[1] << 8 ) |
+ ( ( (PUCHAR)(SrcAddress) )[2] << 16 ) |
+ ( ( (PUCHAR)(SrcAddress) )[3] << 24 )
+ );
+}
+
+ULONG
+SmbGetAlignedUlong (
+ IN PULONG SrcAddress
+ )
+
+{
+ return *(SrcAddress);
+}
+
+VOID
+SmbPutUlong (
+ OUT PULONG DestAddress,
+ IN ULONG Value
+ )
+
+{
+ ( (PUCHAR)(DestAddress) )[0] = BYTE_0(Value);
+ ( (PUCHAR)(DestAddress) )[1] = BYTE_1(Value);
+ ( (PUCHAR)(DestAddress) )[2] = BYTE_2(Value);
+ ( (PUCHAR)(DestAddress) )[3] = BYTE_3(Value);
+ return;
+}
+
+VOID
+SmbPutAlignedUlong (
+ OUT PULONG DestAddress,
+ IN ULONG Value
+ )
+
+{
+ *(DestAddress) = Value;
+ return;
+}
+
+VOID
+SmbMoveUlong (
+ OUT PULONG DestAddress,
+ IN PULONG SrcAddress
+ )
+
+{
+ ( (PUCHAR)(DestAddress) )[0] = ( (PUCHAR)(SrcAddress) )[0];
+ ( (PUCHAR)(DestAddress) )[1] = ( (PUCHAR)(SrcAddress) )[1];
+ ( (PUCHAR)(DestAddress) )[2] = ( (PUCHAR)(SrcAddress) )[2];
+ ( (PUCHAR)(DestAddress) )[3] = ( (PUCHAR)(SrcAddress) )[3];
+ return;
+}
+
+VOID
+SmbPutDate (
+ OUT PSMB_DATE DestAddress,
+ IN SMB_DATE Value
+ )
+
+{
+ ( (PUCHAR)&(DestAddress)->Ushort )[0] = BYTE_0(Value.Ushort);
+ ( (PUCHAR)&(DestAddress)->Ushort )[1] = BYTE_1(Value.Ushort);
+ return;
+}
+
+VOID
+SmbMoveDate (
+ OUT PSMB_DATE DestAddress,
+ IN PSMB_DATE SrcAddress
+ )
+
+{
+ (DestAddress)->Ushort = (USHORT)(
+ ( ( (PUCHAR)&(SrcAddress)->Ushort )[0] ) |
+ ( ( (PUCHAR)&(SrcAddress)->Ushort )[1] << 8 ) );
+ return;
+}
+
+VOID
+SmbZeroDate (
+ IN PSMB_DATE Date
+ )
+
+{
+ (Date)->Ushort = 0;
+}
+
+BOOLEAN
+SmbIsDateZero (
+ IN PSMB_DATE Date
+ )
+
+{
+ return (BOOLEAN)( (Date)->Ushort == 0 );
+}
+
+VOID
+SmbPutTime (
+ OUT PSMB_TIME DestAddress,
+ IN SMB_TIME Value
+ )
+
+{
+ ( (PUCHAR)&(DestAddress)->Ushort )[0] = BYTE_0(Value.Ushort);
+ ( (PUCHAR)&(DestAddress)->Ushort )[1] = BYTE_1(Value.Ushort);
+ return;
+}
+
+VOID
+SmbMoveTime (
+ OUT PSMB_TIME DestAddress,
+ IN PSMB_TIME SrcAddress
+ )
+
+{
+ (DestAddress)->Ushort = (USHORT)(
+ ( ( (PUCHAR)&(SrcAddress)->Ushort )[0] ) |
+ ( ( (PUCHAR)&(SrcAddress)->Ushort )[1] << 8 ) );
+ return;
+}
+
+VOID
+SmbZeroTime (
+ IN PSMB_TIME Time
+ )
+
+{
+ (Time)->Ushort = 0;
+}
+
+BOOLEAN
+SmbIsTimeZero (
+ IN PSMB_TIME Time
+ )
+
+{
+ return (BOOLEAN)( (Time)->Ushort == 0 );
+}
+
+#endif // SMBDBG
+
+
+//
+// Named pipe functions
+//
+
+
+
+NTSTATUS
+WaitNamedPipe(
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues
+ )
+
+{
+ NTSTATUS status;
+ SHORT setup[] = { 0x53, 0 };
+ CLONG outSetupCount = 0;
+ PUCHAR parameters = NULL;
+ CLONG outParameterCount = 0;
+ PUCHAR data = NULL;
+ CLONG outDataCount = 0;
+
+ status = SendAndReceiveTransaction(
+ Redir,
+ DebugString,
+ IdSelections,
+ IdValues,
+ SMB_COM_TRANSACTION,
+ setup,
+ sizeof (setup) / sizeof (SHORT),
+ &outSetupCount,
+ TestPipeName,
+ 0,
+ parameters,
+ 0, // sizeof (parameters)
+ &outParameterCount,
+ data,
+ 0, // sizeof (data)
+ &outDataCount
+ );
+
+ return status;
+}
+
+
+
+NTSTATUS
+QueryNamedPipeHandle(
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues
+ )
+
+{
+ NTSTATUS status;
+ SHORT setup[] = { 0x21, 0 };
+ CLONG outSetupCount = 0;
+ UCHAR parameters[2];
+ CLONG outParameterCount = 2;
+ PUCHAR data;
+ CLONG outDataCount = 0;
+
+ setup[1] = IdValues->Fid[IdSelections->Fid]; // Put fid in setup2
+
+ status = SendAndReceiveTransaction(
+ Redir,
+ DebugString,
+ IdSelections,
+ IdValues,
+ SMB_COM_TRANSACTION,
+ setup,
+ sizeof (setup) / sizeof (SHORT),
+ &outSetupCount,
+ TestPipeName,
+ 0,
+ parameters,
+ 0, // inParameterCount
+ &outParameterCount,
+ data,
+ 0, // inParamterCount
+ &outDataCount
+ );
+
+ printf ("Named pipe handle state is %x\n", *((PUSHORT)parameters));
+ return status;
+}
+
+
+NTSTATUS
+SetNamedPipeHandle(
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues,
+ IN USHORT HandleState
+ )
+
+{
+ NTSTATUS status;
+ SHORT setup[] = { 0x01, 0 };
+ CLONG outSetupCount = 0;
+ UCHAR parameters[2];
+ CLONG outParameterCount = 0;
+ PUCHAR data;
+ CLONG outDataCount = 0;
+
+ setup[1] = IdValues->Fid[IdSelections->Fid]; // Put fid in setup2
+ parameters[0] = (UCHAR) (HandleState & 0xFF);
+ parameters[1] = (UCHAR) (HandleState >> 8);
+
+ status = SendAndReceiveTransaction(
+ Redir,
+ DebugString,
+ IdSelections,
+ IdValues,
+ SMB_COM_TRANSACTION,
+ setup,
+ sizeof (setup) / sizeof (SHORT),
+ &outSetupCount,
+ TestPipeName,
+ 0,
+ parameters,
+ sizeof (parameters),
+ &outParameterCount,
+ data,
+ 0, // inDataCount
+ &outDataCount
+ );
+
+ return status;
+}
+
+
+NTSTATUS
+QueryNamedPipeInfo(
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues,
+ IN USHORT Level
+ )
+
+{
+ NTSTATUS status;
+ SHORT setup[2] = { 0x22, 0 };
+ CLONG outSetupCount = 0;
+ UCHAR parameters[2];
+ CLONG outParameterCount = 0;
+ PUCHAR data;
+ CLONG outDataCount = 0x100;
+
+ setup[1] = IdValues->Fid[IdSelections->Fid]; // Put fid in setup2
+ parameters[0] = (UCHAR) (Level & 0xFF);
+ parameters[1] = (UCHAR) (Level >> 8);
+
+ data = malloc( outDataCount );
+ if (data == NULL)
+ return STATUS_NO_MEMORY;
+
+ status = SendAndReceiveTransaction(
+ Redir,
+ DebugString,
+ IdSelections,
+ IdValues,
+ SMB_COM_TRANSACTION,
+ setup,
+ sizeof (setup) / sizeof (SHORT),
+ &outSetupCount,
+ TestPipeName,
+ 0,
+ parameters,
+ sizeof(parameters), // inParameterCount
+ &outParameterCount,
+ data,
+ 0, // inDataCount
+ &outDataCount
+ );
+
+ if (NT_SUCCESS(status)) {
+ printf ("Pipe status:\n");
+ printf ("\tOutput quota %d, input quota %d\n",
+ *((PUSHORT)&data[0]), *((PUSHORT)&data[2]));
+ printf ("\tMaximum instances %d, current instances %d\n",
+ (USHORT)data[4], (USHORT)data[5]);
+ printf ("\tPipe name (%d bytes) ""%s""\n", data[6], &data[7]);
+ }
+
+ free( data );
+ return status;
+}
+
+
+NTSTATUS
+CallNamedPipe(
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues,
+ IN USHORT OutputDataLength
+ )
+
+{
+ NTSTATUS status;
+ SHORT setup[] = { 0x54, 0 };
+ CLONG outSetupCount = 0;
+ PUCHAR parameters;
+ CLONG outParameterCount = 0;
+ PUCHAR data;
+ CLONG outDataCount = OutputDataLength;
+ USHORT i;
+
+ setup[1] = IdValues->Fid[IdSelections->Fid]; // Put fid in setup2
+
+ data = malloc( outDataCount );
+ if (data == NULL)
+ return STATUS_NO_MEMORY;
+
+ for (i=0; i < OutputDataLength; i++) {
+ data[i] = '$';
+ }
+
+ status = SendAndReceiveTransaction(
+ Redir,
+ DebugString,
+ IdSelections,
+ IdValues,
+ SMB_COM_TRANSACTION,
+ setup,
+ sizeof (setup) / sizeof (SHORT),
+ &outSetupCount,
+ TestPipeName,
+ 0,
+ parameters,
+ 0, // sizeof (parameters)
+ &outParameterCount,
+ data,
+ OutputDataLength,
+ &outDataCount
+ );
+
+ free( data );
+ return status;
+}
+
+
+NTSTATUS
+PeekNamedPipe(
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues,
+ IN USHORT BytesToRead
+ )
+
+{
+ NTSTATUS status;
+ SHORT setup[] = { 0x23, 0 };
+ CLONG outSetupCount = 0;
+ UCHAR parameters[6];
+ CLONG outParameterCount = 6;
+ PUCHAR data;
+ CLONG outDataCount = BytesToRead;
+ CLONG pipeState;
+ PSZ pipeStateString[] = { "Unknown",
+ "Disconnected",
+ "Listening",
+ "Connected",
+ "Closing"
+ };
+
+ setup[1] = IdValues->Fid[IdSelections->Fid]; // Put fid in setup2
+
+ data = malloc( outDataCount );
+ if (data == NULL)
+ return STATUS_NO_MEMORY;
+
+ status = SendAndReceiveTransaction(
+ Redir,
+ DebugString,
+ IdSelections,
+ IdValues,
+ SMB_COM_TRANSACTION,
+ setup,
+ sizeof (setup) / sizeof (SHORT),
+ &outSetupCount,
+ TestPipeName,
+ 0,
+ parameters,
+ 0, // sizeof (parameters)
+ &outParameterCount,
+ data,
+ 0, // sizeof (data)
+ &outDataCount
+ );
+
+ if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {
+ printf ("Pipe info:\n");
+ printf ("\tBytes remaining in pipe %d\n", *(PUSHORT)&parameters[0]);
+ printf ("\tBytes remaining in message %d\n",
+ *(PUSHORT)&parameters[2]);
+ pipeState = *(PUSHORT)&parameters[4];
+ printf ("\tPipe state %s\n",
+ pipeState <= 4 ? pipeStateString[pipeState] : "Unknown");
+ }
+ free( data );
+ return status;
+}
+
+
+NTSTATUS
+TransactNamedPipe(
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues,
+ IN PUCHAR OutputData,
+ IN USHORT OutputDataLength
+ )
+
+{
+ NTSTATUS status;
+ SHORT setup[] = { 0x26, 0 };
+ CLONG outSetupCount = 0;
+ PUCHAR parameters;
+ CLONG outParameterCount = 0;
+ PUCHAR data;
+ CLONG outDataCount = OutputDataLength;
+
+ setup[1] = IdValues->Fid[IdSelections->Fid]; // Put fid in setup2
+
+ data = malloc( outDataCount );
+ if (data == NULL)
+ return STATUS_NO_MEMORY;
+
+ RtlMoveMemory( data, OutputData, OutputDataLength );
+
+ status = SendAndReceiveTransaction(
+ Redir,
+ DebugString,
+ IdSelections,
+ IdValues,
+ SMB_COM_TRANSACTION,
+ setup,
+ sizeof (setup) / sizeof (SHORT),
+ &outSetupCount,
+ TestPipeName,
+ 0,
+ parameters,
+ 0, // sizeof (parameters)
+ &outParameterCount,
+ data,
+ OutputDataLength,
+ &outDataCount
+ );
+
+ free( data );
+ return status;
+}
+
+
+NTSTATUS
+RawReadNamedPipe(
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues
+ )
+
+{
+ NTSTATUS status;
+ SHORT setup[] = { 0x11, 0 };
+ CLONG outSetupCount = 0;
+ PUCHAR parameters;
+ CLONG outParameterCount = 2;
+ PUCHAR data;
+ CLONG outDataCount = 0;
+
+ setup[1] = IdValues->Fid[IdSelections->Fid]; // Put fid in setup2
+
+ status = SendAndReceiveTransaction(
+ Redir,
+ DebugString,
+ IdSelections,
+ IdValues,
+ SMB_COM_TRANSACTION,
+ setup,
+ sizeof (setup) / sizeof (SHORT),
+ &outSetupCount,
+ TestPipeName,
+ 0,
+ parameters,
+ 0, // sizeof (parameters)
+ &outParameterCount,
+ data,
+ 0, // sizeof (data)
+ &outDataCount
+ );
+
+ return status;
+}
+
+
+
+NTSTATUS
+RawWriteNamedPipe(
+ IN PDESCRIPTOR Redir,
+ IN PSZ DebugString,
+ IN PID_SELECTIONS IdSelections,
+ IN PID_VALUES IdValues
+ )
+
+{
+ NTSTATUS status;
+ SHORT setup[] = { 0x31, 0 };
+ CLONG outSetupCount = 0;
+ UCHAR parameters[2];
+ CLONG outParameterCount = 2;
+ UCHAR data[] = { 0, 0 };
+ CLONG outDataCount = 0;
+
+ setup[1] = IdValues->Fid[IdSelections->Fid]; // Put fid in setup2
+
+ status = SendAndReceiveTransaction(
+ Redir,
+ DebugString,
+ IdSelections,
+ IdValues,
+ SMB_COM_TRANSACTION,
+ setup,
+ sizeof (setup) / sizeof (SHORT),
+ &outSetupCount,
+ TestPipeName,
+ 0,
+ parameters,
+ 0, // sizeof (parameters)
+ &outParameterCount,
+ data,
+ sizeof (data),
+ &outDataCount
+ );
+
+ if (NT_SUCCESS(status) && *((PUSHORT)parameters) != 2) {
+ printf( "RawWriteNamedPipe returned %d bytes written\n",
+ *((PUSHORT)parameters));
+ }
+
+ return status;
+}