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.

2450 lines
67 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. NdsFsctl.c
  5. Abstract:
  6. This implements the NDS user mode hooks to the redirector.
  7. Author:
  8. Cory West [CoryWest] 23-Feb-1995
  9. --*/
  10. #include "Procs.h"
  11. #define Dbg (DEBUG_TRACE_NDS)
  12. #pragma alloc_text( PAGE, DispatchNds )
  13. #pragma alloc_text( PAGE, PrepareLockedBufferFromFsd )
  14. #pragma alloc_text( PAGE, DoBrowseFsctl )
  15. #pragma alloc_text( PAGE, NdsRawFragex )
  16. #pragma alloc_text( PAGE, NdsResolveName )
  17. #pragma alloc_text( PAGE, NdsGetObjectInfo )
  18. #pragma alloc_text( PAGE, NdsListSubordinates )
  19. #pragma alloc_text( PAGE, NdsReadAttributes )
  20. #pragma alloc_text( PAGE, NdsGetVolumeInformation )
  21. #pragma alloc_text( PAGE, NdsOpenStream )
  22. #pragma alloc_text( PAGE, NdsSetContext )
  23. #pragma alloc_text( PAGE, NdsGetContext )
  24. #pragma alloc_text( PAGE, NdsVerifyTreeHandle )
  25. #pragma alloc_text( PAGE, NdsGetPrintQueueInfo )
  26. #pragma alloc_text( PAGE, NdsChangePass )
  27. #pragma alloc_text( PAGE, NdsListTrees )
  28. //
  29. // The main handler for all NDS FSCTL calls.
  30. //
  31. NTSTATUS
  32. DispatchNds(
  33. ULONG IoctlCode,
  34. PIRP_CONTEXT IrpContext
  35. )
  36. /*++
  37. Routine Description:
  38. This routine instigates an NDS transaction requested from
  39. the fsctl interface.
  40. Arguments:
  41. IoctlCode - Supplies the code to be used for the NDS transaction.
  42. IrpContext - A pointer to IRP context information for this request.
  43. Return Value:
  44. Status of transaction.
  45. --*/
  46. {
  47. NTSTATUS Status = STATUS_NOT_SUPPORTED;
  48. SECURITY_SUBJECT_CONTEXT SubjectContext;
  49. LARGE_INTEGER Uid;
  50. PAGED_CODE();
  51. //
  52. // Always set the user uid in the irp context so that
  53. // referral creates NEVER go astray.
  54. //
  55. SeCaptureSubjectContext(&SubjectContext);
  56. Uid = GetUid( &SubjectContext );
  57. SeReleaseSubjectContext(&SubjectContext);
  58. IrpContext->Specific.Create.UserUid.QuadPart = Uid.QuadPart;
  59. switch ( IoctlCode ) {
  60. //
  61. // These calls do not require us to lock down
  62. // the user's buffer, but they do generate wire
  63. // traffic.
  64. //
  65. case FSCTL_NWR_NDS_SETCONTEXT:
  66. DebugTrace( 0, Dbg, "DispatchNds: Set Context\n", 0 );
  67. return DoBrowseFsctl( IrpContext, IoctlCode, FALSE );
  68. case FSCTL_NWR_NDS_GETCONTEXT:
  69. DebugTrace( 0, Dbg, "DispatchNds: Get Context\n", 0 );
  70. return DoBrowseFsctl( IrpContext, IoctlCode, FALSE );
  71. case FSCTL_NWR_NDS_OPEN_STREAM:
  72. DebugTrace( 0, Dbg, "DispatchNds: Open Stream\n", 0 );
  73. return DoBrowseFsctl( IrpContext, IoctlCode, FALSE );
  74. case FSCTL_NWR_NDS_VERIFY_TREE:
  75. DebugTrace( 0, Dbg, "DispatchNds: Verify Tree\n", 0 );
  76. return DoBrowseFsctl( IrpContext, IoctlCode, FALSE );
  77. case FSCTL_NWR_NDS_GET_QUEUE_INFO:
  78. DebugTrace( 0, Dbg, "DispatchNds: Get Queue Info\n", 0 );
  79. return DoBrowseFsctl( IrpContext, IoctlCode, FALSE );
  80. case FSCTL_NWR_NDS_GET_VOLUME_INFO:
  81. DebugTrace( 0, Dbg, "DispatchNds: Get Volume Info\n", 0 );
  82. return DoBrowseFsctl( IrpContext, IoctlCode, FALSE );
  83. //
  84. // These four fsctl calls are the basis of browsing. They
  85. // all require a request packet and a user buffer that we
  86. // lock down.
  87. //
  88. case FSCTL_NWR_NDS_RESOLVE_NAME:
  89. DebugTrace( 0, Dbg, "DispatchNds: Resolve Name\n", 0 );
  90. return DoBrowseFsctl( IrpContext, IoctlCode, TRUE );
  91. case FSCTL_NWR_NDS_LIST_SUBS:
  92. DebugTrace( 0, Dbg, "DispatchNds: List Subordinates\n", 0 );
  93. return DoBrowseFsctl( IrpContext, IoctlCode, TRUE );
  94. case FSCTL_NWR_NDS_READ_INFO:
  95. DebugTrace( 0, Dbg, "DispatchNds: Read Object Info\n", 0 );
  96. return DoBrowseFsctl( IrpContext, IoctlCode, TRUE );
  97. case FSCTL_NWR_NDS_READ_ATTR:
  98. DebugTrace( 0, Dbg, "DispatchNds: Read Attribute\n", 0 );
  99. return DoBrowseFsctl( IrpContext, IoctlCode, TRUE );
  100. //
  101. // Support for user mode fragment exchange.
  102. //
  103. case FSCTL_NWR_NDS_RAW_FRAGEX:
  104. DebugTrace( 0, Dbg, "DispatchNds: Raw Fragex\n", 0 );
  105. return NdsRawFragex( IrpContext );
  106. //
  107. // Change an NDS password.
  108. //
  109. case FSCTL_NWR_NDS_CHANGE_PASS:
  110. DebugTrace( 0, Dbg, "DispatchNds: Change Password\n", 0 );
  111. return NdsChangePass( IrpContext );
  112. //
  113. // Special fsctl to list the trees that a particular nt user
  114. // has credentials to since the change pass ui runs under the
  115. // system luid. Sigh.
  116. //
  117. case FSCTL_NWR_NDS_LIST_TREES:
  118. DebugTrace( 0, Dbg, "DispatchNds: List trees\n", 0 );
  119. return NdsListTrees( IrpContext );
  120. default:
  121. DebugTrace( 0, Dbg, "DispatchNds: No Such IOCTL\n", 0 );
  122. break;
  123. }
  124. DebugTrace( 0, Dbg, " -> %08lx\n", Status );
  125. return Status;
  126. }
  127. NTSTATUS
  128. PrepareLockedBufferFromFsd(
  129. PIRP_CONTEXT pIrpContext,
  130. PLOCKED_BUFFER pLockedBuffer
  131. )
  132. /*
  133. Description:
  134. This routine takes the irp context for an FSD request with
  135. a user mode buffer, and locks down the buffer so that it may
  136. be sent to the transport. The locked down buffer, in addition
  137. to being described in the irp and irp context, is described
  138. in the LOCKED_BUFFER structure.
  139. Arguments:
  140. pIrpContext - irp context for this request
  141. pLockedBuffer - the locked response buffer
  142. */
  143. {
  144. PIRP irp;
  145. PIO_STACK_LOCATION irpSp;
  146. PVOID OutputBuffer;
  147. ULONG OutputBufferLength;
  148. PAGED_CODE();
  149. //
  150. // Get the irp and input buffer information and lock the
  151. // buffer to the irp.
  152. //
  153. irp = pIrpContext->pOriginalIrp;
  154. irpSp = IoGetCurrentIrpStackLocation( irp );
  155. OutputBufferLength = irpSp->Parameters.FileSystemControl.OutputBufferLength;
  156. if ( !OutputBufferLength ) {
  157. DebugTrace( 0, Dbg, "No fsd buffer length in PrepareLockedBufferFromFsd...\n", 0 );
  158. return STATUS_BUFFER_TOO_SMALL;
  159. }
  160. NwLockUserBuffer( irp, IoWriteAccess, OutputBufferLength );
  161. NwMapUserBuffer( irp, irp->RequestorMode, (PVOID *)&OutputBuffer );
  162. if ( !OutputBuffer ) {
  163. DebugTrace( 0, Dbg, "No fsd buffer in PrepareLockedBufferFromFsd...\n", 0 );
  164. return STATUS_BUFFER_TOO_SMALL;
  165. }
  166. //
  167. // Update the original MDL record in the Irp context, since
  168. // NwLockUserBuffer may have created a new MDL.
  169. //
  170. pIrpContext->pOriginalMdlAddress = irp->MdlAddress;
  171. //
  172. // Fill in our locked buffer description.
  173. //
  174. pLockedBuffer->pRecvBufferVa = MmGetMdlVirtualAddress( irp->MdlAddress );
  175. pLockedBuffer->dwRecvLen = MdlLength( irp->MdlAddress );
  176. pLockedBuffer->pRecvMdl = irp->MdlAddress;
  177. // DebugTrace( 0, Dbg, "Locked fsd buffer at %08lx\n", pLockedBuffer->pRecvBufferVa );
  178. // DebugTrace( 0, Dbg, " len -> %d\n", pLockedBuffer->dwRecvLen );
  179. // DebugTrace( 0, Dbg, " recv mdl at %08lx\n", pLockedBuffer->pRecvMdl );
  180. return STATUS_SUCCESS;
  181. }
  182. NTSTATUS
  183. DoBrowseFsctl( PIRP_CONTEXT pIrpContext,
  184. ULONG IoctlCode,
  185. BOOL LockdownBuffer
  186. )
  187. /*+++
  188. Description:
  189. This actually sets up for an NDS operation that requires wire
  190. traffic, including locking down the user buffer if necessary.
  191. Arguments:
  192. pIrpContext - the irp context for this request
  193. IoctlCode - the ioctl requested
  194. LockdownBuffer - do we need to lock down the user buffer
  195. ---*/
  196. {
  197. NTSTATUS Status;
  198. PIRP irp;
  199. PIO_STACK_LOCATION irpSp;
  200. PNWR_NDS_REQUEST_PACKET InputBuffer;
  201. ULONG InputBufferLength;
  202. PVOID fsContext, fsObject;
  203. NODE_TYPE_CODE nodeTypeCode;
  204. PSCB pScb = NULL;
  205. PICB pIcb = NULL;
  206. LOCKED_BUFFER LockedBuffer;
  207. PNDS_SECURITY_CONTEXT pCredential;
  208. UNICODE_STRING CredentialName;
  209. PAGED_CODE();
  210. //
  211. // Get the request packet in the input buffer.
  212. //
  213. irp = pIrpContext->pOriginalIrp;
  214. irpSp = IoGetCurrentIrpStackLocation( irp );
  215. InputBuffer = (PNWR_NDS_REQUEST_PACKET) irpSp->Parameters.FileSystemControl.Type3InputBuffer;
  216. InputBufferLength = irpSp->Parameters.FileSystemControl.InputBufferLength;
  217. if ( !InputBuffer ||
  218. !InputBufferLength ) {
  219. DebugTrace( 0, Dbg, "BrowseFsctl has no input buffer...\n", 0 );
  220. return STATUS_BUFFER_TOO_SMALL;
  221. }
  222. //
  223. // tommye - MS bug 32134 (MCS 265)
  224. //
  225. // Probe the input arguments to make sure they are kosher before
  226. // touching them.
  227. //
  228. try {
  229. if ( irp->RequestorMode != KernelMode ) {
  230. ProbeForRead( InputBuffer,
  231. InputBufferLength,
  232. sizeof(CHAR));
  233. //
  234. // tommye
  235. //
  236. // If the output buffer came from user space, then probe it for write.
  237. //
  238. if ((irpSp->Parameters.FileSystemControl.FsControlCode & 3) == METHOD_NEITHER) {
  239. ULONG OutputBufferLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  240. ProbeForWrite( irp->UserBuffer,
  241. OutputBufferLength,
  242. sizeof(CHAR)
  243. );
  244. }
  245. }
  246. } except (EXCEPTION_EXECUTE_HANDLER) {
  247. return GetExceptionCode();
  248. }
  249. //
  250. // Decode the file object and point the irp context the
  251. // the appropriate connection... Should this be in an
  252. // exception frame?
  253. //
  254. nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
  255. &fsContext,
  256. &fsObject );
  257. if ( nodeTypeCode == NW_NTC_ICB_SCB ) {
  258. pIcb = (PICB) fsObject;
  259. pScb = (pIcb->SuperType).Scb;
  260. pIrpContext->pScb = pScb;
  261. pIrpContext->pNpScb = pIrpContext->pScb->pNpScb;
  262. pIrpContext->Icb = pIcb;
  263. //
  264. // If this is a handle made on an ex-create, then
  265. // we have to be aware of our credentials while
  266. // jumping servers.
  267. //
  268. // This is not too intuitive since this doesn't
  269. // seem to be a create path irp, but referrals
  270. // on any path cause the create paths to be
  271. // traversed.
  272. //
  273. if ( pIcb->IsExCredentialHandle ) {
  274. pIrpContext->Specific.Create.fExCredentialCreate = TRUE;
  275. pCredential = (PNDS_SECURITY_CONTEXT) pIcb->pContext;
  276. Status = GetCredentialFromServerName( &pCredential->NdsTreeName,
  277. &CredentialName );
  278. if ( !NT_SUCCESS( Status ) ) {
  279. return STATUS_INVALID_HANDLE;
  280. }
  281. pIrpContext->Specific.Create.puCredentialName = &CredentialName;
  282. }
  283. }
  284. //
  285. // Lock the users buffer if this destined for the transport.
  286. //
  287. if ( LockdownBuffer &&
  288. nodeTypeCode == NW_NTC_ICB_SCB ) {
  289. Status = PrepareLockedBufferFromFsd( pIrpContext, &LockedBuffer );
  290. if ( !NT_SUCCESS( Status ) ) {
  291. return Status;
  292. }
  293. //
  294. // Call the appropriate browser.
  295. //
  296. switch ( IoctlCode ) {
  297. case FSCTL_NWR_NDS_RESOLVE_NAME:
  298. return NdsResolveName( pIrpContext, InputBuffer, InputBufferLength, &LockedBuffer );
  299. case FSCTL_NWR_NDS_LIST_SUBS:
  300. return NdsListSubordinates( pIrpContext, InputBuffer, &LockedBuffer );
  301. case FSCTL_NWR_NDS_READ_INFO:
  302. return NdsGetObjectInfo( pIrpContext, InputBuffer, &LockedBuffer );
  303. case FSCTL_NWR_NDS_READ_ATTR:
  304. return NdsReadAttributes( pIrpContext, InputBuffer, InputBufferLength, &LockedBuffer );
  305. default:
  306. DebugTrace( 0, Dbg, "Invalid ioctl for locked BrowseFsctl...\n", 0 );
  307. return STATUS_NOT_SUPPORTED;
  308. }
  309. }
  310. //
  311. // There's no user reply buffer for these calls, hence there's no lockdown.
  312. //
  313. switch ( IoctlCode ) {
  314. case FSCTL_NWR_NDS_OPEN_STREAM:
  315. //
  316. // There has to be an ICB for this!
  317. //
  318. if ( nodeTypeCode != NW_NTC_ICB_SCB ) {
  319. return STATUS_INVALID_HANDLE;
  320. }
  321. return NdsOpenStream( pIrpContext, InputBuffer, InputBufferLength );
  322. case FSCTL_NWR_NDS_SETCONTEXT:
  323. return NdsSetContext( pIrpContext, InputBuffer, InputBufferLength );
  324. case FSCTL_NWR_NDS_GETCONTEXT:
  325. return NdsGetContext( pIrpContext, InputBuffer, InputBufferLength );
  326. case FSCTL_NWR_NDS_VERIFY_TREE:
  327. //
  328. // Verify that this handle is valid for the specified tree.
  329. //
  330. return NdsVerifyTreeHandle( pIrpContext, InputBuffer, InputBufferLength );
  331. case FSCTL_NWR_NDS_GET_QUEUE_INFO:
  332. //
  333. // Get the queue info for this print queue.
  334. //
  335. return NdsGetPrintQueueInfo( pIrpContext, InputBuffer, InputBufferLength );
  336. case FSCTL_NWR_NDS_GET_VOLUME_INFO:
  337. //
  338. // Get the volume info for this volume object.
  339. // For the new shell property sheets.
  340. //
  341. return NdsGetVolumeInformation( pIrpContext, InputBuffer, InputBufferLength );
  342. }
  343. //
  344. // All others are not supported.
  345. //
  346. return STATUS_NOT_SUPPORTED;
  347. }
  348. NTSTATUS
  349. NdsRawFragex(
  350. PIRP_CONTEXT pIrpContext
  351. )
  352. /*+++
  353. Send a raw user requested fragment.
  354. ---*/
  355. {
  356. NTSTATUS Status;
  357. PIRP irp;
  358. PIO_STACK_LOCATION irpSp;
  359. NODE_TYPE_CODE nodeTypeCode;
  360. PVOID fsContext, fsObject;
  361. PSCB pScb = NULL;
  362. PICB pIcb = NULL;
  363. DWORD NdsVerb;
  364. LOCKED_BUFFER NdsRequest;
  365. PNWR_NDS_REQUEST_PACKET Rrp;
  366. PBYTE RawRequest;
  367. DWORD RawRequestLen;
  368. PNDS_SECURITY_CONTEXT pCredential;
  369. UNICODE_STRING CredentialName;
  370. PAGED_CODE();
  371. //
  372. // Get the request.
  373. //
  374. irp = pIrpContext->pOriginalIrp;
  375. irpSp = IoGetCurrentIrpStackLocation( irp );
  376. Rrp = ( PNWR_NDS_REQUEST_PACKET ) irpSp->Parameters.FileSystemControl.Type3InputBuffer;
  377. RawRequestLen = irpSp->Parameters.FileSystemControl.InputBufferLength;
  378. if ( !Rrp || ( RawRequestLen < sizeof( NWR_NDS_REQUEST_PACKET ) ) ) {
  379. DebugTrace( 0, Dbg, "No raw request buffer.\n", 0 );
  380. return STATUS_INVALID_PARAMETER;
  381. }
  382. //
  383. // Decode the file object and point the irp context
  384. // to the appropriate connection.
  385. //
  386. nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
  387. &fsContext,
  388. &fsObject );
  389. if ( nodeTypeCode != NW_NTC_ICB_SCB ) {
  390. DebugTrace( 0, Dbg, "A raw fragment request requires a server handle.\n", 0 );
  391. return STATUS_INVALID_HANDLE;
  392. }
  393. pIcb = (PICB) fsObject;
  394. pScb = (pIcb->SuperType).Scb;
  395. pIrpContext->pScb = pScb;
  396. pIrpContext->pNpScb = pIrpContext->pScb->pNpScb;
  397. pIrpContext->Icb = pIcb;
  398. //
  399. // If this is a handle made on an ex-create, then
  400. // we have to be aware of our credentials while
  401. // jumping servers.
  402. //
  403. // This is not too intuitive since this doesn't
  404. // seem to be a create path irp, but referrals
  405. // on any path cause the create paths to be
  406. // traversed.
  407. //
  408. if ( pIcb->IsExCredentialHandle ) {
  409. pIrpContext->Specific.Create.fExCredentialCreate = TRUE;
  410. pCredential = (PNDS_SECURITY_CONTEXT) pIcb->pContext;
  411. Status = GetCredentialFromServerName( &pCredential->NdsTreeName,
  412. &CredentialName );
  413. if ( !NT_SUCCESS( Status ) ) {
  414. return STATUS_INVALID_HANDLE;
  415. }
  416. pIrpContext->Specific.Create.puCredentialName = &CredentialName;
  417. }
  418. //
  419. // Dig out the parameters.
  420. //
  421. NdsVerb = Rrp->Parameters.RawRequest.NdsVerb;
  422. RawRequestLen = Rrp->Parameters.RawRequest.RequestLength;
  423. RawRequest = &Rrp->Parameters.RawRequest.Request[0];
  424. //
  425. // Get the reply buffer all locked in for the fragex.
  426. //
  427. Status = PrepareLockedBufferFromFsd( pIrpContext, &NdsRequest );
  428. if ( !NT_SUCCESS( Status ) ) {
  429. return Status;
  430. }
  431. try {
  432. if ( RawRequestLen ) {
  433. Status = FragExWithWait( pIrpContext,
  434. NdsVerb,
  435. &NdsRequest,
  436. "r",
  437. RawRequest,
  438. RawRequestLen );
  439. } else {
  440. Status = FragExWithWait( pIrpContext,
  441. NdsVerb,
  442. &NdsRequest,
  443. NULL );
  444. }
  445. if ( NT_SUCCESS( Status ) ) {
  446. Rrp->Parameters.RawRequest.ReplyLength = NdsRequest.dwBytesWritten;
  447. }
  448. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  449. Status = GetExceptionCode();
  450. }
  451. return Status;
  452. }
  453. NTSTATUS
  454. NdsResolveName(
  455. PIRP_CONTEXT pIrpContext,
  456. PNWR_NDS_REQUEST_PACKET pNdsRequest,
  457. ULONG RequestLength,
  458. PLOCKED_BUFFER pLockedBuffer
  459. )
  460. /*+++
  461. Description:
  462. This function decodes the resolve name request and makes the
  463. actual wire request.
  464. Parameters:
  465. pIrpContext - describes the irp for this request
  466. pLockedBuffer - describes the locked, user mode buffer that we will
  467. write the response into
  468. pNdsRequest - the request parameters
  469. Return Value:
  470. The status of the exchange.
  471. ---*/
  472. {
  473. NTSTATUS Status;
  474. UNICODE_STRING uObjectName;
  475. DWORD dwResolverFlags;
  476. WCHAR ObjectName[MAX_NDS_NAME_CHARS];
  477. PNDS_WIRE_RESPONSE_RESOLVE_NAME pWireResponse;
  478. PNDS_WIRE_RESPONSE_RESOLVE_NAME_REFERRAL pReferral;
  479. PNDS_RESPONSE_RESOLVE_NAME pUserResponse;
  480. IPXaddress *ReferredAddress;
  481. PSCB Scb, OldScb;
  482. PAGED_CODE();
  483. //
  484. // Fill in the resolver flags and the unicode string for the
  485. // object name from the request packet.
  486. //
  487. try {
  488. if (RequestLength < (FIELD_OFFSET(NWR_NDS_REQUEST_PACKET, Parameters.ResolveName.ObjectName) + pNdsRequest->Parameters.ResolveName.ObjectNameLength)) {
  489. DebugTrace( 0, Dbg, "ResolveName Request Length is too short.\n", 0 );
  490. return STATUS_INVALID_PARAMETER;
  491. }
  492. uObjectName.Length = (USHORT)(pNdsRequest->Parameters).ResolveName.ObjectNameLength;
  493. uObjectName.MaximumLength = sizeof( ObjectName );
  494. if ( uObjectName.Length > sizeof( ObjectName ) ) {
  495. ExRaiseStatus( STATUS_INVALID_BUFFER_SIZE );
  496. }
  497. RtlCopyMemory( ObjectName,
  498. (pNdsRequest->Parameters).ResolveName.ObjectName,
  499. uObjectName.Length );
  500. uObjectName.Buffer = ObjectName;
  501. dwResolverFlags = (pNdsRequest->Parameters).ResolveName.ResolverFlags;
  502. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  503. DebugTrace( 0, Dbg, "Bad user mode buffer in resolving name.\n", 0 );
  504. return GetExceptionCode();
  505. }
  506. Status = FragExWithWait( pIrpContext,
  507. NDSV_RESOLVE_NAME,
  508. pLockedBuffer,
  509. "DDDSDDDD",
  510. 0, // version
  511. dwResolverFlags, // flags
  512. 0, // scope
  513. &uObjectName, // distinguished name
  514. 1,0, // transport type
  515. 1,0 ); // treeWalker type
  516. if ( !NT_SUCCESS( Status ) ) {
  517. return Status;
  518. }
  519. Status = NdsCompletionCodetoNtStatus( pLockedBuffer );
  520. if ( !NT_SUCCESS( Status ) ) {
  521. return Status;
  522. }
  523. //
  524. // We need to convert the NDS_WIRE_RESPONSE_RESOLVE_NAME that
  525. // we got from the server into an NDS_RESPONSE_RESOLVE_NAME
  526. // for more general consumption. Notice that a referral packet
  527. // has an additional DWORD in it - what a pain.
  528. //
  529. pWireResponse = (PNDS_WIRE_RESPONSE_RESOLVE_NAME) pLockedBuffer->pRecvBufferVa;
  530. pReferral = (PNDS_WIRE_RESPONSE_RESOLVE_NAME_REFERRAL) pLockedBuffer->pRecvBufferVa;
  531. pUserResponse = (PNDS_RESPONSE_RESOLVE_NAME) pLockedBuffer->pRecvBufferVa;
  532. try {
  533. if ( pWireResponse->RemoteEntry == RESOLVE_NAME_ACCEPT_REMOTE ) {
  534. //
  535. // This server can handle this request.
  536. //
  537. pUserResponse->ServerNameLength = 0;
  538. (pNdsRequest->Parameters).ResolveName.BytesWritten = 4 * sizeof( DWORD );
  539. } else {
  540. //
  541. // tommye - MS 71699
  542. // These were BUGB-G's but we made it a valid check instead.
  543. // Original comment: I have seen this assertion fail because we only get
  544. // a valid competion code (four bytes) and no more data. I wonder
  545. // if the server is sending us this incomplete packet? If we
  546. // don't get a complete referal, we probably shouldn't chase it.
  547. //
  548. if ((pWireResponse->RemoteEntry != RESOLVE_NAME_REFER_REMOTE) ||
  549. (pReferral->ServerAddresses != 1) ||
  550. (pReferral->AddressType != 0) ||
  551. (pReferral->AddressLength != sizeof(IPXaddress))) {
  552. return ERROR_INVALID_PARAMETER;
  553. }
  554. //
  555. // We've been referred to another server. We have to connect
  556. // to the referred server to get the name for the caller.
  557. //
  558. ReferredAddress = (IPXaddress *) pReferral->Address;
  559. OldScb = pIrpContext->pScb;
  560. //
  561. // Dequeue us from our original server. Do not defer the
  562. // logon at this point since a referral means we're in the
  563. // middle of a browse operation.
  564. //
  565. NwDequeueIrpContext( pIrpContext, FALSE );
  566. Status = CreateScb( &Scb,
  567. pIrpContext,
  568. NULL,
  569. ReferredAddress,
  570. NULL,
  571. NULL,
  572. TRUE,
  573. FALSE );
  574. if ( !NT_SUCCESS( Status ) ) {
  575. return Status;
  576. }
  577. RtlCopyMemory( pUserResponse->ReferredServer,
  578. Scb->pNpScb->ServerName.Buffer,
  579. Scb->pNpScb->ServerName.Length );
  580. pUserResponse->ServerNameLength = Scb->pNpScb->ServerName.Length;
  581. (pNdsRequest->Parameters).ResolveName.BytesWritten =
  582. ( 4 * sizeof( DWORD ) ) + Scb->pNpScb->ServerName.Length;
  583. DebugTrace( 0, Dbg, "Resolve name referral to: %wZ\n",
  584. &Scb->pNpScb->ServerName );
  585. //
  586. // Restore the server pointers, we're not ready to jump
  587. // servers yet since this might be a request from the fsd.
  588. //
  589. NwDequeueIrpContext( pIrpContext, FALSE );
  590. NwDereferenceScb( Scb->pNpScb );
  591. pIrpContext->pScb = OldScb;
  592. pIrpContext->pNpScb = OldScb->pNpScb;
  593. }
  594. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  595. DebugTrace( 0, Dbg, "Bad user mode buffer in resolving name.\n", 0 );
  596. return GetExceptionCode();
  597. }
  598. return STATUS_SUCCESS;
  599. }
  600. NTSTATUS
  601. NdsGetObjectInfo(
  602. PIRP_CONTEXT pIrpContext,
  603. PNWR_NDS_REQUEST_PACKET pNdsRequest,
  604. PLOCKED_BUFFER pLockedBuffer
  605. )
  606. /*++
  607. Routine Description:
  608. Get the basic object information for the listed object.
  609. Routine Arguments:
  610. pIrpContext - describes the irp for this request
  611. pLockedBuffer - describes the locked, user mode buffer that we will
  612. write the response into
  613. pNdsRequest - the request parameters
  614. Return Value:
  615. The Status of the exchange.
  616. --*/
  617. {
  618. NTSTATUS Status;
  619. DWORD dwObjId;
  620. PAGED_CODE();
  621. //
  622. // Get the object id from the users request packet.
  623. //
  624. try {
  625. dwObjId = (pNdsRequest->Parameters).GetObjectInfo.ObjectId;
  626. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  627. DebugTrace( 0, Dbg, "Bonk! Lost user mode buffer in NdsGetObjectId...\n", 0 );
  628. Status = GetExceptionCode();
  629. return Status;
  630. }
  631. //
  632. // Hit the wire.
  633. //
  634. Status = FragExWithWait( pIrpContext,
  635. NDSV_READ_ENTRY_INFO,
  636. pLockedBuffer,
  637. "DD",
  638. 0,
  639. dwObjId );
  640. if ( !NT_SUCCESS( Status ) ) {
  641. return Status;
  642. }
  643. Status = NdsCompletionCodetoNtStatus( pLockedBuffer );
  644. if ( NT_SUCCESS( Status ) ) {
  645. try {
  646. (pNdsRequest->Parameters).GetObjectInfo.BytesWritten = pLockedBuffer->dwBytesWritten;
  647. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  648. DebugTrace( 0, Dbg, "Bonk! Lost user mode buffer after getting object info...\n", 0 );
  649. Status = GetExceptionCode();
  650. return Status;
  651. }
  652. }
  653. return Status;
  654. }
  655. NTSTATUS
  656. NdsListSubordinates(
  657. PIRP_CONTEXT pIrpContext,
  658. PNWR_NDS_REQUEST_PACKET pNdsRequest,
  659. PLOCKED_BUFFER pLockedBuffer
  660. )
  661. /*++
  662. Routine Description:
  663. List the immediate subordinates of an object.
  664. Routine Arguments:
  665. pIrpContext - describes the irp for this request
  666. pLockedBuffer - describes the locked, user mode buffer that we will
  667. write the response into
  668. pNdsRequest - the request parameters
  669. Return Value:
  670. The Status of the exchange.
  671. --*/
  672. {
  673. NTSTATUS Status;
  674. DWORD dwParent, dwIterHandle;
  675. PAGED_CODE();
  676. //
  677. // Dig out the request parameters.
  678. //
  679. try {
  680. dwParent = (pNdsRequest->Parameters).ListSubordinates.ObjectId;
  681. dwIterHandle = (DWORD) (pNdsRequest->Parameters).ListSubordinates.IterHandle;
  682. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  683. DebugTrace( 0, Dbg, "Bonk! No user mode buffer in ListSubordinates...\n", 0 );
  684. Status = GetExceptionCode();
  685. return Status;
  686. }
  687. //
  688. // Make the request.
  689. //
  690. Status = FragExWithWait( pIrpContext,
  691. NDSV_LIST,
  692. pLockedBuffer,
  693. "DDDD",
  694. 0,
  695. 0x40,
  696. dwIterHandle,
  697. dwParent );
  698. if ( !NT_SUCCESS( Status ) ) {
  699. return Status;
  700. }
  701. Status = NdsCompletionCodetoNtStatus( pLockedBuffer );
  702. if ( NT_SUCCESS( Status ) ) {
  703. try {
  704. (pNdsRequest->Parameters).ListSubordinates.BytesWritten = pLockedBuffer->dwBytesWritten;
  705. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  706. DebugTrace( 0, Dbg, "Bonk! Lost user mode buffer after getting subordinate list...\n", 0 );
  707. Status = GetExceptionCode();
  708. return Status;
  709. }
  710. }
  711. return Status;
  712. }
  713. NTSTATUS
  714. NdsReadAttributes(
  715. PIRP_CONTEXT pIrpContext,
  716. PNWR_NDS_REQUEST_PACKET pNdsRequest,
  717. ULONG RequestLength,
  718. PLOCKED_BUFFER pLockedBuffer
  719. )
  720. /*++
  721. Routine Description:
  722. Retrieve the named attribute of an object.
  723. Routine Arguments:
  724. pIrpContext - describes the irp for this request
  725. pLockedBuffer - describes the locked, user mode buffer that we will
  726. write the response into
  727. pNdsRequest - the request parameters
  728. Return Value:
  729. The Status of the exchange.
  730. --*/
  731. {
  732. NTSTATUS Status;
  733. DWORD dwIterHandle, dwOid;
  734. UNICODE_STRING uAttributeName;
  735. WCHAR AttributeName[MAX_NDS_SCHEMA_NAME_CHARS]; // was MAX_NDS_NAME_CHARS
  736. PAGED_CODE();
  737. RtlZeroMemory( AttributeName, sizeof( AttributeName ) );
  738. try {
  739. if (RequestLength < (FIELD_OFFSET(NWR_NDS_REQUEST_PACKET, Parameters.ReadAttribute.AttributeName) + pNdsRequest->Parameters.ReadAttribute.AttributeNameLength)) {
  740. DebugTrace( 0, Dbg, "ReadAttributes Request Length is too short.\n", 0 );
  741. return STATUS_INVALID_PARAMETER;
  742. }
  743. uAttributeName.Length = (USHORT)(pNdsRequest->Parameters).ReadAttribute.AttributeNameLength;
  744. uAttributeName.MaximumLength = sizeof( AttributeName );
  745. if ( uAttributeName.Length > uAttributeName.MaximumLength ) {
  746. ExRaiseStatus( STATUS_INVALID_BUFFER_SIZE );
  747. }
  748. RtlCopyMemory( AttributeName,
  749. (pNdsRequest->Parameters).ReadAttribute.AttributeName,
  750. uAttributeName.Length );
  751. uAttributeName.Buffer = AttributeName;
  752. dwIterHandle = (DWORD) (pNdsRequest->Parameters).ReadAttribute.IterHandle;
  753. dwOid = (pNdsRequest->Parameters).ReadAttribute.ObjectId;
  754. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  755. DebugTrace( 0 , Dbg, "Bonk! Exception accessing user mode buffer in read attributes...\n", 0 );
  756. return GetExceptionCode();
  757. }
  758. Status = FragExWithWait( pIrpContext,
  759. NDSV_READ,
  760. pLockedBuffer,
  761. "DDDDDDS",
  762. 0, // version
  763. dwIterHandle, // iteration handle
  764. dwOid, // object id
  765. 1, // info type
  766. //
  767. // The attribute specifier has been seen at zero and
  768. // at 0x4e0000. I don't know why... but zero doesn't
  769. // work sometimes...
  770. //
  771. 0x4e0000, // attrib type
  772. 1, // number of attribs
  773. &uAttributeName ); // attrib name
  774. if ( !NT_SUCCESS( Status ) ) {
  775. return Status;
  776. }
  777. Status = NdsCompletionCodetoNtStatus( pLockedBuffer );
  778. if ( NT_SUCCESS( Status ) ) {
  779. try {
  780. (pNdsRequest->Parameters).ReadAttribute.BytesWritten = pLockedBuffer->dwBytesWritten;
  781. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  782. DebugTrace( 0, Dbg, "Bonk! Lost user mode buffer after reading attribute...\n", 0 );
  783. return GetExceptionCode();
  784. }
  785. }
  786. return Status;
  787. }
  788. NTSTATUS
  789. NdsGetVolumeInformation(
  790. PIRP_CONTEXT pIrpContext,
  791. PNWR_NDS_REQUEST_PACKET pNdsRequest,
  792. ULONG RequestLength
  793. )
  794. /*+++
  795. Description:
  796. This function gets the name of the server that hosts
  797. the listed nds volume.
  798. Parameters:
  799. pIrpContext - describes the irp for this request
  800. pNdsRequest - the request parameters
  801. ---*/
  802. {
  803. NTSTATUS Status;
  804. PIRP irp;
  805. PIO_STACK_LOCATION irpSp;
  806. PSCB pOriginalScb;
  807. PBYTE OutputBuffer = NULL;
  808. ULONG OutputBufferLength;
  809. UNICODE_STRING VolumeObject;
  810. DWORD VolumeOid;
  811. UNICODE_STRING HostServerAttr;
  812. UNICODE_STRING HostVolumeAttr;
  813. UNICODE_STRING Attribute;
  814. PWCHAR ServerString;
  815. ULONG ServerLength;
  816. PAGED_CODE();
  817. try {
  818. if (RequestLength < (FIELD_OFFSET(NWR_NDS_REQUEST_PACKET, Parameters.GetVolumeInfo.VolumeName) + pNdsRequest->Parameters.GetVolumeInfo.VolumeNameLen)) {
  819. DebugTrace( 0, Dbg, "GetVolumeInfo Request Length is too short.\n", 0 );
  820. return STATUS_INVALID_PARAMETER;
  821. }
  822. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  823. return GetExceptionCode();
  824. }
  825. //
  826. // Get the irp and output buffer information.
  827. //
  828. irp = pIrpContext->pOriginalIrp;
  829. irpSp = IoGetCurrentIrpStackLocation( irp );
  830. OutputBufferLength = irpSp->Parameters.FileSystemControl.OutputBufferLength;
  831. if ( OutputBufferLength ) {
  832. NwMapUserBuffer( irp, irp->RequestorMode, (PVOID *)&OutputBuffer );
  833. //
  834. // tommye
  835. //
  836. // NwMapUserBuffer may return a NULL OutputBuffer in low resource
  837. // situations; this was not being checked.
  838. //
  839. if (OutputBuffer == NULL) {
  840. DebugTrace(-1, DEBUG_TRACE_USERNCP, "NwMapUserBuffer returned NULL OutputBuffer", 0);
  841. return STATUS_INSUFFICIENT_RESOURCES;
  842. }
  843. }
  844. else {
  845. return STATUS_BUFFER_TOO_SMALL;
  846. }
  847. try {
  848. //
  849. // Prepare the input information.
  850. //
  851. VolumeObject.Length = (USHORT)pNdsRequest->Parameters.GetVolumeInfo.VolumeNameLen;
  852. VolumeObject.MaximumLength = VolumeObject.Length;
  853. VolumeObject.Buffer = &(pNdsRequest->Parameters.GetVolumeInfo.VolumeName[0]);
  854. // tommye - make sure that the name length isn't bigger than we expect
  855. if (VolumeObject.Length > MAX_NDS_NAME_SIZE) {
  856. DebugTrace( 0 , Dbg, "NdsGetVolumeInformation: Volume name too long!.\n", 0 );
  857. return STATUS_INVALID_PARAMETER;
  858. }
  859. DebugTrace( 0, Dbg, "Retrieving volume info for %wZ\n", &VolumeObject );
  860. HostServerAttr.Buffer = HOST_SERVER_ATTRIBUTE; // L"Host Server"
  861. HostServerAttr.Length = sizeof( HOST_SERVER_ATTRIBUTE ) - sizeof( WCHAR );
  862. HostServerAttr.MaximumLength = HostServerAttr.Length;
  863. HostVolumeAttr.Buffer = HOST_VOLUME_ATTRIBUTE; // L"Host Resource Name"
  864. HostVolumeAttr.Length = sizeof( HOST_VOLUME_ATTRIBUTE ) - sizeof( WCHAR );
  865. HostVolumeAttr.MaximumLength = HostVolumeAttr.Length;
  866. //
  867. // NdsResolveNameKm may have to jump servers to service this
  868. // request, however it's dangerous for us to derefence the original
  869. // scb because that would expose a scavenger race condition. So,
  870. // we add an additional ref-count to the original scb and then clean
  871. // up appropriately afterwards, depending on whether or not we
  872. // jumped servers.
  873. //
  874. pOriginalScb = pIrpContext->pScb;
  875. NwReferenceScb( pOriginalScb->pNpScb );
  876. Status = NdsResolveNameKm ( pIrpContext,
  877. &VolumeObject,
  878. &VolumeOid,
  879. TRUE,
  880. DEFAULT_RESOLVE_FLAGS );
  881. if ( !NT_SUCCESS( Status )) {
  882. NwDereferenceScb( pOriginalScb->pNpScb );
  883. return STATUS_BAD_NETWORK_PATH;
  884. }
  885. if ( pIrpContext->pScb == pOriginalScb ) {
  886. //
  887. // We didn't jump servers.
  888. //
  889. NwDereferenceScb( pOriginalScb->pNpScb );
  890. }
  891. //
  892. // We have to read the server into a temporary buffer so
  893. // we can strip off the x500 prefix and the context
  894. // from the server name. This isn't really what I would
  895. // call nice, but it's the way Netware works.
  896. //
  897. Attribute.Length = 0;
  898. Attribute.MaximumLength = MAX_NDS_NAME_SIZE;
  899. Attribute.Buffer = ALLOCATE_POOL( PagedPool, MAX_NDS_NAME_SIZE );
  900. if (!Attribute.Buffer) {
  901. Status = STATUS_INSUFFICIENT_RESOURCES;
  902. goto CleanupScbReferences;
  903. }
  904. Status = NdsReadStringAttribute( pIrpContext,
  905. VolumeOid,
  906. &HostServerAttr,
  907. &Attribute );
  908. if ( !NT_SUCCESS( Status )) {
  909. FREE_POOL( Attribute.Buffer );
  910. goto CleanupScbReferences;
  911. }
  912. ServerString = Attribute.Buffer;
  913. while( Attribute.Length ) {
  914. if ( *ServerString == L'=' ) {
  915. ServerString += 1;
  916. Attribute.Length -= sizeof( WCHAR );
  917. break;
  918. }
  919. ServerString += 1;
  920. Attribute.Length -= sizeof( WCHAR );
  921. }
  922. if ( Attribute.Length == 0 ) {
  923. DebugTrace( 0, Dbg, "Malformed server for volume.\n", 0 );
  924. FREE_POOL( Attribute.Buffer );
  925. Status = STATUS_UNSUCCESSFUL;
  926. goto CleanupScbReferences;
  927. }
  928. ServerLength = 0;
  929. while ( ServerLength < (Attribute.Length / sizeof( WCHAR )) ) {
  930. if ( ServerString[ServerLength] == L'.' ) {
  931. break;
  932. }
  933. ServerLength++;
  934. }
  935. if ( ServerLength == ( Attribute.Length / sizeof( WCHAR ) ) ) {
  936. DebugTrace( 0, Dbg, "Malformed server for volume.\n", 0 );
  937. FREE_POOL( Attribute.Buffer );
  938. Status = STATUS_UNSUCCESSFUL;
  939. goto CleanupScbReferences;
  940. }
  941. ServerLength *= sizeof( WCHAR );
  942. RtlCopyMemory( OutputBuffer, ServerString, ServerLength );
  943. pNdsRequest->Parameters.GetVolumeInfo.ServerNameLen = ServerLength;
  944. FREE_POOL( Attribute.Buffer );
  945. Attribute.Length = Attribute.MaximumLength = (USHORT)ServerLength;
  946. Attribute.Buffer = (PWCHAR)OutputBuffer;
  947. DebugTrace( 0, Dbg, "Host server is: %wZ\n", &Attribute );
  948. //
  949. // Now do the volume in place. This is the easy one.
  950. //
  951. Attribute.MaximumLength = (USHORT)( OutputBufferLength - ServerLength );
  952. Attribute.Buffer = (PWSTR) ( OutputBuffer + ServerLength );
  953. Attribute.Length = 0;
  954. Status = NdsReadStringAttribute( pIrpContext,
  955. VolumeOid,
  956. &HostVolumeAttr,
  957. &Attribute );
  958. if ( !NT_SUCCESS( Status )) {
  959. goto CleanupScbReferences;
  960. }
  961. pNdsRequest->Parameters.GetVolumeInfo.TargetVolNameLen = Attribute.Length;
  962. DebugTrace( 0, Dbg, "Host volume is: %wZ\n", &Attribute );
  963. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  964. DebugTrace( 0, Dbg, "Exception handling user mode buffer in GetVolumeInfo.\n", 0 );
  965. goto CleanupScbReferences;
  966. }
  967. Status = STATUS_SUCCESS;
  968. CleanupScbReferences:
  969. if ( pIrpContext->pScb != pOriginalScb ) {
  970. //
  971. // We jumped servers and have to cleanup.
  972. //
  973. NwDequeueIrpContext( pIrpContext, FALSE );
  974. NwDereferenceScb( pIrpContext->pScb->pNpScb );
  975. pIrpContext->pScb = pOriginalScb;
  976. pIrpContext->pNpScb = pOriginalScb->pNpScb;
  977. }
  978. return Status;
  979. }
  980. NTSTATUS
  981. NdsOpenStream(
  982. PIRP_CONTEXT pIrpContext,
  983. PNWR_NDS_REQUEST_PACKET pNdsRequest,
  984. ULONG RequestLength
  985. ) {
  986. NTSTATUS Status;
  987. UNICODE_STRING uStream;
  988. WCHAR StreamName[MAX_NDS_NAME_CHARS];
  989. LOCKED_BUFFER NdsRequest;
  990. DWORD dwOid, StreamAccess;
  991. DWORD hNwHandle, dwFileLen;
  992. PICB pIcb;
  993. PSCB pScb = pIrpContext->pNpScb->pScb;
  994. BOOLEAN LicensedConnection = FALSE;
  995. PAGED_CODE();
  996. pIcb = pIrpContext->Icb;
  997. uStream.Length = 0;
  998. uStream.MaximumLength = sizeof( StreamName );
  999. uStream.Buffer = StreamName;
  1000. DebugTrace( 0 , Dbg, "NDS open stream...\n", 0 );
  1001. try {
  1002. if (RequestLength < (ULONG)(FIELD_OFFSET(NWR_NDS_REQUEST_PACKET, Parameters.OpenStream.StreamNameString) + pNdsRequest->Parameters.OpenStream.StreamName.Length)) {
  1003. DebugTrace( 0, Dbg, "OpenStream Request Length is too short.\n", 0 );
  1004. return STATUS_INVALID_PARAMETER;
  1005. }
  1006. dwOid = (pNdsRequest->Parameters).OpenStream.ObjectOid;
  1007. StreamAccess = (pNdsRequest->Parameters).OpenStream.StreamAccess;
  1008. RtlCopyUnicodeString( &uStream, &(pNdsRequest->Parameters).OpenStream.StreamName );
  1009. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  1010. DebugTrace( 0 , Dbg, "Bonk! Bad user mode buffer in open stream.\n", 0 );
  1011. return GetExceptionCode();
  1012. }
  1013. //
  1014. // We have the oid and stream name; let's get the handle.
  1015. //
  1016. Status = NdsAllocateLockedBuffer( &NdsRequest, NDS_BUFFER_SIZE );
  1017. if ( !NT_SUCCESS( Status ) ) {
  1018. return STATUS_INSUFFICIENT_RESOURCES;
  1019. }
  1020. //
  1021. // If we haven't licensed this connection yet, it's time. Get to the
  1022. // head of the queue to protect the SCB fields and authenticate the
  1023. // connection (do not defer the login).
  1024. //
  1025. NwAppendToQueueAndWait( pIrpContext );
  1026. ASSERT( pScb->MajorVersion > 3 );
  1027. if ( ( pScb->UserName.Length == 0 ) &&
  1028. ( pScb->VcbCount == 0 ) &&
  1029. ( pScb->OpenNdsStreams == 0 ) ) {
  1030. if ( pScb->pNpScb->State != SCB_STATE_IN_USE ) {
  1031. Status = ConnectScb( &pScb,
  1032. pIrpContext,
  1033. &(pScb->pNpScb->ServerName),
  1034. NULL, // address
  1035. NULL, // name
  1036. NULL, // password
  1037. FALSE, // defer login
  1038. FALSE, // delete connection
  1039. TRUE ); // existing scb
  1040. if ( !NT_SUCCESS( Status ) ) {
  1041. DebugTrace( 0, Dbg, "Couldn't connect server %08lx to open NDS stream.\n", pScb );
  1042. goto ExitWithCleanup;
  1043. }
  1044. }
  1045. ASSERT( pScb->pNpScb->State == SCB_STATE_IN_USE );
  1046. Status = NdsLicenseConnection( pIrpContext );
  1047. if ( !NT_SUCCESS( Status ) ) {
  1048. Status = STATUS_REMOTE_SESSION_LIMIT;
  1049. goto ExitWithCleanup;
  1050. }
  1051. LicensedConnection = TRUE;
  1052. }
  1053. Status = FragExWithWait( pIrpContext,
  1054. NDSV_OPEN_STREAM,
  1055. &NdsRequest,
  1056. "DDDs",
  1057. 0, // version
  1058. StreamAccess, // file access
  1059. dwOid, // object id
  1060. &uStream ); // attribute name
  1061. if ( !NT_SUCCESS( Status )) {
  1062. goto ExitWithCleanup;
  1063. }
  1064. Status = NdsCompletionCodetoNtStatus( &NdsRequest );
  1065. if ( !NT_SUCCESS( Status )) {
  1066. goto ExitWithCleanup;
  1067. }
  1068. Status = ParseResponse( NULL,
  1069. NdsRequest.pRecvBufferVa,
  1070. NdsRequest.dwBytesWritten,
  1071. "G_DD",
  1072. sizeof( DWORD ), // completion code
  1073. &hNwHandle, // remote handle
  1074. &dwFileLen ); // file length
  1075. if ( !NT_SUCCESS( Status )) {
  1076. goto ExitWithCleanup;
  1077. }
  1078. *(WORD *)(&pIcb->Handle[0]) = (WORD)hNwHandle + 1;
  1079. *( (UNALIGNED DWORD *) (&pIcb->Handle[2]) ) = hNwHandle;
  1080. pIrpContext->pScb->OpenNdsStreams++;
  1081. DebugTrace( 0, Dbg, "File stream opened. Length = %d\n", dwFileLen );
  1082. (pNdsRequest->Parameters).OpenStream.FileLength = dwFileLen;
  1083. pIcb->HasRemoteHandle = TRUE;
  1084. pIcb->FileObject->CurrentByteOffset.QuadPart = 0;
  1085. ExitWithCleanup:
  1086. NdsFreeLockedBuffer( &NdsRequest );
  1087. if ( ( !NT_SUCCESS( Status ) ) &&
  1088. ( LicensedConnection ) ) {
  1089. NdsUnlicenseConnection( pIrpContext );
  1090. }
  1091. NwDequeueIrpContext( pIrpContext, FALSE );
  1092. return Status;
  1093. }
  1094. NTSTATUS
  1095. NdsSetContext(
  1096. PIRP_CONTEXT pIrpContext,
  1097. PNWR_NDS_REQUEST_PACKET pNdsRequest,
  1098. ULONG RequestLength
  1099. ) {
  1100. NTSTATUS Status;
  1101. PLOGON pLogon;
  1102. UNICODE_STRING Tree, Context;
  1103. PNDS_SECURITY_CONTEXT pCredentials;
  1104. PAGED_CODE();
  1105. DebugTrace( 0 , Dbg, "NDS set context.\n", 0 );
  1106. try {
  1107. if (RequestLength < (FIELD_OFFSET(NWR_NDS_REQUEST_PACKET, Parameters.SetContext.TreeAndContextString) + pNdsRequest->Parameters.SetContext.TreeNameLen)) {
  1108. DebugTrace( 0, Dbg, "SetContext Request Length is too short.\n", 0 );
  1109. return STATUS_INVALID_PARAMETER;
  1110. }
  1111. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  1112. return GetExceptionCode();
  1113. }
  1114. //
  1115. // Find out who this is.
  1116. //
  1117. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  1118. pLogon = FindUser( &(pIrpContext->Specific.Create.UserUid), FALSE );
  1119. NwReleaseRcb( &NwRcb );
  1120. if ( !pLogon ) {
  1121. DebugTrace( 0, Dbg, "Couldn't find logon data for this user.\n", 0 );
  1122. return STATUS_ACCESS_DENIED;
  1123. }
  1124. //
  1125. // Verify that this context really is a context.
  1126. //
  1127. Tree.Length = (USHORT)(pNdsRequest->Parameters).SetContext.TreeNameLen;
  1128. Tree.MaximumLength = Tree.Length;
  1129. Tree.Buffer = (pNdsRequest->Parameters).SetContext.TreeAndContextString;
  1130. Context.Length = (USHORT)(pNdsRequest->Parameters).SetContext.ContextLen;
  1131. Context.MaximumLength = Context.Length;
  1132. Context.Buffer = (WCHAR *) (((BYTE *)Tree.Buffer) + Tree.Length);
  1133. Status = NdsVerifyContext( pIrpContext, &Tree, &Context );
  1134. if ( !NT_SUCCESS( Status ) ) {
  1135. return STATUS_INVALID_PARAMETER;
  1136. }
  1137. Status = NdsLookupCredentials( pIrpContext,
  1138. &Tree,
  1139. pLogon,
  1140. &pCredentials,
  1141. CREDENTIAL_READ,
  1142. TRUE );
  1143. if ( !NT_SUCCESS( Status ) ) {
  1144. DebugTrace( 0, Dbg, "No credentials in set context.\n", 0 );
  1145. return STATUS_NO_SUCH_LOGON_SESSION;
  1146. }
  1147. //
  1148. // ALERT! We are holding the credential list!
  1149. //
  1150. if ( Context.Length > MAX_NDS_NAME_SIZE ) {
  1151. DebugTrace( 0, Dbg, "Context too long.\n", 0 );
  1152. Status = STATUS_INVALID_PARAMETER;
  1153. goto ReleaseAndExit;
  1154. }
  1155. try {
  1156. RtlCopyUnicodeString( &pCredentials->CurrentContext, &Context );
  1157. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  1158. DebugTrace( 0, Dbg, "Bad user buffer in SetContext.\n", 0 );
  1159. Status = STATUS_INVALID_PARAMETER;
  1160. goto ReleaseAndExit;
  1161. }
  1162. NwReleaseCredList( pLogon, pIrpContext );
  1163. //
  1164. // RELAX! The credential list is free.
  1165. //
  1166. DebugTrace( 0, Dbg, "New context: %wZ\n", &Context );
  1167. return STATUS_SUCCESS;
  1168. ReleaseAndExit:
  1169. NwReleaseCredList( pLogon, pIrpContext );
  1170. return Status;
  1171. }
  1172. NTSTATUS
  1173. NdsGetContext(
  1174. PIRP_CONTEXT pIrpContext,
  1175. PNWR_NDS_REQUEST_PACKET pNdsRequest,
  1176. ULONG RequestLength
  1177. ) {
  1178. NTSTATUS Status;
  1179. PLOGON pLogon;
  1180. UNICODE_STRING Tree;
  1181. PNDS_SECURITY_CONTEXT pCredentials;
  1182. PAGED_CODE();
  1183. DebugTrace( 0 , Dbg, "NDS get context.\n", 0 );
  1184. try {
  1185. if (RequestLength < (FIELD_OFFSET(NWR_NDS_REQUEST_PACKET, Parameters.GetContext.TreeNameString) + pNdsRequest->Parameters.GetContext.TreeNameLen)) {
  1186. DebugTrace( 0, Dbg, "GetContext Request Length is too short.\n", 0 );
  1187. return STATUS_INVALID_PARAMETER;
  1188. }
  1189. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  1190. return GetExceptionCode();
  1191. }
  1192. //
  1193. // Find out who this is.
  1194. //
  1195. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  1196. pLogon = FindUser( &(pIrpContext->Specific.Create.UserUid), FALSE );
  1197. NwReleaseRcb( &NwRcb );
  1198. if ( !pLogon ) {
  1199. DebugTrace( 0, Dbg, "Couldn't find logon data for this user.\n", 0 );
  1200. return STATUS_ACCESS_DENIED;
  1201. }
  1202. //
  1203. // We know who it is, so get the context.
  1204. //
  1205. Tree.Length = (USHORT)(pNdsRequest->Parameters).GetContext.TreeNameLen;
  1206. Tree.MaximumLength = Tree.Length;
  1207. Tree.Buffer = (pNdsRequest->Parameters).GetContext.TreeNameString;
  1208. Status = NdsLookupCredentials( pIrpContext,
  1209. &Tree,
  1210. pLogon,
  1211. &pCredentials,
  1212. CREDENTIAL_READ,
  1213. FALSE );
  1214. if ( !NT_SUCCESS( Status ) ) {
  1215. //
  1216. // No context has been set, so report none.
  1217. //
  1218. try {
  1219. (pNdsRequest->Parameters).GetContext.Context.Length = 0;
  1220. return STATUS_SUCCESS;
  1221. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  1222. DebugTrace( 0, Dbg, "Bad user buffer in GetContext.\n", 0 );
  1223. return STATUS_INVALID_PARAMETER;
  1224. }
  1225. }
  1226. //
  1227. // Make sure we can report the whole thing.
  1228. // ALERT! We are holding the credential list!
  1229. //
  1230. if ( (pNdsRequest->Parameters).GetContext.Context.MaximumLength <
  1231. pCredentials->CurrentContext.Length ) {
  1232. Status = STATUS_BUFFER_TOO_SMALL;
  1233. goto ReleaseAndExit;
  1234. }
  1235. try {
  1236. RtlCopyUnicodeString( &(pNdsRequest->Parameters).GetContext.Context,
  1237. &pCredentials->CurrentContext );
  1238. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  1239. DebugTrace( 0, Dbg, "Bad user buffer in GetContext.\n", 0 );
  1240. Status = STATUS_INVALID_PARAMETER;
  1241. goto ReleaseAndExit;
  1242. }
  1243. NwReleaseCredList( pLogon, pIrpContext );
  1244. //
  1245. // RELAX! The credential list is free.
  1246. //
  1247. DebugTrace( 0, Dbg, "Reported context: %wZ\n", &pCredentials->CurrentContext );
  1248. return STATUS_SUCCESS;
  1249. ReleaseAndExit:
  1250. NwReleaseCredList( pLogon, pIrpContext );
  1251. return Status;
  1252. }
  1253. NTSTATUS
  1254. NdsVerifyTreeHandle(
  1255. PIRP_CONTEXT pIrpContext,
  1256. PNWR_NDS_REQUEST_PACKET pNdsRequest,
  1257. ULONG RequestLength
  1258. ) {
  1259. NTSTATUS Status;
  1260. UNICODE_STRING NdsTree;
  1261. WCHAR TreeBuffer[NDS_TREE_NAME_LEN];
  1262. PAGED_CODE();
  1263. try {
  1264. if (RequestLength < (ULONG)(FIELD_OFFSET(NWR_NDS_REQUEST_PACKET, Parameters.VerifyTree.NameString) + pNdsRequest->Parameters.VerifyTree.TreeName.Length)) {
  1265. DebugTrace( 0, Dbg, "VerifyTreeHandle Request Length is too short.\n", 0 );
  1266. return STATUS_INVALID_PARAMETER;
  1267. }
  1268. //
  1269. // Check to see if the handle points to a dir server in the
  1270. // specified tree. Make sure to unmunge the tree name in
  1271. // the SCB first, just in case.
  1272. //
  1273. NdsTree.Length = 0;
  1274. NdsTree.MaximumLength = sizeof( TreeBuffer );
  1275. NdsTree.Buffer = TreeBuffer;
  1276. UnmungeCredentialName( &pIrpContext->pScb->NdsTreeName,
  1277. &NdsTree );
  1278. if ( !RtlCompareUnicodeString( &NdsTree,
  1279. &(pNdsRequest->Parameters).VerifyTree.TreeName,
  1280. TRUE ) ) {
  1281. DebugTrace( 0 , Dbg, "NdsVerifyTreeHandle: Success\n", 0 );
  1282. Status = STATUS_SUCCESS;
  1283. } else {
  1284. DebugTrace( 0 , Dbg, "NdsVerifyTreeHandle: Failure\n", 0 );
  1285. Status = STATUS_ACCESS_DENIED;
  1286. }
  1287. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  1288. DebugTrace( 0 , Dbg, "NdsVerifyTreeHandle: Invalid parameters.\n", 0 );
  1289. Status = STATUS_INVALID_PARAMETER;
  1290. }
  1291. return Status;
  1292. }
  1293. NTSTATUS
  1294. NdsGetPrintQueueInfo(
  1295. PIRP_CONTEXT pIrpContext,
  1296. PNWR_NDS_REQUEST_PACKET pNdsRequest,
  1297. ULONG RequestLength
  1298. ) {
  1299. NTSTATUS Status;
  1300. UNICODE_STRING ServerAttribute;
  1301. WCHAR Server[] = L"Host Server";
  1302. PSCB pPrintHost = NULL;
  1303. PNONPAGED_SCB pOriginalNpScb = NULL;
  1304. DWORD dwObjectId, dwObjectType;
  1305. UNICODE_STRING uPrintServer;
  1306. BYTE *pbQueue, *pbRQueue;
  1307. PAGED_CODE();
  1308. try {
  1309. if (RequestLength < (ULONG)FIELD_OFFSET(NWR_NDS_REQUEST_PACKET, Parameters.GetQueueInfo.QueueId)) {
  1310. DebugTrace( 0, Dbg, "GetQueueInfo Request Length is too short.\n", 0 );
  1311. return STATUS_INVALID_PARAMETER;
  1312. }
  1313. if ( pIrpContext->pOriginalIrp->RequestorMode != KernelMode ) {
  1314. ProbeForRead( pNdsRequest->Parameters.GetQueueInfo.QueueName.Buffer,
  1315. pNdsRequest->Parameters.GetQueueInfo.QueueName.Length,
  1316. sizeof(CHAR));
  1317. }
  1318. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  1319. return GetExceptionCode();
  1320. }
  1321. RtlInitUnicodeString( &ServerAttribute, Server );
  1322. //
  1323. // Make sure we have a print queue object. We may
  1324. // have to jump servers if we get referred to another
  1325. // replica. If this is the case, we can't lose the
  1326. // ref count on the original server since that's where
  1327. // the ICB handle is.
  1328. //
  1329. pOriginalNpScb = pIrpContext->pNpScb;
  1330. //
  1331. // tommye - fix for case where pOriginalNpScb == NULL (devctl test case)
  1332. //
  1333. if (pOriginalNpScb == NULL) {
  1334. return STATUS_INVALID_PARAMETER;
  1335. }
  1336. NwReferenceScb( pOriginalNpScb );
  1337. Status = NdsVerifyObject( pIrpContext,
  1338. &(pNdsRequest->Parameters).GetQueueInfo.QueueName,
  1339. TRUE,
  1340. DEFAULT_RESOLVE_FLAGS,
  1341. &dwObjectId,
  1342. &dwObjectType );
  1343. if ( pIrpContext->pNpScb == pOriginalNpScb ) {
  1344. //
  1345. // If we were not referred, remove the extra ref
  1346. // count and clear the original pointer.
  1347. //
  1348. NwDereferenceScb( pOriginalNpScb );
  1349. pOriginalNpScb = NULL;
  1350. }
  1351. if ( !NT_SUCCESS( Status ) ) {
  1352. goto ExitWithCleanup;
  1353. }
  1354. if ( dwObjectType != NDS_OBJECTTYPE_QUEUE ) {
  1355. Status = STATUS_INVALID_PARAMETER;
  1356. goto ExitWithCleanup;
  1357. }
  1358. //
  1359. // Retrieve the host server name.
  1360. //
  1361. Status = NdsReadStringAttribute( pIrpContext,
  1362. dwObjectId,
  1363. &ServerAttribute,
  1364. &(pNdsRequest->Parameters).GetQueueInfo.HostServer );
  1365. if ( !NT_SUCCESS( Status ) ) {
  1366. goto ExitWithCleanup;
  1367. }
  1368. //
  1369. // Dig out the actual server name from the X.500 name.
  1370. //
  1371. Status = NdsGetServerBasicName( &(pNdsRequest->Parameters).GetQueueInfo.HostServer,
  1372. &uPrintServer );
  1373. if ( !NT_SUCCESS( Status ) ) {
  1374. goto ExitWithCleanup;
  1375. }
  1376. //
  1377. // Connect to the actual host server. If there was a referral, we
  1378. // can simply dump the referred server since we are holding the ref
  1379. // count on the original owner of the ICB.
  1380. //
  1381. if ( pOriginalNpScb ) {
  1382. NwDereferenceScb( pIrpContext->pNpScb );
  1383. } else {
  1384. pOriginalNpScb = pIrpContext->pNpScb;
  1385. }
  1386. NwDequeueIrpContext( pIrpContext, FALSE );
  1387. Status = CreateScb( &pPrintHost,
  1388. pIrpContext,
  1389. &uPrintServer,
  1390. NULL,
  1391. NULL,
  1392. NULL,
  1393. FALSE,
  1394. FALSE );
  1395. if ( !NT_SUCCESS( Status ) ) {
  1396. pIrpContext->pNpScb = NULL;
  1397. goto ExitWithCleanup;
  1398. }
  1399. //
  1400. // Re-query the OID of the print queue object on this server.
  1401. // Don't allow any server jumping this time; we only need the
  1402. // oid of the queue.
  1403. //
  1404. Status = NdsVerifyObject( pIrpContext,
  1405. &(pNdsRequest->Parameters).GetQueueInfo.QueueName,
  1406. FALSE,
  1407. RSLV_CREATE_ID,
  1408. &dwObjectId,
  1409. NULL );
  1410. if ( NT_SUCCESS( Status ) ) {
  1411. //
  1412. // Byte swap the queue id.
  1413. //
  1414. pbRQueue = (BYTE *) &dwObjectId;
  1415. pbQueue = (BYTE *) &(pNdsRequest->Parameters).GetQueueInfo.QueueId;
  1416. pbQueue[0] = pbRQueue[3];
  1417. pbQueue[1] = pbRQueue[2];
  1418. pbQueue[2] = pbRQueue[1];
  1419. pbQueue[3] = pbRQueue[0];
  1420. }
  1421. ExitWithCleanup:
  1422. NwDequeueIrpContext( pIrpContext, FALSE );
  1423. //
  1424. // Restore the pointers and ref counts as appropriate.
  1425. //
  1426. if ( pOriginalNpScb ) {
  1427. if ( pIrpContext->pNpScb ) {
  1428. NwDereferenceScb( pIrpContext->pNpScb );
  1429. }
  1430. pIrpContext->pNpScb = pOriginalNpScb;
  1431. pIrpContext->pScb = pOriginalNpScb->pScb;
  1432. }
  1433. return Status;
  1434. }
  1435. NTSTATUS
  1436. NdsChangePass(
  1437. PIRP_CONTEXT pIrpContext
  1438. ) {
  1439. NTSTATUS Status;
  1440. PIRP irp;
  1441. PIO_STACK_LOCATION irpSp;
  1442. PNWR_NDS_REQUEST_PACKET Rrp;
  1443. ULONGLONG InputBufferLength;
  1444. UNICODE_STRING NdsTree;
  1445. UNICODE_STRING UserName;
  1446. UNICODE_STRING CurrentPassword;
  1447. UNICODE_STRING NewPassword;
  1448. PBYTE CurrentString;
  1449. BOOLEAN ServerReferenced = FALSE;
  1450. OEM_STRING OemCurrentPassword;
  1451. BYTE CurrentBuffer[MAX_PW_CHARS];
  1452. OEM_STRING OemNewPassword;
  1453. BYTE NewBuffer[MAX_PW_CHARS];
  1454. NODE_TYPE_CODE nodeTypeCode;
  1455. PSCB Scb;
  1456. PICB pIcb;
  1457. PVOID fsContext, fsObject;
  1458. UNICODE_STRING CredentialName;
  1459. PNDS_SECURITY_CONTEXT pCredential;
  1460. ULONG LocalNdsTreeNameLength;
  1461. ULONG LocalUserNameLength;
  1462. ULONG LocalCurrentPasswordLength;
  1463. ULONG LocalNewPasswordLength;
  1464. PAGED_CODE();
  1465. //
  1466. // Get the request.
  1467. //
  1468. irp = pIrpContext->pOriginalIrp;
  1469. irpSp = IoGetCurrentIrpStackLocation( irp );
  1470. Rrp = ( PNWR_NDS_REQUEST_PACKET ) irpSp->Parameters.FileSystemControl.Type3InputBuffer;
  1471. InputBufferLength = irpSp->Parameters.FileSystemControl.InputBufferLength;
  1472. if ( !Rrp ) {
  1473. DebugTrace( 0, Dbg, "No raw request buffer.\n", 0 );
  1474. return STATUS_INVALID_PARAMETER;
  1475. }
  1476. if ( InputBufferLength <
  1477. ((ULONG) FIELD_OFFSET( NWR_NDS_REQUEST_PACKET, Parameters.ChangePass.StringBuffer[0]))) {
  1478. return STATUS_INVALID_PARAMETER;
  1479. }
  1480. //
  1481. // Decode the file object to see if this is an ex-create handle.
  1482. //
  1483. nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
  1484. &fsContext,
  1485. &fsObject );
  1486. if ( nodeTypeCode == NW_NTC_ICB_SCB ) {
  1487. pIcb = (PICB) fsObject;
  1488. //
  1489. // If this is a handle made on an ex-create, then
  1490. // we have to be aware of our credentials while
  1491. // jumping servers.
  1492. //
  1493. // This is not too intuitive since this doesn't
  1494. // seem to be a create path irp, but referrals
  1495. // on any path cause the create paths to be
  1496. // traversed.
  1497. //
  1498. if ( pIcb->IsExCredentialHandle ) {
  1499. pIrpContext->Specific.Create.fExCredentialCreate = TRUE;
  1500. pCredential = (PNDS_SECURITY_CONTEXT) pIcb->pContext;
  1501. Status = GetCredentialFromServerName( &pCredential->NdsTreeName,
  1502. &CredentialName );
  1503. if ( !NT_SUCCESS( Status ) ) {
  1504. return STATUS_INVALID_HANDLE;
  1505. }
  1506. pIrpContext->Specific.Create.puCredentialName = &CredentialName;
  1507. }
  1508. }
  1509. try {
  1510. if ( irp->RequestorMode != KernelMode ) {
  1511. ProbeForRead( Rrp,
  1512. (ULONG) InputBufferLength,
  1513. sizeof(CHAR)
  1514. );
  1515. }
  1516. //
  1517. // Capture all the interesting parameters locally so that they don't change
  1518. // after validating them.
  1519. //
  1520. LocalNdsTreeNameLength = Rrp->Parameters.ChangePass.NdsTreeNameLength;
  1521. LocalUserNameLength = Rrp->Parameters.ChangePass.UserNameLength;
  1522. LocalCurrentPasswordLength = Rrp->Parameters.ChangePass.CurrentPasswordLength;
  1523. LocalNewPasswordLength = Rrp->Parameters.ChangePass.NewPasswordLength;
  1524. if ( InputBufferLength <
  1525. ((ULONGLONG) FIELD_OFFSET( NWR_NDS_REQUEST_PACKET, Parameters.ChangePass.StringBuffer[0]) +
  1526. (ULONGLONG) LocalNdsTreeNameLength +
  1527. (ULONGLONG) LocalUserNameLength +
  1528. (ULONGLONG) LocalCurrentPasswordLength +
  1529. (ULONGLONG) LocalNewPasswordLength )) {
  1530. return( STATUS_INVALID_PARAMETER );
  1531. }
  1532. //
  1533. // Dig out the parameters.
  1534. //
  1535. CurrentString = ( PBYTE ) &(Rrp->Parameters.ChangePass.StringBuffer[0]);
  1536. NdsTree.Length = NdsTree.MaximumLength =
  1537. ( USHORT ) LocalNdsTreeNameLength;
  1538. NdsTree.Buffer = ( PWCHAR ) CurrentString;
  1539. CurrentString += NdsTree.Length;
  1540. UserName.Length = UserName.MaximumLength =
  1541. ( USHORT ) LocalUserNameLength;
  1542. UserName.Buffer = ( PWCHAR ) CurrentString;
  1543. CurrentString += UserName.Length;
  1544. CurrentPassword.Length = CurrentPassword.MaximumLength =
  1545. ( USHORT ) LocalCurrentPasswordLength;
  1546. CurrentPassword.Buffer = ( PWCHAR ) CurrentString;
  1547. CurrentString += CurrentPassword.Length;
  1548. NewPassword.Length = NewPassword.MaximumLength =
  1549. ( USHORT ) LocalNewPasswordLength;
  1550. NewPassword.Buffer = ( PWCHAR ) CurrentString;
  1551. //
  1552. // Get a server to handle this request.
  1553. //
  1554. //
  1555. // Convert the passwords to the appropriate type.
  1556. //
  1557. OemCurrentPassword.Length = 0;
  1558. OemCurrentPassword.MaximumLength = sizeof( CurrentBuffer );
  1559. OemCurrentPassword.Buffer = CurrentBuffer;
  1560. OemNewPassword.Length = 0;
  1561. OemNewPassword.MaximumLength = sizeof( NewBuffer );
  1562. OemNewPassword.Buffer = NewBuffer;
  1563. RtlUpcaseUnicodeStringToOemString( &OemCurrentPassword,
  1564. &CurrentPassword,
  1565. FALSE );
  1566. RtlUpcaseUnicodeStringToOemString( &OemNewPassword,
  1567. &NewPassword,
  1568. FALSE );
  1569. //
  1570. // Get a dir server to handle the request.
  1571. //
  1572. Status = NdsCreateTreeScb( pIrpContext,
  1573. &Scb,
  1574. &NdsTree,
  1575. NULL,
  1576. NULL,
  1577. TRUE,
  1578. FALSE );
  1579. if ( !NT_SUCCESS( Status ) ) {
  1580. DebugTrace( 0, Dbg, "No dir servers for nds change password.\n", 0 );
  1581. return STATUS_BAD_NETWORK_PATH;
  1582. }
  1583. ServerReferenced = TRUE;
  1584. //
  1585. // Perform the change password.
  1586. //
  1587. Status = NdsTreeLogin( pIrpContext,
  1588. &UserName,
  1589. &OemCurrentPassword,
  1590. &OemNewPassword,
  1591. NULL );
  1592. NwDereferenceScb( Scb->pNpScb );
  1593. ServerReferenced = FALSE;
  1594. if ( !NT_SUCCESS( Status ) ) {
  1595. goto ExitWithCleanup;
  1596. }
  1597. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  1598. DebugTrace( 0, Dbg, "NdsChangePass: Exception dealing with user request.\n", 0 );
  1599. Status = STATUS_INVALID_PARAMETER;
  1600. goto ExitWithCleanup;
  1601. }
  1602. DebugTrace( 0, Dbg, "NdsChangePassword succeeded for %wZ.\n", &UserName );
  1603. Status = STATUS_SUCCESS;
  1604. ExitWithCleanup:
  1605. if ( ServerReferenced ) {
  1606. NwDereferenceScb( Scb->pNpScb );
  1607. }
  1608. //
  1609. // We get STATUS_PASSWORD_EXPIRED when the user is not allowed
  1610. // to change their password on the Netware server, so we return
  1611. // PASSWORD_RESTRICTION instead.
  1612. //
  1613. if ( Status == STATUS_PASSWORD_EXPIRED ) {
  1614. Status = STATUS_PASSWORD_RESTRICTION;
  1615. }
  1616. return Status;
  1617. }
  1618. NTSTATUS
  1619. NdsListTrees(
  1620. PIRP_CONTEXT pIrpContext
  1621. )
  1622. /*+++
  1623. Description:
  1624. This odd little routine takes the NTUSER name of the logged in
  1625. user (on the system) and returns a list of NDS trees that the
  1626. NTUSER is connected to and the user names for those connections.
  1627. This is necessary because the change password ui runs in the
  1628. systems luid and can't access the GET_CONN_STATUS api and because
  1629. the change password code might happen when no user is logged in.
  1630. The return data in the users buffer is an array of
  1631. CONN_INFORMATION structures with the strings packed after the
  1632. structures. There is no continuation of this routine, so pass
  1633. a decent sized buffer.
  1634. ---*/
  1635. {
  1636. NTSTATUS Status;
  1637. PIRP irp;
  1638. PIO_STACK_LOCATION irpSp;
  1639. PNWR_NDS_REQUEST_PACKET Rrp;
  1640. DWORD InputBufferLength;
  1641. DWORD OutputBufferLength;
  1642. PBYTE OutputBuffer;
  1643. UNICODE_STRING NtUserName;
  1644. PLOGON pLogon;
  1645. DWORD dwTreesReturned = 0;
  1646. DWORD dwBytesNeeded;
  1647. PCONN_INFORMATION pConnInfo;
  1648. PLIST_ENTRY pNdsList;
  1649. PNDS_SECURITY_CONTEXT pNdsContext;
  1650. PAGED_CODE();
  1651. //
  1652. // Get the request.
  1653. //
  1654. irp = pIrpContext->pOriginalIrp;
  1655. irpSp = IoGetCurrentIrpStackLocation( irp );
  1656. Rrp = ( PNWR_NDS_REQUEST_PACKET ) irpSp->Parameters.FileSystemControl.Type3InputBuffer;
  1657. InputBufferLength = irpSp->Parameters.FileSystemControl.InputBufferLength;
  1658. OutputBufferLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  1659. NwMapUserBuffer( irp, KernelMode, (PVOID *)&OutputBuffer );
  1660. if ( !Rrp || !OutputBufferLength || !OutputBuffer ) {
  1661. return STATUS_INVALID_PARAMETER;
  1662. }
  1663. //
  1664. // tommye - MS bug 138643
  1665. //
  1666. // Probe the input arguments to make sure they are kosher before
  1667. // touching them.
  1668. //
  1669. try {
  1670. if ( irp->RequestorMode != KernelMode ) {
  1671. ProbeForRead( Rrp,
  1672. (ULONG) InputBufferLength,
  1673. sizeof(CHAR)
  1674. );
  1675. }
  1676. } except (EXCEPTION_EXECUTE_HANDLER) {
  1677. return GetExceptionCode();
  1678. }
  1679. //
  1680. // Dig out the parameters.
  1681. //
  1682. NtUserName.Length = NtUserName.MaximumLength = (USHORT) Rrp->Parameters.ListTrees.NtUserNameLength;
  1683. NtUserName.Buffer = &(Rrp->Parameters.ListTrees.NtUserName[0]);
  1684. DebugTrace( 0, Dbg, "ListTrees: Looking up %wZ\n", &NtUserName );
  1685. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  1686. pLogon = FindUserByName( &NtUserName );
  1687. NwReleaseRcb( &NwRcb );
  1688. if ( !pLogon ) {
  1689. DebugTrace( 0, Dbg, "ListTrees: No such NT user.\n", 0 );
  1690. return STATUS_NO_SUCH_USER;
  1691. }
  1692. //
  1693. // Otherwise build the list of trees.
  1694. //
  1695. Rrp->Parameters.ListTrees.UserLuid = pLogon->UserUid;
  1696. NwAcquireExclusiveCredList( pLogon, pIrpContext );
  1697. pConnInfo = ( PCONN_INFORMATION ) OutputBuffer;
  1698. pNdsList = pLogon->NdsCredentialList.Flink;
  1699. try {
  1700. while ( pNdsList != &(pLogon->NdsCredentialList) ) {
  1701. pNdsContext = CONTAINING_RECORD( pNdsList, NDS_SECURITY_CONTEXT, Next );
  1702. //
  1703. // Check to make sure there's a credential.
  1704. //
  1705. if ( pNdsContext->Credential == NULL ) {
  1706. goto ProcessNextListEntry;
  1707. }
  1708. //
  1709. // Don't report ex create credentials.
  1710. //
  1711. if ( IsCredentialName( &(pNdsContext->NdsTreeName) ) ) {
  1712. goto ProcessNextListEntry;
  1713. }
  1714. //
  1715. // Check to make sure there's space to report.
  1716. //
  1717. dwBytesNeeded = ( sizeof( CONN_INFORMATION ) +
  1718. pNdsContext->Credential->userNameLength +
  1719. pNdsContext->NdsTreeName.Length -
  1720. sizeof( WCHAR ) );
  1721. if ( OutputBufferLength < dwBytesNeeded ) {
  1722. break;
  1723. }
  1724. //
  1725. // Report it! Note that the user name in the credential is NULL terminated.
  1726. //
  1727. pConnInfo->HostServerLength = pNdsContext->NdsTreeName.Length;
  1728. pConnInfo->UserNameLength = pNdsContext->Credential->userNameLength - sizeof( WCHAR );
  1729. pConnInfo->HostServer = (LPWSTR) ( ((BYTE *)pConnInfo) + sizeof( CONN_INFORMATION ) );
  1730. pConnInfo->UserName = (LPWSTR) ( ( (BYTE *)pConnInfo) +
  1731. sizeof( CONN_INFORMATION ) +
  1732. pConnInfo->HostServerLength );
  1733. RtlCopyMemory( pConnInfo->HostServer,
  1734. pNdsContext->NdsTreeName.Buffer,
  1735. pConnInfo->HostServerLength );
  1736. RtlCopyMemory( pConnInfo->UserName,
  1737. ( ((BYTE *) pNdsContext->Credential ) +
  1738. sizeof( NDS_CREDENTIAL ) +
  1739. pNdsContext->Credential->optDataSize ),
  1740. pConnInfo->UserNameLength );
  1741. OutputBufferLength -= dwBytesNeeded;
  1742. dwTreesReturned++;
  1743. pConnInfo = ( PCONN_INFORMATION ) ( ((BYTE *)pConnInfo) + dwBytesNeeded );
  1744. ProcessNextListEntry:
  1745. //
  1746. // Do the next one.
  1747. //
  1748. pNdsList = pNdsList->Flink;
  1749. }
  1750. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  1751. //
  1752. // If we access violate, stop and return what we have.
  1753. //
  1754. DebugTrace( 0, Dbg, "User mode buffer access problem.\n", 0 );
  1755. }
  1756. NwReleaseCredList( pLogon, pIrpContext );
  1757. DebugTrace( 0, Dbg, "Returning %d tree entries.\n", dwTreesReturned );
  1758. Rrp->Parameters.ListTrees.TreesReturned = dwTreesReturned;
  1759. return STATUS_SUCCESS;
  1760. }