windows-nt/Source/XPSP1/NT/ds/netapi/rpcxlate/rxcommon/convargs.c
2020-09-26 16:20:57 +08:00

1444 lines
52 KiB
C

/*++
Copyright (c) 1987-1993 Microsoft Corporation
Module Name:
ConvArgs.c
Abstract:
This module just contains RxpConvertArgs, which is a "captive" subroutine
of RxRemoteApi.
Author:
John Rogers (JohnRo) and a cast of thousands.
Environment:
Portable to any flat, 32-bit environment. (Uses Win32 typedefs.)
Requires ANSI C extensions: slash-slash comments, long external names.
Revision History:
01-Apr-1991 JohnRo
Created portable LanMan (NT) version from LanMan 2.x.
03-May-1991 JohnRo
Clarify that RcvData items are application's, and are 32-bit format.
Fixed bug where aux data caused null pointer fault.
Fixed total avail bytes count bug.
RcvDataPtrPtr and RcvDataPresent are redundant.
More assertion checking.
Quiet debug output.
Reduced recompile hits from header files.
14-May-1991 JohnRo
Need different kinds of data and aux descriptors.
Use FORMAT_LPVOID instead of FORMAT_POINTER (max portability).
05-Jun-1991 JohnRo
Call RapConvertSingleEntry on send data (for setinfo APIs).
Caller needs SendDataPtr and SendDataSize.
Don't set StructSize too small (also, it's really FixedStructSize16).
Show status when various things fail.
Use PARMNUM_ALL equate.
Changed to use CliffV's naming conventions (size=byte count).
Return better error codes.
13-Jun-1991 JohnRo
Must call RxpPackSendBuffer after all. (This fixes server set info
for level 102.) Need DataDesc16 and AuxDesc16 for that purpose.
Also, RxpConvertSingleEntry needs to set ptrs (not offsets) for
use by RxpPackSendBuffer.
15-Jul-1991 JohnRo
Changed RxpConvertDataStructures to allow ERROR_MORE_DATA, e.g. for
print APIs.
17-Jul-1991 JohnRo
Extracted RxpDebug.h from Rxp.h.
18-Jul-1991 RFirth
SetInfo calls pass in 2 parmnums welded into a single DWORD - parmnum
proper (which gets transmitted to down-level server) and field-index
which RapParmNumDescriptor uses to get the type and size of the field
that ParmNum indicates
15-Aug-1991 JohnRo
PC-LINT found a bug calling RxpAuxDataCount(). Changed tabs to spaces.
19-Aug-1991 rfirth
Added Flags parameter
30-Sep-1991 JohnRo
Handle REM_FILL_BYTES correctly so RxNetServiceInstall() works.
Provide debug output indicating cause of ERROR_INVALID_PARAMETER.
Handle possible UNICODE (LPTSTR) for REM_ASCIZ.
Allow descriptors to be UNICODE someday.
DBG is always defined.
21-Nov-1991 JohnRo
Removed NT dependencies to reduce recompiles.
31-Mar-1992 JohnRo
Prevent too large size requests.
10-Dec-1992 JohnRo
Made changes suggested by PC-LINT 5.0
18-May-1993 JohnRo
DosPrintQGetInfoW underestimates number of bytes needed.
Made more changes suggested by PC-LINT 5.0
27-May-1993 JimKel and JohnRo
RAID 11758: Wrong error code for DosPrint APIs with NULL buffer pointer.
--*/
// These must be included first:
#include <rxp.h> // RpcXlate private header file.
// These may be included in any order:
#include <limits.h> // CHAR_BIT.
#include <lmerr.h> // NERR_ and ERROR_ equates.
#include <netdebug.h> // NetpKdPrint(()), FORMAT_ equates, etc.
#include <netlib.h> // NetpMoveMemory(), etc.
#include <prefix.h> // PREFIX_ equates.
#include <remtypes.h> // REM_BYTE, etc.
#include <rxpdebug.h> // IF_DEBUG().
#include <smbgtpt.h> // SmbPutUshort().
#include <tstring.h> // NetpCopy routines, STRLEN().
//
// replace this with a call to RxpFieldSize, currently in setfield.c
//
DBGSTATIC
DWORD
RxpGetFieldSize(
IN LPBYTE Field,
IN LPDESC FieldDesc
);
DBGSTATIC
LPDESC
RxpGetSetInfoDescriptor(
IN LPDESC Descriptor,
IN DWORD FieldIndex,
IN BOOL Is32BitDesc
);
NET_API_STATUS
RxpConvertArgs(
IN LPDESC ParmDescriptorString,
IN LPDESC DataDesc16 OPTIONAL,
IN LPDESC DataDesc32 OPTIONAL,
IN LPDESC DataDescSmb OPTIONAL,
IN LPDESC AuxDesc16 OPTIONAL,
IN LPDESC AuxDesc32 OPTIONAL,
IN LPDESC AuxDescSmb OPTIONAL,
IN DWORD MaximumInputBlockSize,
IN DWORD MaximumOutputBlockSize,
IN OUT LPDWORD CurrentInputBlockSizePtr,
IN OUT LPDWORD CurrentOutputBlockSizePtr,
IN OUT LPBYTE *CurrentOutputBlockPtrPtr,
IN va_list *FirstArgumentPtr, // rest of API's arguments (after
// server name)
OUT LPDWORD SendDataSizePtr16,
OUT LPBYTE *SendDataPtrPtr16,
OUT LPDWORD RcvDataSizePtr,
OUT LPBYTE *RcvDataPtrPtr,
IN DWORD Flags
)
/*++
Routine Description:
RxpConvertArgs is called to convert a set of arguments to a LanMan API
from "stdargs" format (with 32-bit data) to the Remote Admin Protocol
format (with 16-bit data). This routine deals with an "output block"
(a transact SMB request) and an "input block" (a transact SMB response).
Note that this routine assumes that RxpStartBuildingTransaction has
already been called, as has va_start. This routine also assumes that
the caller will invoke va_end.
This routine further builds the parameter buffer, which was initiated by
RxpStartBuildingTransaction. That routine left the parameter buffer in
the following state:
<api_num><parameter_descriptor_string><data_descriptor_string>
This routine adds the parameters to the end of the parameter buffer as it
scans the parameter list as passed to RxRemoteApi and then to this routine.
If there is auxiliary data associated with the primary data structure
(assuming there is a primary data structure), then the auxiliary data
descriptor is added to the end of the parameter buffer. The parameter
buffer will look either like this:
<api_num><parm_desc><data_desc><parms>
or this:
<api_num><parm_desc><data_desc><parms><aux_desc>
depending on whether an auxiliary count was present in data_desc (again, if
there was one). If data is being sent down-level, then it is converted from
native (32-bit) to down-level (16-bit) format. All primary data structures
and associated data structures are packed into a buffer allocated in this
routine and returned to the caller. Variable data (strings/arrays/etc.) is
packed into the buffer in the reverse order to that in which it is
encountered in the descriptor strings. The routine RxpPackSendBuffer must
be called to sort out this situation - the down-level server expects the
variable data in the same order as that in the descriptor strings.
If the parameter string contains "sT" meaning the stack contains a pointer
to a data buffer which is sent, followed by the length of the 16-bit data
(a word) then the 'T' value is actually ignored. We calculate the amount
of data to send based on the descriptors and the data in the buffer
If the parameter string contains 'P' meaning the stack contains a parameter
number, the size of the actual data for that parameter is calculated from
the type of the corresponding field in the data descriptor
Arguments:
ParmDescriptorString - A pointer to a ASCIIZ string describing the API
call parameters (other than server name). Note that this must be the
descriptor string which is actually IN the block being built, as the
string will be modified before it is sent to the remote system.
DataDesc16, DataDesc32, DataDescSmb - pointers to ASCIIZ strings describing
the structure of the data in the call, i.e. the return data structure
for a Enum or GetInfo call. This string is used for adjusting pointers
to data in the local buffers after transfer across the net. If there
is no structure involved in the call then the data descriptors must be
NULL pointers.
AuxDesc16, AuxDesc32, AuxDescSmb - Will be NULL in most cases unless a
REM_AUX_COUNT descriptor char is present in the data descriptors in
which case the aux descriptors define a secondary data format as the
data descriptors define the primary.
MaximumInputBlockSize - Gives the total number of bytes allocated
for the input block.
MaximumOutputBlockSize - Gives the total number of bytes allocated
for the output block.
CurrentInputBlockSizePtr - Points to a DWORD which indicates the number
of bytes needed for the input block so far. This will be updated on
exit from this routine.
CurrentOutputBlockSizePtr - Points to a DWORD which indicates the number
of bytes used in the output block so far. This will be updated on exit
from this routine.
CurrentOutputBlockPtrPtr - Points to a pointer to the next free byte in
the output block. This pointer will be updated by this routine, to
point to the byte after the last byte placed by this routine into the
output block.
FirstArgumentPtr - The remainder of the parameters for the API call as
given by the application. The server name is not included in these
arguments. These arguments will be processing using the ANSI
<stdarg.h> macros. The caller must have called va_start for this, and
must call va_end for RxpConvertArgs.
SendDataSizePtr16 - Points to a DWORD which will be set to the size in
bytes of the area allocated at SendDataSizePtr16.
SendDataPtrPtr16 - Points to an LPBYTE which will be set to point to
a 16-bit version of the API's send buffer (or NULL if none is given).
The caller must free this area after it has been used.
RcvDataSizePtr - Points to a DWORD which will be set with the size of
the receive buffer, if any. (This buffer is in 32-bit format, and is
specified by the application.)
RcvDataPtrPtr - Points to an LPBYTE which will be set with the pointer to
a receive buffer if one was specified in the API's arguments. (For
instance, this will point to the return area for a get-info call.)
This is set to NULL if no receive buffer was specified. The buffer
is in 32-bit native format.
Flags - bit-mapped flags word. Currently the only flag we are interested in
in this routine is ALLOCATE_RESPONSE. If this is set then the caller
wants RxRemoteApi to allocate the final returned data buffer. We need
to know this because we either pass back in RcvDataPtrPtr the address
of the callers buffer or the address of the address of the callers
buffer (in which case the caller must give RxRemoteApi &buffer, not
just buffer. Confused? You will be after this episode of sope)
Return Value:
NET_API_STATUS.
--*/
{
DWORD ArgumentSize; // Size of an argument (in bytes).
DWORD AuxSize = 0; // Size of aux data struct.
DWORD AuxOffset = 0; // aux structure expected.
va_list CurrentArgumentPtr; // Pointer to stack parms.
DWORD CurrentInputBlockSize; // Length of expected parms.
DWORD CurrentOutputBlockSize; // Length of send parameters.
LPBYTE CurrentOutputBlockPtr; // Ptr moves as we put stuff in.
LPDESC CurrentParmDescPtr; // Used to index ParmDescriptorString.
DWORD ParmNum; // Caller's value for ParmNum.
BOOL ParmNumPresent; // API has a ParmNum.
BOOL SendDataPresent; // Send buf ptr present flag.
LPBYTE SendDataPtrNative;
DWORD SendDataSizeNative;
NET_API_STATUS Status;
DESC_CHAR parm_desc_16[MAX_DESC_SUBSTRING+1]; // 16-bit parameter descriptor for setinfo
DESC_CHAR parm_desc_32[MAX_DESC_SUBSTRING+1]; // 32-bit " " " "
//
// create aliases for *SendDataPtrPtr16 and *SendDataSizePtr16 to remove a
// level of indirection every time we use these values
//
LPBYTE pSendData;
DWORD SendSize;
//
// convertUnstructuredDataToString - if TRUE this means that the caller is
// supplying unstructured data which is a UNICODE string. This must be
// converted to ANSI (or OEM)
//
BOOL convertUnstructuredDataToString = FALSE;
IF_DEBUG(CONVARGS) {
NetpKdPrint(("RxpConvertArgs: parm desc='" FORMAT_LPDESC "',\n",
ParmDescriptorString));
if (DataDesc32 != NULL) {
NetpKdPrint((" Data desc 32='" FORMAT_LPDESC "',\n",
DataDesc32));
NetpAssert(DataDesc16 != NULL);
NetpAssert(DataDescSmb != NULL);
if (DataDescSmb != NULL) {
NetpKdPrint((" Data desc (SMB)='" FORMAT_LPDESC "',\n",
DataDescSmb));
}
} else {
NetpAssert(DataDesc16 == NULL);
NetpAssert(DataDescSmb == NULL);
}
if (AuxDesc32 != NULL) {
NetpKdPrint((" Aux desc 32='" FORMAT_LPDESC "',\n",
AuxDesc32));
NetpAssert(AuxDesc16 != NULL);
NetpAssert(AuxDescSmb != NULL);
if (AuxDescSmb != NULL) {
NetpKdPrint((" Aux desc (SMB)='" FORMAT_LPDESC "',\n",
AuxDescSmb));
}
} else {
NetpAssert(AuxDesc16 == NULL);
NetpAssert(AuxDescSmb == NULL);
}
NetpKdPrint((" max inp blk len=" FORMAT_DWORD
", max outp blk len=" FORMAT_DWORD ",\n",
MaximumInputBlockSize, MaximumOutputBlockSize));
NetpKdPrint((" curr inp blk len=" FORMAT_DWORD
", curr outp blk len=" FORMAT_DWORD ".\n",
*CurrentInputBlockSizePtr, *CurrentOutputBlockSizePtr));
NetpAssert( SendDataPtrPtr16 != NULL );
NetpAssert( SendDataSizePtr16 != NULL );
}
//
// Code in this file depends on 16-bit words; the Remote Admin Protocol
// demands it.
//
NetpAssert( ( (sizeof(WORD)) * CHAR_BIT) == 16);
//
// Set found parameter flags to FALSE and pointers to NULL.
//
SendDataPresent = FALSE;
ParmNum = PARMNUM_ALL;
ParmNumPresent = FALSE;
*RcvDataSizePtr = 0;
*RcvDataPtrPtr = NULL;
*SendDataSizePtr16 = 0;
*SendDataPtrPtr16 = NULL;
SendDataSizeNative = 0;
SendDataPtrNative = NULL;
CurrentArgumentPtr = *FirstArgumentPtr;
CurrentInputBlockSize = *CurrentInputBlockSizePtr;
CurrentOutputBlockPtr = *CurrentOutputBlockPtrPtr;
CurrentOutputBlockSize = *CurrentOutputBlockSizePtr;
//
// Now loop for each parameter in the variable arg list. We're going to
// use the COPY of the descriptor here, as we may update it as we go.
//
CurrentParmDescPtr = ParmDescriptorString;
for(; *CurrentParmDescPtr; CurrentParmDescPtr++) {
IF_DEBUG(CONVARGS) {
NetpKdPrint(("RxpConvertArgs: "
"desc at " FORMAT_LPVOID " (" FORMAT_DESC_CHAR ")\n",
(LPVOID) CurrentParmDescPtr, *CurrentParmDescPtr));
}
switch(*CurrentParmDescPtr) {
case REM_WORD: // Word (in 16-bit desc).
{
DWORD Temp; // All "words" in 32-bit APIs are now dwords.
CurrentOutputBlockSize += sizeof(WORD);
if (CurrentOutputBlockSize > MaximumOutputBlockSize) {
return (NERR_NoRoom);
}
Temp = va_arg(CurrentArgumentPtr, DWORD);
if (RapValueWouldBeTruncated(Temp)) {
NetpKdPrint(("RxpConvertArgs: WORD would be trunc'ed.\n"));
return (ERROR_INVALID_PARAMETER); // Would be truncated.
}
//
// Convert endian and length.
//
SmbPutUshort( (LPWORD) CurrentOutputBlockPtr, (WORD) Temp);
CurrentOutputBlockPtr += sizeof(WORD);
break;
}
case REM_ASCIZ: // pointer to send asciz
{
LPTSTR Temp;
Temp = va_arg(CurrentArgumentPtr, LPTSTR);
if (Temp == NULL) {
//
// Update parm desc string: indicate null pointer.
//
*(CurrentParmDescPtr ) = REM_NULL_PTR;
break;
}
#if defined(UNICODE) // RxpConvertArgs()
ArgumentSize = NetpUnicodeToDBCSLen(Temp) + 1;
#else
ArgumentSize = STRLEN(Temp) + 1;
#endif // defined(UNICODE)
CurrentOutputBlockSize += ArgumentSize;
if (CurrentOutputBlockSize > MaximumOutputBlockSize) {
return (NERR_NoRoom);
}
//
// Copy str to output area, converting if necessary.
// (This handles UNICODE to default LAN codepage.)
//
#if defined(UNICODE) // RxpConvertArgs()
NetpCopyWStrToStrDBCS(
(LPSTR) CurrentOutputBlockPtr, // dest
Temp ); // src
#else
NetpCopyTStrToStr(
(LPSTR) CurrentOutputBlockPtr, // dest
Temp); // src
#endif // defined(UNICODE)
CurrentOutputBlockPtr += ArgumentSize;
break;
}
case REM_BYTE_PTR: // pointer to send byte(s)
{
LPVOID Temp;
Temp = va_arg(CurrentArgumentPtr, LPVOID);
if (Temp == NULL) {
//
// Update parm desc string to indicate null pointer.
//
*(CurrentParmDescPtr) = REM_NULL_PTR;
break;
}
ArgumentSize = RapArrayLength(
CurrentParmDescPtr,
&CurrentParmDescPtr,
Request);
CurrentOutputBlockSize += ArgumentSize;
if (CurrentOutputBlockSize > MaximumOutputBlockSize) {
return (NERR_NoRoom);
}
//
// Caller is responsible for all UNICODE-ASCII conversions, we only do ASCII
//
NetpMoveMemory(
CurrentOutputBlockPtr, // dest
Temp, // src
ArgumentSize); // len
CurrentOutputBlockPtr += ArgumentSize;
break;
}
case REM_WORD_PTR: // ptr to send word(s)
case REM_DWORD_PTR: // ptr to send Dword(s)
{
LPVOID Temp;
Temp = va_arg(CurrentArgumentPtr, LPVOID);
if (Temp == NULL) {
//
// Update parm desc string to indicate null pointer.
//
*(CurrentParmDescPtr) = REM_NULL_PTR;
break;
}
ArgumentSize = RapArrayLength(
CurrentParmDescPtr,
&CurrentParmDescPtr,
Request);
CurrentOutputBlockSize += ArgumentSize;
if (CurrentOutputBlockSize > MaximumOutputBlockSize) {
return (NERR_NoRoom);
}
NetpMoveMemory(
CurrentOutputBlockPtr, // dest
Temp, // src
ArgumentSize); // len
CurrentOutputBlockPtr += ArgumentSize;
break;
}
case REM_RCV_WORD_PTR: // pointer to rcv word(s)
case REM_RCV_BYTE_PTR: // pointer to rcv byte(s)
case REM_RCV_DWORD_PTR: // pointer to rcv Dword(s)
{
LPVOID Temp;
Temp = va_arg(CurrentArgumentPtr, LPVOID);
//
// Added this test for a NULL pointer to allow for
// a reserved field (currently MBN) to be a recv
// pointer. - ERICPE 7/19/89
//
if (Temp == NULL) {
// Update parm desc string to indicate null pointer.
*(CurrentParmDescPtr) = REM_NULL_PTR;
break;
}
CurrentInputBlockSize
+= RapArrayLength(
CurrentParmDescPtr,
&CurrentParmDescPtr,
Response);
if ( CurrentInputBlockSize > MaximumInputBlockSize) {
NetpKdPrint(("RxpConvertArgs: len exceeded\n"));
NetpBreakPoint();
return (NERR_InternalError);
}
break;
}
case REM_DWORD: // DWord
{
DWORD Temp;
CurrentOutputBlockSize += sizeof(DWORD);
if (CurrentOutputBlockSize > MaximumOutputBlockSize) {
return (NERR_NoRoom);
}
Temp = va_arg(CurrentArgumentPtr, DWORD);
SmbPutUlong( (LPDWORD) CurrentOutputBlockPtr, Temp);
CurrentOutputBlockPtr += sizeof(DWORD);
break;
}
case REM_RCV_BUF_LEN: // Size of 32-bit receive data buffer
{
DWORD Temp;
Temp = va_arg(CurrentArgumentPtr, DWORD);
IF_DEBUG(CONVARGS) {
NetpKdPrint(("RxpConvertArgs: 32-bit rcv buf len is "
FORMAT_DWORD "\n", Temp));
}
if (RapValueWouldBeTruncated(Temp)) {
NetpKdPrint(("RxpConvertArgs: rcv.buf.len trunc'ed.\n"));
return (ERROR_INVALID_PARAMETER);
}
//
// If the caller of RxRemoteApi requested that we allocate the
// 32-bit receive buffer (typically for an Enum or GetInfo call)
// then this value is still important - it tells the other side
// how large a buffer it should allocate. We could just stick
// in 64K here, but we defer to the caller who might have a
// better idea, and thus make the allocation on the down-level
// machine more efficient. We have the potential problem that if
// we always use 64K then we reduce efficiency at the down-level
// server without being able to easily rectify the situation
//
if( Temp > MAX_TRANSACT_RET_DATA_SIZE )
{
NetpBreakPoint();
return (ERROR_BUFFER_OVERFLOW);
}
*RcvDataSizePtr = Temp;
CurrentOutputBlockSize += sizeof(WORD);
if (CurrentOutputBlockSize > MaximumOutputBlockSize) {
return (NERR_NoRoom);
}
SmbPutUshort( (LPWORD)CurrentOutputBlockPtr, (WORD)Temp);
CurrentOutputBlockPtr += sizeof(WORD);
break;
}
case REM_RCV_BUF_PTR: // pointer to 32-bit receive data buffer
{
LPVOID Temp;
Temp = va_arg(CurrentArgumentPtr, LPBYTE *);
//
// NOTE: This pointer could be NULL. For instance, someone
// could call DosPrintQGetInfo with NULL ptr and 0 bytes in
// buffer, to get the number of bytes needed.
//
if ( Flags & ALLOCATE_RESPONSE ) {
if (Temp == NULL) {
NetpKdPrint(( PREFIX_NETAPI
"RxpConvertArgs: NULL rcv buf ptr.\n" ));
return (ERROR_INVALID_PARAMETER);
}
}
//
// If the caller of RxRemoteApi requested that we allocate the
// 32-bit receive buffer then this value is THE ADDRESS OF THE
// POINTER TO THE BUFFER WHICH WILL BE ALLOCATED LATER.
// RxRemoteApi must make sense of this and do the right thing.
// RxpConvertBlock will make the situation right and allocate a
// buffer into which the 16-bit data will be converted
// (hopefully). This paradigm increases buffer efficiency
// (because after we have received the 16-bit data we know how
// large a buffer to allocate in order to return the 32-bit
// data. Before we receive the data, we don't know how much
// will come back and hence allocate the largest possible
// buffer, which is inefficient)
//
*RcvDataPtrPtr = Temp;
break;
}
case REM_SEND_BUF_PTR: // pointer to send data buffer
SendDataPresent = TRUE;
SendDataPtrNative = va_arg(CurrentArgumentPtr, LPBYTE);
break;
case REM_SEND_BUF_LEN: // Size of send data buffer
SendDataSizeNative = va_arg(CurrentArgumentPtr, DWORD);
if ( SendDataSizeNative > MAX_TRANSACT_SEND_DATA_SIZE )
{
NetpBreakPoint();
return (ERROR_BUFFER_OVERFLOW);
}
break;
case REM_ENTRIES_READ: // Entries read identifier
CurrentInputBlockSize += sizeof(WORD);
if (CurrentInputBlockSize > MaximumInputBlockSize) {
NetpKdPrint(("RxpConvertArgs: entries read, len exceeded\n"));
NetpBreakPoint();
return (NERR_InternalError);
}
(void) va_arg(CurrentArgumentPtr, LPDWORD);
break;
case REM_PARMNUM: // ParmNum identifier
{
DWORD Temp;
DWORD field_index;
LPDESC parm_num_desc;
CurrentOutputBlockSize += sizeof(WORD);
if (CurrentOutputBlockSize > MaximumOutputBlockSize) {
return (NERR_NoRoom);
}
Temp = va_arg(CurrentArgumentPtr, DWORD);
#if 0
// no longer required - parmnum is a pair of words packed into a DWORD making
// the following check meaningless
if (RapValueWouldBeTruncated(Temp)) {
NetpKdPrint(("RxpConvertArgs: parmnum truncated.\n"));
return (ERROR_INVALID_PARAMETER);
}
#endif
ParmNumPresent = TRUE;
//
// ParmNum is the actual value which is sent over the wire and
// uniquely identifies a field. It is a sort of handle
//
ParmNum = PARMNUM_FROM_PARMNUM_PAIR(Temp);
//
// field_index is not sent over the wire but is the ordinal of
// the field that ParmNum refers to, in the structure/descriptor
// This is the value we must use to determine the size of the
// field identified by ParmNum, or else RapParmNumDescriptor
// could have a minor spasm
//
field_index = FIELD_INDEX_FROM_PARMNUM_PAIR(Temp);
SmbPutUshort( (LPWORD)CurrentOutputBlockPtr, (WORD)ParmNum);
CurrentOutputBlockPtr += sizeof(WORD);
//
// if ParmNum is not PARMNUM_ALL get the size of the parameter
// from the data descriptor
//
if (ParmNum != PARMNUM_ALL) {
//
// This call is for a set info. We need to calculate the
// size of the data being passed in the buffer - the caller
// no longer supplies this info
// NOTE: RapParmNumDescriptor wants the FIELD INDEX, not
// the PARMNUM, hence the reason for the convolutions
//
parm_num_desc = RxpGetSetInfoDescriptor(
DataDescSmb, // 16-bit data
field_index, // which field
FALSE // not 32-bit data
);
if (parm_num_desc == NULL) {
return NERR_InternalError;
} else {
NetpAssert(
DESCLEN(parm_num_desc) <= MAX_DESC_SUBSTRING );
strcpy(parm_desc_16, parm_num_desc);
NetpMemoryFree(parm_num_desc);
}
parm_num_desc = RxpGetSetInfoDescriptor(
DataDesc32, // 32-bit data
field_index, // which field
TRUE // 32-bit data
);
if (parm_num_desc == NULL) {
return NERR_InternalError;
} else {
NetpAssert(
DESCLEN(parm_num_desc) <= MAX_DESC_SUBSTRING );
strcpy(parm_desc_32, parm_num_desc);
NetpMemoryFree(parm_num_desc);
}
//
// The following will get the size of a 16-bit parameter in
// SendDataSizeNative. NOTE THAT THIS ASSUMES THERE IS ONLY
// ONE UNSTRUCTURED PARAMETER IN THE BUFFER
//
SendDataSizeNative = RxpGetFieldSize(
SendDataPtrNative,
parm_desc_16
);
//
// HACKHACK - if this is a string, treat it as unstructured
// data by setting DataDescSmb to NULL. Code lower down
// will inspect this and skip the data conversion
//
if (*parm_desc_16 == REM_ASCIZ) {
//
// setting convertUnstructuredDataToString to TRUE will
// cause us to convert an input UNICODE string to ANSI.
// SendDataSizeNative must also be recomputed
//
convertUnstructuredDataToString = TRUE;
DataDescSmb = NULL;
}
}
break;
}
case REM_FILL_BYTES: // Send parm pad field
// This is a rare type but is needed to ensure that the
// send parameters are at least as large as the return
// parameters so that buffer management can be simplified
// on the server.
ArgumentSize = RapArrayLength(
CurrentParmDescPtr,
&CurrentParmDescPtr,
Both); // Lie so space gets alloc'ed.
CurrentOutputBlockSize += ArgumentSize;
if (CurrentOutputBlockSize > MaximumOutputBlockSize) {
return (NERR_NoRoom);
}
// CurrentOutputBlockPtr += ArgumentSize;
break;
default: // Could be a digit from NULL send array
break;
} // switch
} // for
//
// The parameter buffer now contains:
// ApiNumber - word
// ParmDescriptorString - asciiz, (NULL c,i,f,z identifiers replaced with O)
// DataDescSmb - asciiz
// parameters - as identified by ParmDescriptorString.
//
// Now process the data descriptor string.
//
//
// For the receive buffer there is no data to set up for the call, but
// there might have been an REM_AUX_COUNT descriptor in DataDescSmb
// which requires the AuxDescSmb string to be copied onto the end of the
// parameter buffer.
//
//
// if we have data to receive BUT its unstructured then don't check the
// DataDescSmb descriptor
//
// MOD 08/08/91 RLF
// if ((*RcvDataPtrPtr != NULL && DataDescSmb) || SendDataPresent) {
if (DataDescSmb) {
// MOD 08/08/91 RLF
//
// If data to be transfered...
//
//
// Find the length of the fixed length portion of the data
// buffer.
//
// MOD 08/08/91 RLF
// NetpAssert(DataDescSmb != NULL);
// MOD 08/08/91 RLF
AuxOffset = RapAuxDataCountOffset(
DataDescSmb, // descriptor
Both, // transmission mode
FALSE); // not native format
if (AuxOffset != NO_AUX_DATA) {
DWORD AuxDescSize;
DWORD no_aux_check; // check flag.
NetpAssert(AuxDescSmb != NULL);
NetpAssert(sizeof(DESC_CHAR) == 1); // Caller should only give us ASCII, and should handle UNICODE conversion
AuxDescSize = DESCLEN(AuxDescSmb) + 1; // desc str and null
CurrentOutputBlockSize += AuxDescSize; // Add to total len.
if (CurrentOutputBlockSize > MaximumOutputBlockSize) {
return (NERR_NoRoom);
}
IF_DEBUG(CONVARGS) {
NetpKdPrint(( "RxpConvertArgs: copying aux desc...\n" ));
}
NetpMoveMemory(
CurrentOutputBlockPtr, // dest
AuxDescSmb, // src
AuxDescSize); // len
CurrentOutputBlockPtr += AuxDescSize; // Update buffer ptr.
AuxSize = RapStructureSize(
AuxDescSmb,
Both,
FALSE); // not native format
NetpAssert(AuxDescSmb != NULL);
no_aux_check = RapAuxDataCountOffset(
AuxDescSmb, // descriptor
Both, // transmission mode
FALSE); // not native format
if (no_aux_check != NO_AUX_DATA) {
//
// Error if N in AuxDescSmb
//
NetpKdPrint(("RxpConvertArgs: N in aux desc str.\n"));
NetpBreakPoint();
return (NERR_InternalError);
}
}
}
//
// For a send buffer the data pointed to in the fixed structure
// must be copied into the send buffer. Any pointers which already
// point in the send buffer are NULLed as it is illegal to use
// the buffer for the send data, it is our transport buffer.
//
// NOTE - if parmnum was specified the buffer contains only that
// element of the structure so no length checking is needed at this
// side. A parmnum for a pointer type means that the data is at the
// start of the buffer so there is no copying to be done.
//
if (SendDataPresent) { // If a send buffer was specified
//
// if there is no smb data descriptor, but there is data to send, then
// it is unstructured (usually meaning its a string). SendDataPtrNative
// points to the data, and SendDataSizeNative is the amount to send.
// Don't perform any conversions, just copy it to the send data buffer
//
if (DataDescSmb == NULL) {
LPBYTE ptr;
if ((ptr = NetpMemoryAllocate(SendDataSizeNative)) == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// UniCode to ASCII. The caller should have made this
// conversion. We only know about unstructured data
// (ie bytes)
//
IF_DEBUG(CONVARGS) {
NetpKdPrint((
"RxpConvertArgs: copying unstructured (no desc)...\n" ));
}
//
// we may have to convert UNICODE to ANSI
//
if (convertUnstructuredDataToString) {
//
// sleaze: the buffer we just allocated may be twice the size
// of the buffer really required
//
#if defined(UNICODE) // RxpConvertArgs()
NetpCopyWStrToStrDBCS( ptr, (LPTSTR)SendDataPtrNative );
#else
NetpCopyTStrToStr(ptr, SendDataPtrNative);
#endif // defined(UNICODE)
//
// recompute the data size as the length of the narrow-character
// string
//
SendDataSizeNative = strlen( (LPVOID) ptr) + 1;
} else {
NetpMoveMemory(ptr, SendDataPtrNative, SendDataSizeNative);
}
*SendDataPtrPtr16 = ptr;
if( SendDataSizeNative > MAX_TRANSACT_SEND_DATA_SIZE )
{
NetpBreakPoint();
return (ERROR_BUFFER_OVERFLOW);
}
*SendDataSizePtr16 = SendDataSizeNative;
} else if ((ParmNum == PARMNUM_ALL) && (*DataDesc32 != REM_DATA_BLOCK)) {
//
// Only process buffer if no ParmNum and this is not a block send
// (no data structure) or an ASCIZ concatenation send
//
BOOL BogusAllocFlag;
DWORD BytesRequired = 0;
DWORD FixedStructSize16;
DWORD primary_structure_size;
LPBYTE StringLocation;
DWORD TotalStructSize16;
DWORD TotalStructSize32;
IF_DEBUG(CONVARGS) {
NetpKdPrint(( "RxpConvertArgs: PARMNUM_ALL...\n" ));
}
//
// here we calculate the TOTAL data requirement of both the 32-bit
// and 16-bit data. This includes:
// - primary data structures (NOTE: We assume only 1????)
// - variable data for primary structure (strings, arrays, etc)
// - aux data structures
// - variable data for aux structures (strings, arrays, etc)
//
//
// Compute size of 32 bit structure, and other pointers and numbers.
//
primary_structure_size = RapStructureSize(DataDesc32, Both, TRUE);
TotalStructSize32 = RapTotalSize(
SendDataPtrNative, // in structure
DataDesc32, // in desc
DataDesc32, // out desc
FALSE, // no meaningless input ptrs
Both, // transmission mode
NativeToNative); // input and output are native
//
// Compute size of 16 bit structure, and other pointers and numbers.
//
FixedStructSize16 = RapStructureSize(DataDesc16,Both,FALSE);
TotalStructSize16 = RapTotalSize(
SendDataPtrNative, // in structure
DataDesc32, // in desc
DataDesc16, // out desc
FALSE, // no meaningless input ptrs
Both, // transmission mode
NativeToRap); // input is native; output is not.
//
// account for any associated auxiliary structures
//
if (AuxDesc32) {
DWORD aux_size;
DWORD aux_count;
DWORD aux_structure_size;
LPBYTE next_structure;
//
// find out how many auxiliary structures are being sent along
// with the primary
//
aux_count = RapAuxDataCount(SendDataPtrNative,
DataDesc32,
Both,
TRUE // input is native format.
);
//
// aux_structure_size is the size of the fixed portion of the
// auxiliary data
// next_structure is a pointer to the next auxiliary structure
// for which to calculate the total space requirement
//
aux_structure_size = RapStructureSize(AuxDesc32, Request, FALSE);
next_structure = SendDataPtrNative + primary_structure_size;
while (aux_count--) {
//
// get the total size of the aux data - fixed structure
// length (which we already know) and the variable data
// requirement
//
aux_size = RapTotalSize(
next_structure, // where the 32-bit data lives
AuxDesc32, // convert 32-bit
AuxDesc32, // to 32-bit
FALSE, // pointers NOT meaningless
Both, // ?
NativeToNative // 32-bit to 32-bit
);
TotalStructSize32 += aux_size;
//
// do the same for the 16-bit version of the data
//
aux_size = RapTotalSize(
next_structure, // where the 32-bit data lives
AuxDesc32, // convert 32-bit
AuxDesc16, // to 16-bit
FALSE, // pointers NOT meaningless
Both, // ?
NativeToRap // 32-bit to 16-bit
);
TotalStructSize16 += aux_size;
//
// point to next aux structure (probably only 1 anyway?)
//
next_structure += aux_structure_size;
}
}
IF_DEBUG(CONVARGS) {
NetpKdPrint(( "RxpConvertArgs: total size(32)="
FORMAT_DWORD ".\n", TotalStructSize32 ));
}
NetpAssert(TotalStructSize16 >= FixedStructSize16);
IF_DEBUG(CONVARGS) {
NetpKdPrint(( "RxpConvertArgs: total size(16)="
FORMAT_DWORD ".\n", TotalStructSize16 ));
}
if( TotalStructSize16 > MAX_TRANSACT_SEND_DATA_SIZE )
{
NetpBreakPoint();
return (ERROR_BUFFER_OVERFLOW);
}
*SendDataSizePtr16 = SendSize = TotalStructSize16;
*SendDataPtrPtr16 = pSendData = NetpMemoryAllocate( TotalStructSize16 );
if (pSendData == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
StringLocation = (pSendData) + TotalStructSize16;
IF_DEBUG(CONVARGS) {
NetpKdPrint(("RxpConvertArgs: initial StringLocation is "
FORMAT_LPVOID "\n", (LPVOID) StringLocation ));
NetpKdPrint(("RxpConvertArgs: input data "
"(before CSE, partial):\n"));
NetpDbgHexDump( SendDataPtrNative,
NetpDbgReasonable( TotalStructSize16 ) );
NetpKdPrint(("RxpConvertArgs: output data area "
"(before CSE, partial):\n"));
NetpDbgHexDump( pSendData,
NetpDbgReasonable( TotalStructSize16 ) );
}
//
// This routine calls RapConvertSingleEntry to convert the primary
// data structure, but will also convert any auxiliary structures
//
Status = RxpConvertDataStructures(
DataDesc32, // 32-bit data
DataDesc16, // converted from 16-bit
AuxDesc32, // as are the aux structures
AuxDesc16,
SendDataPtrNative, // where the 32-bit lives
pSendData, // and its new 16-bit address
SendSize, // how big the buffer is
1, // only 1 primary structure.
NULL, // don't need number of entries converted.
Both, // do entire structure
NativeToRap // explicit 32->16, implicit TCHAR->codepage
);
//
// We allocated the output buffer large enough, so there's no
// reason that conversion should fail.
//
NetpAssert(Status == NERR_Success);
//
// RxpConvertDataStructures calls RapConvertSingleEntry to pack the
// fixed and variable parts of the data into the buffer. The down-
// level server expects the data in the same order as that in which
// it appears in the descriptor strings. RxpPackSendBuffer exists
// to make this so. Do it
//
Status = RxpPackSendBuffer(
(LPVOID *) SendDataPtrPtr16, // possibly reallocated
SendDataSizePtr16, // possibly realloced
&BogusAllocFlag,
DataDesc16,
AuxDesc16,
FixedStructSize16,
AuxOffset,
AuxSize,
ParmNumPresent
);
if (Status != NERR_Success) {
NetpKdPrint(("RxpConvertArgs: pack send buffer failed, stat="
FORMAT_API_STATUS "\n", Status));
return (Status);
}
IF_DEBUG(CONVARGS) {
NetpKdPrint(("RxpConvertArgs: data "
"(after RxpPackSendBuffer):\n"));
NetpDbgHexDump( pSendData, BytesRequired );
}
//
// MOD 06/25/91 RLF
// Remove this, since reallocation takes place. Does it have any other
// implications?
//
// MOD 08/08/91 RLF
NetpAssert(BogusAllocFlag == FALSE);
// MOD 08/08/91 RLF
//
// MOD 06/25/91 RLF
//
} else if (ParmNum) {
//
// here if there is a parameter to set. Create a buffer for the data
// to be sent in the setinfo call. Copy the caller's data into it.
//
LPBYTE ptr;
LPBYTE enddata;
DWORD bytes_required;
IF_DEBUG(CONVARGS) {
NetpKdPrint(( "RxpConvertArgs: parmnum (not all)...\n" ));
}
if ((ptr = NetpMemoryAllocate(SendDataSizeNative)) == NULL) {
return ERROR_NOT_ENOUGH_MEMORY; // gasp!
}
//
// we now convert the data for the single field from 32-bits to
// 16. Use the descriptors which identify the single field only
//
enddata = ptr + SendDataSizeNative;
bytes_required = 0;
Status = RapConvertSingleEntry(SendDataPtrNative,
parm_desc_32,
FALSE,
ptr,
ptr,
parm_desc_16,
FALSE,
&enddata,
&bytes_required,
Both,
NativeToRap
);
NetpAssert( Status == NERR_Success );
#if DBG
if (!(bytes_required <= SendDataSizeNative)) {
NetpKdPrint(("error: RxpConvertArgs.%d: "
"bytes_required=%d, SendDataSizeNative=%d\n"
"parm_desc_16=%s, parm_desc_32=%s\n",
__LINE__,
bytes_required,
SendDataSizeNative,
parm_desc_16,
parm_desc_32
));
}
NetpAssert(bytes_required <= SendDataSizeNative);
#endif
*SendDataPtrPtr16 = ptr;
//
// SendDataSizeNative is either the size of the buffer in a "sT"
// descriptor pair, or was calculated based on the descriptor type
// and caller's data in a setinfo/parmnum ('P') case
//
if ( SendDataSizeNative > MAX_TRANSACT_SEND_DATA_SIZE )
{
NetpBreakPoint();
return (ERROR_BUFFER_OVERFLOW);
}
*SendDataSizePtr16 = SendDataSizeNative;
} else {
LPBYTE ptr;
//
// send data, PARMNUM_ALL, data desc is REM_DATA_BLOCK. This can
// happen with the NetServiceInstall API (see RxApi/SvcInst.c).
// cbBuffer arg is set by RxNetServiceInstall to be the OUTPUT
// buffer size, despite the LM 2.x app passing the INPUT size.
// (We're just propagating another LanMan kludge here.)
//
// UniCode to ASCII. The caller should have made this
// conversion. We only know about unstructured data
// (ie bytes)
//
NetpAssert( ParmNum == PARMNUM_ALL );
NetpAssert( *DataDesc16 == REM_DATA_BLOCK );
NetpAssert( SendDataSizeNative > 0 );
IF_DEBUG(CONVARGS) {
NetpKdPrint(( "RxpConvertArgs: "
"copying unstructured data with desc...\n" ));
}
//
// Copy unstructured data and tell caller where it is.
//
if ((ptr = NetpMemoryAllocate(SendDataSizeNative)) == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
NetpMoveMemory(
ptr, // dest
SendDataPtrNative, // src
SendDataSizeNative); // size
*SendDataPtrPtr16 = ptr;
if ( SendDataSizeNative > MAX_TRANSACT_SEND_DATA_SIZE )
{
NetpBreakPoint();
return (ERROR_BUFFER_OVERFLOW);
}
*SendDataSizePtr16 = SendDataSizeNative;
}
} // send buffer was specified
//
// The parameter buffers and data buffers are now set up for
// sending to the API worker so tell the caller.
//
*CurrentInputBlockSizePtr = CurrentInputBlockSize;
*CurrentOutputBlockSizePtr = CurrentOutputBlockSize;
*CurrentOutputBlockPtrPtr = CurrentOutputBlockPtr;
return NERR_Success;
} // RxpConvertArgs
DBGSTATIC
DWORD
RxpGetFieldSize(
IN LPBYTE Field,
IN LPDESC FieldDesc
)
{
NetpAssert(Field != NULL);
NetpAssert(FieldDesc != NULL);
if (*FieldDesc == REM_ASCIZ) {
return STRSIZE((LPTSTR)Field);
} else {
LPDESC TempDescPtr = FieldDesc;
return RapGetFieldSize(FieldDesc, &TempDescPtr, Both);
}
} // RxpGetFieldSize
DBGSTATIC
LPDESC
RxpGetSetInfoDescriptor(
IN LPDESC Descriptor,
IN DWORD FieldIndex,
IN BOOL Is32BitDesc
)
/*++
Routine Description:
Allocates a descriptor string which describes a single parameter element
of a structure, for SetInfo calls (where ParmNum != PARMNUM_ALL)
Arguments:
Descriptor - The full descriptor string for the relevant structure
FieldIndex - The ORDINAL number of the field (NOT ParmNum)
Is32BitDesc - Descriptor defines 16-bit data
Return Value:
Pointer to allocated descriptor or NULL if error
--*/
{
LPDESC lpdesc;
lpdesc = RapParmNumDescriptor(Descriptor, FieldIndex, Both, Is32BitDesc);
if (lpdesc == NULL) {
#if DBG
//
// don't expect this to happen - trap it in debug version
//
NetpKdPrint(("error: RxpGetSetInfoDescriptor: RapParmNumDescriptor didn't allocate string\n"));
NetpBreakPoint();
#endif
} else if (*lpdesc == REM_UNSUPPORTED_FIELD) {
#if DBG
//
// don't expect this to happen - trap it in debug version
//
NetpKdPrint(("error: RxpGetSetInfoDescriptor: parameter defines unsupported field\n"));
NetpBreakPoint();
#endif
NetpMemoryFree(lpdesc);
lpdesc = NULL;
}
return lpdesc;
}