Windows NT 4.0 source code leak
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
48 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1987-1991 Microsoft Corporation
  3. Module Name:
  4. vrremote.c
  5. Abstract:
  6. This module contains a routine VrRemoteApi which is a 16-bit only version
  7. of RxRemoteApi from the net\rpcxlate project. This routine supports remoted
  8. lanman APIs from a Virtual Dos Machine.
  9. This routine does not have to convert 32-16-32, but rather receives 16-bit
  10. data and sends a 16-bit transaction packet either to a down-level server
  11. or an NT-level server which must be running XactSrv to respond to this
  12. request.
  13. This routine and the support routines in vrremutl.c were lifted from the
  14. lanman project
  15. Note: since this is 32-bit code which deals with 16-bit data in a few places,
  16. 32-bit data items should be used where possible and only use 16-bit items
  17. where unavoidable
  18. Contents of this file:
  19. VrRemoteApi
  20. VrTransaction
  21. (VrpGetStructureSize)
  22. (VrpGetArrayLength)
  23. (VrpGetFieldSize)
  24. (VrpConvertReceiveBuffer)
  25. (VrpConvertVdmPointer)
  26. (VrpPackSendBuffer)
  27. Author:
  28. Richard L Firth (rfirth) 24-Oct-1991
  29. Environment:
  30. Flat 32-bit, user space
  31. Revision History:
  32. 21-Oct-1991 rfirth
  33. Created
  34. --*/
  35. #include <nt.h>
  36. #include <ntrtl.h> // ASSERT, DbgPrint
  37. #include <nturtl.h>
  38. #include <windows.h>
  39. #include <softpc.h> // x86 virtual machine definitions
  40. #include <vrdlctab.h>
  41. #include <vdmredir.h> // common Vr stuff
  42. #include <lmcons.h>
  43. #include <lmerr.h>
  44. #include <lmwksta.h> // NetWkstaGetInfo
  45. #include <lmapibuf.h> // NetApiBufferFree
  46. #include <apiworke.h> // REM_MAX_PARMS
  47. #include <mvdm.h> // FETCHWORD
  48. #include <vrremote.h> // prototypes
  49. #include <remtypes.h>
  50. #include <smbgtpt.h>
  51. #include <rxp.h> // RxpTransactSmb
  52. #include <apinums.h> // API_W numbers
  53. #include <string.h>
  54. #include <vrdebug.h>
  55. //
  56. // Global data.
  57. //
  58. unsigned short remapi_err_flag;
  59. //
  60. // code
  61. //
  62. NET_API_STATUS
  63. VrTransaction(
  64. IN LPSTR ServerName,
  65. IN LPBYTE SendParmBuffer,
  66. IN DWORD SendParmBufLen,
  67. IN LPBYTE SendDataBuffer,
  68. IN DWORD SendDataBufLen,
  69. OUT LPBYTE ReceiveParmBuffer,
  70. IN DWORD ReceiveParmBufLen,
  71. IN LPBYTE ReceiveDataBuffer,
  72. IN OUT LPDWORD ReceiveDataBufLen,
  73. IN BOOL NullSessionFlag
  74. )
  75. /*++
  76. Routine Description:
  77. Sends a transaction request to a server and receives a response
  78. Arguments:
  79. ServerName - to send request to
  80. SendParmBuffer - send parameters
  81. SendParmBufLen - length of send parameters
  82. SendDataBuffer - send data
  83. SendDataBufLen - length of send data
  84. ReceiveParmBuffer - receive parameter buffer
  85. ReceiveParmBufLen - length of receive parameter buffer
  86. ReceiveDataBuffer - where to receive data
  87. ReceiveDataBufLen - length of data buffer
  88. NullSessionFlag - set if we are to use a null session
  89. Return Value:
  90. NET_API_STATUS
  91. Success - NERR_Success
  92. Failure -
  93. --*/
  94. {
  95. NET_API_STATUS status;
  96. status = RxpTransactSmb(ServerName,
  97. //
  98. // BUGBUG - transport name?
  99. //
  100. NULL,
  101. SendParmBuffer,
  102. SendParmBufLen,
  103. SendDataBuffer,
  104. SendDataBufLen,
  105. ReceiveParmBuffer,
  106. ReceiveParmBufLen,
  107. ReceiveDataBuffer,
  108. ReceiveDataBufLen,
  109. NullSessionFlag
  110. );
  111. if (status == NERR_Success) {
  112. }
  113. return status;
  114. }
  115. NET_API_STATUS
  116. VrRemoteApi(
  117. IN DWORD ApiNumber,
  118. IN LPBYTE ServerNamePointer,
  119. IN LPSTR ParameterDescriptor,
  120. IN LPSTR DataDescriptor,
  121. IN LPSTR AuxDescriptor OPTIONAL,
  122. IN BOOL NullSessionFlag
  123. )
  124. /*++
  125. Routine Description:
  126. This routine creates and sends a 16-bit transaction SMB containing the
  127. parameters and data required for a remoted function call. Any received
  128. data is copied back into the caller's data space as 16-bit data. This
  129. function is being called on behalf of a VDM process which in turn is
  130. running as a virtual Intel 286 which means:
  131. * little endian
  132. * pointers are 32-bits <segment|selector>:<offset>
  133. * stack is 16-bits wide and EXPANDS DOWN
  134. This routine is called as a result of the NetIRemoteAPI function being
  135. called in the VDM. This is an internal function and so the descriptor
  136. parameters are trusted. However, if the original (16-bit) caller gave
  137. us a bad buffer address or length then the results will be unpredictable.
  138. The original API which called NetIRemoteAPI was a pascal calling convention
  139. routine so if its parameter list was:
  140. FAR PASCAL
  141. NetRoutine(server_name, buffer_pointer, buffer_length, &bytes_read, &total);
  142. the stack would look like this: (note: all pointers are far)
  143. +----------------+
  144. stack pointer => | ip | routine was called far
  145. +----------------+
  146. | cs |
  147. +----------------+
  148. | &total | Offset
  149. +----------------+
  150. | &total | Segment
  151. +----------------+
  152. | &bytes_read | Offset
  153. +----------------+
  154. | &bytes_read | Segment
  155. +----------------+
  156. | buffer_length |
  157. +----------------+
  158. | buffer_pointer | Offset
  159. +----------------+
  160. | buffer_pointer | Segment
  161. +----------------+
  162. | server_name | Offset
  163. +----------------+
  164. | server_name | Segment
  165. +----------------+
  166. Assumes:
  167. BYTE is an 8-bit quantity
  168. WORD is a 16-bit quantity
  169. DWORD is a 32-bit quantity
  170. LPSTR is a 32-bit flat pointer to an 8-bit quantity
  171. Arguments:
  172. ApiNumber - Function number of the API required
  173. ServerNamePointer - Flat 32-bit pointer to address of 32-bit segmented
  174. far pointer to ASCIZ server name in Dos image.
  175. Immediately prior to this is a pascal calling
  176. convention stack of 16-bit caller parameters (see
  177. above). The server name identifies the server at
  178. which the API is to be executed
  179. ParameterDescriptor - Flat 32-bit pointer to ASCIZ string which describes
  180. caller parameters
  181. DataDescriptor - Flat 32-bit pointer to ASCIZ string which describes
  182. data structure in caller buffer (if any) or structure
  183. of data returned from server
  184. AuxDescriptor - Flat 32-bit pointer to ASCIZ string which describes
  185. auxiliary data structures in send buffer (if any) or
  186. structure of aux data returned from server
  187. NullSessionFlag - TRUE if we are to use a NULL session
  188. Return Value:
  189. NET_API_STATUS
  190. Success - 0
  191. Failure - NERR_InternalError
  192. Return this when we have a bad descriptor character or we
  193. blow an internal limit. Basically if we return this its
  194. safe to assume the DOS box handed us some garbage (typically
  195. a descriptor string got trashed etc)
  196. --*/
  197. {
  198. //
  199. // redefine our parameter identifiers as old-code identifiers
  200. //
  201. #define api_num ApiNumber
  202. #define servername_ptr ServerNamePointer
  203. #define parm_str ParameterDescriptor
  204. #define data_str DataDescriptor
  205. #define aux_str AuxDescriptor
  206. //
  207. // define a macro to perform the buffer checking and length and pointer
  208. // manipulation. Either quits the routine and returns ERROR_INVALID_PARAMETER
  209. // or updates parm_len and parm_pos to indicate the next available positions
  210. // and makes this_parm_pos available as the current position to write into
  211. //
  212. #define CHECK_PARAMETERS(len) \
  213. { \
  214. parm_len += len; \
  215. if (parm_len > sizeof(parm_buf)) { \
  216. return ERROR_INVALID_PARAMETER; \
  217. } \
  218. this_parm_pos = parm_pos; \
  219. parm_pos += len; \
  220. }
  221. //
  222. // 32-bit flat pointers and buffers
  223. //
  224. BYTE parm_buf[REM_MAX_PARMS]; // Parameter buffer
  225. BYTE computerName[CNLEN+1];
  226. LPBYTE parm_pos; // Pointer into parm_buf
  227. LPBYTE this_parm_pos; // next place to write in parm_buf
  228. LPBYTE parm_ptr; // Ponter to stack parms
  229. LPSTR l_parm; // Used to index parm_str
  230. LPSTR l_data; // Used to index data_str
  231. LPSTR l_aux; // Used to index aux_str
  232. LPBYTE rcv_data_ptr; // Pointer to callers rcv buf
  233. LPBYTE send_data_ptr; // Ptr to send buffer to use
  234. LPBYTE wkstaInfo;
  235. LPBYTE serverName;
  236. //
  237. // lengths - 32-bit variables (even though actual lengths are quite small)
  238. //
  239. DWORD parm_len; // Length of send parameters
  240. DWORD ret_parm_len; // Length of expected parms
  241. DWORD rcv_data_length; // Length of callers rcv buf
  242. DWORD send_data_length; // Length of callers send buf
  243. DWORD parm_num; // Callers value for parm_num
  244. DWORD struct_size; // Size of fixed data struct
  245. DWORD aux_size; // Size of aux data struct
  246. DWORD num_struct; // Loop count for ptr fixup
  247. //
  248. // 16-bit quantities - only used when converting received 16-bit data in
  249. // caller's receive buffer
  250. //
  251. WORD ReceiveBufferSelector;
  252. WORD ReceiveBufferOffset;
  253. WORD converter; // For pointer fixups
  254. //
  255. // various flags
  256. //
  257. BOOL rcv_dl_flag; // Expect return data flag
  258. BOOL send_dl_flag; // Send data buffer flag
  259. BOOL rcv_dp_flag; // rcv buf ptr present flag
  260. BOOL send_dp_flag; // send buf ptr present flag
  261. BOOL parm_num_flag; // API has a parm_num
  262. BOOL alloc_flag;
  263. //
  264. // misc. variables
  265. //
  266. DWORD aux_pos; // aux structure expected
  267. DWORD no_aux_check; // check flag
  268. int len; // General purpose length
  269. API_RET_TYPE status; // Return status from remote
  270. UNICODE_STRING uString;
  271. ANSI_STRING aString;
  272. LPWSTR uncName;
  273. NTSTATUS ntstatus;
  274. //
  275. // Clear the internal error flag
  276. //
  277. remapi_err_flag = 0;
  278. //
  279. // Set found parameter flags to FALSE and ponters to NULL
  280. //
  281. rcv_dl_flag = FALSE;
  282. send_dl_flag = FALSE;
  283. rcv_dp_flag = FALSE;
  284. alloc_flag = FALSE;
  285. send_dp_flag = FALSE;
  286. parm_num_flag = FALSE;
  287. rcv_data_length = 0;
  288. send_data_length= 0;
  289. parm_num = 0;
  290. rcv_data_ptr = NULL;
  291. send_data_ptr = NULL;
  292. //
  293. // Set up parm_ptr to point to first of the callers parmeters
  294. //
  295. parm_ptr = servername_ptr;
  296. parm_pos = parm_buf;
  297. ret_parm_len = 2 * sizeof(WORD); /* Allow for return status & offset */
  298. //
  299. // parse parameter descriptor/build parameter buffer for transaction
  300. // and get interesting information from 16-bit parameters
  301. // When finished, the parameter buffer looks like this:
  302. //
  303. // <api_num><parm_desc><data_desc><parms>[<aux_desc>]
  304. //
  305. // Remember: DOS only deals with ASCII characters
  306. //
  307. *((LPWORD)parm_pos)++ = (WORD)ApiNumber;
  308. parm_len = sizeof(WORD);
  309. len = strlen(ParameterDescriptor) + 1;
  310. parm_len += len;
  311. if (parm_len > sizeof(parm_buf)) {
  312. return NERR_InternalError;
  313. }
  314. l_parm = parm_pos;
  315. RtlCopyMemory(parm_pos, ParameterDescriptor, len);
  316. parm_pos += len;
  317. len = strlen(DataDescriptor) + 1;
  318. parm_len += len;
  319. if (parm_len > sizeof(parm_buf)) {
  320. return NERR_InternalError;
  321. }
  322. l_data = parm_pos;
  323. RtlCopyMemory(parm_pos, DataDescriptor, len);
  324. parm_pos += len;
  325. //
  326. // parse the parameter descriptor strings. Remember interesting things such
  327. // as pointers to buffers, buffer lengths, etc.
  328. //
  329. for (; *l_parm != '\0'; l_parm++) {
  330. switch(*l_parm) {
  331. case REM_WORD:
  332. CHECK_PARAMETERS(sizeof(WORD));
  333. parm_ptr -= sizeof(WORD);
  334. SmbMoveUshort((LPWORD)this_parm_pos, (LPWORD)parm_ptr);
  335. break;
  336. case REM_ASCIZ: {
  337. LPSTR pstring;
  338. //
  339. // the parameter is a pointer to a string. Read the string
  340. // pointer from the caller's stack then check the string proper.
  341. // If the pointer is NULL, change the parameter descriptor sent
  342. // in the SMB to indicate the pointer was NULL at this end
  343. //
  344. parm_ptr -= sizeof(LPSTR);
  345. pstring = LPSTR_FROM_POINTER(parm_ptr);
  346. if (pstring == NULL) {
  347. *(l_parm) = REM_NULL_PTR;
  348. break;
  349. }
  350. len = strlen(pstring) + 1;
  351. CHECK_PARAMETERS(len);
  352. RtlCopyMemory(this_parm_pos, pstring, len);
  353. }
  354. break;
  355. case REM_BYTE_PTR:
  356. case REM_WORD_PTR:
  357. case REM_DWORD_PTR: {
  358. LPBYTE pointer;
  359. parm_ptr -= sizeof(LPBYTE);
  360. pointer = LPBYTE_FROM_POINTER(parm_ptr);
  361. if (pointer == NULL) {
  362. *(l_parm) = REM_NULL_PTR; /* Indicate null pointer */
  363. break;
  364. }
  365. len = VrpGetArrayLength(l_parm, &l_parm);
  366. CHECK_PARAMETERS(len);
  367. RtlCopyMemory(this_parm_pos, pointer, len);
  368. }
  369. break;
  370. case REM_RCV_WORD_PTR:
  371. case REM_RCV_BYTE_PTR:
  372. case REM_RCV_DWORD_PTR: {
  373. LPBYTE pointer;
  374. parm_ptr -= sizeof(LPBYTE*);
  375. pointer = LPBYTE_FROM_POINTER(parm_ptr);
  376. //
  377. // Added this test for a NULL pointer to allow for
  378. // a reserved field (currently MBN) to be a recv
  379. // pointer. - ERICPE 7/19/89
  380. //
  381. if (pointer == NULL) {
  382. *(l_parm) = REM_NULL_PTR;
  383. break;
  384. }
  385. ret_parm_len += VrpGetArrayLength(l_parm, &l_parm);
  386. if (ret_parm_len > sizeof(parm_buf)) {
  387. ASSERT(FALSE);
  388. return NERR_InternalError;
  389. }
  390. }
  391. break;
  392. case REM_DWORD:
  393. CHECK_PARAMETERS(sizeof(DWORD));
  394. parm_ptr -= sizeof(DWORD);
  395. SmbMoveUlong((LPDWORD)this_parm_pos, (LPDWORD)parm_ptr);
  396. break;
  397. case REM_RCV_BUF_LEN:
  398. CHECK_PARAMETERS(sizeof(WORD));
  399. parm_ptr -= sizeof(WORD);
  400. SmbMoveUshort((LPWORD)this_parm_pos, (LPWORD)parm_ptr);
  401. rcv_data_length = (DWORD)SmbGetUshort((LPWORD)parm_ptr);
  402. rcv_dl_flag = TRUE;
  403. #ifdef VR_DIAGNOSE
  404. DbgPrint("VrRemoteApi: rcv_data_length=%x\n", rcv_data_length);
  405. #endif
  406. break;
  407. case REM_RCV_BUF_PTR:
  408. parm_ptr -= sizeof(LPBYTE);
  409. ReceiveBufferOffset = GET_OFFSET(parm_ptr);
  410. ReceiveBufferSelector = GET_SELECTOR(parm_ptr);
  411. rcv_data_ptr = LPBYTE_FROM_POINTER(parm_ptr);
  412. rcv_dp_flag = TRUE;
  413. #ifdef VR_DIAGNOSE
  414. DbgPrint("VrRemoteApi: Off=%x, Sel=%x, data_ptr=%x\n",
  415. ReceiveBufferOffset, ReceiveBufferSelector, rcv_data_ptr);
  416. #endif
  417. break;
  418. case REM_SEND_BUF_PTR:
  419. parm_ptr -= sizeof(LPBYTE);
  420. send_data_ptr = LPBYTE_FROM_POINTER(parm_ptr);
  421. send_dp_flag = TRUE;
  422. break;
  423. case REM_SEND_BUF_LEN:
  424. parm_ptr -= sizeof(WORD);
  425. send_data_length = (DWORD)SmbGetUshort((LPWORD)parm_ptr);
  426. send_dl_flag = TRUE;
  427. break;
  428. case REM_ENTRIES_READ:
  429. ret_parm_len += sizeof(WORD);
  430. if (ret_parm_len > sizeof(parm_buf)) {
  431. ASSERT(FALSE);
  432. return NERR_InternalError;
  433. }
  434. parm_ptr -= sizeof(LPBYTE);
  435. break;
  436. case REM_PARMNUM:
  437. CHECK_PARAMETERS(sizeof(WORD));
  438. parm_ptr -= sizeof(WORD);
  439. parm_num = (DWORD)SmbGetUshort((LPWORD)parm_ptr);
  440. SmbMoveUshort((LPWORD)this_parm_pos, (LPWORD)parm_ptr);
  441. parm_num_flag = TRUE;
  442. break;
  443. case REM_FILL_BYTES:
  444. //
  445. // This is a rare type but is needed to ensure that the
  446. // send paramteres are at least as large as the return
  447. // parameters so that buffer management can be simplified
  448. // on the server.
  449. //
  450. len = VrpGetArrayLength(l_parm, &l_parm);
  451. CHECK_PARAMETERS(len);
  452. break;
  453. default: /* Could be a digit from NULL send array */
  454. break;
  455. }
  456. }
  457. //
  458. // The parameter buffer now contains ;
  459. // api_num - word
  460. // parm_str - asciz, (NULL c,i,f,z identifiers replaced with Z.
  461. // data_str - asciz
  462. // parameters - as identified by parm_str.
  463. //
  464. //
  465. // For the receive buffer there is no data to set up for the call
  466. // but there might have been an REM_AUX_COUNT descriptor in data_str
  467. // which requires the aux_str to be copied onto the end of the
  468. // parameter buffer.
  469. //
  470. if (rcv_dp_flag || send_dp_flag) {
  471. //
  472. // Find the length of the fixed length portion of the data
  473. // buffer.
  474. //
  475. struct_size = VrpGetStructureSize(l_data, &aux_pos);
  476. if (aux_pos != -1) {
  477. l_aux = aux_str;
  478. len = strlen(l_aux) + 1; /* Length of aux descriptor */
  479. CHECK_PARAMETERS(len);
  480. RtlCopyMemory(this_parm_pos, aux_str, len);
  481. aux_size = VrpGetStructureSize(l_aux, &no_aux_check);
  482. if (no_aux_check != -1) { /* Error if N in aux_str */
  483. ASSERT(FALSE);
  484. return NERR_InternalError;
  485. }
  486. }
  487. }
  488. //
  489. // For a send buffer the data pointed to in the fixed structure
  490. // must be copied into the send buffer. Any pointers which already
  491. // point in the send buffer are NULLed as it is illegal to use
  492. // the buffer for the send data, it is our transport buffer.
  493. // NOTE - if parmnum was specified the buffer contains only that
  494. // element of the structure so no length checking is needed at this
  495. // side. A parmnum for a pointer type means that the data is at the
  496. // start of the buffer so there is no copying to be done.
  497. //
  498. if (send_dp_flag) {
  499. //
  500. // Only process buffer if no parm_num and this is not a block send
  501. // (no data structure) or an asciz concatenation send
  502. //
  503. if ((parm_num == 0) && (*l_data != REM_DATA_BLOCK)) {
  504. status = VrpPackSendBuffer(
  505. &send_data_ptr,
  506. &send_data_length,
  507. &alloc_flag,
  508. data_str,
  509. aux_str,
  510. struct_size,
  511. aux_pos,
  512. aux_size,
  513. parm_num_flag,
  514. FALSE
  515. );
  516. if (status != 0) {
  517. return status;
  518. }
  519. }
  520. }
  521. //
  522. // Check for an internal error prior to issuing the transaction
  523. //
  524. if (remapi_err_flag != 0) {
  525. if (alloc_flag) {
  526. LocalFree(send_data_ptr);
  527. }
  528. return NERR_InternalError;
  529. }
  530. //
  531. // get the server name. If it is NULL then we are faking a local API call
  532. // by making a remote call to XactSrv on this machine. Fill in our computer
  533. // name
  534. //
  535. serverName = LPSTR_FROM_POINTER(servername_ptr);
  536. ////////////////////////////////////////////////////////////////////////////////
  537. //// is this actually required any longer?
  538. if (serverName == NULL) {
  539. status = NetWkstaGetInfo(NULL, 100, &wkstaInfo);
  540. if (status) {
  541. if (alloc_flag) {
  542. LocalFree(send_data_ptr);
  543. }
  544. return status;
  545. } else {
  546. computerName[0] = computerName[1] = '\\';
  547. //
  548. // BUGBUG - Unicode - ASCII conversion here
  549. //
  550. strcpy(computerName+2,
  551. ((LPWKSTA_INFO_100)wkstaInfo)->wki100_computername);
  552. NetApiBufferFree(wkstaInfo);
  553. serverName = computerName;
  554. #ifdef VR_DIAGNOSE
  555. DbgPrint("VrRemoteApi: computername is %s\n", serverName);
  556. #endif
  557. }
  558. }
  559. ////////////////////////////////////////////////////////////////////////////////
  560. //
  561. // The parameter buffers and data buffers are now set up for
  562. // sending to the API worker so call transact to send them.
  563. //
  564. RtlInitAnsiString(&aString, serverName);
  565. ntstatus = RtlAnsiStringToUnicodeString(&uString, &aString, (BOOLEAN)TRUE);
  566. if (!NT_SUCCESS(ntstatus)) {
  567. #if DBG
  568. IF_DEBUG(NETAPI) {
  569. DbgPrint("VrRemoteApi: Unexpected situation: RtlAnsiStringToUnicodeString returns %x\n", ntstatus);
  570. }
  571. #endif
  572. return ERROR_NOT_ENOUGH_MEMORY;
  573. }
  574. uncName = uString.Buffer;
  575. #if DBG
  576. IF_DEBUG(NETAPI) {
  577. DbgPrint("VrpTransactVdm: UncName=%ws\n", uncName);
  578. }
  579. #endif
  580. status = RxpTransactSmb((LPTSTR)uncName,
  581. //
  582. // BUGBUG - transport name?
  583. //
  584. NULL,
  585. parm_buf, // Send parm buffer
  586. parm_len, // Send parm length
  587. send_data_ptr, // Send data buffer
  588. send_data_length, // Send data length
  589. parm_buf, // Rcv prm buffer
  590. ret_parm_len, // Rcv parm length
  591. rcv_data_ptr, // Rcv data buffer
  592. &rcv_data_length, // Rcv data length
  593. NullSessionFlag
  594. );
  595. RtlFreeUnicodeString(&uString);
  596. if (status) {
  597. #ifdef VR_DIAGNOSE
  598. DbgPrint("Error: VrRemoteApi: RxpTransactSmb returns %d(%x)\n",
  599. status, status);
  600. #endif
  601. switch (status) {
  602. case NERR_BufTooSmall: /* No data returned from API worker */
  603. rcv_data_length = 0;
  604. break;
  605. case ERROR_MORE_DATA: /* Just a warning for the caller */
  606. break;
  607. case NERR_TooMuchData: /* Just a warning for the caller */
  608. break;
  609. default:
  610. rcv_data_length = 0;
  611. break;
  612. }
  613. }
  614. /* The API call was successful. Now translate the return buffers
  615. * into the local API format.
  616. *
  617. * First copy any data from the return parameter buffer into the
  618. * fields pointed to by the original call parmeters.
  619. * The return parameter buffer contains;
  620. * status, (unsigned short)
  621. * converter, (unsigned short)
  622. * ... - fields described by rcv ptr types in parm_str
  623. */
  624. parm_pos = parm_buf + sizeof(WORD);
  625. converter = (WORD)SmbGetUshort((LPWORD)parm_pos);
  626. parm_pos += sizeof(WORD);
  627. //
  628. // Set up parm_ptr to point to first of the callers parmeters
  629. //
  630. parm_ptr = servername_ptr;
  631. //
  632. // set default value of num_struct to 1, if data, 0 if no data
  633. //
  634. num_struct = (DWORD)((*data_str == '\0') ? 0 : 1);
  635. for (; *parm_str != '\0'; parm_str++) {
  636. switch (*parm_str) {
  637. case REM_RCV_WORD_PTR:
  638. case REM_RCV_BYTE_PTR:
  639. case REM_RCV_DWORD_PTR: {
  640. LPBYTE ptr;
  641. parm_ptr -= sizeof(LPBYTE*);
  642. ptr = LPBYTE_FROM_POINTER(parm_ptr);
  643. //
  644. // if the rcv buffer given to us by the user is NULL,
  645. // (one currently can be - it is an MBZ parameter for
  646. // now in the log read apis...), don't attempt to
  647. // copy anything. len will be garbage in this
  648. // case, so don't update parm_pos either. All we
  649. // use VrpGetArrayLength for is to update parm_str if
  650. // the parameter was NULL.
  651. //
  652. if (ptr != NULL) {
  653. len = VrpGetArrayLength(parm_str, &parm_str);
  654. RtlCopyMemory(ptr, parm_pos, len);
  655. //
  656. // This gross hack is to fix the problem that a
  657. // down level spooler (Lan Server 1.2)
  658. // do not perform level checking
  659. // on the w functions of the api(s):
  660. // DosPrintQGetInfo
  661. // and thus can return NERR_Success
  662. // and bytesavail == 0. This combination
  663. // is technically illegal, and results in
  664. // us attempting to unpack a buffer full of
  665. // garbage. The following code detects this
  666. // condition and resets the amount of returned
  667. // data to zero so we do not attempt to unpack
  668. // the buffer. Since we know the reason for the
  669. // mistake at the server end is that we passed
  670. // them a new level, we return ERROR_INVALID_LEVEL
  671. // in this case.
  672. // ERICPE, 5/16/90.
  673. //
  674. if ((api_num == API_WPrintQGetInfo)
  675. && (status == NERR_Success)
  676. && (*parm_str == REM_RCV_WORD_PTR)
  677. && (*(LPWORD)ptr == 0)) {
  678. rcv_data_length = 0;
  679. status = ERROR_INVALID_LEVEL;
  680. }
  681. //
  682. // END OF GROSS HACK
  683. //
  684. parm_pos += len;
  685. }
  686. }
  687. break;
  688. case REM_ENTRIES_READ: {
  689. LPWORD wptr;
  690. parm_ptr -= sizeof(LPWORD*);
  691. wptr = (LPWORD)POINTER_FROM_POINTER(parm_ptr);
  692. num_struct = (DWORD)SmbGetUshort((LPWORD)parm_pos);
  693. SmbPutUshort((LPWORD)wptr, (WORD)num_struct);
  694. parm_pos += sizeof(WORD);
  695. }
  696. break;
  697. case REM_FILL_BYTES:
  698. //
  699. // Special case, this was not really an input parameter
  700. // so parm_ptr does not get changed. However, the parm_str
  701. // pointer must be advanced past the descriptor field so
  702. // use get VrpGetArrayLength to do this but ignore the
  703. // return length.
  704. //
  705. VrpGetArrayLength(parm_str, &parm_str);
  706. break;
  707. default:
  708. //
  709. // If the descriptor was not a rcv pointer type then step
  710. // over the parmeter pointer.
  711. //
  712. parm_ptr -= VrpGetFieldSize(parm_str, &parm_str);
  713. }
  714. }
  715. //
  716. // Now convert all pointer fields in the receive buffer to local
  717. // pointers.
  718. //
  719. if (rcv_dp_flag && (rcv_data_length != 0)) {
  720. VrpConvertReceiveBuffer(
  721. rcv_data_ptr, // lp
  722. ReceiveBufferSelector, // word
  723. ReceiveBufferOffset, // word
  724. converter, // word
  725. num_struct, // dword
  726. data_str, // lp
  727. aux_str // lp
  728. );
  729. }
  730. if (alloc_flag) {
  731. LocalFree(send_data_ptr);
  732. }
  733. if (remapi_err_flag != 0) {
  734. return NERR_InternalError;
  735. }
  736. return status;
  737. }
  738. DWORD
  739. VrpGetStructureSize(
  740. IN LPSTR Descriptor,
  741. IN LPDWORD AuxOffset
  742. )
  743. /*++
  744. Routine Description:
  745. Calculates the length of the fixed portion of a structure, based on the
  746. descriptor for that structure
  747. Arguments:
  748. Descriptor - pointer to ASCIZ data descriptor string
  749. AuxOffset - pointer to returned dword which is relative position in the
  750. data descriptor where a REM_AUX_NUM descriptor was found
  751. This will be set to -1 if no aux descriptor found
  752. Return Value:
  753. Length in bytes of structure described by Descriptor
  754. --*/
  755. {
  756. DWORD length;
  757. char c;
  758. *AuxOffset = (DWORD)(-1);
  759. for (length = 0; (c = *Descriptor) != '\0'; Descriptor++) {
  760. if (c == REM_AUX_NUM) {
  761. *AuxOffset = length;
  762. length += sizeof(WORD);
  763. } else {
  764. length += VrpGetFieldSize(Descriptor, &Descriptor);
  765. }
  766. }
  767. return length;
  768. }
  769. DWORD
  770. VrpGetArrayLength(
  771. IN LPSTR Descriptor,
  772. IN LPSTR* pDescriptor
  773. )
  774. /*++
  775. Routine Description:
  776. Calculates the length of an array described by an element of a
  777. descriptor string and update the descriptor string pointer to point
  778. to the last char in the element of the descriptor string.
  779. Arguments:
  780. Descriptor - pointer to ASCIZ descriptor string
  781. pDescriptor - pointer to address of Descriptor
  782. Return Value:
  783. Length in bytes of array described by Descriptor
  784. --*/
  785. {
  786. DWORD num_elements;
  787. DWORD element_length;
  788. //
  789. // First set length of an element in the array
  790. //
  791. switch (*Descriptor) {
  792. case REM_WORD:
  793. case REM_WORD_PTR:
  794. case REM_RCV_WORD_PTR:
  795. element_length = sizeof(WORD);
  796. break;
  797. case REM_DWORD:
  798. case REM_DWORD_PTR:
  799. case REM_RCV_DWORD_PTR:
  800. element_length = sizeof(DWORD);
  801. break;
  802. case REM_BYTE:
  803. case REM_BYTE_PTR:
  804. case REM_RCV_BYTE_PTR:
  805. case REM_FILL_BYTES:
  806. element_length = sizeof(BYTE);
  807. break;
  808. //
  809. // Warning: following fixes a bug in which "b21" type
  810. // combinations in parmeter string will be
  811. // handled correctly when pointer to such "bit map"
  812. // in the struct is NULL. These two dumbos could
  813. // interfere so we force a success return.
  814. //
  815. case REM_ASCIZ:
  816. case REM_SEND_LENBUF:
  817. case REM_NULL_PTR:
  818. return 0;
  819. default:
  820. remapi_err_flag = NERR_InternalError;
  821. ASSERT(FALSE);
  822. return 0;
  823. }
  824. //
  825. // Now get numeber of elements in the array
  826. //
  827. for (num_elements = 0, Descriptor++;
  828. (*Descriptor <= '9') && (*Descriptor >= '0');
  829. Descriptor++, (*pDescriptor)++) {
  830. num_elements = (WORD)((10 * num_elements) + ((WORD)*Descriptor - (WORD)'0'));
  831. }
  832. return (num_elements == 0) ? element_length : element_length * num_elements;
  833. }
  834. DWORD
  835. VrpGetFieldSize(
  836. IN LPSTR Descriptor,
  837. IN LPSTR* pDescriptor
  838. )
  839. /*++
  840. Routine Description:
  841. Calculates the length of an field described by an element of a
  842. descriptor string and update the descriptor string pointer to point
  843. to the last char in the element of the descriptor string.
  844. Arguments:
  845. Descriptor - pointer to the descriptor string
  846. pDescriptor - pointer to the address of the descriptor. On exit
  847. this points to the last character in the descriptor
  848. just parsed
  849. Return Value:
  850. Length in bytes of the field parsed
  851. --*/
  852. {
  853. char c;
  854. c = *Descriptor;
  855. if (IS_POINTER(c) || (c == REM_NULL_PTR)) { /* All pointers same size */
  856. while (*(++Descriptor) <= '9' && *Descriptor >= '0') {
  857. (*pDescriptor)++; /* Move ptr to end of field size */
  858. }
  859. return sizeof(LPSTR);
  860. }
  861. //
  862. // Here if descriptor was not a pointer type so have to find the field
  863. // length specifically
  864. //
  865. switch (c) {
  866. case REM_WORD:
  867. case REM_BYTE:
  868. case REM_DWORD:
  869. return VrpGetArrayLength(Descriptor, pDescriptor);
  870. case REM_AUX_NUM:
  871. case REM_PARMNUM:
  872. case REM_RCV_BUF_LEN:
  873. case REM_SEND_BUF_LEN:
  874. return sizeof(WORD);
  875. case REM_DATA_BLOCK:
  876. case REM_IGNORE:
  877. return 0; /* No structure for this */
  878. case REM_DATE_TIME:
  879. return sizeof(DWORD);
  880. default:
  881. remapi_err_flag = NERR_InternalError;
  882. #ifdef VR_DIAGNOSE
  883. DbgPrint("VrpGetFieldSize: offending descriptor is '%c'\n", c);
  884. #endif
  885. ASSERT(FALSE);
  886. return 0;
  887. }
  888. }
  889. VOID
  890. VrpConvertReceiveBuffer(
  891. IN LPBYTE ReceiveBuffer,
  892. IN WORD BufferSelector,
  893. IN WORD BufferOffset,
  894. IN WORD ConverterWord,
  895. IN DWORD NumberStructs,
  896. IN LPSTR DataDescriptor,
  897. IN LPSTR AuxDescriptor
  898. )
  899. /*++
  900. Routine Description:
  901. All pointers in the receive buffer are returned from the API worker as
  902. pointers into the buffer position given to the API on the API worker's
  903. station. In order to convert them into local pointers the segment
  904. of each pointer must be set to the segment of the rcv buffer and the offset
  905. must be set to;
  906. offset of rcv buffer + offset of pointer - converter word.
  907. This routine steps through the receive buffer and calls VrpConvertVdmPointer
  908. to perform the above pointer conversions.
  909. Arguments:
  910. ReceiveBuffer - 32-bit flat pointer to 16-bit DOS buffer
  911. BufferSelector - 16-bit selector of Dos receive buffer
  912. BufferOffset - 16-bit offset of Dos receive buffer
  913. ConverterWord - From API worker
  914. NumberStructs - Entries read parm (or 1 for GetInfo)
  915. DataDescriptor - String for data format
  916. AuxDescriptor - string for aux format
  917. Return Value:
  918. None.
  919. --*/
  920. {
  921. LPSTR l_data;
  922. LPSTR l_aux;
  923. DWORD num_aux;
  924. DWORD i, j;
  925. char c;
  926. for (i = 0; i < NumberStructs; i++) {
  927. //
  928. // convert all pointers in next primary; if we hit a aux word count
  929. // remember number of secondary structures
  930. //
  931. for (l_data = DataDescriptor, num_aux = 0; c = *l_data; l_data++) {
  932. if (c == REM_AUX_NUM) {
  933. num_aux = (DWORD)*(ULPWORD)ReceiveBuffer;
  934. }
  935. if (IS_POINTER(c)) {
  936. VrpConvertVdmPointer(
  937. (ULPWORD)ReceiveBuffer,
  938. BufferSelector,
  939. BufferOffset,
  940. ConverterWord
  941. );
  942. }
  943. ReceiveBuffer += VrpGetFieldSize(l_data, &l_data);
  944. }
  945. //
  946. // convert any pointers in any returned secondary (aux) structures
  947. //
  948. for (j = 0; j < num_aux; j++) {
  949. for (l_aux = AuxDescriptor; c = *l_aux; l_aux++) {
  950. if (IS_POINTER(c)) {
  951. VrpConvertVdmPointer(
  952. (ULPWORD)ReceiveBuffer,
  953. BufferSelector,
  954. BufferOffset,
  955. ConverterWord
  956. );
  957. }
  958. ReceiveBuffer += VrpGetFieldSize(l_aux, &l_aux);
  959. }
  960. }
  961. }
  962. }
  963. VOID
  964. VrpConvertVdmPointer(
  965. IN ULPWORD TargetPointer,
  966. IN WORD BufferSegment,
  967. IN WORD BufferOffset,
  968. IN WORD ConverterWord
  969. )
  970. /*++
  971. Routine Description:
  972. All pointers in the receive buffer are returned from the API worker as
  973. pointers into the buffer position given to to the API on the API worker's
  974. station. In order to convert them into local pointers the segment
  975. of each pointer must be set to the segment of the rcv buffer and the offset
  976. must be set to;
  977. offset of rcv buffer + offset of pointer - converter word.
  978. The pointer is not converted if it is NULL
  979. Arguments:
  980. TargetPointer - 32-bit flat pointer to segmented Dos pointer to convert
  981. BufferSegment - 16-bit selector/segment of target buffer in DOS image
  982. BufferOffset - 16-bit offset within BufferSegment where buffer starts
  983. ConverterWord - 16-bit offset converter word from API worker on server
  984. Return Value:
  985. None.
  986. --*/
  987. {
  988. WORD offset;
  989. if (*((UCHAR * UNALIGNED *)TargetPointer) != NULL) {
  990. SET_SELECTOR(TargetPointer, BufferSegment);
  991. offset = GET_OFFSET(TargetPointer) - ConverterWord;
  992. SET_OFFSET(TargetPointer, BufferOffset + offset);
  993. }
  994. }
  995. NET_API_STATUS
  996. VrpPackSendBuffer(
  997. IN OUT LPBYTE* SendBufferPtr,
  998. IN OUT LPDWORD SendBufLenPtr,
  999. OUT LPBOOL SendBufferAllocated,
  1000. IN OUT LPSTR DataDescriptor,
  1001. IN LPSTR AuxDescriptor,
  1002. IN DWORD StructureSize,
  1003. IN DWORD AuxOffset,
  1004. IN DWORD AuxSize,
  1005. IN BOOL SetInfoFlag,
  1006. IN BOOL OkToModifyDescriptor
  1007. )
  1008. /*++
  1009. Routine Description:
  1010. For a send buffer the data pointed to in the fixed structure
  1011. must be copied into the send buffer. Any pointers which already
  1012. point in the send buffer are NULLed ( or errored if the call is not
  1013. a SetInfo type) as it is illegal to use the buffer for the send data,
  1014. it is our transport buffer
  1015. Note that if the caller's (VDM) buffer is large enough, the variable data
  1016. will be copied there. Eg. if the caller is doing a NetUseAdd which has a
  1017. 26 byte fixed structure (use_info_1) and they placed that structure in a
  1018. 1K buffer, the remote name will be copied into their own buffer at offset 26.
  1019. The data pointed to is in 16-bit little-endian format; any pointers are
  1020. segmented 16:16 pointers combined in the (thankfully) imitable intel way
  1021. to result in a 20-bit linear (virtual) address
  1022. If this function fails, the caller's buffer pointer and length will not
  1023. have altered. If it succeeds however, *SendBufferPtr and *SendBufLenPtr
  1024. may be different to the values passed, depending on whether
  1025. *SendBufferAllocated is TRUE
  1026. Arguments:
  1027. SendBufferPtr - pointer to pointer to caller's 16-bit send buffer.
  1028. We may be able to satisfy the send from this buffer
  1029. if the data is simple (ie no structures to send). If
  1030. we have to send structured data then we may have to
  1031. allocate a new buffer in this routine because we need
  1032. to move all of the caller's data into one buffer and
  1033. (s)he may not have allocated enough space to hold
  1034. everything. Additionally, we cannot assume that we
  1035. can write the caller's data into their own buffer!
  1036. SendBufLenPtr - pointer to the length of the allocated buffer. If
  1037. we allocate a buffer in this routine, this length
  1038. will alter
  1039. SendBufferAllocated - pointer to a flag which will get set (TRUE) if we do
  1040. actually allocate a buffer in this routine
  1041. DataDescriptor - pointer to ASCIZ string which describes the primary
  1042. data structure in the buffer. This may be updated if
  1043. NULL pointers are found where a REM_ASCIZ descriptor
  1044. designates a string pointer
  1045. AuxDescriptor - pointer to ASCIZ string which describes the secondary
  1046. data structure in the buffer
  1047. StructureSize - the size (in bytes) of the fixed portion of the
  1048. primary data structure
  1049. AuxOffset - offset to the REM_AUX_NUM descriptor ('N') within the
  1050. data descriptor, or -1 if there isn't one
  1051. AuxSize - size in bytes of the fixed part of the secondary data
  1052. structure, if any
  1053. SetInfoFlag - indication of whether the API was a SetInfo call
  1054. OkToModifyDescriptor- TRUE if we can modify REM_ASCIZ descriptor chars to
  1055. REM_NULL_PTR in DataDescriptor, if a NULL pointer is
  1056. found in the structure. Used by VrNet routines which
  1057. are not calling VrRemoteApi
  1058. Return Value:
  1059. NET_API_STATUS
  1060. Success - NERR_Success
  1061. Failure - ERROR_NOT_ENOUGH_MEMORY
  1062. NERR_BufTooSmall
  1063. --*/
  1064. {
  1065. LPBYTE struct_ptr;
  1066. LPBYTE c_send_buf;
  1067. LPBYTE send_ptr;
  1068. DWORD c_send_len;
  1069. DWORD buf_length;
  1070. DWORD to_send_len;
  1071. DWORD num_aux;
  1072. LPSTR data_ptr;
  1073. LPSTR l_dsc;
  1074. LPSTR l_str;
  1075. BOOL alloc_flag = FALSE;
  1076. DWORD num_struct;
  1077. DWORD len;
  1078. UCHAR c;
  1079. DWORD numberOfStructureTypes;
  1080. DWORD i, j;
  1081. LPBYTE ptr;
  1082. //
  1083. // Make local copies of the original start and length of the caller's
  1084. // buffer as the originals may change if malloc is used but they
  1085. // will still be needed for the F_RANGE check.
  1086. //
  1087. struct_ptr = c_send_buf = send_ptr = *SendBufferPtr;
  1088. c_send_len = buf_length = *SendBufLenPtr;
  1089. if ((buf_length < StructureSize) || (AuxOffset == StructureSize)) {
  1090. return NERR_BufTooSmall;
  1091. }
  1092. //
  1093. // if the offset to the REM_AUX_NUM descriptor is not -1 then we have
  1094. // associated secondary structures with this primary. The actual number
  1095. // is embedded in the primary structure. Retrieve it
  1096. //
  1097. if (AuxOffset != -1) {
  1098. num_aux = (DWORD)SmbGetUshort((LPWORD)(send_ptr + AuxOffset));
  1099. to_send_len = StructureSize + (num_aux * AuxSize);
  1100. if (buf_length < to_send_len) {
  1101. return NERR_BufTooSmall;
  1102. }
  1103. numberOfStructureTypes = 2;
  1104. } else {
  1105. to_send_len = StructureSize;
  1106. num_aux = AuxSize = 0;
  1107. numberOfStructureTypes = 1;
  1108. }
  1109. //
  1110. // Set up the data pointer to point past fixed length structures
  1111. //
  1112. data_ptr = send_ptr + to_send_len;
  1113. //
  1114. // Any data pointed to by pointers in the data or aux structures
  1115. // must now be copied into the buffer. Start with the primary data
  1116. // structure.
  1117. //
  1118. l_str = DataDescriptor;
  1119. num_struct = 1; /* Only one primary structure allowed */
  1120. for (i = 0; i < numberOfStructureTypes;
  1121. l_str = AuxDescriptor, num_struct = num_aux, i++) {
  1122. for (j = 0 , l_dsc = l_str; j < num_struct; j++, l_dsc = l_str) {
  1123. for (; (c = *l_dsc) != '\0'; l_dsc++) {
  1124. if (IS_POINTER(c)) {
  1125. ptr = LPBYTE_FROM_POINTER(struct_ptr);
  1126. if (ptr == NULL) {
  1127. if ((*l_dsc == REM_ASCIZ) && OkToModifyDescriptor) {
  1128. #ifdef VR_DIAGNOSE
  1129. DbgPrint("VrpPackSendBuffer: modifying descriptor to REM_NULL_PTR\n");
  1130. #endif
  1131. *l_dsc = REM_NULL_PTR;
  1132. }
  1133. struct_ptr += sizeof(LPBYTE);
  1134. VrpGetArrayLength(l_dsc, &l_dsc);
  1135. } else {
  1136. //
  1137. // If the pointer is NULL or points inside the
  1138. // original send buffer ( may have been reallocated)
  1139. // then NULL it as it is not a field being set OR
  1140. // return an error for a non SetInfo type call as
  1141. // it is illegal to have a pointer into the
  1142. // transport buffer.
  1143. //
  1144. if (RANGE_F(ptr, c_send_buf, c_send_len)) {
  1145. if (SetInfoFlag) {
  1146. SmbPutUlong((LPDWORD)struct_ptr, 0L);
  1147. VrpGetArrayLength(l_dsc, &l_dsc);
  1148. struct_ptr += sizeof(LPSTR);
  1149. } else {
  1150. return ERROR_INVALID_PARAMETER;
  1151. }
  1152. } else {
  1153. switch (c) {
  1154. case REM_ASCIZ:
  1155. len = strlen(ptr) + 1;
  1156. break;
  1157. case REM_SEND_LENBUF:
  1158. len = *(LPWORD)ptr;
  1159. break;
  1160. default:
  1161. len = VrpGetArrayLength(l_dsc, &l_dsc);
  1162. }
  1163. //
  1164. // There is data to be copied into the send
  1165. // buffer so check that it will fit.
  1166. //
  1167. to_send_len += len;
  1168. if (to_send_len > buf_length) {
  1169. buf_length = to_send_len + BUF_INC;
  1170. if (!alloc_flag) {
  1171. //
  1172. // Need new buffer
  1173. //
  1174. send_ptr = (LPBYTE)LocalAlloc(LMEM_FIXED, buf_length);
  1175. if (send_ptr == NULL) {
  1176. return ERROR_NOT_ENOUGH_MEMORY;
  1177. }
  1178. alloc_flag = TRUE;
  1179. //
  1180. // Got new buffer, so copy old buffer
  1181. //
  1182. RtlCopyMemory(send_ptr, c_send_buf, to_send_len - len);
  1183. struct_ptr = send_ptr + (struct_ptr - c_send_buf);
  1184. data_ptr = send_ptr + (data_ptr - c_send_buf);
  1185. } else {
  1186. LPBYTE newPtr;
  1187. newPtr = (LPBYTE)LocalReAlloc(send_ptr, buf_length, LMEM_MOVEABLE);
  1188. if (newPtr == NULL) {
  1189. LocalFree(send_ptr);
  1190. return ERROR_NOT_ENOUGH_MEMORY;
  1191. } else if (newPtr != send_ptr) {
  1192. //
  1193. // fix up the pointers
  1194. //
  1195. data_ptr = newPtr + (data_ptr - send_ptr);
  1196. struct_ptr = newPtr + (struct_ptr - send_ptr);
  1197. send_ptr = newPtr;
  1198. }
  1199. }
  1200. }
  1201. //
  1202. // There is room for new data in buffer so copy
  1203. // it and and update the struct and data ptrs
  1204. //
  1205. RtlCopyMemory(data_ptr, ptr, len);
  1206. data_ptr += len;
  1207. struct_ptr += sizeof(LPBYTE);
  1208. }
  1209. }
  1210. } else {
  1211. //
  1212. // If the descriptor was not a pointer type then step
  1213. // over the corresponding data field.
  1214. //
  1215. struct_ptr += VrpGetFieldSize(l_dsc, &l_dsc);
  1216. }
  1217. }
  1218. }
  1219. }
  1220. *SendBufferPtr = send_ptr;
  1221. //
  1222. // Note that this is potentially incorrect: we are actually returning the
  1223. // size of the structure + dynamic data to be sent, which is probably not
  1224. // the same as the size of the buffer we (re)allocated. This is how it is
  1225. // done in Lanman, so we'll do the same thing until it breaks
  1226. //
  1227. *SendBufLenPtr = to_send_len;
  1228. *SendBufferAllocated = alloc_flag;
  1229. return NERR_Success;
  1230. }