Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1028 lines
42 KiB

/*++
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':
if (*CurrentPosition >= StufferState->BufferLimit - sizeof(UCHAR)) {
return(STATUS_BUFFER_OVERFLOW);
}
StufferFLoopTrace((" StufferFloop '0'\n",0));
//just do the wct field...
**CurrentPosition = (UCHAR)MRXSMB_INITIAL_WCT;
*CurrentPosition+=1;
break;
case 'X':
if (*CurrentPosition >= StufferState->BufferLimit - sizeof(ULONG)) {
return(STATUS_BUFFER_OVERFLOW);
}
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;
if (*CurrentPosition >= StufferState->BufferLimit - sizeof(USHORT)) {
return(STATUS_BUFFER_OVERFLOW);
}
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;
if (*CurrentPosition >= StufferState->BufferLimit - sizeof(UCHAR)) {
return(STATUS_BUFFER_OVERFLOW);
}
StufferFLoopTrace((" StufferFloop 'y' arg=%lu\n",arg));
**CurrentPosition = (UCHAR)arg;
*CurrentPosition+=sizeof(UCHAR);
break;
case 'M':
case 'm':
if (CurrentStufferControl == STUFFER_CTL_SKIP) break;
if (*CurrentPosition >= StufferState->BufferLimit - sizeof(UCHAR)) {
return(STATUS_BUFFER_OVERFLOW);
}
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;
if (*CurrentPosition >= StufferState->BufferLimit - sizeof(ULONG)) {
return(STATUS_BUFFER_OVERFLOW);
}
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;
if (*CurrentPosition >= StufferState->BufferLimit - 2*sizeof(ULONG)) {
return(STATUS_BUFFER_OVERFLOW);
}
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':
if (*CurrentPosition >= StufferState->BufferLimit - sizeof(USHORT)) {
return(STATUS_BUFFER_OVERFLOW);
}
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':
if (*CurrentPosition >= StufferState->BufferLimit - sizeof(USHORT)) {
return(STATUS_BUFFER_OVERFLOW);
}
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':
if (*CurrentPosition >= StufferState->BufferLimit - sizeof(USHORT)) {
return(STATUS_BUFFER_OVERFLOW);
}
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);
if (*CurrentPosition >= StufferState->BufferLimit) {
return(STATUS_BUFFER_OVERFLOW);
}
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)) );
if (*CurrentPosition >= StufferState->BufferLimit) {
return(STATUS_BUFFER_OVERFLOW);
}
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));
if (*CurrentPosition >= StufferState->BufferLimit) {
return(STATUS_BUFFER_OVERFLOW);
}
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;
if (*CurrentPosition >= StufferState->BufferLimit) {
return(STATUS_BUFFER_OVERFLOW);
}
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 (*CurrentPosition >= StufferState->BufferLimit) {
return(STATUS_BUFFER_OVERFLOW);
}
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') {
if (*CurrentPosition >= StufferState->BufferLimit - 1) {
return(STATUS_BUFFER_OVERFLOW);
}
//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;
}