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

535 lines
19 KiB
C

/*++
Copyright (c) 1987-1993 Microsoft Corporation
Module Name:
Remote.c
Abstract:
Provides a support routine, RxRemoteAPI, for transporting
an API request to a remote API worker and translating its response.
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
Really pass COPY of parm desc to convert args, like it expects.
Also pass it UNC server name (\\stuff) for ease of use.
Add check for valid computer name.
Use Unicode transitional types.
Changed to use three data descs: 16-bit, 32-bit and SMB versions.
Fixed receive buffer length problem.
RcvDataPresent flag is not needed.
Use RxpFatalErrorCode() rather than checking for specific errors.
Quiet debug output by default.
Reduced recompile hits from header files.
Don't use NET_API_FUNCTION for non-APIs.
07-May-1991 JohnRo
Made changes to reflect CliffV's code review.
Add validation of parm desc.
09-May-1991 JohnRo
Made LINT-suggested changes.
14-May-1991 JohnRo
Pass 3 aux descriptors to RxRemoteApi.
29-May-1991 JohnRo
Handle SendDataPtr16 and SendDataSize16 correctly for setinfo.
Print status if ConvertArgs failed.
13-Jun-1991 JohnRo
RxpConvertArgs needs DataDesc16 and AuxDesc16 to fix server set info
for level 102.
16-Jul-1991 JohnRo
Allow receive data buffer to be zero bytes long with nonnull pointer.
17-Jul-1991 JohnRo
Extracted RxpDebug.h from Rxp.h.
16-Aug-1991 rfirth
Changed interface (NoPermissionRequired => Flags)
25-Sep-1991 JohnRo
Quiet normal debug messages.
21-Nov-1991 JohnRo
Removed NT dependencies to reduce recompiles.
27-Nov-1991 JohnRo
Do some checking of ApiNumber.
31-Mar-1992 JohnRo
Prevent too large size requests.
06-May-1993 JohnRo
RAID 8849: Export RxRemoteApi for DEC and others.
Use NetpKdPrint() where possible.
Use PREFIX_ equates.
--*/
// These must be included first:
#include <windef.h> // IN, DWORD, LPTSTR, etc.
#include <rxp.h> // Private header file.
// These may be included in any order:
#include <apiworke.h> // REM_MAX_PARMS.
#include <limits.h> // CHAR_BIT.
#include <lmerr.h> // NERR_ and ERROR_ equates.
#include <names.h> // NetpIsComputerNameValid().
#include <netdebug.h> // NetpKdPrint(), FORMAT_ equates, etc.
#include <netlib.h> // NetpMemoryFree(), etc.
#include <prefix.h> // PREFIX_ equates.
#include <rap.h> // RapIsValidDescriptorSmb().
#include <rx.h> // My prototype, etc.
#include <rxpdebug.h> // IF_DEBUG().
NET_API_STATUS
RxRemoteApi(
IN DWORD ApiNumber,
IN LPCWSTR UncServerName, // this is not OPTIONAL!
IN LPDESC ParmDescString,
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 Flags,
... // rest of API's arguments
)
// Define equate for last named (non-variable) argument, for use with
// va_start macro.
#define LAST_NAMED_ARGUMENT Flags
/*++
Routine Description:
RxRemoteApi (which is analogous to LanMan's NetIRemoteAPI) formats
parameter and data buffers for transporting a local API request to a
remote API worker and translates the remote response into the local
equivalent.
Arguments:
ApiNumber - Function number of the API required.
ServerName - Points to the name of server this API is to be executed on.
This MUST begin with "\\".
ParmDescString - A pointer to a ASCIIZ string describing the API call
parameters (other than server name).
DataDesc16 - A pointer to a ASCIIZ string 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 DataDesc16 must be
a NULL pointer. DataDesc16 is a "modified" 16-bit descriptor,
which may contain "internal use only" characters.
DataDesc32 - A pointer to the 32-bit version of DataDesc16. Must be NULL
iff DataDesc16 is NULL.
DataDescSmb - An optional pointer to the SMB version of DataDesc16.
This must not contain any "internal use only" characters. Must be NULL
iff DataDesc16 is NULL.
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 these descriptors define a secondary data format as
DataDesc16/DataDescSmb define the primary.
Flags - bitmap of various control flags. Currently defined are:
NO_PERMISSION_REQUIRED (0x1) - This flag is TRUE if this API does not
require any permission on the remote machine, and that a null session
is to be used for this request.
ALLOCATE_RESPONSE (0x2) - Set if this routine and its subordinates
(viz RxpConvertArgs, RxpConvertBlock) allocate a response buffer.
We do this because at this level we know how much data is returned
from the down-level server in an Enum or GetInfo call. We can therefore
better estimate the size of buffer to allocate and return to the caller
with 32-bit data than can the individual RxNet routines. The upshot of
this is that we waste less space
... - The remainder of the parameters for the API call as given by the
application. (The "..." notation is from ANSI C, and refers to a
variable argument list. These arguments will be processing using the
ANSI <stdarg.h> macros.)
Return Value:
NET_API_STATUS.
--*/
{
BYTE parm_buf[REM_MAX_PARMS]; // Parameter buffer
LPDESC ParmDescCopy; // Copy of parm desc in buffer.
LPBYTE parm_pos; // Pointer into parm_buf
va_list ParmPtr; // Pointer to stack parms.
DWORD parm_len; // Length of send parameters
DWORD ret_parm_len; // Length of expected parms
DWORD rcv_data_length; // Length of caller's rcv buf
LPVOID rcv_data_ptr; // Pointer to callers rcv buf
LPVOID SendDataPtr16; // Ptr to send buffer to use
DWORD SendDataSize16; // Size of caller's send buf
LPBYTE SmbRcvBuffer = NULL; // Rcv buffer, 16-bit version.
DWORD SmbRcvBufferLength; // Length of the above.
NET_API_STATUS Status; // Return status from remote.
LPTSTR TransportName = NULL; // Optional transport name.
IF_DEBUG(REMOTE) {
NetpKdPrint(( PREFIX_NETAPI
"RxRemoteApi: entered, api num " FORMAT_DWORD "...\n",
ApiNumber ));
}
//
// Make sure API number doesn't get truncated.
// Note that we can't check against the MAX_API equate anymore, as
// that only includes APIs which we know about. Now that RxRemoteApi is
// being exported for use by anyone, we don't know the maximum API number
// which the app might be using.
//
if ( ((DWORD)(WORD)ApiNumber) != ApiNumber ) {
NetpKdPrint(( PREFIX_NETAPI
"RxpStartBuildingTransaction: API NUMBER "
"(" FORMAT_HEX_DWORD ") TOO LARGE, "
"returning ERROR_INVALID_PARAMETER.\n",
ApiNumber ));
return (ERROR_INVALID_PARAMETER);
}
#if DBG
// Code in this file depends on 16-bit words; the Remote Admin Protocol
// demands it.
NetpAssert( ( (sizeof(WORD)) * CHAR_BIT) == 16);
// We are removing these for the time being because the delay load handler for this
// function returns FALSE by default, so the ASSERT will fire incorrectly. For a future
// release, we should change our delayload handler.
//NetpAssert(RapIsValidDescriptorSmb(ParmDescString));
if (DataDescSmb != NULL) {
//NetpAssert(RapIsValidDescriptorSmb(DataDescSmb));
NetpAssert(DataDesc16 != NULL);
NetpAssert(DataDesc32 != NULL);
} else {
NetpAssert(DataDesc16 == NULL);
NetpAssert(DataDesc32 == NULL);
}
if (AuxDescSmb != NULL) {
//NetpAssert(RapIsValidDescriptorSmb(AuxDescSmb));
NetpAssert(AuxDesc16 != NULL);
NetpAssert(AuxDesc32 != NULL);
} else {
NetpAssert(AuxDesc16 == NULL);
NetpAssert(AuxDesc32 == NULL);
}
#endif
if (! NetpIsUncComputerNameValid((LPWSTR)UncServerName)) {
return (NERR_InvalidComputer);
}
//
// Set found parameter flags to FALSE and pointers to NULL.
//
rcv_data_length = 0;
rcv_data_ptr = NULL;
//
// First build the parameter block which will be sent to the API
// worker. This consists of the two descriptor strings, ParmDescString
// and DataDescSmb, followed by the parameters (or the data pointed
// to by the parameters) that were passed to RxRemoteApi.
//
parm_pos = parm_buf; // Start of parameter buffer.
parm_len = 0;
ret_parm_len = 2* sizeof(WORD); // Allow for return status & converter.
Status = RxpStartBuildingTransaction(
parm_buf, // buffer start
REM_MAX_PARMS, // buffer len
ApiNumber, // API number
ParmDescString, // parm desc (original)
DataDescSmb, // data desc (SMB version)
(LPVOID *)&parm_pos, // roving output ptr
& parm_len, // curr output len (updated)
NULL, // last string ptr (don't care)
& ParmDescCopy); // ptr to parm desc copy
if (Status != NERR_Success) {
//
// Consider increasing REM_MAX_PARMS...
//
NetpKdPrint(( PREFIX_NETAPI
"RxRemoteApi: Buffer overflow!\n" ));
NetpBreakPoint();
return (Status);
}
//
// Set up ParmPtr to point to first of the caller's parameters.
//
va_start(ParmPtr, LAST_NAMED_ARGUMENT);
//
// If this API has specified a transport name, load the transport
// name from the first parameter.
//
if (Flags & USE_SPECIFIC_TRANSPORT) {
//
// Set up ParmPtr to point to first of the caller's parameters.
//
TransportName = va_arg(ParmPtr, LPTSTR);
}
//
// Build the rest of the transaction by converting the rest of the
// 32-bit arguments.
//
Status = RxpConvertArgs(
ParmDescCopy, // copy of desc, in SMB buf, will be updated.
DataDesc16,
DataDesc32,
DataDescSmb,
AuxDesc16,
AuxDesc32,
AuxDescSmb,
REM_MAX_PARMS, // MaximumInputBlockLength
REM_MAX_PARMS, // MaximumOutputBlockLength
& ret_parm_len, // curr inp blk len (updated)
& parm_len, // curr output len (updated)
& parm_pos, // curr output ptr (updated)
& ParmPtr, // rest of API's arguments (after server name)
& SendDataSize16, // caller's send buff siz (set)
(LPBYTE *) & SendDataPtr16, // caller's send buff (set)
& rcv_data_length, // caller's rcv buff len (set)
//
// WARNING: Added complexity. Unfortunate, but there you go.
// If we are to allocate the 32-bit received data buffer for
// the caller then the value passed back in rcv_data_ptr will
// be the address of the caller's pointer to the buffer.
// Although this makes things more difficult to understand
// down here, it simplifies life for the caller. Such is the
// lot of the (put upon) systems programmer...
//
(LPBYTE *)&rcv_data_ptr, // caller's rcv buff (set)
Flags
);
va_end(ParmPtr);
//NetpAssert(RapIsValidDescriptorSmb(ParmDescCopy));
if (Status != NERR_Success) {
NetpKdPrint(( PREFIX_NETAPI
"RxRemoteApi: RxpConvertArgs failed, status="
FORMAT_API_STATUS "\n", Status ));
return (Status);
}
IF_DEBUG(REMOTE) {
NetpKdPrint(( PREFIX_NETAPI
"RxRemoteApi: RxpConvertArgs says r.data.len=" FORMAT_DWORD
"\n", rcv_data_length ));
NetpKdPrint(( PREFIX_NETAPI
"RxRemoteApi: RxpConvertArgs says r.parm.len=" FORMAT_DWORD
"\n", ret_parm_len ));
}
//
// Set SmbRcvBuffer, and SmbRcvBufferLength to some appropriate values.
// Because we now allow the final 32-bit receive buffer to be allocated
// somewhere along the codepath of this routine, it is legal to have a
// non-zero receive data length with a meaningless receive data pointer
// (which could be NULL)
//
if (rcv_data_length != 0) {
//
// Allocate the SMB receive buffer.
//
SmbRcvBufferLength = rcv_data_length;
SmbRcvBuffer = NetpMemoryAllocate( SmbRcvBufferLength );
if (SmbRcvBuffer == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
#if DBG
IF_DEBUG(REMOTE) {
NetpKdPrint(( PREFIX_NETAPI
"RxRemoteApi: allocated " FORMAT_DWORD
" bytes as SmbRcvBuffer @ " FORMAT_LPVOID "\n",
SmbRcvBufferLength, (LPVOID) SmbRcvBuffer ));
}
#endif
} else {
//
// Allow zero-length receive data buffer with nonnull addr.
//
SmbRcvBufferLength = 0;
SmbRcvBuffer = NULL;
//
// Don't understand the commentary here: its not a nonnull addr., and
// as far as I can tell never has been. JR?
// RLF 8-19
//
IF_DEBUG(REMOTE) {
NetpKdPrint(( PREFIX_NETAPI
"RxRemoteApi: using 0 len buffer w/ nonnull addr.\n" ));
}
}
//
// The parameter buffers and data buffers are now set up for
// sending to the API worker so call RxpTransactSmb to send them.
//
NetpAssert( parm_len <= MAX_TRANSACT_SEND_PARM_SIZE );
NetpAssert( SendDataSize16 <= MAX_TRANSACT_SEND_DATA_SIZE );
NetpAssert( ret_parm_len <= MAX_TRANSACT_RET_PARM_SIZE );
NetpAssert( SmbRcvBufferLength <= MAX_TRANSACT_RET_DATA_SIZE );
Status = RxpTransactSmb(
(LPWSTR)UncServerName, // computer name
TransportName,
parm_buf, // Send parm buffer
parm_len, // Send parm length
SendDataPtr16, // Send data buffer
SendDataSize16, // Send data size
parm_buf, // Rcv prm buffer
ret_parm_len, // Rcv parm length
SmbRcvBuffer, // Rcv data buffer
&SmbRcvBufferLength, // Rcv data length (returned actual bytes read)
//
// NoPermissionRequired is now a bit in the Flags word
//
(BOOL)(Flags & NO_PERMISSION_REQUIRED)
);
#if DBG
IF_DEBUG(REMOTE) {
NetpKdPrint(( PREFIX_NETAPI
"RxRemoteApi: back from RxpTransactSmb, status="
FORMAT_API_STATUS "\n", Status ));
}
NetpAssert( SmbRcvBufferLength <= rcv_data_length );
if (SmbRcvBuffer == NULL) {
NetpAssert( SmbRcvBufferLength == 0 );
}
#endif
if (Status != NERR_Success) {
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;
}
}
NetpAssert( SmbRcvBufferLength <= MAX_TRANSACT_RET_DATA_SIZE );
// The API call was successful. Now translate the return buffers
// into the local API format.
//
// If we didn't have some fatal error (e.g. unable to talk to the remote
// machine at all), then convert back... Note that fatal errors don't
// include statuses returned by the remote machine.
//
if (! RxpFatalErrorCode(Status)) {
//
// Set up ParmPtr to point to first of the caller's parameters.
//
va_start(ParmPtr, LAST_NAMED_ARGUMENT);
if (Flags & USE_SPECIFIC_TRANSPORT) {
//
// Skip over the first argument - it's the transport.
//
(VOID) va_arg(ParmPtr, LPTSTR);
}
Status = RxpConvertBlock(
ApiNumber,
parm_buf, // response blk
ParmDescString, // parm desc (original)
DataDesc16,
DataDesc32,
AuxDesc16,
AuxDesc32,
& ParmPtr, // rest of API's args
SmbRcvBuffer, // 16-bit version of rcv buff
SmbRcvBufferLength, // amount of BYTES in SmbRcvBuffer
//
// WARNING: Increased complexity. If the ALLOCATE_RESPONSE
// flag is set, then the caller supplied us with the address
// of the pointer to the buffer (which is about to be
// allocated in RxpConvertBlock). Else, rcv_data_ptr is
// the address of the buffer that the caller has already
// allocated before calling this routine
//
rcv_data_ptr, // native version of rcv buff
rcv_data_length, // length of the above
Flags // allocate a 32-bit response buffer?
);
va_end(ParmPtr);
//
// Don't check Status; we'll just return it to caller.
//
}
if (SendDataPtr16 != NULL) {
NetpMemoryFree(SendDataPtr16); // If add'l mem alloc'ed, free it.
}
if (SmbRcvBuffer != NULL) {
NetpMemoryFree(SmbRcvBuffer);
}
return(Status); // Return status from RxpConvertBlock or
// RxpTransactSmb.
} // RxRemoteApi