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.

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