windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/msgsvc/server/smbcheck.c
2020-09-26 16:20:57 +08:00

273 lines
7.4 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
smbcheck.c
Abstract:
Contains a routine for checking Server Message Block for
syntactical correctness.
Author:
Dan Lafferty (danl) 17-Jul-1991
Environment:
User Mode -Win32
Notes:
These files assume that the buffers and strings are NOT Unicode - just
straight ansi.
Revision History:
17-Jul-1991 danl
ported from LM2.0
--*/
#include <windows.h>
#include <lmcons.h> // network constants and stuff
#include <smbtypes.h> // needed for smb.h
#include <smb.h> // Server Message Block definitions
#include <string.h> // strlen
#include <nb30.h> // Needed in msrv.h
/*
** Msgsmbcheck - check Server Message Block for syntactical correctness
**
** This function is called to verify that a Server Message Block
** is of the specified form. The function returns zero if the
** SMB is correct; if an error is detected, a non-zero value
** indicating the nature of the error is returned.
**
** smbcheck (buffer, size, func, parms, fields)
**
** ENTRY
** buffer - a pointer to the buffer containing the SMB
** size - the number of bytes in the buffer
** func - the expected SMB function code
** parms - the expected number of parameters
** fields - a dope vector describing the expected buffer fields
** within the SMB's buffer area (see below).
**
** RETURN
** an integer status code; zero indicates no errors.
**
** An SMB is a variable length structure whose exact size
** depends on the setting of certain fixed-offset fields
** and whose exact format cannot be determined except by
** examination of the whole structure. Smbcheck checks to
** see that an SMB conforms to a set of specified conditions.
** The "fields" parameter is a dope vector that describes the
** individual fields to be found in the buffer section at the
** end of the SMB. The vector is a null-terminated character
** string. Currently, the elements of the string must be as
** follows:
**
** 'b' - the next element in the buffer area should be
** a variable length buffer prefixed with a byte
** containing either 1 or 5 followed by two bytes
** containing the size of the buffer.
** 'd' - the next element in the buffer area is a null-terminated
** string prefixed with a byte containing 2.
** 'p' - the next element in the buffer area is a null-terminated
** string prefixed with a byte containing 3.
** 's' - the next element in the buffer area is a null-terminated
** string prefixed with a byte containing 4.
**
** SIDE EFFECTS
**
** none
**/
int
Msgsmbcheck(
LPBYTE buffer, // Buffer containing SMB
USHORT size, // size of SMB buffer (in bytes)
UCHAR func, // Function code
int parms, // Parameter count
LPSTR fields // Buffer fields dope vector
)
{
PSMB_HEADER smb; // SMB header pointer
LPBYTE limit; // Upper limit
int errRet = 0;
smb = (PSMB_HEADER) buffer; // Overlay header with buffer
//
// Must be long enough for header
//
if(size <= sizeof(SMB_HEADER)) {
return(2);
}
//
// Message type must be 0xFF
//
if(smb->Protocol[0] != 0xff) {
return(3);
}
//
// Server must be "SMB"
//
if( smb->Protocol[1] != 'S' ||
smb->Protocol[2] != 'M' ||
smb->Protocol[3] != 'B') {
return(4);
}
//
// Must have proper function code
//
if(smb->Command != func) {
return(5);
}
limit = &buffer[size]; // Set upper limit of SMB
buffer += sizeof(SMB_HEADER); // Skip over header
//
// Parameter counts must match
//
if(*buffer++ != (BYTE)parms) {
return(6);
}
//
// Skip parameters and buffer size
//
buffer += (((SHORT)parms & 0xFF) + 1)*sizeof(SHORT);
//
// Check for overflow
//
if(buffer > limit) { // 342440: RC2SS:MSGSVC: Off by one error in Msgsmbcheck
// JonN 8/9/99: I'm not convinced that this should be >=, if
// the dope vector is empty then this is correct
return(7);
}
//
// Loop to check buffer fields
//
try {
while(*fields) {
//
// Check for overflow
//
if(buffer >= limit) {
errRet = 14;
break;
}
//
// Switch on dope vector character
//
switch(*fields++) {
case 'b': // Variable length data block
if(*buffer != '\001' && *buffer != '\005') {
errRet = 8;
break;
}
//
// Check for block code
//
// 342440: RC2SS:MSGSVC: Off by one error in Msgsmbcheck
if(buffer+3 > limit) {
errRet = 15;
break;
}
++buffer; // Skip over block code
size = (USHORT)*buffer++ & (USHORT)0xFF; // Get low-byte size
size += ((USHORT)*buffer++ & (USHORT)0xFF)<< 8; // Get high-byte of buffer size
buffer += size; // Increment pointer
break;
case 'd': // Null-terminated dialect string
if(*buffer++ != '\002') { // Check for string code
errRet = 9;
break;
}
// 342440: RC2SS:MSGSVC: Off by one error in Msgsmbcheck
// buffer += strlen(buffer) + 1; // Skip over the string
for ( ; buffer < limit; buffer++) {
if ('\0' == *buffer)
break;
}
buffer++;
break;
case 'p': // Null-terminated path string
if(*buffer++ != '\003') { // Check for string code
errRet = 10;
break;
}
// 342440: RC2SS:MSGSVC: Off by one error in Msgsmbcheck
// buffer += strlen(buffer) + 1; // Skip over the string
for ( ; buffer < limit; buffer++) {
if ('\0' == *buffer)
break;
}
buffer++;
break;
case 's': // Null-terminated string
if(*buffer++ != '\004') { // Check for string code
errRet = 11;
break;
}
// 342440: RC2SS:MSGSVC: Off by one error in Msgsmbcheck
// buffer += strlen(buffer) + 1; // Skip over the string
for ( ; buffer < limit; buffer++) {
if ('\0' == *buffer)
break;
}
buffer++;
break;
}
if ( errRet ) {
break;
}
//
// Check against end of block
//
if(buffer > limit) {
errRet = 12;
break;
}
}
} except( EXCEPTION_EXECUTE_HANDLER ) {
return(13);
}
return(errRet ? errRet : (buffer != limit) ); // Should be false
}