Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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