Code... The next Listing 12.2 provides support for reading and writing SMB message headers. Most of the header fields are simple integer values, so we can use the smb_Set*() and smb_Get*() functions from Listing 11.1 to move the data in and out of the header buffer. To make subsequent code easier to read, we provide a set of macros with nice clear names to front-end the function calls and assignments that are actually used. Listing 12.2a SMB Header [De]Construction: MB_Header.h/* SMB Headers are always 32 bytes long. */ #define SMB_HDR_SIZE 32 /* FLAGS field bitmasks. */ #define SMB_FLAGS_SERVER_TO_REDIR 0x80 #define SMB_FLAGS_REQUEST_BATCH_OPLOCK 0x40 #define SMB_FLAGS_REQUEST_OPLOCK 0x20 #define SMB_FLAGS_CANONICAL_PATHNAMES 0x10 #define SMB_FLAGS_CASELESS_PATHNAMES 0x08 #define SMB_FLAGS_RESERVED 0x04 #define SMB_FLAGS_CLIENT_BUF_AVAIL 0x02 #define SMB_FLAGS_SUPPORT_LOCKREAD 0x01 #define SMB_FLAGS_MASK 0xFB /* FLAGS2 field bitmasks. */ #define SMB_FLAGS2_UNICODE_STRINGS 0x8000 #define SMB_FLAGS2_32BIT_STATUS 0x4000 #define SMB_FLAGS2_READ_IF_EXECUTE 0x2000 #define SMB_FLAGS2_DFS_PATHNAME 0x1000 #define SMB_FLAGS2_EXTENDED_SECURITY 0x0800 #define SMB_FLAGS2_RESERVED_01 0x0400 #define SMB_FLAGS2_RESERVED_02 0x0200 #define SMB_FLAGS2_RESERVED_03 0x0100 #define SMB_FLAGS2_RESERVED_04 0x0080 #define SMB_FLAGS2_IS_LONG_NAME 0x0040 #define SMB_FLAGS2_RESERVED_05 0x0020 #define SMB_FLAGS2_RESERVED_06 0x0010 #define SMB_FLAGS2_RESERVED_07 0x0008 #define SMB_FLAGS2_SECURITY_SIGNATURE 0x0004 #define SMB_FLAGS2_EAS 0x0002 #define SMB_FLAGS2_KNOWS_LONG_NAMES 0x0001 #define SMB_FLAGS2_MASK 0xF847 /* Field offsets. */ #define SMB_OFFSET_CMD 4 #define SMB_OFFSET_NTSTATUS 5 #define SMB_OFFSET_ECLASS 5 #define SMB_OFFSET_ECODE 7 #define SMB_OFFSET_FLAGS 9 #define SMB_OFFSET_FLAGS2 10 #define SMB_OFFSET_EXTRA 12 #define SMB_OFFSET_TID 24 #define SMB_OFFSET_PID 26 #define SMB_OFFSET_UID 28 #define SMB_OFFSET_MID 30 /* SMB command codes are given in the * SNIA doc. */ /* Write a command byte to the header buffer. */ #define smb_hdrSetCmd( bufr, cmd ) \ (bufr)[SMB_OFFSET_CMD] = (cmd) /* Read a command byte; returns uchar. */ #define smb_hdrGetCmd( bufr ) \ (uchar)((bufr)[SMB_OFFSET_CMD]) /* Write a DOS Error Class to the header buffer. */ #define smb_hdrSetEclassDOS( bufr, Eclass ) \ (bufr)[SMB_OFFSET_ECLASS] = (Eclass) /* Read a DOS Error Class; returns uchar. */ #define smb_hdrGetEclassDOS( bufr ) \ (uchar)((bufr)[SMB_OFFSET_ECLASS]) /* Write a DOS Error Code to the header buffer. */ #define smb_hdrSetEcodeDOS( bufr, Ecode ) \ smb_SetShort( bufr, SMB_OFFSET_ECODE, Ecode ) /* Read a DOS Error Code; returns ushort. */ #define smb_hdrGetEcodeDOS( bufr ) \ smb_GetShort( bufr, SMB_OFFSET_ECODE ) /* Write an NT_STATUS code. */ #define smb_hdrSetNTStatus( bufr, nt_status ) \ smb_PutLong( bufr, SMB_OFFSET_NTSTATUS, nt_status ) /* Read an NT_STATUS code; returns ulong. */ #define smb_hdrGetNTStatus( bufr ) \ smb_GetLong( bufr, SMB_OFFSET_NTSTATUS ) /* Write FLAGS to the header buffer. */ #define smb_hdrSetFlags( bufr, flags ) \ (bufr)[SMB_OFFSET_FLAGS] = (flags) /* Read FLAGS; returns uchar. */ #define smb_hdrGetFlags( bufr ) \ (uchar)((bufr)[SMB_OFFSET_FLAGS]) /* Write FLAGS2 to the header buffer. */ #define smb_hdrSetFlags2( bufr, flags2 ) \ smb_SetShort( bufr, SMB_OFFSET_FLAGS2, flags2 ) /* Read FLAGS2; returns ushort. */ #define smb_hdrGetFlags2( bufr ) \ smb_GetShort( bufr, SMB_OFFSET_FLAGS2 ) /* Write the TID. */ #define smb_hdrSetTID( bufr, TID ) \ smb_SetShort( bufr, SMB_OFFSET_TID, TID ) /* Read the TID; returns ushort. */ #define smb_hdrGetTID( bufr ) \ smb_GetShort( bufr, SMB_OFFSET_TID ) /* Write the PID. */ #define smb_hdrSetPID( bufr, PID ) \ smb_SetShort( bufr, SMB_OFFSET_PID, PID ) /* Read the PID; returns ushort. */ #define smb_hdrGetPID( bufr ) \ smb_GetShort( bufr, SMB_OFFSET_PID ) /* Write the [V]UID. */ #define smb_hdrSetUID( bufr, UID ) \ smb_SetShort( bufr, SMB_OFFSET_UID, UID ) /* Read the [V]UID; returns ushort. */ #define smb_hdrGetUID( bufr ) \ smb_GetShort( bufr, SMB_OFFSET_UID ) /* Write the MID. */ #define smb_hdrSetMID( bufr, MID ) \ smb_SetShort( bufr, SMB_OFFSET_MID, MID ) /* Read the MID; returns ushort. */ #define smb_hdrGetMID( bufr ) \ smb_GetShort( bufr, SMB_OFFSET_MID ) /* Function prototypes. */ int smb_hdrInit( uchar *bufr, int bsize ); /* ---------------------------------------------------- ** * Initialize an empty header structure. * Returns -1 on error, the SMB header size on success. * ---------------------------------------------------- ** */ int smb_hdrCheck( uchar *bufr, int bsize ); /* ---------------------------------------------------- ** * Perform some quick checks on a received buffer to * make sure it's safe to read. This function returns * a negative value if the SMB header is invalid. * ---------------------------------------------------- ** */ Listing 12.2b SMB Header [De]Construction: MB_Header.c#include "smb_header.h" const char *smb_hdrSMBString = "\xffSMB"; int smb_hdrInit( uchar *bufr, int bsize ) /* ---------------------------------------------------- ** * Initialize an empty header structure. * Returns -1 on error, the SMB header size on success. * ---------------------------------------------------- ** */ { int i; if( bsize < SMB_HDR_SIZE ) return( -1 ); for( i = 0; i < 4; i++ ) bufr[i] = smb_hdrSMBString[i]; for( i = 4; i < SMB_HDR_SIZE; i++ ) bufr[i] = '#include "smb_header.h" const char *smb_hdrSMBString = "\xffSMB"; int smb_hdrInit( uchar *bufr, int bsize ) /* ---------------------------------------------------- ** * Initialize an empty header structure. * Returns -1 on error, the SMB header size on success. * ---------------------------------------------------- ** */ { int i; if( bsize < SMB_HDR_SIZE ) return( -1 ); for( i = 0; i < 4; i++ ) bufr[i] = smb_hdrSMBString[i]; for( i = 4; i < SMB_HDR_SIZE; i++ ) bufr[i] = '\0'; return( SMB_HDR_SIZE ); } /* smb_hdrInit */ int smb_hdrCheck( uchar *bufr, int bsize ) /* ---------------------------------------------------- ** * Perform some quick checks on a received buffer to * make sure it's safe to read. This function returns * a negative value if the SMB header is invalid. * ---------------------------------------------------- ** */ { int i; if( NULL == bufr ) return( -1 ); if( bsize < SMB_HDR_SIZE ) return( -2 ); for( i = 0; i < 4; i++ ) if( bufr[i] != smb_hdrSMBString[i] ) return( -3 ); return( SMB_HDR_SIZE ); } /* smb_hdrCheck */'; return( SMB_HDR_SIZE ); } /* smb_hdrInit */ int smb_hdrCheck( uchar *bufr, int bsize ) /* ---------------------------------------------------- ** * Perform some quick checks on a received buffer to * make sure it's safe to read. This function returns * a negative value if the SMB header is invalid. * ---------------------------------------------------- ** */ { int i; if( NULL == bufr ) return( -1 ); if( bsize < SMB_HDR_SIZE ) return( -2 ); for( i = 0; i < 4; i++ ) if( bufr[i] != smb_hdrSMBString[i] ) return( -3 ); return( SMB_HDR_SIZE ); } /* smb_hdrCheck */ The smb_hdrInit() and smb_hdrCheck() functions are there primarily to ensure that the SMB headers are reasonably sane. They check for things like the buffer size, and ensure that the " \xffSMB " string is included correctly in the header buffer. Note that none of these functions or macros handle the reading and writing of the four-byte session header, though that would be trivial. The SESSION MESSAGE header is part of the transport layer, not SMB. It is handled as a simple network-byte-order longword; something from the NBT Session Service that has been carried over into naked transport. (We covered all this back in Chapter 6 on page 129 and Section 8.2 on page 150.) |