mirror of https://github.com/lianthony/NT4.0
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.
2085 lines
47 KiB
2085 lines
47 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
smbdump.c
|
|
|
|
Abstract:
|
|
|
|
This module contains various debug routines for dumping structures
|
|
maintained by the LAN Manager server.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 28-Sept-1990
|
|
|
|
Revision History:
|
|
|
|
Peter Gray (w-peterg) 13-Apr-1992
|
|
|
|
Support for NT style SMBs added.
|
|
|
|
Stephan Mueller (t-stephm) 15-June-1992
|
|
|
|
Changes required to display NT Smbs (according to Spec
|
|
revision 2.22, dated 19-June-1992). Many bug fixes
|
|
|
|
--*/
|
|
|
|
#define INCLUDE_SMB_TRANSACTION
|
|
#define INCLUDE_SMB_SEARCH
|
|
|
|
#include "smbdump.h"
|
|
#include <smbtrace.h>
|
|
|
|
#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
|
|
|
|
// FIXFIX: The following macro is bogus. It will only work on little-endian
|
|
// FIXFIX: machines. There should be a global macro (like SmbGetUlong) that
|
|
// FIXFIX: will allow the NT to be ported to other machines.
|
|
|
|
#define SmbPutUquad(to,from) \
|
|
(to)->LowPart = SmbGetUlong(&(from)->LowPart); \
|
|
(to)->HighPart = SmbGetUlong(&(from)->HighPart)
|
|
|
|
|
|
VOID
|
|
SmbDump (
|
|
IN PVOID Smb,
|
|
IN CLONG SmbLength,
|
|
IN PVOID SmbAddress,
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN CLONG SmbDumpRawLength,
|
|
IN BOOLEAN IsServer
|
|
)
|
|
|
|
{
|
|
UCHAR command = ((PNT_SMB_HEADER)Smb)->Command;
|
|
USHORT subcommand;
|
|
PCHAR parameters = (PCHAR)( (PNT_SMB_HEADER)Smb + 1 );
|
|
PSMB_FIELD_DESCRIPTION descriptor;
|
|
BOOLEAN isResponse;
|
|
BOOLEAN ntFormatStatus;
|
|
BOOLEAN unicodeStrings;
|
|
USHORT usError = 0;
|
|
ULONG ulError = 0L;
|
|
|
|
|
|
if ( SmbLength == 0 ) {
|
|
|
|
//
|
|
// This is an empty raw buffer
|
|
//
|
|
|
|
if ( SmbDumpVerbosityLevel > SMBTRACE_VERBOSITY_OFF ) {
|
|
printf( "(EMPTY BUFFER)\n" );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( SmbGetUlong( (PULONG)Smb ) != SMB_HEADER_PROTOCOL ) {
|
|
|
|
//
|
|
// This is a raw buffer
|
|
//
|
|
|
|
if ( SmbDumpVerbosityLevel > SMBTRACE_VERBOSITY_OFF ) {
|
|
printf( "(RAW BUFFER, %ld BYTES)\n", SmbLength );
|
|
if ( SmbDumpRawLength > 0 ) {
|
|
SmbDumpRawData( Smb, MIN( SmbLength, SmbDumpRawLength ), 0 );
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
isResponse = (BOOLEAN)(
|
|
( ((PNT_SMB_HEADER)Smb)->Flags & SMB_FLAGS_SERVER_TO_REDIR) ?
|
|
TRUE : FALSE );
|
|
|
|
ntFormatStatus = (BOOLEAN)(
|
|
( ((PNT_SMB_HEADER)Smb)->Flags2 & SMB_FLAGS2_NT_STATUS) ?
|
|
TRUE : FALSE );
|
|
|
|
unicodeStrings = (BOOLEAN)(
|
|
( ((PNT_SMB_HEADER)Smb)->Flags2 & SMB_FLAGS2_UNICODE) ?
|
|
TRUE : FALSE );
|
|
|
|
if ( !isResponse &&
|
|
command == SMB_COM_TRANSACTION ||
|
|
command == SMB_COM_TRANSACTION2 ||
|
|
command == SMB_COM_NT_TRANSACT ) {
|
|
|
|
SmbDumpSetTransSubCommand(
|
|
(PNT_SMB_HEADER)Smb,
|
|
SmbGetUshort(
|
|
(PUSHORT)((PREQ_TRANSACTION)( (PNT_SMB_HEADER)Smb + 1 ))->Buffer
|
|
)
|
|
);
|
|
}
|
|
|
|
if ( SmbDumpVerbosityLevel == SMBTRACE_VERBOSITY_OFF ) {
|
|
return;
|
|
}
|
|
|
|
if ( isResponse && !(SmbDumpHeuristics & SMB_DUMP_RESPONSE) ) {
|
|
return;
|
|
}
|
|
|
|
if ( !isResponse && !(SmbDumpHeuristics & SMB_DUMP_REQUEST) ) {
|
|
return;
|
|
}
|
|
|
|
SmbDumpSingleLine( Smb, SmbLength, SmbAddress, IsServer, isResponse, ntFormatStatus );
|
|
|
|
if ( SmbDumpRawLength > 0 ) {
|
|
SmbDumpRawData( Smb, MIN( SmbLength, SmbDumpRawLength ), 0 );
|
|
}
|
|
|
|
if ( SmbDumpVerbosityLevel <= SMBTRACE_VERBOSITY_SINGLE_LINE ) {
|
|
return;
|
|
}
|
|
|
|
if ( !ntFormatStatus &&
|
|
( (usError = SmbGetUshort( &((PNT_SMB_HEADER)Smb)->Status.DosError.Error )) != 0 )
|
|
) {
|
|
SmbDumpError(
|
|
((PNT_SMB_HEADER)Smb)->Status.DosError.ErrorClass,
|
|
SmbGetUshort( &((PNT_SMB_HEADER)Smb)->Status.DosError.Error )
|
|
);
|
|
|
|
} else if( ntFormatStatus &&
|
|
( (ulError = SmbGetUlong( &((PNT_SMB_HEADER)Smb)->Status.NtStatus))
|
|
!= STATUS_SUCCESS )
|
|
) {
|
|
SmbDumpNtError(
|
|
SmbGetUlong( &((PNT_SMB_HEADER)Smb)->Status.NtStatus)
|
|
);
|
|
}
|
|
|
|
if ( SmbDumpVerbosityLevel == SMBTRACE_VERBOSITY_ERROR ) {
|
|
return;
|
|
}
|
|
|
|
SmbDumpHeader( SmbDumpVerbosityLevel, Smb, ntFormatStatus );
|
|
|
|
if ( SmbDumpVerbosityLevel == SMBTRACE_VERBOSITY_HEADER ) {
|
|
printf( "\n" );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// As long as there are more parameter blocks (And X commands), print
|
|
// out the fields.
|
|
//
|
|
|
|
if ( isResponse ) {
|
|
descriptor = SmbDumpTable[command].ResponseDescriptor;
|
|
} else {
|
|
descriptor = SmbDumpTable[command].RequestDescriptor;
|
|
}
|
|
|
|
do {
|
|
|
|
//
|
|
// If write and close SMB, choose the correct descriptor depending
|
|
// on the word count.
|
|
//
|
|
|
|
if ( command == SMB_COM_WRITE_AND_CLOSE ) {
|
|
if ( *(PCHAR)( (PNT_SMB_HEADER)Smb + 1 ) == 6 ) {
|
|
if ( isResponse ) {
|
|
descriptor = SmbDumpTable[SMB_COM_WRITE].ResponseDescriptor;
|
|
} else {
|
|
descriptor = SmbDumpTable[SMB_COM_WRITE].RequestDescriptor;
|
|
}
|
|
} else {
|
|
if ( isResponse ) {
|
|
descriptor = SmbDumpTable[SMB_COM_WRITE_ANDX].ResponseDescriptor;
|
|
} else {
|
|
descriptor = SmbDumpTable[SMB_COM_WRITE_ANDX].RequestDescriptor;
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// Check if this is an NT variant of a common SMB by looking
|
|
// at the word count and checking in the table. Usually, only
|
|
// requests are modified in this way, often adding two words
|
|
// to allow for 64bit offsets.
|
|
//
|
|
|
|
if ( ( SmbDumpTable[command].NtDescriptor !=NULL )
|
|
&& ( *(PCHAR)( (PNT_SMB_HEADER)Smb + 1 )
|
|
== SmbDumpTable[command].NtSpecialWordCount )
|
|
) {
|
|
if( !isResponse && SmbDumpTable[command].NtIsRequest ) {
|
|
descriptor = SmbDumpTable[command].NtDescriptor;
|
|
}
|
|
if( isResponse && !SmbDumpTable[command].NtIsRequest ) {
|
|
descriptor = SmbDumpTable[command].NtDescriptor;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Call SmbDumpDescriptor to display the fields in the SMB.
|
|
// If this routine returns 0, then there was no parameter
|
|
// information for the SMB, so just quit.
|
|
//
|
|
|
|
if ( SmbDumpDescriptor(
|
|
SmbDumpVerbosityLevel,
|
|
descriptor,
|
|
parameters,
|
|
unicodeStrings ) == 0 ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If the SMB is a Transact SMB, dump the parameter block.
|
|
//
|
|
|
|
if ( command == SMB_COM_TRANSACTION2 ||
|
|
command == SMB_COM_NT_TRANSACT
|
|
) {
|
|
if ( isResponse ) {
|
|
|
|
subcommand =
|
|
(UCHAR)SmbDumpGetTransSubCommand( (PNT_SMB_HEADER)Smb );
|
|
|
|
if ( command == 0xFF ) {
|
|
printf( "Transaction not found in list!!!\n" );
|
|
return;
|
|
}
|
|
|
|
parameters = (PCHAR)Smb +
|
|
SmbGetUshort( &((PRESP_TRANSACTION)parameters)->
|
|
ParameterOffset );
|
|
|
|
if( command == SMB_COM_TRANSACTION2 ) {
|
|
descriptor =
|
|
SmbTrans2DumpTable[subcommand].ResponseDescriptor;
|
|
} else {
|
|
descriptor =
|
|
SmbNtTransDumpTable[subcommand].ResponseDescriptor;
|
|
}
|
|
|
|
} else {
|
|
|
|
subcommand =
|
|
*(PUCHAR)&(((PREQ_TRANSACTION)parameters)->Buffer[0]);
|
|
parameters = (PCHAR)Smb +
|
|
SmbGetUshort( &((PREQ_TRANSACTION)parameters)->
|
|
ParameterOffset );
|
|
|
|
if( command == SMB_COM_TRANSACTION2 ) {
|
|
descriptor =
|
|
SmbTrans2DumpTable[subcommand].RequestDescriptor;
|
|
} else {
|
|
descriptor =
|
|
SmbNtTransDumpTable[subcommand].RequestDescriptor;
|
|
}
|
|
}
|
|
|
|
(VOID)SmbDumpDescriptor(
|
|
SmbDumpVerbosityLevel,
|
|
descriptor, parameters,
|
|
unicodeStrings
|
|
);
|
|
} else if( command == SMB_COM_TRANSACTION ) {
|
|
|
|
if ( SmbDumpVerbosityLevel >= SMBTRACE_VERBOSITY_NONESSENTIAL )
|
|
printf("Would dump Transaction's parameter block here.\n");
|
|
|
|
}
|
|
|
|
//
|
|
// Break or setup for dumping a followon command if there is one.
|
|
//
|
|
|
|
if ( !SmbDumpTable[command].IsAndXCommand ||
|
|
((PGENERIC_ANDX)parameters)->AndXCommand
|
|
== SMB_COM_NO_ANDX_COMMAND ||
|
|
( usError | ulError )
|
|
) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
command = ((PGENERIC_ANDX)parameters)->AndXCommand;
|
|
|
|
|
|
parameters = (PCHAR)Smb +
|
|
SmbGetUshort(
|
|
&((PGENERIC_ANDX)parameters)->AndXOffset
|
|
);
|
|
|
|
if ( isResponse ) {
|
|
descriptor = SmbDumpTable[command].ResponseDescriptor;
|
|
} else {
|
|
descriptor = SmbDumpTable[command].RequestDescriptor;
|
|
}
|
|
|
|
printf( "And--%s:\n", SmbDumpTable[command].SmbName );
|
|
}
|
|
|
|
} while ( TRUE );
|
|
|
|
printf( "\n" );
|
|
|
|
return;
|
|
|
|
} // SmbDump
|
|
|
|
//
|
|
// SMB field dump routines. All of these conform to the
|
|
// SMB_FIELD_DUMP_ROUTINE declaration.
|
|
//
|
|
|
|
#define NON_ESSENTIAL_RETURN(a) \
|
|
if ( !EssentialField && \
|
|
SmbDumpVerbosityLevel < SMBTRACE_VERBOSITY_NONESSENTIAL ) { \
|
|
return a; \
|
|
}
|
|
|
|
|
|
USHORT
|
|
SmbDumpAccess (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
USHORT value = SmbGetUshort( (PUSHORT)Field );
|
|
USHORT share = (USHORT)(value & SMB_DA_SHARE_MASK);
|
|
USHORT _access = (USHORT)(value & SMB_DA_ACCESS_MASK);
|
|
|
|
Context; Result; UnicodeStrings;
|
|
|
|
NON_ESSENTIAL_RETURN( 2 );
|
|
|
|
printf( "%04lx - ", value );
|
|
|
|
if ( value & SMB_DA_WRITE_THROUGH ) {
|
|
printf( "WriteThrough, " );
|
|
}
|
|
|
|
switch ( _access ) {
|
|
|
|
case SMB_DA_ACCESS_READ:
|
|
printf( "Read Access, " );
|
|
break;
|
|
|
|
case SMB_DA_ACCESS_WRITE:
|
|
printf( "Write Access, " );
|
|
break;
|
|
|
|
case SMB_DA_ACCESS_READ_WRITE:
|
|
printf( "Read/Write Access, " );
|
|
break;
|
|
|
|
case SMB_DA_ACCESS_EXECUTE:
|
|
printf( "Execute Access, " );
|
|
break;
|
|
|
|
case SMB_DA_FCB:
|
|
printf( "FCB Open" );
|
|
return 2;
|
|
|
|
default:
|
|
printf( "INVALID" );
|
|
}
|
|
|
|
switch ( share ) {
|
|
|
|
case SMB_DA_SHARE_COMPATIBILITY:
|
|
printf( "Compatibility Mode" );
|
|
break;
|
|
|
|
case SMB_DA_SHARE_EXCLUSIVE:
|
|
printf( "Exclusive" );
|
|
break;
|
|
|
|
case SMB_DA_SHARE_DENY_WRITE:
|
|
printf( "Deny Write" );
|
|
break;
|
|
|
|
case SMB_DA_SHARE_DENY_READ:
|
|
printf( "Deny Read" );
|
|
break;
|
|
|
|
case SMB_DA_SHARE_DENY_NONE:
|
|
printf( "Deny None" );
|
|
break;
|
|
}
|
|
|
|
return 2;
|
|
|
|
} // SmbDumpAccess
|
|
|
|
|
|
USHORT
|
|
SmbDumpAction (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
USHORT value = SmbGetUshort( (PUSHORT)Field );
|
|
USHORT action = (USHORT)(value & 0x03);
|
|
|
|
Context; Result; UnicodeStrings;
|
|
|
|
NON_ESSENTIAL_RETURN( 2 );
|
|
|
|
printf( "%04lx - ", value );
|
|
|
|
if ( value & SMB_OACT_OPLOCK ) {
|
|
printf( "Oplock Granted, " );
|
|
} else {
|
|
printf( "Oplock Not Granted, " );
|
|
}
|
|
|
|
switch ( action ) {
|
|
|
|
case SMB_OACT_OPENED:
|
|
printf( "Opened" );
|
|
break;
|
|
|
|
case SMB_OACT_CREATED:
|
|
printf( "Created" );
|
|
break;
|
|
|
|
case SMB_OACT_TRUNCATED:
|
|
printf( "Truncated" );
|
|
break;
|
|
|
|
default:
|
|
printf( "INVALID" );
|
|
break;
|
|
}
|
|
|
|
return 2;
|
|
|
|
} // SmbDumpAction
|
|
|
|
|
|
// dump ASCIIZ prefixed by SMB_FORMAT_ASCII format byte
|
|
USHORT
|
|
SmbDumpFAsciiZ (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
PCHAR FieldText = (PCHAR)Field + 1;
|
|
// +1 for Field format, +1 for \0 character
|
|
USHORT retval = (USHORT)( strlen( (PSZ)FieldText ) + 2 );
|
|
|
|
NON_ESSENTIAL_RETURN( retval );
|
|
|
|
if ( *(PUCHAR)Field != SMB_FORMAT_ASCII ) {
|
|
printf( "(Bad token == %02x) ", *(PUCHAR)Field );
|
|
}
|
|
|
|
printf( "%s", FieldText );
|
|
|
|
return ( retval );
|
|
|
|
Context; Result;
|
|
|
|
} // SmbDumpFAsciiZ
|
|
|
|
|
|
// dump UnicodeZ prefixed by SMB_FORMAT_ASCII format byte
|
|
USHORT
|
|
SmbDumpFUnicodeZ (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
PCHAR FieldText = (PCHAR)Field + 1;
|
|
// +1 for Field format, +2 for two byte string terminator
|
|
USHORT retval = 1 + sizeof(WCHAR);
|
|
|
|
// Ensure string is aligned: if at odd address, round up,
|
|
// and remember that we ate one more byte. This is a hack;
|
|
// alignment should be with respect to the start of the SMB,
|
|
// not address 0, but RtlAllocateHeap, used to allocate our
|
|
// packets, is guaranteed to give properly aligned memory.
|
|
if ( (ULONG)FieldText & 1 ) {
|
|
FieldText++;
|
|
retval++;
|
|
}
|
|
|
|
retval += (USHORT)( wcslen( (PWSTR)FieldText ) * sizeof(WCHAR) );
|
|
|
|
NON_ESSENTIAL_RETURN( retval );
|
|
|
|
if ( *(PUCHAR)Field != SMB_FORMAT_ASCII ) {
|
|
printf( "(Bad token == %02x) ", *(PUCHAR)Field );
|
|
}
|
|
|
|
printf( "%ws" , FieldText );
|
|
|
|
return ( retval );
|
|
|
|
Context; Result;
|
|
|
|
} // SmbDumpFUnicodeZ
|
|
|
|
|
|
// dump ASCIIZ or UnicodeZ (as determined by UnicodeStrings)
|
|
// prefixed by SMB_FORMAT_ASCII format byte
|
|
USHORT
|
|
SmbDumpFStringZ (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
if ( UnicodeStrings ) {
|
|
return SmbDumpFUnicodeZ(
|
|
SmbDumpVerbosityLevel,
|
|
Context,
|
|
Result,
|
|
EssentialField,
|
|
Field,
|
|
UnicodeStrings
|
|
);
|
|
} else {
|
|
return SmbDumpFAsciiZ(
|
|
SmbDumpVerbosityLevel,
|
|
Context,
|
|
Result,
|
|
EssentialField,
|
|
Field,
|
|
UnicodeStrings
|
|
);
|
|
}
|
|
|
|
} // SmbDumpFStringZ
|
|
|
|
|
|
USHORT
|
|
SmbDumpAsciiZ (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
// +1 for \0 character
|
|
USHORT retval = (USHORT)( strlen( (PSZ)Field) + 1 );
|
|
|
|
NON_ESSENTIAL_RETURN( retval );
|
|
|
|
printf( "%s", Field );
|
|
|
|
return retval;
|
|
|
|
Context; Result; UnicodeStrings;
|
|
|
|
} // SmbDumpAsciiZ
|
|
|
|
|
|
USHORT
|
|
SmbDumpUnicodeZ (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
// +2 for two byte string terminator
|
|
USHORT retval = sizeof(WCHAR);
|
|
|
|
// Ensure string is aligned: if at odd address, round up,
|
|
// and remember that we ate one more byte. This is a hack;
|
|
// alignment should be with respect to the start of the SMB,
|
|
// not address 0, but RtlAllocateHeap, used to allocate our
|
|
// packets, is guaranteed to give properly aligned memory.
|
|
if ( (ULONG)Field & 1 ) {
|
|
Field = (PCHAR)Field + 1;
|
|
retval++;
|
|
}
|
|
|
|
retval += (USHORT)( wcslen( (PWSTR)Field ) * sizeof(WCHAR) );
|
|
|
|
NON_ESSENTIAL_RETURN( retval );
|
|
|
|
printf( "%ws", Field );
|
|
|
|
return ( retval );
|
|
|
|
Context; Result; UnicodeStrings;
|
|
|
|
} // SmbDumpUnicodeZ
|
|
|
|
|
|
// dump ASCIIZ or UnicodeZ (as determined by UnicodeStrings)
|
|
USHORT
|
|
SmbDumpStringZ (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
if ( UnicodeStrings ) {
|
|
return SmbDumpUnicodeZ(
|
|
SmbDumpVerbosityLevel,
|
|
Context,
|
|
Result,
|
|
EssentialField,
|
|
Field,
|
|
UnicodeStrings
|
|
);
|
|
} else {
|
|
return SmbDumpAsciiZ(
|
|
SmbDumpVerbosityLevel,
|
|
Context,
|
|
Result,
|
|
EssentialField,
|
|
Field,
|
|
UnicodeStrings
|
|
);
|
|
}
|
|
|
|
} // SmbDumpStringZ
|
|
|
|
|
|
// dump non-\0 terminated Ascii, using length found in *(PULONG)Context
|
|
USHORT
|
|
SmbDumpAscii (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
USHORT retval;
|
|
|
|
if (Context == NULL) {
|
|
printf( "String length unavailable.\n" );
|
|
return 0;
|
|
}
|
|
|
|
retval = (USHORT)(*(PULONG)Context); // we still lose on very long strings
|
|
|
|
NON_ESSENTIAL_RETURN( retval );
|
|
|
|
// note that if string does contain a \0, the rest of the string
|
|
// won't be displayed
|
|
printf( "%.*s", retval, (PSZ)Field );
|
|
|
|
return ( retval );
|
|
|
|
Result; UnicodeStrings;
|
|
|
|
} // SmbDumpAscii
|
|
|
|
|
|
// dump non terminated Unicode, using length (in bytes, not characters)
|
|
// found in *(PULONG)Context
|
|
USHORT
|
|
SmbDumpUnicode (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
USHORT retval;
|
|
USHORT length;
|
|
|
|
if (Context == NULL) {
|
|
printf( "String length unavailable.\n" );
|
|
return 0;
|
|
}
|
|
|
|
length = retval = (USHORT)(*(PULONG)Context); // still lose on long strings
|
|
|
|
// Ensure string is aligned: if at odd address, round up,
|
|
// and remember that we ate one more byte. This is a hack;
|
|
// alignment should be with respect to the start of the SMB,
|
|
// not address 0, but RtlAllocateHeap, used to allocate our
|
|
// packets, is guaranteed to give properly aligned memory.
|
|
if ( (ULONG)Field & 1 ) {
|
|
Field = (PCHAR)Field + 1;
|
|
retval++;
|
|
}
|
|
|
|
NON_ESSENTIAL_RETURN( retval );
|
|
|
|
// note that if string does contain a terminator, the rest of the string
|
|
// won't be displayed
|
|
printf( "%.*ws", length/sizeof(WCHAR), (PSZ)Field );
|
|
|
|
return ( retval );
|
|
|
|
Result; UnicodeStrings;
|
|
|
|
} // SmbDumpUnicode
|
|
|
|
|
|
// dump non terminated ASCII or Unicode (as determined by UnicodeStrings)
|
|
// using length (in bytes, not characters) found in *(PULONG)Context
|
|
USHORT
|
|
SmbDumpString (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
if ( UnicodeStrings ) {
|
|
return SmbDumpUnicode(
|
|
SmbDumpVerbosityLevel,
|
|
Context,
|
|
Result,
|
|
EssentialField,
|
|
Field,
|
|
UnicodeStrings
|
|
);
|
|
} else {
|
|
return SmbDumpAscii(
|
|
SmbDumpVerbosityLevel,
|
|
Context,
|
|
Result,
|
|
EssentialField,
|
|
Field,
|
|
UnicodeStrings
|
|
);
|
|
}
|
|
|
|
} // SmbDumpString
|
|
|
|
|
|
// Dunno what the difference between these two is
|
|
USHORT
|
|
SmbDumpDataBuffer (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
// BUGBUG: incomplete
|
|
printf( "Would dump data here.\n" );
|
|
|
|
return 2;
|
|
|
|
SmbDumpVerbosityLevel, Context, Result, Field,EssentialField,UnicodeStrings;
|
|
|
|
} // SmbDumpDataBuffer
|
|
|
|
|
|
// Dunno what the difference between these two is
|
|
USHORT
|
|
SmbDumpDataBuffer2 (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
// BUGBUG: incomplete
|
|
printf( "Would dump data here.\n" );
|
|
|
|
return 2;
|
|
|
|
SmbDumpVerbosityLevel, Context, Result, Field,EssentialField,UnicodeStrings;
|
|
|
|
} // SmbDumpDataBuffer2
|
|
|
|
// dump length data bytes, where length is found in *(PULONG)Context
|
|
USHORT
|
|
SmbDumpDataBytes (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
USHORT length;
|
|
|
|
if ( Context == NULL ) {
|
|
printf( "Data length unavailable.\n" );
|
|
return 0;
|
|
}
|
|
|
|
length = (USHORT)(*(PULONG)Context);
|
|
|
|
printf("\n");
|
|
SmbDumpRawData( Field, length, 0 );
|
|
|
|
return length;
|
|
|
|
|
|
} // SmbDumpDataBytes
|
|
|
|
|
|
USHORT
|
|
SmbDumpDate (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
SMB_DATE date;
|
|
Context; Result; UnicodeStrings;
|
|
|
|
NON_ESSENTIAL_RETURN( 2 );
|
|
|
|
date.Ushort = SmbGetUshort( (PUSHORT)Field );
|
|
|
|
printf( "%02d/%02d/%04d",
|
|
date.Struct.Month,
|
|
date.Struct.Day,
|
|
date.Struct.Year + 1980
|
|
);
|
|
|
|
return 2;
|
|
|
|
} // SmbDumpDate
|
|
|
|
|
|
// Dump Protocol Dialects. Note that these strings are always ANSI,
|
|
// never Unicode.
|
|
USHORT
|
|
SmbDumpDialects (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
USHORT len = SmbGetUshort( (PUSHORT)(Field)-1 );
|
|
|
|
Context; Result; UnicodeStrings;
|
|
|
|
NON_ESSENTIAL_RETURN( len );
|
|
|
|
printf( "\n" ); // start on a new line
|
|
|
|
do {
|
|
if ( *(PCHAR)Field == SMB_FORMAT_DIALECT ) {
|
|
|
|
Field = (PVOID)((PCHAR)Field + 1);
|
|
printf( "\t%s\n", (PCHAR)Field );
|
|
|
|
Field = (PVOID)((PCHAR)Field + strlen((PCHAR)Field) + 1);
|
|
|
|
} else if ( *(PCHAR)Field == 0 ) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
printf( "(Bad token == %02x) ", *(PUCHAR)Field );
|
|
|
|
break;
|
|
}
|
|
|
|
} while( 1 );
|
|
|
|
return len;
|
|
|
|
} // SmbDumpDialects
|
|
|
|
|
|
USHORT
|
|
SmbDumpFlags4 (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
ULONG c = SmbGetUlong( (PULONG)Field );
|
|
CLONG i;
|
|
PSMB_FLAGS_DESCRIPTION flagsDesc = Context;
|
|
ULONG bitMask = 0;
|
|
|
|
NON_ESSENTIAL_RETURN( 4 );
|
|
|
|
Result; UnicodeStrings;
|
|
|
|
printf( "%04lx - ", c );
|
|
|
|
if ( Context == NULL ) {
|
|
printf( "No flags information available.\n" );
|
|
return 4;
|
|
}
|
|
|
|
for ( i = 0; flagsDesc[i].BitMask != 0; i++ ) {
|
|
|
|
bitMask |= flagsDesc[i].BitMask;
|
|
|
|
if ( (flagsDesc[i].BitMask & c) != 0 ) {
|
|
if ( flagsDesc[i].OnLabel != NULL ) {
|
|
printf( "%s", flagsDesc[i].OnLabel );
|
|
}
|
|
} else {
|
|
if ( flagsDesc[i].OffLabel != NULL ) {
|
|
printf( "%s", flagsDesc[i].OffLabel );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( (~bitMask & c ) != 0 ) {
|
|
printf( "UNKNOWN BIT(S) ON: %04lx\n", ~bitMask & c );
|
|
}
|
|
|
|
return 4;
|
|
|
|
} // SmbDumpFlags4
|
|
|
|
|
|
USHORT
|
|
SmbDumpFlags2 (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
ULONG c = (ULONG) SmbGetUshort( (PUSHORT)Field );
|
|
|
|
SmbDumpFlags4(
|
|
SmbDumpVerbosityLevel,
|
|
Context,
|
|
Result,
|
|
EssentialField,
|
|
&c,
|
|
UnicodeStrings
|
|
);
|
|
|
|
return 2;
|
|
|
|
} // SmbDumpFlags2
|
|
|
|
|
|
// dump USHORT containing DeviceState, using USHORT FileType found
|
|
// in *(PULONG)Context to indicate whether DeviceState is applicable
|
|
USHORT
|
|
SmbDumpDeviceState (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
ULONG c;
|
|
USHORT FileType;
|
|
|
|
c = (ULONG) SmbGetUshort( (PUSHORT)Field );
|
|
|
|
if (Context == NULL) {
|
|
// Assume that the field is inapplicable
|
|
FileType = FileTypeDisk;
|
|
} else {
|
|
FileType = (USHORT)(*(PULONG)Context);
|
|
}
|
|
|
|
if (FileType == FileTypeByteModePipe ||
|
|
FileType == FileTypeMessageModePipe) {
|
|
|
|
SmbDumpUchar(
|
|
SmbDumpVerbosityLevel,
|
|
NULL,
|
|
NULL,
|
|
EssentialField,
|
|
Field,
|
|
UnicodeStrings
|
|
);
|
|
|
|
// mask off instance count
|
|
c = c & ~0xf;
|
|
|
|
SmbDumpFlags4(
|
|
SmbDumpVerbosityLevel,
|
|
SmbDeviceStateFlags,
|
|
Result,
|
|
EssentialField,
|
|
&c,
|
|
UnicodeStrings
|
|
);
|
|
|
|
} else {
|
|
|
|
printf( "%04lx - Field inapplicable for FileType", c );
|
|
|
|
}
|
|
|
|
return 2;
|
|
|
|
} // SmbDumpDeviceState
|
|
|
|
|
|
USHORT
|
|
SmbDumpFlags1 (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
ULONG c = (ULONG) *((PUCHAR)Field);
|
|
|
|
SmbDumpFlags4(
|
|
SmbDumpVerbosityLevel,
|
|
Context,
|
|
Result,
|
|
EssentialField,
|
|
&c,
|
|
UnicodeStrings
|
|
);
|
|
|
|
return 1;
|
|
|
|
} // SmbDumpFlags1
|
|
|
|
|
|
// dump ULONG enum, leave dumped value in *(PULONG)Result if it's non-NULL
|
|
USHORT
|
|
SmbDumpEnum4 (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
ULONG c = SmbGetUlong( (PULONG)Field );
|
|
CLONG i;
|
|
PSMB_ENUM_DESCRIPTION enumDesc = Context;
|
|
BOOLEAN found=FALSE;
|
|
|
|
if (Result != NULL) {
|
|
*(PULONG)Result = (ULONG)c;
|
|
}
|
|
|
|
NON_ESSENTIAL_RETURN( 4 );
|
|
|
|
UnicodeStrings;
|
|
|
|
printf( "%04lx - ", c );
|
|
|
|
if ( Context == NULL ) {
|
|
printf( "No enumerated information available.\n" );
|
|
return 4;
|
|
}
|
|
|
|
for ( i = 0; enumDesc[i].Label != NULL; i++ ) {
|
|
|
|
if ( enumDesc[i].EnumValue == c) {
|
|
printf( "%s", enumDesc[i].Label );
|
|
found=TRUE;
|
|
}
|
|
}
|
|
|
|
if(!found) {
|
|
|
|
printf( "UNKNOWN VALUE: %04lx\n", c );
|
|
|
|
}
|
|
|
|
return 4;
|
|
|
|
} // SmbDumpEnum4
|
|
|
|
|
|
// dump USHORT enum, leave dumped value in *(PULONG)Result if it's non-NULL
|
|
USHORT
|
|
SmbDumpEnum2 (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
ULONG c = (ULONG) SmbGetUshort( (PUSHORT)Field );
|
|
|
|
SmbDumpEnum4(
|
|
SmbDumpVerbosityLevel,
|
|
Context,
|
|
Result,
|
|
EssentialField,
|
|
&c,
|
|
UnicodeStrings
|
|
);
|
|
|
|
return 2;
|
|
|
|
} // SmbDumpEnum2
|
|
|
|
|
|
// dump UCHAR enum, leave dumped value in *(PULONG)Result if it's non-NULL
|
|
USHORT
|
|
SmbDumpEnum1 (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
ULONG c = (ULONG) *((PUCHAR)Field);
|
|
|
|
SmbDumpEnum4(
|
|
SmbDumpVerbosityLevel,
|
|
Context,
|
|
Result,
|
|
EssentialField,
|
|
&c,
|
|
UnicodeStrings
|
|
);
|
|
|
|
return 1;
|
|
|
|
} // SmbDumpEnum1
|
|
|
|
|
|
USHORT
|
|
SmbDumpOpenFunction (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
USHORT value = SmbGetUshort( (PUSHORT)Field );
|
|
USHORT _open = (USHORT)(value & SMB_OFUN_OPEN_MASK);
|
|
USHORT create = (USHORT)(value & SMB_OFUN_CREATE_MASK);
|
|
|
|
Context; Result; UnicodeStrings;
|
|
|
|
NON_ESSENTIAL_RETURN( 2 );
|
|
|
|
printf( "%04lx - Create: ", value );
|
|
|
|
switch ( create ) {
|
|
|
|
case SMB_OFUN_CREATE_FAIL:
|
|
printf( "Fail, " );
|
|
break;
|
|
|
|
case SMB_OFUN_CREATE_CREATE:
|
|
printf( "Succeed, " );
|
|
break;
|
|
|
|
default:
|
|
printf( "INVALID" );
|
|
break;
|
|
}
|
|
|
|
printf( "Open: " );
|
|
|
|
switch ( _open ) {
|
|
|
|
case SMB_OFUN_OPEN_FAIL:
|
|
printf( "Fail" );
|
|
break;
|
|
|
|
//case SMB_OFUN_OPEN_APPEND:
|
|
case SMB_OFUN_OPEN_OPEN:
|
|
printf( "Succeed/Append" );
|
|
break;
|
|
|
|
case SMB_OFUN_OPEN_TRUNCATE:
|
|
printf( "Truncate" );
|
|
break;
|
|
|
|
default:
|
|
printf( "INVALID" );
|
|
break;
|
|
}
|
|
|
|
return 2;
|
|
|
|
} // SmbDumpOpenFunction
|
|
|
|
|
|
USHORT
|
|
SmbDumpResumeKey (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
PCHAR p = Field;
|
|
ULONG value;
|
|
ANSI_STRING fileName;
|
|
|
|
Context; Result; UnicodeStrings;
|
|
|
|
NON_ESSENTIAL_RETURN( sizeof(SMB_RESUME_KEY) );
|
|
|
|
if ( *(PCHAR)Field != SMB_FORMAT_VARIABLE ) {
|
|
printf( "(Bad token == %02lx)\n", *(PUCHAR)Field & (UCHAR)0xFF );
|
|
}
|
|
|
|
p++;
|
|
|
|
value = SmbGetUshort( p );
|
|
printf( "\n Variable Block Length.: %lx\n", value );
|
|
p += sizeof(USHORT);
|
|
|
|
value = *p;
|
|
printf( " Reserved..............: %lx\n", value );
|
|
p += sizeof(UCHAR);
|
|
|
|
fileName.Buffer = p;
|
|
fileName.Length = 11;
|
|
printf( " FileName..............: %Z\n", &fileName );
|
|
p += 11;
|
|
|
|
value = *p;
|
|
printf( " Sid...................: %lx\n", value );
|
|
p += sizeof(UCHAR);
|
|
|
|
value = SmbGetUlong( p );
|
|
printf( " File Index............: %lx\n", value );
|
|
p += sizeof(ULONG);
|
|
|
|
value = SmbGetUlong( p );
|
|
printf( " Consumer..............: %lx\n", value );
|
|
|
|
return sizeof(SMB_RESUME_KEY);
|
|
|
|
} // SmbDumpResumeKey
|
|
|
|
|
|
USHORT
|
|
SmbDumpNtTime (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
TIME_FIELDS timeFields;
|
|
|
|
NON_ESSENTIAL_RETURN( 8 );
|
|
|
|
Context; Result; UnicodeStrings;
|
|
|
|
//
|
|
// special case when time is 'all-zeroes'.
|
|
//
|
|
|
|
if ( ((PLARGE_INTEGER)Field)->LowPart == 0 &&
|
|
((PLARGE_INTEGER)Field)->HighPart == 0
|
|
) {
|
|
|
|
printf("[Time unspecified]");
|
|
|
|
} else {
|
|
|
|
RtlTimeToTimeFields( (PLARGE_INTEGER)Field, &timeFields );
|
|
|
|
printf( "%02ld/%02ld/%04ld %02ld:%02ld:%02ld",
|
|
timeFields.Month,
|
|
timeFields.Day,
|
|
timeFields.Year,
|
|
timeFields.Hour,
|
|
timeFields.Minute,
|
|
timeFields.Second
|
|
);
|
|
}
|
|
|
|
return 8;
|
|
|
|
} // SmbDumpNtTime
|
|
|
|
|
|
USHORT
|
|
SmbDumpTime (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
SMB_TIME time;
|
|
Context; Result; UnicodeStrings;
|
|
|
|
NON_ESSENTIAL_RETURN( 2 );
|
|
|
|
time.Ushort = SmbGetUshort( (PUSHORT)Field );
|
|
|
|
printf( "%02d/%02d/%04d",
|
|
time.Struct.Hours,
|
|
time.Struct.Minutes,
|
|
time.Struct.TwoSeconds * 2
|
|
);
|
|
|
|
return 2;
|
|
|
|
} // SmbDumpTime
|
|
|
|
|
|
USHORT
|
|
SmbDumpTimeSince1970 (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
struct tm timeFields;
|
|
|
|
Context, Result, UnicodeStrings;
|
|
|
|
NON_ESSENTIAL_RETURN( 4 );
|
|
|
|
// This is midnight, January 1, 1970 + a LOT of seconds
|
|
// as long as ints and longs are marginally compatible
|
|
// FIXFIX: we could improve this by doing some of the division manually
|
|
// FIXFIX: to ensure the various values are well within the range of
|
|
// FIXFIX: even 16 bit ints.
|
|
timeFields.tm_isdst = 0;
|
|
timeFields.tm_year = 70;
|
|
timeFields.tm_mon = 0;
|
|
timeFields.tm_mday = 0;
|
|
timeFields.tm_hour = 0;
|
|
timeFields.tm_min = 0;
|
|
timeFields.tm_sec = SmbGetUlong( (PULONG)Field );
|
|
|
|
// mktime will normalize the value given, which is all we want
|
|
// i.e. we can ignore the return value
|
|
mktime( &timeFields );
|
|
|
|
// printf( "Sec. since 1970: %08lx", SmbGetUlong( (PULONG)Field ) );
|
|
printf( "%02d/%02d/%04d %02d:%02d:%02d",
|
|
timeFields.tm_mon,
|
|
timeFields.tm_mday,
|
|
timeFields.tm_year,
|
|
timeFields.tm_hour,
|
|
timeFields.tm_min,
|
|
timeFields.tm_sec
|
|
);
|
|
|
|
return 4;
|
|
|
|
} // SmbDumpTimeSince1970
|
|
|
|
|
|
// dump UCHAR, leave dumped value in *(PULONG)Result if it's non-NULL
|
|
USHORT
|
|
SmbDumpUchar (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
UCHAR c = *(PUCHAR)Field;
|
|
|
|
if (Result != NULL) {
|
|
*(PULONG)Result = (ULONG)c;
|
|
}
|
|
|
|
NON_ESSENTIAL_RETURN( 1 );
|
|
|
|
printf( "%02lx", c );
|
|
|
|
return 1;
|
|
|
|
Context; UnicodeStrings;
|
|
|
|
} // SmbDumpUchar
|
|
|
|
|
|
// dump USHORT, leave dumped value in *(PULONG)Result if it's non-NULL
|
|
USHORT
|
|
SmbDumpUshort (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
USHORT c = SmbGetUshort( (PUSHORT)Field );
|
|
|
|
if (Result != NULL) {
|
|
*(PULONG)Result = (ULONG)c;
|
|
}
|
|
|
|
NON_ESSENTIAL_RETURN( 2 );
|
|
|
|
printf( "%04lx", c );
|
|
|
|
return 2;
|
|
|
|
Context; UnicodeStrings;
|
|
|
|
} // SmbDumpUshort
|
|
|
|
|
|
// dump ULONG, leave dumped value in *(PULONG)Result if it's non-NULL
|
|
USHORT
|
|
SmbDumpUlong (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
ULONG c = SmbGetUlong( (PULONG)Field );
|
|
|
|
if (Result != NULL) {
|
|
*(PULONG)Result = c;
|
|
}
|
|
|
|
NON_ESSENTIAL_RETURN( 4 );
|
|
|
|
printf( "%08lx", c );
|
|
|
|
return 4;
|
|
|
|
Context; UnicodeStrings;
|
|
|
|
} // SmbDumpUlong
|
|
|
|
|
|
USHORT
|
|
SmbDumpUquad (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PVOID Context,
|
|
OUT PVOID Result,
|
|
IN BOOLEAN EssentialField,
|
|
IN PVOID Field,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
LARGE_INTEGER c;
|
|
|
|
SmbPutUquad( &c, (PLARGE_INTEGER)Field );
|
|
|
|
NON_ESSENTIAL_RETURN( 8 );
|
|
|
|
printf( "%08lx:%08lx", c.HighPart, c.LowPart );
|
|
|
|
return 8;
|
|
Context; UnicodeStrings;
|
|
|
|
} // SmbDumpUquad
|
|
|
|
//
|
|
// Other routines used in displaying SMBs.
|
|
//
|
|
|
|
|
|
USHORT
|
|
SmbDumpDescriptor (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PSMB_FIELD_DESCRIPTION Descriptor,
|
|
IN PCHAR Parameters,
|
|
IN BOOLEAN UnicodeStrings
|
|
)
|
|
|
|
{
|
|
PCHAR parameters = Parameters;
|
|
CSHORT i;
|
|
|
|
if ( Descriptor == NULL ) {
|
|
printf( " No parameter information available for this command.\n\n" );
|
|
return 0;
|
|
}
|
|
|
|
for ( i = 0; Descriptor[i].DumpRoutine != NULL; i++ ) {
|
|
|
|
if ( SmbDumpVerbosityLevel >= SMBTRACE_VERBOSITY_NONESSENTIAL ||
|
|
Descriptor[i].EssentialField ) {
|
|
|
|
printf( " %s", Descriptor[i].Label );
|
|
}
|
|
|
|
parameters += Descriptor[i].DumpRoutine(
|
|
SmbDumpVerbosityLevel,
|
|
Descriptor[i].Context,
|
|
Descriptor[i].Result,
|
|
Descriptor[i].EssentialField,
|
|
parameters,
|
|
UnicodeStrings
|
|
);
|
|
|
|
if ( Descriptor[i].EndLabel != NULL &&
|
|
( SmbDumpVerbosityLevel >= SMBTRACE_VERBOSITY_NONESSENTIAL ||
|
|
Descriptor[i].EssentialField ) ) {
|
|
|
|
printf( "%s", Descriptor[i].EndLabel );
|
|
}
|
|
}
|
|
|
|
return (USHORT)(parameters - Parameters);
|
|
|
|
} // SmbDumpDescriptor
|
|
|
|
|
|
VOID
|
|
SmbDumpError (
|
|
IN UCHAR ErrorClass,
|
|
IN USHORT ErrorCode
|
|
)
|
|
|
|
{
|
|
CSHORT i;
|
|
|
|
printf( " ERROR -- Class %ld: ", ErrorClass );
|
|
|
|
switch ( ErrorClass ) {
|
|
|
|
case SMB_ERR_CLASS_DOS:
|
|
printf( "DOS " );
|
|
break;
|
|
|
|
case SMB_ERR_CLASS_SERVER:
|
|
printf( "Server " );
|
|
break;
|
|
|
|
case SMB_ERR_CLASS_HARDWARE:
|
|
printf( "Hardware " );
|
|
break;
|
|
|
|
default:
|
|
printf( "Unknown Code %ld\n", ErrorCode );
|
|
return;
|
|
}
|
|
|
|
printf( "Code %ld: ", ErrorCode );
|
|
|
|
for ( i = 0; SmbErrors[ErrorClass][i].ErrorValue != 0; i++ ) {
|
|
if ( SmbErrors[ErrorClass][i].ErrorValue == ErrorCode ) {
|
|
printf( "%s\n", SmbErrors[ErrorClass][i].ErrorName );
|
|
return;
|
|
}
|
|
}
|
|
|
|
printf( "Unknown\n" );
|
|
return;
|
|
|
|
} // SmbDumpError
|
|
|
|
|
|
VOID
|
|
SmbDumpNtError (
|
|
NTSTATUS Status
|
|
)
|
|
|
|
{
|
|
printf( " ERROR -- Code %X: (error text here)\n", Status );
|
|
|
|
// BUGBUG: incomplete. Perhaps use FormatMessage to produce proper
|
|
// BUGBUG: text.
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
USHORT
|
|
SmbDumpGetTransSubCommand (
|
|
IN PNT_SMB_HEADER SmbHeader
|
|
)
|
|
|
|
{
|
|
CSHORT index;
|
|
USHORT tid = SmbGetAlignedUshort( &SmbHeader->Tid );
|
|
USHORT pid = SmbGetAlignedUshort( &SmbHeader->Pid );
|
|
USHORT uid = SmbGetAlignedUshort( &SmbHeader->Uid );
|
|
USHORT mid = SmbGetAlignedUshort( &SmbHeader->Mid );
|
|
|
|
for ( index = 0; index < SMB_DUMP_MAX_TRANSACTIONS; index++ ) {
|
|
|
|
if ( tid == SmbDumpTransList[index].Tid &&
|
|
pid == SmbDumpTransList[index].Pid &&
|
|
uid == SmbDumpTransList[index].Uid &&
|
|
mid == SmbDumpTransList[index].Mid ) {
|
|
|
|
return SmbDumpTransList[index].SubCommand;
|
|
}
|
|
}
|
|
|
|
printf( "TRANSACTION NOT FOUND!!!\n" );
|
|
return (USHORT)0xFFFF;
|
|
|
|
} // SmbDumpGetTransSubCommand
|
|
|
|
|
|
VOID
|
|
SmbDumpHeader (
|
|
IN CLONG SmbDumpVerbosityLevel,
|
|
IN PNT_SMB_HEADER SmbHeader,
|
|
IN BOOLEAN NtFormatStatus
|
|
)
|
|
|
|
{
|
|
UCHAR flags = SmbHeader->Flags;
|
|
USHORT flags2 = SmbGetAlignedUshort( &SmbHeader->Flags2 );
|
|
USHORT unknownFlags2;
|
|
|
|
printf( "Pid: %04lx, Tid: %04lx, Uid: %04lx, Mid: %04lx\n",
|
|
SmbGetAlignedUshort( &SmbHeader->Pid ),
|
|
SmbGetAlignedUshort( &SmbHeader->Tid ),
|
|
SmbGetAlignedUshort( &SmbHeader->Uid ),
|
|
SmbGetAlignedUshort( &SmbHeader->Mid ) );
|
|
|
|
printf( "Flags: %02lx - ", flags & (UCHAR)0xFF );
|
|
|
|
if ( flags & SMB_FLAGS_LOCK_AND_READ_OK ) {
|
|
printf( "LockAndReadSupported " );
|
|
}
|
|
|
|
if ( flags & SMB_FLAGS_SEND_NO_ACK ) {
|
|
printf( "SendNoAck " );
|
|
}
|
|
|
|
if ( flags & SMB_FLAGS_CASE_INSENSITIVE ) {
|
|
printf( "CaseInsensitive " );
|
|
}
|
|
|
|
if ( flags & SMB_FLAGS_CANONICALIZED_PATHS ) {
|
|
printf( "CanonicalizedPaths " );
|
|
}
|
|
|
|
if ( flags & SMB_FLAGS_OPLOCK ) {
|
|
printf( "Oplock " );
|
|
}
|
|
|
|
if ( flags & SMB_FLAGS_OPLOCK_NOTIFY_ANY ) {
|
|
printf( "NotifyAny " );
|
|
}
|
|
|
|
if ( flags & SMB_FLAGS_SERVER_TO_REDIR ) {
|
|
printf( "Response " );
|
|
}
|
|
|
|
printf( " Flags2: %04lx - ", flags2 & (USHORT)0xFFFF );
|
|
|
|
if ( flags2 & SMB_FLAGS2_KNOWS_LONG_NAMES ) {
|
|
printf( "LongNames " );
|
|
}
|
|
|
|
if ( flags2 & SMB_FLAGS2_KNOWS_EAS ) {
|
|
printf( "EAs " );
|
|
}
|
|
|
|
if ( flags2 & SMB_FLAGS2_IS_LONG_NAME ) {
|
|
printf( "IsLongName " );
|
|
}
|
|
|
|
if ( flags2 & SMB_FLAGS2_PAGING_IO ) {
|
|
printf( "PagingIO " );
|
|
}
|
|
|
|
if ( flags2 & SMB_FLAGS2_NT_STATUS ) {
|
|
printf( "NtFormatStatus " );
|
|
}
|
|
|
|
if ( flags2 & SMB_FLAGS2_UNICODE ) {
|
|
printf( "Unicode " );
|
|
}
|
|
|
|
unknownFlags2 = flags2 & ~(USHORT)(
|
|
SMB_FLAGS2_KNOWS_LONG_NAMES
|
|
| SMB_FLAGS2_KNOWS_EAS
|
|
| SMB_FLAGS2_IS_LONG_NAME
|
|
| SMB_FLAGS2_PAGING_IO
|
|
| SMB_FLAGS2_NT_STATUS
|
|
| SMB_FLAGS2_UNICODE
|
|
);
|
|
|
|
if ( unknownFlags2 ) {
|
|
printf( "UNKNOWN BITS ON: %04lx", unknownFlags2 );
|
|
}
|
|
|
|
printf( "\n" );
|
|
|
|
if ( SmbDumpVerbosityLevel >= SMBTRACE_VERBOSITY_NONESSENTIAL ) {
|
|
|
|
if (
|
|
!NtFormatStatus &&
|
|
( SmbGetUshort( &SmbHeader->Status.DosError.Error ) == 0)
|
|
) {
|
|
|
|
printf( "ErrorClass: 0, ErrorCode: 0\n" );
|
|
|
|
} else if(
|
|
NtFormatStatus &&
|
|
( SmbGetUlong( &SmbHeader->Status.NtStatus ) == STATUS_SUCCESS )
|
|
) {
|
|
|
|
printf( "NtStatus: STATUS_SUCCESS\n" );
|
|
|
|
}
|
|
|
|
printf( "Command: %02lx, Reserved: %02lx\n",
|
|
SmbHeader->Command, SmbHeader->Status.DosError.Reserved );
|
|
|
|
printf( "Reserved2[]: %04lx %04lx %04lx %04lx %04lx %04lx\n",
|
|
SmbGetUshort( &SmbHeader->Reserved2[0] ),
|
|
SmbGetUshort( &SmbHeader->Reserved2[1] ),
|
|
SmbGetUshort( &SmbHeader->Reserved2[2] ),
|
|
SmbGetUshort( &SmbHeader->Reserved2[3] ),
|
|
SmbGetUshort( &SmbHeader->Reserved2[4] ),
|
|
SmbGetUshort( &SmbHeader->Reserved2[5] ) );
|
|
}
|
|
|
|
return;
|
|
|
|
} // SmbDumpHeader
|
|
|
|
|
|
VOID
|
|
SmbDumpSetTransSubCommand (
|
|
IN PNT_SMB_HEADER SmbHeader,
|
|
IN USHORT SubCommand
|
|
)
|
|
|
|
{
|
|
USHORT tid = SmbGetAlignedUshort( &SmbHeader->Tid );
|
|
USHORT pid = SmbGetAlignedUshort( &SmbHeader->Pid );
|
|
USHORT uid = SmbGetAlignedUshort( &SmbHeader->Uid );
|
|
USHORT mid = SmbGetAlignedUshort( &SmbHeader->Mid );
|
|
|
|
SmbDumpTransList[SmbDumpTransIndex].Tid = tid;
|
|
SmbDumpTransList[SmbDumpTransIndex].Pid = pid;
|
|
SmbDumpTransList[SmbDumpTransIndex].Uid = uid;
|
|
SmbDumpTransList[SmbDumpTransIndex].Mid = mid;
|
|
|
|
SmbDumpTransList[SmbDumpTransIndex].SubCommand = SubCommand;
|
|
|
|
if ( ++SmbDumpTransIndex >= SMB_DUMP_MAX_TRANSACTIONS ) {
|
|
SmbDumpTransIndex = 0;
|
|
}
|
|
|
|
return;
|
|
|
|
} // SmbDumpSetTransSubCommand
|
|
|
|
// ASCII-specific
|
|
#undef isprint
|
|
#define isprint(c) ( (c) >= ' ' && (c) <= '~' )
|
|
|
|
|
|
VOID
|
|
SmbDumpRawData (
|
|
IN PCHAR DataStart,
|
|
IN CLONG DataLength,
|
|
IN CLONG Offset
|
|
)
|
|
|
|
{
|
|
CLONG lastByte;
|
|
CCHAR lineBuffer[80];
|
|
PCCHAR bufferPtr;
|
|
|
|
for ( lastByte = Offset + DataLength; Offset < lastByte; Offset += 16 ) {
|
|
|
|
CLONG i;
|
|
|
|
bufferPtr = lineBuffer;
|
|
|
|
sprintf( bufferPtr, " %04lx: ", Offset );
|
|
bufferPtr += 10;
|
|
|
|
|
|
for ( i = 0; i < 16 && Offset + i < lastByte; i++ ) {
|
|
|
|
sprintf( bufferPtr, "%02lx", (UCHAR)DataStart[Offset + i] & (UCHAR)0xFF );
|
|
bufferPtr += 2;
|
|
|
|
if ( i == 7 ) {
|
|
*bufferPtr++ = '-';
|
|
} else {
|
|
*bufferPtr++ = ' ';
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print enough spaces so that the ASCII display lines up.
|
|
//
|
|
|
|
for ( ; i < 16; i++ ) {
|
|
*bufferPtr++ = ' ';
|
|
*bufferPtr++ = ' ';
|
|
*bufferPtr++ = ' ';
|
|
}
|
|
|
|
*bufferPtr++ = ' ';
|
|
*bufferPtr++ = ' ';
|
|
*bufferPtr++ = '*';
|
|
|
|
for ( i = 0; i < 16 && Offset + i < lastByte; i++ ) {
|
|
if ( isprint( DataStart[Offset + i] ) ) {
|
|
*bufferPtr++ = (CCHAR)DataStart[Offset + i];
|
|
} else {
|
|
*bufferPtr++ = '.';
|
|
}
|
|
}
|
|
|
|
*bufferPtr = 0;
|
|
printf( "%s*\n", lineBuffer );
|
|
}
|
|
|
|
return;
|
|
|
|
} // SmbDumpRawData
|
|
|
|
|
|
VOID
|
|
SmbDumpSingleLine (
|
|
IN PNT_SMB_HEADER SmbHeader,
|
|
IN CLONG SmbLength,
|
|
IN PVOID SmbAddress,
|
|
IN BOOLEAN IsServer,
|
|
IN BOOLEAN IsResponse,
|
|
IN BOOLEAN ntFormatStatus
|
|
)
|
|
|
|
{
|
|
UCHAR command = SmbHeader->Command;
|
|
PGENERIC_ANDX parameters = (PGENERIC_ANDX)(SmbHeader + 1);
|
|
|
|
if ( IsResponse ) {
|
|
if ( IsServer ) {
|
|
printf( "SEND RESP: " );
|
|
} else {
|
|
printf( "RECV RESP: " );
|
|
}
|
|
} else {
|
|
if ( IsServer ) {
|
|
printf( "RECV REQ: " );
|
|
} else {
|
|
printf( "SEND REQ: " );
|
|
}
|
|
}
|
|
|
|
//
|
|
// print an original address if one is provided
|
|
//
|
|
if ( SmbAddress != NULL ) {
|
|
printf( "%08lx ", SmbAddress );
|
|
} else {
|
|
printf( "-------- " );
|
|
}
|
|
|
|
printf( "tid %04lx, pid %04lx, len %04lx, ",
|
|
SmbGetAlignedUshort( &SmbHeader->Tid ),
|
|
SmbGetAlignedUshort( &SmbHeader->Pid ),
|
|
SmbLength );
|
|
|
|
printf( "%s%s",
|
|
(
|
|
(SmbDumpTable[command].NtDescriptor !=NULL)
|
|
&& ( *(PCHAR)( SmbHeader + 1 )
|
|
== SmbDumpTable[command].NtSpecialWordCount )
|
|
// && !( !IsResponse ^^ SmbDumpTable[command].NtIsRequest )
|
|
) ? "(NT) " : "",
|
|
SmbDumpTable[command].SmbName );
|
|
|
|
if ( command == SMB_COM_TRANSACTION2 ) {
|
|
|
|
USHORT subCommand;
|
|
|
|
if ( IsResponse ) {
|
|
|
|
subCommand = SmbDumpGetTransSubCommand( SmbHeader );
|
|
|
|
if ( subCommand == (USHORT)0xFF ) {
|
|
printf( " USRV test" );
|
|
} else if ( subCommand > 0x0D ) {
|
|
printf( "Error in SmbDumpTransTable!!! - SubCommand = 0x%lx\n",
|
|
subCommand );
|
|
return;
|
|
} else {
|
|
printf( " %s", SmbTrans2DumpTable[subCommand].SmbName );
|
|
}
|
|
|
|
} else {
|
|
|
|
subCommand =
|
|
SmbGetUshort(
|
|
(PUSHORT)((PREQ_TRANSACTION)(SmbHeader + 1))->Buffer
|
|
);
|
|
if ( subCommand == 0xFF ) {
|
|
printf(" Usrv Test");
|
|
} else if ( subCommand > 0x0D ) {
|
|
printf( "Error in SmbDumpTransTable!!! - SubCommand = 0x%lx\n",
|
|
subCommand );
|
|
return;
|
|
} else {
|
|
printf( " %s", SmbTrans2DumpTable[subCommand].SmbName );
|
|
}
|
|
}
|
|
} else if ( command == SMB_COM_NT_TRANSACT ) {
|
|
|
|
USHORT subCommand;
|
|
|
|
if ( IsResponse ) {
|
|
|
|
subCommand = SmbDumpGetTransSubCommand( SmbHeader );
|
|
|
|
if ( subCommand > 0x05 ) {
|
|
printf("Error in SmbDumpNtTransTable!!! - SubCommand = 0x%lx\n",
|
|
subCommand );
|
|
return;
|
|
} else {
|
|
printf( " %s", SmbNtTransDumpTable[subCommand].SmbName );
|
|
}
|
|
|
|
} else {
|
|
|
|
subCommand =
|
|
SmbGetUshort(
|
|
(PUSHORT)((PREQ_TRANSACTION)(SmbHeader + 1))->Buffer
|
|
);
|
|
if ( subCommand > 0x05 ) {
|
|
printf("Error in SmbDumpNtTransTable!!! - SubCommand = 0x%lx\n",
|
|
subCommand );
|
|
return;
|
|
} else {
|
|
printf( " %s", SmbNtTransDumpTable[subCommand].SmbName );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
while ( SmbDumpTable[command].IsAndXCommand ) {
|
|
|
|
command = parameters->AndXCommand;
|
|
|
|
// Breakout for errors
|
|
if ( (!ntFormatStatus &&
|
|
SmbGetUshort( &((PNT_SMB_HEADER)SmbHeader)->Status.DosError.Error )
|
|
!= 0 )
|
|
|| ( ntFormatStatus &&
|
|
SmbGetUlong( &((PNT_SMB_HEADER)SmbHeader)->Status.NtStatus)
|
|
!= STATUS_SUCCESS ))
|
|
{
|
|
break;
|
|
}
|
|
if ( command != SMB_COM_NO_ANDX_COMMAND ) {
|
|
|
|
printf( ", %s", SmbDumpTable[command].SmbName );
|
|
parameters =
|
|
(PGENERIC_ANDX)( (PCHAR)SmbHeader +
|
|
SmbGetUshort( ¶meters->AndXOffset ) );
|
|
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
printf( "\n" );
|
|
|
|
return;
|
|
|
|
} // SmbDumpSingleLine
|
|
|