Source code of Windows XP (NT5)
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.

730 lines
21 KiB

  1. /*++
  2. Copyright (c) 1993-1996 Microsoft Corporation
  3. Module Name:
  4. exchg95.c
  5. Abstract:
  6. Contains routine which packages the request buffer, makes
  7. the NCP request, and unpackages the response buffer.
  8. Author:
  9. Hans Hurvig (hanshu) Aug-1992 Created
  10. Colin Watson (colinw) 19-Dec-1992
  11. Rita Wong (ritaw) 11-Mar-1993 FSCtl version
  12. Felix Wong (t-felixw) 16-Sep-1996 Ported for Win95 OLEDS
  13. Environment:
  14. Revision History:
  15. --*/
  16. #include <procs.h>
  17. #include <nw95.h>
  18. #include <msnwerr.h>
  19. // This controls automatic OEM<->ANSI translation for string parameters
  20. #define DO_OEM_TRANSLATION 1
  21. ULONG
  22. FsToNwControlCode(
  23. ULONG FsControlCode
  24. )
  25. {
  26. switch ( FsControlCode) {
  27. case FSCTL_NWR_NCP_E3H:
  28. return 0X00e3;
  29. case FSCTL_NWR_NCP_E2H:
  30. return 0X00e2;
  31. case FSCTL_NWR_NCP_E1H:
  32. return 0X00e1;
  33. case FSCTL_NWR_NCP_E0H:
  34. return 0X00e0;
  35. default:
  36. return 0xFFFF;
  37. }
  38. }
  39. NTSTATUS
  40. GetFileServerVersionInfo(
  41. HANDLE DeviceHandle,
  42. VERSION_INFO NWFAR *lpVerInfo
  43. )
  44. {
  45. NTSTATUS NtStatus ;
  46. NtStatus = NwlibMakeNcp(
  47. DeviceHandle, // Connection Handle
  48. FSCTL_NWR_NCP_E3H, // Bindery function
  49. 3, // Max request packet size
  50. 130, // Max response packet size
  51. "b|r", // Format string
  52. // === REQUEST ================================
  53. 0x11, // b Get File Server Information
  54. // === REPLY ==================================
  55. lpVerInfo, // r File Version Structure
  56. sizeof(VERSION_INFO)
  57. );
  58. // Convert HI-LO words to LO-HI
  59. // ===========================================================
  60. lpVerInfo->ConnsSupported = wSWAP( lpVerInfo->ConnsSupported );
  61. lpVerInfo->connsInUse = wSWAP( lpVerInfo->connsInUse );
  62. lpVerInfo->maxVolumes = wSWAP( lpVerInfo->maxVolumes );
  63. lpVerInfo->PeakConns = wSWAP( lpVerInfo->PeakConns );
  64. return NtStatus;
  65. }
  66. NTSTATUS
  67. NwlibMakeNcp(
  68. IN HANDLE DeviceHandle,
  69. IN ULONG FsControlCode,
  70. IN ULONG RequestBufferSize,
  71. IN ULONG ResponseBufferSize,
  72. IN PCHAR FormatString,
  73. ... // Arguments to FormatString
  74. )
  75. /*++
  76. Routine Description:
  77. This function converts the input arguments into an NCP request buffer
  78. based on the format specified in FormatString (e.g. takes a word
  79. and writes it in hi-lo format in the request buffer as required by
  80. an NCP).
  81. It then makes the NCP call via the NtFsControlFile API.
  82. The FormatString also specifies how to convert the fields in the
  83. response buffer from the completed NCP call into the output
  84. arguments.
  85. The FormatString takes the form of "xxxx|yyyy" where each 'x'
  86. indicates an input argument to convert from, and each 'y' indicates
  87. an output argument to convert into. The '|' character separates
  88. the input format from the output format specifications.
  89. String parameters are expected to be in ANSI code and are translated to
  90. OEM code before issuing NCP. Reverse translation is done on the way back
  91. Arguments:
  92. DeviceHandle - Supplies a handle to the network file system driver
  93. which will be making the network request. This function
  94. assumes that the handle was opened for synchronouse I/O access.
  95. FsControlCode - Supplies the control code which determines the
  96. NCP.
  97. RequestBufferSize - Supplies the size of the request buffer in
  98. bytes to be allocated by this routine.
  99. ResponseBufferSize - Supplies the size of the response buffer in
  100. bytes to be allocated by this routine.
  101. FormatString - Supplies an ANSI string which describes how to
  102. convert from the input arguments into NCP request fields, and
  103. from the NCP response fields into the output arguments.
  104. Field types, request/response:
  105. 'b' byte ( byte / byte* )
  106. 'w' hi-lo word ( word / word* )
  107. 'd' hi-lo dword ( dword / dword* )
  108. '-' zero/skip byte ( void )
  109. '=' zero/skip word ( void )
  110. ._. zero/skip string ( word )
  111. 'p' pstring ( char* )
  112. 'P' DBCS pstring ( char* )
  113. 'c' cstring ( char* )
  114. 'C' cstring followed skip word ( char*, word )
  115. 'r' raw bytes ( byte*, word )
  116. 'R' DBCS raw bytes ( byte*, word )
  117. 'u' p unicode string ( UNICODE_STRING * )
  118. 'U' p uppercase string( UNICODE_STRING * )
  119. 'W' word n followed by an array of word[n] ( word, word* )
  120. Return Value:
  121. Return code from the NCP call.
  122. --*/
  123. {
  124. NTSTATUS BinderyStatus = STATUS_SUCCESS;
  125. va_list Arguments;
  126. PCHAR z;
  127. WORD t = 1;
  128. ULONG data_size;
  129. LPBYTE RequestBuffer = NULL;
  130. LPBYTE ResponseBuffer;
  131. LPBYTE ScratchBuffer = NULL;
  132. DWORD ReturnedDataSize;
  133. ULONG NwControlCode;
  134. BOOL GetVersionInfo = TRUE;
  135. BOOL DoMapSpecialJapaneseCharThing = TRUE;
  136. VERSION_INFO VerInfo;
  137. if ((NwControlCode = FsToNwControlCode(FsControlCode)) == 0xFFFF)
  138. return STATUS_UNSUCCESSFUL;
  139. //
  140. // Allocate memory for request and response buffers.
  141. //
  142. ScratchBuffer = (LPBYTE)LocalAlloc(
  143. LMEM_ZEROINIT,
  144. RequestBufferSize + ResponseBufferSize+
  145. 2*sizeof(WORD) // We include size fields in packets
  146. );
  147. if (ScratchBuffer == NULL) {
  148. KdPrint(("NWLIB: NwlibMakeNcp LocalAlloc failed %lu\n", GetLastError()));
  149. return STATUS_NO_MEMORY;
  150. }
  151. // First fill size field for request buffer in
  152. *((WORD *)ScratchBuffer) = LOWORD(RequestBufferSize);
  153. RequestBuffer = ScratchBuffer + sizeof(WORD);
  154. // Calculate pointer to response part
  155. ResponseBuffer = (LPBYTE) ((ULONG) RequestBuffer + RequestBufferSize);
  156. *((WORD *)ResponseBuffer) = LOWORD(ResponseBufferSize);
  157. va_start( Arguments, FormatString );
  158. //
  159. // Convert the input arguments into request packet.
  160. //
  161. z = FormatString;
  162. data_size = 0;
  163. while ( *z && *z != '|')
  164. {
  165. switch ( *z )
  166. {
  167. case '=':
  168. RequestBuffer[data_size++] = 0;
  169. case '-':
  170. RequestBuffer[data_size++] = 0;
  171. break;
  172. case '_':
  173. {
  174. WORD l = va_arg ( Arguments, WORD );
  175. if (data_size + l > RequestBufferSize)
  176. {
  177. KdPrint(("NWLIB: NwlibMakeNcp case '_' request buffer too small\n"));
  178. BinderyStatus = STATUS_BUFFER_TOO_SMALL;
  179. goto CleanExit;
  180. }
  181. while ( l-- )
  182. RequestBuffer[data_size++] = 0;
  183. break;
  184. }
  185. case 'b':
  186. RequestBuffer[data_size++] = va_arg ( Arguments, BYTE );
  187. break;
  188. case 'w':
  189. {
  190. WORD w = va_arg ( Arguments, WORD );
  191. RequestBuffer[data_size++] = (BYTE) (w >> 8);
  192. RequestBuffer[data_size++] = (BYTE) (w >> 0);
  193. break;
  194. }
  195. case 'd':
  196. {
  197. DWORD d = va_arg ( Arguments, DWORD );
  198. RequestBuffer[data_size++] = (BYTE) (d >> 24);
  199. RequestBuffer[data_size++] = (BYTE) (d >> 16);
  200. RequestBuffer[data_size++] = (BYTE) (d >> 8);
  201. RequestBuffer[data_size++] = (BYTE) (d >> 0);
  202. break;
  203. }
  204. case 'c':
  205. {
  206. char* c = va_arg ( Arguments, char* );
  207. WORD l = strlen( c );
  208. if (data_size + l > RequestBufferSize)
  209. {
  210. KdPrint(("NWLIB: NwlibMakeNcp case 'c' request buffer too small\n"));
  211. BinderyStatus = STATUS_BUFFER_TOO_SMALL;
  212. goto CleanExit;
  213. }
  214. RtlCopyMemory( &RequestBuffer[data_size], c, l+1 );
  215. #ifdef DO_OEM_TRANSLATION
  216. CharToOemA( (LPCSTR)&RequestBuffer[data_size],(LPSTR)&RequestBuffer[data_size]);
  217. #endif
  218. data_size += l + 1;
  219. break;
  220. }
  221. case 'C':
  222. {
  223. char* c = va_arg ( Arguments, char* );
  224. WORD l = va_arg ( Arguments, WORD );
  225. WORD len = strlen( c ) + 1;
  226. if (data_size + l > RequestBufferSize)
  227. {
  228. KdPrint(("NWLIB: NwlibMakeNcp case 'C' request buffer too small\n"));
  229. BinderyStatus = STATUS_BUFFER_TOO_SMALL;
  230. goto CleanExit;
  231. }
  232. RtlCopyMemory( &RequestBuffer[data_size], c, len > l? l : len);
  233. #ifdef DO_OEM_TRANSLATION
  234. CharToOemBuffA((LPCSTR)&RequestBuffer[data_size], (LPSTR)&RequestBuffer[data_size],l);
  235. #endif
  236. data_size += l;
  237. RequestBuffer[data_size-1] = 0;
  238. break;
  239. }
  240. case 'P':
  241. case 'p':
  242. {
  243. char* c = va_arg ( Arguments, char* );
  244. BYTE l = strlen( c );
  245. char* p;
  246. if (data_size + l > RequestBufferSize)
  247. {
  248. KdPrint(("NWLIB: NwlibMakeNcp case 'p' request buffer too small\n"));
  249. BinderyStatus = STATUS_BUFFER_TOO_SMALL;
  250. goto CleanExit;
  251. }
  252. RequestBuffer[data_size++] = l;
  253. RtlCopyMemory(p=(char*)&RequestBuffer[data_size], c, l );
  254. //
  255. // Map Japanese special chars
  256. //
  257. if (*z == 'P')
  258. {
  259. if ( GetVersionInfo )
  260. {
  261. BinderyStatus = GetFileServerVersionInfo( DeviceHandle,
  262. &VerInfo );
  263. GetVersionInfo = FALSE;
  264. if ( BinderyStatus == STATUS_SUCCESS )
  265. {
  266. if ( VerInfo.Version > 3 )
  267. {
  268. DoMapSpecialJapaneseCharThing = FALSE;
  269. }
  270. }
  271. }
  272. if ( DoMapSpecialJapaneseCharThing )
  273. {
  274. MapSpecialJapaneseChars(p, (WORD)l);
  275. }
  276. }
  277. #ifdef DO_OEM_TRANSLATION
  278. CharToOemBuffA( (LPCSTR)&RequestBuffer[data_size],
  279. (LPSTR)&RequestBuffer[data_size],
  280. l );
  281. #endif
  282. data_size += l;
  283. break;
  284. }
  285. case 'u':
  286. {
  287. PUNICODE_STRING pUString = va_arg ( Arguments, PUNICODE_STRING );
  288. OEM_STRING OemString;
  289. ULONG Length;
  290. //
  291. // Calculate required string length, excluding trailing NUL.
  292. //
  293. Length = RtlUnicodeStringToOemSize( pUString ) - 1;
  294. ASSERT( Length < 0x100 );
  295. if ( data_size + Length > RequestBufferSize ) {
  296. KdPrint(("NWLIB: NwlibMakeNcp case 'u' request buffer too small\n"));
  297. BinderyStatus = STATUS_BUFFER_TOO_SMALL;
  298. goto CleanExit;
  299. }
  300. RequestBuffer[data_size++] = (UCHAR)Length;
  301. OemString.Buffer = &RequestBuffer[data_size];
  302. OemString.MaximumLength = (USHORT)Length + 1;
  303. BinderyStatus = RtlUnicodeStringToOemString( &OemString, pUString, FALSE );
  304. ASSERT( NT_SUCCESS( BinderyStatus ));
  305. data_size += (USHORT)Length;
  306. break;
  307. }
  308. case 'U':
  309. {
  310. //
  311. // UPPERCASE the string, copy it from unicode to the packet
  312. //
  313. PUNICODE_STRING pUString = va_arg ( Arguments, PUNICODE_STRING );
  314. UNICODE_STRING UUppercaseString;
  315. OEM_STRING OemString;
  316. ULONG Length;
  317. BinderyStatus = RtlUpcaseUnicodeString(&UUppercaseString, pUString, TRUE);
  318. if ( BinderyStatus )
  319. {
  320. goto CleanExit;
  321. }
  322. pUString = &UUppercaseString;
  323. //
  324. // Calculate required string length, excluding trailing NUL.
  325. //
  326. Length = RtlUnicodeStringToOemSize( pUString ) - 1;
  327. ASSERT( Length < 0x100 );
  328. if ( data_size + Length > RequestBufferSize ) {
  329. KdPrint(("NWLIB: NwlibMakeNcp case 'U' request buffer too small\n"));
  330. BinderyStatus = STATUS_BUFFER_TOO_SMALL;
  331. goto CleanExit;
  332. }
  333. RequestBuffer[data_size++] = (UCHAR)Length;
  334. OemString.Buffer = &RequestBuffer[data_size];
  335. OemString.MaximumLength = (USHORT)Length + 1;
  336. BinderyStatus = RtlUnicodeStringToOemString( &OemString, pUString, FALSE );
  337. ASSERT( NT_SUCCESS( BinderyStatus ));
  338. RtlFreeUnicodeString( &UUppercaseString );
  339. data_size += (USHORT)Length;
  340. break;
  341. }
  342. case 'R':
  343. case 'r':
  344. {
  345. BYTE* b = va_arg ( Arguments, BYTE* );
  346. WORD l = va_arg ( Arguments, WORD );
  347. char* c;
  348. if ( data_size + l > RequestBufferSize )
  349. {
  350. KdPrint(("NWLIB: NwlibMakeNcp case 'r' request buffer too small\n"));
  351. BinderyStatus = STATUS_BUFFER_TOO_SMALL;
  352. goto CleanExit;
  353. }
  354. RtlCopyMemory( c = (char*)&RequestBuffer[data_size], b, l );
  355. data_size += l;
  356. //
  357. // Map Japanese special chars
  358. //
  359. if (*z == 'R')
  360. {
  361. if ( GetVersionInfo )
  362. {
  363. BinderyStatus = GetFileServerVersionInfo( DeviceHandle,
  364. &VerInfo );
  365. GetVersionInfo = FALSE;
  366. if ( BinderyStatus == STATUS_SUCCESS )
  367. {
  368. if ( VerInfo.Version > 3 )
  369. {
  370. DoMapSpecialJapaneseCharThing = FALSE;
  371. }
  372. }
  373. }
  374. if ( DoMapSpecialJapaneseCharThing )
  375. {
  376. MapSpecialJapaneseChars(c, (WORD)l);
  377. }
  378. }
  379. break;
  380. }
  381. default:
  382. KdPrint(("NWLIB: NwlibMakeNcp invalid request field, %x\n", *z));
  383. ASSERT(FALSE);
  384. }
  385. if ( data_size > RequestBufferSize )
  386. {
  387. KdPrint(("NWLIB: NwlibMakeNcp too much request data\n"));
  388. BinderyStatus = STATUS_BUFFER_TOO_SMALL;
  389. goto CleanExit;
  390. }
  391. z++;
  392. }
  393. // Nb: Function code passed to this call should contain full content
  394. // of AX, while the one which has been passed to us is only AH. So we
  395. // need to add low byte ( default 0)
  396. BinderyStatus = NWConnControlRequest(
  397. VLMToNWREDIRHandle(DeviceHandle),
  398. NwControlCode<<8+0,
  399. ScratchBuffer,
  400. ResponseBuffer);
  401. if (BinderyStatus != NWSC_SUCCESS) {
  402. KdPrint(("NWLIB: NwlibMakeNcp: NtFsControlFile returns x%08lx\n",
  403. BinderyStatus));
  404. goto CleanExit;
  405. }
  406. ReturnedDataSize = *((WORD *)ResponseBuffer);
  407. ResponseBuffer = ResponseBuffer + sizeof(WORD);
  408. //
  409. // Convert the response packet into output arguments.
  410. //
  411. data_size = 0;
  412. if (*z && *z == '|') {
  413. z++;
  414. }
  415. while ( *z )
  416. {
  417. switch ( *z )
  418. {
  419. case '-':
  420. data_size += 1;
  421. break;
  422. case '=':
  423. data_size += 2;
  424. break;
  425. case '_':
  426. {
  427. WORD l = va_arg ( Arguments, WORD );
  428. data_size += l;
  429. break;
  430. }
  431. case 'b':
  432. {
  433. BYTE* b = va_arg ( Arguments, BYTE* );
  434. *b = ResponseBuffer[data_size++];
  435. break;
  436. }
  437. case 'w':
  438. {
  439. BYTE* b = va_arg ( Arguments, BYTE* );
  440. b[1] = ResponseBuffer[data_size++];
  441. b[0] = ResponseBuffer[data_size++];
  442. break;
  443. }
  444. case 'd':
  445. {
  446. BYTE* b = va_arg ( Arguments, BYTE* );
  447. b[3] = ResponseBuffer[data_size++];
  448. b[2] = ResponseBuffer[data_size++];
  449. b[1] = ResponseBuffer[data_size++];
  450. b[0] = ResponseBuffer[data_size++];
  451. break;
  452. }
  453. case 'c':
  454. {
  455. char* c = va_arg ( Arguments, char* );
  456. WORD l = strlen( (LPSTR)&ResponseBuffer[data_size] );
  457. if ( data_size+l+1 < ReturnedDataSize ) {
  458. RtlCopyMemory( c, &ResponseBuffer[data_size], l+1 );
  459. #ifdef DO_OEM_TRANSLATION
  460. OemToCharA(c,c);
  461. #endif
  462. }
  463. data_size += l+1;
  464. break;
  465. }
  466. case 'C':
  467. {
  468. char* c = va_arg ( Arguments, char* );
  469. WORD l = va_arg ( Arguments, WORD );
  470. WORD len = strlen( (LPSTR)&ResponseBuffer[data_size] ) + 1;
  471. if ( data_size + l < ReturnedDataSize ) {
  472. RtlCopyMemory( c, &ResponseBuffer[data_size], len > l ? l :len);
  473. #ifdef DO_OEM_TRANSLATION
  474. OemToCharBuffA(c,c,len > l ? l :len);
  475. #endif
  476. }
  477. c[l-1] = 0;
  478. data_size += l;
  479. break;
  480. }
  481. case 'P':
  482. case 'p':
  483. {
  484. char* c = va_arg ( Arguments, char* );
  485. BYTE l = ResponseBuffer[data_size++];
  486. if ( data_size+l <= ReturnedDataSize ) {
  487. RtlCopyMemory( c, &ResponseBuffer[data_size], l );
  488. #ifdef DO_OEM_TRANSLATION
  489. OemToCharBuffA(c,c,l);
  490. #endif
  491. c[l] = 0;
  492. }
  493. data_size += l;
  494. //
  495. // Unmap Japanese special chars
  496. //
  497. if (*z == 'P')
  498. {
  499. if ( GetVersionInfo )
  500. {
  501. BinderyStatus = GetFileServerVersionInfo( DeviceHandle,
  502. &VerInfo );
  503. GetVersionInfo = FALSE;
  504. if ( BinderyStatus == STATUS_SUCCESS )
  505. {
  506. if ( VerInfo.Version > 3 )
  507. {
  508. DoMapSpecialJapaneseCharThing = FALSE;
  509. }
  510. }
  511. }
  512. if ( DoMapSpecialJapaneseCharThing )
  513. {
  514. UnmapSpecialJapaneseChars(c, l);
  515. }
  516. }
  517. break;
  518. }
  519. case 'R':
  520. case 'r':
  521. {
  522. BYTE* b = va_arg ( Arguments, BYTE* );
  523. WORD l = va_arg ( Arguments, WORD );
  524. RtlCopyMemory( b, &ResponseBuffer[data_size], l );
  525. data_size += l;
  526. //
  527. // Unmap Japanese special chars
  528. //
  529. if (*z == 'R')
  530. {
  531. if ( GetVersionInfo )
  532. {
  533. BinderyStatus = GetFileServerVersionInfo( DeviceHandle,
  534. &VerInfo );
  535. GetVersionInfo = FALSE;
  536. if ( BinderyStatus == STATUS_SUCCESS )
  537. {
  538. if ( VerInfo.Version > 3 )
  539. {
  540. DoMapSpecialJapaneseCharThing = FALSE;
  541. }
  542. }
  543. }
  544. if ( DoMapSpecialJapaneseCharThing )
  545. {
  546. UnmapSpecialJapaneseChars(b, l);
  547. }
  548. }
  549. break;
  550. }
  551. case 'W':
  552. {
  553. BYTE* b = va_arg ( Arguments, BYTE* );
  554. BYTE* w = va_arg ( Arguments, BYTE* );
  555. WORD i;
  556. b[1] = ResponseBuffer[data_size++];
  557. b[0] = ResponseBuffer[data_size++];
  558. for ( i = 0; i < ((WORD) *b); i++, w += sizeof(WORD) )
  559. {
  560. w[1] = ResponseBuffer[data_size++];
  561. w[0] = ResponseBuffer[data_size++];
  562. }
  563. break;
  564. }
  565. default:
  566. KdPrint(("NWLIB: NwlibMakeNcp invalid response field, %x\n", *z));
  567. ASSERT(FALSE);
  568. }
  569. if ( data_size > ReturnedDataSize )
  570. {
  571. KdPrint(("NWLIB: NwlibMakeNcp not enough response data\n"));
  572. BinderyStatus = STATUS_UNSUCCESSFUL;
  573. goto CleanExit;
  574. }
  575. z++;
  576. }
  577. BinderyStatus = STATUS_SUCCESS;
  578. CleanExit:
  579. if (ScratchBuffer != NULL) {
  580. (void) LocalFree((HLOCAL) ScratchBuffer);
  581. }
  582. va_end( Arguments );
  583. return BinderyStatus;
  584. }