summaryrefslogtreecommitdiffstats
path: root/private/os2/client/vrremote.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/os2/client/vrremote.c1831
1 files changed, 1831 insertions, 0 deletions
diff --git a/private/os2/client/vrremote.c b/private/os2/client/vrremote.c
new file mode 100644
index 000000000..6294f0761
--- /dev/null
+++ b/private/os2/client/vrremote.c
@@ -0,0 +1,1831 @@
+/*++
+
+This file was modified to support 16 bit OS/2 netapi.dll for the OS/2 SS
+The documentation in this file will be updated.
+
+
+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
+
+--*/
+
+#define NTOS2SS 1
+
+#include <wchar.h>
+
+#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> // LM20_PATHLEN
+#include <lmerr.h>
+#include <lmwksta.h> // NetWkstaGetInfo
+#include <lmapibuf.h> // NetApiBufferFree
+#include "apiworke.h" // REM_MAX_PARMS original is at private\net\rpcxlate\apiworke.h
+//#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>
+
+#include <rxuser.h> // RxNetUser...
+#include <lmaccess.h> // USER_PASSWORD_PARMNUM
+#include <crypt.h> // Needed by NetUserPasswordSet
+
+#include "os2crt.h"
+
+#define DWORD unsigned long
+#define APIRET DWORD
+
+//
+// Global data.
+//
+
+unsigned short remapi_err_flag;
+
+
+//
+// external functions
+//
+
+NET_API_STATUS
+ GetLanmanSessionKey(
+ IN LPWSTR ServerName,
+ OUT LPBYTE pSessionKey
+ );
+
+DWORD UWstrlen(IN LPWSTR);
+
+//
+// internal functions (not necessarily private)
+//
+BOOL
+OemToUppercaseUnicode(
+ IN LPSTR AnsiStringPointer,
+ OUT LPWSTR UnicodeStringPointer,
+ IN DWORD MaxLength
+ );
+
+//
+// code
+//
+
+
+APIRET
+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:
+
+ APIRET
+ Success - NERR_Success
+ Failure -
+
+--*/
+
+{
+ APIRET status;
+
+ status = RxpTransactSmb(ServerName,
+
+ //
+ // BUGBUG - transport name?
+ //
+
+ NULL,
+ SendParmBuffer,
+ SendParmBufLen,
+ SendDataBuffer,
+ SendDataBufLen,
+ ReceiveParmBuffer,
+ ReceiveParmBufLen,
+ ReceiveDataBuffer,
+ ReceiveDataBufLen,
+ NullSessionFlag
+ );
+ if (status == NERR_Success) {
+ }
+
+ return status;
+}
+
+
+APIRET
+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:
+
+ APIRET
+ 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+3)*2]; // To keep the local computername
+ 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;
+ BOOL UBufferAllocated = FALSE; // Unicode computername allocated
+
+ //
+ // 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
+ // NIRM ?
+ //
+
+ *((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) || (*serverName == '\0')) {
+ status = NetWkstaGetInfo(NULL, 100L, &wkstaInfo);
+ if (status) {
+ if (alloc_flag) {
+ LocalFree(send_data_ptr);
+ }
+ return status;
+ } else {
+
+ //
+ // BUGBUG - Unicode - ASCII conversion here
+ //
+#ifndef NTOS2SS
+ computerName[0] = computerName[1] = '\\';
+ strcpy(computerName+2,
+ ((LPWKSTA_INFO_100)wkstaInfo)->wki100_computername);
+#else
+ NullSessionFlag = FALSE;
+ computerName[1] = computerName[3] = 0;
+ computerName[0] = computerName[2] = '\\';
+ wcscpy((unsigned short *)(computerName+4),
+ (unsigned short *)(((LPWKSTA_INFO_100)wkstaInfo)->wki100_computername));
+#endif
+ NetApiBufferFree(wkstaInfo);
+ serverName = computerName;
+#ifdef VR_DIAGNOSE
+ DbgPrint("VrRemoteApi: computername is %s\n", serverName);
+#endif
+ uncName = (unsigned short *)computerName;
+
+ }
+ }
+ else {
+ 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;
+ UBufferAllocated = TRUE;
+
+ }
+////////////////////////////////////////////////////////////////////////////////
+
+ //
+ // The parameter buffers and data buffers are now set up for
+ // sending to the API worker so call transact to send them.
+ //
+
+
+#if DBG
+ IF_DEBUG(NETAPI) {
+ DbgPrint("VrpTransactVdm: UncName=%ws\n", uncName);
+ }
+#endif
+
+ status = RxpTransactSmb((char *)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
+ );
+ if (UBufferAllocated) {
+ 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);
+ }
+}
+
+
+APIRET
+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:
+
+ APIRET
+ 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;
+}
+
+APIRET
+VrEncryptSES(
+ IN LPSTR ServerNamePointer,
+ IN LPSTR passwordPointer, // Input password (Not encripted)
+ IN LPSTR encryptedLmOwfPassword // output password (encripted)
+ )
+{
+ APIRET rc;
+
+ CHAR aPassword[ENCRYPTED_PWLEN];
+// LPBYTE parameterPointer;
+// DWORD passwordEncrypted;
+// DWORD passwordLength;
+
+ LM_OWF_PASSWORD lmOwfPassword;
+ LM_SESSION_KEY lanmanKey;
+// ENCRYPTED_LM_OWF_PASSWORD encryptedLmOwfPassword; parm #2
+ NTSTATUS ntStatus;
+ WCHAR uServerName[(LM20_CNLEN + 1)*2];
+ DWORD length;
+ LPSTR lpServerName;
+ LPBYTE BufPtr;
+// PWKSTA_USER_INFO_1 pInfo1;
+ PWKSTA_INFO_100 pInfo2;
+
+
+ RtlCopyMemory(aPassword,
+ passwordPointer,
+ ENCRYPTED_PWLEN);
+
+ //
+ // BUGBUG, this isn't necessarily the correct upper-case function
+ //
+
+ strupr(aPassword);
+
+
+ if ((ServerNamePointer == NULL) || (*ServerNamePointer == '\0')) {
+ //
+ // get server name.
+ //
+ rc = NetWkstaGetInfo(NULL, 100L, &BufPtr);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ pInfo2 = (PWKSTA_INFO_100) BufPtr;
+
+ length = UWstrlen((LPWSTR)pInfo2->wki100_computername);
+ wcscpy((unsigned short *)(uServerName+2),
+ (unsigned short *)(((LPWKSTA_INFO_100)pInfo2)->wki100_computername));
+
+ uServerName[0]=uServerName[1]='\\';
+
+ NetApiBufferFree(BufPtr);
+ } else {
+
+ //
+ // convert the ANSI server name to UNICODE for GetLanmanSessionKey
+ //
+
+ lpServerName = ServerNamePointer;
+ ntStatus = RtlOemToUnicodeN(uServerName,
+ sizeof(uServerName) - sizeof(uServerName[0]),
+ &length,
+ lpServerName,
+ strlen(lpServerName)
+ );
+ if (NT_SUCCESS(ntStatus)) {
+ uServerName[length/sizeof(uServerName[0])] = 0;
+ } else {
+ return ( ERROR_INVALID_PARAMETER );
+ }
+
+ }
+ ntStatus = RtlCalculateLmOwfPassword(aPassword, &lmOwfPassword);
+ if (NT_SUCCESS(ntStatus)) {
+ ntStatus = GetLanmanSessionKey((LPWSTR)uServerName, (LPBYTE)&lanmanKey);
+ if (NT_SUCCESS(ntStatus)) {
+ ntStatus = RtlEncryptLmOwfPwdWithLmSesKey(&lmOwfPassword,
+ &lanmanKey,
+ (PENCRYPTED_LM_OWF_PASSWORD) encryptedLmOwfPassword
+ );
+ }
+ }
+ return(ntStatus);
+}
+
+APIRET
+NetIUserPasswordSet(
+ IN LPSTR ServerNamePointer,
+ IN LPSTR UserNamePointer,
+ IN LPSTR OldPasswordPointer, // Input password (Not encripted)
+ IN LPSTR NewPasswordPointer // output password (encripted))
+ )
+{
+ APIRET rc;
+
+ WCHAR uServerName[(LM20_UNCLEN + 1)*2];
+ WCHAR uUserName[(LM20_UNLEN + 1)*2];
+ WCHAR uOldPassword[(LM20_PWLEN + 1)*2];
+ WCHAR uNewPassword[(LM20_PWLEN + 1)*2];
+ NTSTATUS ntStatus;
+ DWORD length;
+// LPSTR ansiStringPointer;
+ LPBYTE BufPtr;
+// PWKSTA_USER_INFO_1 pInfo1;
+ PWKSTA_INFO_100 pInfo2;
+
+ if ((ServerNamePointer == NULL) || (*ServerNamePointer == '\0')) {
+ //
+ // get server name.
+ //
+ rc = NetWkstaGetInfo(NULL, 100L, &BufPtr);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ pInfo2 = (PWKSTA_INFO_100) BufPtr;
+
+ length = UWstrlen((LPWSTR)pInfo2->wki100_computername);
+ wcscpy((unsigned short *)(uServerName+2),
+ (unsigned short *)(((LPWKSTA_INFO_100)pInfo2)->wki100_computername));
+
+ uServerName[0]=uServerName[1]='\\';
+
+ NetApiBufferFree(BufPtr);
+ } else {
+ ntStatus = RtlOemToUnicodeN(uServerName,
+ sizeof(uServerName) - sizeof(uServerName[0]),
+ &length,
+ ServerNamePointer,
+ strlen(ServerNamePointer)
+ );
+ if (NT_SUCCESS(ntStatus)) {
+ uServerName[length/sizeof(uServerName[0])] = 0;
+ } else {
+ return (ERROR_INVALID_PARAMETER);
+ }
+ }
+ //
+ // copy, upper case and convert to UNICODE, user name
+ //
+
+ if (!OemToUppercaseUnicode(UserNamePointer,
+ uUserName,
+ ARRAY_ELEMENTS(uUserName) - 1)) {
+ return (ERROR_INVALID_PARAMETER);
+ }
+
+ //
+ // copy, upper case and convert to UNICODE, old password
+ //
+
+ if (!OemToUppercaseUnicode(OldPasswordPointer,
+ uOldPassword,
+ ARRAY_ELEMENTS(uOldPassword) - 1)) {
+ return (ERROR_INVALID_PARAMETER);
+ }
+
+ //
+ // copy, upper case and convert to UNICODE, new password
+ //
+
+ if (!OemToUppercaseUnicode(NewPasswordPointer,
+ uNewPassword,
+ ARRAY_ELEMENTS(uNewPassword) - 1)) {
+ return (ERROR_INVALID_PARAMETER);
+ }
+
+ //
+ // make the call to the down-level password set function
+ //
+
+ return RxNetUserPasswordSet((LPTSTR)uServerName,
+ (LPTSTR)uUserName,
+ (LPTSTR)uOldPassword,
+ (LPTSTR)uNewPassword
+ );
+}
+
+BOOL
+OemToUppercaseUnicode(
+ IN LPSTR AnsiStringPointer,
+ OUT LPWSTR UnicodeStringPointer,
+ IN DWORD MaxLength
+ )
+
+/*++
+
+Routine Description:
+
+ given a string in OEM character set, upper cases it then converts it to
+ UNICODE
+
+Arguments:
+
+ AnsiStringPointer - pointer to 8-bit string to convert
+ UnicodeStringPointer - pointer to resultant 16-bit (UNICODE) string
+ MaxLength - maximum output buffer length in # of characters,
+ NOT including terminating NUL
+
+Return Value:
+
+ BOOL
+ TRUE - string converted
+ FALSE - failed for some reason (string too long, Rtl function failed)
+
+--*/
+
+{
+ DWORD stringLength;
+ char scratchpad[UNLEN + 1]; // UNLEN is the largest type of string we'll get
+ NTSTATUS ntStatus;
+ DWORD length;
+
+ stringLength = strlen(AnsiStringPointer);
+ if (stringLength > MaxLength) {
+ return FALSE;
+ }
+ strcpy(scratchpad, AnsiStringPointer);
+
+ //
+ // BUGBUG - this is not necessarily the correct upper-case function
+ //
+
+ strupr(scratchpad);
+ ntStatus = RtlOemToUnicodeN(UnicodeStringPointer,
+ MaxLength * sizeof(*UnicodeStringPointer),
+ &length,
+ scratchpad,
+ stringLength
+ );
+ if (NT_SUCCESS(ntStatus)) {
+ UnicodeStringPointer[length/sizeof(*UnicodeStringPointer)] = 0;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+