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.

7065 lines
190 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. FsCtrl.c
  5. Abstract:
  6. This module implements the File System Control routines for the
  7. NetWare redirector called by the dispatch driver.
  8. Author:
  9. Colin Watson [ColinW] 29-Dec-1992
  10. Revision History:
  11. --*/
  12. #include "Procs.h"
  13. #include "ntddrdr.h"
  14. //
  15. // MUP lock macros
  16. //
  17. #define ACQUIRE_MUP_LOCK() NwAcquireOpenLock()
  18. #define RELEASE_MUP_LOCK() NwReleaseOpenLock()
  19. //
  20. // The local debug trace level
  21. //
  22. #define Dbg (DEBUG_TRACE_FSCTRL)
  23. //
  24. // Local procedure prototypes
  25. //
  26. NTSTATUS
  27. NwCommonDeviceIoControl (
  28. IN PIRP_CONTEXT IrpContext
  29. );
  30. #ifndef _PNP_POWER_
  31. NTSTATUS
  32. StartRedirector(
  33. PIRP_CONTEXT IrpContext
  34. );
  35. NTSTATUS
  36. StopRedirector(
  37. IN PIRP_CONTEXT IrpContext
  38. );
  39. NTSTATUS
  40. BindToTransport (
  41. IN PIRP_CONTEXT IrpContext
  42. );
  43. #endif
  44. NTSTATUS
  45. ChangePassword (
  46. IN PIRP_CONTEXT IrpContext
  47. );
  48. NTSTATUS
  49. SetInfo (
  50. IN PIRP_CONTEXT IrpContext
  51. );
  52. NTSTATUS
  53. SetDebug (
  54. IN PIRP_CONTEXT IrpContext
  55. );
  56. NTSTATUS
  57. GetMessage (
  58. IN PIRP_CONTEXT IrpContext
  59. );
  60. NTSTATUS
  61. GetStats (
  62. IN PIRP_CONTEXT IrpContext
  63. );
  64. NTSTATUS
  65. GetPrintJobId (
  66. IN PIRP_CONTEXT IrpContext
  67. );
  68. NTSTATUS
  69. GetConnectionDetails(
  70. IN PIRP_CONTEXT IrpContext
  71. );
  72. NTSTATUS
  73. GetConnectionDetails2(
  74. IN PIRP_CONTEXT IrpContext
  75. );
  76. NTSTATUS
  77. GetConnectionPerformance(
  78. IN PIRP_CONTEXT IrpContext
  79. );
  80. #ifndef _PNP_POWER_
  81. NTSTATUS
  82. RegisterWithMup(
  83. VOID
  84. );
  85. VOID
  86. DeregisterWithMup(
  87. VOID
  88. );
  89. #endif
  90. NTSTATUS
  91. QueryPath (
  92. IN PIRP_CONTEXT IrpContext
  93. );
  94. NTSTATUS
  95. UserNcp(
  96. ULONG Function,
  97. PIRP_CONTEXT IrpContext
  98. );
  99. NTSTATUS
  100. UserNcpCallback (
  101. IN PIRP_CONTEXT IrpContext,
  102. IN ULONG BytesAvailable,
  103. IN PUCHAR Response
  104. );
  105. NTSTATUS
  106. FspCompleteLogin(
  107. PIRP_CONTEXT IrpContext
  108. );
  109. NTSTATUS
  110. GetConnection(
  111. PIRP_CONTEXT IrpContext
  112. );
  113. NTSTATUS
  114. EnumConnections(
  115. PIRP_CONTEXT IrpContext
  116. );
  117. NTSTATUS
  118. DeleteConnection(
  119. PIRP_CONTEXT IrpContext
  120. );
  121. NTSTATUS
  122. WriteNetResourceEntry(
  123. IN OUT PCHAR *FixedPortion,
  124. IN OUT PWCHAR *EndOfVariableData,
  125. IN PUNICODE_STRING ContainerName OPTIONAL,
  126. IN PUNICODE_STRING LocalName OPTIONAL,
  127. IN PUNICODE_STRING RemoteName,
  128. IN ULONG ScopeFlag,
  129. IN ULONG DisplayFlag,
  130. IN ULONG UsageFlag,
  131. IN ULONG ShareType,
  132. OUT PULONG EntrySize
  133. );
  134. BOOL
  135. CopyStringToBuffer(
  136. IN LPCWSTR SourceString OPTIONAL,
  137. IN DWORD CharacterCount,
  138. IN LPCWSTR FixedDataEnd,
  139. IN OUT LPWSTR *EndOfVariableData,
  140. OUT LPWSTR *VariableDataPointer
  141. );
  142. NTSTATUS
  143. GetRemoteHandle(
  144. IN PIRP_CONTEXT IrpContext
  145. );
  146. NTSTATUS
  147. GetUserName(
  148. IN PIRP_CONTEXT IrpContext
  149. );
  150. NTSTATUS
  151. GetChallenge(
  152. IN PIRP_CONTEXT IrpContext
  153. );
  154. NTSTATUS
  155. WriteConnStatusEntry(
  156. PIRP_CONTEXT pIrpContext,
  157. PSCB pConnectionScb,
  158. PBYTE pbUserBuffer,
  159. DWORD dwBufferLen,
  160. DWORD *pdwBytesWritten,
  161. DWORD *pdwBytesNeeded,
  162. BOOLEAN fCallerScb
  163. );
  164. NTSTATUS
  165. GetConnStatus(
  166. IN PIRP_CONTEXT IrpContext,
  167. PFILE_OBJECT FileObject
  168. );
  169. NTSTATUS
  170. GetConnectionInfo(
  171. IN PIRP_CONTEXT IrpContext
  172. );
  173. NTSTATUS
  174. GetPreferredServer(
  175. IN PIRP_CONTEXT IrpContext
  176. );
  177. NTSTATUS
  178. SetShareBit(
  179. IN PIRP_CONTEXT IrpContext,
  180. PFILE_OBJECT FileObject
  181. );
  182. //
  183. // Statics
  184. //
  185. HANDLE MupHandle = 0;
  186. #ifdef ALLOC_PRAGMA
  187. #pragma alloc_text( PAGE, NwFsdFileSystemControl )
  188. #pragma alloc_text( PAGE, NwCommonFileSystemControl )
  189. #pragma alloc_text( PAGE, NwFsdDeviceIoControl )
  190. #pragma alloc_text( PAGE, NwCommonDeviceIoControl )
  191. #pragma alloc_text( PAGE, ChangePassword )
  192. #pragma alloc_text( PAGE, SetInfo )
  193. #pragma alloc_text( PAGE, GetStats )
  194. #pragma alloc_text( PAGE, GetPrintJobId )
  195. #pragma alloc_text( PAGE, RegisterWithMup )
  196. #pragma alloc_text( PAGE, DeregisterWithMup )
  197. #pragma alloc_text( PAGE, QueryPath )
  198. #pragma alloc_text( PAGE, UserNcp )
  199. #pragma alloc_text( PAGE, GetConnection )
  200. #pragma alloc_text( PAGE, DeleteConnection )
  201. #pragma alloc_text( PAGE, WriteNetResourceEntry )
  202. #pragma alloc_text( PAGE, CopyStringToBuffer )
  203. #pragma alloc_text( PAGE, GetRemoteHandle )
  204. #pragma alloc_text( PAGE, GetUserName )
  205. #pragma alloc_text( PAGE, GetChallenge )
  206. #pragma alloc_text( PAGE, WriteConnStatusEntry )
  207. #pragma alloc_text( PAGE, GetConnectionInfo )
  208. #pragma alloc_text( PAGE, GetPreferredServer )
  209. #ifndef _PNP_POWER_
  210. #pragma alloc_text( PAGE, BindToTransport )
  211. #pragma alloc_text( PAGE, RegisterWithMup )
  212. #pragma alloc_text( PAGE, DeregisterWithMup )
  213. #endif
  214. #ifndef QFE_BUILD
  215. #pragma alloc_text( PAGE1, UserNcpCallback )
  216. #pragma alloc_text( PAGE1, GetConnectionDetails )
  217. #pragma alloc_text( PAGE1, GetConnectionDetails2 )
  218. #pragma alloc_text( PAGE1, GetMessage )
  219. #pragma alloc_text( PAGE1, EnumConnections )
  220. #endif
  221. #endif
  222. #if 0 // Not pageable
  223. // see ifndef QFE_BUILD above
  224. GetConnStatus
  225. #endif
  226. NTSTATUS
  227. NwFsdFileSystemControl (
  228. IN PDEVICE_OBJECT DeviceObject,
  229. IN PIRP Irp
  230. )
  231. /*++
  232. Routine Description:
  233. This routine implements the FSD part of FileSystem control operations
  234. Arguments:
  235. DeviceObject - Supplies the redirector device object.
  236. Irp - Supplies the Irp being processed
  237. Return Value:
  238. NTSTATUS - The FSD status for the IRP
  239. --*/
  240. {
  241. NTSTATUS Status;
  242. PIRP_CONTEXT IrpContext = NULL;
  243. BOOLEAN TopLevel;
  244. PAGED_CODE();
  245. DebugTrace(+1, Dbg, "NwFsdFileSystemControl\n", 0);
  246. FsRtlEnterFileSystem();
  247. TopLevel = NwIsIrpTopLevel( Irp );
  248. //
  249. // Allocate the irp context. If the allocation
  250. // fails then an exception if thrown instead of
  251. // NULL being returned so we just catch the error
  252. // in there.
  253. //
  254. try {
  255. IrpContext = AllocateIrpContext( Irp );
  256. } except (EXCEPTION_EXECUTE_HANDLER) {
  257. Status = STATUS_INSUFFICIENT_RESOURCES;
  258. Irp->IoStatus.Status = Status;
  259. Irp->IoStatus.Information = 0;
  260. IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
  261. goto CleanupAndExit;
  262. }
  263. //
  264. // Process the request
  265. // IrpContext must be NON-NULL here.
  266. //
  267. try {
  268. SetFlag( IrpContext->Flags, IRP_FLAG_IN_FSD );
  269. Status = NwCommonFileSystemControl( IrpContext );
  270. } except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
  271. //
  272. // We had some trouble trying to perform the requested
  273. // operation, so we'll abort the I/O request with
  274. // the error Status that we get back from the
  275. // execption code
  276. //
  277. Status = NwProcessException( IrpContext, GetExceptionCode() );
  278. }
  279. if ( IrpContext ) {
  280. if ( Status != STATUS_PENDING ) {
  281. NwDequeueIrpContext( IrpContext, FALSE );
  282. }
  283. NwCompleteRequest( IrpContext, Status );
  284. }
  285. CleanupAndExit:
  286. if ( TopLevel ) {
  287. NwSetTopLevelIrp( NULL );
  288. }
  289. FsRtlExitFileSystem();
  290. //
  291. // And return to our caller
  292. //
  293. DebugTrace(-1, Dbg, "NwFsdFileSystemControl -> %08lx\n", Status);
  294. return Status;
  295. }
  296. NTSTATUS
  297. NwCommonFileSystemControl (
  298. IN PIRP_CONTEXT IrpContext
  299. )
  300. /*++
  301. Routine Description:
  302. This is the common routine for doing FileSystem control operations called
  303. by both the fsd and fsp threads
  304. Arguments:
  305. IrpContext - Supplies the Irp to process
  306. Return Value:
  307. NTSTATUS - The return status for the operation
  308. --*/
  309. {
  310. NTSTATUS Status;
  311. PIO_STACK_LOCATION IrpSp;
  312. PIRP Irp;
  313. ULONG Function;
  314. PAGED_CODE();
  315. NwReferenceUnlockableCodeSection();
  316. try {
  317. //
  318. // Get a pointer to the current Irp stack location
  319. //
  320. Irp = IrpContext->pOriginalIrp;
  321. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  322. Function = IrpSp->Parameters.FileSystemControl.FsControlCode;
  323. DebugTrace(+1, Dbg, "NwCommonFileSystemControl\n", 0);
  324. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  325. DebugTrace( 0, Dbg, "Function = %08lx\n", Function);
  326. DebugTrace( 0, Dbg, "Function = %d\n", (Function >> 2) & 0x0fff);
  327. //
  328. // We know this is a file system control so we'll case on the
  329. // minor function, and call a internal worker routine to complete
  330. // the irp.
  331. //
  332. if (IrpSp->MinorFunction != IRP_MN_USER_FS_REQUEST ) {
  333. DebugTrace( 0, Dbg, "Invalid FS Control Minor Function %08lx\n", IrpSp->MinorFunction);
  334. return STATUS_INVALID_DEVICE_REQUEST;
  335. }
  336. //
  337. // tommye
  338. //
  339. // If the output buffer came from user space, then probe it for write.
  340. //
  341. if (((Function & 3) == METHOD_NEITHER) && (Irp->RequestorMode != KernelMode)) {
  342. ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  343. try {
  344. ProbeForWrite( Irp->UserBuffer,
  345. OutputBufferLength,
  346. sizeof(CHAR)
  347. );
  348. } except (EXCEPTION_EXECUTE_HANDLER) {
  349. return GetExceptionCode();
  350. }
  351. }
  352. switch (Function) {
  353. case FSCTL_NWR_START:
  354. Status = StartRedirector( IrpContext );
  355. break;
  356. case FSCTL_NWR_STOP:
  357. Status = StopRedirector( IrpContext );
  358. break;
  359. case FSCTL_NWR_LOGON:
  360. Status = Logon( IrpContext );
  361. break;
  362. case FSCTL_NWR_LOGOFF:
  363. Status = Logoff( IrpContext );
  364. break;
  365. case FSCTL_NWR_GET_CONNECTION:
  366. Status = GetConnection( IrpContext );
  367. break;
  368. case FSCTL_NWR_ENUMERATE_CONNECTIONS:
  369. Status = EnumConnections( IrpContext );
  370. break;
  371. case FSCTL_NWR_DELETE_CONNECTION:
  372. Status = DeleteConnection( IrpContext );
  373. break;
  374. case FSCTL_NWR_BIND_TO_TRANSPORT:
  375. #ifndef _PNP_POWER_
  376. Status = BindToTransport( IrpContext );
  377. #else
  378. Status = RegisterTdiPnPEventHandlers( IrpContext );
  379. #endif
  380. break;
  381. case FSCTL_NWR_CHANGE_PASS:
  382. Status = ChangePassword( IrpContext );
  383. break;
  384. case FSCTL_NWR_SET_INFO:
  385. Status = SetInfo( IrpContext );
  386. break;
  387. case FSCTL_NWR_GET_CONN_DETAILS:
  388. Status = GetConnectionDetails( IrpContext );
  389. break;
  390. case FSCTL_NWR_GET_CONN_DETAILS2:
  391. Status = GetConnectionDetails2( IrpContext );
  392. break;
  393. case FSCTL_NWR_GET_MESSAGE:
  394. Status = GetMessage( IrpContext );
  395. break;
  396. case FSCTL_NWR_GET_STATISTICS:
  397. Status = GetStats( IrpContext );
  398. break;
  399. case FSCTL_NWR_GET_USERNAME:
  400. Status = GetUserName( IrpContext );
  401. break;
  402. case FSCTL_NWR_CHALLENGE:
  403. Status = GetChallenge( IrpContext );
  404. break;
  405. case FSCTL_GET_PRINT_ID:
  406. Status = GetPrintJobId( IrpContext );
  407. break;
  408. case FSCTL_NWR_GET_CONN_STATUS:
  409. Status = GetConnStatus( IrpContext, IrpSp->FileObject );
  410. break;
  411. case FSCTL_NWR_GET_CONN_INFO:
  412. Status = GetConnectionInfo( IrpContext );
  413. break;
  414. case FSCTL_NWR_GET_PREFERRED_SERVER:
  415. Status = GetPreferredServer( IrpContext );
  416. break;
  417. case FSCTL_NWR_GET_CONN_PERFORMANCE:
  418. Status = GetConnectionPerformance( IrpContext );
  419. break;
  420. case FSCTL_NWR_SET_SHAREBIT:
  421. Status = SetShareBit( IrpContext, IrpSp->FileObject );
  422. break;
  423. //Terminal Server merge
  424. case FSCTL_NWR_CLOSEALL:
  425. NwCloseAllVcbs( IrpContext );
  426. Status = STATUS_SUCCESS;
  427. break;
  428. default:
  429. if (( Function >= NWR_ANY_NCP(0)) &&
  430. ( Function <= NWR_ANY_HANDLE_NCP(0x00ff))) {
  431. Status = UserNcp( Function, IrpContext );
  432. break;
  433. }
  434. if (( Function >= NWR_ANY_NDS(0)) &&
  435. ( Function <= NWR_ANY_NDS(0x00ff))) {
  436. Status = DispatchNds( Function, IrpContext );
  437. break;
  438. }
  439. DebugTrace( 0, Dbg, "Invalid FS Control Code %08lx\n",
  440. IrpSp->Parameters.FileSystemControl.FsControlCode);
  441. Status = STATUS_INVALID_DEVICE_REQUEST;
  442. break;
  443. }
  444. } finally {
  445. NwDereferenceUnlockableCodeSection ();
  446. DebugTrace(-1, Dbg, "NwCommonFileSystemControl -> %08lx\n", Status);
  447. }
  448. return Status;
  449. }
  450. NTSTATUS
  451. NwFsdDeviceIoControl (
  452. IN PDEVICE_OBJECT DeviceObject,
  453. IN PIRP Irp
  454. )
  455. /*++
  456. Routine Description:
  457. This routine implements the FSD part of DeviceIoControl file operations
  458. Arguments:
  459. DeviceObject - Supplies the redirector device object.
  460. Irp - Supplies the Irp being processed
  461. Return Value:
  462. NTSTATUS - The FSD status for the IRP
  463. --*/
  464. {
  465. NTSTATUS Status;
  466. PIRP_CONTEXT IrpContext = NULL;
  467. BOOLEAN TopLevel;
  468. PAGED_CODE();
  469. DebugTrace(+1, Dbg, "NwFsdDeviceIoControl\n", 0);
  470. FsRtlEnterFileSystem();
  471. TopLevel = NwIsIrpTopLevel( Irp );
  472. //
  473. // Allocate the irp context. If the allocation
  474. // fails then an exception if thrown instead of
  475. // NULL being returned.
  476. //
  477. try {
  478. IrpContext = AllocateIrpContext( Irp );
  479. } except(EXCEPTION_EXECUTE_HANDLER) {
  480. Status = STATUS_INSUFFICIENT_RESOURCES;
  481. Irp->IoStatus.Status = Status;
  482. Irp->IoStatus.Information = 0;
  483. IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
  484. goto CleanupAndExit;
  485. }
  486. try {
  487. SetFlag( IrpContext->Flags, IRP_FLAG_IN_FSD );
  488. Status = NwCommonDeviceIoControl( IrpContext );
  489. } except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
  490. //
  491. // We had some trouble trying to perform the requested
  492. // operation, so we'll abort the I/O request with
  493. // the error Status that we get back from the
  494. // execption code
  495. //
  496. Status = NwProcessException( IrpContext, GetExceptionCode() );
  497. }
  498. if ( IrpContext ) {
  499. if ( Status != STATUS_PENDING ) {
  500. NwDequeueIrpContext( IrpContext, FALSE );
  501. }
  502. NwCompleteRequest(IrpContext, Status);
  503. }
  504. CleanupAndExit:
  505. if ( TopLevel ) {
  506. NwSetTopLevelIrp( NULL );
  507. }
  508. FsRtlExitFileSystem();
  509. //
  510. // And return to our caller
  511. //
  512. DebugTrace(-1, Dbg, "NwFsdDeviceIoControl -> %08lx\n", Status);
  513. return Status;
  514. }
  515. NTSTATUS
  516. NwCommonDeviceIoControl (
  517. IN PIRP_CONTEXT IrpContext
  518. )
  519. /*++
  520. Routine Description:
  521. This is the common routine for doing FileSystem control operations called
  522. by both the fsd and fsp threads
  523. Arguments:
  524. IrpContext - Supplies the Irp to process
  525. Return Value:
  526. NTSTATUS - The return status for the operation
  527. --*/
  528. {
  529. NTSTATUS Status;
  530. PIO_STACK_LOCATION IrpSp;
  531. PIRP Irp;
  532. PAGED_CODE();
  533. NwReferenceUnlockableCodeSection();
  534. try {
  535. //
  536. // Get a pointer to the current Irp stack location
  537. //
  538. Irp = IrpContext->pOriginalIrp;
  539. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  540. DebugTrace(+1, Dbg, "NwCommonDeviceIoControl\n", 0);
  541. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  542. DebugTrace( 0, Dbg, "Function = %08lx\n",
  543. IrpSp->Parameters.DeviceIoControl.IoControlCode);
  544. //
  545. // We know this is a DeviceIoControl so we'll case on the
  546. // minor function, and call a internal worker routine to complete
  547. // the irp.
  548. //
  549. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  550. case IOCTL_REDIR_QUERY_PATH:
  551. Status = QueryPath( IrpContext );
  552. break;
  553. case IOCTL_NWR_RAW_HANDLE:
  554. Status = GetRemoteHandle( IrpContext );
  555. break;
  556. default:
  557. DebugTrace( 0, Dbg, "Invalid IO Control Code %08lx\n",
  558. IrpSp->Parameters.DeviceIoControl.IoControlCode);
  559. Status = STATUS_INVALID_DEVICE_REQUEST;
  560. break;
  561. }
  562. } finally {
  563. NwDereferenceUnlockableCodeSection ();
  564. DebugTrace(-1, Dbg, "NwCommonDeviceIoControl -> %08lx\n", Status);
  565. }
  566. return Status;
  567. }
  568. #ifndef _PNP_POWER_
  569. NTSTATUS
  570. BindToTransport (
  571. IN PIRP_CONTEXT IrpContext
  572. )
  573. /*++
  574. Routine Description:
  575. This routine records the name of the transport to be used and
  576. initialises the PermanentScb.
  577. Arguments:
  578. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  579. Return Value:
  580. NTSTATUS
  581. --*/
  582. {
  583. NTSTATUS Status;
  584. PIRP Irp = IrpContext->pOriginalIrp;
  585. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  586. PNWR_REQUEST_PACKET InputBuffer = Irp->AssociatedIrp.SystemBuffer;
  587. ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  588. SECURITY_SUBJECT_CONTEXT SubjectContext;
  589. PLOGON Logon;
  590. LARGE_INTEGER Uid;
  591. PAGED_CODE();
  592. //
  593. // Don't re-register if we have already registered.
  594. //
  595. if ( TdiBindingHandle != NULL ) {
  596. return STATUS_SUCCESS;
  597. }
  598. // ========= Multi-user support ==============
  599. // Get the LOGON structure
  600. //
  601. SeCaptureSubjectContext(&SubjectContext);
  602. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  603. Uid = GetUid( &SubjectContext );
  604. Logon = FindUser( &Uid, TRUE );
  605. NwReleaseRcb( &NwRcb );
  606. SeReleaseSubjectContext(&SubjectContext);
  607. //
  608. // Now we have the the Logon structure for the user
  609. //=====================================
  610. //
  611. // Register the PnP bind handlers.
  612. //
  613. DebugTrace( 0 , Dbg, "Register TDI bind handlers.\n", 0 );
  614. TdiInitialize();
  615. return TdiRegisterNotificationHandler( HandleTdiBindMessage,
  616. HandleTdiUnbindMessage,
  617. &TdiBindingHandle );
  618. /************************
  619. //
  620. // The old non-pnp code for legacy support.
  621. //
  622. DebugTrace(+1, Dbg, "Bind to transport\n", 0);
  623. try {
  624. if ( FlagOn( IrpContext->Flags, IRP_FLAG_IN_FSD ) ) {
  625. Status = NwPostToFsp( IrpContext, TRUE );
  626. try_return( Status );
  627. }
  628. if (IpxHandle != NULL) {
  629. //
  630. // Can only bind to one transport at a time in this implementation
  631. //
  632. try_return(Status= STATUS_SHARING_VIOLATION);
  633. }
  634. //
  635. // Check some fields in the input buffer.
  636. //
  637. if (InputBufferLength < sizeof(NWR_REQUEST_PACKET)) {
  638. try_return(Status = STATUS_BUFFER_TOO_SMALL);
  639. }
  640. if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
  641. try_return(Status = STATUS_INVALID_PARAMETER);
  642. }
  643. if (InputBufferLength <
  644. (FIELD_OFFSET(NWR_REQUEST_PACKET,Parameters.Bind.TransportName)) +
  645. InputBuffer->Parameters.Bind.TransportNameLength) {
  646. try_return(Status = STATUS_INVALID_PARAMETER);
  647. }
  648. if ( IpxTransportName.Buffer != NULL ) {
  649. FREE_POOL( IpxTransportName.Buffer );
  650. }
  651. Status = SetUnicodeString ( &IpxTransportName,
  652. InputBuffer->Parameters.Bind.TransportNameLength,
  653. InputBuffer->Parameters.Bind.TransportName);
  654. DebugTrace(-1, Dbg, "\"%wZ\"\n", &IpxTransportName);
  655. if ( !NT_SUCCESS(Status) ) {
  656. try_return(Status);
  657. }
  658. Status = IpxOpen();
  659. if ( !NT_SUCCESS(Status) ) {
  660. try_return(Status);
  661. }
  662. //
  663. // Verify that have a large enough stack size.
  664. //
  665. if ( pIpxDeviceObject->StackSize >= FileSystemDeviceObject->StackSize) {
  666. IpxClose();
  667. try_return( Status = STATUS_INVALID_PARAMETER );
  668. }
  669. #ifndef QFE_BUILD
  670. //
  671. // Submit a line change request.
  672. //
  673. SubmitLineChangeRequest();
  674. #endif
  675. //
  676. // Open a handle to IPX.
  677. //
  678. NwPermanentNpScb.Server.Socket = 0;
  679. Status = IPX_Open_Socket( IrpContext, &NwPermanentNpScb.Server );
  680. ASSERT( NT_SUCCESS( Status ) );
  681. Status = SetEventHandler (
  682. IrpContext,
  683. &NwPermanentNpScb.Server,
  684. TDI_EVENT_RECEIVE_DATAGRAM,
  685. &ServerDatagramHandler,
  686. &NwPermanentNpScb );
  687. ASSERT( NT_SUCCESS( Status ) );
  688. IrpContext->pNpScb = &NwPermanentNpScb;
  689. NwRcb.State = RCB_STATE_RUNNING;
  690. try_exit:NOTHING;
  691. } except (EXCEPTION_EXECUTE_HANDLER) {
  692. Status = GetExceptionCode();
  693. }
  694. DebugTrace(-1, Dbg, "Bind to transport\n", 0);
  695. return Status;
  696. ******************/
  697. }
  698. VOID
  699. HandleTdiBindMessage(
  700. IN PUNICODE_STRING DeviceName
  701. )
  702. /*+++
  703. Description: This function is the bind handler for NetPnP
  704. support. This function is registered with TDI and is called
  705. whenever a transport starts up or stops. We watch for IPX
  706. coming and going and do the appropriate thing.
  707. See also: HandleTdiUnbindMessage()
  708. ---*/
  709. {
  710. NTSTATUS Status;
  711. PIRP_CONTEXT IrpContext = NULL;
  712. PIRP pIrp = NULL;
  713. PAGED_CODE();
  714. //
  715. // See if this is IPX requesting a bind. We only bind to NwLnkIpx.
  716. //
  717. if ( !RtlEqualUnicodeString( &TdiIpxDeviceName, DeviceName, TRUE ) ) {
  718. DebugTrace( 0, Dbg, "Ignoring PnP Bind request for %wZ\n", DeviceName );
  719. return;
  720. }
  721. //
  722. // Make sure we aren't already bound.
  723. //
  724. if ( ( NwRcb.State != RCB_STATE_NEED_BIND ) ||
  725. ( IpxHandle != NULL ) ) {
  726. DebugTrace( 0, Dbg, "Discarding duplicate PnP bind request.\n", 0 );
  727. return;
  728. }
  729. ASSERT( IpxTransportName.Buffer == NULL );
  730. ASSERT( pIpxDeviceObject == NULL );
  731. Status = DuplicateUnicodeStringWithString ( &IpxTransportName,
  732. DeviceName,
  733. PagedPool );
  734. if ( !NT_SUCCESS( Status ) ) {
  735. DebugTrace( 0, Dbg, "Failing IPX bind: Can't set device name.\n", 0 );
  736. return;
  737. }
  738. //
  739. // Open IPX.
  740. //
  741. Status = IpxOpen();
  742. if ( !NT_SUCCESS( Status ) ) {
  743. goto ExitWithCleanup;
  744. }
  745. //
  746. // Verify that have a large enough stack size.
  747. //
  748. if ( pIpxDeviceObject->StackSize >= FileSystemDeviceObject->StackSize) {
  749. Status = STATUS_INVALID_PARAMETER;
  750. goto ExitWithCleanup;
  751. }
  752. //
  753. // Submit a line change request.
  754. //
  755. SubmitLineChangeRequest();
  756. //
  757. // Allocate an irp and irp context. AllocateIrpContext may raise status.
  758. //
  759. pIrp = ALLOCATE_IRP( pIpxDeviceObject->StackSize, FALSE );
  760. if ( pIrp == NULL ) {
  761. Status = STATUS_INSUFFICIENT_RESOURCES;
  762. goto ExitWithCleanup;
  763. }
  764. try {
  765. IrpContext = AllocateIrpContext( pIrp );
  766. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  767. Status = STATUS_INSUFFICIENT_RESOURCES;
  768. goto ExitWithCleanup;
  769. }
  770. ASSERT( IrpContext != NULL );
  771. //
  772. // Open a handle to IPX for the permanent scb.
  773. //
  774. NwPermanentNpScb.Server.Socket = 0;
  775. Status = IPX_Open_Socket( IrpContext, &NwPermanentNpScb.Server );
  776. ASSERT( NT_SUCCESS( Status ) );
  777. Status = SetEventHandler (
  778. IrpContext,
  779. &NwPermanentNpScb.Server,
  780. TDI_EVENT_RECEIVE_DATAGRAM,
  781. &ServerDatagramHandler,
  782. &NwPermanentNpScb );
  783. ASSERT( NT_SUCCESS( Status ) );
  784. IrpContext->pNpScb = &NwPermanentNpScb;
  785. NwRcb.State = RCB_STATE_RUNNING;
  786. DebugTrace( 0, Dbg, "Opened IPX for NwRdr.\n", 0 );
  787. Status = STATUS_SUCCESS;
  788. ExitWithCleanup:
  789. if ( !NT_SUCCESS( Status ) ) {
  790. //
  791. // If we failed, clean up our globals.
  792. //
  793. if ( pIpxDeviceObject != NULL ) {
  794. IpxClose();
  795. pIpxDeviceObject = NULL;
  796. }
  797. IpxHandle = NULL;
  798. if ( IpxTransportName.Buffer != NULL ) {
  799. FREE_POOL( IpxTransportName.Buffer );
  800. IpxTransportName.Buffer = NULL;
  801. }
  802. DebugTrace( 0, Dbg, "Failing IPX bind request.\n", 0 );
  803. }
  804. if ( pIrp != NULL ) {
  805. FREE_IRP( pIrp );
  806. }
  807. if ( IrpContext != NULL ) {
  808. IrpContext->pOriginalIrp = NULL; // Avoid FreeIrpContext modifying freed Irp.
  809. FreeIrpContext( IrpContext );
  810. }
  811. return;
  812. }
  813. VOID
  814. HandleTdiUnbindMessage(
  815. IN PUNICODE_STRING DeviceName
  816. )
  817. /*+++
  818. Description: This function is the unbind handler for NetPnP
  819. support. This function is registered with TDI and is called
  820. whenever a transport stops. We watch for IPX coming and going
  821. and do the appropriate thing.
  822. See also: HandleTdiBindMessage()
  823. ---*/
  824. {
  825. DebugTrace( 0, Dbg, "TDI unbind request ignored. Not Supported.\n", 0 );
  826. return;
  827. }
  828. #endif
  829. NTSTATUS
  830. ChangePassword (
  831. IN PIRP_CONTEXT IrpContext
  832. )
  833. /*++
  834. Routine Description:
  835. This routine records a change in the user's cached password.
  836. Arguments:
  837. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  838. Return Value:
  839. NTSTATUS
  840. --*/
  841. {
  842. NTSTATUS Status;
  843. PIRP Irp = IrpContext->pOriginalIrp;
  844. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  845. PNWR_REQUEST_PACKET InputBuffer = Irp->AssociatedIrp.SystemBuffer;
  846. ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  847. UNICODE_STRING UserName;
  848. UNICODE_STRING Password;
  849. UNICODE_STRING ServerName;
  850. LARGE_INTEGER Uid;
  851. PAGED_CODE();
  852. DebugTrace(+1, Dbg, "change password\n", 0);
  853. try {
  854. //
  855. // Check some fields in the input buffer.
  856. //
  857. if (InputBufferLength < sizeof(NWR_REQUEST_PACKET)) {
  858. try_return(Status = STATUS_BUFFER_TOO_SMALL);
  859. }
  860. if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
  861. try_return(Status = STATUS_INVALID_PARAMETER);
  862. }
  863. if (InputBufferLength <
  864. (FIELD_OFFSET(NWR_REQUEST_PACKET,Parameters.ChangePass.UserName)) +
  865. InputBuffer->Parameters.ChangePass.UserNameLength +
  866. InputBuffer->Parameters.ChangePass.PasswordLength +
  867. InputBuffer->Parameters.ChangePass.ServerNameLength ) {
  868. try_return(Status = STATUS_INVALID_PARAMETER);
  869. }
  870. //
  871. // Get local pointer to the fsctl parameters
  872. //
  873. UserName.Buffer = InputBuffer->Parameters.ChangePass.UserName;
  874. UserName.Length = (USHORT)InputBuffer->Parameters.ChangePass.UserNameLength;
  875. Password.Buffer = UserName.Buffer +
  876. (InputBuffer->Parameters.ChangePass.UserNameLength / 2);
  877. Password.Length = (USHORT)InputBuffer->Parameters.ChangePass.PasswordLength;
  878. ServerName.Buffer = Password.Buffer +
  879. (InputBuffer->Parameters.ChangePass.PasswordLength / 2);
  880. ServerName.Length = (USHORT)InputBuffer->Parameters.ChangePass.ServerNameLength;
  881. //
  882. // Update the default password for this user
  883. //
  884. Status = UpdateUsersPassword( &UserName, &Password, &Uid );
  885. //
  886. // Update the default password for this user
  887. //
  888. if ( NT_SUCCESS( Status ) ) {
  889. UpdateServerPassword( IrpContext, &ServerName, &UserName, &Password, &Uid );
  890. }
  891. Status = STATUS_SUCCESS;
  892. try_exit:NOTHING;
  893. } except (EXCEPTION_EXECUTE_HANDLER) {
  894. Status = GetExceptionCode();
  895. }
  896. DebugTrace(-1, Dbg, "Change Password\n", 0);
  897. return Status;
  898. }
  899. NTSTATUS
  900. SetInfo (
  901. IN PIRP_CONTEXT IrpContext
  902. )
  903. /*++
  904. Routine Description:
  905. This routine set netware redirector parameters.
  906. Arguments:
  907. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  908. Return Value:
  909. NTSTATUS
  910. --*/
  911. {
  912. NTSTATUS Status = STATUS_SUCCESS;
  913. PIRP Irp = IrpContext->pOriginalIrp;
  914. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  915. PNWR_REQUEST_PACKET InputBuffer = Irp->AssociatedIrp.SystemBuffer;
  916. ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  917. SECURITY_SUBJECT_CONTEXT SubjectContext;
  918. PLOGON Logon;
  919. LARGE_INTEGER Uid;
  920. PAGED_CODE();
  921. SeCaptureSubjectContext(&SubjectContext);
  922. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  923. Uid = GetUid( &SubjectContext );
  924. Logon = FindUser( &Uid, TRUE );
  925. NwReleaseRcb( &NwRcb );
  926. SeReleaseSubjectContext(&SubjectContext);
  927. DebugTrace(+1, Dbg, "Set info\n", 0);
  928. try {
  929. //
  930. // Check some fields in the input buffer.
  931. //
  932. if (InputBufferLength < sizeof(NWR_REQUEST_PACKET)) {
  933. try_return(Status = STATUS_BUFFER_TOO_SMALL);
  934. }
  935. if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
  936. try_return(Status = STATUS_INVALID_PARAMETER);
  937. }
  938. if (InputBufferLength <
  939. (FIELD_OFFSET(NWR_REQUEST_PACKET,Parameters.SetInfo.PreferredServer)) +
  940. InputBuffer->Parameters.SetInfo.PreferredServerLength +
  941. InputBuffer->Parameters.SetInfo.ProviderNameLength ) {
  942. try_return(Status = STATUS_INVALID_PARAMETER);
  943. }
  944. //
  945. // We don't do anything with a preferred server change, but if we
  946. // get a request to change the preferred tree and context, we
  947. // validate the context. The rest of the changes happen at the next
  948. // login.
  949. //
  950. if ( InputBuffer->Parameters.SetInfo.PreferredServerLength > 0 &&
  951. InputBuffer->Parameters.SetInfo.PreferredServer[0] == '*' ) {
  952. UNICODE_STRING Tree, NewContext;
  953. USHORT i = 0;
  954. //
  955. // Dig out the tree name. Skip over the *.
  956. //
  957. Tree.Length = 0;
  958. Tree.Buffer = InputBuffer->Parameters.SetInfo.PreferredServer + 1;
  959. while ( i < InputBuffer->Parameters.SetInfo.PreferredServerLength ) {
  960. if ( InputBuffer->Parameters.SetInfo.PreferredServer[i] == L'\\' ) {
  961. i++;
  962. Tree.Length -= sizeof( WCHAR );
  963. Tree.MaximumLength = Tree.Length;
  964. break;
  965. } else {
  966. Tree.Length += sizeof( WCHAR );
  967. i++;
  968. }
  969. }
  970. DebugTrace( 0, Dbg, "Tree: %wZ\n", &Tree );
  971. NewContext.Length = (USHORT)InputBuffer->Parameters.SetInfo.PreferredServerLength -
  972. ( Tree.Length + (2 * sizeof( WCHAR ) ) );
  973. NewContext.Buffer = &InputBuffer->Parameters.SetInfo.PreferredServer[i];
  974. NewContext.MaximumLength = NewContext.Length;
  975. //
  976. // Strip off any leading period.
  977. //
  978. if ( NewContext.Buffer[0] == L'.' ) {
  979. NewContext.Buffer++;
  980. NewContext.Length -= sizeof( WCHAR );
  981. NewContext.MaximumLength -= sizeof( WCHAR );
  982. }
  983. DebugTrace( 0, Dbg, "Context: %wZ\n", &NewContext );
  984. Status = NdsVerifyContext( IrpContext, &Tree, &NewContext );
  985. if ( !NT_SUCCESS( Status )) {
  986. try_return( STATUS_INVALID_PARAMETER );
  987. }
  988. }
  989. //
  990. // Next set the provider name string.
  991. //
  992. if ( InputBuffer->Parameters.SetInfo.ProviderNameLength != 0 ) {
  993. PWCH TempBuffer;
  994. TempBuffer = ALLOCATE_POOL_EX( PagedPool, InputBuffer->Parameters.SetInfo.ProviderNameLength );
  995. if ( NwProviderName.Buffer != NULL ) {
  996. FREE_POOL( NwProviderName.Buffer );
  997. }
  998. NwProviderName.Buffer = TempBuffer;
  999. NwProviderName.Length = (USHORT)InputBuffer->Parameters.SetInfo.ProviderNameLength;
  1000. RtlCopyMemory(
  1001. NwProviderName.Buffer,
  1002. (PUCHAR)InputBuffer->Parameters.SetInfo.PreferredServer +
  1003. InputBuffer->Parameters.SetInfo.PreferredServerLength,
  1004. NwProviderName.Length );
  1005. }
  1006. //
  1007. // Set burst mode parameters
  1008. //
  1009. if ( InputBuffer->Parameters.SetInfo.MaximumBurstSize == 0 ) {
  1010. NwBurstModeEnabled = FALSE;
  1011. } else if ( InputBuffer->Parameters.SetInfo.MaximumBurstSize != -1 ) {
  1012. NwBurstModeEnabled = TRUE;
  1013. NwMaxSendSize = InputBuffer->Parameters.SetInfo.MaximumBurstSize;
  1014. NwMaxReceiveSize = InputBuffer->Parameters.SetInfo.MaximumBurstSize;
  1015. }
  1016. //
  1017. // Set print options
  1018. //
  1019. //--- Multi-User modification: ------
  1020. // The NwPrintOption is per "Logon" based
  1021. //
  1022. if ( Logon != NULL ) {
  1023. Logon->NwPrintOptions = InputBuffer->Parameters.SetInfo.PrintOption;
  1024. }
  1025. try_exit:NOTHING;
  1026. } except (EXCEPTION_EXECUTE_HANDLER) {
  1027. Status = GetExceptionCode();
  1028. }
  1029. DebugTrace(-1, Dbg, "Set info\n", 0);
  1030. return Status;
  1031. }
  1032. NTSTATUS
  1033. GetMessage (
  1034. IN PIRP_CONTEXT IrpContext
  1035. )
  1036. /*++
  1037. Routine Description:
  1038. This routine queues an IRP to a list of IRP Contexts available for
  1039. reading server administrative messages.
  1040. Arguments:
  1041. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  1042. Return Value:
  1043. NTSTATUS
  1044. --*/
  1045. {
  1046. NTSTATUS Status = STATUS_PENDING;
  1047. PIRP Irp = IrpContext->pOriginalIrp;
  1048. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  1049. ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  1050. PVOID OutputBuffer;
  1051. KIRQL OldIrql;
  1052. DebugTrace(+1, Dbg, "GetMessage\n", 0);
  1053. //
  1054. // Lock the output buffer - handle any invalid
  1055. // buffer values here
  1056. //
  1057. try {
  1058. NwLockUserBuffer( Irp, IoWriteAccess, OutputBufferLength );
  1059. NwMapUserBuffer( Irp, KernelMode, (PVOID *)&OutputBuffer );
  1060. } except (EXCEPTION_EXECUTE_HANDLER) {
  1061. return GetExceptionCode();
  1062. }
  1063. //
  1064. // tommye MS bug 26590 / MCS 258
  1065. //
  1066. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  1067. // situations; this was not being checked.
  1068. //
  1069. if (OutputBuffer == NULL) {
  1070. Status = STATUS_INSUFFICIENT_RESOURCES;
  1071. }
  1072. else {
  1073. //
  1074. // Update the original MDL record in the Irp context, since
  1075. // NwLockUserBuffer may have created a new MDL.
  1076. //
  1077. IrpContext->pOriginalMdlAddress = Irp->MdlAddress;
  1078. IrpContext->Specific.FileSystemControl.Buffer = OutputBuffer;
  1079. IrpContext->Specific.FileSystemControl.Length = OutputBufferLength;
  1080. KeAcquireSpinLock( &NwMessageSpinLock, &OldIrql );
  1081. //
  1082. // tommye MS 17200 / MCS 366
  1083. //
  1084. // Go ahead and get the cancel lock, this will keep
  1085. // someone from cancelling the Irp while we're in here.
  1086. //
  1087. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  1088. //
  1089. // tommye
  1090. //
  1091. // If this Irp is cancelled, we're done
  1092. //
  1093. if (Irp->Cancel) {
  1094. Status = STATUS_CANCELLED;
  1095. } else {
  1096. InsertTailList( &NwGetMessageList, &IrpContext->NextRequest );
  1097. IoMarkIrpPending( Irp );
  1098. //
  1099. // tommye
  1100. //
  1101. // Set the cancel routine and release the cancel lock
  1102. //
  1103. IoSetCancelRoutine( Irp, NwCancelIrp );
  1104. }
  1105. IoReleaseCancelSpinLock( Irp->CancelIrql );
  1106. KeReleaseSpinLock( &NwMessageSpinLock, OldIrql );
  1107. }
  1108. DebugTrace(-1, Dbg, "Get Message -> %08lx\n", Status );
  1109. return Status;
  1110. }
  1111. NTSTATUS
  1112. GetStats (
  1113. IN PIRP_CONTEXT IrpContext
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. This routine copies Stats into the users buffer.
  1118. Arguments:
  1119. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  1120. Return Value:
  1121. NTSTATUS
  1122. --*/
  1123. {
  1124. NTSTATUS Status = STATUS_PENDING;
  1125. PIRP Irp = IrpContext->pOriginalIrp;
  1126. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  1127. ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  1128. PVOID OutputBuffer;
  1129. PAGED_CODE();
  1130. DebugTrace(+1, Dbg, "GetStats\n", 0);
  1131. NwMapUserBuffer( Irp, KernelMode, (PVOID *)&OutputBuffer );
  1132. //
  1133. // tommye
  1134. //
  1135. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  1136. // situations; this was not being checked.
  1137. //
  1138. if (OutputBuffer == NULL) {
  1139. Status = STATUS_INSUFFICIENT_RESOURCES;
  1140. }
  1141. else {
  1142. if (NwRcb.State != RCB_STATE_RUNNING) {
  1143. Status = STATUS_REDIRECTOR_NOT_STARTED;
  1144. } else if (OutputBufferLength < sizeof(NW_REDIR_STATISTICS)) {
  1145. Status = STATUS_BUFFER_TOO_SMALL;
  1146. } else if (OutputBufferLength != sizeof(NW_REDIR_STATISTICS)) {
  1147. Status = STATUS_INVALID_PARAMETER;
  1148. } else {
  1149. Stats.CurrentCommands = ContextCount;
  1150. try {
  1151. RtlCopyMemory(OutputBuffer, &Stats, OutputBufferLength);
  1152. Irp->IoStatus.Information = OutputBufferLength;
  1153. Status = STATUS_SUCCESS;
  1154. }
  1155. except (EXCEPTION_EXECUTE_HANDLER) {
  1156. Status = GetExceptionCode();
  1157. }
  1158. }
  1159. }
  1160. DebugTrace(-1, Dbg, "GetStats -> %08lx\n", Status );
  1161. return Status;
  1162. }
  1163. NTSTATUS
  1164. GetPrintJobId (
  1165. IN PIRP_CONTEXT IrpContext
  1166. )
  1167. /*++
  1168. Routine Description:
  1169. This routine gets the Job ID for this job.
  1170. Arguments:
  1171. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  1172. Return Value:
  1173. NTSTATUS
  1174. --*/
  1175. {
  1176. NTSTATUS Status = STATUS_PENDING;
  1177. PIRP Irp = IrpContext->pOriginalIrp;
  1178. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  1179. ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  1180. PQUERY_PRINT_JOB_INFO OutputBuffer;
  1181. PICB Icb;
  1182. PVOID FsContext;
  1183. NODE_TYPE_CODE NodeTypeCode;
  1184. PAGED_CODE();
  1185. DebugTrace(+1, Dbg, "GetJobId\n", 0);
  1186. NodeTypeCode = NwDecodeFileObject(
  1187. IrpSp->FileObject,
  1188. &FsContext,
  1189. (PVOID *)&Icb );
  1190. if (NodeTypeCode != NW_NTC_ICB) {
  1191. DebugTrace(0, Dbg, "Not a file\n", 0);
  1192. Status = STATUS_INVALID_PARAMETER;
  1193. } else if ( OutputBufferLength < sizeof( QUERY_PRINT_JOB_INFO ) ) {
  1194. Status = STATUS_BUFFER_TOO_SMALL;
  1195. } else {
  1196. NwMapUserBuffer( Irp, KernelMode, (PVOID *)&OutputBuffer );
  1197. //
  1198. // tommye
  1199. //
  1200. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  1201. // situations; this was not being checked.
  1202. //
  1203. if (OutputBuffer == NULL) {
  1204. Status = STATUS_INSUFFICIENT_RESOURCES;
  1205. }
  1206. else {
  1207. try {
  1208. OutputBuffer->JobId = Icb->JobId;
  1209. Status = STATUS_SUCCESS;
  1210. }
  1211. except (EXCEPTION_EXECUTE_HANDLER) {
  1212. Status = GetExceptionCode();
  1213. }
  1214. }
  1215. }
  1216. DebugTrace(-1, Dbg, "GetJobId -> %08lx\n", Status );
  1217. return Status;
  1218. }
  1219. NTSTATUS
  1220. GetConnectionDetails(
  1221. IN PIRP_CONTEXT IrpContext
  1222. )
  1223. /*++
  1224. Routine Description:
  1225. This routine gets the details for a connection. This is normally used
  1226. for support of NetWare aware Dos applications.
  1227. Arguments:
  1228. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  1229. Return Value:
  1230. NTSTATUS
  1231. --*/
  1232. {
  1233. NTSTATUS Status = STATUS_PENDING;
  1234. PIRP Irp = IrpContext->pOriginalIrp;
  1235. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  1236. ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  1237. PNWR_GET_CONNECTION_DETAILS OutputBuffer;
  1238. PSCB pScb;
  1239. PNONPAGED_SCB pNpScb;
  1240. PICB Icb;
  1241. PVOID FsContext;
  1242. NODE_TYPE_CODE nodeTypeCode;
  1243. PAGED_CODE();
  1244. DebugTrace(+1, Dbg, "GetConnectionDetails\n", 0);
  1245. if ((nodeTypeCode = NwDecodeFileObject( IrpSp->FileObject,
  1246. &FsContext,
  1247. (PVOID *)&Icb )) != NW_NTC_ICB_SCB) {
  1248. DebugTrace(0, Dbg, "Incorrect nodeTypeCode %x\n", nodeTypeCode);
  1249. Status = STATUS_INVALID_PARAMETER;
  1250. DebugTrace(-1, Dbg, "GetConnectionDetails -> %08lx\n", Status );
  1251. return Status;
  1252. }
  1253. //
  1254. // Make sure that this ICB is still active.
  1255. //
  1256. NwVerifyIcb( Icb );
  1257. pScb = (PSCB)Icb->SuperType.Scb;
  1258. nodeTypeCode = pScb->NodeTypeCode;
  1259. if (nodeTypeCode != NW_NTC_SCB) {
  1260. return STATUS_INVALID_DEVICE_REQUEST;
  1261. }
  1262. pNpScb = pScb->pNpScb;
  1263. if ( OutputBufferLength < sizeof( NWR_GET_CONNECTION_DETAILS ) ) {
  1264. Status = STATUS_BUFFER_TOO_SMALL;
  1265. } else {
  1266. PLIST_ENTRY ScbQueueEntry;
  1267. KIRQL OldIrql;
  1268. PNONPAGED_SCB pNextNpScb;
  1269. UCHAR OrderNumber;
  1270. OEM_STRING ServerName;
  1271. NwMapUserBuffer( Irp, KernelMode, (PVOID *)&OutputBuffer );
  1272. //
  1273. // tommye
  1274. //
  1275. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  1276. // situations; this was not being checked.
  1277. //
  1278. if (OutputBuffer == NULL) {
  1279. Status = STATUS_INSUFFICIENT_RESOURCES;
  1280. }
  1281. else {
  1282. KeAcquireSpinLock(&ScbSpinLock, &OldIrql);
  1283. for ( ScbQueueEntry = ScbQueue.Flink, OrderNumber = 1;
  1284. ScbQueueEntry != &ScbQueue ;
  1285. ScbQueueEntry = ScbQueueEntry->Flink, OrderNumber++ ) {
  1286. pNextNpScb = CONTAINING_RECORD(
  1287. ScbQueueEntry,
  1288. NONPAGED_SCB,
  1289. ScbLinks );
  1290. //
  1291. // Check to make sure that this SCB is usable.
  1292. //
  1293. if ( pNextNpScb == pNpScb ) {
  1294. break;
  1295. }
  1296. }
  1297. KeReleaseSpinLock( &ScbSpinLock, OldIrql);
  1298. try {
  1299. OutputBuffer->OrderNumber = OrderNumber;
  1300. RtlZeroMemory( OutputBuffer->ServerName, sizeof(OutputBuffer->ServerName));
  1301. ServerName.Buffer = OutputBuffer->ServerName;
  1302. ServerName.Length = sizeof(OutputBuffer->ServerName);
  1303. ServerName.MaximumLength = sizeof(OutputBuffer->ServerName);
  1304. RtlUpcaseUnicodeStringToCountedOemString( &ServerName, &pNpScb->ServerName, FALSE);
  1305. RtlCopyMemory( OutputBuffer->ServerAddress,
  1306. &pNpScb->ServerAddress,
  1307. sizeof(OutputBuffer->ServerAddress) );
  1308. OutputBuffer->ServerAddress[12];
  1309. OutputBuffer->ConnectionNumberLo = pNpScb->ConnectionNo;
  1310. OutputBuffer->ConnectionNumberHi = pNpScb->ConnectionNoHigh;
  1311. //
  1312. // tommye - MS 71688
  1313. //
  1314. // Changed this from hard-coded '4' and '11' to use the
  1315. // values in pScb.
  1316. //
  1317. OutputBuffer->MajorVersion = pScb->MajorVersion;
  1318. OutputBuffer->MinorVersion = pScb->MinorVersion;
  1319. OutputBuffer->Preferred = pScb->PreferredServer;
  1320. Status = STATUS_SUCCESS;
  1321. }
  1322. except (EXCEPTION_EXECUTE_HANDLER) {
  1323. Status = GetExceptionCode();
  1324. }
  1325. }
  1326. }
  1327. DebugTrace(-1, Dbg, "GetConnectionDetails -> %08lx\n", Status );
  1328. return Status;
  1329. }
  1330. #if 0
  1331. NTSTATUS
  1332. GetOurAddress(
  1333. IN PIRP_CONTEXT IrpContext
  1334. )
  1335. /*++
  1336. Routine Description:
  1337. This routine gets the value of OurAddress. This is normally used
  1338. for support of NetWare aware Dos applications.
  1339. Arguments:
  1340. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  1341. Return Value:
  1342. NTSTATUS
  1343. --*/
  1344. {
  1345. NTSTATUS Status = STATUS_PENDING;
  1346. PIRP Irp = IrpContext->pOriginalIrp;
  1347. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  1348. ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  1349. PNWR_GET_OUR_ADDRESS OutputBuffer;
  1350. PSCB pScb;
  1351. PNONPAGED_SCB pNpScb;
  1352. PICB Icb;
  1353. PVOID FsContext;
  1354. NODE_TYPE_CODE nodeTypeCode;
  1355. DebugTrace(+1, Dbg, "GetOurAddress\n", 0);
  1356. if ((nodeTypeCode = NwDecodeFileObject( IrpSp->FileObject,
  1357. &FsContext,
  1358. (PVOID *)&Icb )) != NW_NTC_ICB_SCB) {
  1359. DebugTrace(0, Dbg, "Incorrect nodeTypeCode %x\n", nodeTypeCode);
  1360. Status = STATUS_INVALID_PARAMETER;
  1361. DebugTrace(-1, Dbg, "GetOurAddress -> %08lx\n", Status );
  1362. }
  1363. //
  1364. // Make sure that this ICB is still active.
  1365. //
  1366. NwVerifyIcb( Icb );
  1367. if ( OutputBufferLength < sizeof( NWR_GET_OUR_ADDRESS ) ) {
  1368. Status = STATUS_BUFFER_TOO_SMALL;
  1369. } else {
  1370. NwMapUserBuffer( Irp, KernelMode, (PVOID *)&OutputBuffer );
  1371. //
  1372. // tommye
  1373. //
  1374. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  1375. // situations; this was not being checked.
  1376. //
  1377. if (OutputBuffer == NULL) {
  1378. Status = STATUS_INSUFFICIENT_RESOURCES;
  1379. }
  1380. else {
  1381. try {
  1382. RtlCopyMemory( OutputBuffer->Address,
  1383. &OurAddress,
  1384. sizeof(OurAddress );
  1385. Status = STATUS_SUCCESS;
  1386. }
  1387. except (EXCEPTION_EXECUTE_HANDLER) {
  1388. Status = GetExceptionCode();
  1389. }
  1390. }
  1391. }
  1392. DebugTrace(-1, Dbg, "GetOurAddress -> %08lx\n", Status );
  1393. return Status;
  1394. }
  1395. #endif
  1396. #ifndef _PNP_POWER_
  1397. NTSTATUS
  1398. StartRedirector(
  1399. PIRP_CONTEXT IrpContext
  1400. )
  1401. /*++
  1402. Routine Description:
  1403. This routine starts the redirector.
  1404. Arguments:
  1405. None.
  1406. Return Value:
  1407. NTSTATUS - The status of the operation.
  1408. --*/
  1409. {
  1410. NTSTATUS Status;
  1411. PAGED_CODE();
  1412. //
  1413. // We need to be in the FSP to Register the MUP.
  1414. //
  1415. if ( FlagOn( IrpContext->Flags, IRP_FLAG_IN_FSD ) ) {
  1416. Status = NwPostToFsp( IrpContext, TRUE );
  1417. return( Status );
  1418. }
  1419. // -- MultiUser ---
  1420. // Logoff and disconnect from all servers.
  1421. // This makes very sure we do this. The workstation is having a
  1422. // hard time deleting other user's connections. Also (at least on
  1423. // slow debugging systems) RCB_STATE_SHUTDOWN cannot be on.
  1424. //
  1425. NwLogoffAllServers( IrpContext, NULL );
  1426. NwRcb.State = RCB_STATE_STARTING;
  1427. FspProcess = PsGetCurrentProcess();
  1428. #ifdef QFE_BUILD
  1429. StartTimer() ;
  1430. #endif
  1431. //
  1432. // Now connect to the MUP.
  1433. //
  1434. RegisterWithMup();
  1435. KeQuerySystemTime( &Stats.StatisticsStartTime );
  1436. NwRcb.State = RCB_STATE_NEED_BIND;
  1437. return( STATUS_SUCCESS );
  1438. }
  1439. NTSTATUS
  1440. StopRedirector(
  1441. PIRP_CONTEXT IrpContext
  1442. )
  1443. /*++
  1444. Routine Description:
  1445. This routine shuts down the redirector.
  1446. Arguments:
  1447. None.
  1448. Return Value:
  1449. NTSTATUS - The status of the operation.
  1450. --*/
  1451. {
  1452. NTSTATUS Status;
  1453. PLIST_ENTRY LogonListEntry;
  1454. ULONG ActiveHandles;
  1455. ULONG RcbOpenCount;
  1456. PAGED_CODE();
  1457. //
  1458. // We need to be in the FSP to Deregister the MUP.
  1459. //
  1460. if ( FlagOn( IrpContext->Flags, IRP_FLAG_IN_FSD ) ) {
  1461. Status = NwPostToFsp( IrpContext, TRUE );
  1462. return( Status );
  1463. }
  1464. //
  1465. // Unregister the bind handler with tdi.
  1466. //
  1467. if ( TdiBindingHandle != NULL ) {
  1468. TdiDeregisterNotificationHandler( TdiBindingHandle );
  1469. TdiBindingHandle = NULL;
  1470. }
  1471. NwRcb.State = RCB_STATE_SHUTDOWN;
  1472. //
  1473. // Invalid all ICBs
  1474. //
  1475. SetFlag( IrpContext->Flags, IRP_FLAG_SEND_ALWAYS );
  1476. ActiveHandles = NwInvalidateAllHandles(NULL, IrpContext);
  1477. //
  1478. // To expedite shutdown, set retry count down to 2.
  1479. //
  1480. DefaultRetryCount = 2;
  1481. //
  1482. // Close all VCBs
  1483. //
  1484. NwCloseAllVcbs( IrpContext );
  1485. //
  1486. // Logoff and disconnect from all servers.
  1487. //
  1488. NwLogoffAllServers( IrpContext, NULL );
  1489. while ( !IsListEmpty( &LogonList ) ) {
  1490. LogonListEntry = RemoveHeadList( &LogonList );
  1491. FreeLogon(CONTAINING_RECORD( LogonListEntry, LOGON, Next ));
  1492. }
  1493. InsertTailList( &LogonList, &Guest.Next ); // just in-case we don't unload.
  1494. StopTimer();
  1495. IpxClose();
  1496. //
  1497. // Remember the open count before calling DeristerWithMup since this
  1498. // will asynchronously cause handle count to get decremented.
  1499. //
  1500. RcbOpenCount = NwRcb.OpenCount;
  1501. DeregisterWithMup( );
  1502. DebugTrace(0, Dbg, "StopRedirector: Active handle count = %d\n", ActiveHandles );
  1503. //
  1504. // On shutdown, we need 0 remote handles and 2 open handles to
  1505. // the redir (one for the service, and one for the MUP) and the timer stopped.
  1506. //
  1507. if ( ActiveHandles == 0 && RcbOpenCount <= 2 ) {
  1508. return( STATUS_SUCCESS );
  1509. } else {
  1510. return( STATUS_REDIRECTOR_HAS_OPEN_HANDLES );
  1511. }
  1512. }
  1513. #endif
  1514. NTSTATUS
  1515. RegisterWithMup(
  1516. VOID
  1517. )
  1518. /*++
  1519. Routine Description:
  1520. This routine register this redirector as a UNC provider.
  1521. Arguments:
  1522. None.
  1523. Return Value:
  1524. NTSTATUS - The status of the operation.
  1525. --*/
  1526. {
  1527. NTSTATUS Status = STATUS_SUCCESS;
  1528. UNICODE_STRING RdrName;
  1529. HANDLE LocalMupHandle = 0;
  1530. PAGED_CODE();
  1531. RtlInitUnicodeString( &RdrName, DD_NWFS_DEVICE_NAME_U );
  1532. //
  1533. // tommye MS 29173 / MCS 362
  1534. //
  1535. // We had a problem with us getting in here twice; since
  1536. // there was no lock, the MupHandle got registered twice
  1537. // and we would leak when we shut down. Because we didn't
  1538. // know if a lock would affect stability around the register
  1539. // call, we'll go ahead and register using a local handle.
  1540. // If we don't have our global handle, then we'll set it to
  1541. // the local. Otherwise, we'll just clean up the local and
  1542. // pretend everything is fine. MUP_LOCK macros are defined
  1543. // at the top of this file.
  1544. //
  1545. if (MupHandle == 0) {
  1546. Status = FsRtlRegisterUncProvider(
  1547. &LocalMupHandle,
  1548. &RdrName,
  1549. FALSE // Do not support mailslots
  1550. );
  1551. /** Lock **/
  1552. ACQUIRE_MUP_LOCK();
  1553. if (MupHandle) {
  1554. RELEASE_MUP_LOCK();
  1555. FsRtlDeregisterUncProvider( LocalMupHandle );
  1556. return STATUS_SUCCESS;
  1557. }
  1558. else {
  1559. MupHandle = LocalMupHandle;
  1560. }
  1561. /** Unlock **/
  1562. RELEASE_MUP_LOCK();
  1563. }
  1564. return( Status );
  1565. }
  1566. VOID
  1567. DeregisterWithMup(
  1568. VOID
  1569. )
  1570. /*++
  1571. Routine Description:
  1572. This routine deregisters this redirector as a UNC provider.
  1573. Arguments:
  1574. None.
  1575. Return Value:
  1576. None.
  1577. --*/
  1578. {
  1579. PAGED_CODE();
  1580. if (MupHandle)
  1581. {
  1582. FsRtlDeregisterUncProvider( MupHandle );
  1583. MupHandle = 0;
  1584. }
  1585. }
  1586. NTSTATUS
  1587. QueryPath(
  1588. PIRP_CONTEXT IrpContext
  1589. )
  1590. /*++
  1591. Routine Description:
  1592. This routine verifies whether a path is a netware path.
  1593. Arguments:
  1594. IrpContext - A pointer to IRP context information for this request.
  1595. Return Value:
  1596. None.
  1597. --*/
  1598. {
  1599. PIRP Irp;
  1600. PIO_STACK_LOCATION IrpSp;
  1601. PQUERY_PATH_REQUEST qpRequest;
  1602. PQUERY_PATH_RESPONSE qpResponse;
  1603. UNICODE_STRING FilePathName;
  1604. ULONG OutputBufferLength;
  1605. ULONG InputBufferLength;
  1606. SECURITY_SUBJECT_CONTEXT SubjectContext;
  1607. UNICODE_STRING DriveName;
  1608. UNICODE_STRING ServerName;
  1609. UNICODE_STRING VolumeName;
  1610. UNICODE_STRING PathName;
  1611. UNICODE_STRING FileName;
  1612. UNICODE_STRING UnicodeUid;
  1613. WCHAR DriveLetter;
  1614. DWORD BaseRequestSize = FIELD_OFFSET(QUERY_PATH_REQUEST, FilePathName);
  1615. NTSTATUS status;
  1616. PAGED_CODE();
  1617. DebugTrace(+1, Dbg, "QueryPath...\n", 0);
  1618. ASSERT (( IOCTL_REDIR_QUERY_PATH & 3) == METHOD_NEITHER);
  1619. RtlInitUnicodeString( &UnicodeUid, NULL );
  1620. try {
  1621. Irp = IrpContext->pOriginalIrp;
  1622. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1623. OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  1624. InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  1625. //
  1626. // The input buffer is either in Irp->AssociatedIrp.SystemBuffer, or
  1627. // in the Type3InputBuffer for type 3 IRP's.
  1628. //
  1629. qpRequest = (PQUERY_PATH_REQUEST)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  1630. qpResponse = (PQUERY_PATH_RESPONSE)qpRequest;
  1631. if ((qpRequest == NULL) ||
  1632. (InputBufferLength < BaseRequestSize) ||
  1633. (OutputBufferLength < sizeof(QUERY_PATH_RESPONSE))) {
  1634. return STATUS_INVALID_PARAMETER;
  1635. }
  1636. //
  1637. // Probe before trying to read the request. This will make sure
  1638. // we don't bugcheck when given a bogus address like 0xffff0000.
  1639. //
  1640. if ( Irp->RequestorMode != KernelMode ) {
  1641. try {
  1642. DWORD FullSize;
  1643. DebugTrace(+1, Dbg, "QueryPath...Probing for Read 1\n", 0);
  1644. ProbeForRead( qpRequest,
  1645. BaseRequestSize,
  1646. sizeof(ULONG)
  1647. );
  1648. DebugTrace(+1, Dbg, "QueryPath...Probing for Read 2\n", 0);
  1649. //
  1650. // Check for the full length of the request including
  1651. // the filename
  1652. //
  1653. FullSize = BaseRequestSize + qpRequest->PathNameLength;
  1654. if (InputBufferLength < FullSize) {
  1655. try_return( status = STATUS_INVALID_PARAMETER );
  1656. }
  1657. ProbeForRead( qpRequest,
  1658. FullSize,
  1659. sizeof(ULONG)
  1660. );
  1661. } except (EXCEPTION_EXECUTE_HANDLER) {
  1662. return GetExceptionCode();
  1663. }
  1664. }
  1665. try {
  1666. FilePathName.Buffer = qpRequest->FilePathName;
  1667. FilePathName.Length = (USHORT)qpRequest->PathNameLength;
  1668. status = CrackPath( &FilePathName, &DriveName, &DriveLetter, &ServerName, &VolumeName, &PathName, &FileName, NULL );
  1669. if (( !NT_SUCCESS( status ) ) ||
  1670. ( ServerName.Length == 0 )) {
  1671. try_return( status = STATUS_BAD_NETWORK_PATH );
  1672. }
  1673. qpResponse->LengthAccepted = VolumeName.Length;
  1674. //
  1675. // As far as the redirector is concerned, QueryPath is a form
  1676. // of create. Set up the IrpContext appropriately.
  1677. //
  1678. IrpContext->Specific.Create.VolumeName = VolumeName;
  1679. IrpContext->Specific.Create.PathName = PathName;
  1680. IrpContext->Specific.Create.DriveLetter = DriveLetter;
  1681. IrpContext->Specific.Create.FullPathName = FilePathName;
  1682. IrpContext->Specific.Create.fExCredentialCreate = FALSE;
  1683. RtlInitUnicodeString( &IrpContext->Specific.Create.UidConnectName, NULL );
  1684. //
  1685. // The irp context specific data is now zeroed out by AllocateIrpContext,
  1686. // so we don't have to worry about re-setting the specific data here.
  1687. //
  1688. SeCaptureSubjectContext(&SubjectContext);
  1689. IrpContext->Specific.Create.UserUid = GetUid( &SubjectContext );
  1690. SeReleaseSubjectContext(&SubjectContext);
  1691. //
  1692. // The slightly more complicated approach. This function
  1693. // handles the resolution of the server/volume duple. It
  1694. // may use the bindery, cached nds information, or fresh
  1695. // nds information.
  1696. //
  1697. status = HandleVolumeAttach( IrpContext,
  1698. &ServerName,
  1699. &VolumeName );
  1700. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1701. status = STATUS_BAD_NETWORK_PATH;
  1702. }
  1703. try_exit: NOTHING;
  1704. } finally {
  1705. RtlFreeUnicodeString(&UnicodeUid);
  1706. }
  1707. return( status );
  1708. }
  1709. NTSTATUS
  1710. UserNcp(
  1711. ULONG IoctlCode,
  1712. PIRP_CONTEXT IrpContext
  1713. )
  1714. /*++
  1715. Routine Description:
  1716. This routine exchanges an NCP with the server.
  1717. TRACKING - We need to filter or security check what the user is
  1718. doing.
  1719. Arguments:
  1720. IoctlCode - Supplies the code to be used for the NCP.
  1721. IrpContext - A pointer to IRP context information for this request.
  1722. Return Value:
  1723. Status of transfer.
  1724. --*/
  1725. {
  1726. PIRP irp;
  1727. PIO_STACK_LOCATION irpSp;
  1728. PVOID OutputBuffer;
  1729. ULONG OutputBufferLength;
  1730. PCHAR InputBuffer;
  1731. ULONG InputBufferLength;
  1732. PICB icb;
  1733. PSCB pScb;
  1734. NODE_TYPE_CODE nodeTypeCode;
  1735. PVOID fsContext;
  1736. NTSTATUS status = STATUS_UNSUCCESSFUL;
  1737. UCHAR Function = ANY_NCP_OPCODE( IoctlCode );
  1738. UCHAR Subfunction = 0;
  1739. irp = IrpContext->pOriginalIrp;
  1740. irpSp = IoGetCurrentIrpStackLocation( irp );
  1741. OutputBufferLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  1742. InputBufferLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  1743. DebugTrace(+1, DEBUG_TRACE_USERNCP, "UserNcp...\n", 0);
  1744. DebugTrace( 0, DEBUG_TRACE_USERNCP, "irp = %08lx\n", (ULONG_PTR)irp);
  1745. //
  1746. // This F2 and ANY NCP must be addressed either to \Device\NwRdr or
  1747. // \Device\NwRdr\<servername> any additional name is not allowed.
  1748. // If the handle used for the Irp specifies \Device\NwRdr then the
  1749. // redirector gets to choose among the connected servers.
  1750. //
  1751. // For HANDLE NCP the file must be an FCB.
  1752. //
  1753. nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
  1754. &fsContext,
  1755. (PVOID *)&icb );
  1756. if ((nodeTypeCode == NW_NTC_ICB_SCB) &&
  1757. (!IS_IT_NWR_ANY_HANDLE_NCP(IoctlCode))) {
  1758. // All ok
  1759. //
  1760. // Make sure that this ICB is still active.
  1761. //
  1762. NwVerifyIcb( icb );
  1763. pScb = (PSCB)icb->SuperType.Scb;
  1764. nodeTypeCode = pScb->NodeTypeCode;
  1765. IrpContext->pScb = pScb;
  1766. IrpContext->pNpScb = IrpContext->pScb->pNpScb;
  1767. } else if (nodeTypeCode == NW_NTC_ICB) {
  1768. if ((IS_IT_NWR_ANY_HANDLE_NCP(IoctlCode)) &&
  1769. (InputBufferLength < 7)) {
  1770. // Buffer needs enough space for the handle!
  1771. DebugTrace(0, DEBUG_TRACE_USERNCP, "Not enough space for handle %x\n", InputBufferLength);
  1772. status = STATUS_INVALID_PARAMETER;
  1773. DebugTrace(-1, DEBUG_TRACE_USERNCP, "UserNcp -> %08lx\n", status );
  1774. return status;
  1775. }
  1776. //
  1777. // Make sure that this ICB is still active.
  1778. // Let through FCB's and DCB's
  1779. //
  1780. NwVerifyIcb( icb );
  1781. pScb = (PSCB)icb->SuperType.Fcb->Scb;
  1782. nodeTypeCode = icb->SuperType.Fcb->NodeTypeCode;
  1783. IrpContext->pScb = pScb;
  1784. IrpContext->pNpScb = IrpContext->pScb->pNpScb;
  1785. //
  1786. // Set the icb pointer in case the cache gets
  1787. // flushed because the write routines look at it.
  1788. //
  1789. IrpContext->Icb = icb;
  1790. AcquireFcbAndFlushCache( IrpContext, icb->NpFcb );
  1791. } else {
  1792. DebugTrace(0, DEBUG_TRACE_USERNCP, "Incorrect nodeTypeCode %x\n", nodeTypeCode);
  1793. DebugTrace(0, DEBUG_TRACE_USERNCP, "Incorrect nodeTypeCode %x\n", irpSp->FileObject);
  1794. status = STATUS_INVALID_PARAMETER;
  1795. DebugTrace(-1, DEBUG_TRACE_USERNCP, "UserNcp -> %08lx\n", status );
  1796. return status;
  1797. }
  1798. if (icb->Pid == INVALID_PID) {
  1799. status = NwMapPid(pScb->pNpScb, (ULONG_PTR)PsGetCurrentThread(), &icb->Pid );
  1800. if ( !NT_SUCCESS( status ) ) {
  1801. return( status );
  1802. }
  1803. DebugTrace(-1, DEBUG_TRACE_USERNCP, "UserNcp Pid = %02lx\n", icb->Pid );
  1804. NwSetEndOfJobRequired(pScb->pNpScb, icb->Pid);
  1805. }
  1806. //
  1807. // We now know where to send the NCP. Lock down the users buffers and
  1808. // build the Mdls required to transfer the data.
  1809. //
  1810. InputBuffer = irpSp->Parameters.FileSystemControl.Type3InputBuffer;
  1811. //
  1812. // tommye - make sure the input buffer is valid
  1813. //
  1814. try {
  1815. //
  1816. // Probe for safety.
  1817. //
  1818. if ( irp->RequestorMode != KernelMode ) {
  1819. ProbeForRead( InputBuffer,
  1820. InputBufferLength,
  1821. sizeof( CHAR ));
  1822. }
  1823. //
  1824. // Map the output buffer if there is one.
  1825. //
  1826. if ( OutputBufferLength ) {
  1827. NwLockUserBuffer( irp, IoWriteAccess, OutputBufferLength );
  1828. NwMapUserBuffer( irp, KernelMode, (PVOID *)&OutputBuffer );
  1829. //
  1830. // tommye MS bug 26590 / MCS 258
  1831. //
  1832. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  1833. // situations; this was not being checked.
  1834. //
  1835. if (OutputBuffer == NULL) {
  1836. DebugTrace(-1, DEBUG_TRACE_USERNCP, "NwMapUserBuffer returned NULL OutputBuffer", 0);
  1837. return STATUS_INSUFFICIENT_RESOURCES;
  1838. }
  1839. } else {
  1840. OutputBuffer = NULL;
  1841. }
  1842. } except (EXCEPTION_EXECUTE_HANDLER) {
  1843. return GetExceptionCode();
  1844. }
  1845. //
  1846. // Update the original MDL record in the Irp context, since
  1847. // NwLockUserBuffer may have created a new MDL.
  1848. //
  1849. IrpContext->pOriginalMdlAddress = irp->MdlAddress;
  1850. try {
  1851. if (InputBufferLength != 0) {
  1852. if (IS_IT_NWR_ANY_NCP(IoctlCode)) {
  1853. Subfunction = InputBuffer[0];
  1854. } else if (InputBufferLength >= 3) {
  1855. Subfunction = InputBuffer[2];
  1856. }
  1857. }
  1858. }
  1859. except (EXCEPTION_EXECUTE_HANDLER) {
  1860. return GetExceptionCode();
  1861. }
  1862. DebugTrace( 0, DEBUG_TRACE_USERNCP, "UserNcp function = %x\n", Function );
  1863. DebugTrace( 0, DEBUG_TRACE_USERNCP, " & Subfunction = %x\n", Subfunction );
  1864. dump( DEBUG_TRACE_USERNCP, InputBuffer, InputBufferLength );
  1865. //dump( DEBUG_TRACE_USERNCP, OutputBuffer, OutputBufferLength );
  1866. if ((Function == NCP_ADMIN_FUNCTION ) &&
  1867. (InputBufferLength >= 4 )) {
  1868. if ( ( (Subfunction == NCP_SUBFUNC_79) ||
  1869. (Subfunction == NCP_CREATE_QUEUE_JOB ) ) &&
  1870. icb->HasRemoteHandle) {
  1871. //
  1872. // Trying to create a job on a queue that already has a job
  1873. // on it. Cancel the old job.
  1874. //
  1875. status = ExchangeWithWait(
  1876. IrpContext,
  1877. SynchronousResponseCallback,
  1878. "Sdw",
  1879. NCP_ADMIN_FUNCTION, NCP_CLOSE_FILE_AND_CANCEL_JOB, // Close File And Cancel Queue Job
  1880. icb->SuperType.Fcb->Vcb->Specific.Print.QueueId,
  1881. icb->JobId );
  1882. if (!NT_SUCCESS(status)) {
  1883. DebugTrace( 0, DEBUG_TRACE_USERNCP, "DeleteOldJob got status -> %08lx\n", status );
  1884. // Don't worry if the delete fails, proceed with the create
  1885. }
  1886. icb->IsPrintJob = FALSE; // App will have to queue or cancel job, not rdr
  1887. } else if ((Subfunction == NCP_PLAIN_TEXT_LOGIN ) ||
  1888. (Subfunction == NCP_ENCRYPTED_LOGIN )) {
  1889. UNICODE_STRING UserName;
  1890. OEM_STRING OemUserName;
  1891. //
  1892. // Trying to do a login.
  1893. //
  1894. //
  1895. // Queue ourselves to the SCB, and wait to get to the front to
  1896. // protect access to server State.
  1897. //
  1898. NwAppendToQueueAndWait( IrpContext );
  1899. //
  1900. // Assume success, store the user name in the SCB.
  1901. //
  1902. try {
  1903. try {
  1904. OemUserName.Length = InputBuffer[ 13 ];
  1905. OemUserName.Buffer = &InputBuffer[14];
  1906. UserName.MaximumLength = OemUserName.Length * sizeof(WCHAR);
  1907. if ( OemUserName.Length == 0 || OemUserName.Length > MAX_USER_NAME_LENGTH ) {
  1908. try_return( status = STATUS_NO_SUCH_USER );
  1909. }
  1910. UserName.Buffer = ALLOCATE_POOL_EX( NonPagedPool, UserName.MaximumLength );
  1911. //
  1912. // Note the the Rtl function would set pUString->Buffer = NULL,
  1913. // if OemString.Length is 0.
  1914. //
  1915. if ( OemUserName.Length != 0 ) {
  1916. status = RtlOemStringToCountedUnicodeString( &UserName, &OemUserName, FALSE );
  1917. } else {
  1918. UserName.Length = 0;
  1919. }
  1920. try_exit: NOTHING;
  1921. } finally {
  1922. NOTHING;
  1923. }
  1924. }
  1925. except (EXCEPTION_EXECUTE_HANDLER) {
  1926. status = GetExceptionCode();
  1927. }
  1928. if ( NT_SUCCESS( status )) {
  1929. if ( pScb->OpenFileCount != 0 &&
  1930. pScb->pNpScb->State == SCB_STATE_IN_USE ) {
  1931. if (!RtlEqualUnicodeString( &pScb->UserName, &UserName, TRUE )) {
  1932. //
  1933. // But were already logged in to this server and at
  1934. // least one other handle is using the connection and
  1935. // the user is trying to change the username.
  1936. //
  1937. FREE_POOL( UserName.Buffer );
  1938. return STATUS_NETWORK_CREDENTIAL_CONFLICT;
  1939. } else {
  1940. PUCHAR VerifyBuffer = ALLOCATE_POOL( PagedPool, InputBufferLength );
  1941. //
  1942. // Same username. Validate password is correct.
  1943. if (VerifyBuffer == NULL) {
  1944. FREE_POOL( UserName.Buffer );
  1945. return STATUS_INSUFFICIENT_RESOURCES;
  1946. }
  1947. RtlCopyMemory( VerifyBuffer, InputBuffer, InputBufferLength );
  1948. if (IS_IT_NWR_ANY_NCP(IoctlCode)) {
  1949. VerifyBuffer[0] = (Subfunction == NCP_PLAIN_TEXT_LOGIN ) ?
  1950. NCP_PLAIN_TEXT_VERIFY_PASSWORD:
  1951. NCP_ENCRYPTED_VERIFY_PASSWORD;
  1952. } else {
  1953. VerifyBuffer[2] = (Subfunction == NCP_PLAIN_TEXT_LOGIN ) ?
  1954. NCP_PLAIN_TEXT_VERIFY_PASSWORD:
  1955. NCP_ENCRYPTED_VERIFY_PASSWORD;
  1956. }
  1957. status = ExchangeWithWait(
  1958. IrpContext,
  1959. SynchronousResponseCallback,
  1960. IS_IT_NWR_ANY_NCP(IoctlCode)? "Sr":"Fbr",
  1961. Function, VerifyBuffer[0],
  1962. &VerifyBuffer[1], InputBufferLength - 1 );
  1963. FREE_POOL( UserName.Buffer );
  1964. FREE_POOL( VerifyBuffer );
  1965. return status;
  1966. }
  1967. }
  1968. if (pScb->UserName.Buffer) {
  1969. FREE_POOL( pScb->UserName.Buffer ); // May include space for password too.
  1970. }
  1971. IrpContext->pNpScb->pScb->UserName = UserName;
  1972. IrpContext->pNpScb->pScb->Password.Buffer = UserName.Buffer;
  1973. IrpContext->pNpScb->pScb->Password.Length = 0;
  1974. } else {
  1975. return( status );
  1976. }
  1977. }
  1978. } else if (Function == NCP_LOGOUT ) {
  1979. //
  1980. // Queue ourselves to the SCB, and wait to get to the front to
  1981. // protect access to server State.
  1982. //
  1983. NwAppendToQueueAndWait( IrpContext );
  1984. if ( pScb->OpenFileCount == 0 &&
  1985. pScb->pNpScb->State == SCB_STATE_IN_USE &&
  1986. !pScb->PreferredServer ) {
  1987. NwLogoffAndDisconnect( IrpContext, pScb->pNpScb);
  1988. return STATUS_SUCCESS;
  1989. } else {
  1990. return(STATUS_CONNECTION_IN_USE);
  1991. }
  1992. }
  1993. IrpContext->Icb = icb;
  1994. //
  1995. // Remember where the response goes.
  1996. //
  1997. IrpContext->Specific.FileSystemControl.Buffer = OutputBuffer;
  1998. IrpContext->Specific.FileSystemControl.Length = OutputBufferLength;
  1999. IrpContext->Specific.FileSystemControl.Function = Function;
  2000. IrpContext->Specific.FileSystemControl.Subfunction = Subfunction;
  2001. //
  2002. // Decide how to send the buffer. If it is small enough, send it
  2003. // by copying the user buffer to our send buffer. If it is bigger
  2004. // we will need to build an MDL for the user's buffer, and used a
  2005. // chained send.
  2006. //
  2007. if ( InputBufferLength == 0 ) {
  2008. // Simple request such as systime.exe
  2009. IrpContext->Specific.FileSystemControl.InputMdl = NULL;
  2010. status = Exchange(
  2011. IrpContext,
  2012. UserNcpCallback,
  2013. "F", Function);
  2014. } else if ( InputBufferLength < MAX_SEND_DATA - sizeof( NCP_REQUEST ) - 2 ) {
  2015. //
  2016. // Send the request by copying it to our send buffer.
  2017. //
  2018. IrpContext->Specific.FileSystemControl.InputMdl = NULL;
  2019. if (!IS_IT_NWR_ANY_HANDLE_NCP(IoctlCode)) {
  2020. //
  2021. // E0, E1, E2 and E3 get mapped to 14,15,16 and 17. These need
  2022. // a length word before the buffer.
  2023. //
  2024. try {
  2025. status = Exchange(
  2026. IrpContext,
  2027. UserNcpCallback,
  2028. IS_IT_NWR_ANY_NCP(IoctlCode)? "Sr":"Fbr",
  2029. Function, InputBuffer[0],
  2030. &InputBuffer[1], InputBufferLength - 1 );
  2031. }
  2032. except (EXCEPTION_EXECUTE_HANDLER) {
  2033. status = GetExceptionCode();
  2034. }
  2035. } else {
  2036. //
  2037. // Replace the 6 bytes of InputBuffer starting at offset 1
  2038. // with the 6 byte NetWare address for this icb. This request
  2039. // is used in some of the 16 bit NCP's used for file locking.
  2040. // These requests are always fairly small.
  2041. //
  2042. if (!icb->HasRemoteHandle) {
  2043. return STATUS_INVALID_HANDLE;
  2044. }
  2045. try {
  2046. status = Exchange(
  2047. IrpContext,
  2048. UserNcpCallback,
  2049. "Fbrr",
  2050. Function,
  2051. InputBuffer[0],
  2052. &icb->Handle, sizeof(icb->Handle),
  2053. &InputBuffer[7], InputBufferLength - 7 );
  2054. }
  2055. except (EXCEPTION_EXECUTE_HANDLER) {
  2056. status = GetExceptionCode();
  2057. }
  2058. }
  2059. } else {
  2060. PMDL pMdl = NULL;
  2061. if (IS_IT_NWR_ANY_HANDLE_NCP(IoctlCode)) {
  2062. return STATUS_INVALID_PARAMETER;
  2063. }
  2064. //
  2065. // We need to chain send the request. Allocate an MDL.
  2066. //
  2067. try {
  2068. try {
  2069. pMdl = ALLOCATE_MDL(
  2070. &InputBuffer[1],
  2071. InputBufferLength - 1,
  2072. TRUE, // Secondary MDL
  2073. TRUE, // Charge quota
  2074. NULL );
  2075. if ( pMdl == NULL ) {
  2076. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  2077. }
  2078. MmProbeAndLockPages( pMdl, irp->RequestorMode, IoReadAccess );
  2079. //
  2080. // Remember the MDL so we can free it.
  2081. //
  2082. IrpContext->Specific.FileSystemControl.InputMdl = pMdl;
  2083. //
  2084. // Send the request.
  2085. //
  2086. status = Exchange(
  2087. IrpContext,
  2088. UserNcpCallback,
  2089. IS_IT_NWR_ANY_NCP(IoctlCode)? "Sf":"Fbf",
  2090. Function, InputBuffer[0],
  2091. pMdl );
  2092. }
  2093. except (EXCEPTION_EXECUTE_HANDLER) {
  2094. status = GetExceptionCode();
  2095. }
  2096. } finally {
  2097. if ((status != STATUS_PENDING ) &&
  2098. ( pMdl != NULL)) {
  2099. FREE_MDL( pMdl );
  2100. }
  2101. }
  2102. }
  2103. DebugTrace(-1, DEBUG_TRACE_USERNCP, "UserNcp -> %08lx\n", status );
  2104. return status;
  2105. }
  2106. NTSTATUS
  2107. UserNcpCallback (
  2108. IN PIRP_CONTEXT IrpContext,
  2109. IN ULONG BytesAvailable,
  2110. IN PUCHAR Response
  2111. )
  2112. /*++
  2113. Routine Description:
  2114. This routine receives the response from a user NCP.
  2115. Arguments:
  2116. Return Value:
  2117. VOID
  2118. --*/
  2119. {
  2120. NTSTATUS Status = STATUS_SUCCESS;
  2121. PVOID Buffer;
  2122. ULONG BufferLength;
  2123. PIRP Irp;
  2124. ULONG Length;
  2125. PICB Icb = IrpContext->Icb;
  2126. PEPresponse *pResponseParameters;
  2127. DebugTrace(0, DEBUG_TRACE_USERNCP, "UserNcpCallback...\n", 0);
  2128. if ( IrpContext->Specific.FileSystemControl.InputMdl != NULL ) {
  2129. MmUnlockPages( IrpContext->Specific.FileSystemControl.InputMdl );
  2130. FREE_MDL( IrpContext->Specific.FileSystemControl.InputMdl );
  2131. }
  2132. if ( BytesAvailable == 0) {
  2133. //
  2134. // No response from server. Status is in pIrpContext->
  2135. // ResponseParameters.Error
  2136. //
  2137. NwDequeueIrpContext( IrpContext, FALSE );
  2138. NwCompleteRequest( IrpContext, STATUS_REMOTE_NOT_LISTENING );
  2139. return STATUS_REMOTE_NOT_LISTENING;
  2140. }
  2141. dump( DEBUG_TRACE_USERNCP, Response, BytesAvailable );
  2142. Buffer = IrpContext->Specific.FileSystemControl.Buffer;
  2143. BufferLength = IrpContext->Specific.FileSystemControl.Length;
  2144. //
  2145. // Get the data from the response.
  2146. //
  2147. Length = MIN( BufferLength, BytesAvailable - 8 );
  2148. if (IrpContext->Specific.FileSystemControl.Function == NCP_ADMIN_FUNCTION ) {
  2149. if (IrpContext->Specific.FileSystemControl.Subfunction == NCP_SUBFUNC_79) {
  2150. //
  2151. // Create Queue Job and File Ncp. If the operation was a success
  2152. // then we need to save the handle. This will allow Write Irps
  2153. // on this Icb to be sent to the server.
  2154. //
  2155. Status = ParseResponse(
  2156. IrpContext,
  2157. Response,
  2158. BytesAvailable,
  2159. "N_r",
  2160. 0x3E,
  2161. Icb->Handle+2,4);
  2162. // Pad the handle to its full 6 bytes.
  2163. Icb->Handle[0] = 0;
  2164. Icb->Handle[1] = 0;
  2165. if (NT_SUCCESS(Status)) {
  2166. Icb->HasRemoteHandle = TRUE;
  2167. }
  2168. //
  2169. // Reset the file offset.
  2170. //
  2171. Icb->FileObject->CurrentByteOffset.QuadPart = 0;
  2172. } else if (IrpContext->Specific.FileSystemControl.Subfunction == NCP_CREATE_QUEUE_JOB ) {
  2173. //
  2174. // Create Queue Job and File Ncp. If the operation was a success
  2175. // then we need to save the handle. This will allow Write Irps
  2176. // on this Icb to be sent to the server.
  2177. //
  2178. Status = ParseResponse(
  2179. IrpContext,
  2180. Response,
  2181. BytesAvailable,
  2182. "N_r",
  2183. 0x2A,
  2184. Icb->Handle,6);
  2185. if (NT_SUCCESS(Status)) {
  2186. Icb->HasRemoteHandle = TRUE;
  2187. }
  2188. //
  2189. // Reset the file offset.
  2190. //
  2191. Icb->FileObject->CurrentByteOffset.QuadPart = 0;
  2192. } else if ((IrpContext->Specific.FileSystemControl.Subfunction == NCP_SUBFUNC_7F) ||
  2193. (IrpContext->Specific.FileSystemControl.Subfunction == NCP_CLOSE_FILE_AND_START_JOB )) {
  2194. // End Job request
  2195. Icb->HasRemoteHandle = FALSE;
  2196. } else if ((IrpContext->Specific.FileSystemControl.Subfunction == NCP_PLAIN_TEXT_LOGIN ) ||
  2197. (IrpContext->Specific.FileSystemControl.Subfunction == NCP_ENCRYPTED_LOGIN )) {
  2198. //
  2199. // Trying to do a login from a 16 bit application.
  2200. //
  2201. Status = ParseResponse(
  2202. IrpContext,
  2203. Response,
  2204. BytesAvailable,
  2205. "N" );
  2206. if ( NT_SUCCESS( Status ) ) {
  2207. //
  2208. // Set the reconnect attempt flag so that we don't try to
  2209. // run this irp context through the reconnect logic. Doing
  2210. // this could deadlock the worker thread that's handling this
  2211. // fsp side request.
  2212. //
  2213. SetFlag( IrpContext->Flags, IRP_FLAG_RECONNECT_ATTEMPT );
  2214. IrpContext->PostProcessRoutine = FspCompleteLogin;
  2215. Status = NwPostToFsp( IrpContext, TRUE );
  2216. return Status;
  2217. } else {
  2218. if (IrpContext->pNpScb->pScb->UserName.Buffer) {
  2219. FREE_POOL( IrpContext->pNpScb->pScb->UserName.Buffer );
  2220. }
  2221. RtlInitUnicodeString( &IrpContext->pNpScb->pScb->UserName, NULL);
  2222. RtlInitUnicodeString( &IrpContext->pNpScb->pScb->Password, NULL);
  2223. }
  2224. }
  2225. }
  2226. pResponseParameters = (PEPresponse *)( ((PEPrequest *)Response) + 1);
  2227. ParseResponse( IrpContext, Response, BytesAvailable, "Nr", Buffer, Length );
  2228. Status = ( ( pResponseParameters->status &
  2229. ( NCP_STATUS_BAD_CONNECTION |
  2230. NCP_STATUS_NO_CONNECTIONS |
  2231. NCP_STATUS_SERVER_DOWN ) ) << 8 ) |
  2232. pResponseParameters->error;
  2233. if ( Status ) {
  2234. //
  2235. // Use the special error code that will cause conversion
  2236. // of the status back to a Dos error code to leave status and
  2237. // error unchanged. This is necessary because many of the
  2238. // NetWare error codes have different meanings depending on the
  2239. // operation being performed.
  2240. //
  2241. Status |= 0xc0010000;
  2242. }
  2243. Irp = IrpContext->pOriginalIrp;
  2244. Irp->IoStatus.Information = Length;
  2245. //
  2246. // We're done with this request. Dequeue the IRP context from
  2247. // SCB and complete the request.
  2248. //
  2249. NwDequeueIrpContext( IrpContext, FALSE );
  2250. NwCompleteRequest( IrpContext, Status );
  2251. return STATUS_SUCCESS;
  2252. }
  2253. NTSTATUS
  2254. FspCompleteLogin(
  2255. PIRP_CONTEXT IrpContext
  2256. )
  2257. /*++
  2258. Routine Description:
  2259. This routine reopens any Vcb directory handles.
  2260. It also sets the Scb as in use. This could have been done
  2261. in the callback routine too.
  2262. Arguments:
  2263. None.
  2264. Return Value:
  2265. NTSTATUS - The status of the operation.
  2266. --*/
  2267. {
  2268. IrpContext->pNpScb->State = SCB_STATE_IN_USE;
  2269. ReconnectScb( IrpContext, IrpContext->pScb );
  2270. return STATUS_SUCCESS;
  2271. }
  2272. NTSTATUS
  2273. GetConnection(
  2274. PIRP_CONTEXT IrpContext
  2275. )
  2276. /*++
  2277. Routine Description:
  2278. This routine returns the path of a connection.
  2279. Arguments:
  2280. None.
  2281. Return Value:
  2282. NTSTATUS - The status of the operation.
  2283. --*/
  2284. {
  2285. NTSTATUS Status;
  2286. PIRP Irp;
  2287. PIO_STACK_LOCATION IrpSp;
  2288. PNWR_SERVER_RESOURCE OutputBuffer;
  2289. PNWR_REQUEST_PACKET InputBuffer;
  2290. ULONG InputBufferLength;
  2291. ULONG OutputBufferLength;
  2292. PVCB Vcb;
  2293. PWCH DriveName;
  2294. ULONG DriveNameLength;
  2295. PVCB * DriveMapTable;
  2296. SECURITY_SUBJECT_CONTEXT SubjectContext;
  2297. PAGED_CODE();
  2298. DebugTrace(0, Dbg, "GetConnection...\n", 0);
  2299. Irp = IrpContext->pOriginalIrp;
  2300. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2301. InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  2302. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  2303. if ( InputBufferLength < (ULONG)FIELD_OFFSET( NWR_REQUEST_PACKET, Parameters.GetConn.DeviceName[1] ) ) {
  2304. return( STATUS_INVALID_PARAMETER );
  2305. }
  2306. Status = STATUS_SUCCESS;
  2307. //---Multi user----
  2308. // Need to get the Uid in order to find the proper DriveMapTable
  2309. //
  2310. SeCaptureSubjectContext(&SubjectContext);
  2311. DriveMapTable = GetDriveMapTable( GetUid( &SubjectContext ) );
  2312. SeReleaseSubjectContext(&SubjectContext);
  2313. //-----
  2314. //
  2315. // Find the VCB
  2316. //
  2317. try {
  2318. if ( Irp->RequestorMode != KernelMode ) {
  2319. ProbeForRead( InputBuffer,
  2320. InputBufferLength,
  2321. sizeof(CHAR)
  2322. );
  2323. }
  2324. DriveName = InputBuffer->Parameters.GetConn.DeviceName;
  2325. DriveNameLength = InputBuffer->Parameters.GetConn.DeviceNameLength;
  2326. Vcb = NULL;
  2327. //
  2328. // check the device name length to see if its sound. This subtraction can't underflow because of the tests above
  2329. //
  2330. if ( DriveNameLength > InputBufferLength - FIELD_OFFSET( NWR_REQUEST_PACKET, Parameters.GetConn.DeviceName) ) {
  2331. return STATUS_INVALID_PARAMETER;
  2332. }
  2333. if ( DriveName[0] >= L'A' && DriveName[0] <= L'Z' &&
  2334. DriveName[1] == L':' &&
  2335. DriveNameLength == sizeof( L"X:" ) - sizeof( L'\0' ) ) {
  2336. Vcb = DriveMapTable[DriveName[0] - 'A'];
  2337. } else if ( _wcsnicmp( DriveName, L"LPT", 3 ) == 0 &&
  2338. DriveName[3] >= '1' && DriveName[3] <= '9' &&
  2339. DriveNameLength == sizeof( L"LPTX" ) - sizeof( L'\0' ) ) {
  2340. Vcb = DriveMapTable[MAX_DISK_REDIRECTIONS + DriveName[3] - '1'];
  2341. }
  2342. if ( Vcb == NULL) {
  2343. return STATUS_NO_SUCH_FILE;
  2344. }
  2345. OutputBuffer = (PNWR_SERVER_RESOURCE)Irp->UserBuffer;
  2346. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  2347. if (OutputBufferLength < Vcb->Path.Length + 2 * sizeof(WCHAR)) {
  2348. InputBuffer->Parameters.GetConn.BytesNeeded =
  2349. Vcb->Path.Length + 2 * sizeof(WCHAR);
  2350. return STATUS_BUFFER_TOO_SMALL;
  2351. }
  2352. //
  2353. // Probe to ensure that the buffer is kosher.
  2354. //
  2355. if ( Irp->RequestorMode != KernelMode ) {
  2356. ProbeForWrite( OutputBuffer,
  2357. OutputBufferLength,
  2358. sizeof(CHAR)
  2359. );
  2360. }
  2361. //
  2362. // Return the Connection name in the form \\server\share<NUL>
  2363. //
  2364. OutputBuffer->UncName[0] = L'\\';
  2365. RtlMoveMemory(
  2366. &OutputBuffer->UncName[1],
  2367. Vcb->Path.Buffer,
  2368. Vcb->Path.Length );
  2369. OutputBuffer->UncName[ (Vcb->Path.Length + sizeof(WCHAR)) / sizeof(WCHAR) ] = L'\0';
  2370. Irp->IoStatus.Information = Vcb->Path.Length + 2 * sizeof(WCHAR);
  2371. } except (EXCEPTION_EXECUTE_HANDLER) {
  2372. return GetExceptionCode();
  2373. }
  2374. return( Status );
  2375. }
  2376. NTSTATUS
  2377. DeleteConnection(
  2378. PIRP_CONTEXT IrpContext
  2379. )
  2380. /*++
  2381. Routine Description:
  2382. This routine returns removes a connection if force is specified or
  2383. if there are no open handles on this Vcb.
  2384. Arguments:
  2385. None.
  2386. Return Value:
  2387. NTSTATUS - The status of the operation.
  2388. --*/
  2389. {
  2390. NTSTATUS Status;
  2391. PIRP Irp;
  2392. PIO_STACK_LOCATION IrpSp;
  2393. PNWR_REQUEST_PACKET InputBuffer;
  2394. ULONG InputBufferLength;
  2395. PICB Icb;
  2396. PVCB Vcb;
  2397. PDCB Dcb;
  2398. PNONPAGED_DCB NonPagedDcb;
  2399. NODE_TYPE_CODE NodeTypeCode;
  2400. PAGED_CODE();
  2401. DebugTrace(0, Dbg, "DeleteConnection...\n", 0);
  2402. Irp = IrpContext->pOriginalIrp;
  2403. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2404. InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  2405. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  2406. if ( InputBufferLength < (ULONG)FIELD_OFFSET( NWR_REQUEST_PACKET, Parameters.GetConn.DeviceName[1] ) ) {
  2407. return( STATUS_INVALID_PARAMETER );
  2408. }
  2409. Status = STATUS_SUCCESS;
  2410. //
  2411. // Wait to get to the head of the SCB queue. We do this in case
  2412. // we need to disconnect, so that we can send packets with the RCB
  2413. // resource held.
  2414. //
  2415. NodeTypeCode = NwDecodeFileObject( IrpSp->FileObject, &NonPagedDcb, &Icb );
  2416. if ( NodeTypeCode == NW_NTC_ICB_SCB ) {
  2417. IrpContext->pNpScb = Icb->SuperType.Scb->pNpScb;
  2418. } else if ( NodeTypeCode == NW_NTC_ICB ) {
  2419. IrpContext->pNpScb = Icb->SuperType.Fcb->Scb->pNpScb;
  2420. Dcb = NonPagedDcb->Fcb;
  2421. } else {
  2422. return( STATUS_INVALID_PARAMETER );
  2423. }
  2424. NwAppendToQueueAndWait( IrpContext );
  2425. ClearFlag( IrpContext->Flags, IRP_FLAG_RECONNECTABLE );
  2426. //
  2427. // Acquire exclusive access to the RCB.
  2428. //
  2429. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  2430. try {
  2431. //
  2432. // Get the a referenced pointer to the node and make sure it is
  2433. // not being closed, and that it is a directory handle.
  2434. //
  2435. if ( NodeTypeCode == NW_NTC_ICB_SCB ) {
  2436. if ( Icb->IsTreeHandle ) {
  2437. //
  2438. // Do an NDS logoff. This will release the RCB.
  2439. //
  2440. Status = NdsLogoff( IrpContext );
  2441. DebugTrace( 0, Dbg, "Nds tree logoff -> %08lx\n", Status );
  2442. } else {
  2443. DebugTrace( 0, Dbg, "Delete connection to SCB %X\n", Icb->SuperType.Scb );
  2444. Status = TreeDisconnectScb( IrpContext, Icb->SuperType.Scb );
  2445. DebugTrace(-1, Dbg, "DeleteConnection -> %08lx\n", Status );
  2446. }
  2447. try_return( NOTHING );
  2448. } else if ( NodeTypeCode != NW_NTC_ICB ||
  2449. Dcb == NULL ||
  2450. ( Dcb->NodeTypeCode != NW_NTC_DCB &&
  2451. Dcb->NodeTypeCode != NW_NTC_FCB) ) {
  2452. DebugTrace(0, Dbg, "Invalid file handle\n", 0);
  2453. Status = STATUS_INVALID_HANDLE;
  2454. DebugTrace(-1, Dbg, "DeleteConnection -> %08lx\n", Status );
  2455. try_return( NOTHING );
  2456. }
  2457. //
  2458. // Make sure that this ICB is still active.
  2459. //
  2460. NwVerifyIcb( Icb );
  2461. Vcb = Dcb->Vcb;
  2462. DebugTrace(0, Dbg, "Attempt to delete VCB = %08lx\n", Vcb);
  2463. //
  2464. // Vcb->OpenFileCount will be 1, (to account for this DCB), if the
  2465. // connection can be deleted.
  2466. //
  2467. if ( !BooleanFlagOn( Vcb->Flags, VCB_FLAG_EXPLICIT_CONNECTION ) ) {
  2468. DebugTrace(0, Dbg, "Cannot delete unredireced connection\n", 0);
  2469. try_return( Status = STATUS_INVALID_DEVICE_REQUEST );
  2470. } else {
  2471. if ( Vcb->OpenFileCount > 1 ) {
  2472. DebugTrace(0, Dbg, "Cannot delete in use connection\n", 0);
  2473. Status = STATUS_CONNECTION_IN_USE;
  2474. } else {
  2475. //
  2476. // To delete the VCB, simply dereference it.
  2477. //
  2478. DebugTrace(0, Dbg, "Deleting connection\n", 0);
  2479. ClearFlag( Vcb->Flags, VCB_FLAG_EXPLICIT_CONNECTION );
  2480. --Vcb->Scb->OpenFileCount;
  2481. NwDereferenceVcb( Vcb, IrpContext, TRUE );
  2482. }
  2483. }
  2484. try_exit: NOTHING;
  2485. } finally {
  2486. //
  2487. // An NDS logoff will have already freed the RCB
  2488. // and dequeued the irp context.
  2489. //
  2490. if ( ! ( Icb->IsTreeHandle ) ) {
  2491. NwReleaseRcb( &NwRcb );
  2492. NwDequeueIrpContext( IrpContext, FALSE );
  2493. }
  2494. }
  2495. Irp->IoStatus.Information = 0;
  2496. return( Status );
  2497. }
  2498. NTSTATUS
  2499. EnumConnections(
  2500. PIRP_CONTEXT IrpContext
  2501. )
  2502. /*++
  2503. Routine Description:
  2504. This routine returns the list of redirector connections.
  2505. Arguments:
  2506. IrpContext - A pointer to the IRP Context block for this request.
  2507. Return Value:
  2508. NTSTATUS - The status of the operation.
  2509. --*/
  2510. {
  2511. NTSTATUS Status;
  2512. PIRP Irp;
  2513. PIO_STACK_LOCATION IrpSp;
  2514. PNWR_SERVER_RESOURCE OutputBuffer;
  2515. PNWR_REQUEST_PACKET InputBuffer;
  2516. ULONG InputBufferLength;
  2517. ULONG OutputBufferLength;
  2518. PVCB Vcb;
  2519. PSCB Scb;
  2520. BOOLEAN OwnRcb;
  2521. UNICODE_STRING LocalName;
  2522. WCHAR PrintPlaceHolder[] = L"LPT1";
  2523. WCHAR DiskPlaceHolder[] = L"A:";
  2524. UNICODE_STRING ContainerName;
  2525. PCHAR FixedPortion;
  2526. PWCHAR EndOfVariableData;
  2527. ULONG EntrySize;
  2528. ULONG_PTR OrigResumeKey;
  2529. ULONG_PTR NewResumeKey;
  2530. ULONG ShareType;
  2531. ULONG EntriesRead = 0;
  2532. ULONG EntriesRequested;
  2533. ULONG ConnectionType;
  2534. PLIST_ENTRY ListEntry;
  2535. UNICODE_STRING Path;
  2536. SECURITY_SUBJECT_CONTEXT SubjectContext;
  2537. LARGE_INTEGER Uid;
  2538. DebugTrace(0, Dbg, "EnumConnections...\n", 0);
  2539. Irp = IrpContext->pOriginalIrp;
  2540. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2541. InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  2542. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  2543. if ( InputBufferLength < (ULONG)FIELD_OFFSET( NWR_REQUEST_PACKET, Parameters.EnumConn.BytesNeeded ) ) {
  2544. return( STATUS_INVALID_PARAMETER );
  2545. }
  2546. //
  2547. // tommye - MS bug 32155
  2548. // Added ProbeForRead to check input buffers.
  2549. // OutputBuffer has been probed by caller.
  2550. //
  2551. try {
  2552. //
  2553. // Probe for safety.
  2554. //
  2555. if ( Irp->RequestorMode != KernelMode ) {
  2556. ProbeForRead( InputBuffer,
  2557. InputBufferLength,
  2558. sizeof( CHAR ));
  2559. }
  2560. ConnectionType = InputBuffer->Parameters.EnumConn.ConnectionType;
  2561. OutputBuffer = (PNWR_SERVER_RESOURCE)Irp->UserBuffer;
  2562. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  2563. //
  2564. // Probe to ensure that the buffer is kosher.
  2565. //
  2566. if ( Irp->RequestorMode != KernelMode ) {
  2567. ProbeForWrite( OutputBuffer,
  2568. OutputBufferLength,
  2569. sizeof(CHAR));
  2570. }
  2571. // ---- Multiuser ---
  2572. // Get the Uid if passed from above
  2573. if ( ConnectionType & CONNTYPE_UID ) {
  2574. Uid = *(PLARGE_INTEGER)(&InputBuffer->Parameters.EnumConn.Uid);
  2575. }
  2576. EntriesRequested = InputBuffer->Parameters.EnumConn.EntriesRequested;
  2577. OrigResumeKey = InputBuffer->Parameters.EnumConn.ResumeKey;
  2578. NewResumeKey = OrigResumeKey;
  2579. DebugTrace(0, Dbg, "Starting resume key is %d\n", OrigResumeKey );
  2580. } except (EXCEPTION_EXECUTE_HANDLER) {
  2581. return GetExceptionCode();
  2582. }
  2583. Status = STATUS_SUCCESS;
  2584. // ---- Multiuser ---
  2585. // Get the Uid if we don't have it yet
  2586. if (!(ConnectionType & CONNTYPE_UID)) {
  2587. SeCaptureSubjectContext(&SubjectContext);
  2588. Uid = GetUid( &SubjectContext );
  2589. SeReleaseSubjectContext(&SubjectContext);
  2590. }
  2591. try {
  2592. //
  2593. // Acquire shared access to the drive map table.
  2594. //
  2595. NwAcquireSharedRcb( &NwRcb, TRUE );
  2596. OwnRcb = TRUE;
  2597. //
  2598. // Initialize returned strings
  2599. //
  2600. RtlInitUnicodeString( &ContainerName, L"\\" );
  2601. FixedPortion = (PCHAR) OutputBuffer;
  2602. EndOfVariableData = (PWCHAR) ((ULONG_PTR) FixedPortion + OutputBufferLength);
  2603. //
  2604. // Run through the global VCB list looking for redirections.
  2605. //
  2606. for ( ListEntry = GlobalVcbList.Flink;
  2607. ListEntry != &GlobalVcbList &&
  2608. EntriesRequested > EntriesRead &&
  2609. Status == STATUS_SUCCESS ;
  2610. ListEntry = ListEntry->Flink ) {
  2611. Vcb = CONTAINING_RECORD( ListEntry, VCB, GlobalVcbListEntry );
  2612. //
  2613. // Skip connections that we've already enumerated.
  2614. //
  2615. if ( Vcb->SequenceNumber <= OrigResumeKey ) {
  2616. continue;
  2617. }
  2618. /* ---- Multi-user ----
  2619. * Skip connections that are not ours
  2620. */
  2621. if ( Vcb->Scb->UserUid.QuadPart != Uid.QuadPart )
  2622. continue;
  2623. //
  2624. // Skip implicit connections, if they are not requested.
  2625. //
  2626. if ( !(ConnectionType & CONNTYPE_IMPLICIT) &&
  2627. !BooleanFlagOn( Vcb->Flags, VCB_FLAG_EXPLICIT_CONNECTION )) {
  2628. continue;
  2629. }
  2630. //
  2631. // Skip connections that are not requested.
  2632. //
  2633. if (BooleanFlagOn( Vcb->Flags, VCB_FLAG_PRINT_QUEUE )) {
  2634. if ( !( ConnectionType & CONNTYPE_PRINT ))
  2635. continue;
  2636. } else {
  2637. if ( !( ConnectionType & CONNTYPE_DISK ))
  2638. continue;
  2639. }
  2640. if ( Vcb->DriveLetter != 0 ) {
  2641. if (BooleanFlagOn( Vcb->Flags, VCB_FLAG_PRINT_QUEUE )) {
  2642. RtlInitUnicodeString( &LocalName, (PCWSTR) PrintPlaceHolder );
  2643. LocalName.Buffer[3] = Vcb->DriveLetter;
  2644. ShareType = RESOURCETYPE_PRINT;
  2645. } else {
  2646. RtlInitUnicodeString( &LocalName, (PCWSTR) DiskPlaceHolder );
  2647. LocalName.Buffer[0] = Vcb->DriveLetter;
  2648. ShareType = RESOURCETYPE_DISK;
  2649. }
  2650. } else { // No drive letter connection, i.e. UNC Connection
  2651. if (BooleanFlagOn( Vcb->Flags, VCB_FLAG_PRINT_QUEUE ))
  2652. ShareType = RESOURCETYPE_PRINT;
  2653. else
  2654. ShareType = RESOURCETYPE_DISK;
  2655. }
  2656. if ( Vcb->DriveLetter >= L'A' && Vcb->DriveLetter <= L'Z' ) {
  2657. Path.Buffer = Vcb->Name.Buffer + 3;
  2658. Path.Length = Vcb->Name.Length - 6;
  2659. } else if ( Vcb->DriveLetter >= L'1' && Vcb->DriveLetter <= L'9' ) {
  2660. Path.Buffer = Vcb->Name.Buffer + 5;
  2661. Path.Length = Vcb->Name.Length - 10;
  2662. } else {
  2663. Path = Vcb->Name;
  2664. }
  2665. // Strip off the unicode prefix
  2666. Path.Buffer += Vcb->Scb->UnicodeUid.Length/sizeof(WCHAR);
  2667. Path.Length -= Vcb->Scb->UnicodeUid.Length;
  2668. Path.MaximumLength -= Vcb->Scb->UnicodeUid.Length;
  2669. try {
  2670. Status = WriteNetResourceEntry(
  2671. &FixedPortion,
  2672. &EndOfVariableData,
  2673. &ContainerName,
  2674. Vcb->DriveLetter != 0 ? &LocalName : NULL,
  2675. &Path,
  2676. RESOURCE_CONNECTED,
  2677. RESOURCEDISPLAYTYPE_SHARE,
  2678. RESOURCEUSAGE_CONNECTABLE,
  2679. ShareType,
  2680. &EntrySize
  2681. );
  2682. } except (EXCEPTION_EXECUTE_HANDLER) {
  2683. Status = GetExceptionCode();
  2684. }
  2685. if ( Status == STATUS_MORE_ENTRIES ) {
  2686. //
  2687. // Could not write current entry into output buffer.
  2688. //
  2689. try {
  2690. InputBuffer->Parameters.EnumConn.BytesNeeded = EntrySize;
  2691. } except (EXCEPTION_EXECUTE_HANDLER) {
  2692. Status = GetExceptionCode();
  2693. }
  2694. } else if ( Status == STATUS_SUCCESS ) {
  2695. //
  2696. // Note that we've returned the current entry.
  2697. //
  2698. EntriesRead++;
  2699. NewResumeKey = Vcb->SequenceNumber;
  2700. DebugTrace(0, Dbg, "Returning VCB %08lx\n", Vcb );
  2701. DebugTrace(0, Dbg, "Sequence # is %08lx\n", NewResumeKey );
  2702. }
  2703. }
  2704. //
  2705. // Return the Servers we are connected to. This is most important for
  2706. // support of NetWare aware 16 bit apps.
  2707. //
  2708. if ((ConnectionType & CONNTYPE_IMPLICIT) &&
  2709. ( ConnectionType & CONNTYPE_DISK )) {
  2710. KIRQL OldIrql;
  2711. PNONPAGED_SCB pNpScb;
  2712. PLIST_ENTRY NextScbQueueEntry;
  2713. ULONG EnumSequenceNumber = 0x80000000;
  2714. NwReleaseRcb( &NwRcb );
  2715. OwnRcb = FALSE;
  2716. RtlInitUnicodeString( &ContainerName, L"\\\\" );
  2717. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  2718. for ( ListEntry = ScbQueue.Flink;
  2719. ListEntry != &ScbQueue &&
  2720. EntriesRequested > EntriesRead &&
  2721. Status == STATUS_SUCCESS ;
  2722. ListEntry = NextScbQueueEntry ) {
  2723. pNpScb = CONTAINING_RECORD( ListEntry, NONPAGED_SCB, ScbLinks );
  2724. Scb = pNpScb->pScb;
  2725. NwReferenceScb( pNpScb );
  2726. KeReleaseSpinLock(&ScbSpinLock, OldIrql);
  2727. //
  2728. // Skip connections that we've already enumerated.
  2729. //
  2730. if (( EnumSequenceNumber <= OrigResumeKey ) ||
  2731. // ---Mutl-user ---
  2732. // Skip over not ours
  2733. ( ( Scb != NULL ) && ( Scb->UserUid.QuadPart != Uid.QuadPart ) ) ||
  2734. ( pNpScb == &NwPermanentNpScb ) ||
  2735. (( pNpScb->State != SCB_STATE_LOGIN_REQUIRED ) &&
  2736. ( pNpScb->State != SCB_STATE_IN_USE ))) {
  2737. //
  2738. // Move to next entry in the list
  2739. //
  2740. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  2741. NextScbQueueEntry = pNpScb->ScbLinks.Flink;
  2742. NwDereferenceScb( pNpScb );
  2743. EnumSequenceNumber++;
  2744. continue;
  2745. }
  2746. DebugTrace( 0, Dbg, " EnumConnections returning Servername = %wZ\n", &pNpScb->ServerName );
  2747. try {
  2748. Status = WriteNetResourceEntry(
  2749. &FixedPortion,
  2750. &EndOfVariableData,
  2751. &ContainerName,
  2752. NULL,
  2753. &pNpScb->ServerName,
  2754. RESOURCE_CONNECTED,
  2755. RESOURCEDISPLAYTYPE_SHARE,
  2756. RESOURCEUSAGE_CONNECTABLE,
  2757. RESOURCETYPE_DISK,
  2758. &EntrySize
  2759. );
  2760. }
  2761. except (EXCEPTION_EXECUTE_HANDLER) {
  2762. Status = GetExceptionCode();
  2763. }
  2764. if ( Status == STATUS_MORE_ENTRIES ) {
  2765. //
  2766. // Could not write current entry into output buffer.
  2767. //
  2768. try {
  2769. InputBuffer->Parameters.EnumConn.BytesNeeded = EntrySize;
  2770. }
  2771. except (EXCEPTION_EXECUTE_HANDLER) {
  2772. Status = GetExceptionCode();
  2773. }
  2774. } else if ( Status == STATUS_SUCCESS ) {
  2775. //
  2776. // Note that we've returned the current entry.
  2777. //
  2778. EntriesRead++;
  2779. NewResumeKey = EnumSequenceNumber;
  2780. DebugTrace(0, Dbg, "Returning SCB %08lx\n", Scb );
  2781. DebugTrace(0, Dbg, "Sequence # is %08lx\n", NewResumeKey );
  2782. }
  2783. //
  2784. // Move to next entry in the list
  2785. //
  2786. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  2787. NextScbQueueEntry = pNpScb->ScbLinks.Flink;
  2788. NwDereferenceScb( pNpScb );
  2789. EnumSequenceNumber++;
  2790. }
  2791. KeReleaseSpinLock(&ScbSpinLock, OldIrql);
  2792. }
  2793. try {
  2794. InputBuffer->Parameters.EnumConn.EntriesReturned = EntriesRead;
  2795. InputBuffer->Parameters.EnumConn.ResumeKey = NewResumeKey;
  2796. }
  2797. except (EXCEPTION_EXECUTE_HANDLER) {
  2798. Status = GetExceptionCode();
  2799. }
  2800. if ( EntriesRead == 0 ) {
  2801. if (Status == STATUS_SUCCESS) {
  2802. Status = STATUS_NO_MORE_ENTRIES;
  2803. }
  2804. Irp->IoStatus.Information = 0;
  2805. }
  2806. else {
  2807. Irp->IoStatus.Information = OutputBufferLength;
  2808. }
  2809. } finally {
  2810. if (OwnRcb) {
  2811. NwReleaseRcb( &NwRcb );
  2812. }
  2813. }
  2814. return( Status );
  2815. }
  2816. NTSTATUS
  2817. WriteNetResourceEntry(
  2818. IN OUT PCHAR *FixedPortion,
  2819. IN OUT PWCHAR *EndOfVariableData,
  2820. IN PUNICODE_STRING ContainerName OPTIONAL,
  2821. IN PUNICODE_STRING LocalName OPTIONAL,
  2822. IN PUNICODE_STRING RemoteName,
  2823. IN ULONG ScopeFlag,
  2824. IN ULONG DisplayFlag,
  2825. IN ULONG UsageFlag,
  2826. IN ULONG ShareType,
  2827. OUT PULONG EntrySize
  2828. )
  2829. /*++
  2830. Routine Description:
  2831. This function packages a NETRESOURCE entry into the user output buffer.
  2832. Arguments:
  2833. FixedPortion - Supplies a pointer to the output buffer where the next
  2834. entry of the fixed portion of the use information will be written.
  2835. This pointer is updated to point to the next fixed portion entry
  2836. after a NETRESOURCE entry is written.
  2837. EndOfVariableData - Supplies a pointer just off the last available byte
  2838. in the output buffer. This is because the variable portion of the
  2839. user information is written into the output buffer starting from
  2840. the end.
  2841. This pointer is updated after any variable length information is
  2842. written to the output buffer.
  2843. ContainerName - Supplies the full path qualifier to make RemoteName
  2844. a full UNC name.
  2845. LocalName - Supplies the local device name, if any.
  2846. RemoteName - Supplies the remote resource name.
  2847. ScopeFlag - Supplies the flag which indicates whether this is a
  2848. CONNECTED or GLOBALNET resource.
  2849. DisplayFlag - Supplies the flag which tells the UI how to display
  2850. the resource.
  2851. UsageFlag - Supplies the flag which indicates that the RemoteName
  2852. is either a container or a connectable resource or both.
  2853. ShareType - Type of the share connected to, RESOURCETYPE_PRINT or
  2854. RESOURCETYPE_DISK
  2855. EntrySize - Receives the size of the NETRESOURCE entry in bytes.
  2856. Return Value:
  2857. STATUS_SUCCESS - Successfully wrote entry into user buffer.
  2858. STATUS_NO_MEMORY - Failed to allocate work buffer.
  2859. STATUS_MORE_ENTRIES - Buffer was too small to fit entry.
  2860. --*/
  2861. {
  2862. BOOL FitInBuffer = TRUE;
  2863. LPNETRESOURCEW NetR = (LPNETRESOURCEW) *FixedPortion;
  2864. UNICODE_STRING TmpRemote;
  2865. PAGED_CODE();
  2866. *EntrySize = sizeof(NETRESOURCEW) +
  2867. RemoteName->Length + NwProviderName.Length + 2 * sizeof(WCHAR);
  2868. if (ARGUMENT_PRESENT(LocalName)) {
  2869. *EntrySize += LocalName->Length + sizeof(WCHAR);
  2870. }
  2871. if (ARGUMENT_PRESENT(ContainerName)) {
  2872. *EntrySize += ContainerName->Length;
  2873. }
  2874. //
  2875. // See if buffer is large enough to fit the entry.
  2876. //
  2877. if (((ULONG_PTR) *FixedPortion + *EntrySize) >
  2878. (ULONG_PTR) *EndOfVariableData) {
  2879. return STATUS_MORE_ENTRIES;
  2880. }
  2881. NetR->dwScope = ScopeFlag;
  2882. NetR->dwType = ShareType;
  2883. NetR->dwDisplayType = DisplayFlag;
  2884. NetR->dwUsage = UsageFlag;
  2885. NetR->lpComment = NULL;
  2886. //
  2887. // Update fixed entry pointer to next entry.
  2888. //
  2889. (ULONG_PTR) (*FixedPortion) += sizeof(NETRESOURCEW);
  2890. //
  2891. // RemoteName
  2892. //
  2893. if (ARGUMENT_PRESENT(ContainerName)) {
  2894. //
  2895. // Prefix the RemoteName with its container name making the
  2896. // it a fully-qualified UNC name.
  2897. //
  2898. TmpRemote.MaximumLength = RemoteName->Length + ContainerName->Length + sizeof(WCHAR);
  2899. TmpRemote.Buffer = ALLOCATE_POOL(
  2900. PagedPool,
  2901. RemoteName->Length + ContainerName->Length + sizeof(WCHAR)
  2902. );
  2903. if (TmpRemote.Buffer == NULL) {
  2904. return STATUS_NO_MEMORY;
  2905. }
  2906. RtlCopyUnicodeString(&TmpRemote, ContainerName);
  2907. RtlAppendUnicodeStringToString(&TmpRemote, RemoteName);
  2908. }
  2909. else {
  2910. TmpRemote = *RemoteName;
  2911. }
  2912. FitInBuffer = CopyStringToBuffer(
  2913. TmpRemote.Buffer,
  2914. TmpRemote.Length / sizeof(WCHAR),
  2915. (LPCWSTR) *FixedPortion,
  2916. EndOfVariableData,
  2917. &NetR->lpRemoteName
  2918. );
  2919. if (ARGUMENT_PRESENT(ContainerName)) {
  2920. FREE_POOL(TmpRemote.Buffer);
  2921. }
  2922. ASSERT(FitInBuffer);
  2923. //
  2924. // LocalName
  2925. //
  2926. if (ARGUMENT_PRESENT(LocalName)) {
  2927. FitInBuffer = CopyStringToBuffer(
  2928. LocalName->Buffer,
  2929. LocalName->Length / sizeof(WCHAR),
  2930. (LPCWSTR) *FixedPortion,
  2931. EndOfVariableData,
  2932. &NetR->lpLocalName
  2933. );
  2934. ASSERT(FitInBuffer);
  2935. }
  2936. else {
  2937. NetR->lpLocalName = NULL;
  2938. }
  2939. //
  2940. // ProviderName
  2941. //
  2942. FitInBuffer = CopyStringToBuffer(
  2943. NwProviderName.Buffer,
  2944. NwProviderName.Length / sizeof(WCHAR),
  2945. (LPCWSTR) *FixedPortion,
  2946. EndOfVariableData,
  2947. &NetR->lpProvider
  2948. );
  2949. ASSERT(FitInBuffer);
  2950. if (! FitInBuffer) {
  2951. return STATUS_MORE_ENTRIES;
  2952. }
  2953. return STATUS_SUCCESS;
  2954. }
  2955. BOOL
  2956. CopyStringToBuffer(
  2957. IN LPCWSTR SourceString OPTIONAL,
  2958. IN DWORD CharacterCount,
  2959. IN LPCWSTR FixedDataEnd,
  2960. IN OUT LPWSTR *EndOfVariableData,
  2961. OUT LPWSTR *VariableDataPointer
  2962. )
  2963. /*++
  2964. Routine Description:
  2965. This is based on ..\nwlib\NwlibCopyStringToBuffer
  2966. This routine puts a single variable-length string into an output buffer.
  2967. The string is not written if it would overwrite the last fixed structure
  2968. in the buffer.
  2969. Arguments:
  2970. SourceString - Supplies a pointer to the source string to copy into the
  2971. output buffer. If SourceString is null then a pointer to a zero terminator
  2972. is inserted into output buffer.
  2973. CharacterCount - Supplies the length of SourceString, not including zero
  2974. terminator. (This in units of characters - not bytes).
  2975. FixedDataEnd - Supplies a pointer to just after the end of the last
  2976. fixed structure in the buffer.
  2977. EndOfVariableData - Supplies an address to a pointer to just after the
  2978. last position in the output buffer that variable data can occupy.
  2979. Returns a pointer to the string written in the output buffer.
  2980. VariableDataPointer - Supplies a pointer to the place in the fixed
  2981. portion of the output buffer where a pointer to the variable data
  2982. should be written.
  2983. Return Value:
  2984. Returns TRUE if string fits into output buffer, FALSE otherwise.
  2985. --*/
  2986. {
  2987. DWORD CharsNeeded = (CharacterCount + 1);
  2988. PAGED_CODE();
  2989. //
  2990. // Determine if source string will fit, allowing for a zero terminator.
  2991. // If not, just set the pointer to NULL.
  2992. //
  2993. if ((*EndOfVariableData - CharsNeeded) >= FixedDataEnd) {
  2994. //
  2995. // It fits. Move EndOfVariableData pointer up to the location where
  2996. // we will write the string.
  2997. //
  2998. *EndOfVariableData -= CharsNeeded;
  2999. //
  3000. // Copy the string to the buffer if it is not null.
  3001. //
  3002. if (CharacterCount > 0 && SourceString != NULL) {
  3003. (VOID) wcsncpy(*EndOfVariableData, SourceString, CharacterCount);
  3004. }
  3005. //
  3006. // Set the zero terminator.
  3007. //
  3008. *(*EndOfVariableData + CharacterCount) = L'\0';
  3009. //
  3010. // Set up the pointer in the fixed data portion to point to where the
  3011. // string is written.
  3012. //
  3013. *VariableDataPointer = *EndOfVariableData;
  3014. return TRUE;
  3015. }
  3016. else {
  3017. //
  3018. // It doesn't fit. Set the offset to NULL.
  3019. //
  3020. *VariableDataPointer = NULL;
  3021. return FALSE;
  3022. }
  3023. }
  3024. NTSTATUS
  3025. GetRemoteHandle(
  3026. IN PIRP_CONTEXT IrpContext
  3027. )
  3028. /*++
  3029. Routine Description:
  3030. This routine gets the NetWare handle for a Directory. This is used
  3031. for support of NetWare aware Dos applications.
  3032. Arguments:
  3033. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  3034. Return Value:
  3035. NTSTATUS
  3036. --*/
  3037. {
  3038. NTSTATUS Status = STATUS_PENDING;
  3039. PIRP Irp = IrpContext->pOriginalIrp;
  3040. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  3041. ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  3042. PCHAR OutputBuffer;
  3043. PICB Icb;
  3044. PDCB Dcb;
  3045. PVOID FsContext;
  3046. NODE_TYPE_CODE nodeTypeCode;
  3047. PAGED_CODE();
  3048. DebugTrace(+1, Dbg, "GetRemoteHandle\n", 0);
  3049. if ((nodeTypeCode = NwDecodeFileObject( IrpSp->FileObject,
  3050. &FsContext,
  3051. (PVOID *)&Icb )) != NW_NTC_ICB) {
  3052. DebugTrace(0, Dbg, "Incorrect nodeTypeCode %x\n", nodeTypeCode);
  3053. Status = STATUS_INVALID_PARAMETER;
  3054. DebugTrace(-1, Dbg, "GetRemoteHandle -> %08lx\n", Status );
  3055. return Status;
  3056. }
  3057. Dcb = (PDCB)Icb->SuperType.Fcb;
  3058. nodeTypeCode = Dcb->NodeTypeCode;
  3059. if ( nodeTypeCode != NW_NTC_DCB ) {
  3060. DebugTrace(0, Dbg, "Not a directory\n", 0);
  3061. #if 1
  3062. if ( nodeTypeCode != NW_NTC_FCB ) {
  3063. Status = STATUS_INVALID_PARAMETER;
  3064. DebugTrace(-1, Dbg, "GetRemoteHandle -> %08lx\n", Status );
  3065. return Status;
  3066. }
  3067. //
  3068. // Return the 6 byte NetWare handle for this file.
  3069. //
  3070. if (!Icb->HasRemoteHandle) {
  3071. Status = STATUS_INVALID_HANDLE;
  3072. DebugTrace(-1, Dbg, "GetRemoteHandle -> %08lx\n", Status );
  3073. return Status;
  3074. }
  3075. if ( OutputBufferLength < ( 6 * sizeof( CHAR )) ) {
  3076. Status = STATUS_BUFFER_TOO_SMALL;
  3077. DebugTrace(-1, Dbg, "GetRemoteHandle -> %08lx\n", Status );
  3078. return Status;
  3079. }
  3080. NwMapUserBuffer( Irp, KernelMode, (PVOID *)&OutputBuffer );
  3081. //
  3082. // tommye
  3083. //
  3084. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  3085. // situations; this was not being checked.
  3086. //
  3087. if (OutputBuffer == NULL) {
  3088. Status = STATUS_INSUFFICIENT_RESOURCES;
  3089. DebugTrace(-1, Dbg, "GetRemoteHandle -> %08lx\n", Status );
  3090. return Status;
  3091. }
  3092. //
  3093. // Probe the output buffer before touching it.
  3094. //
  3095. try {
  3096. if ( Irp->RequestorMode != KernelMode ) {
  3097. ProbeForWrite( OutputBuffer,
  3098. 6 * sizeof(CHAR),
  3099. sizeof(CHAR)
  3100. );
  3101. }
  3102. RtlCopyMemory( OutputBuffer, Icb->Handle, 6 * sizeof(CHAR));
  3103. } except (EXCEPTION_EXECUTE_HANDLER) {
  3104. return GetExceptionCode();
  3105. }
  3106. IrpContext->pOriginalIrp->IoStatus.Information = 6 * sizeof(CHAR);
  3107. Status = STATUS_SUCCESS;
  3108. DebugTrace(-1, Dbg, "GetRemoteHandle -> %08lx\n", Status );
  3109. return Status;
  3110. #else
  3111. Status = STATUS_INVALID_PARAMETER;
  3112. DebugTrace(-1, Dbg, "GetRemoteHandle -> %08lx\n", Status );
  3113. return Status;
  3114. #endif
  3115. }
  3116. //
  3117. // Make sure that this ICB is still active.
  3118. //
  3119. NwVerifyIcb( Icb );
  3120. if ( OutputBufferLength < sizeof( UCHAR ) ) {
  3121. Status = STATUS_BUFFER_TOO_SMALL;
  3122. } else if ( Icb->HasRemoteHandle ) {
  3123. // Already been asked for the handle
  3124. NwMapUserBuffer( Irp, KernelMode, (PVOID *)&OutputBuffer );
  3125. //
  3126. // tommye
  3127. //
  3128. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  3129. // situations; this was not being checked.
  3130. //
  3131. if (OutputBuffer == NULL) {
  3132. DebugTrace(-1, DEBUG_TRACE_USERNCP, "NwMapUserBuffer returned NULL OutputBuffer", 0);
  3133. Status = STATUS_INSUFFICIENT_RESOURCES;
  3134. }
  3135. else {
  3136. try {
  3137. if ( Irp->RequestorMode != KernelMode ) {
  3138. ProbeForWrite(
  3139. OutputBuffer,
  3140. sizeof(CHAR),
  3141. sizeof(CHAR)
  3142. );
  3143. }
  3144. *OutputBuffer = Icb->Handle[0];
  3145. IrpContext->pOriginalIrp->IoStatus.Information = sizeof(CHAR);
  3146. Status = STATUS_SUCCESS;
  3147. } except (EXCEPTION_EXECUTE_HANDLER) {
  3148. Status = GetExceptionCode();
  3149. }
  3150. }
  3151. } else {
  3152. CHAR Handle;
  3153. IrpContext->pScb = Dcb->Scb;
  3154. IrpContext->pNpScb = IrpContext->pScb->pNpScb;
  3155. NwMapUserBuffer( Irp, KernelMode, (PVOID *)&OutputBuffer );
  3156. //
  3157. // tommye
  3158. //
  3159. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  3160. // situations; this was not being checked.
  3161. //
  3162. if (OutputBuffer == NULL) {
  3163. DebugTrace(-1, DEBUG_TRACE_USERNCP, "NwMapUserBuffer returned NULL OutputBuffer", 0);
  3164. Status = STATUS_INSUFFICIENT_RESOURCES;
  3165. }
  3166. else {
  3167. Status = ExchangeWithWait (
  3168. IrpContext,
  3169. SynchronousResponseCallback,
  3170. "SbbJ",
  3171. NCP_DIR_FUNCTION, NCP_ALLOCATE_TEMP_DIR_HANDLE,
  3172. Dcb->Vcb->Specific.Disk.Handle,
  3173. 0,
  3174. &Dcb->RelativeFileName );
  3175. if ( NT_SUCCESS( Status ) ) {
  3176. Status = ParseResponse(
  3177. IrpContext,
  3178. IrpContext->rsp,
  3179. IrpContext->ResponseLength,
  3180. "Nb",
  3181. &Handle );
  3182. if (NT_SUCCESS(Status)) {
  3183. try {
  3184. *OutputBuffer = Handle;
  3185. Icb->Handle[0] = Handle;
  3186. Icb->HasRemoteHandle = TRUE;
  3187. IrpContext->pOriginalIrp->IoStatus.Information = sizeof(CHAR);
  3188. }
  3189. except (EXCEPTION_EXECUTE_HANDLER) {
  3190. Status = GetExceptionCode();
  3191. }
  3192. }
  3193. }
  3194. NwDequeueIrpContext( IrpContext, FALSE );
  3195. DebugTrace( 0, Dbg, " -> %02x\n", Handle );
  3196. }
  3197. }
  3198. DebugTrace(-1, Dbg, "GetRemoteHandle -> %08lx\n", Status );
  3199. return Status;
  3200. }
  3201. NTSTATUS
  3202. GetUserName(
  3203. IN PIRP_CONTEXT IrpContext
  3204. )
  3205. /*++
  3206. Routine Description:
  3207. This routine gets the UserName that would be used to connect to a particular
  3208. server.
  3209. If there are credentials specific to this connection use them
  3210. otherwise use the logon credentials.
  3211. Arguments:
  3212. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  3213. Return Value:
  3214. NTSTATUS
  3215. --*/
  3216. {
  3217. NTSTATUS Status = STATUS_PENDING;
  3218. PIRP Irp = IrpContext->pOriginalIrp;
  3219. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  3220. PWSTR InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  3221. ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  3222. ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  3223. PWSTR OutputBuffer;
  3224. SECURITY_SUBJECT_CONTEXT SubjectContext;
  3225. LARGE_INTEGER Uid;
  3226. UNICODE_STRING UidServer;
  3227. UNICODE_STRING ServerName;
  3228. UNICODE_STRING ConvertedName;
  3229. PUNICODE_STRING pUserName;
  3230. PSCB pScb;
  3231. PLOGON pLogon;
  3232. BOOLEAN CredentialsHeld = FALSE;
  3233. BOOLEAN FailedTreeLookup = FALSE;
  3234. PNDS_SECURITY_CONTEXT pNdsCredentials;
  3235. PAGED_CODE();
  3236. DebugTrace(+1, Dbg, "GetUserName\n", 0);
  3237. SeCaptureSubjectContext(&SubjectContext);
  3238. Uid = GetUid( &SubjectContext );
  3239. SeReleaseSubjectContext(&SubjectContext);
  3240. //
  3241. // Probe the input arguments to make sure they are kosher before
  3242. // touching them.
  3243. //
  3244. try {
  3245. if ( Irp->RequestorMode != KernelMode ) {
  3246. ProbeForRead( InputBuffer,
  3247. InputBufferLength,
  3248. sizeof( CHAR )
  3249. );
  3250. }
  3251. ServerName.Buffer = InputBuffer;
  3252. ServerName.MaximumLength = (USHORT)InputBufferLength;
  3253. ServerName.Length = (USHORT)InputBufferLength;
  3254. Status = MakeUidServer( &UidServer, &Uid, &ServerName );
  3255. if (!NT_SUCCESS(Status)) {
  3256. DebugTrace(-1, Dbg, "GetUserName -> %08lx\n", Status );
  3257. return(Status);
  3258. }
  3259. } except (EXCEPTION_EXECUTE_HANDLER) {
  3260. return (GetExceptionCode());
  3261. }
  3262. DebugTrace( 0, Dbg, " ->UidServer = \"%wZ\"\n", &UidServer );
  3263. //
  3264. // Get the login for this user.
  3265. //
  3266. NwDequeueIrpContext( IrpContext, FALSE );
  3267. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  3268. pLogon = FindUser( &Uid, FALSE);
  3269. NwReleaseRcb( &NwRcb );
  3270. //
  3271. // First try this name as a server. Avoid FindScb creating a
  3272. // connection to the server if one doesn't exist already.
  3273. //
  3274. // Since IRP_FLAG_NOCONNECT is set the last parameter of
  3275. // NwFindScb is never used.
  3276. //
  3277. SetFlag( IrpContext->Flags, IRP_FLAG_NOCONNECT );
  3278. NwFindScb( &pScb, IrpContext, &UidServer, NULL );
  3279. pUserName = NULL;
  3280. //
  3281. // Look for bindery server name, or tree login name.
  3282. //
  3283. if ( pScb != NULL ) {
  3284. if ( pScb->UserName.Buffer != NULL ) {
  3285. pUserName = &pScb->UserName;
  3286. } else if ( pScb->NdsTreeName.Buffer != NULL &&
  3287. pScb->NdsTreeName.Length > 0 ) {
  3288. Status = NdsLookupCredentials( IrpContext,
  3289. &pScb->NdsTreeName,
  3290. pLogon,
  3291. &pNdsCredentials,
  3292. CREDENTIAL_READ,
  3293. FALSE );
  3294. if ( NT_SUCCESS( Status ) ) {
  3295. CredentialsHeld = TRUE;
  3296. if ( pNdsCredentials->Credential ) {
  3297. //
  3298. // If we have login data, get the user name.
  3299. //
  3300. ConvertedName.Length = pNdsCredentials->Credential->userNameLength -
  3301. sizeof( WCHAR );
  3302. ConvertedName.MaximumLength = ConvertedName.Length;
  3303. ConvertedName.Buffer = (USHORT *)
  3304. ( ((BYTE *) pNdsCredentials->Credential ) +
  3305. sizeof( NDS_CREDENTIAL ) +
  3306. pNdsCredentials->Credential->optDataSize );
  3307. pUserName = &ConvertedName;
  3308. } else {
  3309. //
  3310. // If there's no credential data, we're not logged in.
  3311. //
  3312. FailedTreeLookup = TRUE;
  3313. }
  3314. } else {
  3315. FailedTreeLookup = TRUE;
  3316. }
  3317. }
  3318. }
  3319. //
  3320. // If it wasn't a server and we haven't already tried a tree, do so now.
  3321. //
  3322. if ( pUserName == NULL &&
  3323. !FailedTreeLookup ) {
  3324. //
  3325. // ServerName points to a user buffer - so we need
  3326. // to watch for problems accessing the data here
  3327. //
  3328. // NOTE: ServerName points to a usermode buffer
  3329. // so we must protect ourselves around this call.
  3330. //
  3331. try {
  3332. Status = NdsLookupCredentials(
  3333. IrpContext,
  3334. &ServerName,
  3335. pLogon,
  3336. &pNdsCredentials,
  3337. CREDENTIAL_READ,
  3338. FALSE );
  3339. }
  3340. except (EXCEPTION_EXECUTE_HANDLER) {
  3341. Status = GetExceptionCode();
  3342. }
  3343. if ( NT_SUCCESS( Status ) ) {
  3344. CredentialsHeld = TRUE;
  3345. if ( pNdsCredentials->Credential ) {
  3346. //
  3347. // If we've logged in, get the user name.
  3348. //
  3349. ConvertedName.Length = pNdsCredentials->Credential->userNameLength -
  3350. sizeof( WCHAR );
  3351. ConvertedName.MaximumLength = ConvertedName.Length;
  3352. ConvertedName.Buffer = (USHORT *)
  3353. ( ((BYTE *) pNdsCredentials->Credential ) +
  3354. sizeof( NDS_CREDENTIAL ) +
  3355. pNdsCredentials->Credential->optDataSize );
  3356. pUserName = &ConvertedName;
  3357. }
  3358. }
  3359. }
  3360. //
  3361. // If we still don't know, return the default name.
  3362. //
  3363. if ( pUserName == NULL &&
  3364. pLogon != NULL ) {
  3365. pUserName = &pLogon->UserName;
  3366. }
  3367. FREE_POOL(UidServer.Buffer);
  3368. if ( pUserName ) {
  3369. DebugTrace( 0, Dbg, "Get User Name: %wZ\n", pUserName );
  3370. try {
  3371. if (pUserName->Length > OutputBufferLength) {
  3372. DebugTrace(-1, Dbg, "GetUserName -> %08lx\n", STATUS_BUFFER_TOO_SMALL );
  3373. Status = STATUS_BUFFER_TOO_SMALL;
  3374. goto ReleaseAndExit;
  3375. }
  3376. NwMapUserBuffer( Irp, KernelMode, (PVOID *)&OutputBuffer );
  3377. //
  3378. // tommye
  3379. //
  3380. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  3381. // situations; this was not being checked.
  3382. //
  3383. if (OutputBuffer == NULL) {
  3384. DebugTrace(-1, DEBUG_TRACE_USERNCP, "NwMapUserBuffer returned NULL OutputBuffer", 0);
  3385. Status = STATUS_INSUFFICIENT_RESOURCES;
  3386. goto ReleaseAndExit;
  3387. }
  3388. //
  3389. // Probe to ensure that the buffer is kosher.
  3390. //
  3391. if ( Irp->RequestorMode != KernelMode ) {
  3392. ProbeForWrite( OutputBuffer,
  3393. OutputBufferLength,
  3394. sizeof(CHAR)
  3395. );
  3396. }
  3397. IrpContext->pOriginalIrp->IoStatus.Information = pUserName->Length;
  3398. RtlMoveMemory( OutputBuffer, pUserName->Buffer, pUserName->Length);
  3399. Status = STATUS_SUCCESS;
  3400. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  3401. Status = STATUS_INVALID_PARAMETER;
  3402. }
  3403. }
  3404. ReleaseAndExit:
  3405. if ( pScb ) {
  3406. NwDereferenceScb( pScb->pNpScb );
  3407. }
  3408. DebugTrace(-1, Dbg, "GetUserName -> %08lx\n", Status );
  3409. if ( CredentialsHeld ) {
  3410. NwReleaseCredList( pLogon, IrpContext );
  3411. }
  3412. return Status;
  3413. }
  3414. BOOL
  3415. IsSystemLuid()
  3416. {
  3417. SECURITY_SUBJECT_CONTEXT SubjectContext;
  3418. LARGE_INTEGER Uid;
  3419. LUID systemLuid = SYSTEM_LUID;
  3420. LUID localServiceLuid = LOCALSERVICE_LUID;
  3421. LUID netServiceLuid = NETWORKSERVICE_LUID;
  3422. SeCaptureSubjectContext(&SubjectContext);
  3423. Uid = GetUid( &SubjectContext );
  3424. SeReleaseSubjectContext(&SubjectContext);
  3425. if (RtlEqualLuid((PLUID)&Uid, &systemLuid))
  3426. return TRUE;
  3427. else if (RtlEqualLuid((PLUID)&Uid, &localServiceLuid))
  3428. return TRUE;
  3429. else if (RtlEqualLuid((PLUID)&Uid, &netServiceLuid))
  3430. return TRUE;
  3431. else
  3432. return FALSE;
  3433. }
  3434. NTSTATUS
  3435. GetChallenge(
  3436. IN PIRP_CONTEXT IrpContext
  3437. )
  3438. /*++
  3439. Routine Description:
  3440. This routine builds the challenge and session key for rpc using the
  3441. credentials stored in the redirector. The Rpc client can supply a
  3442. password. This allows the redirector to keep the algorithm in one
  3443. place.
  3444. If a password is supplied then use that, if there is a password on this
  3445. specific connection use that, otherwise use the logon credentials.
  3446. Arguments:
  3447. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  3448. Return Value:
  3449. NTSTATUS
  3450. --*/
  3451. {
  3452. NTSTATUS Status = STATUS_PENDING;
  3453. PIRP Irp = IrpContext->pOriginalIrp;
  3454. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  3455. PNWR_GET_CHALLENGE_REQUEST InputBuffer = Irp->AssociatedIrp.SystemBuffer;
  3456. ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  3457. ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  3458. PNWR_GET_CHALLENGE_REPLY OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
  3459. OEM_STRING Password;
  3460. PSCB pScb = NULL;
  3461. PLOGON pLogon;
  3462. BOOLEAN RcbHeld = FALSE;
  3463. SECURITY_SUBJECT_CONTEXT SubjectContext;
  3464. LARGE_INTEGER ProcessUid;
  3465. ULONG RequestFlags;
  3466. LUID _system_luid = SYSTEM_LUID;
  3467. PAGED_CODE();
  3468. DebugTrace(+1, Dbg, "GetChallenge\n", 0);
  3469. //
  3470. // Buffer big enough to contain fixed header?
  3471. //
  3472. if (InputBufferLength <
  3473. (ULONG) FIELD_OFFSET(NWR_GET_CHALLENGE_REQUEST,ServerNameorPassword[0])) {
  3474. return(STATUS_INVALID_PARAMETER);
  3475. }
  3476. //
  3477. // Check output buffer length
  3478. //
  3479. if (OutputBufferLength < sizeof(NWR_GET_CHALLENGE_REPLY)) {
  3480. return(STATUS_INVALID_PARAMETER);
  3481. }
  3482. //
  3483. // tommye - make sure the InputBuffer is kosher
  3484. //
  3485. try {
  3486. //
  3487. // Probe for safety.
  3488. //
  3489. if ( Irp->RequestorMode != KernelMode ) {
  3490. ProbeForRead( InputBuffer,
  3491. InputBufferLength,
  3492. sizeof( CHAR ));
  3493. }
  3494. //
  3495. // Buffer big enough to contain the variable portion. Subtraction here can't underflow because
  3496. // of the previous test
  3497. if ((InputBufferLength - FIELD_OFFSET(NWR_GET_CHALLENGE_REQUEST,ServerNameorPassword[0]) <
  3498. InputBuffer->ServerNameorPasswordLength)) {
  3499. return(STATUS_INVALID_PARAMETER);
  3500. }
  3501. //
  3502. // String length must be an even number of characters
  3503. //
  3504. if (InputBuffer->ServerNameorPasswordLength&(sizeof (WCHAR) - 1)) {
  3505. return(STATUS_INVALID_PARAMETER);
  3506. }
  3507. // Pull out the request flags to use later
  3508. RequestFlags = InputBuffer->Flags;
  3509. } except (EXCEPTION_EXECUTE_HANDLER) {
  3510. return GetExceptionCode();
  3511. }
  3512. //
  3513. // Only allow processes running in the system context to call this api to prevent
  3514. // password attacks.
  3515. //
  3516. /*
  3517. SeCaptureSubjectContext(&SubjectContext);
  3518. SeQueryAuthenticationIdToken(&SubjectContext.PrimaryToken, (PLUID)&ProcessUid);
  3519. SeReleaseSubjectContext(&SubjectContext);
  3520. */
  3521. // if (! RtlEqualLuid(&ProcessUid, &_system_luid)) {
  3522. if (! IsSystemLuid()) {
  3523. return(STATUS_ACCESS_DENIED);
  3524. }
  3525. Password.Buffer = NULL;
  3526. Password.Length = 0;
  3527. if ( RequestFlags == CHALLENGE_FLAGS_SERVERNAME ) {
  3528. PUNICODE_STRING pPassword;
  3529. LARGE_INTEGER Uid;
  3530. UNICODE_STRING UidServer;
  3531. try {
  3532. UNICODE_STRING ServerName;
  3533. if (InputBuffer->ServerNameorPasswordLength == 0) {
  3534. return(STATUS_INVALID_PARAMETER);
  3535. }
  3536. //
  3537. // We have to supply the password from the redirector
  3538. //
  3539. SeCaptureSubjectContext(&SubjectContext);
  3540. Uid = GetUid( &SubjectContext );
  3541. SeReleaseSubjectContext(&SubjectContext);
  3542. ServerName.Buffer = (PWSTR)((PUCHAR)InputBuffer +
  3543. FIELD_OFFSET(NWR_GET_CHALLENGE_REQUEST,ServerNameorPassword[0]));
  3544. ServerName.MaximumLength = (USHORT)InputBuffer->ServerNameorPasswordLength;
  3545. ServerName.Length = (USHORT)InputBuffer->ServerNameorPasswordLength;
  3546. Status = MakeUidServer( &UidServer, &Uid, &ServerName );
  3547. if (!NT_SUCCESS(Status)) {
  3548. DebugTrace(-1, Dbg, "GetChallenge -> %08lx\n", Status );
  3549. return(Status);
  3550. }
  3551. } except (EXCEPTION_EXECUTE_HANDLER) {
  3552. return GetExceptionCode();
  3553. }
  3554. DebugTrace( 0, Dbg, " ->UidServer = \"%wZ\"\n", &UidServer );
  3555. try {
  3556. //
  3557. // Avoid FindScb creating a connection to the server if one
  3558. // doesn't exist already.
  3559. //
  3560. // Since IRP_FLAG_NOCONNECT is set the last parameter of
  3561. // NwFindScb is never used.
  3562. //
  3563. SetFlag( IrpContext->Flags, IRP_FLAG_NOCONNECT );
  3564. NwFindScb( &pScb, IrpContext, &UidServer, NULL );
  3565. if ((pScb != NULL) &&
  3566. (pScb->Password.Buffer != NULL)) {
  3567. pPassword = &pScb->Password;
  3568. } else {
  3569. //
  3570. // Use default credentials for this UID
  3571. //
  3572. NwDequeueIrpContext( IrpContext, FALSE );
  3573. RcbHeld = TRUE;
  3574. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  3575. pLogon = FindUser( &Uid, FALSE);
  3576. if (pLogon != NULL ) {
  3577. pPassword = &pLogon->PassWord;
  3578. } else {
  3579. DebugTrace(-1, Dbg, "GetChallenge -> %08lx\n", STATUS_ACCESS_DENIED );
  3580. return( STATUS_ACCESS_DENIED );
  3581. }
  3582. }
  3583. if (pPassword->Length != 0) {
  3584. Status = RtlUpcaseUnicodeStringToOemString( &Password, pPassword, TRUE );
  3585. if (!NT_SUCCESS(Status)) {
  3586. DebugTrace(-1, Dbg, "GetChallenge -> %08lx\n", Status );
  3587. return( Status );
  3588. }
  3589. } else {
  3590. Password.Buffer = "";
  3591. Password.Length = Password.MaximumLength = 0;
  3592. }
  3593. } finally {
  3594. if (RcbHeld) {
  3595. NwReleaseRcb( &NwRcb );
  3596. }
  3597. if (pScb != NULL) {
  3598. NwDereferenceScb( pScb->pNpScb );
  3599. }
  3600. FREE_POOL(UidServer.Buffer);
  3601. }
  3602. } else {
  3603. UNICODE_STRING LocalPassword;
  3604. try {
  3605. LocalPassword.Buffer = (PWSTR)((PUCHAR)InputBuffer +
  3606. FIELD_OFFSET(NWR_GET_CHALLENGE_REQUEST,ServerNameorPassword[0]));
  3607. LocalPassword.MaximumLength = (USHORT)InputBuffer->ServerNameorPasswordLength;
  3608. LocalPassword.Length = (USHORT)InputBuffer->ServerNameorPasswordLength;
  3609. if (LocalPassword.Length != 0) {
  3610. Status = RtlUpcaseUnicodeStringToOemString( &Password, &LocalPassword, TRUE );
  3611. if (!NT_SUCCESS(Status)) {
  3612. DebugTrace(-1, Dbg, "GetChallenge -> %08lx\n", Status );
  3613. return( Status );
  3614. }
  3615. } else {
  3616. Password.Buffer = "";
  3617. Password.Length = Password.MaximumLength = 0;
  3618. }
  3619. } except (EXCEPTION_EXECUTE_HANDLER) {
  3620. return GetExceptionCode();
  3621. }
  3622. }
  3623. DebugTrace( 0, Dbg, " ->Password = \"%Z\"\n", &Password );
  3624. try {
  3625. RespondToChallenge( (PUCHAR)&InputBuffer->ObjectId, &Password, InputBuffer->Challenge, OutputBuffer->Challenge);
  3626. } finally {
  3627. if ( Password.Length > 0 ) {
  3628. RtlFreeAnsiString( &Password );
  3629. }
  3630. }
  3631. Irp->IoStatus.Information = sizeof(NWR_GET_CHALLENGE_REPLY);
  3632. Status = STATUS_SUCCESS;
  3633. DebugTrace(-1, Dbg, "GetChallenge -> %08lx\n", Status );
  3634. return Status;
  3635. }
  3636. NTSTATUS
  3637. WriteConnStatusEntry(
  3638. PIRP_CONTEXT pIrpContext,
  3639. PSCB pConnectionScb,
  3640. PBYTE pbUserBuffer,
  3641. DWORD dwBufferLen,
  3642. DWORD *pdwBytesWritten,
  3643. DWORD *pdwBytesNeeded,
  3644. BOOLEAN fCallerScb
  3645. )
  3646. {
  3647. NTSTATUS Status;
  3648. PLOGON pLogon;
  3649. PNDS_SECURITY_CONTEXT pNdsContext;
  3650. BOOLEAN fHoldingCredentials = FALSE;
  3651. PUNICODE_STRING puUserName = NULL;
  3652. UNICODE_STRING CredentialName;
  3653. UNICODE_STRING ServerName;
  3654. PCONN_STATUS pStatus;
  3655. DWORD dwBytesNeeded;
  3656. PBYTE pbStrPtr;
  3657. DWORD dwAllowedHandles;
  3658. //
  3659. // If this is an NDS connection, get the credentials.
  3660. //
  3661. if ( ( pConnectionScb->MajorVersion > 3 ) &&
  3662. ( pConnectionScb->UserName.Length == 0 ) ) {
  3663. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  3664. pLogon = FindUser( &(pConnectionScb->UserUid), FALSE );
  3665. NwReleaseRcb( &NwRcb );
  3666. if ( pLogon ) {
  3667. Status = NdsLookupCredentials( pIrpContext,
  3668. &(pConnectionScb->NdsTreeName),
  3669. pLogon,
  3670. &pNdsContext,
  3671. CREDENTIAL_READ,
  3672. FALSE );
  3673. if ( NT_SUCCESS( Status ) ) {
  3674. fHoldingCredentials = TRUE;
  3675. if ( pNdsContext->Credential != NULL ) {
  3676. CredentialName.Length = pNdsContext->Credential->userNameLength -
  3677. sizeof( WCHAR );
  3678. CredentialName.MaximumLength = CredentialName.Length;
  3679. CredentialName.Buffer = (USHORT *)
  3680. ( ((BYTE *) pNdsContext->Credential ) +
  3681. sizeof( NDS_CREDENTIAL ) +
  3682. pNdsContext->Credential->optDataSize );
  3683. puUserName = &CredentialName;
  3684. }
  3685. }
  3686. }
  3687. } else {
  3688. if ( pConnectionScb->UserName.Length != 0 ) {
  3689. puUserName = &(pConnectionScb->UserName);
  3690. } else {
  3691. puUserName = NULL;
  3692. }
  3693. }
  3694. DebugTrace( 0, Dbg, "WriteConnStatus: UserName %wZ\n", puUserName );
  3695. //
  3696. // Strip off the uid from the server name.
  3697. //
  3698. ServerName.Length = (pConnectionScb->UidServerName).Length;
  3699. ServerName.Buffer = (pConnectionScb->UidServerName).Buffer;
  3700. while ( ServerName.Length ) {
  3701. if ( ServerName.Buffer[0] == L'\\' ) {
  3702. ServerName.Length -= sizeof( WCHAR );
  3703. ServerName.Buffer += 1;
  3704. break;
  3705. }
  3706. ServerName.Length -= sizeof( WCHAR );
  3707. ServerName.Buffer += 1;
  3708. }
  3709. DebugTrace( 0, Dbg, "WriteConnStatus: ServerName %wZ\n", &ServerName );
  3710. //
  3711. // Do we have enough space? Don't forget that we have to
  3712. // NULL terminate the WCHAR strings.
  3713. //
  3714. dwBytesNeeded = sizeof( CONN_STATUS );
  3715. dwBytesNeeded += ( ServerName.Length + sizeof( WCHAR ) );
  3716. if ( pConnectionScb->NdsTreeName.Length ) {
  3717. dwBytesNeeded += ( pConnectionScb->NdsTreeName.Length + sizeof( WCHAR ) );
  3718. }
  3719. if ( puUserName ) {
  3720. dwBytesNeeded += ( puUserName->Length + sizeof( WCHAR ) );
  3721. }
  3722. //
  3723. // Pad the end to make sure all structures are aligned.
  3724. //
  3725. dwBytesNeeded = ROUNDUP4( dwBytesNeeded );
  3726. if ( dwBytesNeeded > dwBufferLen ) {
  3727. *pdwBytesNeeded = dwBytesNeeded;
  3728. Status = STATUS_BUFFER_TOO_SMALL;
  3729. goto ExitWithCleanup;
  3730. }
  3731. //
  3732. // Fill in the CONN_STATUS structure.
  3733. //
  3734. try {
  3735. pStatus = (PCONN_STATUS)pbUserBuffer;
  3736. pbStrPtr = pbUserBuffer + sizeof( CONN_STATUS );
  3737. //
  3738. // We always have a server name.
  3739. //
  3740. pStatus->pszServerName = (PWSTR) pbStrPtr;
  3741. pbStrPtr += ( ServerName.Length + sizeof( WCHAR ) );
  3742. //
  3743. // Fill in the user name if applicable.
  3744. //
  3745. if ( puUserName ) {
  3746. pStatus->pszUserName = (PWSTR) pbStrPtr;
  3747. pbStrPtr += ( puUserName->Length + sizeof( WCHAR ) );
  3748. } else {
  3749. pStatus->pszUserName = NULL;
  3750. }
  3751. //
  3752. // Fill in the tree name if applicable.
  3753. //
  3754. if ( pConnectionScb->NdsTreeName.Length ) {
  3755. pStatus->pszTreeName = (PWSTR) pbStrPtr;
  3756. } else {
  3757. pStatus->pszTreeName = NULL;
  3758. }
  3759. //
  3760. // Fill in the connection number if applicable.
  3761. //
  3762. if ( ( pConnectionScb->pNpScb->State == SCB_STATE_IN_USE ) ||
  3763. ( pConnectionScb->pNpScb->State == SCB_STATE_LOGIN_REQUIRED ) ) {
  3764. pStatus->nConnNum = (DWORD)(pConnectionScb->pNpScb->ConnectionNo);
  3765. } else {
  3766. pStatus->nConnNum = 0;
  3767. }
  3768. //
  3769. // Copy the user name over.
  3770. //
  3771. if ( puUserName ) {
  3772. RtlCopyMemory( (PBYTE)(pStatus->pszUserName),
  3773. (PBYTE)(puUserName->Buffer),
  3774. puUserName->Length );
  3775. *(pStatus->pszUserName + (puUserName->Length / sizeof( WCHAR ))) = L'\0';
  3776. }
  3777. //
  3778. // Set the NDS flag and authentication fields.
  3779. //
  3780. if ( ( pConnectionScb->MajorVersion > 3 ) &&
  3781. ( pConnectionScb->UserName.Length == 0 ) ) {
  3782. pStatus->fNds = TRUE;
  3783. if ( pConnectionScb->pNpScb->State == SCB_STATE_IN_USE ) {
  3784. if ( ( pConnectionScb->VcbCount ) || ( pConnectionScb->OpenNdsStreams ) ) {
  3785. pStatus->dwConnType = NW_CONN_NDS_AUTHENTICATED_LICENSED;
  3786. } else {
  3787. pStatus->dwConnType = NW_CONN_NDS_AUTHENTICATED_NO_LICENSE;
  3788. }
  3789. } else if ( pConnectionScb->pNpScb->State == SCB_STATE_LOGIN_REQUIRED ) {
  3790. pStatus->dwConnType = NW_CONN_NOT_AUTHENTICATED;
  3791. } else {
  3792. pStatus->dwConnType = NW_CONN_DISCONNECTED;
  3793. }
  3794. } else {
  3795. pStatus->fNds = FALSE;
  3796. if ( pConnectionScb->pNpScb->State == SCB_STATE_IN_USE ) {
  3797. pStatus->dwConnType = NW_CONN_BINDERY_LOGIN;
  3798. } else if ( pConnectionScb->pNpScb->State == SCB_STATE_LOGIN_REQUIRED ) {
  3799. pStatus->dwConnType = NW_CONN_NOT_AUTHENTICATED;
  3800. } else {
  3801. pStatus->dwConnType = NW_CONN_DISCONNECTED;
  3802. }
  3803. }
  3804. //
  3805. // Copy over the tree name.
  3806. //
  3807. if ( pConnectionScb->NdsTreeName.Length ) {
  3808. RtlCopyMemory( (PBYTE)(pStatus->pszTreeName),
  3809. (PBYTE)(pConnectionScb->NdsTreeName.Buffer),
  3810. pConnectionScb->NdsTreeName.Length );
  3811. *( pStatus->pszTreeName +
  3812. ( pConnectionScb->NdsTreeName.Length / sizeof( WCHAR ) ) ) = L'\0';
  3813. } else {
  3814. pStatus->pszTreeName = NULL;
  3815. }
  3816. //
  3817. // Copy the server name over.
  3818. //
  3819. RtlCopyMemory( (PBYTE)(pStatus->pszServerName),
  3820. (PBYTE)(ServerName.Buffer),
  3821. ServerName.Length );
  3822. *(pStatus->pszServerName + (ServerName.Length / sizeof( WCHAR ))) = L'\0';
  3823. //
  3824. // Set the preferred server field if this is a preferred server
  3825. // and there are no explicit uses for the connection. If the
  3826. // fCallerScb parameter is TRUE, then this SCB has a handle from
  3827. // the caller of the API and we have to make an allowance for
  3828. // that handle. Yes, this is kind of ugly.
  3829. //
  3830. if ( fCallerScb ) {
  3831. dwAllowedHandles = 1;
  3832. } else {
  3833. dwAllowedHandles = 0;
  3834. }
  3835. if ( ( pConnectionScb->PreferredServer ) &&
  3836. ( pConnectionScb->OpenFileCount == 0 ) &&
  3837. ( pConnectionScb->IcbCount == dwAllowedHandles ) ) {
  3838. pStatus->fPreferred = TRUE;
  3839. } else {
  3840. pStatus->fPreferred = FALSE;
  3841. }
  3842. //
  3843. // Fill out the length.
  3844. //
  3845. pStatus->dwTotalLength = dwBytesNeeded;
  3846. *pdwBytesWritten = dwBytesNeeded;
  3847. Status = STATUS_SUCCESS;
  3848. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  3849. Status = GetExceptionCode();
  3850. DebugTrace( 0, Dbg, "Exception %08lx accessing user mode buffer.\n", Status );
  3851. goto ExitWithCleanup;
  3852. }
  3853. ExitWithCleanup:
  3854. if ( fHoldingCredentials ) {
  3855. NwReleaseCredList( pLogon, pIrpContext );
  3856. }
  3857. return Status;
  3858. }
  3859. NTSTATUS
  3860. GetConnStatus(
  3861. IN PIRP_CONTEXT IrpContext,
  3862. IN PFILE_OBJECT FileObject
  3863. )
  3864. /*++
  3865. Get the connection status for the described connection.
  3866. The following connection requests are valid:
  3867. Server (e.g. "MARS312") - returns a single connection
  3868. status structure for this server if the user has a
  3869. connection to the server.
  3870. Tree (e.g. "*MARSDEV") - returns a connection status
  3871. structure for every server in the tree that the user
  3872. has a connection to.
  3873. All Connections (e.g. "") - returns a connection status
  3874. structure for every server that the user has a
  3875. connection to.
  3876. --*/
  3877. {
  3878. NTSTATUS Status = STATUS_SUCCESS;
  3879. PIRP Irp = IrpContext->pOriginalIrp;
  3880. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  3881. PNWR_REQUEST_PACKET InputBuffer;
  3882. ULONG InputBufferLength;
  3883. BYTE *OutputBuffer;
  3884. ULONG OutputBufferLength;
  3885. SECURITY_SUBJECT_CONTEXT SubjectContext;
  3886. LARGE_INTEGER Uid;
  3887. PLIST_ENTRY ListEntry;
  3888. UNICODE_STRING ConnectionName, UidServer;
  3889. BOOL fTreeConnections = FALSE;
  3890. BOOL fServerConnection = FALSE;
  3891. BOOL OwnRcb = FALSE;
  3892. PUNICODE_PREFIX_TABLE_ENTRY PrefixEntry;
  3893. DWORD dwBytesWritten, dwBytesNeeded;
  3894. KIRQL OldIrql;
  3895. PSCB pScb;
  3896. PNONPAGED_SCB pNpScb;
  3897. DWORD dwReturned = 0;
  3898. ULONG SequenceNumber = 0;
  3899. ULONG_PTR ResumeKey;
  3900. NODE_TYPE_CODE nodeTypeCode;
  3901. PICB pIcb;
  3902. PSCB pCallerScb;
  3903. PVOID fsContext, fsContext2;
  3904. //
  3905. // Get the appropriate buffers.
  3906. //
  3907. InputBuffer = (PNWR_REQUEST_PACKET) IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  3908. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  3909. OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  3910. NwMapUserBuffer( Irp, KernelMode, (PVOID *)&OutputBuffer );
  3911. //
  3912. // tommye
  3913. //
  3914. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  3915. // situations; this was not being checked.
  3916. //
  3917. if (OutputBuffer == NULL) {
  3918. DebugTrace(-1, DEBUG_TRACE_USERNCP, "NwMapUserBuffer returned NULL OutputBuffer", 0);
  3919. return STATUS_INSUFFICIENT_RESOURCES;
  3920. }
  3921. if ( InputBufferLength < (ULONG)FIELD_OFFSET( NWR_REQUEST_PACKET, Parameters.GetConnStatus.ConnectionName[1] ) ) {
  3922. return( STATUS_INVALID_PARAMETER );
  3923. }
  3924. //
  3925. // Figure out who this request applies to.
  3926. //
  3927. SeCaptureSubjectContext(&SubjectContext);
  3928. Uid = GetUid( &SubjectContext );
  3929. SeReleaseSubjectContext(&SubjectContext);
  3930. RtlInitUnicodeString( &ConnectionName, NULL );
  3931. RtlInitUnicodeString( &UidServer, NULL );
  3932. //
  3933. // Figure out who the caller of this routine is so we know to
  3934. // ignore their handle when deciding what to return.
  3935. //
  3936. nodeTypeCode = NwDecodeFileObject( FileObject, &fsContext, &fsContext2 );
  3937. if ( nodeTypeCode == NW_NTC_ICB_SCB ) {
  3938. pIcb = (PICB) fsContext2;
  3939. pCallerScb = pIcb->SuperType.Scb;
  3940. DebugTrace( 0, Dbg, "GetConnStatus called by handle on %08lx\n", pCallerScb );
  3941. } else {
  3942. pCallerScb = NULL;
  3943. DebugTrace( 0, Dbg, "Couldn't figure out who called us.\n", 0 );
  3944. }
  3945. //
  3946. //
  3947. // Figure out which connections we're looking for.
  3948. //
  3949. try {
  3950. //
  3951. // Probe for safety.
  3952. //
  3953. if ( Irp->RequestorMode != KernelMode ) {
  3954. ProbeForRead( InputBuffer,
  3955. InputBufferLength,
  3956. sizeof( CHAR )
  3957. );
  3958. }
  3959. if ( InputBuffer->Parameters.GetConnStatus.ConnectionNameLength != 0 ) {
  3960. //
  3961. // Check the connection name length to see if its sound. This
  3962. // subtraction can't underflow because of the test above.
  3963. //
  3964. if ( InputBuffer->Parameters.GetConnStatus.ConnectionNameLength >
  3965. InputBufferLength - FIELD_OFFSET( NWR_REQUEST_PACKET, Parameters.GetConnStatus.ConnectionName) ) {
  3966. return STATUS_INVALID_PARAMETER;
  3967. }
  3968. if ( InputBuffer->Parameters.GetConnStatus.ConnectionName[0] == L'*' ) {
  3969. ConnectionName.Buffer = &(InputBuffer->Parameters.GetConnStatus.ConnectionName[1]);
  3970. ConnectionName.Length = (USHORT)
  3971. ( InputBuffer->Parameters.GetConnStatus.ConnectionNameLength -
  3972. sizeof( WCHAR ) );
  3973. ConnectionName.MaximumLength = ConnectionName.Length;
  3974. fTreeConnections = TRUE;
  3975. DebugTrace( 0, Dbg, "GetConnStatus: Tree is %wZ\n", &ConnectionName );
  3976. } else {
  3977. ConnectionName.Buffer = InputBuffer->Parameters.GetConnStatus.ConnectionName;
  3978. ConnectionName.Length = (USHORT)
  3979. (InputBuffer->Parameters.GetConnStatus.ConnectionNameLength);
  3980. ConnectionName.MaximumLength = ConnectionName.Length;
  3981. fServerConnection = TRUE;
  3982. Status = MakeUidServer( &UidServer, &Uid, &ConnectionName );
  3983. if ( !NT_SUCCESS( Status )) {
  3984. return Status;
  3985. }
  3986. DebugTrace( 0, Dbg, "GetConnStatus: Server is %wZ\n", &UidServer );
  3987. }
  3988. } else {
  3989. DebugTrace( 0, Dbg, "GetConnectionStatus: enumerate all connections.\n", 0 );
  3990. }
  3991. // Pull out the resume key here
  3992. ResumeKey = InputBuffer->Parameters.GetConnStatus.ResumeKey;
  3993. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  3994. Status = GetExceptionCode();
  3995. DebugTrace( 0, Dbg, "Bad input buffer in GetConnStatus.\n" , 0 );
  3996. goto ExitWithCleanup;
  3997. }
  3998. //
  3999. // If this is a server connection, find and return it.
  4000. //
  4001. if ( fServerConnection ) {
  4002. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  4003. OwnRcb = TRUE;
  4004. PrefixEntry = RtlFindUnicodePrefix( &NwRcb.ServerNameTable, &UidServer, 0 );
  4005. if ( !PrefixEntry ) {
  4006. Status = STATUS_INVALID_PARAMETER;
  4007. goto ExitWithCleanup;
  4008. }
  4009. pScb = CONTAINING_RECORD( PrefixEntry, SCB, PrefixEntry );
  4010. if ( ( pScb->PreferredServer ) ||
  4011. ( pScb->OpenFileCount > 0 ) ) {
  4012. //
  4013. // If there are open files, we need to return this.
  4014. // We always write status entries for the preferred
  4015. // server so that we can give default logon info.
  4016. //
  4017. goto ProcessServer;
  4018. }
  4019. //
  4020. // Are there open handles other than the caller?
  4021. //
  4022. if ( pScb == pCallerScb ) {
  4023. if ( pScb->IcbCount > 1 ) {
  4024. ASSERT( pScb->pNpScb->Reference > 1 );
  4025. goto ProcessServer;
  4026. }
  4027. } else {
  4028. if ( pScb->IcbCount > 0 ) {
  4029. ASSERT( pScb->pNpScb->Reference > 0 );
  4030. goto ProcessServer;
  4031. }
  4032. }
  4033. //
  4034. // Not an explicit use for this server.
  4035. //
  4036. goto ExitWithCleanup;
  4037. ProcessServer:
  4038. NwReferenceScb( pScb->pNpScb );
  4039. NwReleaseRcb( &NwRcb );
  4040. OwnRcb = FALSE;
  4041. // NOTE: This routine protects itself when writing
  4042. // to the OutputBuffer
  4043. Status = WriteConnStatusEntry( IrpContext,
  4044. pScb,
  4045. OutputBuffer,
  4046. OutputBufferLength,
  4047. &dwBytesWritten,
  4048. &dwBytesNeeded,
  4049. (BOOLEAN)( pScb == pCallerScb ) );
  4050. NwDereferenceScb( pScb->pNpScb );
  4051. try {
  4052. InputBuffer->Parameters.GetConnStatus.ResumeKey = 0;
  4053. if ( !NT_SUCCESS( Status )) {
  4054. InputBuffer->Parameters.GetConnStatus.EntriesReturned = 0;
  4055. InputBuffer->Parameters.GetConnStatus.BytesNeeded = dwBytesNeeded;
  4056. Irp->IoStatus.Information = 0;
  4057. goto ExitWithCleanup;
  4058. } else {
  4059. InputBuffer->Parameters.GetConnStatus.EntriesReturned = 1;
  4060. InputBuffer->Parameters.GetConnStatus.BytesNeeded = 0;
  4061. Irp->IoStatus.Information = dwBytesWritten;
  4062. goto ExitWithCleanup;
  4063. }
  4064. }
  4065. except (EXCEPTION_EXECUTE_HANDLER) {
  4066. Status = GetExceptionCode();
  4067. goto ExitWithCleanup;
  4068. }
  4069. }
  4070. //
  4071. // We want all connections or all tree connections, so
  4072. // we need to walk the list.
  4073. //
  4074. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  4075. ListEntry = ScbQueue.Flink;
  4076. while ( ListEntry != &ScbQueue ) {
  4077. pNpScb = CONTAINING_RECORD( ListEntry, NONPAGED_SCB, ScbLinks );
  4078. pScb = pNpScb->pScb;
  4079. NwReferenceScb( pNpScb );
  4080. KeReleaseSpinLock(&ScbSpinLock, OldIrql);
  4081. //
  4082. // Make sure we pass up the one's we've already returned.
  4083. //
  4084. if ( ( SequenceNumber >= ResumeKey ) &&
  4085. ( pNpScb != &NwPermanentNpScb ) &&
  4086. ( !IsCredentialName( &(pNpScb->pScb->NdsTreeName) ) ) ) {
  4087. //
  4088. // If there are open files, we need to return this.
  4089. // We always write status entries for the preferred
  4090. // server so that we can give default logon info.
  4091. //
  4092. if ( ( pScb->PreferredServer ) ||
  4093. ( pScb->OpenFileCount > 0 ) ) {
  4094. goto SecondProcessServer;
  4095. }
  4096. //
  4097. // Are there any handles other than the caller?
  4098. //
  4099. if ( pScb == pCallerScb ) {
  4100. if ( pScb->IcbCount > 1 ) {
  4101. ASSERT( pScb->pNpScb->Reference > 2 );
  4102. goto SecondProcessServer;
  4103. }
  4104. } else {
  4105. if ( pScb->IcbCount > 0 ) {
  4106. ASSERT( pScb->pNpScb->Reference > 1 );
  4107. goto SecondProcessServer;
  4108. }
  4109. }
  4110. }
  4111. //
  4112. // Not an interesting server; move to next entry.
  4113. //
  4114. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  4115. ListEntry = pNpScb->ScbLinks.Flink;
  4116. NwDereferenceScb( pNpScb );
  4117. SequenceNumber++;
  4118. continue;
  4119. SecondProcessServer:
  4120. //
  4121. // We have a possible candidate; see if the uid and tree are appropriate.
  4122. //
  4123. if ( ( (pScb->UserUid).QuadPart != Uid.QuadPart ) ||
  4124. ( fTreeConnections &&
  4125. !RtlEqualUnicodeString( &(pScb->NdsTreeName),
  4126. &ConnectionName,
  4127. TRUE ) ) ) {
  4128. //
  4129. // No dice. Move onto the next one.
  4130. //
  4131. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  4132. ListEntry = pNpScb->ScbLinks.Flink;
  4133. NwDereferenceScb( pNpScb );
  4134. SequenceNumber++;
  4135. continue;
  4136. }
  4137. //
  4138. // Ok, we definitely want to report this one.
  4139. // NOTE: This routine protects itself when writing
  4140. // to the OutputBuffer
  4141. //
  4142. Status = WriteConnStatusEntry( IrpContext,
  4143. pScb,
  4144. OutputBuffer,
  4145. OutputBufferLength,
  4146. &dwBytesWritten,
  4147. &dwBytesNeeded,
  4148. (BOOLEAN)( pScb == pCallerScb ) );
  4149. if ( !NT_SUCCESS( Status )) {
  4150. //
  4151. // If we couldn't write this entry, then we have to update
  4152. // the ResumeKey and return. We don't really know how many
  4153. // more there are going to be so we 'suggest' to the caller
  4154. // a 2k buffer size.
  4155. //
  4156. try {
  4157. InputBuffer->Parameters.GetConnStatus.ResumeKey = SequenceNumber;
  4158. InputBuffer->Parameters.GetConnStatus.EntriesReturned = dwReturned;
  4159. InputBuffer->Parameters.GetConnStatus.BytesNeeded = 2048;
  4160. }
  4161. except (EXCEPTION_EXECUTE_HANDLER) {
  4162. Status = GetExceptionCode();
  4163. }
  4164. NwDereferenceScb( pNpScb );
  4165. goto ExitWithCleanup;
  4166. } else {
  4167. OutputBuffer = ( OutputBuffer + dwBytesWritten );
  4168. OutputBufferLength -= dwBytesWritten;
  4169. dwReturned++;
  4170. }
  4171. //
  4172. // Move to next entry in the list.
  4173. //
  4174. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  4175. ListEntry = pNpScb->ScbLinks.Flink;
  4176. NwDereferenceScb( pNpScb );
  4177. SequenceNumber++;
  4178. }
  4179. //
  4180. // We made it through the list.
  4181. //
  4182. KeReleaseSpinLock(&ScbSpinLock, OldIrql);
  4183. try {
  4184. InputBuffer->Parameters.GetConnStatus.ResumeKey = 0;
  4185. InputBuffer->Parameters.GetConnStatus.EntriesReturned = dwReturned;
  4186. InputBuffer->Parameters.GetConnStatus.BytesNeeded = 0;
  4187. Status = STATUS_SUCCESS;
  4188. }
  4189. except (EXCEPTION_EXECUTE_HANDLER) {
  4190. Status = GetExceptionCode();
  4191. }
  4192. ExitWithCleanup:
  4193. //
  4194. // If we returned any entries, then set the status to success.
  4195. //
  4196. if ( dwReturned ) {
  4197. ASSERT( SequenceNumber != 0 );
  4198. Status = STATUS_SUCCESS;
  4199. }
  4200. if ( OwnRcb ) {
  4201. NwReleaseRcb( &NwRcb );
  4202. }
  4203. if ( UidServer.Buffer != NULL ) {
  4204. FREE_POOL( UidServer.Buffer );
  4205. }
  4206. return Status;
  4207. }
  4208. NTSTATUS
  4209. GetConnectionInfo(
  4210. IN PIRP_CONTEXT IrpContext
  4211. )
  4212. /*+++
  4213. GetConnectionInfo:
  4214. Takes a connection name from the new shell and returns
  4215. some info commonly requested by property sheets and the
  4216. such.
  4217. The following connection names are supported:
  4218. Drive Letter: "X:"
  4219. Printer Port: "LPTX:"
  4220. UNC Name: "\\SERVER\Share\{Path\}
  4221. ---*/
  4222. {
  4223. NTSTATUS Status;
  4224. PIRP Irp = IrpContext->pOriginalIrp;
  4225. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  4226. PNWR_REQUEST_PACKET InputBuffer;
  4227. PCONN_INFORMATION pConnInfo;
  4228. ULONG InputBufferLength, OutputBufferLength;
  4229. ULONG BytesNeeded;
  4230. SECURITY_SUBJECT_CONTEXT SubjectContext;
  4231. LARGE_INTEGER Uid;
  4232. UNICODE_STRING ConnectionName;
  4233. UNICODE_STRING UidVolumeName;
  4234. WCHAR DriveLetter = 0;
  4235. BOOLEAN OwnRcb = FALSE;
  4236. BOOLEAN ReferenceVcb = FALSE;
  4237. PVCB Vcb = NULL;
  4238. PSCB Scb = NULL;
  4239. PUNICODE_PREFIX_TABLE_ENTRY Prefix;
  4240. PLOGON pLogon;
  4241. UNICODE_STRING CredentialName;
  4242. UNICODE_STRING ServerName;
  4243. PUNICODE_STRING puUserName = NULL;
  4244. PNDS_SECURITY_CONTEXT pNdsContext;
  4245. BOOLEAN fHoldingCredentials = FALSE;
  4246. PVCB * DriveMapTable;
  4247. //
  4248. // Get the input and output buffers.
  4249. //
  4250. InputBuffer = (PNWR_REQUEST_PACKET) IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  4251. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  4252. OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  4253. if ( OutputBufferLength ) {
  4254. NwMapUserBuffer( Irp, KernelMode, (PVOID *)&pConnInfo );
  4255. } else {
  4256. return STATUS_BUFFER_TOO_SMALL;
  4257. }
  4258. //
  4259. // tommye - MS bug 31996
  4260. // Added ProbeForRead to check input buffer.
  4261. // Also added check for pConnInfo being NULL.
  4262. //
  4263. if (pConnInfo == NULL) {
  4264. return STATUS_INSUFFICIENT_RESOURCES;
  4265. }
  4266. try {
  4267. //
  4268. // Probe for safety.
  4269. //
  4270. if ( Irp->RequestorMode != KernelMode ) {
  4271. ProbeForRead( InputBuffer,
  4272. InputBufferLength,
  4273. sizeof( CHAR ));
  4274. }
  4275. } except (EXCEPTION_EXECUTE_HANDLER) {
  4276. return GetExceptionCode();
  4277. }
  4278. SeCaptureSubjectContext(&SubjectContext);
  4279. Uid = GetUid( &SubjectContext );
  4280. SeReleaseSubjectContext(&SubjectContext);
  4281. RtlInitUnicodeString( &UidVolumeName, NULL );
  4282. //
  4283. // tommye - MS bug 129818
  4284. //
  4285. // Probe ConnectionName for the advertised length
  4286. //
  4287. try {
  4288. ConnectionName.Length = (USHORT)(InputBuffer->Parameters).GetConnInfo.ConnectionNameLength;
  4289. ConnectionName.MaximumLength = ConnectionName.Length;
  4290. ConnectionName.Buffer = &((InputBuffer->Parameters).GetConnInfo.ConnectionName[0]);
  4291. //
  4292. // Probe for safety.
  4293. //
  4294. if ( Irp->RequestorMode != KernelMode ) {
  4295. ProbeForWrite( ConnectionName.Buffer,
  4296. ConnectionName.Length,
  4297. sizeof( CHAR ));
  4298. }
  4299. //
  4300. // Ok, this gets a little hand-wavey, but we have to try and figure
  4301. // what this connection name represents.
  4302. //
  4303. if ( ConnectionName.Length == sizeof( L"X:" ) - sizeof( WCHAR ) ) {
  4304. DriveLetter = ConnectionName.Buffer[0];
  4305. } else if ( ConnectionName.Length == sizeof( L"LPT1:" ) - sizeof( WCHAR ) ) {
  4306. DriveLetter = ConnectionName.Buffer[3];
  4307. }
  4308. } except (EXCEPTION_EXECUTE_HANDLER) {
  4309. return GetExceptionCode();
  4310. }
  4311. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  4312. OwnRcb = TRUE;
  4313. if ( DriveLetter != 0 ) {
  4314. DriveMapTable = GetDriveMapTable( Uid );
  4315. DebugTrace( 0, Dbg, "GetConnectionInfo: Drive %wZ\n", &ConnectionName );
  4316. //
  4317. // This is a drive relative path. Look up the drive letter.
  4318. //
  4319. ASSERT( ( DriveLetter >= L'A' && DriveLetter <= L'Z' ) ||
  4320. ( DriveLetter >= L'1' && DriveLetter <= L'9' ) );
  4321. if ( DriveLetter >= L'A' && DriveLetter <= L'Z' ) {
  4322. Vcb = DriveMapTable[DriveLetter - L'A'];
  4323. } else {
  4324. Vcb = DriveMapTable[MAX_DISK_REDIRECTIONS + DriveLetter - L'1'];
  4325. }
  4326. //
  4327. // Was the Vcb created for this user?
  4328. //
  4329. if ( ( Vcb != NULL ) && ( Uid.QuadPart != Vcb->Scb->UserUid.QuadPart ) ) {
  4330. Status = STATUS_ACCESS_DENIED;
  4331. goto ExitWithCleanup;
  4332. }
  4333. } else {
  4334. //
  4335. // This is a UNC path. Skip over the backslashes and
  4336. // prepend the unicode uid.
  4337. //
  4338. try {
  4339. ConnectionName.Length -= (2 * sizeof( WCHAR ) );
  4340. ConnectionName.Buffer += 2;
  4341. Status = MakeUidServer( &UidVolumeName, &Uid, &ConnectionName );
  4342. }
  4343. except (EXCEPTION_EXECUTE_HANDLER) {
  4344. Status = GetExceptionCode();
  4345. }
  4346. if ( !NT_SUCCESS( Status )) {
  4347. goto ExitWithCleanup;
  4348. }
  4349. DebugTrace( 0, Dbg, "GetConnectionInfo: %wZ\n", &UidVolumeName );
  4350. Prefix = RtlFindUnicodePrefix( &NwRcb.VolumeNameTable, &UidVolumeName, 0 );
  4351. if ( Prefix != NULL ) {
  4352. Vcb = CONTAINING_RECORD( Prefix, VCB, PrefixEntry );
  4353. if ( Vcb->Name.Length != UidVolumeName.Length ) {
  4354. Vcb = NULL;
  4355. }
  4356. }
  4357. //
  4358. // tommye - MS bug 16129 / MCS 360
  4359. //
  4360. // If the client called WNetGetUser and pass only the server name
  4361. // (e.g. "\\novell41") we would fail because we only looked in the
  4362. // volume table. So, we go ahead and look through the server table
  4363. // to see if there are any matches
  4364. //
  4365. else {
  4366. Prefix = RtlFindUnicodePrefix( &NwRcb.ServerNameTable, &UidVolumeName, 0 );
  4367. if (Prefix != NULL) {
  4368. Scb = CONTAINING_RECORD( Prefix, SCB, PrefixEntry );
  4369. goto GotScb;
  4370. }
  4371. }
  4372. }
  4373. if ( !Vcb ) {
  4374. Status = STATUS_BAD_NETWORK_PATH;
  4375. goto ExitWithCleanup;
  4376. }
  4377. DebugTrace( 0, Dbg, "GetConnectionInfo: Vcb is 0x%08lx\n", Vcb );
  4378. NwReferenceVcb( Vcb );
  4379. ReferenceVcb = TRUE;
  4380. NwReleaseRcb( &NwRcb );
  4381. OwnRcb = FALSE;
  4382. //
  4383. // Get the username. This is the same code block as in
  4384. // WriteConnStatusEntry; it should be abstracted out.
  4385. //
  4386. Scb = Vcb->Scb;
  4387. GotScb:
  4388. ASSERT( Scb != NULL );
  4389. if ( ( Scb->MajorVersion > 3 ) &&
  4390. ( Scb->UserName.Length == 0 ) ) {
  4391. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  4392. pLogon = FindUser( &Uid, FALSE );
  4393. NwReleaseRcb( &NwRcb );
  4394. if ( pLogon ) {
  4395. Status = NdsLookupCredentials( IrpContext,
  4396. &(Scb->NdsTreeName),
  4397. pLogon,
  4398. &pNdsContext,
  4399. CREDENTIAL_READ,
  4400. FALSE );
  4401. if ( NT_SUCCESS( Status ) ) {
  4402. fHoldingCredentials = TRUE;
  4403. if ( pNdsContext->Credential != NULL ) {
  4404. CredentialName.Length = pNdsContext->Credential->userNameLength -
  4405. sizeof( WCHAR );
  4406. CredentialName.MaximumLength = CredentialName.Length;
  4407. CredentialName.Buffer = (USHORT *)
  4408. ( ((BYTE *) pNdsContext->Credential ) +
  4409. sizeof( NDS_CREDENTIAL ) +
  4410. pNdsContext->Credential->optDataSize );
  4411. puUserName = &CredentialName;
  4412. }
  4413. }
  4414. }
  4415. } else {
  4416. puUserName = &(Scb->UserName);
  4417. }
  4418. DebugTrace( 0, Dbg, "GetConnectionInfo: UserName %wZ\n", puUserName );
  4419. //
  4420. // Strip off the uid from the server name.
  4421. //
  4422. ServerName.Length = (Scb->UidServerName).Length;
  4423. ServerName.Buffer = (Scb->UidServerName).Buffer;
  4424. while ( ServerName.Length ) {
  4425. if ( ServerName.Buffer[0] == L'\\' ) {
  4426. ServerName.Length -= sizeof( WCHAR );
  4427. ServerName.Buffer += 1;
  4428. break;
  4429. }
  4430. ServerName.Length -= sizeof( WCHAR );
  4431. ServerName.Buffer += 1;
  4432. }
  4433. DebugTrace( 0, Dbg, "GetConnectionInfo: ServerName %wZ\n", &ServerName );
  4434. //
  4435. // Write a single CONN_INFORMATION structure into the output buffer.
  4436. //
  4437. if ( puUserName ) {
  4438. BytesNeeded = sizeof( CONN_INFORMATION ) +
  4439. ServerName.Length +
  4440. puUserName->Length;
  4441. } else {
  4442. BytesNeeded = sizeof( CONN_INFORMATION ) +
  4443. ServerName.Length;
  4444. }
  4445. if ( BytesNeeded > OutputBufferLength ) {
  4446. Status = STATUS_BUFFER_TOO_SMALL;
  4447. goto ExitWithCleanup;
  4448. }
  4449. try {
  4450. pConnInfo->HostServerLength = ServerName.Length;
  4451. pConnInfo->HostServer = (LPWSTR) ( (PBYTE) pConnInfo ) + sizeof( CONN_INFORMATION );
  4452. RtlCopyMemory( pConnInfo->HostServer, ServerName.Buffer, ServerName.Length );
  4453. pConnInfo->UserName = (LPWSTR) ( ( (PBYTE) pConnInfo->HostServer ) +
  4454. ServerName.Length );
  4455. if ( puUserName ) {
  4456. pConnInfo->UserNameLength = puUserName->Length;
  4457. RtlCopyMemory( pConnInfo->UserName, puUserName->Buffer, puUserName->Length );
  4458. } else {
  4459. pConnInfo->UserNameLength = 0;
  4460. }
  4461. Status = STATUS_SUCCESS;
  4462. }
  4463. except (EXCEPTION_EXECUTE_HANDLER) {
  4464. Status = GetExceptionCode();
  4465. }
  4466. ExitWithCleanup:
  4467. if ( fHoldingCredentials ) {
  4468. NwReleaseCredList( pLogon, IrpContext );
  4469. }
  4470. if ( OwnRcb ) {
  4471. NwReleaseRcb( &NwRcb );
  4472. }
  4473. if ( ReferenceVcb ) {
  4474. NwDereferenceVcb( Vcb, NULL, FALSE );
  4475. }
  4476. if ( UidVolumeName.Buffer ) {
  4477. FREE_POOL( UidVolumeName.Buffer );
  4478. }
  4479. return Status;
  4480. }
  4481. NTSTATUS
  4482. GetPreferredServer(
  4483. IN PIRP_CONTEXT IrpContext
  4484. )
  4485. /*+++
  4486. GetPreferredServer:
  4487. Returns the current preferred server.
  4488. ---*/
  4489. {
  4490. NTSTATUS Status;
  4491. PIRP Irp = IrpContext->pOriginalIrp;
  4492. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  4493. BYTE *OutputBuffer;
  4494. ULONG OutputBufferLength;
  4495. SECURITY_SUBJECT_CONTEXT SubjectContext;
  4496. LARGE_INTEGER Uid;
  4497. PLOGON pLogon;
  4498. PUNICODE_STRING PreferredServer;
  4499. //
  4500. // Get the output buffer.
  4501. //
  4502. OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  4503. if ( OutputBufferLength ) {
  4504. NwMapUserBuffer( Irp, KernelMode, (PVOID *)&OutputBuffer );
  4505. } else {
  4506. return STATUS_BUFFER_TOO_SMALL;
  4507. }
  4508. //
  4509. // tommye
  4510. //
  4511. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  4512. // situations; this was not being checked.
  4513. //
  4514. if (OutputBuffer == NULL) {
  4515. DebugTrace(-1, DEBUG_TRACE_USERNCP, "NwMapUserBuffer returned NULL OutputBuffer", 0);
  4516. return STATUS_INSUFFICIENT_RESOURCES;
  4517. }
  4518. //
  4519. // Get the logon structure for the user and return the preferred server.
  4520. //
  4521. SeCaptureSubjectContext(&SubjectContext);
  4522. Uid = GetUid( &SubjectContext );
  4523. SeReleaseSubjectContext(&SubjectContext);
  4524. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  4525. pLogon = FindUser( &Uid, FALSE );
  4526. Status = STATUS_NO_SUCH_LOGON_SESSION;
  4527. if ( ( pLogon ) &&
  4528. ( pLogon->ServerName.Length ) &&
  4529. ( ( pLogon->ServerName.Length + sizeof( UNICODE_STRING ) ) <= OutputBufferLength ) ) {
  4530. try {
  4531. PreferredServer = (PUNICODE_STRING) OutputBuffer;
  4532. PreferredServer->Length = pLogon->ServerName.Length;
  4533. PreferredServer->MaximumLength = pLogon->ServerName.Length;
  4534. PreferredServer->Buffer = ( PWCHAR ) ( OutputBuffer + sizeof( UNICODE_STRING ) );
  4535. RtlCopyMemory(
  4536. PreferredServer->Buffer,
  4537. pLogon->ServerName.Buffer,
  4538. pLogon->ServerName.Length );
  4539. Status = STATUS_SUCCESS;
  4540. }
  4541. except (EXCEPTION_EXECUTE_HANDLER) {
  4542. Status = GetExceptionCode();
  4543. }
  4544. }
  4545. NwReleaseRcb( &NwRcb );
  4546. return Status;
  4547. }
  4548. NTSTATUS
  4549. GetConnectionPerformance(
  4550. IN PIRP_CONTEXT IrpContext
  4551. )
  4552. /*+++
  4553. GetConnectionPerformance:
  4554. Takes a connection name from the new shell and returns
  4555. some estimated performance info to the shell so the shell
  4556. can decide whether or not it wants to download icons, etc.
  4557. The following connection names are supported:
  4558. Drive Letter: "X:"
  4559. Printer Port: "LPTX:"
  4560. UNC Name: "\\SERVER\Share\{Path\}
  4561. ---*/
  4562. {
  4563. NTSTATUS Status;
  4564. PIRP Irp = IrpContext->pOriginalIrp;
  4565. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  4566. PNWR_REQUEST_PACKET InputBuffer;
  4567. ULONG InputBufferLength;
  4568. SECURITY_SUBJECT_CONTEXT SubjectContext;
  4569. LARGE_INTEGER Uid;
  4570. UNICODE_STRING RemoteName;
  4571. WCHAR DriveLetter = 0;
  4572. BOOLEAN OwnRcb = FALSE;
  4573. BOOLEAN ReferenceScb = FALSE;
  4574. PVCB Vcb = NULL;
  4575. PSCB Scb = NULL;
  4576. PLIST_ENTRY ListEntry;
  4577. UNICODE_STRING OriginalUnc;
  4578. PVCB * DriveMapTable;
  4579. //
  4580. // Get the input buffer.
  4581. //
  4582. InputBuffer = (PNWR_REQUEST_PACKET) IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  4583. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  4584. if ( InputBufferLength < (ULONG)FIELD_OFFSET( NWR_REQUEST_PACKET, Parameters.GetConnPerformance.RemoteName[1] ) ) {
  4585. return( STATUS_INVALID_PARAMETER );
  4586. }
  4587. //
  4588. // Get the UID for the caller.
  4589. //
  4590. SeCaptureSubjectContext(&SubjectContext);
  4591. Uid = GetUid( &SubjectContext );
  4592. SeReleaseSubjectContext(&SubjectContext);
  4593. try {
  4594. //
  4595. // Probe for safety.
  4596. //
  4597. if ( Irp->RequestorMode != KernelMode ) {
  4598. ProbeForRead( InputBuffer,
  4599. InputBufferLength,
  4600. sizeof( CHAR )
  4601. );
  4602. }
  4603. //
  4604. // Check the remote name length to see if it is sound. This subtraction
  4605. // can't underflow because of the test above.
  4606. //
  4607. if ( InputBuffer->Parameters.GetConnPerformance.RemoteNameLength >
  4608. InputBufferLength - FIELD_OFFSET( NWR_REQUEST_PACKET, Parameters.GetConnPerformance.RemoteName) ) {
  4609. return STATUS_INVALID_PARAMETER;
  4610. }
  4611. //
  4612. // Dig out the remote name.
  4613. //
  4614. RemoteName.Length = (USHORT)(InputBuffer->Parameters).GetConnPerformance.RemoteNameLength;
  4615. RemoteName.MaximumLength = RemoteName.Length;
  4616. RemoteName.Buffer = &((InputBuffer->Parameters).GetConnPerformance.RemoteName[0]);
  4617. //
  4618. // Ok, this gets a little hand-wavey, but we have to try and figure
  4619. // what this connection name represents (just like in GetConnectionInfo).
  4620. //
  4621. if ( RemoteName.Length == sizeof( L"X:" ) - sizeof( WCHAR ) ) {
  4622. DriveLetter = RemoteName.Buffer[0];
  4623. } else if ( RemoteName.Length == sizeof( L"LPT1:" ) - sizeof( WCHAR ) ) {
  4624. DriveLetter = RemoteName.Buffer[3];
  4625. }
  4626. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  4627. OwnRcb = TRUE;
  4628. DebugTrace( 0, Dbg, "GetConnectionPerformance: Remote Name %wZ\n", &RemoteName );
  4629. if ( DriveLetter != 0 ) {
  4630. DriveMapTable = GetDriveMapTable( Uid );
  4631. if ( ! ( ( ( DriveLetter >= L'a' ) && ( DriveLetter <= L'z' ) ) ||
  4632. ( ( DriveLetter >= L'A' ) && ( DriveLetter <= L'Z' ) ) ||
  4633. ( ( DriveLetter >= L'0' ) && ( DriveLetter <= L'9' ) ) ) ) {
  4634. Status = STATUS_BAD_NETWORK_PATH;
  4635. goto ExitWithCleanup;
  4636. }
  4637. //
  4638. // This is a drive relative path. Look up the drive letter.
  4639. //
  4640. if ( DriveLetter >= L'a' && DriveLetter <= L'z' ) {
  4641. DriveLetter += (WCHAR) ( L'A' - L'a' );
  4642. }
  4643. if ( DriveLetter >= L'A' && DriveLetter <= L'Z' ) {
  4644. Vcb = DriveMapTable[DriveLetter - L'A'];
  4645. } else {
  4646. Vcb = DriveMapTable[MAX_DISK_REDIRECTIONS + DriveLetter - L'1'];
  4647. }
  4648. //
  4649. // Did we get a connection?
  4650. //
  4651. if ( Vcb == NULL ) {
  4652. Status = STATUS_BAD_NETWORK_PATH;
  4653. goto ExitWithCleanup;
  4654. }
  4655. //
  4656. // Was the Vcb created for this user?
  4657. //
  4658. if ( Uid.QuadPart != Vcb->Scb->UserUid.QuadPart ) {
  4659. Status = STATUS_ACCESS_DENIED;
  4660. goto ExitWithCleanup;
  4661. }
  4662. Scb = Vcb->Scb;
  4663. } else {
  4664. //
  4665. // It's valid for the shell to pass us the remote name of a drive
  4666. // with no reference to the drive at all. Since we file these in
  4667. // volume prefix table with their drive letter information, we won't
  4668. // find them if we do a flat munge and lookup. Therefore, we have
  4669. // to walk the global vcb list and find the match.
  4670. //
  4671. //
  4672. // Skip over the first slash of the provided UNC remote name.
  4673. //
  4674. RemoteName.Length -= sizeof( WCHAR );
  4675. RemoteName.Buffer += 1;
  4676. for ( ListEntry = GlobalVcbList.Flink;
  4677. ( ListEntry != &GlobalVcbList ) && ( Scb == NULL );
  4678. ListEntry = ListEntry->Flink ) {
  4679. Vcb = CONTAINING_RECORD( ListEntry, VCB, GlobalVcbListEntry );
  4680. OriginalUnc.Length = Vcb->Name.Length;
  4681. OriginalUnc.MaximumLength = Vcb->Name.MaximumLength;
  4682. OriginalUnc.Buffer = Vcb->Name.Buffer;
  4683. if ( Vcb->DriveLetter ) {
  4684. //
  4685. // Try it as a drive connection.
  4686. //
  4687. while ( ( OriginalUnc.Length ) &&
  4688. ( OriginalUnc.Buffer[0] != L':' ) ) {
  4689. OriginalUnc.Length -= sizeof( WCHAR );
  4690. OriginalUnc.Buffer += 1;
  4691. }
  4692. if ( OriginalUnc.Buffer[0] == L':' ) {
  4693. OriginalUnc.Length -= sizeof( WCHAR );
  4694. OriginalUnc.Buffer += 1;
  4695. if ( RtlEqualUnicodeString( &OriginalUnc,
  4696. &RemoteName,
  4697. TRUE ) ) {
  4698. Scb = Vcb->Scb;
  4699. }
  4700. }
  4701. } else {
  4702. //
  4703. // Try it as a UNC connection; start by skipping
  4704. // only the leading slash, the walking to the next
  4705. // slash.
  4706. //
  4707. OriginalUnc.Length -= sizeof( WCHAR );
  4708. OriginalUnc.Buffer += 1;
  4709. while ( ( OriginalUnc.Length ) &&
  4710. ( OriginalUnc.Buffer[0] != L'\\' ) ) {
  4711. OriginalUnc.Length -= sizeof( WCHAR );
  4712. OriginalUnc.Buffer += 1;
  4713. }
  4714. if ( OriginalUnc.Length ) {
  4715. if ( RtlEqualUnicodeString( &OriginalUnc,
  4716. &RemoteName,
  4717. TRUE ) ) {
  4718. Scb = Vcb->Scb;
  4719. }
  4720. }
  4721. }
  4722. }
  4723. }
  4724. if ( !Scb ) {
  4725. Status = STATUS_BAD_NETWORK_PATH;
  4726. goto ExitWithCleanup;
  4727. }
  4728. NwReferenceScb( Scb->pNpScb );
  4729. ReferenceScb = TRUE;
  4730. NwReleaseRcb( &NwRcb );
  4731. OwnRcb = FALSE;
  4732. DebugTrace( 0, Dbg, "GetConnectionPerformance: Scb is 0x%08lx\n", Scb );
  4733. //
  4734. // Now dig out the performance info from the LIP negotiation.
  4735. //
  4736. // dwSpeed - The speed of the media to the network resource in units of 100bps (e.g 1,200
  4737. // baud point to point link returns 12).
  4738. // dwDelay - The delay introduced by the network when sending information (i.e. the time
  4739. // between starting sending data and the time that it starts being received) in
  4740. // units of a millisecond. This is in addition to any latency that was incorporated
  4741. // into the calculation of dwSpeed, so the value returned will be 0 for accessing
  4742. // most resources.
  4743. // dwOptDataSize - A recommendation for the size of data in bytes that is most efficiently
  4744. // sent through the network when an application makes a single request to
  4745. // the network resource. For example, for a disk network resource, this
  4746. // value might be 2048 or 512 when writing a block of data.
  4747. (InputBuffer->Parameters).GetConnPerformance.dwFlags = WNCON_DYNAMIC;
  4748. (InputBuffer->Parameters).GetConnPerformance.dwDelay = 0;
  4749. (InputBuffer->Parameters).GetConnPerformance.dwOptDataSize = Scb->pNpScb->BufferSize;
  4750. (InputBuffer->Parameters).GetConnPerformance.dwSpeed = Scb->pNpScb->LipDataSpeed;
  4751. //
  4752. // TRACKING: We don't return any good speed info for servers that have not yet
  4753. // negotiated lip. We may return out of date information for servers that have
  4754. // become disconnected unless a RAS line transition occurred. This API is bogus.
  4755. //
  4756. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  4757. Status = GetExceptionCode();
  4758. goto ExitWithCleanup;
  4759. }
  4760. Status = STATUS_SUCCESS;
  4761. ExitWithCleanup:
  4762. if ( OwnRcb ) {
  4763. NwReleaseRcb( &NwRcb );
  4764. }
  4765. if ( ReferenceScb ) {
  4766. NwDereferenceScb( Scb->pNpScb );
  4767. }
  4768. return Status;
  4769. }
  4770. NTSTATUS
  4771. SetShareBit(
  4772. IN PIRP_CONTEXT IrpContext,
  4773. PFILE_OBJECT FileObject
  4774. )
  4775. /*+++
  4776. SetShareBit:
  4777. This function sets the share bit on a file.
  4778. The bit won't get set until all handles to the
  4779. file are closed.
  4780. ---*/
  4781. {
  4782. NTSTATUS Status;
  4783. PIRP Irp = IrpContext->pOriginalIrp;
  4784. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  4785. NODE_TYPE_CODE nodeTypeCode;
  4786. PICB pIcb;
  4787. PFCB pFcb;
  4788. PVOID fsContext, fsContext2;
  4789. DebugTrace( 0, Dbg, "SetShareBit.\n", 0 );
  4790. //
  4791. // Make sure this is a handle to a file.
  4792. //
  4793. nodeTypeCode = NwDecodeFileObject( FileObject, &fsContext, &fsContext2 );
  4794. if ( nodeTypeCode != NW_NTC_ICB ) {
  4795. DebugTrace( 0, Dbg, "You can only set the share bit on a file!\n", 0 );
  4796. return STATUS_INVALID_PARAMETER;
  4797. }
  4798. pIcb = (PICB) fsContext2;
  4799. pFcb = pIcb->SuperType.Fcb;
  4800. if ( pFcb->NodeTypeCode != NW_NTC_FCB ) {
  4801. DebugTrace( 0, Dbg, "You can't set the share bit on a directory!\n", 0 );
  4802. return STATUS_INVALID_PARAMETER;
  4803. }
  4804. //
  4805. // Acquire this FCB so we can muck with the flags.
  4806. //
  4807. NwAcquireExclusiveFcb( pFcb->NonPagedFcb, TRUE );
  4808. SetFlag( pFcb->Flags, FCB_FLAGS_LAZY_SET_SHAREABLE );
  4809. NwReleaseFcb( pFcb->NonPagedFcb );
  4810. return STATUS_SUCCESS;
  4811. }
  4812. VOID
  4813. LazySetShareable(
  4814. PIRP_CONTEXT IrpContext,
  4815. PICB pIcb,
  4816. PFCB pFcb
  4817. )
  4818. /***
  4819. Function Description:
  4820. This function gets called everytime an ICB with a remote handle
  4821. is closed. If we are closing the last ICB to an FCB and the
  4822. caller has requested that we set the shareable bit on the FCB,
  4823. then we need to do so now. Otherwise, we simply return.
  4824. Caveats:
  4825. If we fail to set the shareable bit, there is no way to notify
  4826. the requestor of the operation that the operation was not carried
  4827. out.
  4828. ***/
  4829. {
  4830. NTSTATUS Status;
  4831. PLIST_ENTRY IcbListEntry;
  4832. PICB pCurrentIcb;
  4833. BOOLEAN OtherHandlesExist = FALSE;
  4834. ULONG Attributes;
  4835. BOOLEAN AttributesAreValid = FALSE;
  4836. //
  4837. // Get to the head of the queue, acquire the RCB,
  4838. // and acquire this FCB to protect the ICB list
  4839. // and FCB flags.
  4840. //
  4841. NwAppendToQueueAndWait( IrpContext );
  4842. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  4843. NwAcquireExclusiveFcb( pFcb->NonPagedFcb, TRUE );
  4844. //
  4845. // Scan the other ICBs on this FCB to see if any of
  4846. // them have remote handles.
  4847. //
  4848. for ( IcbListEntry = pFcb->IcbList.Flink;
  4849. IcbListEntry != &(pFcb->IcbList) ;
  4850. IcbListEntry = IcbListEntry->Flink ) {
  4851. pCurrentIcb = CONTAINING_RECORD( IcbListEntry, ICB, ListEntry );
  4852. if ( ( pCurrentIcb != pIcb ) &&
  4853. ( pCurrentIcb->HasRemoteHandle ) ) {
  4854. OtherHandlesExist = TRUE;
  4855. }
  4856. }
  4857. if ( OtherHandlesExist ) {
  4858. //
  4859. // We'll do it when the last handle is closed.
  4860. //
  4861. DebugTrace( 0, Dbg, "LazySetShareable: This isn't the last remote handle.\n", 0 );
  4862. goto ReleaseAllAndExit;
  4863. }
  4864. //
  4865. // We're closing the last handle. Make sure we have valid attributes.
  4866. //
  4867. if ( !FlagOn( pFcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID ) ) {
  4868. if ( !BooleanFlagOn( pFcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
  4869. Status = ExchangeWithWait ( IrpContext,
  4870. SynchronousResponseCallback,
  4871. "FwbbJ",
  4872. NCP_SEARCH_FILE,
  4873. -1,
  4874. pFcb->Vcb->Specific.Disk.Handle,
  4875. SEARCH_ALL_FILES,
  4876. &pFcb->RelativeFileName );
  4877. if ( NT_SUCCESS( Status ) ) {
  4878. Status = ParseResponse( IrpContext,
  4879. IrpContext->rsp,
  4880. IrpContext->ResponseLength,
  4881. "N==_b",
  4882. 14,
  4883. &Attributes );
  4884. if ( NT_SUCCESS( Status ) ) {
  4885. AttributesAreValid = TRUE;
  4886. }
  4887. }
  4888. } else {
  4889. Status = ExchangeWithWait ( IrpContext,
  4890. SynchronousResponseCallback,
  4891. "LbbWDbDbC",
  4892. NCP_LFN_GET_INFO,
  4893. pFcb->Vcb->Specific.Disk.LongNameSpace,
  4894. pFcb->Vcb->Specific.Disk.LongNameSpace,
  4895. SEARCH_ALL_FILES,
  4896. LFN_FLAG_INFO_ATTRIBUTES,
  4897. pFcb->Vcb->Specific.Disk.VolumeNumber,
  4898. pFcb->Vcb->Specific.Disk.Handle,
  4899. 0,
  4900. &pFcb->RelativeFileName );
  4901. if ( NT_SUCCESS( Status ) ) {
  4902. Status = ParseResponse( IrpContext,
  4903. IrpContext->rsp,
  4904. IrpContext->ResponseLength,
  4905. "N_e",
  4906. 4,
  4907. &Attributes );
  4908. if ( NT_SUCCESS( Status ) ) {
  4909. AttributesAreValid = TRUE;
  4910. }
  4911. }
  4912. }
  4913. } else {
  4914. Attributes = pFcb->NonPagedFcb->Attributes;
  4915. AttributesAreValid = TRUE;
  4916. }
  4917. if ( !AttributesAreValid ) {
  4918. DebugTrace( 0, Dbg, "Couldn't get valid attributes for this file.\n", 0 );
  4919. goto ReleaseAllAndExit;
  4920. }
  4921. //
  4922. // Do the set with the shareable bit on!
  4923. //
  4924. if ( BooleanFlagOn( pFcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
  4925. Status = ExchangeWithWait( IrpContext,
  4926. SynchronousResponseCallback,
  4927. "LbbWDW--WW==WW==_W_bDbC",
  4928. NCP_LFN_SET_INFO,
  4929. pFcb->Vcb->Specific.Disk.LongNameSpace,
  4930. pFcb->Vcb->Specific.Disk.LongNameSpace,
  4931. SEARCH_ALL_FILES,
  4932. LFN_FLAG_SET_INFO_ATTRIBUTES,
  4933. Attributes | 0x80,
  4934. 0,
  4935. 0,
  4936. 0,
  4937. 0,
  4938. 8,
  4939. 0,
  4940. 8,
  4941. pFcb->Vcb->Specific.Disk.VolumeNumber,
  4942. pFcb->Vcb->Specific.Disk.Handle,
  4943. 0,
  4944. &pFcb->RelativeFileName );
  4945. } else {
  4946. Status = ExchangeWithWait( IrpContext,
  4947. SynchronousResponseCallback,
  4948. "FbbbU",
  4949. NCP_SET_FILE_ATTRIBUTES,
  4950. Attributes | 0x80,
  4951. pFcb->Vcb->Specific.Disk.Handle,
  4952. SEARCH_ALL_FILES,
  4953. &pFcb->RelativeFileName );
  4954. }
  4955. if ( !NT_SUCCESS( Status ) ) {
  4956. DebugTrace( 0, Dbg, "Failed to set the shareable attribute on the file.\n", 0 );
  4957. ASSERT( FALSE && "File NOT marked as shareable!!" );
  4958. } else {
  4959. DebugTrace( 0, Dbg, "Shareable bit successfully set.\n", 0 );
  4960. ClearFlag( pFcb->Flags, FCB_FLAGS_LAZY_SET_SHAREABLE );
  4961. }
  4962. ReleaseAllAndExit:
  4963. NwReleaseFcb( pFcb->NonPagedFcb );
  4964. NwReleaseRcb( &NwRcb );
  4965. NwDequeueIrpContext( IrpContext, FALSE );
  4966. return;
  4967. }
  4968. NTSTATUS
  4969. GetConnectionDetails2(
  4970. IN PIRP_CONTEXT IrpContext
  4971. )
  4972. /*++
  4973. Routine Description:
  4974. This routine retrieves the details of a connection. This will return details
  4975. as to whether a connection is NDS enabled and if yes, it will return the
  4976. treename. The return structure looks like this:
  4977. typedef struct _CONN_DETAILS2 {
  4978. BOOL fNds; // TRUE if NDS, false for Bindery servers
  4979. WCHAR NdsTreeName[48]; // The tree name or '\0' for a 2.x or 3.x server
  4980. } CONN_DETAILS2, *PCONN_DETAILS2;
  4981. Arguments:
  4982. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  4983. Return Value:
  4984. NTSTATUS
  4985. --*/
  4986. {
  4987. NTSTATUS Status = STATUS_PENDING;
  4988. PIRP Irp = IrpContext->pOriginalIrp;
  4989. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  4990. ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  4991. PCONN_DETAILS2 OutputBuffer;
  4992. PSCB pScb;
  4993. PNONPAGED_SCB pNpScb;
  4994. PICB Icb;
  4995. PVOID FsContext;
  4996. NODE_TYPE_CODE nodeTypeCode;
  4997. PAGED_CODE();
  4998. DebugTrace(+1, Dbg, "GetConnectionDetails2\n", 0);
  4999. if ((nodeTypeCode = NwDecodeFileObject( IrpSp->FileObject,
  5000. &FsContext,
  5001. (PVOID *)&Icb )) != NW_NTC_ICB_SCB) {
  5002. DebugTrace(0, Dbg, "Incorrect nodeTypeCode %x\n", nodeTypeCode);
  5003. Status = STATUS_INVALID_PARAMETER;
  5004. DebugTrace(-1, Dbg, "GetConnectionDetails2 -> %08lx\n", Status );
  5005. return Status;
  5006. }
  5007. //
  5008. // Make sure that this ICB is still active.
  5009. //
  5010. NwVerifyIcb( Icb );
  5011. pScb = (PSCB)Icb->SuperType.Scb;
  5012. nodeTypeCode = pScb->NodeTypeCode;
  5013. if (nodeTypeCode != NW_NTC_SCB) {
  5014. return STATUS_INVALID_DEVICE_REQUEST;
  5015. }
  5016. pNpScb = pScb->pNpScb;
  5017. if ( OutputBufferLength < sizeof( CONN_DETAILS2 ) ) {
  5018. return STATUS_BUFFER_TOO_SMALL;
  5019. }
  5020. NwMapUserBuffer( Irp, KernelMode, (PVOID *)&OutputBuffer );
  5021. //
  5022. // tommye
  5023. //
  5024. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  5025. // situations; this was not being checked.
  5026. //
  5027. if (OutputBuffer == NULL) {
  5028. DebugTrace(-1, DEBUG_TRACE_USERNCP, "NwMapUserBuffer returned NULL OutputBuffer", 0);
  5029. return STATUS_INSUFFICIENT_RESOURCES;
  5030. }
  5031. try {
  5032. //
  5033. // Set the NDS flag
  5034. //
  5035. if ( ( pScb->MajorVersion > 3 ) && ( pScb->UserName.Length == 0 ) ) {
  5036. OutputBuffer->fNds = TRUE;
  5037. } else {
  5038. OutputBuffer->fNds = FALSE;
  5039. }
  5040. //
  5041. // Copy over the tree name.
  5042. //
  5043. if ( pScb->NdsTreeName.Buffer != NULL && pScb->NdsTreeName.Length > 0 ) {
  5044. RtlCopyMemory(
  5045. (PBYTE)( OutputBuffer->NdsTreeName ),
  5046. (PBYTE)(pScb->NdsTreeName.Buffer),
  5047. pScb->NdsTreeName.Length );
  5048. *( OutputBuffer->NdsTreeName +( pScb->NdsTreeName.Length / sizeof( WCHAR ) ) ) = L'\0';
  5049. } else {
  5050. *OutputBuffer->NdsTreeName = L'\0';
  5051. }
  5052. Status = STATUS_SUCCESS;
  5053. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  5054. Status = GetExceptionCode();
  5055. DebugTrace( 0, Dbg, "Exception %08lx accessing user mode buffer.\n", Status );
  5056. }
  5057. DebugTrace(-1, Dbg, "GetConnectionDetails2 -> %08lx\n", Status );
  5058. return Status;
  5059. }