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.

1940 lines
49 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: logonses.cxx
  8. //
  9. // Contents: Code for managing the global list of logon sessions
  10. //
  11. //
  12. // History: 16-April-1996 Created MikeSw
  13. //
  14. //------------------------------------------------------------------------
  15. #include <kerb.hxx>
  16. #define LOGONSES_ALLOCATE
  17. #include <kerbp.h>
  18. #ifdef DEBUG_SUPPORT
  19. static TCHAR THIS_FILE[]=TEXT(__FILE__);
  20. #endif
  21. //+-------------------------------------------------------------------------
  22. //
  23. // Function: KerbInitLogonSessionList
  24. //
  25. // Synopsis: Initializes logon session list
  26. //
  27. // Effects: allocates a resources
  28. //
  29. // Arguments: none
  30. //
  31. // Requires:
  32. //
  33. // Returns: STATUS_SUCCESS on success, other error codes
  34. // on failure
  35. //
  36. // Notes:
  37. //
  38. //
  39. //--------------------------------------------------------------------------
  40. NTSTATUS
  41. KerbInitLogonSessionList(
  42. VOID
  43. )
  44. {
  45. NTSTATUS Status;
  46. Status = KerbInitializeList( &KerbLogonSessionList );
  47. if (!NT_SUCCESS(Status))
  48. {
  49. goto Cleanup;
  50. }
  51. KerberosLogonSessionsInitialized = TRUE;
  52. Cleanup:
  53. if (!NT_SUCCESS(Status))
  54. {
  55. KerbFreeList( &KerbLogonSessionList);
  56. }
  57. return(Status);
  58. }
  59. //+-------------------------------------------------------------------------
  60. //
  61. //
  62. // Function: KerbInitNetworkServiceLoopbackDetection
  63. //
  64. // Synopsis: Initialize the network service session loopback detection
  65. //
  66. // Effects: Allocates a resources
  67. //
  68. // Arguments: none
  69. //
  70. // Requires:
  71. //
  72. // Returns: STATUS_SUCCESS on success, other error codes on failure
  73. //
  74. // Notes:
  75. //
  76. //--------------------------------------------------------------------------
  77. NTSTATUS
  78. KerbInitNetworkServiceLoopbackDetection(
  79. VOID
  80. )
  81. {
  82. NTSTATUS Status = STATUS_SUCCESS;
  83. InitializeListHead(&KerbNetworkServiceSKeyList);
  84. #if DBG
  85. KerbcSKeyEntries = 0;
  86. #endif
  87. KerbhSKeyTimerQueue = NULL;
  88. __try
  89. {
  90. RtlInitializeResource(&KerbNetworkServiceSKeyLock);
  91. }
  92. __except(EXCEPTION_EXECUTE_HANDLER)
  93. {
  94. Status = STATUS_INSUFFICIENT_RESOURCES;
  95. }
  96. return Status;
  97. }
  98. //+-------------------------------------------------------------------------
  99. //
  100. // Function: KerbFreeNetworkServiceSKeyListAndLock
  101. //
  102. // Synopsis: Free the network service session key list and its lock
  103. //
  104. // Effects: Frees a resources
  105. //
  106. // Arguments: none
  107. //
  108. // Requires:
  109. //
  110. // Returns:
  111. //
  112. // Notes:
  113. //
  114. //--------------------------------------------------------------------------
  115. VOID
  116. KerbFreeNetworkServiceSKeyListAndLock(
  117. VOID
  118. )
  119. {
  120. if (RtlAcquireResourceExclusive(&KerbNetworkServiceSKeyLock, TRUE))
  121. {
  122. for (LIST_ENTRY* pListEntry = KerbNetworkServiceSKeyList.Flink;
  123. pListEntry != &KerbNetworkServiceSKeyList;
  124. pListEntry = pListEntry->Flink)
  125. {
  126. KERB_SESSION_KEY_ENTRY* pSKeyEntry = CONTAINING_RECORD(pListEntry, KERB_SESSION_KEY_ENTRY, ListEntry);
  127. KerbFreeSKeyEntry(pSKeyEntry);
  128. }
  129. RtlReleaseResource(&KerbNetworkServiceSKeyLock);
  130. }
  131. RtlDeleteResource(&KerbNetworkServiceSKeyLock);
  132. }
  133. //+-------------------------------------------------------------------------
  134. //
  135. // Function: KerbFreeLogonSessionList
  136. //
  137. // Synopsis: Frees the logon session list
  138. //
  139. // Effects:
  140. //
  141. // Arguments: none
  142. //
  143. // Requires:
  144. //
  145. // Returns: none
  146. //
  147. // Notes:
  148. //
  149. //
  150. //--------------------------------------------------------------------------
  151. VOID
  152. KerbFreeLogonSessionList(
  153. VOID
  154. )
  155. {
  156. PKERB_LOGON_SESSION LogonSession;
  157. if (KerberosLogonSessionsInitialized)
  158. {
  159. KerbLockList(&KerbLogonSessionList);
  160. //
  161. // Go through the list of logon sessions and dereferences them all
  162. //
  163. while (!IsListEmpty(&KerbLogonSessionList.List))
  164. {
  165. LogonSession = CONTAINING_RECORD(
  166. KerbLogonSessionList.List.Flink,
  167. KERB_LOGON_SESSION,
  168. ListEntry.Next
  169. );
  170. KerbReferenceListEntry(
  171. &KerbLogonSessionList,
  172. &LogonSession->ListEntry,
  173. TRUE
  174. );
  175. KerbDereferenceLogonSession(LogonSession);
  176. }
  177. KerbFreeList(&KerbLogonSessionList);
  178. }
  179. }
  180. //+-------------------------------------------------------------------------
  181. //
  182. // Function: KerbAllocateLogonSession
  183. //
  184. // Synopsis: Allocates a logon session structure
  185. //
  186. // Effects: Allocates a logon session, but does not add it to the
  187. // list of logon sessions
  188. //
  189. // Arguments: NewLogonSession - receives a new logon session allocated
  190. // with KerbAllocate
  191. //
  192. // Requires:
  193. //
  194. // Returns: STATUS_SUCCESS on success
  195. // STATUS_INSUFFICIENT_RESOURCES if the allocation fails
  196. //
  197. // Notes:
  198. //
  199. //
  200. //--------------------------------------------------------------------------
  201. NTSTATUS
  202. KerbAllocateLogonSession(
  203. PKERB_LOGON_SESSION * NewLogonSession
  204. )
  205. {
  206. NTSTATUS Status = STATUS_SUCCESS;
  207. PKERB_LOGON_SESSION LogonSession;
  208. LogonSession = (PKERB_LOGON_SESSION) KerbAllocate(
  209. sizeof(KERB_LOGON_SESSION)
  210. );
  211. if (LogonSession == NULL)
  212. {
  213. return(STATUS_INSUFFICIENT_RESOURCES);
  214. }
  215. //
  216. // Set the references to 1 since we are returning a pointer to the
  217. // logon session
  218. //
  219. KerbInitializeListEntry(
  220. &LogonSession->ListEntry
  221. );
  222. InitializeListHead(&LogonSession->SspCredentials);
  223. //
  224. // Initialize the ticket caches
  225. //
  226. KerbInitTicketCache(&LogonSession->PrimaryCredentials.ServerTicketCache);
  227. KerbInitTicketCache(&LogonSession->PrimaryCredentials.AuthenticationTicketCache);
  228. KerbInitTicketCache(&LogonSession->PrimaryCredentials.S4UTicketCache);
  229. Status = RtlInitializeCriticalSection(&LogonSession->Lock);
  230. if (!NT_SUCCESS(Status))
  231. {
  232. KerbFree(LogonSession);
  233. }
  234. else
  235. {
  236. *NewLogonSession = LogonSession;
  237. }
  238. return(Status);
  239. }
  240. //+-------------------------------------------------------------------------
  241. //
  242. // Function: KerbInsertLogonSession
  243. //
  244. // Synopsis: Inserts a logon session into the list of logon sessions
  245. //
  246. // Effects: bumps reference count on logon session
  247. //
  248. // Arguments: LogonSession - LogonSession to insert
  249. //
  250. // Requires:
  251. //
  252. // Returns: STATUS_SUCCESS always
  253. //
  254. // Notes:
  255. //
  256. //
  257. //--------------------------------------------------------------------------
  258. NTSTATUS
  259. KerbInsertLogonSession(
  260. IN PKERB_LOGON_SESSION LogonSession
  261. )
  262. {
  263. KerbInsertListEntry(
  264. &LogonSession->ListEntry,
  265. &KerbLogonSessionList
  266. );
  267. return(STATUS_SUCCESS);
  268. }
  269. //+-------------------------------------------------------------------------
  270. //
  271. // Function: KerbReferenceLogonSession
  272. //
  273. // Synopsis: Locates a logon session from the logon ID and references it
  274. //
  275. // Effects: Increments reference count and possible unlinks it from list
  276. //
  277. // Arguments: LogonId - LogonId of logon session to locate
  278. // RemoveFromList - If TRUE, logon session will be delinked
  279. //
  280. // Requires:
  281. //
  282. // Returns:
  283. //
  284. // Notes:
  285. //
  286. //
  287. //--------------------------------------------------------------------------
  288. PKERB_LOGON_SESSION
  289. KerbReferenceLogonSession(
  290. IN PLUID LogonId,
  291. IN BOOLEAN RemoveFromList
  292. )
  293. {
  294. PLIST_ENTRY ListEntry;
  295. PKERB_LOGON_SESSION LogonSession = NULL;
  296. BOOLEAN Found = FALSE;
  297. KerbLockList(&KerbLogonSessionList);
  298. //
  299. // Go through the list of logon sessions looking for the correct
  300. // LUID
  301. //
  302. for (ListEntry = KerbLogonSessionList.List.Flink ;
  303. ListEntry != &KerbLogonSessionList.List ;
  304. ListEntry = ListEntry->Flink )
  305. {
  306. LogonSession = CONTAINING_RECORD(ListEntry, KERB_LOGON_SESSION, ListEntry.Next);
  307. if (RtlEqualLuid(
  308. &LogonSession->LogonId,
  309. LogonId
  310. ) )
  311. {
  312. D_DebugLog((DEB_TRACE_LSESS,"Referencing session 0x%x:0x%x, Remove=%d\n",
  313. LogonSession->LogonId.HighPart,
  314. LogonSession->LogonId.LowPart,
  315. RemoveFromList
  316. ));
  317. KerbReferenceListEntry(
  318. &KerbLogonSessionList,
  319. &LogonSession->ListEntry,
  320. RemoveFromList
  321. );
  322. Found = TRUE;
  323. break;
  324. }
  325. }
  326. if (!Found)
  327. {
  328. LogonSession = NULL;
  329. }
  330. KerbUnlockList(&KerbLogonSessionList);
  331. return(LogonSession);
  332. }
  333. //+-------------------------------------------------------------------------
  334. //
  335. // Function: KerbFreeLogonSession
  336. //
  337. // Synopsis: Frees a logon session and all associated data
  338. //
  339. // Effects:
  340. //
  341. // Arguments: LogonSession
  342. //
  343. // Requires: the logon session must already be unlinked
  344. //
  345. // Returns: none
  346. //
  347. // Notes:
  348. //
  349. //
  350. //--------------------------------------------------------------------------
  351. VOID
  352. KerbFreeLogonSession(
  353. IN PKERB_LOGON_SESSION LogonSession
  354. )
  355. {
  356. DsysAssert((LogonSession->ListEntry.Next.Flink == NULL) &&
  357. (LogonSession->ListEntry.Next.Blink == NULL));
  358. // Don't purge creds, as there isn't a ref-count for the credential in
  359. // the logon session list,and there might be outstanding handles to your
  360. // credentials in a local system process.
  361. //KerbPurgeCredentials(&LogonSession->SspCredentials);
  362. KerbPurgeTicketCache(&LogonSession->PrimaryCredentials.ServerTicketCache);
  363. KerbPurgeTicketCache(&LogonSession->PrimaryCredentials.AuthenticationTicketCache);
  364. if (LogonSession->PrimaryCredentials.Passwords != NULL)
  365. {
  366. KerbFreeStoredCred(LogonSession->PrimaryCredentials.Passwords);
  367. }
  368. if (LogonSession->PrimaryCredentials.OldPasswords != NULL)
  369. {
  370. KerbFreeStoredCred(LogonSession->PrimaryCredentials.OldPasswords);
  371. }
  372. KerbFreeString(&LogonSession->PrimaryCredentials.UserName);
  373. KerbFreeString(&LogonSession->PrimaryCredentials.DomainName);
  374. if (LogonSession->PrimaryCredentials.ClearPassword.Buffer != NULL)
  375. {
  376. RtlZeroMemory(
  377. LogonSession->PrimaryCredentials.ClearPassword.Buffer,
  378. LogonSession->PrimaryCredentials.ClearPassword.Length
  379. );
  380. KerbFreeString(&LogonSession->PrimaryCredentials.ClearPassword);
  381. }
  382. if (LogonSession->PrimaryCredentials.PublicKeyCreds != NULL)
  383. {
  384. #ifndef WIN32_CHICAGO
  385. KerbReleasePkCreds(
  386. LogonSession,
  387. NULL
  388. );
  389. #endif // WIN32_CHICAGO
  390. }
  391. if ((LogonSession->LogonSessionFlags & KERB_LOGON_CREDMAN_INITIALIZED) != 0)
  392. {
  393. RtlDeleteCriticalSection(&LogonSession->CredmanCredentials.Lock);
  394. }
  395. RtlDeleteCriticalSection(&LogonSession->Lock);
  396. KerbFree(LogonSession);
  397. }
  398. //+-------------------------------------------------------------------------
  399. //
  400. // Function: KerbDereferenceLogonSession
  401. //
  402. // Synopsis: Dereferences a logon session - if reference count goes
  403. // to zero it frees the logon session
  404. //
  405. // Effects: decrements reference count
  406. //
  407. // Arguments: LogonSession - Logon session to dereference
  408. //
  409. // Requires:
  410. //
  411. // Returns: none
  412. //
  413. // Notes:
  414. //
  415. //
  416. //--------------------------------------------------------------------------
  417. VOID
  418. KerbDereferenceLogonSession(
  419. IN PKERB_LOGON_SESSION LogonSession
  420. )
  421. {
  422. if (KerbDereferenceListEntry(
  423. &LogonSession->ListEntry,
  424. &KerbLogonSessionList
  425. ) )
  426. {
  427. D_DebugLog((DEB_TRACE_LSESS,"Dereferencing and freeing logon session 0x%x:0x%x\n",
  428. LogonSession->LogonId.HighPart,
  429. LogonSession->LogonId.HighPart
  430. ));
  431. KerbFreeLogonSession( LogonSession );
  432. }
  433. }
  434. //+-------------------------------------------------------------------------
  435. //
  436. // Function: KerbReferenceLogonSessionByPointer
  437. //
  438. // Synopsis: References a LogonSession by the LogonSession pointer itself.
  439. //
  440. // Effects: Increments reference count and possible unlinks it from list
  441. //
  442. // Arguments: LogonSession - The LogonSession to reference.
  443. // RemoveFromList - If TRUE, LogonSession will be delinked
  444. //
  445. // Requires:
  446. //
  447. // Returns:
  448. //
  449. // Notes:
  450. //
  451. //
  452. //--------------------------------------------------------------------------
  453. VOID
  454. KerbReferenceLogonSessionByPointer(
  455. IN PKERB_LOGON_SESSION LogonSession,
  456. IN BOOLEAN RemoveFromList
  457. )
  458. {
  459. KerbLockList(&KerbLogonSessionList);
  460. KerbReferenceListEntry(
  461. &KerbLogonSessionList,
  462. &LogonSession->ListEntry,
  463. RemoveFromList
  464. );
  465. KerbUnlockList(&KerbLogonSessionList);
  466. }
  467. //+-------------------------------------------------------------------------
  468. //
  469. // Function: KerbGetSaltForEtype
  470. //
  471. // Synopsis: Looks in the list of salt for an etype & returns it if found
  472. //
  473. // Effects: Allocate the output string
  474. //
  475. // Arguments: EncryptionType - etype searched for
  476. // EtypeInfo - List of etypes
  477. // DefaultSalt - salt to use if none provided
  478. // Salt - receives the salt to use. On error, no key should be
  479. // generated.
  480. //
  481. // Requires:
  482. //
  483. // Returns:
  484. //
  485. // Notes:
  486. //
  487. //
  488. //--------------------------------------------------------------------------
  489. NTSTATUS
  490. KerbGetSaltForEtype(
  491. IN ULONG EncryptionType,
  492. IN OPTIONAL PKERB_ETYPE_INFO EtypeInfo,
  493. IN OPTIONAL PKERB_STORED_CREDENTIAL PasswordList,
  494. IN PUNICODE_STRING DefaultSalt,
  495. OUT PUNICODE_STRING SaltToUse
  496. )
  497. {
  498. PKERB_ETYPE_INFO ListEntry;
  499. STRING TempString;
  500. //
  501. // If there is no etype, just use the default
  502. //
  503. if (EtypeInfo == NULL)
  504. {
  505. //
  506. // If we have a password list, get the salt from that.
  507. //
  508. if (ARGUMENT_PRESENT(PasswordList))
  509. {
  510. ULONG Index;
  511. for (Index = 0; Index < PasswordList->CredentialCount ; Index++ )
  512. {
  513. if (PasswordList->Credentials[Index].Key.keytype == (int) EncryptionType)
  514. {
  515. if (PasswordList->Credentials[Index].Salt.Buffer != NULL)
  516. {
  517. return(KerbDuplicateString(
  518. SaltToUse,
  519. &PasswordList->Credentials[Index].Salt
  520. ));
  521. }
  522. else if (PasswordList->DefaultSalt.Buffer != NULL)
  523. {
  524. return(KerbDuplicateString(
  525. SaltToUse,
  526. &PasswordList->DefaultSalt
  527. ));
  528. }
  529. break;
  530. }
  531. }
  532. }
  533. //
  534. // otherise return the default
  535. //
  536. return(KerbDuplicateString(
  537. SaltToUse,
  538. DefaultSalt
  539. ));
  540. }
  541. //
  542. // Otherwise, only return salt if the etype is in the list.
  543. //
  544. for (ListEntry = EtypeInfo; ListEntry != NULL ; ListEntry = ListEntry->next )
  545. {
  546. //
  547. // First check for the encryption type we want.
  548. //
  549. if (ListEntry->value.encryption_type == (int) EncryptionType)
  550. {
  551. //
  552. // if it has salt, return that.
  553. //
  554. if ((ListEntry->value.bit_mask & salt_present) != 0)
  555. {
  556. KERBERR KerbErr;
  557. TempString.Buffer = (PCHAR) ListEntry->value.salt.value;
  558. TempString.Length = (USHORT) ListEntry->value.salt.length;
  559. TempString.MaximumLength = (USHORT) ListEntry->value.salt.length;
  560. KerbErr = KerbStringToUnicodeString(
  561. SaltToUse,
  562. &TempString
  563. );
  564. return(KerbMapKerbError(KerbErr));
  565. }
  566. else
  567. {
  568. //
  569. // Otherwise return the default
  570. //
  571. return(KerbDuplicateString(
  572. SaltToUse,
  573. DefaultSalt
  574. ));
  575. }
  576. }
  577. }
  578. return(STATUS_OBJECT_NAME_NOT_FOUND);
  579. }
  580. //+-------------------------------------------------------------------------
  581. //
  582. // Function: KerbFreeStoredCred
  583. //
  584. // Synopsis: Frees a KERB_STORED_CREDENTIAL
  585. //
  586. // Effects:
  587. //
  588. // Arguments:
  589. //
  590. // Requires:
  591. //
  592. // Returns:
  593. //
  594. // Notes:
  595. //
  596. //
  597. //--------------------------------------------------------------------------
  598. VOID
  599. KerbFreeStoredCred(
  600. IN PKERB_STORED_CREDENTIAL StoredCred
  601. )
  602. {
  603. USHORT Index;
  604. for (Index = 0; Index < StoredCred->CredentialCount + StoredCred->OldCredentialCount ; Index++ )
  605. {
  606. if (StoredCred->Credentials[Index].Salt.Buffer != NULL)
  607. {
  608. KerbFreeString(&StoredCred->Credentials[Index].Salt);
  609. }
  610. }
  611. KerbFree(StoredCred);
  612. }
  613. //+-------------------------------------------------------------------------
  614. //
  615. // Function: KerbBuildPasswordList
  616. //
  617. // Synopsis: Builds a list of passwords for a logged on user
  618. //
  619. // Effects: allocates memory
  620. //
  621. // Arguments: Password - clear or OWF password
  622. // PasswordFlags - Indicates whether the password is clear or OWF
  623. // PasswordList - Receives new password list
  624. //
  625. // Requires:
  626. //
  627. // Returns:
  628. //
  629. // Notes:
  630. //
  631. //
  632. //--------------------------------------------------------------------------
  633. NTSTATUS
  634. KerbBuildPasswordList(
  635. IN PUNICODE_STRING Password,
  636. IN PUNICODE_STRING UserName,
  637. IN PUNICODE_STRING DomainName,
  638. IN PKERB_ETYPE_INFO SuppliedSalt,
  639. IN PKERB_STORED_CREDENTIAL OldPasswords,
  640. IN OPTIONAL PUNICODE_STRING PrincipalName,
  641. IN KERB_ACCOUNT_TYPE AccountType,
  642. IN ULONG PasswordFlags,
  643. OUT PKERB_STORED_CREDENTIAL * PasswordList
  644. )
  645. {
  646. NTSTATUS Status = STATUS_SUCCESS;
  647. ULONG CryptTypes[KERB_MAX_CRYPTO_SYSTEMS];
  648. ULONG CryptCount = 0 ;
  649. PKERB_STORED_CREDENTIAL Credentials = NULL;
  650. UNICODE_STRING KeySalt = {0};
  651. UNICODE_STRING DefaultSalt = {0};
  652. ULONG CredentialSize = 0;
  653. ULONG CredentialCount = 0;
  654. PCRYPTO_SYSTEM CryptoSystem;
  655. ULONG Index, CredentialIndex = 0;
  656. PUCHAR Base;
  657. ULONG Offset;
  658. KERBERR KerbErr;
  659. *PasswordList = NULL;
  660. //
  661. // If we were passed an OWF, then there is just one password
  662. //
  663. if ((PasswordFlags & PRIMARY_CRED_OWF_PASSWORD) != 0)
  664. {
  665. CredentialSize += Password->Length + sizeof(KERB_KEY_DATA);
  666. CredentialCount++;
  667. #ifndef DONT_SUPPORT_OLD_TYPES
  668. CredentialSize += Password->Length + sizeof(KERB_KEY_DATA);
  669. CredentialCount++;
  670. #endif
  671. }
  672. else if ((PasswordFlags & PRIMARY_CRED_CLEAR_PASSWORD) != 0)
  673. {
  674. //
  675. // Build the key salt.
  676. //
  677. KerbErr = KerbBuildKeySalt(
  678. DomainName,
  679. (ARGUMENT_PRESENT(PrincipalName) && PrincipalName->Length != 0) ? PrincipalName : UserName,
  680. (ARGUMENT_PRESENT(PrincipalName) && PrincipalName->Length != 0) ? UnknownAccount : AccountType,
  681. &DefaultSalt
  682. );
  683. if (!KERB_SUCCESS(KerbErr))
  684. {
  685. D_DebugLog((DEB_ERROR,"Can't build salt. Might as well fail here\n"));
  686. Status = KerbMapKerbError(KerbErr);
  687. goto Cleanup;
  688. }
  689. //
  690. // For a cleartext password, build a list of encryption types and
  691. // create a key for each one
  692. //
  693. Status = CDBuildIntegrityVect(
  694. &CryptCount,
  695. CryptTypes
  696. );
  697. if (!NT_SUCCESS(Status))
  698. {
  699. D_DebugLog((DEB_ERROR,"Can't build a list of encryption types: 0x%x.\n",Status));
  700. goto Cleanup;
  701. }
  702. DsysAssert(CryptCount <= KERB_MAX_CRYPTO_SYSTEMS);
  703. //
  704. // Now find the size of the key for each crypto system
  705. //
  706. for (Index = 0; Index < CryptCount; Index++ )
  707. {
  708. Status = CDLocateCSystem(
  709. CryptTypes[Index],
  710. &CryptoSystem
  711. );
  712. if (!NT_SUCCESS(Status))
  713. {
  714. D_DebugLog((DEB_ERROR,"Failed to load %d crypt system: 0x%x.\n",CryptTypes[Index],Status));
  715. goto Cleanup;
  716. }
  717. if (((CryptoSystem->Attributes & CSYSTEM_USE_PRINCIPAL_NAME) == 0) ||
  718. (DefaultSalt.Buffer != NULL ))
  719. {
  720. CredentialSize += sizeof(KERB_KEY_DATA) + CryptoSystem->KeySize;
  721. CredentialCount++;
  722. }
  723. }
  724. }
  725. else
  726. {
  727. //
  728. // No flags set, so nothing we can do.
  729. //
  730. D_DebugLog((DEB_WARN,"Password passed but no flags set\n"));
  731. return(STATUS_SUCCESS);
  732. }
  733. #ifdef notdef
  734. //
  735. // Add the space for the salt
  736. //
  737. CredentialSize += DefaultSalt.Length;
  738. #endif
  739. //
  740. // Add in the size of the base structure
  741. //
  742. CredentialSize += FIELD_OFFSET(KERB_STORED_CREDENTIAL,Credentials);
  743. Credentials = (PKERB_STORED_CREDENTIAL) KerbAllocate(CredentialSize);
  744. if (Credentials == NULL)
  745. {
  746. Status = STATUS_INSUFFICIENT_RESOURCES;
  747. goto Cleanup;
  748. }
  749. //
  750. // Fill in the base structure
  751. //
  752. Credentials->Revision = KERB_PRIMARY_CRED_REVISION;
  753. Credentials->Flags = 0;
  754. Credentials->OldCredentialCount = 0;
  755. //
  756. // Now fill in the individual keys
  757. //
  758. Base = (PUCHAR) Credentials;
  759. Offset = FIELD_OFFSET(KERB_STORED_CREDENTIAL,Credentials) +
  760. CredentialCount * sizeof(KERB_KEY_DATA);
  761. #ifdef notdef
  762. //
  763. // Add the default salt
  764. //
  765. Credentials->DefaultSalt = DefaultSalt;
  766. Credentials->DefaultSalt.Buffer = (LPWSTR) Base+Offset;
  767. RtlCopyMemory(
  768. Base + Offset,
  769. DefaultSalt.Buffer,
  770. DefaultSalt.Length
  771. );
  772. Offset += Credentials->DefaultSalt.Length;
  773. #endif
  774. if ((PasswordFlags & PRIMARY_CRED_OWF_PASSWORD) != 0)
  775. {
  776. RtlCopyMemory(
  777. Base + Offset,
  778. Password->Buffer,
  779. Password->Length
  780. );
  781. if (!KERB_SUCCESS(KerbCreateKeyFromBuffer(
  782. &Credentials->Credentials[CredentialIndex].Key,
  783. Base + Offset,
  784. Password->Length,
  785. KERB_ETYPE_RC4_HMAC_NT
  786. )))
  787. {
  788. Status = STATUS_INSUFFICIENT_RESOURCES;
  789. goto Cleanup;
  790. }
  791. Base += Password->Length;
  792. CredentialIndex++;
  793. #ifndef DONT_SUPPORT_OLD_TYPES
  794. RtlCopyMemory(
  795. Base + Offset,
  796. Password->Buffer,
  797. Password->Length
  798. );
  799. if (!KERB_SUCCESS(KerbCreateKeyFromBuffer(
  800. &Credentials->Credentials[CredentialIndex].Key,
  801. Base + Offset,
  802. Password->Length,
  803. KERB_ETYPE_RC4_HMAC_OLD
  804. )))
  805. {
  806. Status = STATUS_INSUFFICIENT_RESOURCES;
  807. goto Cleanup;
  808. }
  809. Base += Password->Length;
  810. CredentialIndex++;
  811. #endif
  812. }
  813. else if ((PasswordFlags & PRIMARY_CRED_CLEAR_PASSWORD) != 0)
  814. {
  815. KERB_ENCRYPTION_KEY TempKey = {0};
  816. //
  817. // Now find the size of the key for each crypto system
  818. //
  819. for (Index = 0; Index < CryptCount; Index++ )
  820. {
  821. CryptoSystem = NULL;
  822. Status = CDLocateCSystem(
  823. CryptTypes[Index],
  824. &CryptoSystem
  825. );
  826. if (!NT_SUCCESS(Status))
  827. {
  828. Status = STATUS_SUCCESS;
  829. continue;
  830. }
  831. Status = KerbGetSaltForEtype(
  832. CryptTypes[Index],
  833. SuppliedSalt,
  834. OldPasswords,
  835. &DefaultSalt,
  836. &KeySalt
  837. );
  838. if (!NT_SUCCESS(Status))
  839. {
  840. //
  841. // This probably means that the etype wasn't supported by
  842. // the kdc
  843. //
  844. Status = STATUS_SUCCESS;
  845. continue;
  846. }
  847. //
  848. // If we don't have salt, skip this crypt system
  849. //
  850. if (((CryptoSystem->Attributes & CSYSTEM_USE_PRINCIPAL_NAME) != 0) &&
  851. (KeySalt.Buffer == NULL ))
  852. {
  853. continue;
  854. }
  855. KerbErr = KerbHashPasswordEx(
  856. Password,
  857. &KeySalt,
  858. CryptTypes[Index],
  859. &TempKey
  860. );
  861. if (!KERB_SUCCESS(KerbErr))
  862. {
  863. //
  864. // It is possible that the password can't be used for every
  865. // encryption scheme, so skip failures
  866. //
  867. D_DebugLog((DEB_WARN, "Failed to hash pasword %wZ with type 0x%x\n",
  868. Password,CryptTypes[Index] ));
  869. KerbFreeString(&KeySalt);
  870. continue;
  871. }
  872. DsysAssert(CryptoSystem->KeySize >= TempKey.keyvalue.length);
  873. //
  874. // Copy the salt and key data into the credentials
  875. //
  876. Credentials->Credentials[CredentialIndex].Salt = KeySalt;
  877. RtlInitUnicodeString(
  878. &KeySalt,
  879. 0
  880. );
  881. Credentials->Credentials[CredentialIndex].Key = TempKey;
  882. Credentials->Credentials[CredentialIndex].Key.keyvalue.value = Base + Offset;
  883. RtlCopyMemory(
  884. Base + Offset,
  885. TempKey.keyvalue.value,
  886. TempKey.keyvalue.length
  887. );
  888. Offset += TempKey.keyvalue.length;
  889. KerbFreeKey(
  890. &TempKey
  891. );
  892. CredentialIndex++;
  893. }
  894. }
  895. Credentials->CredentialCount = (USHORT) CredentialIndex;
  896. *PasswordList = Credentials;
  897. Credentials = NULL;
  898. Cleanup:
  899. if (Credentials != NULL)
  900. {
  901. KerbFreeStoredCred(Credentials);
  902. }
  903. KerbFreeString(&KeySalt);
  904. KerbFreeString(&DefaultSalt);
  905. return(Status);
  906. }
  907. //+-------------------------------------------------------------------------
  908. //
  909. // Function: KerbCreatePrimaryCredentials
  910. //
  911. // Synopsis: Fills in a new primary credentials structure
  912. //
  913. // Effects: allocates space for the user name and domain name
  914. //
  915. // Arguments: AccountName - Account name of this user
  916. // DomainName - domain name of this user
  917. // Password - Optionally contains a kereros hash of the password
  918. // Note: if present, it is used and zeroed out.
  919. // PrimaryCredentials - contains structure to fill in.
  920. //
  921. // Requires:
  922. //
  923. // Returns:
  924. //
  925. // Notes:
  926. //
  927. //
  928. //--------------------------------------------------------------------------
  929. NTSTATUS
  930. KerbCreatePrimaryCredentials(
  931. IN PUNICODE_STRING AccountName,
  932. IN PUNICODE_STRING DomainName,
  933. IN OPTIONAL PUNICODE_STRING Password,
  934. IN OPTIONAL PUNICODE_STRING OldPassword,
  935. IN ULONG PasswordFlags,
  936. IN PLUID LogonId,
  937. OUT PKERB_PRIMARY_CREDENTIAL PrimaryCredentials
  938. )
  939. {
  940. NTSTATUS Status;
  941. LUID SystemLogonId = SYSTEM_LUID;
  942. BOOLEAN IsSystemLogon = FALSE;
  943. BOOLEAN IsPersonal = KerbRunningPersonal();
  944. //
  945. // We can only accept account name / service name / pwds of max_unicode_length
  946. // -1, because we NULL terminate these for later DES derivation, and the
  947. // input buffers from LogonUser may not be NULL terminated.
  948. //
  949. if ((AccountName->Length > KERB_MAX_UNICODE_STRING) ||
  950. (DomainName->Length > KERB_MAX_UNICODE_STRING))
  951. {
  952. return (STATUS_NAME_TOO_LONG);
  953. }
  954. if ((ARGUMENT_PRESENT(Password) && (Password->Length > KERB_MAX_UNICODE_STRING)) ||
  955. (ARGUMENT_PRESENT(OldPassword) && (OldPassword->Length > KERB_MAX_UNICODE_STRING)))
  956. {
  957. return (STATUS_NAME_TOO_LONG);
  958. }
  959. if (RtlEqualLuid(
  960. &SystemLogonId,
  961. LogonId))
  962. {
  963. IsSystemLogon = TRUE;
  964. }
  965. Status = KerbDuplicateString(
  966. &PrimaryCredentials->UserName,
  967. AccountName
  968. );
  969. if (!NT_SUCCESS(Status))
  970. {
  971. goto Cleanup;
  972. }
  973. //
  974. // The system logon always comes in uppercase, so lowercase it.
  975. //
  976. if (IsSystemLogon)
  977. {
  978. RtlDowncaseUnicodeString(
  979. &PrimaryCredentials->UserName,
  980. &PrimaryCredentials->UserName,
  981. FALSE
  982. );
  983. }
  984. Status = KerbDuplicateString(
  985. &PrimaryCredentials->DomainName,
  986. DomainName
  987. );
  988. if (!NT_SUCCESS(Status))
  989. {
  990. goto Cleanup;
  991. }
  992. //
  993. // Neuter personal so it can't act as a server,
  994. // even if someone has hacked in a machine pwd.
  995. //
  996. if (IsSystemLogon && IsPersonal)
  997. {
  998. PrimaryCredentials->Passwords = NULL;
  999. PrimaryCredentials->OldPasswords = NULL;
  1000. D_DebugLog((DEB_WARN, "Running personal - No kerberos for SYSTEM LUID\n"));
  1001. }
  1002. else
  1003. {
  1004. Status = KerbBuildPasswordList(
  1005. Password,
  1006. &PrimaryCredentials->UserName,
  1007. &PrimaryCredentials->DomainName,
  1008. NULL, // no supplied salt
  1009. NULL, // no old paswords
  1010. NULL, // no principal name
  1011. IsSystemLogon ? MachineAccount : UserAccount,
  1012. PasswordFlags,
  1013. &PrimaryCredentials->Passwords
  1014. );
  1015. if (!NT_SUCCESS(Status))
  1016. {
  1017. goto Cleanup;
  1018. }
  1019. if (ARGUMENT_PRESENT(OldPassword) && (OldPassword->Buffer != NULL))
  1020. {
  1021. Status = KerbBuildPasswordList(
  1022. OldPassword,
  1023. &PrimaryCredentials->UserName,
  1024. &PrimaryCredentials->DomainName,
  1025. NULL, // no supplied salt
  1026. PrimaryCredentials->Passwords,
  1027. NULL, // no principal name
  1028. IsSystemLogon ? MachineAccount : UserAccount,
  1029. PasswordFlags,
  1030. &PrimaryCredentials->OldPasswords
  1031. );
  1032. if (!NT_SUCCESS(Status))
  1033. {
  1034. goto Cleanup;
  1035. }
  1036. }
  1037. //
  1038. // Store the clear password if necessary
  1039. //
  1040. if ((PasswordFlags & PRIMARY_CRED_CLEAR_PASSWORD) != 0)
  1041. {
  1042. Status = KerbDuplicatePassword(
  1043. &PrimaryCredentials->ClearPassword,
  1044. Password
  1045. );
  1046. if (NT_SUCCESS(Status))
  1047. {
  1048. KerbHidePassword(
  1049. &PrimaryCredentials->ClearPassword
  1050. );
  1051. }
  1052. }
  1053. }
  1054. Cleanup:
  1055. if (!NT_SUCCESS(Status))
  1056. {
  1057. KerbFreeString(&PrimaryCredentials->UserName);
  1058. KerbFreeString(&PrimaryCredentials->DomainName);
  1059. if (PrimaryCredentials->ClearPassword.Buffer != NULL)
  1060. {
  1061. RtlZeroMemory(
  1062. PrimaryCredentials->ClearPassword.Buffer,
  1063. PrimaryCredentials->ClearPassword.Length
  1064. );
  1065. KerbFreeString(&PrimaryCredentials->ClearPassword);
  1066. }
  1067. }
  1068. return(Status);
  1069. }
  1070. //+-------------------------------------------------------------------------
  1071. //
  1072. // Function: KerbChangeCredentialsPassword
  1073. //
  1074. // Synopsis: Changes the password for a KERB_PRIMARY_CREDENTIALS -
  1075. // copies the current password into the old password field
  1076. // and then sets the new pasword as the primary password.
  1077. // If no new password is provided, it just fixes up the salt.
  1078. //
  1079. // Effects:
  1080. //
  1081. // Arguments:
  1082. //
  1083. // Requires:
  1084. //
  1085. // Returns:
  1086. //
  1087. // Notes:
  1088. //
  1089. //
  1090. //--------------------------------------------------------------------------
  1091. NTSTATUS
  1092. KerbChangeCredentialsPassword(
  1093. IN PKERB_PRIMARY_CREDENTIAL PrimaryCredentials,
  1094. IN OPTIONAL PUNICODE_STRING NewPassword,
  1095. IN OPTIONAL PKERB_ETYPE_INFO EtypeInfo,
  1096. IN KERB_ACCOUNT_TYPE AccountType,
  1097. IN ULONG PasswordFlags
  1098. )
  1099. {
  1100. NTSTATUS Status = STATUS_SUCCESS;
  1101. PKERB_STORED_CREDENTIAL Passwords = NULL;
  1102. //
  1103. // LogonSession no password was supplied, use the cleartext password
  1104. //
  1105. if (!ARGUMENT_PRESENT(NewPassword) && (PrimaryCredentials->ClearPassword.Buffer == NULL))
  1106. {
  1107. D_DebugLog((DEB_ERROR,"Can't change password without new password\n"));
  1108. Status = STATUS_INVALID_PARAMETER;
  1109. goto Cleanup;
  1110. }
  1111. if (PrimaryCredentials->ClearPassword.Buffer != NULL)
  1112. {
  1113. KerbRevealPassword(&PrimaryCredentials->ClearPassword);
  1114. }
  1115. Status = KerbBuildPasswordList(
  1116. (ARGUMENT_PRESENT(NewPassword) ? NewPassword : &PrimaryCredentials->ClearPassword),
  1117. &PrimaryCredentials->UserName,
  1118. &PrimaryCredentials->DomainName,
  1119. EtypeInfo,
  1120. PrimaryCredentials->Passwords,
  1121. NULL, // no principal name
  1122. AccountType,
  1123. PasswordFlags,
  1124. &Passwords
  1125. );
  1126. if (!NT_SUCCESS(Status))
  1127. {
  1128. if (PrimaryCredentials->ClearPassword.Buffer != NULL)
  1129. {
  1130. KerbHidePassword(&PrimaryCredentials->ClearPassword);
  1131. }
  1132. }
  1133. else if ((PasswordFlags & PRIMARY_CRED_CLEAR_PASSWORD) != 0)
  1134. {
  1135. KerbFreeString(&PrimaryCredentials->ClearPassword);
  1136. Status = KerbDuplicatePassword(
  1137. &PrimaryCredentials->ClearPassword,
  1138. NewPassword
  1139. );
  1140. if (NT_SUCCESS(Status))
  1141. {
  1142. KerbHidePassword(
  1143. &PrimaryCredentials->ClearPassword
  1144. );
  1145. }
  1146. }
  1147. else
  1148. {
  1149. KerbHidePassword(
  1150. &PrimaryCredentials->ClearPassword
  1151. );
  1152. }
  1153. if (!NT_SUCCESS(Status))
  1154. {
  1155. goto Cleanup;
  1156. }
  1157. //
  1158. // Move the current password to the old password
  1159. //
  1160. if (ARGUMENT_PRESENT(NewPassword))
  1161. {
  1162. if (PrimaryCredentials->OldPasswords != NULL)
  1163. {
  1164. KerbFreeStoredCred(PrimaryCredentials->OldPasswords);
  1165. }
  1166. PrimaryCredentials->OldPasswords = PrimaryCredentials->Passwords;
  1167. }
  1168. else
  1169. {
  1170. KerbFreeStoredCred(PrimaryCredentials->Passwords);
  1171. }
  1172. PrimaryCredentials->Passwords = Passwords;
  1173. Passwords = NULL;
  1174. Cleanup:
  1175. if (Passwords != NULL)
  1176. {
  1177. MIDL_user_free(Passwords);
  1178. }
  1179. return(Status);
  1180. }
  1181. //+-------------------------------------------------------------------------
  1182. //
  1183. // Function: KerbCreateLogonSession
  1184. //
  1185. // Synopsis: Allocates a logon session, fills in the various fields,
  1186. // and inserts it on the logon session list
  1187. //
  1188. // Effects:
  1189. //
  1190. // Arguments: LogonId - LogonId for new logon session
  1191. // AccountName - Account name of user
  1192. // Domain Name - Domain name of user
  1193. // Password - password for user
  1194. // OldPassword - Old password for user, if present
  1195. // LogonType - Type of logon
  1196. // NewLogonSession - Receives new logon session (referenced)
  1197. //
  1198. // Requires:
  1199. //
  1200. // Returns:
  1201. //
  1202. // Notes:
  1203. //
  1204. //
  1205. //--------------------------------------------------------------------------
  1206. NTSTATUS
  1207. KerbCreateLogonSession(
  1208. IN PLUID LogonId,
  1209. IN PUNICODE_STRING AccountName,
  1210. IN PUNICODE_STRING DomainName,
  1211. IN OPTIONAL PUNICODE_STRING Password,
  1212. IN OPTIONAL PUNICODE_STRING OldPassword,
  1213. IN ULONG PasswordFlags,
  1214. IN SECURITY_LOGON_TYPE LogonType,
  1215. OUT PKERB_LOGON_SESSION * NewLogonSession
  1216. )
  1217. {
  1218. PKERB_LOGON_SESSION LogonSession = NULL;
  1219. NTSTATUS Status;
  1220. D_DebugLog((DEB_TRACE_LSESS,"Creating logon session for 0x%x:0x%x\n",
  1221. LogonId->HighPart,LogonId->LowPart));
  1222. //
  1223. // Check for a logon session with the same id
  1224. //
  1225. LogonSession = KerbReferenceLogonSession(
  1226. LogonId,
  1227. FALSE // don't unlink
  1228. );
  1229. if (LogonSession != NULL)
  1230. {
  1231. //
  1232. // We already have this logon session, so don't create another one.
  1233. //
  1234. KerbDereferenceLogonSession(LogonSession);
  1235. return(STATUS_OBJECT_NAME_EXISTS);
  1236. }
  1237. //
  1238. // Allocate the new logon session
  1239. //
  1240. Status = KerbAllocateLogonSession( &LogonSession );
  1241. if (!NT_SUCCESS(Status))
  1242. {
  1243. goto Cleanup;
  1244. }
  1245. //
  1246. // Fill in the logon session components
  1247. //
  1248. LogonSession->LogonId = *LogonId;
  1249. LogonSession->Lifetime = KerbGlobalWillNeverTime;
  1250. //
  1251. // All logons are deferred until proven otherwise
  1252. //
  1253. LogonSession->LogonSessionFlags = KERB_LOGON_DEFERRED;
  1254. //
  1255. // If the domain name is equal to the computer name then the logon was
  1256. // local.
  1257. //
  1258. #ifndef WIN32_CHICAGO
  1259. KerbGlobalReadLock();
  1260. if (RtlEqualDomainName(
  1261. DomainName,
  1262. &KerbGlobalMachineName
  1263. ))
  1264. {
  1265. LogonSession->LogonSessionFlags |= KERB_LOGON_LOCAL_ONLY;
  1266. }
  1267. KerbGlobalReleaseLock();
  1268. #endif // WIN32_CHICAGO
  1269. Status = KerbCreatePrimaryCredentials(
  1270. AccountName,
  1271. DomainName,
  1272. Password,
  1273. OldPassword,
  1274. PasswordFlags,
  1275. LogonId,
  1276. &LogonSession->PrimaryCredentials
  1277. );
  1278. if (!NT_SUCCESS(Status))
  1279. {
  1280. goto Cleanup;
  1281. }
  1282. Status = KerbInitializeList(
  1283. &LogonSession->CredmanCredentials
  1284. );
  1285. if (!NT_SUCCESS(Status))
  1286. {
  1287. goto Cleanup;
  1288. }
  1289. LogonSession->LogonSessionFlags |= KERB_LOGON_CREDMAN_INITIALIZED;
  1290. if ((LogonSession->PrimaryCredentials.Passwords == NULL) ||
  1291. (LogonSession->PrimaryCredentials.Passwords->CredentialCount == 0))
  1292. {
  1293. LogonSession->LogonSessionFlags |= KERB_LOGON_NO_PASSWORD;
  1294. }
  1295. //
  1296. // S4ULogon (any reason to keep this??? maybe for debug..)
  1297. //
  1298. if ((PasswordFlags & KERB_LOGON_S4U_SESSION) != 0)
  1299. {
  1300. LogonSession->LogonSessionFlags |= KERB_LOGON_S4U_SESSION;
  1301. }
  1302. //
  1303. // Now that the logon session structure is filled out insert it
  1304. // into the list. After this you need to hold the logon session lock
  1305. // to read or write this logon session.
  1306. //
  1307. Status = KerbInsertLogonSession(LogonSession);
  1308. if (!NT_SUCCESS(Status))
  1309. {
  1310. goto Cleanup;
  1311. }
  1312. *NewLogonSession = LogonSession;
  1313. Cleanup:
  1314. if (!NT_SUCCESS(Status))
  1315. {
  1316. if (NULL != LogonSession)
  1317. {
  1318. KerbFreeLogonSession(LogonSession);
  1319. LogonSession = NULL;
  1320. }
  1321. }
  1322. return(Status);
  1323. }
  1324. #ifndef WIN32_CHICAGO
  1325. //+-------------------------------------------------------------------------
  1326. //
  1327. // Function: KerbCreateLogonSessionFromKerbCred
  1328. //
  1329. // Synopsis: Creates a logon session from the delegation information
  1330. // in a KERB_CRED structure. If a logon session is supplied,
  1331. // it is updated with the supplied information.
  1332. //
  1333. // Effects:
  1334. //
  1335. // Arguments: LogonId - Logon id for the logon session
  1336. // Ticket - Ticket from the AP request containing the client's
  1337. // name and realm.
  1338. // KerbCred - KERB_CRED containing the delegation tickets
  1339. // EncryptedCred - Structure containing information about the
  1340. // tickets, such as session keys, flags, etc.
  1341. //
  1342. // Requires:
  1343. //
  1344. // Returns:
  1345. //
  1346. // Notes:
  1347. //
  1348. //
  1349. //--------------------------------------------------------------------------
  1350. NTSTATUS
  1351. KerbCreateLogonSessionFromKerbCred(
  1352. IN OPTIONAL PLUID LogonId,
  1353. IN PKERB_ENCRYPTED_TICKET Ticket,
  1354. IN PKERB_CRED KerbCred,
  1355. IN PKERB_ENCRYPTED_CRED EncryptedCred,
  1356. IN OUT PKERB_LOGON_SESSION *OldLogonSession
  1357. )
  1358. {
  1359. PKERB_LOGON_SESSION LogonSession = NULL;
  1360. NTSTATUS Status = STATUS_SUCCESS;
  1361. UNICODE_STRING AccountName;
  1362. UNICODE_STRING ShortAccountName;
  1363. UNICODE_STRING DomainName;
  1364. KERB_ENCRYPTED_KDC_REPLY FakeReplyBody;
  1365. KERB_KDC_REPLY FakeReply;
  1366. PKERB_CRED_INFO CredInfo;
  1367. PKERB_CRED_TICKET_LIST TicketList;
  1368. PKERB_CRED_INFO_LIST CredInfoList;
  1369. PKERB_TICKET_CACHE_ENTRY TicketCacheEntry;
  1370. ULONG NameType;
  1371. LPWSTR LastSlash;
  1372. BOOLEAN LogonSessionLocked = FALSE;
  1373. BOOLEAN CreatedLogonSession = TRUE;
  1374. PKERB_TICKET_CACHE TicketCache = NULL;
  1375. ULONG TgtFlags = KERB_TICKET_CACHE_PRIMARY_TGT;
  1376. ULONG CacheFlags = 0;
  1377. AccountName.Buffer = NULL;
  1378. DomainName.Buffer = NULL;
  1379. if (ARGUMENT_PRESENT(LogonId))
  1380. {
  1381. D_DebugLog((DEB_TRACE_LSESS,"Creating logon session for 0x%x:0x%x\n",
  1382. LogonId->HighPart,LogonId->LowPart));
  1383. }
  1384. if (!KERB_SUCCESS(KerbConvertPrincipalNameToString(
  1385. &AccountName,
  1386. &NameType,
  1387. &Ticket->client_name
  1388. )))
  1389. {
  1390. Status = STATUS_INSUFFICIENT_RESOURCES;
  1391. goto Cleanup;
  1392. }
  1393. //
  1394. // We need to strip off everything before the last '\' in case there
  1395. // was a domain name.
  1396. //
  1397. LastSlash = wcsrchr(AccountName.Buffer, L'\\');
  1398. if (LastSlash != NULL)
  1399. {
  1400. ShortAccountName.Buffer = LastSlash+1;
  1401. RtlInitUnicodeString(
  1402. &ShortAccountName,
  1403. ShortAccountName.Buffer
  1404. );
  1405. }
  1406. else
  1407. {
  1408. ShortAccountName = AccountName;
  1409. }
  1410. if (!KERB_SUCCESS(KerbConvertRealmToUnicodeString(
  1411. &DomainName,
  1412. &Ticket->client_realm
  1413. )))
  1414. {
  1415. Status = STATUS_INSUFFICIENT_RESOURCES;
  1416. goto Cleanup;
  1417. }
  1418. D_DebugLog((DEB_TRACE, "Creating delegation logon session for %wZ \\ %wZ\n",
  1419. &DomainName, &ShortAccountName ));
  1420. if ((*OldLogonSession) == NULL)
  1421. {
  1422. //
  1423. // Allocate the new logon session
  1424. //
  1425. Status = KerbAllocateLogonSession( &LogonSession );
  1426. if (!NT_SUCCESS(Status))
  1427. {
  1428. goto Cleanup;
  1429. }
  1430. //
  1431. // Fill in the logon session components
  1432. //
  1433. LogonSession->LogonId = *LogonId;
  1434. LogonSession->Lifetime = KerbGlobalWillNeverTime;
  1435. Status = KerbCreatePrimaryCredentials(
  1436. &ShortAccountName,
  1437. &DomainName,
  1438. NULL, // no password
  1439. NULL, // no old password
  1440. 0, // no flags
  1441. LogonId,
  1442. &LogonSession->PrimaryCredentials
  1443. );
  1444. if (!NT_SUCCESS(Status))
  1445. {
  1446. goto Cleanup;
  1447. }
  1448. LogonSession->LogonSessionFlags |= KERB_LOGON_NO_PASSWORD;
  1449. }
  1450. else
  1451. {
  1452. CreatedLogonSession = FALSE;
  1453. KerbWriteLockLogonSessions(*OldLogonSession);
  1454. LogonSessionLocked = TRUE;
  1455. LogonSession = *OldLogonSession;
  1456. //
  1457. // If the user name & domain name are blank, update them from the
  1458. // ticket.
  1459. //
  1460. if (LogonSession->PrimaryCredentials.UserName.Length == 0)
  1461. {
  1462. KerbFreeString(&LogonSession->PrimaryCredentials.UserName);
  1463. LogonSession->PrimaryCredentials.UserName = AccountName;
  1464. AccountName.Buffer = NULL;
  1465. }
  1466. if (LogonSession->PrimaryCredentials.DomainName.Length == 0)
  1467. {
  1468. KerbFreeString(&LogonSession->PrimaryCredentials.DomainName);
  1469. LogonSession->PrimaryCredentials.DomainName = DomainName;
  1470. DomainName.Buffer = NULL;
  1471. }
  1472. }
  1473. //
  1474. // Now stick the ticket into the ticket cache. First build up a fake
  1475. // KDC reply message from the encryped cred info.
  1476. //
  1477. TicketList = KerbCred->tickets;
  1478. CredInfoList = EncryptedCred->ticket_info;
  1479. while (TicketList != NULL)
  1480. {
  1481. TimeStamp Endtime = {0};
  1482. if (CredInfoList == NULL)
  1483. {
  1484. D_DebugLog((DEB_ERROR, "No ticket info in encrypted cred. %ws, line %d\n", THIS_FILE, __LINE__));
  1485. Status = STATUS_INVALID_PARAMETER;
  1486. goto Cleanup;
  1487. }
  1488. CredInfo = &CredInfoList->value;
  1489. //
  1490. // Set the lifetime to the end or renew_until of the longest lived ticket
  1491. //
  1492. if ((CredInfo->bit_mask & KERB_CRED_INFO_renew_until_present) != 0)
  1493. {
  1494. KerbConvertGeneralizedTimeToLargeInt(
  1495. &Endtime,
  1496. &CredInfo->KERB_CRED_INFO_renew_until,
  1497. 0 // no usec
  1498. );
  1499. }
  1500. else if ((CredInfo->bit_mask & endtime_present) != 0)
  1501. {
  1502. KerbConvertGeneralizedTimeToLargeInt(
  1503. &Endtime,
  1504. &CredInfo->endtime,
  1505. 0 // no usec
  1506. );
  1507. }
  1508. if (Endtime.QuadPart != 0)
  1509. {
  1510. if (LogonSession->Lifetime.QuadPart == KerbGlobalWillNeverTime.QuadPart)
  1511. {
  1512. LogonSession->Lifetime.QuadPart = Endtime.QuadPart;
  1513. }
  1514. else
  1515. {
  1516. LogonSession->Lifetime.QuadPart = max(LogonSession->Lifetime.QuadPart,Endtime.QuadPart);
  1517. }
  1518. }
  1519. RtlZeroMemory(
  1520. &FakeReplyBody,
  1521. sizeof(KERB_ENCRYPTED_KDC_REPLY)
  1522. );
  1523. FakeReplyBody.session_key = CredInfo->key;
  1524. FakeReplyBody.nonce = 0;
  1525. //
  1526. // Set the ticket flags
  1527. //
  1528. if (CredInfo->bit_mask & flags_present)
  1529. {
  1530. FakeReplyBody.flags = CredInfo->flags;
  1531. }
  1532. else
  1533. {
  1534. FakeReplyBody.flags.length = 0;
  1535. FakeReplyBody.flags.value = NULL;
  1536. }
  1537. FakeReplyBody.authtime = Ticket->authtime;
  1538. if (CredInfo->bit_mask & KERB_CRED_INFO_starttime_present)
  1539. {
  1540. FakeReplyBody.KERB_ENCRYPTED_KDC_REPLY_starttime =
  1541. CredInfo->KERB_CRED_INFO_starttime;
  1542. FakeReplyBody.bit_mask |= KERB_ENCRYPTED_KDC_REPLY_starttime_present;
  1543. }
  1544. //
  1545. // If an end time was sent, use it, otherwise assume the ticket
  1546. // lasts forever
  1547. //
  1548. if (CredInfo->bit_mask & endtime_present)
  1549. {
  1550. FakeReplyBody.endtime =
  1551. CredInfo->endtime;
  1552. }
  1553. else
  1554. {
  1555. KerbConvertLargeIntToGeneralizedTime(
  1556. &FakeReplyBody.endtime,
  1557. NULL,
  1558. &KerbGlobalWillNeverTime
  1559. );
  1560. }
  1561. if (CredInfo->bit_mask & KERB_CRED_INFO_renew_until_present)
  1562. {
  1563. FakeReplyBody.KERB_ENCRYPTED_KDC_REPLY_renew_until =
  1564. CredInfo->KERB_CRED_INFO_renew_until;
  1565. FakeReplyBody.bit_mask |= KERB_ENCRYPTED_KDC_REPLY_renew_until_present;
  1566. }
  1567. FakeReplyBody.server_name = TicketList->value.server_name;
  1568. FakeReplyBody.server_realm = TicketList->value.realm;
  1569. //
  1570. // Determine which ticket cache to use
  1571. //
  1572. if ((FakeReplyBody.server_name.name_string != NULL) &&
  1573. _stricmp(
  1574. FakeReplyBody.server_name.name_string->value,
  1575. KDC_PRINCIPAL_NAME_A) == 0)
  1576. {
  1577. TicketCache = &LogonSession->PrimaryCredentials.AuthenticationTicketCache;
  1578. //
  1579. // We only want to use the primary_tgt flag the first time through
  1580. //
  1581. CacheFlags = TgtFlags;
  1582. TgtFlags = 0;
  1583. D_DebugLog((DEB_TRACE,"Adding ticket from kerb_cred to authentication ticket cache\n"));
  1584. }
  1585. else
  1586. {
  1587. TicketCache = &LogonSession->PrimaryCredentials.ServerTicketCache;
  1588. CacheFlags = 0;
  1589. D_DebugLog((DEB_TRACE,"Adding ticket from kerb_cred to server ticket cache\n"));
  1590. }
  1591. FakeReply.client_name = Ticket->client_name;
  1592. FakeReply.ticket = TicketList->value;
  1593. FakeReply.client_realm = Ticket->client_realm;
  1594. Status = KerbCacheTicket(
  1595. TicketCache,
  1596. &FakeReply,
  1597. &FakeReplyBody,
  1598. NULL, // no target name
  1599. NULL,
  1600. CacheFlags,
  1601. TRUE, // link
  1602. &TicketCacheEntry
  1603. );
  1604. if (!NT_SUCCESS(Status))
  1605. {
  1606. D_DebugLog((DEB_ERROR, "Failed to cache ticket: 0x%x. %ws, line %d\n",
  1607. Status, THIS_FILE, __LINE__));
  1608. goto Cleanup;
  1609. }
  1610. LogonSession->LogonSessionFlags &= ~KERB_LOGON_DEFERRED;
  1611. KerbDereferenceTicketCacheEntry(TicketCacheEntry);
  1612. CredInfoList = CredInfoList->next;
  1613. TicketList = TicketList->next;
  1614. }
  1615. //
  1616. // Now that the logon session structure is filled out insert it
  1617. // into the list. After this you need to hold the logon session lock
  1618. // to read or write this logon session.
  1619. //
  1620. if (*OldLogonSession == NULL)
  1621. {
  1622. Status = KerbInsertLogonSession(LogonSession);
  1623. if (!NT_SUCCESS(Status))
  1624. {
  1625. goto Cleanup;
  1626. }
  1627. *OldLogonSession = LogonSession;
  1628. }
  1629. Cleanup:
  1630. if (LogonSessionLocked)
  1631. {
  1632. KerbUnlockLogonSessions(LogonSession);
  1633. }
  1634. if (CreatedLogonSession)
  1635. {
  1636. if (!NT_SUCCESS(Status))
  1637. {
  1638. if (LogonSession != NULL)
  1639. {
  1640. KerbFreeLogonSession(LogonSession);
  1641. }
  1642. }
  1643. }
  1644. KerbFreeString(&AccountName);
  1645. KerbFreeString(&DomainName);
  1646. return(Status);
  1647. }
  1648. #endif // WIN32_CHICAGO