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.

715 lines
20 KiB

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