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.

5504 lines
157 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: tktutil.cxx
  7. //
  8. // Contents:
  9. //
  10. // Functions:
  11. //
  12. // History: 04-Mar-94 wader Created
  13. //
  14. //----------------------------------------------------------------------------
  15. // Place any local #includes files here.
  16. #include "kdcsvr.hxx"
  17. extern "C"
  18. {
  19. #include <dns.h> // DNS_MAX_NAME_LENGTH
  20. #include <ntdsa.h> // CrackSingleName
  21. #include <ntdsapip.h> // DS_USER_PRINCIPAL_NAME_ONLY
  22. }
  23. #include <userall.h>
  24. #include "refer.h"
  25. #define FILENO FILENO_TKTUTIL
  26. #define KDC_WSZ_GC L"gc"
  27. #define KDC_GC_NAMEPARTS 3
  28. //#define DONT_SUPPORT_OLD_TYPES_KDC 1
  29. //
  30. // Static data
  31. //
  32. //
  33. // Fudge factor for comparing timestamps, because network clocks may
  34. // be out of sync.
  35. // Note: The lowpart is first!
  36. //
  37. LARGE_INTEGER SkewTime;
  38. //
  39. // Mapping table for nametypes
  40. //
  41. WCHAR * KdcGlobalNameTypes[] =
  42. {
  43. L"DS_UNKNOWN_NAME",
  44. L"DS_FQDN_1779_NAME",
  45. L"DS_NT4_ACCOUNT_NAME",
  46. L"DS_DISPLAY_NAME",
  47. NULL,
  48. NULL,
  49. L"DS_UNIQUE_ID_NAME",
  50. L"DS_CANONICAL_NAME",
  51. L"DS_USER_PRINCIPAL_NAME",
  52. L"DS_CANONICAL_NAME_EX",
  53. L"DS_SERVICE_PRINCIPAL_NAME",
  54. L"DS_SID_OR_SID_HISTORY_NAME",
  55. L"DS_DNS_DOMAIN_NAME",
  56. };
  57. //+-------------------------------------------------------------------------
  58. //
  59. // Function: KdcBuildNt4Name
  60. //
  61. // Synopsis: Construct an NT4 style name for an account by separating
  62. // the name into a principal & domain name, converting the
  63. // domain name to netbios, and then creating "domain\user" name.
  64. //
  65. // Effects:
  66. //
  67. // Arguments:
  68. //
  69. // Requires:
  70. //
  71. // Returns:
  72. //
  73. // Notes:
  74. //
  75. //
  76. //--------------------------------------------------------------------------
  77. KERBERR
  78. KdcBuildNt4Name(
  79. OUT LPWSTR * Nt4Name,
  80. OUT PUNICODE_STRING OutputRealm,
  81. IN PUNICODE_STRING Upn
  82. )
  83. {
  84. ULONG Index;
  85. KERBERR KerbErr = KDC_ERR_NONE;
  86. LPWSTR OutputName = NULL;
  87. PKDC_DOMAIN_INFO DomainInfo = NULL;
  88. UNICODE_STRING RealmName;
  89. UNICODE_STRING PrincipalName;
  90. TRACE(KDC, KdcBuildNt4Name, DEB_FUNCTION);
  91. //
  92. // Find the first backslash or '@', or '.' in the name
  93. //
  94. RtlInitUnicodeString(
  95. OutputRealm,
  96. NULL
  97. );
  98. *Nt4Name = NULL;
  99. for (Index = Upn->Length/sizeof(WCHAR) - 1; Index > 0 ; Index-- )
  100. {
  101. if (Upn->Buffer[Index] == L'@')
  102. {
  103. break;
  104. }
  105. }
  106. if (Index == 0)
  107. {
  108. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  109. goto Cleanup;
  110. }
  111. //
  112. // Pull out the realm name and look it up in the list of domains
  113. //
  114. PrincipalName = *Upn;
  115. PrincipalName.Length = (USHORT) Index * sizeof(WCHAR);
  116. PrincipalName.MaximumLength = (USHORT) Index * sizeof(WCHAR);
  117. RealmName.Buffer = &Upn->Buffer[Index+1];
  118. RealmName.Length = (USHORT) (Upn->Length - (Index + 1) * sizeof(WCHAR));
  119. RealmName.MaximumLength = RealmName.Length;
  120. KdcLockDomainList();
  121. KerbErr = KdcLookupDomainName(
  122. &DomainInfo,
  123. &RealmName,
  124. &KdcDomainList
  125. );
  126. KdcUnlockDomainList();
  127. if (!KERB_SUCCESS(KerbErr))
  128. {
  129. goto Cleanup;
  130. }
  131. //
  132. // We need a netbios name
  133. //
  134. if (DomainInfo->NetbiosName.Length == 0)
  135. {
  136. //
  137. // Copy out the realm name so we can return a non-authoritative referral
  138. //
  139. if (!NT_SUCCESS(KerbDuplicateString(
  140. OutputRealm,
  141. &DomainInfo->DnsName
  142. )))
  143. {
  144. KerbErr = KRB_ERR_GENERIC;
  145. goto Cleanup;
  146. }
  147. KerbErr = KDC_ERR_WRONG_REALM;
  148. goto Cleanup;
  149. }
  150. //
  151. // now build the output name
  152. //
  153. OutputName = (LPWSTR) MIDL_user_allocate(DomainInfo->NetbiosName.Length + PrincipalName.Length + 2 * sizeof(WCHAR));
  154. if (OutputName == NULL)
  155. {
  156. KerbErr = KRB_ERR_GENERIC;
  157. goto Cleanup;
  158. }
  159. RtlCopyMemory(
  160. OutputName,
  161. DomainInfo->NetbiosName.Buffer,
  162. DomainInfo->NetbiosName.Length
  163. );
  164. OutputName[DomainInfo->NetbiosName.Length/sizeof(WCHAR)] = L'\\';
  165. RtlCopyMemory(
  166. OutputName + DomainInfo->NetbiosName.Length/sizeof(WCHAR) + 1,
  167. PrincipalName.Buffer,
  168. PrincipalName.Length
  169. );
  170. OutputName[1 + (PrincipalName.Length + DomainInfo->NetbiosName.Length)/sizeof(WCHAR)] = L'\0';
  171. *Nt4Name = OutputName;
  172. OutputName = NULL;
  173. Cleanup:
  174. if (DomainInfo != NULL)
  175. {
  176. KdcDereferenceDomainInfo( DomainInfo );
  177. }
  178. if (OutputName != NULL)
  179. {
  180. MIDL_user_free( OutputName );
  181. }
  182. return(KerbErr);
  183. }
  184. //+-------------------------------------------------------------------------
  185. //
  186. // Function: KdcFreeS4UTicketInfo
  187. //
  188. // Synopsis: Frees ticket info used in processing S4UProxy and S4USelf
  189. // requests.
  190. //
  191. // Effects:
  192. //
  193. // Arguments:
  194. //
  195. // Requires:
  196. //
  197. // Returns:
  198. //
  199. // Notes:
  200. //
  201. //
  202. //---
  203. VOID
  204. KdcFreeS4UTicketInfo(PKDC_S4U_TICKET_INFO S4UTicketInfo)
  205. {
  206. TRACE(KDC, KdcFreeTgsTicketInfo, DEB_FUNCTION);
  207. if (S4UTicketInfo == NULL)
  208. {
  209. return;
  210. }
  211. KerbFreeKdcName( &S4UTicketInfo->RequestorServiceName );
  212. KerbFreeString( &S4UTicketInfo->RequestorServiceRealm );
  213. FreeTicketInfo( &S4UTicketInfo->RequestorTicketInfo );
  214. KerbFreeString( &S4UTicketInfo->TargetName );
  215. KerbFreeKdcName( &S4UTicketInfo->PACCName );
  216. KerbFreeString( &S4UTicketInfo->PACCRealm );
  217. KerbFreeKey( &S4UTicketInfo->EvidenceTicketKey );
  218. //
  219. // The evidence ticket is just a pointer to the source
  220. // ticket when doing S4USelf. Otherwise, we unpacked it, and we've
  221. // got to free the memory.
  222. //
  223. if (( S4UTicketInfo->EvidenceTicket != NULL ) &&
  224. (( S4UTicketInfo->Flags & TI_FREETICKET ) != 0))
  225. {
  226. KerbFreeTicket( S4UTicketInfo->EvidenceTicket );
  227. }
  228. }
  229. //+-------------------------------------------------------------------------
  230. //
  231. // Function: KdcFreeU2UTicketInfo
  232. //
  233. // Synopsis: Frees ticket info used for U2U
  234. //
  235. // Effects:
  236. //
  237. // Arguments:
  238. //
  239. // Requires:
  240. //
  241. // Returns:
  242. //
  243. // Notes:
  244. //
  245. //
  246. //---
  247. VOID
  248. KdcFreeU2UTicketInfo(PKDC_U2U_TICKET_INFO U2UTicketInfo)
  249. {
  250. TRACE(KDC, KdcFreeTgsTicketInfo, DEB_FUNCTION);
  251. if (U2UTicketInfo == NULL)
  252. {
  253. return;
  254. }
  255. if ( U2UTicketInfo->Tgt )
  256. {
  257. KerbFreeTicket( U2UTicketInfo->Tgt );
  258. }
  259. KerbFreeKdcName( &U2UTicketInfo->TgtCName );
  260. KerbFreeString( &U2UTicketInfo->TgtCRealm );
  261. FreeTicketInfo( &U2UTicketInfo->TgtTicketInfo );
  262. KerbFreeKdcName( &U2UTicketInfo->cName );
  263. KerbFreeString( &U2UTicketInfo->cRealm );
  264. }
  265. //+-------------------------------------------------------------------------
  266. //
  267. // Function: KdcMatchCrossForestName
  268. //
  269. // Synopsis: Builds a list of the supplemental credentials and then
  270. // encrypts it with the supplied key
  271. //
  272. // Effects:
  273. //
  274. // Arguments:
  275. //
  276. // Requires:
  277. //
  278. // Returns:
  279. //
  280. // Notes:
  281. //
  282. //
  283. //--------------------------------------------------------------------------
  284. KERBERR
  285. KdcMatchCrossForestName(
  286. IN PKERB_INTERNAL_NAME Principal,
  287. OUT PUNICODE_STRING RealmName
  288. )
  289. {
  290. NTSTATUS Status = STATUS_SUCCESS;
  291. LSA_ROUTING_MATCH_TYPE MatchType;
  292. KERBERR KerbErr = KDC_ERR_NONE;
  293. UNICODE_STRING UnicodePrincipal = {0};
  294. TRACE(KDC, KdcMatchCrossForestName, DEB_FUNCTION);
  295. switch (Principal->NameType)
  296. {
  297. case KRB_NT_ENTERPRISE_PRINCIPAL:
  298. MatchType = RoutingMatchUpn;
  299. break;
  300. case KRB_NT_SRV_INST:
  301. MatchType = RoutingMatchSpn;
  302. break;
  303. default:
  304. return KRB_ERR_GENERIC;
  305. }
  306. KerbErr = KerbConvertKdcNameToString(
  307. &UnicodePrincipal,
  308. Principal,
  309. NULL
  310. );
  311. if (!KERB_SUCCESS(KerbErr))
  312. {
  313. goto Cleanup;
  314. }
  315. //
  316. // Can we match the SPN / UPN to external name space (realm)
  317. //
  318. Status = LsaIForestTrustFindMatch(
  319. MatchType,
  320. &UnicodePrincipal,
  321. RealmName
  322. );
  323. if (!NT_SUCCESS(Status))
  324. {
  325. DebugLog((DEB_WARN, "LsaIForestTrustFindMatch failed - %x\n",Status));
  326. goto Cleanup;
  327. }
  328. Cleanup:
  329. if (!NT_SUCCESS(Status))
  330. {
  331. KerbErr = KRB_ERR_GENERIC;
  332. }
  333. KerbFreeString(&UnicodePrincipal);
  334. return KerbErr;
  335. }
  336. //+-------------------------------------------------------------------------
  337. //
  338. // Function: KdcCrackNameAtGC
  339. //
  340. // Synopsis: Cracks a name at a GC by first looking it up for
  341. // UPN/SPN and then constructing an NT4-style name to lookup
  342. //
  343. // Effects:
  344. //
  345. // Arguments:
  346. //
  347. // Requires:
  348. //
  349. // Returns:
  350. //
  351. // Notes:
  352. //
  353. //
  354. //--------------------------------------------------------------------------
  355. KERBERR
  356. KdcCrackNameAtGC(
  357. IN PUNICODE_STRING Upn,
  358. IN PKERB_INTERNAL_NAME PrincipalName,
  359. IN ULONG KdcNameFlags,
  360. IN BOOLEAN bRestrictUserAccounts,
  361. IN BOOLEAN UseLocalHack,
  362. OUT PUNICODE_STRING RealmName,
  363. OUT PKDC_TICKET_INFO TicketInfo,
  364. OUT PBOOLEAN Authoritative,
  365. OUT PBOOLEAN Referral,
  366. OUT PBOOLEAN CrossForest,
  367. OUT PKERB_EXT_ERROR pExtendedError,
  368. OUT OPTIONAL SAMPR_HANDLE * UserHandle,
  369. IN OPTIONAL ULONG WhichFields,
  370. IN OPTIONAL ULONG ExtendedFields,
  371. OUT OPTIONAL PUSER_INTERNAL6_INFORMATION * UserInfo,
  372. OUT OPTIONAL PSID_AND_ATTRIBUTES_LIST GroupMembership
  373. )
  374. {
  375. KERBERR KerbErr = KDC_ERR_NONE;
  376. NTSTATUS Status;
  377. LPWSTR NullTerminatedName = NULL;
  378. UNICODE_STRING CrackedDomain = {0};
  379. UNICODE_STRING LocalCrackedString = {0};
  380. LPWSTR CrackedDnsDomain = NULL;
  381. ULONG CrackedDomainLength = (DNS_MAX_NAME_LENGTH+1);
  382. LPWSTR CrackedName = NULL;
  383. ULONG CrackedNameLength = (UNLEN+DNS_MAX_NAME_LENGTH + 2);
  384. ULONG CrackError = 0;
  385. BOOLEAN Retry = TRUE;
  386. BOOLEAN ReferToRoot = FALSE, UsedHack = FALSE;
  387. ULONG NameFlags = DS_NAME_FLAG_TRUST_REFERRAL | DS_NAME_FLAG_GCVERIFY;
  388. UNICODE_STRING ForestRoot = {0};
  389. ULONG NameType;
  390. TRACE(KDC, KdcCrackNameAtGC, DEB_FUNCTION);
  391. if ( KdcNameFlags & KDC_NAME_S4U_CLIENT )
  392. {
  393. //
  394. // For S4U requests, the name is looked up by both UPN and AltSecId
  395. //
  396. NameType = DS_USER_PRINCIPAL_NAME_AND_ALTSECID;
  397. }
  398. else if ( KdcNameFlags & ( KDC_NAME_CLIENT | KDC_NAME_UPN_TARGET ))
  399. {
  400. //
  401. // For all other name and UPN, only UPN name will do (no AltSecId)
  402. //
  403. NameType = DS_USER_PRINCIPAL_NAME;
  404. }
  405. else
  406. {
  407. NameType = DS_SERVICE_PRINCIPAL_NAME;
  408. }
  409. *Authoritative = TRUE;
  410. #ifdef notyet
  411. //
  412. // Check to see if the name is the machine name, and if so, don't try to
  413. // go to the GC.
  414. //
  415. if ((NameType == DS_USER_PRINCIPAL_NAME) &&
  416. RtlEqualUnicodeString(
  417. SecData.MachineUpn(),
  418. Upn,
  419. TRUE // case insensitive
  420. ))
  421. {
  422. DebugLog((DEB_ERROR,"Trying to lookup machine upn %wZ on GC - failing early\n",
  423. Upn));
  424. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  425. goto Cleanup;
  426. }
  427. #endif
  428. CrackedDnsDomain = (LPWSTR) MIDL_user_allocate(CrackedDomainLength * sizeof( WCHAR ));
  429. if (CrackedDnsDomain == NULL)
  430. {
  431. KerbErr = KRB_ERR_GENERIC;
  432. goto Cleanup;
  433. }
  434. CrackedName = (LPWSTR) MIDL_user_allocate(CrackedNameLength * sizeof ( WCHAR ));
  435. if (CrackedName == NULL)
  436. {
  437. KerbErr = KRB_ERR_GENERIC;
  438. goto Cleanup;
  439. }
  440. //
  441. // We can only retry for user principal names, which have a simple
  442. // structure.
  443. //
  444. if (NameType != DS_USER_PRINCIPAL_NAME)
  445. {
  446. Retry = FALSE;
  447. }
  448. //
  449. // So we didn't find the account locally. Now try the GC.
  450. //
  451. NullTerminatedName = KerbBuildNullTerminatedString(
  452. Upn
  453. );
  454. if (NullTerminatedName == NULL)
  455. {
  456. KerbErr = KRB_ERR_GENERIC;
  457. goto Cleanup;
  458. }
  459. //
  460. // If we are in a recursive state, then we need to *not* go to
  461. // the GC, and try the crack locally. This is because we'll go in
  462. // to a recursive tailspin and die. this is a hack to escape this
  463. // situation until we work out a better soln. with DS folks.
  464. //
  465. if ( UseLocalHack )
  466. {
  467. if (CrackedDnsDomain != NULL)
  468. {
  469. MIDL_user_free(CrackedDnsDomain);
  470. }
  471. if (CrackedName !=NULL)
  472. {
  473. MIDL_user_free(CrackedName);
  474. }
  475. //
  476. // note : these are guaranteed to be '\0' terminated.
  477. //
  478. CrackedDnsDomain = PrincipalName->Names[2].Buffer;
  479. CrackedName = PrincipalName->Names[1].Buffer;
  480. UsedHack = TRUE;
  481. DebugLog(( DEB_WARN, "Special case hack of %ws to '%ws' at domain '%ws'\n",
  482. NullTerminatedName, CrackedName, CrackedDnsDomain ));
  483. Status = STATUS_SUCCESS ;
  484. CrackError = DS_NAME_NO_ERROR ;
  485. goto LocalHack ;
  486. }
  487. Retry:
  488. Status = CrackSingleName(
  489. NameType,
  490. NameFlags,
  491. NullTerminatedName,
  492. DS_UNIQUE_ID_NAME,
  493. &CrackedDomainLength,
  494. CrackedDnsDomain,
  495. &CrackedNameLength,
  496. CrackedName,
  497. &CrackError
  498. );
  499. LocalHack:
  500. if ((Status != STATUS_SUCCESS) ||
  501. ( ( CrackError != DS_NAME_NO_ERROR ) &&
  502. ( CrackError != DS_NAME_ERROR_DOMAIN_ONLY ) &&
  503. ( CrackError != DS_NAME_ERROR_TRUST_REFERRAL)) )
  504. {
  505. //
  506. // If the name is a duplicate, log an event
  507. //
  508. if (CrackError == DS_NAME_ERROR_NOT_UNIQUE)
  509. {
  510. WCHAR LookupType[10];
  511. WCHAR * LookupTypeStr;
  512. if (( NameType < sizeof( KdcGlobalNameTypes ) / sizeof( KdcGlobalNameTypes[0] )) &&
  513. ( KdcGlobalNameTypes[NameType] != NULL ))
  514. {
  515. LookupTypeStr = KdcGlobalNameTypes[NameType];
  516. }
  517. else
  518. {
  519. swprintf(LookupType,L"%d",(ULONG) NameType);
  520. LookupTypeStr = LookupType;
  521. }
  522. ReportServiceEvent(
  523. EVENTLOG_ERROR_TYPE,
  524. KDCEVENT_NAME_NOT_UNIQUE,
  525. 0,
  526. NULL,
  527. 2,
  528. NullTerminatedName,
  529. LookupTypeStr
  530. );
  531. }
  532. //
  533. // If we're in the root domain, we could be getting asked for a
  534. // name outside our forest. Look now, and attempt to
  535. // create the ticket info for that external target realm
  536. //
  537. if (SecData.IsForestRoot() && SecData.IsCrossForestEnabled())
  538. {
  539. KerbErr = KdcMatchCrossForestName(
  540. PrincipalName,
  541. &CrackedDomain
  542. );
  543. if (KERB_SUCCESS(KerbErr))
  544. {
  545. D_DebugLog((DEB_T_TICKETS, "xforest lookup directly - %wZ\n", &CrackedDomain)); // fester: dumb down to DEB_T_TICKETS
  546. *CrossForest = TRUE;
  547. }
  548. }
  549. DebugLog((DEB_WARN,"Failed to resolve name %ws: 0x%x, %d\n",
  550. NullTerminatedName, Status ,CrackError ));
  551. if (Retry)
  552. {
  553. MIDL_user_free(NullTerminatedName);
  554. NullTerminatedName = NULL;
  555. KerbErr = KdcBuildNt4Name(
  556. &NullTerminatedName,
  557. &CrackedDomain,
  558. Upn
  559. );
  560. if (!KERB_SUCCESS(KerbErr))
  561. {
  562. //
  563. // If we got a wrong realm error, then we can return
  564. // a non-authorititive answer
  565. //
  566. if (KerbErr == KDC_ERR_WRONG_REALM)
  567. {
  568. *Authoritative = FALSE;
  569. KerbErr = KDC_ERR_NONE;
  570. }
  571. else
  572. {
  573. goto Cleanup;
  574. }
  575. }
  576. else
  577. {
  578. NameType = DS_NT4_ACCOUNT_NAME;
  579. Retry = FALSE;
  580. //
  581. // Reset lengths
  582. //
  583. CrackedDomainLength = (DNS_MAX_NAME_LENGTH+1);
  584. CrackedNameLength = (UNLEN+DNS_MAX_NAME_LENGTH + 2);
  585. goto Retry;
  586. }
  587. }
  588. else
  589. {
  590. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  591. goto Cleanup;
  592. }
  593. }
  594. else if (CrackError == DS_NAME_ERROR_TRUST_REFERRAL)
  595. {
  596. //
  597. // We got a Xforest referral, go to Root domain
  598. //
  599. D_DebugLog((DEB_T_TICKETS, "CrackName forest res- %S\n", CrackedDnsDomain));
  600. RtlInitUnicodeString(
  601. &CrackedDomain,
  602. CrackedDnsDomain
  603. );
  604. *CrossForest = TRUE;
  605. }
  606. else
  607. {
  608. //
  609. // Success...
  610. //
  611. D_DebugLog((DEB_T_TICKETS, "CrackName local - %S\n", CrackedDnsDomain));
  612. RtlInitUnicodeString(
  613. &CrackedDomain,
  614. CrackedDnsDomain
  615. );
  616. }
  617. //
  618. // Decide whether we can open the account locally.
  619. //
  620. if (SecData.IsOurRealm( &CrackedDomain ))
  621. {
  622. *Referral = FALSE;
  623. RtlInitUnicodeString(
  624. &LocalCrackedString,
  625. CrackedName
  626. );
  627. KerbErr = KdcGetTicketInfo(
  628. &LocalCrackedString,
  629. SAM_OPEN_BY_GUID,
  630. bRestrictUserAccounts,
  631. NULL,
  632. NULL,
  633. TicketInfo,
  634. pExtendedError,
  635. UserHandle,
  636. WhichFields,
  637. ExtendedFields,
  638. UserInfo,
  639. GroupMembership
  640. );
  641. if (!KERB_SUCCESS(KerbErr))
  642. {
  643. goto Cleanup;
  644. }
  645. }
  646. else
  647. {
  648. //
  649. // For UPNs (client) referrals, we don't really need the referral
  650. // information at this stage. Just returned the domain from
  651. // CrackSingleName() after checking that its a name we know about.
  652. //
  653. if ((KdcNameFlags & KDC_NAME_CLIENT) != 0)
  654. {
  655. D_DebugLog((DEB_T_TICKETS, "Generating UPN referral\n"));
  656. KerbDuplicateString(
  657. RealmName,
  658. &CrackedDomain
  659. );
  660. //
  661. // If this wasn't a cross forest routing hint, then we must
  662. // know about the target domain. If it didn't exist in our
  663. // routing tables, we should fail.
  664. //
  665. if (!( *CrossForest ))
  666. {
  667. KerbErr = KdcFindReferralTarget(
  668. TicketInfo,
  669. RealmName,
  670. pExtendedError,
  671. &CrackedDomain,
  672. FALSE, // not need ExactMatch
  673. KdcNameFlags
  674. );
  675. if (!KERB_SUCCESS(KerbErr))
  676. {
  677. //
  678. // Hack for broken trust recursion.
  679. //
  680. if (KerbErr == KDC_ERR_NO_TRUST_PATH)
  681. {
  682. KerbErr = KDC_ERR_S_PRINCIPAL_UNKNOWN;
  683. }
  684. D_DebugLog((DEB_T_TICKETS, "Got UPN w/ uknown trust path %x\n", KerbErr));
  685. goto Cleanup;
  686. }
  687. }
  688. }
  689. else
  690. {
  691. //
  692. // This is either a UPN target (e.g. U2U), or this is an SPN
  693. // target. In both cases, return the Xrealm keys we need.
  694. //
  695. D_DebugLog((DEB_T_TICKETS, "Generating SPN / UPN target referral\n"));
  696. //
  697. // Go to the root domain of our forest when we detect we need to go
  698. // xforest.
  699. //
  700. ReferToRoot = (((KdcNameFlags & ( KDC_NAME_SERVER | KDC_NAME_UPN_TARGET )) != 0) &&
  701. (!SecData.IsForestRoot()) &&
  702. (*CrossForest));
  703. if ( ReferToRoot )
  704. {
  705. Status = SecData.GetKdcForestRoot(&ForestRoot);
  706. if (!NT_SUCCESS(Status))
  707. {
  708. KerbErr = KRB_ERR_GENERIC;
  709. goto Cleanup;
  710. }
  711. }
  712. KerbErr = KdcFindReferralTarget(
  713. TicketInfo,
  714. RealmName,
  715. pExtendedError,
  716. (ReferToRoot ? &ForestRoot : &CrackedDomain),
  717. FALSE, // not need ExactMatch
  718. KdcNameFlags
  719. );
  720. if (!KERB_SUCCESS(KerbErr))
  721. {
  722. //
  723. // Hack for broken trust recursion.
  724. //
  725. if (KerbErr == KDC_ERR_NO_TRUST_PATH)
  726. {
  727. KerbErr = KDC_ERR_S_PRINCIPAL_UNKNOWN;
  728. }
  729. goto Cleanup;
  730. }
  731. //
  732. // Mark our referral realm as the cracked domain
  733. //
  734. if (ReferToRoot)
  735. {
  736. KerbFreeString(&ForestRoot);
  737. KerbFreeString(RealmName);
  738. KerbDuplicateString(
  739. RealmName,
  740. &CrackedDomain
  741. );
  742. }
  743. }
  744. //
  745. // Everything worked, we found the referral target in our trust (or
  746. // a cross forest routing hint).
  747. //
  748. *Referral = TRUE;
  749. }
  750. Cleanup:
  751. if (ReferToRoot && ForestRoot.Buffer != NULL )
  752. {
  753. KerbFreeString(&ForestRoot);
  754. }
  755. if (!UsedHack)
  756. {
  757. if (CrackedDnsDomain != NULL)
  758. {
  759. MIDL_user_free(CrackedDnsDomain);
  760. }
  761. if (CrackedName !=NULL)
  762. {
  763. MIDL_user_free(CrackedName);
  764. }
  765. }
  766. if (!*Authoritative)
  767. {
  768. KerbFreeString(&CrackedDomain);
  769. }
  770. if (NullTerminatedName != NULL)
  771. {
  772. MIDL_user_free(NullTerminatedName);
  773. }
  774. return(KerbErr);
  775. }
  776. //+-------------------------------------------------------------------------
  777. //
  778. // Function: KdcRecursing
  779. //
  780. // Synopsis: Determines if we've started to recurse, and whether
  781. // or not its ok to continue.
  782. //
  783. // Effects:
  784. //
  785. // Arguments: PrincipalName - name to normalize
  786. // PrincipalRealm - Realm that issued principal name
  787. // RequestRealm - Realm field of a KDC request
  788. // NameFlags - flags about name, may be:
  789. // KDC_NAME_CLIENT or KDC_NAME_SERVER
  790. //
  791. // Requires:
  792. //
  793. // Returns:
  794. //
  795. // Notes:
  796. //
  797. //
  798. //--------------------------------------------------------------------------
  799. BOOLEAN
  800. KdcRecursing(
  801. IN PKERB_INTERNAL_NAME PrincipalName,
  802. IN OUT PBOOLEAN UseLocalHack
  803. )
  804. {
  805. BOOLEAN fRet = FALSE;
  806. UNICODE_STRING GCString;
  807. SECPKG_CALL_INFO CallInfo;
  808. *UseLocalHack = FALSE;
  809. if ( LsaIGetCallInfo( &CallInfo ) )
  810. {
  811. if ( CallInfo.Attributes & SECPKG_CALL_RECURSIVE )
  812. {
  813. //
  814. // This problem occurs when trying to crack a name of type:
  815. // gc/dc.domain/domain. We're recursive, & trying to contact
  816. // a gc, so make some assumptions about the name.
  817. //
  818. RtlInitUnicodeString(
  819. &GCString,
  820. KDC_WSZ_GC
  821. );
  822. if (( PrincipalName->NameCount == KDC_GC_NAMEPARTS ) &&
  823. ( RtlEqualUnicodeString( &GCString, &PrincipalName->Names[0], TRUE )))
  824. {
  825. *UseLocalHack = TRUE;
  826. }
  827. else
  828. {
  829. fRet = TRUE;
  830. }
  831. }
  832. }
  833. return fRet;
  834. }
  835. //+-------------------------------------------------------------------------
  836. //
  837. // Function: KdcNormalize
  838. //
  839. // Synopsis: Takes an input name and returns the appropriate ticket
  840. // information or referral information for that name
  841. //
  842. // Effects: If the name is not local, it may call the GC
  843. //
  844. // Arguments: PrincipalName - name to normalize
  845. // PrincipalRealm - Realm that issued principal name
  846. // RequestRealm - Realm field of a KDC request
  847. // NameFlags - flags about name, may be:
  848. // KDC_NAME_CLIENT or KDC_NAME_SERVER
  849. //
  850. // Requires:
  851. //
  852. // Returns:
  853. //
  854. // Notes:
  855. //
  856. //
  857. //--------------------------------------------------------------------------
  858. KERBERR
  859. KdcNormalize(
  860. IN PKERB_INTERNAL_NAME PrincipalName,
  861. IN OPTIONAL PUNICODE_STRING PrincipalRealm,
  862. IN OPTIONAL PUNICODE_STRING RequestRealm,
  863. IN OPTIONAL PUNICODE_STRING TgtClientRealm,
  864. IN ULONG NameFlags,
  865. IN BOOLEAN bRestrictUserAccounts,
  866. OUT PBOOLEAN Referral,
  867. OUT PUNICODE_STRING RealmName,
  868. OUT PKDC_TICKET_INFO TicketInfo,
  869. OUT PKERB_EXT_ERROR pExtendedError,
  870. OUT OPTIONAL SAMPR_HANDLE * UserHandle,
  871. IN OPTIONAL ULONG WhichFields,
  872. IN OPTIONAL ULONG ExtendedFields,
  873. OUT OPTIONAL PUSER_INTERNAL6_INFORMATION * UserInfo,
  874. OUT OPTIONAL PSID_AND_ATTRIBUTES_LIST GroupMembership
  875. )
  876. {
  877. KERBERR KerbErr = KDC_ERR_NONE;
  878. BOOLEAN BuildUpn = FALSE;
  879. BOOLEAN CheckUpn = FALSE;
  880. BOOLEAN CheckSam = FALSE;
  881. BOOLEAN CheckGC = FALSE;
  882. BOOLEAN Reparse = FALSE;
  883. BOOLEAN DoLocalHack = FALSE;
  884. BOOLEAN Authoritative = TRUE;
  885. BOOLEAN CheckForInterDomain = FALSE;
  886. BOOLEAN ExactMatch = FALSE;
  887. BOOLEAN CrossForest = FALSE;
  888. BOOLEAN CheckForCrossForestTgt = FALSE;
  889. UNICODE_STRING OutputPrincipal = {0};
  890. UNICODE_STRING OutputRealm = {0};
  891. UNICODE_STRING InputName = {0};
  892. ULONG Index;
  893. UNICODE_STRING LocalPrincipalName = {0};
  894. UNICODE_STRING Upn = {0};
  895. TRACE(KDC, KdcNormalize, DEB_FUNCTION);
  896. *Referral = FALSE;
  897. if (!ARGUMENT_PRESENT(PrincipalName))
  898. {
  899. DebugLog((DEB_ERROR, "KdcNormalize: Null PrincipalName. Failing\n"));
  900. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  901. goto Cleanup;
  902. }
  903. //
  904. // Make sure the name is not zero length
  905. //
  906. if ((PrincipalName->NameCount == 0) ||
  907. (PrincipalName->Names[0].Length == 0))
  908. {
  909. DebugLog((DEB_ERROR, "KdcNormalize trying to crack zero length name. failing\n"));
  910. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  911. goto Cleanup;
  912. }
  913. D_DebugLog((DEB_T_PAPI, "KdcNormalize [entering] normalizing name, WhichFields %#x, ExtendedFields %#x, PrincipalName ", WhichFields, ExtendedFields));
  914. D_KerbPrintKdcName((DEB_T_PAPI, PrincipalName));
  915. //
  916. // Check if we should look at the GC
  917. //
  918. if ((NameFlags & KDC_NAME_CHECK_GC) != 0)
  919. {
  920. CheckGC = TRUE;
  921. }
  922. switch(PrincipalName->NameType)
  923. {
  924. //
  925. //
  926. // We shouldn't see these types, ever !
  927. //
  928. case KRB_NT_PRINCIPAL_AND_ID:
  929. case KRB_NT_SRV_INST_AND_ID:
  930. //
  931. // Get the sid from the name
  932. //
  933. DsysAssert(FALSE); // these shouldn't be used anymore....
  934. default:
  935. case KRB_NT_UNKNOWN:
  936. //
  937. // Drop through to more interesting name types
  938. //
  939. case KRB_NT_SRV_HST:
  940. case KRB_NT_SRV_INST:
  941. case KRB_NT_PRINCIPAL:
  942. //
  943. // Principal names are just sam names
  944. //
  945. if (PrincipalName->NameCount == 1)
  946. {
  947. //
  948. // If the client supplied our realm name, check SAM - otherwise just
  949. // check for a UPN
  950. //
  951. if (SecData.IsOurRealm(RequestRealm))
  952. {
  953. D_DebugLog((DEB_TRACE, "KdcNormalize checking sam for request realm %wZ\n", RequestRealm));
  954. CheckSam = TRUE;
  955. }
  956. //
  957. // If we don't find it in SAM, build a UPN and look it up.
  958. //
  959. CheckUpn = TRUE;
  960. BuildUpn = TRUE;
  961. OutputPrincipal = PrincipalName->Names[0];
  962. if (ARGUMENT_PRESENT(RequestRealm))
  963. {
  964. OutputRealm = *RequestRealm;
  965. }
  966. else
  967. {
  968. OutputRealm = *SecData.KdcDnsRealmName();
  969. }
  970. break;
  971. }
  972. //
  973. // Drop through
  974. //
  975. //
  976. // Check to see if these are the 'krbtgt' account
  977. //
  978. if ((PrincipalName->NameCount == 2) &&
  979. RtlEqualUnicodeString(
  980. &PrincipalName->Names[0],
  981. SecData.KdcServiceName(),
  982. TRUE)) // case insensitive
  983. {
  984. //
  985. // Check if this is for a different domain - if it is for our
  986. // domain but the principal domain is different, swap the
  987. // domain name.
  988. //
  989. if (ARGUMENT_PRESENT(PrincipalRealm) &&
  990. SecData.IsOurRealm(
  991. &PrincipalName->Names[1]))
  992. {
  993. OutputRealm = *PrincipalRealm;
  994. }
  995. else
  996. {
  997. OutputRealm = PrincipalName->Names[1];
  998. }
  999. //
  1000. // Strip trailing "."
  1001. //
  1002. if ((OutputRealm.Length > 0) &&
  1003. (OutputRealm.Buffer[-1 + OutputRealm.Length/sizeof(WCHAR)] == L'.'))
  1004. {
  1005. OutputRealm.Length -= sizeof(WCHAR);
  1006. }
  1007. if (!SecData.IsOurRealm(
  1008. &OutputRealm
  1009. ))
  1010. {
  1011. CheckForInterDomain = TRUE;
  1012. //
  1013. // Some krbtgt names may be the result of going cross forest.
  1014. // We may not generate the proper SPN in this case, because
  1015. // we'll naturally check it as krbtgt/otherdomain@ourdomain.
  1016. // If we're referring outside of our trust knowledge, this will
  1017. // fail, so just use the SPN alone.
  1018. //
  1019. CheckForCrossForestTgt = TRUE;
  1020. }
  1021. else
  1022. {
  1023. CheckSam = TRUE;
  1024. }
  1025. OutputPrincipal = PrincipalName->Names[0];
  1026. break;
  1027. }
  1028. //
  1029. // Drop through
  1030. //
  1031. case KRB_NT_SRV_XHST:
  1032. //
  1033. // These names can't be SAM names ( SAM doesn't support this name
  1034. // type) and can't be interdomain (or it would have be caught up
  1035. // above).
  1036. //
  1037. // Check this name as a upn/spn.
  1038. //
  1039. CheckUpn = TRUE;
  1040. BuildUpn = TRUE;
  1041. break;
  1042. case KRB_NT_ENT_PRINCIPAL_AND_ID:
  1043. //
  1044. // Get the sid from the name
  1045. //
  1046. DsysAssert(FALSE); // these shouldn't be used anymore....
  1047. case KRB_NT_ENTERPRISE_PRINCIPAL:
  1048. if (PrincipalName->NameCount != 1)
  1049. {
  1050. DebugLog((DEB_ERROR, "KdcNormalize enterprise name with more than one name part!\n"));
  1051. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  1052. break;
  1053. }
  1054. OutputPrincipal = PrincipalName->Names[0];
  1055. CheckUpn = TRUE;
  1056. //
  1057. // If the name wasn't found as a UPN/SPN, reparse and try
  1058. // in SAM
  1059. //
  1060. InputName = PrincipalName->Names[0];
  1061. Reparse = TRUE;
  1062. CheckSam = TRUE;
  1063. //
  1064. // Check for these on the GC
  1065. //
  1066. OutputRealm = *SecData.KdcDnsRealmName();
  1067. break;
  1068. case KRB_NT_MS_PRINCIPAL_AND_ID:
  1069. //
  1070. // Get the sid from the name
  1071. //
  1072. DsysAssert(FALSE); // these shouldn't be used anymore....
  1073. case KRB_NT_MS_PRINCIPAL:
  1074. //
  1075. // These are domainname \ username names
  1076. //
  1077. if (PrincipalName->NameCount > 2)
  1078. {
  1079. DebugLog((DEB_ERROR, "KdcNormalize MS principal has more than two name parts:"));
  1080. KerbPrintKdcName(DEB_ERROR, PrincipalName);
  1081. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  1082. goto Cleanup;
  1083. }
  1084. //
  1085. // Never check the GC for these names
  1086. //
  1087. CheckGC = FALSE;
  1088. //
  1089. // If there are two names, the first one is the principal, the second
  1090. // is the realm
  1091. //
  1092. if (PrincipalName->NameCount == 2)
  1093. {
  1094. DebugLog((DEB_WARN, "KdcNormalize client sent 2-part MS principalname!\n"));
  1095. OutputPrincipal = PrincipalName->Names[0];
  1096. OutputRealm = PrincipalName->Names[1];
  1097. //
  1098. // Strip trailing "."
  1099. //
  1100. if ((OutputRealm.Length > 0) &&
  1101. (OutputRealm.Buffer[-1 + OutputRealm.Length/sizeof(WCHAR)] == L'.'))
  1102. {
  1103. OutputRealm.Length -= sizeof(WCHAR);
  1104. }
  1105. }
  1106. else
  1107. {
  1108. InputName = PrincipalName->Names[0];
  1109. Reparse = TRUE;
  1110. }
  1111. break;
  1112. case KRB_NT_UID:
  1113. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  1114. DebugLog((DEB_WARN, "KdcNormalize unsupported name type: %d\n", PrincipalName->NameType));
  1115. goto Cleanup;
  1116. }
  1117. //
  1118. // Determine our recursion state - we shouldn't be tanking
  1119. //
  1120. if (KdcRecursing( PrincipalName, &DoLocalHack ))
  1121. {
  1122. D_DebugLog((DEB_ERROR, "Recursing :\n"));
  1123. D_KerbPrintKdcName((DEB_ERROR, PrincipalName));
  1124. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  1125. goto Cleanup;
  1126. }
  1127. #if DBG
  1128. if ( DoLocalHack )
  1129. {
  1130. DebugLog((DEB_ERROR, "Doing Local hack\n"));
  1131. }
  1132. #endif
  1133. //
  1134. // If we are supposed to reparse, then the name contains a name that we
  1135. // have to process. Look for '@' and '\' separators.
  1136. //
  1137. if (Reparse)
  1138. {
  1139. DsysAssert(InputName.Length > 0);
  1140. //
  1141. // Find the first backslash or '@', or '.' in the name
  1142. //
  1143. for (Index = InputName.Length/sizeof(WCHAR) - 1; Index > 0 ; Index-- )
  1144. {
  1145. if ((InputName.Buffer[Index] == L'\\') ||
  1146. (InputName.Buffer[Index] == L'@'))
  1147. {
  1148. break;
  1149. }
  1150. }
  1151. //
  1152. // If the name did not have one of those two separators, it
  1153. // must have been of the form "name"
  1154. //
  1155. if (Index == 0)
  1156. {
  1157. OutputRealm = *SecData.KdcDnsRealmName();
  1158. OutputPrincipal = InputName;
  1159. //
  1160. // Lookup this name in SAM.
  1161. //
  1162. CheckSam = TRUE;
  1163. }
  1164. else
  1165. {
  1166. //
  1167. // The name had a '\' or an '@', so pick appart the two
  1168. // pieces.
  1169. //
  1170. //
  1171. // If the separator was an '@' then the second part of the name
  1172. // is the realm. If it was an '\' then the first part is the
  1173. // realm.
  1174. //
  1175. if (InputName.Buffer[Index] == L'@')
  1176. {
  1177. OutputPrincipal = InputName;
  1178. OutputPrincipal.Length = (USHORT) Index * sizeof(WCHAR);
  1179. OutputPrincipal.MaximumLength = (USHORT) Index * sizeof(WCHAR);
  1180. OutputRealm.Buffer = &InputName.Buffer[Index+1];
  1181. OutputRealm.Length = (USHORT) (InputName.Length - (Index + 1) * sizeof(WCHAR));
  1182. OutputRealm.MaximumLength = OutputRealm.Length;
  1183. //
  1184. // Strip off a trailing '.'
  1185. //
  1186. if ((OutputRealm.Length > 0) &&
  1187. (OutputRealm.Buffer[-1 + OutputRealm.Length/sizeof(WCHAR)] == L'.'))
  1188. {
  1189. OutputRealm.Length -= sizeof(WCHAR);
  1190. }
  1191. }
  1192. else
  1193. {
  1194. DsysAssert(InputName.Buffer[Index] == L'\\');
  1195. OutputRealm = InputName;
  1196. OutputRealm.Length = (USHORT) Index * sizeof(WCHAR);
  1197. OutputRealm.MaximumLength = (USHORT) Index * sizeof(WCHAR);
  1198. OutputPrincipal.Buffer = &InputName.Buffer[Index+1];
  1199. OutputPrincipal.Length = (USHORT) (InputName.Length - (Index + 1) * sizeof(WCHAR));
  1200. OutputPrincipal.MaximumLength = OutputPrincipal.Length;
  1201. }
  1202. }
  1203. if ((OutputRealm.Length > 0) &&
  1204. (OutputRealm.Buffer[-1 + OutputRealm.Length/sizeof(WCHAR)] == L'.'))
  1205. {
  1206. OutputRealm.Length -= sizeof(WCHAR);
  1207. }
  1208. //
  1209. // If the domain portion is not for our domain, don't check sam
  1210. //
  1211. if (!SecData.IsOurRealm(
  1212. &OutputRealm
  1213. ))
  1214. {
  1215. CheckForInterDomain = TRUE;
  1216. CheckSam = FALSE;
  1217. }
  1218. else
  1219. {
  1220. //
  1221. // If we don't have a separate realm for the name,
  1222. // check for interdomain. This is because cross-realm
  1223. // requests have our own realm name in the name but
  1224. // another realm name in the domain.
  1225. //
  1226. if (RtlEqualUnicodeString(
  1227. &OutputPrincipal,
  1228. SecData.KdcServiceName(),
  1229. TRUE
  1230. ))
  1231. {
  1232. if (ARGUMENT_PRESENT(PrincipalRealm))
  1233. {
  1234. //
  1235. // Try the supplied realm. If it is present, and points
  1236. // to a different domain, lookup up interdomain
  1237. //
  1238. OutputRealm = *PrincipalRealm;
  1239. if (!SecData.IsOurRealm(
  1240. &OutputRealm
  1241. ))
  1242. {
  1243. CheckForInterDomain = TRUE;
  1244. CheckSam = FALSE;
  1245. }
  1246. else
  1247. {
  1248. CheckSam = TRUE;
  1249. }
  1250. }
  1251. else
  1252. {
  1253. CheckSam = TRUE;
  1254. }
  1255. }
  1256. else
  1257. {
  1258. CheckSam = TRUE;
  1259. }
  1260. }
  1261. }
  1262. // We could end up with CheckUpn and BuildUpn with both client names
  1263. // and spns. We need to allow spns of the type
  1264. // service/hostname to be looked up in sam (without appending an @realm
  1265. // to it). If KDC_NAME_SERVER is passed, it must be an spn, so, we
  1266. // don't add the @realm
  1267. if (CheckUpn)
  1268. {
  1269. D_DebugLog((DEB_T_TICKETS, "KdcNormalize checking UPN\n"));
  1270. if (BuildUpn && ((NameFlags & KDC_NAME_SERVER) == 0))
  1271. {
  1272. D_DebugLog((DEB_T_TICKETS, "KdcNormalize building UPN\n"));
  1273. KerbErr = KerbConvertKdcNameToString(
  1274. &Upn,
  1275. PrincipalName,
  1276. ARGUMENT_PRESENT(RequestRealm) ? RequestRealm : SecData.KdcDnsRealmName()
  1277. );
  1278. }
  1279. else
  1280. {
  1281. KerbErr = KerbConvertKdcNameToString(
  1282. &Upn,
  1283. PrincipalName,
  1284. NULL // no realm name
  1285. );
  1286. }
  1287. if (!KERB_SUCCESS(KerbErr))
  1288. {
  1289. goto Cleanup;
  1290. }
  1291. D_DebugLog((DEB_T_TICKETS, "KdcNormalize Lookup up upn/spn %wZ\n", &Upn));
  1292. KerbErr = KdcGetTicketInfo(
  1293. &Upn,
  1294. (NameFlags & KDC_NAME_SERVER) ? SAM_OPEN_BY_SPN : SAM_OPEN_BY_UPN,
  1295. bRestrictUserAccounts,
  1296. NULL, // no principal name
  1297. NULL, // no realm name,
  1298. TicketInfo,
  1299. pExtendedError,
  1300. UserHandle,
  1301. WhichFields,
  1302. ExtendedFields,
  1303. UserInfo,
  1304. GroupMembership
  1305. );
  1306. if (KERB_SUCCESS(KerbErr))
  1307. {
  1308. goto Cleanup;
  1309. }
  1310. //
  1311. // Some errors aren't recoverable
  1312. //
  1313. if ((KerbErr == KDC_ERR_MUST_USE_USER2USER) ||
  1314. (KerbErr == KDC_ERR_SVC_UNAVAILABLE))
  1315. {
  1316. goto Cleanup;
  1317. }
  1318. }
  1319. //
  1320. // Next check for sam account names, as some of these may later be looked
  1321. // up as UPNs
  1322. //
  1323. if (CheckSam)
  1324. {
  1325. D_DebugLog((DEB_T_TICKETS, "KdcNormalize checking name in SAM\n"));
  1326. KerbErr = KdcGetTicketInfo(
  1327. &OutputPrincipal,
  1328. 0, // no lookup flags means sam name
  1329. bRestrictUserAccounts,
  1330. NULL, // no principal name
  1331. NULL, // no realm name,
  1332. TicketInfo,
  1333. pExtendedError,
  1334. UserHandle,
  1335. WhichFields,
  1336. ExtendedFields,
  1337. UserInfo,
  1338. GroupMembership
  1339. );
  1340. if (KERB_SUCCESS(KerbErr))
  1341. {
  1342. goto Cleanup;
  1343. }
  1344. //
  1345. // Some errors aren't recoverable
  1346. //
  1347. if ((KerbErr == KDC_ERR_MUST_USE_USER2USER) ||
  1348. (KerbErr == KDC_ERR_SVC_UNAVAILABLE))
  1349. {
  1350. goto Cleanup;
  1351. }
  1352. }
  1353. //
  1354. // Now, depending on which flags are set, try to do different things.
  1355. //
  1356. if (CheckForInterDomain)
  1357. {
  1358. D_DebugLog((DEB_T_TICKETS, "KdcNormalize checking name interdomain\n"));
  1359. //
  1360. // If the target name is not KRBTGT, this must be a referral.
  1361. //
  1362. if (!RtlEqualUnicodeString(
  1363. &OutputPrincipal,
  1364. SecData.KdcServiceName(),
  1365. TRUE)) // case insensitive
  1366. {
  1367. *Referral = TRUE;
  1368. }
  1369. if ((NameFlags & KDC_NAME_FOLLOW_REFERRALS) == 0)
  1370. {
  1371. //
  1372. // We need an exact match on the domain name
  1373. //
  1374. if (*Referral)
  1375. {
  1376. DebugLog((DEB_ERROR, "KdcNormalize client asked for principal in another realm but no referrals!\n"));
  1377. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  1378. goto Cleanup;
  1379. }
  1380. //
  1381. // We also only accept the krbtgt account name
  1382. //
  1383. ExactMatch = TRUE;
  1384. }
  1385. KerbErr = KdcFindReferralTarget(
  1386. TicketInfo,
  1387. RealmName,
  1388. pExtendedError,
  1389. &OutputRealm,
  1390. ExactMatch,
  1391. NameFlags
  1392. );
  1393. if (KERB_SUCCESS(KerbErr))
  1394. {
  1395. //
  1396. // Hmmm. If the TGT's client isn't from our realm, and we picked up
  1397. // a non-transitive trust, then this is the wrong path to take.
  1398. // Toss this info, and continue to see if we can go through
  1399. // an xforest routing hint.
  1400. //
  1401. if (ARGUMENT_PRESENT( TgtClientRealm ) && !SecData.IsOurRealm( TgtClientRealm ) &&
  1402. ((TicketInfo->fTicketOpts & AUTH_REQ_TRANSITIVE_TRUST) == 0))
  1403. {
  1404. DebugLog((DEB_ERROR, "Client outside of our realm is attempting to transit\n"));
  1405. DebugLog((DEB_ERROR, "Trying xforest?\n"));
  1406. FreeTicketInfo( TicketInfo );
  1407. KerbFreeString( RealmName );
  1408. }
  1409. else
  1410. {
  1411. //
  1412. // If the output realm & the realm we asked for is different,
  1413. // this is a referral (meaning an we don't have a password
  1414. // for the principal name on this machine)
  1415. //
  1416. if (!KerbCompareUnicodeRealmNames(
  1417. RealmName,
  1418. &OutputRealm
  1419. ))
  1420. {
  1421. *Referral = TRUE;
  1422. }
  1423. goto Cleanup;
  1424. }
  1425. }
  1426. }
  1427. if (CheckGC)
  1428. {
  1429. //
  1430. // If the caller doesn't want us to follow referrals, fail here.
  1431. //
  1432. if ((NameFlags & KDC_NAME_FOLLOW_REFERRALS) == 0)
  1433. {
  1434. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  1435. goto Cleanup;
  1436. }
  1437. if (Upn.Buffer == NULL )
  1438. {
  1439. //
  1440. // Build the UPN here. No reason to build it for tgt accounts.
  1441. //
  1442. if (!CheckForCrossForestTgt)
  1443. {
  1444. KerbErr = KerbConvertKdcNameToString(
  1445. &Upn,
  1446. PrincipalName,
  1447. ARGUMENT_PRESENT(RequestRealm) ? RequestRealm : SecData.KdcDnsRealmName()
  1448. );
  1449. }
  1450. else
  1451. {
  1452. KerbErr = KerbConvertKdcNameToString(
  1453. &Upn,
  1454. PrincipalName,
  1455. NULL // no realm name
  1456. );
  1457. }
  1458. D_DebugLog((DEB_T_TICKETS, "KdcNormalize building UPN\n"));
  1459. if (!KERB_SUCCESS(KerbErr))
  1460. {
  1461. goto Cleanup;
  1462. }
  1463. }
  1464. DsysAssert(Upn.Buffer != NULL);
  1465. D_DebugLog((DEB_T_TICKETS, "KdcNormalize checking name %wZ in GC\n", &Upn));
  1466. //
  1467. // This will allow us to open sam locally as well
  1468. //
  1469. KerbErr = KdcCrackNameAtGC(
  1470. &Upn,
  1471. PrincipalName,
  1472. NameFlags,
  1473. bRestrictUserAccounts,
  1474. DoLocalHack,
  1475. RealmName,
  1476. TicketInfo,
  1477. &Authoritative,
  1478. Referral,
  1479. &CrossForest,
  1480. pExtendedError,
  1481. UserHandle,
  1482. WhichFields,
  1483. ExtendedFields,
  1484. UserInfo,
  1485. GroupMembership
  1486. );
  1487. if (KERB_SUCCESS( KerbErr ))
  1488. {
  1489. D_DebugLog((DEB_T_TICKETS, "Found name in GC\n"));
  1490. goto Cleanup;
  1491. }
  1492. //
  1493. // LAST CHANCE :)
  1494. //
  1495. // This could be an interdomain TGT, potentialy w/ a target outside of our
  1496. // forest. Use the crackname call to determine whether or not to
  1497. // allow the call to proceed. If so, go to our root domain.
  1498. //
  1499. if ( CheckForCrossForestTgt && !DoLocalHack )
  1500. {
  1501. D_DebugLog((DEB_T_TICKETS, "Checking XForest krbtgt\n"));
  1502. KerbErr = KdcCheckForCrossForestReferral(
  1503. TicketInfo,
  1504. RealmName,
  1505. pExtendedError,
  1506. &OutputRealm,
  1507. NameFlags
  1508. );
  1509. if (KERB_SUCCESS(KerbErr))
  1510. {
  1511. DebugLog((DEB_T_TICKETS, "KdcNormalize got referral (%wZ) destined for x forest - %wZ\n", RealmName,&OutputRealm));
  1512. *Referral = TRUE;
  1513. goto Cleanup;
  1514. }
  1515. }
  1516. }
  1517. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  1518. Cleanup:
  1519. KerbFreeString(
  1520. &Upn
  1521. );
  1522. KerbFreeString(
  1523. &LocalPrincipalName
  1524. );
  1525. if (KerbErr == KDC_ERR_C_PRINCIPAL_UNKNOWN)
  1526. {
  1527. if ((NameFlags & KDC_NAME_SERVER) != 0)
  1528. {
  1529. KerbErr = KDC_ERR_S_PRINCIPAL_UNKNOWN;
  1530. }
  1531. }
  1532. D_DebugLog((DEB_T_PAPI, "KdcNormalize returning %#x\n", KerbErr));
  1533. return (KerbErr);
  1534. }
  1535. //+---------------------------------------------------------------------------
  1536. //
  1537. // Function: GetTimeStamps
  1538. //
  1539. // Synopsis: Gets the current time and clock skew envelope.
  1540. //
  1541. // Arguments: [ptsFudge] -- (in) amount of clock skew to allow.
  1542. // [ptsNow] -- (out) the current time
  1543. // [ptsNowPlus] -- (out) the current time plus the skew.
  1544. // [ptsNowMinus] -- (out) the current time less the skew
  1545. //
  1546. // History: 4-23-93 WadeR Created
  1547. //
  1548. //----------------------------------------------------------------------------
  1549. void
  1550. GetTimeStamps( IN PLARGE_INTEGER ptsFudge,
  1551. OUT PLARGE_INTEGER ptsNow,
  1552. OUT PLARGE_INTEGER ptsNowPlus,
  1553. OUT PLARGE_INTEGER ptsNowMinus )
  1554. {
  1555. TRACE(KDC, GetTimeStamps, DEB_FUNCTION);
  1556. GetSystemTimeAsFileTime((PFILETIME) ptsNow );
  1557. ptsNowPlus->QuadPart = ptsNow->QuadPart + ptsFudge->QuadPart;
  1558. ptsNowMinus->QuadPart = ptsNow->QuadPart - ptsFudge->QuadPart;
  1559. }
  1560. //+-------------------------------------------------------------------------
  1561. //
  1562. // Function: KdcBuildTicketTimesAndFlags
  1563. //
  1564. // Synopsis: Computes the times and flags for a new ticket
  1565. //
  1566. // Effects:
  1567. //
  1568. // Arguments:
  1569. //
  1570. // Requires:
  1571. //
  1572. // Returns:
  1573. //
  1574. // Notes:
  1575. //
  1576. //
  1577. //--------------------------------------------------------------------------
  1578. KERBERR
  1579. KdcBuildTicketTimesAndFlags(
  1580. IN ULONG ClientPolicyFlags,
  1581. IN ULONG ServerPolicyFlags,
  1582. IN PLARGE_INTEGER DomainTicketLifespan,
  1583. IN PLARGE_INTEGER DomainTicketRenewspan,
  1584. IN OPTIONAL PKDC_S4U_TICKET_INFO S4UTicketInfo,
  1585. IN OPTIONAL PLARGE_INTEGER LogoffTime,
  1586. IN OPTIONAL PLARGE_INTEGER AccountExpiry,
  1587. IN PKERB_KDC_REQUEST_BODY RequestBody,
  1588. IN OPTIONAL PKERB_ENCRYPTED_TICKET SourceTicket,
  1589. IN OUT PKERB_ENCRYPTED_TICKET Ticket,
  1590. IN OUT OPTIONAL PKERB_EXT_ERROR ExtendedError
  1591. )
  1592. {
  1593. KERBERR KerbErr = KDC_ERR_NONE;
  1594. LARGE_INTEGER RequestEndTime;
  1595. LARGE_INTEGER RequestStartTime;
  1596. LARGE_INTEGER RequestRenewTime;
  1597. LARGE_INTEGER SourceEndTime;
  1598. LARGE_INTEGER SourceRenewTime;
  1599. LARGE_INTEGER SourceStartTime;
  1600. ULONG SourceTicketFlags = 0;
  1601. ULONG FinalTicketFlags = 0;
  1602. ULONG KdcOptions = 0;
  1603. LARGE_INTEGER FinalEndTime;
  1604. LARGE_INTEGER FinalStartTime;
  1605. LARGE_INTEGER FinalRenewTime;
  1606. LARGE_INTEGER LocalLogoffTime;
  1607. BOOLEAN Renewable = FALSE;
  1608. LARGE_INTEGER CurrentTime;
  1609. TRACE(KDC, KdcBuildTicketTimesAndFlags, DEB_FUNCTION);
  1610. GetSystemTimeAsFileTime((PFILETIME)&CurrentTime);
  1611. FinalEndTime.QuadPart = 0;
  1612. FinalStartTime.QuadPart = 0;
  1613. FinalRenewTime.QuadPart = 0;
  1614. KdcOptions = KerbConvertFlagsToUlong(&RequestBody->kdc_options);
  1615. D_DebugLog((DEB_T_TICKETS, "KdcBuildTicketTimesAndFlags ClientPolicyFlags %#x, ServerPolicyFlags %#x, KdcOptions %#x\n",
  1616. ClientPolicyFlags, ServerPolicyFlags, KdcOptions));
  1617. //
  1618. // Get the force logoff time
  1619. //
  1620. if (ARGUMENT_PRESENT(LogoffTime))
  1621. {
  1622. LocalLogoffTime = *LogoffTime;
  1623. }
  1624. else
  1625. {
  1626. LocalLogoffTime = tsInfinity;
  1627. }
  1628. //
  1629. // Get the request times out of the request
  1630. //
  1631. if (RequestBody->bit_mask & KERB_KDC_REQUEST_BODY_starttime_present)
  1632. {
  1633. KerbConvertGeneralizedTimeToLargeInt(
  1634. &RequestStartTime,
  1635. &RequestBody->KERB_KDC_REQUEST_BODY_starttime,
  1636. NULL
  1637. );
  1638. }
  1639. else
  1640. {
  1641. RequestStartTime.QuadPart = 0;
  1642. }
  1643. KerbConvertGeneralizedTimeToLargeInt(
  1644. &RequestEndTime,
  1645. &RequestBody->endtime,
  1646. NULL
  1647. );
  1648. if (RequestBody->bit_mask & KERB_KDC_REQUEST_BODY_renew_until_present)
  1649. {
  1650. KerbConvertGeneralizedTimeToLargeInt(
  1651. &RequestRenewTime,
  1652. &RequestBody->KERB_KDC_REQUEST_BODY_renew_until,
  1653. NULL
  1654. );
  1655. }
  1656. else
  1657. {
  1658. RequestRenewTime.QuadPart = 0;
  1659. }
  1660. //
  1661. // Get the times out of the source ticket (if present)
  1662. //
  1663. if (ARGUMENT_PRESENT(SourceTicket))
  1664. {
  1665. if (SourceTicket->bit_mask & KERB_ENCRYPTED_TICKET_starttime_present)
  1666. {
  1667. KerbConvertGeneralizedTimeToLargeInt(
  1668. &SourceStartTime,
  1669. &SourceTicket->KERB_ENCRYPTED_TICKET_starttime,
  1670. NULL
  1671. );
  1672. }
  1673. else
  1674. {
  1675. SourceStartTime.QuadPart = 0;
  1676. }
  1677. KerbConvertGeneralizedTimeToLargeInt(
  1678. &SourceEndTime,
  1679. &SourceTicket->endtime,
  1680. NULL
  1681. );
  1682. if (SourceTicket->bit_mask & KERB_ENCRYPTED_TICKET_renew_until_present)
  1683. {
  1684. KerbConvertGeneralizedTimeToLargeInt(
  1685. &SourceRenewTime,
  1686. &SourceTicket->KERB_ENCRYPTED_TICKET_renew_until,
  1687. NULL
  1688. );
  1689. }
  1690. else
  1691. {
  1692. SourceRenewTime.QuadPart = 0;
  1693. }
  1694. SourceTicketFlags = KerbConvertFlagsToUlong(&SourceTicket->flags);
  1695. D_DebugLog((DEB_T_TICKETS, "KdcBuildTicketTimesAndFlags SourceTicketFlags %#x\n", SourceTicketFlags));
  1696. }
  1697. else
  1698. {
  1699. //
  1700. // Set the maximums in this case, which is probably an AS request.
  1701. //
  1702. SourceStartTime = CurrentTime;
  1703. SourceEndTime = tsInfinity;
  1704. SourceRenewTime = tsInfinity;
  1705. SourceTicketFlags = 0;
  1706. //
  1707. // Fill in the source flags from what the client policy & domain policy
  1708. // allow
  1709. //
  1710. if ((ClientPolicyFlags & AUTH_REQ_ALLOW_FORWARDABLE) != 0)
  1711. {
  1712. SourceTicketFlags |= KERB_TICKET_FLAGS_forwardable;
  1713. }
  1714. if ((ClientPolicyFlags & AUTH_REQ_ALLOW_PROXIABLE) != 0)
  1715. {
  1716. SourceTicketFlags |= KERB_TICKET_FLAGS_proxiable;
  1717. }
  1718. if ((ClientPolicyFlags & AUTH_REQ_ALLOW_POSTDATE) != 0)
  1719. {
  1720. SourceTicketFlags |= KERB_TICKET_FLAGS_may_postdate;
  1721. }
  1722. if ((ClientPolicyFlags & AUTH_REQ_ALLOW_RENEWABLE) != 0)
  1723. {
  1724. SourceTicketFlags |= KERB_TICKET_FLAGS_renewable;
  1725. }
  1726. D_DebugLog((DEB_T_TICKETS, "KdcBuildTicketTimesAndFlags SourceTicketFlags %#x by ClientPolicyFlags\n", SourceTicketFlags));
  1727. }
  1728. //
  1729. // Start computing the flags, from algorithm in RFC1510 appendix A.6
  1730. //
  1731. //
  1732. // Delegation flags
  1733. //
  1734. if ((ServerPolicyFlags & AUTH_REQ_OK_AS_DELEGATE) != 0)
  1735. {
  1736. FinalTicketFlags |= KERB_TICKET_FLAGS_ok_as_delegate;
  1737. }
  1738. //
  1739. // Forward flags
  1740. //
  1741. if (KdcOptions & KERB_KDC_OPTIONS_forwardable)
  1742. {
  1743. if ((SourceTicketFlags & KERB_TICKET_FLAGS_forwardable) &&
  1744. (ServerPolicyFlags & AUTH_REQ_ALLOW_FORWARDABLE))
  1745. {
  1746. FinalTicketFlags |= KERB_TICKET_FLAGS_forwardable;
  1747. }
  1748. else
  1749. {
  1750. DebugLog((DEB_ERROR, "Asked for forwardable but not allowed\n"));
  1751. // KerbErr = KDC_ERR_BADOPTION;
  1752. // goto Cleanup;
  1753. }
  1754. }
  1755. if (KdcOptions & KERB_KDC_OPTIONS_forwarded)
  1756. {
  1757. if (( KdcIssueForwardedTickets ) &&
  1758. ( SourceTicketFlags & KERB_TICKET_FLAGS_forwardable ) &&
  1759. ( ServerPolicyFlags & AUTH_REQ_ALLOW_FORWARDABLE ))
  1760. {
  1761. FinalTicketFlags |= KERB_TICKET_FLAGS_forwarded;
  1762. }
  1763. else
  1764. {
  1765. DebugLog((DEB_ERROR, "Asked for forwarded but not allowed\n"));
  1766. if ( !KdcIssueForwardedTickets )
  1767. {
  1768. DebugLog((DEB_TRACE, "Forwarded protection ON\n"));
  1769. }
  1770. KerbErr = KDC_ERR_BADOPTION;
  1771. goto Cleanup;
  1772. }
  1773. }
  1774. if (SourceTicketFlags & KERB_TICKET_FLAGS_forwarded)
  1775. {
  1776. FinalTicketFlags |= KERB_TICKET_FLAGS_forwarded;
  1777. }
  1778. //
  1779. // preauth flags
  1780. //
  1781. if (SourceTicketFlags & KERB_TICKET_FLAGS_pre_authent)
  1782. {
  1783. FinalTicketFlags |= KERB_TICKET_FLAGS_pre_authent;
  1784. }
  1785. //
  1786. // Proxy flags
  1787. //
  1788. if (KdcOptions & KERB_KDC_OPTIONS_proxiable)
  1789. {
  1790. if ((SourceTicketFlags & KERB_TICKET_FLAGS_proxiable) &&
  1791. (ServerPolicyFlags & AUTH_REQ_ALLOW_PROXIABLE))
  1792. {
  1793. FinalTicketFlags |= KERB_TICKET_FLAGS_proxiable;
  1794. }
  1795. else
  1796. {
  1797. DebugLog((DEB_ERROR, "Asked for proxiable but not allowed\n"));
  1798. // KerbErr = KDC_ERR_BADOPTION;
  1799. // goto Cleanup;
  1800. }
  1801. }
  1802. if (KdcOptions & KERB_KDC_OPTIONS_proxy)
  1803. {
  1804. if ((SourceTicketFlags & KERB_TICKET_FLAGS_proxiable) &&
  1805. (ServerPolicyFlags & AUTH_REQ_ALLOW_PROXIABLE))
  1806. {
  1807. FinalTicketFlags |= KERB_TICKET_FLAGS_proxy;
  1808. }
  1809. else
  1810. {
  1811. DebugLog((DEB_ERROR, "Asked for proxy but not allowed\n"));
  1812. KerbErr = KDC_ERR_BADOPTION;
  1813. goto Cleanup;
  1814. }
  1815. }
  1816. //
  1817. // Postdate
  1818. //
  1819. if (KdcOptions & KERB_KDC_OPTIONS_allow_postdate)
  1820. {
  1821. if ((SourceTicketFlags & KERB_TICKET_FLAGS_may_postdate) &&
  1822. (ServerPolicyFlags & AUTH_REQ_ALLOW_POSTDATE))
  1823. {
  1824. FinalTicketFlags |= KERB_TICKET_FLAGS_may_postdate;
  1825. }
  1826. else
  1827. {
  1828. DebugLog((DEB_ERROR, "KdcBuildTicketTimesAndFlags asked for allow_postdate but not allowed: "
  1829. "KdcOptions %#x, SourceTicketFlags %#x, ServerPolicyFlags %#x\n",
  1830. KdcOptions, SourceTicketFlags, ServerPolicyFlags));
  1831. KerbErr = KDC_ERR_POLICY;
  1832. goto Cleanup;
  1833. }
  1834. }
  1835. if (KdcOptions & KERB_KDC_OPTIONS_postdated)
  1836. {
  1837. if ((SourceTicketFlags & KERB_TICKET_FLAGS_may_postdate) &&
  1838. (ServerPolicyFlags & AUTH_REQ_ALLOW_POSTDATE))
  1839. {
  1840. FinalTicketFlags |= KERB_TICKET_FLAGS_postdated | KERB_TICKET_FLAGS_invalid;
  1841. //
  1842. // Start time is required here
  1843. //
  1844. if (RequestStartTime.QuadPart == 0)
  1845. {
  1846. DebugLog((DEB_ERROR, "KdcBuildTicketTimesAndFlags asked for postdate but start time not present: "
  1847. "KdcOptions %#x, SourceTicketFlags %#x, ServerPolicyFlags %#x\n",
  1848. KdcOptions, SourceTicketFlags, ServerPolicyFlags));
  1849. KerbErr = KDC_ERR_CANNOT_POSTDATE;
  1850. goto Cleanup;
  1851. }
  1852. }
  1853. else
  1854. {
  1855. KerbErr = (SourceTicketFlags & KERB_TICKET_FLAGS_may_postdate)
  1856. ? KDC_ERR_POLICY : KDC_ERR_CANNOT_POSTDATE;
  1857. DebugLog((DEB_ERROR, "KdcBuildTicketTimesAndFlags asked for postdated but not allowed: "
  1858. "KdcOptions %#x, SourceTicketFlags %#x, ServerPolicyFlags %#x, KerbErr %#x\n",
  1859. KdcOptions, SourceTicketFlags, ServerPolicyFlags, KerbErr));
  1860. goto Cleanup;
  1861. }
  1862. }
  1863. //
  1864. // Validate
  1865. //
  1866. if (KdcOptions & KERB_KDC_OPTIONS_validate)
  1867. {
  1868. if ((SourceTicketFlags & KERB_TICKET_FLAGS_invalid) == 0)
  1869. {
  1870. DebugLog((DEB_ERROR, "Trying to validate a valid ticket\n"));
  1871. KerbErr = KDC_ERR_POLICY;
  1872. goto Cleanup;
  1873. }
  1874. if ((SourceStartTime.QuadPart == 0) ||
  1875. (SourceStartTime.QuadPart < CurrentTime.QuadPart - SkewTime.QuadPart))
  1876. {
  1877. DebugLog((DEB_ERROR, "Trying to validate a ticket before it is valid\n"));
  1878. KerbErr = KRB_AP_ERR_TKT_NYV;
  1879. goto Cleanup;
  1880. }
  1881. }
  1882. //
  1883. // Start filling in time fields
  1884. //
  1885. if (ARGUMENT_PRESENT(SourceTicket))
  1886. {
  1887. //
  1888. // For S4UProxy, we need to use the authtime from the evidence ticket.
  1889. // This ensures that the PAC_CLIENT_INFO (aka PAC verifier) remains
  1890. // constant, and correct.
  1891. //
  1892. if ( ARGUMENT_PRESENT(S4UTicketInfo) &&
  1893. ( S4UTicketInfo->Flags & TI_PRXY_REQUESTOR_THIS_REALM))
  1894. {
  1895. Ticket->authtime = S4UTicketInfo->EvidenceTicket->authtime;
  1896. }
  1897. else
  1898. {
  1899. Ticket->authtime = SourceTicket->authtime;
  1900. }
  1901. }
  1902. else
  1903. {
  1904. KerbConvertLargeIntToGeneralizedTime(
  1905. &Ticket->authtime,
  1906. NULL,
  1907. &CurrentTime
  1908. );
  1909. }
  1910. //
  1911. // The times are computed differently for renewing a ticket and for
  1912. // getting a new ticket.
  1913. //
  1914. if ((KdcOptions & KERB_KDC_OPTIONS_renew) != 0)
  1915. {
  1916. if ((SourceRenewTime.QuadPart == 0) ||
  1917. (SourceStartTime.QuadPart == 0) ||
  1918. ((SourceTicketFlags & KERB_TICKET_FLAGS_renewable) == 0) ||
  1919. ((ServerPolicyFlags & AUTH_REQ_ALLOW_RENEWABLE) == 0))
  1920. {
  1921. DebugLog((DEB_ERROR,"Trying to renew a non-renewable ticket or against policy\n"));
  1922. KerbErr = KDC_ERR_BADOPTION;
  1923. goto Cleanup;
  1924. }
  1925. //
  1926. // Make sure the renew time is in the future
  1927. //
  1928. if (SourceRenewTime.QuadPart < CurrentTime.QuadPart)
  1929. {
  1930. DebugLog((DEB_ERROR, "Trying to renew a ticket past its renew time\n"));
  1931. KerbErr = KRB_AP_ERR_TKT_EXPIRED;
  1932. goto Cleanup;
  1933. }
  1934. //
  1935. // Make sure the end time is not in the past
  1936. //
  1937. if (SourceEndTime.QuadPart < CurrentTime.QuadPart)
  1938. {
  1939. DebugLog((DEB_ERROR, "Trying to renew an expired ticket\n"));
  1940. KerbErr = KRB_AP_ERR_TKT_EXPIRED;
  1941. goto Cleanup;
  1942. }
  1943. FinalStartTime = CurrentTime;
  1944. //
  1945. // The end time is the minimum of the current time plus lifespan
  1946. // of the old ticket and the renew until time of the old ticket
  1947. //
  1948. FinalEndTime.QuadPart = CurrentTime.QuadPart + (SourceEndTime.QuadPart - SourceStartTime.QuadPart);
  1949. if (FinalEndTime.QuadPart > SourceRenewTime.QuadPart)
  1950. {
  1951. FinalEndTime = SourceRenewTime;
  1952. }
  1953. FinalRenewTime = SourceRenewTime;
  1954. FinalTicketFlags = SourceTicketFlags;
  1955. #if DBG
  1956. D_DebugLog((DEB_T_TIME, "KdcBuildTicketTimesAndFlags Renewal ticket time info\n"));
  1957. PrintTime(DEB_T_TIME, " FinalRenewTime =", &FinalRenewTime);
  1958. PrintTime(DEB_T_TIME, " FinalEndTime =", &FinalEndTime);
  1959. PrintTime(DEB_T_TIME, " SourceEndTime =", &SourceEndTime);
  1960. PrintTime(DEB_T_TIME, " SourceRenewTime =", &SourceRenewTime);
  1961. #endif
  1962. Renewable = TRUE;
  1963. }
  1964. else
  1965. {
  1966. //
  1967. // Compute start and end times for normal tickets
  1968. //
  1969. //
  1970. // Set the start time
  1971. //
  1972. if (RequestStartTime.QuadPart == 0)
  1973. {
  1974. FinalStartTime = CurrentTime;
  1975. }
  1976. else
  1977. {
  1978. FinalStartTime = RequestStartTime;
  1979. }
  1980. //
  1981. // Set the end time
  1982. //
  1983. if (RequestEndTime.QuadPart == 0)
  1984. {
  1985. FinalEndTime = tsInfinity;
  1986. }
  1987. else
  1988. {
  1989. FinalEndTime = RequestEndTime;
  1990. }
  1991. if (FinalEndTime.QuadPart > SourceEndTime.QuadPart)
  1992. {
  1993. FinalEndTime = SourceEndTime;
  1994. }
  1995. if (FinalEndTime.QuadPart > CurrentTime.QuadPart + DomainTicketLifespan->QuadPart)
  1996. {
  1997. FinalEndTime.QuadPart = CurrentTime.QuadPart + DomainTicketLifespan->QuadPart;
  1998. }
  1999. //
  2000. // Check for renewable-ok
  2001. //
  2002. if ((KdcOptions & KERB_KDC_OPTIONS_renewable_ok) &&
  2003. (FinalEndTime.QuadPart < RequestEndTime.QuadPart) &&
  2004. (SourceTicketFlags & KERB_TICKET_FLAGS_renewable))
  2005. {
  2006. KdcOptions |= KERB_KDC_OPTIONS_renewable;
  2007. RequestRenewTime = RequestEndTime;
  2008. //
  2009. // Make sure that the source ticket had a renewtime (it
  2010. // should because it is renewable)
  2011. //
  2012. DsysAssert(SourceRenewTime.QuadPart != 0);
  2013. if (RequestRenewTime.QuadPart > SourceRenewTime.QuadPart)
  2014. {
  2015. RequestRenewTime = SourceRenewTime;
  2016. }
  2017. }
  2018. }
  2019. if (!Renewable)
  2020. {
  2021. //
  2022. // Compute renew times
  2023. //
  2024. if (RequestRenewTime.QuadPart == 0)
  2025. {
  2026. RequestRenewTime = tsInfinity;
  2027. }
  2028. if ((KdcOptions & KERB_KDC_OPTIONS_renewable) &&
  2029. (SourceTicketFlags & KERB_TICKET_FLAGS_renewable) &&
  2030. (ServerPolicyFlags & AUTH_REQ_ALLOW_RENEWABLE))
  2031. {
  2032. FinalRenewTime = RequestRenewTime;
  2033. if (FinalRenewTime.QuadPart > FinalStartTime.QuadPart + DomainTicketRenewspan->QuadPart)
  2034. {
  2035. FinalRenewTime.QuadPart = FinalStartTime.QuadPart + DomainTicketRenewspan->QuadPart;
  2036. }
  2037. DsysAssert(SourceRenewTime.QuadPart != 0);
  2038. if (FinalRenewTime.QuadPart > SourceRenewTime.QuadPart)
  2039. {
  2040. FinalRenewTime = SourceRenewTime;
  2041. }
  2042. FinalTicketFlags |= KERB_TICKET_FLAGS_renewable;
  2043. }
  2044. else
  2045. {
  2046. FinalRenewTime.QuadPart = 0;
  2047. }
  2048. }
  2049. //
  2050. // more on postdating
  2051. //
  2052. if (FinalStartTime.QuadPart > CurrentTime.QuadPart + SkewTime.QuadPart)
  2053. {
  2054. if ( ! ( (FinalTicketFlags & KERB_TICKET_FLAGS_may_postdate)
  2055. && (FinalTicketFlags & KERB_TICKET_FLAGS_postdated)
  2056. && (FinalTicketFlags & KERB_TICKET_FLAGS_invalid) ) )
  2057. {
  2058. DebugLog((DEB_ERROR, "KdcBuildTicketTimesAndFlags postdate CANNOT_POSTDATE: "
  2059. "KdcOptions %#x, SourceTicketFlags %#x, SourceTicketFlags %#x, "
  2060. "FinalStartTime %#I64x, CurrentTime %#I64x, SkewTime %#I64x\n",
  2061. KdcOptions, SourceTicketFlags, ServerPolicyFlags,
  2062. FinalStartTime.QuadPart, CurrentTime.QuadPart, SkewTime.QuadPart));
  2063. KerbErr = KDC_ERR_CANNOT_POSTDATE;
  2064. }
  2065. else
  2066. {
  2067. DebugLog((DEB_ERROR, "KdcBuildTicketTimesAndFlags postdate ERR_POLICY: "
  2068. "KdcOptions %#x, SourceTicketFlags %#x, SourceTicketFlags %#x, "
  2069. "FinalStartTime %#I64x, CurrentTime %#I64x, SkewTime %#I64x\n",
  2070. KdcOptions, SourceTicketFlags, ServerPolicyFlags,
  2071. FinalStartTime.QuadPart, CurrentTime.QuadPart, SkewTime.QuadPart));
  2072. KerbErr = KDC_ERR_POLICY; // do not allow postdating
  2073. }
  2074. FILL_EXT_ERROR_EX2(ExtendedError, STATUS_TIME_DIFFERENCE_AT_DC, FILENO, __LINE__);
  2075. goto Cleanup;
  2076. }
  2077. //
  2078. // Make sure the final ticket is valid
  2079. //
  2080. if (FinalStartTime.QuadPart > FinalEndTime.QuadPart)
  2081. {
  2082. DebugLog((DEB_ERROR, "Client asked for endtime before starttime\n"));
  2083. KerbErr = KDC_ERR_NEVER_VALID;
  2084. FILL_EXT_ERROR_EX(ExtendedError, STATUS_TIME_DIFFERENCE_AT_DC, FILENO, __LINE__);
  2085. goto Cleanup;
  2086. }
  2087. //
  2088. // Incorporate the logoff time (according to logon hours) by reseting
  2089. // both the final end time and final renew time
  2090. //
  2091. if (FinalEndTime.QuadPart > LocalLogoffTime.QuadPart)
  2092. {
  2093. FinalEndTime.QuadPart = LocalLogoffTime.QuadPart;
  2094. }
  2095. if (FinalRenewTime.QuadPart > LocalLogoffTime.QuadPart)
  2096. {
  2097. FinalRenewTime.QuadPart = LocalLogoffTime.QuadPart;
  2098. }
  2099. //
  2100. // Tickets good only until acct expires.
  2101. // We make the assumption that the sam has
  2102. // already checked this against the current time
  2103. // when we're checking the logon restrictions.
  2104. //
  2105. if ((ARGUMENT_PRESENT(AccountExpiry) &&
  2106. (AccountExpiry->QuadPart != 0 )))
  2107. {
  2108. if (FinalEndTime.QuadPart > AccountExpiry->QuadPart)
  2109. {
  2110. FinalEndTime.QuadPart = AccountExpiry->QuadPart;
  2111. }
  2112. if (FinalRenewTime.QuadPart > AccountExpiry->QuadPart)
  2113. {
  2114. FinalRenewTime.QuadPart = AccountExpiry->QuadPart;
  2115. }
  2116. }
  2117. //
  2118. // Fill in the times in the ticket
  2119. //
  2120. KerbConvertLargeIntToGeneralizedTime(
  2121. &Ticket->KERB_ENCRYPTED_TICKET_starttime,
  2122. NULL,
  2123. &FinalStartTime
  2124. );
  2125. Ticket->bit_mask |= KERB_ENCRYPTED_TICKET_starttime_present;
  2126. KerbConvertLargeIntToGeneralizedTime(
  2127. &Ticket->endtime,
  2128. NULL,
  2129. &FinalEndTime
  2130. );
  2131. if (FinalRenewTime.QuadPart != 0)
  2132. {
  2133. KerbConvertLargeIntToGeneralizedTime(
  2134. &Ticket->KERB_ENCRYPTED_TICKET_renew_until,
  2135. NULL,
  2136. &FinalRenewTime
  2137. );
  2138. Ticket->bit_mask |= KERB_ENCRYPTED_TICKET_renew_until_present;
  2139. }
  2140. //
  2141. // Finally, get the remainder ticket flags, based on S4U logic, if needed.
  2142. //
  2143. // TBD: Set the right flags for proxy requests.
  2144. //
  2145. if ( ARGUMENT_PRESENT( S4UTicketInfo ) &&
  2146. (( S4UTicketInfo->Flags & TI_S4USELF_INFO ) != 0))
  2147. {
  2148. //
  2149. // If the client account is sensitive, turn off fwdable bit
  2150. //
  2151. if (( S4UTicketInfo->Flags & TI_SENSITIVE_CLIENT_ACCOUNT ) != 0)
  2152. {
  2153. FinalTicketFlags &= ~KERB_TICKET_FLAGS_forwardable;
  2154. D_DebugLog((DEB_ERROR, "S4U - Turning off fwdable flag (client restriction)\n"));
  2155. }
  2156. else if ((( S4UTicketInfo->Flags & TI_TARGET_OUR_REALM ) != 0) &&
  2157. (( ServerPolicyFlags & AUTH_REQ_ALLOW_S4U_DELEGATE ) == 0))
  2158. {
  2159. //
  2160. // If the server is in our realm, it must have T2A4D bit set.
  2161. //
  2162. FinalTicketFlags &= ~KERB_TICKET_FLAGS_forwardable;
  2163. D_DebugLog((DEB_ERROR, "S4U - Turning off fwdable flag (svr restriction)\n"));
  2164. }
  2165. }
  2166. //
  2167. // Copy in the flags
  2168. //
  2169. DsysAssert(Ticket->flags.length == sizeof(ULONG) * 8);
  2170. *((PULONG) Ticket->flags.value) = KerbConvertUlongToFlagUlong(FinalTicketFlags);
  2171. Cleanup:
  2172. #if DBG
  2173. DebugLog((DEB_T_TIME, "KdcBuildTicketTimesAndFlags Final Ticket Flags %#x, times -\n", FinalTicketFlags));
  2174. PrintTime(DEB_T_TIME, " RequestRenewTime =", &RequestRenewTime);
  2175. PrintTime(DEB_T_TIME, " RequestEndTime =", &RequestEndTime);
  2176. PrintTime(DEB_T_TIME, " RequestStartTime =", &RequestStartTime);
  2177. PrintTime(DEB_T_TIME, " FinalRenewTime =", &FinalRenewTime);
  2178. PrintTime(DEB_T_TIME, " FinalEndTime =", &FinalEndTime);
  2179. PrintTime(DEB_T_TIME, " FinalStartTime =", &FinalStartTime);
  2180. PrintTime(DEB_T_TIME, " SourceRenewTime =", &SourceRenewTime);
  2181. PrintTime(DEB_T_TIME, " SourceEndTime =", &SourceEndTime);
  2182. PrintTime(DEB_T_TIME, " SourceStartTime =", &SourceStartTime);
  2183. #endif
  2184. return(KerbErr);
  2185. }
  2186. //+-------------------------------------------------------------------------
  2187. //
  2188. // Function: KdcGetUserKeys
  2189. //
  2190. // Synopsis: retrieves user keys
  2191. //
  2192. // Effects:
  2193. //
  2194. // Arguments:
  2195. //
  2196. // Requires:
  2197. //
  2198. // Returns:
  2199. //
  2200. // Notes:
  2201. //
  2202. //
  2203. //--------------------------------------------------------------------------
  2204. KERBERR
  2205. KdcGetUserKeys(
  2206. IN SAMPR_HANDLE UserHandle,
  2207. IN PUSER_INTERNAL6_INFORMATION UserInfo,
  2208. OUT PKERB_STORED_CREDENTIAL * Passwords,
  2209. OUT PKERB_STORED_CREDENTIAL * OldPasswords,
  2210. OUT PKERB_EXT_ERROR pExtendedError
  2211. )
  2212. {
  2213. KERBERR KerbErr = KDC_ERR_NONE;
  2214. NTSTATUS Status;
  2215. PKERB_STORED_CREDENTIAL Keys = NULL;
  2216. PKERB_STORED_CREDENTIAL StoredCreds = NULL;
  2217. PKERB_STORED_CREDENTIAL Cred64 = NULL;
  2218. ULONG CredentialSize = 0;
  2219. ULONG NewCredentialCount = 0;
  2220. ULONG NewCredentialSize = 0;
  2221. ULONG Index, CredentialIndex = 0, Offset;
  2222. USHORT Flags = 0;
  2223. PUCHAR Base;
  2224. BOOLEAN UseStoredCreds = FALSE, UnMarshalledCreds = FALSE;
  2225. PCRYPTO_SYSTEM NullCryptoSystem = NULL;
  2226. BOOLEAN UseBuiltins = TRUE;
  2227. PNT_OWF_PASSWORD OldNtPassword = NULL;
  2228. PNT_OWF_PASSWORD OldNtPasswordSecond = NULL;
  2229. NT_OWF_PASSWORD OldPasswordData = {0}; // Previous password (from current)
  2230. NT_OWF_PASSWORD OldPasswordDataSecond = {0}; // Password history two previous (from current)
  2231. PUSER_ALL_INFORMATION UserAll = &UserInfo->I1;
  2232. TRACE(KDC, KdcGetUserKeys, DEB_FUNCTION);
  2233. //
  2234. // First get any primary credentials
  2235. //
  2236. Status = SamIRetrievePrimaryCredentials(
  2237. UserHandle,
  2238. &GlobalKerberosName,
  2239. (PVOID *) &StoredCreds,
  2240. &CredentialSize
  2241. );
  2242. //
  2243. // if there is not value, it's O.K we will default to using
  2244. // Builtin credentials
  2245. //
  2246. if (STATUS_DS_NO_ATTRIBUTE_OR_VALUE==Status)
  2247. {
  2248. Status = STATUS_SUCCESS;
  2249. }
  2250. if (!NT_SUCCESS(Status))
  2251. {
  2252. DebugLog((DEB_ERROR, "Failed to retrieve primary credentials: 0x%x\n",Status));
  2253. KerbErr = KRB_ERR_GENERIC;
  2254. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  2255. goto Cleanup;
  2256. }
  2257. //
  2258. // We need to unmarshall these creds from the DS
  2259. // They'll be stored in 32 bit format, but we've
  2260. // got to put them into 64 bit format.
  2261. // KerbUnpack32BitStoredCredential()
  2262. //
  2263. #ifdef _WIN64
  2264. Status = KdcUnpack32BitStoredCredential(
  2265. (PKERB_STORED_CREDENTIAL32) StoredCreds,
  2266. &Cred64,
  2267. &CredentialSize
  2268. );
  2269. if (!NT_SUCCESS(Status))
  2270. {
  2271. DebugLog((DEB_ERROR, "Failed to unpack 32bit stored credential, contact Todds - %x\n", Status));
  2272. DsysAssert(FALSE); // FATAL - If we ever fail above, contact Todds
  2273. goto Cleanup;
  2274. }
  2275. if (NULL != StoredCreds)
  2276. {
  2277. LocalFree(StoredCreds);
  2278. StoredCreds = Cred64;
  2279. UnMarshalledCreds = TRUE; // diff't allocator
  2280. }
  2281. #endif
  2282. //
  2283. // First compute the current passwords
  2284. //
  2285. //
  2286. // Figure out the size of the stored credentials
  2287. //
  2288. if ((UserAll->UserAccountControl & USER_USE_DES_KEY_ONLY) != 0)
  2289. {
  2290. UseBuiltins = FALSE;
  2291. }
  2292. if ((StoredCreds != NULL) &&
  2293. (CredentialSize > sizeof(KERB_STORED_CREDENTIAL) &&
  2294. (StoredCreds->Revision == KERB_PRIMARY_CRED_REVISION) &&
  2295. (CredentialSize > (sizeof(KERB_STORED_CREDENTIAL)
  2296. - (ANYSIZE_ARRAY * sizeof(KERB_KEY_DATA))
  2297. + StoredCreds->CredentialCount * sizeof(KERB_KEY_DATA)
  2298. ))) &&
  2299. (StoredCreds->DefaultSalt.Length + (ULONG_PTR) StoredCreds->DefaultSalt.Buffer <= CredentialSize ))
  2300. {
  2301. UseStoredCreds = TRUE;
  2302. Flags = StoredCreds->Flags;
  2303. NewCredentialSize += StoredCreds->DefaultSalt.Length;
  2304. for (Index = 0; Index < StoredCreds->CredentialCount ; Index++ )
  2305. {
  2306. //
  2307. // Validat the offsets
  2308. //
  2309. if ((StoredCreds->Credentials[Index].Key.keyvalue.length +
  2310. (ULONG_PTR) StoredCreds->Credentials[Index].Key.keyvalue.value <= CredentialSize )
  2311. &&
  2312. (StoredCreds->Credentials[Index].Salt.Length +
  2313. (ULONG_PTR) StoredCreds->Credentials[Index].Salt.Buffer <= CredentialSize ))
  2314. {
  2315. NewCredentialCount++;
  2316. NewCredentialSize += sizeof(KERB_KEY_DATA) +
  2317. StoredCreds->Credentials[Index].Key.keyvalue.length +
  2318. StoredCreds->Credentials[Index].Salt.Length;
  2319. }
  2320. else
  2321. {
  2322. LPWSTR Buff = NULL;
  2323. DebugLog((DEB_ERROR,"Corrupt credentials for user %wZ\n",
  2324. &UserAll->UserName ));
  2325. DsysAssert(FALSE);
  2326. Buff = KerbBuildNullTerminatedString(&UserAll->UserName);
  2327. if (NULL == Buff)
  2328. {
  2329. break;
  2330. }
  2331. ReportServiceEvent(
  2332. EVENTLOG_ERROR_TYPE,
  2333. KDCEVENT_CORRUPT_CREDENTIALS,
  2334. 0, // no raw data
  2335. NULL, // no raw data
  2336. 1, // number of strings
  2337. Buff
  2338. );
  2339. UseStoredCreds = FALSE;
  2340. NewCredentialCount = 0;
  2341. NewCredentialSize = 0;
  2342. if (NULL != Buff)
  2343. {
  2344. MIDL_user_free(Buff);
  2345. }
  2346. break;
  2347. }
  2348. }
  2349. }
  2350. //
  2351. // If the password length is the size of the OWF password, use it as the
  2352. // key. Otherwise hash it. This is for the case where not password is
  2353. // set.
  2354. //
  2355. if (UseBuiltins)
  2356. {
  2357. //
  2358. // Add a key for RC4_HMAC_NT
  2359. //
  2360. if (UserAll->NtPasswordPresent)
  2361. {
  2362. NewCredentialSize += sizeof(KERB_KEY_DATA) + sizeof(NT_OWF_PASSWORD);
  2363. NewCredentialCount++;
  2364. }
  2365. #ifndef DONT_SUPPORT_OLD_TYPES_KDC
  2366. //
  2367. // Add a key for RC4_HMAC_OLD & MD4_RC4
  2368. if (UserAll->NtPasswordPresent)
  2369. {
  2370. NewCredentialSize += sizeof(KERB_KEY_DATA) + sizeof(NT_OWF_PASSWORD);
  2371. NewCredentialCount++;
  2372. NewCredentialSize += sizeof(KERB_KEY_DATA) + sizeof(NT_OWF_PASSWORD);
  2373. NewCredentialCount++;
  2374. }
  2375. #endif
  2376. //
  2377. // if there is no password, treat it as blank
  2378. //
  2379. if (!(UserAll->LmPasswordPresent || UserAll->NtPasswordPresent))
  2380. {
  2381. NewCredentialSize += sizeof(KERB_KEY_DATA) + sizeof(NT_OWF_PASSWORD);
  2382. NewCredentialCount++;
  2383. }
  2384. #ifndef DONT_SUPPORT_OLD_TYPES_KDC
  2385. if (!(UserAll->LmPasswordPresent || UserAll->NtPasswordPresent))
  2386. {
  2387. NewCredentialSize += sizeof(KERB_KEY_DATA) + sizeof(NT_OWF_PASSWORD);
  2388. NewCredentialCount++;
  2389. NewCredentialSize += sizeof(KERB_KEY_DATA) + sizeof(NT_OWF_PASSWORD);
  2390. NewCredentialCount++;
  2391. }
  2392. #endif
  2393. }
  2394. //
  2395. // Add a key for the null crypto system
  2396. //
  2397. Status = CDLocateCSystem(
  2398. KERB_ETYPE_NULL,
  2399. &NullCryptoSystem
  2400. );
  2401. if (NT_SUCCESS(Status))
  2402. {
  2403. NewCredentialSize += sizeof(KERB_KEY_DATA) + NullCryptoSystem->KeySize;
  2404. NewCredentialCount++;
  2405. }
  2406. //
  2407. // Add the space for the base structure
  2408. //
  2409. NewCredentialSize += sizeof(KERB_STORED_CREDENTIAL) - (ANYSIZE_ARRAY * sizeof(KERB_KEY_DATA));
  2410. //
  2411. // Allocate space for the credentials and start filling them in
  2412. //
  2413. Keys = (PKERB_STORED_CREDENTIAL) MIDL_user_allocate(NewCredentialSize);
  2414. if (Keys == NULL)
  2415. {
  2416. KerbErr = KRB_ERR_GENERIC;
  2417. goto Cleanup;
  2418. }
  2419. RtlZeroMemory(
  2420. Keys,
  2421. NewCredentialSize
  2422. );
  2423. Offset = sizeof(KERB_STORED_CREDENTIAL) -
  2424. (ANYSIZE_ARRAY * sizeof(KERB_KEY_DATA)) +
  2425. NewCredentialCount * sizeof(KERB_KEY_DATA);
  2426. Base = (PUCHAR) Keys;
  2427. Keys->CredentialCount = (USHORT) NewCredentialCount;
  2428. Keys->OldCredentialCount = 0;
  2429. Keys->Revision = KERB_PRIMARY_CRED_REVISION;
  2430. Keys->Flags = Flags;
  2431. //
  2432. // Add the credentials built from the OWF passwords first.
  2433. //
  2434. if (UseBuiltins)
  2435. {
  2436. //
  2437. // Create the key for RC4_HMAC_NT
  2438. //
  2439. if (UserAll->NtPasswordPresent)
  2440. {
  2441. RtlCopyMemory(
  2442. Base+Offset,
  2443. UserAll->NtPassword.Buffer,
  2444. UserAll->NtPassword.Length
  2445. );
  2446. KerbErr = KerbCreateKeyFromBuffer(
  2447. &Keys->Credentials[CredentialIndex].Key,
  2448. Base+Offset,
  2449. UserAll->NtPassword.Length,
  2450. KERB_ETYPE_RC4_HMAC_NT
  2451. );
  2452. if (!KERB_SUCCESS(KerbErr))
  2453. {
  2454. goto Cleanup;
  2455. }
  2456. Offset += UserAll->NtPassword.Length;
  2457. //
  2458. // Set an empty salt for this key
  2459. //
  2460. Keys->Credentials[CredentialIndex].Salt.Length = 0;
  2461. Keys->Credentials[CredentialIndex].Salt.MaximumLength = 0;
  2462. Keys->Credentials[CredentialIndex].Salt.Buffer = (LPWSTR) (Base + Offset);
  2463. CredentialIndex++;
  2464. }
  2465. #ifndef DONT_SUPPORT_OLD_TYPES_KDC
  2466. //
  2467. // Create the key for RC4_HMAC_OLD
  2468. //
  2469. if (UserAll->NtPasswordPresent)
  2470. {
  2471. RtlCopyMemory(
  2472. Base+Offset,
  2473. UserAll->NtPassword.Buffer,
  2474. UserAll->NtPassword.Length
  2475. );
  2476. KerbErr = KerbCreateKeyFromBuffer(
  2477. &Keys->Credentials[CredentialIndex].Key,
  2478. Base+Offset,
  2479. UserAll->NtPassword.Length,
  2480. (ULONG) KERB_ETYPE_RC4_HMAC_OLD
  2481. );
  2482. if (!KERB_SUCCESS(KerbErr))
  2483. {
  2484. goto Cleanup;
  2485. }
  2486. Offset += UserAll->NtPassword.Length;
  2487. //
  2488. // Set an empty salt for this key
  2489. //
  2490. Keys->Credentials[CredentialIndex].Salt.Length = 0;
  2491. Keys->Credentials[CredentialIndex].Salt.MaximumLength = 0;
  2492. Keys->Credentials[CredentialIndex].Salt.Buffer = (LPWSTR) (Base + Offset);
  2493. CredentialIndex++;
  2494. RtlCopyMemory(
  2495. Base+Offset,
  2496. UserAll->NtPassword.Buffer,
  2497. UserAll->NtPassword.Length
  2498. );
  2499. KerbErr = KerbCreateKeyFromBuffer(
  2500. &Keys->Credentials[CredentialIndex].Key,
  2501. Base+Offset,
  2502. UserAll->NtPassword.Length,
  2503. (ULONG) KERB_ETYPE_RC4_MD4
  2504. );
  2505. if (!KERB_SUCCESS(KerbErr))
  2506. {
  2507. goto Cleanup;
  2508. }
  2509. Offset += UserAll->NtPassword.Length;
  2510. //
  2511. // Set an empty salt for this key
  2512. //
  2513. Keys->Credentials[CredentialIndex].Salt.Length = 0;
  2514. Keys->Credentials[CredentialIndex].Salt.MaximumLength = 0;
  2515. Keys->Credentials[CredentialIndex].Salt.Buffer = (LPWSTR) (Base + Offset);
  2516. CredentialIndex++;
  2517. }
  2518. #endif
  2519. //
  2520. // If no passwords were present, add the null password
  2521. //
  2522. if (!(UserAll->LmPasswordPresent || UserAll->NtPasswordPresent))
  2523. {
  2524. KERB_ENCRYPTION_KEY TempKey;
  2525. UNICODE_STRING NullString;
  2526. RtlInitUnicodeString(
  2527. &NullString,
  2528. NULL
  2529. );
  2530. KerbErr = KerbHashPassword(
  2531. &NullString,
  2532. KERB_ETYPE_RC4_HMAC_NT,
  2533. &TempKey
  2534. );
  2535. if (!KERB_SUCCESS(KerbErr))
  2536. {
  2537. goto Cleanup;
  2538. }
  2539. Keys->Credentials[CredentialIndex].Key = TempKey;
  2540. Keys->Credentials[CredentialIndex].Key.keyvalue.value = Base + Offset;
  2541. RtlCopyMemory(
  2542. Base+Offset,
  2543. TempKey.keyvalue.value,
  2544. TempKey.keyvalue.length
  2545. );
  2546. Offset += TempKey.keyvalue.length;
  2547. //
  2548. // Set an empty salt for this key
  2549. //
  2550. Keys->Credentials[CredentialIndex].Salt.Length = 0;
  2551. Keys->Credentials[CredentialIndex].Salt.MaximumLength = 0;
  2552. Keys->Credentials[CredentialIndex].Salt.Buffer = (LPWSTR) (Base + Offset);
  2553. CredentialIndex++;
  2554. KerbFreeKey(&TempKey);
  2555. }
  2556. #ifndef DONT_SUPPORT_OLD_TYPES_KDC
  2557. if (!(UserAll->LmPasswordPresent || UserAll->NtPasswordPresent))
  2558. {
  2559. KERB_ENCRYPTION_KEY TempKey;
  2560. UNICODE_STRING NullString;
  2561. RtlInitUnicodeString(
  2562. &NullString,
  2563. NULL
  2564. );
  2565. KerbErr = KerbHashPassword(
  2566. &NullString,
  2567. (ULONG) KERB_ETYPE_RC4_HMAC_OLD,
  2568. &TempKey
  2569. );
  2570. if (!KERB_SUCCESS(KerbErr))
  2571. {
  2572. goto Cleanup;
  2573. }
  2574. Keys->Credentials[CredentialIndex].Key = TempKey;
  2575. Keys->Credentials[CredentialIndex].Key.keyvalue.value = Base + Offset;
  2576. RtlCopyMemory(
  2577. Base+Offset,
  2578. TempKey.keyvalue.value,
  2579. TempKey.keyvalue.length
  2580. );
  2581. Offset += TempKey.keyvalue.length;
  2582. //
  2583. // Set an empty salt for this key
  2584. //
  2585. Keys->Credentials[CredentialIndex].Salt.Length = 0;
  2586. Keys->Credentials[CredentialIndex].Salt.MaximumLength = 0;
  2587. Keys->Credentials[CredentialIndex].Salt.Buffer = (LPWSTR) (Base + Offset);
  2588. CredentialIndex++;
  2589. KerbFreeKey(&TempKey);
  2590. KerbErr = KerbHashPassword(
  2591. &NullString,
  2592. (ULONG) KERB_ETYPE_RC4_MD4,
  2593. &TempKey
  2594. );
  2595. if (!KERB_SUCCESS(KerbErr))
  2596. {
  2597. goto Cleanup;
  2598. }
  2599. Keys->Credentials[CredentialIndex].Key = TempKey;
  2600. Keys->Credentials[CredentialIndex].Key.keyvalue.value = Base + Offset;
  2601. RtlCopyMemory(
  2602. Base+Offset,
  2603. TempKey.keyvalue.value,
  2604. TempKey.keyvalue.length
  2605. );
  2606. Offset += TempKey.keyvalue.length;
  2607. CredentialIndex++;
  2608. KerbFreeKey(&TempKey);
  2609. }
  2610. #endif
  2611. }
  2612. //
  2613. // Add the null crypto system
  2614. //
  2615. if (NullCryptoSystem != NULL)
  2616. {
  2617. UNICODE_STRING NullString;
  2618. RtlInitUnicodeString(
  2619. &NullString,
  2620. NULL
  2621. );
  2622. Status = NullCryptoSystem->HashString(
  2623. &NullString,
  2624. Base+Offset
  2625. );
  2626. DsysAssert(NT_SUCCESS(Status));
  2627. Keys->Credentials[CredentialIndex].Key.keyvalue.value = Base+Offset;
  2628. Keys->Credentials[CredentialIndex].Key.keyvalue.length = NullCryptoSystem->KeySize;
  2629. Keys->Credentials[CredentialIndex].Key.keytype = KERB_ETYPE_NULL;
  2630. Offset += NullCryptoSystem->KeySize;
  2631. CredentialIndex++;
  2632. }
  2633. //
  2634. // Now add the stored passwords
  2635. //
  2636. if (UseStoredCreds)
  2637. {
  2638. //
  2639. // Copy the default salt
  2640. //
  2641. if (StoredCreds->DefaultSalt.Buffer != NULL)
  2642. {
  2643. Keys->DefaultSalt.Buffer = (LPWSTR) (Base+Offset);
  2644. RtlCopyMemory(
  2645. Base + Offset,
  2646. (PBYTE) StoredCreds->DefaultSalt.Buffer + (ULONG_PTR) StoredCreds,
  2647. StoredCreds->DefaultSalt.Length
  2648. );
  2649. Offset += StoredCreds->DefaultSalt.Length;
  2650. Keys->DefaultSalt.Length = Keys->DefaultSalt.MaximumLength = StoredCreds->DefaultSalt.Length;
  2651. }
  2652. for (Index = 0; Index < StoredCreds->CredentialCount ; Index++ )
  2653. {
  2654. //
  2655. // Copy the key
  2656. //
  2657. Keys->Credentials[CredentialIndex] = StoredCreds->Credentials[Index];
  2658. Keys->Credentials[CredentialIndex].Key.keyvalue.value = Base+Offset;
  2659. RtlCopyMemory(
  2660. Keys->Credentials[CredentialIndex].Key.keyvalue.value,
  2661. StoredCreds->Credentials[Index].Key.keyvalue.value + (ULONG_PTR) StoredCreds,
  2662. StoredCreds->Credentials[Index].Key.keyvalue.length
  2663. );
  2664. Offset += StoredCreds->Credentials[Index].Key.keyvalue.length;
  2665. //
  2666. // Copy the salt
  2667. //
  2668. if (StoredCreds->Credentials[Index].Salt.Buffer != NULL)
  2669. {
  2670. Keys->Credentials[CredentialIndex].Salt.Buffer = (LPWSTR) (Base+Offset);
  2671. RtlCopyMemory(
  2672. Base + Offset,
  2673. (PBYTE) StoredCreds->Credentials[Index].Salt.Buffer + (ULONG_PTR) StoredCreds,
  2674. StoredCreds->Credentials[Index].Salt.Length
  2675. );
  2676. Offset += StoredCreds->Credentials[Index].Salt.Length;
  2677. Keys->Credentials[CredentialIndex].Salt.Length =
  2678. Keys->Credentials[CredentialIndex].Salt.MaximumLength =
  2679. StoredCreds->Credentials[Index].Salt.Length;
  2680. }
  2681. CredentialIndex++;
  2682. }
  2683. }
  2684. DsysAssert(CredentialIndex == NewCredentialCount);
  2685. DsysAssert(Offset == NewCredentialSize);
  2686. *Passwords = Keys;
  2687. Keys = NULL;
  2688. //
  2689. // Now compute the old passwords
  2690. //
  2691. //
  2692. // Figure out the size of the stored credentials
  2693. //
  2694. NewCredentialCount = 0;
  2695. NewCredentialSize = 0;
  2696. CredentialIndex = 0;
  2697. if ((StoredCreds != NULL) &&
  2698. (CredentialSize > sizeof(KERB_STORED_CREDENTIAL) &&
  2699. (StoredCreds->Revision == KERB_PRIMARY_CRED_REVISION) &&
  2700. (CredentialSize > (sizeof(KERB_STORED_CREDENTIAL)
  2701. - (ANYSIZE_ARRAY * sizeof(KERB_KEY_DATA))
  2702. + (StoredCreds->OldCredentialCount + StoredCreds->CredentialCount) * sizeof(KERB_KEY_DATA)
  2703. ))))
  2704. {
  2705. UseStoredCreds = TRUE;
  2706. Flags = StoredCreds->Flags;
  2707. for (Index = 0; Index < StoredCreds->OldCredentialCount ; Index++ )
  2708. {
  2709. if (StoredCreds->Credentials[StoredCreds->CredentialCount + Index].Key.keyvalue.length +
  2710. (ULONG_PTR) StoredCreds->Credentials[StoredCreds->CredentialCount + Index].Key.keyvalue.value <=
  2711. CredentialSize )
  2712. {
  2713. NewCredentialCount++;
  2714. NewCredentialSize += sizeof(KERB_KEY_DATA) +
  2715. StoredCreds->Credentials[StoredCreds->CredentialCount + Index].Key.keyvalue.length;
  2716. }
  2717. else
  2718. {
  2719. LPWSTR Buff = NULL;
  2720. DebugLog((DEB_ERROR,"Corrupt credentials for user %wZ\n",
  2721. &UserAll->UserName ));
  2722. DsysAssert(FALSE);
  2723. Buff = KerbBuildNullTerminatedString(&UserAll->UserName);
  2724. if (NULL == Buff)
  2725. {
  2726. break;
  2727. }
  2728. ReportServiceEvent(
  2729. EVENTLOG_ERROR_TYPE,
  2730. KDCEVENT_CORRUPT_CREDENTIALS,
  2731. 0, // no raw data
  2732. NULL, // no raw data
  2733. 1, // number of strings
  2734. Buff
  2735. );
  2736. if (NULL != Buff)
  2737. {
  2738. MIDL_user_free(Buff);
  2739. }
  2740. UseStoredCreds = FALSE;
  2741. NewCredentialCount = 0;
  2742. NewCredentialSize = 0;
  2743. break;
  2744. }
  2745. }
  2746. }
  2747. //
  2748. // If the password length is the size of the OWF password, use it as the
  2749. // key. Otherwise hash it. This is for the case where not password is
  2750. // set.
  2751. //
  2752. // The Password histroy is appended to a SAMI_PRIVATE_DATA_PASSWORD_RELATIVE_TYPE structure.
  2753. // After this structure, there is blocks of 16 bytes for each password. The first password is
  2754. // the current password. The following blocks (if any) is the history of passwords.
  2755. //
  2756. // The index looks strange (PENCRYPTED_NT_OWF_PASSWORD) (PrivateData + 1) + 1
  2757. // the (PrivateData + 1) points to after the SAMI_PRIVATE_DATA_PASSWORD_RELATIVE_TYPE header
  2758. // and the final + 1 skips over the current password in the password history
  2759. if (UseBuiltins)
  2760. {
  2761. PSAMI_PRIVATE_DATA_PASSWORD_RELATIVE_TYPE PrivateData;
  2762. if (UserAll->PrivateData.Length >= sizeof(SAMI_PRIVATE_DATA_PASSWORD_RELATIVE_TYPE))
  2763. {
  2764. PrivateData= (PSAMI_PRIVATE_DATA_PASSWORD_RELATIVE_TYPE) UserAll->PrivateData.Buffer;
  2765. if (PrivateData->DataType == SamPrivateDataPassword)
  2766. {
  2767. //
  2768. // The old password is the 2nd entry
  2769. //
  2770. if (PrivateData->NtPasswordHistory.Length >= 2* sizeof(ENCRYPTED_NT_OWF_PASSWORD))
  2771. {
  2772. //
  2773. // Decrypt the old password with the RID. The history starts
  2774. // at the first byte after the structure.
  2775. //
  2776. Status = RtlDecryptNtOwfPwdWithIndex(
  2777. (PENCRYPTED_NT_OWF_PASSWORD) (PrivateData + 1) + 1,
  2778. (PLONG)&UserAll->UserId,
  2779. &OldPasswordData
  2780. );
  2781. if (!NT_SUCCESS(Status))
  2782. {
  2783. DebugLog((DEB_ERROR,"Failed to decrypt old password: 0x%x\n",Status));
  2784. KerbErr = KRB_ERR_GENERIC;
  2785. goto Cleanup;
  2786. }
  2787. OldNtPassword = &OldPasswordData ;
  2788. // Now check for the second previous password - this will be the third password in history
  2789. if (PrivateData->NtPasswordHistory.Length >= 3 * sizeof(ENCRYPTED_NT_OWF_PASSWORD))
  2790. {
  2791. //
  2792. // Decrypt the old password with the RID. The history starts
  2793. // at the first byte after the structure.
  2794. //
  2795. Status = RtlDecryptNtOwfPwdWithIndex(
  2796. (PENCRYPTED_NT_OWF_PASSWORD) (PrivateData + 1) + 2,
  2797. (PLONG)&UserAll->UserId,
  2798. &OldPasswordDataSecond
  2799. );
  2800. if (!NT_SUCCESS(Status))
  2801. {
  2802. DebugLog((DEB_ERROR,"Failed to decrypt second previous password: 0x%x\n",Status));
  2803. KerbErr = KRB_ERR_GENERIC;
  2804. goto Cleanup;
  2805. }
  2806. OldNtPasswordSecond = &OldPasswordDataSecond;
  2807. }
  2808. }
  2809. }
  2810. }
  2811. if (OldNtPassword != NULL)
  2812. {
  2813. //
  2814. // Add an RC4_HMAC_NT key
  2815. //
  2816. NewCredentialSize += sizeof(KERB_KEY_DATA) + sizeof(NT_OWF_PASSWORD);
  2817. NewCredentialCount++;
  2818. if (OldNtPasswordSecond != NULL)
  2819. {
  2820. //
  2821. // Add an RC4_HMAC_NT key for the second previous password
  2822. //
  2823. NewCredentialSize += sizeof(KERB_KEY_DATA) + sizeof(NT_OWF_PASSWORD);
  2824. NewCredentialCount++;
  2825. }
  2826. #ifndef DONT_SUPPORT_OLD_TYPES_KDC
  2827. //
  2828. // Add a key for RC4_HMAC_OLD & RC4_MD4
  2829. //
  2830. NewCredentialSize += sizeof(KERB_KEY_DATA) + sizeof(NT_OWF_PASSWORD);
  2831. NewCredentialCount++;
  2832. NewCredentialSize += sizeof(KERB_KEY_DATA) + sizeof(NT_OWF_PASSWORD);
  2833. NewCredentialCount++;
  2834. #endif
  2835. }
  2836. }
  2837. //
  2838. // Add the space for the base structure
  2839. //
  2840. NewCredentialSize += sizeof(KERB_STORED_CREDENTIAL) - (ANYSIZE_ARRAY * sizeof(KERB_KEY_DATA));
  2841. //
  2842. // Allocate space for the credentials and start filling them in
  2843. //
  2844. Keys = (PKERB_STORED_CREDENTIAL) MIDL_user_allocate(NewCredentialSize);
  2845. if (Keys == NULL)
  2846. {
  2847. KerbErr = KRB_ERR_GENERIC;
  2848. goto Cleanup;
  2849. }
  2850. RtlZeroMemory(
  2851. Keys,
  2852. NewCredentialSize
  2853. );
  2854. Offset = sizeof(KERB_STORED_CREDENTIAL) -
  2855. (ANYSIZE_ARRAY * sizeof(KERB_KEY_DATA)) +
  2856. NewCredentialCount * sizeof(KERB_KEY_DATA);
  2857. Base = (PUCHAR) Keys;
  2858. Keys->CredentialCount = (USHORT) NewCredentialCount;
  2859. Keys->OldCredentialCount = 0;
  2860. Keys->Revision = KERB_PRIMARY_CRED_REVISION;
  2861. Keys->Flags = Flags;
  2862. //
  2863. // Add the credentials built from the OWF passwords first. We don't
  2864. // include a blank password or the null crypt system because they
  2865. // were present in the normal password
  2866. //
  2867. if (UseBuiltins)
  2868. {
  2869. //
  2870. // Create the key for RC4_HMAC_NT
  2871. //
  2872. if (OldNtPassword != NULL)
  2873. {
  2874. //
  2875. // Set an empty salt for this key
  2876. //
  2877. Keys->Credentials[CredentialIndex].Salt.Length = 0;
  2878. Keys->Credentials[CredentialIndex].Salt.MaximumLength = 0;
  2879. Keys->Credentials[CredentialIndex].Salt.Buffer = (LPWSTR) (Base + Offset);
  2880. RtlCopyMemory(
  2881. Base+Offset,
  2882. OldNtPassword,
  2883. NT_OWF_PASSWORD_LENGTH
  2884. );
  2885. KerbErr = KerbCreateKeyFromBuffer(
  2886. &Keys->Credentials[CredentialIndex++].Key,
  2887. Base+Offset,
  2888. UserAll->NtPassword.Length,
  2889. KERB_ETYPE_RC4_HMAC_NT
  2890. );
  2891. if (!KERB_SUCCESS(KerbErr))
  2892. {
  2893. goto Cleanup;
  2894. }
  2895. // We don't know any other way to get the old password length. If
  2896. // it was present, it must be sizeof(NT_OWF_PASSWORD)
  2897. Offset += sizeof(NT_OWF_PASSWORD);
  2898. if (OldNtPasswordSecond != NULL)
  2899. {
  2900. //
  2901. // Set an empty salt for this key for the second previous password
  2902. //
  2903. Keys->Credentials[CredentialIndex].Salt.Length = 0;
  2904. Keys->Credentials[CredentialIndex].Salt.MaximumLength = 0;
  2905. Keys->Credentials[CredentialIndex].Salt.Buffer = (LPWSTR) (Base + Offset);
  2906. RtlCopyMemory(
  2907. Base+Offset,
  2908. OldNtPasswordSecond,
  2909. NT_OWF_PASSWORD_LENGTH
  2910. );
  2911. KerbErr = KerbCreateKeyFromBuffer(
  2912. &Keys->Credentials[CredentialIndex++].Key,
  2913. Base+Offset,
  2914. UserAll->NtPassword.Length,
  2915. KERB_ETYPE_RC4_HMAC_NT
  2916. );
  2917. if (!KERB_SUCCESS(KerbErr))
  2918. {
  2919. goto Cleanup;
  2920. }
  2921. // We don't know any other way to get the old password length. If
  2922. // it was present, it must be sizeof(NT_OWF_PASSWORD)
  2923. Offset += sizeof(NT_OWF_PASSWORD);
  2924. }
  2925. #ifndef DONT_SUPPORT_OLD_TYPES_KDC
  2926. //
  2927. // Create the key for RC4_HMAC_OLD
  2928. //
  2929. //
  2930. // Set an empty salt for this key
  2931. //
  2932. Keys->Credentials[CredentialIndex].Salt.Length = 0;
  2933. Keys->Credentials[CredentialIndex].Salt.MaximumLength = 0;
  2934. Keys->Credentials[CredentialIndex].Salt.Buffer = (LPWSTR) (Base + Offset);
  2935. RtlCopyMemory(
  2936. Base+Offset,
  2937. OldNtPassword,
  2938. NT_OWF_PASSWORD_LENGTH
  2939. );
  2940. KerbErr = KerbCreateKeyFromBuffer(
  2941. &Keys->Credentials[CredentialIndex++].Key,
  2942. Base+Offset,
  2943. UserAll->NtPassword.Length,
  2944. (ULONG) KERB_ETYPE_RC4_HMAC_OLD
  2945. );
  2946. if (!KERB_SUCCESS(KerbErr))
  2947. {
  2948. goto Cleanup;
  2949. }
  2950. // We don't know any other way to get the old password length. If
  2951. // it was present, it must be sizeof(NT_OWF_PASSWORD)
  2952. Offset += sizeof(NT_OWF_PASSWORD);
  2953. //
  2954. // Create the key for RC4_HMAC_OLD
  2955. //
  2956. //
  2957. // Set an empty salt for this key
  2958. //
  2959. Keys->Credentials[CredentialIndex].Salt.Length = 0;
  2960. Keys->Credentials[CredentialIndex].Salt.MaximumLength = 0;
  2961. Keys->Credentials[CredentialIndex].Salt.Buffer = (LPWSTR) (Base + Offset);
  2962. RtlCopyMemory(
  2963. Base+Offset,
  2964. OldNtPassword,
  2965. NT_OWF_PASSWORD_LENGTH
  2966. );
  2967. KerbErr = KerbCreateKeyFromBuffer(
  2968. &Keys->Credentials[CredentialIndex++].Key,
  2969. Base+Offset,
  2970. UserAll->NtPassword.Length,
  2971. (ULONG) KERB_ETYPE_RC4_MD4
  2972. );
  2973. if (!KERB_SUCCESS(KerbErr))
  2974. {
  2975. goto Cleanup;
  2976. }
  2977. // We don't know any other way to get the old password length. If
  2978. // it was present, it must be sizeof(NT_OWF_PASSWORD)
  2979. Offset += sizeof(NT_OWF_PASSWORD);
  2980. #endif
  2981. }
  2982. }
  2983. //
  2984. // Now add the stored passwords
  2985. //
  2986. if (UseStoredCreds)
  2987. {
  2988. for (Index = 0; Index < StoredCreds->OldCredentialCount ; Index++ )
  2989. {
  2990. Keys->Credentials[CredentialIndex] = StoredCreds->Credentials[StoredCreds->CredentialCount + Index];
  2991. Keys->Credentials[CredentialIndex].Key.keyvalue.value = Base+Offset;
  2992. RtlCopyMemory(
  2993. Keys->Credentials[CredentialIndex].Key.keyvalue.value,
  2994. StoredCreds->Credentials[StoredCreds->CredentialCount + Index].Key.keyvalue.value + (ULONG_PTR) StoredCreds,
  2995. StoredCreds->Credentials[StoredCreds->CredentialCount + Index].Key.keyvalue.length
  2996. );
  2997. Offset += StoredCreds->Credentials[StoredCreds->CredentialCount + Index].Key.keyvalue.length;
  2998. //
  2999. // Note - don't use salt here.
  3000. //
  3001. CredentialIndex++;
  3002. }
  3003. }
  3004. DsysAssert(CredentialIndex == NewCredentialCount);
  3005. DsysAssert(Offset == NewCredentialSize);
  3006. *OldPasswords = Keys;
  3007. Keys = NULL;
  3008. KerbErr = KDC_ERR_NONE;
  3009. Cleanup:
  3010. if (StoredCreds != NULL)
  3011. {
  3012. if (!UnMarshalledCreds)
  3013. {
  3014. LocalFree(StoredCreds);
  3015. }
  3016. else
  3017. {
  3018. MIDL_user_free(Cred64);
  3019. }
  3020. }
  3021. if (Keys != NULL)
  3022. {
  3023. MIDL_user_free(Keys);
  3024. }
  3025. return (KerbErr);
  3026. }
  3027. //+-------------------------------------------------------------------------
  3028. //
  3029. // Function: KerbDuplicateCredentials
  3030. //
  3031. // Synopsis: Copies a set of credentials (passwords)
  3032. //
  3033. // Effects: allocates output with MIDL_user_allocate
  3034. //
  3035. // Arguments: NewCredentials - recevies new set of credentials
  3036. // OldCredentials - contains credentials to copy
  3037. //
  3038. // Requires:
  3039. //
  3040. // Returns:
  3041. //
  3042. // Notes:
  3043. //
  3044. //
  3045. //--------------------------------------------------------------------------
  3046. KERBERR
  3047. KdcDuplicateCredentials(
  3048. OUT PKERB_STORED_CREDENTIAL * NewCredentials,
  3049. OUT PULONG ReturnCredentialSize,
  3050. IN PKERB_STORED_CREDENTIAL OldCredentials,
  3051. IN BOOLEAN MarshallKeys
  3052. )
  3053. {
  3054. KERBERR KerbErr = KDC_ERR_NONE;
  3055. PKERB_STORED_CREDENTIAL Credential = NULL;
  3056. ULONG CredentialSize;
  3057. USHORT Index;
  3058. PBYTE Where;
  3059. LONG_PTR Offset;
  3060. TRACE(KDC, KdcDuplicateCredentials, DEB_FUNCTION);
  3061. //
  3062. // If there were no credentials, so be it. We can live with that.
  3063. //
  3064. if (OldCredentials == NULL)
  3065. {
  3066. *NewCredentials = NULL;
  3067. goto Cleanup;
  3068. }
  3069. //
  3070. // Calculate the size of the new credentials by summing the size of
  3071. // the base structure plus the keys
  3072. //
  3073. CredentialSize = sizeof(KERB_STORED_CREDENTIAL)
  3074. - ANYSIZE_ARRAY * sizeof(KERB_KEY_DATA)
  3075. + OldCredentials->CredentialCount * sizeof(KERB_KEY_DATA)
  3076. + OldCredentials->DefaultSalt.Length;
  3077. for ( Index = 0;
  3078. Index < OldCredentials->CredentialCount + OldCredentials->OldCredentialCount ;
  3079. Index++ )
  3080. {
  3081. CredentialSize += OldCredentials->Credentials[Index].Key.keyvalue.length +
  3082. OldCredentials->Credentials[Index].Salt.Length;
  3083. }
  3084. //
  3085. // Allocate the new credential and copy over the old credentials
  3086. //
  3087. Credential = (PKERB_STORED_CREDENTIAL) MIDL_user_allocate(CredentialSize);
  3088. if (Credential == NULL)
  3089. {
  3090. KerbErr = KRB_ERR_GENERIC;
  3091. goto Cleanup;
  3092. }
  3093. Credential->Revision = OldCredentials->Revision;
  3094. Credential->Flags = OldCredentials->Flags;
  3095. Credential->CredentialCount = OldCredentials->CredentialCount;
  3096. Credential->OldCredentialCount = OldCredentials->OldCredentialCount;
  3097. //
  3098. // Set the offset for data to be after the last array element
  3099. //
  3100. RtlCopyMemory(
  3101. &Credential->Credentials[0],
  3102. &OldCredentials->Credentials[0],
  3103. OldCredentials->CredentialCount * sizeof(KERB_KEY_DATA)
  3104. );
  3105. Where = (PBYTE) &Credential->Credentials[Credential->CredentialCount];
  3106. if (MarshallKeys)
  3107. {
  3108. Offset = (LONG_PTR) Credential;
  3109. }
  3110. else
  3111. {
  3112. Offset = 0;
  3113. }
  3114. Credential->DefaultSalt = OldCredentials->DefaultSalt;
  3115. if (Credential->DefaultSalt.Buffer != NULL)
  3116. {
  3117. Credential->DefaultSalt.Buffer = (LPWSTR) (Where - Offset);
  3118. RtlCopyMemory(
  3119. Where,
  3120. OldCredentials->DefaultSalt.Buffer,
  3121. Credential->DefaultSalt.Length
  3122. );
  3123. Where += Credential->DefaultSalt.Length;
  3124. }
  3125. for ( Index = 0;
  3126. Index < OldCredentials->CredentialCount + OldCredentials->OldCredentialCount ;
  3127. Index++ )
  3128. {
  3129. Credential->Credentials[Index] = OldCredentials->Credentials[Index];
  3130. Credential->Credentials[Index].Key.keyvalue.value = (Where - Offset);
  3131. RtlCopyMemory(
  3132. Where,
  3133. OldCredentials->Credentials[Index].Key.keyvalue.value,
  3134. OldCredentials->Credentials[Index].Key.keyvalue.length
  3135. );
  3136. Where += OldCredentials->Credentials[Index].Key.keyvalue.length;
  3137. if (Credential->Credentials[Index].Salt.Buffer != NULL)
  3138. {
  3139. Credential->Credentials[Index].Salt.Buffer = (LPWSTR) (Where - Offset);
  3140. RtlCopyMemory(
  3141. Where,
  3142. OldCredentials->Credentials[Index].Salt.Buffer,
  3143. OldCredentials->Credentials[Index].Salt.Length
  3144. );
  3145. Where += OldCredentials->Credentials[Index].Salt.Length;
  3146. }
  3147. }
  3148. DsysAssert(Where - (PUCHAR) Credential == (LONG) CredentialSize);
  3149. *NewCredentials = Credential;
  3150. Credential = NULL;
  3151. *ReturnCredentialSize = CredentialSize;
  3152. Cleanup:
  3153. if (Credential != NULL)
  3154. {
  3155. MIDL_user_free(Credential);
  3156. }
  3157. return(KerbErr);
  3158. }
  3159. //+---------------------------------------------------------------------------
  3160. //
  3161. // Function: KdcGetTicketInfo
  3162. //
  3163. // Synopsis: Gets the info needed to build a ticket for a principal
  3164. // using name of the principal.
  3165. //
  3166. //
  3167. // Effects:
  3168. //
  3169. // Arguments: Name -- (in) Normalized of principal
  3170. // LookupFlags - Flags for SamIGetUserLogonInformation
  3171. // PrincipalName - (in) non-normalized principal name
  3172. // Realm - (in) client realm, to be used when mapping principals
  3173. // from another domain onto accounts in this one.
  3174. // TicketInfo -- (out) Ticket info.
  3175. // pExtendedError -- (out) Extended error
  3176. // UserHandle - receives handle to the user
  3177. // WhichFields - optionally specifies additional fields to fetch for RetUserInfo
  3178. // ExtendedFields - optionally specifies extended fields to fetch for RetUserInfo
  3179. // RetUserInfo - Optionally receives the user all info structure
  3180. // GroupMembership - Optionally receives the user's group membership
  3181. //
  3182. // Returns: KerbErr
  3183. //
  3184. // Algorithm:
  3185. //
  3186. // History: 10-Nov-93 WadeR Created
  3187. // 22-Mar-95 SuChang Modified to use RIDs
  3188. //
  3189. //
  3190. //----------------------------------------------------------------------------
  3191. KERBERR
  3192. KdcGetTicketInfo(
  3193. IN PUNICODE_STRING GenericUserName,
  3194. IN ULONG LookupFlags,
  3195. IN BOOLEAN bRestrictUserAccounts,
  3196. IN OPTIONAL PKERB_INTERNAL_NAME PrincipalName,
  3197. IN OPTIONAL PKERB_REALM Realm,
  3198. OUT PKDC_TICKET_INFO TicketInfo,
  3199. OUT PKERB_EXT_ERROR pExtendedError,
  3200. OUT OPTIONAL SAMPR_HANDLE * UserHandle,
  3201. IN OPTIONAL ULONG WhichFields,
  3202. IN OPTIONAL ULONG ExtendedFields,
  3203. OUT OPTIONAL PUSER_INTERNAL6_INFORMATION * RetUserInfo,
  3204. OUT OPTIONAL PSID_AND_ATTRIBUTES_LIST GroupMembership
  3205. )
  3206. {
  3207. NTSTATUS Status = STATUS_NOT_FOUND;
  3208. KERBERR KerbErr = KDC_ERR_NONE;
  3209. SID_AND_ATTRIBUTES_LIST LocalMembership;
  3210. SAMPR_HANDLE LocalUserHandle = NULL;
  3211. PUSER_INTERNAL6_INFORMATION UserInfo = NULL;
  3212. PUSER_ALL_INFORMATION UserAll;
  3213. GUID testGuid = {0};
  3214. UNICODE_STRING TUserName = {0};
  3215. PUNICODE_STRING UserName = NULL;
  3216. UNICODE_STRING AlternateName = {0};
  3217. UNICODE_STRING TempString = {0};
  3218. BOOL IsValidGuid = FALSE;
  3219. TRACE(KDC, GetTicketInfo, DEB_FUNCTION);
  3220. D_DebugLog((DEB_T_PAPI, "KdcGetTicketInfo [entering] bRestrictUserAccounts %s, WhichFields %#x, ExtendedFields %#x, GenericUserName %wZ, LookupFlags %#x, PrincipalName ",
  3221. bRestrictUserAccounts ? "true" : "false", WhichFields, ExtendedFields, GenericUserName, LookupFlags));
  3222. D_KerbPrintKdcName((DEB_T_PAPI, PrincipalName));
  3223. //
  3224. // Add the fields we are going to require locally to the WhichFields parameter
  3225. //
  3226. WhichFields |=
  3227. USER_ALL_KDC_GET_USER_KEYS |
  3228. USER_ALL_PASSWORDMUSTCHANGE |
  3229. USER_ALL_USERACCOUNTCONTROL |
  3230. USER_ALL_USERID |
  3231. USER_ALL_USERNAME;
  3232. ExtendedFields |=
  3233. USER_EXTENDED_FIELD_KVNO | // passwd version raid #306501
  3234. USER_EXTENDED_FIELD_LOCKOUT_THRESHOLD; // for individual account lockout rather than domain wide
  3235. TUserName = *GenericUserName;
  3236. UserName = &TUserName;
  3237. RtlZeroMemory(TicketInfo, sizeof(KDC_TICKET_INFO));
  3238. RtlZeroMemory(&LocalMembership, sizeof(SID_AND_ATTRIBUTES_LIST));
  3239. if (ARGUMENT_PRESENT( RetUserInfo ))
  3240. {
  3241. *RetUserInfo = NULL;
  3242. }
  3243. if (!ARGUMENT_PRESENT(GroupMembership))
  3244. {
  3245. LookupFlags |= SAM_NO_MEMBERSHIPS;
  3246. }
  3247. //
  3248. // If this is the krbtgt account, use the cached version
  3249. //
  3250. if (!ARGUMENT_PRESENT(UserHandle) &&
  3251. !ARGUMENT_PRESENT(RetUserInfo) &&
  3252. !ARGUMENT_PRESENT(GroupMembership) &&
  3253. (KdcState == Running) &&
  3254. RtlEqualUnicodeString(
  3255. SecData.KdcServiceName(),
  3256. UserName,
  3257. TRUE // case insensitive
  3258. ))
  3259. {
  3260. //
  3261. // Duplicate the cached copy of the KRBTGT information
  3262. //
  3263. D_DebugLog((DEB_T_TICKETS, "KdcGetTicketInfo using cached ticket info for krbtgt account\n"));
  3264. KerbErr = SecData.GetKrbtgtTicketInfo(
  3265. TicketInfo
  3266. );
  3267. if (KERB_SUCCESS(KerbErr))
  3268. {
  3269. goto Cleanup;
  3270. }
  3271. }
  3272. //
  3273. // If we cracked this name at a dc, and it's the same domain, we will
  3274. // not be able to generate a referral ticket. So, we need to be able
  3275. // to open the sam locally. Further more, crack name and sam lookups
  3276. // are much faster with guids (even though we have to do the string
  3277. // to guid operation.
  3278. //
  3279. if (LookupFlags & SAM_OPEN_BY_GUID)
  3280. {
  3281. if (IsValidGuid = IsStringGuid(UserName->Buffer, &testGuid))
  3282. {
  3283. UserName->Buffer = (LPWSTR)&testGuid;
  3284. }
  3285. }
  3286. //
  3287. // The caller may provide an empty user name so as to force the lookup
  3288. // using the AltSecId. This is used when mapping names from an MIT realm
  3289. //
  3290. if (UserName->Length > 0)
  3291. {
  3292. //
  3293. // Open the user account
  3294. //
  3295. #if DBG
  3296. if (IsValidGuid)
  3297. {
  3298. D_KerbPrintGuid(DEB_TRACE, "KdcGetTicketInfo account is Guid ", &testGuid);
  3299. }
  3300. #endif
  3301. Status = SamIGetUserLogonInformation2(
  3302. GlobalAccountDomainHandle,
  3303. LookupFlags,
  3304. UserName,
  3305. WhichFields,
  3306. ExtendedFields,
  3307. &UserInfo,
  3308. &LocalMembership,
  3309. &LocalUserHandle
  3310. );
  3311. //
  3312. // WASBUG: For now, if we couldn't find the account try again
  3313. // with a '$' at the end (if there wasn't one already)
  3314. //
  3315. if (((Status == STATUS_NOT_FOUND) ||
  3316. (Status == STATUS_NO_SUCH_USER)) &&
  3317. (!IsValidGuid) &&
  3318. ((LookupFlags & ~SAM_NO_MEMBERSHIPS) == 0) &&
  3319. (UserName->Length >= sizeof(WCHAR)) &&
  3320. (UserName->Buffer[UserName->Length/sizeof(WCHAR)-1] != L'$'))
  3321. {
  3322. Status = KerbDuplicateString(
  3323. &TempString,
  3324. UserName
  3325. );
  3326. if (!NT_SUCCESS(Status))
  3327. {
  3328. KerbErr = KRB_ERR_GENERIC;
  3329. goto Cleanup;
  3330. }
  3331. DsysAssert(TempString.MaximumLength >= TempString.Length + sizeof(WCHAR));
  3332. TempString.Buffer[TempString.Length/sizeof(WCHAR)] = L'$';
  3333. TempString.Length += sizeof(WCHAR);
  3334. D_DebugLog((DEB_TRACE, "Account not found ,trying machine account %wZ\n",
  3335. &TempString ));
  3336. Status = SamIGetUserLogonInformation2(
  3337. GlobalAccountDomainHandle,
  3338. LookupFlags,
  3339. &TempString,
  3340. WhichFields,
  3341. ExtendedFields,
  3342. &UserInfo,
  3343. &LocalMembership,
  3344. &LocalUserHandle
  3345. );
  3346. }
  3347. }
  3348. //
  3349. // If we still can't find the account, try the altsecid using
  3350. // the supplied principal name.
  3351. //
  3352. if (((Status == STATUS_NOT_FOUND) || (Status == STATUS_NO_SUCH_USER)) &&
  3353. ARGUMENT_PRESENT(PrincipalName) )
  3354. {
  3355. KerbErr = KerbBuildAltSecId(
  3356. &AlternateName,
  3357. PrincipalName,
  3358. Realm,
  3359. NULL // no unicode realm name
  3360. );
  3361. if (KERB_SUCCESS(KerbErr))
  3362. {
  3363. D_DebugLog((DEB_TRACE,"User account not found, trying alternate id: %wZ\n",&AlternateName ));
  3364. LookupFlags |= SAM_OPEN_BY_ALTERNATE_ID,
  3365. Status = SamIGetUserLogonInformation2(
  3366. GlobalAccountDomainHandle,
  3367. LookupFlags,
  3368. &AlternateName,
  3369. WhichFields,
  3370. ExtendedFields,
  3371. &UserInfo,
  3372. &LocalMembership,
  3373. &LocalUserHandle
  3374. );
  3375. }
  3376. }
  3377. if (!NT_SUCCESS(Status))
  3378. {
  3379. DebugLog((DEB_T_TICKETS,"Could not open User %wZ: 0x%x\n",
  3380. UserName,
  3381. Status
  3382. ));
  3383. if ((Status == STATUS_NO_SUCH_USER) || (Status == STATUS_NOT_FOUND) ||
  3384. (Status == STATUS_OBJECT_NAME_NOT_FOUND))
  3385. {
  3386. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  3387. }
  3388. else if (Status == STATUS_NO_LOGON_SERVERS)
  3389. {
  3390. //If there's no GC, this sam call returns STATUS_NO_LOGON_SERVERS
  3391. //and we should return this to the client. see bug 226073
  3392. FILL_EXT_ERROR(pExtendedError, Status,FILENO, __LINE__);
  3393. KerbErr = KDC_ERR_SVC_UNAVAILABLE;
  3394. }
  3395. else if (Status != STATUS_INVALID_SERVER_STATE)
  3396. {
  3397. WCHAR LookupType[10];
  3398. WCHAR * LookupTypeStr;
  3399. WCHAR AccountName[MAX_PATH+1];
  3400. PUNICODE_STRING LookupName = NULL;
  3401. if (AlternateName.Buffer != NULL)
  3402. {
  3403. LookupName = &AlternateName;
  3404. }
  3405. else if (TempString.Buffer != NULL)
  3406. {
  3407. LookupName = &TempString;
  3408. }
  3409. else
  3410. {
  3411. LookupName = UserName;
  3412. }
  3413. if (LookupName->Length < MAX_PATH * sizeof(WCHAR))
  3414. {
  3415. RtlCopyMemory(
  3416. AccountName,
  3417. LookupName->Buffer,
  3418. LookupName->Length
  3419. );
  3420. AccountName[LookupName->Length/sizeof(WCHAR)] = L'\0';
  3421. }
  3422. else
  3423. {
  3424. RtlCopyMemory(
  3425. AccountName,
  3426. LookupName->Buffer,
  3427. MAX_PATH * sizeof(WCHAR)
  3428. );
  3429. AccountName[MAX_PATH] = L'\0';
  3430. }
  3431. //
  3432. // Log name collisions separately to provide
  3433. // more information
  3434. //
  3435. if (Status == STATUS_OBJECT_NAME_COLLISION)
  3436. {
  3437. DS_NAME_FORMAT NameFormat = DS_UNKNOWN_NAME;
  3438. if ((LookupFlags & SAM_OPEN_BY_UPN) != 0)
  3439. {
  3440. NameFormat = DS_USER_PRINCIPAL_NAME;
  3441. }
  3442. else if ((LookupFlags & SAM_OPEN_BY_SPN) != 0)
  3443. {
  3444. NameFormat = DS_SERVICE_PRINCIPAL_NAME;
  3445. }
  3446. //
  3447. // Potentially deadly error, pass back to caller.
  3448. //
  3449. FILL_EXT_ERROR_EX(pExtendedError, Status,FILENO, __LINE__);
  3450. if (( NameFormat < sizeof( KdcGlobalNameTypes ) / sizeof( KdcGlobalNameTypes[0] )) &&
  3451. ( KdcGlobalNameTypes[NameFormat] != NULL ))
  3452. {
  3453. LookupTypeStr = KdcGlobalNameTypes[NameFormat];
  3454. }
  3455. else
  3456. {
  3457. swprintf(LookupType,L"%d",(ULONG) NameFormat);
  3458. LookupTypeStr = LookupType;
  3459. }
  3460. ReportServiceEvent(
  3461. EVENTLOG_ERROR_TYPE,
  3462. KDCEVENT_NAME_NOT_UNIQUE,
  3463. 0,
  3464. NULL,
  3465. 2,
  3466. AccountName,
  3467. LookupTypeStr
  3468. );
  3469. KerbErr = KDC_ERR_PRINCIPAL_NOT_UNIQUE;
  3470. }
  3471. else
  3472. {
  3473. swprintf(LookupType,L"0x%x",LookupFlags);
  3474. ReportServiceEvent(
  3475. EVENTLOG_ERROR_TYPE,
  3476. KDCEVENT_SAM_CALL_FAILED,
  3477. sizeof(NTSTATUS),
  3478. &Status,
  3479. 2,
  3480. AccountName,
  3481. LookupType
  3482. );
  3483. KerbErr = KRB_ERR_GENERIC;
  3484. }
  3485. }
  3486. else
  3487. {
  3488. // Potentially deadly error, pass back to caller.
  3489. FILL_EXT_ERROR_EX(pExtendedError, Status,FILENO, __LINE__);
  3490. KerbErr = KRB_ERR_GENERIC;
  3491. }
  3492. goto Cleanup;
  3493. }
  3494. D_DebugLog((DEB_T_TICKETS, "KdcGetTicketInfo getting user keys\n"));
  3495. //
  3496. // if an account does not have at one SPNs registered, it is an user
  3497. // account and enforce user2user
  3498. //
  3499. if (bRestrictUserAccounts && ((UserInfo->I1.UserAccountControl & USER_MACHINE_ACCOUNT_MASK) == 0))
  3500. {
  3501. if ((ExtendedFields & USER_EXTENDED_FIELD_SPN) == 0)
  3502. {
  3503. DebugLog((DEB_ERROR, "KdcGetTicketInfo can't restrict user accounts if USER_EXTENDED_FIELD_SPN is not requested\n"));
  3504. KerbErr = KRB_ERR_GENERIC;
  3505. goto Cleanup;
  3506. }
  3507. if ((UserInfo->RegisteredSPNs == NULL) || (UserInfo->RegisteredSPNs->NumSPNs == 0))
  3508. {
  3509. DebugLog((DEB_ERROR, "KdcVerifyKdcRequest must use user2user UserAccountControl %#x, GenericUserName %wZ, PrincipalName: ",
  3510. UserInfo->I1.UserAccountControl, GenericUserName));
  3511. KerbPrintKdcName(DEB_ERROR, PrincipalName);
  3512. KerbErr = KDC_ERR_MUST_USE_USER2USER;
  3513. goto Cleanup;
  3514. }
  3515. }
  3516. UserAll = &UserInfo->I1;
  3517. KerbErr = KdcGetUserKeys(
  3518. LocalUserHandle,
  3519. UserInfo,
  3520. &TicketInfo->Passwords,
  3521. &TicketInfo->OldPasswords,
  3522. pExtendedError
  3523. );
  3524. if (!KERB_SUCCESS(KerbErr))
  3525. {
  3526. DebugLog((DEB_ERROR,"Failed to get user keys: 0x%x\n",KerbErr));
  3527. goto Cleanup;
  3528. }
  3529. if (!NT_SUCCESS(KerbDuplicateString(
  3530. &TicketInfo->AccountName,
  3531. &UserAll->UserName )))
  3532. {
  3533. KerbErr = KRB_ERR_GENERIC;
  3534. goto Cleanup;
  3535. }
  3536. if ((UserAll->UserAccountControl & USER_TRUSTED_FOR_DELEGATION) != 0)
  3537. {
  3538. TicketInfo->fTicketOpts |= AUTH_REQ_OK_AS_DELEGATE;
  3539. }
  3540. if ((UserAll->UserAccountControl & USER_NOT_DELEGATED) == 0)
  3541. {
  3542. TicketInfo->fTicketOpts |= AUTH_REQ_ALLOW_FORWARDABLE | AUTH_REQ_ALLOW_PROXIABLE;
  3543. }
  3544. if ((UserAll->UserAccountControl & USER_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION) != 0)
  3545. {
  3546. TicketInfo->fTicketOpts |= AUTH_REQ_ALLOW_S4U_DELEGATE;
  3547. }
  3548. TicketInfo->fTicketOpts |= AUTH_REQ_ALLOW_RENEWABLE |
  3549. AUTH_REQ_ALLOW_NOADDRESS |
  3550. AUTH_REQ_ALLOW_ENC_TKT_IN_SKEY |
  3551. AUTH_REQ_ALLOW_VALIDATE;
  3552. //
  3553. // These flags aren't turned on by default:
  3554. // AUTH_REQ_VALIDATE_CLIENT
  3555. //
  3556. //
  3557. // Mask with the domain policy flags
  3558. //
  3559. TicketInfo->fTicketOpts &= SecData.KdcFlags();
  3560. TicketInfo->PasswordExpires = UserAll->PasswordMustChange;
  3561. TicketInfo->PasswordVersion = UserInfo->KeyVersionNumber; // Raid #306501
  3562. TicketInfo->LockoutThreshold = UserInfo->LockoutThreshold; // account lockout
  3563. TicketInfo->UserAccountControl = UserAll->UserAccountControl;
  3564. TicketInfo->UserId = UserAll->UserId;
  3565. if (ARGUMENT_PRESENT(RetUserInfo))
  3566. {
  3567. *RetUserInfo = UserInfo;
  3568. UserInfo = NULL;
  3569. }
  3570. if (ARGUMENT_PRESENT(GroupMembership))
  3571. {
  3572. *GroupMembership = LocalMembership;
  3573. RtlZeroMemory(
  3574. &LocalMembership,
  3575. sizeof(SID_AND_ATTRIBUTES_LIST)
  3576. );
  3577. }
  3578. if (ARGUMENT_PRESENT(UserHandle))
  3579. {
  3580. *UserHandle = LocalUserHandle;
  3581. LocalUserHandle = NULL;
  3582. }
  3583. Cleanup:
  3584. KerbFreeString( &TempString );
  3585. KerbFreeString( &AlternateName );
  3586. SamIFree_UserInternal6Information( UserInfo );
  3587. if (LocalUserHandle != NULL)
  3588. {
  3589. SamrCloseHandle(&LocalUserHandle);
  3590. }
  3591. SamIFreeSidAndAttributesList( &LocalMembership );
  3592. if ( !KERB_SUCCESS( KerbErr ))
  3593. {
  3594. FreeTicketInfo( TicketInfo );
  3595. RtlZeroMemory(TicketInfo, sizeof(KDC_TICKET_INFO));
  3596. }
  3597. D_DebugLog((DEB_T_PAPI, "KdcGetTicketInfo returning %#x\n", KerbErr));
  3598. return KerbErr;
  3599. }
  3600. //+---------------------------------------------------------------------------
  3601. //
  3602. // Function: FreeTicketInfo
  3603. //
  3604. // Synopsis: Frees a KDC_TICKET_INFO structure
  3605. //
  3606. // Effects:
  3607. //
  3608. // Arguments:
  3609. //
  3610. // Returns:
  3611. //
  3612. // Algorithm:
  3613. //
  3614. // History: 22-Mar-95 SuChang Created
  3615. //
  3616. // Notes:
  3617. //
  3618. //----------------------------------------------------------------------------
  3619. VOID
  3620. FreeTicketInfo(
  3621. IN PKDC_TICKET_INFO TicketInfo
  3622. )
  3623. {
  3624. TRACE(KDC, FreeTicketInfo, DEB_FUNCTION);
  3625. if (ARGUMENT_PRESENT(TicketInfo))
  3626. {
  3627. KerbFreeString(
  3628. &TicketInfo->AccountName
  3629. );
  3630. KerbFreeString(
  3631. &TicketInfo->TrustedForest
  3632. );
  3633. if (TicketInfo->Passwords != NULL)
  3634. {
  3635. MIDL_user_free(TicketInfo->Passwords);
  3636. TicketInfo->Passwords = NULL;
  3637. }
  3638. if (TicketInfo->OldPasswords != NULL)
  3639. {
  3640. MIDL_user_free(TicketInfo->OldPasswords);
  3641. TicketInfo->OldPasswords = NULL;
  3642. }
  3643. if (TicketInfo->TrustSid != NULL)
  3644. {
  3645. MIDL_user_free(TicketInfo->TrustSid);
  3646. TicketInfo->TrustSid = NULL;
  3647. }
  3648. }
  3649. }
  3650. //--------------------------------------------------------------------
  3651. //
  3652. // Name: BuildReply
  3653. //
  3654. // Synopsis: Extracts reply information from an internal ticket
  3655. //
  3656. // Arguments: pkitTicket - (in) ticket data comes from
  3657. // dwNonce - (in) goes into the reply
  3658. // pkrReply - (out) reply that is built
  3659. //
  3660. // Notes: BUG 456265: Need to set tsKeyExpiry properly.
  3661. // See 3.1.3, 3.3.3 of the Kerberos V5 R5.2 spec
  3662. // tsKeyExpiry is zero for GetTGSTicket, and the
  3663. // expiry time of the client's key for GetASTicket.
  3664. //
  3665. //--------------------------------------------------------------------
  3666. KERBERR
  3667. BuildReply(
  3668. IN OPTIONAL PKDC_TICKET_INFO ClientInfo,
  3669. IN ULONG Nonce,
  3670. IN PKERB_PRINCIPAL_NAME ServerName,
  3671. IN KERB_REALM ServerRealm,
  3672. IN OPTIONAL PKERB_HOST_ADDRESSES HostAddresses,
  3673. IN PKERB_TICKET Ticket,
  3674. OUT PKERB_ENCRYPTED_KDC_REPLY ReplyMessage
  3675. )
  3676. {
  3677. KERBERR KerbErr = KDC_ERR_NONE;
  3678. PKERB_ENCRYPTED_TICKET EncryptedTicket = (PKERB_ENCRYPTED_TICKET) Ticket->encrypted_part.cipher_text.value;
  3679. KERB_ENCRYPTED_KDC_REPLY ReplyBody;
  3680. LARGE_INTEGER CurrentTime;
  3681. TRACE(KDC, BuildReply, DEB_FUNCTION);
  3682. RtlZeroMemory(
  3683. &ReplyBody,
  3684. sizeof(KERB_ENCRYPTED_KDC_REPLY)
  3685. );
  3686. //
  3687. // Use the same flags field
  3688. //
  3689. ReplyBody.flags = ReplyMessage->flags;
  3690. ReplyBody.session_key = EncryptedTicket->key;
  3691. ReplyBody.last_request = (PKERB_LAST_REQUEST) MIDL_user_allocate(sizeof(KERB_LAST_REQUEST));
  3692. if (ReplyBody.last_request == NULL)
  3693. {
  3694. KerbErr = KRB_ERR_GENERIC;
  3695. goto Cleanup;
  3696. }
  3697. RtlZeroMemory(
  3698. ReplyBody.last_request,
  3699. sizeof(KERB_LAST_REQUEST)
  3700. );
  3701. ReplyBody.last_request->next = NULL;
  3702. ReplyBody.last_request->value.last_request_type = 0;
  3703. GetSystemTimeAsFileTime((PFILETIME)&CurrentTime);
  3704. KerbConvertLargeIntToGeneralizedTime(
  3705. &ReplyBody.last_request->value.last_request_value,
  3706. NULL, // no usec
  3707. &CurrentTime
  3708. );
  3709. ReplyBody.nonce = Nonce;
  3710. DsysAssert((ReplyBody.flags.length == EncryptedTicket->flags.length) &&
  3711. (ReplyBody.flags.length== 8 * sizeof(ULONG)));
  3712. //
  3713. // Assign the flags over
  3714. //
  3715. *((PULONG)ReplyBody.flags.value) = *((PULONG)EncryptedTicket->flags.value);
  3716. if (ARGUMENT_PRESENT(ClientInfo))
  3717. {
  3718. KerbConvertLargeIntToGeneralizedTime(
  3719. &ReplyBody.key_expiration,
  3720. NULL,
  3721. &ClientInfo->PasswordExpires
  3722. );
  3723. ReplyBody.bit_mask |= key_expiration_present;
  3724. }
  3725. //
  3726. // Fill in the times
  3727. //
  3728. ReplyBody.authtime = EncryptedTicket->authtime;
  3729. ReplyBody.endtime = EncryptedTicket->endtime;
  3730. if (EncryptedTicket->bit_mask & KERB_ENCRYPTED_TICKET_starttime_present)
  3731. {
  3732. ReplyBody.KERB_ENCRYPTED_KDC_REPLY_starttime =
  3733. EncryptedTicket->KERB_ENCRYPTED_TICKET_starttime;
  3734. ReplyBody.bit_mask |= KERB_ENCRYPTED_KDC_REPLY_starttime_present;
  3735. }
  3736. if (EncryptedTicket->bit_mask & KERB_ENCRYPTED_TICKET_renew_until_present)
  3737. {
  3738. ReplyBody.KERB_ENCRYPTED_KDC_REPLY_renew_until =
  3739. EncryptedTicket->KERB_ENCRYPTED_TICKET_renew_until;
  3740. ReplyBody.bit_mask |= KERB_ENCRYPTED_KDC_REPLY_renew_until_present;
  3741. }
  3742. ReplyBody.server_realm = ServerRealm;
  3743. ReplyBody.server_name = *ServerName;
  3744. //
  3745. // Fill in the host addresses
  3746. //
  3747. if (HostAddresses != NULL)
  3748. {
  3749. ReplyBody.KERB_ENCRYPTED_KDC_REPLY_client_addresses = HostAddresses;
  3750. ReplyBody.bit_mask |= KERB_ENCRYPTED_KDC_REPLY_client_addresses_present;
  3751. }
  3752. *ReplyMessage = ReplyBody;
  3753. Cleanup:
  3754. if (!KERB_SUCCESS(KerbErr))
  3755. {
  3756. if (ReplyBody.last_request != NULL)
  3757. {
  3758. MIDL_user_free(ReplyBody.last_request);
  3759. ReplyBody.last_request = NULL;
  3760. }
  3761. }
  3762. return(KerbErr);
  3763. }
  3764. //+-------------------------------------------------------------------------
  3765. //
  3766. // Function: KdcBuildSupplementalCredentials
  3767. //
  3768. // Synopsis: Builds a list of the supplemental credentials and then
  3769. // encrypts it with the supplied key
  3770. //
  3771. // Effects:
  3772. //
  3773. // Arguments:
  3774. //
  3775. // Requires:
  3776. //
  3777. // Returns:
  3778. //
  3779. // Notes:
  3780. //
  3781. //
  3782. //--------------------------------------------------------------------------
  3783. KERBERR
  3784. KdcBuildSupplementalCredentials(
  3785. IN PUSER_INTERNAL6_INFORMATION UserInfo,
  3786. IN PKERB_ENCRYPTION_KEY CredentialKey,
  3787. OUT PPAC_INFO_BUFFER * EncryptedCreds
  3788. )
  3789. {
  3790. NTSTATUS Status;
  3791. KERBERR KerbErr = KDC_ERR_NONE;
  3792. PBYTE Credentials = NULL;
  3793. ULONG CredentialSize = 0;
  3794. KERB_ENCRYPTED_DATA EncryptedData = {0};
  3795. PPAC_CREDENTIAL_INFO CredInfo = NULL;
  3796. PPAC_INFO_BUFFER ReturnCreds = NULL;
  3797. ULONG ReturnCredSize;
  3798. Status = PAC_BuildCredentials(
  3799. (PSAMPR_USER_ALL_INFORMATION)&UserInfo->I1,
  3800. &Credentials,
  3801. &CredentialSize
  3802. );
  3803. if (!NT_SUCCESS(Status))
  3804. {
  3805. KerbErr = KRB_ERR_GENERIC;
  3806. goto Cleanup;
  3807. }
  3808. KerbErr = KerbAllocateEncryptionBufferWrapper(
  3809. CredentialKey->keytype,
  3810. CredentialSize,
  3811. &EncryptedData.cipher_text.length,
  3812. &EncryptedData.cipher_text.value
  3813. );
  3814. if (!KERB_SUCCESS(KerbErr))
  3815. {
  3816. goto Cleanup;
  3817. }
  3818. KerbErr = KerbEncryptDataEx(
  3819. &EncryptedData,
  3820. CredentialSize,
  3821. Credentials,
  3822. KERB_NO_KEY_VERSION,
  3823. KERB_NON_KERB_SALT,
  3824. CredentialKey
  3825. );
  3826. if (!KERB_SUCCESS(KerbErr))
  3827. {
  3828. goto Cleanup;
  3829. }
  3830. //
  3831. // Compute the size of the blob returned
  3832. //
  3833. ReturnCredSize = sizeof(PAC_INFO_BUFFER) +
  3834. FIELD_OFFSET(PAC_CREDENTIAL_INFO, Data) +
  3835. EncryptedData.cipher_text.length ;
  3836. ReturnCreds = (PPAC_INFO_BUFFER) MIDL_user_allocate(ReturnCredSize);
  3837. if (ReturnCreds == NULL)
  3838. {
  3839. KerbErr = KRB_ERR_GENERIC;
  3840. goto Cleanup;
  3841. }
  3842. //
  3843. // Fill in the outer structure
  3844. //
  3845. ReturnCreds->ulType = PAC_CREDENTIAL_TYPE;
  3846. ReturnCreds->cbBufferSize = ReturnCredSize - sizeof(PAC_INFO_BUFFER);
  3847. ReturnCreds->Data = (PBYTE) (ReturnCreds + 1);
  3848. CredInfo = (PPAC_CREDENTIAL_INFO) ReturnCreds->Data;
  3849. //
  3850. // Fill in the inner structure
  3851. //
  3852. CredInfo->EncryptionType = EncryptedData.encryption_type;
  3853. if (EncryptedData.bit_mask & version_present)
  3854. {
  3855. CredInfo->Version = EncryptedData.version;
  3856. }
  3857. else
  3858. {
  3859. CredInfo->Version = 0;
  3860. }
  3861. RtlCopyMemory(
  3862. CredInfo->Data,
  3863. EncryptedData.cipher_text.value,
  3864. EncryptedData.cipher_text.length
  3865. );
  3866. *EncryptedCreds = ReturnCreds;
  3867. ReturnCreds = NULL;
  3868. Cleanup:
  3869. if (Credentials != NULL)
  3870. {
  3871. MIDL_user_free(Credentials);
  3872. }
  3873. if (ReturnCreds != NULL)
  3874. {
  3875. MIDL_user_free(ReturnCreds);
  3876. }
  3877. if (EncryptedData.cipher_text.value != NULL)
  3878. {
  3879. MIDL_user_free(EncryptedData.cipher_text.value);
  3880. }
  3881. return (KerbErr);
  3882. }
  3883. //+-------------------------------------------------------------------------
  3884. //
  3885. // Function: KdcBuildPacVerifier
  3886. //
  3887. // Synopsis: Builds a verifier for the PAC. This structure ties the
  3888. // PAC to the ticket by including the client name and
  3889. // ticket authime in the PAC.
  3890. //
  3891. // Effects:
  3892. //
  3893. // Arguments:
  3894. //
  3895. // Requires:
  3896. //
  3897. // Returns:
  3898. //
  3899. // Notes:
  3900. //
  3901. //
  3902. //--------------------------------------------------------------------------
  3903. KERBERR
  3904. KdcBuildPacVerifier(
  3905. IN PTimeStamp ClientId,
  3906. IN PUNICODE_STRING ClientName,
  3907. OUT PPAC_INFO_BUFFER * Verifier
  3908. )
  3909. {
  3910. ULONG ReturnVerifierSize = 0;
  3911. PPAC_CLIENT_INFO ClientInfo = NULL;
  3912. PPAC_INFO_BUFFER ReturnVerifier = NULL;
  3913. //
  3914. // Compute the size of the blob returned
  3915. //
  3916. ReturnVerifierSize = sizeof(PAC_INFO_BUFFER) + sizeof(PAC_CLIENT_INFO) +
  3917. ClientName->Length - sizeof(WCHAR) * ANYSIZE_ARRAY;
  3918. ReturnVerifier = (PPAC_INFO_BUFFER) MIDL_user_allocate(ReturnVerifierSize);
  3919. if (ReturnVerifier == NULL)
  3920. {
  3921. return(KRB_ERR_GENERIC);
  3922. }
  3923. //
  3924. // Fill in the outer structure
  3925. //
  3926. ReturnVerifier->ulType = PAC_CLIENT_INFO_TYPE;
  3927. ReturnVerifier->cbBufferSize = ReturnVerifierSize - sizeof(PAC_INFO_BUFFER);
  3928. ReturnVerifier->Data = (PBYTE) (ReturnVerifier + 1);
  3929. ClientInfo = (PPAC_CLIENT_INFO) ReturnVerifier->Data;
  3930. ClientInfo->ClientId = *ClientId;
  3931. ClientInfo->NameLength = ClientName->Length;
  3932. RtlCopyMemory(
  3933. ClientInfo->Name,
  3934. ClientName->Buffer,
  3935. ClientName->Length
  3936. );
  3937. *Verifier = ReturnVerifier;
  3938. return(KDC_ERR_NONE);
  3939. }
  3940. //+---------------------------------------------------------------------------
  3941. //
  3942. // Name: KdcIsOurDomain
  3943. //
  3944. // Synopsis: Tells us if this sid is from our domain.
  3945. //
  3946. // Arguments:
  3947. //
  3948. //
  3949. //+---------------------------------------------------------------------------
  3950. BOOLEAN
  3951. KdcIsOurDomain(
  3952. IN PSID InputSid,
  3953. OUT PULONG Rid
  3954. )
  3955. {
  3956. BOOLEAN fRet = FALSE;
  3957. SID *Sid = (SID*) InputSid;
  3958. Sid->SubAuthorityCount--;
  3959. if (RtlEqualSid( Sid, GlobalDomainSid ))
  3960. {
  3961. D_DebugLog((DEB_T_PAC, "%p\n", Sid));
  3962. D_DebugLog((DEB_T_PAC, "%p add subauthority %i\n", &Sid->SubAuthority[Sid->SubAuthorityCount], Sid->SubAuthorityCount));
  3963. *Rid = Sid->SubAuthority[Sid->SubAuthorityCount];
  3964. D_DebugLog((DEB_T_PAC, "Rid %x\n", (*Rid)));
  3965. fRet = TRUE;
  3966. }
  3967. Sid->SubAuthorityCount++;
  3968. return fRet;
  3969. }
  3970. //+---------------------------------------------------------------------------
  3971. //
  3972. // Name: GetPacAndSuppCred
  3973. //
  3974. // Synopsis:
  3975. //
  3976. // Arguments:
  3977. //
  3978. // Notes: ppPac is allocated using CoTaskMemAlloc and
  3979. // ppadlSuppCreds is allocated using operator 'new'.
  3980. //
  3981. //+---------------------------------------------------------------------------
  3982. KERBERR
  3983. GetPacAndSuppCred(
  3984. IN PUSER_INTERNAL6_INFORMATION UserInfo,
  3985. IN PSID_AND_ATTRIBUTES_LIST GroupMembership,
  3986. IN ULONG SignatureSize,
  3987. IN OPTIONAL PKERB_ENCRYPTION_KEY CredentialKey,
  3988. IN OPTIONAL PTimeStamp ClientId,
  3989. IN OPTIONAL PUNICODE_STRING ClientName,
  3990. OUT PPACTYPE * Pac,
  3991. OUT PKERB_EXT_ERROR pExtendedError
  3992. )
  3993. {
  3994. KERBERR KerbErr = KDC_ERR_NONE;
  3995. NTSTATUS Status;
  3996. PPACTYPE NewPac = NULL;
  3997. PPAC_INFO_BUFFER Credentials[2];
  3998. ULONG AdditionalDataCount = 0;
  3999. ULONG ExtraSidCount = 0, GroupCount = 0, Rid;
  4000. SID_AND_ATTRIBUTES_LIST ExtraSidList = {0};
  4001. PSID_AND_ATTRIBUTES ExtraSids = NULL;
  4002. SAMPR_GET_GROUPS_BUFFER GroupsBuffer = {0};
  4003. PGROUP_MEMBERSHIP Groups = NULL;
  4004. TRACE(KDC, GetPACandSuppCred, DEB_FUNCTION);
  4005. RtlZeroMemory(
  4006. Credentials,
  4007. sizeof(Credentials)
  4008. );
  4009. *Pac = NULL;
  4010. D_DebugLog((DEB_T_PAC,
  4011. "GetPacAndSuppCred User %wZ, FullName %wZ, Upn %wZ, UserId %#x, UserAccountControl %#x, ExtendedFields %#x, WhichFields %#x\n",
  4012. &UserInfo->I1.UserName,
  4013. &UserInfo->I1.FullName,
  4014. &UserInfo->UPN,
  4015. &UserInfo->I1.UserId,
  4016. UserInfo->I1.UserAccountControl,
  4017. UserInfo->ExtendedFields,
  4018. UserInfo->I1.WhichFields));
  4019. if (ARGUMENT_PRESENT(CredentialKey) &&
  4020. (CredentialKey->keyvalue.value != NULL) )
  4021. {
  4022. KerbErr = KdcBuildSupplementalCredentials(
  4023. UserInfo,
  4024. CredentialKey,
  4025. &Credentials[AdditionalDataCount]
  4026. );
  4027. if (!KERB_SUCCESS(KerbErr))
  4028. {
  4029. goto Cleanup;
  4030. }
  4031. AdditionalDataCount++;
  4032. }
  4033. if (ARGUMENT_PRESENT(ClientId))
  4034. {
  4035. KerbErr = KdcBuildPacVerifier(
  4036. ClientId,
  4037. ClientName,
  4038. &Credentials[AdditionalDataCount]
  4039. );
  4040. if (!KERB_SUCCESS(KerbErr))
  4041. {
  4042. goto Cleanup;
  4043. }
  4044. AdditionalDataCount++;
  4045. }
  4046. //
  4047. // Now we have to build up our PSAMPR_GET_GROUPS buffer. This is
  4048. // meant to reduce the overall PAC size. Be pessimistic about the buffer size
  4049. // we'll need.
  4050. //
  4051. SafeAllocaAllocate( Groups, ( GroupMembership->Count * sizeof(GROUP_MEMBERSHIP) ));
  4052. if ( Groups == NULL )
  4053. {
  4054. KerbErr = KRB_ERR_GENERIC;
  4055. goto Cleanup;
  4056. }
  4057. SafeAllocaAllocate( ExtraSids, ( GroupMembership->Count * sizeof(SID_AND_ATTRIBUTES) ));
  4058. if ( ExtraSids == NULL )
  4059. {
  4060. KerbErr = KRB_ERR_GENERIC;
  4061. goto Cleanup;
  4062. }
  4063. for ( ULONG i = 0 ; i < GroupMembership->Count ; i++ )
  4064. {
  4065. //
  4066. // If this is in our domain, add it to the Groups.
  4067. //
  4068. if ( KdcIsOurDomain( GroupMembership->SidAndAttributes[i].Sid, &Rid ))
  4069. {
  4070. D_DebugLog((DEB_T_PAC, "Adding %i from %p\n", Rid, GroupMembership->SidAndAttributes[i].Sid ));
  4071. Groups[GroupCount].RelativeId = Rid;
  4072. Groups[GroupCount].Attributes = GroupMembership->SidAndAttributes[i].Attributes;
  4073. GroupCount++;
  4074. }
  4075. else
  4076. {
  4077. D_DebugLog(( DEB_T_PAC, "Adding %p to extrasids\n", GroupMembership->SidAndAttributes[i].Sid ));
  4078. ExtraSids[ExtraSidCount] = GroupMembership->SidAndAttributes[i];
  4079. ExtraSidCount++;
  4080. }
  4081. }
  4082. GroupsBuffer.Groups = Groups;
  4083. GroupsBuffer.MembershipCount = GroupCount;
  4084. ExtraSidList.SidAndAttributes = ExtraSids;
  4085. ExtraSidList.Count = ExtraSidCount;
  4086. //
  4087. // NOTE: this is o.k. because we don't lock the secdata while acecssing
  4088. // the machine name
  4089. //
  4090. Status = PAC_Init(
  4091. (PSAMPR_USER_ALL_INFORMATION)&UserInfo->I1,
  4092. &GroupsBuffer,
  4093. &ExtraSidList,
  4094. GlobalDomainSid,
  4095. &GlobalDomainName,
  4096. SecData.MachineName(),
  4097. SignatureSize,
  4098. AdditionalDataCount,
  4099. Credentials,
  4100. &NewPac
  4101. );
  4102. if (!NT_SUCCESS(Status))
  4103. {
  4104. DebugLog((DEB_ERROR,"Failed to init pac: 0x%x\n",Status));
  4105. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  4106. KerbErr = KRB_ERR_GENERIC;
  4107. goto Cleanup;
  4108. }
  4109. *Pac = NewPac;
  4110. NewPac = NULL;
  4111. Cleanup:
  4112. while (AdditionalDataCount > 0)
  4113. {
  4114. if (Credentials[--AdditionalDataCount] != NULL)
  4115. {
  4116. MIDL_user_free(Credentials[AdditionalDataCount]);
  4117. }
  4118. }
  4119. SafeAllocaFree( Groups );
  4120. SafeAllocaFree( ExtraSids );
  4121. if (NewPac != NULL)
  4122. {
  4123. MIDL_user_free(NewPac);
  4124. }
  4125. return(KerbErr);
  4126. }
  4127. //+-------------------------------------------------------------------------
  4128. //
  4129. // Function: KdcFreeInternalTicket
  4130. //
  4131. // Synopsis: frees a constructed ticket
  4132. //
  4133. // Effects:
  4134. //
  4135. // Arguments:
  4136. //
  4137. // Requires:
  4138. //
  4139. // Returns:
  4140. //
  4141. // Notes:
  4142. //
  4143. //
  4144. //--------------------------------------------------------------------------
  4145. VOID
  4146. KdcFreeInternalTicket(
  4147. IN PKERB_TICKET Ticket
  4148. )
  4149. {
  4150. PKERB_ENCRYPTED_TICKET EncryptedTicket = (PKERB_ENCRYPTED_TICKET) Ticket->encrypted_part.cipher_text.value;
  4151. TRACE(KDC, KdcFreeInternalTicket, DEB_FUNCTION);
  4152. if (EncryptedTicket != NULL)
  4153. {
  4154. KerbFreeKey(
  4155. &EncryptedTicket->key
  4156. );
  4157. KerbFreePrincipalName(&EncryptedTicket->client_name);
  4158. KerbFreeRealm(&EncryptedTicket->client_realm);
  4159. if (EncryptedTicket->KERB_ENCRYPTED_TICKET_authorization_data != NULL)
  4160. {
  4161. KerbFreeAuthData(EncryptedTicket->KERB_ENCRYPTED_TICKET_authorization_data);
  4162. }
  4163. if (EncryptedTicket->transited.contents.value != NULL)
  4164. {
  4165. MIDL_user_free(EncryptedTicket->transited.contents.value);
  4166. EncryptedTicket->transited.contents.value = 0;
  4167. EncryptedTicket->transited.contents.length = 0;
  4168. }
  4169. Ticket->encrypted_part.cipher_text.value = NULL;
  4170. Ticket->encrypted_part.cipher_text.length = 0;
  4171. }
  4172. KerbFreePrincipalName(
  4173. &Ticket->server_name
  4174. );
  4175. }
  4176. //+-------------------------------------------------------------------------
  4177. //
  4178. // Function: KdcFreeKdcReply
  4179. //
  4180. // Synopsis: frees a kdc reply
  4181. //
  4182. // Effects:
  4183. //
  4184. // Arguments:
  4185. //
  4186. // Requires:
  4187. //
  4188. // Returns:
  4189. //
  4190. // Notes:
  4191. //
  4192. //
  4193. //--------------------------------------------------------------------------
  4194. VOID
  4195. KdcFreeKdcReply(
  4196. IN PKERB_KDC_REPLY Reply
  4197. )
  4198. {
  4199. TRACE(KDC, KdcFreeKdcReply, DEB_FUNCTION);
  4200. KerbFreePrincipalName(&Reply->ticket.server_name);
  4201. if (Reply->ticket.encrypted_part.cipher_text.value != NULL)
  4202. {
  4203. MIDL_user_free(Reply->ticket.encrypted_part.cipher_text.value);
  4204. }
  4205. if (Reply->encrypted_part.cipher_text.value != NULL)
  4206. {
  4207. MIDL_user_free(Reply->encrypted_part.cipher_text.value);
  4208. }
  4209. if (Reply->KERB_KDC_REPLY_preauth_data != NULL)
  4210. {
  4211. KerbFreePreAuthData((PKERB_PA_DATA_LIST) Reply->KERB_KDC_REPLY_preauth_data);
  4212. }
  4213. }
  4214. //+-------------------------------------------------------------------------
  4215. //
  4216. // Function: KdcFreeKdcReplyBody
  4217. //
  4218. // Synopsis: frees a constructed KDC reply body
  4219. //
  4220. // Effects:
  4221. //
  4222. // Arguments:
  4223. //
  4224. // Requires:
  4225. //
  4226. // Returns:
  4227. //
  4228. // Notes:
  4229. //
  4230. //
  4231. //--------------------------------------------------------------------------
  4232. VOID
  4233. KdcFreeKdcReplyBody(
  4234. IN PKERB_ENCRYPTED_KDC_REPLY ReplyBody
  4235. )
  4236. {
  4237. TRACE(KDC, KdcFreeKdcReplyBody, DEB_FUNCTION);
  4238. //
  4239. // The names & the session key are just pointers into the ticket,
  4240. // so they don't need to be freed.
  4241. //
  4242. if (ReplyBody->last_request != NULL)
  4243. {
  4244. MIDL_user_free(ReplyBody->last_request);
  4245. ReplyBody->last_request = NULL;
  4246. }
  4247. ReplyBody->KERB_ENCRYPTED_KDC_REPLY_client_addresses = NULL;
  4248. }
  4249. //+-------------------------------------------------------------------------
  4250. //
  4251. // Function: KdcVerifyTgsChecksum
  4252. //
  4253. // Synopsis: Verify the checksum on a TGS request
  4254. //
  4255. // Effects:
  4256. //
  4257. // Arguments:
  4258. //
  4259. // Requires:
  4260. //
  4261. // Returns:
  4262. //
  4263. // Notes:
  4264. //
  4265. //
  4266. //--------------------------------------------------------------------------
  4267. KERBERR
  4268. KdcVerifyTgsChecksum(
  4269. IN PKERB_KDC_REQUEST_BODY RequestBody,
  4270. IN PKERB_ENCRYPTION_KEY Key,
  4271. IN PKERB_CHECKSUM OldChecksum
  4272. )
  4273. {
  4274. PCHECKSUM_FUNCTION ChecksumFunction;
  4275. PCHECKSUM_BUFFER CheckBuffer = NULL;
  4276. KERB_MESSAGE_BUFFER MarshalledRequestBody = {0, NULL};
  4277. NTSTATUS Status;
  4278. KERBERR KerbErr = KDC_ERR_NONE;
  4279. KERB_CHECKSUM Checksum = {0};
  4280. Status = CDLocateCheckSum(
  4281. OldChecksum->checksum_type,
  4282. &ChecksumFunction
  4283. );
  4284. if (!NT_SUCCESS(Status))
  4285. {
  4286. KerbErr = KDC_ERR_SUMTYPE_NOSUPP;
  4287. goto Cleanup;
  4288. }
  4289. //
  4290. // Allocate enough space for the checksum
  4291. //
  4292. Checksum.checksum.value = (PUCHAR) MIDL_user_allocate(ChecksumFunction->CheckSumSize);
  4293. if (Checksum.checksum.value == NULL)
  4294. {
  4295. KerbErr = KRB_ERR_GENERIC;
  4296. goto Cleanup;
  4297. }
  4298. Checksum.checksum.length = ChecksumFunction->CheckSumSize;
  4299. //
  4300. // Initialize the checksum
  4301. //
  4302. if ((OldChecksum->checksum_type == KERB_CHECKSUM_REAL_CRC32) ||
  4303. (OldChecksum->checksum_type == KERB_CHECKSUM_CRC32))
  4304. {
  4305. if (ChecksumFunction->Initialize)
  4306. {
  4307. Status = ChecksumFunction->Initialize(
  4308. 0,
  4309. &CheckBuffer
  4310. );
  4311. }
  4312. else
  4313. {
  4314. KerbErr = KRB_ERR_GENERIC;
  4315. }
  4316. }
  4317. else
  4318. {
  4319. if (NULL != ChecksumFunction->InitializeEx2)
  4320. {
  4321. Status = ChecksumFunction->InitializeEx2(
  4322. Key->keyvalue.value,
  4323. (ULONG) Key->keyvalue.length,
  4324. OldChecksum->checksum.value,
  4325. KERB_TGS_REQ_AP_REQ_AUTH_CKSUM_SALT,
  4326. &CheckBuffer
  4327. );
  4328. }
  4329. else if (ChecksumFunction->InitializeEx)
  4330. {
  4331. Status = ChecksumFunction->InitializeEx(
  4332. Key->keyvalue.value,
  4333. (ULONG) Key->keyvalue.length,
  4334. KERB_TGS_REQ_AP_REQ_AUTH_CKSUM_SALT,
  4335. &CheckBuffer
  4336. );
  4337. }
  4338. else
  4339. {
  4340. KerbErr = KRB_ERR_GENERIC;
  4341. }
  4342. }
  4343. if (!NT_SUCCESS(Status))
  4344. {
  4345. KerbErr = KRB_ERR_GENERIC;
  4346. }
  4347. if (!KERB_SUCCESS(KerbErr))
  4348. {
  4349. goto Cleanup;
  4350. }
  4351. KerbErr = KerbPackData(
  4352. RequestBody,
  4353. KERB_MARSHALLED_REQUEST_BODY_PDU,
  4354. &MarshalledRequestBody.BufferSize,
  4355. &MarshalledRequestBody.Buffer
  4356. );
  4357. if (!KERB_SUCCESS(KerbErr))
  4358. {
  4359. goto Cleanup;
  4360. }
  4361. //
  4362. // Now checksum the buffer
  4363. //
  4364. ChecksumFunction->Sum(
  4365. CheckBuffer,
  4366. MarshalledRequestBody.BufferSize,
  4367. MarshalledRequestBody.Buffer
  4368. );
  4369. ChecksumFunction->Finalize(
  4370. CheckBuffer,
  4371. Checksum.checksum.value
  4372. );
  4373. //
  4374. // Now compare
  4375. //
  4376. if ((OldChecksum->checksum.length != Checksum.checksum.length) ||
  4377. !RtlEqualMemory(
  4378. OldChecksum->checksum.value,
  4379. Checksum.checksum.value,
  4380. Checksum.checksum.length
  4381. ))
  4382. {
  4383. DebugLog((DEB_ERROR,"Checksum on TGS request body did not match\n"));
  4384. KerbErr = KRB_AP_ERR_MODIFIED;
  4385. goto Cleanup;
  4386. }
  4387. Cleanup:
  4388. if (CheckBuffer != NULL)
  4389. {
  4390. ChecksumFunction->Finish(&CheckBuffer);
  4391. }
  4392. if (MarshalledRequestBody.Buffer != NULL)
  4393. {
  4394. MIDL_user_free(MarshalledRequestBody.Buffer);
  4395. }
  4396. if (Checksum.checksum.value != NULL)
  4397. {
  4398. MIDL_user_free(Checksum.checksum.value);
  4399. }
  4400. return(KerbErr);
  4401. }
  4402. //+-------------------------------------------------------------------------
  4403. //
  4404. // Function: KdcVerifyKdcRequest
  4405. //
  4406. // Synopsis: Verifies that the AP request accompanying a TGS or PAC request
  4407. // is valid.
  4408. //
  4409. // Effects:
  4410. //
  4411. // Arguments: ApRequest - The AP request to verify
  4412. // UnmarshalledRequest - The unmarshalled request,
  4413. // returned to avoid needing to
  4414. // EncryptedTicket - Receives the ticket granting ticket
  4415. // SessionKey - receives the key to use in the reply
  4416. //
  4417. // Requires:
  4418. //
  4419. // Returns: kerberos errors
  4420. //
  4421. // Notes:
  4422. //
  4423. //
  4424. //--------------------------------------------------------------------------
  4425. KERBERR
  4426. KdcVerifyKdcRequest(
  4427. IN PUCHAR RequestMessage,
  4428. IN ULONG RequestSize,
  4429. IN OPTIONAL SOCKADDR * ClientAddress,
  4430. IN BOOLEAN IsKdcRequest,
  4431. OUT OPTIONAL PKERB_AP_REQUEST * UnmarshalledRequest,
  4432. OUT OPTIONAL PKERB_AUTHENTICATOR * UnmarshalledAuthenticator,
  4433. OUT PKERB_ENCRYPTED_TICKET *EncryptedTicket,
  4434. OUT PKERB_ENCRYPTION_KEY SessionKey,
  4435. OUT OPTIONAL PKERB_ENCRYPTION_KEY ServerKey,
  4436. OUT PKDC_TICKET_INFO ServerTicketInfo,
  4437. OUT PBOOLEAN UseSubKey,
  4438. OUT PKERB_EXT_ERROR pExtendedError
  4439. )
  4440. {
  4441. KERBERR KerbErr = KDC_ERR_NONE;
  4442. PKERB_AP_REQUEST Request = NULL;
  4443. PKERB_ENCRYPTED_TICKET EncryptPart = NULL;
  4444. PKERB_AUTHENTICATOR Authenticator = NULL;
  4445. PKERB_INTERNAL_NAME ServerName = NULL;
  4446. UNICODE_STRING LocalServerRealm = {0};
  4447. UNICODE_STRING ServerRealm;
  4448. PKERB_ENCRYPTION_KEY KeyToUse;
  4449. BOOLEAN Referral = FALSE;
  4450. TRACE(KDC, KdcVerifyKdcRequest, DEB_FUNCTION);
  4451. ServerRealm.Buffer = NULL;
  4452. //
  4453. // First unpack the KDC request.
  4454. //
  4455. KerbErr = KerbUnpackApRequest(
  4456. RequestMessage,
  4457. RequestSize,
  4458. &Request
  4459. );
  4460. if (!KERB_SUCCESS(KerbErr))
  4461. {
  4462. DebugLog((DEB_ERROR, "Failed to unpack KDC request: 0x%x\n", KerbErr));
  4463. KerbErr = KDC_ERR_NO_RESPONSE;
  4464. goto Cleanup;
  4465. }
  4466. KerbErr = KerbConvertPrincipalNameToKdcName(
  4467. &ServerName,
  4468. &Request->ticket.server_name
  4469. );
  4470. if (!KERB_SUCCESS(KerbErr))
  4471. {
  4472. goto Cleanup;
  4473. }
  4474. KerbErr = KerbConvertRealmToUnicodeString(
  4475. &ServerRealm,
  4476. &Request->ticket.realm
  4477. );
  4478. if (!KERB_SUCCESS(KerbErr))
  4479. {
  4480. goto Cleanup;
  4481. }
  4482. //
  4483. // Get ticket info for the server
  4484. //
  4485. KerbErr = KdcNormalize(
  4486. ServerName,
  4487. &ServerRealm,
  4488. &ServerRealm,
  4489. NULL,
  4490. KDC_NAME_SERVER | KDC_NAME_INBOUND,
  4491. FALSE, // do not restrict user accounts (user2user)
  4492. &Referral,
  4493. &LocalServerRealm,
  4494. ServerTicketInfo,
  4495. pExtendedError,
  4496. NULL, // no user handle
  4497. 0L, // no fields to fetch
  4498. 0L, // no extended fileds to fetch
  4499. NULL, // no user all
  4500. NULL // no group membership
  4501. );
  4502. if (!KERB_SUCCESS(KerbErr))
  4503. {
  4504. DebugLog((DEB_WARN, "KdcVerifyKdcRequest failed to get TGS ticket to service in another realm %#x: ", KerbErr));
  4505. KerbPrintKdcName(DEB_WARN, ServerName);
  4506. goto Cleanup;
  4507. }
  4508. //
  4509. // Now Check the ticket
  4510. //
  4511. Retry:
  4512. KeyToUse = KerbGetKeyFromList(
  4513. ServerTicketInfo->Passwords,
  4514. Request->ticket.encrypted_part.encryption_type
  4515. );
  4516. if (KeyToUse == NULL)
  4517. {
  4518. DebugLog((DEB_ERROR,"Server does not have proper key to decrypt ticket: 0x%x\n",
  4519. Request->ticket.encrypted_part.encryption_type ));
  4520. //
  4521. // If this is our second attempt, do not overwrite the error code we had
  4522. //
  4523. if (KERB_SUCCESS(KerbErr))
  4524. {
  4525. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  4526. }
  4527. goto Cleanup;
  4528. }
  4529. //
  4530. // We don't need to supply a service name or service because we've looked up
  4531. // the account locally.
  4532. //
  4533. KerbErr = KerbCheckTicket(
  4534. &Request->ticket,
  4535. &Request->authenticator,
  4536. KeyToUse,
  4537. Authenticators,
  4538. &SkewTime,
  4539. 0, // zero service names
  4540. NULL, // any service
  4541. NULL,
  4542. TRUE, // must check for clock_skew per RFC bug #322448 & 385404 (time skew only)
  4543. IsKdcRequest,
  4544. &EncryptPart,
  4545. &Authenticator,
  4546. NULL,
  4547. SessionKey,
  4548. UseSubKey
  4549. );
  4550. if (!KERB_SUCCESS(KerbErr))
  4551. {
  4552. DebugLog((DEB_ERROR,"Failed to check ticket : 0x%x for",KerbErr));
  4553. KerbPrintKdcName(DEB_ERROR, ServerName);
  4554. //
  4555. // If an old password is available, give it a try. We remove the
  4556. // current password & put the old password in here.
  4557. //
  4558. if (ServerTicketInfo->OldPasswords && (KerbErr == KRB_AP_ERR_MODIFIED))
  4559. {
  4560. MIDL_user_free(ServerTicketInfo->Passwords);
  4561. ServerTicketInfo->Passwords = ServerTicketInfo->OldPasswords;
  4562. ServerTicketInfo->OldPasswords = NULL;
  4563. goto Retry;
  4564. }
  4565. //
  4566. // Here's the case where we're trying to use an expired TGT. Have
  4567. // the client retry using a new TGT
  4568. //
  4569. if (KerbErr == KRB_AP_ERR_TKT_EXPIRED)
  4570. {
  4571. FILL_EXT_ERROR_EX(pExtendedError, STATUS_TIME_DIFFERENCE_AT_DC, FILENO, __LINE__);
  4572. }
  4573. goto Cleanup;
  4574. }
  4575. //
  4576. // Verify the address from the ticket
  4577. //
  4578. // NOTE: the check mandated by RFC1510 can be thwarted by a registry setting
  4579. // (KdcDontCheckAddresses) to allow seamless operation through NATs
  4580. //
  4581. if ((EncryptPart->bit_mask & KERB_ENCRYPTED_TICKET_client_addresses_present) &&
  4582. ARGUMENT_PRESENT(ClientAddress) &&
  4583. !KdcDontCheckAddresses)
  4584. {
  4585. ULONG TicketFlags = KerbConvertFlagsToUlong(&EncryptPart->flags);
  4586. //
  4587. // Only check initial tickets
  4588. //
  4589. if ((TicketFlags & (KERB_TICKET_FLAGS_forwarded | KERB_TICKET_FLAGS_proxy)) == 0)
  4590. {
  4591. if ( !KerbVerifyClientAddress(
  4592. ClientAddress,
  4593. EncryptPart->KERB_ENCRYPTED_TICKET_client_addresses ))
  4594. {
  4595. KerbErr = KRB_AP_ERR_BADADDR;
  4596. DebugLog((DEB_ERROR,"Client sent request with wrong address\n"));
  4597. goto Cleanup;
  4598. }
  4599. }
  4600. }
  4601. //
  4602. // Verify that if the server is a trusted domain account, that it is an
  4603. // acceptable ticket (transitively). Verify that for non transitive
  4604. // trust the client realm is the same as the requesting ticket realm
  4605. //
  4606. if (((ServerTicketInfo->fTicketOpts & AUTH_REQ_TRANSITIVE_TRUST) == 0) &&
  4607. (ServerTicketInfo->UserId != DOMAIN_USER_RID_KRBTGT))
  4608. {
  4609. if (!KerbCompareRealmNames(
  4610. &EncryptPart->client_realm,
  4611. &Request->ticket.realm
  4612. ))
  4613. {
  4614. //
  4615. // Could be a S4USelf request, in which case, we're looping back to local domain
  4616. //
  4617. if (!SecData.IsOurRealm(&EncryptPart->client_realm))
  4618. {
  4619. DebugLog((DEB_WARN, "KdcVerifyKdcRequest client from realm %s attempted to access non transitve trust via %s : illegal\n",
  4620. &EncryptPart->client_realm,
  4621. &Request->ticket.realm
  4622. ));
  4623. KerbErr = KDC_ERR_PATH_NOT_ACCEPTED;
  4624. goto Cleanup;
  4625. }
  4626. }
  4627. }
  4628. //
  4629. // If the caller wanted the server key, return it here.
  4630. //
  4631. if (ServerKey != NULL)
  4632. {
  4633. KerbErr = KerbDuplicateKey(
  4634. ServerKey,
  4635. KeyToUse
  4636. );
  4637. if (!KERB_SUCCESS(KerbErr))
  4638. {
  4639. goto Cleanup;
  4640. }
  4641. }
  4642. *EncryptedTicket = EncryptPart;
  4643. EncryptPart = NULL;
  4644. if (ARGUMENT_PRESENT(UnmarshalledRequest))
  4645. {
  4646. *UnmarshalledRequest = Request;
  4647. Request = NULL;
  4648. }
  4649. if (ARGUMENT_PRESENT(UnmarshalledAuthenticator))
  4650. {
  4651. *UnmarshalledAuthenticator = Authenticator;
  4652. Authenticator = NULL;
  4653. }
  4654. Cleanup:
  4655. KerbFreeApRequest(Request);
  4656. KerbFreeString(&LocalServerRealm);
  4657. KerbFreeKdcName(&ServerName);
  4658. KerbFreeString(&ServerRealm);
  4659. KerbFreeAuthenticator(Authenticator);
  4660. KerbFreeTicket(EncryptPart);
  4661. return(KerbErr);
  4662. }
  4663. #if DBG
  4664. void
  4665. PrintRequest( ULONG ulDebLevel, PKERB_KDC_REQUEST_BODY Request )
  4666. {
  4667. TRACE(KDC, PrintRequest, DEB_FUNCTION);
  4668. }
  4669. void
  4670. PrintTicket( ULONG ulDebLevel,
  4671. char * pszMessage,
  4672. PKERB_TICKET pkitTicket)
  4673. {
  4674. TRACE(KDC, PrintTicket, DEB_FUNCTION);
  4675. }
  4676. #endif // DBG