/*++ 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 #include #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+DataSizeBufferLimit); } #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; }