You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1531 lines
49 KiB
1531 lines
49 KiB
/*++
|
|
|
|
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;
|
|
}
|