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.

1238 lines
30 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. NdsRead.c
  5. Abstract:
  6. This module implements the NDS read and request routines called
  7. by the redirector natively and the support routines that go with
  8. them.
  9. Author:
  10. Cory West [CoryWest] 23-Feb-1995
  11. --*/
  12. #include "Procs.h"
  13. #define Dbg (DEBUG_TRACE_NDS)
  14. #pragma alloc_text( PAGE, NdsResolveNameKm )
  15. #pragma alloc_text( PAGE, NdsReadStringAttribute )
  16. #pragma alloc_text( PAGE, NdsReadAttributesKm )
  17. #pragma alloc_text( PAGE, NdsCompletionCodetoNtStatus )
  18. #pragma alloc_text( PAGE, FreeNdsContext )
  19. #pragma alloc_text( PAGE, NdsPing )
  20. #pragma alloc_text( PAGE, NdsGetUserName )
  21. #pragma alloc_text( PAGE, NdsGetServerBasicName )
  22. #pragma alloc_text( PAGE, NdsGetServerName )
  23. #pragma alloc_text( PAGE, NdsReadPublicKey )
  24. #pragma alloc_text( PAGE, NdsCheckGroupMembership )
  25. #pragma alloc_text( PAGE, NdsAllocateLockedBuffer )
  26. #pragma alloc_text( PAGE, NdsFreeLockedBuffer )
  27. NTSTATUS
  28. NdsResolveNameKm (
  29. PIRP_CONTEXT pIrpContext,
  30. IN PUNICODE_STRING puObjectName,
  31. OUT DWORD *dwObjectId,
  32. BOOLEAN AllowDsJump,
  33. DWORD dwFlags
  34. )
  35. /*++
  36. Description:
  37. This is a wrapper routine to the browser routine NdsResolveName
  38. for kernel components that need to resolve NDS names.
  39. Arguments:
  40. pIrpContext - must point to the dir server that we should query
  41. puObjectName - what we want to resolve
  42. *dwObjectId - where to report the result
  43. AllowDsJump - if we are referred to another dir server, can we jump?
  44. --*/
  45. {
  46. NTSTATUS Status;
  47. PNWR_NDS_REQUEST_PACKET Rrp;
  48. PNDS_RESPONSE_RESOLVE_NAME Rsp;
  49. LOCKED_BUFFER NdsRequestBuffer;
  50. PSCB Scb, OldScb;
  51. UNICODE_STRING ReferredServer;
  52. BOOL fReleasedCredentials = FALSE;
  53. PLOGON pLogon;
  54. PAGED_CODE();
  55. //
  56. // Note: If you are holding the credential resource coming in, then you
  57. // need to be at the head of the queue.
  58. //
  59. //
  60. // Prepare the request and response buffers.
  61. //
  62. Rrp = ALLOCATE_POOL( PagedPool, NDS_BUFFER_SIZE );
  63. if ( !Rrp ) {
  64. return STATUS_INSUFFICIENT_RESOURCES;
  65. }
  66. Status = NdsAllocateLockedBuffer( &NdsRequestBuffer, NDS_BUFFER_SIZE );
  67. if ( !NT_SUCCESS( Status ) ) {
  68. FREE_POOL( Rrp );
  69. return Status;
  70. }
  71. //
  72. // Set up the request packet.
  73. //
  74. RtlZeroMemory( Rrp, NDS_BUFFER_SIZE );
  75. Rrp->Version = 0;
  76. Rrp->Parameters.ResolveName.ObjectNameLength = puObjectName->Length;
  77. Rrp->Parameters.ResolveName.ResolverFlags = dwFlags;
  78. RtlCopyMemory( Rrp->Parameters.ResolveName.ObjectName,
  79. puObjectName->Buffer,
  80. puObjectName->Length );
  81. //
  82. // Do the resolve.
  83. //
  84. Status = NdsResolveName( pIrpContext, Rrp, NDS_BUFFER_SIZE, &NdsRequestBuffer );
  85. if ( !NT_SUCCESS( Status ) ) {
  86. goto ExitWithCleanup;
  87. }
  88. Status = NdsCompletionCodetoNtStatus( &NdsRequestBuffer );
  89. if ( !NT_SUCCESS( Status ) ) {
  90. goto ExitWithCleanup;
  91. }
  92. Rsp = ( PNDS_RESPONSE_RESOLVE_NAME ) NdsRequestBuffer.pRecvBufferVa;
  93. if ( ( Rsp->RemoteEntry == RESOLVE_NAME_REFER_REMOTE ) &&
  94. ( AllowDsJump ) ) {
  95. //
  96. // We need to queue this request to another server
  97. // since this server doesn't have any details about
  98. // the object.
  99. //
  100. ReferredServer.Length = (USHORT) Rsp->ServerNameLength;
  101. ReferredServer.MaximumLength = ReferredServer.Length;
  102. ReferredServer.Buffer = Rsp->ReferredServer;
  103. OldScb = pIrpContext->pScb;
  104. ASSERT( OldScb != NULL );
  105. //
  106. // If you hold the credential lock, this is the time to let go of it or
  107. // we might deadlock. We can reclaim it after we are at the head of the
  108. // new SCB queue
  109. //
  110. if (BooleanFlagOn (pIrpContext->Flags, IRP_FLAG_HAS_CREDENTIAL_LOCK)) {
  111. PSCB pScb;
  112. pScb = pIrpContext->pNpScb->pScb;
  113. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  114. pLogon = FindUser( &pScb->UserUid, FALSE );
  115. NwReleaseRcb( &NwRcb );
  116. NwReleaseCredList( pLogon, pIrpContext );
  117. fReleasedCredentials = TRUE;
  118. }
  119. NwDequeueIrpContext( pIrpContext, FALSE );
  120. Status = CreateScb( &Scb,
  121. pIrpContext,
  122. &ReferredServer,
  123. NULL,
  124. NULL,
  125. NULL,
  126. TRUE,
  127. FALSE );
  128. if (fReleasedCredentials == TRUE) {
  129. //
  130. // You have to be at the head of the queue before you
  131. // grab the resource
  132. //
  133. if ( pIrpContext->pNpScb->Requests.Flink != &pIrpContext->NextRequest )
  134. {
  135. NwAppendToQueueAndWait( pIrpContext );
  136. }
  137. NwAcquireExclusiveCredList( pLogon, pIrpContext );
  138. }
  139. if ( !NT_SUCCESS( Status ) ) {
  140. goto ExitWithCleanup;
  141. }
  142. //
  143. // Since we've jumped servers, dereference the old host
  144. // server. The new one was referenced in CreateScb().
  145. //
  146. NwDereferenceScb( OldScb->pNpScb );
  147. }
  148. *dwObjectId = Rsp->EntryId;
  149. ExitWithCleanup:
  150. NdsFreeLockedBuffer( &NdsRequestBuffer );
  151. FREE_POOL( Rrp );
  152. return Status;
  153. }
  154. NTSTATUS
  155. NdsReadStringAttribute(
  156. PIRP_CONTEXT pIrpContext,
  157. IN DWORD dwObjectId,
  158. IN PUNICODE_STRING puAttributeName,
  159. OUT PUNICODE_STRING puAttributeVal
  160. )
  161. /*++
  162. Description:
  163. This is a wrapper routine to the browser routine NdsReadAttributes
  164. for kernel components that need to read NDS string attributes.
  165. Arguments:
  166. pIrpContext - must point to the dir server that we should query
  167. dwObjectId - oid of the object to query
  168. puAttributeName - attribute that we want
  169. puAttributeVal - value of the attribute
  170. --*/
  171. {
  172. NTSTATUS Status;
  173. PNWR_NDS_REQUEST_PACKET Rrp;
  174. DWORD dwRequestSize, dwAttributeCount;
  175. LOCKED_BUFFER NdsRequest;
  176. PAGED_CODE();
  177. //
  178. // Set up the request and response buffers.
  179. //
  180. dwRequestSize = sizeof( NWR_NDS_REQUEST_PACKET ) + puAttributeName->Length;
  181. Rrp = ( PNWR_NDS_REQUEST_PACKET ) ALLOCATE_POOL( PagedPool, dwRequestSize );
  182. if ( !Rrp ) {
  183. return STATUS_INSUFFICIENT_RESOURCES;
  184. }
  185. Status = NdsAllocateLockedBuffer( &NdsRequest, NDS_BUFFER_SIZE );
  186. if ( !NT_SUCCESS( Status ) ) {
  187. FREE_POOL( Rrp );
  188. return Status;
  189. }
  190. //
  191. // Prepare the request packet.
  192. //
  193. RtlZeroMemory( (BYTE *)Rrp, dwRequestSize );
  194. Rrp->Version = 0;
  195. Rrp->Parameters.ReadAttribute.ObjectId = dwObjectId;
  196. Rrp->Parameters.ReadAttribute.IterHandle = DUMMY_ITER_HANDLE;
  197. Rrp->Parameters.ReadAttribute.AttributeNameLength = puAttributeName->Length;
  198. RtlCopyMemory( Rrp->Parameters.ReadAttribute.AttributeName,
  199. puAttributeName->Buffer,
  200. puAttributeName->Length );
  201. //
  202. // Make the request.
  203. //
  204. Status = NdsReadAttributes( pIrpContext, Rrp, NDS_BUFFER_SIZE, &NdsRequest );
  205. if ( !NT_SUCCESS( Status ) ) {
  206. goto ExitWithCleanup;
  207. }
  208. //
  209. // Dig out the string attribute and return it.
  210. //
  211. Status = ParseResponse( NULL,
  212. NdsRequest.pRecvBufferVa,
  213. NdsRequest.dwBytesWritten,
  214. "G___D_S_T",
  215. sizeof( DWORD ), // completion code
  216. sizeof( DWORD ), // iter handle
  217. sizeof( DWORD ), // info type
  218. &dwAttributeCount, // attribute count
  219. sizeof( DWORD ), // syntax id
  220. NULL, // attribute name
  221. sizeof( DWORD ), // number of values
  222. puAttributeVal ); // attribute string
  223. if ( !NT_SUCCESS( Status ) ) {
  224. goto ExitWithCleanup;
  225. }
  226. ExitWithCleanup:
  227. FREE_POOL( Rrp );
  228. NdsFreeLockedBuffer( &NdsRequest );
  229. return Status;
  230. }
  231. NTSTATUS
  232. NdsReadAttributesKm(
  233. PIRP_CONTEXT pIrpContext,
  234. IN DWORD dwObjectId,
  235. IN PUNICODE_STRING puAttributeName,
  236. IN OUT PLOCKED_BUFFER pNdsRequest
  237. )
  238. /*++
  239. Description:
  240. This is a wrapper routine to the browser routine NdsReadAttributes
  241. for kernel components that need to read NDS string attributes and
  242. get back the raw response.
  243. Arguments:
  244. pIrpContext - must point to the dir server that we should query
  245. dwObjectId - oid of the object to query
  246. puAttributeName - attribute that we want
  247. puAttributeVal - value of the attribute
  248. --*/
  249. {
  250. NTSTATUS Status;
  251. PNWR_NDS_REQUEST_PACKET Rrp;
  252. DWORD dwRequestSize;
  253. PAGED_CODE();
  254. //
  255. // Set up the request.
  256. //
  257. dwRequestSize = sizeof( NWR_NDS_REQUEST_PACKET ) + puAttributeName->Length;
  258. Rrp = ( PNWR_NDS_REQUEST_PACKET ) ALLOCATE_POOL( PagedPool, dwRequestSize );
  259. if ( !Rrp ) {
  260. return STATUS_INSUFFICIENT_RESOURCES;
  261. }
  262. RtlZeroMemory( (BYTE *)Rrp, dwRequestSize );
  263. Rrp->Version = 0;
  264. Rrp->Parameters.ReadAttribute.ObjectId = dwObjectId;
  265. Rrp->Parameters.ReadAttribute.IterHandle = DUMMY_ITER_HANDLE;
  266. Rrp->Parameters.ReadAttribute.AttributeNameLength = puAttributeName->Length;
  267. RtlCopyMemory( Rrp->Parameters.ReadAttribute.AttributeName,
  268. puAttributeName->Buffer,
  269. puAttributeName->Length );
  270. Status = NdsReadAttributes( pIrpContext, Rrp, NDS_BUFFER_SIZE, pNdsRequest );
  271. FREE_POOL( Rrp );
  272. return Status;
  273. }
  274. //
  275. // Frosting and other helper wrapper functions.
  276. //
  277. NTSTATUS
  278. NdsCompletionCodetoNtStatus(
  279. IN PLOCKED_BUFFER pLockedBuffer
  280. )
  281. /*+++
  282. Description:
  283. Translates the completion code of an NDS transaction into
  284. an NTSTATUS error code.
  285. Arguments:
  286. pLockedBuffer - describes the locked reply buffer that contains
  287. the response.
  288. ---*/
  289. {
  290. NTSTATUS Status;
  291. PAGED_CODE();
  292. //
  293. // Try to get the completion code from the user's buffer.
  294. //
  295. try {
  296. Status = *((DWORD *)pLockedBuffer->pRecvBufferVa);
  297. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  298. return STATUS_UNSUCCESSFUL;
  299. }
  300. //
  301. // Decode it.
  302. //
  303. if ( Status != STATUS_SUCCESS ) {
  304. DebugTrace( 0, Dbg, "NDS Error Code: %08lx\n", Status );
  305. switch ( Status ) {
  306. case -601: // No such entry.
  307. case -602: // No such value.
  308. case -603: // No such attribute.
  309. case -607: // Illegal attribute.
  310. case -610: // Illegal ds name.
  311. Status = STATUS_BAD_NETWORK_PATH;
  312. break;
  313. //
  314. // These may only come on a VERIFY_PASSWORD verb, which
  315. // we do not support. I'm not sure, though.
  316. //
  317. case -216: // Password too short.
  318. case -215: // Duplicate password.
  319. Status = STATUS_PASSWORD_RESTRICTION;
  320. break;
  321. case -222: // Expired password (and no grace logins left).
  322. Status = STATUS_PASSWORD_EXPIRED;
  323. break;
  324. case -223: // Expired password; this is a successful grace login.
  325. Status = NWRDR_PASSWORD_HAS_EXPIRED;
  326. break;
  327. case -639: // Incomplete authentication.
  328. case -672: // No access.
  329. case -677: // Invalid identity.
  330. case -669: // Wrong password.
  331. Status = STATUS_WRONG_PASSWORD;
  332. break;
  333. case -197: // Intruder lockout active.
  334. case -220: // Account expired or disabled.
  335. Status = STATUS_ACCOUNT_DISABLED;
  336. break;
  337. case -218: // Login time restrictions.
  338. Status = STATUS_LOGIN_TIME_RESTRICTION;
  339. break;
  340. case -217: // Maximum logins exceeded.
  341. Status = STATUS_CONNECTION_COUNT_LIMIT;
  342. break;
  343. case -630: // We get this back for bogus resolve
  344. // name calls. Glenn prefers this error.
  345. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  346. break;
  347. default:
  348. Status = STATUS_UNSUCCESSFUL;
  349. }
  350. }
  351. return Status;
  352. }
  353. VOID
  354. FreeNdsContext(
  355. IN PNDS_SECURITY_CONTEXT pNdsSecContext
  356. )
  357. /*++
  358. Routine Description:
  359. Free the referenced NDS context.
  360. --*/
  361. {
  362. PAGED_CODE();
  363. //
  364. // Make sure this is a valid thing to be mucking with.
  365. //
  366. if ( !pNdsSecContext ||
  367. pNdsSecContext->ntc != NW_NTC_NDS_CREDENTIAL ) {
  368. DebugTrace( 0, Dbg, "FreeNdsContext didn't get an NDS context.\n", 0 );
  369. return;
  370. }
  371. if ( pNdsSecContext->Credential ) {
  372. FREE_POOL( pNdsSecContext->Credential );
  373. }
  374. if ( pNdsSecContext->Signature ) {
  375. FREE_POOL( pNdsSecContext->Signature );
  376. }
  377. if ( pNdsSecContext->PublicNdsKey ) {
  378. FREE_POOL( pNdsSecContext->PublicNdsKey );
  379. }
  380. if ( pNdsSecContext->Password.Buffer ) {
  381. FREE_POOL( pNdsSecContext->Password.Buffer );
  382. }
  383. DebugTrace( 0, Dbg, "Freeing NDS security context at 0x%08lx\n", pNdsSecContext );
  384. FREE_POOL( pNdsSecContext );
  385. return;
  386. }
  387. VOID
  388. NdsPing(
  389. IN PIRP_CONTEXT pIrpContext,
  390. IN PSCB pScb
  391. )
  392. /*++
  393. Routine Description:
  394. Examine the server for NDS support and record the NDS tree
  395. name in the SCB for later reference.
  396. Routine Arguments:
  397. pIrpContext - A pointer to the IRP context for this transaction.
  398. pScb - The SCB for the server.
  399. Return Value:
  400. NTSTATUS - Status of the operation.
  401. --*/
  402. {
  403. NTSTATUS Status;
  404. OEM_STRING OemTreeName;
  405. BYTE OemBuffer[NDS_TREE_NAME_LEN];
  406. UNICODE_STRING TreeName;
  407. WCHAR WBuffer[NDS_TREE_NAME_LEN];
  408. UNICODE_STRING CredentialName;
  409. PAGED_CODE();
  410. pScb->NdsTreeName.Length = 0;
  411. OemTreeName.Length = NDS_TREE_NAME_LEN;
  412. OemTreeName.MaximumLength = NDS_TREE_NAME_LEN;
  413. OemTreeName.Buffer = OemBuffer;
  414. Status = ExchangeWithWait( pIrpContext,
  415. SynchronousResponseCallback,
  416. "N",
  417. NDS_REQUEST, // NDS Function 104
  418. NDS_PING ); // NDS Subfunction 1
  419. if ( !NT_SUCCESS( Status ) ) {
  420. return;
  421. }
  422. //
  423. // Pull out the padded NDS name
  424. //
  425. Status = ParseResponse( pIrpContext,
  426. pIrpContext->rsp,
  427. pIrpContext->ResponseLength,
  428. "N_r",
  429. 2 * sizeof( DWORD ),
  430. OemBuffer,
  431. NDS_TREE_NAME_LEN );
  432. if ( !NT_SUCCESS( Status ) ) {
  433. return;
  434. }
  435. //
  436. // Strip off the padding and convert to unicode.
  437. //
  438. while ( OemTreeName.Length > 0 &&
  439. OemBuffer[OemTreeName.Length - 1] == '_' ) {
  440. OemTreeName.Length--;
  441. }
  442. //
  443. // Copy or munge the tree name, depending on the create type.
  444. //
  445. if ( pIrpContext->Specific.Create.fExCredentialCreate ) {
  446. TreeName.Length = 0;
  447. TreeName.MaximumLength = sizeof( WBuffer );
  448. TreeName.Buffer = WBuffer;
  449. Status = RtlOemStringToUnicodeString( &TreeName,
  450. &OemTreeName,
  451. FALSE );
  452. if ( !NT_SUCCESS( Status ) ) {
  453. pScb->NdsTreeName.Length = 0;
  454. return;
  455. }
  456. Status = BuildExCredentialServerName( &TreeName,
  457. pIrpContext->Specific.Create.puCredentialName,
  458. &CredentialName );
  459. if ( !NT_SUCCESS( Status ) ) {
  460. return;
  461. }
  462. RtlCopyUnicodeString( &pScb->NdsTreeName, &CredentialName );
  463. FREE_POOL( CredentialName.Buffer );
  464. } else {
  465. Status = RtlOemStringToUnicodeString( &pScb->NdsTreeName,
  466. &OemTreeName,
  467. FALSE );
  468. if ( !NT_SUCCESS( Status ) ) {
  469. pScb->NdsTreeName.Length = 0;
  470. return;
  471. }
  472. }
  473. DebugTrace( 0, Dbg, "Nds Ping: Tree is ""%wZ""\n", &pScb->NdsTreeName);
  474. return;
  475. }
  476. NTSTATUS
  477. NdsGetUserName(
  478. IN PIRP_CONTEXT pIrpContext,
  479. IN DWORD dwUserOid,
  480. OUT PUNICODE_STRING puUserName
  481. )
  482. /*++
  483. Description:
  484. Get the fully distinguished name of the user referred to
  485. by the provided oid.
  486. --*/
  487. {
  488. NTSTATUS Status;
  489. LOCKED_BUFFER NdsRequest;
  490. PAGED_CODE();
  491. //
  492. // Allocate buffer space.
  493. //
  494. Status = NdsAllocateLockedBuffer( &NdsRequest, NDS_BUFFER_SIZE );
  495. if ( !NT_SUCCESS( Status ) ) {
  496. return STATUS_INSUFFICIENT_RESOURCES;
  497. }
  498. //
  499. // Make the request.
  500. //
  501. Status = FragExWithWait( pIrpContext,
  502. NDSV_READ_ENTRY_INFO,
  503. &NdsRequest,
  504. "DD",
  505. 0,
  506. dwUserOid );
  507. if ( !NT_SUCCESS(Status) ) {
  508. goto ExitWithCleanup;
  509. }
  510. Status = NdsCompletionCodetoNtStatus( &NdsRequest );
  511. if ( !NT_SUCCESS( Status ) ) {
  512. goto ExitWithCleanup;
  513. }
  514. Status = ParseResponse( NULL,
  515. NdsRequest.pRecvBufferVa,
  516. NdsRequest.dwBytesWritten,
  517. "G_St",
  518. sizeof( NDS_RESPONSE_GET_OBJECT_INFO ),
  519. NULL,
  520. puUserName );
  521. //
  522. // We either got it or we didn't.
  523. //
  524. ExitWithCleanup:
  525. NdsFreeLockedBuffer( &NdsRequest );
  526. return Status;
  527. }
  528. NTSTATUS
  529. NdsGetServerBasicName(
  530. IN PUNICODE_STRING pServerX500Name,
  531. IN OUT PUNICODE_STRING pServerName
  532. ) {
  533. //
  534. // Dig out the first component of the server's X.500 name.
  535. // We count on the X500 prefix for the server object being "CN=",
  536. // which might be unwise.
  537. //
  538. USHORT usPrefixSize, usSrv;
  539. PAGED_CODE();
  540. usPrefixSize = sizeof( "CN=" ) - sizeof( "" );
  541. usSrv = 0;
  542. if ( ( pServerX500Name->Buffer[0] != L'C' ) ||
  543. ( pServerX500Name->Buffer[1] != L'N' ) ||
  544. ( pServerX500Name->Buffer[2] != L'=' ) ) {
  545. DebugTrace( 0, Dbg, "NdsGetServerBasicName: Bad prefix.\n", 0 );
  546. return STATUS_INVALID_PARAMETER;
  547. }
  548. if ( pServerX500Name->Length <= usPrefixSize ) {
  549. DebugTrace( 0, Dbg, "NdsGetServerBasicName: Bad string length.\n", 0 );
  550. return STATUS_INVALID_PARAMETER;
  551. }
  552. pServerName->Buffer = pServerX500Name->Buffer + usPrefixSize;
  553. pServerName->Length = 0;
  554. while ( ( usSrv < MAX_SERVER_NAME_LENGTH ) &&
  555. ( pServerName->Buffer[usSrv++] != L'.' ) ) {
  556. pServerName->Length += sizeof( WCHAR );
  557. }
  558. if ( usSrv == MAX_SERVER_NAME_LENGTH ) {
  559. DebugTrace( 0, Dbg, "NdsGetServerBasicName: Bad server name response.\n", 0 );
  560. return STATUS_BAD_NETWORK_PATH;
  561. }
  562. pServerName->MaximumLength = pServerName->Length;
  563. return STATUS_SUCCESS;
  564. }
  565. NTSTATUS
  566. NdsGetServerName(
  567. IN PIRP_CONTEXT pIrpContext,
  568. OUT PUNICODE_STRING puServerName
  569. )
  570. /*++
  571. Description:
  572. Get the fully distinguished name of the server that we
  573. are connected to.
  574. --*/
  575. {
  576. NTSTATUS Status;
  577. LOCKED_BUFFER NdsRequest;
  578. PAGED_CODE();
  579. //
  580. // Make the request.
  581. //
  582. Status = NdsAllocateLockedBuffer( &NdsRequest, NDS_BUFFER_SIZE );
  583. if ( !NT_SUCCESS( Status ) ) {
  584. return STATUS_INSUFFICIENT_RESOURCES;
  585. }
  586. Status = FragExWithWait( pIrpContext,
  587. NDSV_GET_SERVER_ADDRESS,
  588. &NdsRequest,
  589. NULL );
  590. if ( !NT_SUCCESS(Status) ) {
  591. goto ExitWithCleanup;
  592. }
  593. Status = NdsCompletionCodetoNtStatus( &NdsRequest );
  594. if ( !NT_SUCCESS( Status ) ) {
  595. goto ExitWithCleanup;
  596. }
  597. //
  598. // Get the server name from the response.
  599. //
  600. Status = ParseResponse( NULL,
  601. NdsRequest.pRecvBufferVa,
  602. NdsRequest.dwBytesWritten,
  603. "G_T",
  604. sizeof( DWORD ),
  605. puServerName );
  606. if ( !NT_SUCCESS(Status) ) {
  607. goto ExitWithCleanup;
  608. }
  609. ExitWithCleanup:
  610. NdsFreeLockedBuffer( &NdsRequest );
  611. return Status;
  612. }
  613. NTSTATUS
  614. NdsReadPublicKey(
  615. IN PIRP_CONTEXT pIrpContext,
  616. IN DWORD dwEntryId,
  617. OUT BYTE *pPubKeyVal,
  618. IN OUT DWORD *pPubKeyLen
  619. )
  620. /*++
  621. Routine Description:
  622. Read the public key referenced by the given entry id.
  623. Routine Arguments:
  624. pIrpContext - The IRP context for this connection.
  625. dwEntryId - The entry id of the key.
  626. pPubKeyVal - The destination buffer for the public key.
  627. pPubKeyLen - The length of the public key destination buffer.
  628. Return Value:
  629. The length of the key.
  630. --*/
  631. {
  632. NTSTATUS Status;
  633. LOCKED_BUFFER NdsRequest;
  634. PNWR_NDS_REQUEST_PACKET Rrp;
  635. DWORD dwAttrNameLen, dwAttrLen, dwRcvLen, dwNumEntries;
  636. BYTE *pRcv;
  637. PAGED_CODE();
  638. //
  639. // Allocate and zero send and receive space.
  640. //
  641. Rrp = ALLOCATE_POOL( PagedPool, NDS_BUFFER_SIZE );
  642. if ( !Rrp ) {
  643. return STATUS_INSUFFICIENT_RESOURCES;
  644. }
  645. Status = NdsAllocateLockedBuffer( &NdsRequest, NDS_BUFFER_SIZE );
  646. if ( !NT_SUCCESS( Status ) ) {
  647. FREE_POOL( Rrp );
  648. return STATUS_INSUFFICIENT_RESOURCES;
  649. }
  650. //
  651. // Fill in and prepare the request buffer.
  652. //
  653. RtlZeroMemory( Rrp, NDS_BUFFER_SIZE );
  654. Rrp->Version = 0;
  655. Rrp->Parameters.ReadAttribute.ObjectId = dwEntryId;
  656. Rrp->Parameters.ReadAttribute.IterHandle = DUMMY_ITER_HANDLE;
  657. Rrp->Parameters.ReadAttribute.AttributeNameLength =
  658. sizeof( PUBLIC_KEY_ATTRIBUTE ) - sizeof( WCHAR );
  659. RtlCopyMemory( Rrp->Parameters.ReadAttribute.AttributeName,
  660. PUBLIC_KEY_ATTRIBUTE,
  661. sizeof( PUBLIC_KEY_ATTRIBUTE ) - sizeof( WCHAR ) );
  662. //
  663. // Do the exchange.
  664. //
  665. Status = NdsReadAttributes( pIrpContext,
  666. Rrp,
  667. NDS_BUFFER_SIZE,
  668. &NdsRequest );
  669. if ( !NT_SUCCESS( Status ) ) {
  670. goto ExitWithCleanup;
  671. }
  672. //
  673. // Skip over the attribute header and name.
  674. //
  675. Status = ParseResponse( NULL,
  676. NdsRequest.pRecvBufferVa,
  677. NdsRequest.dwBytesWritten,
  678. "G_D",
  679. 5 * sizeof( DWORD ),
  680. &dwAttrNameLen );
  681. if ( !NT_SUCCESS( Status ) ) {
  682. Status = STATUS_UNSUCCESSFUL;
  683. goto ExitWithCleanup;
  684. }
  685. //
  686. // Skip over the part we've parsed and pull out the attribute.
  687. //
  688. pRcv = (PBYTE)NdsRequest.pRecvBufferVa +
  689. ( 6 * sizeof( DWORD ) ) +
  690. ROUNDUP4(dwAttrNameLen);
  691. dwRcvLen = NdsRequest.dwBytesWritten -
  692. ( 6 * sizeof( DWORD ) ) +
  693. ROUNDUP4(dwAttrNameLen);
  694. Status = ParseResponse( NULL,
  695. pRcv,
  696. dwRcvLen,
  697. "GDD",
  698. &dwNumEntries,
  699. &dwAttrLen );
  700. if ( !NT_SUCCESS( Status ) ||
  701. dwNumEntries != 1 ) {
  702. Status = STATUS_UNSUCCESSFUL;
  703. goto ExitWithCleanup;
  704. }
  705. DebugTrace( 0, Dbg, "Public Key Length: %d\n", dwAttrLen );
  706. pRcv += ( 2 * sizeof( DWORD ) );
  707. if ( dwAttrLen <= *pPubKeyLen ) {
  708. RtlCopyMemory( pPubKeyVal, pRcv, dwAttrLen );
  709. *pPubKeyLen = dwAttrLen;
  710. Status = STATUS_SUCCESS;
  711. } else {
  712. DebugTrace( 0, Dbg, "Public key buffer is too small.\n", 0 );
  713. Status = STATUS_BUFFER_TOO_SMALL;
  714. }
  715. ExitWithCleanup:
  716. NdsFreeLockedBuffer( &NdsRequest );
  717. FREE_POOL( Rrp );
  718. return Status;
  719. }
  720. NTSTATUS
  721. NdsCheckGroupMembership(
  722. PIRP_CONTEXT pIrpContext,
  723. DWORD dwUserOid,
  724. PUNICODE_STRING puGroupName
  725. ) {
  726. NTSTATUS Status;
  727. UNICODE_STRING GroupListAttribute;
  728. LOCKED_BUFFER NdsRequest;
  729. PNDS_RESPONSE_READ_ATTRIBUTE pAttributeResponse;
  730. PNDS_ATTRIBUTE pAttribute;
  731. PBYTE pAttribData;
  732. DWORD dwAttribLength, dwCurrentLength;
  733. DWORD dwNumAttributes, dwCurrentAttribute;
  734. UNICODE_STRING Group;
  735. USHORT GroupLength;
  736. PAGED_CODE();
  737. RtlInitUnicodeString( &GroupListAttribute, GROUPS_ATTRIBUTE );
  738. Status = NdsAllocateLockedBuffer( &NdsRequest, NDS_BUFFER_SIZE );
  739. if ( !NT_SUCCESS( Status ) ) {
  740. return STATUS_INSUFFICIENT_RESOURCES;
  741. }
  742. Status = NdsReadAttributesKm( pIrpContext,
  743. dwUserOid,
  744. &GroupListAttribute,
  745. &NdsRequest );
  746. if ( !NT_SUCCESS( Status ) ) {
  747. goto ExitWithCleanup;
  748. }
  749. pAttributeResponse = ( PNDS_RESPONSE_READ_ATTRIBUTE ) NdsRequest.pRecvBufferVa;
  750. ASSERT( pAttributeResponse->NumAttributes > 0 );
  751. //
  752. // Skip over the response header and walk down the attribute
  753. // until we get to the data. This is a little clunky.
  754. //
  755. pAttribute = ( PNDS_ATTRIBUTE ) ( pAttributeResponse + 1 );
  756. dwCurrentLength = sizeof( NDS_RESPONSE_READ_ATTRIBUTE );
  757. dwAttribLength = ROUNDUP4( pAttribute->AttribNameLength );
  758. dwAttribLength += ( 2 * sizeof( DWORD ) );
  759. //
  760. // Make sure we don't walk past the end of the buffer because
  761. // of a bad packet from the server.
  762. //
  763. if ( ( dwCurrentLength + dwAttribLength ) > NDS_BUFFER_SIZE ) {
  764. return STATUS_UNSUCCESSFUL;
  765. }
  766. pAttribData = ( ( BYTE * )pAttribute ) + dwAttribLength;
  767. dwCurrentLength += dwAttribLength;
  768. //
  769. // This is DWORD aligned for four byte DWORDs.
  770. //
  771. if ( ( NDS_BUFFER_SIZE - dwCurrentLength ) < sizeof( DWORD ) ) {
  772. return STATUS_UNSUCCESSFUL;
  773. }
  774. dwNumAttributes = * ( ( DWORD * ) pAttribData );
  775. if ( dwNumAttributes == 0 ) {
  776. Status = STATUS_UNSUCCESSFUL;
  777. goto ExitWithCleanup;
  778. }
  779. //
  780. // Each attribute is an NDS string DWORD aligned.
  781. //
  782. Status = STATUS_UNSUCCESSFUL;
  783. pAttribData += sizeof( DWORD );
  784. dwCurrentLength += sizeof( DWORD );
  785. for ( dwCurrentAttribute = 0;
  786. dwCurrentAttribute < dwNumAttributes ;
  787. dwCurrentAttribute++ ) {
  788. Group.Length = Group.MaximumLength =
  789. ( USHORT )( * ( ( DWORD * ) pAttribData ) ) - sizeof( WCHAR );
  790. Group.Buffer = ( PWCHAR ) ( pAttribData + sizeof( DWORD ) );
  791. if ( ( Group.Length + dwCurrentLength ) > NDS_BUFFER_SIZE ) {
  792. return STATUS_UNSUCCESSFUL;
  793. }
  794. //
  795. // Strip off the X500 prefix and the context.
  796. //
  797. GroupLength = 0;
  798. while ( GroupLength < ( Group.Length / sizeof( WCHAR ) ) ) {
  799. if ( Group.Buffer[GroupLength++] == L'=' ) {
  800. Group.Buffer += 1;
  801. Group.Length -= sizeof( WCHAR );
  802. Group.MaximumLength -= sizeof( WCHAR );
  803. GroupLength = ( Group.Length / sizeof( WCHAR ) );
  804. }
  805. Group.Buffer += 1;
  806. Group.Length -= sizeof( WCHAR );
  807. Group.MaximumLength -= sizeof( WCHAR );
  808. }
  809. GroupLength = 0;
  810. while ( GroupLength < ( Group.Length / sizeof( WCHAR ) ) ) {
  811. if ( Group.Buffer[GroupLength++] == L'.' ) {
  812. Group.Length = ( GroupLength - 1 ) * sizeof( WCHAR );
  813. Group.MaximumLength = Group.Length;
  814. break;
  815. }
  816. }
  817. if ( RtlEqualUnicodeString( puGroupName, &Group, TRUE ) ) {
  818. DebugTrace( 0, Dbg, "Group check for %wZ succeeded.\n", &Group );
  819. Status = STATUS_SUCCESS;
  820. goto ExitWithCleanup;
  821. }
  822. //
  823. // Dig out the attribute size and process the next entry.
  824. //
  825. dwAttribLength = ROUNDUP4( * ( ( DWORD * ) pAttribData ) );
  826. dwAttribLength += sizeof( DWORD );
  827. pAttribData += dwAttribLength;
  828. dwCurrentLength += dwAttribLength;
  829. }
  830. ExitWithCleanup:
  831. NdsFreeLockedBuffer( &NdsRequest );
  832. return Status;
  833. }
  834. NTSTATUS
  835. NdsAllocateLockedBuffer(
  836. PLOCKED_BUFFER NdsRequest,
  837. DWORD BufferSize
  838. )
  839. /*++
  840. Description:
  841. Allocate a buffer for io. Lock it down and fill in the
  842. buffer data structure that we pass around.
  843. --*/
  844. {
  845. PAGED_CODE();
  846. NdsRequest->pRecvBufferVa = ALLOCATE_POOL( PagedPool, BufferSize );
  847. if ( !NdsRequest->pRecvBufferVa ) {
  848. DebugTrace( 0, Dbg, "Couldn't allocate locked io buffer.\n", 0 );
  849. return STATUS_INSUFFICIENT_RESOURCES;
  850. }
  851. NdsRequest->dwRecvLen = BufferSize;
  852. NdsRequest->pRecvMdl = ALLOCATE_MDL( NdsRequest->pRecvBufferVa,
  853. BufferSize,
  854. FALSE,
  855. FALSE,
  856. NULL );
  857. if ( !NdsRequest->pRecvMdl ) {
  858. DebugTrace( 0, Dbg, "Couldn't allocate mdl for locked io buffer.\n", 0 );
  859. FREE_POOL( NdsRequest->pRecvBufferVa );
  860. return STATUS_INSUFFICIENT_RESOURCES;
  861. }
  862. MmProbeAndLockPages( NdsRequest->pRecvMdl,
  863. KernelMode,
  864. IoWriteAccess );
  865. return STATUS_SUCCESS;
  866. }
  867. NTSTATUS
  868. NdsFreeLockedBuffer(
  869. PLOCKED_BUFFER NdsRequest
  870. )
  871. /*++
  872. Description:
  873. Free a buffer allocated for io.
  874. --*/
  875. {
  876. PAGED_CODE();
  877. MmUnlockPages( NdsRequest->pRecvMdl );
  878. FREE_MDL( NdsRequest->pRecvMdl );
  879. FREE_POOL( NdsRequest->pRecvBufferVa );
  880. return STATUS_SUCCESS;
  881. }