955 lines
38 KiB
C
955 lines
38 KiB
C
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Stuffer.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the SMBstuffer formating primitives. the following controlstring
|
|
characters are defined for the stuffer: (** means nyi...**d means downlevel part not implemented)
|
|
|
|
0 placeholder for the wct
|
|
1 pad to word boundary
|
|
X placeholderfor&X
|
|
W,w format a word from the next parameter
|
|
D,d format the next parameter as a Dword
|
|
Y,y format the next parameter as a byte
|
|
L,l the next parameter is a PLARGE_INTEGER; format it in
|
|
M,m format a zero byte
|
|
** 2 the next parameter points to a tagged dialect ASCIZI string to be copied in
|
|
** 3 the next parameter points to a tagged devicename ASCIIZ string
|
|
4 the next parameter is either 04-tagged ASCIIZ or UNICODEZ as determined by flags2
|
|
> the next parameters is ASCIIZ or UNICODEZ as determined by flags2; it is to be appended
|
|
to the previous 04-tagged item by backing up over the previous null.
|
|
A,a the next parameter is an ASCIIZ string
|
|
U,u the next parameter is a UNICODEZ string
|
|
V,v the next parameter is a UNICODEnoZ string
|
|
z the next parameter is a PUNICODE_STRING to be stringed as ASCIZI
|
|
or UNICODEZ as determined by flags2
|
|
N,n the next parameter is a PNET_ROOT whose name is to be stringed as ASCIIZ
|
|
or UNICODEZ as determined by flags2
|
|
R,r the next 2 parameters are a PBYTE* and a size; reserve the region and store the pointer
|
|
Q,q the current position is the data offset WORD...remember it
|
|
5 the current position is the start of the data; fill in the data pointer
|
|
P,p the current position is the parameter offset WORD...remember it
|
|
6 the current position is the start of the parameters; fill in the param pointer
|
|
B,b the current position is the Bcc WORD...remember it; also, fill in wct
|
|
s the next parameter has the alignment information....pad accordingly
|
|
S pad to DWORD
|
|
c the next 2 parameters are count/addr...copy in the data.
|
|
! End of this protocol; fill in the bcc field
|
|
? next parameter is BOOLEAN_ULONG; 0=>immediate return
|
|
. NOOP
|
|
|
|
For controls with a upper/lowercase pair, the uppercase version indicates that a position tag
|
|
is supplied in the checked version.
|
|
|
|
Author:
|
|
|
|
Joe Linn 3-3-95
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, SmbStuffWrapRtlAssert)
|
|
#pragma alloc_text(PAGE, SmbMrxInitializeStufferFacilities)
|
|
#pragma alloc_text(PAGE, SmbMrxFinalizeStufferFacilities)
|
|
#pragma alloc_text(PAGE, MRxSmbSetInitialSMB)
|
|
#pragma alloc_text(PAGE, MRxSmbStartSMBCommand)
|
|
#pragma alloc_text(PAGE, MrxSMBWillThisFit)
|
|
#pragma alloc_text(PAGE, MRxSmbStuffSMB)
|
|
#pragma alloc_text(PAGE, MRxSmbStuffAppendRawData)
|
|
#pragma alloc_text(PAGE, MRxSmbStuffAppendSmbData)
|
|
#pragma alloc_text(PAGE, MRxSmbStuffSetByteCount)
|
|
#endif
|
|
|
|
//
|
|
// The local debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_ALWAYS)
|
|
|
|
|
|
#define MRXSMB_INITIAL_WCT (0xcc)
|
|
#define MRXSMB_INITIAL_BCC (0xface)
|
|
#define MRXSMB_INITIAL_DATAOFFSET (0xd0ff)
|
|
#define MRXSMB_INITIAL_PARAMOFFSET (0xb0ff)
|
|
#define MRXSMB_INITIAL_ANDX (0xdede00ff)
|
|
|
|
#if 0
|
|
//this is old...........
|
|
#if DBG
|
|
|
|
// a little presto-changeo to get assert messages in user mode
|
|
// the key is that MRxSmbRxImports->pRxNetNameTable will not be NULL...
|
|
// it will point to the netnametable. this
|
|
// seems like a small enough price to pay on the way to an rtl assert!
|
|
|
|
VOID
|
|
SmbStuffWrapRtlAssert(
|
|
IN PVOID FailedAssertion,
|
|
IN PVOID FileName,
|
|
IN ULONG LineNumber,
|
|
IN PCHAR Message
|
|
)
|
|
|
|
{
|
|
char STARS[] = "**************************************";
|
|
|
|
PAGED_CODE();
|
|
|
|
if (MRxSmbRxImports->pRxNetNameTable == NULL){
|
|
// do our own thing
|
|
RxDbgTrace(0,Dbg,("%s\n%s\n",STARS,STARS));
|
|
RxDbgTrace (0,Dbg,("Failed Assertion %s\n",FailedAssertion));
|
|
RxDbgTrace(0,Dbg,("%s at line %lu\n",FileName,LineNumber));
|
|
if (Message) {
|
|
RxDbgTrace (0,Dbg,("%s\n",Message));
|
|
}
|
|
RxDbgTrace(0,Dbg,("%s\n%s\n",STARS,STARS));
|
|
} else RtlAssert(FailedAssertion,FileName,LineNumber,Message);
|
|
}
|
|
|
|
#ifdef RtlAssert
|
|
#undef RtlAssert
|
|
#endif //ifdef RtlAssert
|
|
#define RtlAssert SmbStuffWrapRtlAssert
|
|
|
|
#endif
|
|
#endif //if 0
|
|
|
|
|
|
NTSTATUS
|
|
SmbMrxInitializeStufferFacilities(
|
|
void
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine initializes things for the SMB minirdr. we will allocate enough stuff
|
|
to get us going. right now....we do nothing.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return(RX_MAP_STATUS(SUCCESS));
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbMrxFinalizeStufferFacilities(
|
|
void
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine finalizes things for the SMB minirdr. we give back everything that
|
|
we have allocated. right now....we do nothing.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return(RX_MAP_STATUS(SUCCESS));
|
|
}
|
|
#if DBG
|
|
#define BUILD_HEADER_ROUTINE BuildHeaderRoutine
|
|
typedef
|
|
NTSTATUS
|
|
(NTAPI *PMRXSMB_BUILD_HEADER_ROUTINE) (
|
|
PSMB_EXCHANGE pExchange,
|
|
PVOID pBuffer,
|
|
ULONG BufferLength,
|
|
PULONG pBufferConsumed,
|
|
PUCHAR pLastCommandInHeader,
|
|
PUCHAR *pNextCommandPtr
|
|
);
|
|
#else
|
|
#define BUILD_HEADER_ROUTINE SmbCeBuildSmbHeader
|
|
#endif
|
|
|
|
NTSTATUS
|
|
MRxSmbSetInitialSMB (
|
|
IN OUT PSMBSTUFFER_BUFFER_STATE StufferState
|
|
STUFFERTRACE_CONTROLPOINT_ARGS
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PNT_SMB_HEADER NtSmbHeader;
|
|
ULONG BufferConsumed;
|
|
PBYTE ScanPosition;
|
|
PUCHAR pCommand;
|
|
|
|
#if DBG
|
|
PMRXSMB_BUILD_HEADER_ROUTINE BUILD_HEADER_ROUTINE = SmbCeBuildSmbHeader;
|
|
#endif //if DBG
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT ( StufferState != NULL ); //CODE.IMPROVEMENT shouldn't we have a nodetype??
|
|
ASSERT ( sizeof(NT_SMB_HEADER) == sizeof(SMB_HEADER) );
|
|
//RxDbgTrace(0, Dbg, ("MrxSMBSetInitialSMB base=%08lx,limit=%08lx\n",
|
|
// StufferState->BufferBase,StufferState->BufferLimit));
|
|
ASSERT ( (StufferState->BufferLimit - StufferState->BufferBase) > sizeof(SMB_HEADER));
|
|
NtSmbHeader = (PNT_SMB_HEADER)(StufferState->BufferBase);
|
|
RtlZeroMemory(NtSmbHeader,sizeof(NT_SMB_HEADER));
|
|
|
|
//this stuff is reinitialized
|
|
StufferState->DataMdl = NULL; //note that this is not finalized or anything
|
|
StufferState->DataSize = 0;
|
|
StufferState->CurrentWct = NULL;
|
|
StufferState->PreviousCommand = SMB_COM_NO_ANDX_COMMAND;
|
|
StufferState->CurrentCommand = SMB_COM_NO_ANDX_COMMAND;
|
|
StufferState->FlagsCopy = 0;
|
|
StufferState->Flags2Copy = 0;
|
|
StufferState->CurrentPosition = ((PBYTE)NtSmbHeader);
|
|
|
|
RxDbgTraceDoit(
|
|
StufferState->ControlPoint = ControlPoint;
|
|
StufferState->PrintCLoop = FALSE;
|
|
StufferState->PrintFLoop = FALSE;
|
|
while (EnablePrints) {
|
|
ULONG c = EnablePrints & 0xff;
|
|
EnablePrints >>= 8;
|
|
if (c=='C') StufferState->PrintCLoop = TRUE;
|
|
if (c=='F') StufferState->PrintFLoop = TRUE;
|
|
if (c=='X') BUILD_HEADER_ROUTINE = MRxSmbBuildSmbHeaderTestSurrogate;
|
|
}
|
|
)
|
|
|
|
Status = BUILD_HEADER_ROUTINE(
|
|
StufferState->Exchange,
|
|
NtSmbHeader,
|
|
(ULONG)(StufferState->BufferLimit - StufferState->BufferBase),
|
|
&BufferConsumed,
|
|
&StufferState->PreviousCommand,
|
|
&pCommand);
|
|
|
|
if (Status!=RX_MAP_STATUS(SUCCESS)) {
|
|
RxDbgTrace(0, Dbg, ("MrxSMBSetInitialSMB buildhdr failure st=%08lx\n",Status));
|
|
RxLog(("BuildHdr failed %lx %lx",StufferState->Exchange,Status));
|
|
SmbLog(LOG,
|
|
MRxSmbSetInitialSMB,
|
|
LOGPTR(StufferState->Exchange)
|
|
LOGULONG(Status));
|
|
return Status;
|
|
}
|
|
|
|
//copy the flags
|
|
StufferState->FlagsCopy = NtSmbHeader->Flags;
|
|
StufferState->Flags2Copy = SmbGetAlignedUshort(&NtSmbHeader->Flags2);
|
|
if (StufferState->Exchange->Type == ORDINARY_EXCHANGE) {
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = (PSMB_PSE_ORDINARY_EXCHANGE)StufferState->Exchange;
|
|
if (BooleanFlagOn(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_TURNON_DFS_FLAG)) {
|
|
StufferState->Flags2Copy |= SMB_FLAGS2_DFS;
|
|
SmbPutUshort(&NtSmbHeader->Flags2,(USHORT)StufferState->Flags2Copy);
|
|
}
|
|
}
|
|
|
|
StufferState->CurrentPosition += BufferConsumed;
|
|
|
|
if (BufferConsumed > sizeof(SMB_HEADER)) {
|
|
if (pCommand != NULL) {
|
|
*pCommand = SMB_COM_NO_ANDX_COMMAND;
|
|
}
|
|
|
|
StufferState->CurrentWct = StufferState->CurrentPosition;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
#define RETURN_A_START_PROBLEM(xxyy) {\
|
|
RxDbgTrace(0,Dbg,("MRxSmbStartSMBCommand gotta problem= %lu\n",xxyy)); \
|
|
StufferState->SpecificProblem = xxyy; \
|
|
return(RX_MAP_STATUS(INVALID_PARAMETER)); \
|
|
}
|
|
NTSTATUS
|
|
MRxSmbStartSMBCommand (
|
|
IN OUT PSMBSTUFFER_BUFFER_STATE StufferState,
|
|
IN INITIAL_SMBBUG_DISPOSITION InitialSMBDisposition,
|
|
IN UCHAR Command, //joejoe this next four params could come from a table...2offset and you're smaller
|
|
IN ULONG MaximumBufferUsed,
|
|
IN ULONG MaximumSize,
|
|
IN ULONG InitialAlignment,
|
|
IN ULONG MaximumResponseHeader,
|
|
IN UCHAR Flags,
|
|
IN UCHAR FlagsMask,
|
|
IN USHORT Flags2,
|
|
IN USHORT Flags2Mask
|
|
STUFFERTRACE_CONTROLPOINT_ARGS
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine checks to see if the condition is stable. If not, it
|
|
goes into a wait loop alternately getting the resource and then
|
|
waiting on the event.
|
|
|
|
|
|
Arguments:
|
|
joejoe review this
|
|
StufferState - the header buffer being used
|
|
InitialSMBDisposition tells when/if to reinit the stuffer state
|
|
Command - the smb command being set up
|
|
MaximumBufferUsed - the amount of the header buffer that will be used (as opposed to the data)
|
|
this has to be conjured up in advance. if you're not willing to do this, then
|
|
just push out the current smb. this value should include any data pads!
|
|
MaximumSize - the size of the data. this is to keep from overrunning the srv's smbbuf
|
|
InitialAlignment - a compound argument (i.e. you get it from a constant) the top half
|
|
tells the alignment unit and the bottom gives the spacing within
|
|
MaximumResponseHeader - how much of the srv's response buffer this will use up
|
|
Flags - the required flags settings
|
|
FlagsMask - which bits of the flags are important
|
|
Flags2 - the required flags2 settings
|
|
Flags2Mask - which flags2 bits are important
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
UCHAR NewFlags;
|
|
USHORT NewFlags2;
|
|
PBYTE *CurrentPosition = &(StufferState->CurrentPosition);
|
|
PNT_SMB_HEADER NtSmbHeader = (PNT_SMB_HEADER)(StufferState->BufferBase);
|
|
ULONG AlignmentUnit = InitialAlignment >> 16;
|
|
ULONG StufferStateRequirement = MaximumBufferUsed + AlignmentUnit;
|
|
#if DBG
|
|
PBYTE OriginalPosition = *CurrentPosition;
|
|
#endif
|
|
|
|
PAGED_CODE();
|
|
|
|
if (StufferState->DataSize) {
|
|
StufferState->SpecificProblem = xSMBbufSTATUS_CANT_COMPOUND;
|
|
return(RX_MAP_STATUS(INVALID_PARAMETER));
|
|
}
|
|
|
|
if ((InitialSMBDisposition==SetInitialSMB_yyUnconditionally)
|
|
|| ((InitialSMBDisposition==SetInitialSMB_ForReuse)&&(StufferState->Started))) {
|
|
MRxSmbSetInitialSMB( StufferState STUFFERTRACE_NOPREFIX(ControlPoint,EnablePrints) );
|
|
}
|
|
|
|
StufferState->Started = TRUE;
|
|
|
|
//joejoe temporary hack
|
|
switch (StufferState->CurrentCommand) {
|
|
case SMB_COM_LOCKING_ANDX:
|
|
case SMB_COM_OPEN_ANDX:
|
|
case SMB_COM_READ_ANDX:
|
|
case SMB_COM_WRITE_ANDX:
|
|
case SMB_COM_SESSION_SETUP_ANDX:
|
|
//case SMB_COM_LOGOFF_ANDX:
|
|
case SMB_COM_TREE_CONNECT_ANDX:
|
|
case SMB_COM_NT_CREATE_ANDX:
|
|
case SMB_COM_NO_ANDX_COMMAND:
|
|
break;
|
|
default:
|
|
StufferState->SpecificProblem = xSMBbufSTATUS_CANT_COMPOUND;
|
|
return(RX_MAP_STATUS(INVALID_PARAMETER));
|
|
}
|
|
|
|
if (*CurrentPosition+StufferStateRequirement >= StufferState->BufferLimit ) {
|
|
StufferState->SpecificProblem = xSMBbufSTATUS_CANT_COMPOUND;
|
|
return(RX_MAP_STATUS(INVALID_PARAMETER));
|
|
}
|
|
|
|
if (StufferState->RxContext) {
|
|
PRX_CONTEXT RxContext = StufferState->RxContext;
|
|
PMRX_SRV_CALL SrvCall;
|
|
ULONG CurrentOffset;
|
|
if (RxContext->MajorFunction != IRP_MJ_CREATE) {
|
|
SrvCall = RxContext->pFcb->pNetRoot->pSrvCall; //joejoe cache it?
|
|
} else {
|
|
SrvCall = RxContext->Create.pSrvCall;
|
|
}
|
|
ASSERT(SrvCall);
|
|
CurrentOffset = (ULONG)(*CurrentPosition - StufferState->BufferBase);
|
|
if (CurrentOffset+StufferStateRequirement+MaximumSize
|
|
> GetServerMaximumBufferSize(SrvCall) ) {
|
|
StufferState->SpecificProblem = xSMBbufSTATUS_SERVER_OVERRUN;
|
|
return(RX_MAP_STATUS(INVALID_PARAMETER));
|
|
}
|
|
}
|
|
|
|
NewFlags = Flags | (UCHAR)(StufferState->FlagsCopy);
|
|
NewFlags2 = Flags2 | (USHORT)(StufferState->Flags2Copy);
|
|
if ( ((NewFlags&FlagsMask)!=Flags) ||
|
|
((NewFlags2&Flags2Mask)!=Flags2) ) {
|
|
StufferState->SpecificProblem = xSMBbufSTATUS_FLAGS_CONFLICT;
|
|
return(RX_MAP_STATUS(INVALID_PARAMETER));
|
|
}
|
|
StufferState->FlagsCopy = NtSmbHeader->Flags = NewFlags;
|
|
StufferState->Flags2Copy = NewFlags2;
|
|
SmbPutAlignedUshort(&NtSmbHeader->Flags2, NewFlags2);
|
|
|
|
if (!StufferState->CurrentWct) {
|
|
NtSmbHeader->Command = Command;
|
|
} else {
|
|
PGENERIC_ANDX GenericAndX = (PGENERIC_ANDX)StufferState->CurrentWct;
|
|
if (AlignmentUnit) {
|
|
ULONG AlignmentMask = (AlignmentUnit-1);
|
|
ULONG AlignmentResidue = InitialAlignment&AlignmentMask;
|
|
RxDbgTrace(0, Dbg, ("Aligning start of smb cp&m,m,r=%08lx %08lx %08lx\n",
|
|
((ULONG)(ULONG_PTR)(*CurrentPosition))&AlignmentMask,
|
|
AlignmentMask, AlignmentResidue)
|
|
);
|
|
for (;(((ULONG_PTR)(*CurrentPosition))&AlignmentMask)!=AlignmentResidue;) {
|
|
**CurrentPosition = ',';
|
|
*CurrentPosition += 1;
|
|
}
|
|
}
|
|
GenericAndX->AndXCommand = Command;
|
|
GenericAndX->AndXReserved = 0;
|
|
SmbPutUshort (&GenericAndX->AndXOffset,
|
|
(USHORT)(*CurrentPosition - StufferState->BufferBase));
|
|
}
|
|
StufferState->CurrentWct = *CurrentPosition;
|
|
StufferState->CurrentCommand = Command;
|
|
StufferState->CurrentDataOffset = 0;
|
|
return RX_MAP_STATUS(SUCCESS);
|
|
}
|
|
|
|
BOOLEAN
|
|
MrxSMBWillThisFit(
|
|
IN PSMBSTUFFER_BUFFER_STATE StufferState,
|
|
IN ULONG AlignmentUnit,
|
|
IN ULONG DataSize
|
|
)
|
|
{
|
|
//joejoe actually some stuff will fit that this says no...........
|
|
return(StufferState->CurrentPosition+AlignmentUnit+DataSize<StufferState->BufferLimit);
|
|
}
|
|
|
|
#if RDBSSTRACE
|
|
#define StufferFLoopTrace(Z) { if (StufferState->PrintFLoop) {RxDbgTraceLV__norx(0,StufferState->ControlPoint,900,Z);}}
|
|
#define StufferCLoopTrace(Z) { if (StufferState->PrintCLoop) {RxDbgTraceLV__norx(0,StufferState->ControlPoint,800,Z);}}
|
|
#else // DBG
|
|
#define StufferFLoopTrace(Z)
|
|
#define StufferCLoopTrace(Z)
|
|
#endif // DBG
|
|
|
|
NTSTATUS
|
|
MRxSmbStuffSMB (
|
|
IN OUT PSMBSTUFFER_BUFFER_STATE StufferState,
|
|
...
|
|
)
|
|
{
|
|
va_list AP;
|
|
PBYTE BufferBase = (StufferState->BufferBase);
|
|
PBYTE *CurrentPosition = &(StufferState->CurrentPosition);
|
|
PBYTE *CurrentWct = &(StufferState->CurrentWct);
|
|
PBYTE *CurrentBcc = &(StufferState->CurrentBcc);
|
|
PBYTE *CurrentDataOffset = &(StufferState->CurrentDataOffset);
|
|
PBYTE *CurrentParamOffset = &(StufferState->CurrentParamOffset);
|
|
SMB_STUFFER_CONTROLS CurrentStufferControl = STUFFER_CTL_NORMAL;
|
|
PSMB_HEADER SmbHeader = (PSMB_HEADER)BufferBase;
|
|
PSZ CurrentFormatString = NULL;
|
|
ULONG arg;
|
|
UCHAR WordCount;
|
|
USHORT ByteCount;
|
|
//joejoe change this to zero later.....apparently some servers croak on nonzero pad
|
|
#define PADBYTE ((UCHAR)0xee)
|
|
PBYTE CopyPtr; ULONG CopyCount,EarlyReturn;
|
|
PBYTE *RegionPtr;
|
|
PUNICODE_STRING Zstring;
|
|
PSZ Astring;
|
|
PNET_ROOT NetRoot;
|
|
PLARGE_INTEGER LargeInteger;
|
|
PBYTE PreviousPosition;
|
|
#if DBG
|
|
ULONG offset, required_WCT;
|
|
ULONG CurrentOffset_tmp;
|
|
#endif
|
|
|
|
PAGED_CODE();
|
|
|
|
va_start(AP,StufferState);
|
|
for (;;) {
|
|
switch (CurrentStufferControl) {
|
|
case STUFFER_CTL_SKIP:
|
|
case STUFFER_CTL_NORMAL:
|
|
CurrentFormatString = va_arg(AP,PSZ);
|
|
StufferCLoopTrace(("StufferAC = %s\n",CurrentFormatString));
|
|
ASSERT (CurrentFormatString);
|
|
for (;*CurrentFormatString;CurrentFormatString++) {
|
|
char CurrentFormatChar = *CurrentFormatString;
|
|
#if DBG
|
|
{ char msgbuf[80];
|
|
switch (CurrentFormatChar) {
|
|
case 'W': case 'w':
|
|
case 'D': case 'd':
|
|
case 'Y': case 'y':
|
|
case 'M': case 'm':
|
|
case 'L': case 'l':
|
|
case 'c': case '4': case '>':
|
|
case '!':
|
|
//this guys are skipable
|
|
break;
|
|
default:
|
|
if (CurrentStufferControl != STUFFER_CTL_SKIP) break;
|
|
DbgPrint("Bad skip char '%c'\n",*CurrentFormatString);
|
|
//DbgBreakPoint();
|
|
}}
|
|
//these are the ones that we do the offset check for
|
|
{ char msgbuf[80];
|
|
#ifndef WIN9X
|
|
RxSprintf(msgbuf,"control char '%c'\n",*CurrentFormatString);
|
|
#endif
|
|
switch (CurrentFormatChar) {
|
|
case 'W': case 'D': case 'Y': case 'M': case 'B':
|
|
case 'Q': case 'A': case 'U': case 'V':
|
|
case 'N':
|
|
case 'L':
|
|
case 'R':
|
|
case 'P':
|
|
offset = va_arg(AP,ULONG);
|
|
required_WCT = offset>>16;
|
|
offset = offset & 0xffff;
|
|
CurrentOffset_tmp = (ULONG)(*CurrentPosition-*CurrentWct);
|
|
if (offset && (offset != CurrentOffset_tmp)){
|
|
DbgPrint("Bad offset %d; should be %d\n",offset,CurrentOffset_tmp);
|
|
//DbgBreakPoint();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}}
|
|
#endif
|
|
switch (CurrentFormatChar) {
|
|
case '0':
|
|
StufferFLoopTrace((" StufferFloop '0'\n",0));
|
|
//just do the wct field...
|
|
**CurrentPosition = (UCHAR)MRXSMB_INITIAL_WCT;
|
|
*CurrentPosition+=1;
|
|
break;
|
|
case 'X':
|
|
StufferFLoopTrace((" StufferFloop 'X'\n",0));
|
|
//do the wct field and the &x
|
|
**CurrentPosition = (UCHAR)MRXSMB_INITIAL_WCT;
|
|
*CurrentPosition+=1;
|
|
SmbPutUlong (*CurrentPosition, (ULONG)MRXSMB_INITIAL_ANDX);
|
|
*CurrentPosition+=sizeof(ULONG);
|
|
break;
|
|
case 'W':
|
|
case 'w':
|
|
arg = va_arg(AP,ULONG);
|
|
if (CurrentStufferControl == STUFFER_CTL_SKIP) break;
|
|
StufferFLoopTrace((" StufferFloop 'w' arg=%lu\n",arg));
|
|
SmbPutUshort (*CurrentPosition, (USHORT)arg);
|
|
*CurrentPosition+=sizeof(USHORT);
|
|
break;
|
|
case 'Y':
|
|
case 'y':
|
|
arg = va_arg(AP,UCHAR);
|
|
if (CurrentStufferControl == STUFFER_CTL_SKIP) break;
|
|
StufferFLoopTrace((" StufferFloop 'y' arg=%lu\n",arg));
|
|
**CurrentPosition = (UCHAR)arg;
|
|
*CurrentPosition+=sizeof(UCHAR);
|
|
break;
|
|
case 'M':
|
|
case 'm':
|
|
if (CurrentStufferControl == STUFFER_CTL_SKIP) break;
|
|
StufferFLoopTrace((" StufferFloop 'm'\n",0));
|
|
**CurrentPosition = 0;
|
|
*CurrentPosition+=sizeof(UCHAR);
|
|
break;
|
|
case 'D':
|
|
case 'd':
|
|
arg = va_arg(AP,ULONG);
|
|
if (CurrentStufferControl == STUFFER_CTL_SKIP) break;
|
|
StufferFLoopTrace((" StufferFloop 'd' arg=%lu\n",arg));
|
|
SmbPutUlong (*CurrentPosition, arg);
|
|
*CurrentPosition+=sizeof(ULONG);
|
|
break;
|
|
case 'L':
|
|
case 'l':
|
|
LargeInteger = va_arg(AP,PLARGE_INTEGER);
|
|
if (CurrentStufferControl == STUFFER_CTL_SKIP) break;
|
|
StufferFLoopTrace((" StufferFloop 'l' arg=%0lx %0lx\n",
|
|
LargeInteger->HighPart, LargeInteger->LowPart));
|
|
SmbPutUlong (*CurrentPosition, LargeInteger->LowPart);
|
|
SmbPutUlong (*CurrentPosition, LargeInteger->HighPart);
|
|
*CurrentPosition+=2*sizeof(ULONG);
|
|
break;
|
|
case 'B':
|
|
case 'b':
|
|
ASSERT (**CurrentWct == MRXSMB_INITIAL_WCT);
|
|
WordCount = (UCHAR)((*CurrentPosition-*CurrentWct)>>1); //the one gets shifted off
|
|
StufferFLoopTrace((" StufferFloop 'b' Wct=%lu\n",WordCount));
|
|
DbgDoit( ASSERT(!required_WCT || (WordCount == (required_WCT&0x7fff))); )
|
|
**CurrentWct = (UCHAR)WordCount;
|
|
SmbPutUshort (*CurrentPosition, (USHORT)MRXSMB_INITIAL_BCC);
|
|
*CurrentBcc = *CurrentPosition;
|
|
*CurrentPosition+=sizeof(USHORT);
|
|
break;
|
|
case 'Q':
|
|
case 'q':
|
|
StufferFLoopTrace((" StufferFloop 'q' \n",0));
|
|
SmbPutUshort (*CurrentPosition, (USHORT)MRXSMB_INITIAL_DATAOFFSET);
|
|
*CurrentDataOffset = *CurrentPosition;
|
|
*CurrentPosition+=sizeof(USHORT);
|
|
break;
|
|
case '5':
|
|
//fill in the data offset
|
|
ASSERT (SmbGetUshort (*CurrentDataOffset) == MRXSMB_INITIAL_DATAOFFSET);
|
|
ByteCount = (USHORT)(*CurrentPosition-BufferBase);
|
|
StufferFLoopTrace((" StufferFloop '5' offset=%lu\n",ByteCount));
|
|
SmbPutUshort (*CurrentDataOffset, (USHORT)ByteCount);
|
|
break;
|
|
case 'P':
|
|
case 'p':
|
|
StufferFLoopTrace((" StufferFloop 'p' \n",0));
|
|
SmbPutUshort (*CurrentPosition, (USHORT)MRXSMB_INITIAL_PARAMOFFSET);
|
|
*CurrentParamOffset = *CurrentPosition;
|
|
*CurrentPosition+=sizeof(USHORT);
|
|
break;
|
|
case '6':
|
|
//fill in the data offset
|
|
ASSERT (SmbGetUshort (*CurrentParamOffset) == MRXSMB_INITIAL_PARAMOFFSET);
|
|
ByteCount = (USHORT)(*CurrentPosition-BufferBase);
|
|
StufferFLoopTrace((" StufferFloop '6' offset=%lu\n",ByteCount));
|
|
SmbPutUshort (*CurrentParamOffset, (USHORT)ByteCount);
|
|
break;
|
|
case 'S':
|
|
// pad to ULONG; we loop behind instead of adding so we can clear
|
|
// out behind ourselves; apparently, some server croak on nonzero padding
|
|
StufferFLoopTrace((" StufferFloop 'S' \n",0));
|
|
PreviousPosition = *CurrentPosition;
|
|
*CurrentPosition = (PBYTE)QuadAlignPtr(*CurrentPosition);
|
|
for (;PreviousPosition!=*CurrentPosition;) {
|
|
//StufferFLoopTrace((" StufferFloop 'S' prev,curr=%08lx %08lx\n",PreviousPosition,*CurrentPosition));
|
|
*PreviousPosition++ = PADBYTE;
|
|
}
|
|
break;
|
|
case 's':
|
|
// pad to arg; we loop behind instead of adding so we can clear
|
|
// out behind ourselves; apparently, some server croak on nonzero padding
|
|
arg = va_arg(AP,ULONG);
|
|
StufferFLoopTrace((" StufferFloop 's' arg=\n",arg));
|
|
PreviousPosition = *CurrentPosition;
|
|
*CurrentPosition += arg-1;
|
|
*CurrentPosition = (PBYTE)( ((ULONG_PTR)(*CurrentPosition)) & ~((LONG)(arg-1)) );
|
|
for (;PreviousPosition!=*CurrentPosition;) {
|
|
//StufferFLoopTrace((" StufferFloop 'S' prev,curr=%08lx %08lx\n",PreviousPosition,*CurrentPosition));
|
|
*PreviousPosition++ = PADBYTE;
|
|
}
|
|
break;
|
|
case '1':
|
|
// pad to USHORT; we loop behind instead of adding so we can clear
|
|
// out behind ourselves; apparently, some server croak on nonzero padding
|
|
StufferFLoopTrace((" StufferFloop '1' Curr=%08lx \n",*CurrentPosition));
|
|
PreviousPosition = *CurrentPosition;
|
|
*CurrentPosition += sizeof(USHORT)-1;
|
|
StufferFLoopTrace((" Curr=%08lx \n",*CurrentPosition));
|
|
*CurrentPosition = (PBYTE)( ((ULONG_PTR)(*CurrentPosition)) & ~((LONG)(sizeof(USHORT)-1)) );
|
|
StufferFLoopTrace((" Curr=%08lx \n",*CurrentPosition));
|
|
for (;PreviousPosition!=*CurrentPosition;) {
|
|
StufferFLoopTrace((" StufferFloop '1' prev,curr=%08lx %08lx\n",PreviousPosition,*CurrentPosition));
|
|
*PreviousPosition++ = PADBYTE;
|
|
}
|
|
break;
|
|
case 'c':
|
|
// copy in the bytes....used a lot in transact
|
|
CopyCount = va_arg(AP,ULONG);
|
|
CopyPtr = va_arg(AP,PBYTE);
|
|
if (CurrentStufferControl == STUFFER_CTL_SKIP) break;
|
|
StufferFLoopTrace((" StufferFloop 'c' copycount = %lu\n", CopyCount));
|
|
PreviousPosition = *CurrentPosition;
|
|
*CurrentPosition += CopyCount;
|
|
for (;PreviousPosition!=*CurrentPosition;) {
|
|
//StufferFLoopTrace((" StufferFloop 'S' prev,curr=%08lx %08lx\n",PreviousPosition,*CurrentPosition));
|
|
*PreviousPosition++ = *CopyPtr++;
|
|
}
|
|
break;
|
|
case 'R':
|
|
case 'r':
|
|
// copy in the bytes....used a lot in transact
|
|
RegionPtr = va_arg(AP,PBYTE*);
|
|
CopyCount = va_arg(AP,ULONG);
|
|
StufferFLoopTrace((" StufferFloop 'r' regionsize = %lu\n", CopyCount));
|
|
*RegionPtr = *CurrentPosition;
|
|
*CurrentPosition += CopyCount;
|
|
IF_DEBUG {
|
|
PreviousPosition = *RegionPtr;
|
|
for (;PreviousPosition!=*CurrentPosition;) {
|
|
//StufferFLoopTrace((" StufferFloop 'S' prev,curr=%08lx %08lx\n",PreviousPosition,*CurrentPosition));
|
|
*PreviousPosition++ = '-';
|
|
}
|
|
}
|
|
break;
|
|
case 'A':
|
|
case 'a':
|
|
//copy byte from an asciiz including the trailing NULL
|
|
Astring = va_arg(AP,PSZ);
|
|
StufferFLoopTrace((" StufferFloop 'a' stringing = %s\n", Astring));
|
|
CopyCount = strlen(Astring)+1;
|
|
//if (((ULONG)(*CurrentPosition))&1) {
|
|
// StufferFLoopTrace((" StufferFloop 'a' aligning\n", 0));
|
|
// *CurrentPosition+=1;
|
|
//}
|
|
PreviousPosition = *CurrentPosition;
|
|
*CurrentPosition += CopyCount;
|
|
if (*CurrentPosition >= StufferState->BufferLimit) {
|
|
StufferFLoopTrace((" StufferFloop 'a' bufferoverrun\n", 0));
|
|
ASSERT(!"BufferOverrun");
|
|
return(RX_MAP_STATUS(BUFFER_OVERFLOW));
|
|
}
|
|
RtlCopyMemory(PreviousPosition,Astring,CopyCount);
|
|
break;
|
|
case 'z':
|
|
case '4':
|
|
case '>':
|
|
Zstring = va_arg(AP,PUNICODE_STRING);
|
|
StufferFLoopTrace((" StufferFloop '4/z/>' stringing = %wZ, cp=\n", Zstring,*CurrentPosition ));
|
|
if (CurrentStufferControl == STUFFER_CTL_SKIP) break;
|
|
if (CurrentFormatChar=='4') {
|
|
//first lay down a x'04' and then copy either a asciiz or a unicodez depending on the flags setting
|
|
**CurrentPosition = (UCHAR)4; //ascii marker
|
|
*CurrentPosition+=1;
|
|
} else if (CurrentFormatChar=='>'){
|
|
//back up over the previous NULL
|
|
//
|
|
*CurrentPosition-=(FlagOn(SmbHeader->Flags2,SMB_FLAGS2_UNICODE)?sizeof(WCHAR):sizeof(char));
|
|
StufferFLoopTrace((" StufferFloop '4/z/>' afterroolback, cp=\n", *CurrentPosition ));
|
|
}
|
|
if (FlagOn(SmbHeader->Flags2,SMB_FLAGS2_UNICODE)){
|
|
|
|
if (((ULONG_PTR)(*CurrentPosition))&1) {
|
|
StufferFLoopTrace((" StufferFloop '4/z/>' aligning\n", 0));
|
|
*CurrentPosition+=1;
|
|
}
|
|
PreviousPosition = *CurrentPosition;
|
|
*CurrentPosition += (Zstring->Length + sizeof(WCHAR));
|
|
if (*CurrentPosition >= StufferState->BufferLimit) {
|
|
StufferFLoopTrace((" StufferFloop '4/z/>' bufferoverrun\n", 0));
|
|
ASSERT(!"BufferOverrun");
|
|
return(RX_MAP_STATUS(BUFFER_OVERFLOW));
|
|
}
|
|
RtlCopyMemory(PreviousPosition,Zstring->Buffer,Zstring->Length);
|
|
*(((PWCHAR)(*CurrentPosition))-1) = 0;
|
|
|
|
} else {
|
|
|
|
NTSTATUS Status;
|
|
OEM_STRING OemString;
|
|
|
|
OemString.Length =
|
|
OemString.MaximumLength =
|
|
(USHORT)( StufferState->BufferLimit - *CurrentPosition - sizeof(CHAR));
|
|
OemString.Buffer = *CurrentPosition;
|
|
|
|
if (FlagOn(SmbHeader->Flags,SMB_FLAGS_CASE_INSENSITIVE) &&
|
|
!FlagOn(SmbHeader->Flags2,SMB_FLAGS2_KNOWS_LONG_NAMES)) {
|
|
Status = RtlUpcaseUnicodeStringToOemString(
|
|
&OemString,
|
|
Zstring,
|
|
FALSE);
|
|
} else {
|
|
Status = RtlUnicodeStringToOemString(
|
|
&OemString,
|
|
Zstring,
|
|
FALSE);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
StufferFLoopTrace((" StufferFloop '4/z/>' bufferoverrun(ascii)\n", 0));
|
|
ASSERT(!"BufferOverrun");
|
|
return(RX_MAP_STATUS(BUFFER_OVERFLOW));
|
|
}
|
|
|
|
*CurrentPosition += OemString.Length + 1;
|
|
*(*CurrentPosition-1) = 0;
|
|
|
|
}
|
|
break;
|
|
case 'U':
|
|
case 'u':
|
|
//copy bytes from an UNICODE string including a trailing NULL
|
|
Zstring = va_arg(AP,PUNICODE_STRING);
|
|
StufferFLoopTrace((" StufferFloop 'u' stringing = %wZ\n", Zstring));
|
|
if (((ULONG_PTR)(*CurrentPosition))&1) {
|
|
StufferFLoopTrace((" StufferFloop 'u' aligning\n", 0));
|
|
*CurrentPosition+=1;
|
|
}
|
|
PreviousPosition = *CurrentPosition;
|
|
*CurrentPosition += (Zstring->Length + sizeof(WCHAR));
|
|
if (*CurrentPosition >= StufferState->BufferLimit) {
|
|
StufferFLoopTrace((" StufferFloop 'u' bufferoverrun\n", 0));
|
|
return(RX_MAP_STATUS(BUFFER_OVERFLOW));
|
|
}
|
|
RtlCopyMemory(PreviousPosition,Zstring->Buffer,Zstring->Length);
|
|
*(((PWCHAR)(*CurrentPosition))-1) = 0;
|
|
break;
|
|
case 'V':
|
|
case 'v':
|
|
//copy bytes from an UNICODE string no trailing NUL
|
|
Zstring = va_arg(AP,PUNICODE_STRING);
|
|
StufferFLoopTrace((" StufferFloop 'v' stringing = %wZ\n", Zstring));
|
|
if (((ULONG_PTR)(*CurrentPosition))&1) {
|
|
StufferFLoopTrace((" StufferFloop 'v' aligning\n", 0));
|
|
*CurrentPosition+=1;
|
|
}
|
|
PreviousPosition = *CurrentPosition;
|
|
*CurrentPosition += Zstring->Length;
|
|
if (*CurrentPosition >= StufferState->BufferLimit) {
|
|
StufferFLoopTrace((" StufferFloop 'v' bufferoverrun\n", 0));
|
|
ASSERT(!"BufferOverrun");
|
|
return(RX_MAP_STATUS(BUFFER_OVERFLOW));
|
|
}
|
|
RtlCopyMemory(PreviousPosition,Zstring->Buffer,Zstring->Length);
|
|
break;
|
|
case 'N':
|
|
case 'n':
|
|
//copy bytes from a NetRoot name....w null
|
|
//joejoe we need to do the # thing here
|
|
NetRoot = va_arg(AP,PNET_ROOT);
|
|
ASSERT(NodeType(NetRoot)==RDBSS_NTC_NETROOT);
|
|
Zstring = &NetRoot->PrefixEntry.Prefix;
|
|
StufferFLoopTrace((" StufferFloop 'n' stringing = %wZ\n", Zstring));
|
|
if (StufferState->Flags2Copy&SMB_FLAGS2_UNICODE) {
|
|
if (((ULONG_PTR)(*CurrentPosition))&1) {
|
|
StufferFLoopTrace((" StufferFloop 'n' aligning\n", 0));
|
|
*CurrentPosition+=1;
|
|
}
|
|
PreviousPosition = *CurrentPosition;
|
|
*CurrentPosition += (Zstring->Length + 2 * sizeof(WCHAR)); //extra \ plus a nul
|
|
if (*CurrentPosition >= StufferState->BufferLimit) {
|
|
StufferFLoopTrace((" StufferFloop 'n' bufferoverrun\n", 0));
|
|
ASSERT(!"BufferOverrun");
|
|
return(RX_MAP_STATUS(BUFFER_OVERFLOW));
|
|
}
|
|
*((PWCHAR)PreviousPosition) = '\\';
|
|
RtlCopyMemory(PreviousPosition+sizeof(WCHAR),Zstring->Buffer,Zstring->Length);
|
|
*(((PWCHAR)(*CurrentPosition))-1) = 0;
|
|
}
|
|
break;
|
|
case '?':
|
|
//early out....used in transact to do the setup
|
|
EarlyReturn = va_arg(AP,ULONG);
|
|
StufferFLoopTrace((" StufferFloop '?' out if 0==%08lx\n",EarlyReturn));
|
|
if (EarlyReturn==0) return RX_MAP_STATUS(SUCCESS);
|
|
break;
|
|
case '.':
|
|
//noop...used to reenter without a real formatting string
|
|
StufferFLoopTrace((" StufferFloop '.'\n",0));
|
|
break;
|
|
case '!':
|
|
if (CurrentStufferControl == STUFFER_CTL_SKIP) break;
|
|
ASSERT (SmbGetUshort (*CurrentBcc) == MRXSMB_INITIAL_BCC);
|
|
ByteCount = (USHORT)(*CurrentPosition-*CurrentBcc-sizeof(USHORT));
|
|
StufferFLoopTrace((" StufferFloop '!' arg=%lu\n",ByteCount));
|
|
SmbPutUshort (*CurrentBcc, (USHORT)ByteCount);
|
|
return RX_MAP_STATUS(SUCCESS);
|
|
default:
|
|
StufferFLoopTrace((" StufferFloop '%c' BADBADBAD\n",*CurrentFormatString));
|
|
ASSERT(!"Illegal Controlstring character\n");
|
|
} //switch
|
|
}//for
|
|
break;
|
|
case 0:
|
|
return RX_MAP_STATUS(SUCCESS);
|
|
default:
|
|
StufferCLoopTrace((" StufferCloop %u BADBADBAD\n",CurrentStufferControl));
|
|
ASSERT(!"IllegalStufferControl\n");
|
|
}//switch
|
|
|
|
CurrentStufferControl = va_arg(AP,SMB_STUFFER_CONTROLS);
|
|
StufferCLoopTrace((" StufferCloop NewStufferControl=%u \n",CurrentStufferControl));
|
|
|
|
} //for
|
|
|
|
return RX_MAP_STATUS(SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
MRxSmbStuffAppendRawData(
|
|
IN OUT PSMBSTUFFER_BUFFER_STATE StufferState,
|
|
IN PMDL Mdl
|
|
)
|
|
{
|
|
PMDL pMdl;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(!StufferState->DataMdl);
|
|
pMdl = StufferState->DataMdl = Mdl;
|
|
StufferState->DataSize = 0;
|
|
|
|
while (pMdl != NULL) {
|
|
StufferState->DataSize += pMdl->ByteCount;
|
|
pMdl = pMdl->Next;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
MRxSmbStuffAppendSmbData(
|
|
IN OUT PSMBSTUFFER_BUFFER_STATE StufferState,
|
|
IN PMDL Mdl
|
|
)
|
|
{
|
|
ULONG Offset;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(!StufferState->DataMdl);
|
|
StufferState->DataMdl = Mdl;
|
|
StufferState->DataSize = Mdl->ByteCount;
|
|
//now reach back into the buffer and set the SMB data offset; if it is already set...just get out
|
|
if (SmbGetUshort (StufferState->CurrentDataOffset) == MRXSMB_INITIAL_DATAOFFSET){
|
|
Offset = (ULONG)(StufferState->CurrentPosition - StufferState->BufferBase);
|
|
RxDbgTrace(0, Dbg,("MRxSmbStuffAppendSmbData offset=%lu\n",Offset));
|
|
SmbPutUshort (StufferState->CurrentDataOffset, (USHORT)Offset);
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
MRxSmbStuffSetByteCount(
|
|
IN OUT PSMBSTUFFER_BUFFER_STATE StufferState
|
|
)
|
|
{
|
|
ULONG ByteCount;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT (SmbGetUshort (StufferState->CurrentBcc) == MRXSMB_INITIAL_BCC);
|
|
ByteCount = (ULONG)(StufferState->CurrentPosition
|
|
- StufferState->CurrentBcc
|
|
- sizeof(USHORT)
|
|
+ StufferState->DataSize);
|
|
RxDbgTrace(0, Dbg,("MRxSmbStuffSetByteCount ByteCount=%lu\n",ByteCount));
|
|
SmbPutUshort (StufferState->CurrentBcc, (USHORT)ByteCount);
|
|
return;
|
|
}
|
|
|
|
|