1532 lines
48 KiB
C
1532 lines
48 KiB
C
/*++
|
||
|
||
Copyright (c) 1987-1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
vrremote.c
|
||
|
||
Abstract:
|
||
|
||
This module contains a routine VrRemoteApi which is a 16-bit only version
|
||
of RxRemoteApi from the net\rpcxlate project. This routine supports remoted
|
||
lanman APIs from a Virtual Dos Machine.
|
||
|
||
This routine does not have to convert 32-16-32, but rather receives 16-bit
|
||
data and sends a 16-bit transaction packet either to a down-level server
|
||
or an NT-level server which must be running XactSrv to respond to this
|
||
request.
|
||
|
||
This routine and the support routines in vrremutl.c were lifted from the
|
||
lanman project
|
||
|
||
Note: since this is 32-bit code which deals with 16-bit data in a few places,
|
||
32-bit data items should be used where possible and only use 16-bit items
|
||
where unavoidable
|
||
|
||
Contents of this file:
|
||
|
||
VrRemoteApi
|
||
VrTransaction
|
||
(VrpGetStructureSize)
|
||
(VrpGetArrayLength)
|
||
(VrpGetFieldSize)
|
||
(VrpConvertReceiveBuffer)
|
||
(VrpConvertVdmPointer)
|
||
(VrpPackSendBuffer)
|
||
|
||
Author:
|
||
|
||
Richard L Firth (rfirth) 24-Oct-1991
|
||
|
||
Environment:
|
||
|
||
Flat 32-bit, user space
|
||
|
||
Revision History:
|
||
|
||
21-Oct-1991 rfirth
|
||
Created
|
||
|
||
--*/
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h> // ASSERT, DbgPrint
|
||
#include <nturtl.h>
|
||
#include <windows.h>
|
||
#include <softpc.h> // x86 virtual machine definitions
|
||
#include <vrdlctab.h>
|
||
#include <vdmredir.h> // common Vr stuff
|
||
#include <lmcons.h>
|
||
#include <lmerr.h>
|
||
#include <lmwksta.h> // NetWkstaGetInfo
|
||
#include <lmapibuf.h> // NetApiBufferFree
|
||
#include <apiworke.h> // REM_MAX_PARMS
|
||
#include <mvdm.h> // FETCHWORD
|
||
#include <vrremote.h> // prototypes
|
||
#include <remtypes.h>
|
||
#include <smbgtpt.h>
|
||
#include <rxp.h> // RxpTransactSmb
|
||
#include <apinums.h> // API_W numbers
|
||
#include <string.h>
|
||
#include <vrdebug.h>
|
||
|
||
//
|
||
// Global data.
|
||
//
|
||
|
||
unsigned short remapi_err_flag;
|
||
|
||
//
|
||
// code
|
||
//
|
||
|
||
|
||
NET_API_STATUS
|
||
VrTransaction(
|
||
IN LPSTR ServerName,
|
||
IN LPBYTE SendParmBuffer,
|
||
IN DWORD SendParmBufLen,
|
||
IN LPBYTE SendDataBuffer,
|
||
IN DWORD SendDataBufLen,
|
||
OUT LPBYTE ReceiveParmBuffer,
|
||
IN DWORD ReceiveParmBufLen,
|
||
IN LPBYTE ReceiveDataBuffer,
|
||
IN OUT LPDWORD ReceiveDataBufLen,
|
||
IN BOOL NullSessionFlag
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sends a transaction request to a server and receives a response
|
||
|
||
Arguments:
|
||
|
||
ServerName - to send request to
|
||
SendParmBuffer - send parameters
|
||
SendParmBufLen - length of send parameters
|
||
SendDataBuffer - send data
|
||
SendDataBufLen - length of send data
|
||
ReceiveParmBuffer - receive parameter buffer
|
||
ReceiveParmBufLen - length of receive parameter buffer
|
||
ReceiveDataBuffer - where to receive data
|
||
ReceiveDataBufLen - length of data buffer
|
||
NullSessionFlag - set if we are to use a null session
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS
|
||
Success - NERR_Success
|
||
Failure -
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS status;
|
||
|
||
status = RxpTransactSmb(ServerName,
|
||
|
||
//
|
||
// BUGBUG - transport name?
|
||
//
|
||
|
||
NULL,
|
||
SendParmBuffer,
|
||
SendParmBufLen,
|
||
SendDataBuffer,
|
||
SendDataBufLen,
|
||
ReceiveParmBuffer,
|
||
ReceiveParmBufLen,
|
||
ReceiveDataBuffer,
|
||
ReceiveDataBufLen,
|
||
NullSessionFlag
|
||
);
|
||
if (status == NERR_Success) {
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
VrRemoteApi(
|
||
IN DWORD ApiNumber,
|
||
IN LPBYTE ServerNamePointer,
|
||
IN LPSTR ParameterDescriptor,
|
||
IN LPSTR DataDescriptor,
|
||
IN LPSTR AuxDescriptor OPTIONAL,
|
||
IN BOOL NullSessionFlag
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine creates and sends a 16-bit transaction SMB containing the
|
||
parameters and data required for a remoted function call. Any received
|
||
data is copied back into the caller's data space as 16-bit data. This
|
||
function is being called on behalf of a VDM process which in turn is
|
||
running as a virtual Intel 286 which means:
|
||
|
||
* little endian
|
||
* pointers are 32-bits <segment|selector>:<offset>
|
||
* stack is 16-bits wide and EXPANDS DOWN
|
||
|
||
This routine is called as a result of the NetIRemoteAPI function being
|
||
called in the VDM. This is an internal function and so the descriptor
|
||
parameters are trusted. However, if the original (16-bit) caller gave
|
||
us a bad buffer address or length then the results will be unpredictable.
|
||
|
||
The original API which called NetIRemoteAPI was a pascal calling convention
|
||
routine so if its parameter list was:
|
||
|
||
FAR PASCAL
|
||
NetRoutine(server_name, buffer_pointer, buffer_length, &bytes_read, &total);
|
||
|
||
the stack would look like this: (note: all pointers are far)
|
||
|
||
+----------------+
|
||
stack pointer => | ip | routine was called far
|
||
+----------------+
|
||
| cs |
|
||
+----------------+
|
||
| &total | Offset
|
||
+----------------+
|
||
| &total | Segment
|
||
+----------------+
|
||
| &bytes_read | Offset
|
||
+----------------+
|
||
| &bytes_read | Segment
|
||
+----------------+
|
||
| buffer_length |
|
||
+----------------+
|
||
| buffer_pointer | Offset
|
||
+----------------+
|
||
| buffer_pointer | Segment
|
||
+----------------+
|
||
| server_name | Offset
|
||
+----------------+
|
||
| server_name | Segment
|
||
+----------------+
|
||
|
||
Assumes:
|
||
|
||
BYTE is an 8-bit quantity
|
||
WORD is a 16-bit quantity
|
||
DWORD is a 32-bit quantity
|
||
LPSTR is a 32-bit flat pointer to an 8-bit quantity
|
||
|
||
Arguments:
|
||
|
||
ApiNumber - Function number of the API required
|
||
|
||
ServerNamePointer - Flat 32-bit pointer to address of 32-bit segmented
|
||
far pointer to ASCIZ server name in Dos image.
|
||
Immediately prior to this is a pascal calling
|
||
convention stack of 16-bit caller parameters (see
|
||
above). The server name identifies the server at
|
||
which the API is to be executed
|
||
|
||
ParameterDescriptor - Flat 32-bit pointer to ASCIZ string which describes
|
||
caller parameters
|
||
|
||
DataDescriptor - Flat 32-bit pointer to ASCIZ string which describes
|
||
data structure in caller buffer (if any) or structure
|
||
of data returned from server
|
||
|
||
AuxDescriptor - Flat 32-bit pointer to ASCIZ string which describes
|
||
auxiliary data structures in send buffer (if any) or
|
||
structure of aux data returned from server
|
||
|
||
NullSessionFlag - TRUE if we are to use a NULL session
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS
|
||
Success - 0
|
||
Failure - NERR_InternalError
|
||
Return this when we have a bad descriptor character or we
|
||
blow an internal limit. Basically if we return this its
|
||
safe to assume the DOS box handed us some garbage (typically
|
||
a descriptor string got trashed etc)
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// redefine our parameter identifiers as old-code identifiers
|
||
//
|
||
|
||
#define api_num ApiNumber
|
||
#define servername_ptr ServerNamePointer
|
||
#define parm_str ParameterDescriptor
|
||
#define data_str DataDescriptor
|
||
#define aux_str AuxDescriptor
|
||
|
||
//
|
||
// define a macro to perform the buffer checking and length and pointer
|
||
// manipulation. Either quits the routine and returns ERROR_INVALID_PARAMETER
|
||
// or updates parm_len and parm_pos to indicate the next available positions
|
||
// and makes this_parm_pos available as the current position to write into
|
||
//
|
||
|
||
#define CHECK_PARAMETERS(len) \
|
||
{ \
|
||
parm_len += len; \
|
||
if (parm_len > sizeof(parm_buf)) { \
|
||
return ERROR_INVALID_PARAMETER; \
|
||
} \
|
||
this_parm_pos = parm_pos; \
|
||
parm_pos += len; \
|
||
}
|
||
|
||
//
|
||
// 32-bit flat pointers and buffers
|
||
//
|
||
|
||
BYTE parm_buf[REM_MAX_PARMS]; // Parameter buffer
|
||
BYTE computerName[CNLEN+1];
|
||
LPBYTE parm_pos; // Pointer into parm_buf
|
||
LPBYTE this_parm_pos; // next place to write in parm_buf
|
||
LPBYTE parm_ptr; // Ponter to stack parms
|
||
LPSTR l_parm; // Used to index parm_str
|
||
LPSTR l_data; // Used to index data_str
|
||
LPSTR l_aux; // Used to index aux_str
|
||
LPBYTE rcv_data_ptr; // Pointer to callers rcv buf
|
||
LPBYTE send_data_ptr; // Ptr to send buffer to use
|
||
LPBYTE wkstaInfo;
|
||
LPBYTE serverName;
|
||
|
||
//
|
||
// lengths - 32-bit variables (even though actual lengths are quite small)
|
||
//
|
||
|
||
DWORD parm_len; // Length of send parameters
|
||
DWORD ret_parm_len; // Length of expected parms
|
||
DWORD rcv_data_length; // Length of callers rcv buf
|
||
DWORD send_data_length; // Length of callers send buf
|
||
DWORD parm_num; // Callers value for parm_num
|
||
DWORD struct_size; // Size of fixed data struct
|
||
DWORD aux_size; // Size of aux data struct
|
||
DWORD num_struct; // Loop count for ptr fixup
|
||
|
||
//
|
||
// 16-bit quantities - only used when converting received 16-bit data in
|
||
// caller's receive buffer
|
||
//
|
||
|
||
WORD ReceiveBufferSelector;
|
||
WORD ReceiveBufferOffset;
|
||
WORD converter; // For pointer fixups
|
||
|
||
//
|
||
// various flags
|
||
//
|
||
|
||
BOOL rcv_dl_flag; // Expect return data flag
|
||
BOOL send_dl_flag; // Send data buffer flag
|
||
BOOL rcv_dp_flag; // rcv buf ptr present flag
|
||
BOOL send_dp_flag; // send buf ptr present flag
|
||
BOOL parm_num_flag; // API has a parm_num
|
||
BOOL alloc_flag;
|
||
|
||
//
|
||
// misc. variables
|
||
//
|
||
|
||
DWORD aux_pos; // aux structure expected
|
||
DWORD no_aux_check; // check flag
|
||
int len; // General purpose length
|
||
API_RET_TYPE status; // Return status from remote
|
||
|
||
UNICODE_STRING uString;
|
||
ANSI_STRING aString;
|
||
LPWSTR uncName;
|
||
NTSTATUS ntstatus;
|
||
|
||
|
||
//
|
||
// Clear the internal error flag
|
||
//
|
||
|
||
remapi_err_flag = 0;
|
||
|
||
//
|
||
// Set found parameter flags to FALSE and ponters to NULL
|
||
//
|
||
|
||
rcv_dl_flag = FALSE;
|
||
send_dl_flag = FALSE;
|
||
rcv_dp_flag = FALSE;
|
||
alloc_flag = FALSE;
|
||
send_dp_flag = FALSE;
|
||
parm_num_flag = FALSE;
|
||
rcv_data_length = 0;
|
||
send_data_length= 0;
|
||
parm_num = 0;
|
||
rcv_data_ptr = NULL;
|
||
send_data_ptr = NULL;
|
||
|
||
//
|
||
// Set up parm_ptr to point to first of the callers parmeters
|
||
//
|
||
|
||
parm_ptr = servername_ptr;
|
||
parm_pos = parm_buf;
|
||
ret_parm_len = 2 * sizeof(WORD); /* Allow for return status & offset */
|
||
|
||
|
||
//
|
||
// parse parameter descriptor/build parameter buffer for transaction
|
||
// and get interesting information from 16-bit parameters
|
||
// When finished, the parameter buffer looks like this:
|
||
//
|
||
// <api_num><parm_desc><data_desc><parms>[<aux_desc>]
|
||
//
|
||
// Remember: DOS only deals with ASCII characters
|
||
//
|
||
|
||
*((LPWORD)parm_pos)++ = (WORD)ApiNumber;
|
||
parm_len = sizeof(WORD);
|
||
|
||
len = strlen(ParameterDescriptor) + 1;
|
||
parm_len += len;
|
||
if (parm_len > sizeof(parm_buf)) {
|
||
return NERR_InternalError;
|
||
}
|
||
l_parm = parm_pos;
|
||
RtlCopyMemory(parm_pos, ParameterDescriptor, len);
|
||
parm_pos += len;
|
||
|
||
len = strlen(DataDescriptor) + 1;
|
||
parm_len += len;
|
||
if (parm_len > sizeof(parm_buf)) {
|
||
return NERR_InternalError;
|
||
}
|
||
l_data = parm_pos;
|
||
RtlCopyMemory(parm_pos, DataDescriptor, len);
|
||
parm_pos += len;
|
||
|
||
//
|
||
// parse the parameter descriptor strings. Remember interesting things such
|
||
// as pointers to buffers, buffer lengths, etc.
|
||
//
|
||
|
||
for (; *l_parm != '\0'; l_parm++) {
|
||
switch(*l_parm) {
|
||
case REM_WORD:
|
||
CHECK_PARAMETERS(sizeof(WORD));
|
||
parm_ptr -= sizeof(WORD);
|
||
SmbMoveUshort((LPWORD)this_parm_pos, (LPWORD)parm_ptr);
|
||
break;
|
||
|
||
case REM_ASCIZ: {
|
||
LPSTR pstring;
|
||
|
||
//
|
||
// the parameter is a pointer to a string. Read the string
|
||
// pointer from the caller's stack then check the string proper.
|
||
// If the pointer is NULL, change the parameter descriptor sent
|
||
// in the SMB to indicate the pointer was NULL at this end
|
||
//
|
||
|
||
parm_ptr -= sizeof(LPSTR);
|
||
pstring = LPSTR_FROM_POINTER(parm_ptr);
|
||
if (pstring == NULL) {
|
||
*(l_parm) = REM_NULL_PTR;
|
||
break;
|
||
}
|
||
len = strlen(pstring) + 1;
|
||
CHECK_PARAMETERS(len);
|
||
RtlCopyMemory(this_parm_pos, pstring, len);
|
||
}
|
||
break;
|
||
|
||
case REM_BYTE_PTR:
|
||
case REM_WORD_PTR:
|
||
case REM_DWORD_PTR: {
|
||
LPBYTE pointer;
|
||
|
||
parm_ptr -= sizeof(LPBYTE);
|
||
pointer = LPBYTE_FROM_POINTER(parm_ptr);
|
||
if (pointer == NULL) {
|
||
*(l_parm) = REM_NULL_PTR; /* Indicate null pointer */
|
||
break;
|
||
}
|
||
len = VrpGetArrayLength(l_parm, &l_parm);
|
||
CHECK_PARAMETERS(len);
|
||
RtlCopyMemory(this_parm_pos, pointer, len);
|
||
}
|
||
break;
|
||
|
||
|
||
case REM_RCV_WORD_PTR:
|
||
case REM_RCV_BYTE_PTR:
|
||
case REM_RCV_DWORD_PTR: {
|
||
LPBYTE pointer;
|
||
|
||
parm_ptr -= sizeof(LPBYTE*);
|
||
pointer = LPBYTE_FROM_POINTER(parm_ptr);
|
||
|
||
//
|
||
// 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 (pointer == NULL) {
|
||
*(l_parm) = REM_NULL_PTR;
|
||
break;
|
||
}
|
||
ret_parm_len += VrpGetArrayLength(l_parm, &l_parm);
|
||
if (ret_parm_len > sizeof(parm_buf)) {
|
||
ASSERT(FALSE);
|
||
return NERR_InternalError;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case REM_DWORD:
|
||
CHECK_PARAMETERS(sizeof(DWORD));
|
||
parm_ptr -= sizeof(DWORD);
|
||
SmbMoveUlong((LPDWORD)this_parm_pos, (LPDWORD)parm_ptr);
|
||
break;
|
||
|
||
case REM_RCV_BUF_LEN:
|
||
CHECK_PARAMETERS(sizeof(WORD));
|
||
parm_ptr -= sizeof(WORD);
|
||
SmbMoveUshort((LPWORD)this_parm_pos, (LPWORD)parm_ptr);
|
||
rcv_data_length = (DWORD)SmbGetUshort((LPWORD)parm_ptr);
|
||
rcv_dl_flag = TRUE;
|
||
#ifdef VR_DIAGNOSE
|
||
DbgPrint("VrRemoteApi: rcv_data_length=%x\n", rcv_data_length);
|
||
#endif
|
||
break;
|
||
|
||
case REM_RCV_BUF_PTR:
|
||
parm_ptr -= sizeof(LPBYTE);
|
||
ReceiveBufferOffset = GET_OFFSET(parm_ptr);
|
||
ReceiveBufferSelector = GET_SELECTOR(parm_ptr);
|
||
rcv_data_ptr = LPBYTE_FROM_POINTER(parm_ptr);
|
||
rcv_dp_flag = TRUE;
|
||
#ifdef VR_DIAGNOSE
|
||
DbgPrint("VrRemoteApi: Off=%x, Sel=%x, data_ptr=%x\n",
|
||
ReceiveBufferOffset, ReceiveBufferSelector, rcv_data_ptr);
|
||
#endif
|
||
break;
|
||
|
||
case REM_SEND_BUF_PTR:
|
||
parm_ptr -= sizeof(LPBYTE);
|
||
send_data_ptr = LPBYTE_FROM_POINTER(parm_ptr);
|
||
send_dp_flag = TRUE;
|
||
break;
|
||
|
||
case REM_SEND_BUF_LEN:
|
||
parm_ptr -= sizeof(WORD);
|
||
send_data_length = (DWORD)SmbGetUshort((LPWORD)parm_ptr);
|
||
send_dl_flag = TRUE;
|
||
break;
|
||
|
||
case REM_ENTRIES_READ:
|
||
ret_parm_len += sizeof(WORD);
|
||
if (ret_parm_len > sizeof(parm_buf)) {
|
||
ASSERT(FALSE);
|
||
return NERR_InternalError;
|
||
}
|
||
parm_ptr -= sizeof(LPBYTE);
|
||
break;
|
||
|
||
case REM_PARMNUM:
|
||
CHECK_PARAMETERS(sizeof(WORD));
|
||
parm_ptr -= sizeof(WORD);
|
||
parm_num = (DWORD)SmbGetUshort((LPWORD)parm_ptr);
|
||
SmbMoveUshort((LPWORD)this_parm_pos, (LPWORD)parm_ptr);
|
||
parm_num_flag = TRUE;
|
||
break;
|
||
|
||
case REM_FILL_BYTES:
|
||
|
||
//
|
||
// This is a rare type but is needed to ensure that the
|
||
// send paramteres are at least as large as the return
|
||
// parameters so that buffer management can be simplified
|
||
// on the server.
|
||
//
|
||
|
||
len = VrpGetArrayLength(l_parm, &l_parm);
|
||
CHECK_PARAMETERS(len);
|
||
break;
|
||
|
||
default: /* Could be a digit from NULL send array */
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// The parameter buffer now contains ;
|
||
// api_num - word
|
||
// parm_str - asciz, (NULL c,i,f,z identifiers replaced with Z.
|
||
// data_str - asciz
|
||
// parameters - as identified by parm_str.
|
||
//
|
||
|
||
//
|
||
// 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 data_str
|
||
// which requires the aux_str to be copied onto the end of the
|
||
// parameter buffer.
|
||
//
|
||
|
||
if (rcv_dp_flag || send_dp_flag) {
|
||
//
|
||
// Find the length of the fixed length portion of the data
|
||
// buffer.
|
||
//
|
||
|
||
struct_size = VrpGetStructureSize(l_data, &aux_pos);
|
||
if (aux_pos != -1) {
|
||
l_aux = aux_str;
|
||
len = strlen(l_aux) + 1; /* Length of aux descriptor */
|
||
CHECK_PARAMETERS(len);
|
||
RtlCopyMemory(this_parm_pos, aux_str, len);
|
||
aux_size = VrpGetStructureSize(l_aux, &no_aux_check);
|
||
if (no_aux_check != -1) { /* Error if N in aux_str */
|
||
ASSERT(FALSE);
|
||
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 (send_dp_flag) {
|
||
//
|
||
// Only process buffer if no parm_num and this is not a block send
|
||
// (no data structure) or an asciz concatenation send
|
||
//
|
||
|
||
if ((parm_num == 0) && (*l_data != REM_DATA_BLOCK)) {
|
||
status = VrpPackSendBuffer(
|
||
&send_data_ptr,
|
||
&send_data_length,
|
||
&alloc_flag,
|
||
data_str,
|
||
aux_str,
|
||
struct_size,
|
||
aux_pos,
|
||
aux_size,
|
||
parm_num_flag,
|
||
FALSE
|
||
);
|
||
if (status != 0) {
|
||
return status;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Check for an internal error prior to issuing the transaction
|
||
//
|
||
|
||
if (remapi_err_flag != 0) {
|
||
if (alloc_flag) {
|
||
LocalFree(send_data_ptr);
|
||
}
|
||
return NERR_InternalError;
|
||
}
|
||
|
||
//
|
||
// get the server name. If it is NULL then we are faking a local API call
|
||
// by making a remote call to XactSrv on this machine. Fill in our computer
|
||
// name
|
||
//
|
||
|
||
serverName = LPSTR_FROM_POINTER(servername_ptr);
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
//// is this actually required any longer?
|
||
|
||
if (serverName == NULL) {
|
||
status = NetWkstaGetInfo(NULL, 100, &wkstaInfo);
|
||
if (status) {
|
||
if (alloc_flag) {
|
||
LocalFree(send_data_ptr);
|
||
}
|
||
return status;
|
||
} else {
|
||
computerName[0] = computerName[1] = '\\';
|
||
|
||
//
|
||
// BUGBUG - Unicode - ASCII conversion here
|
||
//
|
||
|
||
strcpy(computerName+2,
|
||
(LPSTR)((LPWKSTA_INFO_100)wkstaInfo)->wki100_computername);
|
||
NetApiBufferFree(wkstaInfo);
|
||
serverName = computerName;
|
||
#ifdef VR_DIAGNOSE
|
||
DbgPrint("VrRemoteApi: computername is %s\n", serverName);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
//
|
||
// The parameter buffers and data buffers are now set up for
|
||
// sending to the API worker so call transact to send them.
|
||
//
|
||
|
||
RtlInitAnsiString(&aString, serverName);
|
||
ntstatus = RtlAnsiStringToUnicodeString(&uString, &aString, (BOOLEAN)TRUE);
|
||
if (!NT_SUCCESS(ntstatus)) {
|
||
|
||
#if DBG
|
||
IF_DEBUG(NETAPI) {
|
||
DbgPrint("VrRemoteApi: Unexpected situation: RtlAnsiStringToUnicodeString returns %x\n", ntstatus);
|
||
}
|
||
#endif
|
||
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
uncName = uString.Buffer;
|
||
|
||
#if DBG
|
||
IF_DEBUG(NETAPI) {
|
||
DbgPrint("VrpTransactVdm: UncName=%ws\n", uncName);
|
||
}
|
||
#endif
|
||
|
||
status = RxpTransactSmb((LPTSTR)uncName,
|
||
|
||
//
|
||
// BUGBUG - transport name?
|
||
//
|
||
|
||
NULL,
|
||
parm_buf, // Send parm buffer
|
||
parm_len, // Send parm length
|
||
send_data_ptr, // Send data buffer
|
||
send_data_length, // Send data length
|
||
parm_buf, // Rcv prm buffer
|
||
ret_parm_len, // Rcv parm length
|
||
rcv_data_ptr, // Rcv data buffer
|
||
&rcv_data_length, // Rcv data length
|
||
NullSessionFlag
|
||
);
|
||
RtlFreeUnicodeString(&uString);
|
||
|
||
if (status) {
|
||
#ifdef VR_DIAGNOSE
|
||
DbgPrint("Error: VrRemoteApi: RxpTransactSmb returns %d(%x)\n",
|
||
status, status);
|
||
#endif
|
||
switch (status) {
|
||
case NERR_BufTooSmall: /* No data returned from API worker */
|
||
rcv_data_length = 0;
|
||
break;
|
||
|
||
case ERROR_MORE_DATA: /* Just a warning for the caller */
|
||
break;
|
||
|
||
case NERR_TooMuchData: /* Just a warning for the caller */
|
||
break;
|
||
|
||
default:
|
||
rcv_data_length = 0;
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* The API call was successful. Now translate the return buffers
|
||
* into the local API format.
|
||
*
|
||
* First copy any data from the return parameter buffer into the
|
||
* fields pointed to by the original call parmeters.
|
||
* The return parameter buffer contains;
|
||
* status, (unsigned short)
|
||
* converter, (unsigned short)
|
||
* ... - fields described by rcv ptr types in parm_str
|
||
*/
|
||
|
||
parm_pos = parm_buf + sizeof(WORD);
|
||
converter = (WORD)SmbGetUshort((LPWORD)parm_pos);
|
||
parm_pos += sizeof(WORD);
|
||
|
||
//
|
||
// Set up parm_ptr to point to first of the callers parmeters
|
||
//
|
||
|
||
parm_ptr = servername_ptr;
|
||
|
||
//
|
||
// set default value of num_struct to 1, if data, 0 if no data
|
||
//
|
||
|
||
num_struct = (DWORD)((*data_str == '\0') ? 0 : 1);
|
||
|
||
for (; *parm_str != '\0'; parm_str++) {
|
||
switch (*parm_str) {
|
||
case REM_RCV_WORD_PTR:
|
||
case REM_RCV_BYTE_PTR:
|
||
case REM_RCV_DWORD_PTR: {
|
||
LPBYTE ptr;
|
||
|
||
parm_ptr -= sizeof(LPBYTE*);
|
||
ptr = LPBYTE_FROM_POINTER(parm_ptr);
|
||
|
||
//
|
||
// if the rcv buffer given to us by the user is NULL,
|
||
// (one currently can be - it is an MBZ parameter for
|
||
// now in the log read apis...), don't attempt to
|
||
// copy anything. len will be garbage in this
|
||
// case, so don't update parm_pos either. All we
|
||
// use VrpGetArrayLength for is to update parm_str if
|
||
// the parameter was NULL.
|
||
//
|
||
|
||
if (ptr != NULL) {
|
||
len = VrpGetArrayLength(parm_str, &parm_str);
|
||
RtlCopyMemory(ptr, parm_pos, len);
|
||
|
||
//
|
||
// This gross hack is to fix the problem that a
|
||
// down level spooler (Lan Server 1.2)
|
||
// do not perform level checking
|
||
// on the w functions of the api(s):
|
||
// DosPrintQGetInfo
|
||
// and thus can return NERR_Success
|
||
// and bytesavail == 0. This combination
|
||
// is technically illegal, and results in
|
||
// us attempting to unpack a buffer full of
|
||
// garbage. The following code detects this
|
||
// condition and resets the amount of returned
|
||
// data to zero so we do not attempt to unpack
|
||
// the buffer. Since we know the reason for the
|
||
// mistake at the server end is that we passed
|
||
// them a new level, we return ERROR_INVALID_LEVEL
|
||
// in this case.
|
||
// ERICPE, 5/16/90.
|
||
//
|
||
|
||
if ((api_num == API_WPrintQGetInfo)
|
||
&& (status == NERR_Success)
|
||
&& (*parm_str == REM_RCV_WORD_PTR)
|
||
&& (*(LPWORD)ptr == 0)) {
|
||
rcv_data_length = 0;
|
||
status = ERROR_INVALID_LEVEL;
|
||
}
|
||
|
||
//
|
||
// END OF GROSS HACK
|
||
//
|
||
|
||
parm_pos += len;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case REM_ENTRIES_READ: {
|
||
LPWORD wptr;
|
||
|
||
parm_ptr -= sizeof(LPWORD*);
|
||
wptr = (LPWORD)POINTER_FROM_POINTER(parm_ptr);
|
||
num_struct = (DWORD)SmbGetUshort((LPWORD)parm_pos);
|
||
SmbPutUshort((LPWORD)wptr, (WORD)num_struct);
|
||
parm_pos += sizeof(WORD);
|
||
}
|
||
break;
|
||
|
||
case REM_FILL_BYTES:
|
||
//
|
||
// Special case, this was not really an input parameter
|
||
// so parm_ptr does not get changed. However, the parm_str
|
||
// pointer must be advanced past the descriptor field so
|
||
// use get VrpGetArrayLength to do this but ignore the
|
||
// return length.
|
||
//
|
||
|
||
VrpGetArrayLength(parm_str, &parm_str);
|
||
break;
|
||
|
||
default:
|
||
//
|
||
// If the descriptor was not a rcv pointer type then step
|
||
// over the parmeter pointer.
|
||
//
|
||
|
||
parm_ptr -= VrpGetFieldSize(parm_str, &parm_str);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Now convert all pointer fields in the receive buffer to local
|
||
// pointers.
|
||
//
|
||
|
||
if (rcv_dp_flag && (rcv_data_length != 0)) {
|
||
VrpConvertReceiveBuffer(
|
||
rcv_data_ptr, // lp
|
||
ReceiveBufferSelector, // word
|
||
ReceiveBufferOffset, // word
|
||
converter, // word
|
||
num_struct, // dword
|
||
data_str, // lp
|
||
aux_str // lp
|
||
);
|
||
}
|
||
|
||
if (alloc_flag) {
|
||
LocalFree(send_data_ptr);
|
||
}
|
||
|
||
if (remapi_err_flag != 0) {
|
||
return NERR_InternalError;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
DWORD
|
||
VrpGetStructureSize(
|
||
IN LPSTR Descriptor,
|
||
IN LPDWORD AuxOffset
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Calculates the length of the fixed portion of a structure, based on the
|
||
descriptor for that structure
|
||
|
||
Arguments:
|
||
|
||
Descriptor - pointer to ASCIZ data descriptor string
|
||
AuxOffset - pointer to returned dword which is relative position in the
|
||
data descriptor where a REM_AUX_NUM descriptor was found
|
||
This will be set to -1 if no aux descriptor found
|
||
|
||
Return Value:
|
||
|
||
Length in bytes of structure described by Descriptor
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD length;
|
||
char c;
|
||
|
||
*AuxOffset = (DWORD)(-1);
|
||
for (length = 0; (c = *Descriptor) != '\0'; Descriptor++) {
|
||
if (c == REM_AUX_NUM) {
|
||
*AuxOffset = length;
|
||
length += sizeof(WORD);
|
||
} else {
|
||
length += VrpGetFieldSize(Descriptor, &Descriptor);
|
||
}
|
||
}
|
||
return length;
|
||
}
|
||
|
||
|
||
DWORD
|
||
VrpGetArrayLength(
|
||
IN LPSTR Descriptor,
|
||
IN LPSTR* pDescriptor
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Calculates the length of an array described by an element of a
|
||
descriptor string and update the descriptor string pointer to point
|
||
to the last char in the element of the descriptor string.
|
||
|
||
Arguments:
|
||
|
||
Descriptor - pointer to ASCIZ descriptor string
|
||
pDescriptor - pointer to address of Descriptor
|
||
|
||
Return Value:
|
||
|
||
Length in bytes of array described by Descriptor
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD num_elements;
|
||
DWORD element_length;
|
||
|
||
//
|
||
// First set length of an element in the array
|
||
//
|
||
|
||
switch (*Descriptor) {
|
||
case REM_WORD:
|
||
case REM_WORD_PTR:
|
||
case REM_RCV_WORD_PTR:
|
||
element_length = sizeof(WORD);
|
||
break;
|
||
|
||
case REM_DWORD:
|
||
case REM_DWORD_PTR:
|
||
case REM_RCV_DWORD_PTR:
|
||
element_length = sizeof(DWORD);
|
||
break;
|
||
|
||
case REM_BYTE:
|
||
case REM_BYTE_PTR:
|
||
case REM_RCV_BYTE_PTR:
|
||
case REM_FILL_BYTES:
|
||
element_length = sizeof(BYTE);
|
||
break;
|
||
|
||
//
|
||
// Warning: following fixes a bug in which "b21" type
|
||
// combinations in parmeter string will be
|
||
// handled correctly when pointer to such "bit map"
|
||
// in the struct is NULL. These two dumbos could
|
||
// interfere so we force a success return.
|
||
//
|
||
|
||
case REM_ASCIZ:
|
||
case REM_SEND_LENBUF:
|
||
case REM_NULL_PTR:
|
||
return 0;
|
||
|
||
default:
|
||
remapi_err_flag = NERR_InternalError;
|
||
ASSERT(FALSE);
|
||
return 0;
|
||
}
|
||
|
||
//
|
||
// Now get numeber of elements in the array
|
||
//
|
||
|
||
for (num_elements = 0, Descriptor++;
|
||
(*Descriptor <= '9') && (*Descriptor >= '0');
|
||
Descriptor++, (*pDescriptor)++) {
|
||
num_elements = (WORD)((10 * num_elements) + ((WORD)*Descriptor - (WORD)'0'));
|
||
}
|
||
|
||
return (num_elements == 0) ? element_length : element_length * num_elements;
|
||
}
|
||
|
||
|
||
DWORD
|
||
VrpGetFieldSize(
|
||
IN LPSTR Descriptor,
|
||
IN LPSTR* pDescriptor
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Calculates the length of an field described by an element of a
|
||
descriptor string and update the descriptor string pointer to point
|
||
to the last char in the element of the descriptor string.
|
||
|
||
Arguments:
|
||
|
||
Descriptor - pointer to the descriptor string
|
||
pDescriptor - pointer to the address of the descriptor. On exit
|
||
this points to the last character in the descriptor
|
||
just parsed
|
||
|
||
Return Value:
|
||
|
||
Length in bytes of the field parsed
|
||
|
||
--*/
|
||
|
||
{
|
||
char c;
|
||
|
||
c = *Descriptor;
|
||
if (IS_POINTER(c) || (c == REM_NULL_PTR)) { /* All pointers same size */
|
||
while (*(++Descriptor) <= '9' && *Descriptor >= '0') {
|
||
(*pDescriptor)++; /* Move ptr to end of field size */
|
||
}
|
||
return sizeof(LPSTR);
|
||
}
|
||
|
||
//
|
||
// Here if descriptor was not a pointer type so have to find the field
|
||
// length specifically
|
||
//
|
||
|
||
switch (c) {
|
||
case REM_WORD:
|
||
case REM_BYTE:
|
||
case REM_DWORD:
|
||
return VrpGetArrayLength(Descriptor, pDescriptor);
|
||
|
||
case REM_AUX_NUM:
|
||
case REM_PARMNUM:
|
||
case REM_RCV_BUF_LEN:
|
||
case REM_SEND_BUF_LEN:
|
||
return sizeof(WORD);
|
||
|
||
case REM_DATA_BLOCK:
|
||
case REM_IGNORE:
|
||
return 0; /* No structure for this */
|
||
|
||
case REM_DATE_TIME:
|
||
return sizeof(DWORD);
|
||
|
||
default:
|
||
remapi_err_flag = NERR_InternalError;
|
||
#ifdef VR_DIAGNOSE
|
||
DbgPrint("VrpGetFieldSize: offending descriptor is '%c'\n", c);
|
||
#endif
|
||
ASSERT(FALSE);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
VrpConvertReceiveBuffer(
|
||
IN LPBYTE ReceiveBuffer,
|
||
IN WORD BufferSelector,
|
||
IN WORD BufferOffset,
|
||
IN WORD ConverterWord,
|
||
IN DWORD NumberStructs,
|
||
IN LPSTR DataDescriptor,
|
||
IN LPSTR AuxDescriptor
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
All pointers in the receive buffer are returned from the API worker as
|
||
pointers into the buffer position given to the API on the API worker's
|
||
station. In order to convert them into local pointers the segment
|
||
of each pointer must be set to the segment of the rcv buffer and the offset
|
||
must be set to;
|
||
|
||
offset of rcv buffer + offset of pointer - converter word.
|
||
|
||
This routine steps through the receive buffer and calls VrpConvertVdmPointer
|
||
to perform the above pointer conversions.
|
||
|
||
Arguments:
|
||
|
||
ReceiveBuffer - 32-bit flat pointer to 16-bit DOS buffer
|
||
BufferSelector - 16-bit selector of Dos receive buffer
|
||
BufferOffset - 16-bit offset of Dos receive buffer
|
||
ConverterWord - From API worker
|
||
NumberStructs - Entries read parm (or 1 for GetInfo)
|
||
DataDescriptor - String for data format
|
||
AuxDescriptor - string for aux format
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
LPSTR l_data;
|
||
LPSTR l_aux;
|
||
DWORD num_aux;
|
||
DWORD i, j;
|
||
char c;
|
||
|
||
|
||
for (i = 0; i < NumberStructs; i++) {
|
||
//
|
||
// convert all pointers in next primary; if we hit a aux word count
|
||
// remember number of secondary structures
|
||
//
|
||
|
||
for (l_data = DataDescriptor, num_aux = 0; c = *l_data; l_data++) {
|
||
if (c == REM_AUX_NUM) {
|
||
num_aux = (DWORD)*(ULPWORD)ReceiveBuffer;
|
||
}
|
||
if (IS_POINTER(c)) {
|
||
VrpConvertVdmPointer(
|
||
(ULPWORD)ReceiveBuffer,
|
||
BufferSelector,
|
||
BufferOffset,
|
||
ConverterWord
|
||
);
|
||
}
|
||
ReceiveBuffer += VrpGetFieldSize(l_data, &l_data);
|
||
}
|
||
|
||
//
|
||
// convert any pointers in any returned secondary (aux) structures
|
||
//
|
||
|
||
for (j = 0; j < num_aux; j++) {
|
||
for (l_aux = AuxDescriptor; c = *l_aux; l_aux++) {
|
||
if (IS_POINTER(c)) {
|
||
VrpConvertVdmPointer(
|
||
(ULPWORD)ReceiveBuffer,
|
||
BufferSelector,
|
||
BufferOffset,
|
||
ConverterWord
|
||
);
|
||
}
|
||
ReceiveBuffer += VrpGetFieldSize(l_aux, &l_aux);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
VrpConvertVdmPointer(
|
||
IN ULPWORD TargetPointer,
|
||
IN WORD BufferSegment,
|
||
IN WORD BufferOffset,
|
||
IN WORD ConverterWord
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
All pointers in the receive buffer are returned from the API worker as
|
||
pointers into the buffer position given to to the API on the API worker's
|
||
station. In order to convert them into local pointers the segment
|
||
of each pointer must be set to the segment of the rcv buffer and the offset
|
||
must be set to;
|
||
|
||
offset of rcv buffer + offset of pointer - converter word.
|
||
|
||
The pointer is not converted if it is NULL
|
||
|
||
Arguments:
|
||
|
||
TargetPointer - 32-bit flat pointer to segmented Dos pointer to convert
|
||
BufferSegment - 16-bit selector/segment of target buffer in DOS image
|
||
BufferOffset - 16-bit offset within BufferSegment where buffer starts
|
||
ConverterWord - 16-bit offset converter word from API worker on server
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
WORD offset;
|
||
|
||
if (*((UCHAR * UNALIGNED *)TargetPointer) != NULL) {
|
||
SET_SELECTOR(TargetPointer, BufferSegment);
|
||
offset = GET_OFFSET(TargetPointer) - ConverterWord;
|
||
SET_OFFSET(TargetPointer, BufferOffset + offset);
|
||
}
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
VrpPackSendBuffer(
|
||
IN OUT LPBYTE* SendBufferPtr,
|
||
IN OUT LPDWORD SendBufLenPtr,
|
||
OUT LPBOOL SendBufferAllocated,
|
||
IN OUT LPSTR DataDescriptor,
|
||
IN LPSTR AuxDescriptor,
|
||
IN DWORD StructureSize,
|
||
IN DWORD AuxOffset,
|
||
IN DWORD AuxSize,
|
||
IN BOOL SetInfoFlag,
|
||
IN BOOL OkToModifyDescriptor
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
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 ( or errored if the call is not
|
||
a SetInfo type) as it is illegal to use the buffer for the send data,
|
||
it is our transport buffer
|
||
|
||
Note that if the caller's (VDM) buffer is large enough, the variable data
|
||
will be copied there. Eg. if the caller is doing a NetUseAdd which has a
|
||
26 byte fixed structure (use_info_1) and they placed that structure in a
|
||
1K buffer, the remote name will be copied into their own buffer at offset 26.
|
||
|
||
The data pointed to is in 16-bit little-endian format; any pointers are
|
||
segmented 16:16 pointers combined in the (thankfully) imitable intel way
|
||
to result in a 20-bit linear (virtual) address
|
||
|
||
If this function fails, the caller's buffer pointer and length will not
|
||
have altered. If it succeeds however, *SendBufferPtr and *SendBufLenPtr
|
||
may be different to the values passed, depending on whether
|
||
*SendBufferAllocated is TRUE
|
||
|
||
Arguments:
|
||
|
||
SendBufferPtr - pointer to pointer to caller's 16-bit send buffer.
|
||
We may be able to satisfy the send from this buffer
|
||
if the data is simple (ie no structures to send). If
|
||
we have to send structured data then we may have to
|
||
allocate a new buffer in this routine because we need
|
||
to move all of the caller's data into one buffer and
|
||
(s)he may not have allocated enough space to hold
|
||
everything. Additionally, we cannot assume that we
|
||
can write the caller's data into their own buffer!
|
||
|
||
SendBufLenPtr - pointer to the length of the allocated buffer. If
|
||
we allocate a buffer in this routine, this length
|
||
will alter
|
||
|
||
SendBufferAllocated - pointer to a flag which will get set (TRUE) if we do
|
||
actually allocate a buffer in this routine
|
||
|
||
DataDescriptor - pointer to ASCIZ string which describes the primary
|
||
data structure in the buffer. This may be updated if
|
||
NULL pointers are found where a REM_ASCIZ descriptor
|
||
designates a string pointer
|
||
|
||
AuxDescriptor - pointer to ASCIZ string which describes the secondary
|
||
data structure in the buffer
|
||
|
||
StructureSize - the size (in bytes) of the fixed portion of the
|
||
primary data structure
|
||
|
||
AuxOffset - offset to the REM_AUX_NUM descriptor ('N') within the
|
||
data descriptor, or -1 if there isn't one
|
||
|
||
AuxSize - size in bytes of the fixed part of the secondary data
|
||
structure, if any
|
||
|
||
SetInfoFlag - indication of whether the API was a SetInfo call
|
||
|
||
OkToModifyDescriptor- TRUE if we can modify REM_ASCIZ descriptor chars to
|
||
REM_NULL_PTR in DataDescriptor, if a NULL pointer is
|
||
found in the structure. Used by VrNet routines which
|
||
are not calling VrRemoteApi
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS
|
||
Success - NERR_Success
|
||
Failure - ERROR_NOT_ENOUGH_MEMORY
|
||
NERR_BufTooSmall
|
||
--*/
|
||
|
||
{
|
||
|
||
LPBYTE struct_ptr;
|
||
LPBYTE c_send_buf;
|
||
LPBYTE send_ptr;
|
||
DWORD c_send_len;
|
||
DWORD buf_length;
|
||
DWORD to_send_len;
|
||
DWORD num_aux;
|
||
LPSTR data_ptr;
|
||
LPSTR l_dsc;
|
||
LPSTR l_str;
|
||
BOOL alloc_flag = FALSE;
|
||
DWORD num_struct;
|
||
DWORD len;
|
||
UCHAR c;
|
||
DWORD numberOfStructureTypes;
|
||
DWORD i, j;
|
||
LPBYTE ptr;
|
||
|
||
//
|
||
// Make local copies of the original start and length of the caller's
|
||
// buffer as the originals may change if malloc is used but they
|
||
// will still be needed for the F_RANGE check.
|
||
//
|
||
|
||
struct_ptr = c_send_buf = send_ptr = *SendBufferPtr;
|
||
c_send_len = buf_length = *SendBufLenPtr;
|
||
|
||
if ((buf_length < StructureSize) || (AuxOffset == StructureSize)) {
|
||
return NERR_BufTooSmall;
|
||
}
|
||
|
||
//
|
||
// if the offset to the REM_AUX_NUM descriptor is not -1 then we have
|
||
// associated secondary structures with this primary. The actual number
|
||
// is embedded in the primary structure. Retrieve it
|
||
//
|
||
|
||
if (AuxOffset != -1) {
|
||
num_aux = (DWORD)SmbGetUshort((LPWORD)(send_ptr + AuxOffset));
|
||
to_send_len = StructureSize + (num_aux * AuxSize);
|
||
if (buf_length < to_send_len) {
|
||
return NERR_BufTooSmall;
|
||
}
|
||
numberOfStructureTypes = 2;
|
||
} else {
|
||
to_send_len = StructureSize;
|
||
num_aux = AuxSize = 0;
|
||
numberOfStructureTypes = 1;
|
||
}
|
||
|
||
//
|
||
// Set up the data pointer to point past fixed length structures
|
||
//
|
||
|
||
data_ptr = send_ptr + to_send_len;
|
||
|
||
//
|
||
// Any data pointed to by pointers in the data or aux structures
|
||
// must now be copied into the buffer. Start with the primary data
|
||
// structure.
|
||
//
|
||
|
||
l_str = DataDescriptor;
|
||
num_struct = 1; /* Only one primary structure allowed */
|
||
|
||
for (i = 0; i < numberOfStructureTypes;
|
||
l_str = AuxDescriptor, num_struct = num_aux, i++) {
|
||
for (j = 0 , l_dsc = l_str; j < num_struct; j++, l_dsc = l_str) {
|
||
for (; (c = *l_dsc) != '\0'; l_dsc++) {
|
||
if (IS_POINTER(c)) {
|
||
ptr = LPBYTE_FROM_POINTER(struct_ptr);
|
||
if (ptr == NULL) {
|
||
if ((*l_dsc == REM_ASCIZ) && OkToModifyDescriptor) {
|
||
#ifdef VR_DIAGNOSE
|
||
DbgPrint("VrpPackSendBuffer: modifying descriptor to REM_NULL_PTR\n");
|
||
#endif
|
||
*l_dsc = REM_NULL_PTR;
|
||
}
|
||
struct_ptr += sizeof(LPBYTE);
|
||
VrpGetArrayLength(l_dsc, &l_dsc);
|
||
} else {
|
||
|
||
//
|
||
// If the pointer is NULL or points inside the
|
||
// original send buffer ( may have been reallocated)
|
||
// then NULL it as it is not a field being set OR
|
||
// return an error for a non SetInfo type call as
|
||
// it is illegal to have a pointer into the
|
||
// transport buffer.
|
||
//
|
||
|
||
if (RANGE_F(ptr, c_send_buf, c_send_len)) {
|
||
if (SetInfoFlag) {
|
||
SmbPutUlong((LPDWORD)struct_ptr, 0L);
|
||
VrpGetArrayLength(l_dsc, &l_dsc);
|
||
struct_ptr += sizeof(LPSTR);
|
||
} else {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
} else {
|
||
switch (c) {
|
||
case REM_ASCIZ:
|
||
len = strlen(ptr) + 1;
|
||
break;
|
||
|
||
case REM_SEND_LENBUF:
|
||
len = *(LPWORD)ptr;
|
||
break;
|
||
|
||
default:
|
||
len = VrpGetArrayLength(l_dsc, &l_dsc);
|
||
}
|
||
|
||
//
|
||
// There is data to be copied into the send
|
||
// buffer so check that it will fit.
|
||
//
|
||
|
||
to_send_len += len;
|
||
if (to_send_len > buf_length) {
|
||
buf_length = to_send_len + BUF_INC;
|
||
if (!alloc_flag) {
|
||
|
||
//
|
||
// Need new buffer
|
||
//
|
||
|
||
send_ptr = (LPBYTE)LocalAlloc(LMEM_FIXED, buf_length);
|
||
if (send_ptr == NULL) {
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
alloc_flag = TRUE;
|
||
|
||
//
|
||
// Got new buffer, so copy old buffer
|
||
//
|
||
|
||
RtlCopyMemory(send_ptr, c_send_buf, to_send_len - len);
|
||
struct_ptr = send_ptr + (struct_ptr - c_send_buf);
|
||
data_ptr = send_ptr + (data_ptr - c_send_buf);
|
||
} else {
|
||
LPBYTE newPtr;
|
||
|
||
newPtr = (LPBYTE)LocalReAlloc(send_ptr, buf_length, LMEM_MOVEABLE);
|
||
if (newPtr == NULL) {
|
||
LocalFree(send_ptr);
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
} else if (newPtr != send_ptr) {
|
||
|
||
//
|
||
// fix up the pointers
|
||
//
|
||
|
||
data_ptr = newPtr + (data_ptr - send_ptr);
|
||
struct_ptr = newPtr + (struct_ptr - send_ptr);
|
||
send_ptr = newPtr;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// There is room for new data in buffer so copy
|
||
// it and and update the struct and data ptrs
|
||
//
|
||
|
||
RtlCopyMemory(data_ptr, ptr, len);
|
||
data_ptr += len;
|
||
struct_ptr += sizeof(LPBYTE);
|
||
}
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// If the descriptor was not a pointer type then step
|
||
// over the corresponding data field.
|
||
//
|
||
|
||
struct_ptr += VrpGetFieldSize(l_dsc, &l_dsc);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
*SendBufferPtr = send_ptr;
|
||
|
||
//
|
||
// Note that this is potentially incorrect: we are actually returning the
|
||
// size of the structure + dynamic data to be sent, which is probably not
|
||
// the same as the size of the buffer we (re)allocated. This is how it is
|
||
// done in Lanman, so we'll do the same thing until it breaks
|
||
//
|
||
|
||
*SendBufLenPtr = to_send_len;
|
||
*SendBufferAllocated = alloc_flag;
|
||
|
||
return NERR_Success;
|
||
}
|