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

5099 lines
134 KiB

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