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.

4477 lines
142 KiB

  1. /*++
  2. Copyright (c) 1993-2000 Microsoft Corporation
  3. Module Name:
  4. ctxtcli.cxx
  5. Abstract:
  6. API and support routines for handling security contexts.
  7. Author:
  8. Cliff Van Dyke (CliffV) 13-Jul-1993
  9. Revision History:
  10. ChandanS 03-Aug-1996 Stolen from net\svcdlls\ntlmssp\common\context.c
  11. --*/
  12. //
  13. // Common include files.
  14. //
  15. #include <global.h>
  16. #include <align.h> // ALIGN_WCHAR, etc
  17. #include <credp.h>
  18. #include <kerberos.h>
  19. #include "msp.h"
  20. #include "nlp.h"
  21. NTSTATUS
  22. SsprHandleFirstCall(
  23. IN LSA_SEC_HANDLE CredentialHandle,
  24. IN OUT PLSA_SEC_HANDLE ContextHandle,
  25. IN ULONG ContextReqFlags,
  26. IN ULONG InputTokenSize,
  27. IN PVOID InputToken,
  28. IN PUNICODE_STRING TargetServerName OPTIONAL,
  29. IN OUT PULONG OutputTokenSize,
  30. OUT PVOID *OutputToken,
  31. OUT PULONG ContextAttributes,
  32. OUT PTimeStamp ExpirationTime,
  33. OUT PUCHAR SessionKey,
  34. OUT PULONG NegotiateFlags
  35. )
  36. /*++
  37. Routine Description:
  38. Handle the First Call part of InitializeSecurityContext.
  39. Arguments:
  40. All arguments same as for InitializeSecurityContext
  41. Return Value:
  42. STATUS_SUCCESS -- All OK
  43. SEC_I_CONTINUE_NEEDED -- Caller should call again later
  44. SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
  45. SEC_E_BUFFER_TOO_SMALL -- Buffer for output token isn't big enough
  46. SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
  47. --*/
  48. {
  49. SspPrint(( SSP_API_MORE, "Entering SsprHandleFirstCall\n" ));
  50. NTSTATUS Status = STATUS_SUCCESS;
  51. PSSP_CONTEXT Context = NULL;
  52. PSSP_CREDENTIAL Credential = NULL;
  53. PNEGOTIATE_MESSAGE NegotiateMessage = NULL;
  54. ULONG NegotiateMessageSize = 0;
  55. PCHAR Where = NULL;
  56. ULONG NegotiateFlagsKeyStrength;
  57. STRING NtLmLocalOemComputerNameString;
  58. STRING NtLmLocalOemPrimaryDomainNameString;
  59. //
  60. // Initialization
  61. //
  62. *ContextAttributes = 0;
  63. *NegotiateFlags = 0;
  64. RtlInitString( &NtLmLocalOemComputerNameString, NULL );
  65. RtlInitString( &NtLmLocalOemPrimaryDomainNameString, NULL );
  66. //
  67. // Get a pointer to the credential
  68. //
  69. Status = SspCredentialReferenceCredential(
  70. CredentialHandle,
  71. FALSE,
  72. &Credential );
  73. if ( !NT_SUCCESS( Status ) )
  74. {
  75. SspPrint(( SSP_CRITICAL, "SsprHandleFirstCall: invalid credential handle.\n" ));
  76. goto Cleanup;
  77. }
  78. if ( (Credential->CredentialUseFlags & SECPKG_CRED_OUTBOUND) == 0 ) {
  79. Status = SEC_E_INVALID_CREDENTIAL_USE;
  80. SspPrint(( SSP_CRITICAL, "SsprHandleFirstCall: invalid credential use.\n" ));
  81. goto Cleanup;
  82. }
  83. //
  84. // Allocate a new context
  85. //
  86. Context = SspContextAllocateContext( );
  87. if ( Context == NULL) {
  88. Status = STATUS_NO_MEMORY;
  89. SspPrint(( SSP_CRITICAL, "SsprHandleFirstCall: SspContextAllocateContext returned NULL\n"));
  90. goto Cleanup;
  91. }
  92. //
  93. // Build a handle to the newly created context.
  94. //
  95. *ContextHandle = (LSA_SEC_HANDLE) Context;
  96. //
  97. // We don't support any options.
  98. //
  99. // Complain about those that require we do something.
  100. //
  101. if ( (ContextReqFlags & ISC_REQ_PROMPT_FOR_CREDS) != 0 ) {
  102. Status = SEC_E_INVALID_CONTEXT_REQ;
  103. SspPrint(( SSP_CRITICAL,
  104. "SsprHandleFirstCall: invalid ContextReqFlags 0x%lx.\n",
  105. ContextReqFlags ));
  106. goto Cleanup;
  107. }
  108. //
  109. // Capture the default credentials from the credential structure.
  110. //
  111. if ( Credential->DomainName.Buffer != NULL ) {
  112. Status = NtLmDuplicateUnicodeString(
  113. &Context->DomainName,
  114. &Credential->DomainName
  115. );
  116. if (!NT_SUCCESS(Status)) {
  117. SspPrint(( SSP_CRITICAL,
  118. "SsprHandleFirstCall: NtLmDuplicateUnicodeString (DomainName) returned %d\n",Status));
  119. goto Cleanup;
  120. }
  121. }
  122. if ( Credential->UserName.Buffer != NULL ) {
  123. Status = NtLmDuplicateUnicodeString(
  124. &Context->UserName,
  125. &Credential->UserName
  126. );
  127. if (!NT_SUCCESS(Status)) {
  128. SspPrint(( SSP_CRITICAL,
  129. "SsprHandleFirstCall: NtLmDuplicateUnicodeString (UserName) returned %d\n", Status ));
  130. goto Cleanup;
  131. }
  132. }
  133. Status = SspCredentialGetPassword(
  134. Credential,
  135. &Context->Password
  136. );
  137. if (!NT_SUCCESS(Status)) {
  138. SspPrint(( SSP_CRITICAL,
  139. "SsprHandleFirstCall: SspCredentialGetPassword returned %d\n", Status ));
  140. goto Cleanup;
  141. }
  142. //
  143. // save away any marshalled credential info.
  144. //
  145. Status = CredpExtractMarshalledTargetInfo(
  146. TargetServerName,
  147. &Context->TargetInfo
  148. );
  149. if (!NT_SUCCESS(Status)) {
  150. SspPrint(( SSP_CRITICAL,
  151. "SsprHandleFirstCall: CredpExtractMarshalledTargetInfo returned %d\n", Status ));
  152. goto Cleanup;
  153. }
  154. //
  155. // Compute the negotiate flags
  156. //
  157. //
  158. // Supported key strength(s)
  159. //
  160. NegotiateFlagsKeyStrength = NTLMSSP_NEGOTIATE_56;
  161. NegotiateFlagsKeyStrength |= NTLMSSP_NEGOTIATE_128;
  162. Context->NegotiateFlags = NTLMSSP_NEGOTIATE_UNICODE |
  163. NTLMSSP_NEGOTIATE_OEM |
  164. NTLMSSP_NEGOTIATE_NTLM |
  165. ((NtLmGlobalLmProtocolSupported != 0)
  166. ? NTLMSSP_NEGOTIATE_NTLM2 : 0 ) |
  167. NTLMSSP_REQUEST_TARGET |
  168. NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
  169. NegotiateFlagsKeyStrength |
  170. NTLMSSP_NEGOTIATE_VERSION;
  171. if ((ContextReqFlags & ISC_REQ_CONFIDENTIALITY) != 0) {
  172. if (NtLmGlobalEncryptionEnabled) {
  173. //
  174. // CONFIDENTIALITY implies INTEGRITY
  175. //
  176. ContextReqFlags |= ISC_REQ_INTEGRITY;
  177. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL |
  178. NTLMSSP_NEGOTIATE_LM_KEY |
  179. NTLMSSP_NEGOTIATE_KEY_EXCH ;
  180. *ContextAttributes |= ISC_RET_CONFIDENTIALITY;
  181. Context->ContextFlags |= ISC_RET_CONFIDENTIALITY;
  182. } else {
  183. Status = STATUS_NOT_SUPPORTED;
  184. SspPrint(( SSP_CRITICAL,
  185. "SsprHandleFirstCall: NtLmGlobalEncryptionEnabled is FALSE\n"));
  186. goto Cleanup;
  187. }
  188. }
  189. //
  190. // If the caller specified INTEGRITY, SEQUENCE_DETECT or REPLAY_DETECT,
  191. // that means they want to use the MakeSignature/VerifySignature
  192. // calls. Add this to the negotiate.
  193. //
  194. if (ContextReqFlags &
  195. (ISC_REQ_INTEGRITY | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT))
  196. {
  197. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN |
  198. NTLMSSP_NEGOTIATE_KEY_EXCH |
  199. NTLMSSP_NEGOTIATE_LM_KEY;
  200. }
  201. if ( (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN) ||
  202. (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_SEAL)
  203. )
  204. {
  205. //
  206. // allows us to support gss-style seal/unseal for LDAP.
  207. //
  208. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLM2;
  209. }
  210. if ((ContextReqFlags & ISC_REQ_INTEGRITY) != 0)
  211. {
  212. *ContextAttributes |= ISC_RET_INTEGRITY;
  213. Context->ContextFlags |= ISC_RET_INTEGRITY;
  214. }
  215. if ((ContextReqFlags & ISC_REQ_SEQUENCE_DETECT) != 0)
  216. {
  217. *ContextAttributes |= ISC_RET_SEQUENCE_DETECT;
  218. Context->ContextFlags |= ISC_RET_SEQUENCE_DETECT;
  219. }
  220. if ((ContextReqFlags & ISC_REQ_REPLAY_DETECT) != 0)
  221. {
  222. *ContextAttributes |= ISC_RET_REPLAY_DETECT;
  223. Context->ContextFlags |= ISC_RET_REPLAY_DETECT;
  224. }
  225. if ( (ContextReqFlags & ISC_REQ_NULL_SESSION ) != 0) {
  226. *ContextAttributes |= ISC_RET_NULL_SESSION;
  227. Context->ContextFlags |= ISC_RET_NULL_SESSION;
  228. }
  229. if ( (ContextReqFlags & ISC_REQ_CONNECTION ) != 0) {
  230. *ContextAttributes |= ISC_RET_CONNECTION;
  231. Context->ContextFlags |= ISC_RET_CONNECTION;
  232. }
  233. //
  234. // Check if the caller wants identify level
  235. //
  236. if ((ContextReqFlags & ISC_REQ_IDENTIFY)!= 0) {
  237. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_IDENTIFY;
  238. *ContextAttributes |= ISC_RET_IDENTIFY;
  239. Context->ContextFlags |= ISC_RET_IDENTIFY;
  240. }
  241. IF_DEBUG( USE_OEM ) {
  242. Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_UNICODE;
  243. }
  244. if ( ((ContextReqFlags & ISC_REQ_MUTUAL_AUTH) != 0 ) &&
  245. (NtLmGlobalMutualAuthLevel < 2 ) ) {
  246. *ContextAttributes |= ISC_RET_MUTUAL_AUTH ;
  247. if ( NtLmGlobalMutualAuthLevel == 0 )
  248. {
  249. Context->ContextFlags |= ISC_RET_MUTUAL_AUTH ;
  250. }
  251. }
  252. //
  253. // For connection oriented security, we send a negotiate message to
  254. // the server. For datagram, we get back the server's
  255. // capabilities in the challenge message.
  256. //
  257. if ((ContextReqFlags & ISC_REQ_DATAGRAM) == 0) {
  258. BOOLEAN CheckForLocal;
  259. if ( (Credential->DomainName.Buffer == NULL &&
  260. Credential->UserName.Buffer == NULL &&
  261. Credential->Password.Buffer == NULL )
  262. )
  263. {
  264. CheckForLocal = TRUE;
  265. } else {
  266. CheckForLocal = FALSE;
  267. }
  268. if ( CheckForLocal ) {
  269. //
  270. // snap up a copy of the globals so we can just take the critsect once.
  271. // the old way took the critsect twice, once to read sizes, second time
  272. // to grab buffers - bad news if the global got bigger in between.
  273. //
  274. RtlAcquireResourceShared(&NtLmGlobalCritSect, TRUE);
  275. if ( NtLmGlobalOemComputerNameString.Buffer == NULL ||
  276. NtLmGlobalOemPrimaryDomainNameString.Buffer == NULL ) {
  277. //
  278. // user has picked a computer name or domain name
  279. // that failed to convert to OEM. disable the loopback
  280. // detection.
  281. // Sometime beyond Win2k, Negotiate package should have
  282. // a general, robust scheme for detecting loopback.
  283. //
  284. CheckForLocal = FALSE;
  285. } else {
  286. Status = NtLmDuplicateString(
  287. &NtLmLocalOemComputerNameString,
  288. &NtLmGlobalOemComputerNameString
  289. );
  290. if ( NT_SUCCESS(Status) ) {
  291. Status = NtLmDuplicateString(
  292. &NtLmLocalOemPrimaryDomainNameString,
  293. &NtLmGlobalOemPrimaryDomainNameString
  294. );
  295. }
  296. }
  297. RtlReleaseResource(&NtLmGlobalCritSect);
  298. if (!NT_SUCCESS(Status)) {
  299. SspPrint(( SSP_CRITICAL,
  300. "SsprHandleFirstCall: NtLmDuplicateUnicodeString (GlobalOemComputerName or GlobalOemPrimaryDomainName) returned %d\n", Status ));
  301. goto Cleanup;
  302. }
  303. }
  304. //
  305. // Allocate a Negotiate message
  306. //
  307. NegotiateMessageSize = sizeof(*NegotiateMessage) +
  308. NtLmLocalOemComputerNameString.Length +
  309. NtLmLocalOemPrimaryDomainNameString.Length;
  310. if ((ContextReqFlags & ISC_REQ_ALLOCATE_MEMORY) == 0)
  311. {
  312. if ( NegotiateMessageSize > *OutputTokenSize ) {
  313. Status = SEC_E_BUFFER_TOO_SMALL;
  314. SspPrint(( SSP_CRITICAL,
  315. "SsprHandleFirstCall: OutputTokenSize is %d\n", *OutputTokenSize));
  316. goto Cleanup;
  317. }
  318. }
  319. NegotiateMessage = (PNEGOTIATE_MESSAGE)
  320. NtLmAllocateLsaHeap( NegotiateMessageSize );
  321. if ( NegotiateMessage == NULL) {
  322. Status = STATUS_NO_MEMORY;
  323. SspPrint(( SSP_CRITICAL, "SsprHandleFirstCall: Error allocating NegotiateMessage.\n"));
  324. goto Cleanup;
  325. }
  326. //
  327. // If this is the first call,
  328. // build a Negotiate message.
  329. //
  330. strcpy( (char *) NegotiateMessage->Signature, NTLMSSP_SIGNATURE );
  331. NegotiateMessage->MessageType = NtLmNegotiate;
  332. NegotiateMessage->NegotiateFlags = Context->NegotiateFlags;
  333. NegotiateMessage->Version = NTLMSSP_ENGINE_VERSION;
  334. IF_DEBUG( REQUEST_TARGET ) {
  335. NegotiateMessage->NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
  336. }
  337. //
  338. // Copy the DomainName and ComputerName into the negotiate message so
  339. // the other side can determine if this is a call from the local system.
  340. //
  341. // Pass the names in the OEM character set since the character set
  342. // hasn't been negotiated yet.
  343. //
  344. // Skip passing the workstation name if credentials were specified. This
  345. // ensures the other side doesn't fall into the case that this is the
  346. // local system. We wan't to ensure the new credentials are
  347. // authenticated.
  348. //
  349. Where = (PCHAR)(NegotiateMessage+1);
  350. if ( CheckForLocal ) {
  351. SspContextCopyString( NegotiateMessage,
  352. &NegotiateMessage->OemWorkstationName,
  353. &NtLmLocalOemComputerNameString,
  354. &Where );
  355. NegotiateMessage->NegotiateFlags |=
  356. NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED;
  357. //
  358. // OEM_DOMAIN_SUPPLIED used to always be supplied - but the
  359. // only case it is ever used is when NTLMSSP_NEGOTIATE_LOCAL_CALL
  360. // is set.
  361. //
  362. SspContextCopyString( NegotiateMessage,
  363. &NegotiateMessage->OemDomainName,
  364. &NtLmLocalOemPrimaryDomainNameString,
  365. &Where );
  366. NegotiateMessage->NegotiateFlags |=
  367. NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED;
  368. }
  369. if ((ContextReqFlags & ISC_REQ_ALLOCATE_MEMORY) == 0)
  370. {
  371. RtlCopyMemory( *OutputToken,
  372. NegotiateMessage,
  373. NegotiateMessageSize );
  374. }
  375. else
  376. {
  377. *OutputToken = NegotiateMessage;
  378. NegotiateMessage = NULL;
  379. *ContextAttributes |= ISC_RET_ALLOCATED_MEMORY;
  380. }
  381. *OutputTokenSize = NegotiateMessageSize;
  382. }
  383. //
  384. // Save a reference to the credential in the context.
  385. //
  386. Context->Credential = Credential;
  387. Credential = NULL;
  388. //
  389. // Check for a caller requesting datagram security.
  390. //
  391. if ((ContextReqFlags & ISC_REQ_DATAGRAM) != 0) {
  392. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_DATAGRAM;
  393. Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_NT_ONLY;
  394. Context->ContextFlags |= ISC_RET_DATAGRAM;
  395. *ContextAttributes |= ISC_RET_DATAGRAM;
  396. // If datagram security is required, then we don't send back a token
  397. *OutputTokenSize = 0;
  398. //
  399. // Generate a session key for this context if sign or seal was
  400. // requested.
  401. //
  402. if ((Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_SIGN |
  403. NTLMSSP_NEGOTIATE_SEAL)) != 0) {
  404. Status = SspGenerateRandomBits(
  405. Context->SessionKey,
  406. MSV1_0_USER_SESSION_KEY_LENGTH
  407. );
  408. if ( !NT_SUCCESS( Status ) ) {
  409. SspPrint(( SSP_CRITICAL,
  410. "SsprHandleFirstCall: SspGenerateRandomBits failed\n"));
  411. goto Cleanup;
  412. }
  413. }
  414. RtlCopyMemory(
  415. SessionKey,
  416. Context->SessionKey,
  417. MSV1_0_USER_SESSION_KEY_LENGTH
  418. );
  419. //
  420. // Unless client wants to force its use,
  421. // Turn off strong crypt, because we can't negotiate it.
  422. //
  423. if (!NtLmGlobalDatagramUse128BitEncryption) {
  424. Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_128;
  425. }
  426. //
  427. // likewise for 56bit. note that package init handles turning
  428. // off 56bit if 128bit is configured for datagram.
  429. //
  430. if (!NtLmGlobalDatagramUse56BitEncryption) {
  431. Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_56;
  432. }
  433. //
  434. // Unless client wants to require NTLM2, can't use its
  435. // message processing features because we start using
  436. // MD5 sigs, full duplex mode, and datagram rekey before
  437. // we know if the server supports NTLM2.
  438. //
  439. if (!NtLmGlobalRequireNtlm2) {
  440. Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_NTLM2;
  441. }
  442. //
  443. // done fiddling with the negotiate flags, output them.
  444. //
  445. *NegotiateFlags = Context->NegotiateFlags;
  446. //
  447. // send back the negotiate flags to control signing and sealing
  448. //
  449. *NegotiateFlags |= NTLMSSP_APP_SEQ;
  450. }
  451. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH )
  452. {
  453. Status = SspGenerateRandomBits(
  454. Context->SessionKey,
  455. MSV1_0_USER_SESSION_KEY_LENGTH
  456. );
  457. if ( !NT_SUCCESS( Status ) ) {
  458. SspPrint(( SSP_CRITICAL,
  459. "SsprHandleFirstCall: SspGenerateRandomBits failed\n"));
  460. goto Cleanup;
  461. }
  462. RtlCopyMemory(
  463. SessionKey,
  464. Context->SessionKey,
  465. MSV1_0_USER_SESSION_KEY_LENGTH
  466. );
  467. }
  468. //
  469. // Return output parameters to the caller.
  470. //
  471. *ExpirationTime = SspContextGetTimeStamp( Context, TRUE );
  472. Status = SEC_I_CONTINUE_NEEDED;
  473. Context->State = NegotiateSentState;
  474. SspPrint(( SSP_NEGOTIATE_FLAGS,
  475. "SsprHandleFirstCall: NegotiateFlags = %lx\n", Context->NegotiateFlags));
  476. //
  477. // Check that caller asked for minimum security required.
  478. //
  479. if (!SsprCheckMinimumSecurity(
  480. Context->NegotiateFlags,
  481. NtLmGlobalMinimumClientSecurity)) {
  482. Status = SEC_E_UNSUPPORTED_FUNCTION;
  483. SspPrint(( SSP_CRITICAL,
  484. "SsprHandleFirstCall: "
  485. "Caller didn't request minimum security requirements (caller=0x%lx wanted=0x%lx).\n",
  486. Context->NegotiateFlags, NtLmGlobalMinimumClientSecurity ));
  487. goto Cleanup;
  488. }
  489. //
  490. // Free and locally used resources.
  491. //
  492. Cleanup:
  493. if ( Context != NULL ) {
  494. //
  495. // If we failed,
  496. // deallocate the context we allocated above.
  497. //
  498. // Delinking is a side effect of referencing, so do that.
  499. //
  500. if ( !NT_SUCCESS(Status) ) {
  501. PSSP_CONTEXT LocalContext;
  502. SspContextReferenceContext( *ContextHandle, TRUE, &LocalContext );
  503. ASSERT( LocalContext != NULL );
  504. if ( LocalContext != NULL ) {
  505. SspContextDereferenceContext( LocalContext );
  506. }
  507. }
  508. // Always dereference it.
  509. SspContextDereferenceContext( Context );
  510. }
  511. if ( NegotiateMessage != NULL ) {
  512. (VOID) NtLmFreeLsaHeap( NegotiateMessage );
  513. }
  514. if ( Credential != NULL ) {
  515. SspCredentialDereferenceCredential( Credential );
  516. }
  517. if ( NtLmLocalOemComputerNameString.Buffer != NULL ) {
  518. (VOID) NtLmFreePrivateHeap( NtLmLocalOemComputerNameString.Buffer );
  519. }
  520. if ( NtLmLocalOemPrimaryDomainNameString.Buffer != NULL ) {
  521. (VOID) NtLmFreePrivateHeap( NtLmLocalOemPrimaryDomainNameString.Buffer );
  522. }
  523. SspPrint(( SSP_API_MORE, "Leaving SsprHandleFirstCall: 0x%lx\n", Status ));
  524. return Status;
  525. UNREFERENCED_PARAMETER( InputToken );
  526. UNREFERENCED_PARAMETER( InputTokenSize );
  527. }
  528. //+-------------------------------------------------------------------------
  529. //
  530. // Function: SppGenerateExplicitCredAudit
  531. //
  532. // Synopsis: Generates audit event when a logon is initiated by
  533. // explicitly supplying credentials.
  534. //
  535. // Arguments: pContext -- pointer to SSP context
  536. // pChallengeMessage -- pointer to challenge message. the target
  537. // information is extracted from this.
  538. // ChallengeMessageSize -- size of the above
  539. // DoUnicode -- whether the target info is in
  540. // unicode or ascii format.
  541. //
  542. // Returns: NTSTATUS code
  543. //
  544. //--------------------------------------------------------------------------
  545. NTSTATUS
  546. NTAPI
  547. SppGenerateExplicitCredAudit(
  548. IN PSSP_CONTEXT pContext,
  549. IN PCHALLENGE_MESSAGE pChallengeMessage,
  550. IN ULONG ChallengeMessageSize,
  551. IN BOOLEAN DoUnicode
  552. )
  553. {
  554. NTSTATUS Status = STATUS_SUCCESS;
  555. UNICODE_STRING TargetName = { 0 };
  556. UNICODE_STRING TargetInfo = { 0 };
  557. PUNICODE_STRING pTargetName = NULL;
  558. PUNICODE_STRING pTargetInfo = NULL;
  559. PWSTR pszTemp = NULL;
  560. ASSERT( DoUnicode && L"SppGenerateExplicitCredAudit: DoUnicode is FALSE" );
  561. //
  562. // we do not handle non-unicode for now.
  563. //
  564. if ( !pContext || !pContext->Credential || !DoUnicode)
  565. {
  566. goto Cleanup;
  567. }
  568. //
  569. // extract target info from ChallengeMessage
  570. //
  571. if ((pChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO) &&
  572. (pChallengeMessage->TargetInfo.Length != 0) &&
  573. (pChallengeMessage->TargetInfo.Buffer != NULL))
  574. {
  575. //
  576. // target info is present. convert to absolute format now.
  577. //
  578. if (SspConvertRelativeToAbsolute (
  579. pChallengeMessage,
  580. ChallengeMessageSize,
  581. &pChallengeMessage->TargetInfo,
  582. (PSTRING)&TargetInfo,
  583. DoUnicode,
  584. TRUE // NULL target info OK
  585. ))
  586. {
  587. //
  588. // get the DNS computer name
  589. //
  590. Status = MsvpAvlToString(
  591. &TargetInfo,
  592. MsvAvDnsComputerName,
  593. &pszTemp
  594. );
  595. if ( NT_SUCCESS(Status) && pszTemp )
  596. {
  597. //
  598. // initialize the target name/info to the same value
  599. //
  600. RtlInitUnicodeString( &TargetInfo, pszTemp );
  601. RtlInitUnicodeString( &TargetName, pszTemp );
  602. }
  603. else
  604. {
  605. //
  606. // DNS name not available, get the Netbios computer name
  607. //
  608. Status = MsvpAvlToString(
  609. &TargetInfo,
  610. MsvAvNbComputerName,
  611. &pszTemp
  612. );
  613. if ( NT_SUCCESS(Status) && pszTemp )
  614. {
  615. //
  616. // initialize the target name/info to the same value
  617. //
  618. RtlInitUnicodeString( &TargetInfo, pszTemp );
  619. RtlInitUnicodeString( &TargetName, pszTemp );
  620. }
  621. }
  622. }
  623. else
  624. {
  625. SspPrint(( SSP_CRITICAL,
  626. "SppGenerateExplicitCredAudit: "
  627. "ChallengeMessage.TargetInfo size wrong %ld\n",
  628. ChallengeMessageSize ));
  629. }
  630. }
  631. if ( TargetInfo.Length && TargetName.Length )
  632. {
  633. pTargetInfo = &TargetInfo;
  634. pTargetName = &TargetName;
  635. }
  636. //
  637. // target info not available or could not be extracted,
  638. // but we may have "domain name\0servername" (or "servername")
  639. // in TargetName instead, use that if available.
  640. //
  641. else if ((pChallengeMessage->TargetName.Length != 0) &&
  642. (pChallengeMessage->TargetName.Buffer != NULL))
  643. {
  644. if (SspConvertRelativeToAbsolute (
  645. pChallengeMessage,
  646. ChallengeMessageSize,
  647. &pChallengeMessage->TargetName,
  648. (PSTRING)&TargetName,
  649. DoUnicode,
  650. TRUE // NULL target info OK
  651. ))
  652. {
  653. //
  654. // determine the TargetName format
  655. // "domain name\0servername" or "servername"
  656. //
  657. PWSTR psz = TargetName.Buffer;
  658. USHORT cb = 0;
  659. while ((cb < TargetName.Length) && *psz)
  660. {
  661. psz++;
  662. cb += sizeof(WCHAR);
  663. }
  664. if ( cb < TargetName.Length )
  665. {
  666. //
  667. // we have "domain name\0servername", skip the
  668. // domain name part.
  669. //
  670. psz++;
  671. TargetName.Buffer = psz;
  672. TargetName.Length = TargetName.Length - cb;
  673. TargetName.MaximumLength = TargetName.Length;
  674. }
  675. pTargetName = pTargetInfo = &TargetName;
  676. }
  677. else
  678. {
  679. SspPrint(( SSP_CRITICAL,
  680. "SppGenerateExplicitCredAudit: "
  681. "ChallengeMessage.TargetName size wrong %ld\n",
  682. ChallengeMessageSize ));
  683. }
  684. }
  685. {
  686. SECPKG_CALL_INFO CallInfo;
  687. LsaFunctions->GetCallInfo(&CallInfo);
  688. Status = I_LsaIAuditLogonUsingExplicitCreds(
  689. EVENTLOG_AUDIT_SUCCESS,
  690. &pContext->Credential->LogonId, // user1 logon id
  691. NULL, // user1 logon guid
  692. (HANDLE) (ULONG_PTR) CallInfo.ProcessId,
  693. &pContext->UserName,
  694. &pContext->DomainName,
  695. NULL, // user2 logon guid (NULL for ntlm)
  696. pTargetName,
  697. pTargetInfo
  698. );
  699. }
  700. Cleanup:
  701. if ( pszTemp )
  702. {
  703. NtLmFree( pszTemp );
  704. }
  705. return Status;
  706. }
  707. NTSTATUS
  708. SsprHandleChallengeMessage(
  709. IN LSA_SEC_HANDLE CredentialHandle,
  710. IN OUT PLSA_SEC_HANDLE ContextHandle,
  711. IN ULONG ContextReqFlags,
  712. IN ULONG InputTokenSize,
  713. IN PVOID InputToken,
  714. IN ULONG SecondInputTokenSize,
  715. IN PVOID SecondInputToken,
  716. IN PUNICODE_STRING TargetServerName,
  717. IN OUT PULONG OutputTokenSize,
  718. OUT PVOID *OutputToken,
  719. IN OUT PULONG SecondOutputTokenSize,
  720. OUT PVOID *SecondOutputToken,
  721. OUT PULONG ContextAttributes,
  722. OUT PTimeStamp ExpirationTime,
  723. OUT PUCHAR SessionKey,
  724. OUT PULONG NegotiateFlags
  725. )
  726. /*++
  727. Routine Description:
  728. Handle the Challenge message part of InitializeSecurityContext.
  729. Arguments:
  730. DomainName,UserName,Password - Passed in credentials to be used for this
  731. context.
  732. DomainNameSize,userNameSize,PasswordSize - length in characters of the
  733. credentials to be used for this context.
  734. SessionKey - Session key to use for this context
  735. NegotiateFlags - Flags negotiated for this context
  736. TargetServerName - Target server name, used by CredMgr to associates NT4 servers with domains
  737. All other arguments same as for InitializeSecurityContext
  738. Return Value:
  739. STATUS_SUCCESS - Message handled
  740. SEC_I_CONTINUE_NEEDED -- Caller should call again later
  741. SEC_E_INVALID_TOKEN -- Token improperly formatted
  742. SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
  743. SEC_E_BUFFER_TOO_SMALL -- Buffer for output token isn't big enough
  744. SEC_E_NO_CREDENTIALS -- There are no credentials for this client
  745. SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
  746. --*/
  747. {
  748. SECURITY_STATUS SecStatus = STATUS_SUCCESS;
  749. PSSP_CONTEXT Context = NULL;
  750. PCHALLENGE_MESSAGE ChallengeMessage = NULL;
  751. PNTLM_CHALLENGE_MESSAGE NtLmChallengeMessage = NULL;
  752. PAUTHENTICATE_MESSAGE AuthenticateMessage = NULL;
  753. PNTLM_INITIALIZE_RESPONSE NtLmInitializeResponse = NULL;
  754. PMSV1_0_GETCHALLENRESP_RESPONSE ChallengeResponseMessage = NULL;
  755. STRING UserName = {0};
  756. STRING DomainName = {0};
  757. STRING Workstation = {0};
  758. STRING LmChallengeResponse = {0};
  759. STRING NtChallengeResponse = {0};
  760. STRING DatagramSessionKey = {0};
  761. BOOLEAN DoUnicode = TRUE;
  762. NTSTATUS Status = STATUS_SUCCESS;
  763. NTSTATUS ProtocolStatus;
  764. NTSTATUS AuditStatus = STATUS_SUCCESS;
  765. MSV1_0_GETCHALLENRESP_REQUEST TempChallengeResponse;
  766. PMSV1_0_GETCHALLENRESP_REQUEST GetChallengeResponse;
  767. ULONG GetChallengeResponseSize;
  768. UNICODE_STRING RevealedPassword = {0};
  769. ULONG ChallengeResponseSize;
  770. ULONG AuthenticateMessageSize;
  771. PCHAR Where;
  772. UCHAR DatagramKey[MSV1_0_USER_SESSION_KEY_LENGTH];
  773. PLUID ClientLogonId = NULL;
  774. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel = SecurityImpersonation;
  775. BOOLEAN UseSuppliedCreds = FALSE;
  776. PSSP_CREDENTIAL Credential = NULL;
  777. BOOLEAN fCallFromRedir = FALSE;
  778. BOOLEAN fShareLevel = FALSE; // is target down-level share based security (no username) ?
  779. BOOLEAN fCredmanCredentials = FALSE; // used credman creds?
  780. UNICODE_STRING TargetName = {0};
  781. UNICODE_STRING DefectiveTargetName = {0}; // for broken servers.
  782. LPWSTR szCredTargetDomain = NULL;
  783. LPWSTR szCredTargetServer = NULL;
  784. LPWSTR szCredTargetDnsDomain = NULL;
  785. LPWSTR szCredTargetDnsServer = NULL;
  786. LPWSTR szCredTargetDnsTree = NULL;
  787. LPWSTR szCredTargetPreDFSServer = NULL;
  788. LUID LogonIdNetworkService = NETWORKSERVICE_LUID;
  789. PSSP_CONTEXT ServerContext = NULL; // server context referenced during loopback
  790. HANDLE ClientTokenHandle = NULL; // access token associated with client
  791. // which called AcquireCredentialsHandle (OUTBOUND)
  792. SspPrint((SSP_API_MORE, "Entering SsprHandleChallengeMessage\n"));
  793. //
  794. // Initialization
  795. //
  796. *ContextAttributes = 0;
  797. *NegotiateFlags = 0;
  798. GetChallengeResponse = &TempChallengeResponse;
  799. if (*ContextHandle == NULL)
  800. {
  801. // This is possibly an old style redir call (for 4.0 and before)
  802. // so, alloc the context and replace the creds if new ones exists
  803. fCallFromRedir = TRUE;
  804. SspPrint((SSP_API_MORE, "SsprHandleChallengeMessage: *ContextHandle is NULL (old-style RDR)\n"));
  805. if ((ContextReqFlags & ISC_REQ_USE_SUPPLIED_CREDS) != 0)
  806. {
  807. UseSuppliedCreds = TRUE;
  808. }
  809. // This is a superflous check since we alloc only if the caller
  810. // has asked us too. This is to make sure that the redir always asks us to alloc
  811. if (!(ContextReqFlags & ISC_REQ_ALLOCATE_MEMORY))
  812. {
  813. SecStatus = STATUS_NOT_SUPPORTED;
  814. goto Cleanup;
  815. }
  816. SecStatus = SspCredentialReferenceCredential(
  817. CredentialHandle,
  818. FALSE,
  819. &Credential );
  820. if ( !NT_SUCCESS( SecStatus ) )
  821. {
  822. SspPrint(( SSP_CRITICAL,
  823. "SsprHandleChallengeMessage: SspCredentialReferenceCredential returns %x.\n", SecStatus ));
  824. goto Cleanup;
  825. }
  826. //
  827. // Allocate a new context
  828. //
  829. Context = SspContextAllocateContext();
  830. if (Context == NULL)
  831. {
  832. SspPrint(( SSP_CRITICAL,
  833. "SsprHandleChallengeMessage: SspContextAllocateContext returns NULL.\n" ));
  834. SecStatus = STATUS_NO_MEMORY;
  835. goto Cleanup;
  836. }
  837. // We've just added a context, we don't nornally add and then
  838. // reference it.
  839. SspContextDereferenceContext( Context );
  840. *ContextHandle = (LSA_SEC_HANDLE) Context;
  841. //
  842. // Capture the default credentials from the credential structure.
  843. //
  844. if ( Credential->DomainName.Buffer != NULL ) {
  845. Status = NtLmDuplicateUnicodeString(
  846. &Context->DomainName,
  847. &Credential->DomainName
  848. );
  849. if (!NT_SUCCESS(Status)) {
  850. SspPrint(( SSP_CRITICAL,
  851. "SsprHandleChallengeMessage: NtLmDuplicateUnicodeString (DomainName) returned %d\n",Status));
  852. SecStatus = SspNtStatusToSecStatus( Status,
  853. SEC_E_INSUFFICIENT_MEMORY);
  854. goto Cleanup;
  855. }
  856. }
  857. if ( Credential->UserName.Buffer != NULL ) {
  858. Status = NtLmDuplicateUnicodeString(
  859. &Context->UserName,
  860. &Credential->UserName
  861. );
  862. if (!NT_SUCCESS(Status)) {
  863. SspPrint(( SSP_CRITICAL,
  864. "SsprHandleChallengeMessage: NtLmDuplicateUnicodeString (UserName) returned %d\n", Status ));
  865. SecStatus = SspNtStatusToSecStatus( Status,
  866. SEC_E_INSUFFICIENT_MEMORY);
  867. goto Cleanup;
  868. }
  869. }
  870. SecStatus = SspCredentialGetPassword(
  871. Credential,
  872. &Context->Password
  873. );
  874. if (!NT_SUCCESS(SecStatus)) {
  875. SspPrint(( SSP_CRITICAL,
  876. "SsprHandleChallengeMessage: SspCredentialGetPassword returned %d\n", SecStatus ));
  877. goto Cleanup;
  878. }
  879. // Assign the Credential
  880. Context->Credential = Credential;
  881. Credential = NULL;
  882. //
  883. // fake it
  884. //
  885. Context->NegotiateFlags = NTLMSSP_NEGOTIATE_UNICODE |
  886. NTLMSSP_NEGOTIATE_OEM |
  887. NTLMSSP_REQUEST_TARGET |
  888. NTLMSSP_REQUEST_INIT_RESPONSE |
  889. ((NtLmGlobalLmProtocolSupported != 0)
  890. ? NTLMSSP_NEGOTIATE_NTLM2 : 0 ) |
  891. NTLMSSP_TARGET_TYPE_SERVER |
  892. NTLMSSP_NEGOTIATE_VERSION;
  893. *ExpirationTime = SspContextGetTimeStamp(Context, TRUE);
  894. Context->State = NegotiateSentState;
  895. // If creds are passed in by the RDR, then replace the ones in the context
  896. if (UseSuppliedCreds)
  897. {
  898. if (SecondInputTokenSize < sizeof(NTLM_CHALLENGE_MESSAGE))
  899. {
  900. SspPrint(( SSP_CRITICAL,
  901. "SsprHandleChallengeMessage: Invalid SecondInputTokensize.\n" ));
  902. SecStatus = SEC_E_INVALID_TOKEN;
  903. goto Cleanup;
  904. }
  905. NtLmChallengeMessage = (PNTLM_CHALLENGE_MESSAGE) NtLmAllocatePrivateHeap(SecondInputTokenSize);
  906. if (NtLmChallengeMessage == NULL)
  907. {
  908. SspPrint(( SSP_CRITICAL,
  909. "SsprHandleChallengeMessage: Error while allocating NtLmChallengeMessage\n" ));
  910. SecStatus = STATUS_NO_MEMORY;
  911. goto Cleanup;
  912. }
  913. RtlCopyMemory(NtLmChallengeMessage,
  914. SecondInputToken,
  915. SecondInputTokenSize);
  916. //
  917. // NULL session is only true if user, domain, and password are all
  918. // empty strings in stead of NULLs
  919. //
  920. if (((NtLmChallengeMessage->Password.Length == 0) && (NtLmChallengeMessage->Password.Buffer != NULL)) &&
  921. ((NtLmChallengeMessage->UserName.Length == 0) && (NtLmChallengeMessage->UserName.Buffer != NULL)) &&
  922. ((NtLmChallengeMessage->DomainName.Length == 0) && (NtLmChallengeMessage->DomainName.Buffer != NULL)))
  923. {
  924. // This could only be a null session request
  925. SspPrint(( SSP_WARNING, "SsprHandleChallengeMessage: null session NtLmChallengeMessage\n" ));
  926. if (Context->Password.Buffer != NULL)
  927. {
  928. // free it first
  929. NtLmFreePrivateHeap (Context->Password.Buffer);
  930. }
  931. Context->Password.Buffer = (LPWSTR) NtLmAllocatePrivateHeap(sizeof(WCHAR));
  932. if (Context->Password.Buffer == NULL)
  933. {
  934. SspPrint(( SSP_CRITICAL,
  935. "SsprHandleChallengeMessage: NtLmAllocatePrivateHeap(Password) returns NULL.\n"));
  936. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  937. goto Cleanup;
  938. }
  939. Context->Password.Length = 0;
  940. Context->Password.MaximumLength = 0;
  941. *(Context->Password.Buffer) = L'\0';
  942. SspHidePassword(&Context->Password);
  943. if (Context->UserName.Buffer != NULL)
  944. {
  945. // free it first
  946. NtLmFreePrivateHeap (Context->UserName.Buffer);
  947. }
  948. Context->UserName.Buffer = (LPWSTR) NtLmAllocatePrivateHeap(sizeof(WCHAR));
  949. if (Context->UserName.Buffer == NULL)
  950. {
  951. SspPrint(( SSP_CRITICAL,
  952. "SsprHandleChallengeMessage: NtLmAllocatePrivateHeap(UserName) returns NULL.\n"));
  953. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  954. goto Cleanup;
  955. }
  956. Context->UserName.Length = 0;
  957. Context->UserName.MaximumLength = sizeof(WCHAR);
  958. *(Context->UserName.Buffer) = L'\0';
  959. if (Context->DomainName.Buffer != NULL)
  960. {
  961. // free it first
  962. NtLmFreePrivateHeap (Context->DomainName.Buffer);
  963. }
  964. Context->DomainName.Buffer = (LPWSTR) NtLmAllocatePrivateHeap(sizeof(WCHAR));
  965. if (Context->DomainName.Buffer == NULL)
  966. {
  967. SspPrint(( SSP_CRITICAL,
  968. "SsprHandleChallengeMessage: NtLmAllocatePrivateHeap(DomainName) returns NULL.\n"));
  969. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  970. goto Cleanup;
  971. }
  972. Context->DomainName.Length = 0;
  973. Context->DomainName.MaximumLength = sizeof(WCHAR);
  974. *(Context->DomainName.Buffer) = L'\0';
  975. }
  976. else
  977. {
  978. ULONG_PTR BufferTail = (ULONG_PTR)NtLmChallengeMessage + SecondInputTokenSize;
  979. UNICODE_STRING AbsoluteString;
  980. if (NtLmChallengeMessage->Password.Buffer != 0)
  981. {
  982. AbsoluteString.Buffer = (LPWSTR)((PUCHAR)NtLmChallengeMessage + NtLmChallengeMessage->Password.Buffer);
  983. //
  984. // verify buffer not out of range.
  985. //
  986. if ( ( (ULONG_PTR)AbsoluteString.Buffer > BufferTail ) ||
  987. ( (ULONG_PTR)((PUCHAR)AbsoluteString.Buffer + NtLmChallengeMessage->Password.Length) > BufferTail ) ||
  988. ( (ULONG_PTR)AbsoluteString.Buffer < (ULONG_PTR)NtLmChallengeMessage )
  989. )
  990. {
  991. SecStatus = SEC_E_NO_CREDENTIALS;
  992. SspPrint(( SSP_CRITICAL,
  993. "SsprHandleChallengeMessage: Buffer overflow (Password).\n" ));
  994. goto Cleanup;
  995. }
  996. if (Context->Password.Buffer != NULL)
  997. {
  998. // free it first
  999. NtLmFreePrivateHeap (Context->Password.Buffer);
  1000. Context->Password.Buffer = NULL;
  1001. }
  1002. AbsoluteString.Length = AbsoluteString.MaximumLength = NtLmChallengeMessage->Password.Length;
  1003. SecStatus = NtLmDuplicatePassword(
  1004. &Context->Password,
  1005. &AbsoluteString
  1006. );
  1007. if (!NT_SUCCESS(SecStatus))
  1008. {
  1009. SspPrint(( SSP_CRITICAL,
  1010. "SsprHandleChallengeMessage: NtLmDuplicatePassword returns 0x%lx.\n",SecStatus ));
  1011. goto Cleanup;
  1012. }
  1013. SspHidePassword(&Context->Password);
  1014. }
  1015. if (NtLmChallengeMessage->UserName.Length != 0)
  1016. {
  1017. AbsoluteString.Buffer = (LPWSTR)((PUCHAR)NtLmChallengeMessage + NtLmChallengeMessage->UserName.Buffer);
  1018. //
  1019. // verify buffer not out of range.
  1020. //
  1021. if ( ( (ULONG_PTR)AbsoluteString.Buffer > BufferTail ) ||
  1022. ( (ULONG_PTR)((PUCHAR)AbsoluteString.Buffer + NtLmChallengeMessage->UserName.Length) > BufferTail ) ||
  1023. ( (ULONG_PTR)AbsoluteString.Buffer < (ULONG_PTR)NtLmChallengeMessage )
  1024. )
  1025. {
  1026. SecStatus = SEC_E_NO_CREDENTIALS;
  1027. SspPrint(( SSP_CRITICAL,
  1028. "SsprHandleChallengeMessage: Buffer overflow (UserName).\n" ));
  1029. goto Cleanup;
  1030. }
  1031. if (Context->UserName.Buffer != NULL)
  1032. {
  1033. // free it first
  1034. NtLmFreePrivateHeap (Context->UserName.Buffer);
  1035. }
  1036. AbsoluteString.Length = AbsoluteString.MaximumLength = NtLmChallengeMessage->UserName.Length;
  1037. SecStatus = NtLmDuplicateUnicodeString(&Context->UserName,
  1038. &AbsoluteString);
  1039. if (!NT_SUCCESS(SecStatus))
  1040. {
  1041. SspPrint(( SSP_CRITICAL,
  1042. "SsprHandleChallengeMessage: NtLmDuplicateUnicodeString(UserName) returns 0x%lx.\n",SecStatus ));
  1043. goto Cleanup;
  1044. }
  1045. }
  1046. if (NtLmChallengeMessage->DomainName.Length != 0)
  1047. {
  1048. AbsoluteString.Buffer = (LPWSTR)((PUCHAR)NtLmChallengeMessage + NtLmChallengeMessage->DomainName.Buffer);
  1049. //
  1050. // verify buffer not out of range.
  1051. //
  1052. if ( ( (ULONG_PTR)AbsoluteString.Buffer > BufferTail ) ||
  1053. ( (ULONG_PTR)((PUCHAR)AbsoluteString.Buffer + NtLmChallengeMessage->DomainName.Length) > BufferTail ) ||
  1054. ( (ULONG_PTR)AbsoluteString.Buffer < (ULONG_PTR)NtLmChallengeMessage )
  1055. )
  1056. {
  1057. SecStatus = SEC_E_NO_CREDENTIALS;
  1058. SspPrint(( SSP_CRITICAL,
  1059. "SsprHandleChallengeMessage: Buffer overflow (DomainName).\n" ));
  1060. goto Cleanup;
  1061. }
  1062. if (Context->DomainName.Buffer != NULL)
  1063. {
  1064. // free it first
  1065. NtLmFreePrivateHeap (Context->DomainName.Buffer);
  1066. }
  1067. AbsoluteString.Length = AbsoluteString.MaximumLength = NtLmChallengeMessage->DomainName.Length;
  1068. SecStatus = NtLmDuplicateUnicodeString(&Context->DomainName,
  1069. &AbsoluteString);
  1070. if (!NT_SUCCESS(SecStatus))
  1071. {
  1072. SspPrint(( SSP_CRITICAL,
  1073. "SsprHandleChallengeMessage: NtLmDuplicateUnicodeString(DomainName) returns 0x%lx.\n",SecStatus ));
  1074. goto Cleanup;
  1075. }
  1076. }
  1077. }
  1078. if (NtLmChallengeMessage)
  1079. {
  1080. NtLmFreePrivateHeap (NtLmChallengeMessage);
  1081. NtLmChallengeMessage = NULL;
  1082. }
  1083. } // end of special casing if credentials are supplied in the first init call
  1084. } // end of special casing for the old style redir
  1085. //
  1086. // Find the currently existing context.
  1087. //
  1088. SecStatus = SspContextReferenceContext( *ContextHandle, FALSE, &Context );
  1089. if ( !NT_SUCCESS(SecStatus) )
  1090. {
  1091. SspPrint(( SSP_CRITICAL,
  1092. "SsprHandleChallengeMessage: invalid context handle.\n" ));
  1093. goto Cleanup;
  1094. }
  1095. //
  1096. // passing Accept handle to Init can cause AV
  1097. //
  1098. if ( Context->Credential == NULL ) {
  1099. SspPrint(( SSP_CRITICAL,
  1100. "SsprHandleChallengeMessage: invalid context handle, missing credential.\n" ));
  1101. SecStatus = STATUS_INVALID_HANDLE;
  1102. goto Cleanup;
  1103. }
  1104. //
  1105. // If this is not reauthentication (or is datagram reauthentication)
  1106. // pull the context out of the associated credential.
  1107. //
  1108. if ((Context->State != AuthenticateSentState) ||
  1109. (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) != 0)
  1110. {
  1111. ClientLogonId = &Context->Credential->LogonId;
  1112. ImpersonationLevel = Context->Credential->ImpersonationLevel;
  1113. }
  1114. //
  1115. // process the TargetServerName to see if marshalled target info was
  1116. // passed in. This can happen if the caller passes in marshalled target
  1117. // info for each call to InitializeSecurityContext(), or, uses the downlevel
  1118. // RDR path which happened previously in this routine.
  1119. //
  1120. Status = CredpExtractMarshalledTargetInfo(
  1121. TargetServerName,
  1122. &Context->TargetInfo
  1123. );
  1124. if (!NT_SUCCESS(Status)) {
  1125. SspPrint(( SSP_CRITICAL,
  1126. "SsprHandleChallengeMessage: CredpExtractMarshalledTargetInfo returned %d\n", Status ));
  1127. goto Cleanup;
  1128. }
  1129. //
  1130. // If we have already sent the authenticate message, then this must be
  1131. // RPC calling Initialize a third time to re-authenticate a connection.
  1132. // This happens when a new interface is called over an existing
  1133. // connection. What we do here is build a NULL authenticate message
  1134. // that the server will recognize and also ignore.
  1135. //
  1136. //
  1137. // That being said, if we are doing datagram style authentication then
  1138. // the story is different. The server may have dropped this security
  1139. // context and then the client sent another packet over. The server
  1140. // will then be trying to restore the context, so we need to build
  1141. // another authenticate message.
  1142. //
  1143. if ( Context->State == AuthenticateSentState ) {
  1144. AUTHENTICATE_MESSAGE NullMessage;
  1145. if (((Context->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) ==
  1146. NTLMSSP_NEGOTIATE_DATAGRAM) &&
  1147. (InputTokenSize != 0) &&
  1148. (InputToken != NULL) ) {
  1149. //
  1150. // we are doing a reauthentication for datagram, so let this
  1151. // through. We don't want the security.dll remapping this
  1152. // context.
  1153. //
  1154. *ContextAttributes |= SSP_RET_REAUTHENTICATION;
  1155. } else {
  1156. //
  1157. // To make sure this is the intended meaning of the call, check
  1158. // that the input token is NULL.
  1159. //
  1160. if ( (InputTokenSize != 0) || (InputToken != NULL) ) {
  1161. SecStatus = SEC_E_INVALID_TOKEN;
  1162. SspPrint(( SSP_CRITICAL,
  1163. "SsprHandleChallengeMessage: (re-auth) invalid InputTokenSize.\n" ));
  1164. goto Cleanup;
  1165. }
  1166. if ( (*OutputTokenSize < sizeof(NullMessage)) &&
  1167. ((ContextReqFlags & ISC_REQ_ALLOCATE_MEMORY) == 0))
  1168. {
  1169. SecStatus = SEC_E_BUFFER_TOO_SMALL;
  1170. SspPrint(( SSP_CRITICAL,
  1171. "SsprHandleChallengeMessage: invalid OutputTokenSize.\n" ));
  1172. }
  1173. else {
  1174. RtlZeroMemory( &NullMessage, sizeof(NullMessage) );
  1175. strcpy( (char *)NullMessage.Signature, NTLMSSP_SIGNATURE );
  1176. NullMessage.MessageType = NtLmAuthenticate;
  1177. if ((ContextReqFlags & ISC_REQ_ALLOCATE_MEMORY) == 0)
  1178. {
  1179. RtlCopyMemory( *OutputToken,
  1180. &NullMessage,
  1181. sizeof(NullMessage));
  1182. }
  1183. else
  1184. {
  1185. PAUTHENTICATE_MESSAGE NewNullMessage = (PAUTHENTICATE_MESSAGE)
  1186. NtLmAllocateLsaHeap(sizeof(NullMessage));
  1187. if ( NewNullMessage == NULL)
  1188. {
  1189. SecStatus = STATUS_NO_MEMORY;
  1190. SspPrint(( SSP_CRITICAL,
  1191. "SsprHandleChallengeMessage: Error allocating NewNullMessage.\n" ));
  1192. goto Cleanup;
  1193. }
  1194. *OutputToken = NewNullMessage;
  1195. NewNullMessage = NULL;
  1196. *ContextAttributes |= ISC_RET_ALLOCATED_MEMORY;
  1197. }
  1198. *OutputTokenSize = sizeof(NullMessage);
  1199. }
  1200. *ContextAttributes |= SSP_RET_REAUTHENTICATION;
  1201. goto Cleanup;
  1202. }
  1203. } else if ( Context->State != NegotiateSentState ) {
  1204. SspPrint(( SSP_CRITICAL,
  1205. "SsprHandleChallengeMessage: "
  1206. "Context not in NegotiateSentState\n" ));
  1207. SecStatus = SEC_E_OUT_OF_SEQUENCE;
  1208. goto Cleanup;
  1209. }
  1210. //
  1211. // We don't support any options.
  1212. // Complain about those that require we do something.
  1213. //
  1214. if ( (ContextReqFlags & ISC_REQ_PROMPT_FOR_CREDS) != 0 ){
  1215. SspPrint(( SSP_CRITICAL,
  1216. "SsprHandleChallengeMessage: invalid ContextReqFlags 0x%lx.\n",
  1217. ContextReqFlags ));
  1218. SecStatus = SEC_E_INVALID_CONTEXT_REQ;
  1219. goto Cleanup;
  1220. }
  1221. //
  1222. // Ignore the Credential Handle.
  1223. //
  1224. // Since this is the second call,
  1225. // the credential is implied by the Context.
  1226. // We could double check that the Credential Handle is either NULL or
  1227. // correct. However, our implementation doesn't maintain a close
  1228. // association between the two (actually no association) so checking
  1229. // would require a lot of overhead.
  1230. //
  1231. UNREFERENCED_PARAMETER( CredentialHandle );
  1232. //
  1233. // Get the ChallengeMessage.
  1234. //
  1235. if ( InputTokenSize < sizeof(OLD_CHALLENGE_MESSAGE) ) {
  1236. SspPrint(( SSP_CRITICAL,
  1237. "SsprHandleChallengeMessage: "
  1238. "ChallengeMessage size wrong %ld\n",
  1239. InputTokenSize ));
  1240. SecStatus = SEC_E_INVALID_TOKEN;
  1241. goto Cleanup;
  1242. }
  1243. SecStatus = SspContextGetMessage( InputToken,
  1244. InputTokenSize,
  1245. NtLmChallenge,
  1246. (PVOID *)&ChallengeMessage );
  1247. if ( !NT_SUCCESS(SecStatus) ) {
  1248. SspPrint(( SSP_CRITICAL,
  1249. "SsprHandleChallengeMessage: "
  1250. "ChallengeMessage GetMessage returns 0x%lx\n",
  1251. SecStatus ));
  1252. goto Cleanup;
  1253. }
  1254. //
  1255. // for down-level RDR, EXPORTED_CONTEXT is a hint that we are talking to
  1256. // share level target.
  1257. //
  1258. if ( fCallFromRedir )
  1259. {
  1260. if ( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_EXPORTED_CONTEXT )
  1261. {
  1262. ChallengeMessage->NegotiateFlags &= ~(NTLMSSP_NEGOTIATE_EXPORTED_CONTEXT);
  1263. fShareLevel = TRUE;
  1264. SspPrint(( SSP_WARNING,
  1265. "SsprHandleChallengeMessage: "
  1266. "downlevel sharelevel security target\n"));
  1267. }
  1268. }
  1269. if ( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM ) {
  1270. //
  1271. // take out any flags we didn't ask for -- self defense from bogus combinations
  1272. //
  1273. ChallengeMessage->NegotiateFlags &=
  1274. ( Context->NegotiateFlags |
  1275. NTLMSSP_NEGOTIATE_TARGET_INFO |
  1276. NTLMSSP_TARGET_TYPE_SERVER |
  1277. NTLMSSP_TARGET_TYPE_DOMAIN |
  1278. NTLMSSP_NEGOTIATE_LOCAL_CALL);
  1279. }
  1280. //
  1281. // Determine if the caller wants OEM or UNICODE
  1282. //
  1283. if ( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_UNICODE ) {
  1284. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE;
  1285. Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_OEM;
  1286. DoUnicode = TRUE;
  1287. } else if ( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_OEM ){
  1288. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_OEM;
  1289. Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_UNICODE;
  1290. DoUnicode = FALSE;
  1291. } else {
  1292. SspPrint(( SSP_CRITICAL,
  1293. "SsprHandleChallengeMessage: "
  1294. "ChallengeMessage bad NegotiateFlags 0x%lx\n",
  1295. ChallengeMessage->NegotiateFlags ));
  1296. SecStatus = SEC_E_INVALID_TOKEN;
  1297. goto Cleanup;
  1298. }
  1299. //
  1300. // Copy other interesting negotiate flags into the context
  1301. //
  1302. if ( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO ) {
  1303. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
  1304. } else {
  1305. Context->NegotiateFlags &= ~(NTLMSSP_NEGOTIATE_TARGET_INFO);
  1306. }
  1307. //
  1308. // if got NTLM2, or if LM_KEY specifically forbidden don't use LM_KEY
  1309. //
  1310. if ((ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)) {
  1311. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY ) {
  1312. SspPrint(( SSP_NEGOTIATE_FLAGS,
  1313. "SsprHandleChallengeMessage: "
  1314. "Server support NTLM2 caused LM_KEY to be disabled.\n" ));
  1315. }
  1316. ChallengeMessage->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
  1317. Context->NegotiateFlags &= ~(NTLMSSP_NEGOTIATE_LM_KEY);
  1318. }
  1319. //
  1320. // if we did not get NTLM2 remove it from context negotiate flags
  1321. //
  1322. if (!(ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)) {
  1323. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2 ) {
  1324. SspPrint(( SSP_NEGOTIATE_FLAGS,
  1325. "SsprHandleChallengeMessage: "
  1326. "Server didn't support NTLM2 and client did.\n" ));
  1327. }
  1328. Context->NegotiateFlags &= ~(NTLMSSP_NEGOTIATE_NTLM2);
  1329. }
  1330. if ((ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM) == 0) {
  1331. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM ) {
  1332. SspPrint(( SSP_NEGOTIATE_FLAGS,
  1333. "SsprHandleChallengeMessage: "
  1334. "Server didn't support NTLM and client did.\n" ));
  1335. }
  1336. Context->NegotiateFlags &= ~(NTLMSSP_NEGOTIATE_NTLM);
  1337. }
  1338. if ((ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) == 0) {
  1339. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH ) {
  1340. SspPrint(( SSP_NEGOTIATE_FLAGS,
  1341. "SsprHandleChallengeMessage: "
  1342. "Server didn't support KEY_EXCH and client did.\n" ));
  1343. }
  1344. Context->NegotiateFlags &= ~(NTLMSSP_NEGOTIATE_KEY_EXCH);
  1345. }
  1346. if ((ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) == 0) {
  1347. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY ) {
  1348. SspPrint(( SSP_NEGOTIATE_FLAGS,
  1349. "SsprHandleChallengeMessage: "
  1350. "Server didn't support LM_KEY and client did.\n" ));
  1351. }
  1352. Context->NegotiateFlags &= ~(NTLMSSP_NEGOTIATE_LM_KEY);
  1353. }
  1354. //
  1355. // make sure KEY_EXCH is always set if DATAGRAM negotiated and we need a key
  1356. // this is for local internal use; its now safe because we've got the bits
  1357. // to go on the wire copied...
  1358. //
  1359. if ((Context->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) &&
  1360. (Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL)))
  1361. {
  1362. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH;
  1363. }
  1364. //
  1365. // allow negotiate of certain options such as sign/seal when server
  1366. // asked for it, but client didn't.
  1367. //
  1368. #if 0
  1369. ////
  1370. if ( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_SEAL ) {
  1371. if ( (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_SEAL) == 0 ) {
  1372. SspPrint(( SSP_SESSION_KEYS,
  1373. "SsprHandleChallengeMessage: client didn't request SEAL but server did, adding SEAL.\n"));
  1374. }
  1375. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
  1376. }
  1377. if ( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN ) {
  1378. if ( (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN) == 0 ) {
  1379. SspPrint(( SSP_SESSION_KEYS,
  1380. "SsprHandleChallengeMessage: client didn't request SIGN but server did, adding SIGN.\n"));
  1381. }
  1382. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
  1383. }
  1384. ////
  1385. #endif
  1386. //
  1387. // if server didn't support certain crypto strengths, insure they
  1388. // are disabled.
  1389. //
  1390. if ( (ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_56) == 0 ) {
  1391. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_56 ) {
  1392. SspPrint(( SSP_NEGOTIATE_FLAGS,
  1393. "SsprHandleChallengeMessage: Client supported 56, but server didn't.\n"));
  1394. }
  1395. Context->NegotiateFlags &= ~(NTLMSSP_NEGOTIATE_56);
  1396. }
  1397. if ( (ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_128) == 0 ) {
  1398. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_128 ) {
  1399. SspPrint(( SSP_NEGOTIATE_FLAGS,
  1400. "SsprHandleChallengeMessage: Client supported 128, but server didn't.\n"));
  1401. }
  1402. Context->NegotiateFlags &= ~(NTLMSSP_NEGOTIATE_128);
  1403. }
  1404. //
  1405. // Check that server gave minimum security required.
  1406. // not done for legacy down-level case, as, NegotiateFlags are
  1407. // constructed from incomplete information.
  1408. //
  1409. if ( !fCallFromRedir )
  1410. {
  1411. if (!SsprCheckMinimumSecurity(
  1412. Context->NegotiateFlags,
  1413. NtLmGlobalMinimumClientSecurity)) {
  1414. SecStatus = SEC_E_UNSUPPORTED_FUNCTION;
  1415. SspPrint(( SSP_CRITICAL,
  1416. "SsprHandleChallengeMessage: "
  1417. "ChallengeMessage didn't support minimum security requirements.\n" ));
  1418. goto Cleanup;
  1419. }
  1420. }
  1421. if (ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN ) {
  1422. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
  1423. } else {
  1424. Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
  1425. }
  1426. //
  1427. // Determine that the caller negotiated to NTLM or nothing, but not
  1428. // NetWare.
  1429. //
  1430. if ( (ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NETWARE) &&
  1431. ((ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM) == 0) &&
  1432. ((ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) == 0)
  1433. ) {
  1434. SecStatus = STATUS_NOT_SUPPORTED;
  1435. SspPrint(( SSP_CRITICAL,
  1436. "SsprHandleChallengeMessage: "
  1437. "ChallengeMessage asked for Netware only.\n" ));
  1438. goto Cleanup;
  1439. }
  1440. if (ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) {
  1441. if (InputTokenSize >= RTL_SIZEOF_THROUGH_FIELD(CHALLENGE_MESSAGE, Version)) {
  1442. C_ASSERT(sizeof(NTLM_VER_INFO) == sizeof(ULONG64));
  1443. RtlCopyMemory(&Context->ServerVersion, &ChallengeMessage->Version, sizeof(ChallengeMessage->Version));
  1444. SspPrint(( SSP_VERSION,
  1445. "SsprHandleChallengeMessage: ServerVersion %#I64x, Major %I64d, Minor %I64d, Build %I64d, Revision %I64d\n",
  1446. ChallengeMessage->Version,
  1447. Context->ServerVersion.Major,
  1448. Context->ServerVersion.Minor,
  1449. Context->ServerVersion.Build,
  1450. Context->ServerVersion.Revision ));
  1451. } else {
  1452. SecStatus = SEC_E_INVALID_TOKEN;
  1453. SspPrint(( SSP_CRITICAL,
  1454. "SsprHandleChallengeMessage: ChallengeMessage size too small with NTLMSSP_NEGOTIATE_VERSION\n" ));
  1455. goto Cleanup;
  1456. }
  1457. }
  1458. //
  1459. // Check if we negotiated for identify level
  1460. //
  1461. if (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_IDENTIFY) {
  1462. if (ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_IDENTIFY) {
  1463. Context->ContextFlags |= ISC_REQ_IDENTIFY;
  1464. *ContextAttributes |= ISC_RET_IDENTIFY;
  1465. } else {
  1466. SecStatus = STATUS_NOT_SUPPORTED;
  1467. SspPrint(( SSP_CRITICAL,
  1468. "SsprHandleChallengeMessage: "
  1469. "ChallengeMessage bad NegotiateFlags 0x%lx\n",
  1470. ChallengeMessage->NegotiateFlags ));
  1471. goto Cleanup;
  1472. }
  1473. }
  1474. //
  1475. // If the server is running on this same machine,
  1476. // just duplicate our caller's token and use it.
  1477. //
  1478. while ( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_LOCAL_CALL )
  1479. {
  1480. ULONG_PTR ServerContextHandle;
  1481. static const UCHAR FixedSessionKey[MSV1_0_USER_SESSION_KEY_LENGTH] = {
  1482. 'S', 'y', 's', 't', 'e', 'm', 'L', 'i',
  1483. 'b', 'r', 'a', 'r', 'y', 'D', 'T', 'C'
  1484. };
  1485. SspPrint(( SSP_MISC,
  1486. "SsprHandleChallengeMessage: Local Call.\n"));
  1487. //
  1488. // Require the new challenge message if we are going to access the
  1489. // server context handle
  1490. //
  1491. if ( InputTokenSize < sizeof(CHALLENGE_MESSAGE) ) {
  1492. SecStatus = SEC_E_INVALID_TOKEN;
  1493. SspPrint(( SSP_CRITICAL,
  1494. "SsprHandleChallengeMessage: invalid InputTokenSize.\n"));
  1495. goto Cleanup;
  1496. }
  1497. //
  1498. // Open the server's context here within this process.
  1499. //
  1500. ServerContextHandle = (ULONG_PTR)(ChallengeMessage->ServerContextHandle);
  1501. SspContextReferenceContext(
  1502. ServerContextHandle,
  1503. FALSE,
  1504. &ServerContext
  1505. );
  1506. if ( ServerContext == NULL )
  1507. {
  1508. //
  1509. // This means the server has lied about this being a local call or
  1510. // the server process has exitted.
  1511. // this can happen if the client and server have not had netbios
  1512. // machine names set, so, allow this and continue processing
  1513. // as if this were not loopback.
  1514. //
  1515. SspPrint(( SSP_WARNING,
  1516. "SsprHandleChallengeMessage: "
  1517. "ChallengeMessage bad ServerContextHandle 0x%p\n",
  1518. ChallengeMessage->ServerContextHandle));
  1519. ChallengeMessage->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_LOCAL_CALL;
  1520. break;
  1521. }
  1522. if (((ServerContext->NegotiateFlags & NTLMSSP_NEGOTIATE_LOCAL_CALL) == 0) ||
  1523. (ServerContext->State != ChallengeSentState)
  1524. )
  1525. {
  1526. SspPrint(( SSP_WARNING,
  1527. "SsprHandleChallengeMessage: "
  1528. "ChallengeMessage claimed ServerContextHandle in bad state 0x%p\n",
  1529. ChallengeMessage->ServerContextHandle));
  1530. ChallengeMessage->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_LOCAL_CALL;
  1531. break;
  1532. }
  1533. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_LOCAL_CALL;
  1534. //
  1535. // Local loopback for network servcice
  1536. //
  1537. if ( (Context->Credential->MutableCredFlags & SSP_CREDENTIAL_FLAG_WAS_NETWORK_SERVICE) )
  1538. {
  1539. SspPrint((SSP_WARNING, "SsprHandleChallengeMessage using networkservice in local loopback\n"));
  1540. ClientLogonId = &LogonIdNetworkService;
  1541. }
  1542. //
  1543. // open the token associated with the caller at the time of the
  1544. // AcquireCredentialsHandle() call.
  1545. //
  1546. SecStatus = LsaFunctions->OpenTokenByLogonId(
  1547. ClientLogonId,
  1548. &ClientTokenHandle
  1549. );
  1550. if (!NT_SUCCESS(SecStatus))
  1551. {
  1552. SspPrint(( SSP_CRITICAL,
  1553. "SsprHandleChallengeMessage: "
  1554. "Could not open client token 0x%lx\n",
  1555. SecStatus ));
  1556. goto Cleanup;
  1557. }
  1558. if ( ImpersonationLevel < SecurityImpersonation )
  1559. {
  1560. SspPrint(( SSP_WARNING, "Reducing impersonation level %lu to %lu\n",
  1561. SecurityImpersonation, ImpersonationLevel));
  1562. }
  1563. if ((Context->NegotiateFlags & NTLMSSP_NEGOTIATE_IDENTIFY) != 0) {
  1564. ImpersonationLevel = min(SecurityIdentification, ImpersonationLevel);
  1565. }
  1566. SecStatus = SspDuplicateToken(
  1567. ClientTokenHandle,
  1568. ImpersonationLevel,
  1569. &ServerContext->TokenHandle
  1570. );
  1571. if (!NT_SUCCESS(SecStatus)) {
  1572. SspPrint(( SSP_CRITICAL,
  1573. "SsprHandleChallengeMessage: "
  1574. "Could not duplicate client token 0x%lx\n",
  1575. SecStatus ));
  1576. goto Cleanup;
  1577. }
  1578. //
  1579. // enable all privileges in the duplicated token, to be consistent
  1580. // with what a network logon normally looks like
  1581. // (all privileges held are enabled by default).
  1582. //
  1583. if (!SspEnableAllPrivilegesToken(ServerContext->TokenHandle))
  1584. {
  1585. SspPrint(( SSP_CRITICAL,
  1586. "SsprHandleChallengeMessage: "
  1587. "Could not enable all privileges for loopback.\n"));
  1588. }
  1589. //
  1590. // give local call a hard-coded session key so calls into RDR
  1591. // to fetch a session key succeed (eg: RtlGetUserSessionKeyClient)
  1592. //
  1593. RtlCopyMemory(Context->SessionKey, FixedSessionKey, MSV1_0_USER_SESSION_KEY_LENGTH);
  1594. //
  1595. // Don't pass any credentials in the authenticate message.
  1596. //
  1597. RtlInitString( &DomainName, NULL );
  1598. RtlInitString( &UserName, NULL );
  1599. RtlInitString( &Workstation, NULL );
  1600. RtlInitString( &NtChallengeResponse, NULL );
  1601. RtlInitString( &LmChallengeResponse, NULL );
  1602. RtlInitString( &DatagramSessionKey, NULL );
  1603. break;
  1604. }
  1605. //
  1606. // If the server is running on a diffent machine,
  1607. // determine the caller's DomainName, UserName and ChallengeResponse
  1608. // to pass back in the AuthenicateMessage.
  1609. //
  1610. if ( (ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_LOCAL_CALL) == 0 )
  1611. {
  1612. //
  1613. // Build the GetChallengeResponse message to pass to the LSA.
  1614. //
  1615. PCHAR MarshalPtr; // marshalling pointer
  1616. ULONG MarshalBytes;
  1617. UNICODE_STRING TargetInfo;
  1618. CREDENTIAL_TARGET_INFORMATIONW CredTargetInfo;
  1619. //
  1620. // insure all fields NULL.
  1621. //
  1622. ZeroMemory( &CredTargetInfo, sizeof(CredTargetInfo) );
  1623. ZeroMemory( GetChallengeResponse, sizeof(*GetChallengeResponse) );
  1624. GetChallengeResponseSize = sizeof(*GetChallengeResponse);
  1625. GetChallengeResponse->MessageType = MsV1_0Lm20GetChallengeResponse;
  1626. GetChallengeResponse->ParameterControl = 0;
  1627. if ( Context->Credential )
  1628. {
  1629. PUNICODE_STRING TmpDomainName = &(Context->Credential->DomainName);
  1630. PUNICODE_STRING TmpUserName = &(Context->Credential->UserName);
  1631. PUNICODE_STRING TmpPassword = &(Context->Credential->Password);
  1632. if ( (TmpDomainName->Buffer != NULL) ||
  1633. (TmpUserName->Buffer != NULL) ||
  1634. (TmpPassword->Buffer != NULL)
  1635. )
  1636. {
  1637. UseSuppliedCreds = TRUE;
  1638. }
  1639. }
  1640. //
  1641. // if caller specifically asked for non nt session key, give it to them
  1642. //
  1643. if ( (ChallengeMessage->NegotiateFlags & NTLMSSP_REQUEST_NON_NT_SESSION_KEY ) ||
  1644. (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY))
  1645. {
  1646. GetChallengeResponse->ParameterControl |= RETURN_NON_NT_USER_SESSION_KEY;
  1647. }
  1648. GetChallengeResponse->ParameterControl |= GCR_NTLM3_PARMS;
  1649. //
  1650. // if TargetInfo present, use it, otherwise construct it from target name
  1651. //
  1652. if (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
  1653. {
  1654. if ( InputTokenSize < RTL_SIZEOF_THROUGH_FIELD(CHALLENGE_MESSAGE, TargetInfo) ) {
  1655. SspPrint(( SSP_CRITICAL,
  1656. "SspHandleChallengeMessage: "
  1657. "ChallengeMessage size wrong when target info flag on %ld\n",
  1658. InputTokenSize ));
  1659. SecStatus = SEC_E_INVALID_TOKEN;
  1660. goto Cleanup;
  1661. }
  1662. //
  1663. // validate and relocate the target info
  1664. //
  1665. if (!SspConvertRelativeToAbsolute (
  1666. ChallengeMessage,
  1667. InputTokenSize,
  1668. &ChallengeMessage->TargetInfo,
  1669. (PSTRING)&TargetInfo,
  1670. DoUnicode,
  1671. TRUE // NULL target info OK
  1672. ))
  1673. {
  1674. SspPrint(( SSP_CRITICAL,
  1675. "SspHandleChallengeMessage: "
  1676. "ChallengeMessage.TargetInfo size wrong %ld\n",
  1677. InputTokenSize ));
  1678. SecStatus = SEC_E_INVALID_TOKEN;
  1679. goto Cleanup;
  1680. }
  1681. //
  1682. // Calculate mashal data size for the target info case
  1683. //
  1684. if ( UseSuppliedCreds )
  1685. {
  1686. MarshalBytes =
  1687. TargetInfo.Length +
  1688. Context->DomainName.Length +
  1689. Context->UserName.Length +
  1690. Context->Password.Length +
  1691. (4*sizeof(WCHAR));
  1692. } else {
  1693. MarshalBytes =
  1694. TargetInfo.Length +
  1695. (DNLEN * sizeof(WCHAR)) +
  1696. (UNLEN * sizeof(WCHAR)) +
  1697. (PWLEN * sizeof(WCHAR)) +
  1698. (4*sizeof(WCHAR));
  1699. }
  1700. //
  1701. // Sets a "reasonable" upper limit on the token size
  1702. // to avoid unbounded stack allocations. The limit is
  1703. // NTLMSSP_MAX_MESSAGE_SIZE*4 for historical reasons.
  1704. //
  1705. if ((NTLMSSP_MAX_MESSAGE_SIZE*4)<MarshalBytes){
  1706. SspPrint(( SSP_CRITICAL,
  1707. "SspHandleChallengeMessage: "
  1708. "ChallengeMessage.TargetInfo size wrong %ld\n",
  1709. InputTokenSize ));
  1710. SecStatus = SEC_E_INVALID_TOKEN;
  1711. goto Cleanup;
  1712. }
  1713. //
  1714. // Allocate buffer for GetChallengeResponse + marshalled data
  1715. //
  1716. SafeAllocaAllocate(GetChallengeResponse, MarshalBytes +
  1717. sizeof(*GetChallengeResponse));
  1718. if (!GetChallengeResponse){
  1719. SecStatus = STATUS_NO_MEMORY;
  1720. goto Cleanup;
  1721. }
  1722. //
  1723. // Copy in the MSV1_0_GETCHALLENRESP_REQUEST structure so far
  1724. //
  1725. *GetChallengeResponse = TempChallengeResponse;
  1726. MarshalPtr = (PCHAR)(GetChallengeResponse+1);
  1727. // TargetInfo now contains the server's netbios domain name
  1728. //
  1729. // MSV needs the server name to be 'in' the passed in buffer.
  1730. //
  1731. SspContextCopyStringAbsolute(
  1732. GetChallengeResponse,
  1733. (PSTRING)&GetChallengeResponse->ServerName,
  1734. (PSTRING)&TargetInfo,
  1735. &MarshalPtr
  1736. );
  1737. GetChallengeResponseSize += GetChallengeResponse->ServerName.Length;
  1738. //
  1739. // tell GCR that its an AV list.
  1740. //
  1741. GetChallengeResponse->ParameterControl |= GCR_TARGET_INFO;
  1742. // get various target names
  1743. if ( !UseSuppliedCreds )
  1744. {
  1745. ULONG AvFlags = 0;
  1746. //
  1747. // Uplevel -- get the info from the comprehensive TARGET_INFO
  1748. //
  1749. //
  1750. Status = MsvpAvlToString(
  1751. &TargetInfo,
  1752. MsvAvNbDomainName,
  1753. &szCredTargetDomain
  1754. );
  1755. if (!NT_SUCCESS(Status))
  1756. {
  1757. SecStatus = SspNtStatusToSecStatus( Status,
  1758. SEC_E_INSUFFICIENT_MEMORY );
  1759. goto Cleanup;
  1760. }
  1761. Status = MsvpAvlToString(
  1762. &TargetInfo,
  1763. MsvAvNbComputerName,
  1764. &szCredTargetServer
  1765. );
  1766. if (!NT_SUCCESS(Status))
  1767. {
  1768. SecStatus = SspNtStatusToSecStatus( Status,
  1769. SEC_E_INSUFFICIENT_MEMORY );
  1770. goto Cleanup;
  1771. }
  1772. Status = MsvpAvlToString(
  1773. &TargetInfo,
  1774. MsvAvDnsDomainName,
  1775. &szCredTargetDnsDomain
  1776. );
  1777. if (!NT_SUCCESS(Status))
  1778. {
  1779. SecStatus = SspNtStatusToSecStatus( Status,
  1780. SEC_E_INSUFFICIENT_MEMORY );
  1781. goto Cleanup;
  1782. }
  1783. Status = MsvpAvlToString(
  1784. &TargetInfo,
  1785. MsvAvDnsComputerName,
  1786. &szCredTargetDnsServer
  1787. );
  1788. if (!NT_SUCCESS(Status))
  1789. {
  1790. SecStatus = SspNtStatusToSecStatus( Status,
  1791. SEC_E_INSUFFICIENT_MEMORY );
  1792. goto Cleanup;
  1793. }
  1794. Status = MsvpAvlToString(
  1795. &TargetInfo,
  1796. MsvAvDnsTreeName,
  1797. &szCredTargetDnsTree
  1798. );
  1799. if (!NT_SUCCESS(Status))
  1800. {
  1801. SecStatus = SspNtStatusToSecStatus( Status,
  1802. SEC_E_INSUFFICIENT_MEMORY );
  1803. goto Cleanup;
  1804. }
  1805. if ( TargetServerName && TargetServerName->Length )
  1806. {
  1807. //
  1808. // check TargetServerName against szTargetServer. If they don't match, we have a DFS share.
  1809. // Add Pre-DFS ServerName
  1810. //
  1811. LPWSTR szTargetServerName = TargetServerName->Buffer;
  1812. DWORD cchTarget = TargetServerName->Length / sizeof(WCHAR);
  1813. DWORD IndexSlash;
  1814. for (IndexSlash = 0 ; IndexSlash < cchTarget; IndexSlash++)
  1815. {
  1816. if (TargetServerName->Buffer[IndexSlash] == L'/')
  1817. {
  1818. cchTarget -= IndexSlash;
  1819. szTargetServerName = &TargetServerName->Buffer[ IndexSlash+1 ];
  1820. break;
  1821. }
  1822. }
  1823. szCredTargetPreDFSServer = (LPWSTR)NtLmAllocatePrivateHeap( (cchTarget+1) * sizeof(WCHAR) );
  1824. if ( szCredTargetPreDFSServer == NULL )
  1825. {
  1826. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1827. goto Cleanup;
  1828. }
  1829. CopyMemory( szCredTargetPreDFSServer, szTargetServerName, cchTarget*sizeof(WCHAR) );
  1830. szCredTargetPreDFSServer[ cchTarget ] = L'\0';
  1831. CredTargetInfo.TargetName = szCredTargetPreDFSServer;
  1832. }
  1833. //
  1834. // see if server enabled the funky guest bit (tm)
  1835. //
  1836. Status = MsvpAvlToFlag(
  1837. &TargetInfo,
  1838. MsvAvFlags,
  1839. &AvFlags
  1840. );
  1841. if ( Status == STATUS_SUCCESS )
  1842. {
  1843. if ( AvFlags & MSV1_0_AV_FLAG_FORCE_GUEST )
  1844. {
  1845. CredTargetInfo.Flags |= CRED_TI_ONLY_PASSWORD_REQUIRED;
  1846. }
  1847. }
  1848. }
  1849. } else {
  1850. BOOLEAN DefectiveTarget = FALSE;
  1851. // downlevel - first call may have been handled by redir
  1852. //
  1853. // validate and relocate the target name
  1854. //
  1855. if (!SspConvertRelativeToAbsolute (
  1856. ChallengeMessage,
  1857. InputTokenSize,
  1858. &ChallengeMessage->TargetName,
  1859. (PSTRING)&TargetName,
  1860. DoUnicode,
  1861. TRUE // NULL targetname OK
  1862. ))
  1863. {
  1864. SspPrint(( SSP_CRITICAL,
  1865. "SspHandleChallengeMessage: "
  1866. "ChallengeMessage.TargetName size wrong %ld\n",
  1867. InputTokenSize ));
  1868. SecStatus = SEC_E_INVALID_TOKEN;
  1869. goto Cleanup;
  1870. }
  1871. //
  1872. // certain flavors of Unix servers set UNICODE and OEM flags,
  1873. // but supply an OEM buffer. Try to resolve that here.
  1874. //
  1875. if ( (DoUnicode) &&
  1876. (ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_OEM)
  1877. )
  1878. {
  1879. if ( IsTextUnicode( TargetName.Buffer, TargetName.Length, NULL ) == 0 )
  1880. {
  1881. DefectiveTarget = TRUE;
  1882. }
  1883. }
  1884. //
  1885. // convert TargetName to Unicode if needed
  1886. //
  1887. if ( !DoUnicode || DefectiveTarget )
  1888. {
  1889. UNICODE_STRING TempString;
  1890. Status = RtlOemStringToUnicodeString(
  1891. &TempString,
  1892. (PSTRING)&TargetName,
  1893. TRUE);
  1894. if ( !NT_SUCCESS(Status) ) {
  1895. SecStatus = SspNtStatusToSecStatus( Status,
  1896. SEC_E_INSUFFICIENT_MEMORY );
  1897. goto Cleanup;
  1898. }
  1899. TargetName = TempString;
  1900. if ( DefectiveTarget )
  1901. {
  1902. //
  1903. // save it so we can free it later.
  1904. //
  1905. DefectiveTargetName = TargetName;
  1906. }
  1907. }
  1908. if ( !UseSuppliedCreds )
  1909. {
  1910. // ChallengeMessage->TargetName will be the server's netbios domain name
  1911. if ( TargetName.Buffer && TargetName.Length )
  1912. {
  1913. LPWSTR szTmpTargetName;
  1914. szTmpTargetName = (PWSTR)NtLmAllocatePrivateHeap( TargetName.Length + sizeof(WCHAR) );
  1915. if ( szTmpTargetName == NULL )
  1916. {
  1917. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1918. goto Cleanup;
  1919. }
  1920. RtlCopyMemory( szTmpTargetName, TargetName.Buffer, TargetName.Length );
  1921. szTmpTargetName[ TargetName.Length/sizeof(WCHAR) ] = L'\0';
  1922. if ( ChallengeMessage->NegotiateFlags & NTLMSSP_TARGET_TYPE_SERVER )
  1923. {
  1924. szCredTargetServer = szTmpTargetName;
  1925. } else if ( ChallengeMessage->NegotiateFlags & NTLMSSP_TARGET_TYPE_DOMAIN )
  1926. {
  1927. szCredTargetDomain = szTmpTargetName;
  1928. }
  1929. // TODO: what if TARGET_TYPE not specified, or TARGET_TYPE_SHARE ?
  1930. }
  1931. if ( TargetServerName && TargetServerName->Length )
  1932. {
  1933. //
  1934. // check TargetServerName against szTargetServer. If they don't match, we have a DFS share.
  1935. // Add Pre-DFS ServerName
  1936. //
  1937. LPWSTR szTargetServerName = TargetServerName->Buffer;
  1938. DWORD cchTarget = TargetServerName->Length / sizeof(WCHAR);
  1939. DWORD IndexSlash;
  1940. for (IndexSlash = 0 ; IndexSlash < cchTarget; IndexSlash++)
  1941. {
  1942. if (TargetServerName->Buffer[IndexSlash] == L'/')
  1943. {
  1944. cchTarget -= IndexSlash;
  1945. szTargetServerName = &TargetServerName->Buffer[ IndexSlash+1 ];
  1946. break;
  1947. }
  1948. }
  1949. szCredTargetPreDFSServer = (LPWSTR)NtLmAllocatePrivateHeap( (cchTarget+1) * sizeof(WCHAR) );
  1950. if ( szCredTargetPreDFSServer == NULL )
  1951. {
  1952. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1953. goto Cleanup;
  1954. }
  1955. CopyMemory( szCredTargetPreDFSServer, szTargetServerName, cchTarget*sizeof(WCHAR) );
  1956. szCredTargetPreDFSServer[ cchTarget ] = L'\0';
  1957. CredTargetInfo.TargetName = szCredTargetPreDFSServer;
  1958. }
  1959. if ( fShareLevel )
  1960. {
  1961. CredTargetInfo.Flags |= CRED_TI_ONLY_PASSWORD_REQUIRED;
  1962. }
  1963. }
  1964. //
  1965. // Calculate mashal data size for the target name case
  1966. //
  1967. if ( UseSuppliedCreds )
  1968. {
  1969. MarshalBytes =
  1970. TargetName.Length +
  1971. Context->DomainName.Length +
  1972. Context->UserName.Length +
  1973. Context->Password.Length +
  1974. (4*sizeof(WCHAR));
  1975. } else {
  1976. MarshalBytes =
  1977. TargetName.Length +
  1978. (DNLEN * sizeof(WCHAR)) +
  1979. (UNLEN * sizeof(WCHAR)) +
  1980. (PWLEN * sizeof(WCHAR)) +
  1981. (4*sizeof(WCHAR));
  1982. }
  1983. //
  1984. // Set a "reasonable" upper limit on the token size
  1985. // to avoid unbounded stack allocations. The limit is
  1986. // NTLMSSP_MAX_MESSAGE_SIZE*4 for historical reasons.
  1987. //
  1988. if ((NTLMSSP_MAX_MESSAGE_SIZE*4)<MarshalBytes){
  1989. SspPrint(( SSP_CRITICAL,
  1990. "SspHandleChallengeMessage: "
  1991. "ChallengeMessage size wrong \n"));
  1992. SecStatus = SEC_E_INVALID_TOKEN;
  1993. goto Cleanup;
  1994. }
  1995. //
  1996. // Allocate buffer for GetChallengeResponse + marshalled data
  1997. //
  1998. SafeAllocaAllocate(GetChallengeResponse, MarshalBytes +
  1999. sizeof(*GetChallengeResponse));
  2000. if (!GetChallengeResponse){
  2001. SecStatus = STATUS_NO_MEMORY;
  2002. goto Cleanup;
  2003. }
  2004. //
  2005. // Copy in the MSV1_0_GETCHALLENRESP_REQUEST structure so far
  2006. //
  2007. *GetChallengeResponse = TempChallengeResponse;
  2008. MarshalPtr = (PCHAR)(GetChallengeResponse+1);
  2009. //
  2010. // MSV needs the server name to be 'in' the passed in buffer.
  2011. //
  2012. SspContextCopyStringAbsolute(
  2013. GetChallengeResponse,
  2014. (PSTRING)&GetChallengeResponse->ServerName,
  2015. (PSTRING)&TargetName,
  2016. &MarshalPtr
  2017. );
  2018. GetChallengeResponseSize += GetChallengeResponse->ServerName.Length;
  2019. }
  2020. if ( !UseSuppliedCreds )
  2021. {
  2022. ULONG CredTypes[] = {CRED_TYPE_DOMAIN_PASSWORD};
  2023. BOOLEAN bIsOwfPassword = FALSE;
  2024. SECPKG_CALL_INFO CallInfo = {0};
  2025. CredTargetInfo.NetbiosDomainName = szCredTargetDomain;
  2026. CredTargetInfo.NetbiosServerName = szCredTargetServer;
  2027. CredTargetInfo.DnsDomainName = szCredTargetDnsDomain;
  2028. CredTargetInfo.DnsServerName = szCredTargetDnsServer;
  2029. CredTargetInfo.DnsTreeName = szCredTargetDnsTree;
  2030. CredTargetInfo.PackageName = NTLMSP_NAME;
  2031. CredTargetInfo.CredTypeCount = COUNTOF(CredTypes);
  2032. CredTargetInfo.CredTypes = CredTypes;
  2033. //
  2034. // if marshalled TargetInfo was supplied, we prefer those fields.
  2035. //
  2036. if ( Context->TargetInfo )
  2037. {
  2038. CredTargetInfo.TargetName = Context->TargetInfo->TargetName;
  2039. CredTargetInfo.NetbiosServerName = Context->TargetInfo->NetbiosServerName;
  2040. CredTargetInfo.DnsServerName = Context->TargetInfo->DnsServerName;
  2041. CredTargetInfo.NetbiosDomainName = Context->TargetInfo->NetbiosDomainName;
  2042. CredTargetInfo.DnsDomainName = Context->TargetInfo->DnsDomainName;
  2043. CredTargetInfo.DnsTreeName = Context->TargetInfo->DnsTreeName;
  2044. CredTargetInfo.Flags |= Context->TargetInfo->Flags;
  2045. }
  2046. SecStatus = CopyCredManCredentials (
  2047. ClientLogonId,
  2048. &CredTargetInfo,
  2049. Context,
  2050. fShareLevel,
  2051. TRUE, // allow OWF passwords
  2052. &bIsOwfPassword
  2053. );
  2054. if ( NT_SUCCESS(SecStatus) )
  2055. {
  2056. fCredmanCredentials = TRUE;
  2057. if (bIsOwfPassword)
  2058. {
  2059. GetChallengeResponse->ParameterControl |= GCR_USE_OWF_PASSWORD;
  2060. }
  2061. }
  2062. if ( SecStatus == STATUS_NOT_FOUND )
  2063. {
  2064. SecStatus = STATUS_SUCCESS;
  2065. }
  2066. if ( !NT_SUCCESS(SecStatus) )
  2067. {
  2068. goto Cleanup;
  2069. }
  2070. //
  2071. // stow away a copy of the marshalled target info.
  2072. //
  2073. if (!LsaFunctions->GetCallInfo(&CallInfo))
  2074. {
  2075. SecStatus = STATUS_INTERNAL_ERROR;
  2076. goto Cleanup;
  2077. }
  2078. if ( fCredmanCredentials || (CallInfo.Attributes & SECPKG_CALL_KERNEL_MODE) )
  2079. {
  2080. CredMarshalTargetInfo(
  2081. &CredTargetInfo,
  2082. (PUSHORT*)&(Context->pbMarshalledTargetInfo),
  2083. &Context->cbMarshalledTargetInfo
  2084. );
  2085. }
  2086. } else {
  2087. //
  2088. // if an explicit cred was supplied, check if it was a marshalled
  2089. // cred, and if so, reject smartcard attempts.
  2090. //
  2091. if ( Context->UserName.Length != 0 &&
  2092. Context->DomainName.Length == 0
  2093. // Password may or may not contain a PIN for cert case.
  2094. )
  2095. {
  2096. UNICODE_STRING UnpickledUserName;
  2097. UNICODE_STRING UnpickledDomainName;
  2098. UNICODE_STRING UnpickledPassword;
  2099. Status = CredpProcessUserNameCredential(
  2100. &Context->UserName,
  2101. &UnpickledUserName,
  2102. &UnpickledDomainName,
  2103. &UnpickledPassword
  2104. );
  2105. if ( NT_SUCCESS(Status) )
  2106. {
  2107. NtLmFreePrivateHeap( UnpickledUserName.Buffer );
  2108. NtLmFreePrivateHeap( UnpickledDomainName.Buffer );
  2109. NtLmFreePrivateHeap( UnpickledPassword.Buffer );
  2110. }
  2111. else if ( Status == STATUS_NOT_SUPPORTED )
  2112. {
  2113. goto Cleanup;
  2114. }
  2115. Status = STATUS_SUCCESS;
  2116. }
  2117. }
  2118. SspContextCopyStringAbsolute(
  2119. GetChallengeResponse,
  2120. (PSTRING)&GetChallengeResponse->LogonDomainName,
  2121. (PSTRING)&Context->DomainName,
  2122. &MarshalPtr
  2123. );
  2124. GetChallengeResponseSize += GetChallengeResponse->LogonDomainName.Length;
  2125. SspContextCopyStringAbsolute(
  2126. GetChallengeResponse,
  2127. (PSTRING)&GetChallengeResponse->UserName,
  2128. (PSTRING)&Context->UserName,
  2129. &MarshalPtr
  2130. );
  2131. GetChallengeResponseSize += GetChallengeResponse->UserName.Length;
  2132. //
  2133. // Check for null session. This is the case if the caller supplies
  2134. // an empty username, domainname, and password.
  2135. //
  2136. //
  2137. // duplicate the hidden password string, then reveal it into
  2138. // new buffer. This avoids thread race conditions during hide/reveal
  2139. // and also allows us to avoid re-hiding the material.
  2140. // TODO: add flag that indicates to LSA that provided password is encrypted.
  2141. //
  2142. SecStatus = NtLmDuplicatePassword( &RevealedPassword, &Context->Password );
  2143. if (!NT_SUCCESS( SecStatus ) ) {
  2144. SspPrint(( SSP_CRITICAL,
  2145. "SsprHandleChallengeMessage: NtLmDuplicatePassword returned %d\n",Status));
  2146. goto Cleanup;
  2147. }
  2148. SspRevealPassword(&RevealedPassword);
  2149. if (((Context->ContextFlags & ISC_RET_NULL_SESSION) != 0) ||
  2150. (((Context->DomainName.Length == 0) && (Context->DomainName.Buffer != NULL)) &&
  2151. ((Context->UserName.Length == 0) && (Context->UserName.Buffer != NULL)) &&
  2152. ((Context->Password.Length == 0) && (Context->Password.Buffer != NULL)))) {
  2153. SspPrint(( SSP_WARNING, "SsprHandleChallengeMessage: null session context\n" ));
  2154. GetChallengeResponse->ParameterControl |= NULL_SESSION_REQUESTED |
  2155. USE_PRIMARY_PASSWORD;
  2156. } else {
  2157. //
  2158. // We aren't doing a null session intentionally. MSV may choose
  2159. // to do a null session if we have no credentials available.
  2160. //
  2161. if ( Context->DomainName.Buffer == NULL )
  2162. {
  2163. BOOLEAN FoundAt = FALSE;
  2164. //
  2165. // if it's a UPN, don't fill in the domain field.
  2166. //
  2167. if ( Context->UserName.Buffer != NULL )
  2168. {
  2169. ULONG i;
  2170. for (i = 0 ; i < (Context->UserName.Length / sizeof(WCHAR)) ; i++)
  2171. {
  2172. if ( Context->UserName.Buffer[i] == '@' )
  2173. {
  2174. FoundAt = TRUE;
  2175. break;
  2176. }
  2177. }
  2178. }
  2179. if ( !FoundAt )
  2180. {
  2181. GetChallengeResponse->ParameterControl |=
  2182. RETURN_PRIMARY_LOGON_DOMAINNAME;
  2183. }
  2184. }
  2185. if ( Context->UserName.Buffer == NULL )
  2186. {
  2187. GetChallengeResponse->ParameterControl |= RETURN_PRIMARY_USERNAME;
  2188. }
  2189. //
  2190. // The password may be a zero length password
  2191. //
  2192. GetChallengeResponse->Password = RevealedPassword;
  2193. if ( Context->Password.Buffer == NULL ) {
  2194. GetChallengeResponse->ParameterControl |= USE_PRIMARY_PASSWORD;
  2195. } else {
  2196. //
  2197. // MSV needs the password to be 'in' the passed in buffer.
  2198. //
  2199. RtlCopyMemory(MarshalPtr,
  2200. GetChallengeResponse->Password.Buffer,
  2201. GetChallengeResponse->Password.Length);
  2202. GetChallengeResponse->Password.Buffer =
  2203. (LPWSTR)(MarshalPtr);
  2204. GetChallengeResponseSize += GetChallengeResponse->Password.Length +
  2205. sizeof(WCHAR);
  2206. }
  2207. }
  2208. //
  2209. // scrub the cleartext password now to avoid pagefile exposure
  2210. // during lengthy processing.
  2211. //
  2212. if ( RevealedPassword.Buffer != NULL ) {
  2213. ZeroMemory( RevealedPassword.Buffer, RevealedPassword.Length );
  2214. NtLmFreePrivateHeap( RevealedPassword.Buffer );
  2215. RevealedPassword.Buffer = NULL;
  2216. }
  2217. GetChallengeResponse->LogonId = *ClientLogonId;
  2218. RtlCopyMemory( &GetChallengeResponse->ChallengeToClient,
  2219. ChallengeMessage->Challenge,
  2220. MSV1_0_CHALLENGE_LENGTH );
  2221. //
  2222. // if NTLM2 negotiated, then ask MSV1_0 to mix my challenge with the server's...
  2223. //
  2224. if (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)
  2225. {
  2226. GetChallengeResponse->ParameterControl |= GENERATE_CLIENT_CHALLENGE;
  2227. } else {
  2228. //
  2229. // if it's share level, and:
  2230. // 1. User only supplied a password, or
  2231. // 2. Credman returned the creds
  2232. // allow downgrade to NTLMv1 from NTLMv2.
  2233. //
  2234. if ( fShareLevel )
  2235. {
  2236. if ( (GetChallengeResponse->UserName.Length == 0) &&
  2237. (GetChallengeResponse->LogonDomainName.Length == 0) &&
  2238. (GetChallengeResponse->Password.Buffer != NULL)
  2239. )
  2240. {
  2241. GetChallengeResponse->ParameterControl |= GCR_ALLOW_NTLM;
  2242. }
  2243. if ( fCredmanCredentials )
  2244. {
  2245. GetChallengeResponse->ParameterControl |= GCR_ALLOW_NTLM;
  2246. }
  2247. }
  2248. //
  2249. // DataGram can not negotiate if it is non NTLM2, allow to use LM key
  2250. //
  2251. if (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM)
  2252. {
  2253. //
  2254. // handle smart servers that know to use NtUserSessionKey
  2255. //
  2256. if (Context->ServerVersion.Revision >= NTLMSSP_REVISION_W2K3 && NtLmGlobalLmProtocolSupported >= NoLm)
  2257. {
  2258. SspPrint((SSP_WARNING, "SsprHandleChallengeMessage turning off LM keys\n"));
  2259. GetChallengeResponse->ParameterControl &= ~RETURN_NON_NT_USER_SESSION_KEY;
  2260. Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_LM_KEY; // tell the server we turn off LM key
  2261. }
  2262. else // let it through, this might fail if NoLmHash is stored in SAM
  2263. {
  2264. GetChallengeResponse->ParameterControl |= GCR_ALLOW_LM;
  2265. }
  2266. }
  2267. }
  2268. if (!DoUnicode) {
  2269. GetChallengeResponse->ParameterControl |= GCR_USE_OEM_SET;
  2270. }
  2271. //
  2272. // Get the DomainName, UserName, and ChallengeResponse from the MSV
  2273. //
  2274. Status = LsaApCallPackage(
  2275. (PLSA_CLIENT_REQUEST)(-1),
  2276. GetChallengeResponse,
  2277. GetChallengeResponse,
  2278. GetChallengeResponseSize,
  2279. (PVOID *)&ChallengeResponseMessage,
  2280. &ChallengeResponseSize,
  2281. &ProtocolStatus );
  2282. if ( !NT_SUCCESS(Status) ) {
  2283. SspPrint(( SSP_CRITICAL,
  2284. "SsprHandleChallengeMessage: "
  2285. "ChallengeMessage LsaCall to get ChallengeResponse returns 0x%lx\n",
  2286. Status ));
  2287. SecStatus = SspNtStatusToSecStatus( Status, SEC_E_NO_CREDENTIALS);
  2288. goto Cleanup;
  2289. }
  2290. if ( !NT_SUCCESS(ProtocolStatus) ) {
  2291. Status = ProtocolStatus;
  2292. SspPrint(( SSP_CRITICAL,
  2293. "SsprHandleChallengeMessage: ChallengeMessage LsaCall "
  2294. "to get ChallengeResponse returns ProtocolStatus 0x%lx\n",
  2295. Status ));
  2296. SecStatus = SspNtStatusToSecStatus( Status, SEC_E_NO_CREDENTIALS);
  2297. goto Cleanup;
  2298. }
  2299. //
  2300. // Check to see if we are doing a null session
  2301. //
  2302. if ((ChallengeResponseMessage->CaseSensitiveChallengeResponse.Length == 0) &&
  2303. (ChallengeResponseMessage->CaseInsensitiveChallengeResponse.Length == 1)) {
  2304. SspPrint(( SSP_WARNING, "SsprHandleChallengeMessage: null session\n" ));
  2305. *ContextAttributes |= ISC_RET_NULL_SESSION;
  2306. Context->ContextFlags |= ISC_RET_NULL_SESSION;
  2307. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
  2308. } else {
  2309. //
  2310. // Normalize things by copying the default domain name and user name
  2311. // into the ChallengeResponseMessage structure.
  2312. //
  2313. if ( Context->DomainName.Buffer != NULL ) {
  2314. ChallengeResponseMessage->LogonDomainName = Context->DomainName;
  2315. }
  2316. if ( Context->UserName.Buffer != NULL ) {
  2317. ChallengeResponseMessage->UserName = Context->UserName;
  2318. }
  2319. }
  2320. //
  2321. // Convert the domainname/user name to the right character set.
  2322. //
  2323. if ( DoUnicode ) {
  2324. DomainName = *(PSTRING)&ChallengeResponseMessage->LogonDomainName;
  2325. UserName = *(PSTRING)&ChallengeResponseMessage->UserName;
  2326. Workstation = *(PSTRING)&NtLmGlobalUnicodeComputerNameString;
  2327. } else {
  2328. Status = RtlUpcaseUnicodeStringToOemString(
  2329. &DomainName,
  2330. &ChallengeResponseMessage->LogonDomainName,
  2331. TRUE);
  2332. if ( !NT_SUCCESS(Status) ) {
  2333. SspPrint(( SSP_CRITICAL,
  2334. "SsprHandleChallengeMessage: RtlUpcaseUnicodeToOemString (DomainName) returned 0x%lx.\n", Status));
  2335. SecStatus = SspNtStatusToSecStatus( Status,
  2336. SEC_E_INSUFFICIENT_MEMORY);
  2337. goto Cleanup;
  2338. }
  2339. Status = RtlUpcaseUnicodeStringToOemString(
  2340. &UserName,
  2341. &ChallengeResponseMessage->UserName,
  2342. TRUE);
  2343. if ( !NT_SUCCESS(Status) ) {
  2344. SspPrint(( SSP_CRITICAL,
  2345. "SsprHandleChallengeMessage: RtlUpcaseUnicodeToOemString (UserName) returned 0x%lx.\n", Status));
  2346. SecStatus = SspNtStatusToSecStatus( Status,
  2347. SEC_E_INSUFFICIENT_MEMORY);
  2348. goto Cleanup;
  2349. }
  2350. Workstation = NtLmGlobalOemComputerNameString;
  2351. }
  2352. //
  2353. // Save the ChallengeResponses
  2354. //
  2355. LmChallengeResponse =
  2356. ChallengeResponseMessage->CaseInsensitiveChallengeResponse;
  2357. NtChallengeResponse =
  2358. ChallengeResponseMessage->CaseSensitiveChallengeResponse;
  2359. //
  2360. // prepare to send encrypted randomly generated session key
  2361. //
  2362. DatagramSessionKey.Buffer = (CHAR*)DatagramKey;
  2363. DatagramSessionKey.Length =
  2364. DatagramSessionKey.MaximumLength = 0;
  2365. //
  2366. // Generate the session key, or encrypt the previosly generated random one,
  2367. // from various bits of info. Fill in session key if needed.
  2368. //
  2369. SecStatus = SsprMakeSessionKey(
  2370. Context,
  2371. &LmChallengeResponse,
  2372. ChallengeResponseMessage->UserSessionKey,
  2373. ChallengeResponseMessage->LanmanSessionKey,
  2374. &DatagramSessionKey
  2375. );
  2376. if (SecStatus != SEC_E_OK)
  2377. {
  2378. SspPrint(( SSP_CRITICAL,
  2379. "SsprHandleChallengeMessage: SsprMakeSessionKey\n"));
  2380. goto Cleanup;
  2381. }
  2382. }
  2383. //
  2384. // If the caller specified SEQUENCE_DETECT or REPLAY_DETECT,
  2385. // that means they want to use the MakeSignature/VerifySignature
  2386. // calls. Add this to the returned attributes and the context
  2387. // negotiate flags.
  2388. //
  2389. if ((Context->NegotiateFlags &
  2390. ChallengeMessage->NegotiateFlags &
  2391. NTLMSSP_NEGOTIATE_SIGN) ||
  2392. (ContextReqFlags & ISC_REQ_REPLAY_DETECT)) {
  2393. Context->ContextFlags |= ISC_RET_REPLAY_DETECT;
  2394. *ContextAttributes |= ISC_RET_REPLAY_DETECT;
  2395. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
  2396. }
  2397. if ((Context->NegotiateFlags &
  2398. ChallengeMessage->NegotiateFlags &
  2399. NTLMSSP_NEGOTIATE_SIGN) ||
  2400. (ContextReqFlags & ISC_REQ_SEQUENCE_DETECT)) {
  2401. Context->ContextFlags |= ISC_RET_SEQUENCE_DETECT;
  2402. *ContextAttributes |= ISC_RET_SEQUENCE_DETECT;
  2403. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
  2404. }
  2405. if ((Context->NegotiateFlags &
  2406. ChallengeMessage->NegotiateFlags &
  2407. NTLMSSP_NEGOTIATE_SIGN) ||
  2408. (ContextReqFlags & ISC_REQ_INTEGRITY)) {
  2409. Context->ContextFlags |= ISC_RET_INTEGRITY;
  2410. *ContextAttributes |= ISC_RET_INTEGRITY;
  2411. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
  2412. }
  2413. if ((Context->NegotiateFlags &
  2414. ChallengeMessage->NegotiateFlags &
  2415. NTLMSSP_NEGOTIATE_SEAL) ||
  2416. (ContextReqFlags & ISC_REQ_CONFIDENTIALITY)) {
  2417. if (NtLmGlobalEncryptionEnabled) {
  2418. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
  2419. Context->ContextFlags |= ISC_REQ_CONFIDENTIALITY;
  2420. *ContextAttributes |= ISC_REQ_CONFIDENTIALITY;
  2421. } else {
  2422. SecStatus = STATUS_NOT_SUPPORTED;
  2423. SspPrint(( SSP_CRITICAL,
  2424. "SsprHandleChallengeMessage: NtLmGlobalEncryption not enabled.\n"));
  2425. goto Cleanup;
  2426. }
  2427. }
  2428. if ((Context->NegotiateFlags &
  2429. ChallengeMessage->NegotiateFlags &
  2430. NTLMSSP_NEGOTIATE_DATAGRAM) ==
  2431. NTLMSSP_NEGOTIATE_DATAGRAM ) {
  2432. *ContextAttributes |= ISC_RET_DATAGRAM;
  2433. Context->ContextFlags |= ISC_RET_DATAGRAM;
  2434. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_DATAGRAM;
  2435. }
  2436. //
  2437. // Slip in the hacky mutual auth override here:
  2438. //
  2439. if ( ((ContextReqFlags & ISC_REQ_MUTUAL_AUTH) != 0 ) &&
  2440. (NtLmGlobalMutualAuthLevel < 2 ) ) {
  2441. *ContextAttributes |= ISC_RET_MUTUAL_AUTH ;
  2442. if ( NtLmGlobalMutualAuthLevel == 0 )
  2443. {
  2444. Context->ContextFlags |= ISC_RET_MUTUAL_AUTH ;
  2445. }
  2446. }
  2447. if ( (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_LOCAL_CALL) &&
  2448. (ContextReqFlags & ISC_REQ_DELEGATE)
  2449. )
  2450. {
  2451. //
  2452. // for loopback, we can indeed support another hop.
  2453. //
  2454. *ContextAttributes |= ISC_RET_DELEGATE;
  2455. Context->ContextFlags |= ISC_RET_DELEGATE;
  2456. }
  2457. //
  2458. // Allocate an authenticate message
  2459. //
  2460. AuthenticateMessageSize =
  2461. sizeof(*AuthenticateMessage) +
  2462. LmChallengeResponse.Length +
  2463. NtChallengeResponse.Length +
  2464. DomainName.Length +
  2465. UserName.Length +
  2466. Workstation.Length +
  2467. DatagramSessionKey.Length;
  2468. if ((ContextReqFlags & ISC_REQ_ALLOCATE_MEMORY) == 0)
  2469. {
  2470. if ( AuthenticateMessageSize > *OutputTokenSize ) {
  2471. SspPrint(( SSP_CRITICAL,
  2472. "SsprHandleChallengeMessage: OutputTokenSize is 0x%lx.\n", *OutputTokenSize));
  2473. SecStatus = SEC_E_BUFFER_TOO_SMALL;
  2474. goto Cleanup;
  2475. }
  2476. }
  2477. AuthenticateMessage = (PAUTHENTICATE_MESSAGE)
  2478. NtLmAllocateLsaHeap(AuthenticateMessageSize );
  2479. if ( AuthenticateMessage == NULL ) {
  2480. SecStatus = STATUS_NO_MEMORY;
  2481. SspPrint(( SSP_CRITICAL,
  2482. "SsprHandleChallengeMessage: Error allocating AuthenticateMessage.\n" ));
  2483. goto Cleanup;
  2484. }
  2485. //
  2486. // Build the authenticate message
  2487. //
  2488. strcpy( (char *)AuthenticateMessage->Signature, NTLMSSP_SIGNATURE );
  2489. AuthenticateMessage->MessageType = NtLmAuthenticate;
  2490. AuthenticateMessage->Version = NTLMSSP_ENGINE_VERSION;
  2491. Where = (PCHAR)(AuthenticateMessage+1);
  2492. //
  2493. // Copy the strings needing 2 byte alignment.
  2494. //
  2495. SspContextCopyString( AuthenticateMessage,
  2496. &AuthenticateMessage->DomainName,
  2497. &DomainName,
  2498. &Where );
  2499. SspContextCopyString( AuthenticateMessage,
  2500. &AuthenticateMessage->UserName,
  2501. &UserName,
  2502. &Where );
  2503. SspContextCopyString( AuthenticateMessage,
  2504. &AuthenticateMessage->Workstation,
  2505. &Workstation,
  2506. &Where );
  2507. //
  2508. // Copy the strings not needing special alignment.
  2509. //
  2510. SspContextCopyString( AuthenticateMessage,
  2511. &AuthenticateMessage->LmChallengeResponse,
  2512. &LmChallengeResponse,
  2513. &Where );
  2514. SspContextCopyString( AuthenticateMessage,
  2515. &AuthenticateMessage->NtChallengeResponse,
  2516. &NtChallengeResponse,
  2517. &Where );
  2518. SspContextCopyString( AuthenticateMessage,
  2519. &AuthenticateMessage->SessionKey,
  2520. &DatagramSessionKey,
  2521. &Where );
  2522. AuthenticateMessage->NegotiateFlags = Context->NegotiateFlags;
  2523. ASSERT((AuthenticateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) && L"NTLMSSP_NEGOTIATE_VERSION should be set");
  2524. SspPrint(( SSP_NEGOTIATE_FLAGS,
  2525. "SsprHandleChallengeMessage: ChallengeFlags: %lx AuthenticateFlags: %lx\n",
  2526. ChallengeMessage->NegotiateFlags, AuthenticateMessage->NegotiateFlags ));
  2527. //
  2528. // Copy the AuthenticateMessage to the caller's address space.
  2529. //
  2530. if ((ContextReqFlags & ISC_REQ_ALLOCATE_MEMORY) == 0)
  2531. {
  2532. RtlCopyMemory( *OutputToken,
  2533. AuthenticateMessage,
  2534. AuthenticateMessageSize );
  2535. }
  2536. else
  2537. {
  2538. *OutputToken = AuthenticateMessage;
  2539. AuthenticateMessage = NULL;
  2540. *ContextAttributes |= ISC_RET_ALLOCATED_MEMORY;
  2541. }
  2542. *OutputTokenSize = AuthenticateMessageSize;
  2543. // we need to send a second token back for the rdr
  2544. if (fCallFromRedir)
  2545. {
  2546. NtLmInitializeResponse = (PNTLM_INITIALIZE_RESPONSE)
  2547. NtLmAllocateLsaHeap(sizeof(NTLM_INITIALIZE_RESPONSE));
  2548. if ( NtLmInitializeResponse == NULL ) {
  2549. SecStatus = STATUS_NO_MEMORY;
  2550. SspPrint(( SSP_CRITICAL,
  2551. "SsprHandleChallengeMessage: Error allocating NtLmInitializeResponse.\n" ));
  2552. goto Cleanup;
  2553. }
  2554. RtlCopyMemory(
  2555. NtLmInitializeResponse->UserSessionKey,
  2556. ChallengeResponseMessage->UserSessionKey,
  2557. MSV1_0_USER_SESSION_KEY_LENGTH
  2558. );
  2559. RtlCopyMemory(
  2560. NtLmInitializeResponse->LanmanSessionKey,
  2561. ChallengeResponseMessage->LanmanSessionKey,
  2562. MSV1_0_LANMAN_SESSION_KEY_LENGTH
  2563. );
  2564. *SecondOutputToken = NtLmInitializeResponse;
  2565. NtLmInitializeResponse = NULL;
  2566. *SecondOutputTokenSize = sizeof(NTLM_INITIALIZE_RESPONSE);
  2567. }
  2568. // SspPrint((SSP_API_MORE, "Client session key = %p\n", Context->SessionKey));
  2569. //
  2570. // Return output parameters to the caller.
  2571. //
  2572. *ExpirationTime = SspContextGetTimeStamp( Context, TRUE );
  2573. SecStatus = STATUS_SUCCESS;
  2574. //
  2575. // Generate the explicit cred used audit for non null sessions
  2576. //
  2577. // LocalLoopBack uses implicit credentials only
  2578. //
  2579. if (NtChallengeResponse.Length) // both local loopback and null session have NtChallengeResponse zero length
  2580. {
  2581. AuditStatus = SppGenerateExplicitCredAudit(
  2582. Context,
  2583. ChallengeMessage,
  2584. InputTokenSize,
  2585. DoUnicode
  2586. );
  2587. }
  2588. //
  2589. // Free and locally used resources.
  2590. //
  2591. Cleanup:
  2592. if ( RevealedPassword.Buffer != NULL ) {
  2593. ZeroMemory( RevealedPassword.Buffer, RevealedPassword.Length );
  2594. NtLmFreePrivateHeap( RevealedPassword.Buffer );
  2595. }
  2596. if ( ServerContext != NULL )
  2597. {
  2598. SspContextDereferenceContext( ServerContext );
  2599. }
  2600. if ( Context != NULL ) {
  2601. Context->LastStatus = SecStatus;
  2602. Context->DownLevel = fCallFromRedir;
  2603. //
  2604. // Don't allow this context to be used again.
  2605. //
  2606. if ( NT_SUCCESS(SecStatus) ) {
  2607. Context->State = AuthenticateSentState;
  2608. } else if ( SecStatus == SEC_I_CALL_NTLMSSP_SERVICE ) {
  2609. Context->State = PassedToServiceState;
  2610. } else {
  2611. Context->State = IdleState;
  2612. }
  2613. RtlCopyMemory(
  2614. SessionKey,
  2615. Context->SessionKey,
  2616. MSV1_0_USER_SESSION_KEY_LENGTH );
  2617. *NegotiateFlags = Context->NegotiateFlags;
  2618. // If we just created the context (because rdr may be talking to
  2619. // a pre NT 5.0 server,, we need to dereference it again.
  2620. if (fCallFromRedir && !NT_SUCCESS(SecStatus))
  2621. {
  2622. PSSP_CONTEXT LocalContext;
  2623. SspContextReferenceContext( *ContextHandle, TRUE, &LocalContext );
  2624. ASSERT(LocalContext != NULL);
  2625. if (LocalContext != NULL)
  2626. {
  2627. SspContextDereferenceContext( LocalContext );
  2628. }
  2629. }
  2630. SspContextDereferenceContext( Context );
  2631. }
  2632. if (szCredTargetPreDFSServer != NULL)
  2633. {
  2634. NtLmFreePrivateHeap( szCredTargetPreDFSServer );
  2635. }
  2636. if (szCredTargetDomain != NULL)
  2637. {
  2638. NtLmFreePrivateHeap( szCredTargetDomain );
  2639. }
  2640. if (szCredTargetServer != NULL)
  2641. {
  2642. NtLmFreePrivateHeap( szCredTargetServer );
  2643. }
  2644. if (szCredTargetDnsDomain != NULL)
  2645. {
  2646. NtLmFreePrivateHeap( szCredTargetDnsDomain );
  2647. }
  2648. if (szCredTargetDnsServer != NULL)
  2649. {
  2650. NtLmFreePrivateHeap( szCredTargetDnsServer );
  2651. }
  2652. if (szCredTargetDnsTree != NULL)
  2653. {
  2654. NtLmFreePrivateHeap( szCredTargetDnsTree );
  2655. }
  2656. if ( ChallengeMessage != NULL ) {
  2657. (VOID) NtLmFreePrivateHeap( ChallengeMessage );
  2658. }
  2659. if ( AuthenticateMessage != NULL ) {
  2660. (VOID) NtLmFreeLsaHeap( AuthenticateMessage );
  2661. }
  2662. if ( ChallengeResponseMessage != NULL ) {
  2663. (VOID) LsaFunctions->FreeLsaHeap( ChallengeResponseMessage );
  2664. }
  2665. if ( !DoUnicode ) {
  2666. RtlFreeUnicodeString( &TargetName );
  2667. if ( DomainName.Buffer != NULL) {
  2668. RtlFreeOemString( &DomainName );
  2669. }
  2670. if ( UserName.Buffer != NULL) {
  2671. RtlFreeOemString( &UserName );
  2672. }
  2673. }
  2674. RtlFreeUnicodeString( &DefectiveTargetName );
  2675. if ( ClientTokenHandle )
  2676. {
  2677. CloseHandle( ClientTokenHandle );
  2678. }
  2679. if (GetChallengeResponse && (GetChallengeResponse!=&TempChallengeResponse)){
  2680. SafeAllocaFree(GetChallengeResponse);
  2681. }
  2682. SspPrint(( SSP_API_MORE, "Leaving SsprHandleChallengeMessage: 0x%lx\n", SecStatus ));
  2683. return SecStatus;
  2684. }
  2685. NTSTATUS
  2686. CredpParseUserName(
  2687. IN OUT LPWSTR ParseName,
  2688. OUT LPWSTR* pUserName,
  2689. OUT LPWSTR* pDomainName
  2690. )
  2691. /*++
  2692. Routine Description:
  2693. This routine separates a passed in user name into domain and username. A user name must have one
  2694. of the following two syntaxes:
  2695. <DomainName>\<UserName>
  2696. <UserName>@<DnsDomainName>
  2697. The name is considered to have the first syntax if the string contains an \.
  2698. A string containing a @ is ambiguous since <UserName> may contain an @.
  2699. For the second syntax, the last @ in the string is used since <UserName> may
  2700. contain an @ but <DnsDomainName> cannot.
  2701. Arguments:
  2702. ParseName - Name of user to validate - will be modified
  2703. pUserName - Returned pointing to canonical name inside of ParseName
  2704. pDomainName - Returned pointing to domain name inside of ParseName
  2705. Return Values:
  2706. The following status codes may be returned:
  2707. STATUS_INVALID_ACCOUNT_NAME - The user name is not valid.
  2708. --*/
  2709. {
  2710. LPWSTR SlashPointer;
  2711. *pUserName = NULL;
  2712. *pDomainName = NULL;
  2713. //
  2714. // NULL is invalid
  2715. //
  2716. if ( ParseName == NULL ) {
  2717. return STATUS_INVALID_ACCOUNT_NAME;
  2718. }
  2719. //
  2720. // Classify the input account name.
  2721. //
  2722. // The name is considered to be <DomainName>\<UserName> if the string
  2723. // contains an \.
  2724. //
  2725. SlashPointer = wcsrchr( ParseName, L'\\' );
  2726. if ( SlashPointer != NULL ) {
  2727. //
  2728. // point the output strings
  2729. //
  2730. *pDomainName = ParseName;
  2731. //
  2732. // Skip the backslash
  2733. //
  2734. *SlashPointer = L'\0';
  2735. SlashPointer ++;
  2736. *pUserName = SlashPointer;
  2737. } else {
  2738. //
  2739. // it's a UPN.
  2740. // leave it intact in the UserName field.
  2741. // set the DomainName to empty string, so the rest of the logon code
  2742. // avoids filling in the default.
  2743. //
  2744. *pUserName = ParseName;
  2745. *pDomainName = L"";
  2746. }
  2747. return STATUS_SUCCESS;
  2748. }
  2749. NTSTATUS
  2750. CopyCredManCredentials(
  2751. IN PLUID LogonId,
  2752. IN CREDENTIAL_TARGET_INFORMATIONW* pTargetInfo,
  2753. IN OUT PSSP_CONTEXT Context,
  2754. IN BOOLEAN fShareLevel,
  2755. IN BOOLEAN bAllowOwfPassword,
  2756. OUT BOOLEAN* pbIsOwfPassword
  2757. )
  2758. /*++
  2759. Routine Description:
  2760. Look for a keyring credential entry for the specified domain, and copy to Context handle if found
  2761. Arguments:
  2762. LogonId -- LogonId of the calling process.
  2763. pTargetInfo -- Information on target to search for creds.
  2764. Context - Points to the ContextHandle of the Context
  2765. to be referenced.
  2766. fShareLevel - whether it is for sharelevel
  2767. bAllowOwfPassword - whether to look for OWF password, this prevents
  2768. username/domainname in Context from being trashed
  2769. pbIsOwfPassword - whether the cred found consists of OWFs
  2770. Return Value:
  2771. STATUS_SUCCESS -- All OK
  2772. STATUS_NOT_FOUND - Credential couldn't be found.
  2773. All others are real failures and should be returned to the caller.
  2774. --*/
  2775. {
  2776. NTSTATUS Status;
  2777. PENCRYPTED_CREDENTIALW *EncryptedCredentials = NULL;
  2778. PCREDENTIALW *Credentials = NULL;
  2779. PCREDENTIALW pPasswordForCertCred = NULL;
  2780. ULONG CredentialCount;
  2781. WCHAR* UserName = NULL;
  2782. WCHAR* DomainName = NULL;
  2783. UNICODE_STRING TempString = {0};
  2784. WCHAR szTempBuffer[UNLEN + UNLEN + 4]; // to hold domain\username or username@dnsdomainname
  2785. ENCRYPTED_CREDENTIALW* pCertCred = NULL;
  2786. KERB_QUERY_SUPPLEMENTAL_CREDS_RESPONSE* pQuerySuppCredResp = NULL;
  2787. if (!Context) // validate context only after call to Lookup
  2788. {
  2789. return STATUS_NOT_FOUND;
  2790. }
  2791. Status = LsaFunctions->CrediReadDomainCredentials(
  2792. LogonId,
  2793. CREDP_FLAGS_IN_PROCESS, // Allow password to be returned
  2794. pTargetInfo,
  2795. 0, // no flags
  2796. &CredentialCount,
  2797. &EncryptedCredentials
  2798. );
  2799. Credentials = (PCREDENTIALW *)EncryptedCredentials;
  2800. if (!NT_SUCCESS(Status))
  2801. {
  2802. //
  2803. // Ideally, only STATUS_NO_SUCH_LOGON_SESSION should be converted to
  2804. // STATUS_NOT_FOUND. However, swallowing all failures and asserting
  2805. // these specific two works around a bug in CrediReadDomainCredentials
  2806. // which returns invalid parameter if the target is a user account name.
  2807. // Eventually, CrediReadDomainCredentials should return a more
  2808. // appropriate error in this case.
  2809. //
  2810. SspPrint((SSP_WARNING, "CopyCredManCredentials: CrediReadDomainCredentials returned %x, LogonId %#x:%#x\n",
  2811. Status, LogonId->HighPart, LogonId->LowPart));
  2812. ASSERT(
  2813. (Status == STATUS_NO_SUCH_LOGON_SESSION)||
  2814. (Status == STATUS_INVALID_PARAMETER)||
  2815. (Status == STATUS_NOT_FOUND)
  2816. );
  2817. return STATUS_NOT_FOUND;
  2818. }
  2819. //
  2820. // NULL terminate scatch buffer
  2821. //
  2822. szTempBuffer[COUNTOF(szTempBuffer) - 1] = L'\0';
  2823. //
  2824. // Loop through the list of credentials
  2825. //
  2826. for ( ULONG CredIndex = 0; CredIndex < CredentialCount; CredIndex++ )
  2827. {
  2828. //
  2829. // NTLM only supports password credentials
  2830. // skip OWF passwords if not allowed
  2831. //
  2832. if ( (Credentials[CredIndex]->Type != CRED_TYPE_DOMAIN_PASSWORD)
  2833. || (!bAllowOwfPassword && (Credentials[CredIndex]->Flags & CRED_FLAGS_OWF_CRED_BLOB)) )
  2834. {
  2835. continue;
  2836. }
  2837. //
  2838. // For Share level connects, don't allow matching against * creds.
  2839. //
  2840. // CRED_FLAGS_PASSWORD_FOR_CERT cred is *Session cred
  2841. //
  2842. if ( fShareLevel )
  2843. {
  2844. if ( (Credentials[CredIndex]->TargetName) &&
  2845. (wcschr( Credentials[CredIndex]->TargetName, L'*' ) != NULL) )
  2846. {
  2847. continue;
  2848. }
  2849. }
  2850. if ((Credentials[CredIndex]->Flags & CRED_FLAGS_PASSWORD_FOR_CERT))
  2851. {
  2852. pPasswordForCertCred = Credentials[CredIndex];
  2853. continue;
  2854. }
  2855. if ( Credentials[CredIndex]->Flags & CRED_FLAGS_PROMPT_NOW )
  2856. {
  2857. Status = SEC_E_LOGON_DENIED;
  2858. goto Cleanup;
  2859. }
  2860. //
  2861. // Sanity check the credential
  2862. //
  2863. if ( Credentials[CredIndex]->UserName == NULL )
  2864. {
  2865. Status = STATUS_NOT_FOUND;
  2866. goto Cleanup;
  2867. }
  2868. //
  2869. // Convert the UserName to domain name and user name
  2870. //
  2871. RtlCopyMemory(
  2872. szTempBuffer,
  2873. Credentials[CredIndex]->UserName,
  2874. sizeof(WCHAR) * min(wcslen(Credentials[CredIndex]->UserName) + 1, COUNTOF(szTempBuffer) - 1)
  2875. );
  2876. Status = CredpParseUserName( szTempBuffer, &UserName, &DomainName );
  2877. if (!NT_SUCCESS(Status))
  2878. {
  2879. goto Cleanup;
  2880. }
  2881. //
  2882. // Free the existing domain name and add the new one
  2883. //
  2884. if (Context->DomainName.Buffer)
  2885. {
  2886. NtLmFreePrivateHeap (Context->DomainName.Buffer);
  2887. Context->DomainName.Buffer = NULL;
  2888. Context->DomainName.Length = 0;
  2889. }
  2890. if ( DomainName )
  2891. {
  2892. RtlInitUnicodeString( &TempString, DomainName );
  2893. Status = NtLmDuplicateUnicodeString(&Context->DomainName, &TempString);
  2894. if ( !NT_SUCCESS( Status ) )
  2895. {
  2896. goto Cleanup;
  2897. }
  2898. }
  2899. //
  2900. // Free the existing user name and add the new one
  2901. //
  2902. RtlInitUnicodeString( &TempString, UserName );
  2903. if (Context->UserName.Buffer)
  2904. {
  2905. NtLmFreePrivateHeap (Context->UserName.Buffer);
  2906. Context->UserName.Buffer = NULL;
  2907. }
  2908. Status = NtLmDuplicateUnicodeString(&Context->UserName, &TempString);
  2909. if ( !NT_SUCCESS( Status ) )
  2910. {
  2911. goto Cleanup;
  2912. }
  2913. SspPrint((SSP_CRED, "CopyCredManCredentials copying credmain passwords\n"));
  2914. TempString.Buffer = (PWSTR) Credentials[CredIndex]->CredentialBlob;
  2915. TempString.MaximumLength = (USHORT) Credentials[CredIndex]->CredentialBlobSize;
  2916. TempString.Length = (USHORT) EncryptedCredentials[CredIndex]->ClearCredentialBlobSize;
  2917. //
  2918. // zero length password must be treated as blank or NTLM will assume it
  2919. // should use the password of the currently logged in user.
  2920. //
  2921. if ( TempString.Length == 0 )
  2922. {
  2923. TempString.Buffer = L"";
  2924. }
  2925. //
  2926. // Free the existing password and add the new one
  2927. //
  2928. if (Context->Password.Buffer)
  2929. {
  2930. NtLmFreePrivateHeap (Context->Password.Buffer);
  2931. Context->Password.Buffer = NULL;
  2932. }
  2933. Status = NtLmDuplicatePassword(&Context->Password, &TempString);
  2934. if (!NT_SUCCESS(Status))
  2935. {
  2936. goto Cleanup;
  2937. }
  2938. *pbIsOwfPassword = (BOOLEAN) (Credentials[CredIndex]->Flags & CRED_FLAGS_OWF_CRED_BLOB);
  2939. goto Cleanup;
  2940. }
  2941. //
  2942. // now call kerberos to get password for cert cred
  2943. //
  2944. if (pPasswordForCertCred)
  2945. {
  2946. KERB_QUERY_SUPPLEMENTAL_CREDS_REQUEST QuerySuppCred;
  2947. UNICODE_STRING KerberosPackageName = CONSTANT_UNICODE_STRING((MICROSOFT_KERBEROS_NAME_W));
  2948. UNICODE_STRING MsvPackageName = CONSTANT_UNICODE_STRING((NTLMSP_NAME));
  2949. ULONG cbResponse = 0;
  2950. NTSTATUS SubStatus = STATUS_UNSUCCESSFUL;
  2951. ENCRYPTED_CREDENTIALW* pPasswordCred = NULL;
  2952. SspPrint((SSP_CRED, "CopyCredManCredentials querying passwords for cert %ws\n", pPasswordForCertCred->TargetName));
  2953. Status = LsaFunctions->CrediRead(
  2954. LogonId,
  2955. CREDP_FLAGS_IN_PROCESS, // CredFlags
  2956. pPasswordForCertCred->TargetName,
  2957. CRED_TYPE_DOMAIN_CERTIFICATE, // CredType
  2958. 0, // no Flags
  2959. &pCertCred
  2960. );
  2961. if (!NT_SUCCESS(Status))
  2962. {
  2963. goto Cleanup;
  2964. }
  2965. RtlZeroMemory(&QuerySuppCred, sizeof(QuerySuppCred));
  2966. QuerySuppCred.MessageType = KerbQuerySupplementalCredentialsMessage;
  2967. QuerySuppCred.PackageName = MsvPackageName;
  2968. QuerySuppCred.MarshalledCreds = (CREDENTIALW *) pCertCred;
  2969. QuerySuppCred.LogonId = *LogonId;
  2970. Status = LsaFunctions->CallPackage(
  2971. &KerberosPackageName,
  2972. &QuerySuppCred,
  2973. sizeof(QuerySuppCred),
  2974. reinterpret_cast<VOID**>(&pQuerySuppCredResp),
  2975. &cbResponse,
  2976. &SubStatus
  2977. );
  2978. if (!NT_SUCCESS(Status))
  2979. {
  2980. SspPrint((SSP_WARNING, "CopyCredManCredentials CallPackage failed with Status %#x\n", Status));
  2981. Status = STATUS_NOT_FOUND;
  2982. goto Cleanup;
  2983. }
  2984. if (!NT_SUCCESS(SubStatus))
  2985. {
  2986. SspPrint((SSP_WARNING, "CopyCredManCredentials CallPackage failed with SubStatus %#x\n", SubStatus));
  2987. Status = STATUS_NOT_FOUND;
  2988. goto Cleanup;
  2989. }
  2990. ASSERT( pQuerySuppCredResp );
  2991. pPasswordCred = &pQuerySuppCredResp->ReturnedCreds;
  2992. //
  2993. // NTLM only supports password credentials and Sanity check the
  2994. // credential
  2995. //
  2996. if ( (pPasswordCred->Cred.Type != CRED_TYPE_DOMAIN_PASSWORD) ||
  2997. (pPasswordCred->Cred.Flags & CRED_FLAGS_PASSWORD_FOR_CERT) ||
  2998. (!bAllowOwfPassword && (pPasswordCred->Cred.Flags & CRED_FLAGS_OWF_CRED_BLOB)) )
  2999. {
  3000. Status = STATUS_NOT_FOUND;
  3001. goto Cleanup;
  3002. }
  3003. if (pPasswordCred->Cred.Flags & CRED_FLAGS_PROMPT_NOW)
  3004. {
  3005. Status = SEC_E_LOGON_DENIED;
  3006. goto Cleanup;
  3007. }
  3008. if (pPasswordCred->Cred.UserName == NULL)
  3009. {
  3010. Status = STATUS_NOT_FOUND;
  3011. goto Cleanup;
  3012. }
  3013. SspPrint((SSP_CRED, "CopyCredManCredentials using domain\\user %ws\n", pPasswordCred->Cred.UserName));
  3014. //
  3015. // Convert the UserName to domain name and user name
  3016. //
  3017. RtlCopyMemory(
  3018. szTempBuffer,
  3019. pPasswordCred->Cred.UserName,
  3020. sizeof(WCHAR) * min(wcslen(pPasswordCred->Cred.UserName) + 1, COUNTOF(szTempBuffer) - 1)
  3021. );
  3022. Status = CredpParseUserName( szTempBuffer, &UserName, &DomainName );
  3023. if (!NT_SUCCESS(Status))
  3024. {
  3025. goto Cleanup;
  3026. }
  3027. //
  3028. // Free the existing domain name and add the new one
  3029. //
  3030. if (Context->DomainName.Buffer)
  3031. {
  3032. NtLmFreePrivateHeap(Context->DomainName.Buffer);
  3033. Context->DomainName.Buffer = NULL;
  3034. Context->DomainName.Length = 0;
  3035. }
  3036. if ( DomainName )
  3037. {
  3038. RtlInitUnicodeString( &TempString, DomainName );
  3039. }
  3040. Status = NtLmDuplicateUnicodeString(&Context->DomainName, &TempString);
  3041. if (!NT_SUCCESS(Status))
  3042. {
  3043. goto Cleanup;
  3044. }
  3045. //
  3046. // Free the existing user name and add the new one
  3047. //
  3048. RtlInitUnicodeString( &TempString, UserName );
  3049. if (Context->UserName.Buffer)
  3050. {
  3051. NtLmFreePrivateHeap(Context->UserName.Buffer);
  3052. Context->UserName.Buffer = NULL;
  3053. }
  3054. Status = NtLmDuplicateUnicodeString(&Context->UserName, &TempString);
  3055. if (!NT_SUCCESS(Status))
  3056. {
  3057. goto Cleanup;
  3058. }
  3059. TempString.Buffer = (PWSTR) pPasswordCred->Cred.CredentialBlob;
  3060. TempString.MaximumLength = (USHORT) pPasswordCred->Cred.CredentialBlobSize;
  3061. TempString.Length = (USHORT) pPasswordCred->ClearCredentialBlobSize;
  3062. //
  3063. // Free the existing password and add the new one
  3064. //
  3065. if (Context->Password.Buffer)
  3066. {
  3067. NtLmFreePrivateHeap(Context->Password.Buffer);
  3068. Context->Password.Buffer = NULL;
  3069. }
  3070. Status = NtLmDuplicatePassword(&Context->Password, &TempString);
  3071. if (!NT_SUCCESS(Status))
  3072. {
  3073. goto Cleanup;
  3074. }
  3075. *pbIsOwfPassword = (BOOLEAN) (pPasswordCred->Cred.Flags & CRED_FLAGS_OWF_CRED_BLOB);
  3076. //
  3077. // now this cred is good to go, write it into credman before we return
  3078. //
  3079. //
  3080. // we consider failures of CrediWrite non-fatal, ignore the return code
  3081. //
  3082. (VOID) LsaFunctions->CrediWrite(
  3083. LogonId,
  3084. CREDP_FLAGS_IN_PROCESS, // CredFlags
  3085. pPasswordCred,
  3086. 0 // no Flags
  3087. );
  3088. goto Cleanup;
  3089. }
  3090. SspPrint((SSP_CRED, "CopyCredManCredentials no credman credential found\n"));
  3091. Status = STATUS_NOT_FOUND;
  3092. Cleanup:
  3093. //
  3094. // Free the returned credentials
  3095. //
  3096. if (pCertCred)
  3097. {
  3098. LsaFunctions->FreeLsaHeap(pCertCred);
  3099. }
  3100. if (EncryptedCredentials)
  3101. {
  3102. LsaFunctions->CrediFreeCredentials(
  3103. CredentialCount,
  3104. EncryptedCredentials
  3105. );
  3106. }
  3107. if (pQuerySuppCredResp)
  3108. {
  3109. LsaFunctions->FreeLsaHeap(pQuerySuppCredResp);
  3110. }
  3111. #if DBG
  3112. if (!NT_SUCCESS(Status))
  3113. {
  3114. SspPrint((SSP_WARNING, "CopyCredManCredentials failed to get credman password Status %#x\n", Status));
  3115. }
  3116. #endif // DBG
  3117. return Status;
  3118. }
  3119. NTSTATUS
  3120. CredpExtractMarshalledTargetInfo(
  3121. IN PUNICODE_STRING TargetServerName,
  3122. OUT CREDENTIAL_TARGET_INFORMATIONW **pTargetInfo
  3123. )
  3124. {
  3125. CREDENTIAL_TARGET_INFORMATIONW *NewTargetInfo;
  3126. NTSTATUS Status;
  3127. //
  3128. // LSA will set Length to include only the non-marshalled portion,
  3129. // with MaximumLength trailing data to include marshalled portion.
  3130. //
  3131. if ( (TargetServerName == NULL) ||
  3132. (TargetServerName->Buffer == NULL) ||
  3133. (TargetServerName->Length >= TargetServerName->MaximumLength) ||
  3134. ((TargetServerName->MaximumLength - TargetServerName->Length) < CRED_MARSHALED_TI_SIZE_SIZE )
  3135. )
  3136. {
  3137. return STATUS_SUCCESS;
  3138. }
  3139. //
  3140. // Unmarshal the target info
  3141. //
  3142. Status = CredUnmarshalTargetInfo (
  3143. TargetServerName->Buffer,
  3144. TargetServerName->MaximumLength,
  3145. &NewTargetInfo,
  3146. NULL );
  3147. if ( !NT_SUCCESS(Status) )
  3148. {
  3149. if ( Status == STATUS_INVALID_PARAMETER )
  3150. {
  3151. Status = STATUS_SUCCESS;
  3152. }
  3153. }
  3154. else
  3155. {
  3156. if ( *pTargetInfo != NULL )
  3157. {
  3158. LocalFree( *pTargetInfo );
  3159. }
  3160. *pTargetInfo = NewTargetInfo;
  3161. }
  3162. return Status ;
  3163. }
  3164. NTSTATUS
  3165. CredpProcessUserNameCredential(
  3166. IN PUNICODE_STRING MarshalledUserName,
  3167. OUT PUNICODE_STRING UserName,
  3168. OUT PUNICODE_STRING DomainName,
  3169. OUT PUNICODE_STRING Password
  3170. )
  3171. {
  3172. WCHAR FastUserName[ UNLEN+1 ];
  3173. LPWSTR SlowUserName = NULL;
  3174. LPWSTR TempUserName;
  3175. CRED_MARSHAL_TYPE CredMarshalType;
  3176. PUSERNAME_TARGET_CREDENTIAL_INFO pCredentialUserName = NULL;
  3177. CREDENTIAL_TARGET_INFORMATIONW TargetInfo;
  3178. BOOLEAN bIsOwfPassword = FALSE;
  3179. ULONG CredTypes;
  3180. SECPKG_CLIENT_INFO ClientInfo;
  3181. SSP_CONTEXT SspContext;
  3182. NTSTATUS Status = STATUS_NOT_FOUND;
  3183. ZeroMemory( &SspContext, sizeof(SspContext) );
  3184. if ( (MarshalledUserName->Length+sizeof(WCHAR)) <= sizeof(FastUserName) )
  3185. {
  3186. TempUserName = FastUserName;
  3187. } else {
  3188. SlowUserName = (LPWSTR)NtLmAllocatePrivateHeap( MarshalledUserName->Length + sizeof(WCHAR) );
  3189. if ( SlowUserName == NULL )
  3190. {
  3191. return STATUS_INSUFFICIENT_RESOURCES;
  3192. }
  3193. TempUserName = SlowUserName;
  3194. }
  3195. //
  3196. // copy the input to a NULL terminated string, then attempt to unmarshal it.
  3197. //
  3198. RtlCopyMemory( TempUserName,
  3199. MarshalledUserName->Buffer,
  3200. MarshalledUserName->Length
  3201. );
  3202. TempUserName[ MarshalledUserName->Length / sizeof(WCHAR) ] = L'\0';
  3203. if (!CredUnmarshalCredentialW(
  3204. TempUserName,
  3205. &CredMarshalType,
  3206. (VOID**)&pCredentialUserName
  3207. ))
  3208. {
  3209. goto Cleanup;
  3210. }
  3211. if ( (CredMarshalType != UsernameTargetCredential) )
  3212. {
  3213. Status = STATUS_NOT_SUPPORTED;
  3214. goto Cleanup;
  3215. }
  3216. //
  3217. // now query credential manager for a match.
  3218. //
  3219. Status = LsaFunctions->GetClientInfo(&ClientInfo);
  3220. if (!NT_SUCCESS(Status))
  3221. {
  3222. goto Cleanup;
  3223. }
  3224. ZeroMemory( &TargetInfo, sizeof(TargetInfo) );
  3225. CredTypes = CRED_TYPE_DOMAIN_PASSWORD;
  3226. TargetInfo.Flags = CRED_TI_USERNAME_TARGET;
  3227. TargetInfo.TargetName = pCredentialUserName->UserName;
  3228. TargetInfo.PackageName = NTLMSP_NAME;
  3229. TargetInfo.CredTypeCount = 1;
  3230. TargetInfo.CredTypes = &CredTypes;
  3231. Status = CopyCredManCredentials(
  3232. &ClientInfo.LogonId,
  3233. &TargetInfo,
  3234. &SspContext,
  3235. FALSE,
  3236. FALSE, // do not allow OWF passwords
  3237. &bIsOwfPassword
  3238. );
  3239. if (!NT_SUCCESS(Status))
  3240. {
  3241. goto Cleanup;
  3242. }
  3243. //
  3244. // do not support OWF password via UserNameCredentials
  3245. //
  3246. ASSERT(!bIsOwfPassword);
  3247. *UserName = SspContext.UserName;
  3248. *DomainName = SspContext.DomainName;
  3249. *Password = SspContext.Password;
  3250. SspRevealPassword( Password );
  3251. Status = STATUS_SUCCESS;
  3252. Cleanup:
  3253. if (!NT_SUCCESS(Status))
  3254. {
  3255. NtLmFreePrivateHeap( SspContext.UserName.Buffer );
  3256. NtLmFreePrivateHeap( SspContext.DomainName.Buffer );
  3257. NtLmFreePrivateHeap( SspContext.Password.Buffer );
  3258. }
  3259. if ( SlowUserName )
  3260. {
  3261. NtLmFreePrivateHeap( SlowUserName );
  3262. }
  3263. if ( pCredentialUserName != NULL )
  3264. {
  3265. CredFree( pCredentialUserName );
  3266. }
  3267. return Status;
  3268. }
  3269. #if 0
  3270. //+-------------------------------------------------------------------------
  3271. //
  3272. // Function: SpQueryLsaModeContextAttributes
  3273. //
  3274. // Synopsis: Querys attributes of the specified context
  3275. //
  3276. // Effects:
  3277. //
  3278. // Arguments:
  3279. //
  3280. // Requires:
  3281. //
  3282. // Returns:
  3283. //
  3284. // Notes:
  3285. //
  3286. //
  3287. //--------------------------------------------------------------------------
  3288. ULONG SavedUseValidated = 0xFF;
  3289. WCHAR SavedCredentialName[1024] = L"SaveMe";
  3290. ULONG SavedCredentialType = 0x22;
  3291. ULONG SavedCredTypes = CRED_TYPE_DOMAIN_PASSWORD;
  3292. CREDENTIAL_TARGET_INFORMATIONW SavedTargetInfo = {
  3293. L"ntdsdc9",
  3294. L"NTDSDC9",
  3295. L"NTDSDC9.ntdev.microsoft.com",
  3296. L"NTDEV",
  3297. L"ntdev.microsoft.com",
  3298. L"ntdev.microsoft.com",
  3299. L"NTLM",
  3300. 0,
  3301. 1,
  3302. &SavedCredTypes
  3303. };
  3304. NTSTATUS NTAPI
  3305. SpQueryLsaModeContextAttributes(
  3306. IN LSA_SEC_HANDLE ContextHandle,
  3307. IN ULONG ContextAttribute,
  3308. IN OUT PVOID Buffer
  3309. )
  3310. {
  3311. NTSTATUS Status = STATUS_SUCCESS;
  3312. DWORD WinStatus;
  3313. PSSP_CONTEXT Context = NULL;
  3314. SecPkgContext_CredentialNameW CredentialNameInfo;
  3315. ULONG CredentialNameSize;
  3316. LPWSTR UserCredentialName;
  3317. PCREDENTIAL_TARGET_INFORMATIONW TempTargetInfo = NULL;
  3318. ULONG TempTargetInfoSize;
  3319. PCREDENTIAL_TARGET_INFORMATIONW UserTargetInfo;
  3320. SecPkgContext_TargetInformationW TargetInfo;
  3321. SspPrint((SSP_API, "Entering SpQueryLsaModeContextAttributes for ctxt:0x%x, Attr:0x%x\n", ContextHandle, ContextAttribute));
  3322. //
  3323. // Find the currently existing context.
  3324. //
  3325. Status = SspContextReferenceContext( ContextHandle, FALSE, &Context );
  3326. if ( !NT_SUCCESS(Status) )
  3327. {
  3328. SspPrint(( SSP_CRITICAL,
  3329. "SpQueryLsaModeContextAttributes: invalid context handle.\n" ));
  3330. goto Cleanup;
  3331. }
  3332. //
  3333. // Return the appropriate information
  3334. //
  3335. switch(ContextAttribute) {
  3336. case SECPKG_ATTR_CREDENTIAL_NAME:
  3337. CredentialNameSize = (wcslen(SavedCredentialName) + 1) * sizeof(WCHAR);
  3338. Status = LsaFunctions->AllocateClientBuffer(
  3339. NULL,
  3340. CredentialNameSize,
  3341. (PVOID *) &UserCredentialName );
  3342. if (!NT_SUCCESS(Status)) {
  3343. goto Cleanup;
  3344. }
  3345. // Copy the name to the user's address space
  3346. Status = LsaFunctions->CopyToClientBuffer(
  3347. NULL,
  3348. CredentialNameSize,
  3349. UserCredentialName,
  3350. SavedCredentialName );
  3351. if (!NT_SUCCESS(Status)) {
  3352. goto Cleanup;
  3353. }
  3354. // Copy the struct itself to the user's address space
  3355. CredentialNameInfo.CredentialType = SavedCredentialType;
  3356. CredentialNameInfo.sCredentialName = UserCredentialName;
  3357. Status = LsaFunctions->CopyToClientBuffer(
  3358. NULL,
  3359. sizeof(CredentialNameInfo),
  3360. Buffer,
  3361. &CredentialNameInfo );
  3362. if (!NT_SUCCESS(Status)) {
  3363. goto Cleanup;
  3364. }
  3365. break;
  3366. case SECPKG_ATTR_TARGET_INFORMATION:
  3367. //
  3368. // Marshall the target info into a single buffer.
  3369. //
  3370. WinStatus = CredpConvertTargetInfo ( DoWtoW,
  3371. &SavedTargetInfo,
  3372. &TempTargetInfo,
  3373. &TempTargetInfoSize );
  3374. if ( WinStatus != NO_ERROR ) {
  3375. Status = STATUS_NO_MEMORY;
  3376. goto Cleanup;
  3377. }
  3378. //
  3379. // Allocate a buffer the same size in the client's address space.
  3380. //
  3381. Status = LsaFunctions->AllocateClientBuffer(
  3382. NULL,
  3383. TempTargetInfoSize,
  3384. (PVOID *) &UserTargetInfo );
  3385. if (!NT_SUCCESS(Status)) {
  3386. goto Cleanup;
  3387. }
  3388. //
  3389. // Relocate all pointers to be user-buffer-specific
  3390. // YUCK!!
  3391. //
  3392. TempTargetInfo->TargetName = (LPWSTR)( ((LPBYTE)(TempTargetInfo->TargetName)) -
  3393. ((LPBYTE)(TempTargetInfo)) +
  3394. ((LPBYTE)UserTargetInfo) );
  3395. TempTargetInfo->NetbiosServerName = (LPWSTR)( ((LPBYTE)(TempTargetInfo->NetbiosServerName)) -
  3396. ((LPBYTE)(TempTargetInfo)) +
  3397. ((LPBYTE)UserTargetInfo) );
  3398. TempTargetInfo->DnsServerName = (LPWSTR)( ((LPBYTE)(TempTargetInfo->DnsServerName)) -
  3399. ((LPBYTE)(TempTargetInfo)) +
  3400. ((LPBYTE)UserTargetInfo) );
  3401. TempTargetInfo->NetbiosDomainName = (LPWSTR)( ((LPBYTE)(TempTargetInfo->NetbiosDomainName)) -
  3402. ((LPBYTE)(TempTargetInfo)) +
  3403. ((LPBYTE)UserTargetInfo) );
  3404. TempTargetInfo->DnsDomainName = (LPWSTR)( ((LPBYTE)(TempTargetInfo->DnsDomainName)) -
  3405. ((LPBYTE)(TempTargetInfo)) +
  3406. ((LPBYTE)UserTargetInfo) );
  3407. TempTargetInfo->DnsTreeName = (LPWSTR)( ((LPBYTE)(TempTargetInfo->DnsTreeName)) -
  3408. ((LPBYTE)(TempTargetInfo)) +
  3409. ((LPBYTE)UserTargetInfo) );
  3410. TempTargetInfo->PackageName = (LPWSTR)( ((LPBYTE)(TempTargetInfo->PackageName)) -
  3411. ((LPBYTE)(TempTargetInfo)) +
  3412. ((LPBYTE)UserTargetInfo) );
  3413. TempTargetInfo->CredTypes = (LPDWORD)( ((LPBYTE)(TempTargetInfo->CredTypes)) -
  3414. ((LPBYTE)(TempTargetInfo)) +
  3415. ((LPBYTE)UserTargetInfo) );
  3416. //
  3417. // Copy the target info to the user's address space
  3418. //
  3419. Status = LsaFunctions->CopyToClientBuffer(
  3420. NULL,
  3421. TempTargetInfoSize,
  3422. UserTargetInfo,
  3423. TempTargetInfo );
  3424. if (!NT_SUCCESS(Status)) {
  3425. goto Cleanup;
  3426. }
  3427. //
  3428. // Copy the struct itself to the user's address space
  3429. //
  3430. TargetInfo.TargetInformation = UserTargetInfo;
  3431. Status = LsaFunctions->CopyToClientBuffer(
  3432. NULL,
  3433. sizeof(TargetInfo),
  3434. Buffer,
  3435. &TargetInfo );
  3436. if (!NT_SUCCESS(Status)) {
  3437. goto Cleanup;
  3438. }
  3439. break;
  3440. default:
  3441. Status = STATUS_NOT_SUPPORTED;
  3442. break;
  3443. }
  3444. Cleanup:
  3445. if (Context != NULL) {
  3446. SspContextDereferenceContext( Context );
  3447. }
  3448. if ( TempTargetInfo != NULL ) {
  3449. CredFree( TempTargetInfo );
  3450. }
  3451. SspPrint((SSP_API, "Leaving SpQueryLsaModeContextAttributes for ctxt:0x%x, Attr:0x%x\n", ContextHandle, ContextAttribute));
  3452. return (SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  3453. }
  3454. //+-------------------------------------------------------------------------
  3455. //
  3456. // Function: SpSetContextAttributes
  3457. //
  3458. // Synopsis: Set attributes of the specified context
  3459. //
  3460. // Effects:
  3461. //
  3462. // Arguments:
  3463. //
  3464. // Requires:
  3465. //
  3466. // Returns:
  3467. //
  3468. // Notes:
  3469. //
  3470. //
  3471. //--------------------------------------------------------------------------
  3472. NTSTATUS NTAPI
  3473. SpSetContextAttributes(
  3474. IN LSA_SEC_HANDLE ContextHandle,
  3475. IN ULONG ContextAttribute,
  3476. IN PVOID Buffer,
  3477. IN ULONG BufferSize
  3478. )
  3479. {
  3480. NTSTATUS Status = STATUS_SUCCESS;
  3481. PSSP_CONTEXT Context = NULL;
  3482. PSecPkgContext_CredentialNameW CredentialNameInfo;
  3483. ULONG CredentialNameSize;
  3484. LPBYTE LocalBuffer = NULL;
  3485. SspPrint((SSP_API, "Entering SpSetContextAttributes for ctxt:0x%x, Attr:0x%x\n", ContextHandle, ContextAttribute));
  3486. //
  3487. // Find the currently existing context.
  3488. //
  3489. Status = SspContextReferenceContext( ContextHandle, FALSE, &Context );
  3490. if ( !NT_SUCCESS(Status) )
  3491. {
  3492. SspPrint(( SSP_CRITICAL,
  3493. "SpSetContextAttributes: invalid context handle.\n" ));
  3494. goto Cleanup;
  3495. }
  3496. //
  3497. // Grab a local copy of the data
  3498. //
  3499. // Sanity check this size before allocating
  3500. LocalBuffer = (LPBYTE) NtLmAllocatePrivateHeap( BufferSize );
  3501. if ( LocalBuffer == NULL ) {
  3502. Status = STATUS_NO_MEMORY;
  3503. goto Cleanup;
  3504. }
  3505. Status = LsaFunctions->CopyFromClientBuffer(
  3506. NULL,
  3507. BufferSize,
  3508. LocalBuffer,
  3509. Buffer );
  3510. if (!NT_SUCCESS(Status)) {
  3511. goto Cleanup;
  3512. }
  3513. //
  3514. // Return the appropriate information
  3515. //
  3516. switch(ContextAttribute) {
  3517. case SECPKG_ATTR_USE_VALIDATED:
  3518. if ( BufferSize != sizeof(SavedUseValidated) ) {
  3519. Status = STATUS_INVALID_PARAMETER;
  3520. goto Cleanup;
  3521. }
  3522. SavedUseValidated = *(LPDWORD)LocalBuffer;
  3523. break;
  3524. case SECPKG_ATTR_CREDENTIAL_NAME:
  3525. if ( BufferSize <= sizeof(SecPkgContext_CredentialNameW) ) {
  3526. Status = STATUS_INVALID_PARAMETER;
  3527. goto Cleanup;
  3528. }
  3529. // Sanity check the pointer and the contained string.
  3530. CredentialNameInfo = (PSecPkgContext_CredentialNameW) LocalBuffer;
  3531. SavedCredentialType = CredentialNameInfo->CredentialType;
  3532. // I'm guessing at the offset of the string.
  3533. wcscpy( SavedCredentialName, (LPWSTR)(CredentialNameInfo+1) );
  3534. break;
  3535. default:
  3536. Status = STATUS_NOT_SUPPORTED;
  3537. break;
  3538. }
  3539. Cleanup:
  3540. if (Context != NULL) {
  3541. SspContextDereferenceContext( Context );
  3542. }
  3543. if ( LocalBuffer != NULL ) {
  3544. NtLmFreePrivateHeap( LocalBuffer );
  3545. }
  3546. SspPrint((SSP_API, "Leaving SpSetContextAttributes for ctxt:0x%x, Attr:0x%x\n", ContextHandle, ContextAttribute));
  3547. return (SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  3548. }
  3549. #endif