Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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