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

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