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.

4471 lines
136 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: ctxtapi.cxx
  8. //
  9. // Contents: Context APIs for Kerberos package
  10. //
  11. //
  12. // History: 16-April-1996 Created MikeSw
  13. // 26-Sep-1998 ChandanS
  14. // Added more debugging support etc.
  15. //
  16. //------------------------------------------------------------------------
  17. #include <kerb.hxx>
  18. #include <kerbp.h>
  19. #include "kerbevt.h"
  20. #include <gssapip.h>
  21. #include <krbaudit.h>
  22. #ifdef RETAIL_LOG_SUPPORT
  23. static TCHAR THIS_FILE[]=TEXT(__FILE__);
  24. #endif
  25. UNICODE_STRING KerbTargetPrefix = {sizeof(L"krb5://")-sizeof(WCHAR),sizeof(L"krb5://"),L"krb5://" };
  26. #define FILENO FILENO_CTXTAPI
  27. //+-------------------------------------------------------------------------
  28. //
  29. // Function: SpDeleteContext
  30. //
  31. // Synopsis: Deletes a Kerberos context
  32. //
  33. // Effects:
  34. //
  35. // Arguments: ContextHandle - The context to delete
  36. //
  37. // Requires:
  38. //
  39. // Returns: STATUS_SUCCESS or STATUS_INVALID_HANDLE
  40. //
  41. // Notes:
  42. //
  43. //
  44. //--------------------------------------------------------------------------
  45. NTSTATUS NTAPI
  46. SpDeleteContext(
  47. IN LSA_SEC_HANDLE ContextHandle
  48. )
  49. {
  50. NTSTATUS Status;
  51. PKERB_CONTEXT Context;
  52. KERB_CONTEXT_STATE ContextState;
  53. ULONG ClientProcess = 0;
  54. D_DebugLog((DEB_TRACE_API,"SpDeleteContext 0x%x called\n",ContextHandle));
  55. if (!KerbGlobalInitialized)
  56. {
  57. Status = STATUS_INVALID_SERVER_STATE;
  58. Context = NULL;
  59. goto Cleanup;
  60. }
  61. Status = KerbReferenceContext(
  62. ContextHandle,
  63. TRUE, // unlink handle
  64. &Context
  65. );
  66. if (Context == NULL)
  67. {
  68. D_DebugLog((DEB_ERROR,"SpDeleteContext: Context 0x%x not located. %ws, line %d\n",ContextHandle, THIS_FILE, __LINE__));
  69. goto Cleanup;
  70. }
  71. #ifndef WIN32_CHICAGO
  72. KerbReadLockContexts();
  73. // Need to copy out the context data else we'll end up holding the lock
  74. // for too long a time.
  75. //
  76. ContextState = Context->ContextState;
  77. ClientProcess = Context->ClientProcess;
  78. KerbUnlockContexts();
  79. // If this was a context that was dropped in the middle,
  80. // audit it as a logon failure.
  81. //
  82. if (ContextState == ApReplySentState)
  83. {
  84. LsaFunctions->AuditLogon(
  85. STATUS_UNFINISHED_CONTEXT_DELETED,
  86. STATUS_SUCCESS,
  87. &Context->ClientName,
  88. &Context->ClientRealm,
  89. NULL, // no workstation
  90. Context->UserSid,
  91. Network,
  92. &KerberosSource,
  93. &Context->LogonId
  94. );
  95. }
  96. #endif // WIN32_CHICAGO
  97. //
  98. // Now dereference the Context. If nobody else is using this Context
  99. // currently it will be freed.
  100. //
  101. KerbDereferenceContext(Context);
  102. Status = STATUS_SUCCESS;
  103. Cleanup:
  104. D_DebugLog((DEB_TRACE_LEAKS,"SpDeleteContext returned 0x%x, Context 0x%x, Pid 0x%x\n",KerbMapKerbNtStatusToNtStatus(Status), Context, ClientProcess));
  105. D_DebugLog((DEB_TRACE_API, "SpDeleteContext returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  106. return(KerbMapKerbNtStatusToNtStatus(Status));
  107. }
  108. //+-------------------------------------------------------------------------
  109. //
  110. // Function: KerbProcessTargetNames
  111. //
  112. // Synopsis: Takes the target names from both the negotiate hint and
  113. // supplied by the caller and creates the real Kerberos target
  114. // name.
  115. //
  116. // Effects:
  117. //
  118. // Arguments: TargetName - supplies the name passed in the TargetName
  119. // parameter of InitializeSecurityContext.
  120. // SuppTargetName - If present, an alternate name passed in
  121. // a security token.
  122. // Flags - flags to use when cracking a name. May be:
  123. // KERB_CRACK_NAME_USE_WKSTA_REALM - if no realm can be
  124. // determined, use the realm of the wksta
  125. // KERB_CRACK_NAME_REALM_SUPPLIED - the caller has the
  126. // realm name, so treat "@" in the name as a normal
  127. // character, not a spacer.
  128. // UseSpnRealmSupplied - If the target name was an spn and it
  129. // contained a realm, it's set to TRUE
  130. // FinalTarget - The processed name. Must be freed with KerbFreeKdcName.
  131. // TargetRealm - If the name contains a realm portions, this is
  132. // the realm. Should be freed using KerbFreeString.
  133. //
  134. //
  135. // Requires:
  136. //
  137. // Returns:
  138. //
  139. // Notes: If the name has an "@" in it, it is converted into a standard
  140. // Kerberos V5 name - everything after the "@" is put in the
  141. // realm field, and everything before the @ is separted at the
  142. // "/" characters into different pieces of the name. Depending
  143. // on the number of pieces, it is passed as a KRB_NT_PRINCIPAL (1)
  144. // or KRB_NT_SRV_INSTANCE (2), or KRB_NT_SRV_XHST (3+)
  145. //
  146. // If the name has an "\" in it, it is assumed to be an NT4
  147. // name & put as is into a KRB_NT_MS_PRINCIPAL_NAME name
  148. //
  149. // If the name has neither a "\" or a "@" or a "/", it is
  150. // assumed to be a simple name & passed as KRB_NT_PRINCIPAL
  151. // in the caller's domain.
  152. //
  153. //
  154. //
  155. //--------------------------------------------------------------------------
  156. #ifdef later
  157. #define KERB_LOCALHOST_NAME L"localhost"
  158. #endif
  159. NTSTATUS
  160. KerbProcessTargetNames(
  161. IN PUNICODE_STRING TargetName,
  162. IN OPTIONAL PUNICODE_STRING SuppTargetName,
  163. IN ULONG Flags,
  164. IN OUT PULONG ProcessFlags,
  165. OUT PKERB_INTERNAL_NAME * FinalTarget,
  166. OUT PUNICODE_STRING TargetRealm,
  167. OUT OPTIONAL PKERB_SPN_CACHE_ENTRY * SpnCacheEntry
  168. )
  169. {
  170. NTSTATUS Status = STATUS_SUCCESS;
  171. USHORT NameType = 0;
  172. PKERB_INTERNAL_NAME OutputName = NULL;
  173. USHORT NameParts = 0, ExtraNameParts = 0;
  174. ULONG NameLength = 0;
  175. USHORT Index, NameIndex;
  176. PUNICODE_STRING RealTargetName;
  177. UNICODE_STRING SuppliedRealm = {0};
  178. UNICODE_STRING EmptyString = {0};
  179. UNICODE_STRING SidString = {0};
  180. UNICODE_STRING FirstNamePart = {0};
  181. PKERB_SPN_CACHE_ENTRY LocalCacheEntry = NULL;
  182. #ifdef later
  183. UNICODE_STRING LocalhostName = {0};
  184. BOOLEAN ReplaceLocalhost = FALSE;
  185. #endif
  186. BOOLEAN DoneParsing = FALSE;
  187. BOOLEAN PurgedEntry = FALSE;
  188. PKERB_MIT_REALM MitRealm;
  189. BOOLEAN UsedAlternateName;
  190. PUCHAR Where;
  191. PKERB_SID_CACHE_ENTRY CacheEntry = NULL;
  192. *ProcessFlags = 0;
  193. //
  194. // If a supplemental target name was supplied, use it as it is more likely
  195. // to be correct.
  196. //
  197. if (ARGUMENT_PRESENT(SuppTargetName) && (SuppTargetName->Length > 0))
  198. {
  199. RealTargetName = SuppTargetName;
  200. }
  201. else
  202. {
  203. RealTargetName = TargetName;
  204. }
  205. //
  206. // If this is an IP address, we don't handle it so bail now.
  207. //
  208. if (KerbIsIpAddress(RealTargetName))
  209. {
  210. D_DebugLog((DEB_ERROR,"Ip address passed as target name: %wZ. Failing InitSecCtxt\n",
  211. RealTargetName ));
  212. Status = SEC_E_TARGET_UNKNOWN;
  213. goto Cleanup;
  214. }
  215. #ifdef later
  216. RtlInitUnicodeString(
  217. &LocalhostName,
  218. KERB_LOCALHOST_NAME
  219. );
  220. #endif
  221. //
  222. // Initialize the first part of the name to the whole string
  223. //
  224. FirstNamePart.Buffer = RealTargetName->Buffer;
  225. FirstNamePart.Length = RealTargetName->Length;
  226. FirstNamePart.MaximumLength = FirstNamePart.Length;
  227. //
  228. // Check the characters in the name. Search backwards to front because
  229. // username may have "@" signs in them.
  230. //
  231. for ( Index = (RealTargetName->Length / sizeof(WCHAR)); Index-- > 0; )
  232. {
  233. switch(RealTargetName->Buffer[Index])
  234. {
  235. case L'@':
  236. //
  237. // If we have a realm name already, ignore this character.
  238. //
  239. if ((Flags & KERB_CRACK_NAME_REALM_SUPPLIED) != 0)
  240. {
  241. break;
  242. }
  243. //
  244. // If we haven't hit any other separators, this is user@domain kind
  245. // of name
  246. //
  247. if (NameType == 0)
  248. {
  249. NameType = KRB_NT_PRINCIPAL;
  250. NameParts++;
  251. SuppliedRealm.Buffer = &RealTargetName->Buffer[Index] + 1;
  252. SuppliedRealm.Length = RealTargetName->Length - (Index + 1) * sizeof(WCHAR);
  253. SuppliedRealm.MaximumLength = SuppliedRealm.Length;
  254. if (SuppliedRealm.Length == 0)
  255. {
  256. Status = SEC_E_TARGET_UNKNOWN;
  257. goto Cleanup;
  258. }
  259. FirstNamePart.Buffer = RealTargetName->Buffer;
  260. FirstNamePart.Length = Index * sizeof(WCHAR);
  261. FirstNamePart.MaximumLength = FirstNamePart.Length;
  262. }
  263. // else
  264. // {
  265. // Status = SEC_E_TARGET_UNKNOWN;
  266. // goto Cleanup;
  267. // }
  268. break;
  269. case L'/':
  270. //
  271. // All names that have a '/' separator are KRB_NT_SRV_INST
  272. // If we saw an @before this, we need to do something special.
  273. //
  274. NameType = KRB_NT_SRV_INST;
  275. NameParts ++;
  276. break;
  277. case '\\':
  278. //
  279. // If we have a realm name already, ignore this character.
  280. //
  281. if ((Flags & KERB_CRACK_NAME_REALM_SUPPLIED) != 0)
  282. {
  283. break;
  284. }
  285. //
  286. // If we hit a backslash, this is an NT4 style name, so treat it
  287. // as such.
  288. // Just for error checking purposes, make sure that the current
  289. // name type was 0
  290. //
  291. if (NameType != 0)
  292. {
  293. Status = SEC_E_TARGET_UNKNOWN;
  294. goto Cleanup;
  295. }
  296. NameType = KRB_NT_MS_PRINCIPAL;
  297. NameParts = 1;
  298. SuppliedRealm.Buffer = RealTargetName->Buffer;
  299. SuppliedRealm.Length = Index * sizeof(WCHAR);
  300. SuppliedRealm.MaximumLength = SuppliedRealm.Length;
  301. FirstNamePart.Buffer = &RealTargetName->Buffer[Index] + 1;
  302. FirstNamePart.Length = RealTargetName->Length - (Index + 1) * sizeof(WCHAR);
  303. FirstNamePart.MaximumLength = FirstNamePart.Length;
  304. if (SuppliedRealm.Length == 0 || FirstNamePart.Length == 0)
  305. {
  306. Status = SEC_E_TARGET_UNKNOWN;
  307. goto Cleanup;
  308. }
  309. DoneParsing = TRUE;
  310. break;
  311. default:
  312. break;
  313. }
  314. if (DoneParsing)
  315. {
  316. break;
  317. }
  318. }
  319. //
  320. // If we didn't exit early, then we were sent a name with no "@" sign.
  321. // If there were no separators, then it is a flat principal name
  322. //
  323. if (!DoneParsing && (NameType == 0))
  324. {
  325. if (NameParts == 0)
  326. {
  327. //
  328. // The name has no separators, so it is a flat principal name
  329. //
  330. NameType = KRB_NT_PRINCIPAL;
  331. NameParts = 1;
  332. }
  333. }
  334. //
  335. // For KRB_NT_SRV_INST, get the name parts correct and tell the caller
  336. // that a realm was supplied in the spn
  337. //
  338. if (NameType == KRB_NT_SRV_INST)
  339. {
  340. if (SuppliedRealm.Length == 0)
  341. {
  342. // We have an spn of the form a/b..../n and the name parts needs
  343. // to be upped by one
  344. // If we had an spn of the form a/b@c, then the name
  345. // parts would be right.
  346. NameParts++;
  347. }
  348. else
  349. {
  350. // We need to filter this back to the caller so that the
  351. // name canonicalization bit is not set.
  352. *ProcessFlags |= KERB_GET_TICKET_NO_CANONICALIZE;
  353. }
  354. }
  355. //
  356. // Check for an MIT realm with the supplied realm - if the name type is
  357. // KRB_NT_PRINCIPAL, send it as a UPN unless we can find an MIT realm.
  358. // If we are not a member of a domain, then we can't default so use
  359. // the domain name supplied. Also, if we are using supplied credentials
  360. // we don't want to use the wksta realm.
  361. //
  362. if ((NameType == KRB_NT_PRINCIPAL) && (KerbGetGlobalRole() != KerbRoleStandalone) &&
  363. ((Flags & KERB_CRACK_NAME_USE_WKSTA_REALM) != 0))
  364. {
  365. BOOLEAN Result;
  366. Result = KerbLookupMitRealm(
  367. &SuppliedRealm,
  368. &MitRealm,
  369. &UsedAlternateName
  370. );
  371. //
  372. // If we didn't find a realm, use this as a UPN
  373. //
  374. if (!Result)
  375. {
  376. //
  377. // If the caller supplied the realm separately, then don't
  378. // send it as a UPN.
  379. //
  380. if ((Flags & KERB_CRACK_NAME_REALM_SUPPLIED) == 0)
  381. {
  382. NameType = KRB_NT_ENTERPRISE_PRINCIPAL;
  383. NameParts = 1;
  384. FirstNamePart = *RealTargetName;
  385. RtlInitUnicodeString(
  386. &SuppliedRealm,
  387. NULL
  388. );
  389. }
  390. }
  391. //
  392. // For logon, its interesting to know if we're doing an MIT realm lookup
  393. //
  394. else
  395. {
  396. D_DebugLog((DEB_TRACE, "Using MIT realm in Process TargetName\n"));
  397. *ProcessFlags |= KERB_MIT_REALM_USED;
  398. }
  399. }
  400. NameLength = FirstNamePart.Length + NameParts * sizeof(WCHAR);
  401. D_DebugLog((DEB_TRACE_CTXT,
  402. "Parsed name %wZ (%wZ) into:\n\t name type 0x%x, name count %d, \n\t realm %wZ, \n\t first part %wZ\n",
  403. TargetName,
  404. SuppTargetName,
  405. NameType,
  406. NameParts,
  407. &SuppliedRealm,
  408. &FirstNamePart
  409. ));
  410. #ifdef later
  411. //
  412. // If the name end in "localhost", replace it with our dns machine
  413. // name.
  414. //
  415. if ((NameType == KRB_NT_SRV_INST) &&
  416. (NameParts == 2) &&
  417. (RealTargetName->Length > LocalhostName.Length) &&
  418. RtlEqualMemory(
  419. RealTargetName->Buffer + (RealTargetName->Length - LocalhostName.Length ) / sizeof(WCHAR),
  420. LocalhostName.Buffer,
  421. LocalhostName.Length
  422. ))
  423. {
  424. NameLength -= LocalhostName.Length;
  425. KerbGlobalReadLock();
  426. NameLength += KerbGlobalMitMachineServiceName->Names[1].Length;
  427. //
  428. // Set the flag to indicate we need to replace the name, and that
  429. // the global lock is held.
  430. //
  431. ReplaceLocalhost = TRUE;
  432. }
  433. #endif
  434. //
  435. // Create the output names
  436. //
  437. OutputName = (PKERB_INTERNAL_NAME) KerbAllocate(KERB_INTERNAL_NAME_SIZE(NameParts + ExtraNameParts) + NameLength);
  438. if (OutputName == NULL)
  439. {
  440. Status = STATUS_INSUFFICIENT_RESOURCES;
  441. goto Cleanup;
  442. }
  443. OutputName->NameCount = NameParts + ExtraNameParts;
  444. OutputName->NameType = NameType;
  445. Where = (PUCHAR) OutputName + KERB_INTERNAL_NAME_SIZE(NameParts+ExtraNameParts);
  446. NameIndex = 0;
  447. //
  448. // If there is only one part of the name, handle that first
  449. //
  450. if (NameParts == 1)
  451. {
  452. OutputName->Names[0].Length = FirstNamePart.Length;
  453. OutputName->Names[0].MaximumLength = FirstNamePart.Length + sizeof(WCHAR);
  454. OutputName->Names[0].Buffer = (LPWSTR) Where;
  455. RtlCopyMemory(
  456. Where,
  457. FirstNamePart.Buffer,
  458. FirstNamePart.Length
  459. );
  460. OutputName->Names[0].Buffer[FirstNamePart.Length / sizeof(WCHAR)] = L'\0';
  461. Where += FirstNamePart.Length + sizeof(WCHAR);
  462. NameIndex = 1;
  463. }
  464. else
  465. {
  466. UNICODE_STRING TempName;
  467. //
  468. // Build up the name, piece by piece
  469. //
  470. DoneParsing = FALSE;
  471. NameIndex = 0;
  472. TempName.Buffer = FirstNamePart.Buffer;
  473. for ( Index = 0; Index <= FirstNamePart.Length / sizeof(WCHAR) ; Index++ )
  474. {
  475. //
  476. // If we hit the end or a separator, build a name part
  477. //
  478. if ((Index == FirstNamePart.Length / sizeof(WCHAR)) ||
  479. (FirstNamePart.Buffer[Index] == L'/') )
  480. {
  481. #ifdef later
  482. if ((NameIndex == 1) && (ReplaceLocalhost))
  483. {
  484. OutputName->Names[NameIndex].Length = KerbGlobalMitMachineServiceName->Names[1].Length;
  485. OutputName->Names[NameIndex].MaximumLength = OutputName->Names[NameIndex].Length + sizeof(WCHAR);
  486. OutputName->Names[NameIndex].Buffer = (LPWSTR) Where;
  487. RtlCopyMemory(
  488. Where,
  489. KerbGlobalMitMachineServiceName->Names[1].Buffer,
  490. OutputName->Names[NameIndex].Length
  491. );
  492. //
  493. // Release the lock now
  494. //
  495. KerbGlobalReleaseLock();
  496. ReplaceLocalhost = FALSE;
  497. }
  498. else
  499. #endif
  500. {
  501. OutputName->Names[NameIndex].Length = (USHORT) (&FirstNamePart.Buffer[Index] - TempName.Buffer) * sizeof(WCHAR);
  502. OutputName->Names[NameIndex].MaximumLength = OutputName->Names[NameIndex].Length + sizeof(WCHAR);
  503. OutputName->Names[NameIndex].Buffer = (LPWSTR) Where;
  504. RtlCopyMemory(
  505. Where,
  506. TempName.Buffer,
  507. OutputName->Names[NameIndex].Length
  508. );
  509. }
  510. Where += OutputName->Names[NameIndex].Length;
  511. *(LPWSTR)Where = L'\0';
  512. Where += sizeof(WCHAR);
  513. NameIndex++;
  514. TempName.Buffer = &FirstNamePart.Buffer[Index+1];
  515. }
  516. }
  517. DsysAssert(NameParts == NameIndex);
  518. }
  519. //
  520. // Now that we've built the output name, check SPN Cache.
  521. //
  522. if ( ARGUMENT_PRESENT(SpnCacheEntry) &&
  523. NameType == KRB_NT_SRV_INST &&
  524. SuppliedRealm.Length == 0 )
  525. {
  526. LocalCacheEntry = KerbLocateSpnCacheEntry(OutputName);
  527. if (NULL != LocalCacheEntry)
  528. {
  529. DebugLog((DEB_TRACE_SPN_CACHE, "Found in SPN Cache %p ", LocalCacheEntry));
  530. D_KerbPrintKdcName(DEB_TRACE_SPN_CACHE, LocalCacheEntry->Spn);
  531. *SpnCacheEntry = LocalCacheEntry;
  532. LocalCacheEntry = NULL;
  533. *ProcessFlags |= KERB_TARGET_USED_SPN_CACHE;
  534. }
  535. }
  536. D_DebugLog((DEB_TRACE_CTXT,"Cracked name %wZ into: ", RealTargetName));
  537. D_KerbPrintKdcName(DEB_TRACE_CTXT,OutputName);
  538. if (((Flags & KERB_CRACK_NAME_USE_WKSTA_REALM) == 0) || SuppliedRealm.Length > 0)
  539. {
  540. Status = KerbDuplicateString(
  541. TargetRealm,
  542. &SuppliedRealm
  543. );
  544. }
  545. else
  546. {
  547. if ((Flags & KERB_CRACK_NAME_USE_WKSTA_REALM) == 0)
  548. {
  549. DsysAssert(FALSE); // hey, this shouldn't ever be hit...
  550. RtlInitUnicodeString(
  551. TargetRealm,
  552. NULL
  553. );
  554. }
  555. else
  556. {
  557. //
  558. // There was no realm name provided, so use the wksta domain
  559. //
  560. Status = KerbGetOurDomainName(
  561. TargetRealm
  562. );
  563. }
  564. }
  565. if (!NT_SUCCESS(Status))
  566. {
  567. goto Cleanup;
  568. }
  569. *FinalTarget = OutputName;
  570. OutputName = NULL;
  571. Cleanup:
  572. #ifdef later
  573. if (ReplaceLocalhost)
  574. {
  575. KerbGlobalReleaseLock();
  576. }
  577. #endif
  578. if ( LocalCacheEntry )
  579. {
  580. KerbDereferenceSpnCacheEntry( LocalCacheEntry );
  581. }
  582. if (OutputName != NULL)
  583. {
  584. KerbFree(OutputName);
  585. }
  586. return(Status);
  587. }
  588. //+-------------------------------------------------------------------------
  589. //
  590. // Function: KerbValidateChannelBindings
  591. //
  592. // Synopsis: Validates the channel bindings copied from the client.
  593. //
  594. // Effects:
  595. //
  596. // Arguments: pBuffer -- Input buffer that contains channel bindings
  597. //
  598. // Requires:
  599. //
  600. // Returns:
  601. //
  602. // Notes:
  603. //
  604. //--------------------------------------------------------------------------
  605. NTSTATUS
  606. KerbValidateChannelBindings(
  607. IN PVOID pBuffer,
  608. IN ULONG ulBufferLength
  609. )
  610. {
  611. PSEC_CHANNEL_BINDINGS pClientBindings = (PSEC_CHANNEL_BINDINGS) pBuffer;
  612. DWORD dwBindingLength;
  613. DWORD dwInitiatorEnd;
  614. DWORD dwAcceptorEnd;
  615. DWORD dwApplicationEnd;
  616. //
  617. // If channel bindings were specified, they had better be there
  618. //
  619. if (pBuffer == NULL || ulBufferLength < sizeof(SEC_CHANNEL_BINDINGS))
  620. {
  621. return STATUS_INVALID_PARAMETER;
  622. }
  623. //
  624. // Make sure we got one contiguous buffer
  625. //
  626. dwBindingLength = sizeof(SEC_CHANNEL_BINDINGS)
  627. + pClientBindings->cbInitiatorLength
  628. + pClientBindings->cbAcceptorLength
  629. + pClientBindings->cbApplicationDataLength;
  630. //
  631. // Make sure the lengths are valid and check for overflow
  632. //
  633. if (dwBindingLength > ulBufferLength)
  634. {
  635. return STATUS_INVALID_PARAMETER;
  636. }
  637. dwInitiatorEnd = pClientBindings->dwInitiatorOffset + pClientBindings->cbInitiatorLength;
  638. dwAcceptorEnd = pClientBindings->dwAcceptorOffset + pClientBindings->cbAcceptorLength;
  639. dwApplicationEnd = pClientBindings->dwApplicationDataOffset + pClientBindings->cbApplicationDataLength;
  640. if ((dwInitiatorEnd > dwBindingLength || dwInitiatorEnd < pClientBindings->dwInitiatorOffset)
  641. ||
  642. (dwAcceptorEnd > dwBindingLength || dwAcceptorEnd < pClientBindings->dwAcceptorOffset)
  643. ||
  644. (dwApplicationEnd > dwBindingLength || dwApplicationEnd < pClientBindings->dwApplicationDataOffset))
  645. {
  646. return STATUS_INVALID_PARAMETER;
  647. }
  648. return STATUS_SUCCESS;
  649. }
  650. //+-------------------------------------------------------------------------
  651. //
  652. // Function: SpInitLsaModeContext
  653. //
  654. // Synopsis: Kerberos implementation of InitializeSecurityContext. This
  655. // routine handles the client side of authentication by
  656. // acquiring a ticket to the specified target. If a context
  657. // handle is passed in, then the input buffer is used to
  658. // verify the authenticity of the server.
  659. //
  660. // Effects:
  661. //
  662. // Arguments:
  663. //
  664. // Requires:
  665. //
  666. // Returns:
  667. //
  668. // Notes:
  669. //
  670. //
  671. //--------------------------------------------------------------------------
  672. NTSTATUS NTAPI
  673. SpInitLsaModeContext(
  674. IN OPTIONAL LSA_SEC_HANDLE CredentialHandle,
  675. IN OPTIONAL LSA_SEC_HANDLE ContextHandle,
  676. IN OPTIONAL PUNICODE_STRING TargetName,
  677. IN ULONG ContextRequirements,
  678. IN ULONG TargetDataRep,
  679. IN PSecBufferDesc InputBuffers,
  680. OUT PLSA_SEC_HANDLE NewContextHandle,
  681. IN OUT PSecBufferDesc OutputBuffers,
  682. OUT PULONG ContextAttributes,
  683. OUT PTimeStamp ExpirationTime,
  684. OUT PBOOLEAN MappedContext,
  685. OUT PSecBuffer ContextData
  686. )
  687. {
  688. PKERB_LOGON_SESSION LogonSession = NULL;
  689. PKERB_CREDENTIAL Credential = NULL;
  690. PKERB_TICKET_CACHE_ENTRY TicketCacheEntry = NULL;
  691. ULONG TicketOptions = 0;
  692. NTSTATUS Status = STATUS_SUCCESS;
  693. LUID LogonId;
  694. PUCHAR Request = NULL;
  695. ULONG RequestSize = 0;
  696. PUCHAR Reply = NULL;
  697. ULONG ReplySize;
  698. PSecBuffer OutputToken = NULL;
  699. PSecBuffer InputToken = NULL;
  700. UNICODE_STRING LocalTargetName;
  701. UNICODE_STRING TargetDomainName;
  702. PKERB_INTERNAL_NAME TargetInternalName = NULL;
  703. ULONG Index;
  704. PKERB_CONTEXT Context = NULL;
  705. ULONG Nonce = 0;
  706. ULONG ProcessFlags = 0;
  707. ULONG ReceiveNonce = 0;
  708. ULONG ContextFlags = 0;
  709. ULONG ContextAttribs = 0;
  710. TimeStamp ContextLifetime;
  711. BOOLEAN DoThirdLeg = FALSE;
  712. BOOLEAN GetAuthTicket = FALSE;
  713. BOOLEAN UseNullSession = FALSE;
  714. BOOLEAN GetServerTgt = FALSE;
  715. PKERB_ERROR ErrorMessage = NULL;
  716. PKERB_ERROR_METHOD_DATA ErrorData = NULL;
  717. PKERB_EXT_ERROR pExtendedError = NULL;
  718. PKERB_TGT_REPLY TgtReply = NULL;
  719. PKERB_SPN_CACHE_ENTRY SpnCacheEntry = NULL;
  720. ULONG ContextRetries = 0;
  721. KERB_CONTEXT_STATE ContextState = InvalidState;
  722. KERB_ENCRYPTION_KEY SubSessionKey = {0};
  723. BOOLEAN ClientAskedForDelegate = FALSE, ClientAskedForDelegateIfSafe = FALSE;
  724. ULONG ClientProcess = 0;
  725. PKERB_CREDMAN_CRED CredManCredentials = NULL;
  726. NTSTATUS InitialStatus = STATUS_SUCCESS;
  727. PSEC_CHANNEL_BINDINGS pChannelBindings = NULL;
  728. PBYTE pbMarshalledTargetInfo = NULL;
  729. ULONG cbMarshalledTargetInfo = 0;
  730. LUID NetworkServiceLuid = NETWORKSERVICE_LUID;
  731. KERB_INITSC_INFO InitSCTraceInfo;
  732. InitSCTraceInfo.EventTrace.Size = 0;
  733. D_DebugLog((DEB_TRACE_API,"SpInitLsaModeContext 0x%x called\n",ContextHandle));
  734. if( KerbEventTraceFlag ) // Event Trace: KerbInitSecurityContextStart {No Data}
  735. {
  736. InitSCTraceInfo.EventTrace.Guid = KerbInitSCGuid;
  737. InitSCTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_START;
  738. InitSCTraceInfo.EventTrace.Flags = WNODE_FLAG_TRACED_GUID;
  739. InitSCTraceInfo.EventTrace.Size = sizeof (EVENT_TRACE_HEADER);
  740. TraceEvent(
  741. KerbTraceLoggerHandle,
  742. (PEVENT_TRACE_HEADER)&InitSCTraceInfo
  743. );
  744. }
  745. //
  746. // Initialize the outputs.
  747. //
  748. *ContextAttributes = 0;
  749. *NewContextHandle = 0;
  750. *ExpirationTime = KerbGlobalHasNeverTime;
  751. *MappedContext = FALSE;
  752. ContextData->pvBuffer = NULL;
  753. ContextData->cbBuffer = 0;
  754. LocalTargetName.Buffer = NULL;
  755. LocalTargetName.Length = 0;
  756. TargetDomainName.Buffer = NULL;
  757. TargetDomainName.Length = 0;
  758. if (!KerbGlobalInitialized)
  759. {
  760. Status = STATUS_INVALID_SERVER_STATE;
  761. goto Cleanup;
  762. }
  763. //
  764. // Make sure we have at least one ip address
  765. //
  766. KerbGlobalReadLock();
  767. if (KerbGlobalNoTcpUdp)
  768. {
  769. Status = STATUS_NETWORK_UNREACHABLE;
  770. }
  771. KerbGlobalReleaseLock();
  772. if (!NT_SUCCESS(Status))
  773. {
  774. goto Cleanup;
  775. }
  776. //
  777. // Delegate will mean delegate_if_safe for this
  778. // release (NT5)
  779. //
  780. if ( ContextRequirements & ISC_REQ_DELEGATE )
  781. {
  782. ClientAskedForDelegate = TRUE;
  783. ContextRequirements |= ISC_REQ_DELEGATE_IF_SAFE ;
  784. ContextRequirements &= ~(ISC_REQ_DELEGATE) ;
  785. }
  786. else if ( ContextRequirements & ISC_REQ_DELEGATE_IF_SAFE )
  787. {
  788. ClientAskedForDelegateIfSafe = TRUE;
  789. }
  790. //////////////////////////////////////////////////////////////////////
  791. //
  792. // Process the input tokens
  793. //
  794. /////////////////////////////////////////////////////////////////////
  795. //
  796. // First locate the output token.
  797. //
  798. for (Index = 0; Index < OutputBuffers->cBuffers ; Index++ )
  799. {
  800. if (BUFFERTYPE(OutputBuffers->pBuffers[Index]) == SECBUFFER_TOKEN)
  801. {
  802. OutputToken = &OutputBuffers->pBuffers[Index];
  803. Status = LsaFunctions->MapBuffer(OutputToken,OutputToken);
  804. break;
  805. }
  806. }
  807. if (!NT_SUCCESS(Status))
  808. {
  809. D_DebugLog((DEB_ERROR,"Failed to map output token: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  810. goto Cleanup;
  811. }
  812. //
  813. // Now locate the Input token.
  814. //
  815. for (Index = 0; Index < InputBuffers->cBuffers ; Index++ )
  816. {
  817. if (BUFFERTYPE(InputBuffers->pBuffers[Index]) == SECBUFFER_TOKEN)
  818. {
  819. InputToken = &InputBuffers->pBuffers[Index];
  820. Status = LsaFunctions->MapBuffer(InputToken,InputToken);
  821. break;
  822. }
  823. }
  824. if (!NT_SUCCESS(Status))
  825. {
  826. D_DebugLog((DEB_ERROR,"Failed to map Input token: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  827. goto Cleanup;
  828. }
  829. //
  830. // Check to see if we were passed an additional name
  831. //
  832. for (Index = 0; Index < InputBuffers->cBuffers ; Index++ )
  833. {
  834. if (BUFFERTYPE(InputBuffers->pBuffers[Index]) == SECBUFFER_NEGOTIATION_INFO)
  835. {
  836. Status = LsaFunctions->MapBuffer(
  837. &InputBuffers->pBuffers[Index],
  838. &InputBuffers->pBuffers[Index]
  839. );
  840. if (!NT_SUCCESS(Status))
  841. {
  842. D_DebugLog( (DEB_ERROR, "Failed to map incoming SECBUFFER_NEGOTIATION_INFO. %x, %ws, %d", Status, THIS_FILE, __LINE__) );
  843. goto Cleanup;
  844. }
  845. LocalTargetName.Buffer = (LPWSTR) InputBuffers->pBuffers[Index].pvBuffer;
  846. //
  847. // We can only stick 64k in a the length field, so make sure the
  848. // buffer is not too big.
  849. //
  850. if (InputBuffers->pBuffers[Index].cbBuffer > 0xffff)
  851. {
  852. Status = SEC_E_INVALID_TOKEN;
  853. goto Cleanup;
  854. }
  855. LocalTargetName.Length =
  856. LocalTargetName.MaximumLength = (USHORT) InputBuffers->pBuffers[Index].cbBuffer;
  857. break;
  858. }
  859. }
  860. //
  861. // Process the target names
  862. //
  863. Status = KerbProcessTargetNames(
  864. TargetName,
  865. &LocalTargetName,
  866. 0, // No flags
  867. &ProcessFlags,
  868. &TargetInternalName,
  869. &TargetDomainName,
  870. &SpnCacheEntry
  871. );
  872. if (!NT_SUCCESS(Status))
  873. {
  874. goto Cleanup;
  875. }
  876. //
  877. // Check to see if we were passed channel bindings
  878. //
  879. for( Index = 0; Index < InputBuffers->cBuffers; Index++ )
  880. {
  881. if( BUFFERTYPE(InputBuffers->pBuffers[Index]) == SECBUFFER_CHANNEL_BINDINGS )
  882. {
  883. PVOID temp = NULL;
  884. Status = LsaFunctions->MapBuffer(
  885. &InputBuffers->pBuffers[Index],
  886. &InputBuffers->pBuffers[Index]
  887. );
  888. if( !NT_SUCCESS(Status) )
  889. {
  890. D_DebugLog( (DEB_ERROR,
  891. "Failed to map incoming SECBUFFER_CHANNEL_BINDINGS. %x, %ws, %d\n",
  892. Status,
  893. THIS_FILE,
  894. __LINE__) );
  895. goto Cleanup;
  896. }
  897. pChannelBindings = (PSEC_CHANNEL_BINDINGS) InputBuffers->pBuffers[Index].pvBuffer;
  898. Status = KerbValidateChannelBindings(pChannelBindings,
  899. InputBuffers->pBuffers[Index].cbBuffer);
  900. if (!NT_SUCCESS(Status))
  901. {
  902. pChannelBindings = NULL;
  903. goto Cleanup;
  904. }
  905. break;
  906. }
  907. }
  908. //////////////////////////////////////////////////////////////////////
  909. //
  910. // If the caller passed in a context handle, deal with updating an
  911. // existing context.
  912. //
  913. /////////////////////////////////////////////////////////////////////
  914. //
  915. // If the input context handle is no NULL then we are actually
  916. // finalizing an already-existing context. So be it.
  917. //
  918. //
  919. // Use "while" so we can break out.
  920. //
  921. while (ContextHandle != 0)
  922. {
  923. D_DebugLog((DEB_TRACE_CTXT,"SpInitLsaModeContext: Second call to Initialize\n"));
  924. if (InputToken == NULL)
  925. {
  926. D_DebugLog((DEB_ERROR,"Trying to complete a context with no input token! %ws, line %d\n", THIS_FILE, __LINE__));
  927. Status = SEC_E_INVALID_TOKEN;
  928. goto Cleanup;
  929. }
  930. //
  931. // First reference the context.
  932. //
  933. Status = KerbReferenceContext(
  934. ContextHandle,
  935. FALSE, // don't unlink
  936. &Context
  937. );
  938. if (Context == NULL)
  939. {
  940. D_DebugLog((DEB_ERROR,"Failed to reference context 0x%x. %ws, line %d\n",ContextHandle, THIS_FILE, __LINE__));
  941. goto Cleanup;
  942. }
  943. //
  944. // Check the mode of the context to make sure we can finalize it.
  945. //
  946. KerbReadLockContexts();
  947. ContextState = Context->ContextState;
  948. if ((ContextState != ApRequestSentState) &&
  949. (ContextState != TgtRequestSentState))
  950. {
  951. D_DebugLog((DEB_ERROR,"Invalid context state: %d. %ws, line %d\n",
  952. Context->ContextState, THIS_FILE, __LINE__));
  953. Status = STATUS_INVALID_HANDLE;
  954. KerbUnlockContexts();
  955. goto Cleanup;
  956. }
  957. ContextRetries = Context->Retries;
  958. ContextFlags = Context->ContextFlags;
  959. ContextAttribs = Context->ContextAttributes;
  960. Nonce = Context->Nonce;
  961. CredentialHandle = Context->CredentialHandle;
  962. ClientProcess = Context->ClientProcess;
  963. KerbUnlockContexts();
  964. //
  965. // If we are not doing datagram, unpack the AP or TGT reply.
  966. //
  967. if ((ContextFlags & ISC_RET_DATAGRAM) == 0)
  968. {
  969. ////////////////////////////////////////////////////
  970. //
  971. // Handle a TGT reply - get out the TGT & the name of
  972. // the server
  973. //
  974. ////////////////////////////////////////////////////
  975. if (ContextState == TgtRequestSentState)
  976. {
  977. D_DebugLog((DEB_TRACE_U2U, "SpInitLsaModeContext calling KerbUnpackTgtReply\n"));
  978. KerbWriteLockContexts();
  979. if (!(Context->ContextAttributes & KERB_CONTEXT_USER_TO_USER))
  980. {
  981. Context->ContextAttributes |= KERB_CONTEXT_USER_TO_USER;
  982. DebugLog((DEB_WARN, "SpInitLsaModeContext * use_sesion_key but USER2USER-OUTBOUND not set, added it now\n"));
  983. }
  984. KerbUnlockContexts();
  985. Status = KerbUnpackTgtReply(
  986. Context,
  987. (PUCHAR) InputToken->pvBuffer,
  988. InputToken->cbBuffer,
  989. &TargetInternalName,
  990. &TargetDomainName,
  991. &TgtReply
  992. );
  993. if (!NT_SUCCESS(Status))
  994. {
  995. D_DebugLog((DEB_ERROR,"Failed to unpack TGT reply: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  996. //
  997. // Check for an error message
  998. //
  999. Status = KerbReceiveErrorMessage(
  1000. (PUCHAR) InputToken->pvBuffer,
  1001. InputToken->cbBuffer,
  1002. Context,
  1003. &ErrorMessage,
  1004. &ErrorData
  1005. );
  1006. if (!NT_SUCCESS(Status))
  1007. {
  1008. goto Cleanup;
  1009. }
  1010. KerbReportKerbError(
  1011. NULL,
  1012. NULL,
  1013. NULL,
  1014. NULL,
  1015. KLIN(FILENO,__LINE__),
  1016. ErrorMessage,
  1017. ((NULL != ErrorMessage) ? ErrorMessage->error_code : KRB_ERR_GENERIC),
  1018. pExtendedError,
  1019. FALSE
  1020. );
  1021. //
  1022. // Ahh. We have an error message. See if it is an
  1023. // error we can handle, and if so, Now we need to
  1024. // try to build a better AP request. Or, if we have
  1025. // already retried once, fail.
  1026. //
  1027. DebugLog((DEB_WARN, "SpInitLsaModeContext received KERB_ERROR message with error 0x%x, can't handle\n",
  1028. ErrorMessage->error_code ));
  1029. if ((ErrorMessage->error_code == KRB_ERR_GENERIC)
  1030. && (ErrorData != NULL)
  1031. && (ErrorData->bit_mask & data_value_present)
  1032. && (ErrorData->data_type == KERB_AP_ERR_TYPE_NTSTATUS)
  1033. && (ErrorData->data_value.length == sizeof(ULONG)))
  1034. {
  1035. Status = *((PULONG)ErrorData->data_value.value);
  1036. }
  1037. else
  1038. {
  1039. Status = KerbMapKerbError((KERBERR) ErrorMessage->error_code);
  1040. if (NT_SUCCESS(Status))
  1041. {
  1042. Status = STATUS_INTERNAL_ERROR;
  1043. }
  1044. }
  1045. goto Cleanup;
  1046. }
  1047. //
  1048. // Break out so we generate a normal request now
  1049. //
  1050. break;
  1051. }
  1052. else // not user-to-user
  1053. {
  1054. ////////////////////////////////////////////////////
  1055. //
  1056. // This is the response to an AP request. It could be
  1057. // an AP reply or an error. Handle both cases
  1058. //
  1059. ////////////////////////////////////////////////////
  1060. //
  1061. // Now unpack the AP reply
  1062. //
  1063. Status = KerbVerifyApReply(
  1064. Context,
  1065. (PUCHAR) InputToken->pvBuffer,
  1066. InputToken->cbBuffer,
  1067. &ReceiveNonce
  1068. );
  1069. if (!NT_SUCCESS(Status))
  1070. {
  1071. //
  1072. // Check for an error message
  1073. //
  1074. Status = KerbReceiveErrorMessage(
  1075. (PUCHAR) InputToken->pvBuffer,
  1076. InputToken->cbBuffer,
  1077. Context,
  1078. &ErrorMessage,
  1079. &ErrorData
  1080. );
  1081. if (!NT_SUCCESS(Status))
  1082. {
  1083. goto Cleanup;
  1084. }
  1085. KerbReportKerbError(
  1086. NULL,
  1087. NULL,
  1088. NULL,
  1089. NULL,
  1090. KLIN(FILENO, __LINE__),
  1091. ErrorMessage,
  1092. ((NULL != ErrorMessage) ? ErrorMessage->error_code : KRB_ERR_GENERIC),
  1093. pExtendedError,
  1094. FALSE
  1095. );
  1096. DebugLog((DEB_WARN,"Failed to verify AP reply: 0x%x\n",ErrorMessage->error_code));
  1097. //
  1098. // Ahh. We have an error message. See if it is an
  1099. // error we can handle, and if so, Now we need to
  1100. // try to build a better AP request. Or, if we have
  1101. // already retried once, fail. We can't get a new ticket
  1102. // with user-to-user.
  1103. //
  1104. if ((ContextRetries != 0) ||
  1105. (((KERBERR) ErrorMessage->error_code != KRB_AP_ERR_SKEW) &&
  1106. ((KERBERR) ErrorMessage->error_code != KRB_AP_ERR_TKT_NYV) &&
  1107. ((KERBERR) ErrorMessage->error_code != KRB_AP_ERR_USER_TO_USER_REQUIRED) &&
  1108. ((KERBERR) ErrorMessage->error_code != KRB_AP_ERR_MODIFIED)) ||
  1109. (((KERBERR) ErrorMessage->error_code == KRB_AP_ERR_MODIFIED) &&
  1110. ((ContextAttribs & KERB_CONTEXT_USER_TO_USER) != 0)))
  1111. {
  1112. if ((ErrorMessage->error_code == KRB_ERR_GENERIC) &&
  1113. (ErrorData != NULL) && (ErrorData->data_type == KERB_AP_ERR_TYPE_NTSTATUS) &&
  1114. ((ErrorData->bit_mask & data_value_present) != 0) &&
  1115. (ErrorData->data_value.value != NULL) &&
  1116. (ErrorData->data_value.length == sizeof(ULONG)))
  1117. {
  1118. Status = *((PULONG)ErrorMessage->error_data.value);
  1119. if (NT_SUCCESS(Status))
  1120. {
  1121. Status = STATUS_INTERNAL_ERROR;
  1122. }
  1123. }
  1124. if (ErrorMessage->error_code == KRB_AP_ERR_MODIFIED)
  1125. {
  1126. //
  1127. // If the server couldn't decrypt the ticket,
  1128. // then the target name is wrong for the server.
  1129. //
  1130. DebugLog((DEB_ERROR, "App modified error (NO CONTINUE, bail)\n"));
  1131. KerbReportApError(ErrorMessage);
  1132. Status = SEC_E_WRONG_PRINCIPAL;
  1133. }
  1134. else if (ErrorMessage->error_code == KRB_AP_ERR_TKT_NYV)
  1135. {
  1136. DebugLog((DEB_ERROR, "Not yet valid error - Check Time Skew\n"));
  1137. KerbReportApError(ErrorMessage);
  1138. Status = STATUS_TIME_DIFFERENCE_AT_DC;
  1139. }
  1140. else
  1141. {
  1142. DebugLog((DEB_ERROR, "InitSecContext Received KERB_ERROR message with error 0x%x, can't handle. %ws, line %d\n",
  1143. ErrorMessage->error_code, THIS_FILE, __LINE__ ));
  1144. Status = KerbMapKerbError((KERBERR) ErrorMessage->error_code);
  1145. if (NT_SUCCESS(Status))
  1146. {
  1147. Status = STATUS_INTERNAL_ERROR;
  1148. }
  1149. }
  1150. goto Cleanup;
  1151. }
  1152. else
  1153. {
  1154. //
  1155. // Check to see if the server supports skew
  1156. //
  1157. if ((ErrorMessage->error_code == KRB_AP_ERR_SKEW) &&
  1158. (ErrorData == NULL) || ((ErrorData != NULL) && (ErrorData->data_type != KERB_AP_ERR_TYPE_SKEW_RECOVERY)))
  1159. {
  1160. //
  1161. // The server doesn't support skew recovery.
  1162. //
  1163. D_DebugLog((DEB_WARN,"Skew error but server doesn't handle skew recovery.\n"));
  1164. Status = KerbMapKerbError((KERBERR) ErrorMessage->error_code);
  1165. goto Cleanup;
  1166. }
  1167. //
  1168. // Here's where we'll punt "not yet valid tickets" and friends...
  1169. //
  1170. if (ErrorMessage->error_code == KRB_AP_ERR_TKT_NYV)
  1171. {
  1172. KerbPurgeServiceTicketAndTgt(
  1173. Context,
  1174. CredentialHandle,
  1175. CredManCredentials
  1176. );
  1177. DebugLog((DEB_ERROR, "Purged all tickets due to NYV error!\n"));
  1178. }
  1179. KerbWriteLockContexts();
  1180. Context->Retries++;
  1181. KerbUnlockContexts();
  1182. }
  1183. ////////////////////////////////////////////////////
  1184. //
  1185. // We got an error we can handle. For user-to-user
  1186. // required, we received the TGT so we can get
  1187. // the appropriate ticket. For modified, we want
  1188. // to toss the old ticket & get a new one, hopefully
  1189. // with a better key.
  1190. //
  1191. ////////////////////////////////////////////////////
  1192. if ((KERBERR) ErrorMessage->error_code == KRB_AP_ERR_USER_TO_USER_REQUIRED)
  1193. {
  1194. D_DebugLog((DEB_TRACE_U2U, "SpInitLsaModeContext received KRB_AP_ERR_USER_TO_USER_REQUIRED\n"));
  1195. if ((ErrorMessage->bit_mask & error_data_present) == 0)
  1196. {
  1197. DebugLog((DEB_ERROR,"Server requires user-to-user but didn't send TGT reply. %ws, line %d\n", THIS_FILE, __LINE__));
  1198. Status = STATUS_NO_TGT_REPLY;
  1199. goto Cleanup;
  1200. }
  1201. //
  1202. // Check for TGT reply
  1203. //
  1204. Status = KerbUnpackTgtReply(
  1205. Context,
  1206. ErrorMessage->error_data.value,
  1207. ErrorMessage->error_data.length,
  1208. &TargetInternalName,
  1209. &TargetDomainName,
  1210. &TgtReply
  1211. );
  1212. if (!NT_SUCCESS(Status))
  1213. {
  1214. Status = STATUS_INVALID_PARAMETER;
  1215. goto Cleanup;
  1216. }
  1217. //
  1218. // Fall through into normal ticket handling
  1219. //
  1220. ContextFlags |= ISC_RET_USE_SESSION_KEY;
  1221. //
  1222. // Remove the old ticket cache entry
  1223. //
  1224. KerbWriteLockContexts();
  1225. TicketCacheEntry = Context->TicketCacheEntry;
  1226. Context->TicketCacheEntry = NULL;
  1227. KerbUnlockContexts();
  1228. if (TicketCacheEntry != NULL)
  1229. {
  1230. KerbFreeString(
  1231. &TargetDomainName
  1232. );
  1233. KerbFreeKdcName(
  1234. &TargetInternalName
  1235. );
  1236. //
  1237. // Get the target name from the old ticket
  1238. //
  1239. KerbReadLockTicketCache();
  1240. Status = KerbDuplicateString(
  1241. &TargetDomainName,
  1242. &TicketCacheEntry->DomainName
  1243. );
  1244. if (NT_SUCCESS(Status))
  1245. {
  1246. Status = KerbDuplicateKdcName(
  1247. &TargetInternalName,
  1248. TicketCacheEntry->ServiceName
  1249. );
  1250. }
  1251. KerbUnlockTicketCache();
  1252. if (!NT_SUCCESS(Status))
  1253. {
  1254. goto Cleanup;
  1255. }
  1256. //
  1257. // Free this ticket cache entry
  1258. //
  1259. KerbRemoveTicketCacheEntry(TicketCacheEntry);
  1260. //
  1261. // Remove the reference holding it to the context
  1262. //
  1263. KerbDereferenceTicketCacheEntry(TicketCacheEntry);
  1264. TicketCacheEntry = NULL;
  1265. }
  1266. break;
  1267. }
  1268. else if ((KERBERR) ErrorMessage->error_code == KRB_AP_ERR_MODIFIED)
  1269. {
  1270. DebugLog((DEB_WARN, "App modified error (purge ticket!)\n"));
  1271. KerbWriteLockContexts();
  1272. TicketCacheEntry = Context->TicketCacheEntry;
  1273. Context->TicketCacheEntry = NULL;
  1274. KerbUnlockContexts();
  1275. if (TicketCacheEntry != NULL)
  1276. {
  1277. //
  1278. // Get rid of the old ticket in the context
  1279. KerbFreeString(
  1280. &TargetDomainName
  1281. );
  1282. KerbFreeKdcName(
  1283. &TargetInternalName
  1284. );
  1285. //
  1286. // Get the target name from the old ticket
  1287. //
  1288. KerbReadLockTicketCache();
  1289. Status = KerbDuplicateString(
  1290. &TargetDomainName,
  1291. &TicketCacheEntry->DomainName
  1292. );
  1293. if (NT_SUCCESS(Status))
  1294. {
  1295. Status = KerbDuplicateKdcName(
  1296. &TargetInternalName,
  1297. TicketCacheEntry->ServiceName
  1298. );
  1299. }
  1300. KerbUnlockTicketCache();
  1301. if (!NT_SUCCESS(Status))
  1302. {
  1303. goto Cleanup;
  1304. }
  1305. //
  1306. // Free this ticket cache entry
  1307. //
  1308. KerbRemoveTicketCacheEntry(TicketCacheEntry);
  1309. //
  1310. // Remove the reference holding it to the context
  1311. //
  1312. KerbDereferenceTicketCacheEntry(TicketCacheEntry);
  1313. TicketCacheEntry = NULL;
  1314. }
  1315. }
  1316. break;
  1317. }
  1318. }
  1319. ////////////////////////////////////////////////////
  1320. //
  1321. // We successfully decrypted the AP reply. At this point
  1322. // we want to finalize the context. For DCE style we send
  1323. // a useless AP reply to the server.
  1324. //
  1325. ////////////////////////////////////////////////////
  1326. //
  1327. // If the caller wanted DCE style authentication, build another
  1328. // AP reply
  1329. //
  1330. KerbWriteLockContexts();
  1331. if ((Context->ContextFlags & ISC_RET_USED_DCE_STYLE) != 0)
  1332. {
  1333. DoThirdLeg = TRUE;
  1334. }
  1335. else
  1336. {
  1337. DoThirdLeg = FALSE;
  1338. }
  1339. Context->ReceiveNonce = ReceiveNonce;
  1340. KerbUnlockContexts();
  1341. if (DoThirdLeg)
  1342. {
  1343. //
  1344. // Build an AP reply to send back to the server.
  1345. //
  1346. Status = KerbBuildThirdLegApReply(
  1347. Context,
  1348. ReceiveNonce,
  1349. &Reply,
  1350. &ReplySize
  1351. );
  1352. if (!NT_SUCCESS(Status))
  1353. {
  1354. D_DebugLog((DEB_ERROR,"Failed to build AP reply: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1355. goto Cleanup;
  1356. }
  1357. if (OutputToken == NULL)
  1358. {
  1359. D_DebugLog((DEB_ERROR,"Output token missing. %ws, line %d\n", THIS_FILE, __LINE__));
  1360. Status = SEC_E_INVALID_TOKEN;
  1361. goto Cleanup;
  1362. }
  1363. //
  1364. // Return the AP reply in the output buffer.
  1365. //
  1366. if ((ContextRequirements & ISC_REQ_ALLOCATE_MEMORY) == 0)
  1367. {
  1368. if (OutputToken->cbBuffer < ReplySize)
  1369. {
  1370. ULONG ErrorData[3];
  1371. ErrorData[0] = ReplySize;
  1372. ErrorData[1] = OutputToken->cbBuffer;
  1373. ErrorData[2] = ClientProcess;
  1374. DebugLog((DEB_ERROR,"Output token is too small - sent in %d, needed %d. %ws, line %d\n",
  1375. OutputToken->cbBuffer,ReplySize, THIS_FILE, __LINE__ ));
  1376. OutputToken->cbBuffer = ReplySize;
  1377. Status = STATUS_BUFFER_TOO_SMALL;
  1378. KerbReportNtstatus(
  1379. KERBEVT_INSUFFICIENT_TOKEN_SIZE,
  1380. Status,
  1381. NULL,
  1382. 0,
  1383. ErrorData,
  1384. 3
  1385. );
  1386. goto Cleanup;
  1387. }
  1388. RtlCopyMemory(
  1389. OutputToken->pvBuffer,
  1390. Reply,
  1391. ReplySize
  1392. );
  1393. }
  1394. else
  1395. {
  1396. OutputToken->pvBuffer = Reply;
  1397. Reply = NULL;
  1398. *ContextAttributes |= ISC_RET_ALLOCATED_MEMORY;
  1399. }
  1400. OutputToken->cbBuffer = ReplySize;
  1401. }
  1402. else
  1403. {
  1404. //
  1405. // No return message, so set the return length to zero.
  1406. //
  1407. if (OutputToken != NULL)
  1408. {
  1409. OutputToken->cbBuffer = 0;
  1410. }
  1411. }
  1412. }
  1413. else
  1414. {
  1415. //////////////////////////////////////////////////////////////////////
  1416. //
  1417. // We are doing datagram, so we don't expect anything from the
  1418. // server but perhaps an error. If we get an error, handle it.
  1419. // Otherwise, build an AP request to send to the server
  1420. //
  1421. /////////////////////////////////////////////////////////////////////
  1422. //
  1423. // We are doing datagram. Build the AP request for the
  1424. // server side.
  1425. //
  1426. //
  1427. // Check for an error message
  1428. //
  1429. if ((InputToken != NULL) && (InputToken->cbBuffer != 0))
  1430. {
  1431. Status = KerbReceiveErrorMessage(
  1432. (PUCHAR) InputToken->pvBuffer,
  1433. InputToken->cbBuffer,
  1434. Context,
  1435. &ErrorMessage,
  1436. &ErrorData
  1437. );
  1438. if (!NT_SUCCESS(Status))
  1439. {
  1440. goto Cleanup;
  1441. }
  1442. KerbReportKerbError(
  1443. NULL,
  1444. NULL,
  1445. NULL,
  1446. NULL,
  1447. KLIN(FILENO, __LINE__),
  1448. ErrorMessage,
  1449. ((NULL != ErrorMessage) ? ErrorMessage->error_code : KRB_ERR_GENERIC),
  1450. pExtendedError,
  1451. FALSE
  1452. );
  1453. //
  1454. // Check for a real error
  1455. //
  1456. if ((ErrorData != NULL) && (ErrorData->data_type == KERB_AP_ERR_TYPE_NTSTATUS) &&
  1457. ((ErrorData->bit_mask & data_value_present) != 0) &&
  1458. (ErrorData->data_value.value != NULL) &&
  1459. (ErrorData->data_value.length == sizeof(ULONG)))
  1460. {
  1461. Status = *((PULONG)ErrorMessage->error_data.value);
  1462. if (NT_SUCCESS(Status))
  1463. {
  1464. Status = STATUS_INTERNAL_ERROR;
  1465. }
  1466. goto Cleanup;
  1467. }
  1468. }
  1469. //
  1470. // Get the associated credential
  1471. //
  1472. Status = KerbReferenceCredential(
  1473. CredentialHandle,
  1474. KERB_CRED_OUTBOUND | KERB_CRED_TGT_AVAIL,
  1475. FALSE,
  1476. &Credential);
  1477. if (!NT_SUCCESS(Status))
  1478. {
  1479. DebugLog((DEB_WARN,"Failed to locate credential: 0x%x\n",Status));
  1480. goto Cleanup;
  1481. }
  1482. //
  1483. // Get the logon id from the credentials so we can locate the
  1484. // logon session.
  1485. //
  1486. LogonId = Credential->LogonId;
  1487. //
  1488. // Get the logon session
  1489. //
  1490. LogonSession = KerbReferenceLogonSession( &LogonId, FALSE );
  1491. if (LogonSession == NULL)
  1492. {
  1493. Status = STATUS_NO_SUCH_LOGON_SESSION;
  1494. goto Cleanup;
  1495. }
  1496. KerbReadLockLogonSessions(LogonSession);
  1497. if (Credential->SuppliedCredentials != NULL)
  1498. {
  1499. GetAuthTicket = TRUE;
  1500. } else if (((Credential->CredentialFlags & KERB_CRED_NULL_SESSION) != 0) ||
  1501. ((ContextRequirements & ISC_REQ_NULL_SESSION) != 0))
  1502. {
  1503. UseNullSession = TRUE;
  1504. ContextFlags |= ISC_RET_NULL_SESSION;
  1505. }
  1506. KerbUnlockLogonSessions(LogonSession);
  1507. KerbReadLockContexts();
  1508. TicketCacheEntry = Context->TicketCacheEntry;
  1509. //
  1510. // Get the session key to use from the context
  1511. //
  1512. if (Context->SessionKey.keyvalue.value != 0)
  1513. {
  1514. if (!KERB_SUCCESS(KerbDuplicateKey(
  1515. &SubSessionKey,
  1516. &Context->SessionKey
  1517. )))
  1518. {
  1519. Status = STATUS_INSUFFICIENT_RESOURCES;
  1520. }
  1521. }
  1522. Context->TicketCacheEntry = NULL;
  1523. KerbUnlockContexts();
  1524. if (!NT_SUCCESS(Status))
  1525. {
  1526. goto Cleanup;
  1527. }
  1528. D_DebugLog((DEB_TRACE_CTXT2,"Building AP request for datagram oriented context\n"));
  1529. //
  1530. // If we are building a null session, build the special null
  1531. // session AP request
  1532. //
  1533. if (UseNullSession)
  1534. {
  1535. Status = KerbBuildNullSessionApRequest(
  1536. &Request,
  1537. &RequestSize
  1538. );
  1539. //
  1540. // Turn off all unsupported flags
  1541. //
  1542. ContextFlags &= ( ISC_RET_ALLOCATED_MEMORY |
  1543. ISC_RET_CONNECTION |
  1544. ISC_RET_DATAGRAM |
  1545. ISC_RET_NULL_SESSION );
  1546. }
  1547. else
  1548. {
  1549. if (TicketCacheEntry == NULL)
  1550. {
  1551. DebugLog((DEB_ERROR, "SpInitLsaModeContext does have service ticket\n"));
  1552. Status = STATUS_INTERNAL_ERROR;
  1553. goto Cleanup;
  1554. }
  1555. Status = KerbBuildApRequest(
  1556. LogonSession,
  1557. Credential,
  1558. CredManCredentials,
  1559. TicketCacheEntry,
  1560. ErrorMessage,
  1561. ContextAttribs,
  1562. &ContextFlags,
  1563. &Request,
  1564. &RequestSize,
  1565. &Nonce,
  1566. &SubSessionKey,
  1567. pChannelBindings
  1568. );
  1569. }
  1570. if (!NT_SUCCESS(Status))
  1571. {
  1572. DebugLog((DEB_ERROR,"Failed to build AP request: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1573. goto Cleanup;
  1574. }
  1575. //
  1576. // Return the AP request in the output buffer.
  1577. //
  1578. if ((ContextRequirements & ISC_REQ_ALLOCATE_MEMORY) == 0)
  1579. {
  1580. if (OutputToken->cbBuffer < RequestSize)
  1581. {
  1582. ULONG ErrorData[3];
  1583. ErrorData[0] = RequestSize;
  1584. ErrorData[1] = OutputToken->cbBuffer;
  1585. ErrorData[2] = ClientProcess;
  1586. D_DebugLog((DEB_ERROR,"Output token is too small - sent in %d, needed %d. %ws, line %d\n",
  1587. OutputToken->cbBuffer,RequestSize, THIS_FILE, __LINE__ ));
  1588. OutputToken->cbBuffer = RequestSize;
  1589. Status = STATUS_BUFFER_TOO_SMALL;
  1590. KerbReportNtstatus(
  1591. KERBEVT_INSUFFICIENT_TOKEN_SIZE,
  1592. Status,
  1593. NULL,
  1594. 0,
  1595. ErrorData,
  1596. 3
  1597. );
  1598. goto Cleanup;
  1599. }
  1600. RtlCopyMemory(
  1601. OutputToken->pvBuffer,
  1602. Request,
  1603. RequestSize
  1604. );
  1605. }
  1606. else
  1607. {
  1608. OutputToken->pvBuffer = Request;
  1609. *ContextAttributes |= ISC_RET_ALLOCATED_MEMORY;
  1610. Request = NULL;
  1611. }
  1612. OutputToken->cbBuffer = RequestSize;
  1613. }
  1614. //
  1615. //
  1616. // We're done - we finalized.
  1617. //
  1618. Status = STATUS_SUCCESS;
  1619. KerbReadLockContexts();
  1620. Context->ContextFlags = ContextFlags;
  1621. *ContextAttributes |= Context->ContextFlags;
  1622. KerbUtcTimeToLocalTime(
  1623. ExpirationTime,
  1624. &Context->Lifetime
  1625. );
  1626. *NewContextHandle = ContextHandle;
  1627. KerbUnlockContexts();
  1628. goto Cleanup;
  1629. }
  1630. //////////////////////////////////////////////////////////////////////
  1631. //
  1632. // We need to create a request to the server, possibly a TGT request
  1633. // or an AP request depending on what phase of the protocol we're in.
  1634. //
  1635. /////////////////////////////////////////////////////////////////////
  1636. DsysAssert(!((Context != NULL) ^ ((ErrorMessage != NULL) || (TgtReply != NULL))));
  1637. D_DebugLog((DEB_TRACE_CTXT,"SpInitLsaModeContext: First call to Initialize\n"));
  1638. //
  1639. // This is the case where we are constructing a new context.
  1640. //
  1641. //
  1642. // Get the associated credential and its TGT, if needed
  1643. //
  1644. Status = KerbReferenceCredential(
  1645. CredentialHandle,
  1646. KERB_CRED_OUTBOUND | KERB_CRED_TGT_AVAIL,
  1647. FALSE,
  1648. &Credential
  1649. );
  1650. if (!NT_SUCCESS(Status))
  1651. {
  1652. InitialStatus = Status;
  1653. Status = KerbReferenceCredential(
  1654. CredentialHandle,
  1655. KERB_CRED_OUTBOUND,
  1656. FALSE,
  1657. &Credential
  1658. );
  1659. if( !NT_SUCCESS( Status ) || Credential->SuppliedCredentials != NULL)
  1660. {
  1661. Status = InitialStatus;
  1662. D_DebugLog((DEB_WARN,"Failed to locate credential 0x%x\n",Status));
  1663. goto Cleanup;
  1664. }
  1665. //
  1666. // if we got here, only explicit or credman creds are allowed.
  1667. // If the explicit creds failed to get a TGT from above, its also
  1668. // time to bail, as explicit creds never should fall back to credman.
  1669. //
  1670. }
  1671. //
  1672. // Get the logon id from the credentials so we can locate the
  1673. // logon session.
  1674. //
  1675. LogonId = Credential->LogonId;
  1676. //
  1677. // Get the logon session
  1678. //
  1679. LogonSession = KerbReferenceLogonSession( &LogonId, FALSE );
  1680. if (LogonSession == NULL)
  1681. {
  1682. Status = STATUS_NO_SUCH_LOGON_SESSION;
  1683. goto Cleanup;
  1684. }
  1685. KerbWriteLockLogonSessions(LogonSession);
  1686. if (Credential->SuppliedCredentials != NULL)
  1687. {
  1688. GetAuthTicket = TRUE;
  1689. // Ignore SPN cache for supplied credentials
  1690. ProcessFlags &= ~KERB_TARGET_UNKNOWN_SPN;
  1691. }
  1692. else if (((Credential->CredentialFlags & KERB_CRED_NULL_SESSION) != 0) ||
  1693. ((ContextRequirements & ISC_REQ_NULL_SESSION) != 0))
  1694. {
  1695. UseNullSession = TRUE;
  1696. ContextFlags |= ISC_RET_NULL_SESSION;
  1697. }
  1698. else
  1699. {
  1700. //
  1701. // go to the credential manager to try and find
  1702. // credentials for this specific target
  1703. //
  1704. ULONG ExtraTargetFlags = 0;
  1705. if ((ContextRequirements & ISC_REQ_USE_SUPPLIED_CREDS) != 0)
  1706. {
  1707. ExtraTargetFlags = CRED_TI_ONLY_PASSWORD_REQUIRED;
  1708. }
  1709. Status = KerbCheckCredMgrForGivenTarget(
  1710. LogonSession,
  1711. Credential,
  1712. TargetName, // original targetname, may contain marshalled targetinfo
  1713. TargetInternalName,
  1714. ExtraTargetFlags,
  1715. &TargetDomainName,
  1716. NULL,
  1717. &CredManCredentials,
  1718. &pbMarshalledTargetInfo,
  1719. &cbMarshalledTargetInfo
  1720. );
  1721. if (!NT_SUCCESS(Status))
  1722. {
  1723. KerbUnlockLogonSessions(LogonSession);
  1724. D_DebugLog((DEB_ERROR,"Failed to get outbound ticket: 0x%x\n",Status));
  1725. goto Cleanup;
  1726. }
  1727. if (CredManCredentials != NULL)
  1728. {
  1729. GetAuthTicket = TRUE;
  1730. ProcessFlags &= ~KERB_TARGET_UNKNOWN_SPN;
  1731. }
  1732. else
  1733. {
  1734. //
  1735. // if this is a local account logon then we have to have a cred man
  1736. // credential
  1737. //
  1738. if ((Credential->CredentialFlags & KERB_CRED_LOCAL_ACCOUNT) != 0)
  1739. {
  1740. KerbUnlockLogonSessions(LogonSession);
  1741. D_DebugLog((DEB_WARN, "Trying to use a local logon session with Kerberos\n"));
  1742. Status = SEC_E_NO_CREDENTIALS;
  1743. goto Cleanup;
  1744. }
  1745. //
  1746. // if no credman cred was found, we didn't use explicit creds,
  1747. // and the initial credential reference for TGT_AVAIL failed, bail now.
  1748. //
  1749. if( !NT_SUCCESS( InitialStatus ) )
  1750. {
  1751. KerbUnlockLogonSessions(LogonSession);
  1752. Status = InitialStatus;
  1753. D_DebugLog((DEB_WARN,"Failed to locate credential 0x%x\n",Status));
  1754. goto Cleanup;
  1755. }
  1756. }
  1757. }
  1758. #if DBG
  1759. D_DebugLog((DEB_TRACE_CTXT, "SpInitLsaModeContext: Initailizing context for %wZ\\%wZ\n",
  1760. &LogonSession->PrimaryCredentials.DomainName,
  1761. &LogonSession->PrimaryCredentials.UserName ));
  1762. #endif
  1763. KerbUnlockLogonSessions(LogonSession);
  1764. //////////////////////////////////////////////////////////////////////
  1765. //
  1766. // Process all the context requirements. We don't support all of them
  1767. // and some of them are mutually exclusive. In general, we don't fail
  1768. // if we're asked to do something we can't do, unless it seems mandatory,
  1769. // like allocating memory.
  1770. //
  1771. /////////////////////////////////////////////////////////////////////
  1772. //
  1773. // Figure out the context flags
  1774. //
  1775. if ((ContextRequirements & ISC_REQ_MUTUAL_AUTH) != 0)
  1776. {
  1777. D_DebugLog((DEB_TRACE_CTXT,"Client wants mutual auth.\n"));
  1778. ContextFlags |= ISC_RET_MUTUAL_AUTH;
  1779. }
  1780. if ((ContextRequirements & ISC_REQ_SEQUENCE_DETECT) != 0)
  1781. {
  1782. D_DebugLog((DEB_TRACE_CTXT, "Client wants sequence detect\n"));
  1783. ContextFlags |= ISC_RET_SEQUENCE_DETECT | ISC_RET_INTEGRITY;
  1784. }
  1785. if ((ContextRequirements & ISC_REQ_REPLAY_DETECT) != 0)
  1786. {
  1787. D_DebugLog((DEB_TRACE_CTXT, "Client wants replay detect\n"));
  1788. ContextFlags |= ISC_RET_REPLAY_DETECT | ISC_RET_INTEGRITY;
  1789. }
  1790. if ((ContextRequirements & ISC_REQ_INTEGRITY) != 0)
  1791. {
  1792. D_DebugLog((DEB_TRACE_CTXT, "Client wants integrity\n"));
  1793. ContextFlags |= ISC_RET_INTEGRITY;
  1794. }
  1795. if ((ContextRequirements & ISC_REQ_CONFIDENTIALITY) != 0)
  1796. {
  1797. D_DebugLog((DEB_TRACE_CTXT, "Client wants privacy\n"));
  1798. ContextFlags |= (ISC_RET_CONFIDENTIALITY |
  1799. ISC_RET_INTEGRITY |
  1800. ISC_RET_SEQUENCE_DETECT |
  1801. ISC_RET_REPLAY_DETECT );
  1802. }
  1803. if ((ContextRequirements & ISC_REQ_USE_DCE_STYLE) != 0)
  1804. {
  1805. D_DebugLog((DEB_TRACE_CTXT, "Client wants DCE style\n"));
  1806. ContextFlags |= ISC_RET_USED_DCE_STYLE;
  1807. }
  1808. if ((ContextRequirements & ISC_REQ_EXTENDED_ERROR) != 0)
  1809. {
  1810. D_DebugLog((DEB_TRACE_CTXT, "Client wants extended error\n"));
  1811. ContextFlags |= ISC_RET_EXTENDED_ERROR;
  1812. }
  1813. if ((ContextRequirements & ISC_REQ_DATAGRAM) != 0)
  1814. {
  1815. if ((ContextRequirements & ISC_REQ_CONNECTION) != 0)
  1816. {
  1817. D_DebugLog((DEB_ERROR,"Client wanted both data gram and connection. %ws, line %d\n", THIS_FILE, __LINE__));
  1818. Status = SEC_E_UNSUPPORTED_FUNCTION;
  1819. goto Cleanup;
  1820. }
  1821. D_DebugLog((DEB_TRACE_CTXT, "Client wants Datagram style\n"));
  1822. ContextFlags |= ISC_RET_DATAGRAM;
  1823. }
  1824. if ((ContextRequirements & ISC_REQ_USE_SESSION_KEY) != 0)
  1825. {
  1826. D_DebugLog((DEB_TRACE_U2U, "SpInitLsaModeContext Client wants sub-session key\n"));
  1827. //
  1828. // Can't do this with datagram because we need to be able to
  1829. // start sealing messages after the first call to Initialize.
  1830. //
  1831. // With a null session there is no real ticket so we don't ever
  1832. // need the server TGT either.
  1833. //
  1834. // Can't do DCE style because they don't have this.
  1835. //
  1836. if (!UseNullSession && (ContextRequirements & (ISC_REQ_DATAGRAM | ISC_REQ_USE_DCE_STYLE)) == 0)
  1837. {
  1838. //
  1839. // If we are in the first call, get a server TGT
  1840. //
  1841. if (ContextState == InvalidState)
  1842. {
  1843. GetServerTgt = TRUE;
  1844. }
  1845. ContextFlags |= ISC_RET_USE_SESSION_KEY;
  1846. }
  1847. else
  1848. {
  1849. D_DebugLog((DEB_WARN,"Client wanted both datagram and session key, dropping session key\n"));
  1850. }
  1851. }
  1852. if ((ContextRequirements & ISC_REQ_DELEGATE) != 0)
  1853. {
  1854. D_DebugLog((DEB_TRACE_CTXT, "Client wants Delegation\n"));
  1855. if ((ContextFlags & ISC_RET_MUTUAL_AUTH) == 0)
  1856. {
  1857. D_DebugLog((DEB_WARN,"Can't do delegate without mutual\n"));
  1858. }
  1859. else
  1860. {
  1861. ContextFlags |= ISC_RET_DELEGATE;
  1862. }
  1863. }
  1864. else if ((ContextRequirements & ISC_REQ_DELEGATE_IF_SAFE) != 0)
  1865. {
  1866. D_DebugLog((DEB_TRACE_CTXT, "Client wants Delegation, if safe\n"));
  1867. if ((ContextFlags & ISC_RET_MUTUAL_AUTH) == 0)
  1868. {
  1869. D_DebugLog((DEB_WARN,"Can't do delegate without mutual\n"));
  1870. }
  1871. else
  1872. {
  1873. ContextFlags |= ISC_RET_DELEGATE_IF_SAFE;
  1874. }
  1875. }
  1876. if ((ContextRequirements & ISC_REQ_CONNECTION) != 0)
  1877. {
  1878. D_DebugLog((DEB_TRACE_CTXT, "Client wants Connection style\n"));
  1879. ContextFlags |= ISC_RET_CONNECTION;
  1880. }
  1881. if ((ContextRequirements & ISC_REQ_IDENTIFY) != 0)
  1882. {
  1883. D_DebugLog((DEB_TRACE_CTXT, "Client wants Identify level\n"));
  1884. ContextFlags |= ISC_RET_IDENTIFY;
  1885. if (((ContextRequirements & ISC_REQ_DELEGATE) != 0) ||
  1886. ((ContextRequirements & ISC_REQ_DELEGATE_IF_SAFE) != 0))
  1887. {
  1888. D_DebugLog((DEB_WARN, "Client wants Delegation and Indentify, turning off delegation\n"));
  1889. ContextFlags &= ~ISC_RET_DELEGATE;
  1890. ContextFlags &= ~ISC_RET_DELEGATE_IF_SAFE;
  1891. }
  1892. }
  1893. //////////////////////////////////////////////////////////////////////
  1894. //
  1895. // Get the ticket necessary to process the request. At this point:
  1896. // - TicketCacheEntry should contain the ticket to re-use
  1897. // - ErrorMessage should contain the error message, if there was one
  1898. //
  1899. /////////////////////////////////////////////////////////////////////
  1900. //
  1901. // Get the outbound ticket. If the credential has attached supplied
  1902. // credentials, get an AS ticket instead.
  1903. //
  1904. if (GetServerTgt)
  1905. {
  1906. //
  1907. // Nothing to do
  1908. //
  1909. }
  1910. else if (!UseNullSession)
  1911. {
  1912. D_DebugLog((DEB_TRACE_CTXT,"SpInitLsaModeContext: Getting outbound ticket for %wZ (%wZ) or ",
  1913. TargetName, &LocalTargetName ));
  1914. D_KerbPrintKdcName(DEB_TRACE_CTXT, TargetInternalName );
  1915. //
  1916. // If we got a skew error and we already have a cached ticket, don't
  1917. // bother getting a new ticket.
  1918. //
  1919. KerbReadLockContexts();
  1920. if (ErrorMessage != NULL)
  1921. {
  1922. if (((KERBERR) ErrorMessage->error_code == KRB_AP_ERR_SKEW) &&
  1923. (Context->TicketCacheEntry != NULL))
  1924. {
  1925. KerbReferenceTicketCacheEntry(Context->TicketCacheEntry);
  1926. TicketCacheEntry = Context->TicketCacheEntry;
  1927. }
  1928. else
  1929. {
  1930. //
  1931. // use2user assumes ticketTicketCacheEntry to be non null at
  1932. // this point
  1933. //
  1934. DsysAssert((Context->TicketCacheEntry != NULL) || ((ContextAttribs & KERB_CONTEXT_USER_TO_USER) == 0));
  1935. }
  1936. }
  1937. KerbUnlockContexts();
  1938. //
  1939. // If we don't have a ticket in the context, go ahead and get
  1940. // a new ticket
  1941. //
  1942. if (TicketCacheEntry == NULL)
  1943. {
  1944. D_DebugLog((DEB_TRACE, "Getting service ticket\n"));
  1945. Status = KerbGetServiceTicket(
  1946. LogonSession,
  1947. Credential,
  1948. CredManCredentials,
  1949. TargetInternalName,
  1950. &TargetDomainName,
  1951. SpnCacheEntry,
  1952. ProcessFlags,
  1953. TicketOptions,
  1954. 0, // no enc type
  1955. ErrorMessage,
  1956. NULL, // no authorization data
  1957. TgtReply, // no tgt reply
  1958. &TicketCacheEntry,
  1959. NULL // don't return logon guid
  1960. );
  1961. if (Status == STATUS_USER2USER_REQUIRED)
  1962. {
  1963. D_DebugLog((DEB_TRACE_U2U, "SpInitLsaModeContext failed to get serviceticket: STATUS_USER2USER_REQUIRED\n"));
  1964. Status = STATUS_SUCCESS;
  1965. ContextFlags |= ISC_RET_USE_SESSION_KEY;
  1966. GetServerTgt = TRUE;
  1967. }
  1968. else if (!NT_SUCCESS(Status))
  1969. {
  1970. DebugLog((DEB_WARN,"Failed to get outbound ticket: 0x%x\n",Status));
  1971. goto Cleanup;
  1972. }
  1973. }
  1974. //
  1975. // fail user2user in data gram: not enough round trips to complete the protocol
  1976. //
  1977. if ((ContextFlags & ISC_RET_USE_SESSION_KEY) && (ContextFlags & ISC_RET_DATAGRAM))
  1978. {
  1979. DebugLog((DEB_ERROR, "SpInitLsaModeContext Client needed session key in datagram, dropping session key\n"));
  1980. ContextFlags |= ~ISC_RET_USE_SESSION_KEY;
  1981. Status = STATUS_LOGON_FAILURE;
  1982. goto Cleanup;
  1983. }
  1984. }
  1985. else
  1986. {
  1987. //
  1988. // Turn off all unsupported flags
  1989. //
  1990. ContextFlags &= ( ISC_RET_ALLOCATED_MEMORY |
  1991. ISC_RET_CONNECTION |
  1992. ISC_RET_DATAGRAM |
  1993. ISC_RET_NULL_SESSION );
  1994. }
  1995. //////////////////////////////////////////////////////////////////////
  1996. //
  1997. // Build the request - an AP request for standard Kerberos, or a TGT
  1998. // request.
  1999. //
  2000. /////////////////////////////////////////////////////////////////////
  2001. //
  2002. // For datagram requests, there is no output.
  2003. //
  2004. if ((ContextFlags & ISC_RET_DATAGRAM) == 0)
  2005. {
  2006. //
  2007. // This is the case where we are constructing a response.
  2008. //
  2009. if (OutputToken == NULL)
  2010. {
  2011. D_DebugLog((DEB_ERROR,"Trying to initialize a context with no output token! %ws, line %d\n", THIS_FILE, __LINE__));
  2012. Status = SEC_E_INVALID_TOKEN;
  2013. goto Cleanup;
  2014. }
  2015. if (UseNullSession)
  2016. {
  2017. Status = KerbBuildNullSessionApRequest(
  2018. &Request,
  2019. &RequestSize
  2020. );
  2021. }
  2022. else if (GetServerTgt)
  2023. {
  2024. D_DebugLog((DEB_TRACE,"Building TGT request for "));
  2025. KerbPrintKdcName(DEB_TRACE, TargetInternalName);
  2026. if (((ContextRequirements & ISC_REQ_MUTUAL_AUTH) != 0) &&
  2027. (!ARGUMENT_PRESENT(TargetName) || TargetName->Length == 0))
  2028. {
  2029. D_DebugLog((DEB_ERROR, "Client wanted mutual auth, but did not supply target name\n"));
  2030. Status = SEC_E_UNSUPPORTED_FUNCTION;
  2031. goto Cleanup;
  2032. }
  2033. Status = KerbBuildTgtRequest(
  2034. TargetInternalName,
  2035. &TargetDomainName,
  2036. &ContextAttribs,
  2037. &Request,
  2038. &RequestSize
  2039. );
  2040. if (!NT_SUCCESS(Status))
  2041. {
  2042. goto Cleanup;
  2043. }
  2044. }
  2045. else
  2046. {
  2047. D_DebugLog((DEB_TRACE_CTXT2,"Building AP request for connection oriented context\n"));
  2048. Status = KerbBuildApRequest(
  2049. LogonSession,
  2050. Credential,
  2051. CredManCredentials,
  2052. TicketCacheEntry,
  2053. ErrorMessage,
  2054. ContextAttribs,
  2055. &ContextFlags,
  2056. &Request,
  2057. &RequestSize,
  2058. &Nonce,
  2059. &SubSessionKey,
  2060. pChannelBindings
  2061. );
  2062. //
  2063. // Set the receive nonce to be the nonce, as the code below
  2064. // expects it to be valid.
  2065. //
  2066. ReceiveNonce = Nonce;
  2067. }
  2068. if (!NT_SUCCESS(Status))
  2069. {
  2070. D_DebugLog((DEB_ERROR,"Failed to build AP request: 0x%x\n. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2071. goto Cleanup;
  2072. }
  2073. if (OutputToken == NULL)
  2074. {
  2075. Status = SEC_E_INVALID_TOKEN;
  2076. goto Cleanup;
  2077. }
  2078. //
  2079. // Return the AP request in the output buffer.
  2080. //
  2081. if ((ContextRequirements & ISC_REQ_ALLOCATE_MEMORY) == 0)
  2082. {
  2083. if (OutputToken->cbBuffer < RequestSize)
  2084. {
  2085. ULONG ErrorData[3];
  2086. ErrorData[0] = RequestSize;
  2087. ErrorData[1] = OutputToken->cbBuffer;
  2088. ErrorData[2] = ClientProcess;
  2089. D_DebugLog((DEB_ERROR,"Output token is too small - sent in %d, needed %d. %ws, line %d\n",
  2090. OutputToken->cbBuffer,RequestSize, THIS_FILE, __LINE__ ));
  2091. OutputToken->cbBuffer = RequestSize;
  2092. Status = STATUS_BUFFER_TOO_SMALL;
  2093. KerbReportNtstatus(
  2094. KERBEVT_INSUFFICIENT_TOKEN_SIZE,
  2095. Status,
  2096. NULL,
  2097. 0,
  2098. ErrorData,
  2099. 3
  2100. );
  2101. goto Cleanup;
  2102. }
  2103. RtlCopyMemory(
  2104. OutputToken->pvBuffer,
  2105. Request,
  2106. RequestSize
  2107. );
  2108. }
  2109. else
  2110. {
  2111. OutputToken->pvBuffer = Request;
  2112. if (OutputToken->pvBuffer == NULL)
  2113. {
  2114. Status = STATUS_INSUFFICIENT_RESOURCES;
  2115. goto Cleanup;
  2116. }
  2117. *ContextAttributes |= ISC_RET_ALLOCATED_MEMORY;
  2118. //
  2119. // Set this to NULL so it won't be freed by us on cleanup.
  2120. //
  2121. Request = NULL;
  2122. }
  2123. OutputToken->cbBuffer = RequestSize;
  2124. }
  2125. else
  2126. {
  2127. //
  2128. // All we do here is allocate a nonce for use in the context.
  2129. //
  2130. Nonce = KerbAllocateNonce();
  2131. if (OutputToken != NULL)
  2132. {
  2133. OutputToken->cbBuffer = 0;
  2134. }
  2135. }
  2136. //////////////////////////////////////////////////////////////////////
  2137. //
  2138. // If we haven't yet created a context, created one now. If we have,
  2139. // update the context with the latest status.
  2140. //
  2141. /////////////////////////////////////////////////////////////////////
  2142. //
  2143. // Allocate a client context, if we don't already have one
  2144. //
  2145. if (Context == NULL)
  2146. {
  2147. Status = KerbCreateClientContext(
  2148. LogonSession,
  2149. Credential,
  2150. CredManCredentials,
  2151. TicketCacheEntry,
  2152. TargetName,
  2153. Nonce,
  2154. ContextFlags,
  2155. ContextAttribs,
  2156. &SubSessionKey,
  2157. &Context,
  2158. &ContextLifetime
  2159. );
  2160. //CredManCredentials = NULL;
  2161. }
  2162. else
  2163. {
  2164. Status = KerbUpdateClientContext(
  2165. Context,
  2166. TicketCacheEntry,
  2167. Nonce,
  2168. ReceiveNonce,
  2169. ContextFlags,
  2170. ContextAttribs,
  2171. &SubSessionKey,
  2172. &ContextLifetime
  2173. );
  2174. }
  2175. if (!NT_SUCCESS(Status))
  2176. {
  2177. D_DebugLog((DEB_ERROR,"Failed to create client context: 0x%x. %ws, line %d\n",
  2178. Status, THIS_FILE, __LINE__));
  2179. goto Cleanup;
  2180. }
  2181. //
  2182. // Keep track of network service session keys to detect whether network
  2183. // logon session is for local network service
  2184. //
  2185. if (RtlEqualLuid(&LogonId, &NetworkServiceLuid))
  2186. {
  2187. FILETIME CurTime = {0};
  2188. GetSystemTimeAsFileTime(&CurTime);
  2189. //
  2190. // use 2 times KerbGlobalSkewTime as ticket life time
  2191. //
  2192. KerbGetTime(*((TimeStamp*) &CurTime)) += 2 * KerbGetTime(KerbGlobalSkewTime);
  2193. Status = KerbCreateSKeyEntry(&SubSessionKey, &CurTime);
  2194. if (!NT_SUCCESS(Status))
  2195. {
  2196. D_DebugLog((DEB_ERROR, "Failed to create session key entry: 0x%x. %ws, line %d\n",
  2197. Status, THIS_FILE, __LINE__));
  2198. goto Cleanup;
  2199. }
  2200. }
  2201. //
  2202. // Hold on to the ticket for later use
  2203. //
  2204. KerbWriteLockContexts();
  2205. if ((Context->TicketCacheEntry == NULL) && (TicketCacheEntry != NULL))
  2206. {
  2207. KerbReferenceTicketCacheEntry(TicketCacheEntry);
  2208. Context->TicketCacheEntry = TicketCacheEntry;
  2209. }
  2210. ClientProcess = Context->ClientProcess;
  2211. KerbUnlockContexts();
  2212. //
  2213. // update the context with the marshalled target info.
  2214. //
  2215. if( NT_SUCCESS(Status) && pbMarshalledTargetInfo )
  2216. {
  2217. if( Context->pbMarshalledTargetInfo == NULL )
  2218. {
  2219. Context->pbMarshalledTargetInfo = pbMarshalledTargetInfo;
  2220. Context->cbMarshalledTargetInfo = cbMarshalledTargetInfo;
  2221. pbMarshalledTargetInfo = NULL;
  2222. }
  2223. }
  2224. //
  2225. // Return the correct flags
  2226. //
  2227. *NewContextHandle = KerbGetContextHandle(Context);
  2228. *ContextAttributes |= ContextFlags;
  2229. KerbUtcTimeToLocalTime(
  2230. ExpirationTime,
  2231. &ContextLifetime
  2232. );
  2233. //
  2234. // If mutual authentication was requested, ask for a continuation
  2235. //
  2236. if (((ContextFlags & ( ISC_RET_USED_DCE_STYLE |
  2237. ISC_RET_DATAGRAM |
  2238. ISC_RET_MUTUAL_AUTH )) != 0) ||
  2239. GetServerTgt )
  2240. {
  2241. Status = SEC_I_CONTINUE_NEEDED;
  2242. }
  2243. Cleanup:
  2244. // Adjust for the new meaning of delegate/delegate-if-safe if they got munged somehow.
  2245. if (ClientAskedForDelegateIfSafe && (*ContextAttributes & ISC_RET_DELEGATE))
  2246. {
  2247. (*ContextAttributes) &= ~ISC_RET_DELEGATE;
  2248. (*ContextAttributes) |= ISC_RET_DELEGATE_IF_SAFE;
  2249. }
  2250. else if ((ClientAskedForDelegate) && (*ContextAttributes & ISC_RET_DELEGATE_IF_SAFE))
  2251. {
  2252. (*ContextAttributes) &= ~ISC_RET_DELEGATE_IF_SAFE;
  2253. (*ContextAttributes) |= ISC_RET_DELEGATE;
  2254. }
  2255. if ( Status == STATUS_WRONG_PASSWORD )
  2256. {
  2257. //
  2258. // don't leak WRONG_PASSWORD to the caller.
  2259. //
  2260. Status = STATUS_LOGON_FAILURE;
  2261. }
  2262. if ( KerbEventTraceFlag ) // Event Trace: KerbInitSecurityContextEnd {Status, CredSource, DomainName, UserName, Target, (ExtErr), (Klininfo)}
  2263. {
  2264. PCWSTR TraceStrings[] =
  2265. {
  2266. L"CredMan",
  2267. L"Supplied",
  2268. L"Context",
  2269. L"LogonSession",
  2270. L"None"
  2271. };
  2272. enum { TSTR_CREDMAN = 0, TSTR_SUPPLIED, TSTR_CONTEXT, TSTR_LOGONSESSION, TSTR_NONE };
  2273. UNICODE_STRING UNICODE_NONE = { 4*sizeof(WCHAR), 4*sizeof(WCHAR), L"NONE" };
  2274. UNICODE_STRING CredSource;
  2275. PUNICODE_STRING trace_DomainName, trace_UserName, trace_target;
  2276. trace_target = (Context != NULL) ? &Context->ServerPrincipalName : &UNICODE_NONE;
  2277. if( Context != NULL && Context->CredManCredentials != NULL )
  2278. {
  2279. RtlInitUnicodeString( &CredSource, TraceStrings[TSTR_CREDMAN] );
  2280. trace_DomainName = &Context->CredManCredentials->SuppliedCredentials->DomainName;
  2281. trace_UserName = &Context->CredManCredentials->SuppliedCredentials->UserName;
  2282. }
  2283. else if( Credential != NULL && Credential->SuppliedCredentials != NULL )
  2284. {
  2285. RtlInitUnicodeString( &CredSource, TraceStrings[TSTR_SUPPLIED] );
  2286. trace_DomainName = &Credential->SuppliedCredentials->DomainName;
  2287. trace_UserName = &Credential->SuppliedCredentials->UserName;
  2288. }
  2289. else if( Context != NULL )
  2290. {
  2291. RtlInitUnicodeString( &CredSource, TraceStrings[TSTR_CONTEXT] );
  2292. trace_DomainName = &Context->ClientRealm;
  2293. trace_UserName = &Context->ClientName;
  2294. }
  2295. else if( LogonSession != NULL )
  2296. {
  2297. RtlInitUnicodeString( &CredSource, TraceStrings[TSTR_LOGONSESSION] );
  2298. trace_DomainName = &LogonSession->PrimaryCredentials.DomainName;
  2299. trace_UserName = &LogonSession->PrimaryCredentials.UserName;
  2300. }
  2301. else
  2302. {
  2303. RtlInitUnicodeString( &CredSource, TraceStrings[TSTR_NONE] );
  2304. trace_DomainName = &UNICODE_NONE;
  2305. trace_UserName = &UNICODE_NONE;
  2306. }
  2307. INSERT_ULONG_INTO_MOF( Status, InitSCTraceInfo.MofData, 0 );
  2308. INSERT_UNICODE_STRING_INTO_MOF( CredSource, InitSCTraceInfo.MofData, 1 );
  2309. INSERT_UNICODE_STRING_INTO_MOF( *trace_DomainName, InitSCTraceInfo.MofData, 3 );
  2310. INSERT_UNICODE_STRING_INTO_MOF( *trace_UserName, InitSCTraceInfo.MofData, 5 );
  2311. INSERT_UNICODE_STRING_INTO_MOF( *trace_target, InitSCTraceInfo.MofData, 7 );
  2312. InitSCTraceInfo.EventTrace.Size = sizeof(EVENT_TRACE_HEADER) + 9*sizeof(MOF_FIELD);
  2313. //Check for extended error
  2314. if( pExtendedError != NULL )
  2315. {
  2316. INSERT_ULONG_INTO_MOF( pExtendedError->status, InitSCTraceInfo.MofData, 9 );
  2317. INSERT_ULONG_INTO_MOF( pExtendedError->klininfo, InitSCTraceInfo.MofData, 10 );
  2318. InitSCTraceInfo.EventTrace.Size += 2*sizeof(MOF_FIELD);
  2319. }
  2320. // Set trace parameters
  2321. InitSCTraceInfo.EventTrace.Guid = KerbInitSCGuid;
  2322. InitSCTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_END;
  2323. InitSCTraceInfo.EventTrace.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
  2324. TraceEvent(
  2325. KerbTraceLoggerHandle,
  2326. (PEVENT_TRACE_HEADER)&InitSCTraceInfo
  2327. );
  2328. }
  2329. //
  2330. // If we allocated a context, unlink it now
  2331. //
  2332. if (Context != NULL)
  2333. {
  2334. if (!NT_SUCCESS(Status))
  2335. {
  2336. //
  2337. // Only unlink the context if we just created it
  2338. //
  2339. if (ContextHandle == 0)
  2340. {
  2341. KerbReferenceContextByPointer(
  2342. Context,
  2343. TRUE
  2344. );
  2345. KerbDereferenceContext(Context);
  2346. }
  2347. else
  2348. {
  2349. //
  2350. // Set the context to an invalid state.
  2351. //
  2352. KerbWriteLockContexts();
  2353. Context->ContextState = InvalidState;
  2354. KerbUnlockContexts();
  2355. }
  2356. }
  2357. else
  2358. {
  2359. KerbWriteLockContexts();
  2360. if (Status == STATUS_SUCCESS)
  2361. {
  2362. Context->ContextState = AuthenticatedState;
  2363. }
  2364. else if (!GetServerTgt)
  2365. {
  2366. Context->ContextState = ApRequestSentState;
  2367. }
  2368. else
  2369. {
  2370. Context->ContextState = TgtRequestSentState;
  2371. //
  2372. // mark the context as user2user
  2373. //
  2374. Context->ContextAttributes |= KERB_CONTEXT_USER_TO_USER;
  2375. DebugLog((DEB_TRACE_U2U, "SpInitLsaModeContext (TGT in TGT reply) USER2USER-OUTBOUND set\n"));
  2376. }
  2377. KerbUnlockContexts();
  2378. }
  2379. KerbDereferenceContext(Context);
  2380. }
  2381. if ((Status == STATUS_SUCCESS) ||
  2382. ((Status == SEC_I_CONTINUE_NEEDED) && ((ContextFlags & ISC_RET_DATAGRAM) != 0)))
  2383. {
  2384. NTSTATUS TempStatus;
  2385. //
  2386. // On real success we map the context to the callers address
  2387. // space.
  2388. //
  2389. TempStatus = KerbMapContext(
  2390. Context,
  2391. MappedContext,
  2392. ContextData
  2393. );
  2394. D_DebugLog((DEB_TRACE, "SpInitLsaModeContext called KerbMapContext ContextAttributes %#x, %#x\n", Context->ContextAttributes, TempStatus));
  2395. if (!NT_SUCCESS(TempStatus))
  2396. {
  2397. Status = TempStatus;
  2398. }
  2399. //
  2400. // Update the skew time with a success
  2401. //
  2402. KerbUpdateSkewTime(FALSE);
  2403. }
  2404. if (NULL != CredManCredentials)
  2405. {
  2406. KerbDereferenceCredmanCred(
  2407. CredManCredentials,
  2408. &LogonSession->CredmanCredentials
  2409. );
  2410. }
  2411. if( pbMarshalledTargetInfo )
  2412. {
  2413. LocalFree( pbMarshalledTargetInfo );
  2414. }
  2415. if (TgtReply != NULL)
  2416. {
  2417. KerbFreeData(KERB_TGT_REPLY_PDU, TgtReply);
  2418. }
  2419. if (LogonSession != NULL)
  2420. {
  2421. KerbDereferenceLogonSession( LogonSession );
  2422. }
  2423. if (Credential != NULL)
  2424. {
  2425. KerbDereferenceCredential( Credential );
  2426. }
  2427. if (TicketCacheEntry != NULL)
  2428. {
  2429. KerbDereferenceTicketCacheEntry( TicketCacheEntry );
  2430. }
  2431. if ( SpnCacheEntry != NULL )
  2432. {
  2433. KerbDereferenceSpnCacheEntry( SpnCacheEntry);
  2434. }
  2435. KerbFreeKerbError( ErrorMessage );
  2436. if (NULL != pExtendedError)
  2437. {
  2438. KerbFree(pExtendedError);
  2439. }
  2440. if (ErrorData != NULL)
  2441. {
  2442. MIDL_user_free(ErrorData);
  2443. }
  2444. if (Request != NULL)
  2445. {
  2446. KerbFree(Request);
  2447. }
  2448. if (Reply != NULL)
  2449. {
  2450. KerbFree(Reply);
  2451. }
  2452. KerbFreeKey(&SubSessionKey);
  2453. KerbFreeString( &TargetDomainName );
  2454. KerbFreeKdcName( &TargetInternalName );
  2455. D_DebugLog((DEB_TRACE_LEAKS,"SpInitLsaModeContext returned 0x%x, Context 0x%x, Pid 0x%x\n",KerbMapKerbNtStatusToNtStatus(Status), *NewContextHandle, ClientProcess));
  2456. D_DebugLog((DEB_TRACE_API, "SpInitLsaModeContext returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  2457. return(KerbMapKerbNtStatusToNtStatus(Status));
  2458. }
  2459. NTSTATUS NTAPI
  2460. SpApplyControlToken(
  2461. IN LSA_SEC_HANDLE ContextHandle,
  2462. IN PSecBufferDesc ControlToken
  2463. )
  2464. {
  2465. NTSTATUS Status = STATUS_NOT_SUPPORTED;
  2466. D_DebugLog((DEB_TRACE_API,"SpApplyControlToken Called\n"));
  2467. D_DebugLog((DEB_TRACE_API,"SpApplyControlToken returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  2468. return(KerbMapKerbNtStatusToNtStatus(Status));
  2469. }
  2470. #ifndef WIN32_CHICAGO //we don't do server side stuff
  2471. //+-------------------------------------------------------------------------
  2472. //
  2473. // Function: SpAcceptLsaModeContext
  2474. //
  2475. // Synopsis: Kerberos support routine for AcceptSecurityContext call.
  2476. // This routine accepts an AP request message from a client
  2477. // and verifies that it is a valid ticket. If mutual
  2478. // authentication is desired an AP reply is generated to
  2479. // send back to the client.
  2480. //
  2481. // Effects:
  2482. //
  2483. // Arguments:
  2484. //
  2485. // Requires:
  2486. //
  2487. // Returns:
  2488. //
  2489. // Notes:
  2490. //
  2491. //
  2492. //--------------------------------------------------------------------------
  2493. NTSTATUS NTAPI
  2494. SpAcceptLsaModeContext(
  2495. IN OPTIONAL LSA_SEC_HANDLE CredentialHandle,
  2496. IN OPTIONAL LSA_SEC_HANDLE ContextHandle,
  2497. IN PSecBufferDesc InputBuffers,
  2498. IN ULONG ContextRequirements,
  2499. IN ULONG TargetDataRep,
  2500. OUT PLSA_SEC_HANDLE NewContextHandle,
  2501. OUT PSecBufferDesc OutputBuffers,
  2502. OUT PULONG ContextAttributes,
  2503. OUT PTimeStamp ExpirationTime,
  2504. OUT PBOOLEAN MappedContext,
  2505. OUT PSecBuffer ContextData
  2506. )
  2507. {
  2508. PKERB_LOGON_SESSION LogonSession = NULL;
  2509. PKERB_CREDENTIAL Credential = NULL;
  2510. NTSTATUS Status = STATUS_SUCCESS;
  2511. NTSTATUS LastStatus = STATUS_SUCCESS;
  2512. PKERB_AP_REQUEST Request = NULL;
  2513. PUCHAR Reply = NULL;
  2514. PSecBuffer InputToken = NULL;
  2515. PSecBuffer OutputToken = NULL;
  2516. ULONG Index;
  2517. ULONG ReplySize;
  2518. LUID LogonId;
  2519. PKERB_ENCRYPTED_TICKET InternalTicket = NULL;
  2520. PKERB_AUTHENTICATOR InternalAuthenticator = NULL;
  2521. KERB_ENCRYPTION_KEY SessionKey;
  2522. KERB_ENCRYPTION_KEY TicketKey;
  2523. KERB_ENCRYPTION_KEY ServerKey;
  2524. PKERB_CONTEXT Context = NULL;
  2525. TimeStamp ContextLifetime;
  2526. HANDLE TokenHandle = 0;
  2527. ULONG ContextFlags = 0;
  2528. ULONG ContextAttribs = KERB_CONTEXT_INBOUND;
  2529. ULONG Nonce = 0;
  2530. ULONG ReceiveNonce = 0;
  2531. BOOLEAN UseSuppliedCreds = FALSE;
  2532. ULONG_PTR LocalCredentialHandle = 0;
  2533. PSID UserSid = NULL;
  2534. KERBERR KerbErr = KDC_ERR_NONE;
  2535. KERB_CONTEXT_STATE ContextState = InvalidState;
  2536. UNICODE_STRING ServiceDomain = {0};
  2537. UNICODE_STRING ClientName = {0};
  2538. UNICODE_STRING ClientDomain = {0};
  2539. BOOLEAN IsTgtRequest = FALSE;
  2540. ULONG ClientProcess = 0;
  2541. PSEC_CHANNEL_BINDINGS pChannelBindings = NULL;
  2542. KERB_ACCEPTSC_INFO AcceptSCTraceInfo;
  2543. D_DebugLog((DEB_TRACE_API,"SpAcceptLsaModeContext 0x%x called\n",ContextHandle));
  2544. if( KerbEventTraceFlag ) // Event Trace: KerbAcceptSecurityContextStart {No Data}
  2545. {
  2546. AcceptSCTraceInfo.EventTrace.Guid = KerbAcceptSCGuid;
  2547. AcceptSCTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_START;
  2548. AcceptSCTraceInfo.EventTrace.Flags = WNODE_FLAG_TRACED_GUID;
  2549. AcceptSCTraceInfo.EventTrace.Size = sizeof (EVENT_TRACE_HEADER);
  2550. TraceEvent(
  2551. KerbTraceLoggerHandle,
  2552. (PEVENT_TRACE_HEADER)&AcceptSCTraceInfo
  2553. );
  2554. }
  2555. //
  2556. // Initialize the outputs.
  2557. //
  2558. *ContextAttributes = 0;
  2559. *NewContextHandle = 0;
  2560. *ExpirationTime = KerbGlobalHasNeverTime;
  2561. *MappedContext = FALSE;
  2562. ContextData->pvBuffer = NULL;
  2563. ContextData->cbBuffer = 0;
  2564. RtlZeroMemory(
  2565. &SessionKey,
  2566. sizeof(KERB_ENCRYPTION_KEY)
  2567. );
  2568. TicketKey = SessionKey;
  2569. ServerKey = TicketKey;
  2570. if (!KerbGlobalInitialized)
  2571. {
  2572. Status = STATUS_INVALID_SERVER_STATE;
  2573. goto Cleanup;
  2574. }
  2575. //
  2576. // First locate the Input token.
  2577. //
  2578. for (Index = 0; Index < InputBuffers->cBuffers ; Index++ )
  2579. {
  2580. if (BUFFERTYPE(InputBuffers->pBuffers[Index]) == SECBUFFER_TOKEN)
  2581. {
  2582. InputToken = &InputBuffers->pBuffers[Index];
  2583. Status = LsaFunctions->MapBuffer(InputToken,InputToken);
  2584. break;
  2585. }
  2586. }
  2587. if (!NT_SUCCESS(Status))
  2588. {
  2589. D_DebugLog((DEB_ERROR,"Failed to map Input token: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2590. goto Cleanup;
  2591. }
  2592. //
  2593. // Check to see if we were passed channel bindings
  2594. //
  2595. for( Index = 0; Index < InputBuffers->cBuffers; Index++ )
  2596. {
  2597. if( BUFFERTYPE(InputBuffers->pBuffers[Index]) == SECBUFFER_CHANNEL_BINDINGS )
  2598. {
  2599. PVOID temp = NULL;
  2600. Status = LsaFunctions->MapBuffer(
  2601. &InputBuffers->pBuffers[Index],
  2602. &InputBuffers->pBuffers[Index]
  2603. );
  2604. if( !NT_SUCCESS(Status) )
  2605. {
  2606. goto Cleanup;
  2607. }
  2608. pChannelBindings = (PSEC_CHANNEL_BINDINGS) InputBuffers->pBuffers[Index].pvBuffer;
  2609. Status = KerbValidateChannelBindings(pChannelBindings,
  2610. InputBuffers->pBuffers[Index].cbBuffer);
  2611. if (!NT_SUCCESS(Status))
  2612. {
  2613. pChannelBindings = NULL;
  2614. goto Cleanup;
  2615. }
  2616. break;
  2617. }
  2618. }
  2619. //
  2620. // Locate the output token
  2621. //
  2622. for (Index = 0; Index < OutputBuffers->cBuffers ; Index++ )
  2623. {
  2624. if (BUFFERTYPE(OutputBuffers->pBuffers[Index]) == SECBUFFER_TOKEN)
  2625. {
  2626. OutputToken = &OutputBuffers->pBuffers[Index];
  2627. Status = LsaFunctions->MapBuffer(OutputToken,OutputToken);
  2628. break;
  2629. }
  2630. }
  2631. if (!NT_SUCCESS(Status))
  2632. {
  2633. D_DebugLog((DEB_ERROR,"Failed to map output token: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2634. goto Cleanup;
  2635. }
  2636. //
  2637. // If the context handle is no NULL we are finalizing a context
  2638. //
  2639. if (ContextHandle != 0)
  2640. {
  2641. if (InputToken == NULL)
  2642. {
  2643. D_DebugLog((DEB_ERROR,"Trying to complete a context with no input token! %ws, line %d\n", THIS_FILE, __LINE__));
  2644. Status = SEC_E_INVALID_TOKEN;
  2645. goto Cleanup;
  2646. }
  2647. //
  2648. // First reference the context.
  2649. //
  2650. Status = KerbReferenceContext(
  2651. ContextHandle,
  2652. FALSE, // don't unlink
  2653. &Context
  2654. );
  2655. if (Context == NULL)
  2656. {
  2657. D_DebugLog((DEB_ERROR,"Failed to reference context 0x%x. %ws, line %d\n",ContextHandle, THIS_FILE, __LINE__));
  2658. goto Cleanup;
  2659. }
  2660. //
  2661. // Check the mode of the context to make sure we can finalize it.
  2662. //
  2663. KerbReadLockContexts();
  2664. ContextState = Context->ContextState;
  2665. if (((ContextState != ApReplySentState) &&
  2666. (ContextState != TgtReplySentState) &&
  2667. (ContextState != ErrorMessageSentState)) ||
  2668. ((Context->ContextAttributes & KERB_CONTEXT_INBOUND) == 0))
  2669. {
  2670. D_DebugLog((DEB_ERROR,"Invalid context state: %d. %ws, line %d\n",
  2671. Context->ContextState, THIS_FILE, __LINE__));
  2672. Status = STATUS_INVALID_HANDLE;
  2673. KerbUnlockContexts();
  2674. goto Cleanup;
  2675. }
  2676. if ((Context->ContextAttributes & KERB_CONTEXT_USED_SUPPLIED_CREDS) != 0)
  2677. {
  2678. UseSuppliedCreds = TRUE;
  2679. }
  2680. ContextFlags = Context->ContextFlags;
  2681. LogonId = Context->LogonId;
  2682. LocalCredentialHandle = Context->CredentialHandle;
  2683. ClientProcess = Context->ClientProcess;
  2684. KerbUnlockContexts();
  2685. }
  2686. if (CredentialHandle != 0)
  2687. {
  2688. if ((LocalCredentialHandle != 0) && (CredentialHandle != LocalCredentialHandle))
  2689. {
  2690. D_DebugLog((DEB_ERROR,"Different cred handle passsed to subsequent call to AcceptSecurityContext: 0x%x instead of 0x%x. %ws, line %d\n",
  2691. CredentialHandle, LocalCredentialHandle, THIS_FILE, __LINE__ ));
  2692. Status = STATUS_WRONG_CREDENTIAL_HANDLE;
  2693. goto Cleanup;
  2694. }
  2695. }
  2696. else
  2697. {
  2698. CredentialHandle = LocalCredentialHandle;
  2699. }
  2700. //
  2701. // If we are finalizing a context, do that here
  2702. //
  2703. if (ContextState == ApReplySentState)
  2704. {
  2705. //
  2706. // If we are doing datgram, then the finalize is actually an AP request
  2707. //
  2708. if ((ContextFlags & ISC_RET_DATAGRAM) != 0)
  2709. {
  2710. //
  2711. // Get the logon session
  2712. //
  2713. LogonSession = KerbReferenceLogonSession( &LogonId, FALSE );
  2714. if (LogonSession == NULL)
  2715. {
  2716. Status = STATUS_NO_SUCH_LOGON_SESSION;
  2717. goto Cleanup;
  2718. }
  2719. //
  2720. // If we are using supplied creds, get the credentials. Copy
  2721. // out the domain name so we can use it to verify the PAC.
  2722. //
  2723. Status = KerbReferenceCredential(
  2724. LocalCredentialHandle,
  2725. KERB_CRED_INBOUND,
  2726. FALSE, // don't dereference
  2727. &Credential
  2728. );
  2729. if (!NT_SUCCESS(Status))
  2730. {
  2731. goto Cleanup;
  2732. }
  2733. if (UseSuppliedCreds)
  2734. {
  2735. KerbReadLockLogonSessions(LogonSession);
  2736. Status = KerbDuplicateString(
  2737. &ServiceDomain,
  2738. &Credential->SuppliedCredentials->DomainName
  2739. );
  2740. KerbUnlockLogonSessions(LogonSession);
  2741. }
  2742. else
  2743. {
  2744. KerbReadLockLogonSessions(LogonSession);
  2745. Status = KerbDuplicateString(
  2746. &ServiceDomain,
  2747. &LogonSession->PrimaryCredentials.DomainName
  2748. );
  2749. KerbUnlockLogonSessions(LogonSession);
  2750. }
  2751. if (!NT_SUCCESS(Status))
  2752. {
  2753. goto Cleanup;
  2754. }
  2755. //
  2756. // Verify the AP request
  2757. //
  2758. Status = KerbVerifyApRequest(
  2759. Context,
  2760. (PUCHAR) InputToken->pvBuffer,
  2761. InputToken->cbBuffer,
  2762. LogonSession,
  2763. Credential,
  2764. UseSuppliedCreds,
  2765. ((ContextRequirements & ASC_REQ_ALLOW_CONTEXT_REPLAY) == 0),
  2766. &Request,
  2767. &InternalTicket,
  2768. &InternalAuthenticator,
  2769. &SessionKey,
  2770. &TicketKey,
  2771. &ServerKey,
  2772. &ContextFlags,
  2773. &ContextAttribs,
  2774. &KerbErr,
  2775. pChannelBindings
  2776. );
  2777. //
  2778. // We don't allow user-to-user recovery with datagram
  2779. //
  2780. if ((Status == STATUS_REPARSE_OBJECT) // this is a TGT request
  2781. || ((Status == SEC_E_NO_CREDENTIALS) && (KerbErr == KRB_AP_ERR_USER_TO_USER_REQUIRED)))
  2782. {
  2783. DebugLog((DEB_ERROR, "Won't allow user2user with Datagram. %ws, line %d\n", THIS_FILE, __LINE__));
  2784. Status = SEC_E_INVALID_TOKEN;
  2785. KerbErr = KRB_AP_ERR_MSG_TYPE;
  2786. goto ErrorReturn;
  2787. }
  2788. if (!NT_SUCCESS(Status))
  2789. {
  2790. DebugLog((DEB_ERROR,"Failed to verify AP request: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2791. //
  2792. // Let the skew tracker know about the failure
  2793. //
  2794. if (KerbErr == KRB_AP_ERR_SKEW)
  2795. {
  2796. KerbUpdateSkewTime(TRUE);
  2797. }
  2798. //
  2799. // Go to ErrorReturn so we can return an error message
  2800. //
  2801. goto ErrorReturn;
  2802. }
  2803. //
  2804. // Turn on the flag if it was called for
  2805. //
  2806. if ((ContextRequirements & ASC_REQ_ALLOW_CONTEXT_REPLAY) != 0)
  2807. {
  2808. ContextFlags |= ASC_RET_ALLOW_CONTEXT_REPLAY;
  2809. }
  2810. //
  2811. // Record the success
  2812. //
  2813. KerbUpdateSkewTime(FALSE);
  2814. //
  2815. // Check if the caller wants to allow null sessions
  2816. //
  2817. if (((ContextFlags & ISC_RET_NULL_SESSION) != 0) &&
  2818. ((ContextRequirements & ASC_REQ_ALLOW_NULL_SESSION) == 0))
  2819. {
  2820. D_DebugLog((DEB_ERROR,"Received null session but not allowed. %ws, line %d\n", THIS_FILE, __LINE__));
  2821. Status = STATUS_LOGON_FAILURE;
  2822. goto Cleanup;
  2823. }
  2824. //
  2825. // Save away the ReceiveNonce if it was provided
  2826. //
  2827. if ((InternalAuthenticator!= NULL) &&
  2828. ((InternalAuthenticator->bit_mask & KERB_AUTHENTICATOR_sequence_number_present) != 0))
  2829. {
  2830. //
  2831. // If the number is unsigned, convert it as unsigned. Otherwise
  2832. // convert as signed.
  2833. //
  2834. if (ASN1intxisuint32(&InternalAuthenticator->KERB_AUTHENTICATOR_sequence_number))
  2835. {
  2836. ReceiveNonce = ASN1intx2uint32(&InternalAuthenticator->KERB_AUTHENTICATOR_sequence_number);
  2837. }
  2838. else
  2839. {
  2840. ReceiveNonce = (ULONG) ASN1intx2int32(&InternalAuthenticator->KERB_AUTHENTICATOR_sequence_number);
  2841. }
  2842. }
  2843. else
  2844. {
  2845. ReceiveNonce = 0;
  2846. }
  2847. //
  2848. // Authentication succeeded, so build a token
  2849. //
  2850. Status = KerbCreateTokenFromTicket(
  2851. InternalTicket,
  2852. InternalAuthenticator,
  2853. ContextFlags,
  2854. &ServerKey,
  2855. &ServiceDomain,
  2856. &SessionKey,
  2857. &LogonId,
  2858. &UserSid,
  2859. &TokenHandle,
  2860. &ClientName,
  2861. &ClientDomain
  2862. );
  2863. if (!NT_SUCCESS(Status))
  2864. {
  2865. DebugLog((DEB_ERROR,"Failed to create token from ticket: 0x%x. %ws, line %d\n",
  2866. Status, THIS_FILE, __LINE__));
  2867. goto Cleanup;
  2868. }
  2869. Status = KerbUpdateServerContext(
  2870. Context,
  2871. InternalTicket,
  2872. Request,
  2873. &SessionKey,
  2874. &LogonId,
  2875. &UserSid,
  2876. ContextFlags,
  2877. ContextAttribs,
  2878. Nonce,
  2879. ReceiveNonce,
  2880. &TokenHandle,
  2881. &ClientName,
  2882. &ClientDomain,
  2883. &ContextLifetime
  2884. );
  2885. if (!NT_SUCCESS(Status))
  2886. {
  2887. DebugLog((DEB_ERROR,"Failed to create server context: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2888. goto Cleanup;
  2889. }
  2890. }
  2891. else
  2892. {
  2893. //
  2894. // Now unpack the AP reply
  2895. //
  2896. Status = KerbVerifyApReply(
  2897. Context,
  2898. (PUCHAR) InputToken->pvBuffer,
  2899. InputToken->cbBuffer,
  2900. &Nonce
  2901. );
  2902. if (!NT_SUCCESS(Status))
  2903. {
  2904. DebugLog((DEB_ERROR,"Failed to verify AP reply: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2905. goto Cleanup;
  2906. }
  2907. //
  2908. // We're done - we finalized.
  2909. //
  2910. Status = STATUS_SUCCESS;
  2911. if (OutputToken != NULL)
  2912. {
  2913. OutputToken->cbBuffer = 0;
  2914. }
  2915. }
  2916. KerbReadLockContexts();
  2917. *ContextAttributes = KerbMapContextFlags(Context->ContextFlags);
  2918. KerbUtcTimeToLocalTime(
  2919. ExpirationTime,
  2920. &Context->Lifetime
  2921. );
  2922. if (OutputToken != NULL)
  2923. {
  2924. OutputToken->cbBuffer = 0;
  2925. }
  2926. *NewContextHandle = ContextHandle;
  2927. KerbUnlockContexts();
  2928. goto Cleanup; // datagram and finalized contexts exit here.
  2929. }
  2930. //
  2931. // Get the associated credential
  2932. //
  2933. Status = KerbReferenceCredential(
  2934. CredentialHandle,
  2935. KERB_CRED_INBOUND,
  2936. FALSE,
  2937. &Credential
  2938. );
  2939. if (!NT_SUCCESS(Status))
  2940. {
  2941. D_DebugLog((DEB_WARN,"Failed to locate credential 0x%x\n",Status));
  2942. goto Cleanup;
  2943. }
  2944. //
  2945. // Get the logon id from the credentials so we can locate the
  2946. // logon session.
  2947. //
  2948. LogonId = Credential->LogonId;
  2949. //
  2950. // Get the logon session
  2951. //
  2952. LogonSession = KerbReferenceLogonSession( &LogonId, FALSE );
  2953. if (LogonSession == NULL)
  2954. {
  2955. Status = STATUS_NO_SUCH_LOGON_SESSION;
  2956. goto Cleanup;
  2957. }
  2958. KerbReadLockLogonSessions(LogonSession);
  2959. if ((Credential->CredentialFlags & KERB_CRED_LOCAL_ACCOUNT) != 0)
  2960. {
  2961. D_DebugLog((DEB_WARN, "Trying to use a local logon session with Kerberos\n"));
  2962. KerbUnlockLogonSessions(LogonSession);
  2963. Status = SEC_E_NO_CREDENTIALS;
  2964. goto Cleanup;
  2965. }
  2966. if (Credential->SuppliedCredentials != NULL)
  2967. {
  2968. UseSuppliedCreds = TRUE;
  2969. ContextAttribs |= KERB_CONTEXT_USED_SUPPLIED_CREDS;
  2970. Status = KerbDuplicateString(
  2971. &ServiceDomain,
  2972. &Credential->SuppliedCredentials->DomainName
  2973. );
  2974. }
  2975. else
  2976. {
  2977. Status = KerbDuplicateString(
  2978. &ServiceDomain,
  2979. &LogonSession->PrimaryCredentials.DomainName
  2980. );
  2981. }
  2982. #if DBG
  2983. D_DebugLog((DEB_TRACE_CTXT, "SpAcceptLsaModeContext: Accepting context for %wZ\\%wZ\n",
  2984. &LogonSession->PrimaryCredentials.DomainName,
  2985. &LogonSession->PrimaryCredentials.UserName ));
  2986. #endif
  2987. KerbUnlockLogonSessions(LogonSession);
  2988. if (!NT_SUCCESS(Status))
  2989. {
  2990. goto Cleanup;
  2991. }
  2992. //
  2993. // If datagram was requested, note it now. There is no input
  2994. // buffer on the first call using datagram.
  2995. //
  2996. if ((ContextRequirements & ASC_REQ_DATAGRAM) != 0)
  2997. {
  2998. D_DebugLog((DEB_TRACE_CTXT2, "Accepting datagram first call\n"));
  2999. //
  3000. // Verify that there is no input token or it is small. RPC passes
  3001. // in two bytes for the DEC package that we can ignore.
  3002. //
  3003. if ((InputToken != NULL) &&
  3004. (InputToken->cbBuffer > 4))
  3005. {
  3006. D_DebugLog((DEB_WARN, "Non null input token passed to AcceptSecurityContext for datagram\n"));
  3007. Status = SEC_E_INVALID_TOKEN;
  3008. goto Cleanup;
  3009. }
  3010. ContextFlags |= ISC_RET_DATAGRAM;
  3011. ReceiveNonce = 0;
  3012. //
  3013. // Build a server context
  3014. //
  3015. Status = KerbCreateEmptyContext(
  3016. Credential,
  3017. ContextFlags,
  3018. ContextAttribs,
  3019. &LogonId,
  3020. &Context,
  3021. &ContextLifetime
  3022. );
  3023. if (!NT_SUCCESS(Status))
  3024. {
  3025. D_DebugLog((DEB_ERROR,"Failed to create server context: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  3026. goto Cleanup;
  3027. }
  3028. if (OutputToken != NULL)
  3029. {
  3030. OutputToken->cbBuffer = 0;
  3031. }
  3032. }
  3033. else
  3034. {
  3035. D_DebugLog((DEB_TRACE_CTXT2,"Accepting connection first call\n"));
  3036. //
  3037. // Unmarshall the AP request
  3038. //
  3039. if ((InputToken == NULL) ||
  3040. (InputToken->cbBuffer == 0))
  3041. {
  3042. D_DebugLog((DEB_WARN, "Null input token passed to AcceptSecurityContext for datagram\n"));
  3043. Status = SEC_E_INVALID_TOKEN;
  3044. goto Cleanup;
  3045. }
  3046. //
  3047. // Verify the AP request
  3048. //
  3049. Status = KerbVerifyApRequest(
  3050. Context,
  3051. (PUCHAR) InputToken->pvBuffer,
  3052. InputToken->cbBuffer,
  3053. LogonSession,
  3054. Credential,
  3055. UseSuppliedCreds,
  3056. ((ContextRequirements & ASC_REQ_ALLOW_CONTEXT_REPLAY) == 0),
  3057. &Request,
  3058. &InternalTicket,
  3059. &InternalAuthenticator,
  3060. &SessionKey,
  3061. &TicketKey,
  3062. &ServerKey,
  3063. &ContextFlags,
  3064. &ContextAttribs,
  3065. &KerbErr,
  3066. pChannelBindings
  3067. );
  3068. if (!NT_SUCCESS(Status))
  3069. {
  3070. //
  3071. // Track time skew errors
  3072. //
  3073. if ((KerbErr == KRB_AP_ERR_SKEW) ||
  3074. (KerbErr == KRB_AP_ERR_TKT_NYV))
  3075. {
  3076. KerbUpdateSkewTime(TRUE);
  3077. }
  3078. DebugLog((DEB_ERROR,"Failed to verify AP request: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  3079. goto ErrorReturn;
  3080. }
  3081. ContextFlags |= ISC_RET_CONNECTION;
  3082. //
  3083. // Check if this was a user-to-user tgt request. If so, then
  3084. // there was no AP request
  3085. //
  3086. if (Status == STATUS_REPARSE_OBJECT)
  3087. {
  3088. IsTgtRequest = TRUE;
  3089. Status = KerbHandleTgtRequest(
  3090. LogonSession,
  3091. Credential,
  3092. UseSuppliedCreds,
  3093. (PUCHAR) InputToken->pvBuffer,
  3094. InputToken->cbBuffer,
  3095. ContextRequirements,
  3096. OutputToken,
  3097. &LogonId,
  3098. ContextAttributes,
  3099. &Context,
  3100. &ContextLifetime,
  3101. &KerbErr
  3102. );
  3103. if (!NT_SUCCESS(Status))
  3104. {
  3105. goto ErrorReturn;
  3106. }
  3107. ContextFlags |= ISC_RET_USE_SESSION_KEY;
  3108. D_DebugLog((DEB_TRACE_U2U, "SpAcceptLsaModeContext handled TGT request and use_session_key set, ContextAttributes %#x\n", Context->ContextAttributes));
  3109. }
  3110. else // not a user-to-user request
  3111. {
  3112. //
  3113. // Track successful time if this wasn't an error recovery
  3114. //
  3115. if (ContextState != ErrorMessageSentState)
  3116. {
  3117. KerbUpdateSkewTime(FALSE);
  3118. }
  3119. if ((InternalAuthenticator != NULL) &&
  3120. (InternalAuthenticator->bit_mask & KERB_AUTHENTICATOR_sequence_number_present))
  3121. {
  3122. //
  3123. // If the number is unsigned, convert it as unsigned. Otherwise
  3124. // convert as signed.
  3125. //
  3126. if (ASN1intxisuint32(&InternalAuthenticator->KERB_AUTHENTICATOR_sequence_number))
  3127. {
  3128. ReceiveNonce = ASN1intx2uint32(&InternalAuthenticator->KERB_AUTHENTICATOR_sequence_number);
  3129. }
  3130. else
  3131. {
  3132. ReceiveNonce = (ULONG) ASN1intx2int32(&InternalAuthenticator->KERB_AUTHENTICATOR_sequence_number);
  3133. }
  3134. }
  3135. else
  3136. {
  3137. ReceiveNonce = 0;
  3138. }
  3139. //
  3140. // Initialize the opposite direction nonce to the same value
  3141. //
  3142. Nonce = ReceiveNonce;
  3143. //
  3144. // Turn on the flag if it was called for
  3145. //
  3146. if ((ContextRequirements & ASC_REQ_ALLOW_CONTEXT_REPLAY) != 0)
  3147. {
  3148. ContextFlags |= ASC_RET_ALLOW_CONTEXT_REPLAY;
  3149. }
  3150. //
  3151. // Check if the caller wants to allow null sessions
  3152. //
  3153. if (((ContextFlags & ISC_RET_NULL_SESSION) != 0) &&
  3154. ((ContextRequirements & ASC_REQ_ALLOW_NULL_SESSION) == 0))
  3155. {
  3156. D_DebugLog((DEB_ERROR,"Received null session but not allowed. %ws, line %d\n", THIS_FILE, __LINE__));
  3157. Status = STATUS_LOGON_FAILURE;
  3158. goto Cleanup;
  3159. }
  3160. //
  3161. // Authentication succeeded, so build a token
  3162. //
  3163. D_DebugLog((DEB_TRACE_CTXT2, "AcceptLsaModeContext: Creating token from ticket\n"));
  3164. Status = KerbCreateTokenFromTicket(
  3165. InternalTicket,
  3166. InternalAuthenticator,
  3167. ContextFlags,
  3168. &ServerKey,
  3169. &ServiceDomain,
  3170. &SessionKey,
  3171. &LogonId,
  3172. &UserSid,
  3173. &TokenHandle,
  3174. &ClientName,
  3175. &ClientDomain
  3176. );
  3177. if (!NT_SUCCESS(Status))
  3178. {
  3179. DebugLog((DEB_ERROR,"Failed to create token from ticket: 0x%x. %ws, line %d\n",
  3180. Status, THIS_FILE, __LINE__));
  3181. goto Cleanup;
  3182. }
  3183. //
  3184. // If the caller wants mutual authentication, build an AP reply
  3185. //
  3186. if (((ContextFlags & ISC_RET_MUTUAL_AUTH) != 0) ||
  3187. ((ContextFlags & ISC_RET_USED_DCE_STYLE) != 0))
  3188. {
  3189. //
  3190. // We require an output token in this case.
  3191. //
  3192. if (OutputToken == NULL)
  3193. {
  3194. Status = SEC_E_INVALID_TOKEN;
  3195. goto Cleanup;
  3196. }
  3197. //
  3198. // Build the reply message
  3199. //
  3200. D_DebugLog((DEB_TRACE_CTXT2,"SpAcceptLsaModeContext: Building AP reply\n"));
  3201. Status = KerbBuildApReply(
  3202. InternalAuthenticator,
  3203. Request,
  3204. ContextFlags,
  3205. ContextAttribs,
  3206. &TicketKey,
  3207. &SessionKey,
  3208. &Nonce,
  3209. &Reply,
  3210. &ReplySize
  3211. );
  3212. if (!NT_SUCCESS(Status))
  3213. {
  3214. DebugLog((DEB_ERROR,"Failed to build AP reply: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  3215. goto Cleanup;
  3216. }
  3217. if (OutputToken == NULL)
  3218. {
  3219. D_DebugLog((DEB_ERROR,"Output token missing. %ws, line %d\n", THIS_FILE, __LINE__));
  3220. Status = STATUS_INVALID_PARAMETER;
  3221. goto Cleanup;
  3222. }
  3223. //
  3224. // Return the AP reply in the output buffer.
  3225. //
  3226. if ((ContextRequirements & ISC_REQ_ALLOCATE_MEMORY) == 0)
  3227. {
  3228. if (OutputToken->cbBuffer < ReplySize)
  3229. {
  3230. ULONG ErrorData[3];
  3231. ErrorData[0] = ReplySize;
  3232. ErrorData[1] = OutputToken->cbBuffer;
  3233. ErrorData[2] = ClientProcess;
  3234. D_DebugLog((DEB_ERROR,"Output token is too small - sent in %d, needed %d. %ws, line %d\n",
  3235. OutputToken->cbBuffer,ReplySize, THIS_FILE, __LINE__ ));
  3236. OutputToken->cbBuffer = ReplySize;
  3237. Status = STATUS_BUFFER_TOO_SMALL;
  3238. KerbReportNtstatus(
  3239. KERBEVT_INSUFFICIENT_TOKEN_SIZE,
  3240. Status,
  3241. NULL,
  3242. 0,
  3243. ErrorData,
  3244. 3
  3245. );
  3246. goto Cleanup;
  3247. }
  3248. RtlCopyMemory(
  3249. OutputToken->pvBuffer,
  3250. Reply,
  3251. ReplySize
  3252. );
  3253. }
  3254. else
  3255. {
  3256. OutputToken->pvBuffer = Reply;
  3257. Reply = NULL;
  3258. *ContextAttributes |= ASC_RET_ALLOCATED_MEMORY;
  3259. }
  3260. OutputToken->cbBuffer = ReplySize;
  3261. }
  3262. else
  3263. {
  3264. if (OutputToken != NULL)
  3265. {
  3266. OutputToken->cbBuffer = 0;
  3267. }
  3268. }
  3269. //
  3270. // Build a server context if we don't already have one.
  3271. //
  3272. //
  3273. // Turn on the flag if it was called for
  3274. //
  3275. if ((ContextRequirements & ASC_REQ_ALLOW_CONTEXT_REPLAY) != 0)
  3276. {
  3277. ContextFlags |= ASC_RET_ALLOW_CONTEXT_REPLAY;
  3278. }
  3279. if (Context == NULL)
  3280. {
  3281. Status = KerbCreateServerContext(
  3282. LogonSession,
  3283. Credential,
  3284. InternalTicket,
  3285. Request,
  3286. &SessionKey,
  3287. &LogonId,
  3288. &UserSid,
  3289. ContextFlags,
  3290. ContextAttribs,
  3291. Nonce,
  3292. ReceiveNonce,
  3293. &TokenHandle,
  3294. &ClientName,
  3295. &ClientDomain,
  3296. &Context,
  3297. &ContextLifetime
  3298. );
  3299. }
  3300. else
  3301. {
  3302. //
  3303. // Update an existing context
  3304. //
  3305. Status = KerbUpdateServerContext(
  3306. Context,
  3307. InternalTicket,
  3308. Request,
  3309. &SessionKey,
  3310. &LogonId,
  3311. &UserSid,
  3312. ContextFlags,
  3313. ContextAttribs,
  3314. Nonce,
  3315. ReceiveNonce,
  3316. &TokenHandle,
  3317. &ClientName,
  3318. &ClientDomain,
  3319. &ContextLifetime
  3320. );
  3321. }
  3322. if (!NT_SUCCESS(Status))
  3323. {
  3324. DebugLog((DEB_ERROR,"Failed to create or update server context: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  3325. goto Cleanup;
  3326. }
  3327. } // not a TGT request
  3328. } // not datagram
  3329. *NewContextHandle = KerbGetContextHandle(Context);
  3330. KerbUtcTimeToLocalTime(
  3331. ExpirationTime,
  3332. &ContextLifetime
  3333. );
  3334. #if DBG
  3335. KerbReadLockContexts();
  3336. ClientProcess = Context->ClientProcess;
  3337. KerbUnlockContexts();
  3338. #endif // DBG
  3339. *ContextAttributes |= KerbMapContextFlags(ContextFlags);
  3340. if (IsTgtRequest || (((ContextFlags & ISC_RET_USED_DCE_STYLE) != 0) ||
  3341. ((ContextFlags & ISC_RET_DATAGRAM) != 0)))
  3342. {
  3343. Status = SEC_I_CONTINUE_NEEDED;
  3344. }
  3345. goto Cleanup;
  3346. ErrorReturn:
  3347. //
  3348. // Generate a KERB_ERROR message if necessary, meaning that there was
  3349. // an authentication failure.
  3350. //
  3351. if ((OutputToken != NULL ) &&
  3352. (!KERB_SUCCESS(KerbErr) ||
  3353. ((ContextRequirements & ASC_REQ_EXTENDED_ERROR) != 0) ||
  3354. ((ContextFlags & ISC_RET_EXTENDED_ERROR) != 0)))
  3355. {
  3356. NTSTATUS TempStatus;
  3357. PBYTE ErrorMessage = NULL;
  3358. ULONG ErrorMessageSize;
  3359. PBYTE ErrorData = NULL;
  3360. ULONG ErrorDataSize = 0;
  3361. //
  3362. // Check whether it is an error we want the client to retry on.
  3363. // For datagram, we can't handle this.
  3364. //
  3365. if (ContextRequirements & ASC_REQ_DATAGRAM)
  3366. {
  3367. goto Cleanup;
  3368. }
  3369. if (!(((ContextRequirements & ASC_REQ_EXTENDED_ERROR) != 0) ||
  3370. (KerbErr == KRB_AP_ERR_USER_TO_USER_REQUIRED) ||
  3371. (KerbErr == KRB_AP_ERR_SKEW) ||
  3372. (KerbErr == KRB_AP_ERR_TKT_NYV) ||
  3373. (KerbErr == KRB_AP_ERR_TKT_EXPIRED) ||
  3374. (KerbErr == KRB_AP_ERR_MODIFIED) ))
  3375. {
  3376. goto Cleanup;
  3377. }
  3378. //
  3379. // Create an empty context that can be used later
  3380. //
  3381. if (Context == NULL)
  3382. {
  3383. TempStatus = KerbCreateEmptyContext(
  3384. Credential,
  3385. ContextFlags,
  3386. ContextAttribs,
  3387. &LogonId,
  3388. &Context,
  3389. &ContextLifetime
  3390. );
  3391. if (!NT_SUCCESS(TempStatus))
  3392. {
  3393. goto Cleanup;
  3394. }
  3395. }
  3396. //
  3397. // if the error code is one with error data, build the error data
  3398. //
  3399. switch ((UINT_PTR) KerbErr)
  3400. {
  3401. case (UINT_PTR) KRB_AP_ERR_USER_TO_USER_REQUIRED:
  3402. NTSTATUS TempStatus;
  3403. TempStatus = KerbBuildTgtErrorReply(
  3404. LogonSession,
  3405. Credential,
  3406. UseSuppliedCreds,
  3407. Context,
  3408. &ErrorDataSize,
  3409. &ErrorData
  3410. );
  3411. D_DebugLog((DEB_TRACE_U2U, "SpAcceptLsaModeContext called KerbBuildTgtErrorReply %#x\n", TempStatus));
  3412. if (TempStatus == STATUS_USER2USER_REQUIRED)
  3413. {
  3414. KerbErr = KRB_AP_ERR_NO_TGT;
  3415. }
  3416. else if (!NT_SUCCESS(TempStatus))
  3417. {
  3418. D_DebugLog((DEB_ERROR,"Failed to build tgt error reply: 0x%x. Ignoring. %ws, line %d\n",TempStatus, THIS_FILE, __LINE__));
  3419. }
  3420. break;
  3421. case (UINT_PTR) KDC_ERR_NONE:
  3422. //
  3423. // In this case, return the KRB_ERR_GENERIC and the NTSTATUS code
  3424. // in the error data
  3425. //
  3426. KerbErr = KRB_ERR_GENERIC;
  3427. ErrorData = (PUCHAR) &Status;
  3428. ErrorDataSize = sizeof(ULONG);
  3429. break;
  3430. }
  3431. TempStatus = KerbBuildGssErrorMessage(
  3432. KerbErr,
  3433. ErrorData,
  3434. ErrorDataSize,
  3435. Context,
  3436. &ErrorMessageSize,
  3437. &ErrorMessage
  3438. );
  3439. if ((ErrorData != NULL) && (ErrorData != (PUCHAR) &Status))
  3440. {
  3441. MIDL_user_free(ErrorData);
  3442. }
  3443. if (!NT_SUCCESS(TempStatus))
  3444. {
  3445. goto Cleanup;
  3446. }
  3447. *ContextAttributes |= ASC_RET_EXTENDED_ERROR;
  3448. if ((ContextRequirements & ISC_REQ_ALLOCATE_MEMORY) == 0)
  3449. {
  3450. if (OutputToken->cbBuffer < ErrorMessageSize)
  3451. {
  3452. D_DebugLog((DEB_ERROR,"Output token is too small - sent in %d, needed %d. %ws, line %d\n",
  3453. OutputToken->cbBuffer,ErrorMessageSize, THIS_FILE, __LINE__ ));
  3454. MIDL_user_free(ErrorMessage);
  3455. goto Cleanup;
  3456. }
  3457. else
  3458. {
  3459. DsysAssert(OutputToken->pvBuffer != NULL);
  3460. RtlCopyMemory(
  3461. OutputToken->pvBuffer,
  3462. ErrorMessage,
  3463. ErrorMessageSize
  3464. );
  3465. OutputToken->cbBuffer = ErrorMessageSize;
  3466. MIDL_user_free(ErrorMessage);
  3467. }
  3468. }
  3469. else
  3470. {
  3471. DsysAssert(OutputToken->pvBuffer == NULL);
  3472. OutputToken->cbBuffer = ErrorMessageSize;
  3473. OutputToken->pvBuffer = ErrorMessage;
  3474. ErrorMessage = NULL;
  3475. *ContextAttributes |= ASC_RET_ALLOCATED_MEMORY;
  3476. }
  3477. *ContextAttributes |= ASC_RET_EXTENDED_ERROR;
  3478. *NewContextHandle = KerbGetContextHandle(Context);
  3479. KerbUtcTimeToLocalTime(
  3480. ExpirationTime,
  3481. &ContextLifetime
  3482. );
  3483. *ContextAttributes |= KerbMapContextFlags(ContextFlags);
  3484. LastStatus = Status;
  3485. //
  3486. // now it is time to mark the context as user2user
  3487. //
  3488. if (KerbErr == KRB_AP_ERR_USER_TO_USER_REQUIRED)
  3489. {
  3490. DebugLog((DEB_TRACE_U2U, "SpInitLsaModeContext (TGT in error reply) USER2USER-INBOUND set\n"));
  3491. KerbWriteLockContexts()
  3492. Context->ContextAttributes |= KERB_CONTEXT_USER_TO_USER;
  3493. KerbUnlockContexts();
  3494. }
  3495. Status = SEC_I_CONTINUE_NEEDED;
  3496. }
  3497. Cleanup:
  3498. if( KerbEventTraceFlag ) // Event Trace: KerbAcceptSecurityContextEnd {Status, CredSource, DomainName, UserName, Target, (ExtError), (klininfo)}
  3499. {
  3500. PCWSTR TraceStrings[] =
  3501. {
  3502. L"CredMan",
  3503. L"Supplied",
  3504. L"Context",
  3505. L"LogonSession",
  3506. L"None"
  3507. };
  3508. enum { TSTR_CREDMAN = 0, TSTR_SUPPLIED, TSTR_CONTEXT, TSTR_LOGONSESSION, TSTR_NONE };
  3509. UNICODE_STRING UNICODE_NONE = { 4*sizeof(WCHAR), 4*sizeof(WCHAR), L"NONE" };
  3510. UNICODE_STRING CredSource;
  3511. PUNICODE_STRING trace_DomainName, trace_UserName, trace_target;
  3512. trace_target = (Context!=NULL) ? &Context->ServerPrincipalName : &UNICODE_NONE;
  3513. if( Context != NULL && Context->CredManCredentials != NULL )
  3514. {
  3515. RtlInitUnicodeString( &CredSource, TraceStrings[TSTR_CREDMAN] );
  3516. trace_DomainName = &Context->CredManCredentials->SuppliedCredentials->DomainName;
  3517. trace_UserName = &Context->CredManCredentials->SuppliedCredentials->UserName;
  3518. }
  3519. else if( Credential != NULL && Credential->SuppliedCredentials != NULL )
  3520. {
  3521. RtlInitUnicodeString( &CredSource, TraceStrings[TSTR_SUPPLIED] );
  3522. trace_DomainName = &Credential->SuppliedCredentials->DomainName;
  3523. trace_UserName = &Credential->SuppliedCredentials->UserName;
  3524. }
  3525. else if( Context != NULL )
  3526. {
  3527. RtlInitUnicodeString( &CredSource, TraceStrings[TSTR_CONTEXT] );
  3528. trace_DomainName = &Context->ClientRealm;
  3529. trace_UserName = &Context->ClientName;
  3530. }
  3531. else if( LogonSession != NULL )
  3532. {
  3533. RtlInitUnicodeString( &CredSource, TraceStrings[TSTR_LOGONSESSION] );
  3534. trace_DomainName = &LogonSession->PrimaryCredentials.DomainName;
  3535. trace_UserName = &LogonSession->PrimaryCredentials.UserName;
  3536. }
  3537. else
  3538. {
  3539. RtlInitUnicodeString( &CredSource, TraceStrings[TSTR_NONE] );
  3540. trace_DomainName = &UNICODE_NONE;
  3541. trace_UserName = &UNICODE_NONE;
  3542. }
  3543. INSERT_ULONG_INTO_MOF( Status, AcceptSCTraceInfo.MofData, 0 );
  3544. INSERT_UNICODE_STRING_INTO_MOF( CredSource, AcceptSCTraceInfo.MofData, 1 );
  3545. INSERT_UNICODE_STRING_INTO_MOF( *trace_DomainName, AcceptSCTraceInfo.MofData, 3 );
  3546. INSERT_UNICODE_STRING_INTO_MOF( *trace_UserName, AcceptSCTraceInfo.MofData, 5 );
  3547. INSERT_UNICODE_STRING_INTO_MOF( *trace_target, AcceptSCTraceInfo.MofData, 7 );
  3548. AcceptSCTraceInfo.EventTrace.Size = sizeof(EVENT_TRACE_HEADER) + 9*sizeof(MOF_FIELD);
  3549. // Set trace parameters
  3550. AcceptSCTraceInfo.EventTrace.Guid = KerbAcceptSCGuid;
  3551. AcceptSCTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_END;
  3552. AcceptSCTraceInfo.EventTrace.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
  3553. TraceEvent(
  3554. KerbTraceLoggerHandle,
  3555. (PEVENT_TRACE_HEADER)&AcceptSCTraceInfo
  3556. );
  3557. }
  3558. //
  3559. // First, handle auditing
  3560. //
  3561. if (Status == STATUS_SUCCESS)
  3562. {
  3563. //
  3564. // Don't audit if we didn't create a token.
  3565. //
  3566. if (Context->UserSid != NULL)
  3567. {
  3568. UNICODE_STRING WorkstationName = {0};
  3569. //
  3570. // note that UserSid will only be non-Null if the ClientName, ClientRealm were updated in the context.
  3571. // and the context is currently referenced, so the fields won't vanish under us.
  3572. //
  3573. if ((InternalTicket != NULL) &&
  3574. ((InternalTicket->bit_mask & KERB_ENCRYPTED_TICKET_client_addresses_present) != 0))
  3575. {
  3576. (VOID) KerbGetClientNetbiosAddress(
  3577. &WorkstationName,
  3578. InternalTicket->KERB_ENCRYPTED_TICKET_client_addresses
  3579. );
  3580. //
  3581. // The following generates a successful audit event.
  3582. // A new field (logon GUID) was added to this audit event.
  3583. //
  3584. // In order to send this new field to LSA, we had two options:
  3585. // 1) add new function (AuditLogonEx) to LSA dispatch table
  3586. // 2) define a private (LsaI) function to do the job
  3587. //
  3588. // option#2 was chosen because the logon GUID is a Kerberos only
  3589. // feature.
  3590. //
  3591. (void) KerbAuditLogon(
  3592. Status,
  3593. Status,
  3594. InternalTicket,
  3595. Context->UserSid,
  3596. &WorkstationName,
  3597. &LogonId
  3598. );
  3599. KerbFreeString(&WorkstationName);
  3600. }
  3601. }
  3602. }
  3603. else if (!NT_SUCCESS(Status) || (LastStatus != STATUS_SUCCESS))
  3604. {
  3605. if (Context != NULL)
  3606. {
  3607. LsaFunctions->AuditLogon(
  3608. STATUS_LOGON_FAILURE,
  3609. (LastStatus != STATUS_SUCCESS) ? LastStatus : Status,
  3610. &Context->ClientName,
  3611. &Context->ClientRealm,
  3612. NULL, // no workstation
  3613. NULL, // no sid instead of a bogus one
  3614. Network,
  3615. &KerberosSource,
  3616. &LogonId
  3617. );
  3618. }
  3619. else
  3620. {
  3621. UNICODE_STRING EmptyString = NULL_UNICODE_STRING;
  3622. LsaFunctions->AuditLogon(
  3623. (LastStatus != STATUS_SUCCESS) ? LastStatus : Status,
  3624. STATUS_SUCCESS,
  3625. &EmptyString,
  3626. &EmptyString,
  3627. NULL, // no workstation
  3628. NULL,
  3629. Network,
  3630. &KerberosSource,
  3631. &LogonId
  3632. );
  3633. }
  3634. }
  3635. if (Context != NULL)
  3636. {
  3637. if (!NT_SUCCESS(Status))
  3638. {
  3639. //
  3640. // Only unlink the context if we just created it.
  3641. //
  3642. if (ContextHandle == 0)
  3643. {
  3644. KerbReferenceContextByPointer(
  3645. Context,
  3646. TRUE
  3647. );
  3648. KerbDereferenceContext(Context);
  3649. }
  3650. else
  3651. {
  3652. //
  3653. // Set the context to an invalid state.
  3654. //
  3655. KerbWriteLockContexts();
  3656. Context->ContextState = InvalidState;
  3657. KerbUnlockContexts();
  3658. }
  3659. }
  3660. else
  3661. {
  3662. KerbWriteLockContexts();
  3663. if (Status == STATUS_SUCCESS)
  3664. {
  3665. Context->ContextState = AuthenticatedState;
  3666. }
  3667. else
  3668. {
  3669. if ((*ContextAttributes & ASC_RET_EXTENDED_ERROR) != 0)
  3670. {
  3671. Context->ContextState = ErrorMessageSentState;
  3672. }
  3673. else if (!IsTgtRequest)
  3674. {
  3675. Context->ContextState = ApReplySentState;
  3676. }
  3677. else
  3678. {
  3679. //
  3680. // else the HandleTgtRequest set the state
  3681. //
  3682. DsysAssert(Context->ContextState == TgtReplySentState);
  3683. }
  3684. }
  3685. KerbUnlockContexts();
  3686. }
  3687. KerbDereferenceContext(Context);
  3688. }
  3689. if (Status == STATUS_SUCCESS)
  3690. {
  3691. //
  3692. // On real success we map the context to the callers address
  3693. // space.
  3694. //
  3695. Status = KerbMapContext(
  3696. Context,
  3697. MappedContext,
  3698. ContextData
  3699. );
  3700. DebugLog((DEB_TRACE, "SpAcceptLsaModeContext called KerbMapContext ContextAttributes %#x, %#x\n", Context->ContextAttributes, Status));
  3701. }
  3702. if (LogonSession != NULL)
  3703. {
  3704. KerbDereferenceLogonSession( LogonSession );
  3705. }
  3706. if (Credential != NULL)
  3707. {
  3708. KerbDereferenceCredential( Credential );
  3709. }
  3710. if (InternalTicket != NULL)
  3711. {
  3712. KerbFreeTicket( InternalTicket );
  3713. }
  3714. if (InternalAuthenticator != NULL)
  3715. {
  3716. KerbFreeAuthenticator(InternalAuthenticator);
  3717. }
  3718. if (Request != NULL)
  3719. {
  3720. KerbFreeApRequest(Request);
  3721. }
  3722. if (Reply != NULL)
  3723. {
  3724. KerbFree(Reply);
  3725. }
  3726. KerbFreeKey(&SessionKey);
  3727. KerbFreeKey(&ServerKey);
  3728. if (UserSid != NULL)
  3729. {
  3730. KerbFree(UserSid);
  3731. }
  3732. //
  3733. // If there was a problem with the context or AP reply, the TokenHandle
  3734. // will not be reset to NULL. If it is NULL, close it so we don't leak
  3735. //
  3736. if ( TokenHandle != NULL )
  3737. {
  3738. D_DebugLog(( DEB_TRACE, "Closing token handle because context creation failed (%x)\n",
  3739. Status ));
  3740. NtClose( TokenHandle );
  3741. }
  3742. //
  3743. // Update performance counter
  3744. //
  3745. #ifndef WIN32_CHICAGO
  3746. if (ContextHandle == 0)
  3747. {
  3748. I_SamIIncrementPerformanceCounter(KerbServerContextCounter);
  3749. }
  3750. #endif // WIN32_CHICAGO
  3751. KerbFreeKey(&TicketKey);
  3752. KerbFreeString(&ServiceDomain);
  3753. KerbFreeString(&ClientDomain);
  3754. KerbFreeString(&ClientName);
  3755. D_DebugLog((DEB_TRACE_LEAKS,"SpAcceptLsaModeContext returned 0x%x, Context 0x%x, Pid 0x%x\n",KerbMapKerbNtStatusToNtStatus(Status), *NewContextHandle, ClientProcess));
  3756. D_DebugLog((DEB_TRACE_API, "SpAcceptLsaModeContext returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  3757. return(KerbMapKerbNtStatusToNtStatus(Status));
  3758. }
  3759. #endif WIN32_CHICAGO //we don't do server side stuff