windows-nt/Source/XPSP1/NT/ds/netapi/xactsrv/xssubs.c

2045 lines
52 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991-92 Microsoft Corporation
Module Name:
XsSubs.c
Abstract:
This module contains various subroutines for XACTSRV.
Author:
David Treadwell (davidtr) 07-Jan-1991
Revision History:
05-Oct-1992 JohnRo
RAID 3556: DosPrintQGetInfo(from downlevel) level 3, rc=124. (4&5 too.)
(Fixed XsFillAuxEnumBuffer.)
--*/
#include "XactSrvP.h"
#include <WinBase.h> // GetCurrentProcessId prototype
#include <align.h>
VOID
SmbCapturePtr(
LPBYTE PointerDestination,
LPBYTE PointerSource
);
DWORD
XsBytesForConvertedStructure (
IN LPBYTE InStructure,
IN LPDESC InStructureDesc,
IN LPDESC OutStructureDesc,
IN RAP_CONVERSION_MODE Mode,
IN BOOL MeaninglessInputPointers
)
/*++
Routine Description:
This routine determines the number of bytes that would be required
to hold the input structure when converted to the structure
described by OutStructureDesc.
Arguments:
InStructure - a pointer to the actual input structure.
InStructureDesc - a pointer to an ASCIIZ describing the format of the
input structure.
OutStructureDesc - a pointer to an ASCIIZ describing the format of the
output structure.
Mode - indicates mode of conversion (native to RAP or vice versa).
Return Value:
DWORD - The number of bytes required to hold the converted structure.
--*/
{
NET_API_STATUS status;
DWORD bytesRequired = 0;
//
// Use RapConvertSingleEntry to get the size that the input structure
// will take when converted to the format specified in the output
// structure description. That routine should not actually write
// anything--it should simply appear that there is no room to
// write more data into, just as if an Enum buffer is full.
//
//
// Should handle errors from RapConvertSingleEntry.
// But the way this is used, existing code probably
// won't break if we just ignore them.
//
status = RapConvertSingleEntry(
InStructure,
InStructureDesc,
MeaninglessInputPointers,
NULL,
NULL,
OutStructureDesc,
FALSE,
NULL,
&bytesRequired,
Response,
Mode
);
//
// For native structures, we should make sure the buffer is an even amount,
// to allow an even boundary for strings, as in Unicode.
//
if ( Mode == RapToNative ) {
bytesRequired = ROUND_UP_COUNT( bytesRequired, ALIGN_DWORD );
}
return bytesRequired;
} // XsBytesForConvertedStructure
LPVOID
XsCaptureParameters (
IN LPTRANSACTION Transaction,
OUT LPDESC *AuxDescriptor
)
/*++
Routine Description:
This routine captures all input parameters from the transaction block
and puts them into a consistent structure that API handlers can access.
It allocates memory to hold this structure. This memory should be
freed by XsSetParameters after the API handler has done its work.
Arguments:
Transaction - a pointer to the transaction block describing the
request.
AuxDescriptor - a pointer to a LPDESC which will hold a pointer to
the auxiliary descriptor string if there is one, or NULL if there
is not.
Return Value:
LPVOID - a pointer to a buffer containing the captured parameters.
--*/
{
LPDESC descriptorString;
LPDESC descriptor;
LPBYTE inParams;
DWORD outParamsLength;
LPBYTE outParams;
LPBYTE outParamsPtr;
WORD rcvBufferLength;
//
// The first two bytes of the parameter section are the API number,
// then comes the descriptor string.
//
descriptorString = Transaction->InParameters + 2;
//
// Find the actual parameter data in the input.
//
inParams = XsFindParameters( Transaction );
//
// Find out how much space to allocate to hold the parameters.
//
outParamsLength = RapStructureSize( descriptorString, Response, FALSE );
//
// Allocate space to hold the output parameters.
// In addition when the request fails the current APIs set the buflen field
// In order to account for this additional buffer space is allocated. Since
// this field is not located at the same offset we need to compute the
// additional space reqd. to be the maximum of all the offsets. Currently
// the 16 byte offset seems to suffice. When modifying apiparam.h ensure
// that this is the case.
//
outParams = NetpMemoryAllocate( sizeof(XS_PARAMETER_HEADER)
+ outParamsLength +
sizeof(DWORD) * 4);
if ( outParams == NULL ) {
IF_DEBUG(ERRORS) {
NetpKdPrint(( "XsCaptureParameters: unable to allocate %ld bytes\n",
outParamsLength ));
}
return NULL;
}
//
// Zero out the parameters and set outParamsPtr to the start of the
// actual parameters.
//
RtlZeroMemory( outParams, sizeof(XS_PARAMETER_HEADER) + outParamsLength );
outParamsPtr = outParams + sizeof(XS_PARAMETER_HEADER);
//
// For each character in the descriptor string, fill in the output
// parameters as appropriate.
//
for ( descriptor = descriptorString; *descriptor != '\0'; ) {
switch ( *descriptor++ ) {
case REM_ASCIZ:
//
// The parameter is a pointer to a string. The actual string
// is in the parameter data, so put a pointer to it in the
// output structure.
//
// String parameters just get passed as is. It
// is up to the API handler to convert the actual data.
//
//
// !!! Parameter string descriptors may not have maximum length
// counts.
//
if( isdigit( *descriptor ) ) {
NetpMemoryFree( outParams );
return NULL;
}
SmbCapturePtr( outParamsPtr, inParams );
//
// Update pointers -- move inParams past end of string.
//
inParams += ( strlen( inParams ) + 1 );
outParamsPtr += sizeof(LPSTR);
break;
case REM_BYTE_PTR:
case REM_FILL_BYTES:
//
// The parameter is a pointer to a byte or array of bytes.
//
SmbCapturePtr( outParamsPtr, inParams );
inParams += sizeof(BYTE) * RapDescArrayLength( descriptor );
outParamsPtr += sizeof(LPBYTE);
break;
case REM_DWORD:
//
// The parameter is a dword or array of dwords.
//
// !!! This assumes that an array of words will never be passed
// as a parameter.
if( isdigit( *descriptor ) ) {
NetpMemoryFree( outParams );
return NULL;
}
//
// Copy over the double word and update pointers.
//
SmbPutUlong(
(LPDWORD)outParamsPtr,
SmbGetUlong( (LPDWORD)inParams )
);
inParams += sizeof(DWORD);
outParamsPtr += sizeof(DWORD);
break;
case REM_ENTRIES_READ:
case REM_RCV_WORD_PTR:
//
// Count of entries read (e) or receive word pointer (h).
// This is an output parameter, so just zero it and
// increment the output parameter pointer.
//
SmbPutUshort( (LPWORD)outParamsPtr, 0 );
outParamsPtr += sizeof(WORD);
break;
case REM_RCV_DWORD_PTR:
//
// Count of receive dword pointer (i).
// This is an output parameter, so just zero it and
// increment the output parameter pointer.
//
SmbPutUlong( (LPDWORD)outParamsPtr, 0 );
outParamsPtr += sizeof(DWORD);
break;
case REM_NULL_PTR:
//
// Null pointer. Set output parameter to NULL, and increment
// pointers.
//
SmbCapturePtr( outParamsPtr, NULL );
outParamsPtr += sizeof(LPSTR);
break;
case REM_RCV_BUF_LEN:
//
// The length of the receive buffer (r).
//
rcvBufferLength = SmbGetUshort( (LPWORD)inParams );
//
// If the indicated buffer length is greater than the max
// data count on the transaction, somebody messed up. Set
// the length to MaxDataCount.
//
if ( rcvBufferLength > (WORD)Transaction->MaxDataCount ) {
IF_DEBUG(ERRORS) {
NetpKdPrint(( "XsCaptureParameters: OutBufLen %lx greater than MaxDataCount %lx.\n",
rcvBufferLength, Transaction->MaxDataCount ));
}
rcvBufferLength = (WORD)Transaction->MaxDataCount;
}
//
// Put the max output data length in the output parameters.
//
SmbPutUshort( (LPWORD)outParamsPtr, rcvBufferLength );
//
// Fill in the receive buffer with zeroes for security.
//
RtlZeroMemory( Transaction->OutData, (DWORD)rcvBufferLength );
inParams += sizeof(WORD);
outParamsPtr += sizeof(WORD);
break;
case REM_RCV_BUF_PTR:
//
// A pointer to a receive data buffer. There is nothing in
// the transaction corresponding to this, but set a longword
// in the output parameters to point to the data output
// section of the transaction.
//
SmbCapturePtr(
outParamsPtr,
Transaction->OutData
);
outParamsPtr += sizeof(LPBYTE);
break;
case REM_RCV_BYTE_PTR:
//
// Return bytes, so just increment output parameter pointer.
//
outParamsPtr += sizeof(BYTE) * RapDescArrayLength( descriptor );
break;
case REM_SEND_BUF_LEN:
//
// The size of an input data buffer. Put the size of the
// received data in the output structure.
//
SmbPutUshort(
(LPWORD)outParamsPtr,
(WORD)Transaction->DataCount
);
outParamsPtr += sizeof(WORD);
break;
case REM_SEND_BUF_PTR:
//
// A pointer to a send data buffer. There is nothing in the
// transaction corresponding to this, but set a longword in
// the output parameters to point to the data input section
// of the transaction.
//
SmbCapturePtr( outParamsPtr, Transaction->InData );
outParamsPtr += sizeof(LPBYTE);
break;
case REM_WORD:
case REM_PARMNUM:
//
// The parameter is a word.
//
// !!! This assumes that an array of words will never be passed
// as a parameter.
if( isdigit( *descriptor ) ) {
NetpMemoryFree( outParams );
return NULL;
}
//
// Copy over the word and update pointers.
//
SmbPutUshort(
(LPWORD)outParamsPtr,
SmbGetUshort( (LPWORD)inParams )
);
inParams += sizeof(WORD);
outParamsPtr += sizeof(WORD);
break;
default:
IF_DEBUG(ERRORS) {
NetpKdPrint(( "XsCaptureParameters: unsupported character at %lx: "
"%c\n", descriptor - 1, *( descriptor - 1 ) ));
NetpBreakPoint( );
}
}
}
//
// Examine the data descriptor string to see if an auxiliary descriptor
// string exists. If it does, the string starts right after the end
// of the parameters.
//
*AuxDescriptor = XsAuxiliaryDescriptor( ++descriptor, inParams );
return outParams;
} // XsCaptureParameters
BOOL
XsCheckBufferSize (
IN WORD BufferLength,
IN LPDESC Descriptor,
IN BOOL NativeFormat
)
/*++
Routine Description:
This routine determines if there is enough room in the buffer for the
fixed component of at least one entry of the described structure.
Arguments:
BufferLength - the length of the buffer to test.
Descriptor - the format of the structure in the buffer.
NativeFormat - TRUE iff the buffer is in native (as opposed to RAP) format.
Return Value:
BOOL - True if there is enough room, false if there isn't.
--*/
{
if ( (DWORD)BufferLength
>= RapStructureSize( Descriptor, Response, NativeFormat )) {
return TRUE;
} else {
return FALSE;
}
} // XsCheckBufferSize
BOOL
XsCheckSmbDescriptor(
IN LPDESC SmbDescriptor,
IN LPDESC ActualDescriptor
)
/*++
Routine Description:
This routine checks whether a descriptor passed in the SMB matches
the actual descriptor expected, taking into account that the actual
descriptor may have ignore fields which have no corresponding field in
the SMB descriptor, and that the SMB descriptor may have null pointer
fields instead of normal pointer fields. However, array-type fields
have to be of the same length in both descriptors.
Arguments:
SmbDescriptor - the descriptor to be validated.
ActualDescriptor - the descriptor expected. Does not have to be an
exact match - see the description above.
Return Value:
BOOL - TRUE if the descriptor is valid,
FALSE otherwise.
--*/
{
DESC_CHAR smbField;
DESC_CHAR expField;
DWORD smbFieldSize;
DWORD expFieldSize;
while (( smbField = *SmbDescriptor++ ) != '\0' ) {
smbFieldSize = RapDescArrayLength( SmbDescriptor );
//
// Skip over ignore fields.
//
while ( *ActualDescriptor == REM_IGNORE ) {
ActualDescriptor++;
}
//
// There should be a corresponding field expected.
//
if (( expField = *ActualDescriptor++ ) == '\0' ) {
return FALSE;
}
expFieldSize = RapDescArrayLength( ActualDescriptor );
//
// If both are actual data fields, they must be the same type and of
// same length.
//
if (( !RapIsPointer( expField ) || smbField != REM_NULL_PTR ) &&
( smbField != expField || smbFieldSize != expFieldSize )) {
return FALSE;
}
//
// SMB provides a null pointer field, we are expecting any pointer.
// This is OK, as long as there is no input array length.
//
if ( smbField == REM_NULL_PTR &&
( !RapIsPointer( expField ) || smbFieldSize != 1 )) {
return FALSE;
}
}
return TRUE;
} // XsCheckSmbDescriptor
NET_API_STATUS
XsConvertSetInfoBuffer(
IN LPBYTE InBuffer,
IN WORD BufferLength,
IN WORD ParmNum,
IN BOOL ConvertStrings,
IN BOOL MeaninglessInputPointers,
IN LPDESC InStructureDesc,
IN LPDESC OutStructureDesc,
IN LPDESC InSetInfoDesc,
IN LPDESC OutSetInfoDesc,
OUT LPBYTE * OutBuffer,
OUT LPDWORD OutBufferLength OPTIONAL
)
/*++
Routine Description:
This routine converts data for a SetInfo call based on the parameter
number (ParmNum) value. The ParmNum indicates the field in the whole
structure which has to be changed, and may be 0.
Arguments:
InBuffer - a pointer to the input buffer in 16-bit format.
BufferLength - the length of the input buffer.
ParmNum - the parameter number.
ConvertStrings - a boolean indicating whether string parameter data
should be converted to a pointer form. If TRUE, the return data
buffer will have a pointer to another place in the buffer where
the string will be. If FALSE, the data buffer will have only the
physical string.
InStructureDesc - the exact descriptor of the input buffer.
OutStructureDesc - the descriptor of the 32-bit output data, as found
in RemDef.h.
InSetInfoDesc - the setinfo-specific descriptor of the input structure
format, as found in RemDef.h.
OutSetInfoDesc - the setinfo-specific descriptor of the output structure
format, as found in RemDef.h.
OutBuffer - a pointer to an LPBYTE which will get a pointer to the
resulting output buffer.
OutBufferLength - an optional pointer to a DWORD which will get the
length of the resulting output buffer.
Return Value:
NET_API_STATUS - NERR_Success if conversion was successful; otherwise
the appropriate status to return to the user. The only exception is
ERROR_NOT_SUPPORTED, which indicates that the particular parameter
number is valid, but not on NT.
--*/
{
LPDESC fieldDesc = NULL;
DWORD stringLength;
LPDESC subDesc = NULL;
LPDESC subDesc2 = NULL;
DWORD bufferSize;
LPBYTE stringLocation;
DWORD bytesRequired = 0;
LPDESC OutDescCopy = OutStructureDesc;
NET_API_STATUS status = NERR_Success;
//
// The buffer length should be greater than 0.
//
if ( BufferLength == 0 ) {
return NERR_BufTooSmall;
}
if ( ParmNum != PARMNUM_ALL ) {
//
// Check 16-bit parameter to see if it could be changed in OS/2.
//
fieldDesc = RapParmNumDescriptor( InSetInfoDesc, (DWORD)ParmNum,
Both, FALSE );
if ( fieldDesc == NULL ) {
return NERR_NoRoom;
}
if ( fieldDesc[0] == REM_UNSUPPORTED_FIELD ) {
status = ERROR_INVALID_PARAMETER;
goto cleanup;
} else {
InStructureDesc = RapParmNumDescriptor( InStructureDesc,
(DWORD)ParmNum, Both, FALSE );
}
NetpMemoryFree( fieldDesc );
//
// Check 32-bit parameter to see if it is valid in NT.
//
fieldDesc = RapParmNumDescriptor( OutSetInfoDesc, (DWORD)ParmNum,
Both, TRUE );
if ( fieldDesc == NULL ) {
return NERR_NoRoom;
}
if ( fieldDesc[0] == REM_IGNORE ) {
status = ERROR_NOT_SUPPORTED;
goto cleanup;
} else {
OutStructureDesc = RapParmNumDescriptor( OutStructureDesc,
(DWORD)ParmNum, Both, TRUE );
}
//
// Filter out strings that are too long for LM2.x.
//
if ( InStructureDesc[0] == REM_ASCIZ
|| InStructureDesc[0] == REM_ASCIZ_TRUNCATABLE ) {
subDesc = InStructureDesc + 1;
stringLength = RapDescStringLength( subDesc );
subDesc = NULL;
if ( stringLength && strlen( InBuffer ) >= stringLength ) {
switch( InStructureDesc[0] ) {
case REM_ASCIZ:
status = ERROR_INVALID_PARAMETER;
goto cleanup;
case REM_ASCIZ_TRUNCATABLE:
InBuffer[stringLength - 1] = '\0';
}
}
}
//
// If a descriptor is a string pointer, the data is the actual
// string, rather than a pointer. Find the length of the string,
// and create a descriptor.
//
// Assuming all these arrays are string data, we
// use available macros to generate an array big
// enough to hold the converted string.
if ( InStructureDesc[0] == REM_ASCIZ
|| InStructureDesc[0] == REM_ASCIZ_TRUNCATABLE ) {
if (( subDesc = NetpMemoryAllocate( MAX_DESC_SUBSTRING + 1 ))
== NULL ) {
status = NERR_NoRoom;
goto cleanup;
}
stringLength = strlen( InBuffer ) + 1;
subDesc[0] = REM_BYTE;
_ltoa( stringLength, &subDesc[1], 10 );
InStructureDesc = subDesc;
}
//
// If output descriptor is a string pointer, and we are asked to keep
// strings inline, make the target data an array of bytes. We find out
// the length required by "walking" the input descriptor, and then
// allocate memory to hold a similar descriptor.
//
// Assuming all these arrays are string data, we
// use available macros to generate an array big
// enough to hold the converted string. Because of the way
// RAP works, if the destination string is Unicode, the destination
// array will be exactly twice as long, and RAP will automatically
// do the Unicode conversion.
//
if (( OutStructureDesc[0] == REM_ASCIZ
|| OutStructureDesc[0] == REM_ASCIZ_TRUNCATABLE )
&& !ConvertStrings ) {
OutDescCopy = OutStructureDesc;
subDesc2 = InStructureDesc + 1;
stringLength = RapDescArrayLength( subDesc2 );
if (( subDesc2 = NetpMemoryAllocate( MAX_DESC_SUBSTRING + 1 ))
== NULL ) {
status = NERR_NoRoom;
goto cleanup;
}
subDesc2[0] = REM_BYTE;
_ltoa( STRING_SPACE_REQD( stringLength ), &subDesc2[1], 10 ) ;
OutStructureDesc = subDesc2;
}
}
if ( !XsCheckBufferSize( BufferLength, InStructureDesc, FALSE )) {
status = NERR_BufTooSmall;
goto cleanup;
}
//
// Find out how big a 32-bit data buffer we need.
//
bufferSize = XsBytesForConvertedStructure(
InBuffer,
InStructureDesc,
OutStructureDesc,
RapToNative,
MeaninglessInputPointers
);
//
// Allocate enough memory to hold the converted native buffer.
//
*OutBuffer = NetpMemoryAllocate( bufferSize );
if ( *OutBuffer == NULL ) {
status = NERR_NoRoom;
goto cleanup;
}
//
// Convert 16-bit data into 32-bit data and store it in the native
// buffer.
//
stringLocation = *OutBuffer + bufferSize;
bytesRequired = 0;
status = RapConvertSingleEntry(
InBuffer,
InStructureDesc,
MeaninglessInputPointers,
*OutBuffer,
*OutBuffer,
OutStructureDesc,
FALSE,
&stringLocation,
&bytesRequired,
Response,
RapToNative
);
if ( status != NERR_Success ) {
IF_DEBUG(ERRORS) {
NetpKdPrint(( "XsConvertSetInfoBuffer: RapConvertSingleEntry "
"failed %X\n", status ));
}
status = NERR_InternalError;
goto cleanup;
}
cleanup:
//
// Free buffers.
//
NetpMemoryFree( subDesc );
NetpMemoryFree( subDesc2 );
NetpMemoryFree( fieldDesc );
if ( OutBufferLength != NULL ) {
*OutBufferLength = bytesRequired;
}
return status;
} // XsConvertSetInfoBuffer
NET_API_STATUS
XsDefaultEnumVerifyFunction (
NET_API_STATUS ConvertStatus,
PBYTE ConvertedEntry,
PBYTE BaseAddress
)
/*++
Routine Description:
This is the default routine called by XsFillEnumBuffer to determine
whether each converted entry should be retained or discarded. This
routine directs XsFillEnumBuffer to discard any entry which
RapConvertSingleEntry encountered an error trying to convert.
Parameters:
ConvertStatus - the status which RapConvertSingleEntry encountered
trying to convert this entry.
ConvertedEntry - a pointer to the buffer containing the converted entry.
BaseAddress - A pointer to the base used to calculate offsets.
Return Value:
NET_API_STATUS - NERR_Success if the entry should be retained,
or an error code if the entry should be discarded.
--*/
{
UNREFERENCED_PARAMETER(ConvertedEntry);
UNREFERENCED_PARAMETER(BaseAddress);
return ConvertStatus;
}
VOID
XsFillAuxEnumBuffer (
IN LPBYTE InBuffer,
IN DWORD NumberOfEntries,
IN LPDESC InStructureDesc,
IN LPDESC InAuxStructureDesc,
IN OUT LPBYTE OutBuffer,
IN LPBYTE OutBufferStart,
IN DWORD OutBufferLength,
IN LPDESC OutStructureDesc,
IN LPDESC OutAuxStructureDesc,
IN PXACTSRV_ENUM_VERIFY_FUNCTION VerifyFunction OPTIONAL,
OUT LPDWORD BytesRequired,
OUT LPDWORD EntriesFilled,
OUT LPDWORD InvalidEntries OPTIONAL
)
/*++
Routine Description:
This routine copies all Enum structures which have auxiliary data
from 32-bit format to 16-bit format. As many complete entries as
possible are copied, then possibly some incomplete entries.
All pointer fields are converted to offsets so that this buffer
may be returned directly to the requesting client.
Enum buffers with auxiliary data have one or more auxiliary
structures, with possible variable data, after each entry.
Arguments:
InBuffer - a pointer to the input information in 32-bit format.
NumberOfEntries - the count of fixed structures in the input buffer.
InStructureDesc - description of the input fixed structure.
InAuxStructureDesc - description of the input auxiliary structure.
OutBuffer - a pointer to where to write the 16-bit buffer.
OutBufferStart - a pointer to the actual start of the 16-bit buffer.
Used to calculate offsets for all pointers in structures.
OutBufferLength - length of the output buffer.
OutStructureDesc - description of the output fixed structure.
OutAuxStructureDesc - description of the output fixed structure.
VerifyFunction - a pointer to a function which is be called after
each enum record is converted in order to determine whether
the record should be retained or discarded. The function
is passed the return code from RapConvertSingleEntry and
a pointer to the converted entry. It must return NERR_SUCCESS
if the entry is to be retained, or any error code if the entry
is to be discarded. If no function is supplied, a default function
is used, which discards an entry only if RapConvertSingleEntry
returned an error trying to convert it.
BytesRequired - a pointer to a DWORD to receive the total number of
bytes that would be required to hold the entire output buffer.
EntriesFilled - a pointer to a DWORD to receive the total number of
entries that could be put in the buffer given.
InvalidEntries - an optional pointer to a DWORD to receive the total
number of entries discarded by the verify function. If NULL, this
value will be not be available to the caller.
Return Value:
None.
--*/
{
NET_API_STATUS status;
DWORD currentEntry;
LPBYTE currentInEntryPtr;
LPBYTE currentOutEntryPtr;
LPBYTE outputStringLocation;
LPBYTE oldStringLocation;
DWORD inputStructureSize;
DWORD inputAuxStructureSize;
DWORD outputStructureSize;
DWORD outputAuxStructureSize;
DWORD inputAuxCount;
DWORD currentAux;
DWORD outputAuxOffset;
DWORD newBytesRequired;
DWORD auxBytesRequired;
DWORD remainingSize;
DWORD invalidEntries = 0;
//
// In degenerate case, just call FillEnumBuffer.
//
if ( InAuxStructureDesc == NULL || OutAuxStructureDesc == NULL ) {
XsFillEnumBuffer (
InBuffer,
NumberOfEntries,
InStructureDesc,
OutBuffer,
OutBufferStart,
OutBufferLength,
OutStructureDesc,
VerifyFunction,
BytesRequired,
EntriesFilled,
InvalidEntries
);
return;
}
if ( VerifyFunction == NULL ) {
VerifyFunction = &XsDefaultEnumVerifyFunction;
}
//
// Set up sizes of input and output structures.
//
inputStructureSize = RapStructureSize( InStructureDesc, Response, TRUE );
inputAuxStructureSize
= RapStructureSize( InAuxStructureDesc, Response, TRUE );
outputStructureSize = RapStructureSize( OutStructureDesc, Response, FALSE );
outputAuxStructureSize
= RapStructureSize( OutAuxStructureDesc, Response, FALSE );
outputAuxOffset = RapAuxDataCountOffset( InStructureDesc, Response, TRUE );
outputStringLocation = (LPBYTE)OutBuffer + OutBufferLength;
*BytesRequired = 0;
//
// Check if one fixed entry will fit.
//
if ( inputStructureSize > OutBufferLength ) {
*EntriesFilled = 0;
goto cleanup;
}
//
// Loop through the entries, converting along the way.
//
currentInEntryPtr = InBuffer;
currentOutEntryPtr = OutBuffer;
*EntriesFilled = 0;
for ( currentEntry = 0; currentEntry < NumberOfEntries; currentEntry++ ) {
//
// If there wasn't enough room for the conversion, we can quit now.
//
if ( currentOutEntryPtr + outputStructureSize > outputStringLocation ) {
break;
}
newBytesRequired = *BytesRequired;
oldStringLocation = outputStringLocation;
//
// Get the auxiliary number count.
//
inputAuxCount = RapAuxDataCount(
currentInEntryPtr,
InStructureDesc,
Response,
TRUE
);
NetpAssert( inputAuxCount != NO_AUX_DATA );
//
// Convert the fixed entry.
//
status = RapConvertSingleEntry(
currentInEntryPtr,
InStructureDesc,
FALSE,
OutBufferStart,
currentOutEntryPtr,
OutStructureDesc,
TRUE,
&outputStringLocation,
&newBytesRequired,
Response,
NativeToRap
);
//
// Check if the entry is valid. If it is not, fix up pointers,
// and start with the next entry in the list.
// If there are more than 65536 auxiliary structures (which
// probably never happens anyway), this entry is automatically
// invalid.
//
status = (*VerifyFunction)(
status,
currentOutEntryPtr,
OutBufferStart
);
if ( status != NERR_Success || inputAuxCount > 0xFFFF ) {
invalidEntries++;
currentInEntryPtr += inputStructureSize
+ inputAuxCount * inputAuxStructureSize;
outputStringLocation = oldStringLocation;
continue;
}
//
// Prepare pointers for converting the auxiliary structures.
//
currentInEntryPtr += inputStructureSize;
currentOutEntryPtr += outputStructureSize;
//
// Try to add the auxiliary structures.
//
for ( currentAux = 0; currentAux < inputAuxCount; currentAux++ ) {
remainingSize = (DWORD)(outputStringLocation - currentOutEntryPtr);
auxBytesRequired = 0;
status = RapConvertSingleEntry(
currentInEntryPtr,
InAuxStructureDesc,
FALSE,
OutBufferStart,
currentOutEntryPtr,
OutAuxStructureDesc,
TRUE,
&outputStringLocation,
&auxBytesRequired,
Response,
NativeToRap
);
//
// Did this aux. entry fit? If all the aux. entries do not fit,
// we are going to play it safe and say the main entry did not
// fit.
//
if ( status != NERR_Success || auxBytesRequired > remainingSize ) {
goto cleanup;
}
currentInEntryPtr += inputAuxStructureSize;
currentOutEntryPtr += outputAuxStructureSize;
newBytesRequired += auxBytesRequired;
}
*BytesRequired = newBytesRequired;
*EntriesFilled += 1;
}
cleanup:
if ( InvalidEntries != NULL ) {
*InvalidEntries = invalidEntries;
}
return;
} // XsFillAuxEnumBuffer
VOID
XsFillEnumBuffer (
IN LPBYTE InBuffer,
IN DWORD NumberOfEntries,
IN LPDESC InStructureDesc,
IN OUT LPBYTE OutBuffer,
IN LPBYTE OutBufferStart,
IN DWORD OutBufferLength,
IN LPDESC OutStructureDesc,
IN PXACTSRV_ENUM_VERIFY_FUNCTION VerifyFunction OPTIONAL,
OUT LPDWORD BytesRequired,
OUT LPDWORD EntriesFilled,
OUT LPDWORD InvalidEntries OPTIONAL
)
/*++
Routine Description:
This routine copies all Enum structures from 32-bit format to
16-bit format. As many complete entries as possible are copied,
then possibly some incomplete entries. All pointer fields
are converted to offsets so that this buffer may be returned
directly to the requesting client.
Arguments:
InBuffer - a pointer to the input information in 32-bit format.
NumberOfEntries - the count of fixed structures in the input buffer.
InStructureDesc - description of the input fixed structure.
OutBuffer - a pointer to where to write the 16-bit buffer.
OutBufferStart - a pointer to the actual start of the 16-bit buffer.
Used to calculate offsets for all pointers in structures.
OutBufferLength - length of the output buffer.
OutStructureDesc - description of the output fixed structure.
VerifyFunction - a pointer to a function which is be called after
each enum record is converted in order to determine whether
the record should be retained or discarded. The function
is passed the return code from RapConvertSingleEntry and
a pointer to the converted entry. It must return NERR_SUCCESS
if the entry is to be retained, or any error code if the entry
is to be discarded. If no function is supplied, a default function
is used, which discards an entry only if RapConvertSingleEntry
returned an error trying to convert it.
BytesRequired - a pointer to a DWORD to receive the total number of
bytes that would be required to hold the entire output buffer.
EntriesFilled - a pointer to a DWORD to receive the total number of
entries that could be put in the buffer given.
InvalidEntries - an optional pointer to a DWORD to receive the total
number of entries discarded by the verify function. If NULL, this
value will be not be available to the caller.
Return Value:
None.
--*/
{
NET_API_STATUS status;
DWORD currentEntry;
LPBYTE currentInEntryPtr;
LPBYTE currentOutEntryPtr;
LPBYTE outputStringLocation;
LPBYTE oldStringLocation;
DWORD inputStructureSize;
DWORD outputStructureSize;
DWORD newBytesRequired;
DWORD invalidEntries = 0;
if ( VerifyFunction == NULL ) {
VerifyFunction = &XsDefaultEnumVerifyFunction;
}
//
// Set up sizes of input and output structures.
//
inputStructureSize = RapStructureSize( InStructureDesc, Response, TRUE );
outputStructureSize = RapStructureSize( OutStructureDesc, Response, FALSE );
outputStringLocation = (LPBYTE)OutBuffer + OutBufferLength;
*BytesRequired = 0;
//
// Check if one fixed entry will fit.
//
if ( inputStructureSize > OutBufferLength ) {
*EntriesFilled = 0;
goto cleanup;
}
//
// Loop through the entries, converting along the way.
//
currentInEntryPtr = InBuffer;
currentOutEntryPtr = OutBuffer;
*EntriesFilled = 0;
for ( currentEntry = 0; currentEntry < NumberOfEntries; currentEntry++ ) {
//
// If there wasn't enough room for the conversion, we can quit now.
//
if ( currentOutEntryPtr + outputStructureSize > outputStringLocation ) {
break;
}
newBytesRequired = *BytesRequired;
oldStringLocation = outputStringLocation;
status = RapConvertSingleEntry(
currentInEntryPtr,
InStructureDesc,
FALSE,
OutBufferStart,
currentOutEntryPtr,
OutStructureDesc,
TRUE,
&outputStringLocation,
&newBytesRequired,
Response,
NativeToRap
);
//
// If the conversion was successful, increment the buffer pointers,
// the count of bytes required, and the number of converted entries.
//
status = (*VerifyFunction)(
status,
currentOutEntryPtr,
OutBufferStart
);
if ( status == NERR_Success ) {
currentInEntryPtr += inputStructureSize;
currentOutEntryPtr += outputStructureSize;
*BytesRequired = newBytesRequired;
*EntriesFilled += 1;
} else {
invalidEntries++;
currentInEntryPtr += inputStructureSize;
outputStringLocation = oldStringLocation;
}
}
cleanup:
if ( InvalidEntries != NULL ) {
*InvalidEntries = invalidEntries;
}
return;
} // XsFillEnumBuffer
LPBYTE
XsFindParameters (
IN LPTRANSACTION Transaction
)
/*++
Routine Description:
This routine finds the start of the parameters section in the
transaction block of a remote down-level API request.
Arguments:
Transaction - a pointer to a transaction block containing information
about the API to process.
Return Value:
None.
--*/
{
LPBYTE s;
//
// Skip over the API number and parameters description string.
//
for ( s = Transaction->InParameters + 2; *s != '\0'; s++ );
//
// Skip over the zero terminator and the data description string.
//
for ( s++; *s != '\0'; s++ );
//
// Return a pointer to the location after the zero terminator.
//
return s + 1;
} // XsFindParameters
WORD
XsPackReturnData (
IN LPVOID Buffer,
IN WORD BufferLength,
IN LPDESC Descriptor,
IN DWORD EntriesRead
)
/*++
Routine Description:
This routine, called by get info and enum API handlers, packs the
output data so that no unused data is returned to the client. This
is necessary because buffers are filled with variable-length data
starting at the end, thereby leaving potentially large gaps of
unused space between the end of fixed structures and the beginning
of variable-length data.
Arguments:
Buffer - a pointer to the buffer to pack.
BufferLength - the length of this buffer.
Descriptor - a pointer to a string which describes the fixed structures
in the buffer.
EntriesRead - the count of fixed structures in the buffer.
Return Value:
WORD - the "converter word" which informs the client how much
to adjust pointers in the fixed structures so that they are
meaningful.
--*/
{
DWORD structureSize;
LPBYTE lastFixedStructure;
LPBYTE endOfFixedStructures;
DWORD lastPointerOffset;
DWORD beginningOfVariableData;
//
// If there is no data, return immediately.
//
if ( EntriesRead == 0 ) {
return 0;
}
//
// Find the size of a single fixed-length structure.
//
structureSize = RapStructureSize( Descriptor, Response, FALSE );
//
// Use this and the number of entries to find the location of the
// last fixed structure and where the fixed structures end.
//
endOfFixedStructures = (LPBYTE)Buffer + EntriesRead * structureSize;
lastFixedStructure = endOfFixedStructures - structureSize;
//
// Find the offset into the fixed structure of the last pointer
// to variable data. The value stored at this offset in the last
// structure is the offset to the first variable data.
//
lastPointerOffset = RapLastPointerOffset( Descriptor, Response, FALSE );
//
// If there are no pointers, there is obviously no data to pack.
//
if ( lastPointerOffset == NO_POINTER_IN_STRUCTURE ) {
return 0;
}
beginningOfVariableData =
SmbGetUlong( (LPDWORD)(lastFixedStructure + lastPointerOffset) );
//
// If this offset is NULL, then the data overflowed, hence the buffer
// is nearly full. Don't do any packing.
//
// Also, if the gap is less than MAXIMUM_ALLOWABLE_DATA_GAP then it
// isn't worth doing the packing because of the time involved in
// the data copy.
//
if ( beginningOfVariableData == (DWORD)0 ||
(DWORD_PTR)Buffer + beginningOfVariableData -
(DWORD_PTR)endOfFixedStructures <= MAXIMUM_ALLOWABLE_DATA_GAP ) {
return 0;
}
//
// Move the variable data up to follow the fixed structures.
//
RtlMoveMemory(
endOfFixedStructures,
(LPBYTE)Buffer + beginningOfVariableData,
BufferLength - beginningOfVariableData
);
//
// Return the distance we moved the variable data.
//
return (WORD)( (DWORD_PTR)Buffer + beginningOfVariableData -
(DWORD_PTR)endOfFixedStructures );
} // XsPackReturnData
VOID
XsSetDataCount(
IN OUT LPWORD DataCount,
IN LPDESC Descriptor,
IN WORD Converter,
IN DWORD EntriesRead,
IN WORD ReturnStatus
)
/*++
Routine Description:
This routine calculates the return data count based on a number
of characteristics of the return data. This routine will examine
the buffer size, the number of entries placed in the buffer,
whether the data was packed, and what the return code was to
determine the return data size. The following assumptions are made
about the data: only calls with ReturnCode = NERR_Success or
ERROR_MORE_DATA return any data to the client; and if there is
no pointer in the fixed entries, then there is no variable data.
Handlers which cannot assure these two assumptions must determine
the data count manually.
Arguments:
DataCount - a pointer to a short word indicating the maximum
return data count (usually the BufLen parameter). On return,
this word will hold the actual return data count.
Descriptor - a string describing the structure of the fixed
entries in the buffer.
Converter - The adjustment value for pointers in data. A non-zero
value indicates data in the buffer is packed.
EntriesRead - Number of entries placed in the buffer. Used to
determine data count for buffers with no variable data.
ReturnStatus - Return status of the API call, as it will be returned
to the client (in other words, converted to a WORD).
Return Value:
None.
--*/
{
if (( ReturnStatus != NERR_Success )
&& ( ReturnStatus != ERROR_MORE_DATA)) {
//
// If the return status is not NERR_Success or ERROR_MORE_DATA, then
// the return data count is 0.
SmbPutUshort( DataCount, 0 );
return;
}
if ( RapLastPointerOffset( Descriptor, Response, FALSE )
== NO_POINTER_IN_STRUCTURE ) {
//
// If there is no variable data, the return data count is the size
// of the fixed structures.
SmbPutUshort( DataCount,
(WORD)(RapStructureSize( Descriptor, Response, FALSE )
* EntriesRead ));
return;
}
SmbPutUshort( DataCount, SmbGetUshort( DataCount ) - Converter );
return;
} // XsSetDataCount
VOID
XsSetParameters (
IN LPTRANSACTION Transaction,
IN LPXS_PARAMETER_HEADER Header,
IN LPVOID Parameters
)
/*++
Routine Description:
This routine takes parameters from the structure allocated by
XsCaptureParameters and uses the descriptor string to place them in
the correct format in the transaction block. It also frees the
buffer holding the parameter structure.
Arguments:
Transaction - a pointer to the transaction block describing the
request.
Header - a pointer to the parameter header, which contains information
from the API handler such as the converter word and return status.
Parameters - a pointer to the parameter structure.
Return Value:
None.
--*/
{
LPBYTE inParams = Parameters;
LPBYTE outParams = Transaction->OutParameters;
LPDESC descriptorString;
LPDESC descriptor;
LPBYTE outParamsMax = outParams + Transaction->MaxParameterCount;
//
// The first two bytes of the parameter section are the API number,
// then comes the descriptor string.
//
descriptorString = Transaction->InParameters + 2;
//
// Set up the first part of the output parameters from the parameter
// header.
//
if( outParams + sizeof(WORD) > outParamsMax ) goto insuff_buffer;
SmbPutUshort( (LPWORD)outParams, Header->Status );
outParams += sizeof(WORD);
if( outParams + sizeof(WORD) > outParamsMax ) goto insuff_buffer;
SmbPutUshort( (LPWORD)outParams, Header->Converter );
outParams += sizeof(WORD);
//
// Initially set the size of the return data to 0. If there is a
// receive buffer for this call, the API handler has changed the
// buffer length parameter to the count of data returned, which
// will be transferred to the DataCount variable later.
//
Transaction->DataCount = 0;
//
// Walk through the descriptor string, converting from the total
// parameter set to the smaller set passed back to the client. In
// general, only information the client does not already know is
// passed back as parameters.
//
for ( descriptor = descriptorString; *descriptor != '\0'; ) {
switch ( *descriptor++ ) {
case REM_ASCIZ:
case REM_NULL_PTR:
//
// !!! Parameter string descriptors may not have maximum length
// counts.
//
NetpAssert( !isdigit( *descriptor ));
//
// The parameter is a pointer to a string, which is
// not returned to the client.
//
inParams += sizeof(LPSTR);
break;
case REM_BYTE_PTR:
case REM_FILL_BYTES:
//
// Array of bytes, doesn't get sent back.
//
//
// Skip over any numeric characters in descriptor.
//
RapAsciiToDecimal( &descriptor );
inParams += sizeof(LPBYTE);
break;
case REM_DWORD:
//
// The parameter is a input word not returned to the client.
//
// !!! This assumes that an array of dwords will never be passed
// as a parameter.
NetpAssert( !isdigit( *descriptor ));
inParams += sizeof(DWORD);
break;
case REM_ENTRIES_READ:
case REM_RCV_WORD_PTR:
//
// Count of entries read (e) or receive word pointer (h).
// This is an output parameter, so copy over the word.
//
if( outParams + sizeof(WORD) > outParamsMax ) goto insuff_buffer;
SmbPutUshort(
(LPWORD)outParams,
SmbGetUshort( (LPWORD)inParams )
);
inParams += sizeof(WORD);
outParams += sizeof(WORD);
break;
case REM_RCV_DWORD_PTR:
//
// Count of receive dword pointer (h).
// This is an output parameter, so copy over the word.
//
if( outParams + sizeof(DWORD) > outParamsMax ) goto insuff_buffer;
SmbPutUlong(
(LPDWORD)outParams,
SmbGetUlong( (LPDWORD)inParams )
);
inParams += sizeof(DWORD);
outParams += sizeof(DWORD);
break;
case REM_RCV_BUF_LEN:
//
// The length of the receive buffer (r). The parameter is not
// returned to the client, but it is used to set the return
// data count.
//
Transaction->DataCount = (DWORD)SmbGetUshort( (LPWORD)inParams );
inParams += sizeof(WORD);
break;
case REM_RCV_BUF_PTR:
case REM_SEND_BUF_PTR:
//
// A pointer to a data buffer. This is not returned to the
// client.
//
inParams += sizeof(LPBYTE);
break;
case REM_RCV_BYTE_PTR: {
//
// The parameter indicates return bytes.
//
DWORD arraySize;
arraySize = sizeof(BYTE) * RapDescArrayLength( descriptor );
if( outParams + arraySize > outParamsMax ) goto insuff_buffer;
RtlCopyMemory( outParams, inParams, arraySize );
outParams += arraySize;
inParams += arraySize;
break;
}
case REM_SEND_BUF_LEN:
case REM_WORD:
case REM_PARMNUM:
//
// The parameter is a input word not returned to the client.
//
// !!! This assumes that an array of words will never be passed
// as a parameter.
NetpAssert( !isdigit( *descriptor ));
inParams += sizeof(WORD);
break;
default:
IF_DEBUG(ERRORS) {
NetpKdPrint(( "XsSetParameters: unsupported character at %lx: %c\n",
descriptor - 1, *( descriptor - 1 )));
NetpBreakPoint( );
}
}
}
//
// Indicate the number of response parameter bytes.
//
Transaction->ParameterCount =
(DWORD)((DWORD_PTR)outParams - (DWORD_PTR)(Transaction->OutParameters) );
//
// Free the parameter buffer allocated by XsCaptureParameters.
//
NetpMemoryFree( Header );
return;
insuff_buffer:
Header->Status = NERR_BufTooSmall;
return;
} // XsSetParameters
NET_API_STATUS
XsValidateShareName(
IN LPSTR ShareName
)
/*++
Routine Description:
This routine determines whether the supplied string is a valid share
name of the format \\computer\share, with both computer name and
share name no longer than permitted by LanMan 2.0. It does not
attempt to determine whether the share actually exists.
Arguments:
ShareName - The share name to be validated (an ASCII string)
Return Value:
NET_API_STATUS - NERR_Success if the share name is valid,
ERROR_INVALID_PARAMETER otherwise.
--*/
{
DWORD componentLength;
NET_API_STATUS status = NERR_Success;
if ( ShareName == NULL ) { // NULL is OK
return NERR_Success;
}
componentLength = 0;
while ( *ShareName == '\\' ) {
componentLength++;
ShareName++;
}
if ( componentLength != 2 ) {
status = ERROR_INVALID_PARAMETER;
goto cleanup;
}
componentLength = 0;
while (( *ShareName != '\\' ) && ( *ShareName != '\0' )) {
componentLength++;
ShareName++;
}
if (( *ShareName == '\0' ) ||
( componentLength < 1 ) || ( componentLength > MAX_PATH )) {
status = ERROR_INVALID_PARAMETER;
goto cleanup;
}
componentLength = 0;
while ( *ShareName == '\\' ) {
componentLength++;
ShareName++;
}
if ( componentLength != 1 ) {
status = ERROR_INVALID_PARAMETER;
goto cleanup;
}
componentLength = 0;
while (( *ShareName != '\\' ) && ( *ShareName != '\0' )) {
componentLength++;
ShareName++;
}
if (( *ShareName == '\\' ) ||
( componentLength < 1 ) || ( componentLength > MAX_PATH )) {
status = ERROR_INVALID_PARAMETER;
goto cleanup;
}
cleanup:
return status;
}
VOID
SmbCapturePtr(
LPBYTE PointerDestination,
LPBYTE PointerValue
)
/*++
Routine Description:
This routine captures a pointer from the supplied buffer and places it
into the destination buffer.
Arguments:
PointerDestination - A pointer to the pointer value destination.
PointerSource - A pointer to the pointer value source.
Return Value:
None.
--*/
{
XsSmbPutPointer( PointerDestination, PointerValue );
}