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.

3067 lines
74 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: ctxtmgr.cxx
  8. //
  9. // Contents: Code for managing contexts list for the Kerberos package
  10. //
  11. //
  12. // History: 17-April-1996 Created MikeSw
  13. // 26-Sep-1998 ChandanS
  14. // Added more debugging support etc.
  15. //
  16. //------------------------------------------------------------------------
  17. #include <kerb.hxx>
  18. #define CTXTMGR_ALLOCATE
  19. #include <kerbp.h>
  20. #include "userapi.h"
  21. #ifdef RETAIL_LOG_SUPPORT
  22. static TCHAR THIS_FILE[]=TEXT(__FILE__);
  23. #endif
  24. ULONG
  25. HandleToListIndex(
  26. ULONG_PTR ContextHandle
  27. );
  28. //+-------------------------------------------------------------------------
  29. //
  30. // Function: KerbInitContextList
  31. //
  32. // Synopsis: Initializes the contexts list
  33. //
  34. // Effects: allocates a resources
  35. //
  36. // Arguments: none
  37. //
  38. // Requires:
  39. //
  40. // Returns: STATUS_SUCCESS on success, other error codes
  41. // on failure
  42. //
  43. // Notes:
  44. //
  45. //
  46. //--------------------------------------------------------------------------
  47. NTSTATUS
  48. KerbInitContextList(
  49. VOID
  50. )
  51. {
  52. NTSTATUS Status = STATUS_SUCCESS;
  53. ULONG Index = 0;
  54. __try {
  55. RtlInitializeResource( &KerbContextResource );
  56. } __except(EXCEPTION_EXECUTE_HANDLER)
  57. {
  58. return STATUS_INSUFFICIENT_RESOURCES;
  59. }
  60. for(Index = 0 ; Index < KERB_USERLIST_COUNT ; Index++)
  61. {
  62. Status = KerbInitializeList( &KerbContextList[Index] );
  63. if (!NT_SUCCESS(Status))
  64. {
  65. goto Cleanup;
  66. }
  67. }
  68. KerberosContextsInitialized = TRUE;
  69. Cleanup:
  70. if (!NT_SUCCESS(Status))
  71. {
  72. ULONG i;
  73. RtlDeleteResource( &KerbContextResource );
  74. for( i = 0 ; i < Index ; i++ )
  75. {
  76. KerbFreeList( &KerbContextList[i] );
  77. }
  78. }
  79. return Status;
  80. }
  81. //+-------------------------------------------------------------------------
  82. //
  83. // Function: KerbFreeContextList
  84. //
  85. // Synopsis: Frees the contexts list
  86. //
  87. // Effects:
  88. //
  89. // Arguments: none
  90. //
  91. // Requires:
  92. //
  93. // Returns: none
  94. //
  95. // Notes:
  96. //
  97. //
  98. //--------------------------------------------------------------------------
  99. VOID
  100. KerbFreeContextList(
  101. VOID
  102. )
  103. {
  104. PKERB_CONTEXT Context;
  105. #if 0
  106. if (KerberosContextsInitialized)
  107. {
  108. KerbLockList(&KerbContextList);
  109. //
  110. // Go through the list of logon sessions and dereferences them all
  111. //
  112. while (!IsListEmpty(&KerbContextList.List))
  113. {
  114. Context = CONTAINING_RECORD(
  115. KerbContextList.List.Flink,
  116. KERB_CONTEXT,
  117. ListEntry.Next
  118. );
  119. KerbReferenceListEntry(
  120. &KerbContextList,
  121. &Context->ListEntry,
  122. TRUE
  123. );
  124. KerbDereferenceContext(Context);
  125. }
  126. KerbFreeList(&KerbContextList);
  127. }
  128. #endif
  129. }
  130. //+-------------------------------------------------------------------------
  131. //
  132. // Function: KerbAllocateContext
  133. //
  134. // Synopsis: Allocates a Context structure
  135. //
  136. // Effects: Allocates a Context, but does not add it to the
  137. // list of Contexts
  138. //
  139. // Arguments: NewContext - receives a new Context allocated
  140. // with KerbAllocate
  141. //
  142. // Requires:
  143. //
  144. // Returns: STATUS_SUCCESS on success
  145. // STATUS_INSUFFICIENT_RESOURCES if the allocation fails
  146. //
  147. // Notes:
  148. //
  149. //
  150. //--------------------------------------------------------------------------
  151. NTSTATUS
  152. KerbAllocateContext(
  153. OUT PKERB_CONTEXT * NewContext,
  154. IN BOOLEAN UserMode
  155. )
  156. {
  157. PKERB_CONTEXT Context;
  158. SECPKG_CALL_INFO CallInfo = {0};
  159. //
  160. // Get the client process ID if we are running in the LSA
  161. //
  162. if (!UserMode)
  163. {
  164. if (!LsaFunctions->GetCallInfo(&CallInfo))
  165. {
  166. D_DebugLog((DEB_ERROR,"Failed to get call info\n. %ws, line %d\n",
  167. THIS_FILE, __LINE__));
  168. DsysAssert(FALSE);
  169. return(STATUS_INSUFFICIENT_RESOURCES);
  170. }
  171. }
  172. Context = (PKERB_CONTEXT) KerbAllocate(
  173. sizeof(KERB_CONTEXT) );
  174. if (Context == NULL)
  175. {
  176. return(STATUS_INSUFFICIENT_RESOURCES);
  177. }
  178. Context->ClientProcess = CallInfo.ProcessId;
  179. Context->ContextState = IdleState;
  180. //
  181. // Set the references to 1 since we are returning a pointer to the
  182. // logon session
  183. //
  184. KerbInitializeListEntry(
  185. &Context->ListEntry
  186. );
  187. *NewContext = Context;
  188. return(STATUS_SUCCESS);
  189. }
  190. //+-------------------------------------------------------------------------
  191. //
  192. // Function: KerbInsertContext
  193. //
  194. // Synopsis: Inserts a logon session into the list of logon sessions
  195. //
  196. // Effects: bumps reference count on logon session
  197. //
  198. // Arguments: Context - Context to insert
  199. //
  200. // Requires:
  201. //
  202. // Returns: STATUS_SUCCESS always
  203. //
  204. // Notes:
  205. //
  206. //
  207. //--------------------------------------------------------------------------
  208. NTSTATUS
  209. KerbInsertContext(
  210. IN PKERB_CONTEXT Context
  211. )
  212. {
  213. ULONG ListIndex;
  214. ListIndex = HandleToListIndex( Context->LsaContextHandle );
  215. Context->ContextTag = KERB_CONTEXT_TAG_ACTIVE;
  216. KerbInsertListEntry(
  217. &Context->ListEntry,
  218. &KerbContextList[ListIndex]
  219. );
  220. return(STATUS_SUCCESS);
  221. }
  222. //+-------------------------------------------------------------------------
  223. //
  224. // Function: KerbReferenceContext
  225. //
  226. // Synopsis: Locates a context context handleand references it
  227. //
  228. // Effects: Increments reference count and possible unlinks it from list
  229. //
  230. // Arguments: ContextHandle - Handle of context to reference.
  231. // RemoveFromList - If TRUE, context will be delinked.
  232. //
  233. // Requires:
  234. //
  235. // Returns:
  236. //
  237. // Notes:
  238. //
  239. //
  240. //--------------------------------------------------------------------------
  241. SECURITY_STATUS
  242. KerbReferenceContext(
  243. IN LSA_SEC_HANDLE ContextHandle,
  244. IN BOOLEAN RemoveFromList,
  245. OUT PKERB_CONTEXT * FoundContext
  246. )
  247. {
  248. PKERB_CONTEXT Context = NULL;
  249. BOOLEAN Found = FALSE;
  250. SECPKG_CLIENT_INFO ClientInfo;
  251. NTSTATUS Status = STATUS_SUCCESS;
  252. ULONG ListIndex = 0;
  253. BOOLEAN ListLocked = FALSE;
  254. if (KerberosState == KerberosLsaMode)
  255. {
  256. Status = LsaFunctions->GetClientInfo(&ClientInfo);
  257. if (!NT_SUCCESS(Status))
  258. {
  259. SECPKG_CALL_INFO CallInfo;
  260. //
  261. // Check to see if the call is terminating. If so, give it
  262. // TCB privilege because it is really the LSA doing this.
  263. //
  264. if (LsaFunctions->GetCallInfo(&CallInfo))
  265. {
  266. if ((CallInfo.Attributes & SECPKG_CALL_CLEANUP) != 0)
  267. {
  268. Status = STATUS_SUCCESS;
  269. RtlZeroMemory(
  270. &ClientInfo,
  271. sizeof(SECPKG_CLIENT_INFO)
  272. );
  273. ClientInfo.HasTcbPrivilege = TRUE;
  274. }
  275. }
  276. if (!NT_SUCCESS(Status))
  277. {
  278. D_DebugLog((DEB_ERROR,"Failed to get client info: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  279. *FoundContext = NULL ;
  280. return(Status);
  281. }
  282. }
  283. }
  284. else
  285. {
  286. ClientInfo.HasTcbPrivilege = FALSE ;
  287. ClientInfo.ProcessID = GetCurrentProcessId();
  288. }
  289. //
  290. // Go through the list of logon sessions looking for the correct
  291. // context
  292. //
  293. __try {
  294. Context = (PKERB_CONTEXT)ContextHandle;
  295. while ( Context->ContextTag == KERB_CONTEXT_TAG_ACTIVE )
  296. {
  297. ListIndex = HandleToListIndex( Context->LsaContextHandle );
  298. KerbLockList(&KerbContextList[ListIndex]);
  299. ListLocked = TRUE;
  300. //
  301. // Make sure that if we aren't trying to remove it we are
  302. // from the correct process.
  303. //
  304. if (!ClientInfo.HasTcbPrivilege &&
  305. (Context->ClientProcess != ClientInfo.ProcessID) &&
  306. (KerberosState == KerberosLsaMode))
  307. {
  308. D_DebugLog((DEB_ERROR,"Trying to reference a context from another process! %ws, line %d\n", THIS_FILE, __LINE__));
  309. Found = FALSE;
  310. break;
  311. }
  312. //
  313. // If the context is expired, don't allow it to be referenced.
  314. //
  315. if (KerbGlobalEnforceTime && !RemoveFromList)
  316. {
  317. TimeStamp CurrentTime;
  318. TimeStamp ContextExpires;
  319. GetSystemTimeAsFileTime((PFILETIME) &CurrentTime);
  320. ContextExpires = Context->Lifetime;
  321. if (KerbGetTime(ContextExpires) < KerbGetTime(CurrentTime))
  322. {
  323. D_DebugLog((DEB_WARN, "Trying to reference expired context\n"));
  324. Found = FALSE;
  325. Status = SEC_E_CONTEXT_EXPIRED;
  326. break;
  327. }
  328. }
  329. KerbReferenceListEntry(
  330. &KerbContextList[ ListIndex ],
  331. &Context->ListEntry,
  332. RemoveFromList
  333. );
  334. Found = TRUE;
  335. break;
  336. }
  337. } __except( EXCEPTION_EXECUTE_HANDLER )
  338. {
  339. D_DebugLog((DEB_ERROR,"Trying to reference invalid context %ws, line %d\n", THIS_FILE, __LINE__));
  340. Found = FALSE;
  341. }
  342. if( ListLocked )
  343. {
  344. KerbUnlockList(&KerbContextList[ListIndex]);
  345. }
  346. if (!Found)
  347. {
  348. Context = NULL;
  349. }
  350. *FoundContext = Context ;
  351. if ( Context )
  352. {
  353. return Status;
  354. }
  355. else if (NT_SUCCESS(Status))
  356. {
  357. return SEC_E_INVALID_HANDLE ;
  358. }
  359. else
  360. {
  361. return Status;
  362. }
  363. }
  364. //+-------------------------------------------------------------------------
  365. //
  366. // Function: KerbReferenceContextByLsaHandle
  367. //
  368. // Synopsis: Locates a context by lsa context handle and references it
  369. //
  370. // Effects: Increments reference count and possible unlinks it from list
  371. //
  372. // Arguments: ContextHandle - Lsa Handle of context to reference.
  373. // RemoveFromList - If TRUE, context will be delinked.
  374. //
  375. // Requires:
  376. //
  377. // Returns:
  378. //
  379. // Notes:
  380. //
  381. //
  382. //--------------------------------------------------------------------------
  383. SECURITY_STATUS
  384. KerbReferenceContextByLsaHandle(
  385. IN LSA_SEC_HANDLE ContextHandle,
  386. IN BOOLEAN RemoveFromList,
  387. OUT PKERB_CONTEXT *FoundContext
  388. )
  389. {
  390. PLIST_ENTRY ListEntry;
  391. PKERB_CONTEXT Context = NULL;
  392. BOOLEAN Found = FALSE;
  393. NTSTATUS Status = STATUS_SUCCESS;
  394. ULONG ListIndex;
  395. ListIndex = HandleToListIndex( ContextHandle );
  396. KerbLockList(&KerbContextList[ListIndex]);
  397. //
  398. // Go through the list of logon sessions looking for the correct
  399. // context
  400. //
  401. for (ListEntry = KerbContextList[ListIndex].List.Flink ;
  402. ListEntry != &KerbContextList[ListIndex].List ;
  403. ListEntry = ListEntry->Flink )
  404. {
  405. Context = CONTAINING_RECORD(ListEntry, KERB_CONTEXT, ListEntry.Next);
  406. if (ContextHandle == Context->LsaContextHandle)
  407. {
  408. //
  409. // Make sure that if we aren't trying to remove it we are
  410. // from the correct process.
  411. //
  412. //
  413. // If the context is expired, don't allow it to be referenced.
  414. //
  415. if (KerbGlobalEnforceTime && !RemoveFromList )
  416. {
  417. TimeStamp CurrentTime;
  418. TimeStamp ContextExpires;
  419. GetSystemTimeAsFileTime((PFILETIME) &CurrentTime );
  420. ContextExpires = Context->Lifetime;
  421. if (KerbGetTime(ContextExpires) < KerbGetTime(CurrentTime))
  422. {
  423. D_DebugLog((DEB_WARN, "Trying to reference expired context\n"));
  424. Found = FALSE;
  425. Status = SEC_E_CONTEXT_EXPIRED;
  426. break;
  427. }
  428. }
  429. KerbReferenceListEntry(
  430. &KerbContextList[ListIndex],
  431. &Context->ListEntry,
  432. RemoveFromList
  433. );
  434. Found = TRUE;
  435. break;
  436. }
  437. }
  438. KerbUnlockList(&KerbContextList[ListIndex]);
  439. if (!Found)
  440. {
  441. Context = NULL;
  442. }
  443. *FoundContext = Context ;
  444. if ( Context )
  445. {
  446. return Status;
  447. }
  448. else if (NT_SUCCESS(Status))
  449. {
  450. return SEC_E_INVALID_HANDLE ;
  451. }
  452. else
  453. {
  454. return Status;
  455. }
  456. }
  457. //+-------------------------------------------------------------------------
  458. //
  459. // Function: KerbReferenceContextByPointer
  460. //
  461. // Synopsis: References a context by the context pointer itself.
  462. //
  463. // Effects: Increments reference count and possible unlinks it from list
  464. //
  465. // Arguments: Context - The context to reference.
  466. // RemoveFromList - If TRUE, context will be delinked
  467. //
  468. // Requires:
  469. //
  470. // Returns:
  471. //
  472. // Notes:
  473. //
  474. //
  475. //--------------------------------------------------------------------------
  476. VOID
  477. KerbReferenceContextByPointer(
  478. IN PKERB_CONTEXT Context,
  479. IN BOOLEAN RemoveFromList
  480. )
  481. {
  482. ULONG ListIndex;
  483. ListIndex = HandleToListIndex( Context->LsaContextHandle );
  484. KerbLockList(&KerbContextList[ListIndex]);
  485. KerbReferenceListEntry(
  486. &KerbContextList[ListIndex],
  487. &Context->ListEntry,
  488. RemoveFromList
  489. );
  490. KerbUnlockList(&KerbContextList[ListIndex]);
  491. }
  492. //+-------------------------------------------------------------------------
  493. //
  494. // Function: KerbFreeContext
  495. //
  496. // Synopsis: Frees a context that is unlinked
  497. //
  498. // Effects: frees all storage associated with the context
  499. //
  500. // Arguments: Context - context to free
  501. //
  502. // Requires:
  503. //
  504. // Returns: none
  505. //
  506. // Notes:
  507. //
  508. //
  509. //--------------------------------------------------------------------------
  510. VOID
  511. KerbFreeContext(
  512. IN PKERB_CONTEXT Context
  513. )
  514. {
  515. #ifndef WIN32_CHICAGO
  516. if (Context->TokenHandle != NULL)
  517. {
  518. NtClose(Context->TokenHandle);
  519. }
  520. #endif // WIN32_CHICAGO
  521. Context->ContextTag = KERB_CONTEXT_TAG_DELETE;
  522. KerbFreeKey(&Context->SessionKey);
  523. KerbFreeKey(&Context->TicketKey);
  524. if (Context->TicketCacheEntry != NULL)
  525. {
  526. KerbDereferenceTicketCacheEntry(Context->TicketCacheEntry);
  527. }
  528. if (Context->UserSid != NULL)
  529. {
  530. KerbFree(Context->UserSid);
  531. }
  532. KerbFreeString(&Context->ClientName);
  533. KerbFreeString(&Context->ClientRealm);
  534. KerbFreeString(&Context->ClientPrincipalName);
  535. KerbFreeString(&Context->ServerPrincipalName);
  536. if( Context->pbMarshalledTargetInfo )
  537. {
  538. LocalFree( Context->pbMarshalledTargetInfo );
  539. }
  540. KerbFree(Context);
  541. }
  542. //+-------------------------------------------------------------------------
  543. //
  544. // Function: KerbDereferenceContext
  545. //
  546. // Synopsis: Dereferences a logon session - if reference count goes
  547. // to zero it frees the logon session
  548. //
  549. // Effects: decrements reference count
  550. //
  551. // Arguments: Context - Logon session to dereference
  552. //
  553. // Requires:
  554. //
  555. // Returns: none
  556. //
  557. // Notes:
  558. //
  559. //
  560. //--------------------------------------------------------------------------
  561. VOID
  562. KerbDereferenceContext(
  563. IN PKERB_CONTEXT Context
  564. )
  565. {
  566. ULONG ListIndex;
  567. ListIndex = HandleToListIndex( Context->LsaContextHandle );
  568. if (KerbDereferenceListEntry(
  569. &Context->ListEntry,
  570. &KerbContextList[ListIndex]
  571. ) )
  572. {
  573. KerbFreeContext(Context);
  574. }
  575. }
  576. //+-------------------------------------------------------------------------
  577. //
  578. // Function: KerbCreateEmptyContext
  579. //
  580. // Synopsis: Creates a context for the server of a datagram authentication
  581. // session. Since there is no input message, all the fields
  582. // are initialized to zero.
  583. //
  584. // Effects: Allocates and links a context.
  585. //
  586. // Arguments: Credential - Credential to hang this context off of
  587. // ContextFlags - Flags for the context
  588. // LogonId = LogonId of the creating logon session
  589. // NewContext - receives referenced context pointer,
  590. // ContextLifetime - Lifetime for the context.
  591. //
  592. // Requires:
  593. //
  594. // Returns: NTSTATUS code
  595. //
  596. // Notes:
  597. //
  598. //
  599. //--------------------------------------------------------------------------
  600. NTSTATUS
  601. KerbCreateEmptyContext(
  602. IN PKERB_CREDENTIAL Credential,
  603. IN ULONG ContextFlags,
  604. IN ULONG ContextAttributes,
  605. IN PLUID LogonId,
  606. OUT PKERB_CONTEXT * NewContext,
  607. OUT PTimeStamp ContextLifetime
  608. )
  609. {
  610. NTSTATUS Status;
  611. PKERB_CONTEXT Context = NULL;
  612. Status = KerbAllocateContext( &Context, FALSE );
  613. if (!NT_SUCCESS(Status))
  614. {
  615. goto Cleanup;
  616. }
  617. Context->CredentialHandle = KerbGetCredentialHandle(Credential);
  618. Context->ContextFlags = ContextFlags;
  619. Context->ContextAttributes = ContextAttributes;
  620. Context->Lifetime = KerbGlobalWillNeverTime;
  621. Context->CredManCredentials = NULL;
  622. GetSystemTimeAsFileTime((PFILETIME)
  623. &(Context->StartTime)
  624. );
  625. Context->LogonId = *LogonId;
  626. *ContextLifetime = Context->Lifetime;
  627. Status = KerbInsertContext(
  628. Context
  629. );
  630. if (!NT_SUCCESS(Status))
  631. {
  632. D_DebugLog((DEB_ERROR,"Failed to insert context: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  633. goto Cleanup;
  634. }
  635. *NewContext = Context;
  636. Cleanup:
  637. if (!NT_SUCCESS(Status))
  638. {
  639. if (Context != NULL)
  640. {
  641. KerbFreeContext(Context);
  642. }
  643. }
  644. return(Status);
  645. }
  646. //+-------------------------------------------------------------------------
  647. //
  648. // Function: KerbCreateClientContext
  649. //
  650. // Synopsis: Creates a context for the client of an authentication
  651. // session.
  652. //
  653. // Effects: Allocates and links a context.
  654. //
  655. // Arguments: LogonSession - Logon session to lock when accessing the credential
  656. // Credential - Credential to hang this context off of
  657. // TicketCacheEntry - Ticket around which to build this context
  658. // TargetName - target name supplied by client.
  659. // Nonce - Nonce used in AP request
  660. // SubSessionKey - subsession key to use, if present
  661. // ContextFlags - Flags passed in by client for authentication
  662. // options.
  663. // NewContext - receives referenced context pointer,
  664. // ContextLifetime - Lifetime for the context.
  665. //
  666. // Requires:
  667. //
  668. // Returns: NTSTATUS code
  669. //
  670. // Notes:
  671. //
  672. //
  673. //--------------------------------------------------------------------------
  674. NTSTATUS
  675. KerbCreateClientContext(
  676. IN PKERB_LOGON_SESSION LogonSession,
  677. IN PKERB_CREDENTIAL Credential,
  678. IN OPTIONAL PKERB_CREDMAN_CRED CredManCredentials,
  679. IN OPTIONAL PKERB_TICKET_CACHE_ENTRY TicketCacheEntry,
  680. IN OPTIONAL PUNICODE_STRING TargetName,
  681. IN ULONG Nonce,
  682. IN ULONG ContextFlags,
  683. IN ULONG ContextAttributes,
  684. IN OPTIONAL PKERB_ENCRYPTION_KEY SubSessionKey,
  685. OUT PKERB_CONTEXT * NewContext,
  686. OUT PTimeStamp ContextLifetime
  687. )
  688. {
  689. NTSTATUS Status;
  690. PKERB_CONTEXT Context = NULL;
  691. Status = KerbAllocateContext( &Context, FALSE );
  692. if (!NT_SUCCESS(Status))
  693. {
  694. goto Cleanup;
  695. }
  696. if (ARGUMENT_PRESENT(TicketCacheEntry))
  697. {
  698. //
  699. // If we are doing datagram, reference the cache entry and
  700. // store a pointer to it in the context. The ticket cache cannot be
  701. // read locked at this point because the call to acquire a write
  702. // lock will block.
  703. //
  704. if ((ContextFlags & ISC_RET_DATAGRAM) != 0)
  705. {
  706. KerbReferenceTicketCacheEntry(TicketCacheEntry);
  707. Context->TicketCacheEntry = TicketCacheEntry;
  708. }
  709. KerbReadLockTicketCache();
  710. //
  711. // Duplicate the session key into the context
  712. //
  713. if (ARGUMENT_PRESENT(SubSessionKey) && (SubSessionKey->keyvalue.value != NULL))
  714. {
  715. if (!KERB_SUCCESS(KerbDuplicateKey(
  716. &Context->SessionKey,
  717. SubSessionKey
  718. )))
  719. {
  720. KerbUnlockTicketCache();
  721. Status = STATUS_INSUFFICIENT_RESOURCES;
  722. goto Cleanup;
  723. }
  724. }
  725. else
  726. {
  727. //
  728. // For datagram, create a key
  729. //
  730. if ((ContextFlags & ISC_RET_DATAGRAM) != 0)
  731. {
  732. KERBERR KerbErr;
  733. SECPKG_CALL_INFO CallInfo;
  734. if (!LsaFunctions->GetCallInfo(&CallInfo))
  735. {
  736. D_DebugLog((DEB_ERROR,"Failed to get client info: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  737. Status = STATUS_INSUFFICIENT_RESOURCES;
  738. KerbUnlockTicketCache();
  739. goto Cleanup;
  740. }
  741. //
  742. // If we are configured for strong encryption & we have said to
  743. // use it for datagram or this is an inprocess caller, then create
  744. // a strong key.
  745. //
  746. D_DebugLog((DEB_TRACE_CTXT,"Making exportable key for datagram client context\n"));
  747. if ((KerbGlobalStrongEncryptionPermitted &&
  748. KerbGlobalUseStrongEncryptionForDatagram) ||
  749. (CallInfo.Attributes & SECPKG_CALL_IN_PROC))
  750. {
  751. KerbErr = KerbMakeKey(
  752. TicketCacheEntry->SessionKey.keytype,
  753. &Context->SessionKey
  754. );
  755. }
  756. else
  757. {
  758. KerbErr = KerbMakeExportableKey(
  759. TicketCacheEntry->SessionKey.keytype,
  760. &Context->SessionKey
  761. );
  762. }
  763. if (!KERB_SUCCESS(KerbErr))
  764. {
  765. Status = KerbMapKerbError(KerbErr);
  766. KerbUnlockTicketCache();
  767. goto Cleanup;
  768. }
  769. }
  770. else
  771. {
  772. if (!KERB_SUCCESS(KerbDuplicateKey(
  773. &Context->SessionKey,
  774. &TicketCacheEntry->SessionKey
  775. )))
  776. {
  777. KerbUnlockTicketCache();
  778. Status = STATUS_INSUFFICIENT_RESOURCES;
  779. goto Cleanup;
  780. }
  781. }
  782. }
  783. if (!KERB_SUCCESS(KerbDuplicateKey(
  784. &Context->TicketKey,
  785. &TicketCacheEntry->SessionKey
  786. )))
  787. {
  788. KerbUnlockTicketCache();
  789. Status = STATUS_INSUFFICIENT_RESOURCES;
  790. goto Cleanup;
  791. }
  792. //
  793. // Get the client's realm
  794. //
  795. Status = KerbDuplicateString(
  796. &Context->ClientRealm,
  797. &TicketCacheEntry->DomainName);
  798. if (!NT_SUCCESS(Status))
  799. {
  800. KerbUnlockTicketCache();
  801. goto Cleanup;
  802. }
  803. //
  804. // Get the client's name.
  805. //
  806. if (!KERB_SUCCESS(KerbConvertKdcNameToString(
  807. &Context->ClientName,
  808. TicketCacheEntry->ClientName,
  809. NULL)))
  810. {
  811. Status = STATUS_INSUFFICIENT_RESOURCES;
  812. KerbUnlockTicketCache();
  813. goto Cleanup;
  814. }
  815. Context->Lifetime = TicketCacheEntry->EndTime;
  816. Context->StartTime = TicketCacheEntry->StartTime;
  817. Context->RenewTime = TicketCacheEntry->RenewUntil;
  818. Context->EncryptionType = TicketCacheEntry->Ticket.encrypted_part.encryption_type;
  819. KerbUnlockTicketCache();
  820. }
  821. else
  822. {
  823. Context->Lifetime = KerbGlobalWillNeverTime;
  824. Context->RenewTime = KerbGlobalWillNeverTime;
  825. GetSystemTimeAsFileTime((PFILETIME)
  826. &(Context->StartTime)
  827. );
  828. Context->EncryptionType = KERB_ETYPE_NULL;
  829. }
  830. Context->Nonce = Nonce;
  831. //
  832. // For now, until the server sends us a separate nonce, use the one
  833. // we generated for receiving data
  834. //
  835. Context->ReceiveNonce = Nonce;
  836. Context->CredentialHandle = KerbGetCredentialHandle(Credential);
  837. //KerbReadLockLogonSessions(LogonSession); // FESTER: Needed??
  838. if (ARGUMENT_PRESENT(CredManCredentials))
  839. {
  840. Context->ContextAttributes |= KERB_CONTEXT_USING_CREDMAN;
  841. Context->CredManCredentials = CredManCredentials; // don't ref, as we don't use it..
  842. }
  843. else if ((Credential->SuppliedCredentials != NULL))
  844. {
  845. Context->ContextAttributes |= KERB_CONTEXT_USED_SUPPLIED_CREDS;
  846. }
  847. //KerbUnlockLogonSessions(LogonSession);
  848. Context->ContextFlags = ContextFlags;
  849. Context->ContextAttributes = KERB_CONTEXT_OUTBOUND | ContextAttributes;
  850. //
  851. // if the caller supplied a target name, stash it in the context
  852. //
  853. if (ARGUMENT_PRESENT(TargetName))
  854. {
  855. Status = KerbDuplicateString(
  856. &Context->ServerPrincipalName,
  857. TargetName
  858. );
  859. if (!NT_SUCCESS(Status))
  860. {
  861. goto Cleanup;
  862. }
  863. }
  864. *ContextLifetime = Context->Lifetime;
  865. Status = KerbInsertContext(
  866. Context
  867. );
  868. if (!NT_SUCCESS(Status))
  869. {
  870. D_DebugLog((DEB_ERROR,"Failed to insert context: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  871. goto Cleanup;
  872. }
  873. *NewContext = Context;
  874. Cleanup:
  875. if (!NT_SUCCESS(Status))
  876. {
  877. if (Context != NULL)
  878. {
  879. KerbFreeContext(Context);
  880. }
  881. }
  882. return(Status);
  883. }
  884. //+-------------------------------------------------------------------------
  885. //
  886. // Function: KerbCreateSKeyEntry
  887. //
  888. // Synopsis: Create a session key entry
  889. //
  890. // Effects:
  891. //
  892. // Arguments: pSessionKey - session key that is used, mostly SubKey
  893. // pExpireTime - time that the session key expires
  894. //
  895. // Requires: Memory allocator must zero out memory because KerbFreeSKeyEntry
  896. // relies on that behavior
  897. //
  898. // Returns:
  899. //
  900. // Notes:
  901. //
  902. //
  903. //--------------------------------------------------------------------------
  904. NTSTATUS
  905. KerbCreateSKeyEntry(
  906. IN KERB_ENCRYPTION_KEY* pSessionKey,
  907. IN FILETIME* pExpireTime
  908. )
  909. {
  910. NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
  911. KERB_SESSION_KEY_ENTRY* pSessionKeyEntry = NULL;
  912. if (!pSessionKey || !pExpireTime)
  913. {
  914. return STATUS_INVALID_PARAMETER;
  915. }
  916. pSessionKeyEntry = (KERB_SESSION_KEY_ENTRY*) KerbAllocate(sizeof(KERB_SESSION_KEY_ENTRY));
  917. if (!pSessionKeyEntry)
  918. {
  919. return STATUS_NO_MEMORY;
  920. }
  921. InitializeListHead(&pSessionKeyEntry->ListEntry); // so that un-linking always works
  922. NtStatus = KerbMapKerbError(KerbDuplicateKey(&pSessionKeyEntry->SessionKey, pSessionKey));
  923. if (NT_SUCCESS(NtStatus))
  924. {
  925. pSessionKeyEntry->ExpireTime = *pExpireTime;
  926. NtStatus = KerbInsertSKey(pSessionKeyEntry);
  927. }
  928. if (!NT_SUCCESS(NtStatus))
  929. {
  930. KerbFreeSKeyEntry(pSessionKeyEntry);
  931. }
  932. return NtStatus;
  933. }
  934. //+-------------------------------------------------------------------------
  935. //
  936. // Function: KerbDoesSKeyExist
  937. //
  938. // Synopsis: check whether a session key entry exists the session key list
  939. //
  940. // Effects:
  941. //
  942. // Arguments: pKey - key to be located
  943. // pbExist - whether session key entry exists
  944. //
  945. // Requires:
  946. //
  947. // Returns: If an entry is found, ppSKeyEntry points to the entry
  948. // that contains pKey hence should be non null
  949. //
  950. // Notes:
  951. //
  952. //
  953. //--------------------------------------------------------------------------
  954. NTSTATUS
  955. KerbDoesSKeyExist(
  956. IN KERB_ENCRYPTION_KEY* pKey,
  957. OUT BOOLEAN* pbExist
  958. )
  959. {
  960. FILETIME CurrentTime = {0};
  961. NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
  962. if (!pKey || !pbExist)
  963. {
  964. return STATUS_INVALID_PARAMETER;
  965. }
  966. *pbExist = FALSE;
  967. GetSystemTimeAsFileTime(&CurrentTime);
  968. DebugLog((DEB_TRACE_LOOPBACK, "KerbDoesSKeyExist, curtime %#x:%#x\n", CurrentTime.dwHighDateTime, CurrentTime.dwLowDateTime));
  969. if (RtlAcquireResourceShared(&KerbNetworkServiceSKeyLock, TRUE))
  970. {
  971. NtStatus = STATUS_SUCCESS;
  972. for (LIST_ENTRY* pListEntry = KerbNetworkServiceSKeyList.Flink;
  973. NT_SUCCESS(NtStatus) && pListEntry != &KerbNetworkServiceSKeyList;
  974. pListEntry = pListEntry->Flink)
  975. {
  976. KERB_SESSION_KEY_ENTRY* pSKeyEntry = CONTAINING_RECORD(pListEntry, KERB_SESSION_KEY_ENTRY, ListEntry);
  977. //
  978. // only keys that have not expired are checked
  979. //
  980. if (KerbGetTime(* (TimeStamp*)&pSKeyEntry->ExpireTime) > KerbGetTime(* (TimeStamp*)&CurrentTime))
  981. {
  982. BOOLEAN bEqual = FALSE;
  983. NtStatus = KerbEqualKey(&pSKeyEntry->SessionKey, pKey, &bEqual);
  984. if (NT_SUCCESS(NtStatus) && bEqual)
  985. {
  986. //
  987. // found it
  988. //
  989. DebugLog((DEB_TRACE_LOOPBACK, "KerbDoesSKeyExist, keyexpire %#x:%#x found\n", pSKeyEntry->ExpireTime.dwHighDateTime, pSKeyEntry->ExpireTime.dwLowDateTime));
  990. *pbExist = TRUE;
  991. break;
  992. }
  993. }
  994. }
  995. RtlReleaseResource(&KerbNetworkServiceSKeyLock);
  996. }
  997. return NtStatus;
  998. }
  999. //+-----------------------------------------------------------------------
  1000. //
  1001. // Function: KerbEqualKey
  1002. //
  1003. // Synopsis: Compare two keys
  1004. //
  1005. // Effects:
  1006. //
  1007. // Arguments: pKeyFoo - one key
  1008. // pKeyBar - the other key
  1009. //
  1010. // Returns: NTSTATUS
  1011. //
  1012. // History:
  1013. //
  1014. //------------------------------------------------------------------------
  1015. NTSTATUS
  1016. KerbEqualKey(
  1017. IN KERB_ENCRYPTION_KEY* pKeyFoo,
  1018. IN KERB_ENCRYPTION_KEY* pKeyBar,
  1019. OUT BOOLEAN* pbEqual
  1020. )
  1021. {
  1022. if (!pKeyFoo || !pKeyBar || !pbEqual)
  1023. {
  1024. return STATUS_INVALID_PARAMETER;
  1025. }
  1026. *pbEqual = (pKeyFoo->keytype == pKeyBar->keytype) &&
  1027. (pKeyFoo->keyvalue.length == pKeyBar->keyvalue.length) &&
  1028. (pKeyFoo->keyvalue.length == RtlCompareMemory(pKeyFoo->keyvalue.value, pKeyBar->keyvalue.value, pKeyFoo->keyvalue.length));
  1029. return STATUS_SUCCESS;
  1030. }
  1031. //+-------------------------------------------------------------------------
  1032. //
  1033. // Function: KerbInsertSessionKey
  1034. //
  1035. // Synopsis: Insert an session key entry to KerbNetWorkSessionKeyList
  1036. //
  1037. // Effects:
  1038. //
  1039. // Arguments: pSKeyEntry - entry to be inserted
  1040. //
  1041. // Requires:
  1042. //
  1043. // Returns:
  1044. //
  1045. // Notes:
  1046. //
  1047. //
  1048. //--------------------------------------------------------------------------
  1049. NTSTATUS
  1050. KerbInsertSKey(
  1051. IN KERB_SESSION_KEY_ENTRY* pSKeyEntry
  1052. )
  1053. {
  1054. NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
  1055. if (!pSKeyEntry)
  1056. {
  1057. return STATUS_INVALID_PARAMETER;
  1058. }
  1059. if (RtlAcquireResourceExclusive(&KerbNetworkServiceSKeyLock, TRUE))
  1060. {
  1061. NtStatus = STATUS_SUCCESS;
  1062. InsertHeadList(&KerbNetworkServiceSKeyList, &pSKeyEntry->ListEntry);
  1063. RtlReleaseResource(&KerbNetworkServiceSKeyLock);
  1064. }
  1065. #if DBG
  1066. ULONG cSKeyEntries = 0;
  1067. if (NT_SUCCESS(NtStatus))
  1068. {
  1069. cSKeyEntries = InterlockedIncrement(&KerbcSKeyEntries);
  1070. }
  1071. DebugLog((DEB_TRACE_LOOPBACK, "KerbInsertSKey, status 0x%x, keyexpire %#x:%#x, total %d keys\n", NtStatus, pSKeyEntry->ExpireTime.dwHighDateTime, pSKeyEntry->ExpireTime.dwLowDateTime, cSKeyEntries));
  1072. #endif
  1073. return NtStatus;
  1074. }
  1075. //+-------------------------------------------------------------------------
  1076. //
  1077. // Function: KerbTrimSKeyList
  1078. //
  1079. // Synopsis: Release session key entries that have expired
  1080. //
  1081. // Effects:
  1082. //
  1083. // Arguments:
  1084. //
  1085. // Requires:
  1086. //
  1087. // Returns:
  1088. //
  1089. // Notes:
  1090. //
  1091. //
  1092. //--------------------------------------------------------------------------
  1093. VOID
  1094. KerbTrimSKeyList(
  1095. VOID
  1096. )
  1097. {
  1098. FILETIME CurrentTime = {0};
  1099. BOOLEAN bCleanUpNeeded = FALSE;
  1100. GetSystemTimeAsFileTime(&CurrentTime);
  1101. DebugLog((DEB_TRACE_LOOPBACK, "KerbTrimSKeyList, curtime %#x:%#x\n", CurrentTime.dwHighDateTime, CurrentTime.dwLowDateTime));
  1102. if (RtlAcquireResourceShared(&KerbNetworkServiceSKeyLock, TRUE))
  1103. {
  1104. for (LIST_ENTRY* pListEntry = KerbNetworkServiceSKeyList.Flink;
  1105. pListEntry != &KerbNetworkServiceSKeyList;
  1106. pListEntry = pListEntry->Flink)
  1107. {
  1108. KERB_SESSION_KEY_ENTRY* pSKeyEntry = CONTAINING_RECORD(pListEntry, KERB_SESSION_KEY_ENTRY, ListEntry);
  1109. if (KerbGetTime(* (TimeStamp*)&pSKeyEntry->ExpireTime) <= KerbGetTime(* (TimeStamp*)&CurrentTime))
  1110. {
  1111. bCleanUpNeeded = TRUE;
  1112. break;
  1113. }
  1114. }
  1115. if (bCleanUpNeeded)
  1116. {
  1117. RtlConvertSharedToExclusive(&KerbNetworkServiceSKeyLock);
  1118. for (LIST_ENTRY* pListEntry = KerbNetworkServiceSKeyList.Flink;
  1119. pListEntry != &KerbNetworkServiceSKeyList;
  1120. /* updating pListEntry inside the loop */)
  1121. {
  1122. KERB_SESSION_KEY_ENTRY* pSKeyEntry = CONTAINING_RECORD(pListEntry, KERB_SESSION_KEY_ENTRY, ListEntry);
  1123. //
  1124. // Update next link before pListEntry is deleted
  1125. //
  1126. pListEntry = pListEntry->Flink;
  1127. //
  1128. // only delete keys that expired
  1129. //
  1130. if (KerbGetTime(* (TimeStamp*)&pSKeyEntry->ExpireTime) <= KerbGetTime(* (TimeStamp*)&CurrentTime))
  1131. {
  1132. KerbFreeSKeyEntry(pSKeyEntry);
  1133. }
  1134. }
  1135. }
  1136. RtlReleaseResource(&KerbNetworkServiceSKeyLock);
  1137. }
  1138. }
  1139. //+-------------------------------------------------------------------------
  1140. //
  1141. // Function: KerbNetworkServiceSKeyListCleanupCallback
  1142. //
  1143. // Synopsis: Clean up network service session key list
  1144. //
  1145. // Effects:
  1146. //
  1147. // Arguments: pContext - the context parameter, see RtlCreateTimer
  1148. // bTimeOut - whether a timeout has occurred
  1149. //
  1150. // Requires:
  1151. //
  1152. // Returns:
  1153. //
  1154. // Notes:
  1155. //
  1156. //
  1157. //--------------------------------------------------------------------------
  1158. VOID
  1159. KerbNetworkServiceSKeyListCleanupCallback(
  1160. IN VOID* pContext,
  1161. IN BOOLEAN bTimeOut
  1162. )
  1163. {
  1164. DebugLog((DEB_TRACE_LOOPBACK, "KerbNetworkServiceSKeyListCleanupCallback is called\n"));
  1165. KerbTrimSKeyList();
  1166. }
  1167. //+-------------------------------------------------------------------------
  1168. //
  1169. // Function: KerbFreeSKeyEntry
  1170. //
  1171. // Synopsis: Free a session key entry
  1172. //
  1173. // Effects:
  1174. //
  1175. // Arguments: pSKeyEntry - session key entry to free
  1176. //
  1177. // Requires: pSKeyEntry->ListEntry must have been initialized properly
  1178. //
  1179. // Returns:
  1180. //
  1181. // Notes:
  1182. //
  1183. //
  1184. //--------------------------------------------------------------------------
  1185. VOID
  1186. KerbFreeSKeyEntry(
  1187. IN KERB_SESSION_KEY_ENTRY* pSKeyEntry
  1188. )
  1189. {
  1190. if (pSKeyEntry)
  1191. {
  1192. RemoveEntryList(&pSKeyEntry->ListEntry);
  1193. #if DBG
  1194. LONG cSKeyEntries = 0;
  1195. cSKeyEntries = InterlockedDecrement(&KerbcSKeyEntries);
  1196. DebugLog((DEB_TRACE_LOOPBACK, "KerbFreeSKeyEntry, keyexpire %#x:%#x, %d keys left\n", pSKeyEntry->ExpireTime.dwHighDateTime, pSKeyEntry->ExpireTime.dwLowDateTime, cSKeyEntries));
  1197. #endif
  1198. KerbFreeKey(&pSKeyEntry->SessionKey);
  1199. KerbFree(pSKeyEntry);
  1200. }
  1201. }
  1202. //+-------------------------------------------------------------------------
  1203. //
  1204. // Function: KerbCreateSKeyTimer
  1205. //
  1206. // Synopsis: Create a timer and set the callback to clean up the session
  1207. // key list
  1208. //
  1209. // Effects:
  1210. //
  1211. // Arguments:
  1212. //
  1213. // Requires:
  1214. //
  1215. // Returns:
  1216. //
  1217. // Notes:
  1218. //
  1219. //
  1220. //--------------------------------------------------------------------------
  1221. NTSTATUS
  1222. KerbCreateSKeyTimer(
  1223. VOID
  1224. )
  1225. {
  1226. NTSTATUS NtStatus;
  1227. HANDLE hTimer = NULL;
  1228. KerbhSKeyTimerQueue = NULL;
  1229. NtStatus = RtlCreateTimerQueue(&KerbhSKeyTimerQueue);
  1230. if (NT_SUCCESS(NtStatus))
  1231. {
  1232. NtStatus = RtlCreateTimer(
  1233. KerbhSKeyTimerQueue,
  1234. &hTimer,
  1235. KerbNetworkServiceSKeyListCleanupCallback,
  1236. NULL, // no context
  1237. KERB_DEFAULT_SKEWTIME * 60 * 1000, // 5 min
  1238. KERB_DEFAULT_SKEWTIME * KERB_SKLIST_CALLBACK_FEQ * 60 * 1000, // 50 min
  1239. 0
  1240. );
  1241. }
  1242. return NtStatus;
  1243. }
  1244. //+-------------------------------------------------------------------------
  1245. //
  1246. // Function: KerbFreeSKeyTimer
  1247. //
  1248. // Synopsis: Free network service key list timer queue
  1249. //
  1250. // Effects:
  1251. //
  1252. // Arguments:
  1253. //
  1254. // Requires:
  1255. //
  1256. // Returns:
  1257. //
  1258. // Notes:
  1259. //
  1260. //
  1261. //--------------------------------------------------------------------------
  1262. VOID
  1263. KerbFreeSKeyTimer(
  1264. VOID
  1265. )
  1266. {
  1267. if (KerbhSKeyTimerQueue)
  1268. {
  1269. RtlDeleteTimerQueue(KerbhSKeyTimerQueue);
  1270. KerbhSKeyTimerQueue = NULL;
  1271. }
  1272. }
  1273. //+-------------------------------------------------------------------------
  1274. //
  1275. // Function: KerbUpdateServerContext
  1276. //
  1277. // Synopsis: Creates a context for the server of an authentication
  1278. // session.
  1279. //
  1280. // Effects: Allocates and links a context.
  1281. //
  1282. // Arguments: Context - Context to update
  1283. // InternalTicket - Ticket used to create this context.
  1284. // SessionKey - Session key from the ticket.
  1285. // LogonId - Logon ID of the context
  1286. // UserSid - User's sid, held onto by context
  1287. // ContextFlags - SSPI Flags for this context
  1288. // ContextAttributes - Internal attributes of context
  1289. // TokenHandle - Handle the token for this context
  1290. // ContextLifetime - Lifetime for the context.
  1291. //
  1292. // Requires:
  1293. //
  1294. // Returns: NTSTATUS code
  1295. //
  1296. // Notes:
  1297. //
  1298. //
  1299. //--------------------------------------------------------------------------
  1300. NTSTATUS
  1301. KerbUpdateServerContext(
  1302. IN PKERB_CONTEXT Context,
  1303. IN PKERB_ENCRYPTED_TICKET InternalTicket,
  1304. IN PKERB_AP_REQUEST ApRequest,
  1305. IN PKERB_ENCRYPTION_KEY SessionKey,
  1306. IN PLUID LogonId,
  1307. IN PSID * UserSid,
  1308. IN ULONG ContextFlags,
  1309. IN ULONG ContextAttributes,
  1310. IN ULONG Nonce,
  1311. IN ULONG ReceiveNonce,
  1312. IN OUT PHANDLE TokenHandle,
  1313. IN PUNICODE_STRING ClientName,
  1314. IN PUNICODE_STRING ClientDomain,
  1315. OUT PTimeStamp ContextLifetime
  1316. )
  1317. {
  1318. NTSTATUS Status = STATUS_SUCCESS;
  1319. KerbWriteLockContexts();
  1320. if (!KERB_SUCCESS(KerbDuplicateKey(
  1321. &Context->SessionKey,
  1322. SessionKey
  1323. )))
  1324. {
  1325. Status = STATUS_INSUFFICIENT_RESOURCES;
  1326. goto Cleanup;
  1327. }
  1328. //
  1329. // If this was not a null session and there is a ticket available,
  1330. // pull interesting information out of the ticket
  1331. //
  1332. if (ARGUMENT_PRESENT(InternalTicket))
  1333. {
  1334. KerbConvertGeneralizedTimeToLargeInt(
  1335. &Context->Lifetime,
  1336. &InternalTicket->endtime,
  1337. 0
  1338. );
  1339. if (InternalTicket->bit_mask & KERB_ENCRYPTED_TICKET_renew_until_present)
  1340. {
  1341. KerbConvertGeneralizedTimeToLargeInt(
  1342. &Context->RenewTime,
  1343. &InternalTicket->KERB_ENCRYPTED_TICKET_renew_until,
  1344. 0
  1345. );
  1346. }
  1347. //
  1348. // Stick the client name in the context
  1349. //
  1350. Context->ClientName = *ClientName;
  1351. RtlInitUnicodeString(
  1352. ClientName,
  1353. NULL
  1354. );
  1355. Context->ClientRealm = *ClientDomain;
  1356. RtlInitUnicodeString(
  1357. ClientDomain,
  1358. NULL
  1359. );
  1360. if (!KERB_SUCCESS(KerbDuplicateKey(
  1361. &Context->TicketKey,
  1362. &InternalTicket->key)))
  1363. {
  1364. Status = STATUS_INSUFFICIENT_RESOURCES;
  1365. goto Cleanup;
  1366. }
  1367. //
  1368. // Copy the principal names from the ticket
  1369. //
  1370. if (!KERB_SUCCESS(KerbConvertPrincipalNameToFullServiceString(
  1371. &Context->ClientPrincipalName,
  1372. &InternalTicket->client_name,
  1373. InternalTicket->client_realm
  1374. )))
  1375. {
  1376. Status = STATUS_INSUFFICIENT_RESOURCES;
  1377. goto Cleanup;
  1378. }
  1379. if (!KERB_SUCCESS(KerbConvertPrincipalNameToFullServiceString(
  1380. &Context->ServerPrincipalName,
  1381. &ApRequest->ticket.server_name,
  1382. ApRequest->ticket.realm
  1383. )))
  1384. {
  1385. Status = STATUS_INSUFFICIENT_RESOURCES;
  1386. goto Cleanup;
  1387. }
  1388. }
  1389. else
  1390. {
  1391. Context->Lifetime = KerbGlobalWillNeverTime;
  1392. Context->RenewTime = KerbGlobalWillNeverTime;
  1393. Context->EncryptionType = KERB_ETYPE_NULL;
  1394. }
  1395. //
  1396. // If we generated a nonce to send to the client, use it. Otherwise use
  1397. // the receive nonce from the AP req.
  1398. //
  1399. if (Nonce != 0)
  1400. {
  1401. Context->Nonce = Nonce;
  1402. }
  1403. else
  1404. {
  1405. Context->Nonce = ReceiveNonce;
  1406. }
  1407. Context->ReceiveNonce = ReceiveNonce;
  1408. Context->LogonId = *LogonId;
  1409. Context->ContextFlags |= ContextFlags;
  1410. Context->TokenHandle = *TokenHandle;
  1411. Context->UserSid = *UserSid;
  1412. Context->ContextAttributes = KERB_CONTEXT_INBOUND;
  1413. Context->ContextAttributes |= ContextAttributes;
  1414. *ContextLifetime = Context->Lifetime;
  1415. //
  1416. // Null the token handle so the caller does not free it
  1417. //
  1418. *TokenHandle = NULL;
  1419. *UserSid = NULL;
  1420. Cleanup:
  1421. KerbUnlockContexts();
  1422. return(Status);
  1423. }
  1424. //+-------------------------------------------------------------------------
  1425. //
  1426. // Function: KerbCreateServerContext
  1427. //
  1428. // Synopsis: Creates a context for the server of an authentication
  1429. // session.
  1430. //
  1431. // Effects: Allocates and links a context.
  1432. //
  1433. // Arguments: LogonSession - Logon session to lock when accessing the credential
  1434. // Credential - Credential to hang this context off of
  1435. // InternalTicket - Ticket used to create this context.
  1436. // SessionKey - Session key from the ticket.
  1437. // LogonId - Logon ID of the context
  1438. // UserSid - User's SID, held on to in context.
  1439. // ContextFlags - SSPI Flags for this context
  1440. // ContextAttributes - Internal attributes of context
  1441. // TokenHandle - Handle the token for this context
  1442. // NewContext - receives referenced context pointer
  1443. // ContextLifetime - Lifetime for the context.
  1444. //
  1445. // Requires:
  1446. //
  1447. // Returns: NTSTATUS code
  1448. //
  1449. // Notes:
  1450. //
  1451. //
  1452. //--------------------------------------------------------------------------
  1453. NTSTATUS
  1454. KerbCreateServerContext(
  1455. IN PKERB_LOGON_SESSION LogonSession,
  1456. IN PKERB_CREDENTIAL Credential,
  1457. IN OPTIONAL PKERB_ENCRYPTED_TICKET InternalTicket,
  1458. IN PKERB_AP_REQUEST ApRequest,
  1459. IN PKERB_ENCRYPTION_KEY SessionKey,
  1460. IN PLUID LogonId,
  1461. IN PSID * UserSid,
  1462. IN ULONG ContextFlags,
  1463. IN ULONG ContextAttributes,
  1464. IN ULONG Nonce,
  1465. IN ULONG ReceiveNonce,
  1466. IN OUT PHANDLE TokenHandle,
  1467. IN PUNICODE_STRING ClientName,
  1468. IN PUNICODE_STRING ClientDomain,
  1469. OUT PKERB_CONTEXT * NewContext,
  1470. OUT PTimeStamp ContextLifetime
  1471. )
  1472. {
  1473. NTSTATUS Status;
  1474. PKERB_CONTEXT Context = NULL;
  1475. Status = KerbAllocateContext( &Context, FALSE );
  1476. if (!NT_SUCCESS(Status))
  1477. {
  1478. goto Cleanup;
  1479. }
  1480. if (!KERB_SUCCESS(KerbDuplicateKey(
  1481. &Context->SessionKey,
  1482. SessionKey
  1483. )))
  1484. {
  1485. Status = STATUS_INSUFFICIENT_RESOURCES;
  1486. goto Cleanup;
  1487. }
  1488. //
  1489. // If this wasn't a null session, stick the info from the ticket into
  1490. // the context.
  1491. //
  1492. if (ARGUMENT_PRESENT(InternalTicket))
  1493. {
  1494. KerbConvertGeneralizedTimeToLargeInt(
  1495. &Context->Lifetime,
  1496. &InternalTicket->endtime,
  1497. 0
  1498. );
  1499. if (InternalTicket->bit_mask & KERB_ENCRYPTED_TICKET_renew_until_present)
  1500. {
  1501. KerbConvertGeneralizedTimeToLargeInt(
  1502. &Context->RenewTime,
  1503. &InternalTicket->KERB_ENCRYPTED_TICKET_renew_until,
  1504. 0
  1505. );
  1506. }
  1507. if (InternalTicket->bit_mask & KERB_ENCRYPTED_TICKET_starttime_present)
  1508. {
  1509. KerbConvertGeneralizedTimeToLargeInt(
  1510. &Context->StartTime,
  1511. &InternalTicket->starttime,
  1512. 0
  1513. );
  1514. }
  1515. else // use current time
  1516. {
  1517. GetSystemTimeAsFileTime((PFILETIME)
  1518. &(Context->StartTime)
  1519. );
  1520. }
  1521. Context->ClientName = *ClientName;
  1522. RtlInitUnicodeString(
  1523. ClientName,
  1524. NULL
  1525. );
  1526. Context->ClientRealm = *ClientDomain;
  1527. RtlInitUnicodeString(
  1528. ClientDomain,
  1529. NULL
  1530. );
  1531. if (!KERB_SUCCESS(KerbDuplicateKey(
  1532. &Context->TicketKey,
  1533. &InternalTicket->key)))
  1534. {
  1535. Status = STATUS_INSUFFICIENT_RESOURCES;
  1536. goto Cleanup;
  1537. }
  1538. //
  1539. // Copy the principal names from the ticket
  1540. //
  1541. if (!KERB_SUCCESS(KerbConvertPrincipalNameToFullServiceString(
  1542. &Context->ClientPrincipalName,
  1543. &InternalTicket->client_name,
  1544. InternalTicket->client_realm
  1545. )))
  1546. {
  1547. Status = STATUS_INSUFFICIENT_RESOURCES;
  1548. goto Cleanup;
  1549. }
  1550. if (!KERB_SUCCESS(KerbConvertPrincipalNameToFullServiceString(
  1551. &Context->ServerPrincipalName,
  1552. &ApRequest->ticket.server_name,
  1553. ApRequest->ticket.realm
  1554. )))
  1555. {
  1556. Status = STATUS_INSUFFICIENT_RESOURCES;
  1557. goto Cleanup;
  1558. }
  1559. }
  1560. else
  1561. {
  1562. Context->Lifetime = KerbGlobalWillNeverTime;
  1563. Context->RenewTime = KerbGlobalWillNeverTime;
  1564. GetSystemTimeAsFileTime((PFILETIME)
  1565. &(Context->StartTime)
  1566. );
  1567. Context->EncryptionType = KERB_ETYPE_NULL;
  1568. }
  1569. //
  1570. // If we generated a nonce to send to the client, use it. Otherwise use
  1571. // the receive nonce from the AP req.
  1572. //
  1573. // if (Nonce != 0)
  1574. // {
  1575. Context->Nonce = Nonce;
  1576. // }
  1577. // else
  1578. // {
  1579. // Context->Nonce = ReceiveNonce;
  1580. // }
  1581. Context->ReceiveNonce = ReceiveNonce;
  1582. Context->CredentialHandle = KerbGetCredentialHandle(Credential);
  1583. Context->LogonId = *LogonId;
  1584. Context->ContextFlags = ContextFlags;
  1585. Context->TokenHandle = *TokenHandle;
  1586. Context->UserSid = *UserSid;
  1587. //
  1588. // Null the token handle so the caller does not free it
  1589. //
  1590. *TokenHandle = NULL;
  1591. *UserSid = NULL;
  1592. Context->ContextAttributes = KERB_CONTEXT_INBOUND;
  1593. Context->ContextAttributes |= ContextAttributes;
  1594. KerbReadLockLogonSessions(LogonSession);
  1595. if (Credential->SuppliedCredentials != NULL)
  1596. {
  1597. Context->ContextAttributes |= KERB_CONTEXT_USED_SUPPLIED_CREDS;
  1598. }
  1599. KerbUnlockLogonSessions(LogonSession);
  1600. *ContextLifetime = Context->Lifetime;
  1601. Status = KerbInsertContext(
  1602. Context
  1603. );
  1604. if (!NT_SUCCESS(Status))
  1605. {
  1606. D_DebugLog((DEB_ERROR,"Failed to insert context: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1607. goto Cleanup;
  1608. }
  1609. *NewContext = Context;
  1610. Cleanup:
  1611. if (!NT_SUCCESS(Status))
  1612. {
  1613. if (Context != NULL)
  1614. {
  1615. KerbFreeContext(Context);
  1616. }
  1617. }
  1618. return(Status);
  1619. }
  1620. //+-------------------------------------------------------------------------
  1621. //
  1622. // Function: KerbMapContext
  1623. //
  1624. // Synopsis: Maps a context to the caller's address space
  1625. //
  1626. // Effects:
  1627. //
  1628. // Arguments: Context - The context to map
  1629. // CopyToken - If TRUE, duplicate token to client
  1630. // MappedContext - Set to TRUE on success
  1631. // ContextData - Receives a buffer in the LSA's address space
  1632. // with the mapped context.
  1633. //
  1634. // Requires:
  1635. //
  1636. // Returns:
  1637. //
  1638. // Notes:
  1639. //
  1640. //
  1641. //--------------------------------------------------------------------------
  1642. NTSTATUS
  1643. KerbMapContext(
  1644. IN PKERB_CONTEXT Context,
  1645. OUT PBOOLEAN MappedContext,
  1646. OUT PSecBuffer ContextData
  1647. )
  1648. {
  1649. NTSTATUS Status ;
  1650. PKERB_PACKED_CONTEXT PackedContext = NULL ;
  1651. ULONG ContextSize ;
  1652. PUCHAR CopyTo ;
  1653. ULONG CurrentOffset ;
  1654. KerbWriteLockContexts();
  1655. //
  1656. // If we already mapped the context don't try to do it again. We may
  1657. // be able to map user-mode contexts multiple times, though.
  1658. //
  1659. if (KerberosState == KerberosLsaMode)
  1660. {
  1661. if ((Context->ContextAttributes & KERB_CONTEXT_MAPPED) != 0)
  1662. {
  1663. KerbUnlockContexts();
  1664. Status = STATUS_SUCCESS;
  1665. goto Cleanup;
  1666. }
  1667. Context->ContextAttributes |= KERB_CONTEXT_MAPPED;
  1668. }
  1669. ContextSize = sizeof(KERB_PACKED_CONTEXT) +
  1670. Context->ClientName.Length +
  1671. Context->ClientRealm.Length +
  1672. Context->SessionKey.keyvalue.length +
  1673. Context->cbMarshalledTargetInfo ;
  1674. PackedContext = (PKERB_PACKED_CONTEXT) KerbAllocate( ContextSize );
  1675. if (PackedContext == NULL)
  1676. {
  1677. Context->ContextAttributes &= ~(KERB_CONTEXT_MAPPED);
  1678. KerbUnlockContexts();
  1679. Status = STATUS_INSUFFICIENT_RESOURCES;
  1680. goto Cleanup;
  1681. }
  1682. CurrentOffset = sizeof( KERB_PACKED_CONTEXT );
  1683. CopyTo = (PUCHAR) ( PackedContext + 1 );
  1684. PackedContext->ContextType = KERB_PACKED_CONTEXT_MAP ;
  1685. PackedContext->Pad = 0 ;
  1686. PackedContext->Lifetime = Context->Lifetime ;
  1687. PackedContext->RenewTime = Context->RenewTime ;
  1688. PackedContext->StartTime = Context->StartTime;
  1689. PackedContext->ClientName.Length = Context->ClientName.Length ;
  1690. PackedContext->ClientName.MaximumLength = Context->ClientName.Length ;
  1691. PackedContext->ClientName.Buffer = CurrentOffset ;
  1692. RtlCopyMemory(
  1693. CopyTo,
  1694. Context->ClientName.Buffer,
  1695. Context->ClientName.Length );
  1696. CurrentOffset += Context->ClientName.Length ;
  1697. CopyTo += Context->ClientName.Length ;
  1698. PackedContext->ClientRealm.Length = Context->ClientRealm.Length ;
  1699. PackedContext->ClientRealm.MaximumLength = Context->ClientRealm.Length ;
  1700. PackedContext->ClientRealm.Buffer = CurrentOffset ;
  1701. RtlCopyMemory(
  1702. CopyTo,
  1703. Context->ClientRealm.Buffer,
  1704. Context->ClientRealm.Length );
  1705. CurrentOffset += Context->ClientRealm.Length ;
  1706. CopyTo += Context->ClientRealm.Length ;
  1707. PackedContext->LsaContextHandle = (ULONG) Context->LsaContextHandle ;
  1708. PackedContext->LogonId = Context->LogonId ;
  1709. PackedContext->CredentialHandle = 0 ;
  1710. PackedContext->SessionKeyType = Context->SessionKey.keytype ;
  1711. PackedContext->SessionKeyOffset = CurrentOffset ;
  1712. PackedContext->SessionKeyLength = Context->SessionKey.keyvalue.length ;
  1713. RtlCopyMemory(
  1714. CopyTo,
  1715. Context->SessionKey.keyvalue.value,
  1716. Context->SessionKey.keyvalue.length );
  1717. CurrentOffset += PackedContext->SessionKeyLength ;
  1718. CopyTo += PackedContext->SessionKeyLength;
  1719. if( Context->pbMarshalledTargetInfo )
  1720. {
  1721. PackedContext->MarshalledTargetInfo = CurrentOffset;
  1722. PackedContext->MarshalledTargetInfoLength = Context->cbMarshalledTargetInfo;
  1723. RtlCopyMemory(
  1724. CopyTo,
  1725. Context->pbMarshalledTargetInfo,
  1726. Context->cbMarshalledTargetInfo );
  1727. CurrentOffset += PackedContext->MarshalledTargetInfoLength;
  1728. CopyTo += PackedContext->MarshalledTargetInfoLength;
  1729. }
  1730. PackedContext->Nonce = Context->Nonce ;
  1731. PackedContext->ReceiveNonce = Context->ReceiveNonce ;
  1732. PackedContext->ContextFlags = Context->ContextFlags ;
  1733. PackedContext->ContextAttributes = Context->ContextAttributes ;
  1734. PackedContext->EncryptionType = Context->EncryptionType ;
  1735. KerbUnlockContexts();
  1736. //
  1737. // If there is a token in the context, copy it also
  1738. //
  1739. #ifndef WIN32_CHICAGO
  1740. if ((KerberosState == KerberosLsaMode) && (Context->TokenHandle != NULL))
  1741. {
  1742. HANDLE duplicateHandle;
  1743. Status = LsaFunctions->DuplicateHandle(
  1744. Context->TokenHandle,
  1745. &duplicateHandle
  1746. );
  1747. if (!NT_SUCCESS(Status))
  1748. {
  1749. D_DebugLog((DEB_ERROR,"Failed to duplicate handle: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1750. goto Cleanup;
  1751. }
  1752. PackedContext->TokenHandle = HandleToUlong(duplicateHandle);
  1753. NtClose(Context->TokenHandle);
  1754. Context->TokenHandle = NULL;
  1755. }
  1756. else
  1757. {
  1758. PackedContext->TokenHandle = NULL;
  1759. }
  1760. #endif // WIN32_CHICAGO
  1761. ContextData->pvBuffer = PackedContext;
  1762. ContextData->cbBuffer = ContextSize;
  1763. *MappedContext = TRUE;
  1764. Status = STATUS_SUCCESS;
  1765. Cleanup:
  1766. if (!NT_SUCCESS(Status))
  1767. {
  1768. if (PackedContext != NULL)
  1769. {
  1770. KerbFree(PackedContext);
  1771. }
  1772. }
  1773. return(Status);
  1774. }
  1775. #if 0
  1776. NTSTATUS
  1777. KerbMapContext(
  1778. IN PKERB_CONTEXT Context,
  1779. OUT PBOOLEAN MappedContext,
  1780. OUT PSecBuffer ContextData
  1781. )
  1782. {
  1783. NTSTATUS Status;
  1784. PKERB_CONTEXT PackedContext = NULL;
  1785. ULONG ContextSize;
  1786. KerbWriteLockContexts();
  1787. //
  1788. // If we already mapped the context don't try to do it again. We may
  1789. // be able to map user-mode contexts multiple times, though.
  1790. //
  1791. if (KerberosState == KerberosLsaMode)
  1792. {
  1793. if ((Context->ContextAttributes & KERB_CONTEXT_MAPPED) != 0)
  1794. {
  1795. KerbUnlockContexts();
  1796. Status = STATUS_SUCCESS;
  1797. goto Cleanup;
  1798. }
  1799. Context->ContextAttributes |= KERB_CONTEXT_MAPPED;
  1800. }
  1801. ContextSize = sizeof(KERB_CONTEXT) +
  1802. Context->ClientName.Length +
  1803. Context->ClientRealm.Length +
  1804. Context->SessionKey.keyvalue.length;
  1805. PackedContext = (PKERB_CONTEXT) KerbAllocate(ContextSize);
  1806. if (PackedContext == NULL)
  1807. {
  1808. KerbUnlockContexts();
  1809. Status = STATUS_INSUFFICIENT_RESOURCES;
  1810. goto Cleanup;
  1811. }
  1812. RtlCopyMemory(
  1813. PackedContext,
  1814. Context,
  1815. sizeof(KERB_CONTEXT)
  1816. );
  1817. PackedContext->ClientName.Buffer = (LPWSTR) sizeof(KERB_CONTEXT);
  1818. RtlCopyMemory(
  1819. PackedContext+1,
  1820. Context->ClientName.Buffer,
  1821. Context->ClientName.Length
  1822. );
  1823. PackedContext->ClientName.MaximumLength = PackedContext->ClientName.Length;
  1824. PackedContext->ClientRealm.Buffer = (LPWSTR) (sizeof(KERB_CONTEXT) + PackedContext->ClientName.Length);
  1825. RtlCopyMemory(
  1826. (PUCHAR) PackedContext + (UINT_PTR) PackedContext->ClientRealm.Buffer,
  1827. Context->ClientRealm.Buffer,
  1828. Context->ClientRealm.Length
  1829. );
  1830. PackedContext->ClientRealm.MaximumLength = PackedContext->ClientRealm.Length;
  1831. RtlZeroMemory(
  1832. &PackedContext->TicketKey,
  1833. sizeof(KERB_ENCRYPTION_KEY)
  1834. );
  1835. RtlZeroMemory(
  1836. &PackedContext->ClientPrincipalName,
  1837. sizeof(UNICODE_STRING)
  1838. );
  1839. RtlZeroMemory(
  1840. &PackedContext->ServerPrincipalName,
  1841. sizeof(UNICODE_STRING)
  1842. );
  1843. //
  1844. // Pack in the session key
  1845. //
  1846. PackedContext->SessionKey.keyvalue.value = (PUCHAR) PackedContext->ClientRealm.Buffer + PackedContext->ClientRealm.MaximumLength;
  1847. RtlCopyMemory(
  1848. PackedContext->SessionKey.keyvalue.value + (UINT_PTR) PackedContext,
  1849. Context->SessionKey.keyvalue.value,
  1850. Context->SessionKey.keyvalue.length
  1851. );
  1852. KerbUnlockContexts();
  1853. //
  1854. // If there is a token in the context, copy it also
  1855. //
  1856. #ifndef WIN32_CHICAGO
  1857. if ((KerberosState == KerberosLsaMode) && (Context->TokenHandle != NULL))
  1858. {
  1859. Status = LsaFunctions->DuplicateHandle(
  1860. Context->TokenHandle,
  1861. &PackedContext->TokenHandle
  1862. );
  1863. if (!NT_SUCCESS(Status))
  1864. {
  1865. D_DebugLog((DEB_ERROR,"Failed to duplicate handle: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1866. goto Cleanup;
  1867. }
  1868. NtClose(Context->TokenHandle);
  1869. Context->TokenHandle = NULL;
  1870. }
  1871. else
  1872. {
  1873. PackedContext->TokenHandle = NULL;
  1874. }
  1875. #endif // WIN32_CHICAGO
  1876. ContextData->pvBuffer = PackedContext;
  1877. ContextData->cbBuffer = ContextSize;
  1878. *MappedContext = TRUE;
  1879. Status = STATUS_SUCCESS;
  1880. Cleanup:
  1881. if (!NT_SUCCESS(Status))
  1882. {
  1883. if (PackedContext != NULL)
  1884. {
  1885. KerbFree(PackedContext);
  1886. }
  1887. }
  1888. return(Status);
  1889. }
  1890. #endif
  1891. #ifndef WIN32_CHICAGO
  1892. //+-------------------------------------------------------------------------
  1893. //
  1894. // Function: KerbGetTokenUser
  1895. //
  1896. // Synopsis: Returns user field from a token
  1897. //
  1898. // Effects: allocates memory with LocalAlloc
  1899. //
  1900. // Arguments:
  1901. //
  1902. // Requires:
  1903. //
  1904. // Returns:
  1905. //
  1906. // Notes:
  1907. //
  1908. //
  1909. //--------------------------------------------------------------------------
  1910. NTSTATUS
  1911. KerbGetTokenUser(
  1912. HANDLE Token,
  1913. PTOKEN_USER * pTokenUser
  1914. )
  1915. {
  1916. PTOKEN_USER LocalTokenUser = NULL;
  1917. NTSTATUS Status;
  1918. ULONG TokenUserSize = 0;
  1919. //
  1920. // Query the token user. First pass in NULL to get back the
  1921. // required size.
  1922. //
  1923. Status = NtQueryInformationToken(
  1924. Token,
  1925. TokenUser,
  1926. NULL,
  1927. 0,
  1928. &TokenUserSize
  1929. );
  1930. if (Status != STATUS_BUFFER_TOO_SMALL)
  1931. {
  1932. DsysAssert(Status != STATUS_SUCCESS);
  1933. return(Status);
  1934. }
  1935. //
  1936. // Now allocate the required ammount of memory and try again.
  1937. //
  1938. LocalTokenUser = (PTOKEN_USER) LocalAlloc(0,TokenUserSize);
  1939. if (LocalTokenUser == NULL)
  1940. {
  1941. return(STATUS_INSUFFICIENT_RESOURCES);
  1942. }
  1943. Status = NtQueryInformationToken(
  1944. Token,
  1945. TokenUser,
  1946. LocalTokenUser,
  1947. TokenUserSize,
  1948. &TokenUserSize
  1949. );
  1950. if (NT_SUCCESS(Status))
  1951. {
  1952. *pTokenUser = LocalTokenUser;
  1953. }
  1954. else
  1955. {
  1956. LocalFree(LocalTokenUser);
  1957. }
  1958. return(Status);
  1959. }
  1960. #endif // WIN32_CHICAGO
  1961. #ifndef WIN32_CHICAGO
  1962. //+-------------------------------------------------------------------------
  1963. //
  1964. // Function: KerbCreateTokenDacl
  1965. //
  1966. // Synopsis: Modifies DACL on the context token to grant access to the
  1967. // the caller.
  1968. //
  1969. // Effects:
  1970. //
  1971. // Arguments: Token - Token to modify
  1972. //
  1973. // Requires:
  1974. //
  1975. // Returns:
  1976. //
  1977. // Notes:
  1978. //
  1979. //
  1980. //--------------------------------------------------------------------------
  1981. NTSTATUS
  1982. KerbCreateTokenDacl(
  1983. HANDLE Token
  1984. )
  1985. {
  1986. NTSTATUS Status;
  1987. PTOKEN_USER ProcessTokenUser = NULL;
  1988. PTOKEN_USER ThreadTokenUser = NULL;
  1989. PTOKEN_USER ImpersonationTokenUser = NULL;
  1990. HANDLE ProcessToken = NULL;
  1991. HANDLE ImpersonationToken = NULL;
  1992. BOOL fInsertImpersonatingUser = FALSE;
  1993. ULONG AclLength;
  1994. PACL NewDacl = NULL;
  1995. SECURITY_DESCRIPTOR SecurityDescriptor;
  1996. //
  1997. // it's possible that the current thread is impersonating a user.
  1998. // if that's the case, get it's token user, and revert to insure we
  1999. // can open the process token.
  2000. //
  2001. Status = NtOpenThreadToken(
  2002. NtCurrentThread(),
  2003. TOKEN_QUERY | TOKEN_IMPERSONATE,
  2004. TRUE,
  2005. &ImpersonationToken
  2006. );
  2007. if( NT_SUCCESS(Status) )
  2008. {
  2009. //
  2010. // stop impersonating.
  2011. //
  2012. RevertToSelf();
  2013. //
  2014. // get the token user for the impersonating user.
  2015. //
  2016. Status = KerbGetTokenUser(
  2017. ImpersonationToken,
  2018. &ImpersonationTokenUser
  2019. );
  2020. if (!NT_SUCCESS(Status))
  2021. {
  2022. goto Cleanup;
  2023. }
  2024. }
  2025. //
  2026. // Open the process token to find out the user sid
  2027. //
  2028. Status = NtOpenProcessToken(
  2029. NtCurrentProcess(),
  2030. TOKEN_QUERY,
  2031. &ProcessToken
  2032. );
  2033. if (!NT_SUCCESS(Status))
  2034. {
  2035. goto Cleanup;
  2036. }
  2037. Status = KerbGetTokenUser(
  2038. ProcessToken,
  2039. &ProcessTokenUser
  2040. );
  2041. if (!NT_SUCCESS(Status))
  2042. {
  2043. goto Cleanup;
  2044. }
  2045. //
  2046. // Now get the token user for the thread.
  2047. //
  2048. Status = KerbGetTokenUser(
  2049. Token,
  2050. &ThreadTokenUser
  2051. );
  2052. if (!NT_SUCCESS(Status))
  2053. {
  2054. goto Cleanup;
  2055. }
  2056. AclLength = 4 * sizeof( ACCESS_ALLOWED_ACE ) - 4 * sizeof( ULONG ) +
  2057. RtlLengthSid( ProcessTokenUser->User.Sid ) +
  2058. RtlLengthSid( ThreadTokenUser->User.Sid ) +
  2059. RtlLengthSid( KerbGlobalLocalSystemSid ) +
  2060. RtlLengthSid( KerbGlobalAliasAdminsSid ) +
  2061. sizeof( ACL );
  2062. //
  2063. // determine if we need to add impersonation token sid onto the token Dacl.
  2064. //
  2065. if( ImpersonationTokenUser &&
  2066. !RtlEqualSid( ImpersonationTokenUser->User.Sid, ProcessTokenUser->User.Sid ) &&
  2067. !RtlEqualSid( ImpersonationTokenUser->User.Sid, ThreadTokenUser->User.Sid )
  2068. )
  2069. {
  2070. AclLength += (sizeof(ACCESS_ALLOWED_ACE) - sizeof( ULONG )) +
  2071. RtlLengthSid( ImpersonationTokenUser->User.Sid );
  2072. fInsertImpersonatingUser = TRUE;
  2073. }
  2074. NewDacl = (PACL) LocalAlloc(0, AclLength );
  2075. if (NewDacl == NULL) {
  2076. Status = STATUS_INSUFFICIENT_RESOURCES;
  2077. goto Cleanup;
  2078. }
  2079. Status = RtlCreateAcl( NewDacl, AclLength, ACL_REVISION2 );
  2080. DsysAssert(NT_SUCCESS( Status ));
  2081. Status = RtlAddAccessAllowedAce (
  2082. NewDacl,
  2083. ACL_REVISION2,
  2084. TOKEN_ALL_ACCESS,
  2085. ProcessTokenUser->User.Sid
  2086. );
  2087. DsysAssert( NT_SUCCESS( Status ));
  2088. Status = RtlAddAccessAllowedAce (
  2089. NewDacl,
  2090. ACL_REVISION2,
  2091. TOKEN_ALL_ACCESS,
  2092. ThreadTokenUser->User.Sid
  2093. );
  2094. DsysAssert( NT_SUCCESS( Status ));
  2095. if( fInsertImpersonatingUser )
  2096. {
  2097. Status = RtlAddAccessAllowedAce (
  2098. NewDacl,
  2099. ACL_REVISION2,
  2100. TOKEN_ALL_ACCESS,
  2101. ImpersonationTokenUser->User.Sid
  2102. );
  2103. DsysAssert( NT_SUCCESS( Status ));
  2104. }
  2105. Status = RtlAddAccessAllowedAce (
  2106. NewDacl,
  2107. ACL_REVISION2,
  2108. TOKEN_ALL_ACCESS,
  2109. KerbGlobalAliasAdminsSid
  2110. );
  2111. DsysAssert( NT_SUCCESS( Status ));
  2112. Status = RtlAddAccessAllowedAce (
  2113. NewDacl,
  2114. ACL_REVISION2,
  2115. TOKEN_ALL_ACCESS,
  2116. KerbGlobalLocalSystemSid
  2117. );
  2118. DsysAssert( NT_SUCCESS( Status ));
  2119. Status = RtlCreateSecurityDescriptor (
  2120. &SecurityDescriptor,
  2121. SECURITY_DESCRIPTOR_REVISION
  2122. );
  2123. DsysAssert( NT_SUCCESS( Status ));
  2124. Status = RtlSetDaclSecurityDescriptor(
  2125. &SecurityDescriptor,
  2126. TRUE,
  2127. NewDacl,
  2128. FALSE
  2129. );
  2130. DsysAssert( NT_SUCCESS( Status ));
  2131. Status = NtSetSecurityObject(
  2132. Token,
  2133. DACL_SECURITY_INFORMATION,
  2134. &SecurityDescriptor
  2135. );
  2136. DsysAssert( NT_SUCCESS( Status ));
  2137. Cleanup:
  2138. if( ImpersonationToken != NULL ) {
  2139. //
  2140. // put the thread token back if we were impersonating.
  2141. //
  2142. SetThreadToken( NULL, ImpersonationToken );
  2143. NtClose( ImpersonationToken );
  2144. }
  2145. if (ThreadTokenUser != NULL) {
  2146. LocalFree( ThreadTokenUser );
  2147. }
  2148. if (ProcessTokenUser != NULL) {
  2149. LocalFree( ProcessTokenUser );
  2150. }
  2151. if (ImpersonationTokenUser != NULL) {
  2152. LocalFree( ImpersonationTokenUser );
  2153. }
  2154. if (NewDacl != NULL) {
  2155. LocalFree( NewDacl );
  2156. }
  2157. if (ProcessToken != NULL)
  2158. {
  2159. NtClose(ProcessToken);
  2160. }
  2161. return( Status );
  2162. }
  2163. #endif // WIN32_CHICAGO
  2164. //+-------------------------------------------------------------------------
  2165. //
  2166. // Function: KerbCreateUserModeContext
  2167. //
  2168. // Synopsis: Creates a user-mode context to support impersonation and
  2169. // message integrity and privacy
  2170. //
  2171. // Effects:
  2172. //
  2173. // Arguments:
  2174. //
  2175. // Requires:
  2176. //
  2177. // Returns:
  2178. //
  2179. // Notes:
  2180. //
  2181. //
  2182. //--------------------------------------------------------------------------
  2183. NTSTATUS
  2184. KerbCreateUserModeContext(
  2185. IN LSA_SEC_HANDLE ContextHandle,
  2186. IN PSecBuffer MarshalledContext,
  2187. OUT PKERB_CONTEXT * NewContext
  2188. )
  2189. {
  2190. NTSTATUS Status;
  2191. PKERB_CONTEXT Context = NULL;
  2192. PKERB_PACKED_CONTEXT PackedContext ;
  2193. UNICODE_STRING String ;
  2194. KERB_ENCRYPTION_KEY Key ;
  2195. if (MarshalledContext->cbBuffer < sizeof(KERB_PACKED_CONTEXT))
  2196. {
  2197. D_DebugLog((DEB_ERROR,"Invalid buffer size for marshalled context: was 0x%x, needed 0x%x. %ws, line %d\n",
  2198. MarshalledContext->cbBuffer, sizeof(KERB_CONTEXT), THIS_FILE, __LINE__));
  2199. return(STATUS_INVALID_PARAMETER);
  2200. }
  2201. PackedContext = (PKERB_PACKED_CONTEXT) MarshalledContext->pvBuffer;
  2202. Status = KerbAllocateContext( &Context, TRUE );
  2203. if (!NT_SUCCESS(Status))
  2204. {
  2205. goto Cleanup;
  2206. }
  2207. Context->Lifetime = PackedContext->Lifetime ;
  2208. Context->RenewTime = PackedContext->RenewTime ;
  2209. Context->StartTime = PackedContext->StartTime;
  2210. String.Length = PackedContext->ClientName.Length ;
  2211. String.MaximumLength = PackedContext->ClientName.MaximumLength ;
  2212. String.Buffer = (PWSTR)((PUCHAR) PackedContext + PackedContext->ClientName.Buffer );
  2213. Status = KerbDuplicateString(
  2214. &Context->ClientName,
  2215. &String );
  2216. if ( !NT_SUCCESS( Status ) )
  2217. {
  2218. goto Cleanup ;
  2219. }
  2220. String.Length = PackedContext->ClientRealm.Length ;
  2221. String.MaximumLength = PackedContext->ClientRealm.MaximumLength ;
  2222. String.Buffer = (PWSTR)((PUCHAR) PackedContext + PackedContext->ClientRealm.Buffer );
  2223. Status = KerbDuplicateString(
  2224. &Context->ClientRealm,
  2225. &String );
  2226. if ( !NT_SUCCESS( Status ) )
  2227. {
  2228. goto Cleanup ;
  2229. }
  2230. Context->LogonId = PackedContext->LogonId ;
  2231. Context->TokenHandle = (HANDLE) ULongToPtr(PackedContext->TokenHandle);
  2232. Context->CredentialHandle = NULL ;
  2233. Context->Nonce = PackedContext->Nonce ;
  2234. Context->ReceiveNonce = PackedContext->ReceiveNonce ;
  2235. Context->ContextFlags = PackedContext->ContextFlags ;
  2236. Context->ContextAttributes = PackedContext->ContextAttributes ;
  2237. Context->EncryptionType = PackedContext->EncryptionType ;
  2238. Key.keytype = PackedContext->SessionKeyType ;
  2239. Key.keyvalue.value = (PUCHAR) ((PUCHAR) PackedContext + PackedContext->SessionKeyOffset );
  2240. Key.keyvalue.length = PackedContext->SessionKeyLength ;
  2241. if (!KERB_SUCCESS(KerbDuplicateKey(
  2242. &Context->SessionKey,
  2243. &Key)))
  2244. {
  2245. Status = STATUS_INSUFFICIENT_RESOURCES;
  2246. goto Cleanup;
  2247. }
  2248. //
  2249. // Null out string buffers that aren't meant to be copied.
  2250. //
  2251. Context->ClientPrincipalName.Buffer = NULL;
  2252. Context->ServerPrincipalName.Buffer = NULL;
  2253. Context->TicketKey.keyvalue.value = NULL;
  2254. Context->UserSid = NULL;
  2255. Context->TicketCacheEntry = NULL;
  2256. //
  2257. // Modify the DACL on the token to grant access to the caller
  2258. //
  2259. #ifndef WIN32_CHICAGO
  2260. if (Context->TokenHandle != NULL)
  2261. {
  2262. Status = KerbCreateTokenDacl(
  2263. Context->TokenHandle
  2264. );
  2265. if (!NT_SUCCESS(Status))
  2266. {
  2267. goto Cleanup;
  2268. }
  2269. }
  2270. #endif // WIN32_CHICAGO
  2271. //
  2272. // We didn't copy the ticket here, so don't store the entry
  2273. //
  2274. Context->TicketCacheEntry = NULL;
  2275. KerbInitializeListEntry(
  2276. &Context->ListEntry
  2277. );
  2278. if( ContextHandle != 0 )
  2279. {
  2280. Context->LsaContextHandle = ContextHandle;
  2281. } else {
  2282. Context->LsaContextHandle = (ULONG_PTR)Context;
  2283. }
  2284. Status = KerbInsertContext(
  2285. Context
  2286. );
  2287. if (!NT_SUCCESS(Status))
  2288. {
  2289. D_DebugLog((DEB_ERROR,"Failed to insert context: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2290. goto Cleanup;
  2291. }
  2292. *NewContext = Context;
  2293. Cleanup:
  2294. if (!NT_SUCCESS(Status))
  2295. {
  2296. if (Context != NULL)
  2297. {
  2298. KerbFreeContext(Context);
  2299. }
  2300. }
  2301. return(Status);
  2302. }
  2303. #if 0
  2304. NTSTATUS
  2305. KerbCreateUserModeContext(
  2306. IN LSA_SEC_HANDLE ContextHandle,
  2307. IN PSecBuffer MarshalledContext,
  2308. OUT PKERB_CONTEXT * NewContext
  2309. )
  2310. {
  2311. NTSTATUS Status;
  2312. PKERB_CONTEXT Context = NULL;
  2313. PKERB_CONTEXT LsaContext;
  2314. if (MarshalledContext->cbBuffer < sizeof(KERB_CONTEXT))
  2315. {
  2316. D_DebugLog((DEB_ERROR,"Invalid buffer size for marshalled context: was 0x%x, needed 0x%x. %ws, line %d\n",
  2317. MarshalledContext->cbBuffer, sizeof(KERB_CONTEXT), THIS_FILE, __LINE__));
  2318. return(STATUS_INVALID_PARAMETER);
  2319. }
  2320. LsaContext = (PKERB_CONTEXT) MarshalledContext->pvBuffer;
  2321. //
  2322. // Normalize the client name.
  2323. //
  2324. LsaContext->ClientName.Buffer = (LPWSTR) ((PUCHAR) LsaContext->ClientName.Buffer + (UINT_PTR) LsaContext);
  2325. LsaContext->ClientRealm.Buffer = (LPWSTR) ((PUCHAR) LsaContext->ClientRealm.Buffer + (UINT_PTR) LsaContext);
  2326. LsaContext->SessionKey.keyvalue.value = (PUCHAR) LsaContext->SessionKey.keyvalue.value + (UINT_PTR) LsaContext;
  2327. Status = KerbAllocateContext( &Context, TRUE );
  2328. if (!NT_SUCCESS(Status))
  2329. {
  2330. goto Cleanup;
  2331. }
  2332. *Context = *LsaContext;
  2333. //
  2334. // Null out string buffers that aren't meant to be copied.
  2335. //
  2336. Context->ClientName.Buffer = NULL;
  2337. Context->ClientRealm.Buffer = NULL;
  2338. Context->SessionKey.keyvalue.value = NULL;
  2339. Context->UserSid = NULL;
  2340. Context->TicketCacheEntry = NULL;
  2341. //
  2342. // Modify the DACL on the token to grant access to the caller
  2343. //
  2344. #ifndef WIN32_CHICAGO
  2345. if (Context->TokenHandle != NULL)
  2346. {
  2347. Status = KerbCreateTokenDacl(
  2348. Context->TokenHandle
  2349. );
  2350. if (!NT_SUCCESS(Status))
  2351. {
  2352. goto Cleanup;
  2353. }
  2354. }
  2355. #endif // WIN32_CHICAGO
  2356. //
  2357. // We didn't copy the ticket here, so don't store the entry
  2358. //
  2359. Context->TicketCacheEntry = NULL;
  2360. KerbInitializeListEntry(
  2361. &Context->ListEntry
  2362. );
  2363. Context->LsaContextHandle = ContextHandle;
  2364. Status = KerbDuplicateString(
  2365. &Context->ClientName,
  2366. &LsaContext->ClientName
  2367. );
  2368. if (!NT_SUCCESS(Status))
  2369. {
  2370. goto Cleanup;
  2371. }
  2372. Status = KerbDuplicateString(
  2373. &Context->ClientRealm,
  2374. &LsaContext->ClientRealm
  2375. );
  2376. if (!NT_SUCCESS(Status))
  2377. {
  2378. goto Cleanup;
  2379. }
  2380. if (!KERB_SUCCESS(KerbDuplicateKey(
  2381. &Context->SessionKey,
  2382. &LsaContext->SessionKey)))
  2383. {
  2384. Status = STATUS_INSUFFICIENT_RESOURCES;
  2385. goto Cleanup;
  2386. }
  2387. Status = KerbInsertContext(
  2388. Context
  2389. );
  2390. if (!NT_SUCCESS(Status))
  2391. {
  2392. D_DebugLog((DEB_ERROR,"Failed to insert context: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2393. goto Cleanup;
  2394. }
  2395. *NewContext = Context;
  2396. Cleanup:
  2397. if (!NT_SUCCESS(Status))
  2398. {
  2399. if (Context != NULL)
  2400. {
  2401. KerbFreeContext(Context);
  2402. }
  2403. }
  2404. return(Status);
  2405. }
  2406. #endif
  2407. //+-------------------------------------------------------------------------
  2408. //
  2409. // Function: KerbUpdateClientContext
  2410. //
  2411. // Synopsis: updates context with latest info
  2412. //
  2413. // Effects:
  2414. //
  2415. // Arguments:
  2416. //
  2417. // Requires:
  2418. //
  2419. // Returns:
  2420. //
  2421. // Notes:
  2422. //
  2423. //
  2424. //--------------------------------------------------------------------------
  2425. NTSTATUS
  2426. KerbUpdateClientContext(
  2427. IN PKERB_CONTEXT Context,
  2428. IN OPTIONAL PKERB_TICKET_CACHE_ENTRY TicketCacheEntry,
  2429. IN ULONG Nonce,
  2430. IN ULONG ReceiveNonce,
  2431. IN ULONG ContextFlags,
  2432. IN ULONG ContextAttributes,
  2433. IN OPTIONAL PKERB_ENCRYPTION_KEY SubSessionKey,
  2434. OUT PTimeStamp ContextLifetime
  2435. )
  2436. {
  2437. NTSTATUS Status = STATUS_SUCCESS;
  2438. KerbWriteLockContexts();
  2439. if (ARGUMENT_PRESENT(TicketCacheEntry))
  2440. {
  2441. KerbReadLockTicketCache();
  2442. //
  2443. // Duplicate the session key into the context
  2444. //
  2445. KerbFreeKey(
  2446. &Context->SessionKey
  2447. );
  2448. if (ARGUMENT_PRESENT(SubSessionKey) && (SubSessionKey->keyvalue.value != NULL))
  2449. {
  2450. if (!KERB_SUCCESS(KerbDuplicateKey(
  2451. &Context->SessionKey,
  2452. SubSessionKey
  2453. )))
  2454. {
  2455. KerbUnlockTicketCache();
  2456. Status = STATUS_INSUFFICIENT_RESOURCES;
  2457. goto Cleanup;
  2458. }
  2459. }
  2460. else
  2461. {
  2462. if (!KERB_SUCCESS(KerbDuplicateKey(
  2463. &Context->SessionKey,
  2464. &TicketCacheEntry->SessionKey
  2465. )))
  2466. {
  2467. KerbUnlockTicketCache();
  2468. Status = STATUS_INSUFFICIENT_RESOURCES;
  2469. goto Cleanup;
  2470. }
  2471. }
  2472. KerbFreeKey(
  2473. &Context->TicketKey
  2474. );
  2475. if (!KERB_SUCCESS(KerbDuplicateKey(
  2476. &Context->TicketKey,
  2477. &TicketCacheEntry->SessionKey
  2478. )))
  2479. {
  2480. KerbUnlockTicketCache();
  2481. Status = STATUS_INSUFFICIENT_RESOURCES;
  2482. goto Cleanup;
  2483. }
  2484. Context->Lifetime = TicketCacheEntry->EndTime;
  2485. Context->RenewTime = TicketCacheEntry->RenewUntil;
  2486. Context->EncryptionType = TicketCacheEntry->Ticket.encrypted_part.encryption_type;
  2487. KerbUnlockTicketCache();
  2488. }
  2489. else
  2490. {
  2491. Context->Lifetime = KerbGlobalWillNeverTime;
  2492. Context->RenewTime = KerbGlobalWillNeverTime;
  2493. Context->EncryptionType = KERB_ETYPE_NULL;
  2494. }
  2495. Context->Nonce = Nonce;
  2496. //
  2497. // If the server sent us a nonce for receiving data, use it. Otherwise use
  2498. // the nonce we generated.
  2499. //
  2500. // if (ReceiveNonce != 0)
  2501. // {
  2502. Context->ReceiveNonce = ReceiveNonce;
  2503. // }
  2504. // else
  2505. // {
  2506. // Context->ReceiveNonce = Nonce;
  2507. // }
  2508. //
  2509. // delegation flags are not additive, turn it off before updating it
  2510. //
  2511. Context->ContextFlags &= ~(ISC_RET_DELEGATE_IF_SAFE | ISC_RET_DELEGATE);
  2512. Context->ContextFlags |= ContextFlags;
  2513. Context->ContextAttributes |= KERB_CONTEXT_OUTBOUND | ContextAttributes;
  2514. *ContextLifetime = Context->Lifetime;
  2515. Cleanup:
  2516. KerbUnlockContexts();
  2517. return(Status);
  2518. }
  2519. ULONG
  2520. HandleToListIndex(
  2521. ULONG_PTR ContextHandle
  2522. )
  2523. {
  2524. ASSERT( (KERB_USERLIST_COUNT != 0) );
  2525. ASSERT( (KERB_USERLIST_COUNT & 1) == 0 );
  2526. ULONG Number ;
  2527. ULONG Hash;
  2528. ULONG HashFinal;
  2529. Number = (ULONG)ContextHandle;
  2530. Hash = Number;
  2531. Hash += Number >> 8;
  2532. Hash += Number >> 16;
  2533. Hash += Number >> 24;
  2534. HashFinal = Hash;
  2535. HashFinal += Hash >> 4;
  2536. //
  2537. // insure power of two if not one.
  2538. //
  2539. return ( HashFinal & (KERB_USERLIST_COUNT-1) ) ;
  2540. }