- A Smattering of SMB Dialects
- Greetings: The NEGOTIATE PROTOCOL REQUEST
- Gesundheit: The NEGOTIATE PROTOCOL RESPONSE
- Are We There Yet?
13.2 Greetings: The NEGOTIATE PROTOCOL REQUEST
We have already provided a detailed breakdown of a NEGOTIATE PROTOCOL REQUEST SMB (back in Section 11.3 on page 186), so we don’t need to go to the trouble of fully dissecting it again. The interesting part of the request is the data section (the parameter section is empty). If we were to write a client that supported all of the dialects in our chart, the NEGOTIATE_PROTOCOL_REQUEST.SMB_DATA field would break out something like this:
SMB_DATA { ByteCount = 131 Bytes { Dialect[0] = "\x02PC NETWORK PROGRAM 1.0" Dialect[1] = "\x02MICROSOFT NETWORKS 1.03" Dialect[2] = "\x02MICROSOFT NETWORKS 3.0" Dialect[3] = "\x02LANMAN1.0" Dialect[4] = "\x02LM1.2X002" Dialect[5] = "\x02LANMAN2.1" Dialect[6] = "\x02Samba" Dialect[7] = "\x02NT LM 0.12" Dialect[8] = "\x02CIFS" } }
Each dialect string is preceded by a byte containing the value 0x02. This, perhaps, was originally intended to make it easier to parse the buffer. In addition to the 0x02 prefix the dialect strings are nul-terminated, so if you go to the trouble of counting up the bytes to see if the ByteCount value is correct in this example don’t forget to add 1 to each string length.
Listing 13.1 provides code for creating a NEGOTIATE PROTOCOL REQUEST message. It also takes care of writing an NBT Session Message header for us — something we must not forget to do.
Listing 13.1 Negotiate Protocol Request
/* Define the SMB message command code. */ #define SMB_COM_NEGOTIATE 0x72 int nbt_SessionHeader( uchar *bufr, ulong size ) /* ---------------------------------------------------- ** * This function writes the NBT Session Service header. * Note that we use NBT byte order, not SMB. * ---------------------------------------------------- ** */ { if( size > 0x0001FFFF ) /* That's the NBT maximum. */ return( -1 ); bufr[0] = 0; bufr[1] = (size >> 16) & 0xFF; bufr[2] = (size >> 8) & 0xFF; bufr[3] = size & 0xFF; return( (int)size ); } /* nbt_SessionHeader */ int smb_NegProtRequest( uchar *bufr, int bsize, int namec, uchar **namev ) /* ---------------------------------------------------- ** * Build a Negotiate Protocol Request message. * ---------------------------------------------------- ** */ { uchar *smb_bufr; int i; int length; int offset; ushort bytecount; uchar flags; ushort flags2; /* Set aside four bytes for the session header. */ bsize = bsize - 4; smb_bufr = bufr + 4; /* Make sure we have enough room for the header, * the WORDCOUNT field, and the BYTECOUNT field. * That's the absolute minimum (with no dialects). */ if( bsize < (SMB_HDR_SIZE + 3) ) return( -1 ); /* Initialize the SMB header. * This zero-fills all header fields except for * the Protocol field ("\ffSMB"). * We have already tested the buffer size so * we can void the return value. */ (void)smb_hdrInit( smb_bufr, bsize ); /* Hard-coded flags values... */ flags = SMB_FLAGS_CANONICAL_PATHNAMES; flags |= SMB_FLAGS_CASELESS_PATHNAMES; flags2 = SMB_FLAGS2_KNOWS_LONG_NAMES; /* Fill in the header. */ smb_hdrSetCmd( smb_bufr, SMB_COM_NEGOTIATE ); smb_hdrSetFlags( smb_bufr, flags ); smb_hdrSetFlags2( smb_bufr, flags2 ); /* Fill in the (empty) parameter block. */ smb_bufr[SMB_HDR_SIZE] = 0; /* Copy the dialect names into the message. * Set offset to indicate the start of the * BYTES field, skipping BYTECOUNT. We will * fill in BYTECOUNT later. */ offset = SMB_HDR_SIZE + 3; for( bytecount = i = 0; i < namec; i++ ) { length = strlen(namev[i]) + 1; /* includes nul */ if( bsize < (offset + 1 + length) ) /* includes 0x02 */ return( -1 ); smb_bufr[offset++] = '\x02'; (void)memcpy( &smb_bufr[offset], namev[i], length ); offset += length; bytecount += length + 1; } /* The offset is now the total size of the SMB message. */ if( nbt_SessionHeader( bufr, (ulong)offset ) < offset ) return( -1 ); /* The BYTECOUNT field starts one byte beyond the end * of the header (one byte for the WORDCOUNT field). */ smb_SetShort( smb_bufr, (SMB_HDR_SIZE + 1), bytecount ); /* Return the total size of the packet. */ return( offset + 4 ); } /* smb_NegProtRequest */