Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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