Leaked source code of windows server 2003
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.

3476 lines
78 KiB

  1. /*++
  2. Copyright (c) 1993/4 Microsoft Corporation
  3. Module Name:
  4. ncp.c
  5. Abstract:
  6. Contains routine which accepts the bop from a 16 bit
  7. application and processes the request appropriately.
  8. Normally it performes an NCP exchange on behalf of the
  9. application.
  10. Author:
  11. Colin Watson (colinw) 07-Jul-1993
  12. Environment:
  13. Revision History:
  14. --*/
  15. #include "procs.h"
  16. #define BASE_DOS_ERROR ((NTSTATUS )0xC0010000L)
  17. #include <packon.h>
  18. typedef struct _TTSOUTPACKET {
  19. UCHAR SubFunction;
  20. USHORT cx;
  21. USHORT dx;
  22. } TTSOUTPACKET, *PTTSOUTPACKET ;
  23. typedef struct _TTSINPACKET{
  24. USHORT cx;
  25. USHORT dx;
  26. } TTSINPACKET, *PTTSINPACKET;
  27. #include <packoff.h>
  28. VOID
  29. InitDosTable(
  30. PNWDOSTABLE pdt
  31. );
  32. VOID
  33. LoadPreferredServerName(
  34. VOID
  35. );
  36. VOID
  37. ProcessResourceArray(
  38. LPNETRESOURCE NetResource,
  39. DWORD NumElements
  40. );
  41. VOID
  42. ProcessResource(
  43. LPNETRESOURCE NetResource
  44. );
  45. VOID
  46. SendNCP(
  47. ULONG Command
  48. );
  49. VOID
  50. SendF2NCP(
  51. ULONG Command
  52. );
  53. UCHAR
  54. AttachmentControl(
  55. ULONG Command
  56. );
  57. VOID
  58. SendNCP2(
  59. ULONG Command,
  60. PUCHAR Request,
  61. ULONG RequestLength,
  62. PUCHAR Reply,
  63. ULONG ReplyLength
  64. );
  65. VOID
  66. CloseConnection(
  67. CONN_INDEX Connection
  68. );
  69. NTSTATUS
  70. InitConnection(
  71. CONN_INDEX Connection
  72. );
  73. VOID
  74. GetDirectoryHandle(
  75. VOID
  76. );
  77. VOID
  78. LoadDriveHandleTable(
  79. VOID
  80. );
  81. VOID
  82. AllocateDirectoryHandle(
  83. VOID
  84. );
  85. VOID
  86. ResetDrive(
  87. UCHAR Drive
  88. );
  89. VOID
  90. AllocateDirectoryHandle2(
  91. VOID
  92. );
  93. PWCHAR
  94. BuildUNC(
  95. IN PUCHAR aName,
  96. IN ULONG aLength
  97. );
  98. VOID
  99. GetServerDateAndTime(
  100. VOID
  101. );
  102. VOID
  103. GetShellVersion(
  104. IN USHORT Command
  105. );
  106. VOID
  107. TTS(
  108. VOID
  109. );
  110. VOID
  111. OpenCreateFile(
  112. VOID
  113. );
  114. BOOL
  115. IsItNetWare(
  116. PUCHAR Name
  117. );
  118. VOID
  119. SetCompatibility(
  120. VOID
  121. );
  122. VOID
  123. OpenQueueFile(
  124. VOID
  125. );
  126. VOID
  127. AttachHandle(
  128. VOID
  129. );
  130. VOID
  131. ProcessExit(
  132. VOID
  133. );
  134. VOID
  135. SystemLogout(
  136. VOID
  137. );
  138. VOID
  139. ServerFileCopy(
  140. VOID
  141. );
  142. VOID
  143. SetStatus(
  144. NTSTATUS Status
  145. );
  146. //
  147. // The following pointer contains the 32 bit virtual address of where
  148. // the nw16.exe tsr holds the workstation structures.
  149. //
  150. PNWDOSTABLE pNwDosTable;
  151. //
  152. // Global variables used to hold the state for this process
  153. //
  154. UCHAR OriginalPrimary = 0;
  155. HANDLE ServerHandles[MC];
  156. HANDLE Win32DirectoryHandleTable[MD];
  157. PWCHAR Drives[MD]; // Strings such as R: or a unc name
  158. UCHAR SearchDriveTable[16];
  159. BOOLEAN Initialized = FALSE;
  160. BOOLEAN TablesValid = FALSE; // Reload each time a process starts
  161. BOOLEAN DriveHandleTableValid = FALSE; // Reload first time process does NW API
  162. WORD DosTableSegment;
  163. WORD DosTableOffset;
  164. extern UCHAR LockMode;
  165. #if NWDBG
  166. BOOL GotDebugState = FALSE;
  167. extern int DebugCtrl;
  168. #endif
  169. VOID
  170. Nw16Register(
  171. VOID
  172. )
  173. /*++
  174. Routine Description:
  175. This function is called by wow when nw16.sys is loaded.
  176. Arguments:
  177. Return Value:
  178. None.
  179. --*/
  180. {
  181. DWORD status;
  182. HANDLE enumHandle;
  183. LPNETRESOURCE netResource;
  184. DWORD numElements;
  185. DWORD bufferSize;
  186. DWORD dwScope = RESOURCE_CONNECTED;
  187. NwPrint(("Nw16Register\n"));
  188. if ( !Initialized) {
  189. UCHAR CurDir[256];
  190. DosTableSegment = getAX();
  191. DosTableOffset = getDX();
  192. //
  193. // this call always made from Real Mode (hence FALSE for last param)
  194. //
  195. pNwDosTable = (PNWDOSTABLE) GetVDMPointer (
  196. (ULONG)((DosTableSegment << 16)|DosTableOffset),
  197. sizeof(NWDOSTABLE),
  198. FALSE
  199. );
  200. InitDosTable( pNwDosTable );
  201. if ((GetCurrentDirectoryA(sizeof(CurDir)-1, CurDir) >= 2) &&
  202. (CurDir[1] == ':')) {
  203. pNwDosTable->CurrentDrive = tolower(CurDir[0]) - 'a';
  204. }
  205. InitLocks();
  206. }
  207. #if NWDBG
  208. {
  209. WCHAR Value[80];
  210. if (GetEnvironmentVariableW(L"NWDEBUG",
  211. Value,
  212. sizeof(Value)/sizeof(Value[0]) - 1)) {
  213. DebugCtrl = Value[0] - '0';
  214. // 0 Use logfile
  215. // 1 Use debugger
  216. // 2/undefined No debug output
  217. // 4 Use logfile, close on process exit
  218. // 8 Use logfile, verbose, close on process exit
  219. DebugControl( DebugCtrl );
  220. GotDebugState = TRUE; // Don't look again until process exits vdm
  221. }
  222. }
  223. #endif
  224. LoadPreferredServerName();
  225. //
  226. // Attempt to allow for MD drives
  227. //
  228. bufferSize = (MD*sizeof(NETRESOURCE))+1024;
  229. netResource = (LPNETRESOURCE) LocalAlloc(LPTR, bufferSize);
  230. if (netResource == NULL) {
  231. NwPrint(("Nw16Register: LocalAlloc Failed %d\n",GetLastError));
  232. setCF(1);
  233. return;
  234. }
  235. //-----------------------------------//
  236. // Get a handle for a top level enum //
  237. //-----------------------------------//
  238. status = NPOpenEnum(
  239. dwScope,
  240. RESOURCETYPE_DISK,
  241. 0,
  242. NULL,
  243. &enumHandle);
  244. if ( status != WN_SUCCESS) {
  245. NwPrint(("Nw16Register:WNetOpenEnum failed %d\n",status));
  246. //
  247. // If there is an extended error, display it.
  248. //
  249. if (status == WN_EXTENDED_ERROR) {
  250. DisplayExtendedError();
  251. }
  252. goto LoadLocal;
  253. }
  254. // ---- Multi-user code change : Add "while" ----
  255. while ( status == WN_SUCCESS ) {
  256. //-----------------------------//
  257. // Enumerate the disk devices. //
  258. //-----------------------------//
  259. numElements = 0xffffffff;
  260. status = NwEnumConnections(
  261. enumHandle,
  262. &numElements,
  263. netResource,
  264. &bufferSize,
  265. TRUE); // Include implicit connections
  266. if ( status == WN_SUCCESS) {
  267. //----------------------------------------//
  268. // Insert the results in the Nw Dos Table //
  269. //----------------------------------------//
  270. ProcessResourceArray( netResource, numElements);
  271. }
  272. } // end while
  273. if ( status == WN_NO_MORE_ENTRIES ) {
  274. status = WN_SUCCESS;
  275. } else
  276. if ( status != WN_SUCCESS) {
  277. NwPrint(("Nw16Register:NwEnumResource failed %d\n",status));
  278. //
  279. // If there is an extended error, display it.
  280. //
  281. if (status == WN_EXTENDED_ERROR) {
  282. DisplayExtendedError();
  283. }
  284. WNetCloseEnum(enumHandle);
  285. goto LoadLocal;
  286. }
  287. //------------------------------------------//
  288. // Close the EnumHandle & print the results //
  289. //------------------------------------------//
  290. status = NPCloseEnum(enumHandle);
  291. if (status != WN_SUCCESS) {
  292. NwPrint(("Nw16Register:WNetCloseEnum failed %d\n",status));
  293. //
  294. // If there is an extended error, display it.
  295. //
  296. if (status == WN_EXTENDED_ERROR) {
  297. DisplayExtendedError();
  298. }
  299. goto LoadLocal;
  300. }
  301. LoadLocal:
  302. //
  303. // Add the local devices so that NetWare apps don't try to map them
  304. // to remote servers.
  305. //
  306. {
  307. USHORT Drive;
  308. WCHAR DriveString[4];
  309. UINT Type;
  310. DriveString[1] = L':';
  311. DriveString[2] = L'\\';
  312. DriveString[3] = L'\0';
  313. //
  314. // Hardwire A: and B: because hitting the floppy drive with
  315. // GetDriveType takes too long.
  316. //
  317. pNwDosTable->DriveFlagTable[0] = LOCAL_DRIVE;
  318. pNwDosTable->DriveFlagTable[1] = LOCAL_DRIVE;
  319. for (Drive = 2; Drive <= 'Z' - 'A'; Drive++ ) {
  320. if (pNwDosTable->DriveFlagTable[Drive] == 0) {
  321. DriveString[0] = L'A' + Drive;
  322. Type = GetDriveTypeW( DriveString );
  323. //
  324. // 0 means drive type cannot be determined, all others are
  325. // provided by other filesystems.
  326. //
  327. if (Type != 1) {
  328. pNwDosTable->DriveFlagTable[Drive] = LOCAL_DRIVE;
  329. }
  330. }
  331. }
  332. #ifdef NWDBG
  333. for (Drive = 0; Drive < MD; Drive++ ) {
  334. DriveString[0] = L'A' + Drive;
  335. NwPrint(("%c(%d)=%x,",'A' + Drive,
  336. GetDriveTypeW( DriveString ),
  337. pNwDosTable->DriveFlagTable[Drive] ));
  338. if (!((Drive + 1) % 8)) {
  339. NwPrint(("\n",0));
  340. }
  341. }
  342. NwPrint(("\n"));
  343. #endif
  344. }
  345. if ( !Initialized ) {
  346. Initialized = TRUE;
  347. pNwDosTable->PrimaryServer = OriginalPrimary;
  348. }
  349. TablesValid = TRUE;
  350. LocalFree(netResource);
  351. setCF(0);
  352. NwPrint(("Nw16Register: End\n"));
  353. }
  354. VOID
  355. LoadPreferredServerName(
  356. VOID
  357. )
  358. {
  359. //
  360. // If we already have a connection to somewhere then we already have a
  361. // preferred servername of some sort.
  362. //
  363. if (pNwDosTable->ConnectionIdTable[0].ci_InUse == IN_USE) {
  364. return;
  365. }
  366. //
  367. // Load the server name table with the preferred/nearest server.
  368. //
  369. CopyMemory( pNwDosTable->ServerNameTable[0], "*", sizeof("*"));
  370. if (NT_SUCCESS(OpenConnection( 0 ))) {
  371. if( NT_SUCCESS(InitConnection(0)) ) {
  372. //
  373. // Close the handle so that the rdr can be stopped if
  374. // user is not running a netware aware application.
  375. //
  376. CloseConnection(0);
  377. pNwDosTable->PrimaryServer = 1;
  378. return;
  379. }
  380. }
  381. pNwDosTable->PrimaryServer = 0;
  382. }
  383. VOID
  384. ProcessResourceArray(
  385. LPNETRESOURCE NetResource,
  386. DWORD NumElements
  387. )
  388. {
  389. DWORD i;
  390. for (i=0; i<NumElements ;i++ ) {
  391. ProcessResource(&(NetResource[i]));
  392. }
  393. return;
  394. }
  395. VOID
  396. ProcessResource(
  397. LPNETRESOURCE NetResource
  398. )
  399. {
  400. SERVERNAME ServerName;
  401. int ServerNameLength;
  402. int i;
  403. int Connection;
  404. BOOLEAN Found = FALSE;
  405. //
  406. // Extract Server Name from RemoteName, skipping first 2 chars that
  407. // contain backslashes and taking care to handle entries that only
  408. // contain a servername.
  409. //
  410. ServerNameLength = wcslen( NetResource->lpRemoteName );
  411. ASSERT(NetResource->lpRemoteName[0] == '\\');
  412. ASSERT(NetResource->lpRemoteName[1] == '\\');
  413. for (i = 2; i <= ServerNameLength; i++) {
  414. if ((NetResource->lpRemoteName[i] == '\\') ||
  415. (i == ServerNameLength )){
  416. ServerNameLength = i - 2;
  417. WideCharToMultiByte(
  418. CP_OEMCP,
  419. 0,
  420. &NetResource->lpRemoteName[2],
  421. ServerNameLength,
  422. ServerName,
  423. sizeof( ServerName ),
  424. NULL,
  425. NULL );
  426. CharUpperBuffA( ServerName, ServerNameLength );
  427. ZeroMemory( &ServerName[ServerNameLength],
  428. SERVERNAME_LENGTH - ServerNameLength );
  429. break;
  430. }
  431. }
  432. //
  433. // Now try to find ServerName in the connection table. If there are
  434. // more than MC servers in the table already then skip this one.
  435. //
  436. for (Connection = 0; Connection < MC ; Connection++ ) {
  437. if ((pNwDosTable->ConnectionIdTable[Connection].ci_InUse == IN_USE) &&
  438. (!memcmp( pNwDosTable->ServerNameTable[Connection], ServerName, SERVERNAME_LENGTH))) {
  439. Found = TRUE;
  440. break;
  441. }
  442. }
  443. NwPrint(("Nw16ProcessResource Server: %s\n",ServerName));
  444. if ( Found == FALSE ) {
  445. for (Connection = 0; Connection < MC ; Connection++ ) {
  446. if (pNwDosTable->ConnectionIdTable[Connection].ci_InUse == FREE) {
  447. CopyMemory( pNwDosTable->ServerNameTable[Connection],
  448. ServerName,
  449. SERVERNAME_LENGTH);
  450. if ((NT_SUCCESS(OpenConnection( (CONN_INDEX)Connection ))) &&
  451. ( NT_SUCCESS(InitConnection( (CONN_INDEX)Connection ) ))) {
  452. Found = TRUE;
  453. } else {
  454. // Couldn't talk to the server so ignore it.
  455. ZeroMemory( pNwDosTable->ServerNameTable[Connection], SERVERNAME_LENGTH );
  456. }
  457. break; // Escape from for (Connection =...
  458. }
  459. }
  460. }
  461. //
  462. // Build the drive id and drive flag tables. Entries 0 - 25
  463. // are reserved for drives redirected to letters. We use drives
  464. // 26 - 31 for UNC drives.
  465. //
  466. if ( Found == TRUE ) {
  467. DRIVE Drive;
  468. DRIVE NextUncDrive = 26;
  469. if ( NetResource->dwType != RESOURCETYPE_DISK ) {
  470. return;
  471. }
  472. if ( NetResource->lpLocalName != NULL) {
  473. Drive = NetResource->lpLocalName[0] - L'A';
  474. } else {
  475. if ( NextUncDrive < MD ) {
  476. Drive = NextUncDrive++;
  477. } else {
  478. //
  479. // No room in the table for this UNC drive.
  480. //
  481. return;
  482. }
  483. }
  484. //
  485. // We have a drive and a connection. Complete the table
  486. // mappings.
  487. //
  488. pNwDosTable->DriveIdTable[ Drive ] = Connection + 1;
  489. pNwDosTable->DriveFlagTable[ Drive ] = PERMANENT_NETWORK_DRIVE;
  490. }
  491. }
  492. VOID
  493. InitDosTable(
  494. PNWDOSTABLE pdt
  495. )
  496. /*++
  497. Routine Description:
  498. This routine Initializes the NetWare Dos Table to its empty values.
  499. Arguments:
  500. pdt - Supplies the table to be initialized.
  501. Return Value:
  502. None
  503. --*/
  504. {
  505. ZeroMemory( ServerHandles, sizeof(ServerHandles) );
  506. ZeroMemory( Drives, sizeof(Drives) );
  507. ZeroMemory( (PVOID) pdt, sizeof(NWDOSTABLE) );
  508. ZeroMemory( Win32DirectoryHandleTable, sizeof(Win32DirectoryHandleTable) );
  509. FillMemory( SearchDriveTable, sizeof(SearchDriveTable), 0xff );
  510. }
  511. UCHAR CpuInProtectMode;
  512. VOID
  513. Nw16Handler(
  514. VOID
  515. )
  516. /*++
  517. Routine Description:
  518. This function is called by wow when nw16.sys traps an Int and
  519. bop's into 32 bit mode.
  520. Arguments:
  521. Return Value:
  522. None,
  523. --*/
  524. {
  525. USHORT Command;
  526. WORD offset;
  527. //
  528. // get the CPU mode once: the memory references it's required for won't
  529. // change during this call. Cuts down number of calls to getMSW()
  530. //
  531. CpuInProtectMode = IS_PROTECT_MODE();
  532. setCF(0);
  533. if ( TablesValid == FALSE ) {
  534. //
  535. // Load the tables unless the process is exiting.
  536. //
  537. if ((pNwDosTable->SavedAx & 0xff00) != 0x4c00) {
  538. Nw16Register();
  539. }
  540. #if NWDBG
  541. if (GotDebugState == FALSE) {
  542. WCHAR Value[80];
  543. if (GetEnvironmentVariableW(L"NWDEBUG",
  544. Value,
  545. sizeof(Value)/sizeof(Value[0]) - 1)) {
  546. DebugCtrl = Value[0] - '0';
  547. // 0 Use logfile
  548. // 1 Use debugger
  549. // 2/undefined No debug output
  550. // 4 Use logfile, close on process exit
  551. // 8 Use logfile, verbose, close on process exit
  552. DebugControl( DebugCtrl );
  553. }
  554. GotDebugState = TRUE; // Don't look again until process exits vdm
  555. }
  556. #endif
  557. }
  558. //
  559. // Normal AX register is used to get into 32 bit code so get applications
  560. // AX from the shared datastructure.
  561. //
  562. Command = pNwDosTable->SavedAx;
  563. //
  564. // set AX register so that AH gets preserved
  565. //
  566. setAX( Command );
  567. NwPrint(("Nw16Handler process command %x\n", Command ));
  568. VrDumpRealMode16BitRegisters( FALSE );
  569. VrDumpNwData();
  570. switch (Command & 0xff00) {
  571. case 0x3C00:
  572. case 0x3D00:
  573. OpenCreateFile();
  574. break;
  575. case 0x4C00:
  576. ProcessExit(); // Close all handles
  577. goto default_dos_handler; // Let Dos handle rest of processing
  578. break;
  579. case 0x9f00:
  580. OpenQueueFile();
  581. break;
  582. case 0xB300: // Packet Signing
  583. setAL(0); // not supported
  584. break;
  585. case 0xB400:
  586. AttachHandle();
  587. break;
  588. case 0xB500:
  589. switch (Command & 0x00ff) {
  590. case 03:
  591. setAX((WORD)pNwDosTable->TaskModeByte);
  592. break;
  593. case 04:
  594. setES((WORD)(CpuInProtectMode ? pNwDosTable->PmSelector : DosTableSegment));
  595. setBX((WORD)(DosTableOffset + &((PNWDOSTABLE)0)->TaskModeByte));
  596. break;
  597. case 06:
  598. setAX(2);
  599. break;
  600. default:
  601. goto default_dos_handler;
  602. }
  603. break;
  604. case 0xB800: // Capture - Not supported
  605. setAL(0xff);
  606. setCF(1);
  607. break;
  608. case 0xBB00: // Set EOJ status
  609. {
  610. static UCHAR EOJstatus = 1;
  611. setAL(EOJstatus);
  612. EOJstatus = pNwDosTable->SavedAx & 0x00ff;
  613. }
  614. break;
  615. case 0xBC00:
  616. case 0xBD00:
  617. case 0xBE00:
  618. case 0xC200:
  619. case 0xC300:
  620. case 0xC400:
  621. case 0xC500:
  622. case 0xC600:
  623. Locks(Command);
  624. break;
  625. case 0xC700:
  626. TTS();
  627. break;
  628. case 0xCB00:
  629. case 0xCD00:
  630. case 0xCF00:
  631. case 0xD000:
  632. case 0xD100:
  633. case 0xD200:
  634. case 0xD300:
  635. case 0xD400:
  636. case 0xD500:
  637. Locks(Command);
  638. break;
  639. case 0xD700:
  640. SystemLogout();
  641. break;
  642. case 0xDB00:
  643. {
  644. UCHAR Drive;
  645. UCHAR Count = 0;
  646. for (Drive = 0; Drive < MD; Drive++) {
  647. if (pNwDosTable->DriveFlagTable[Drive] == LOCAL_DRIVE ) {
  648. Count++;
  649. }
  650. }
  651. setAL(Count);
  652. }
  653. break;
  654. case 0xDC00: // Get station number
  655. {
  656. CONN_INDEX Connection = SelectConnection();
  657. if (Connection == 0xff) {
  658. setAL(0xff);
  659. setCF(1);
  660. } else {
  661. PCONNECTIONID pConnection =
  662. &pNwDosTable->ConnectionIdTable[Connection];
  663. setAL(pConnection->ci_ConnectionLo);
  664. setAH(pConnection->ci_ConnectionHi);
  665. setCH( (UCHAR)((pConnection->ci_ConnectionHi == 0) ?
  666. pConnection->ci_ConnectionLo / 10 + '0':
  667. 'X'));
  668. setCL((UCHAR)(pConnection->ci_ConnectionLo % 10 + '0'));
  669. }
  670. }
  671. break;
  672. case 0xDD00: // Set NetWare Error mode
  673. {
  674. static UCHAR ErrorMode = 0;
  675. setAL( ErrorMode );
  676. ErrorMode = getDL();
  677. }
  678. break;
  679. case 0xDE00:
  680. {
  681. static UCHAR BroadCastMode = 0;
  682. UCHAR OpCode = getDL();
  683. if ( OpCode < 4) {
  684. BroadCastMode = OpCode;
  685. }
  686. setAL(BroadCastMode);
  687. }
  688. break;
  689. case 0xDF00: // Capture - Not supported
  690. setAL(0xff);
  691. setCF(1);
  692. break;
  693. case 0xE000:
  694. case 0xE100:
  695. case 0xE300:
  696. SendNCP(Command);
  697. break;
  698. case 0xE200:
  699. AllocateDirectoryHandle();
  700. break;
  701. case 0xE700:
  702. GetServerDateAndTime();
  703. break;
  704. case 0xE900:
  705. switch (Command & 0x00ff) {
  706. PUCHAR ptr;
  707. case 0:
  708. GetDirectoryHandle();
  709. break;
  710. case 1:
  711. ptr = GetVDMPointer (
  712. (ULONG)((getDS() << 16)|getDX()),
  713. sizeof(SearchDriveTable),
  714. CpuInProtectMode
  715. );
  716. RtlMoveMemory( ptr, SearchDriveTable, sizeof(SearchDriveTable) );
  717. break;
  718. case 2:
  719. ptr = GetVDMPointer (
  720. (ULONG)((getDS() << 16)|getDX()),
  721. sizeof(SearchDriveTable),
  722. CpuInProtectMode
  723. );
  724. RtlMoveMemory( SearchDriveTable, ptr, sizeof(SearchDriveTable) );
  725. break;
  726. case 5:
  727. AllocateDirectoryHandle2();
  728. break;
  729. case 7:
  730. setAL(0xff); // Drive depth not yet implemented
  731. break;
  732. #ifdef NWDBG
  733. // Debug control
  734. case 0xf0: // Use logfile
  735. case 0xf1: // Use debugger
  736. case 0xf2: // No debug output
  737. DebugControl(Command & 0x000f);
  738. break;
  739. #endif
  740. default:
  741. NwPrint(("Nw16Handler unprocessed interrupt %x\n", pNwDosTable->SavedAx ));
  742. }
  743. break;
  744. case 0xEA00:
  745. GetShellVersion(Command);
  746. break;
  747. case 0xEB00:
  748. case 0xEC00:
  749. case 0xED00:
  750. Locks(Command);
  751. break;
  752. case 0xEF00:
  753. NwPrint(("Nw32: %x\n", pNwDosTable->SavedAx ));
  754. switch (Command & 0xff) {
  755. case 00:
  756. if (DriveHandleTableValid == FALSE) {
  757. LoadDriveHandleTable();
  758. }
  759. offset = (WORD)&((PNWDOSTABLE)0)->DriveHandleTable;
  760. break;
  761. case 01:
  762. offset = (WORD)&((PNWDOSTABLE)0)->DriveFlagTable;
  763. break;
  764. case 02:
  765. offset = (WORD)&((PNWDOSTABLE)0)->DriveIdTable;
  766. break;
  767. case 03:
  768. offset = (WORD)&((PNWDOSTABLE)0)->ConnectionIdTable;
  769. break;
  770. case 04:
  771. offset = (WORD)&((PNWDOSTABLE)0)->ServerNameTable;
  772. break;
  773. default:
  774. goto default_dos_handler;
  775. }
  776. setSI((WORD)(DosTableOffset + offset));
  777. setES((WORD)(CpuInProtectMode ? pNwDosTable->PmSelector : DosTableSegment));
  778. setAL(0);
  779. break;
  780. case 0xF100:
  781. setAL(AttachmentControl(Command));
  782. break;
  783. case 0xF200:
  784. SendF2NCP(Command);
  785. break;
  786. case 0xF300:
  787. ServerFileCopy();
  788. break;
  789. default:
  790. default_dos_handler:
  791. NwPrint(("Nw16Handler unprocessed interrupt %x\n", pNwDosTable->SavedAx ));
  792. //
  793. // if we don't handle this call, we modify the return ip to point to
  794. // code that will restore the stack and jump far into dos
  795. //
  796. setIP((WORD)(getIP() + 3));
  797. }
  798. #if NWDBG
  799. pNwDosTable->SavedAx = getAX();
  800. #endif
  801. VrDumpRealMode16BitRegisters( FALSE );
  802. }
  803. CONN_INDEX
  804. SelectConnection(
  805. VOID
  806. )
  807. /*++
  808. Routine Description:
  809. Pick target connection for current transaction
  810. Arguments:
  811. None
  812. Return Value:
  813. Index into ConnectionIdTable or 0xff,
  814. --*/
  815. {
  816. UCHAR IndexConnection;
  817. if ( pNwDosTable->PreferredServer != 0 ) {
  818. return(pNwDosTable->PreferredServer - 1);
  819. }
  820. // select default server if current drive is mapped by us?
  821. if ( pNwDosTable->PrimaryServer != 0 ) {
  822. return(pNwDosTable->PrimaryServer - 1);
  823. }
  824. // Need to pick another
  825. for (IndexConnection = 0; IndexConnection < MC ; IndexConnection++ ) {
  826. if (pNwDosTable->ConnectionIdTable[IndexConnection].ci_InUse == IN_USE) {
  827. pNwDosTable->PrimaryServer = IndexConnection + 1;
  828. return(pNwDosTable->PrimaryServer - 1);
  829. }
  830. }
  831. // No servers in the table so find the nearest/preferred.
  832. LoadPreferredServerName();
  833. return(pNwDosTable->PrimaryServer - 1);
  834. }
  835. CONN_INDEX
  836. SelectConnectionInCWD(
  837. VOID
  838. )
  839. /*++
  840. Routine Description:
  841. Pick target connection for current transaction. Give preference to
  842. the current working directory.
  843. Arguments:
  844. None
  845. Return Value:
  846. Index into ConnectionIdTable or 0xff,
  847. --*/
  848. {
  849. UCHAR IndexConnection;
  850. CHAR CurDir[256];
  851. USHORT Drive;
  852. // Try to return the connection for CWD first.
  853. if ((GetCurrentDirectoryA(sizeof(CurDir)-1, CurDir) >= 2) &&
  854. (CurDir[1] == ':')) {
  855. Drive = tolower(CurDir[0]) - 'a';
  856. IndexConnection = pNwDosTable->DriveIdTable[ Drive ] - 1 ;
  857. if (pNwDosTable->ConnectionIdTable[IndexConnection].ci_InUse == IN_USE) {
  858. return IndexConnection ;
  859. }
  860. }
  861. if ( pNwDosTable->PreferredServer != 0 ) {
  862. return(pNwDosTable->PreferredServer - 1);
  863. }
  864. if ( pNwDosTable->PrimaryServer != 0 ) {
  865. return(pNwDosTable->PrimaryServer - 1);
  866. }
  867. // Need to pick another
  868. for (IndexConnection = 0; IndexConnection < MC ; IndexConnection++ ) {
  869. if (pNwDosTable->ConnectionIdTable[IndexConnection].ci_InUse == IN_USE) {
  870. pNwDosTable->PrimaryServer = IndexConnection + 1;
  871. return(pNwDosTable->PrimaryServer - 1);
  872. }
  873. }
  874. // No servers in the table so find the nearest/preferred.
  875. LoadPreferredServerName();
  876. return(pNwDosTable->PrimaryServer - 1);
  877. }
  878. VOID
  879. SendNCP(
  880. ULONG Command
  881. )
  882. /*++
  883. Routine Description:
  884. Implement generic Send NCP function.
  885. ASSUMES called from Nw16Handler
  886. Arguments:
  887. Command - Supply the opcode 0xexxx
  888. DS:SI - Supply Request buffer & length
  889. ES:DI - Supply Reply buffer & length
  890. On return AL = Status of operation.
  891. Return Value:
  892. None.
  893. --*/
  894. {
  895. PUCHAR Request, Reply;
  896. ULONG RequestLength, ReplyLength;
  897. UCHAR OpCode;
  898. OpCode = (UCHAR)((Command >> 8) - 0xcc);
  899. Request = GetVDMPointer (
  900. (ULONG)((getDS() << 16)|getSI()),
  901. sizeof(WORD),
  902. CpuInProtectMode
  903. );
  904. Reply = GetVDMPointer (
  905. (ULONG)((getES() << 16)|getDI()),
  906. sizeof(WORD),
  907. CpuInProtectMode
  908. );
  909. RequestLength = *(WORD UNALIGNED*)Request;
  910. ReplyLength = *(WORD UNALIGNED*)Reply;
  911. Request = GetVDMPointer (
  912. (ULONG)((getDS() << 16)|getSI() + sizeof(WORD)),
  913. (USHORT)RequestLength,
  914. CpuInProtectMode
  915. );
  916. Reply = GetVDMPointer (
  917. (ULONG)((getES() << 16)|getDI()) + sizeof(WORD),
  918. (USHORT)ReplyLength,
  919. CpuInProtectMode
  920. );
  921. NwPrint(("SubRequest %x, RequestLength %x\n", Request[0], RequestLength ));
  922. SendNCP2( NWR_ANY_NCP(OpCode ),
  923. Request,
  924. RequestLength,
  925. Reply,
  926. ReplyLength);
  927. }
  928. VOID
  929. SendF2NCP(
  930. ULONG Command
  931. )
  932. /*++
  933. Routine Description:
  934. Implement generic Send NCP function. No length to be inseted by
  935. the redirector in the request buffer.
  936. ASSUMES called from Nw16Handler
  937. Arguments:
  938. Command - Supply the opcode 0xf2xx
  939. DS:SI CX - Supply Request buffer & length
  940. ES:DI DX - Supply Reply buffer & length
  941. On return AL = Status of operation.
  942. Return Value:
  943. None.
  944. --*/
  945. {
  946. PUCHAR Request, Reply;
  947. ULONG RequestLength, ReplyLength;
  948. UCHAR OpCode;
  949. OpCode = (UCHAR)(Command & 0x00ff);
  950. RequestLength = getCX();
  951. ReplyLength = getDX();
  952. Request = GetVDMPointer (
  953. (ULONG)((getDS() << 16)|getSI()),
  954. (USHORT)RequestLength,
  955. CpuInProtectMode
  956. );
  957. Reply = GetVDMPointer (
  958. (ULONG)((getES() << 16)|getDI()),
  959. (USHORT)ReplyLength,
  960. CpuInProtectMode
  961. );
  962. NwPrint(("F2SubRequest %x, RequestLength %x\n", Request[2], RequestLength ));
  963. #if 0
  964. if ((RequestLength != 0) &&
  965. (OpCode == 0x17)) {
  966. if ((Request[2] == 0x17) ||
  967. (Request[2] == 0x18)) {
  968. //
  969. // The request was for an encryption key. Tell the
  970. // application that encryption is not supported.
  971. //
  972. setAL(0xfb);
  973. return;
  974. } else if ((Request[2] == 0x14 ) ||
  975. (Request[2] == 0x3f )) {
  976. //
  977. // Plaintext login or Verify Bindery Object Password.
  978. // Convert to its WNET equivalent version.
  979. //
  980. UCHAR Name[256];
  981. UCHAR Password[256];
  982. UCHAR ServerName[sizeof(SERVERNAME)+3];
  983. PUCHAR tmp;
  984. CONN_INDEX Connection;
  985. NETRESOURCEA Nr;
  986. Connection = SelectConnection();
  987. if ( Connection == 0xff ) {
  988. setAL(0xff);
  989. setCF(1);
  990. return;
  991. }
  992. ZeroMemory( &Nr, sizeof(NETRESOURCE));
  993. ServerName[0] = '\\';
  994. ServerName[1] = '\\';
  995. RtlCopyMemory( ServerName+2, pNwDosTable->ServerNameTable[Connection], sizeof(SERVERNAME) );
  996. ServerName[sizeof(ServerName)-1] = '\0';
  997. Nr.lpRemoteName = ServerName;
  998. Nr.dwType = RESOURCETYPE_DISK;
  999. // point to password length.
  1000. tmp = &Request[6] + Request[5];
  1001. Name[Request[5]] = '\0';
  1002. RtlMoveMemory( Name, &Request[6], Request[5]);
  1003. Password[tmp[0]] = '\0';
  1004. RtlMoveMemory( Password, tmp+1, tmp[0]);
  1005. NwPrint(("Connect to %s as %s password %s\n", ServerName, Name, Password ));
  1006. if (NO_ERROR == WNetAddConnection2A( &Nr, Password, Name, 0)) {
  1007. setAL(0);
  1008. } else {
  1009. setAL(255);
  1010. }
  1011. return;
  1012. }
  1013. }
  1014. #endif
  1015. SendNCP2( NWR_ANY_F2_NCP(OpCode ),
  1016. Request,
  1017. RequestLength,
  1018. Reply,
  1019. ReplyLength);
  1020. }
  1021. VOID
  1022. SendNCP2(
  1023. ULONG Command,
  1024. PUCHAR Request,
  1025. ULONG RequestLength,
  1026. PUCHAR Reply,
  1027. ULONG ReplyLength
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. Pick target connection for current transaction
  1032. This routine effectively opens a handle for each NCP sent. This means that
  1033. we don't keep handles open to servers unnecessarily which would cause
  1034. problems if a user tries to delete the connection or stop the workstation.
  1035. If this causes to much of a load then the fallback is to spin off a thread
  1036. that waits on an event with a timeout and periodically sweeps the
  1037. server handle table removing stale handles. Setting the event would cause
  1038. the thread to exit. Critical sections would need to be added to protect
  1039. handles. Dll Init/exit routine to kill the thread and close the handles
  1040. would also be needed.
  1041. Arguments:
  1042. Command - Supply the opcode
  1043. Request, RequestLength - Supply Request buffer & length
  1044. Reply, ReplyLength - Supply Reply buffer & length
  1045. On return AL = Status of operation.
  1046. Return Value:
  1047. None.
  1048. --*/
  1049. {
  1050. CONN_INDEX Connection = SelectConnection();
  1051. NTSTATUS status;
  1052. IO_STATUS_BLOCK IoStatusBlock;
  1053. HANDLE Handle;
  1054. NwPrint(("Send NCP %x to %d:%s\n", Command, Connection, pNwDosTable->ServerNameTable[Connection] ));
  1055. NwPrint(("RequestLength %x\n", RequestLength ));
  1056. NwPrint(("Reply %x, ReplyLength %x\n", Reply, ReplyLength ));
  1057. if (Connection == 0xff) {
  1058. setAL(0xff);
  1059. setCF(1);
  1060. return;
  1061. };
  1062. if ( ServerHandles[Connection] == NULL ) {
  1063. status = OpenConnection( Connection );
  1064. if (!NT_SUCCESS(status)) {
  1065. SetStatus(status);
  1066. return;
  1067. } else {
  1068. InitConnection( Connection );
  1069. }
  1070. }
  1071. Handle = ServerHandles[Connection];
  1072. //
  1073. // If its a CreateJobandFile NCP then we need to use the handle
  1074. // created through Dos so that the writes go into the spoolfile created
  1075. // by this NCP.
  1076. //
  1077. if (Command == NWR_ANY_F2_NCP(0x17)) {
  1078. if ((Request[2] == 0x68) ||
  1079. (Request[2] == 0x79)) {
  1080. Handle = GET_NT_HANDLE();
  1081. }
  1082. } else if (Command == NWR_ANY_NCP(0x17)) {
  1083. if ((Request[0] == 0x68) ||
  1084. (Request[0] == 0x79)) {
  1085. Handle = GET_NT_HANDLE();
  1086. }
  1087. }
  1088. FormattedDump( Request, RequestLength );
  1089. //
  1090. // Make the NCP request on the appropriate handle
  1091. //
  1092. status = NtFsControlFile(
  1093. Handle,
  1094. NULL,
  1095. NULL,
  1096. NULL,
  1097. &IoStatusBlock,
  1098. Command,
  1099. (PVOID) (Request),
  1100. RequestLength,
  1101. (PVOID) Reply,
  1102. ReplyLength);
  1103. if (NT_SUCCESS(status)) {
  1104. status = IoStatusBlock.Status;
  1105. FormattedDump( Reply, ReplyLength );
  1106. }
  1107. if (!NT_SUCCESS(status)) {
  1108. SetStatus(status);
  1109. setCF(1);
  1110. NwPrint(("NtStatus %x, DosError %x\n", status, getAL() ));
  1111. } else {
  1112. setAL(0);
  1113. }
  1114. }
  1115. NTSTATUS
  1116. OpenConnection(
  1117. CONN_INDEX Connection
  1118. )
  1119. /*++
  1120. Routine Description:
  1121. Open the handle to the redirector to access the specified server.
  1122. Arguments:
  1123. Connection - Supplies the index to use for the handle
  1124. Return Value:
  1125. Status of the operation
  1126. --*/
  1127. {
  1128. NTSTATUS Status;
  1129. IO_STATUS_BLOCK IoStatusBlock;
  1130. OBJECT_ATTRIBUTES ObjectAttributes;
  1131. LPWSTR FullName;
  1132. UCHAR AnsiName[SERVERNAME_LENGTH+sizeof(UCHAR)];
  1133. UNICODE_STRING UServerName;
  1134. OEM_STRING AServerName;
  1135. if ( Connection >= MC) {
  1136. return( BASE_DOS_ERROR + 249 ); // No free connection slots
  1137. }
  1138. if (ServerHandles[Connection] != NULL ) {
  1139. CloseConnection(Connection);
  1140. }
  1141. FullName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
  1142. sizeof( DD_NWFS_DEVICE_NAME_U ) +
  1143. (SERVERNAME_LENGTH + 1) * sizeof(WCHAR)
  1144. );
  1145. if ( FullName == NULL ) {
  1146. return ERROR_NOT_ENOUGH_MEMORY;
  1147. }
  1148. CopyMemory(AnsiName,
  1149. pNwDosTable->ServerNameTable[Connection],
  1150. SERVERNAME_LENGTH);
  1151. AnsiName[SERVERNAME_LENGTH] = '\0';
  1152. RtlInitAnsiString( &AServerName, AnsiName );
  1153. Status = RtlOemStringToUnicodeString( &UServerName,
  1154. &AServerName,
  1155. TRUE);
  1156. if (!NT_SUCCESS(Status)) {
  1157. LocalFree( FullName );
  1158. return(Status);
  1159. }
  1160. wcscpy( FullName, DD_NWFS_DEVICE_NAME_U );
  1161. wcscat( FullName, L"\\");
  1162. wcscat( FullName, UServerName.Buffer );
  1163. RtlFreeUnicodeString(&UServerName);
  1164. RtlInitUnicodeString( &UServerName, FullName );
  1165. InitializeObjectAttributes(
  1166. &ObjectAttributes,
  1167. &UServerName,
  1168. OBJ_CASE_INSENSITIVE,
  1169. NULL,
  1170. NULL
  1171. );
  1172. //
  1173. // Open a handle to the server.
  1174. //
  1175. //
  1176. // Try to login to the nearest server. This is necessary for
  1177. // the real preferred server if there are no redirections to
  1178. // it. The rdr can logout and disconnect. SYSCON doesn't like
  1179. // running from such a server.
  1180. //
  1181. Status = NtOpenFile(
  1182. &ServerHandles[Connection],
  1183. SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  1184. &ObjectAttributes,
  1185. &IoStatusBlock,
  1186. FILE_SHARE_VALID_FLAGS,
  1187. FILE_SYNCHRONOUS_IO_NONALERT
  1188. );
  1189. if ( NT_SUCCESS(Status)) {
  1190. Status = IoStatusBlock.Status;
  1191. }
  1192. if (!NT_SUCCESS(Status)) {
  1193. //
  1194. // Failed to login. Use the non-login method. This allows the
  1195. // app to do a bindery login or query the bindery.
  1196. //
  1197. Status = NtOpenFile(
  1198. &ServerHandles[Connection],
  1199. SYNCHRONIZE,
  1200. &ObjectAttributes,
  1201. &IoStatusBlock,
  1202. FILE_SHARE_VALID_FLAGS,
  1203. FILE_SYNCHRONOUS_IO_NONALERT
  1204. );
  1205. if ( NT_SUCCESS(Status)) {
  1206. Status = IoStatusBlock.Status;
  1207. }
  1208. }
  1209. NwPrint(("Nw16:OpenConnection %d: %wZ status = %08lx\n", Connection, &UServerName, Status));
  1210. LocalFree( FullName );
  1211. if (!NT_SUCCESS(Status)) {
  1212. SetStatus(Status);
  1213. return Status;
  1214. }
  1215. return Status;
  1216. }
  1217. VOID
  1218. CloseConnection(
  1219. CONN_INDEX Connection
  1220. )
  1221. /*++
  1222. Routine Description:
  1223. Close the connection handle
  1224. Arguments:
  1225. Connection - Supplies the index to use for the handle
  1226. Return Value:
  1227. None.
  1228. --*/
  1229. {
  1230. if (ServerHandles[Connection]) {
  1231. NwPrint(("CloseConnection: %d\n",Connection));
  1232. NtClose(ServerHandles[Connection]);
  1233. ServerHandles[Connection] = NULL;
  1234. }
  1235. }
  1236. NTSTATUS
  1237. InitConnection(
  1238. CONN_INDEX Connection
  1239. )
  1240. /*++
  1241. Routine Description:
  1242. Get the connection status from the redirector.
  1243. Arguments:
  1244. Connection - Supplies the index to use for the handle
  1245. Return Value:
  1246. Status of the operation
  1247. --*/
  1248. {
  1249. NTSTATUS Status;
  1250. IO_STATUS_BLOCK IoStatusBlock;
  1251. NWR_GET_CONNECTION_DETAILS Details;
  1252. Status = NtFsControlFile(
  1253. ServerHandles[Connection],
  1254. NULL,
  1255. NULL,
  1256. NULL,
  1257. &IoStatusBlock,
  1258. FSCTL_NWR_GET_CONN_DETAILS,
  1259. NULL,
  1260. 0,
  1261. (PVOID) &Details,
  1262. sizeof(Details));
  1263. if (Status == STATUS_SUCCESS) {
  1264. Status = IoStatusBlock.Status;
  1265. }
  1266. NwPrint(("Nw16:InitConnection: %d status = %08lx\n",Connection, Status));
  1267. if (!NT_SUCCESS(Status)) {
  1268. SetStatus(Status);
  1269. CloseConnection(Connection);
  1270. } else {
  1271. PCONNECTIONID pConnection =
  1272. &pNwDosTable->ConnectionIdTable[Connection];
  1273. pConnection->ci_OrderNo= Details.OrderNumber;
  1274. CopyMemory(pNwDosTable->ServerNameTable[Connection],
  1275. Details.ServerName,
  1276. sizeof(SERVERNAME));
  1277. CopyMemory(pConnection->ci_ServerAddress,
  1278. Details.ServerAddress,
  1279. sizeof(pConnection->ci_ServerAddress));
  1280. pConnection->ci_ConnectionNo= Details.ConnectionNumberLo;
  1281. pConnection->ci_ConnectionLo= Details.ConnectionNumberLo;
  1282. pConnection->ci_ConnectionHi= Details.ConnectionNumberHi;
  1283. pConnection->ci_MajorVersion= Details.MajorVersion;
  1284. pConnection->ci_MinorVersion= Details.MinorVersion;
  1285. pConnection->ci_InUse = IN_USE;
  1286. pConnection->ci_1 = 0;
  1287. pConnection->ci_ConnectionStatus = 2;
  1288. //
  1289. // If this is the preferred conection then record it as special.
  1290. // If this is the first drive then also record it. Usually it gets
  1291. // overwritten by the preferred.
  1292. //
  1293. if (( Details.Preferred ) ||
  1294. ( OriginalPrimary == 0 )) {
  1295. NwPrint(("Nw16InitConnection: Primary Connection is %d\n", Connection+1));
  1296. pNwDosTable->PrimaryServer = OriginalPrimary = (UCHAR)Connection + 1;
  1297. }
  1298. setAL(0);
  1299. }
  1300. return Status;
  1301. }
  1302. VOID
  1303. GetDirectoryHandle(
  1304. VOID
  1305. )
  1306. /*++
  1307. Routine Description:
  1308. Obtain a NetWare handle for the current directory.
  1309. If a NetWare handle is assigned then the Win32 handle created for
  1310. the directory handle is kept open. When the process exits, the Win32
  1311. handle will close. When all the Win32 handles from this process are
  1312. closed an endjob NCP will be sent freeing the directory handle on the
  1313. server.
  1314. Arguments:
  1315. DX supplies the drive.
  1316. AL returns the handle.
  1317. AH returns the status flags.
  1318. Return Value:
  1319. None.
  1320. --*/
  1321. {
  1322. USHORT Drive = getDX();
  1323. NwPrint(("Nw32:GetDirectoryHandle %c: ", 'A' + Drive));
  1324. GetDirectoryHandle2( Drive );
  1325. setAL(pNwDosTable->DriveHandleTable[Drive]);
  1326. setAH(pNwDosTable->DriveFlagTable[Drive]);
  1327. NwPrint(("Handle = %x, Flags =%x\n", pNwDosTable->DriveHandleTable[Drive],
  1328. pNwDosTable->DriveFlagTable[Drive] ));
  1329. }
  1330. ULONG
  1331. GetDirectoryHandle2(
  1332. DWORD Drive
  1333. )
  1334. /*++
  1335. Routine Description:
  1336. Obtain a NetWare handle for the current directory.
  1337. If a NetWare handle is assigned then the Win32 handle created for
  1338. the directory handle is kept open. When the process exits, the Win32
  1339. handle will close. When all the Win32 handles from this process are
  1340. closed an endjob NCP will be sent freeing the directory handle on the
  1341. server.
  1342. Note: Updates DriveHandleTable.
  1343. Arguments:
  1344. Drive supplies the drive index (0 = a:).
  1345. Return Value:
  1346. returns the handle.
  1347. --*/
  1348. {
  1349. DWORD BytesReturned;
  1350. if (Drive >= MD) {
  1351. setAL( 0x98 ); // Volume does not exist
  1352. return 0xffffffff;
  1353. }
  1354. NwPrint(("Nw32:GetDirectoryHandle2 %c:\n", 'A' + Drive));
  1355. //
  1356. // If we don't have a handle and its either a temporary or
  1357. // permanent drive then create it.
  1358. //
  1359. if (( Win32DirectoryHandleTable[Drive] == 0 ) &&
  1360. ( (pNwDosTable->DriveFlagTable[Drive] & 3) != 0 )){
  1361. WCHAR DriveString[4];
  1362. PWCHAR Name;
  1363. //
  1364. // We don't have a handle for this drive.
  1365. // Open an NT handle to the current directory and
  1366. // ask the redirector for a NetWare directory handle.
  1367. //
  1368. if (Drive <= ('Z' - 'A')) {
  1369. DriveString[0] = L'A' + (WCHAR)Drive;
  1370. DriveString[1] = L':';
  1371. DriveString[2] = L'.';
  1372. DriveString[3] = L'\0';
  1373. Name = DriveString;
  1374. } else {
  1375. Name = Drives[Drive];
  1376. if( Name == NULL ) {
  1377. NwPrint(("\nNw32:GetDirectoryHandle2 Drive not mapped\n",0));
  1378. return 0xffffffff;
  1379. }
  1380. }
  1381. Win32DirectoryHandleTable[Drive] =
  1382. CreateFileW( Name,
  1383. 0,
  1384. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1385. NULL,
  1386. OPEN_EXISTING,
  1387. FILE_FLAG_BACKUP_SEMANTICS,
  1388. 0);
  1389. if (Win32DirectoryHandleTable[Drive] != INVALID_HANDLE_VALUE) {
  1390. if ( DeviceIoControl(
  1391. Win32DirectoryHandleTable[Drive],
  1392. IOCTL_NWR_RAW_HANDLE,
  1393. NULL,
  1394. 0,
  1395. (PUCHAR)&pNwDosTable->DriveHandleTable[Drive],
  1396. sizeof(pNwDosTable->DriveHandleTable[Drive]),
  1397. &BytesReturned,
  1398. NULL ) == FALSE ) {
  1399. NwPrint(("\nNw32:GetDirectoryHandle2 DeviceIoControl %x\n", GetLastError()));
  1400. CloseHandle( Win32DirectoryHandleTable[Drive] );
  1401. Win32DirectoryHandleTable[Drive] = 0;
  1402. return 0xffffffff;
  1403. } else {
  1404. ASSERT( BytesReturned == sizeof(pNwDosTable->DriveHandleTable[Drive]));
  1405. NwPrint(("\nNw32:GetDirectoryHandle2 Success %x\n", pNwDosTable->DriveHandleTable[Drive]));
  1406. }
  1407. } else {
  1408. NwPrint(("\nNw32:GetDirectoryHandle2 CreateFile %x\n", GetLastError()));
  1409. Win32DirectoryHandleTable[Drive] = 0;
  1410. return 0xffffffff;
  1411. }
  1412. }
  1413. return (ULONG)pNwDosTable->DriveHandleTable[Drive];
  1414. }
  1415. VOID
  1416. LoadDriveHandleTable(
  1417. VOID
  1418. )
  1419. /*++
  1420. Routine Description:
  1421. Open handles to all the NetWare drives
  1422. Arguments:
  1423. none.
  1424. Return Value:
  1425. none.
  1426. --*/
  1427. {
  1428. USHORT Drive;
  1429. for (Drive = 0; Drive < MD; Drive++ ) {
  1430. GetDirectoryHandle2(Drive);
  1431. }
  1432. DriveHandleTableValid = TRUE;
  1433. }
  1434. VOID
  1435. AllocateDirectoryHandle(
  1436. VOID
  1437. )
  1438. /*++
  1439. Routine Description:
  1440. Allocate permanent or temporary handle for drive.
  1441. For a permanent handle, we map this to a "net use".
  1442. ASSUMES called from Nw16Handler
  1443. Arguments:
  1444. DS:SI supplies the request.
  1445. ES:DI supplies the response.
  1446. AL returns the completion code.
  1447. Return Value:
  1448. None.
  1449. --*/
  1450. {
  1451. PUCHAR Request=GetVDMPointer (
  1452. (ULONG)((getDS() << 16)|getSI()),
  1453. 2,
  1454. CpuInProtectMode
  1455. );
  1456. PUCHAR Reply = GetVDMPointer (
  1457. (ULONG)((getES() << 16)|getDI()),
  1458. 4,
  1459. CpuInProtectMode
  1460. );
  1461. USHORT RequestLength = *(USHORT UNALIGNED *)( Request );
  1462. Request=GetVDMPointer (
  1463. (ULONG)((getDS() << 16)|getSI()),
  1464. RequestLength+2,
  1465. CpuInProtectMode
  1466. );
  1467. FormattedDump( Request, RequestLength+2 );
  1468. if (( Request[2] == 0x12) ||
  1469. ( Request[2] == 0x13)) {
  1470. // do temp drives need different handling?
  1471. UCHAR Drive = Request[4] - 'A';
  1472. if (Drive >= MD) {
  1473. setAL( 0x98 ); // Volume does not exist
  1474. return;
  1475. }
  1476. if (pNwDosTable->DriveHandleTable[Drive] != 0) {
  1477. NwPrint(("Nw32: Move directory handle %d\n", Drive));
  1478. //
  1479. // We already have a directory handle assigned for this
  1480. // process. Ask the server to point the handle at the requested
  1481. // position.
  1482. //
  1483. SendNCP2(FSCTL_NWR_NCP_E2H, Request+2, RequestLength, Reply+2, 2);
  1484. if (getAL() == 0) {
  1485. // Record the new handle.
  1486. pNwDosTable->DriveIdTable[ Drive ] = SelectConnection()+1;
  1487. if (Request[2] == 0x12) {
  1488. pNwDosTable->DriveFlagTable[ Drive ] =
  1489. PERMANENT_NETWORK_DRIVE;
  1490. } else {
  1491. pNwDosTable->DriveFlagTable[ Drive ] =
  1492. TEMPORARY_NETWORK_DRIVE;
  1493. }
  1494. pNwDosTable->DriveHandleTable[Drive] = Reply[2];
  1495. NwPrint(("Nw32: Move directory handle -> %x\n", Reply[2]));
  1496. }
  1497. } else {
  1498. NETRESOURCE Nr;
  1499. WCHAR DriveString[3];
  1500. ULONG Handle;
  1501. if (Request[2] == 0x12) {
  1502. NwPrint(("Nw32: Allocate permanent directory handle %d\n", Drive));
  1503. } else {
  1504. NwPrint(("Nw32: Allocate temporary directory handle %d\n", Drive));
  1505. }
  1506. if (Drives[Drive] != NULL) {
  1507. // Tidy up the old name for this drive.
  1508. LocalFree( Drives[Drive] );
  1509. Drives[Drive] = NULL;
  1510. }
  1511. DriveString[0] = L'A' + Drive; // A through Z
  1512. DriveString[1] = L':';
  1513. DriveString[2] = L'\0';
  1514. //
  1515. // This is effectively a net use!
  1516. //
  1517. ZeroMemory( &Nr, sizeof(NETRESOURCE));
  1518. Nr.lpRemoteName = BuildUNC(&Request[6], Request[5]);
  1519. Nr.dwType = RESOURCETYPE_DISK;
  1520. // Save where this drive points.
  1521. Drives[Drive] = Nr.lpRemoteName;
  1522. if (DriveString[0] <= L'Z') {
  1523. Nr.lpLocalName = DriveString;
  1524. if (NO_ERROR != WNetAddConnection2W( &Nr, NULL, NULL, 0)) {
  1525. NwPrint(("Nw32: Allocate ->%d\n", GetLastError()));
  1526. setAL(0x98); // Volume does not exist
  1527. return;
  1528. }
  1529. }
  1530. if (Request[2] == 0x12) {
  1531. pNwDosTable->DriveFlagTable[ Drive ] =
  1532. PERMANENT_NETWORK_DRIVE;
  1533. } else {
  1534. pNwDosTable->DriveFlagTable[ Drive ] =
  1535. TEMPORARY_NETWORK_DRIVE;
  1536. }
  1537. Handle = GetDirectoryHandle2( Drive );
  1538. if (Handle == 0xffffffff) {
  1539. if (DriveString[0] <= L'Z') {
  1540. WNetCancelConnection2W( DriveString, 0, TRUE);
  1541. }
  1542. ResetDrive( Drive );
  1543. setAL(0x9c); // Invalid path
  1544. } else {
  1545. //
  1546. // We have a drive and a connection. Complete the table
  1547. // mappings.
  1548. //
  1549. pNwDosTable->DriveIdTable[ Drive ] = SelectConnection()+1;
  1550. Reply[2] = (UCHAR)(Handle & 0xff);
  1551. Reply[3] = (UCHAR)(0xff); //should be effective rights
  1552. setAL(0); // Successful
  1553. }
  1554. }
  1555. } else if ( Request[2] == 0x14 ) {
  1556. UCHAR DirHandle = Request[3];
  1557. UCHAR Drive;
  1558. CONN_INDEX Connection = SelectConnection();
  1559. NwPrint(("Nw32: Deallocate directory handle %d on Connection %d\n", DirHandle, Connection));
  1560. for (Drive = 0; Drive < MD; Drive++) {
  1561. NwPrint(("Nw32: Drive %c: is DirHandle %d, Connection %d\n",
  1562. 'A' + Drive,
  1563. pNwDosTable->DriveHandleTable[Drive],
  1564. pNwDosTable->DriveIdTable[ Drive ]-1 ));
  1565. if ((pNwDosTable->DriveHandleTable[Drive] == DirHandle) &&
  1566. (pNwDosTable->DriveIdTable[ Drive ] == Connection+1)) {
  1567. //
  1568. // This is effectively a net use del!
  1569. //
  1570. NwPrint(("Nw32: Deallocate directory handle %c\n", 'A' + Drive));
  1571. ResetDrive(Drive);
  1572. setAL(0);
  1573. return;
  1574. }
  1575. }
  1576. setAL(0x9b); // Bad directory handle
  1577. return;
  1578. } else {
  1579. SendNCP(pNwDosTable->SavedAx);
  1580. }
  1581. FormattedDump( Reply, Reply[0] );
  1582. }
  1583. VOID
  1584. ResetDrive(
  1585. UCHAR Drive
  1586. )
  1587. /*++
  1588. Routine Description:
  1589. Do a net use del
  1590. Arguments:
  1591. Drive - Supplies the target drive.
  1592. Return Value:
  1593. None.
  1594. --*/
  1595. {
  1596. NwPrint(("Nw32: Reset Drive %c:\n", 'A' + Drive ));
  1597. if ((pNwDosTable->DriveFlagTable[ Drive ] &
  1598. ( PERMANENT_NETWORK_DRIVE | TEMPORARY_NETWORK_DRIVE )) == 0) {
  1599. return;
  1600. }
  1601. if (Win32DirectoryHandleTable[Drive] != 0) {
  1602. CloseHandle( Win32DirectoryHandleTable[Drive] );
  1603. Win32DirectoryHandleTable[Drive] = 0;
  1604. }
  1605. if (Drive <= (L'Z' - L'A')) {
  1606. DWORD WStatus;
  1607. WCHAR DriveString[3];
  1608. DriveString[0] = L'A' + Drive;
  1609. DriveString[1] = L':';
  1610. DriveString[2] = L'\0';
  1611. WStatus = WNetCancelConnection2W( DriveString, 0, TRUE);
  1612. if( WStatus != NO_ERROR ) {
  1613. NwPrint(("Nw32: WNetCancelConnection2W failed %d\n", WStatus ));
  1614. }
  1615. }
  1616. // Turn off flags that show this drive as redirected
  1617. pNwDosTable->DriveFlagTable[ Drive ] &=
  1618. ~( PERMANENT_NETWORK_DRIVE | TEMPORARY_NETWORK_DRIVE );
  1619. pNwDosTable->DriveHandleTable[Drive] = 0;
  1620. }
  1621. VOID
  1622. AllocateDirectoryHandle2(
  1623. VOID
  1624. )
  1625. /*++
  1626. Routine Description:
  1627. Allocate root drive
  1628. ASSUMES called from Nw16Handler
  1629. Arguments:
  1630. BL supplies drive to map.
  1631. DS:DX supplies the pathname
  1632. AL returns the completion code.
  1633. Return Value:
  1634. None.
  1635. --*/
  1636. {
  1637. UCHAR Drive = getBL()-1;
  1638. PUCHAR Name=GetVDMPointer (
  1639. (ULONG)((getDS() << 16)|getDX()),
  1640. 256, // longest valid path
  1641. CpuInProtectMode
  1642. );
  1643. NETRESOURCE Nr;
  1644. WCHAR DriveString[3];
  1645. ULONG Handle;
  1646. NwPrint(("Nw32: e905 map drive %c to %s\n", Drive + 'A', Name ));
  1647. if (Drive >= MD) {
  1648. setAL( 0x98 ); // Volume does not exist
  1649. setCF(1);
  1650. return;
  1651. }
  1652. if (pNwDosTable->DriveHandleTable[Drive] != 0) {
  1653. NwPrint(("Nw32: Drive already redirected\n"));
  1654. ResetDrive(Drive);
  1655. }
  1656. NwPrint(("Nw32: Allocate permanent directory handle\n"));
  1657. if (Drives[Drive] != NULL) {
  1658. // Tidy up the old name for this drive.
  1659. LocalFree( Drives[Drive] );
  1660. Drives[Drive] = NULL;
  1661. }
  1662. //
  1663. // This is effectively a net use!
  1664. //
  1665. ZeroMemory( &Nr, sizeof(NETRESOURCE));
  1666. Nr.lpRemoteName = BuildUNC( Name, strlen(Name));
  1667. // Save where this drive points.
  1668. Drives[Drive] = Nr.lpRemoteName;
  1669. if (Drive <= (L'Z' - L'A')) {
  1670. DriveString[0] = L'A' + Drive; // A through Z
  1671. DriveString[1] = L':';
  1672. DriveString[2] = L'\0';
  1673. Nr.lpLocalName = DriveString;
  1674. Nr.dwType = RESOURCETYPE_DISK;
  1675. if (NO_ERROR != WNetAddConnection2W( &Nr, NULL, NULL, 0)) {
  1676. NwPrint(("Nw32: Allocate0 ->%d\n", GetLastError()));
  1677. if (GetLastError() == ERROR_ALREADY_ASSIGNED) {
  1678. WNetCancelConnection2W( DriveString, 0, TRUE);
  1679. if (NO_ERROR != WNetAddConnection2W( &Nr, NULL, NULL, 0)) {
  1680. NwPrint(("Nw32: Allocate1 ->%d\n", GetLastError()));
  1681. ResetDrive( Drive );
  1682. setAL(0x03); // Volume does not exist
  1683. setCF(1);
  1684. return;
  1685. }
  1686. } else {
  1687. NwPrint(("Nw32: Allocate2 ->%d\n", GetLastError()));
  1688. ResetDrive( Drive );
  1689. setAL(0x03); // Volume does not exist
  1690. setCF(1);
  1691. return;
  1692. }
  1693. }
  1694. }
  1695. //
  1696. // Set flags so that GetDirectory2 will open handle
  1697. //
  1698. pNwDosTable->DriveIdTable[ Drive ] = SelectConnection()+1;
  1699. pNwDosTable->DriveFlagTable[ Drive ] = PERMANENT_NETWORK_DRIVE;
  1700. Handle = GetDirectoryHandle2( Drive );
  1701. if (Handle == 0xffffffff) {
  1702. ResetDrive( Drive );
  1703. setAL(0x03); // Invalid path
  1704. setCF(1);
  1705. } else {
  1706. setAL(0); // Successful
  1707. }
  1708. NwPrint(("Nw32: Returning %x\n",getAL()));
  1709. }
  1710. PWCHAR
  1711. BuildUNC(
  1712. IN PUCHAR aName,
  1713. IN ULONG aLength
  1714. )
  1715. /*++
  1716. Routine Description:
  1717. This routine takes the ansi name, prepends the appropriate server name
  1718. (if appropriate) and converts to Unicode.
  1719. Arguments:
  1720. IN aName - Supplies the ansi name.
  1721. IN aLength - Supplies the ansi name length in bytes.
  1722. Return Value:
  1723. Unicode string
  1724. --*/
  1725. {
  1726. UNICODE_STRING Name;
  1727. UCHAR ServerName[sizeof(SERVERNAME)+1];
  1728. CONN_INDEX Connection;
  1729. ANSI_STRING TempAnsi;
  1730. UNICODE_STRING TempUnicode;
  1731. USHORT x;
  1732. // conversion rules for aName to Name are:
  1733. // foo: "\\server\foo\"
  1734. // foo:bar\baz "\\server\foo\bar\baz"
  1735. // foo:\bar\baz "\\server\foo\bar\baz"
  1736. #ifdef NWDBG
  1737. TempAnsi.Buffer = aName;
  1738. TempAnsi.Length = (USHORT)aLength;
  1739. TempAnsi.MaximumLength = (USHORT)aLength;
  1740. NwPrint(("Nw32: BuildUNC %Z\n", &TempAnsi));
  1741. #endif
  1742. Connection = SelectConnection();
  1743. if ( Connection == 0xff ) {
  1744. return NULL;
  1745. }
  1746. Name.MaximumLength = (USHORT)(aLength + sizeof(SERVERNAME) + 5) * sizeof(WCHAR);
  1747. Name.Buffer = (PWSTR)LocalAlloc( LMEM_FIXED, (ULONG)Name.MaximumLength);
  1748. if (Name.Buffer == NULL) {
  1749. return NULL;
  1750. }
  1751. Name.Length = 4;
  1752. Name.Buffer[0] = L'\\';
  1753. Name.Buffer[1] = L'\\';
  1754. //
  1755. // Be careful because ServerName might be 48 bytes long and therefore
  1756. // not null terminated.
  1757. //
  1758. RtlCopyMemory( ServerName, pNwDosTable->ServerNameTable[Connection], sizeof(SERVERNAME) );
  1759. ServerName[sizeof(ServerName)-1] = '\0';
  1760. RtlInitAnsiString( &TempAnsi, ServerName );
  1761. RtlAnsiStringToUnicodeString( &TempUnicode, &TempAnsi, TRUE);
  1762. RtlAppendUnicodeStringToString( &Name, &TempUnicode );
  1763. RtlFreeUnicodeString( &TempUnicode );
  1764. // Now pack servername to volume seperator if necessary.
  1765. if ((aLength != 0) &&
  1766. (aName[0] != '\\')) {
  1767. RtlAppendUnicodeToString( &Name, L"\\");
  1768. }
  1769. // aName might not be null terminated so be careful creating TempAnsi
  1770. TempAnsi.Buffer = aName;
  1771. TempAnsi.Length = (USHORT)aLength;
  1772. TempAnsi.MaximumLength = (USHORT)aLength;
  1773. if (!NT_SUCCESS(RtlAnsiStringToUnicodeString( &TempUnicode, &TempAnsi, TRUE))) {
  1774. LocalFree( Name.Buffer );
  1775. return NULL;
  1776. }
  1777. RtlAppendUnicodeStringToString( &Name, &TempUnicode );
  1778. // If the name already has a volume seperator then don't add another.
  1779. for (x=0; x < (Name.Length/sizeof(WCHAR)) ; x++ ) {
  1780. if (Name.Buffer[x] == L':') {
  1781. // Strip the colon if it is immediately followed by a backslash
  1782. if (((Name.Length/sizeof(WCHAR))-1 > x) &&
  1783. (Name.Buffer[x+1] == L'\\')) {
  1784. RtlMoveMemory( &Name.Buffer[x],
  1785. &Name.Buffer[x+1],
  1786. Name.Length - ((x + 1) * sizeof(WCHAR)));
  1787. Name.Length -= sizeof(WCHAR);
  1788. } else {
  1789. // Replace the colon with a backslash
  1790. Name.Buffer[x] = L'\\';
  1791. }
  1792. goto skip;
  1793. }
  1794. }
  1795. skip:
  1796. RtlFreeUnicodeString( &TempUnicode );
  1797. // Strip trailing backslash if present.
  1798. if ((Name.Length >= sizeof(WCHAR) ) &&
  1799. (Name.Buffer[(Name.Length/sizeof(WCHAR)) - 1 ] == L'\\')) {
  1800. Name.Length -= sizeof(WCHAR);
  1801. }
  1802. // Return pointer to a null terminated wide char string.
  1803. Name.Buffer[Name.Length/sizeof(WCHAR)] = L'\0';
  1804. NwPrint(("Nw32: BuildUNC %ws\n", Name.Buffer));
  1805. return Name.Buffer;
  1806. }
  1807. VOID
  1808. GetServerDateAndTime(
  1809. VOID
  1810. )
  1811. /*++
  1812. Routine Description:
  1813. Implement Funtion E7h
  1814. ASSUMES called from Nw16Handler
  1815. Arguments:
  1816. none.
  1817. Return Value:
  1818. none.
  1819. --*/
  1820. {
  1821. PUCHAR Reply = GetVDMPointer (
  1822. (ULONG)((getDS() << 16)|getDX()),
  1823. 7,
  1824. CpuInProtectMode
  1825. );
  1826. SendNCP2( NWR_ANY_NCP(0x14), NULL, 0, Reply, 7 );
  1827. }
  1828. VOID
  1829. GetShellVersion(
  1830. IN USHORT Command
  1831. )
  1832. /*++
  1833. Routine Description:
  1834. Get the environment variables. Needs to be configurable for
  1835. Japanese machines.
  1836. Arguments:
  1837. Command supplies the callers AX.
  1838. Return Value:
  1839. none.
  1840. --*/
  1841. {
  1842. setAX(0); // MSDOS, PC
  1843. setBX(0x031a); // Shell version
  1844. setCX(0);
  1845. if ( (Command & 0x00ff) != 0) {
  1846. LONG tmp;
  1847. HKEY Key = NULL;
  1848. HINSTANCE hInst;
  1849. int retval;
  1850. PUCHAR Reply = GetVDMPointer (
  1851. (ULONG)((getES() << 16)|getDI()),
  1852. 40,
  1853. CpuInProtectMode
  1854. );
  1855. if ( Reply == NULL ) {
  1856. return;
  1857. }
  1858. hInst = GetModuleHandleA( "nwapi16.dll" );
  1859. if (hInst == NULL) {
  1860. return;
  1861. }
  1862. retval = LoadStringA( hInst, IsNEC_98 ? IDS_CLIENT_ID_STRING_NEC98 : IDS_CLIENT_ID_STRING, Reply, 40 );
  1863. //
  1864. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  1865. // \NWCWorkstation\Parameters
  1866. //
  1867. tmp = RegOpenKeyExW(
  1868. HKEY_LOCAL_MACHINE,
  1869. NW_WORKSTATION_REGKEY,
  1870. REG_OPTION_NON_VOLATILE, // options
  1871. KEY_READ, // desired access
  1872. &Key
  1873. );
  1874. if (tmp != ERROR_SUCCESS) {
  1875. return;
  1876. }
  1877. tmp = 40; // Max size for the string.
  1878. RegQueryValueExA(
  1879. Key,
  1880. "ShellVersion",
  1881. NULL,
  1882. NULL,
  1883. Reply,
  1884. &tmp);
  1885. ASSERT( tmp <= 40 );
  1886. RegCloseKey( Key );
  1887. }
  1888. }
  1889. #include <packon.h>
  1890. typedef struct _TTSOUTPACKETTYPE {
  1891. UCHAR SubFunction;
  1892. USHORT cx;
  1893. USHORT dx;
  1894. } TTSOUTPACKETTYPE;
  1895. typedef struct _TTSINPACKETTYPE {
  1896. USHORT cx;
  1897. USHORT dx;
  1898. } TTSINPACKETTYPE;
  1899. #include <packoff.h>
  1900. VOID
  1901. TTS(
  1902. VOID
  1903. )
  1904. /*++
  1905. Routine Description:
  1906. Transaction Tracking System
  1907. Arguments:
  1908. none.
  1909. Return Value:
  1910. none.
  1911. --*/
  1912. {
  1913. UCHAR bOutput;
  1914. UCHAR bInput[2];
  1915. TTSINPACKET TTsInPacket;
  1916. TTSOUTPACKET TTsOutPacket;
  1917. switch ( pNwDosTable->SavedAx & 0x00ff )
  1918. {
  1919. case 2:
  1920. // NCP Tts Available
  1921. bOutput = 0;
  1922. SendNCP2( NWR_ANY_F2_NCP(0x22), &bOutput, sizeof(UCHAR), NULL, 0);
  1923. if (getAL() == 0xFF) {
  1924. setAL(01);
  1925. }
  1926. break;
  1927. case 0:
  1928. // NCP Tts Begin/Abort
  1929. bOutput = 1;
  1930. SendNCP2( NWR_ANY_F2_NCP(0x22), &bOutput, sizeof(UCHAR), NULL, 0);
  1931. break;
  1932. case 3:
  1933. // NCP Tts Begin/Abort
  1934. bOutput = 3;
  1935. SendNCP2( NWR_ANY_F2_NCP(0x22), &bOutput, sizeof(UCHAR), NULL, 0);
  1936. break;
  1937. case 1:
  1938. // NCP Tts End
  1939. bOutput = 2;
  1940. SendNCP2( NWR_ANY_F2_NCP(0x22),
  1941. &bOutput, sizeof(UCHAR),
  1942. (PUCHAR)&TTsInPacket, sizeof(TTsInPacket));
  1943. setCX(TTsInPacket.cx);
  1944. setDX(TTsInPacket.dx);
  1945. break;
  1946. case 4:
  1947. // NCP Tts Status
  1948. TTsOutPacket.SubFunction = 4;
  1949. TTsOutPacket.cx = getCX();
  1950. TTsOutPacket.dx = getDX();
  1951. SendNCP2( NWR_ANY_F2_NCP(0x22),
  1952. (PUCHAR)&TTsOutPacket, sizeof(TTsOutPacket),
  1953. NULL, 0);
  1954. break;
  1955. case 5:
  1956. case 7:
  1957. // NCP Tts Get App/Station Thresholds
  1958. bOutput = (pNwDosTable->SavedAx & 0x00ff);
  1959. SendNCP2( NWR_ANY_F2_NCP(0x22),
  1960. &bOutput, sizeof(UCHAR),
  1961. bInput, sizeof(bInput));
  1962. setCX( (USHORT)((bInput[0] << 8 ) || bInput[1]) );
  1963. break;
  1964. case 6:
  1965. case 8:
  1966. // NCP Tts Set App/Station Thresholds
  1967. TTsOutPacket.SubFunction = (pNwDosTable->SavedAx & 0x00ff);
  1968. TTsOutPacket.cx = getCX();
  1969. SendNCP2( NWR_ANY_F2_NCP(0x22),
  1970. (PUCHAR)&TTsOutPacket, sizeof(UCHAR) + sizeof(USHORT),
  1971. NULL, 0);
  1972. break;
  1973. default:
  1974. pNwDosTable->SavedAx = 0xc7FF;
  1975. break;
  1976. }
  1977. return;
  1978. }
  1979. VOID
  1980. OpenCreateFile(
  1981. VOID
  1982. )
  1983. /*++
  1984. Routine Description:
  1985. Look at the file being opened to determine if it is
  1986. a compatibility mode open to a file on a NetWare drive.
  1987. Arguments:
  1988. none.
  1989. Return Value:
  1990. none.
  1991. --*/
  1992. {
  1993. WORD Command = pNwDosTable->SavedAx;
  1994. PUCHAR Name;
  1995. if ((Command & OF_SHARE_MASK ) != OF_SHARE_COMPAT) {
  1996. return;
  1997. }
  1998. Name = GetVDMPointer (
  1999. (ULONG)((getDS() << 16)|getDX()),
  2000. 256,
  2001. CpuInProtectMode
  2002. );
  2003. NwPrint(("Nw16Handler Compatibility Open of %s\n", Name ));
  2004. //
  2005. // We already know its a Create or Open with sharing options
  2006. // set to compatibility mode or the tsr wouldn't have bopped to us.
  2007. //
  2008. if (IsItNetWare(Name)) {
  2009. SetCompatibility();
  2010. }
  2011. }
  2012. BOOL
  2013. IsItNetWare(
  2014. PUCHAR Name
  2015. )
  2016. /*++
  2017. Routine Description:
  2018. Look at the filename being opened to determine if it is on a NetWare drive.
  2019. Arguments:
  2020. none.
  2021. Return Value:
  2022. none.
  2023. --*/
  2024. {
  2025. UCHAR Drive;
  2026. Drive = tolower(Name[0])-'a';
  2027. NwPrint(("Nw16Handler IsItNetWare %s\n", Name ));
  2028. if (Name[1] == ':') {
  2029. if (pNwDosTable->DriveFlagTable[Drive] == LOCAL_DRIVE) {
  2030. // Definitely not a netware drive.
  2031. return FALSE;
  2032. }
  2033. } else if ((IS_ASCII_PATH_SEPARATOR(Name[0])) &&
  2034. (IS_ASCII_PATH_SEPARATOR(Name[0]))) {
  2035. // Assume only UNC names that the tsr built are NetWare
  2036. if ((getDS() == DosTableSegment ) &&
  2037. (getDX() == (WORD)(DosTableOffset + FIELD_OFFSET(NWDOSTABLE, DeNovellBuffer[0] )))) {
  2038. return TRUE;
  2039. }
  2040. return FALSE;
  2041. } else {
  2042. Drive = pNwDosTable->CurrentDrive;
  2043. }
  2044. //
  2045. // If this is a drive we don't know about, refresh our tables.
  2046. //
  2047. if (pNwDosTable->DriveFlagTable[Drive] == 0 ) {
  2048. Nw16Register();
  2049. }
  2050. if (pNwDosTable->DriveFlagTable[Drive] &
  2051. (TEMPORARY_NETWORK_DRIVE | PERMANENT_NETWORK_DRIVE )) {
  2052. return TRUE;
  2053. }
  2054. return FALSE;
  2055. }
  2056. VOID
  2057. SetCompatibility(
  2058. VOID
  2059. )
  2060. /*++
  2061. Routine Description:
  2062. Take the Create/Open file request in AX and modify appropriately
  2063. Arguments:
  2064. none.
  2065. Return Value:
  2066. none.
  2067. --*/
  2068. {
  2069. WORD Command = getAX();
  2070. if (( Command & OF_READ_WRITE_MASK) == OF_READ ) {
  2071. setAX((WORD)(Command | OF_SHARE_DENY_WRITE));
  2072. } else {
  2073. setAX((WORD)(Command | OF_SHARE_EXCLUSIVE));
  2074. }
  2075. }
  2076. VOID
  2077. OpenQueueFile(
  2078. VOID
  2079. )
  2080. /*++
  2081. Routine Description:
  2082. Build the UNC filename \\server\queue using the contents of the shared
  2083. datastructures and the CreateJobandFile NCP.
  2084. Arguments:
  2085. none.
  2086. Return Value:
  2087. none.
  2088. --*/
  2089. {
  2090. CONN_INDEX Connection = SelectConnection();
  2091. PUCHAR Request;
  2092. PUCHAR Buffer = pNwDosTable->DeNovellBuffer;
  2093. int index;
  2094. if ( Connection == 0xff ) {
  2095. //
  2096. // No need to return an errorcode. The NCP exchange
  2097. // will fail and give an appropriate call to the application.
  2098. //
  2099. return;
  2100. }
  2101. if ( ServerHandles[Connection] == NULL ) {
  2102. NTSTATUS status;
  2103. status = OpenConnection( Connection );
  2104. if (!NT_SUCCESS(status)) {
  2105. SetStatus(status);
  2106. return;
  2107. }
  2108. }
  2109. //
  2110. // CreateJobandQueue open in progress. The purpose of this
  2111. // open being processed is to translate the information in
  2112. // the CreateJob NCP into a pathname to be opened by the 16
  2113. // bit code.
  2114. //
  2115. //
  2116. // Users DS:SI points at a CreateJob NCB. Inside the request is
  2117. // the objectid of the queue. Ask the server for the queue name.
  2118. //
  2119. Request = GetVDMPointer (
  2120. (ULONG)((getDS() << 16)|getSI()),
  2121. 8,
  2122. CpuInProtectMode);
  2123. NwlibMakeNcp(
  2124. ServerHandles[Connection],
  2125. FSCTL_NWR_NCP_E3H,
  2126. 7, // RequestSize
  2127. 61, // ResponseSize
  2128. "br|_r",
  2129. 0x36, // Get Bindery Object Name
  2130. Request+3, 4,
  2131. 6, // Skip ObjectId and Type
  2132. pNwDosTable->DeNovellBuffer2, 48 );
  2133. pNwDosTable->DeNovellBuffer2[54] = '\0';
  2134. Buffer[0] = '\\';
  2135. Buffer[1] = '\\';
  2136. Buffer += 2; // Point to after backslashes
  2137. // Copy the servername
  2138. for (index = 0; index < sizeof(SERVERNAME); index++) {
  2139. Buffer[index] = pNwDosTable->ServerNameTable[Connection][index];
  2140. if (Buffer[index] == '\0') {
  2141. break;
  2142. }
  2143. }
  2144. Buffer[index] = '\\';
  2145. RtlCopyMemory( &Buffer[index+1], &pNwDosTable->DeNovellBuffer2[0], 48 );
  2146. NwPrint(("Nw32: CreateQueue Job and File %s\n", pNwDosTable->DeNovellBuffer));
  2147. //
  2148. // Set up 16 bit registers to do the DOS OpenFile for \\server\queue
  2149. //
  2150. setDS((WORD)(CpuInProtectMode ? pNwDosTable->PmSelector : DosTableSegment));
  2151. setDX( (WORD)(DosTableOffset + FIELD_OFFSET(NWDOSTABLE, DeNovellBuffer[0] )) );
  2152. setAX(0x3d02); // Set to OpenFile
  2153. }
  2154. VOID
  2155. AttachHandle(
  2156. VOID
  2157. )
  2158. /*++
  2159. Routine Description:
  2160. This routine implements Int 21 B4. Which is supposed to create a
  2161. Dos Handle that corresponds to a specified 6 byte NetWare handle.
  2162. This is used as a replacement for doing a DosOpen on "NETQ" and usin the
  2163. handle returned from there.
  2164. Arguments:
  2165. none.
  2166. Return Value:
  2167. none.
  2168. --*/
  2169. {
  2170. if ( pNwDosTable->CreatedJob ) {
  2171. NwPrint(("Nw32: AttachHandle %x\n", pNwDosTable->JobHandle));
  2172. setAX( pNwDosTable->JobHandle );
  2173. pNwDosTable->CreatedJob = 0; // Only return it once.
  2174. } else {
  2175. NwPrint(("Nw32: AttachHandle failed, no job\n"));
  2176. setAX(ERROR_FILE_NOT_FOUND);
  2177. setCF(1);
  2178. }
  2179. }
  2180. VOID
  2181. ProcessExit(
  2182. VOID
  2183. )
  2184. /*++
  2185. Routine Description:
  2186. Cleanup all cached handles. Unmap all temporary drives.
  2187. Cleanup the server name table so that if another dos app
  2188. is started we reload all the useful information such as
  2189. the servers connection number.
  2190. Note: Dos always completes processing after we complete.
  2191. Arguments:
  2192. none.
  2193. Return Value:
  2194. none.
  2195. --*/
  2196. {
  2197. UCHAR Connection;
  2198. UCHAR Drive;
  2199. USHORT Command = pNwDosTable->SavedAx;
  2200. ResetLocks();
  2201. for (Drive = 0; Drive < MD; Drive++) {
  2202. NwPrint(("Nw32: Deallocate directory handle %c\n", 'A' + Drive));
  2203. if (Win32DirectoryHandleTable[Drive] != 0) {
  2204. CloseHandle( Win32DirectoryHandleTable[Drive] );
  2205. Win32DirectoryHandleTable[Drive] = 0;
  2206. pNwDosTable->DriveHandleTable[Drive] = 0;
  2207. }
  2208. }
  2209. for (Connection = 0; Connection < MC ; Connection++ ) {
  2210. if (pNwDosTable->ConnectionIdTable[Connection].ci_InUse == IN_USE) {
  2211. CloseConnection(Connection);
  2212. pNwDosTable->ConnectionIdTable[Connection].ci_InUse = FREE;
  2213. ZeroMemory( pNwDosTable->ServerNameTable[Connection], SERVERNAME_LENGTH );
  2214. }
  2215. }
  2216. pNwDosTable->PreferredServer = 0;
  2217. LockMode = 0;
  2218. TablesValid = FALSE;
  2219. DriveHandleTableValid = FALSE;
  2220. #if NWDBG
  2221. if (DebugCtrl & ~3 ) {
  2222. DebugControl( 2 ); // Close logfile
  2223. }
  2224. GotDebugState = FALSE;
  2225. #endif
  2226. //
  2227. // set AX register so that AH gets preserved
  2228. //
  2229. setAX( Command );
  2230. }
  2231. VOID
  2232. SystemLogout(
  2233. VOID
  2234. )
  2235. /*++
  2236. Routine Description:
  2237. This api is called by the NetWare login.
  2238. Remove all NetWare redirected drives and logout connections
  2239. that don't have open handles on them. Don't detach the connections.
  2240. Arguments:
  2241. none.
  2242. Return Value:
  2243. none.
  2244. --*/
  2245. {
  2246. UCHAR Connection;
  2247. UCHAR Drive;
  2248. USHORT Command = pNwDosTable->SavedAx;
  2249. ResetLocks();
  2250. for (Drive = 0; Drive < MD; Drive++) {
  2251. ResetDrive(Drive);
  2252. }
  2253. for (Connection = 0; Connection < MC ; Connection++ ) {
  2254. if (pNwDosTable->ConnectionIdTable[Connection].ci_InUse == IN_USE) {
  2255. if ( ServerHandles[Connection] == NULL ) {
  2256. OpenConnection( Connection );
  2257. }
  2258. if (ServerHandles[Connection] != NULL ) {
  2259. NwlibMakeNcp(
  2260. ServerHandles[Connection],
  2261. NWR_ANY_F2_NCP(NCP_LOGOUT),
  2262. 0, // RequestSize
  2263. 0, // ResponseSize
  2264. "");
  2265. CloseConnection(Connection);
  2266. }
  2267. //pNwDosTable->ConnectionIdTable[Connection].ci_InUse = FREE;
  2268. //ZeroMemory( pNwDosTable->ServerNameTable[Connection], SERVERNAME_LENGTH );
  2269. }
  2270. }
  2271. pNwDosTable->PreferredServer = 0;
  2272. pNwDosTable->PrimaryServer = 0;
  2273. // No servers in the table so find the nearest/preferred.
  2274. LoadPreferredServerName();
  2275. //
  2276. // set AX register so that AH gets preserved
  2277. // and AL says success.
  2278. //
  2279. setAX( (USHORT)(Command & 0xff00) );
  2280. }
  2281. UCHAR
  2282. AttachmentControl(
  2283. ULONG Command
  2284. )
  2285. /*++
  2286. Routine Description:
  2287. Implement Funtion F1h
  2288. Arguments:
  2289. none.
  2290. Return Value:
  2291. Return status.
  2292. --*/
  2293. {
  2294. UCHAR Connection = getDL();
  2295. if ((Connection < 1) ||
  2296. (Connection > MC)) {
  2297. return 0xf7;
  2298. }
  2299. Connection -= 1;
  2300. switch (Command & 0x00ff) {
  2301. case 0: // Attach
  2302. NwPrint(("Nw16AttachmentControl: Attach connection %d\n", Connection));
  2303. pNwDosTable->ConnectionIdTable[Connection].ci_InUse = IN_USE;
  2304. if ( ServerHandles[Connection] == NULL ) {
  2305. NTSTATUS status = OpenConnection( Connection );
  2306. if (!NT_SUCCESS(status)) {
  2307. pNwDosTable->ConnectionIdTable[Connection].ci_InUse = FREE;
  2308. ZeroMemory( pNwDosTable->ServerNameTable[Connection], SERVERNAME_LENGTH );
  2309. return (UCHAR)RtlNtStatusToDosError(status);
  2310. } else {
  2311. InitConnection(Connection);
  2312. }
  2313. }
  2314. return 0;
  2315. break;
  2316. case 1: // Detach
  2317. NwPrint(("Nw16AttachmentControl: Detach connection %d\n", Connection));
  2318. if (pNwDosTable->ConnectionIdTable[Connection].ci_InUse != IN_USE) {
  2319. return 0xff;
  2320. } else {
  2321. pNwDosTable->ConnectionIdTable[Connection].ci_InUse = FREE;
  2322. if (ServerHandles[Connection] != NULL ) {
  2323. CloseConnection(Connection);
  2324. }
  2325. ZeroMemory( pNwDosTable->ServerNameTable[Connection], SERVERNAME_LENGTH );
  2326. if (pNwDosTable->PrimaryServer == (UCHAR)Connection + 1 ) {
  2327. // Need to pick another
  2328. UCHAR IndexConnection;
  2329. pNwDosTable->PrimaryServer = 0;
  2330. for (IndexConnection = 0; IndexConnection < MC ; IndexConnection++ ) {
  2331. if (pNwDosTable->ConnectionIdTable[IndexConnection].ci_InUse == IN_USE) {
  2332. pNwDosTable->PrimaryServer = IndexConnection + 1;
  2333. }
  2334. }
  2335. }
  2336. if (pNwDosTable->PreferredServer == (UCHAR)Connection + 1 ) {
  2337. pNwDosTable->PreferredServer = 0;
  2338. }
  2339. return 0;
  2340. }
  2341. case 2: // Logout
  2342. NwPrint(("Nw16AttachmentControl: Logout connection %d\n", Connection));
  2343. if (pNwDosTable->ConnectionIdTable[Connection].ci_InUse != IN_USE) {
  2344. return 0xff;
  2345. } else {
  2346. UCHAR Drive;
  2347. if ( ServerHandles[Connection] == NULL ) {
  2348. OpenConnection( Connection );
  2349. }
  2350. for (Drive = 0; Drive < MD; Drive++ ) {
  2351. if (pNwDosTable->DriveIdTable[ Drive ] == (Connection + 1)) {
  2352. ResetDrive(Drive);
  2353. }
  2354. }
  2355. if (ServerHandles[Connection] != NULL ) {
  2356. NwlibMakeNcp(
  2357. ServerHandles[Connection],
  2358. NWR_ANY_F2_NCP(NCP_LOGOUT),
  2359. 0, // RequestSize
  2360. 0, // ResponseSize
  2361. "");
  2362. CloseConnection(Connection);
  2363. }
  2364. return 0;
  2365. }
  2366. }
  2367. return 0xff;
  2368. }
  2369. VOID
  2370. ServerFileCopy(
  2371. VOID
  2372. )
  2373. /*++
  2374. Routine Description:
  2375. Build the NCP that tells the server to move a file on the server.
  2376. Arguments:
  2377. none.
  2378. Return Value:
  2379. none.
  2380. --*/
  2381. {
  2382. DWORD BytesReturned;
  2383. UCHAR SrcHandle[6];
  2384. UCHAR DestHandle[6];
  2385. NTSTATUS status;
  2386. PUCHAR Buffer;
  2387. Buffer = GetVDMPointer (
  2388. (ULONG)((getES() << 16)|getDI()),
  2389. 16,
  2390. CpuInProtectMode
  2391. );
  2392. if ( DeviceIoControl(
  2393. GET_NT_SRCHANDLE(),
  2394. IOCTL_NWR_RAW_HANDLE,
  2395. NULL,
  2396. 0,
  2397. (PUCHAR)&SrcHandle,
  2398. sizeof(SrcHandle),
  2399. &BytesReturned,
  2400. NULL ) == FALSE ) {
  2401. setAL(0xff);
  2402. return;
  2403. }
  2404. if ( DeviceIoControl(
  2405. GET_NT_HANDLE(),
  2406. IOCTL_NWR_RAW_HANDLE,
  2407. NULL,
  2408. 0,
  2409. (PUCHAR)&DestHandle,
  2410. sizeof(DestHandle),
  2411. &BytesReturned,
  2412. NULL ) == FALSE ) {
  2413. setAL(0xff);
  2414. return;
  2415. }
  2416. status = NwlibMakeNcp(
  2417. GET_NT_SRCHANDLE(),
  2418. NWR_ANY_F2_NCP(0x4A),
  2419. 25, // RequestSize
  2420. 4, // ResponseSize
  2421. "brrddd|d",
  2422. 0,
  2423. SrcHandle, 6,
  2424. DestHandle, 6,
  2425. *(DWORD UNALIGNED*)&Buffer[4],
  2426. *(DWORD UNALIGNED*)&Buffer[8],
  2427. *(DWORD UNALIGNED*)&Buffer[12],
  2428. &BytesReturned
  2429. );
  2430. setDX((WORD)(BytesReturned >> 16));
  2431. setCX((WORD)BytesReturned);
  2432. if (!NT_SUCCESS(status)) {
  2433. SetStatus(status);
  2434. return;
  2435. } else {
  2436. setAL(0);
  2437. }
  2438. }
  2439. VOID
  2440. SetStatus(
  2441. NTSTATUS Status
  2442. )
  2443. /*++
  2444. Routine Description:
  2445. Convert an NTSTATUS into the appropriate register settings and updates
  2446. to the dos tables.
  2447. Arguments:
  2448. none.
  2449. Return Value:
  2450. none.
  2451. --*/
  2452. {
  2453. UCHAR DosStatus = (UCHAR)RtlNtStatusToDosError(Status);
  2454. if ((!DosStatus) &&
  2455. (Status != 0)) {
  2456. //
  2457. // We have a connection bit set
  2458. //
  2459. if ( Status & (NCP_STATUS_BAD_CONNECTION << 8)) {
  2460. DosStatus = 0xfc;
  2461. } else {
  2462. DosStatus = 0xff;
  2463. }
  2464. }
  2465. if (DosStatus) {
  2466. setCF(1);
  2467. }
  2468. setAL(DosStatus);
  2469. }