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

2389 lines
79 KiB

  1. /*++
  2. Copyright (c) 1993-2000 Microsoft Corporation
  3. Module Name:
  4. ctxtsrv.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. JClark 28-Jun-2000 Added WMI Trace Logging Support
  12. --*/
  13. //
  14. // Common include files.
  15. //
  16. #include <global.h>
  17. #include <align.h> // ALIGN_WCHAR, etc
  18. #include "Trace.h"
  19. NTSTATUS
  20. SsprHandleNegotiateMessage(
  21. IN ULONG_PTR CredentialHandle,
  22. IN OUT PULONG_PTR ContextHandle,
  23. IN ULONG ContextReqFlags,
  24. IN ULONG InputTokenSize,
  25. IN PVOID InputToken,
  26. IN OUT PULONG OutputTokenSize,
  27. OUT PVOID *OutputToken,
  28. OUT PULONG ContextAttributes,
  29. OUT PTimeStamp ExpirationTime
  30. )
  31. /*++
  32. Routine Description:
  33. Handle the Negotiate message part of AcceptSecurityContext.
  34. Arguments:
  35. All arguments same as for AcceptSecurityContext
  36. Return Value:
  37. STATUS_SUCCESS - Message handled
  38. SEC_I_CONTINUE_NEEDED -- Caller should call again later
  39. SEC_E_INVALID_TOKEN -- Token improperly formatted
  40. SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
  41. SEC_E_BUFFER_TOO_SMALL -- Buffer for output token isn't big enough
  42. SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
  43. --*/
  44. {
  45. NTSTATUS Status = STATUS_SUCCESS;
  46. PSSP_CONTEXT Context = NULL;
  47. PSSP_CREDENTIAL Credential = NULL;
  48. STRING TargetName;
  49. ULONG TargetFlags = 0;
  50. PNEGOTIATE_MESSAGE NegotiateMessage = NULL;
  51. PCHALLENGE_MESSAGE ChallengeMessage = NULL;
  52. ULONG ChallengeMessageSize = 0;
  53. PCHAR Where = NULL;
  54. ULONG NegotiateFlagsKeyStrength;
  55. UNICODE_STRING NtLmLocalUnicodeTargetName;
  56. UNICODE_STRING TargetInfo;
  57. STRING NtLmLocalOemTargetName;
  58. STRING OemWorkstationName;
  59. STRING OemDomainName;
  60. SspPrint(( SSP_API_MORE, "Entering SsprNegotiateMessage\n" ));
  61. //
  62. // Initialization
  63. //
  64. *ContextAttributes = 0;
  65. RtlInitString( &TargetName, NULL );
  66. RtlInitUnicodeString( &NtLmLocalUnicodeTargetName, NULL );
  67. RtlInitString( &NtLmLocalOemTargetName, NULL );
  68. RtlInitUnicodeString( &TargetInfo, NULL );
  69. //
  70. // Get a pointer to the credential
  71. //
  72. Status = SspCredentialReferenceCredential(
  73. CredentialHandle,
  74. FALSE,
  75. &Credential );
  76. if ( !NT_SUCCESS( Status ) ) {
  77. SspPrint(( SSP_CRITICAL,
  78. "SsprHandleNegotiateMessage: invalid credential handle.\n" ));
  79. goto Cleanup;
  80. }
  81. if ( (Credential->CredentialUseFlags & SECPKG_CRED_INBOUND) == 0 ) {
  82. Status = SEC_E_INVALID_CREDENTIAL_USE;
  83. SspPrint(( SSP_CRITICAL,
  84. "SsprHandleNegotiateMessage: invalid credential use.\n" ));
  85. goto Cleanup;
  86. }
  87. //
  88. // Allocate a new context
  89. //
  90. Context = SspContextAllocateContext( );
  91. if ( Context == NULL ) {
  92. Status = STATUS_NO_MEMORY;
  93. SspPrint(( SSP_CRITICAL,
  94. "SsprHandleNegotiateMessage: SspContextAllocateContext() returned NULL.\n" ));
  95. goto Cleanup;
  96. }
  97. //
  98. // Build a handle to the newly created context.
  99. //
  100. *ContextHandle = (ULONG_PTR) Context;
  101. if ( (ContextReqFlags & ASC_REQ_IDENTIFY) != 0 ) {
  102. *ContextAttributes |= ASC_RET_IDENTIFY;
  103. Context->ContextFlags |= ASC_RET_IDENTIFY;
  104. }
  105. if ( (ContextReqFlags & ASC_REQ_DATAGRAM) != 0 ) {
  106. *ContextAttributes |= ASC_RET_DATAGRAM;
  107. Context->ContextFlags |= ASC_RET_DATAGRAM;
  108. }
  109. if ( (ContextReqFlags & ASC_REQ_CONNECTION) != 0 ) {
  110. *ContextAttributes |= ASC_RET_CONNECTION;
  111. Context->ContextFlags |= ASC_RET_CONNECTION;
  112. }
  113. if ( (ContextReqFlags & ASC_REQ_INTEGRITY) != 0 ) {
  114. *ContextAttributes |= ASC_RET_INTEGRITY;
  115. Context->ContextFlags |= ASC_RET_INTEGRITY;
  116. }
  117. if ( (ContextReqFlags & ASC_REQ_REPLAY_DETECT) != 0){
  118. *ContextAttributes |= ASC_RET_REPLAY_DETECT;
  119. Context->ContextFlags |= ASC_RET_REPLAY_DETECT;
  120. }
  121. if ( (ContextReqFlags & ASC_REQ_SEQUENCE_DETECT ) != 0) {
  122. *ContextAttributes |= ASC_RET_SEQUENCE_DETECT;
  123. Context->ContextFlags |= ASC_RET_SEQUENCE_DETECT;
  124. }
  125. // Nothing to return, we might need this on the next server side call.
  126. if ( (ContextReqFlags & ASC_REQ_ALLOW_NULL_SESSION ) != 0) {
  127. Context->ContextFlags |= ASC_REQ_ALLOW_NULL_SESSION;
  128. }
  129. if ( (ContextReqFlags & ASC_REQ_ALLOW_NON_USER_LOGONS ) != 0) {
  130. *ContextAttributes |= ASC_RET_ALLOW_NON_USER_LOGONS;
  131. Context->ContextFlags |= ASC_RET_ALLOW_NON_USER_LOGONS;
  132. }
  133. if ( ContextReqFlags & ASC_REQ_CONFIDENTIALITY ) {
  134. if (NtLmGlobalEncryptionEnabled) {
  135. *ContextAttributes |= ASC_RET_CONFIDENTIALITY;
  136. Context->ContextFlags |= ASC_RET_CONFIDENTIALITY;
  137. } else {
  138. Status = STATUS_NOT_SUPPORTED;
  139. SspPrint(( SSP_CRITICAL,
  140. "SsprHandleNegotiateMessage: invalid ContextReqFlags 0x%lx\n", ContextReqFlags ));
  141. goto Cleanup;
  142. }
  143. }
  144. //
  145. // Supported key strength(s)
  146. //
  147. NegotiateFlagsKeyStrength = NTLMSSP_NEGOTIATE_56;
  148. NegotiateFlagsKeyStrength |= NTLMSSP_NEGOTIATE_128;
  149. //
  150. // Get the NegotiateMessage. If we are re-establishing a datagram
  151. // context then there may not be one.
  152. //
  153. if ( InputTokenSize >= sizeof(OLD_NEGOTIATE_MESSAGE) ) {
  154. Status = SspContextGetMessage( InputToken,
  155. InputTokenSize,
  156. NtLmNegotiate,
  157. (PVOID *)&NegotiateMessage );
  158. if ( !NT_SUCCESS(Status) ) {
  159. SspPrint(( SSP_CRITICAL,
  160. "SsprHandleNegotiateMessage: "
  161. "NegotiateMessage GetMessage returns 0x%lx\n",
  162. Status ));
  163. goto Cleanup;
  164. }
  165. //
  166. // Compute the TargetName to return in the ChallengeMessage.
  167. //
  168. if ( NegotiateMessage->NegotiateFlags & NTLMSSP_REQUEST_TARGET ||
  169. NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2 ) {
  170. RtlAcquireResourceShared(&NtLmGlobalCritSect, TRUE);
  171. if ( NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_UNICODE) {
  172. Status = NtLmDuplicateUnicodeString( &NtLmLocalUnicodeTargetName, &NtLmGlobalUnicodeTargetName );
  173. TargetName = *((PSTRING)&NtLmLocalUnicodeTargetName);
  174. } else {
  175. Status = NtLmDuplicateString( &NtLmLocalOemTargetName, &NtLmGlobalOemTargetName );
  176. TargetName = NtLmLocalOemTargetName;
  177. }
  178. //
  179. // if client is NTLM2-aware, send it target info AV pairs
  180. //
  181. if (NT_SUCCESS(Status))
  182. {
  183. Status = NtLmDuplicateUnicodeString( &TargetInfo, &NtLmGlobalNtLm3TargetInfo );
  184. }
  185. TargetFlags = NtLmGlobalTargetFlags;
  186. RtlReleaseResource (&NtLmGlobalCritSect);
  187. TargetFlags |= NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO;
  188. if (!NT_SUCCESS(Status)) {
  189. SspPrint(( SSP_CRITICAL,
  190. "SsprHandleNegotiateMessage: "
  191. "failed to duplicate UnicodeTargetName or OemTargetName error 0x%lx\n",
  192. Status ));
  193. goto Cleanup;
  194. }
  195. } else {
  196. TargetFlags = 0;
  197. }
  198. if (NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) {
  199. if (InputTokenSize >= RTL_SIZEOF_THROUGH_FIELD(NEGOTIATE_MESSAGE, Version)) {
  200. C_ASSERT(sizeof(NTLM_VER_INFO) == sizeof(ULONG64));
  201. RtlCopyMemory(&Context->ClientVersion, &NegotiateMessage->Version, sizeof(NegotiateMessage->Version));
  202. SspPrint(( SSP_VERSION,
  203. "SsprHandleNegotiateMessage: ClientVersion %#I64x, Major %I64d, Minor %I64d, Build %I64d, Revision %I64d\n",
  204. NegotiateMessage->Version,
  205. Context->ClientVersion.Major,
  206. Context->ClientVersion.Minor,
  207. Context->ClientVersion.Build,
  208. Context->ClientVersion.Revision ));
  209. } else {
  210. Status = SEC_E_INVALID_TOKEN;
  211. SspPrint(( SSP_CRITICAL,
  212. "SsprHandleNegotiateMessage: NegotiateMessage size too small with NTLMSSP_NEGOTIATE_VERSION\n" ));
  213. goto Cleanup;
  214. }
  215. }
  216. //
  217. // Allocate a Challenge message
  218. //
  219. ChallengeMessageSize = sizeof(*ChallengeMessage) +
  220. TargetName.Length +
  221. TargetInfo.Length;
  222. if ((ContextReqFlags & ASC_REQ_ALLOCATE_MEMORY) == 0)
  223. {
  224. if ( ChallengeMessageSize > *OutputTokenSize ) {
  225. SspPrint(( SSP_CRITICAL,
  226. "SsprHandleNegotiateMessage: invalid ChallengeMessageSize\n"));
  227. Status = SEC_E_BUFFER_TOO_SMALL;
  228. goto Cleanup;
  229. }
  230. }
  231. ChallengeMessage = (PCHALLENGE_MESSAGE)
  232. NtLmAllocateLsaHeap( ChallengeMessageSize );
  233. if ( ChallengeMessage == NULL ) {
  234. SspPrint(( SSP_CRITICAL,
  235. "SsprHandleNegotiateMessage: Error allocating ChallengeMessage.\n" ));
  236. Status = STATUS_NO_MEMORY;
  237. goto Cleanup;
  238. }
  239. ChallengeMessage->NegotiateFlags = NTLMSSP_NEGOTIATE_VERSION;
  240. //
  241. // Check that both sides can use the same authentication model. For
  242. // compatibility with beta 1 and 2 (builds 612 and 683), no requested
  243. // authentication type is assumed to be NTLM. If NetWare is explicitly
  244. // asked for, it is assumed that NTLM would have been also, so if it
  245. // wasn't, return an error.
  246. //
  247. if ( (NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NETWARE) &&
  248. ((NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM) == 0) &&
  249. ((NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) == 0)
  250. ) {
  251. Status = STATUS_NOT_SUPPORTED;
  252. SspPrint(( SSP_CRITICAL,
  253. "SsprHandleNegotiateMessage: "
  254. "NegotiateMessage asked for Netware only.\n" ));
  255. goto Cleanup;
  256. } else {
  257. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLM;
  258. }
  259. //
  260. // if client can do NTLM2, nuke LM_KEY
  261. //
  262. if (NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) {
  263. NegotiateMessage->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
  264. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLM2;
  265. } else if (NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) {
  266. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_LM_KEY;
  267. }
  268. //
  269. // If the client wants to always sign messages, so be it.
  270. //
  271. if (NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN ) {
  272. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
  273. }
  274. //
  275. // If the caller wants identify level, so be it.
  276. //
  277. if (NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_IDENTIFY ) {
  278. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_IDENTIFY;
  279. *ContextAttributes |= ASC_RET_IDENTIFY;
  280. Context->ContextFlags |= ASC_RET_IDENTIFY;
  281. }
  282. //
  283. // Determine if the caller wants OEM or UNICODE
  284. //
  285. // Prefer UNICODE if caller allows both.
  286. //
  287. if ( NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_UNICODE ) {
  288. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE;
  289. } else if ( NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_OEM ){
  290. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_OEM;
  291. } else {
  292. Status = SEC_E_INVALID_TOKEN;
  293. SspPrint(( SSP_CRITICAL,
  294. "SsprHandleNegotiateMessage: "
  295. "NegotiateMessage bad NegotiateFlags 0x%lx\n",
  296. NegotiateMessage->NegotiateFlags ));
  297. goto Cleanup;
  298. }
  299. //
  300. // Client wants Sign capability, OK.
  301. //
  302. if (NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN) {
  303. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
  304. *ContextAttributes |= (ASC_RET_SEQUENCE_DETECT | ASC_RET_REPLAY_DETECT);
  305. Context->ContextFlags |= (ASC_RET_SEQUENCE_DETECT | ASC_RET_REPLAY_DETECT);
  306. }
  307. //
  308. // Client wants Seal, OK.
  309. //
  310. if (NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_SEAL)
  311. {
  312. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
  313. *ContextAttributes |= ASC_RET_CONFIDENTIALITY;
  314. Context->ContextFlags |= ASC_RET_CONFIDENTIALITY;
  315. }
  316. if (NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
  317. {
  318. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH;
  319. }
  320. if ( (NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_56) &&
  321. (NegotiateFlagsKeyStrength & NTLMSSP_NEGOTIATE_56) )
  322. {
  323. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_56;
  324. }
  325. if ( (NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_128) &&
  326. (NegotiateFlagsKeyStrength & NTLMSSP_NEGOTIATE_128) )
  327. {
  328. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_128;
  329. }
  330. //
  331. // If the client supplied the Domain Name and User Name,
  332. // and did not request datagram, see if the client is running
  333. // on this local machine.
  334. //
  335. if ( ( (NegotiateMessage->NegotiateFlags &
  336. NTLMSSP_NEGOTIATE_DATAGRAM) == 0) &&
  337. ( (NegotiateMessage->NegotiateFlags &
  338. (NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED|
  339. NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED)) ==
  340. (NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED|
  341. NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED) ) ) {
  342. //
  343. // The client must pass the new negotiate message if they pass
  344. // these flags
  345. //
  346. if (InputTokenSize < RTL_SIZEOF_THROUGH_FIELD(NEGOTIATE_MESSAGE, OemWorkstationName)) {
  347. Status = SEC_E_INVALID_TOKEN;
  348. SspPrint(( SSP_CRITICAL,
  349. "SsprHandleNegotiateMessage: invalid InputTokenSize.\n" ));
  350. goto Cleanup;
  351. }
  352. //
  353. // Convert the names to absolute references so we
  354. // can compare them
  355. //
  356. if ( !SspConvertRelativeToAbsolute(
  357. NegotiateMessage,
  358. InputTokenSize,
  359. &NegotiateMessage->OemDomainName,
  360. &OemDomainName,
  361. FALSE, // No special alignment
  362. FALSE ) ) { // NULL not OK
  363. Status = SEC_E_INVALID_TOKEN;
  364. SspPrint(( SSP_CRITICAL,
  365. "SsprHandleNegotiateMessage: Error from SspConvertRelativeToAbsolute.\n" ));
  366. goto Cleanup;
  367. }
  368. if ( !SspConvertRelativeToAbsolute(
  369. NegotiateMessage,
  370. InputTokenSize,
  371. &NegotiateMessage->OemWorkstationName,
  372. &OemWorkstationName,
  373. FALSE, // No special alignment
  374. FALSE ) ) { // NULL not OK
  375. Status = SEC_E_INVALID_TOKEN;
  376. SspPrint(( SSP_CRITICAL,
  377. "SsprHandleNegotiateMessage: Error from SspConvertRelativeToAbsolute.\n" ));
  378. goto Cleanup;
  379. }
  380. //
  381. // If both strings match,
  382. // this is a local call.
  383. // The strings have already been uppercased.
  384. //
  385. RtlAcquireResourceShared(&NtLmGlobalCritSect, TRUE);
  386. if ( RtlEqualString( &OemWorkstationName,
  387. &NtLmGlobalOemComputerNameString,
  388. FALSE ) &&
  389. RtlEqualString( &OemDomainName,
  390. &NtLmGlobalOemPrimaryDomainNameString,
  391. FALSE )
  392. )
  393. {
  394. #if DBG
  395. IF_DEBUG( NO_LOCAL ) {
  396. // nothing.
  397. } else {
  398. #endif
  399. ChallengeMessage->NegotiateFlags |=
  400. NTLMSSP_NEGOTIATE_LOCAL_CALL;
  401. SspPrint(( SSP_MISC,
  402. "SsprHandleNegotiateMessage: Local Call.\n" ));
  403. ChallengeMessage->ServerContextHandle = (ULONG64)*ContextHandle;
  404. #if DBG
  405. }
  406. #endif
  407. }
  408. RtlReleaseResource (&NtLmGlobalCritSect);
  409. }
  410. //
  411. // Check if datagram is being negotiated
  412. //
  413. if ( (NegotiateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) ==
  414. NTLMSSP_NEGOTIATE_DATAGRAM) {
  415. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_DATAGRAM;
  416. }
  417. } else {
  418. //
  419. // No negotiate message. We need to check if the caller is asking
  420. // for datagram.
  421. //
  422. if ((ContextReqFlags & ASC_REQ_DATAGRAM) == 0 ) {
  423. SspPrint(( SSP_CRITICAL,
  424. "SsprHandleNegotiateMessage: "
  425. "NegotiateMessage size wrong %ld\n",
  426. InputTokenSize ));
  427. Status = SEC_E_INVALID_TOKEN;
  428. goto Cleanup;
  429. }
  430. //
  431. // always send target info -- new for NTLM3!
  432. //
  433. TargetFlags = NTLMSSP_NEGOTIATE_TARGET_INFO;
  434. RtlAcquireResourceShared(&NtLmGlobalCritSect, TRUE);
  435. Status = NtLmDuplicateUnicodeString( &TargetInfo, &NtLmGlobalNtLm3TargetInfo );
  436. RtlReleaseResource(&NtLmGlobalCritSect);
  437. if ( !NT_SUCCESS(Status) ) {
  438. SspPrint(( SSP_CRITICAL,
  439. "SsprHandleNegotiateMessage(datagram): Error duplicate TargetInfo %#x\n", Status ));
  440. goto Cleanup;
  441. }
  442. //
  443. // Allocate a Challenge message
  444. //
  445. ChallengeMessageSize = sizeof(*ChallengeMessage) + TargetInfo.Length;
  446. if ((ContextReqFlags & ASC_REQ_ALLOCATE_MEMORY) == 0)
  447. {
  448. if ( ChallengeMessageSize > *OutputTokenSize ) {
  449. Status = SEC_E_BUFFER_TOO_SMALL;
  450. SspPrint(( SSP_CRITICAL,
  451. "SsprHandleNegotiateMessage: invalid ChallengeMessageSize.\n" ));
  452. goto Cleanup;
  453. }
  454. }
  455. ChallengeMessage = (PCHALLENGE_MESSAGE)
  456. NtLmAllocateLsaHeap(ChallengeMessageSize );
  457. if ( ChallengeMessage == NULL ) {
  458. Status = STATUS_NO_MEMORY;
  459. SspPrint(( SSP_CRITICAL,
  460. "SsprHandleNegotiateMessage: Error allocating ChallengeMessage.\n" ));
  461. goto Cleanup;
  462. }
  463. //
  464. // Record in the context that we are doing datagram. We will tell
  465. // the client everything we can negotiate and let it decide what
  466. // to negotiate.
  467. //
  468. ChallengeMessage->NegotiateFlags = NTLMSSP_NEGOTIATE_DATAGRAM |
  469. NTLMSSP_NEGOTIATE_UNICODE |
  470. NTLMSSP_NEGOTIATE_OEM |
  471. NTLMSSP_NEGOTIATE_SIGN |
  472. NTLMSSP_NEGOTIATE_LM_KEY |
  473. NTLMSSP_NEGOTIATE_NTLM |
  474. NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
  475. NTLMSSP_NEGOTIATE_IDENTIFY |
  476. NTLMSSP_NEGOTIATE_NTLM2 |
  477. NTLMSSP_NEGOTIATE_KEY_EXCH |
  478. NegotiateFlagsKeyStrength |
  479. NTLMSSP_NEGOTIATE_VERSION;
  480. if (NtLmGlobalEncryptionEnabled) {
  481. ChallengeMessage->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
  482. }
  483. }
  484. //
  485. // Build the Challenge Message
  486. //
  487. strcpy( (char *) ChallengeMessage->Signature, NTLMSSP_SIGNATURE );
  488. ChallengeMessage->MessageType = NtLmChallenge;
  489. ChallengeMessage->Version = NTLMSSP_ENGINE_VERSION;
  490. Status = SspGenerateRandomBits( (UCHAR*)ChallengeMessage->Challenge,
  491. MSV1_0_CHALLENGE_LENGTH );
  492. if ( !NT_SUCCESS( Status ) ) {
  493. SspPrint(( SSP_CRITICAL,
  494. "SsprHandleNegotiateMessage: SspGenerateRandomBits failed\n"));
  495. goto Cleanup;
  496. }
  497. Where = (PCHAR)(ChallengeMessage + 1);
  498. SspContextCopyString( ChallengeMessage,
  499. &ChallengeMessage->TargetName,
  500. &TargetName,
  501. &Where );
  502. SspContextCopyString( ChallengeMessage,
  503. &ChallengeMessage->TargetInfo,
  504. (PSTRING)&TargetInfo,
  505. &Where );
  506. ChallengeMessage->NegotiateFlags |= TargetFlags;
  507. //
  508. // Save the Challenge and Negotiate Flags in the Context so it
  509. // is available when the authenticate message comes in.
  510. //
  511. RtlCopyMemory( Context->Challenge,
  512. ChallengeMessage->Challenge,
  513. sizeof( Context->Challenge ) );
  514. Context->NegotiateFlags = ChallengeMessage->NegotiateFlags;
  515. if (!SsprCheckMinimumSecurity(
  516. Context->NegotiateFlags,
  517. NtLmGlobalMinimumServerSecurity)) {
  518. Status = SEC_E_UNSUPPORTED_FUNCTION;
  519. SspPrint(( SSP_CRITICAL,
  520. "SsprHandleNegotiateMessage: "
  521. "NegotiateMessage didn't support minimum security requirements. (caller=0x%lx wanted=0x%lx\n",
  522. Context->NegotiateFlags, NtLmGlobalMinimumServerSecurity ));
  523. goto Cleanup;
  524. }
  525. if ((ContextReqFlags & ASC_REQ_ALLOCATE_MEMORY) == 0)
  526. {
  527. RtlCopyMemory( *OutputToken,
  528. ChallengeMessage,
  529. ChallengeMessageSize );
  530. }
  531. else
  532. {
  533. *OutputToken = ChallengeMessage;
  534. ChallengeMessage = NULL;
  535. *ContextAttributes |= ASC_RET_ALLOCATED_MEMORY;
  536. }
  537. *OutputTokenSize = ChallengeMessageSize;
  538. //
  539. // Return output parameters to the caller.
  540. //
  541. *ExpirationTime = SspContextGetTimeStamp( Context, TRUE );
  542. Context->State = ChallengeSentState;
  543. Status = SEC_I_CONTINUE_NEEDED;
  544. //
  545. // Free and locally used resources.
  546. //
  547. Cleanup:
  548. if ( Context != NULL ) {
  549. //
  550. // If we failed, deallocate the context we allocated above.
  551. // Delinking is a side effect of referencing, so do that.
  552. //
  553. if ( !NT_SUCCESS(Status) ) {
  554. PSSP_CONTEXT LocalContext;
  555. SspContextReferenceContext( *ContextHandle,
  556. TRUE,
  557. &LocalContext
  558. );
  559. ASSERT( LocalContext != NULL );
  560. if ( LocalContext != NULL ) {
  561. SspContextDereferenceContext( LocalContext );
  562. }
  563. }
  564. // Always dereference it.
  565. SspContextDereferenceContext( Context );
  566. }
  567. if ( NegotiateMessage != NULL ) {
  568. (VOID) NtLmFreePrivateHeap( NegotiateMessage );
  569. }
  570. if ( ChallengeMessage != NULL ) {
  571. (VOID) NtLmFreeLsaHeap( ChallengeMessage );
  572. }
  573. if ( Credential != NULL ) {
  574. SspCredentialDereferenceCredential( Credential );
  575. }
  576. if ( NtLmLocalUnicodeTargetName.Buffer != NULL ) {
  577. (VOID) NtLmFreePrivateHeap( NtLmLocalUnicodeTargetName.Buffer );
  578. }
  579. if ( NtLmLocalOemTargetName.Buffer != NULL ) {
  580. (VOID) NtLmFreePrivateHeap( NtLmLocalOemTargetName.Buffer );
  581. }
  582. if (TargetInfo.Buffer != NULL ) {
  583. (VOID) NtLmFreePrivateHeap( TargetInfo.Buffer );
  584. }
  585. SspPrint(( SSP_API_MORE, "Leaving SsprHandleNegotiateMessage: 0x%lx\n", Status ));
  586. return Status;
  587. }
  588. NTSTATUS
  589. SsprHandleAuthenticateMessage(
  590. IN LSA_SEC_HANDLE CredentialHandle,
  591. IN OUT PLSA_SEC_HANDLE ContextHandle,
  592. IN ULONG ContextReqFlags,
  593. IN ULONG InputTokenSize,
  594. IN PVOID InputToken,
  595. IN ULONG SecondInputTokenSize,
  596. IN PVOID SecondInputToken,
  597. IN OUT PULONG OutputTokenSize,
  598. OUT PVOID *OutputToken,
  599. OUT PULONG ContextAttributes,
  600. OUT PTimeStamp ExpirationTime,
  601. OUT PUCHAR SessionKey,
  602. OUT PULONG NegotiateFlags,
  603. OUT PHANDLE TokenHandle,
  604. OUT PNTSTATUS ApiSubStatus,
  605. OUT PTimeStamp PasswordExpiry,
  606. OUT PULONG UserFlags
  607. )
  608. /*++
  609. Routine Description:
  610. Handle the authenticate message part of AcceptSecurityContext.
  611. Arguments:
  612. SessionKey - The session key for the context, used for signing and sealing
  613. NegotiateFlags - The flags negotiated for the context, used for sign & seal
  614. ApiSubStatus - Returns the substatus for why the logon failed.
  615. PasswordExpiry - Contains the time that the authenticated user's password
  616. expires, or 0x7fffffff ffffffff for local callers.
  617. UserFlags - UserFlags returned in LogonProfile.
  618. All other arguments same as for AcceptSecurityContext
  619. Return Value:
  620. STATUS_SUCCESS - Message handled
  621. SEC_E_INVALID_TOKEN -- Token improperly formatted
  622. SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
  623. SEC_E_BUFFER_TOO_SMALL -- Buffer for output token isn't big enough
  624. SEC_E_LOGON_DENIED -- User is no allowed to logon to this server
  625. SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
  626. --*/
  627. {
  628. SECURITY_STATUS SecStatus = STATUS_SUCCESS;
  629. NTSTATUS Status = STATUS_SUCCESS;
  630. PSSP_CONTEXT Context = NULL;
  631. PNEGOTIATE_MESSAGE NegotiateMessage = NULL;
  632. PAUTHENTICATE_MESSAGE AuthenticateMessage = NULL;
  633. PNTLM_AUTHENTICATE_MESSAGE NtLmAuthenticateMessage = NULL;
  634. PNTLM_ACCEPT_RESPONSE NtLmAcceptResponse = NULL;
  635. ULONG MsvLogonMessageSize = 0;
  636. PMSV1_0_LM20_LOGON MsvLogonMessage = NULL;
  637. ULONG MsvSubAuthLogonMessageSize = 0;
  638. PMSV1_0_SUBAUTH_LOGON MsvSubAuthLogonMessage = NULL;
  639. ULONG LogonProfileMessageSize;
  640. PMSV1_0_LM20_LOGON_PROFILE LogonProfileMessage = NULL;
  641. LSA_TOKEN_INFORMATION_TYPE TokenInformationType = LsaTokenInformationNull;
  642. BOOLEAN DoUnicode = FALSE;
  643. STRING DomainName2;
  644. STRING UserName2;
  645. STRING Workstation2;
  646. STRING SessionKeyString = {0, 0, NULL};
  647. UNICODE_STRING DomainName;
  648. UNICODE_STRING UserName;
  649. UNICODE_STRING Workstation;
  650. LARGE_INTEGER KickOffTime;
  651. LUID LogonId = {0};
  652. HANDLE LocalTokenHandle = NULL;
  653. BOOLEAN LocalTokenHandleOpenned = FALSE;
  654. TOKEN_SOURCE SourceContext;
  655. NTSTATUS SubStatus = STATUS_SUCCESS;
  656. STRING OriginName;
  657. PCHAR Where;
  658. PSSP_CREDENTIAL Credential = NULL;
  659. BOOLEAN fCallFromSrv = FALSE;
  660. PUNICODE_STRING AccountName = NULL;
  661. PUNICODE_STRING AuthenticatingAuthority = NULL;
  662. PUNICODE_STRING WorkstationName = NULL;
  663. STRING NtChallengeResponse;
  664. STRING LmChallengeResponse;
  665. BOOL fSubAuth = FALSE;
  666. ULONG SubAuthPackageId = 0;
  667. PSID AllocatedAuditSid = NULL ;
  668. PSID AuditSid = NULL;
  669. BOOLEAN fAvoidGuestAudit = FALSE;
  670. SECPKG_PRIMARY_CRED PrimaryCredentials;
  671. BOOL IsDatagramLmKeyCorrectionOn = FALSE;
  672. //Tracing State
  673. NTLM_TRACE_INFO TraceInfo = {0};
  674. PLSA_SEC_HANDLE TraceOldContextHandle = ContextHandle;
  675. ASSERT(LM_RESPONSE_LENGTH >= MSV1_0_USER_SESSION_KEY_LENGTH);
  676. SspPrint(( SSP_API_MORE, "Entering SsprHandleAuthenticateMessage\n"));
  677. //
  678. // Initialization
  679. //
  680. *ContextAttributes = 0;
  681. RtlInitUnicodeString(
  682. &DomainName,
  683. NULL
  684. );
  685. RtlInitUnicodeString(
  686. &UserName,
  687. NULL
  688. );
  689. RtlInitUnicodeString(
  690. &Workstation,
  691. NULL
  692. );
  693. *ApiSubStatus = STATUS_SUCCESS;
  694. PasswordExpiry->LowPart = 0xffffffff;
  695. PasswordExpiry->HighPart = 0x7fffffff;
  696. *UserFlags = 0;
  697. RtlZeroMemory(&PrimaryCredentials, sizeof(SECPKG_PRIMARY_CRED));
  698. if (*ContextHandle == NULL)
  699. {
  700. // This is possibly an old style srv call (for 4.0 and before)
  701. // so, alloc the context and replace the creds if new ones exists
  702. fCallFromSrv = TRUE;
  703. SspPrint((SSP_API_MORE, "SsprHandleAuthenticateMessage: *ContextHandle is NULL (old style SRV)\n"));
  704. SECPKG_CALL_INFO CallInfo = {0};
  705. //
  706. // Client must have TCB, otherwise an un-trusted LSA-client could use a
  707. // stolen challenge/response pair to network logon any user
  708. //
  709. if ( !LsaFunctions->GetCallInfo( &CallInfo ) ||
  710. ((CallInfo.Attributes & SECPKG_CALL_IS_TCB) == 0)
  711. )
  712. {
  713. SecStatus = STATUS_PRIVILEGE_NOT_HELD;
  714. SspPrint((SSP_CRITICAL,
  715. "SsprHandleAuthenticateMessage: Client does not hold Tcb\n"));
  716. goto Cleanup;
  717. }
  718. SecStatus = SspCredentialReferenceCredential(
  719. CredentialHandle,
  720. FALSE,
  721. &Credential );
  722. if ( !NT_SUCCESS( SecStatus ) )
  723. {
  724. SspPrint(( SSP_CRITICAL,
  725. "SsprHandleAuthenticateMessage: SspCredentialReferenceCredential returns %x.\n", SecStatus ));
  726. goto Cleanup;
  727. }
  728. // check the validity of the NtlmAuthenticateMessage
  729. if (SecondInputTokenSize < sizeof(NTLM_AUTHENTICATE_MESSAGE))
  730. {
  731. SspPrint(( SSP_CRITICAL,
  732. "SsprHandleAuthenticateMessage: NtlmAuthenticateMessage size if bogus.\n" ));
  733. SecStatus = SEC_E_INVALID_TOKEN;
  734. goto Cleanup;
  735. }
  736. // This is a superflous check since we alloc only if the caller
  737. // has asked us too. This is to make sure that the srv always allocs
  738. if (ContextReqFlags & ISC_REQ_ALLOCATE_MEMORY)
  739. {
  740. SspPrint(( SSP_CRITICAL,
  741. "SsprHandleAuthenticateMessage: ContextReqFlags has ISC_REQ_ALLOCATE_MEMORY.\n" ));
  742. SecStatus = STATUS_NOT_SUPPORTED;
  743. goto Cleanup;
  744. }
  745. if (*OutputTokenSize < sizeof(NTLM_ACCEPT_RESPONSE))
  746. {
  747. SspPrint(( SSP_CRITICAL,
  748. "SsprHandleAuthenticateMessage: NtlmAcceptResponse size if bogus.\n" ));
  749. SecStatus = SEC_E_INVALID_TOKEN;
  750. goto Cleanup;
  751. }
  752. //
  753. // Allocate a new context
  754. //
  755. Context = SspContextAllocateContext();
  756. if (Context == NULL)
  757. {
  758. SspPrint(( SSP_CRITICAL,
  759. "SsprHandleAuthenticateMessage: SspContextAllocateContext returns NULL.\n" ));
  760. SecStatus = STATUS_NO_MEMORY;
  761. goto Cleanup;
  762. }
  763. // We've just added a context, we don't nornally add and then
  764. // reference it.
  765. SspContextDereferenceContext( Context );
  766. *ContextHandle = (LSA_SEC_HANDLE) Context;
  767. // Assign the Credential
  768. Context->Credential = Credential;
  769. Credential = NULL;
  770. NtLmAuthenticateMessage = (PNTLM_AUTHENTICATE_MESSAGE) SecondInputToken;
  771. if (NtLmAuthenticateMessage == NULL)
  772. {
  773. SspPrint(( SSP_CRITICAL,
  774. "SsprHandleAuthenticateMessage: Error while assigning NtLmAuthenticateMessage\n" ));
  775. SecStatus = STATUS_NO_MEMORY;
  776. goto Cleanup;
  777. }
  778. // copy challenge from NTLM_AUTHENTICATE_MESSAGE
  779. RtlCopyMemory(Context->Challenge,
  780. NtLmAuthenticateMessage->ChallengeToClient,
  781. MSV1_0_CHALLENGE_LENGTH);
  782. if (NtLmAuthenticateMessage->ParameterControl & MSV1_0_SUBAUTHENTICATION_FLAGS)
  783. {
  784. fSubAuth = TRUE;
  785. SubAuthPackageId = (NtLmAuthenticateMessage->ParameterControl >>
  786. MSV1_0_SUBAUTHENTICATION_DLL_SHIFT)
  787. ;
  788. }
  789. Context->State = ChallengeSentState;
  790. Context->NegotiateFlags = NTLMSSP_NEGOTIATE_UNICODE ;
  791. //
  792. // The server may request this option with a <= 4.0 client, in
  793. // which case HandleNegotiateMessage, which normally sets
  794. // this flag, won't have been called.
  795. //
  796. if ( (ContextReqFlags & ASC_REQ_ALLOW_NON_USER_LOGONS ) != 0) {
  797. *ContextAttributes |= ASC_RET_ALLOW_NON_USER_LOGONS;
  798. Context->ContextFlags |= ASC_RET_ALLOW_NON_USER_LOGONS;
  799. }
  800. }
  801. //
  802. // Find the currently existing context.
  803. //
  804. SecStatus = SspContextReferenceContext( *ContextHandle, FALSE, &Context );
  805. if ( !NT_SUCCESS(SecStatus) )
  806. {
  807. SspPrint(( SSP_CRITICAL,
  808. "SsprHandleAuthenticateMessage: Error from SspContextReferenceContext.\n" ));
  809. goto Cleanup;
  810. }
  811. if ( ( Context->State != ChallengeSentState) &&
  812. ( Context->State != AuthenticatedState) ) {
  813. SspPrint(( SSP_CRITICAL,
  814. "SsprHandleAuthenticateMessage: "
  815. "Context not in ChallengeSentState\n" ));
  816. SecStatus = SEC_E_OUT_OF_SEQUENCE;
  817. goto Cleanup;
  818. }
  819. //
  820. // Ignore the Credential Handle.
  821. //
  822. // Since this is the second call,
  823. // the credential is implied by the Context.
  824. // We could double check that the Credential Handle is either NULL or
  825. // correct. However, our implementation doesn't maintain a close
  826. // association between the two (actually no association) so checking
  827. // would require a lot of overhead.
  828. //
  829. UNREFERENCED_PARAMETER( CredentialHandle );
  830. //
  831. // Get the AuthenticateMessage.
  832. //
  833. if ( InputTokenSize < sizeof(OLD_AUTHENTICATE_MESSAGE) ) {
  834. SspPrint(( SSP_CRITICAL,
  835. "SsprHandleAuthenticateMessage: "
  836. "AuthenticateMessage size wrong %ld\n",
  837. InputTokenSize ));
  838. SecStatus = SEC_E_INVALID_TOKEN;
  839. goto Cleanup;
  840. }
  841. SecStatus = SspContextGetMessage( InputToken,
  842. InputTokenSize,
  843. NtLmAuthenticate,
  844. (PVOID *)&AuthenticateMessage );
  845. if ( !NT_SUCCESS(SecStatus) ) {
  846. SspPrint(( SSP_CRITICAL,
  847. "SsprHandleAuthenticateMessage: "
  848. "AuthenticateMessage GetMessage returns 0x%lx\n",
  849. SecStatus ));
  850. goto Cleanup;
  851. }
  852. if (fCallFromSrv)
  853. {
  854. // Copy the Context Negotiate Flags from what's sent in
  855. Context->NegotiateFlags |= AuthenticateMessage->NegotiateFlags;
  856. }
  857. //
  858. // If the call comes and we have already authenticated, then it is
  859. // probably RPC trying to reauthenticate, which happens when someone
  860. // calls two interfaces on the same connection. In this case we don't
  861. // have to do anything - we just return success and let them get on
  862. // with it. We do want to check that the input token is all zeros,
  863. // though.
  864. //
  865. if ( Context->State == AuthenticatedState ) {
  866. AUTHENTICATE_MESSAGE NullMessage;
  867. *OutputTokenSize = 0;
  868. //
  869. // Check that all the fields are null. There are 5 strings
  870. // in the Authenticate message that have to be set to zero.
  871. //
  872. RtlZeroMemory(&NullMessage.LmChallengeResponse, 5 * sizeof(STRING32));
  873. if (memcmp(&AuthenticateMessage->LmChallengeResponse,
  874. &NullMessage.LmChallengeResponse,
  875. sizeof(STRING32) * 5) ) {
  876. SecStatus = SEC_E_INVALID_TOKEN;
  877. SspPrint(( SSP_CRITICAL,
  878. "SsprHandleAuthenticateMessage: "
  879. "AuthenticateMessage->LmChallengeResponse is not zeroed\n"));
  880. }
  881. else
  882. {
  883. *ContextAttributes = SSP_RET_REAUTHENTICATION;
  884. SecStatus = STATUS_SUCCESS;
  885. }
  886. goto Cleanup;
  887. }
  888. //
  889. // If we are re-establishing a datagram context, get the negotiate flags
  890. // out of this message.
  891. //
  892. if ((Context->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) != 0) {
  893. if ((InputTokenSize < RTL_SIZEOF_THROUGH_FIELD(AUTHENTICATE_MESSAGE, NegotiateFlags)) ||
  894. ((AuthenticateMessage->NegotiateFlags &
  895. NTLMSSP_NEGOTIATE_DATAGRAM) == 0) ) {
  896. SecStatus = SEC_E_INVALID_TOKEN;
  897. goto Cleanup;
  898. }
  899. Context->NegotiateFlags = AuthenticateMessage->NegotiateFlags;
  900. //
  901. // always do key exchange with datagram if we need a key (for SIGN or SEAL)
  902. //
  903. if (Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL))
  904. {
  905. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH;
  906. }
  907. //
  908. // if got NTLM2, don't use LM_KEY
  909. //
  910. if ( (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) != 0 )
  911. {
  912. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY ) {
  913. SspPrint(( SSP_NEGOTIATE_FLAGS,
  914. "SsprHandleAuthenticateMessage: "
  915. "AuthenticateMessage (datagram) NTLM2 caused LM_KEY to be disabled.\n" ));
  916. }
  917. Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
  918. }
  919. if (AuthenticateMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
  920. {
  921. if (InputTokenSize >= RTL_SIZEOF_THROUGH_FIELD(AUTHENTICATE_MESSAGE, Version))
  922. {
  923. C_ASSERT(sizeof(NTLM_VER_INFO) == sizeof(ULONG64));
  924. RtlCopyMemory(&Context->ClientVersion, &AuthenticateMessage->Version, sizeof(AuthenticateMessage->Version));
  925. SspPrint(( SSP_VERSION,
  926. "SsprHandleAuthenticateMessage: ClientVersion %#I64x, Major %I64d, Minor %I64d, Build %I64d, Revision %I64d\n",
  927. AuthenticateMessage->Version,
  928. Context->ClientVersion.Major,
  929. Context->ClientVersion.Minor,
  930. Context->ClientVersion.Build,
  931. Context->ClientVersion.Revision ));
  932. }
  933. else
  934. {
  935. SecStatus = SEC_E_INVALID_TOKEN;
  936. SspPrint(( SSP_CRITICAL,
  937. "SsprHandleAuthenticateMessage: AuthenticateMessage size too small with NTLMSSP_NEGOTIATE_VERSION\n" ));
  938. goto Cleanup;
  939. }
  940. }
  941. if ( (Context->ClientVersion.Revision >= NTLMSSP_REVISION_W2K3)
  942. && ((Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_LM_KEY | NTLMSSP_NEGOTIATE_NTLM2)) == 0) )
  943. {
  944. // smartclient knows to turn off LM KEY
  945. SspPrint(( SSP_WARNING, "SsprHandleAuthenticateMessage client turned off LM keys\n" ));
  946. IsDatagramLmKeyCorrectionOn = TRUE;
  947. }
  948. }
  949. //
  950. // Check that client asked for minimum security required.
  951. // not done for legacy down-level case, as, NegotiateFlags are
  952. // constructed from incomplete information.
  953. //
  954. if ( !fCallFromSrv )
  955. {
  956. if (!SsprCheckMinimumSecurity(
  957. AuthenticateMessage->NegotiateFlags,
  958. NtLmGlobalMinimumServerSecurity)) {
  959. SecStatus = SEC_E_UNSUPPORTED_FUNCTION;
  960. SspPrint(( SSP_CRITICAL,
  961. "SsprHandleAuthenticateMessage: "
  962. "client didn't support minimum security requirements.\n" ));
  963. goto Cleanup;
  964. }
  965. }
  966. //
  967. // Convert relative pointers to absolute.
  968. //
  969. DoUnicode = ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_UNICODE ) != 0;
  970. if (!SspConvertRelativeToAbsolute(AuthenticateMessage,
  971. InputTokenSize,
  972. &AuthenticateMessage->LmChallengeResponse,
  973. (PSTRING) &LmChallengeResponse,
  974. FALSE, // No special alignment
  975. TRUE ) ) { // NULL OK
  976. SecStatus = SEC_E_INVALID_TOKEN;
  977. goto Cleanup;
  978. }
  979. if (!SspConvertRelativeToAbsolute(AuthenticateMessage,
  980. InputTokenSize,
  981. &AuthenticateMessage->NtChallengeResponse,
  982. (PSTRING) &NtChallengeResponse,
  983. FALSE, // No special alignment
  984. TRUE ) ) { // NULL OK
  985. SecStatus = SEC_E_INVALID_TOKEN;
  986. goto Cleanup;
  987. }
  988. if (!SspConvertRelativeToAbsolute(AuthenticateMessage,
  989. InputTokenSize,
  990. &AuthenticateMessage->DomainName,
  991. &DomainName2,
  992. DoUnicode, // Unicode alignment
  993. TRUE ) ) { // NULL OK
  994. SecStatus = SEC_E_INVALID_TOKEN;
  995. goto Cleanup;
  996. }
  997. if ( !SspConvertRelativeToAbsolute( AuthenticateMessage,
  998. InputTokenSize,
  999. &AuthenticateMessage->UserName,
  1000. &UserName2,
  1001. DoUnicode, // Unicode alignment
  1002. #ifdef notdef
  1003. //
  1004. // Allow null sessions. The server should guard against them if
  1005. // it doesn't want them.
  1006. //
  1007. FALSE )) { // User name cannot be NULL
  1008. #endif // notdef
  1009. TRUE ) ) { // NULL OK
  1010. SecStatus = SEC_E_INVALID_TOKEN;
  1011. goto Cleanup;
  1012. }
  1013. if ( !SspConvertRelativeToAbsolute( AuthenticateMessage,
  1014. InputTokenSize,
  1015. &AuthenticateMessage->Workstation,
  1016. &Workstation2,
  1017. DoUnicode, // Unicode alignment
  1018. TRUE ) ) { // NULL OK
  1019. SecStatus = SEC_E_INVALID_TOKEN;
  1020. goto Cleanup;
  1021. }
  1022. //
  1023. // If this is datagram, get the session key
  1024. //
  1025. /// if ((Context->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) != 0) {
  1026. if ((Context->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) != 0) {
  1027. if ( !SspConvertRelativeToAbsolute( AuthenticateMessage,
  1028. InputTokenSize,
  1029. &AuthenticateMessage->SessionKey,
  1030. &SessionKeyString,
  1031. FALSE, // No special alignment
  1032. TRUE) ) { // NULL OK
  1033. SecStatus = SEC_E_INVALID_TOKEN;
  1034. goto Cleanup;
  1035. }
  1036. //
  1037. // It should be NULL if this is a local call
  1038. //
  1039. if (((Context->NegotiateFlags & NTLMSSP_NEGOTIATE_LOCAL_CALL) == 0) &&
  1040. (SessionKeyString.Buffer == NULL)) {
  1041. SecStatus = SEC_E_INVALID_TOKEN;
  1042. goto Cleanup;
  1043. }
  1044. if (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_LOCAL_CALL)
  1045. {
  1046. static const UCHAR FixedSessionKey[MSV1_0_USER_SESSION_KEY_LENGTH] = {
  1047. 'S', 'y', 's', 't', 'e', 'm', 'L', 'i',
  1048. 'b', 'r', 'a', 'r', 'y', 'D', 'T', 'C'
  1049. };
  1050. RtlCopyMemory(Context->SessionKey, FixedSessionKey, MSV1_0_USER_SESSION_KEY_LENGTH);
  1051. }
  1052. }
  1053. //
  1054. // Convert the domainname/user name/workstation to the right character set.
  1055. //
  1056. if ( DoUnicode ) {
  1057. DomainName = *((PUNICODE_STRING) &DomainName2);
  1058. UserName = *((PUNICODE_STRING) &UserName2);
  1059. Workstation = *((PUNICODE_STRING) &Workstation2);
  1060. } else {
  1061. SspPrint(( SSP_API_MORE, "SsprHandleAuthenticateMessage: Not doing Unicode\n"));
  1062. Status = RtlOemStringToUnicodeString(
  1063. &DomainName,
  1064. &DomainName2,
  1065. TRUE);
  1066. if ( !NT_SUCCESS(Status) ) {
  1067. SecStatus = SspNtStatusToSecStatus( Status,
  1068. SEC_E_INSUFFICIENT_MEMORY );
  1069. goto Cleanup;
  1070. }
  1071. Status = RtlOemStringToUnicodeString(
  1072. &UserName,
  1073. &UserName2,
  1074. TRUE);
  1075. if ( !NT_SUCCESS(Status) ) {
  1076. SecStatus = SspNtStatusToSecStatus( Status,
  1077. SEC_E_INSUFFICIENT_MEMORY );
  1078. goto Cleanup;
  1079. }
  1080. Status = RtlOemStringToUnicodeString(
  1081. &Workstation,
  1082. &Workstation2,
  1083. TRUE);
  1084. if ( !NT_SUCCESS(Status) ) {
  1085. SecStatus = SspNtStatusToSecStatus( Status,
  1086. SEC_E_INSUFFICIENT_MEMORY );
  1087. goto Cleanup;
  1088. }
  1089. }
  1090. //
  1091. // Trace the username, domain name and workstation
  1092. //
  1093. if (NtlmGlobalEventTraceFlag){
  1094. //Header goo
  1095. SET_TRACE_HEADER(TraceInfo,
  1096. NtlmAcceptGuid,
  1097. EVENT_TRACE_TYPE_INFO,
  1098. WNODE_FLAG_TRACED_GUID|WNODE_FLAG_USE_MOF_PTR,
  1099. 10);
  1100. int TraceHint = TRACE_ACCEPT_INFO;
  1101. SET_TRACE_DATA(TraceInfo,
  1102. TRACE_INITACC_STAGEHINT,
  1103. TraceHint);
  1104. SET_TRACE_DATAPTR(TraceInfo,
  1105. TRACE_INITACC_INCONTEXT,
  1106. TraceOldContextHandle);
  1107. SET_TRACE_DATAPTR(TraceInfo,
  1108. TRACE_INITACC_OUTCONTEXT,
  1109. ContextHandle);
  1110. // lets see the negotiate flags here
  1111. SET_TRACE_DATA(TraceInfo,
  1112. TRACE_INITACC_STATUS,
  1113. Context->NegotiateFlags);
  1114. SET_TRACE_USTRING(TraceInfo,
  1115. TRACE_INITACC_CLIENTNAME,
  1116. UserName);
  1117. SET_TRACE_USTRING(TraceInfo,
  1118. TRACE_INITACC_CLIENTDOMAIN,
  1119. DomainName);
  1120. SET_TRACE_USTRING(TraceInfo,
  1121. TRACE_INITACC_WORKSTATION,
  1122. Workstation);
  1123. TraceEvent(
  1124. NtlmGlobalTraceLoggerHandle,
  1125. (PEVENT_TRACE_HEADER)&TraceInfo
  1126. );
  1127. }
  1128. //
  1129. // If the client is on the same machine as we are, just
  1130. // use the token the client has already placed in our context structure,
  1131. //
  1132. if ( (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_LOCAL_CALL ) &&
  1133. Context->TokenHandle != NULL &&
  1134. DomainName.Length == 0 &&
  1135. UserName.Length == 0 &&
  1136. Workstation.Length == 0 &&
  1137. AuthenticateMessage->NtChallengeResponse.Length == 0 &&
  1138. AuthenticateMessage->LmChallengeResponse.Length == 0 )
  1139. {
  1140. static const UCHAR FixedSessionKey[MSV1_0_USER_SESSION_KEY_LENGTH] = {
  1141. 'S', 'y', 's', 't', 'e', 'm', 'L', 'i',
  1142. 'b', 'r', 'a', 'r', 'y', 'D', 'T', 'C'
  1143. };
  1144. LocalTokenHandle = Context->TokenHandle;
  1145. Context->TokenHandle = NULL;
  1146. KickOffTime.HighPart = 0x7FFFFFFF;
  1147. KickOffTime.LowPart = 0xFFFFFFFF;
  1148. RtlCopyMemory(Context->SessionKey, FixedSessionKey, MSV1_0_USER_SESSION_KEY_LENGTH);
  1149. SspPrint(( SSP_MISC, "SsprHandleAuthenticateMessage: Local Call\n"));
  1150. if ( (ContextReqFlags & ASC_REQ_DELEGATE) )
  1151. {
  1152. //
  1153. // can support another hop if loopback.
  1154. //
  1155. *ContextAttributes |= ASC_RET_DELEGATE;
  1156. Context->ContextFlags |= ASC_RET_DELEGATE;
  1157. }
  1158. //
  1159. // If the client is on a different machine than we are,
  1160. // use LsaLogonUser to create a token for the client.
  1161. //
  1162. } else {
  1163. //
  1164. // Store user name and domain name
  1165. //
  1166. SecStatus = NtLmDuplicateUnicodeString(
  1167. &Context->UserName,
  1168. &UserName);
  1169. if (!NT_SUCCESS(SecStatus)) {
  1170. goto Cleanup;
  1171. }
  1172. SecStatus = NtLmDuplicateUnicodeString(
  1173. &Context->DomainName,
  1174. &DomainName);
  1175. if (!NT_SUCCESS(SecStatus)) {
  1176. goto Cleanup;
  1177. }
  1178. //
  1179. // Allocate an MSV1_0 network logon message
  1180. //
  1181. if (!fSubAuth)
  1182. {
  1183. //
  1184. // The string buffers may be used as structure pointers later on.
  1185. // Align them to pointer boundaries to avoid alignment problems.
  1186. //
  1187. MsvLogonMessageSize =
  1188. ROUND_UP_COUNT(sizeof(*MsvLogonMessage) +
  1189. DomainName.Length +
  1190. UserName.Length +
  1191. Workstation.Length, ALIGN_LPVOID) +
  1192. ROUND_UP_COUNT(AuthenticateMessage->NtChallengeResponse.Length, ALIGN_LPVOID) +
  1193. AuthenticateMessage->LmChallengeResponse.Length;
  1194. MsvLogonMessage = (PMSV1_0_LM20_LOGON)
  1195. NtLmAllocatePrivateHeap(MsvLogonMessageSize );
  1196. if ( MsvLogonMessage == NULL ) {
  1197. SecStatus = STATUS_NO_MEMORY;
  1198. SspPrint(( SSP_CRITICAL,
  1199. "SsprHandleAuthenticateMessage: Error allocating MsvLogonMessage"));
  1200. goto Cleanup;
  1201. }
  1202. //
  1203. // Build the MSV1_0 network logon message to pass to the LSA.
  1204. //
  1205. MsvLogonMessage->MessageType = MsV1_0NetworkLogon;
  1206. Where = (PCHAR)(MsvLogonMessage+1);
  1207. SspContextCopyStringAbsolute( MsvLogonMessage,
  1208. (PSTRING)&MsvLogonMessage->LogonDomainName,
  1209. (PSTRING)&DomainName,
  1210. &Where );
  1211. SspContextCopyStringAbsolute( MsvLogonMessage,
  1212. (PSTRING)&MsvLogonMessage->UserName,
  1213. (PSTRING)&UserName,
  1214. &Where );
  1215. SspContextCopyStringAbsolute( MsvLogonMessage,
  1216. (PSTRING)&MsvLogonMessage->Workstation,
  1217. (PSTRING)&Workstation,
  1218. &Where );
  1219. RtlCopyMemory( MsvLogonMessage->ChallengeToClient,
  1220. Context->Challenge,
  1221. sizeof( MsvLogonMessage->ChallengeToClient ) );
  1222. Where = (PCHAR) ROUND_UP_POINTER(Where, ALIGN_LPVOID);
  1223. SspContextCopyStringAbsolute( MsvLogonMessage,
  1224. &MsvLogonMessage->CaseSensitiveChallengeResponse,
  1225. &NtChallengeResponse,
  1226. &Where );
  1227. Where = (PCHAR) ROUND_UP_POINTER(Where, ALIGN_LPVOID);
  1228. SspContextCopyStringAbsolute(MsvLogonMessage,
  1229. &MsvLogonMessage->CaseInsensitiveChallengeResponse,
  1230. &LmChallengeResponse,
  1231. &Where );
  1232. MsvLogonMessage->ParameterControl = MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
  1233. // This is required by the pre 4.0 server
  1234. if (fCallFromSrv)
  1235. {
  1236. MsvLogonMessage->ParameterControl = MSV1_0_CLEARTEXT_PASSWORD_ALLOWED | NtLmAuthenticateMessage->ParameterControl;
  1237. if ( (Context->ContextFlags & ASC_RET_ALLOW_NON_USER_LOGONS ) != 0)
  1238. {
  1239. MsvLogonMessage->ParameterControl |= MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
  1240. }
  1241. } else {
  1242. MsvLogonMessage->ParameterControl |= MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
  1243. }
  1244. //
  1245. // Get the profile path for EFS
  1246. //
  1247. MsvLogonMessage->ParameterControl |= MSV1_0_RETURN_PROFILE_PATH;
  1248. //
  1249. // By passing in the RETURN_PASSWORD_EXPIRY flag, the password
  1250. // expiration time is returned in the logoff time
  1251. //
  1252. MsvLogonMessage->ParameterControl |= MSV1_0_RETURN_PASSWORD_EXPIRY;
  1253. //
  1254. // for Personal easy file/print sharing, hint to LsaLogonUser
  1255. // that Forced Guest may occur.
  1256. //
  1257. MsvLogonMessage->ParameterControl |= MSV1_0_ALLOW_FORCE_GUEST;
  1258. }
  1259. else
  1260. {
  1261. MsvSubAuthLogonMessageSize =
  1262. ROUND_UP_COUNT(sizeof(*MsvSubAuthLogonMessage) +
  1263. DomainName.Length +
  1264. UserName.Length +
  1265. Workstation.Length, ALIGN_LPVOID) +
  1266. ROUND_UP_COUNT(AuthenticateMessage->NtChallengeResponse.Length, ALIGN_LPVOID) +
  1267. AuthenticateMessage->LmChallengeResponse.Length;
  1268. MsvSubAuthLogonMessage = (PMSV1_0_SUBAUTH_LOGON)
  1269. NtLmAllocatePrivateHeap(MsvSubAuthLogonMessageSize );
  1270. if ( MsvSubAuthLogonMessage == NULL ) {
  1271. SecStatus = STATUS_NO_MEMORY;
  1272. SspPrint(( SSP_CRITICAL,
  1273. "SsprHandleAuthenticateMessage: Error allocating MsvSubAuthLogonMessage"));
  1274. goto Cleanup;
  1275. }
  1276. //
  1277. // Build the MSV1_0 subauth logon message to pass to the LSA.
  1278. //
  1279. MsvSubAuthLogonMessage->MessageType = MsV1_0SubAuthLogon;
  1280. Where = (PCHAR)(MsvSubAuthLogonMessage + 1);
  1281. SspContextCopyStringAbsolute( MsvSubAuthLogonMessage,
  1282. (PSTRING)&MsvSubAuthLogonMessage->LogonDomainName,
  1283. (PSTRING)&DomainName,
  1284. &Where );
  1285. SspContextCopyStringAbsolute( MsvSubAuthLogonMessage,
  1286. (PSTRING)&MsvSubAuthLogonMessage->UserName,
  1287. (PSTRING)&UserName,
  1288. &Where );
  1289. SspContextCopyStringAbsolute( MsvSubAuthLogonMessage,
  1290. (PSTRING)&MsvSubAuthLogonMessage->Workstation,
  1291. (PSTRING)&Workstation,
  1292. &Where );
  1293. RtlCopyMemory( MsvSubAuthLogonMessage->ChallengeToClient,
  1294. Context->Challenge,
  1295. sizeof( MsvSubAuthLogonMessage->ChallengeToClient ) );
  1296. Where = (PCHAR) ROUND_UP_POINTER(Where, ALIGN_LPVOID);
  1297. SspContextCopyStringAbsolute( MsvSubAuthLogonMessage,
  1298. &MsvSubAuthLogonMessage->AuthenticationInfo1,
  1299. &LmChallengeResponse,
  1300. &Where );
  1301. Where = (PCHAR) ROUND_UP_POINTER(Where, ALIGN_LPVOID);
  1302. SspContextCopyStringAbsolute(MsvSubAuthLogonMessage,
  1303. &MsvSubAuthLogonMessage->AuthenticationInfo2,
  1304. &NtChallengeResponse,
  1305. &Where );
  1306. MsvSubAuthLogonMessage->ParameterControl = MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
  1307. MsvSubAuthLogonMessage->SubAuthPackageId = SubAuthPackageId;
  1308. // This is required by the pre 4.0 server
  1309. if (fCallFromSrv)
  1310. {
  1311. MsvSubAuthLogonMessage->ParameterControl = MSV1_0_CLEARTEXT_PASSWORD_ALLOWED | NtLmAuthenticateMessage->ParameterControl;
  1312. }
  1313. if ( (Context->ContextFlags & ASC_RET_ALLOW_NON_USER_LOGONS ) != 0) {
  1314. MsvSubAuthLogonMessage->ParameterControl |= MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
  1315. }
  1316. //
  1317. // By passing in the RETURN_PASSWORD_EXPIRY flag, the password
  1318. // expiration time is returned in the logoff time
  1319. //
  1320. MsvSubAuthLogonMessage->ParameterControl |= MSV1_0_RETURN_PASSWORD_EXPIRY;
  1321. //
  1322. // for Personal easy file/print sharing, hint to LsaLogonUser
  1323. // that Forced Guest may occur.
  1324. //
  1325. MsvSubAuthLogonMessage->ParameterControl |= MSV1_0_ALLOW_FORCE_GUEST;
  1326. }
  1327. //
  1328. // if NTLM2 is negotiated, then mix my challenge with the client's...
  1329. // But, special case for null sessions. since we already negotiated
  1330. // NTLM2, but the LmChallengeResponse field is actually used
  1331. // here. REVIEW -- maybe don't negotiate NTLM2 if NULL session
  1332. //
  1333. if ((Context->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) &&
  1334. (AuthenticateMessage->LmChallengeResponse.Length >= MSV1_0_CHALLENGE_LENGTH))
  1335. {
  1336. MsvLogonMessage->ParameterControl |= MSV1_0_USE_CLIENT_CHALLENGE;
  1337. }
  1338. //
  1339. // Log this user on.
  1340. //
  1341. // No origin (could use F(workstaion))
  1342. RtlInitString( &OriginName, NULL );
  1343. strncpy( SourceContext.SourceName,
  1344. "NtLmSsp ",
  1345. sizeof(SourceContext.SourceName) );
  1346. RtlZeroMemory( &SourceContext.SourceIdentifier,
  1347. sizeof(SourceContext.SourceIdentifier) );
  1348. {
  1349. PVOID TokenInformation;
  1350. PSECPKG_SUPPLEMENTAL_CRED_ARRAY Credentials = NULL;
  1351. if (!fSubAuth)
  1352. {
  1353. Status = LsaApLogonUserEx2(
  1354. (PLSA_CLIENT_REQUEST) (-1),
  1355. Network,
  1356. MsvLogonMessage,
  1357. MsvLogonMessage,
  1358. MsvLogonMessageSize,
  1359. (PVOID *) &LogonProfileMessage,
  1360. &LogonProfileMessageSize,
  1361. &LogonId,
  1362. &SubStatus,
  1363. &TokenInformationType,
  1364. &TokenInformation,
  1365. &AccountName,
  1366. &AuthenticatingAuthority,
  1367. &WorkstationName,
  1368. &PrimaryCredentials,
  1369. &Credentials
  1370. );
  1371. }
  1372. else
  1373. {
  1374. Status = LsaApLogonUserEx2(
  1375. (PLSA_CLIENT_REQUEST) (-1),
  1376. Network,
  1377. MsvSubAuthLogonMessage,
  1378. MsvSubAuthLogonMessage,
  1379. MsvSubAuthLogonMessageSize,
  1380. (PVOID *) &LogonProfileMessage,
  1381. &LogonProfileMessageSize,
  1382. &LogonId,
  1383. &SubStatus,
  1384. &TokenInformationType,
  1385. &TokenInformation,
  1386. &AccountName,
  1387. &AuthenticatingAuthority,
  1388. &WorkstationName,
  1389. &PrimaryCredentials,
  1390. &Credentials
  1391. );
  1392. }
  1393. if ( !NT_SUCCESS(Status) ) {
  1394. SspPrint(( SSP_CRITICAL,
  1395. "SsprHandleAuthenticateMessage: "
  1396. "LsaApLogonUserEx2 returns 0x%lx for context 0x%x\n",
  1397. Status, Context ));
  1398. SecStatus = SspNtStatusToSecStatus( Status, SEC_E_LOGON_DENIED );
  1399. if (Status == STATUS_PASSWORD_MUST_CHANGE) {
  1400. *ApiSubStatus = Status;
  1401. }
  1402. else if (Status == STATUS_ACCOUNT_RESTRICTION) {
  1403. *ApiSubStatus = SubStatus;
  1404. } else {
  1405. *ApiSubStatus = Status;
  1406. }
  1407. goto Cleanup;
  1408. }
  1409. if ( !NT_SUCCESS(SubStatus) ) {
  1410. SspPrint(( SSP_CRITICAL,
  1411. "SsprHandleAuthenticateMessage: "
  1412. "LsaApLogonUserEx2 returns SubStatus of 0x%lx\n",
  1413. SubStatus ));
  1414. SecStatus = SspNtStatusToSecStatus( SubStatus, SEC_E_LOGON_DENIED );
  1415. goto Cleanup;
  1416. }
  1417. //
  1418. // Set package-specific flags in the logon session
  1419. //
  1420. if (fCallFromSrv)
  1421. {
  1422. I_LsaISetPackageAttrInLogonSession(&LogonId, LOGONSES_FLAG_NTLM_DOWNLEVEL);
  1423. }
  1424. //
  1425. // Check if this was a null session. The TokenInformationType will
  1426. // be LsaTokenInformationNull if it is. If so, we may need to fail
  1427. // the logon.
  1428. //
  1429. if (TokenInformationType == LsaTokenInformationNull)
  1430. {
  1431. //
  1432. // RESTRICT_NULL_SESSIONS deemed too risky because legacy behavior of package
  1433. // allows null sessions from SYSTEM.
  1434. //
  1435. #ifdef RESTRICT_NULL_SESSIONS
  1436. if ((Context->ContextFlags & ASC_REQ_ALLOW_NULL_SESSION) == 0) {
  1437. SspPrint(( SSP_CRITICAL,
  1438. "SsprHandleAuthenticateMessage: "
  1439. "Null session logon attempted but not allowed\n" ));
  1440. SecStatus = SEC_E_LOGON_DENIED;
  1441. goto Cleanup;
  1442. }
  1443. #endif
  1444. *ContextAttributes |= ASC_RET_NULL_SESSION;
  1445. Context->ContextFlags |= ASC_RET_NULL_SESSION;
  1446. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
  1447. AuditSid = NtLmGlobalAnonymousSid;
  1448. }
  1449. else
  1450. {
  1451. PLSA_TOKEN_INFORMATION_V2 TokenInfoV2 ;
  1452. TokenInfoV2 = (PLSA_TOKEN_INFORMATION_V2) TokenInformation ;
  1453. SafeAllocaAllocate( AllocatedAuditSid, RtlLengthSid( TokenInfoV2->User.User.Sid ) );
  1454. if ( AllocatedAuditSid )
  1455. {
  1456. RtlCopyMemory( AllocatedAuditSid,
  1457. TokenInfoV2->User.User.Sid,
  1458. RtlLengthSid( TokenInfoV2->User.User.Sid ) );
  1459. }
  1460. AuditSid = AllocatedAuditSid;
  1461. }
  1462. Status = LsaFunctions->CreateTokenEx(
  1463. &LogonId,
  1464. &SourceContext,
  1465. Network,
  1466. (((Context->NegotiateFlags & NTLMSSP_NEGOTIATE_IDENTIFY) != 0) ?
  1467. SecurityIdentification : SecurityImpersonation),
  1468. TokenInformationType,
  1469. TokenInformation,
  1470. NULL,
  1471. WorkstationName,
  1472. ((LogonProfileMessage->UserFlags & LOGON_PROFILE_PATH_RETURNED) != 0) ? &LogonProfileMessage->UserParameters : NULL,
  1473. &PrimaryCredentials,
  1474. SecSessionPrimaryCred,
  1475. &LocalTokenHandle,
  1476. &SubStatus);
  1477. if ( !NT_SUCCESS(Status) && (LocalTokenHandle == NULL) ) {
  1478. LsaFunctions->DeleteLogonSession(&LogonId);
  1479. }
  1480. if (Status == STATUS_ACCOUNT_RESTRICTION) {
  1481. *ApiSubStatus = SubStatus;
  1482. } else {
  1483. *ApiSubStatus = Status;
  1484. }
  1485. } // end of block for LsaLogonUser
  1486. if ( !NT_SUCCESS(Status) ) {
  1487. SspPrint(( SSP_CRITICAL,
  1488. "SsprHandleAuthenticateMessage: "
  1489. "CreateToken returns 0x%lx\n",
  1490. Status ));
  1491. SecStatus = Status;
  1492. goto Cleanup;
  1493. }
  1494. if ( !NT_SUCCESS(SubStatus) ) {
  1495. SspPrint(( SSP_CRITICAL,
  1496. "SsprHandleAuthenticateMessage: "
  1497. "CreateToken returns SubStatus of 0x%lx\n",
  1498. SubStatus ));
  1499. SecStatus = SubStatus;
  1500. goto Cleanup;
  1501. }
  1502. LocalTokenHandleOpenned = TRUE;
  1503. //
  1504. // Don't allow cleartext password on the logon.
  1505. // Except if called from Downlevel
  1506. if (!fCallFromSrv)
  1507. {
  1508. if ( LogonProfileMessage->UserFlags & LOGON_NOENCRYPTION ) {
  1509. SspPrint(( SSP_CRITICAL,
  1510. "SsprHandleAuthenticateMessage: "
  1511. "LsaLogonUser used cleartext password\n" ));
  1512. SecStatus = SEC_E_LOGON_DENIED;
  1513. goto Cleanup;
  1514. }
  1515. }
  1516. //
  1517. // If we did a guest logon, set the substatus to be STATUS_NO_SUCH_USER
  1518. //
  1519. if ( LogonProfileMessage->UserFlags & LOGON_GUEST ) {
  1520. fAvoidGuestAudit = TRUE;
  1521. *ApiSubStatus = STATUS_NO_SUCH_USER;
  1522. #if 0
  1523. //
  1524. // If caller required Sign/Seal, fail them here
  1525. //
  1526. if (
  1527. (!NtLmGlobalForceGuest) &&
  1528. (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_SEAL)
  1529. )
  1530. {
  1531. SspPrint(( SSP_CRITICAL,
  1532. "SsprHandleAuthenticateMessage: "
  1533. "LsaLogonUser logged user as a guest but seal is requested\n" ));
  1534. SecStatus = SEC_E_LOGON_DENIED;
  1535. goto Cleanup;
  1536. }
  1537. #endif
  1538. }
  1539. //
  1540. // Save important information about the caller.
  1541. //
  1542. KickOffTime = LogonProfileMessage->KickOffTime;
  1543. //
  1544. // By passing in the RETURN_PASSWORD_EXPIRY flag, the password
  1545. // expiration time is returned in the logoff time
  1546. //
  1547. *PasswordExpiry = LogonProfileMessage->LogoffTime;
  1548. *UserFlags = LogonProfileMessage->UserFlags;
  1549. //
  1550. // set the session key to what the client sent us (if anything)
  1551. //
  1552. if (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH &&
  1553. AuthenticateMessage->SessionKey.Length == MSV1_0_USER_SESSION_KEY_LENGTH)
  1554. {
  1555. RtlCopyMemory(
  1556. Context->SessionKey,
  1557. SessionKeyString.Buffer,
  1558. MSV1_0_USER_SESSION_KEY_LENGTH
  1559. );
  1560. }
  1561. //
  1562. // Generate the session key, or decrypt the generated random one sent to
  1563. // us by the client, from various bits of info
  1564. //
  1565. SecStatus = SsprMakeSessionKey(
  1566. Context,
  1567. &LmChallengeResponse,
  1568. LogonProfileMessage->UserSessionKey,
  1569. LogonProfileMessage->LanmanSessionKey,
  1570. NULL
  1571. );
  1572. if ( !NT_SUCCESS(SecStatus) ) {
  1573. SspPrint(( SSP_CRITICAL,
  1574. "SsprHandleAuthenticateMessage: "
  1575. "SsprMakeSessionKey failed.\n" ));
  1576. goto Cleanup;
  1577. }
  1578. }
  1579. //
  1580. // Copy the logon domain name returned by the LSA if it is different.
  1581. // from the one the caller passed in. This may happen with temp duplicate
  1582. // accounts and local account
  1583. //
  1584. if ((LogonProfileMessage != NULL) &&
  1585. (LogonProfileMessage->LogonDomainName.Length != 0) &&
  1586. !RtlEqualUnicodeString(
  1587. &Context->DomainName,
  1588. &LogonProfileMessage->LogonDomainName,
  1589. TRUE // case insensitive
  1590. )) {
  1591. //
  1592. // erase the old domain name
  1593. //
  1594. if (Context->DomainName.Buffer != NULL) {
  1595. NtLmFreePrivateHeap(Context->DomainName.Buffer);
  1596. Context->DomainName.Buffer = NULL;
  1597. Context->DomainName.Length = Context->DomainName.MaximumLength = 0;
  1598. }
  1599. SecStatus = NtLmDuplicateUnicodeString(
  1600. &Context->DomainName,
  1601. &LogonProfileMessage->LogonDomainName
  1602. );
  1603. if (!NT_SUCCESS(SecStatus)) {
  1604. goto Cleanup;
  1605. }
  1606. }
  1607. //
  1608. // use SAM account username in case of UPN logon
  1609. //
  1610. if ((TokenInformationType != LsaTokenInformationNull)
  1611. && (0 != PrimaryCredentials.DownlevelName.Length) // older DCs do not send DownlevelName for network logon
  1612. && !RtlEqualUnicodeString(
  1613. &Context->UserName,
  1614. &PrimaryCredentials.DownlevelName,
  1615. TRUE // case insensitive
  1616. )) {
  1617. //
  1618. // erase the old user name
  1619. //
  1620. if (Context->UserName.Buffer != NULL) {
  1621. NtLmFreePrivateHeap(Context->UserName.Buffer);
  1622. Context->UserName.Buffer = NULL;
  1623. Context->UserName.Length = Context->UserName.MaximumLength = 0;
  1624. }
  1625. SecStatus = NtLmDuplicateUnicodeString(
  1626. &Context->UserName,
  1627. &PrimaryCredentials.DownlevelName
  1628. );
  1629. if (!NT_SUCCESS(SecStatus)) {
  1630. goto Cleanup;
  1631. }
  1632. }
  1633. //
  1634. // Allow the context to live until kickoff time.
  1635. //
  1636. SspContextSetTimeStamp( Context, KickOffTime );
  1637. //
  1638. // Return output parameters to the caller.
  1639. //
  1640. *ExpirationTime = SspContextGetTimeStamp( Context, TRUE );
  1641. //
  1642. // Return output token
  1643. //
  1644. if (fCallFromSrv)
  1645. {
  1646. NtLmAcceptResponse = (PNTLM_ACCEPT_RESPONSE) *OutputToken;
  1647. if (NtLmAcceptResponse == NULL)
  1648. {
  1649. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1650. goto Cleanup;
  1651. }
  1652. LUID UNALIGNED * TempLogonId = (LUID UNALIGNED *) &NtLmAcceptResponse->LogonId;
  1653. *TempLogonId = LogonId;
  1654. NtLmAcceptResponse->UserFlags = LogonProfileMessage->UserFlags;
  1655. RtlCopyMemory(
  1656. NtLmAcceptResponse->UserSessionKey,
  1657. LogonProfileMessage->UserSessionKey,
  1658. MSV1_0_USER_SESSION_KEY_LENGTH
  1659. );
  1660. RtlCopyMemory(
  1661. NtLmAcceptResponse->LanmanSessionKey,
  1662. LogonProfileMessage->LanmanSessionKey,
  1663. MSV1_0_LANMAN_SESSION_KEY_LENGTH
  1664. );
  1665. LARGE_INTEGER UNALIGNED *TempKickoffTime = (LARGE_INTEGER UNALIGNED *) &NtLmAcceptResponse->KickoffTime;
  1666. *TempKickoffTime = LogonProfileMessage->KickOffTime;
  1667. }
  1668. else
  1669. {
  1670. *OutputTokenSize = 0;
  1671. }
  1672. //
  1673. // We don't support sign/seal options if fallback to Guest
  1674. // this is because the client and server won't have a matched session-key
  1675. // AND even if they did match (ie: blank password), the session-key
  1676. // would likely be well-known.
  1677. //
  1678. SecStatus = STATUS_SUCCESS;
  1679. //
  1680. // Free and locally used resources.
  1681. //
  1682. Cleanup:
  1683. //
  1684. // Audit this logon
  1685. //
  1686. if (NT_SUCCESS(SecStatus)) {
  1687. //
  1688. // If we don't have an account name, this was a local connection
  1689. // and we didn't build a new token, so don't bother auditing.
  1690. // also, don't bother auditing logons that fellback to guest.
  1691. //
  1692. if ( (AccountName != NULL) &&
  1693. ((AccountName->Length != 0) || (*ContextAttributes & ASC_RET_NULL_SESSION)) &&
  1694. !fAvoidGuestAudit ) {
  1695. LsaFunctions->AuditLogon(
  1696. STATUS_SUCCESS,
  1697. STATUS_SUCCESS,
  1698. AccountName,
  1699. AuthenticatingAuthority,
  1700. WorkstationName,
  1701. AuditSid,
  1702. Network,
  1703. &SourceContext,
  1704. &LogonId
  1705. );
  1706. }
  1707. } else {
  1708. LsaFunctions->AuditLogon(
  1709. !NT_SUCCESS(Status) ? Status : SecStatus,
  1710. SubStatus,
  1711. &UserName,
  1712. &DomainName,
  1713. &Workstation,
  1714. NULL,
  1715. Network,
  1716. &SourceContext,
  1717. &LogonId
  1718. );
  1719. }
  1720. if ( Context != NULL ) {
  1721. //
  1722. // client does not negotiate version, do not send the newer status code
  1723. //
  1724. if ( (STATUS_AUTHENTICATION_FIREWALL_FAILED == SecStatus)
  1725. && (Context->ClientVersion.Revision < NTLMSSP_REVISION_W2K3_RC1) ) {
  1726. SspPrint(( SSP_WARNING,
  1727. "SsprHandleAuthenticateMessage: remapping STATUS_AUTHENTICATION_FIREWALL_FAILED to STATUS_NO_SUCH_USER\n",
  1728. SubStatus ));
  1729. SecStatus = STATUS_NO_SUCH_USER;
  1730. }
  1731. Context->Server = TRUE;
  1732. Context->LastStatus = SecStatus;
  1733. Context->DownLevel = fCallFromSrv;
  1734. //
  1735. // Don't allow this context to be used again.
  1736. //
  1737. if ( NT_SUCCESS(SecStatus) ) {
  1738. Context->State = AuthenticatedState;
  1739. if ( LocalTokenHandle ) {
  1740. *TokenHandle = LocalTokenHandle;
  1741. }
  1742. LocalTokenHandle = NULL;
  1743. RtlCopyMemory(
  1744. SessionKey,
  1745. Context->SessionKey,
  1746. MSV1_0_USER_SESSION_KEY_LENGTH );
  1747. *NegotiateFlags = Context->NegotiateFlags;
  1748. //
  1749. // tricky here:
  1750. //
  1751. // datagram client side context is mapped during the first call, so
  1752. // remove LM key correction so that the mapped context on the
  1753. // server side would have matching flags
  1754. //
  1755. if (IsDatagramLmKeyCorrectionOn) {
  1756. SspPrint(( SSP_WARNING, "SsprHandleAuthenticateMessage turning on LM keys\n" ));
  1757. *NegotiateFlags |= NTLMSSP_NEGOTIATE_LM_KEY;
  1758. }
  1759. if ( !fAvoidGuestAudit ) {
  1760. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_SEAL ) {
  1761. *ContextAttributes |= ASC_RET_CONFIDENTIALITY;
  1762. }
  1763. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN ) {
  1764. *ContextAttributes |= ASC_RET_REPLAY_DETECT |
  1765. ASC_RET_SEQUENCE_DETECT |
  1766. ASC_RET_INTEGRITY;
  1767. }
  1768. if ( ContextReqFlags & ASC_REQ_REPLAY_DETECT ) {
  1769. *ContextAttributes |= ASC_RET_REPLAY_DETECT;
  1770. }
  1771. if ( ContextReqFlags & ASC_REQ_SEQUENCE_DETECT ) {
  1772. *ContextAttributes |= ASC_RET_SEQUENCE_DETECT;
  1773. }
  1774. }
  1775. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_IDENTIFY ) {
  1776. *ContextAttributes |= ASC_RET_IDENTIFY;
  1777. }
  1778. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM ) {
  1779. *ContextAttributes |= ASC_RET_DATAGRAM;
  1780. }
  1781. if ( ContextReqFlags & ASC_REQ_ALLOW_NON_USER_LOGONS ) {
  1782. *ContextAttributes |= ASC_RET_ALLOW_NON_USER_LOGONS;
  1783. }
  1784. //
  1785. // if caller wants only INTEGRITY, then wants application
  1786. // supplied sequence numbers...
  1787. //
  1788. if ((Context->ContextFlags &
  1789. (ASC_REQ_INTEGRITY | ASC_REQ_REPLAY_DETECT | ASC_REQ_SEQUENCE_DETECT)) ==
  1790. ASC_REQ_INTEGRITY)
  1791. {
  1792. *NegotiateFlags |= NTLMSSP_APP_SEQ;
  1793. }
  1794. } else {
  1795. Context->State = IdleState;
  1796. }
  1797. // If we just created this context, then we need to dereference it
  1798. // once more with feeling
  1799. if (fCallFromSrv && !NT_SUCCESS(SecStatus))
  1800. {
  1801. PSSP_CONTEXT LocalContext;
  1802. SspContextReferenceContext (*ContextHandle, TRUE, &LocalContext);
  1803. ASSERT (LocalContext != NULL);
  1804. if (LocalContext != NULL)
  1805. {
  1806. SspContextDereferenceContext( LocalContext );
  1807. }
  1808. }
  1809. SspContextDereferenceContext( Context );
  1810. }
  1811. if ( NegotiateMessage != NULL ) {
  1812. (VOID) NtLmFreePrivateHeap( NegotiateMessage );
  1813. }
  1814. if ( AuthenticateMessage != NULL ) {
  1815. (VOID) NtLmFreePrivateHeap( AuthenticateMessage );
  1816. }
  1817. if ( MsvLogonMessage != NULL ) {
  1818. (VOID) NtLmFreePrivateHeap( MsvLogonMessage );
  1819. }
  1820. if ( MsvSubAuthLogonMessage != NULL ) {
  1821. (VOID) NtLmFreePrivateHeap( MsvSubAuthLogonMessage );
  1822. }
  1823. if ( LogonProfileMessage != NULL ) {
  1824. (VOID) LsaFunctions->FreeLsaHeap( LogonProfileMessage );
  1825. }
  1826. if ( LocalTokenHandle != NULL && LocalTokenHandleOpenned ) {
  1827. (VOID) NtClose( LocalTokenHandle );
  1828. }
  1829. if ( !DoUnicode ) {
  1830. if ( DomainName.Buffer != NULL) {
  1831. RtlFreeUnicodeString( &DomainName );
  1832. }
  1833. if ( UserName.Buffer != NULL) {
  1834. RtlFreeUnicodeString( &UserName );
  1835. }
  1836. if ( Workstation.Buffer != NULL) {
  1837. RtlFreeUnicodeString( &Workstation );
  1838. }
  1839. }
  1840. if (AccountName != NULL) {
  1841. if (AccountName->Buffer != NULL) {
  1842. LsaFunctions->FreeLsaHeap(AccountName->Buffer);
  1843. }
  1844. LsaFunctions->FreeLsaHeap(AccountName);
  1845. }
  1846. if (AuthenticatingAuthority != NULL) {
  1847. if (AuthenticatingAuthority->Buffer != NULL) {
  1848. LsaFunctions->FreeLsaHeap(AuthenticatingAuthority->Buffer);
  1849. }
  1850. LsaFunctions->FreeLsaHeap(AuthenticatingAuthority);
  1851. }
  1852. if (WorkstationName != NULL) {
  1853. if (WorkstationName->Buffer != NULL) {
  1854. LsaFunctions->FreeLsaHeap(WorkstationName->Buffer);
  1855. }
  1856. LsaFunctions->FreeLsaHeap(WorkstationName);
  1857. }
  1858. if ( AllocatedAuditSid )
  1859. {
  1860. SafeAllocaFree( AllocatedAuditSid );
  1861. }
  1862. //
  1863. // need to free the PrimaryCredentials fields filled in by LsaApLogonUserEx2
  1864. //
  1865. if ( PrimaryCredentials.DownlevelName.Buffer )
  1866. {
  1867. LsaFunctions->FreeLsaHeap(PrimaryCredentials.DownlevelName.Buffer);
  1868. }
  1869. if ( PrimaryCredentials.DomainName.Buffer )
  1870. {
  1871. LsaFunctions->FreeLsaHeap(PrimaryCredentials.DomainName.Buffer);
  1872. }
  1873. if ( PrimaryCredentials.UserSid )
  1874. {
  1875. LsaFunctions->FreeLsaHeap(PrimaryCredentials.UserSid);
  1876. }
  1877. if ( PrimaryCredentials.LogonServer.Buffer )
  1878. {
  1879. LsaFunctions->FreeLsaHeap(PrimaryCredentials.LogonServer.Buffer);
  1880. }
  1881. //
  1882. // Set a flag telling RPC not to destroy the connection yet
  1883. //
  1884. if (!NT_SUCCESS(SecStatus)) {
  1885. *ContextAttributes |= ASC_RET_THIRD_LEG_FAILED;
  1886. }
  1887. SspPrint(( SSP_API_MORE, "Leaving SsprHandleAutheticateMessage: 0x%lx\n", SecStatus ));
  1888. return SecStatus;
  1889. }