/*++ 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)¶meters[0]); printf ("\tBytes remaining in message %d\n", *(PUSHORT)¶meters[2]); pipeState = *(PUSHORT)¶meters[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; }