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

5675 lines
150 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: miscapi.cxx
  8. //
  9. // Contents: Code for miscellaneous lsa mode Kerberos entrypoints
  10. //
  11. //
  12. // History: 16-April-1996 MikeSw Created
  13. //
  14. //------------------------------------------------------------------------
  15. #include <kerb.hxx>
  16. #include <kerbp.h>
  17. #include <crypt.h> // NT_OWF_PASSWORD_LENGTH
  18. #include <kerbpass.h>
  19. #include <spncache.h>
  20. #ifdef RETAIL_LOG_SUPPORT
  21. static TCHAR THIS_FILE[]=TEXT(__FILE__);
  22. #endif
  23. //
  24. // LsaApCallPackage() function dispatch table
  25. //
  26. NTSTATUS NTAPI
  27. KerbDebugRequest(
  28. IN PLSA_CLIENT_REQUEST ClientRequest,
  29. IN PVOID ProtocolSubmitBuffer,
  30. IN PVOID ClientBufferBase,
  31. IN ULONG SubmitBufferLength,
  32. OUT PVOID *ProtocolReturnBuffer,
  33. OUT PULONG ReturnBufferLength,
  34. OUT PNTSTATUS ProtocolStatus
  35. );
  36. NTSTATUS NTAPI
  37. KerbQueryTicketCache(
  38. IN PLSA_CLIENT_REQUEST ClientRequest,
  39. IN PVOID ProtocolSubmitBuffer,
  40. IN PVOID ClientBufferBase,
  41. IN ULONG SubmitBufferLength,
  42. OUT PVOID *ProtocolReturnBuffer,
  43. OUT PULONG ReturnBufferLength,
  44. OUT PNTSTATUS ProtocolStatus
  45. );
  46. NTSTATUS NTAPI
  47. KerbQueryTicketCacheEx(
  48. IN PLSA_CLIENT_REQUEST ClientRequest,
  49. IN PVOID ProtocolSubmitBuffer,
  50. IN PVOID ClientBufferBase,
  51. IN ULONG SubmitBufferLength,
  52. OUT PVOID *ProtocolReturnBuffer,
  53. OUT PULONG ReturnBufferLength,
  54. OUT PNTSTATUS ProtocolStatus
  55. );
  56. NTSTATUS NTAPI
  57. KerbChangeMachinePassword(
  58. IN PLSA_CLIENT_REQUEST ClientRequest,
  59. IN PVOID ProtocolSubmitBuffer,
  60. IN PVOID ClientBufferBase,
  61. IN ULONG SubmitBufferLength,
  62. OUT PVOID *ProtocolReturnBuffer,
  63. OUT PULONG ReturnBufferLength,
  64. OUT PNTSTATUS ProtocolStatus
  65. );
  66. NTSTATUS NTAPI
  67. KerbVerifyPac(
  68. IN PLSA_CLIENT_REQUEST ClientRequest,
  69. IN PVOID ProtocolSubmitBuffer,
  70. IN PVOID ClientBufferBase,
  71. IN ULONG SubmitBufferLength,
  72. OUT PVOID *ProtocolReturnBuffer,
  73. OUT PULONG ReturnBufferLength,
  74. OUT PNTSTATUS ProtocolStatus
  75. );
  76. NTSTATUS NTAPI
  77. KerbRetrieveTicket(
  78. IN PLSA_CLIENT_REQUEST ClientRequest,
  79. IN PVOID ProtocolSubmitBuffer,
  80. IN PVOID ClientBufferBase,
  81. IN ULONG SubmitBufferLength,
  82. OUT PVOID *ProtocolReturnBuffer,
  83. OUT PULONG ReturnBufferLength,
  84. OUT PNTSTATUS ProtocolStatus
  85. );
  86. NTSTATUS NTAPI
  87. KerbSetIpAddresses(
  88. IN PLSA_CLIENT_REQUEST ClientRequest,
  89. IN PVOID ProtocolSubmitBuffer,
  90. IN PVOID ClientBufferBase,
  91. IN ULONG SubmitBufferLength,
  92. OUT PVOID *ProtocolReturnBuffer,
  93. OUT PULONG ReturnBufferLength,
  94. OUT PNTSTATUS ProtocolStatus
  95. );
  96. NTSTATUS NTAPI
  97. KerbPurgeTicket(
  98. IN PLSA_CLIENT_REQUEST ClientRequest,
  99. IN PVOID ProtocolSubmitBuffer,
  100. IN PVOID ClientBufferBase,
  101. IN ULONG SubmitBufferLength,
  102. OUT PVOID *ProtocolReturnBuffer,
  103. OUT PULONG ReturnBufferLength,
  104. OUT PNTSTATUS ProtocolStatus
  105. );
  106. NTSTATUS NTAPI
  107. KerbPurgeTicketEx(
  108. IN PLSA_CLIENT_REQUEST ClientRequest,
  109. IN PVOID ProtocolSubmitBuffer,
  110. IN PVOID ClientBufferBase,
  111. IN ULONG SubmitBufferLength,
  112. OUT PVOID *ProtocolReturnBuffer,
  113. OUT PULONG ReturnBufferLength,
  114. OUT PNTSTATUS ProtocolStatus
  115. );
  116. NTSTATUS NTAPI
  117. KerbRetrieveEncodedTicket(
  118. IN PLSA_CLIENT_REQUEST ClientRequest,
  119. IN PVOID ProtocolSubmitBuffer,
  120. IN PVOID ClientBufferBase,
  121. IN ULONG SubmitBufferLength,
  122. OUT PVOID *ProtocolReturnBuffer,
  123. OUT PULONG ReturnBufferLength,
  124. OUT PNTSTATUS ProtocolStatus
  125. );
  126. NTSTATUS NTAPI
  127. KerbRetrieveEncodedTicketEx(
  128. IN PLSA_CLIENT_REQUEST ClientRequest,
  129. IN PVOID ProtocolSubmitBuffer,
  130. IN PVOID ClientBufferBase,
  131. IN ULONG SubmitBufferLength,
  132. OUT PVOID *ProtocolReturnBuffer,
  133. OUT PULONG ReturnBufferLength,
  134. OUT PNTSTATUS ProtocolStatus
  135. );
  136. NTSTATUS NTAPI
  137. KerbAddBindingCacheEntry(
  138. IN PLSA_CLIENT_REQUEST ClientRequest,
  139. IN PVOID ProtocolSubmitBuffer,
  140. IN PVOID ClientBufferBase,
  141. IN ULONG SubmitBufferLength,
  142. OUT PVOID *ProtocolReturnBuffer,
  143. OUT PULONG ReturnBufferLength,
  144. OUT PNTSTATUS ProtocolStatus
  145. );
  146. NTSTATUS NTAPI
  147. KerbDecryptMessage(
  148. IN PLSA_CLIENT_REQUEST ClientRequest,
  149. IN PVOID ProtocolSubmitBuffer,
  150. IN PVOID ClientBufferBase,
  151. IN ULONG SubmitBufferLength,
  152. OUT PVOID *ProtocolReturnBuffer,
  153. OUT PULONG ReturnBufferLength,
  154. OUT PNTSTATUS ProtocolStatus
  155. );
  156. NTSTATUS NTAPI
  157. KerbVerifyCredentials(
  158. IN PLSA_CLIENT_REQUEST ClientRequest,
  159. IN PVOID ProtocolSubmitBuffer,
  160. IN PVOID ClientBufferBase,
  161. IN ULONG SubmitBufferSize,
  162. OUT PVOID *ProtocolReturnBuffer,
  163. OUT PULONG ReturnBufferLength,
  164. OUT PNTSTATUS ProtocolStatus
  165. );
  166. NTSTATUS NTAPI
  167. KerbRefreshSmartcardCredentials(
  168. IN PLSA_CLIENT_REQUEST ClientRequest,
  169. IN PVOID ProtocolSubmitBuffer,
  170. IN PVOID ClientBufferBase,
  171. IN ULONG SubmitBufferLength,
  172. OUT PVOID *ProtocolReturnBuffer,
  173. OUT PULONG ReturnBufferLength,
  174. OUT PNTSTATUS ProtocolStatus
  175. );
  176. NTSTATUS NTAPI
  177. KerbAddExtraCredential(
  178. IN PLSA_CLIENT_REQUEST ClientRequest,
  179. IN PVOID ProtocolSubmitBuffer,
  180. IN PVOID ClientBufferBase,
  181. IN ULONG SubmitBufferLength,
  182. OUT PVOID *ProtocolReturnBuffer,
  183. OUT PULONG ReturnBufferLength,
  184. OUT PNTSTATUS ProtocolStatus
  185. );
  186. NTSTATUS NTAPI
  187. KerbTicketAsRequestSafe(
  188. IN PLSA_CLIENT_REQUEST ClientRequest,
  189. IN PVOID ProtocolSubmitBuffer,
  190. IN PVOID ClientBufferBase,
  191. IN ULONG SubmitBufferLength,
  192. OUT PVOID *ProtocolReturnBuffer,
  193. OUT PULONG ReturnBufferLength,
  194. OUT PNTSTATUS ProtocolStatus
  195. );
  196. PLSA_AP_CALL_PACKAGE
  197. KerbCallPackageDispatch[] = {
  198. #if DBG
  199. KerbDebugRequest,
  200. #else
  201. NULL,
  202. #endif
  203. KerbQueryTicketCache,
  204. KerbChangeMachinePassword,
  205. KerbVerifyPac,
  206. KerbRetrieveTicket,
  207. KerbSetIpAddresses,
  208. KerbPurgeTicket,
  209. KerbChangePassword,
  210. KerbRetrieveEncodedTicket,
  211. #if DBG
  212. KerbDecryptMessage,
  213. #else
  214. NULL,
  215. #endif
  216. KerbAddBindingCacheEntry,
  217. KerbSetPassword,
  218. KerbSetPassword,
  219. KerbVerifyCredentials,
  220. KerbQueryTicketCacheEx,
  221. KerbPurgeTicketEx,
  222. // KerbRetrieveEncodedTicketEx,
  223. KerbRefreshSmartcardCredentials,
  224. KerbAddExtraCredential,
  225. NULL,
  226. KerbTicketAsRequestSafe,
  227. };
  228. //+-------------------------------------------------------------------------
  229. //
  230. // Function: SpGetUserInfo
  231. //
  232. // Synopsis: Gets information about a user
  233. //
  234. // Effects:
  235. //
  236. // Arguments:
  237. //
  238. // Requires:
  239. //
  240. // Returns:
  241. //
  242. // Notes:
  243. //
  244. //
  245. //--------------------------------------------------------------------------
  246. NTSTATUS NTAPI
  247. SpGetUserInfo(
  248. IN PLUID LogonId,
  249. IN ULONG Flags,
  250. OUT PSecurityUserData * UserData
  251. )
  252. {
  253. return(STATUS_NOT_SUPPORTED);
  254. }
  255. //+-------------------------------------------------------------------------
  256. //
  257. // Function: LsaApCallPackage
  258. //
  259. // Synopsis: Kerberos entrypoint for LsaCallAuthenticationPackage
  260. //
  261. // Effects:
  262. //
  263. // Arguments:
  264. //
  265. // Requires:
  266. //
  267. // Returns:
  268. //
  269. // Notes:
  270. //
  271. //
  272. //--------------------------------------------------------------------------
  273. NTSTATUS NTAPI
  274. LsaApCallPackage(
  275. IN PLSA_CLIENT_REQUEST ClientRequest,
  276. IN PVOID ProtocolSubmitBuffer,
  277. IN PVOID ClientBufferBase,
  278. IN ULONG SubmitBufferLength,
  279. OUT PVOID *ProtocolReturnBuffer,
  280. OUT PULONG ReturnBufferLength,
  281. OUT PNTSTATUS ProtocolStatus
  282. )
  283. {
  284. NTSTATUS Status;
  285. ULONG MessageType;
  286. PLSA_AP_CALL_PACKAGE TempFn = NULL;
  287. //
  288. // Get the messsage type from the protocol submit buffer.
  289. //
  290. if ( SubmitBufferLength < sizeof(KERB_PROTOCOL_MESSAGE_TYPE) )
  291. {
  292. return STATUS_INVALID_PARAMETER;
  293. }
  294. MessageType =
  295. (ULONG) *((PKERB_PROTOCOL_MESSAGE_TYPE)(ProtocolSubmitBuffer));
  296. if ((MessageType >=
  297. (sizeof(KerbCallPackageDispatch)/sizeof(KerbCallPackageDispatch[0]))) ||
  298. (KerbCallPackageDispatch[MessageType] == NULL))
  299. {
  300. return STATUS_INVALID_PARAMETER;
  301. }
  302. //
  303. // Allow the dispatch routines to only set the return buffer information
  304. // on success conditions.
  305. //
  306. *ProtocolReturnBuffer = NULL;
  307. *ReturnBufferLength = 0;
  308. //
  309. // Call the appropriate routine for this message.
  310. //
  311. TempFn = KerbCallPackageDispatch[MessageType];
  312. D_DebugLog((DEB_WARN, "LsaApCallPackage %#x(%d), TempFn %p\n", MessageType, MessageType, TempFn));
  313. if (!TempFn)
  314. {
  315. Status = STATUS_NOT_SUPPORTED;
  316. goto Cleanup;
  317. }
  318. Status = (*TempFn)(
  319. ClientRequest,
  320. ProtocolSubmitBuffer,
  321. ClientBufferBase,
  322. SubmitBufferLength,
  323. ProtocolReturnBuffer,
  324. ReturnBufferLength,
  325. ProtocolStatus );
  326. // RtlCheckForOrphanedCriticalSections(NtCurrentThread());
  327. Cleanup:
  328. return(Status);
  329. }
  330. NTSTATUS NTAPI
  331. LsaApCallPackageUntrusted(
  332. IN PLSA_CLIENT_REQUEST ClientRequest,
  333. IN PVOID ProtocolSubmitBuffer,
  334. IN PVOID ClientBufferBase,
  335. IN ULONG SubmitBufferLength,
  336. OUT PVOID *ProtocolReturnBuffer,
  337. OUT PULONG ReturnBufferLength,
  338. OUT PNTSTATUS ProtocolStatus
  339. )
  340. {
  341. KERB_PROTOCOL_MESSAGE_TYPE MessageType;
  342. //
  343. // Get the messsage type from the protocol submit buffer.
  344. //
  345. if ( SubmitBufferLength < sizeof(KERB_PROTOCOL_MESSAGE_TYPE) ) {
  346. return STATUS_INVALID_PARAMETER;
  347. }
  348. MessageType = *((PKERB_PROTOCOL_MESSAGE_TYPE)(ProtocolSubmitBuffer));
  349. if ( MessageType >=
  350. (sizeof(KerbCallPackageDispatch)/sizeof(KerbCallPackageDispatch[0])))
  351. {
  352. return STATUS_INVALID_PARAMETER;
  353. }
  354. //
  355. // Untrusted clients are not allowed to call the ChangeMachinePassword function
  356. //
  357. if (MessageType == KerbChangeMachinePasswordMessage)
  358. {
  359. return STATUS_ACCESS_DENIED;
  360. }
  361. //
  362. // Allow the dispatch routines to only set the return buffer information
  363. // on success conditions.
  364. //
  365. *ProtocolReturnBuffer = NULL;
  366. *ReturnBufferLength = 0;
  367. //
  368. // Call the appropriate routine for this message.
  369. //
  370. return(LsaApCallPackage(
  371. ClientRequest,
  372. ProtocolSubmitBuffer,
  373. ClientBufferBase,
  374. SubmitBufferLength,
  375. ProtocolReturnBuffer,
  376. ReturnBufferLength,
  377. ProtocolStatus) );
  378. }
  379. NTSTATUS NTAPI
  380. LsaApCallPackagePassthrough(
  381. IN PLSA_CLIENT_REQUEST ClientRequest,
  382. IN PVOID ProtocolSubmitBuffer,
  383. IN PVOID ClientBufferBase,
  384. IN ULONG SubmitBufferLength,
  385. OUT PVOID *ProtocolReturnBuffer,
  386. OUT PULONG ReturnBufferLength,
  387. OUT PNTSTATUS ProtocolStatus
  388. )
  389. {
  390. KERB_PROTOCOL_MESSAGE_TYPE MessageType;
  391. //
  392. // Get the messsage type from the protocol submit buffer.
  393. //
  394. if ( SubmitBufferLength < sizeof(KERB_PROTOCOL_MESSAGE_TYPE) ) {
  395. return STATUS_INVALID_PARAMETER;
  396. }
  397. MessageType = *((PKERB_PROTOCOL_MESSAGE_TYPE)(ProtocolSubmitBuffer));
  398. if ( MessageType >=
  399. (sizeof(KerbCallPackageDispatch)/sizeof(KerbCallPackageDispatch[0])))
  400. {
  401. return STATUS_INVALID_PARAMETER;
  402. }
  403. //
  404. // only allow passthrough related requests.
  405. //
  406. if (MessageType != KerbVerifyPacMessage)
  407. {
  408. return STATUS_ACCESS_DENIED;
  409. }
  410. //
  411. // Allow the dispatch routines to only set the return buffer information
  412. // on success conditions.
  413. //
  414. *ProtocolReturnBuffer = NULL;
  415. *ReturnBufferLength = 0;
  416. //
  417. // Call the appropriate routine for this message.
  418. //
  419. return(LsaApCallPackage(
  420. ClientRequest,
  421. ProtocolSubmitBuffer,
  422. ClientBufferBase,
  423. SubmitBufferLength,
  424. ProtocolReturnBuffer,
  425. ReturnBufferLength,
  426. ProtocolStatus) );
  427. }
  428. //+-------------------------------------------------------------------------
  429. //
  430. // Function: KerbDebugRequest
  431. //
  432. // Synopsis: CallPackage entrypoint for debugging
  433. //
  434. // Effects:
  435. //
  436. // Arguments:
  437. //
  438. // Requires:
  439. //
  440. // Returns:
  441. //
  442. // Notes:
  443. //
  444. //
  445. //--------------------------------------------------------------------------
  446. NTSTATUS NTAPI
  447. KerbDebugRequest(
  448. IN PLSA_CLIENT_REQUEST ClientRequest,
  449. IN PVOID ProtocolSubmitBuffer,
  450. IN PVOID ClientBufferBase,
  451. IN ULONG SubmitBufferLength,
  452. OUT PVOID *ProtocolReturnBuffer,
  453. OUT PULONG ReturnBufferLength,
  454. OUT PNTSTATUS ProtocolStatus
  455. )
  456. {
  457. NTSTATUS Status = STATUS_SUCCESS;
  458. #if DBG
  459. PVOID Handle = NULL;
  460. PBYTE AuthData = NULL;
  461. UNICODE_STRING AccountName = {0};
  462. BYTE Buffer[sizeof(KERB_DEBUG_REPLY) + sizeof(KERB_DEBUG_STATS) - sizeof(UCHAR) * ANYSIZE_ARRAY];
  463. PKERB_DEBUG_REQUEST DebugRequest;
  464. PKERB_DEBUG_REPLY DebugReply = (PKERB_DEBUG_REPLY) Buffer;
  465. PKERB_DEBUG_STATS DebugStats = (PKERB_DEBUG_STATS) DebugReply->Data;
  466. if (SubmitBufferLength < sizeof(*DebugRequest)) {
  467. Status = STATUS_INVALID_PARAMETER;
  468. goto Cleanup;
  469. }
  470. DebugRequest = (PKERB_DEBUG_REQUEST) ProtocolSubmitBuffer;
  471. switch(DebugRequest->DebugRequest) {
  472. case KERB_DEBUG_REQ_BREAKPOINT:
  473. DbgBreakPoint();
  474. break;
  475. case KERB_DEBUG_REQ_STATISTICS:
  476. DebugReply->MessageType = KerbDebugRequestMessage;
  477. DebugStats->CacheHits = KerbTicketCacheHits;
  478. DebugStats->CacheMisses = KerbTicketCacheMisses;
  479. DebugStats->SkewedRequests = KerbSkewState.SkewedRequests;
  480. DebugStats->SuccessRequests = KerbSkewState.SuccessRequests;
  481. DebugStats->LastSync = KerbSkewState.LastSync;
  482. Status = LsaFunctions->AllocateClientBuffer(
  483. NULL,
  484. sizeof(Buffer),
  485. ProtocolReturnBuffer
  486. );
  487. if (!NT_SUCCESS(Status))
  488. {
  489. goto Cleanup;
  490. }
  491. Status = LsaFunctions->CopyToClientBuffer(
  492. NULL,
  493. sizeof(Buffer),
  494. *ProtocolReturnBuffer,
  495. DebugReply
  496. );
  497. if (!NT_SUCCESS(Status))
  498. {
  499. LsaFunctions->FreeClientBuffer(
  500. NULL,
  501. *ProtocolReturnBuffer
  502. );
  503. *ProtocolReturnBuffer = NULL;
  504. }
  505. else
  506. {
  507. *ReturnBufferLength = sizeof(Buffer);
  508. }
  509. break;
  510. case KERB_DEBUG_CREATE_TOKEN:
  511. {
  512. UNICODE_STRING String, String2;
  513. ULONG AuthDataSize = 0;
  514. HANDLE TokenHandle = NULL;
  515. LUID LogonId;
  516. NTSTATUS SubStatus;
  517. RtlInitUnicodeString(
  518. &String,
  519. L"Administrator"
  520. );
  521. RtlInitUnicodeString(
  522. &String2,
  523. NULL
  524. );
  525. Status = LsaFunctions->OpenSamUser(
  526. &String,
  527. SecNameSamCompatible,
  528. &String2,
  529. TRUE, // allow guest
  530. 0, // reserved
  531. &Handle
  532. );
  533. if (!NT_SUCCESS(Status))
  534. {
  535. DebugLog((DEB_ERROR,"Failed to open sam user: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  536. goto Cleanup;
  537. }
  538. Status = LsaFunctions->GetUserAuthData(
  539. Handle,
  540. &AuthData,
  541. &AuthDataSize
  542. );
  543. if (!NT_SUCCESS(Status))
  544. {
  545. DebugLog((DEB_ERROR,"Failed to get auth data: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  546. goto Cleanup;
  547. }
  548. //
  549. // Now create that token
  550. //
  551. Status = LsaFunctions->ConvertAuthDataToToken(
  552. AuthData,
  553. AuthDataSize,
  554. SecurityImpersonation,
  555. &KerberosSource,
  556. Network,
  557. &String,
  558. &TokenHandle,
  559. &LogonId,
  560. &AccountName,
  561. &SubStatus
  562. );
  563. if (!NT_SUCCESS(Status))
  564. {
  565. DebugLog((DEB_ERROR,"Failed to create token: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  566. goto Cleanup;
  567. }
  568. NtClose(TokenHandle);
  569. DebugLog((DEB_ERROR,"Logged on account is %wZ. %ws, line %d\n",&AccountName, THIS_FILE, __LINE__));
  570. break;
  571. }
  572. default:
  573. Status = STATUS_INVALID_PARAMETER;
  574. }
  575. Cleanup:
  576. if( Handle != NULL )
  577. {
  578. LsaFunctions->CloseSamUser( Handle );
  579. }
  580. if( AuthData != NULL )
  581. {
  582. LsaFunctions->FreeLsaHeap( AuthData );
  583. }
  584. if( AccountName.Buffer != NULL )
  585. {
  586. LsaFunctions->FreeLsaHeap( AccountName.Buffer );
  587. }
  588. #else
  589. Status = STATUS_INVALID_PARAMETER;
  590. #endif
  591. return(Status);
  592. }
  593. //+-------------------------------------------------------------------------
  594. //
  595. // Function: KerbRefreshSmartcardCredentials
  596. //
  597. // Synopsis: Notifies Kerberos when the smart card credentials need to
  598. // be updated. Basically a workaround for winlogon session
  599. // switching behavior during TS connects / re-connects.
  600. // When this happens, your HPROV goes bad...
  601. //
  602. // Effects:
  603. //
  604. // Arguments:
  605. //
  606. // Requires:
  607. //
  608. // Returns:
  609. //
  610. // Notes:
  611. //
  612. //
  613. //--------------------------------------------------------------------------
  614. NTSTATUS NTAPI
  615. KerbRefreshSmartcardCredentials(
  616. IN PLSA_CLIENT_REQUEST ClientRequest,
  617. IN PVOID ProtocolSubmitBuffer,
  618. IN PVOID ClientBufferBase,
  619. IN ULONG SubmitBufferLength,
  620. OUT PVOID *ProtocolReturnBuffer,
  621. OUT PULONG ReturnBufferLength,
  622. OUT PNTSTATUS ProtocolStatus
  623. )
  624. {
  625. NTSTATUS Status = STATUS_SUCCESS;
  626. PKERB_LOGON_SESSION LogonSession = NULL;
  627. PKERB_REFRESH_SCCRED_REQUEST ChangeRequest;
  628. SECPKG_CLIENT_INFO ClientInfo;
  629. PLUID LogonId;
  630. if (SubmitBufferLength < sizeof(KERB_REFRESH_SCCRED_REQUEST))
  631. {
  632. Status = STATUS_INVALID_PARAMETER;
  633. goto Cleanup;
  634. }
  635. ChangeRequest = (PKERB_REFRESH_SCCRED_REQUEST) ProtocolSubmitBuffer;
  636. if (ARGUMENT_PRESENT(ProtocolReturnBuffer))
  637. {
  638. *ProtocolReturnBuffer = NULL;
  639. }
  640. if (ARGUMENT_PRESENT(ReturnBufferLength))
  641. {
  642. *ReturnBufferLength = 0;
  643. }
  644. //
  645. // If the caller did not provide a logon id, use the caller's logon id.
  646. //
  647. Status = LsaFunctions->GetClientInfo( &ClientInfo );
  648. if ( !NT_SUCCESS( Status ))
  649. {
  650. goto Cleanup;
  651. }
  652. if ( RtlIsZeroLuid( &ChangeRequest->LogonId ))
  653. {
  654. LogonId = &ClientInfo.LogonId;
  655. }
  656. else if ( !ClientInfo.HasTcbPrivilege )
  657. {
  658. Status = STATUS_PRIVILEGE_NOT_HELD;
  659. goto Cleanup;
  660. }
  661. else
  662. {
  663. LogonId = &ChangeRequest->LogonId;
  664. }
  665. LogonSession = KerbReferenceLogonSession(
  666. LogonId,
  667. FALSE
  668. );
  669. DsysAssert(LogonSession != NULL);
  670. if (LogonSession == NULL)
  671. {
  672. Status = STATUS_NO_SUCH_LOGON_SESSION;
  673. goto Cleanup;
  674. }
  675. KerbReleasePkCreds(
  676. LogonSession,
  677. NULL,
  678. TRUE // ok for reuse - save PIN and SChelper data
  679. );
  680. Status = STATUS_SUCCESS;
  681. Cleanup:
  682. if (LogonSession != NULL)
  683. {
  684. KerbDereferenceLogonSession(LogonSession);
  685. }
  686. *ProtocolStatus = Status;
  687. return(STATUS_SUCCESS);
  688. }
  689. //+-------------------------------------------------------------------------
  690. //
  691. // Function: KerbChangeMachinePassword
  692. //
  693. // Synopsis: Notifies Kerberos when the machine password has changed
  694. //
  695. // Effects:
  696. //
  697. // Arguments:
  698. //
  699. // Requires:
  700. //
  701. // Returns:
  702. //
  703. // Notes:
  704. //
  705. //
  706. //--------------------------------------------------------------------------
  707. NTSTATUS NTAPI
  708. KerbChangeMachinePassword(
  709. IN PLSA_CLIENT_REQUEST ClientRequest,
  710. IN PVOID ProtocolSubmitBuffer,
  711. IN PVOID ClientBufferBase,
  712. IN ULONG SubmitBufferLength,
  713. OUT PVOID *ProtocolReturnBuffer,
  714. OUT PULONG ReturnBufferLength,
  715. OUT PNTSTATUS ProtocolStatus
  716. )
  717. {
  718. NTSTATUS Status = STATUS_SUCCESS;
  719. LUID SystemLogonId = SYSTEM_LUID;
  720. PKERB_LOGON_SESSION SystemLogonSession = NULL;
  721. PKERB_CHANGE_MACH_PWD_REQUEST ChangeRequest;
  722. ULONG StructureSize = sizeof(KERB_CHANGE_MACH_PWD_REQUEST);
  723. if (ARGUMENT_PRESENT(ProtocolReturnBuffer))
  724. {
  725. *ProtocolReturnBuffer = NULL;
  726. }
  727. if (ARGUMENT_PRESENT(ReturnBufferLength))
  728. {
  729. *ReturnBufferLength = 0;
  730. }
  731. #if _WIN64
  732. SECPKG_CALL_INFO CallInfo;
  733. if(!LsaFunctions->GetCallInfo(&CallInfo))
  734. {
  735. Status = STATUS_INTERNAL_ERROR;
  736. goto Cleanup;
  737. }
  738. if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
  739. {
  740. StructureSize = sizeof(KERB_CHANGE_MACH_PWD_REQUEST_WOW64);
  741. }
  742. #endif // _WIN64
  743. if (SubmitBufferLength < StructureSize)
  744. {
  745. Status = STATUS_INVALID_PARAMETER;
  746. goto Cleanup;
  747. }
  748. if (!KerbGlobalInitialized)
  749. {
  750. Status = STATUS_SUCCESS;
  751. DsysAssert(FALSE);
  752. goto Cleanup;
  753. }
  754. ChangeRequest = (PKERB_CHANGE_MACH_PWD_REQUEST) ProtocolSubmitBuffer;
  755. #if _WIN64
  756. KERB_CHANGE_MACH_PWD_REQUEST LocalChangeRequest;
  757. //
  758. // Thunk 32-bit pointers if this is a WOW caller
  759. //
  760. if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
  761. {
  762. PKERB_CHANGE_MACH_PWD_REQUEST_WOW64 ChangeRequestWOW =
  763. (PKERB_CHANGE_MACH_PWD_REQUEST_WOW64) ChangeRequest;
  764. LocalChangeRequest.MessageType = ChangeRequest->MessageType;
  765. UNICODE_STRING_FROM_WOW_STRING(&LocalChangeRequest.NewPassword,
  766. &ChangeRequestWOW->NewPassword);
  767. UNICODE_STRING_FROM_WOW_STRING(&LocalChangeRequest.OldPassword,
  768. &ChangeRequestWOW->OldPassword);
  769. ChangeRequest = &LocalChangeRequest;
  770. }
  771. #endif // _WIN64
  772. //
  773. // Find the system logon session.
  774. //
  775. SystemLogonSession = KerbReferenceLogonSession(
  776. &SystemLogonId,
  777. FALSE // don't unlink
  778. );
  779. DsysAssert(SystemLogonSession != NULL);
  780. if (SystemLogonSession == NULL)
  781. {
  782. Status = STATUS_NO_SUCH_LOGON_SESSION;
  783. goto Cleanup;
  784. }
  785. //
  786. // Calculate the new password list
  787. //
  788. if (ChangeRequest->NewPassword.Buffer != NULL)
  789. {
  790. //
  791. // If there is an old password, update with that one first so it
  792. // will later get moved to the old password field.
  793. //
  794. KerbWriteLockLogonSessions(SystemLogonSession);
  795. if (ChangeRequest->OldPassword.Buffer != NULL)
  796. {
  797. Status = KerbChangeCredentialsPassword(
  798. &SystemLogonSession->PrimaryCredentials,
  799. &ChangeRequest->OldPassword,
  800. NULL, // no etype info
  801. MachineAccount,
  802. PRIMARY_CRED_CLEAR_PASSWORD
  803. );
  804. }
  805. if (NT_SUCCESS(Status))
  806. {
  807. Status = KerbChangeCredentialsPassword(
  808. &SystemLogonSession->PrimaryCredentials,
  809. &ChangeRequest->NewPassword,
  810. NULL, // no etype info
  811. MachineAccount,
  812. PRIMARY_CRED_CLEAR_PASSWORD
  813. );
  814. }
  815. KerbUnlockLogonSessions(SystemLogonSession);
  816. if (!NT_SUCCESS(Status))
  817. {
  818. goto Cleanup;
  819. }
  820. //
  821. // Update the flags to indicate that we have a password
  822. //
  823. KerbWriteLockLogonSessions(SystemLogonSession);
  824. SystemLogonSession->LogonSessionFlags &= ~(KERB_LOGON_LOCAL_ONLY | KERB_LOGON_NO_PASSWORD);
  825. KerbUnlockLogonSessions(SystemLogonSession);
  826. }
  827. else
  828. {
  829. //
  830. // Update the flags to indicate that we do not have a password
  831. //
  832. KerbWriteLockLogonSessions(SystemLogonSession);
  833. SystemLogonSession->LogonSessionFlags |= (KERB_LOGON_LOCAL_ONLY | KERB_LOGON_NO_PASSWORD);
  834. KerbUnlockLogonSessions(SystemLogonSession);
  835. }
  836. Status = STATUS_SUCCESS;
  837. Cleanup:
  838. if (SystemLogonSession != NULL)
  839. {
  840. KerbDereferenceLogonSession(SystemLogonSession);
  841. }
  842. *ProtocolStatus = Status;
  843. return(STATUS_SUCCESS);
  844. }
  845. //+-------------------------------------------------------------------------
  846. //
  847. // Function: KerbNameLength
  848. //
  849. // Synopsis: returns length in bytes of variable portion of KERB_INTERNAL_NAME
  850. //
  851. // Effects:
  852. //
  853. // Arguments:
  854. //
  855. // Requires:
  856. //
  857. // Returns:
  858. //
  859. // Notes: This code is (effectively) duplicated in
  860. // KerbWOWNameLength. Make sure any changes
  861. // made here are applied there as well.
  862. //
  863. //--------------------------------------------------------------------------
  864. ULONG
  865. KerbNameLength(
  866. IN PKERB_INTERNAL_NAME Name
  867. )
  868. {
  869. ULONG Length = 0;
  870. ULONG Index;
  871. if (!ARGUMENT_PRESENT(Name))
  872. {
  873. return(0);
  874. }
  875. Length = sizeof(KERB_INTERNAL_NAME)
  876. - sizeof(UNICODE_STRING)
  877. + Name->NameCount * sizeof(UNICODE_STRING) ;
  878. for (Index = 0; Index < Name->NameCount ;Index++ )
  879. {
  880. Length += Name->Names[Index].Length;
  881. }
  882. Length = ROUND_UP_COUNT(Length, sizeof(LPWSTR));
  883. return(Length);
  884. }
  885. ULONG
  886. KerbStringNameLength(
  887. IN PKERB_INTERNAL_NAME Name
  888. )
  889. {
  890. ULONG Length = 0;
  891. ULONG Index;
  892. Length = Name->NameCount * sizeof(WCHAR); // for separators & null terminator
  893. for (Index = 0; Index < Name->NameCount ;Index++ )
  894. {
  895. Length += Name->Names[Index].Length;
  896. }
  897. return(Length);
  898. }
  899. //+-------------------------------------------------------------------------
  900. //
  901. // Function: KerbPutKdcName
  902. //
  903. // Synopsis: Copies a Kdc name to a buffer
  904. //
  905. // Effects:
  906. //
  907. // Arguments:
  908. //
  909. // Requires:
  910. //
  911. // Returns:
  912. //
  913. // Notes: This code is (effectively) duplicated in
  914. // KerbPutWOWKdcName. Make sure any changes
  915. // made here are applied there as well.
  916. //
  917. //--------------------------------------------------------------------------
  918. VOID
  919. KerbPutKdcName(
  920. IN PKERB_INTERNAL_NAME InputName,
  921. OUT PKERB_EXTERNAL_NAME * OutputName,
  922. IN LONG_PTR Offset,
  923. IN OUT PBYTE * Where
  924. )
  925. {
  926. ULONG Index;
  927. PKERB_INTERNAL_NAME LocalName = (PKERB_INTERNAL_NAME) *Where;
  928. if (!ARGUMENT_PRESENT(InputName))
  929. {
  930. *OutputName = NULL;
  931. return;
  932. }
  933. *Where += sizeof(KERB_INTERNAL_NAME) - sizeof(UNICODE_STRING) +
  934. InputName->NameCount * sizeof(UNICODE_STRING);
  935. LocalName->NameType = InputName->NameType;
  936. LocalName->NameCount = InputName->NameCount;
  937. for (Index = 0; Index < InputName->NameCount ; Index++ )
  938. {
  939. LocalName->Names[Index].Length =
  940. LocalName->Names[Index].MaximumLength =
  941. InputName->Names[Index].Length;
  942. LocalName->Names[Index].Buffer = (LPWSTR) (*Where + Offset);
  943. RtlCopyMemory(
  944. *Where,
  945. InputName->Names[Index].Buffer,
  946. InputName->Names[Index].Length
  947. );
  948. *Where += InputName->Names[Index].Length;
  949. }
  950. *Where = (PBYTE) ROUND_UP_POINTER(*Where,sizeof(LPWSTR));
  951. *OutputName = (PKERB_EXTERNAL_NAME) ((PBYTE) LocalName + Offset);
  952. }
  953. //+-------------------------------------------------------------------------
  954. //
  955. // Function: KerbPutKdcNameAsString
  956. //
  957. // Synopsis: Copies a KERB_INTERNAL_NAME into a buffer
  958. //
  959. // Effects:
  960. //
  961. // Arguments: InputString - String to 'put'
  962. // OutputString - Receives 'put' string
  963. // Offset - Difference in addresses of local and client buffers.
  964. // Where - Location in local buffer to place string.
  965. //
  966. // Requires:
  967. //
  968. // Returns:
  969. //
  970. // Notes: This code is (effectively) duplicated in
  971. // KerbPutKdcNameAsWOWString. Make sure any
  972. // changes made here are applied there as well.
  973. //
  974. //--------------------------------------------------------------------------
  975. VOID
  976. KerbPutKdcNameAsString(
  977. IN PKERB_INTERNAL_NAME InputName,
  978. OUT PUNICODE_STRING OutputName,
  979. IN LONG_PTR Offset,
  980. IN OUT PBYTE * Where
  981. )
  982. {
  983. USHORT Index;
  984. OutputName->Buffer = (LPWSTR) (*Where + Offset);
  985. OutputName->Length = 0;
  986. OutputName->MaximumLength = 0;
  987. for (Index = 0; Index < InputName->NameCount ; Index++ )
  988. {
  989. RtlCopyMemory(
  990. *Where,
  991. InputName->Names[Index].Buffer,
  992. InputName->Names[Index].Length
  993. );
  994. *Where += InputName->Names[Index].Length;
  995. OutputName->Length = OutputName->Length + InputName->Names[Index].Length;
  996. if (Index == (InputName->NameCount - 1))
  997. {
  998. *((LPWSTR) *Where) = L'\0';
  999. OutputName->MaximumLength = OutputName->Length + sizeof(WCHAR);
  1000. }
  1001. else
  1002. {
  1003. *((LPWSTR) *Where) = L'/';
  1004. OutputName->Length += sizeof(WCHAR);
  1005. }
  1006. *Where += sizeof(WCHAR);
  1007. }
  1008. }
  1009. //+-------------------------------------------------------------------------
  1010. //
  1011. // Function: KerbPutString
  1012. //
  1013. // Synopsis: Copies a UNICODE_STRING into a buffer
  1014. //
  1015. // Effects:
  1016. //
  1017. // Arguments: InputString - String to 'put'
  1018. // OutputString - Receives 'put' string
  1019. // Offset - Difference in addresses of local and client buffers.
  1020. // Where - Location in local buffer to place string.
  1021. //
  1022. // Requires:
  1023. //
  1024. // Returns:
  1025. //
  1026. // Notes: This code is (effectively) duplicated in
  1027. // KerbPutWOWString. Make sure any changes
  1028. // made here are applied there as well.
  1029. //
  1030. //--------------------------------------------------------------------------
  1031. VOID
  1032. KerbPutString(
  1033. IN PUNICODE_STRING InputString,
  1034. OUT PUNICODE_STRING OutputString,
  1035. IN LONG_PTR Offset,
  1036. IN OUT PBYTE * Where
  1037. )
  1038. {
  1039. OutputString->Length = OutputString->MaximumLength = InputString->Length;
  1040. OutputString->Buffer = (LPWSTR) (*Where + Offset);
  1041. RtlCopyMemory(
  1042. *Where,
  1043. InputString->Buffer,
  1044. InputString->Length
  1045. );
  1046. *Where += InputString->Length;
  1047. }
  1048. //+-------------------------------------------------------------------------
  1049. //
  1050. // Function: ComputeTicketCacheSize
  1051. //
  1052. // Synopsis: Computes the size necessary to store contents of a ticket cache
  1053. //
  1054. // Effects:
  1055. //
  1056. // Arguments: TicketCache cache to compute the size of
  1057. // WowClient is this a WOW client? (64-bit only)
  1058. // CacheSize used to append the size of cache
  1059. // CacheEntries used to append the number of entries
  1060. //
  1061. // Requires:
  1062. //
  1063. // Returns: Nothing
  1064. //
  1065. // Notes:
  1066. //
  1067. //
  1068. //--------------------------------------------------------------------------
  1069. void
  1070. KerbComputeTicketCacheSize(
  1071. IN KERB_PRIMARY_CREDENTIAL * PrimaryCredentials,
  1072. IN BOOLEAN WowClient,
  1073. IN OUT ULONG * CacheSize,
  1074. IN OUT ULONG * CacheEntries
  1075. )
  1076. {
  1077. DsysAssert( CacheSize );
  1078. DsysAssert( CacheEntries );
  1079. #if _WIN64
  1080. ULONG CacheEntrySize = WowClient ?
  1081. (ULONG) sizeof( KERB_TICKET_CACHE_INFO_WOW64 ) :
  1082. (ULONG) sizeof( KERB_TICKET_CACHE_INFO );
  1083. #else
  1084. ULONG CacheEntrySize = sizeof( KERB_TICKET_CACHE_INFO );
  1085. DsysAssert( WowClient == FALSE );
  1086. #endif // _WIN64
  1087. KERB_TICKET_CACHE * TicketCaches[3] = {
  1088. &PrimaryCredentials->AuthenticationTicketCache,
  1089. &PrimaryCredentials->ServerTicketCache,
  1090. &PrimaryCredentials->S4UTicketCache
  1091. };
  1092. if ( *CacheSize == 0 ) {
  1093. *CacheSize = FIELD_OFFSET( KERB_QUERY_TKT_CACHE_RESPONSE, Tickets );
  1094. }
  1095. for ( ULONG i = 0 ; i < 3 ; i++ ) {
  1096. KERB_TICKET_CACHE * TicketCache = TicketCaches[i];
  1097. for ( PLIST_ENTRY ListEntry = TicketCache->CacheEntries.Flink ;
  1098. ListEntry != &TicketCache->CacheEntries ;
  1099. ListEntry = ListEntry->Flink ) {
  1100. KERB_TICKET_CACHE_ENTRY * CacheEntry;
  1101. CacheEntry= CONTAINING_RECORD(
  1102. ListEntry,
  1103. KERB_TICKET_CACHE_ENTRY,
  1104. ListEntry.Next
  1105. );
  1106. DsysAssert( CacheEntry->ServiceName != NULL );
  1107. *CacheEntries += 1;
  1108. *CacheSize += CacheEntrySize +
  1109. KerbStringNameLength( CacheEntry->ServiceName ) +
  1110. CacheEntry->DomainName.Length;
  1111. }
  1112. }
  1113. }
  1114. void
  1115. KerbBuildQueryTicketCacheResponse(
  1116. IN KERB_PRIMARY_CREDENTIAL * PrimaryCredentials,
  1117. IN PKERB_QUERY_TKT_CACHE_RESPONSE CacheResponse,
  1118. IN BOOLEAN WowClient,
  1119. IN OUT LONG_PTR * Offset,
  1120. IN OUT PBYTE * Where,
  1121. IN OUT ULONG * Index
  1122. )
  1123. {
  1124. DsysAssert( Offset );
  1125. DsysAssert( Where );
  1126. DsysAssert( Index );
  1127. #if _WIN64
  1128. PKERB_QUERY_TKT_CACHE_RESPONSE_WOW64 CacheResponseWOW64 = (PKERB_QUERY_TKT_CACHE_RESPONSE_WOW64) CacheResponse;
  1129. ULONG CacheEntrySize = WowClient ?
  1130. (ULONG) sizeof( KERB_TICKET_CACHE_INFO_WOW64 ) :
  1131. (ULONG) sizeof( KERB_TICKET_CACHE_INFO );
  1132. #else
  1133. ULONG CacheEntrySize = sizeof( KERB_TICKET_CACHE_INFO );
  1134. DsysAssert( WowClient == FALSE );
  1135. #endif // _WIN64
  1136. KERB_TICKET_CACHE * TicketCaches[3] = {
  1137. &PrimaryCredentials->AuthenticationTicketCache,
  1138. &PrimaryCredentials->ServerTicketCache,
  1139. &PrimaryCredentials->S4UTicketCache
  1140. };
  1141. if ( *Where == NULL ) {
  1142. *Where = ( PBYTE )( CacheResponse->Tickets ) + CacheResponse->CountOfTickets * CacheEntrySize;
  1143. }
  1144. for ( ULONG i = 0 ; i < 3 ; i++ ) {
  1145. KERB_TICKET_CACHE * TicketCache = TicketCaches[i];
  1146. for ( PLIST_ENTRY ListEntry = TicketCache->CacheEntries.Flink ;
  1147. ListEntry != &TicketCache->CacheEntries ;
  1148. ListEntry = ListEntry->Flink ) {
  1149. KERB_TICKET_CACHE_ENTRY * CacheEntry;
  1150. CacheEntry= CONTAINING_RECORD(
  1151. ListEntry,
  1152. KERB_TICKET_CACHE_ENTRY,
  1153. ListEntry.Next
  1154. );
  1155. #if _WIN64
  1156. if ( !WowClient ) {
  1157. #endif // _WIN64
  1158. CacheResponse->Tickets[*Index].StartTime = CacheEntry->StartTime;
  1159. CacheResponse->Tickets[*Index].EndTime = CacheEntry->EndTime;
  1160. CacheResponse->Tickets[*Index].RenewTime = CacheEntry->RenewUntil;
  1161. CacheResponse->Tickets[*Index].EncryptionType = (LONG) CacheEntry->Ticket.encrypted_part.encryption_type;
  1162. CacheResponse->Tickets[*Index].TicketFlags = CacheEntry->TicketFlags;
  1163. CacheResponse->Tickets[*Index].ServerName.Buffer = (LPWSTR) (*Where + *Offset);
  1164. CacheResponse->Tickets[*Index].ServerName.Length = CacheEntry->ServiceName->Names[0].Length;
  1165. CacheResponse->Tickets[*Index].ServerName.MaximumLength = CacheEntry->ServiceName->Names[0].Length;
  1166. KerbPutString(
  1167. &CacheEntry->DomainName,
  1168. &CacheResponse->Tickets[*Index].RealmName,
  1169. *Offset,
  1170. Where
  1171. );
  1172. KerbPutKdcNameAsString(
  1173. CacheEntry->ServiceName,
  1174. &CacheResponse->Tickets[*Index].ServerName,
  1175. *Offset,
  1176. Where
  1177. );
  1178. #if _WIN64
  1179. }
  1180. else
  1181. {
  1182. CacheResponseWOW64->Tickets[*Index].StartTime = CacheEntry->StartTime;
  1183. CacheResponseWOW64->Tickets[*Index].EndTime = CacheEntry->EndTime;
  1184. CacheResponseWOW64->Tickets[*Index].RenewTime = CacheEntry->RenewUntil;
  1185. CacheResponseWOW64->Tickets[*Index].EncryptionType = ( LONG )CacheEntry->Ticket.encrypted_part.encryption_type;
  1186. CacheResponseWOW64->Tickets[*Index].TicketFlags = CacheEntry->TicketFlags;
  1187. CacheResponseWOW64->Tickets[*Index].ServerName.Buffer = PtrToUlong (*Where + *Offset);
  1188. CacheResponseWOW64->Tickets[*Index].ServerName.Length = CacheEntry->ServiceName->Names[0].Length;
  1189. CacheResponseWOW64->Tickets[*Index].ServerName.MaximumLength = CacheEntry->ServiceName->Names[0].Length;
  1190. KerbPutWOWString(
  1191. &CacheEntry->DomainName,
  1192. &CacheResponseWOW64->Tickets[*Index].RealmName,
  1193. *Offset,
  1194. Where
  1195. );
  1196. KerbPutKdcNameAsWOWString(
  1197. CacheEntry->ServiceName,
  1198. &CacheResponseWOW64->Tickets[*Index].ServerName,
  1199. *Offset,
  1200. Where
  1201. );
  1202. }
  1203. #endif // _WIN64
  1204. (*Index)++;
  1205. }
  1206. }
  1207. }
  1208. //+-------------------------------------------------------------------------
  1209. //
  1210. // Function: KerbQueryTicketCache
  1211. //
  1212. // Synopsis: Retrieves the list of tickets for the specified logon session
  1213. //
  1214. // Effects:
  1215. //
  1216. // Arguments: Same as Callpackage
  1217. //
  1218. // Requires:
  1219. //
  1220. // Returns:
  1221. //
  1222. // Notes:
  1223. //
  1224. //
  1225. //--------------------------------------------------------------------------
  1226. NTSTATUS NTAPI
  1227. KerbQueryTicketCache(
  1228. IN PLSA_CLIENT_REQUEST ClientRequest,
  1229. IN PVOID ProtocolSubmitBuffer,
  1230. IN PVOID ClientBufferBase,
  1231. IN ULONG SubmitBufferLength,
  1232. OUT PVOID *ProtocolReturnBuffer,
  1233. OUT PULONG ReturnBufferLength,
  1234. OUT PNTSTATUS ProtocolStatus
  1235. )
  1236. {
  1237. NTSTATUS Status;
  1238. PKERB_QUERY_TKT_CACHE_REQUEST CacheRequest = ( PKERB_QUERY_TKT_CACHE_REQUEST )ProtocolSubmitBuffer;
  1239. SECPKG_CLIENT_INFO ClientInfo;
  1240. PLUID LogonId;
  1241. PKERB_LOGON_SESSION LogonSession = NULL;
  1242. PKERB_QUERY_TKT_CACHE_RESPONSE CacheResponse = NULL;
  1243. PKERB_QUERY_TKT_CACHE_RESPONSE ClientCacheResponse = NULL;
  1244. ULONG CacheSize = 0;
  1245. ULONG CacheEntries = 0;
  1246. BOOLEAN LockHeld = FALSE;
  1247. LONG_PTR Offset;
  1248. PBYTE Where = NULL;
  1249. ULONG Index = 0;
  1250. //
  1251. // Verify the request.
  1252. //
  1253. if ( SubmitBufferLength < sizeof( KERB_QUERY_TKT_CACHE_REQUEST )) {
  1254. Status = STATUS_INVALID_PARAMETER;
  1255. goto Cleanup;
  1256. }
  1257. //
  1258. // Find the caller's logon id & TCB status
  1259. //
  1260. Status = LsaFunctions->GetClientInfo( &ClientInfo );
  1261. if ( !NT_SUCCESS( Status )) {
  1262. goto Cleanup;
  1263. }
  1264. //
  1265. // If the caller did not provide a logon id, use the caller's logon id.
  1266. //
  1267. if ( RtlIsZeroLuid( &CacheRequest->LogonId )) {
  1268. LogonId = &ClientInfo.LogonId;
  1269. } else if ( !ClientInfo.HasTcbPrivilege ) {
  1270. //
  1271. // Caller must have TCB privilege in order to access to someone
  1272. // else's ticket cache.
  1273. //
  1274. Status = STATUS_PRIVILEGE_NOT_HELD;
  1275. goto Cleanup;
  1276. } else {
  1277. LogonId = &CacheRequest->LogonId;
  1278. }
  1279. LogonSession = KerbReferenceLogonSession(
  1280. LogonId,
  1281. FALSE // don't unlink
  1282. );
  1283. if ( LogonSession == NULL ) {
  1284. Status = STATUS_NO_SUCH_LOGON_SESSION;
  1285. goto Cleanup;
  1286. }
  1287. #if _WIN64
  1288. SECPKG_CALL_INFO CallInfo;
  1289. if( !LsaFunctions->GetCallInfo( &CallInfo )) {
  1290. Status = STATUS_INTERNAL_ERROR;
  1291. goto Cleanup;
  1292. }
  1293. #endif // _WIN64
  1294. //
  1295. // Prowl through the caches and find all the tickets
  1296. //
  1297. DsysAssert( !LockHeld );
  1298. KerbReadLockLogonSessions(LogonSession);
  1299. KerbReadLockTicketCache();
  1300. LockHeld = TRUE;
  1301. //
  1302. // Calculate the size needed for all the ticket information
  1303. //
  1304. KerbComputeTicketCacheSize(
  1305. &LogonSession->PrimaryCredentials,
  1306. #if _WIN64
  1307. (( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) != 0 ),
  1308. #else
  1309. FALSE,
  1310. #endif
  1311. &CacheSize,
  1312. &CacheEntries
  1313. );
  1314. //
  1315. // Now allocate two copies of the structure - one in our process, one in
  1316. // the client's process. We then build the structure in our process but
  1317. // with pointer valid in the client's process.
  1318. //
  1319. SafeAllocaAllocate(CacheResponse, CacheSize);
  1320. if ( CacheResponse == NULL )
  1321. {
  1322. Status = STATUS_INSUFFICIENT_RESOURCES;
  1323. goto Cleanup;
  1324. }
  1325. Status = LsaFunctions->AllocateClientBuffer(
  1326. NULL,
  1327. CacheSize,
  1328. ( PVOID * )&ClientCacheResponse
  1329. );
  1330. if ( !NT_SUCCESS( Status )) {
  1331. goto Cleanup;
  1332. }
  1333. Offset = ( LONG_PTR )(( PBYTE )ClientCacheResponse - ( PBYTE )CacheResponse );
  1334. //
  1335. // Build up the return structure
  1336. //
  1337. CacheResponse->MessageType = KerbQueryTicketCacheMessage;
  1338. CacheResponse->CountOfTickets = CacheEntries;
  1339. KerbBuildQueryTicketCacheResponse(
  1340. &LogonSession->PrimaryCredentials,
  1341. CacheResponse,
  1342. #if _WIN64
  1343. (( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) != 0 ),
  1344. #else
  1345. FALSE,
  1346. #endif
  1347. &Offset,
  1348. &Where,
  1349. &Index
  1350. );
  1351. //
  1352. // Copy the structure to the client's address space
  1353. //
  1354. Status = LsaFunctions->CopyToClientBuffer(
  1355. NULL,
  1356. CacheSize,
  1357. ClientCacheResponse,
  1358. CacheResponse
  1359. );
  1360. if (!NT_SUCCESS(Status))
  1361. {
  1362. goto Cleanup;
  1363. }
  1364. *ProtocolReturnBuffer = ClientCacheResponse;
  1365. ClientCacheResponse = NULL;
  1366. *ReturnBufferLength = CacheSize;
  1367. Cleanup:
  1368. if (LockHeld)
  1369. {
  1370. KerbUnlockTicketCache();
  1371. KerbUnlockLogonSessions( LogonSession );
  1372. }
  1373. if (LogonSession != NULL)
  1374. {
  1375. KerbDereferenceLogonSession( LogonSession );
  1376. }
  1377. SafeAllocaFree(CacheResponse);
  1378. if (ClientCacheResponse != NULL)
  1379. {
  1380. LsaFunctions->FreeClientBuffer(
  1381. NULL,
  1382. ClientCacheResponse
  1383. );
  1384. }
  1385. *ProtocolStatus = Status;
  1386. return STATUS_SUCCESS;
  1387. }
  1388. //+-------------------------------------------------------------------------
  1389. //
  1390. // Function: ComputeTicketCacheSizeEx
  1391. //
  1392. // Synopsis: Computes the size necessary to store contents of a ticket cache
  1393. //
  1394. // Effects:
  1395. //
  1396. // Arguments: TicketCache cache to compute the size of
  1397. // WowClient is this a WOW client (64-bit only)
  1398. // CacheSize used to append the size of cache
  1399. // CacheEntries used to append the number of entries
  1400. //
  1401. // Requires:
  1402. //
  1403. // Returns: Nothing
  1404. //
  1405. // Notes:
  1406. //
  1407. //
  1408. //--------------------------------------------------------------------------
  1409. void
  1410. KerbComputeTicketCacheSizeEx(
  1411. IN KERB_PRIMARY_CREDENTIAL * PrimaryCredentials,
  1412. IN BOOLEAN WowClient,
  1413. IN OUT ULONG * CacheSize,
  1414. IN OUT ULONG * CacheEntries
  1415. )
  1416. {
  1417. DsysAssert( CacheSize );
  1418. DsysAssert( CacheEntries );
  1419. #if _WIN64
  1420. ULONG CacheEntrySize = WowClient ?
  1421. (ULONG) sizeof( KERB_TICKET_CACHE_INFO_EX_WOW64 ) :
  1422. (ULONG) sizeof( KERB_TICKET_CACHE_INFO_EX );
  1423. #else
  1424. ULONG CacheEntrySize = sizeof( KERB_TICKET_CACHE_INFO_EX );
  1425. DsysAssert( WowClient == FALSE );
  1426. #endif // _WIN64
  1427. KERB_TICKET_CACHE * TicketCaches[3] = {
  1428. &PrimaryCredentials->AuthenticationTicketCache,
  1429. &PrimaryCredentials->ServerTicketCache,
  1430. &PrimaryCredentials->S4UTicketCache
  1431. };
  1432. if ( *CacheSize == 0 ) {
  1433. *CacheSize = FIELD_OFFSET( KERB_QUERY_TKT_CACHE_EX_RESPONSE, Tickets );
  1434. }
  1435. for ( ULONG i = 0 ; i < 3 ; i++ ) {
  1436. KERB_TICKET_CACHE * TicketCache = TicketCaches[i];
  1437. for ( PLIST_ENTRY ListEntry = TicketCache->CacheEntries.Flink ;
  1438. ListEntry != &TicketCache->CacheEntries ;
  1439. ListEntry = ListEntry->Flink ) {
  1440. KERB_TICKET_CACHE_ENTRY * CacheEntry;
  1441. CacheEntry= CONTAINING_RECORD(
  1442. ListEntry,
  1443. KERB_TICKET_CACHE_ENTRY,
  1444. ListEntry.Next
  1445. );
  1446. DsysAssert( CacheEntry->ServiceName != NULL );
  1447. *CacheEntries += 1;
  1448. *CacheSize += CacheEntrySize +
  1449. // client name
  1450. PrimaryCredentials->UserName.Length +
  1451. // client realm
  1452. PrimaryCredentials->DomainName.Length +
  1453. // server name
  1454. KerbStringNameLength( CacheEntry->ServiceName ) +
  1455. // server realm
  1456. CacheEntry->DomainName.Length;
  1457. }
  1458. }
  1459. }
  1460. void
  1461. KerbBuildQueryTicketCacheResponseEx(
  1462. IN KERB_PRIMARY_CREDENTIAL * PrimaryCredentials,
  1463. IN PKERB_QUERY_TKT_CACHE_EX_RESPONSE CacheResponse,
  1464. IN BOOLEAN WowClient,
  1465. IN OUT LONG_PTR * Offset,
  1466. IN OUT PBYTE * Where,
  1467. IN OUT ULONG * Index
  1468. )
  1469. {
  1470. DsysAssert( Offset );
  1471. DsysAssert( Where );
  1472. DsysAssert( Index );
  1473. #if _WIN64
  1474. PKERB_QUERY_TKT_CACHE_EX_RESPONSE_WOW64 CacheResponseWOW64 = (PKERB_QUERY_TKT_CACHE_EX_RESPONSE_WOW64) CacheResponse;
  1475. ULONG CacheEntrySize = WowClient ?
  1476. (ULONG) sizeof( KERB_TICKET_CACHE_INFO_EX_WOW64 ) :
  1477. (ULONG) sizeof( KERB_TICKET_CACHE_INFO_EX );
  1478. #else
  1479. ULONG CacheEntrySize = sizeof( KERB_TICKET_CACHE_INFO_EX );
  1480. DsysAssert( WowClient == FALSE );
  1481. #endif // _WIN64
  1482. KERB_TICKET_CACHE * TicketCaches[3] = {
  1483. &PrimaryCredentials->AuthenticationTicketCache,
  1484. &PrimaryCredentials->ServerTicketCache,
  1485. &PrimaryCredentials->S4UTicketCache
  1486. };
  1487. if ( *Where == NULL ) {
  1488. *Where = ( PBYTE )( CacheResponse->Tickets ) + CacheResponse->CountOfTickets * CacheEntrySize;
  1489. }
  1490. for ( ULONG i = 0 ; i < 3 ; i++ ) {
  1491. KERB_TICKET_CACHE * TicketCache = TicketCaches[i];
  1492. for ( PLIST_ENTRY ListEntry = TicketCache->CacheEntries.Flink ;
  1493. ListEntry != &TicketCache->CacheEntries ;
  1494. ListEntry = ListEntry->Flink ) {
  1495. KERB_TICKET_CACHE_ENTRY * CacheEntry;
  1496. CacheEntry= CONTAINING_RECORD(
  1497. ListEntry,
  1498. KERB_TICKET_CACHE_ENTRY,
  1499. ListEntry.Next
  1500. );
  1501. #if _WIN64
  1502. if ( !WowClient ) {
  1503. #endif // _WIN64
  1504. CacheResponse->Tickets[*Index].StartTime = CacheEntry->StartTime;
  1505. CacheResponse->Tickets[*Index].EndTime = CacheEntry->EndTime;
  1506. CacheResponse->Tickets[*Index].RenewTime = CacheEntry->RenewUntil;
  1507. CacheResponse->Tickets[*Index].EncryptionType = ( LONG )CacheEntry->Ticket.encrypted_part.encryption_type;
  1508. CacheResponse->Tickets[*Index].TicketFlags = CacheEntry->TicketFlags;
  1509. KerbPutString(
  1510. &PrimaryCredentials->UserName,
  1511. &CacheResponse->Tickets[*Index].ClientName,
  1512. *Offset,
  1513. Where
  1514. );
  1515. KerbPutString(
  1516. &PrimaryCredentials->DomainName,
  1517. &CacheResponse->Tickets[*Index].ClientRealm,
  1518. *Offset,
  1519. Where
  1520. );
  1521. KerbPutKdcNameAsString(
  1522. CacheEntry->ServiceName,
  1523. &CacheResponse->Tickets[*Index].ServerName,
  1524. *Offset,
  1525. Where
  1526. );
  1527. KerbPutString(
  1528. &CacheEntry->DomainName,
  1529. &CacheResponse->Tickets[*Index].ServerRealm,
  1530. *Offset,
  1531. Where
  1532. );
  1533. #if _WIN64
  1534. } else {
  1535. CacheResponseWOW64->Tickets[*Index].StartTime = CacheEntry->StartTime;
  1536. CacheResponseWOW64->Tickets[*Index].EndTime = CacheEntry->EndTime;
  1537. CacheResponseWOW64->Tickets[*Index].RenewTime = CacheEntry->RenewUntil;
  1538. CacheResponseWOW64->Tickets[*Index].EncryptionType = ( LONG )CacheEntry->Ticket.encrypted_part.encryption_type;
  1539. CacheResponseWOW64->Tickets[*Index].TicketFlags = CacheEntry->TicketFlags;
  1540. KerbPutWOWString(
  1541. &PrimaryCredentials->UserName,
  1542. &CacheResponseWOW64->Tickets[*Index].ClientName,
  1543. *Offset,
  1544. Where
  1545. );
  1546. KerbPutWOWString(
  1547. &PrimaryCredentials->DomainName,
  1548. &CacheResponseWOW64->Tickets[*Index].ClientRealm,
  1549. *Offset,
  1550. Where
  1551. );
  1552. KerbPutKdcNameAsWOWString(
  1553. CacheEntry->ServiceName,
  1554. &CacheResponseWOW64->Tickets[*Index].ServerName,
  1555. *Offset,
  1556. Where
  1557. );
  1558. KerbPutWOWString(
  1559. &CacheEntry->DomainName,
  1560. &CacheResponseWOW64->Tickets[*Index].ServerRealm,
  1561. *Offset,
  1562. Where
  1563. );
  1564. }
  1565. #endif // _WIN64
  1566. (*Index)++;
  1567. }
  1568. }
  1569. }
  1570. //+-------------------------------------------------------------------------
  1571. //
  1572. // Function: KerbAddExtraCredential
  1573. //
  1574. // Synopsis: Retrieves the list of tickets for the specified logon session
  1575. //
  1576. // Effects:
  1577. //
  1578. // Arguments: Same as Callpackage
  1579. //
  1580. // Requires:
  1581. //
  1582. // Returns:
  1583. //
  1584. // Notes:
  1585. //
  1586. //
  1587. //--------------------------------------------------------------------------
  1588. NTSTATUS NTAPI
  1589. KerbAddExtraCredential(
  1590. IN PLSA_CLIENT_REQUEST ClientRequest,
  1591. IN PVOID ProtocolSubmitBuffer,
  1592. IN PVOID ClientBufferBase,
  1593. IN ULONG SubmitBufferSize,
  1594. OUT PVOID *ProtocolReturnBuffer,
  1595. OUT PULONG ReturnBufferLength,
  1596. OUT PNTSTATUS ProtocolStatus
  1597. )
  1598. {
  1599. NTSTATUS Status;
  1600. SECPKG_CLIENT_INFO ClientInfo;
  1601. PLUID LogonId;
  1602. PKERB_ADD_CREDENTIALS_REQUEST AddCredRequest = (PKERB_ADD_CREDENTIALS_REQUEST) ProtocolSubmitBuffer;
  1603. PKERB_LOGON_SESSION LogonSession = NULL;
  1604. if (ARGUMENT_PRESENT( ReturnBufferLength ))
  1605. {
  1606. *ReturnBufferLength = 0;
  1607. }
  1608. if (ARGUMENT_PRESENT( ProtocolReturnBuffer ))
  1609. {
  1610. *ProtocolReturnBuffer = NULL;
  1611. }
  1612. if ( SubmitBufferSize < sizeof( KERB_ADD_CREDENTIALS_REQUEST ))
  1613. {
  1614. Status = STATUS_INVALID_PARAMETER;
  1615. goto Cleanup;
  1616. }
  1617. #if _WIN64
  1618. SECPKG_CALL_INFO CallInfo;
  1619. if( !LsaFunctions->GetCallInfo( &CallInfo ))
  1620. {
  1621. Status = STATUS_INTERNAL_ERROR;
  1622. goto Cleanup;
  1623. }
  1624. if (( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) != 0)
  1625. {
  1626. Status = STATUS_NOT_SUPPORTED;
  1627. goto Cleanup;
  1628. }
  1629. #endif // _WIN64
  1630. Status = LsaFunctions->GetClientInfo( &ClientInfo );
  1631. if ( !NT_SUCCESS( Status ))
  1632. {
  1633. goto Cleanup;
  1634. }
  1635. //
  1636. // If the caller did not provide a logon id, use the caller's logon id.
  1637. //
  1638. if ( RtlIsZeroLuid( &AddCredRequest->LogonId ))
  1639. {
  1640. LogonId = &ClientInfo.LogonId;
  1641. }
  1642. else if ( !ClientInfo.HasTcbPrivilege )
  1643. {
  1644. Status = STATUS_PRIVILEGE_NOT_HELD;
  1645. goto Cleanup;
  1646. }
  1647. else
  1648. {
  1649. LogonId = &AddCredRequest->LogonId;
  1650. }
  1651. LogonSession = KerbReferenceLogonSession(
  1652. LogonId,
  1653. FALSE
  1654. );
  1655. if ( LogonSession == NULL )
  1656. {
  1657. Status = STATUS_NO_SUCH_LOGON_SESSION;
  1658. goto Cleanup;
  1659. }
  1660. NULL_RELOCATE_ONE( &AddCredRequest->DomainName );
  1661. NULL_RELOCATE_ONE( &AddCredRequest->Password );
  1662. NULL_RELOCATE_ONE( &AddCredRequest->UserName );
  1663. //
  1664. // We will default nothing for this request.
  1665. //
  1666. if (( AddCredRequest->DomainName.Length == 0 ) ||
  1667. ( AddCredRequest->UserName.Length == 0 ))
  1668. {
  1669. Status = STATUS_INVALID_PARAMETER;
  1670. goto Cleanup;
  1671. }
  1672. if (((AddCredRequest->Flags & (KERB_REQUEST_ADD_CREDENTIAL | KERB_REQUEST_REPLACE_CREDENTIAL )) != 0) &&
  1673. ( AddCredRequest->Password.Length == 0 ))
  1674. {
  1675. Status = STATUS_INVALID_PARAMETER;
  1676. goto Cleanup;
  1677. }
  1678. Status = KerbAddExtraCredentialsToLogonSession(
  1679. LogonSession,
  1680. AddCredRequest
  1681. );
  1682. if (!NT_SUCCESS( Status ))
  1683. {
  1684. D_DebugLog((DEB_ERROR, "KerbAddExtraCredentialToLogonSession failed %x\n", Status));
  1685. goto Cleanup;
  1686. }
  1687. Cleanup:
  1688. if ( LogonSession != NULL )
  1689. {
  1690. KerbDereferenceLogonSession( LogonSession );
  1691. }
  1692. *ProtocolStatus = Status;
  1693. return STATUS_SUCCESS;
  1694. }
  1695. //+-------------------------------------------------------------------------
  1696. //
  1697. // Function: KerbQueryTicketCacheEx
  1698. //
  1699. // Synopsis: Retrieves the list of tickets for the specified logon session
  1700. //
  1701. // Effects:
  1702. //
  1703. // Arguments: Same as Callpackage
  1704. //
  1705. // Requires:
  1706. //
  1707. // Returns:
  1708. //
  1709. // Notes:
  1710. //
  1711. //
  1712. //--------------------------------------------------------------------------
  1713. NTSTATUS NTAPI
  1714. KerbQueryTicketCacheEx(
  1715. IN PLSA_CLIENT_REQUEST ClientRequest,
  1716. IN PVOID ProtocolSubmitBuffer,
  1717. IN PVOID ClientBufferBase,
  1718. IN ULONG SubmitBufferLength,
  1719. OUT PVOID *ProtocolReturnBuffer,
  1720. OUT PULONG ReturnBufferLength,
  1721. OUT PNTSTATUS ProtocolStatus
  1722. )
  1723. {
  1724. NTSTATUS Status;
  1725. PKERB_QUERY_TKT_CACHE_REQUEST CacheRequest = ( PKERB_QUERY_TKT_CACHE_REQUEST )ProtocolSubmitBuffer;
  1726. SECPKG_CLIENT_INFO ClientInfo;
  1727. PLUID LogonId;
  1728. PKERB_LOGON_SESSION LogonSession = NULL;
  1729. PKERB_QUERY_TKT_CACHE_EX_RESPONSE CacheResponse = NULL;
  1730. PKERB_QUERY_TKT_CACHE_EX_RESPONSE ClientCacheResponse = NULL;
  1731. ULONG CacheSize = 0;
  1732. ULONG CacheEntries = 0;
  1733. BOOLEAN TicketCacheLocked = FALSE;
  1734. BOOLEAN CredmanLocked = FALSE;
  1735. PLIST_ENTRY ListEntry;
  1736. LONG_PTR Offset;
  1737. PBYTE Where = NULL;
  1738. ULONG Index = 0;
  1739. //
  1740. // Verify the request.
  1741. //
  1742. if ( SubmitBufferLength < sizeof( KERB_QUERY_TKT_CACHE_REQUEST )) {
  1743. Status = STATUS_INVALID_PARAMETER;
  1744. goto Cleanup;
  1745. }
  1746. //
  1747. // Find the caller's logon id & TCB status
  1748. //
  1749. Status = LsaFunctions->GetClientInfo( &ClientInfo );
  1750. if ( !NT_SUCCESS( Status )) {
  1751. goto Cleanup;
  1752. }
  1753. //
  1754. // If the caller did not provide a logon id, use the caller's logon id.
  1755. //
  1756. if ( RtlIsZeroLuid( &CacheRequest->LogonId )) {
  1757. LogonId = &ClientInfo.LogonId;
  1758. } else if ( !ClientInfo.HasTcbPrivilege ) {
  1759. //
  1760. // Caller must have TCB privilege in order to access to someone
  1761. // else's ticket cache.
  1762. //
  1763. Status = STATUS_PRIVILEGE_NOT_HELD;
  1764. goto Cleanup;
  1765. } else {
  1766. LogonId = &CacheRequest->LogonId;
  1767. }
  1768. LogonSession = KerbReferenceLogonSession(
  1769. LogonId,
  1770. FALSE
  1771. );
  1772. if ( LogonSession == NULL ) {
  1773. Status = STATUS_NO_SUCH_LOGON_SESSION;
  1774. goto Cleanup;
  1775. }
  1776. #if _WIN64
  1777. SECPKG_CALL_INFO CallInfo;
  1778. if( !LsaFunctions->GetCallInfo( &CallInfo )) {
  1779. Status = STATUS_INTERNAL_ERROR;
  1780. goto Cleanup;
  1781. }
  1782. #endif // _WIN64
  1783. //
  1784. // Prowl through the caches and find all the tickets
  1785. //
  1786. DsysAssert( !TicketCacheLocked );
  1787. KerbReadLockLogonSessions( LogonSession );
  1788. KerbLockList( &LogonSession->CredmanCredentials );
  1789. CredmanLocked = TRUE;
  1790. KerbReadLockTicketCache();
  1791. TicketCacheLocked = TRUE;
  1792. //
  1793. // Calculate the size needed for all the ticket information
  1794. //
  1795. KerbComputeTicketCacheSizeEx(
  1796. &LogonSession->PrimaryCredentials,
  1797. #if _WIN64
  1798. (( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) != 0 ),
  1799. #else
  1800. FALSE,
  1801. #endif
  1802. &CacheSize,
  1803. &CacheEntries
  1804. );
  1805. for ( ListEntry = LogonSession->CredmanCredentials.List.Flink;
  1806. ListEntry != &LogonSession->CredmanCredentials.List;
  1807. ListEntry = ListEntry->Flink ) {
  1808. PKERB_CREDMAN_CRED CredmanCred = CONTAINING_RECORD(
  1809. ListEntry,
  1810. KERB_CREDMAN_CRED,
  1811. ListEntry.Next
  1812. );
  1813. if ( CredmanCred->SuppliedCredentials == NULL ) {
  1814. continue;
  1815. }
  1816. KerbComputeTicketCacheSizeEx(
  1817. CredmanCred->SuppliedCredentials,
  1818. #if _WIN64
  1819. (( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) != 0 ),
  1820. #else
  1821. FALSE,
  1822. #endif
  1823. &CacheSize,
  1824. &CacheEntries
  1825. );
  1826. }
  1827. //
  1828. // Now allocate two copies of the structure - one in our process, one in
  1829. // the client's process. We then build the structure in our process but
  1830. // with pointer valid in the client's process.
  1831. //
  1832. SafeAllocaAllocate(CacheResponse, CacheSize);
  1833. if ( CacheResponse == NULL )
  1834. {
  1835. Status = STATUS_INSUFFICIENT_RESOURCES;
  1836. goto Cleanup;
  1837. }
  1838. Status = LsaFunctions->AllocateClientBuffer(
  1839. NULL,
  1840. CacheSize,
  1841. ( PVOID * )&ClientCacheResponse
  1842. );
  1843. if ( !NT_SUCCESS( Status )) {
  1844. goto Cleanup;
  1845. }
  1846. Offset = ( LONG_PTR )(( PBYTE )ClientCacheResponse - ( PBYTE )CacheResponse );
  1847. //
  1848. // Build up the return structure
  1849. //
  1850. CacheResponse->MessageType = KerbQueryTicketCacheExMessage;
  1851. CacheResponse->CountOfTickets = CacheEntries;
  1852. KerbBuildQueryTicketCacheResponseEx(
  1853. &LogonSession->PrimaryCredentials,
  1854. CacheResponse,
  1855. #if _WIN64
  1856. (( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) != 0 ),
  1857. #else
  1858. FALSE,
  1859. #endif
  1860. &Offset,
  1861. &Where,
  1862. &Index
  1863. );
  1864. for ( ListEntry = LogonSession->CredmanCredentials.List.Flink;
  1865. ListEntry != &LogonSession->CredmanCredentials.List;
  1866. ListEntry = ListEntry->Flink ) {
  1867. PKERB_CREDMAN_CRED CredmanCred = CONTAINING_RECORD(
  1868. ListEntry,
  1869. KERB_CREDMAN_CRED,
  1870. ListEntry.Next
  1871. );
  1872. if ( CredmanCred->SuppliedCredentials == NULL ) {
  1873. continue;
  1874. }
  1875. KerbBuildQueryTicketCacheResponseEx(
  1876. CredmanCred->SuppliedCredentials,
  1877. CacheResponse,
  1878. #if _WIN64
  1879. (( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) != 0 ),
  1880. #else
  1881. FALSE,
  1882. #endif
  1883. &Offset,
  1884. &Where,
  1885. &Index
  1886. );
  1887. }
  1888. //
  1889. // Copy the structure to the client's address space
  1890. //
  1891. Status = LsaFunctions->CopyToClientBuffer(
  1892. NULL,
  1893. CacheSize,
  1894. ClientCacheResponse,
  1895. CacheResponse
  1896. );
  1897. if ( !NT_SUCCESS( Status )) {
  1898. goto Cleanup;
  1899. }
  1900. *ProtocolReturnBuffer = ClientCacheResponse;
  1901. ClientCacheResponse = NULL;
  1902. *ReturnBufferLength = CacheSize;
  1903. Cleanup:
  1904. if ( CredmanLocked ) {
  1905. KerbUnlockList( &LogonSession->CredmanCredentials );
  1906. }
  1907. if ( TicketCacheLocked ) {
  1908. KerbUnlockTicketCache();
  1909. KerbUnlockLogonSessions( LogonSession );
  1910. }
  1911. if ( LogonSession != NULL ) {
  1912. KerbDereferenceLogonSession( LogonSession );
  1913. }
  1914. SafeAllocaFree( CacheResponse );
  1915. if ( ClientCacheResponse != NULL ) {
  1916. LsaFunctions->FreeClientBuffer(
  1917. NULL,
  1918. ClientCacheResponse
  1919. );
  1920. }
  1921. *ProtocolStatus = Status;
  1922. return STATUS_SUCCESS;
  1923. }
  1924. //+-------------------------------------------------------------------------
  1925. //
  1926. // Function: KerbPackExternalTicket
  1927. //
  1928. // Synopsis: Marshalls a ticket cache entry for return to the caller
  1929. //
  1930. // Effects: Allocates memory in client's address space
  1931. //
  1932. // Arguments:
  1933. //
  1934. // Requires:
  1935. //
  1936. // Returns:
  1937. //
  1938. // Notes:
  1939. //
  1940. //
  1941. //--------------------------------------------------------------------------
  1942. NTSTATUS
  1943. KerbPackExternalTicket(
  1944. IN PKERB_TICKET_CACHE_ENTRY CacheEntry,
  1945. IN BOOL RetrieveTicketAsKerbCred,
  1946. IN BOOL AllowTgtSessionKey,
  1947. OUT PULONG ClientTicketSize,
  1948. OUT PUCHAR * ClientTicket
  1949. )
  1950. {
  1951. ULONG TicketSize = 0;
  1952. NTSTATUS Status = STATUS_SUCCESS;
  1953. PKERB_EXTERNAL_TICKET TicketResponse = NULL;
  1954. PBYTE ClientTicketResponse = NULL;
  1955. KERB_MESSAGE_BUFFER EncodedTicket = {0};
  1956. LONG_PTR Offset;
  1957. PBYTE Where;
  1958. BOOL fTicketOnStack = FALSE;
  1959. KERB_TICKET_CACHE_ENTRY CacheEntryT;
  1960. *ClientTicket = NULL;
  1961. *ClientTicketSize = 0;
  1962. #if _WIN64
  1963. SECPKG_CALL_INFO CallInfo;
  1964. //
  1965. // Return a 32-bit external ticket if this is a WOW caller
  1966. //
  1967. if(!LsaFunctions->GetCallInfo(&CallInfo))
  1968. {
  1969. Status = STATUS_INTERNAL_ERROR;
  1970. goto Cleanup;
  1971. }
  1972. #endif // _WIN64
  1973. //
  1974. // 448010: do not fess up the session key for primary TGTs unless
  1975. // the caller is trusted or policy is set appropriately
  1976. //
  1977. if ( !AllowTgtSessionKey &&
  1978. ( CacheEntry->CacheFlags & KERB_TICKET_CACHE_PRIMARY_TGT )) {
  1979. CacheEntryT = *CacheEntry;
  1980. RtlZeroMemory( &CacheEntryT.SessionKey, sizeof( KERB_ENCRYPTION_KEY ));
  1981. CacheEntry = &CacheEntryT;
  1982. }
  1983. //
  1984. // Encode the ticket
  1985. //
  1986. if ( RetrieveTicketAsKerbCred )
  1987. {
  1988. Status = KerbBuildKerbCred(
  1989. NULL, // service ticket
  1990. CacheEntry,
  1991. &EncodedTicket.Buffer,
  1992. &EncodedTicket.BufferSize
  1993. );
  1994. if ( !NT_SUCCESS( Status ))
  1995. {
  1996. goto Cleanup;
  1997. }
  1998. }
  1999. else
  2000. {
  2001. KERBERR KerbErr;
  2002. KerbErr = KerbPackData(
  2003. &CacheEntry->Ticket,
  2004. KERB_TICKET_PDU,
  2005. &EncodedTicket.BufferSize,
  2006. &EncodedTicket.Buffer
  2007. );
  2008. if (!KERB_SUCCESS(KerbErr))
  2009. {
  2010. Status = KerbMapKerbError(KerbErr);
  2011. goto Cleanup;
  2012. }
  2013. }
  2014. //
  2015. // NOTE: The 64-bit code below is (effectively) duplicated in
  2016. // the WOW helper routine. If modifying one, make sure
  2017. // to apply the change(s) to the other as well.
  2018. //
  2019. #if _WIN64
  2020. if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
  2021. {
  2022. Status = KerbPackExternalWOWTicket(CacheEntry,
  2023. &EncodedTicket,
  2024. &TicketResponse,
  2025. &ClientTicketResponse,
  2026. &TicketSize);
  2027. if (!NT_SUCCESS(Status))
  2028. {
  2029. goto Cleanup;
  2030. }
  2031. }
  2032. else
  2033. {
  2034. #endif // _WIN64
  2035. TicketSize = sizeof(KERB_EXTERNAL_TICKET) +
  2036. CacheEntry->DomainName.Length +
  2037. CacheEntry->TargetDomainName.Length +
  2038. CacheEntry->ClientDomainName.Length +
  2039. CacheEntry->SessionKey.keyvalue.length +
  2040. KerbNameLength(CacheEntry->ServiceName) +
  2041. KerbNameLength(CacheEntry->TargetName) +
  2042. KerbNameLength(CacheEntry->ClientName) +
  2043. EncodedTicket.BufferSize
  2044. ;
  2045. //
  2046. // Now allocate two copies of the structure - one in our process,
  2047. // one in the client's process. We then build the structure in our
  2048. // process but with pointer valid in the client's process
  2049. //
  2050. SafeAllocaAllocate(TicketResponse, TicketSize);
  2051. fTicketOnStack = TRUE;
  2052. if (TicketResponse == NULL)
  2053. {
  2054. Status = STATUS_INSUFFICIENT_RESOURCES;
  2055. goto Cleanup;
  2056. }
  2057. Status = LsaFunctions->AllocateClientBuffer(
  2058. NULL,
  2059. TicketSize,
  2060. (PVOID *) &ClientTicketResponse
  2061. );
  2062. if (!NT_SUCCESS(Status))
  2063. {
  2064. goto Cleanup;
  2065. }
  2066. Offset = (LONG_PTR) (ClientTicketResponse - (PBYTE) TicketResponse);
  2067. Where = ((PUCHAR) (TicketResponse + 1));
  2068. //
  2069. // Copy the non-pointer fields
  2070. //
  2071. TicketResponse->TicketFlags = CacheEntry->TicketFlags;
  2072. TicketResponse->Flags = 0;
  2073. TicketResponse->KeyExpirationTime.QuadPart = 0;
  2074. TicketResponse->StartTime = CacheEntry->StartTime;
  2075. TicketResponse->EndTime = CacheEntry->EndTime;
  2076. TicketResponse->RenewUntil = CacheEntry->RenewUntil;
  2077. TicketResponse->TimeSkew = CacheEntry->TimeSkew;
  2078. TicketResponse->SessionKey.KeyType = CacheEntry->SessionKey.keytype;
  2079. //
  2080. // Copy the structure to the client's address space
  2081. //
  2082. //
  2083. // These are PVOID aligned
  2084. //
  2085. //
  2086. // Make sure the two name types are the same
  2087. //
  2088. DsysAssert(sizeof(KERB_INTERNAL_NAME) == sizeof(KERB_EXTERNAL_NAME));
  2089. DsysAssert(FIELD_OFFSET(KERB_INTERNAL_NAME,NameType) == FIELD_OFFSET(KERB_EXTERNAL_NAME,NameType));
  2090. DsysAssert(FIELD_OFFSET(KERB_INTERNAL_NAME,NameCount) == FIELD_OFFSET(KERB_EXTERNAL_NAME,NameCount));
  2091. DsysAssert(FIELD_OFFSET(KERB_INTERNAL_NAME,Names) == FIELD_OFFSET(KERB_EXTERNAL_NAME,Names));
  2092. KerbPutKdcName(
  2093. CacheEntry->ServiceName,
  2094. &TicketResponse->ServiceName,
  2095. Offset,
  2096. &Where
  2097. );
  2098. KerbPutKdcName(
  2099. CacheEntry->TargetName,
  2100. &TicketResponse->TargetName,
  2101. Offset,
  2102. &Where
  2103. );
  2104. KerbPutKdcName(
  2105. CacheEntry->ClientName,
  2106. &TicketResponse->ClientName,
  2107. Offset,
  2108. &Where
  2109. );
  2110. //
  2111. // From here on, they are WCHAR aligned
  2112. //
  2113. KerbPutString(
  2114. &CacheEntry->DomainName,
  2115. &TicketResponse->DomainName,
  2116. Offset,
  2117. &Where
  2118. );
  2119. KerbPutString(
  2120. &CacheEntry->TargetDomainName,
  2121. &TicketResponse->TargetDomainName,
  2122. Offset,
  2123. &Where
  2124. );
  2125. KerbPutString(
  2126. &CacheEntry->ClientDomainName,
  2127. &TicketResponse->AltTargetDomainName, // ClientDomainName
  2128. Offset,
  2129. &Where
  2130. );
  2131. //
  2132. // And from here they are BYTE aligned
  2133. //
  2134. TicketResponse->SessionKey.Value = (PBYTE) (Where + Offset);
  2135. RtlCopyMemory(
  2136. Where,
  2137. CacheEntry->SessionKey.keyvalue.value,
  2138. CacheEntry->SessionKey.keyvalue.length
  2139. );
  2140. Where += CacheEntry->SessionKey.keyvalue.length;
  2141. TicketResponse->SessionKey.Length = CacheEntry->SessionKey.keyvalue.length;
  2142. TicketResponse->EncodedTicketSize = EncodedTicket.BufferSize;
  2143. TicketResponse->EncodedTicket = Where + Offset;
  2144. RtlCopyMemory(
  2145. Where,
  2146. EncodedTicket.Buffer,
  2147. EncodedTicket.BufferSize
  2148. );
  2149. Where += EncodedTicket.BufferSize;
  2150. DsysAssert(Where - ((PUCHAR) TicketResponse) == (LONG_PTR) TicketSize);
  2151. #if _WIN64
  2152. }
  2153. #endif // _WIN64
  2154. //
  2155. // Copy the mess to the client
  2156. //
  2157. Status = LsaFunctions->CopyToClientBuffer(
  2158. NULL,
  2159. TicketSize,
  2160. ClientTicketResponse,
  2161. TicketResponse
  2162. );
  2163. if (!NT_SUCCESS(Status))
  2164. {
  2165. goto Cleanup;
  2166. }
  2167. *ClientTicket = ClientTicketResponse;
  2168. *ClientTicketSize = TicketSize;
  2169. ClientTicketResponse = NULL;
  2170. Cleanup:
  2171. if (EncodedTicket.Buffer != NULL)
  2172. {
  2173. MIDL_user_free(EncodedTicket.Buffer);
  2174. }
  2175. if (ClientTicketResponse != NULL)
  2176. {
  2177. LsaFunctions->FreeClientBuffer(
  2178. NULL,
  2179. ClientTicketResponse
  2180. );
  2181. }
  2182. if (fTicketOnStack)
  2183. {
  2184. SafeAllocaFree(TicketResponse);
  2185. }
  2186. else
  2187. {
  2188. KerbFree(TicketResponse);
  2189. }
  2190. return(Status);
  2191. }
  2192. KERBERR
  2193. KerbBuildFullServiceName(
  2194. IN OPTIONAL PUNICODE_STRING pDomainName,
  2195. IN PUNICODE_STRING pServiceName,
  2196. IN ULONG NameType,
  2197. OUT PKERB_INTERNAL_NAME* ppFullServiceName
  2198. )
  2199. {
  2200. PKERB_INTERNAL_NAME pFinalName = NULL;
  2201. PUCHAR pWhere;
  2202. ULONG NameParts;
  2203. ULONG NameLength = 0;
  2204. if ((NameType == KRB_NT_MS_PRINCIPAL) ||
  2205. (NameType == KRB_NT_MS_PRINCIPAL_AND_ID))
  2206. {
  2207. NameParts = 1;
  2208. NameLength = (pDomainName ? pDomainName->Length : 0) + pServiceName->Length + 2 * sizeof(WCHAR);
  2209. }
  2210. else if ((NameType == KRB_NT_PRINCIPAL) ||
  2211. (NameType == KRB_NT_PRINCIPAL_AND_ID) ||
  2212. (NameType == KRB_NT_ENTERPRISE_PRINCIPAL) ||
  2213. (NameType == KRB_NT_ENT_PRINCIPAL_AND_ID))
  2214. {
  2215. NameParts = 1;
  2216. NameLength = pServiceName->Length + sizeof(WCHAR);
  2217. }
  2218. else
  2219. {
  2220. NameParts = pDomainName && pDomainName->Length ? 2 : 1;
  2221. NameLength = (pDomainName ? pDomainName->Length : 0) + pServiceName->Length + 2 * sizeof(WCHAR);
  2222. }
  2223. *ppFullServiceName = NULL;
  2224. pFinalName = (PKERB_INTERNAL_NAME) MIDL_user_allocate(KERB_INTERNAL_NAME_SIZE(NameParts) + NameLength);
  2225. if (pFinalName == NULL)
  2226. {
  2227. return(KRB_ERR_GENERIC);
  2228. }
  2229. RtlZeroMemory(
  2230. pFinalName,
  2231. KERB_INTERNAL_NAME_SIZE(NameParts) + NameLength
  2232. );
  2233. pWhere = (PUCHAR) pFinalName + KERB_INTERNAL_NAME_SIZE(NameParts);
  2234. pFinalName->NameType = (USHORT) NameType;
  2235. pFinalName->NameCount = (USHORT) NameParts;
  2236. if ((NameType == KRB_NT_MS_PRINCIPAL) ||
  2237. (NameType == KRB_NT_MS_PRINCIPAL_AND_ID))
  2238. {
  2239. //
  2240. // If the domain name does not have an initial '\', reserve space for one
  2241. //
  2242. pFinalName->Names[0].Buffer = (PWSTR) pWhere;
  2243. // This is dependent on our naming conventions.
  2244. //
  2245. // The full service name is the '\' domain name ':' service name.
  2246. //
  2247. pFinalName->Names[0].Length = (USHORT) ((pDomainName ? pDomainName->Length : 0) +
  2248. pServiceName->Length +
  2249. sizeof(WCHAR));
  2250. pFinalName->Names[0].MaximumLength =
  2251. pFinalName->Names[0].Length + sizeof(WCHAR);
  2252. if (pDomainName && pDomainName->Length)
  2253. {
  2254. RtlCopyMemory(
  2255. pFinalName->Names[0].Buffer,
  2256. pDomainName->Buffer,
  2257. pDomainName->Length
  2258. );
  2259. pWhere += pDomainName->Length;
  2260. }
  2261. if (pDomainName && (pDomainName->Length != 0) && (pServiceName->Length != 0))
  2262. {
  2263. *(PWSTR) pWhere = L'\\';
  2264. pWhere += sizeof(WCHAR);
  2265. }
  2266. RtlCopyMemory(
  2267. pWhere,
  2268. pServiceName->Buffer,
  2269. pServiceName->Length
  2270. );
  2271. pWhere += pServiceName->Length;
  2272. pFinalName->Names[0].Length = (USHORT)(pWhere - (PUCHAR) pFinalName->Names[0].Buffer);
  2273. *(LPWSTR) pWhere = L'\0';
  2274. }
  2275. else if ((NameType == KRB_NT_PRINCIPAL) ||
  2276. (NameType == KRB_NT_PRINCIPAL_AND_ID) ||
  2277. (NameType == KRB_NT_ENTERPRISE_PRINCIPAL)||
  2278. (NameType == KRB_NT_ENT_PRINCIPAL_AND_ID))
  2279. {
  2280. //
  2281. // Principals have no domain name
  2282. //
  2283. pFinalName->Names[0].Length = pServiceName->Length;
  2284. pFinalName->Names[0].MaximumLength = pServiceName->Length + sizeof(WCHAR);
  2285. pFinalName->Names[0].Buffer = (PWSTR) pWhere;
  2286. RtlCopyMemory(
  2287. pWhere,
  2288. pServiceName->Buffer,
  2289. pServiceName->Length
  2290. );
  2291. pWhere += pServiceName->Length;
  2292. *((LPWSTR) pWhere) = L'\0';
  2293. }
  2294. else
  2295. {
  2296. pFinalName->Names[0].Length = pServiceName->Length;
  2297. pFinalName->Names[0].MaximumLength = pServiceName->Length + sizeof(WCHAR);
  2298. pFinalName->Names[0].Buffer = (PWSTR) pWhere;
  2299. RtlCopyMemory(
  2300. pWhere,
  2301. pServiceName->Buffer,
  2302. pServiceName->Length
  2303. );
  2304. pWhere += pServiceName->Length;
  2305. *((PWSTR) pWhere) = L'\0';
  2306. pWhere += sizeof(WCHAR);
  2307. if (pDomainName && pDomainName->Length)
  2308. {
  2309. pFinalName->Names[1].Length = pDomainName->Length;
  2310. pFinalName->Names[1].MaximumLength = pDomainName->Length + sizeof(WCHAR);
  2311. pFinalName->Names[1].Buffer = (PWSTR) pWhere;
  2312. RtlCopyMemory(
  2313. pWhere,
  2314. pDomainName->Buffer,
  2315. pDomainName->Length
  2316. );
  2317. pWhere += pDomainName->Length;
  2318. *((PWSTR) pWhere) = L'\0';
  2319. pWhere += sizeof(WCHAR);
  2320. }
  2321. }
  2322. *ppFullServiceName = pFinalName;
  2323. return (KDC_ERR_NONE);
  2324. }
  2325. //+-------------------------------------------------------------------------
  2326. //
  2327. // Function: KerbTicketAsRequest
  2328. //
  2329. // Synopsis: Retrieves ticket via As Request
  2330. //
  2331. // Effects:
  2332. //
  2333. // Arguments: Same as Callpackage
  2334. //
  2335. // Requires:
  2336. //
  2337. // Returns:
  2338. //
  2339. // Notes:
  2340. //
  2341. //
  2342. //--------------------------------------------------------------------------
  2343. NTSTATUS NTAPI
  2344. KerbTicketAsRequest(
  2345. IN PLSA_CLIENT_REQUEST ClientRequest,
  2346. IN PVOID ProtocolSubmitBuffer,
  2347. IN PVOID ClientBufferBase,
  2348. IN ULONG SubmitBufferSize,
  2349. OUT PVOID *ProtocolReturnBuffer,
  2350. OUT PULONG ReturnBufferLength,
  2351. OUT PNTSTATUS ProtocolStatus
  2352. )
  2353. {
  2354. NTSTATUS Status;
  2355. KERBERR KerbErr;
  2356. KERB_TICKET_AS_REQUEST* pAsRequest = NULL;
  2357. PBYTE pClientTicketResponse = NULL;
  2358. ULONG TicketSize = 0;
  2359. PKERB_LOGON_SESSION pLogonSession = NULL;
  2360. LUID LogonId = {0};
  2361. PKERB_TICKET_CACHE_ENTRY pTicketCacheEntry = NULL;
  2362. KERB_ENCRYPTION_KEY CredentialKey = {0};
  2363. PKERB_INTERNAL_NAME KdcServiceName = NULL;
  2364. PKERB_INTERNAL_NAME ClientName = NULL;
  2365. UNICODE_STRING ClientRealm = {0};
  2366. UNICODE_STRING CorrectRealm = {0};
  2367. ULONG RetryCount = KERB_CLIENT_REFERRAL_MAX;
  2368. PKERB_MIT_REALM MitRealm = NULL;
  2369. ULONG RequestFlags = 0;
  2370. BOOLEAN UsingSuppliedCreds = FALSE;
  2371. BOOLEAN UseWkstaRealm = TRUE;
  2372. BOOLEAN MitRealmLogon = FALSE;
  2373. BOOLEAN UsedPrimaryLogonCreds = FALSE;
  2374. pAsRequest = (KERB_TICKET_AS_REQUEST*) ProtocolSubmitBuffer;
  2375. //
  2376. // Verify the request
  2377. //
  2378. if ( !pAsRequest || (SubmitBufferSize < sizeof(KERB_TICKET_AS_REQUEST)) )
  2379. {
  2380. D_DebugLog((DEB_ERROR, "KerbTicketAsRequest %p %d\n", pAsRequest, SubmitBufferSize));
  2381. Status = STATUS_INVALID_PARAMETER;
  2382. goto Cleanup;
  2383. }
  2384. NULL_RELOCATE_ONE(&pAsRequest->ClientName);
  2385. NULL_RELOCATE_ONE(&pAsRequest->ClientRealm);
  2386. NULL_RELOCATE_ONE(&pAsRequest->ServerName);
  2387. NULL_RELOCATE_ONE(&pAsRequest->ServerRealm);
  2388. NULL_RELOCATE_ONE(&pAsRequest->ClientPassword);
  2389. D_DebugLog((DEB_WARN, "ClientRealm (%wZ), ClientName (%wZ), ClientPassword (%wZ), ServerRealm (%wZ), ServerName (%wZ)\n",
  2390. &pAsRequest->ClientRealm,
  2391. &pAsRequest->ClientName,
  2392. &pAsRequest->ClientPassword,
  2393. &pAsRequest->ServerRealm,
  2394. &pAsRequest->ServerName));
  2395. Status = NtAllocateLocallyUniqueId( &LogonId );
  2396. if (NT_SUCCESS(Status))
  2397. {
  2398. Status = KerbCreateLogonSession(
  2399. &LogonId,
  2400. &pAsRequest->ClientName,
  2401. &pAsRequest->ClientRealm,
  2402. &pAsRequest->ClientPassword,
  2403. NULL, // no old password
  2404. PRIMARY_CRED_CLEAR_PASSWORD,
  2405. KERB_LOGON_DUMMY_SESSION,
  2406. &pLogonSession
  2407. );
  2408. }
  2409. //
  2410. // Parse the name
  2411. //
  2412. if (NT_SUCCESS(Status))
  2413. {
  2414. Status = KerbGetClientNameAndRealm(
  2415. &pLogonSession->LogonId,
  2416. &pLogonSession->PrimaryCredentials,
  2417. NULL,
  2418. &MitRealmLogon,
  2419. UseWkstaRealm,
  2420. &ClientName,
  2421. &ClientRealm
  2422. );
  2423. }
  2424. if (!NT_SUCCESS(Status))
  2425. {
  2426. goto Cleanup;
  2427. }
  2428. //
  2429. // if we're doing a MIT logon, add the MIT logon flag
  2430. //
  2431. if (MitRealmLogon && UsedPrimaryLogonCreds)
  2432. {
  2433. pLogonSession->LogonSessionFlags |= KERB_LOGON_MIT_REALM;
  2434. }
  2435. TicketAsRequestRestart:
  2436. D_DebugLog((DEB_TRACE, "KerbTicketAsRequest GetTicketRestart ClientRealm %wZ\n", &ClientRealm));
  2437. KerbErr = KerbBuildFullServiceName(
  2438. &pAsRequest->ServerRealm,
  2439. &pAsRequest->ServerName,
  2440. pAsRequest->NameType,
  2441. &KdcServiceName
  2442. );
  2443. if (!KERB_SUCCESS(KerbErr))
  2444. {
  2445. Status = STATUS_INSUFFICIENT_RESOURCES;
  2446. goto Cleanup;
  2447. }
  2448. D_DebugLog((DEB_TRACE, "KdcServiceName is "));
  2449. D_KerbPrintKdcName((DEB_TRACE, KdcServiceName));
  2450. Status = KerbGetAuthenticationTicket(
  2451. pLogonSession,
  2452. NULL, // no supplied cred
  2453. NULL, // no credman cred
  2454. KdcServiceName,
  2455. &ClientRealm,
  2456. ClientName,
  2457. RequestFlags,
  2458. KERB_TICKET_CACHE_PRIMARY_TGT,
  2459. &pTicketCacheEntry,
  2460. &CredentialKey,
  2461. &CorrectRealm
  2462. );
  2463. //
  2464. // If it failed but gave us another realm to try, go there
  2465. //
  2466. if (!NT_SUCCESS(Status) && (CorrectRealm.Length != 0))
  2467. {
  2468. if (--RetryCount != 0)
  2469. {
  2470. KerbFreeKdcName(&KdcServiceName);
  2471. KerbFreeString(&ClientRealm);
  2472. ClientRealm = CorrectRealm;
  2473. CorrectRealm.Buffer = NULL;
  2474. //
  2475. // Might be an MIT realm, in which case we'll need to adjust
  2476. // the client name. This will also populate the realm list
  2477. // with appropriate entries, so the KerbGetKdcBinding will not
  2478. // hit DNS again.
  2479. //
  2480. if (KerbLookupMitRealmWithSrvLookup(
  2481. &ClientRealm,
  2482. &MitRealm,
  2483. FALSE,
  2484. FALSE
  2485. ))
  2486. {
  2487. D_DebugLog((DEB_TRACE,"Reacquiring client name & realm after referral\n"));
  2488. UseWkstaRealm = FALSE;
  2489. KerbFreeKdcName(&ClientName);
  2490. Status = KerbGetClientNameAndRealm(
  2491. &LogonId,
  2492. &pLogonSession->PrimaryCredentials,
  2493. NULL,
  2494. NULL,
  2495. UseWkstaRealm,
  2496. &ClientName,
  2497. &ClientRealm
  2498. );
  2499. if (!NT_SUCCESS(Status))
  2500. {
  2501. goto Cleanup;
  2502. }
  2503. }
  2504. goto TicketAsRequestRestart;
  2505. }
  2506. else
  2507. {
  2508. // Tbd: Log error here? Max referrals reached..
  2509. goto Cleanup;
  2510. }
  2511. }
  2512. else if ((Status == STATUS_NO_SUCH_USER) && UsingSuppliedCreds && UseWkstaRealm)
  2513. {
  2514. //
  2515. // We tried using the realm of the workstation and the account couldn't
  2516. // be found - try the realm from the UPN now.
  2517. //
  2518. if (KerbIsThisOurDomain(&ClientRealm))
  2519. {
  2520. UseWkstaRealm = FALSE;
  2521. KerbFreeKdcName(&ClientName);
  2522. KerbFreeString(&ClientRealm);
  2523. //
  2524. // Only do this if the caller did not supply a
  2525. // domain name
  2526. //
  2527. if (pLogonSession->PrimaryCredentials.DomainName.Length == 0)
  2528. {
  2529. Status = KerbGetClientNameAndRealm(
  2530. &LogonId,
  2531. &pLogonSession->PrimaryCredentials,
  2532. NULL,
  2533. NULL,
  2534. UseWkstaRealm,
  2535. &ClientName,
  2536. &ClientRealm
  2537. );
  2538. }
  2539. if (!NT_SUCCESS(Status))
  2540. {
  2541. goto Cleanup;
  2542. }
  2543. goto TicketAsRequestRestart;
  2544. }
  2545. }
  2546. if (pTicketCacheEntry == NULL)
  2547. {
  2548. Status = SEC_E_NO_CREDENTIALS;
  2549. goto Cleanup;
  2550. }
  2551. Status = KerbPackExternalTicket(
  2552. pTicketCacheEntry,
  2553. FALSE,
  2554. TRUE,
  2555. &TicketSize,
  2556. &pClientTicketResponse
  2557. );
  2558. if (!NT_SUCCESS(Status))
  2559. {
  2560. goto Cleanup;
  2561. }
  2562. *ProtocolReturnBuffer = pClientTicketResponse;
  2563. pClientTicketResponse = NULL;
  2564. *ReturnBufferLength = TicketSize;
  2565. Cleanup:
  2566. if (pTicketCacheEntry)
  2567. {
  2568. KerbDereferenceTicketCacheEntry(pTicketCacheEntry);
  2569. }
  2570. if (pLogonSession)
  2571. {
  2572. KerbDereferenceLogonSession(pLogonSession);
  2573. }
  2574. if (pClientTicketResponse)
  2575. {
  2576. LsaFunctions->FreeClientBuffer(
  2577. NULL,
  2578. pClientTicketResponse
  2579. );
  2580. }
  2581. KerbFreeKey(&CredentialKey);
  2582. KerbFreeKdcName(&ClientName);
  2583. KerbFreeString(&ClientRealm);
  2584. KerbFreeString(&CorrectRealm);
  2585. KerbFreeKdcName(&KdcServiceName);
  2586. *ProtocolStatus = Status;
  2587. return (STATUS_SUCCESS);
  2588. }
  2589. NTSTATUS NTAPI
  2590. KerbTicketAsRequestSafe(
  2591. IN PLSA_CLIENT_REQUEST ClientRequest,
  2592. IN PVOID ProtocolSubmitBuffer,
  2593. IN PVOID ClientBufferBase,
  2594. IN ULONG SubmitBufferLength,
  2595. OUT PVOID *ProtocolReturnBuffer,
  2596. OUT PULONG ReturnBufferLength,
  2597. OUT PNTSTATUS ProtocolStatus
  2598. )
  2599. {
  2600. NTSTATUS Status;
  2601. __try
  2602. {
  2603. Status = KerbTicketAsRequest(
  2604. ClientRequest,
  2605. ProtocolSubmitBuffer,
  2606. ClientBufferBase,
  2607. SubmitBufferLength,
  2608. ProtocolReturnBuffer,
  2609. ReturnBufferLength,
  2610. ProtocolStatus
  2611. );
  2612. }
  2613. __except (EXCEPTION_EXECUTE_HANDLER)
  2614. {
  2615. Status = GetExceptionCode();
  2616. D_DebugLog((DEB_ERROR, "KerbTicketAsRequest encountered an exception %#x\n", Status));
  2617. }
  2618. return Status;
  2619. }
  2620. //+-------------------------------------------------------------------------
  2621. //
  2622. // Function: KerbRetrieveTicket
  2623. //
  2624. // Synopsis: Retrieves the initial ticket cache entry.
  2625. //
  2626. // Effects:
  2627. //
  2628. // Arguments: Same as Callpackage
  2629. //
  2630. // Requires:
  2631. //
  2632. // Returns:
  2633. //
  2634. // Notes:
  2635. //
  2636. //
  2637. //--------------------------------------------------------------------------
  2638. NTSTATUS NTAPI
  2639. KerbRetrieveTicket(
  2640. IN PLSA_CLIENT_REQUEST ClientRequest,
  2641. IN PVOID ProtocolSubmitBuffer,
  2642. IN PVOID ClientBufferBase,
  2643. IN ULONG SubmitBufferLength,
  2644. OUT PVOID *ProtocolReturnBuffer,
  2645. OUT PULONG ReturnBufferLength,
  2646. OUT PNTSTATUS ProtocolStatus
  2647. )
  2648. {
  2649. NTSTATUS Status;
  2650. SECPKG_CLIENT_INFO ClientInfo;
  2651. PLUID LogonId;
  2652. PKERB_LOGON_SESSION LogonSession = NULL;
  2653. PKERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
  2654. PBYTE ClientTicketResponse = NULL;
  2655. PKERB_TICKET_CACHE_ENTRY CacheEntry = NULL;
  2656. ULONG TicketSize = 0;
  2657. //
  2658. // Verify the request.
  2659. //
  2660. if (SubmitBufferLength < sizeof(KERB_QUERY_TKT_CACHE_REQUEST))
  2661. {
  2662. Status = STATUS_INVALID_PARAMETER;
  2663. goto Cleanup;
  2664. }
  2665. CacheRequest = (PKERB_QUERY_TKT_CACHE_REQUEST) ProtocolSubmitBuffer;
  2666. //
  2667. // Find the callers logon id & TCB status
  2668. //
  2669. Status = LsaFunctions->GetClientInfo(&ClientInfo);
  2670. if (!NT_SUCCESS(Status))
  2671. {
  2672. goto Cleanup;
  2673. }
  2674. //
  2675. // If the caller did not provide a logon id, use the caller's logon id.
  2676. //
  2677. if ( RtlIsZeroLuid( &CacheRequest->LogonId ) )
  2678. {
  2679. LogonId = &ClientInfo.LogonId;
  2680. }
  2681. else
  2682. {
  2683. //
  2684. // Verify the caller has TCB privilege if they want access to someone
  2685. // elses ticket cache.
  2686. //
  2687. if (!ClientInfo.HasTcbPrivilege)
  2688. {
  2689. Status = STATUS_PRIVILEGE_NOT_HELD;
  2690. goto Cleanup;
  2691. }
  2692. LogonId = &CacheRequest->LogonId;
  2693. }
  2694. LogonSession = KerbReferenceLogonSession(
  2695. LogonId,
  2696. FALSE // don't unlink
  2697. );
  2698. if (LogonSession == NULL)
  2699. {
  2700. Status = STATUS_NO_SUCH_LOGON_SESSION;
  2701. goto Cleanup;
  2702. }
  2703. //
  2704. // Now find the TGT from the authentication ticket cache.
  2705. //
  2706. KerbReadLockLogonSessions(LogonSession);
  2707. CacheEntry = KerbLocateTicketCacheEntryByRealm(
  2708. &LogonSession->PrimaryCredentials.AuthenticationTicketCache,
  2709. NULL, // get initial ticket
  2710. KERB_TICKET_CACHE_PRIMARY_TGT
  2711. );
  2712. KerbUnlockLogonSessions(LogonSession);
  2713. if (CacheEntry == NULL)
  2714. {
  2715. Status = SEC_E_NO_CREDENTIALS;
  2716. goto Cleanup;
  2717. }
  2718. KerbReadLockTicketCache();
  2719. Status = KerbPackExternalTicket(
  2720. CacheEntry,
  2721. FALSE,
  2722. ( ClientInfo.HasTcbPrivilege || KerbGlobalAllowTgtSessionKey ),
  2723. &TicketSize,
  2724. &ClientTicketResponse
  2725. );
  2726. KerbUnlockTicketCache();
  2727. if (!NT_SUCCESS(Status))
  2728. {
  2729. goto Cleanup;
  2730. }
  2731. *ProtocolReturnBuffer = ClientTicketResponse;
  2732. ClientTicketResponse = NULL;
  2733. *ReturnBufferLength = TicketSize;
  2734. Cleanup:
  2735. if (LogonSession != NULL)
  2736. {
  2737. KerbDereferenceLogonSession(LogonSession);
  2738. }
  2739. if (CacheEntry != NULL)
  2740. {
  2741. KerbDereferenceTicketCacheEntry(CacheEntry);
  2742. }
  2743. if (ClientTicketResponse != NULL)
  2744. {
  2745. LsaFunctions->FreeClientBuffer(
  2746. NULL,
  2747. ClientTicketResponse
  2748. );
  2749. }
  2750. *ProtocolStatus = Status;
  2751. return(STATUS_SUCCESS);
  2752. }
  2753. //+-------------------------------------------------------------------------
  2754. //
  2755. // Function: KerbSetIpAddresses
  2756. //
  2757. // Synopsis: Saves the IP addresses passed in by netlogon
  2758. //
  2759. // Effects:
  2760. //
  2761. // Arguments: Same as Callpackage
  2762. //
  2763. // Requires:
  2764. //
  2765. // Returns:
  2766. //
  2767. // Notes:
  2768. //
  2769. //
  2770. //--------------------------------------------------------------------------
  2771. NTSTATUS NTAPI
  2772. KerbSetIpAddresses(
  2773. IN PLSA_CLIENT_REQUEST ClientRequest,
  2774. IN PVOID ProtocolSubmitBuffer,
  2775. IN PVOID ClientBufferBase,
  2776. IN ULONG SubmitBufferLength,
  2777. OUT PVOID *ProtocolReturnBuffer,
  2778. OUT PULONG ReturnBufferLength,
  2779. OUT PNTSTATUS ProtocolStatus
  2780. )
  2781. {
  2782. NTSTATUS Status;
  2783. PKERB_UPDATE_ADDRESSES_REQUEST UpdateRequest;
  2784. //
  2785. // This can only be called internally.
  2786. //
  2787. if (ClientRequest != NULL)
  2788. {
  2789. DebugLog((DEB_ERROR,"Can't update addresses from outside process. %ws, line %d\n", THIS_FILE, __LINE__));
  2790. Status = STATUS_ACCESS_DENIED;
  2791. goto Cleanup;
  2792. }
  2793. //
  2794. // Verify the request.
  2795. //
  2796. if (SubmitBufferLength < FIELD_OFFSET(KERB_UPDATE_ADDRESSES_REQUEST, Addresses))
  2797. {
  2798. Status = STATUS_INVALID_PARAMETER;
  2799. goto Cleanup;
  2800. }
  2801. UpdateRequest = (PKERB_UPDATE_ADDRESSES_REQUEST) ProtocolSubmitBuffer;
  2802. //
  2803. // Validate the input
  2804. //
  2805. if (SubmitBufferLength < (sizeof(KERB_UPDATE_ADDRESSES_REQUEST)
  2806. + UpdateRequest->AddressCount * (sizeof(SOCKET_ADDRESS) + sizeof(struct sockaddr_in))
  2807. - ANYSIZE_ARRAY * sizeof(ULONG)))
  2808. {
  2809. Status = STATUS_INVALID_PARAMETER;
  2810. goto Cleanup;
  2811. }
  2812. Status= KerbUpdateGlobalAddresses(
  2813. (PSOCKET_ADDRESS) UpdateRequest->Addresses,
  2814. UpdateRequest->AddressCount
  2815. );
  2816. //
  2817. // Copy them into the global for others to use
  2818. //
  2819. Cleanup:
  2820. *ProtocolStatus = Status;
  2821. return(STATUS_SUCCESS);
  2822. }
  2823. //+-------------------------------------------------------------------------
  2824. //
  2825. // Function: KerbVerifyPac
  2826. //
  2827. // Synopsis: Verifies that a PAC was signed by a valid KDC
  2828. //
  2829. // Effects:
  2830. //
  2831. // Arguments: Same as for LsaApCallAuthenticationPackage. The submit
  2832. // buffer must contain a KERB_VERIFY_PAC_REQUEST message.
  2833. //
  2834. // Requires:
  2835. //
  2836. // Returns: STATUS_SUCCESS. The real error is in the protocol status.
  2837. //
  2838. // Notes:
  2839. //
  2840. //
  2841. //--------------------------------------------------------------------------
  2842. NTSTATUS NTAPI
  2843. KerbVerifyPac(
  2844. IN PLSA_CLIENT_REQUEST ClientRequest,
  2845. IN PVOID ProtocolSubmitBuffer,
  2846. IN PVOID ClientBufferBase,
  2847. IN ULONG SubmitBufferLength,
  2848. OUT PVOID *ProtocolReturnBuffer,
  2849. OUT PULONG ReturnBufferLength,
  2850. OUT PNTSTATUS ProtocolStatus
  2851. )
  2852. {
  2853. NTSTATUS Status;
  2854. PKERB_VERIFY_PAC_REQUEST VerifyRequest;
  2855. DWORD MaxBufferSize;
  2856. if (ARGUMENT_PRESENT(ProtocolReturnBuffer))
  2857. {
  2858. *ProtocolReturnBuffer = NULL;
  2859. }
  2860. if (ARGUMENT_PRESENT(ReturnBufferLength))
  2861. {
  2862. *ReturnBufferLength = 0;
  2863. }
  2864. if (SubmitBufferLength < sizeof(*VerifyRequest)) {
  2865. Status = STATUS_INVALID_PARAMETER;
  2866. goto Cleanup;
  2867. }
  2868. if (!KerbGlobalInitialized)
  2869. {
  2870. Status = STATUS_SUCCESS;
  2871. DsysAssert(FALSE);
  2872. goto Cleanup;
  2873. }
  2874. VerifyRequest = (PKERB_VERIFY_PAC_REQUEST) ProtocolSubmitBuffer;
  2875. MaxBufferSize = SubmitBufferLength -
  2876. FIELD_OFFSET(KERB_VERIFY_PAC_REQUEST, ChecksumAndSignature);
  2877. if ((VerifyRequest->ChecksumLength > MaxBufferSize) ||
  2878. (VerifyRequest->SignatureLength > MaxBufferSize) ||
  2879. ((VerifyRequest->ChecksumLength + VerifyRequest->SignatureLength) >
  2880. MaxBufferSize))
  2881. {
  2882. Status = STATUS_INVALID_PARAMETER;
  2883. goto Cleanup;
  2884. }
  2885. if (KerbKdcHandle == NULL)
  2886. {
  2887. Status = STATUS_MUST_BE_KDC;
  2888. goto Cleanup;
  2889. }
  2890. DsysAssert(KerbKdcVerifyPac != NULL);
  2891. Status = (*KerbKdcVerifyPac)(
  2892. VerifyRequest->ChecksumLength,
  2893. VerifyRequest->ChecksumAndSignature,
  2894. VerifyRequest->SignatureType,
  2895. VerifyRequest->SignatureLength,
  2896. VerifyRequest->ChecksumAndSignature + VerifyRequest->ChecksumLength
  2897. );
  2898. Cleanup:
  2899. *ProtocolStatus = Status;
  2900. return(STATUS_SUCCESS);
  2901. }
  2902. NTSTATUS
  2903. KerbPurgePrimaryCredentialsTickets(
  2904. IN KERB_PRIMARY_CREDENTIAL * PrimaryCredentials,
  2905. IN OPTIONAL PUNICODE_STRING ServerName,
  2906. IN OPTIONAL PUNICODE_STRING ServerRealm
  2907. )
  2908. {
  2909. NTSTATUS Status;
  2910. DsysAssert( PrimaryCredentials );
  2911. if ( ServerName == NULL && ServerRealm == NULL ) {
  2912. Status = STATUS_SUCCESS;
  2913. KerbPurgeTicketCache( &PrimaryCredentials->AuthenticationTicketCache );
  2914. KerbPurgeTicketCache( &PrimaryCredentials->ServerTicketCache );
  2915. KerbPurgeTicketCache( &PrimaryCredentials->S4UTicketCache );
  2916. } else if ( ServerName != NULL && ServerRealm != NULL ) {
  2917. KERB_TICKET_CACHE * TicketCaches[3] = {
  2918. &PrimaryCredentials->AuthenticationTicketCache,
  2919. &PrimaryCredentials->ServerTicketCache,
  2920. &PrimaryCredentials->S4UTicketCache
  2921. };
  2922. //
  2923. // Prowl through the caches and remove all the matching tickets
  2924. //
  2925. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  2926. KerbWriteLockTicketCache();
  2927. for ( ULONG i = 0 ; i < 3 ; i++ ) {
  2928. KERB_TICKET_CACHE * TicketCache = TicketCaches[i];
  2929. for ( PLIST_ENTRY ListEntry = TicketCache->CacheEntries.Flink ;
  2930. ListEntry != &TicketCache->CacheEntries ;
  2931. ListEntry = ListEntry->Flink ) {
  2932. KERB_TICKET_CACHE_ENTRY * CacheEntry;
  2933. UNICODE_STRING SearchName = {0};
  2934. CacheEntry= CONTAINING_RECORD(
  2935. ListEntry,
  2936. KERB_TICKET_CACHE_ENTRY,
  2937. ListEntry.Next
  2938. );
  2939. if ( !KERB_SUCCESS( KerbConvertKdcNameToString(
  2940. &SearchName,
  2941. CacheEntry->ServiceName,
  2942. NULL ))) { // no realm
  2943. Status = STATUS_INSUFFICIENT_RESOURCES;
  2944. KerbUnlockTicketCache();
  2945. goto Cleanup;
  2946. }
  2947. //
  2948. // Check to see if the server & realm name matches
  2949. //
  2950. if ( RtlEqualUnicodeString(
  2951. &SearchName,
  2952. ServerName,
  2953. TRUE ) &&
  2954. RtlEqualUnicodeString(
  2955. &CacheEntry->DomainName,
  2956. ServerRealm,
  2957. TRUE )) {
  2958. D_DebugLog((DEB_TRACE,"Purging a ticket!\n"));
  2959. Status = STATUS_SUCCESS;
  2960. //
  2961. // Move back one entry so that Remove() does not
  2962. // trash the iteration
  2963. //
  2964. ListEntry = ListEntry->Blink;
  2965. KerbRemoveTicketCacheEntry( CacheEntry );
  2966. }
  2967. KerbFreeString(&SearchName);
  2968. }
  2969. }
  2970. KerbUnlockTicketCache();
  2971. } else {
  2972. //
  2973. // ServerName and ServerRealm need to be either both specified or
  2974. // both NULL. Getting here means that only one of them is NULL,
  2975. // and the assert below will specify which one it is.
  2976. //
  2977. DsysAssert( ServerName != NULL );
  2978. DsysAssert( ServerRealm != NULL );
  2979. Status = STATUS_SUCCESS;
  2980. }
  2981. Cleanup:
  2982. return Status;
  2983. }
  2984. //+-------------------------------------------------------------------------
  2985. //
  2986. // Function: KerbPurgeTicket
  2987. //
  2988. // Synopsis: Removes ticket from the ticket cache
  2989. //
  2990. // Effects:
  2991. //
  2992. // Arguments: Same as Callpackage
  2993. //
  2994. // Requires:
  2995. //
  2996. // Returns:
  2997. //
  2998. // Notes:
  2999. //
  3000. //
  3001. //--------------------------------------------------------------------------
  3002. NTSTATUS NTAPI
  3003. KerbPurgeTicket(
  3004. IN PLSA_CLIENT_REQUEST ClientRequest,
  3005. IN PVOID ProtocolSubmitBuffer,
  3006. IN PVOID ClientBufferBase,
  3007. IN ULONG SubmitBufferSize,
  3008. OUT PVOID *ProtocolReturnBuffer,
  3009. OUT PULONG ReturnBufferLength,
  3010. OUT PNTSTATUS ProtocolStatus
  3011. )
  3012. {
  3013. NTSTATUS Status;
  3014. ULONG StructureSize = sizeof( KERB_PURGE_TKT_CACHE_REQUEST );
  3015. PKERB_PURGE_TKT_CACHE_REQUEST PurgeRequest = ( PKERB_PURGE_TKT_CACHE_REQUEST )ProtocolSubmitBuffer;
  3016. SECPKG_CLIENT_INFO ClientInfo;
  3017. PLUID LogonId;
  3018. PKERB_LOGON_SESSION LogonSession = NULL;
  3019. //
  3020. // Verify the request.
  3021. //
  3022. D_DebugLog((DEB_TRACE, "Purging ticket cache\n"));
  3023. //
  3024. // Any purging will also tag SPN cache for purge
  3025. //
  3026. KerbCleanupSpnCache();
  3027. #if _WIN64
  3028. SECPKG_CALL_INFO CallInfo;
  3029. if(!LsaFunctions->GetCallInfo(&CallInfo))
  3030. {
  3031. Status = STATUS_INTERNAL_ERROR;
  3032. goto Cleanup;
  3033. }
  3034. if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
  3035. {
  3036. StructureSize = sizeof( KERB_PURGE_TKT_CACHE_REQUEST_WOW64 );
  3037. }
  3038. #endif // _WIN64
  3039. if (SubmitBufferSize < StructureSize)
  3040. {
  3041. Status = STATUS_INVALID_PARAMETER;
  3042. goto Cleanup;
  3043. }
  3044. #if _WIN64
  3045. KERB_PURGE_TKT_CACHE_REQUEST LocalPurgeRequest;
  3046. if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
  3047. {
  3048. //
  3049. // Thunk 32-bit pointers if this is a WOW caller
  3050. //
  3051. PKERB_PURGE_TKT_CACHE_REQUEST_WOW64 PurgeRequestWOW =
  3052. ( PKERB_PURGE_TKT_CACHE_REQUEST_WOW64 )PurgeRequest;
  3053. LocalPurgeRequest.MessageType = PurgeRequestWOW->MessageType;
  3054. LocalPurgeRequest.LogonId = PurgeRequestWOW->LogonId;
  3055. UNICODE_STRING_FROM_WOW_STRING(
  3056. &LocalPurgeRequest.ServerName,
  3057. &PurgeRequestWOW->ServerName );
  3058. UNICODE_STRING_FROM_WOW_STRING(
  3059. &LocalPurgeRequest.RealmName,
  3060. &PurgeRequestWOW->RealmName );
  3061. PurgeRequest = &LocalPurgeRequest;
  3062. }
  3063. #endif // _WIN64
  3064. //
  3065. // Normalize the strings
  3066. //
  3067. NULL_RELOCATE_ONE( &PurgeRequest->ServerName );
  3068. NULL_RELOCATE_ONE( &PurgeRequest->RealmName );
  3069. //
  3070. // Find the callers logon id & TCB status
  3071. //
  3072. Status = LsaFunctions->GetClientInfo( &ClientInfo );
  3073. if (!NT_SUCCESS(Status))
  3074. {
  3075. goto Cleanup;
  3076. }
  3077. //
  3078. // If the caller did not provide a logon id, use the caller's logon id.
  3079. //
  3080. if ( RtlIsZeroLuid( &PurgeRequest->LogonId )) {
  3081. LogonId = &ClientInfo.LogonId;
  3082. } else if ( !ClientInfo.HasTcbPrivilege ) {
  3083. //
  3084. // The caller must have TCB privilege in order to access someone
  3085. // else's ticket cache.
  3086. //
  3087. Status = STATUS_PRIVILEGE_NOT_HELD;
  3088. goto Cleanup;
  3089. } else {
  3090. LogonId = &PurgeRequest->LogonId;
  3091. }
  3092. LogonSession = KerbReferenceLogonSession(
  3093. LogonId,
  3094. FALSE // don't unlink
  3095. );
  3096. if (LogonSession == NULL)
  3097. {
  3098. Status = STATUS_NO_SUCH_LOGON_SESSION;
  3099. goto Cleanup;
  3100. }
  3101. //
  3102. // If no servername / realm name were supplied, purge all tickets
  3103. //
  3104. if ((PurgeRequest->ServerName.Length) == 0 && (PurgeRequest->RealmName.Length == 0))
  3105. {
  3106. D_DebugLog((DEB_TRACE, "Purging all tickets\n"));
  3107. Status = KerbPurgePrimaryCredentialsTickets(
  3108. &LogonSession->PrimaryCredentials,
  3109. NULL,
  3110. NULL
  3111. );
  3112. } else {
  3113. D_DebugLog(( DEB_TRACE, "Purging tickets %wZ\\%wZ\n",
  3114. &PurgeRequest->RealmName,
  3115. &PurgeRequest->ServerName ));
  3116. Status = KerbPurgePrimaryCredentialsTickets(
  3117. &LogonSession->PrimaryCredentials,
  3118. &PurgeRequest->ServerName,
  3119. &PurgeRequest->RealmName
  3120. );
  3121. }
  3122. Cleanup:
  3123. if (LogonSession != NULL)
  3124. {
  3125. KerbDereferenceLogonSession(LogonSession);
  3126. }
  3127. *ProtocolReturnBuffer = NULL;
  3128. *ReturnBufferLength = 0;
  3129. *ProtocolStatus = Status;
  3130. return STATUS_SUCCESS;
  3131. }
  3132. //+-------------------------------------------------------------------------
  3133. //
  3134. // Function: KerbPurgeTicketEx
  3135. //
  3136. // Synopsis: Removes ticket from the ticket cache
  3137. //
  3138. // Effects:
  3139. //
  3140. // Arguments: Same as Callpackage
  3141. //
  3142. // Requires:
  3143. //
  3144. // Returns:
  3145. //
  3146. // Notes:
  3147. //
  3148. //
  3149. //--------------------------------------------------------------------------
  3150. NTSTATUS NTAPI
  3151. KerbPurgeTicketEx(
  3152. IN PLSA_CLIENT_REQUEST ClientRequest,
  3153. IN PVOID ProtocolSubmitBuffer,
  3154. IN PVOID ClientBufferBase,
  3155. IN ULONG SubmitBufferSize,
  3156. OUT PVOID *ProtocolReturnBuffer,
  3157. OUT PULONG ReturnBufferLength,
  3158. OUT PNTSTATUS ProtocolStatus
  3159. )
  3160. {
  3161. NTSTATUS Status;
  3162. ULONG StructureSize = sizeof( KERB_PURGE_TKT_CACHE_EX_REQUEST );
  3163. PKERB_PURGE_TKT_CACHE_EX_REQUEST PurgeRequest = ( PKERB_PURGE_TKT_CACHE_EX_REQUEST )ProtocolSubmitBuffer;
  3164. SECPKG_CLIENT_INFO ClientInfo;
  3165. PLUID LogonId;
  3166. PKERB_LOGON_SESSION LogonSession = NULL;
  3167. //
  3168. // Verify the request.
  3169. //
  3170. D_DebugLog((DEB_TRACE, "Purging ticket cache Ex\n"));
  3171. //
  3172. // Any purging will also tag SPN cache for purge
  3173. //
  3174. KerbCleanupSpnCache();
  3175. #if _WIN64
  3176. SECPKG_CALL_INFO CallInfo;
  3177. if( !LsaFunctions->GetCallInfo( &CallInfo )) {
  3178. Status = STATUS_INTERNAL_ERROR;
  3179. goto Cleanup;
  3180. }
  3181. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) {
  3182. StructureSize = sizeof( KERB_PURGE_TKT_CACHE_EX_REQUEST_WOW64 );
  3183. }
  3184. #endif
  3185. if ( SubmitBufferSize < StructureSize ) {
  3186. Status = STATUS_INVALID_PARAMETER;
  3187. goto Cleanup;
  3188. }
  3189. #if _WIN64
  3190. KERB_PURGE_TKT_CACHE_EX_REQUEST LocalPurgeRequest;
  3191. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) {
  3192. //
  3193. // Thunk 32-bit pointers if this is a WOW caller
  3194. //
  3195. PKERB_PURGE_TKT_CACHE_EX_REQUEST_WOW64 PurgeRequestWOW =
  3196. ( PKERB_PURGE_TKT_CACHE_EX_REQUEST_WOW64 )PurgeRequest;
  3197. LocalPurgeRequest.MessageType = PurgeRequestWOW->MessageType;
  3198. LocalPurgeRequest.LogonId = PurgeRequestWOW->LogonId;
  3199. UNICODE_STRING_FROM_WOW_STRING(
  3200. &LocalPurgeRequest.TicketTemplate.ClientName,
  3201. &PurgeRequestWOW->TicketTemplate.ClientName );
  3202. UNICODE_STRING_FROM_WOW_STRING(
  3203. &LocalPurgeRequest.TicketTemplate.ClientRealm,
  3204. &PurgeRequestWOW->TicketTemplate.ClientRealm );
  3205. UNICODE_STRING_FROM_WOW_STRING(
  3206. &LocalPurgeRequest.TicketTemplate.ServerName,
  3207. &PurgeRequestWOW->TicketTemplate.ServerName );
  3208. UNICODE_STRING_FROM_WOW_STRING(
  3209. &LocalPurgeRequest.TicketTemplate.ServerRealm,
  3210. &PurgeRequestWOW->TicketTemplate.ServerRealm );
  3211. LocalPurgeRequest.TicketTemplate.StartTime = PurgeRequestWOW->TicketTemplate.StartTime;
  3212. LocalPurgeRequest.TicketTemplate.EndTime = PurgeRequestWOW->TicketTemplate.EndTime;
  3213. LocalPurgeRequest.TicketTemplate.RenewTime = PurgeRequestWOW->TicketTemplate.RenewTime;
  3214. LocalPurgeRequest.TicketTemplate.EncryptionType = PurgeRequestWOW->TicketTemplate.EncryptionType;
  3215. LocalPurgeRequest.TicketTemplate.TicketFlags = PurgeRequestWOW->TicketTemplate.TicketFlags;
  3216. PurgeRequest = &LocalPurgeRequest;
  3217. }
  3218. #endif
  3219. //
  3220. // Normalize the strings
  3221. //
  3222. NULL_RELOCATE_ONE( &PurgeRequest->TicketTemplate.ClientName );
  3223. NULL_RELOCATE_ONE( &PurgeRequest->TicketTemplate.ClientRealm );
  3224. NULL_RELOCATE_ONE( &PurgeRequest->TicketTemplate.ServerName );
  3225. NULL_RELOCATE_ONE( &PurgeRequest->TicketTemplate.ServerRealm );
  3226. //
  3227. // Find the callers logon id & TCB status
  3228. //
  3229. Status = LsaFunctions->GetClientInfo( &ClientInfo );
  3230. if ( !NT_SUCCESS( Status )) {
  3231. goto Cleanup;
  3232. }
  3233. //
  3234. // If the caller did not provide a logon id, use the caller's logon id
  3235. //
  3236. if ( RtlIsZeroLuid( &PurgeRequest->LogonId )) {
  3237. LogonId = &ClientInfo.LogonId;
  3238. } else if ( !ClientInfo.HasTcbPrivilege ) {
  3239. //
  3240. // The caller is required to have the TCB privilege
  3241. // in order to access someone else's ticket cache
  3242. //
  3243. Status = STATUS_PRIVILEGE_NOT_HELD;
  3244. goto Cleanup;
  3245. } else {
  3246. LogonId = &PurgeRequest->LogonId;
  3247. }
  3248. LogonSession = KerbReferenceLogonSession(
  3249. LogonId,
  3250. FALSE
  3251. );
  3252. if ( LogonSession == NULL ) {
  3253. Status = STATUS_NO_SUCH_LOGON_SESSION;
  3254. goto Cleanup;
  3255. }
  3256. //
  3257. // Purge the entire ticket cache?
  3258. //
  3259. if ( PurgeRequest->Flags & KERB_PURGE_ALL_TICKETS ) {
  3260. D_DebugLog(( DEB_TRACE, "Purging all tickets\n" ));
  3261. Status = KerbPurgePrimaryCredentialsTickets(
  3262. &LogonSession->PrimaryCredentials,
  3263. NULL,
  3264. NULL
  3265. );
  3266. DsysAssert( NT_SUCCESS( Status ));
  3267. KerbLockList( &LogonSession->CredmanCredentials );
  3268. for ( PLIST_ENTRY ListEntry = LogonSession->CredmanCredentials.List.Flink;
  3269. ListEntry != &LogonSession->CredmanCredentials.List;
  3270. ListEntry = ListEntry->Flink ) {
  3271. PKERB_CREDMAN_CRED CredmanCred = CONTAINING_RECORD(
  3272. ListEntry,
  3273. KERB_CREDMAN_CRED,
  3274. ListEntry.Next
  3275. );
  3276. if ( CredmanCred->SuppliedCredentials == NULL) {
  3277. continue;
  3278. }
  3279. Status = KerbPurgePrimaryCredentialsTickets(
  3280. CredmanCred->SuppliedCredentials,
  3281. NULL,
  3282. NULL
  3283. );
  3284. DsysAssert( NT_SUCCESS( Status ));
  3285. }
  3286. KerbUnlockList( &LogonSession->CredmanCredentials );
  3287. } else {
  3288. BOOLEAN MatchClient = (
  3289. PurgeRequest->TicketTemplate.ClientName.Length > 0 ||
  3290. PurgeRequest->TicketTemplate.ClientRealm.Length > 0 );
  3291. BOOLEAN MatchServer = (
  3292. PurgeRequest->TicketTemplate.ServerName.Length > 0 ||
  3293. PurgeRequest->TicketTemplate.ServerRealm.Length > 0 );
  3294. BOOLEAN Found = FALSE;
  3295. //
  3296. // Take a look at the primary credentials and see if they need cleaning
  3297. //
  3298. if ( !MatchClient ||
  3299. ( RtlEqualUnicodeString(
  3300. &LogonSession->PrimaryCredentials.UserName,
  3301. &PurgeRequest->TicketTemplate.ClientName,
  3302. TRUE ) &&
  3303. RtlEqualUnicodeString(
  3304. &LogonSession->PrimaryCredentials.DomainName,
  3305. &PurgeRequest->TicketTemplate.ClientRealm,
  3306. TRUE ))) {
  3307. UNICODE_STRING * MatchServerName;
  3308. UNICODE_STRING * MatchServerRealm;
  3309. if ( MatchServer ) {
  3310. MatchServerName = &PurgeRequest->TicketTemplate.ServerName;
  3311. MatchServerRealm = &PurgeRequest->TicketTemplate.ServerRealm;
  3312. } else {
  3313. MatchServerName = NULL;
  3314. MatchServerRealm = NULL;
  3315. }
  3316. Status = KerbPurgePrimaryCredentialsTickets(
  3317. &LogonSession->PrimaryCredentials,
  3318. MatchServerName,
  3319. MatchServerRealm
  3320. );
  3321. if ( NT_SUCCESS( Status )) {
  3322. Found = TRUE;
  3323. } else if ( Status != STATUS_OBJECT_NAME_NOT_FOUND ) {
  3324. goto Cleanup;
  3325. }
  3326. }
  3327. //
  3328. // Now look at the credman credentials and purge those
  3329. //
  3330. KerbLockList( &LogonSession->CredmanCredentials );
  3331. for ( PLIST_ENTRY ListEntry = LogonSession->CredmanCredentials.List.Flink;
  3332. ListEntry != &LogonSession->CredmanCredentials.List;
  3333. ListEntry = ListEntry->Flink ) {
  3334. PKERB_CREDMAN_CRED CredmanCred = CONTAINING_RECORD(
  3335. ListEntry,
  3336. KERB_CREDMAN_CRED,
  3337. ListEntry.Next
  3338. );
  3339. if ( CredmanCred->SuppliedCredentials == NULL ) {
  3340. continue;
  3341. }
  3342. if ( !MatchClient ||
  3343. ( RtlEqualUnicodeString(
  3344. &CredmanCred->SuppliedCredentials->UserName,
  3345. &PurgeRequest->TicketTemplate.ClientName,
  3346. TRUE ) &&
  3347. RtlEqualUnicodeString(
  3348. &CredmanCred->SuppliedCredentials->DomainName,
  3349. &PurgeRequest->TicketTemplate.ClientRealm,
  3350. TRUE ))) {
  3351. UNICODE_STRING * MatchServerName;
  3352. UNICODE_STRING * MatchServerRealm;
  3353. if ( MatchServer ) {
  3354. MatchServerName = &PurgeRequest->TicketTemplate.ServerName;
  3355. MatchServerRealm = &PurgeRequest->TicketTemplate.ServerRealm;
  3356. } else {
  3357. MatchServerName = NULL;
  3358. MatchServerRealm = NULL;
  3359. }
  3360. Status = KerbPurgePrimaryCredentialsTickets(
  3361. CredmanCred->SuppliedCredentials,
  3362. MatchServerName,
  3363. MatchServerRealm
  3364. );
  3365. if ( NT_SUCCESS( Status )) {
  3366. Found = TRUE;
  3367. } else if ( Status != STATUS_OBJECT_NAME_NOT_FOUND ) {
  3368. KerbUnlockList( &LogonSession->CredmanCredentials );
  3369. goto Cleanup;
  3370. }
  3371. }
  3372. }
  3373. KerbUnlockList( &LogonSession->CredmanCredentials );
  3374. if ( Found ) {
  3375. Status = STATUS_SUCCESS;
  3376. } else {
  3377. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  3378. }
  3379. }
  3380. Cleanup:
  3381. if ( LogonSession ) {
  3382. KerbDereferenceLogonSession( LogonSession );
  3383. }
  3384. *ProtocolReturnBuffer = NULL;
  3385. *ReturnBufferLength = NULL;
  3386. *ProtocolStatus = Status;
  3387. return STATUS_SUCCESS;
  3388. }
  3389. //+-------------------------------------------------------------------------
  3390. //
  3391. // Function: KerbRetrieveEncodedTicket
  3392. //
  3393. // Synopsis: Retrieves an asn.1 encoded ticket from the ticket cache
  3394. // specified.
  3395. //
  3396. // Effects:
  3397. //
  3398. // Arguments: Same as Callpackage
  3399. //
  3400. // Requires:
  3401. //
  3402. // Returns:
  3403. //
  3404. // Notes:
  3405. //
  3406. //
  3407. //--------------------------------------------------------------------------
  3408. NTSTATUS NTAPI
  3409. KerbRetrieveEncodedTicket(
  3410. IN PLSA_CLIENT_REQUEST ClientRequest,
  3411. IN PVOID ProtocolSubmitBuffer,
  3412. IN PVOID ClientBufferBase,
  3413. IN ULONG SubmitBufferSize,
  3414. OUT PVOID *ProtocolReturnBuffer,
  3415. OUT PULONG ReturnBufferLength,
  3416. OUT PNTSTATUS ProtocolStatus
  3417. )
  3418. {
  3419. NTSTATUS Status;
  3420. SECPKG_CLIENT_INFO ClientInfo;
  3421. LUID DummyLogonId, *LogonId;
  3422. PKERB_LOGON_SESSION LogonSession = NULL;
  3423. PKERB_CREDENTIAL Credential = NULL;
  3424. KERB_PRIMARY_CREDENTIAL * PrimaryCreds = NULL;
  3425. PKERB_RETRIEVE_TKT_REQUEST RetrieveRequest = ( PKERB_RETRIEVE_TKT_REQUEST )ProtocolSubmitBuffer;
  3426. PKERB_RETRIEVE_TKT_RESPONSE RetrieveResponse = NULL;
  3427. KERB_TICKET_CACHE_ENTRY * CacheEntry = NULL;
  3428. PBYTE ClientResponse = NULL;
  3429. ULONG ResponseSize;
  3430. PKERB_INTERNAL_NAME TargetName = NULL;
  3431. UNICODE_STRING TargetRealm = {0};
  3432. ULONG Flags = 0;
  3433. ULONG StructureSize = sizeof( KERB_RETRIEVE_TKT_REQUEST );
  3434. //
  3435. // Verify the request.
  3436. //
  3437. D_DebugLog(( DEB_TRACE, "Retrieving encoded ticket\n" ));
  3438. #if _WIN64
  3439. SECPKG_CALL_INFO CallInfo;
  3440. //
  3441. // Return 32-bit cache entries if this is a WOW caller
  3442. //
  3443. if (!LsaFunctions->GetCallInfo(&CallInfo))
  3444. {
  3445. Status = STATUS_INTERNAL_ERROR;
  3446. goto Cleanup;
  3447. }
  3448. if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
  3449. {
  3450. Status = STATUS_NOT_SUPPORTED;
  3451. goto Cleanup;
  3452. }
  3453. #endif // _WIN64
  3454. if (SubmitBufferSize < StructureSize)
  3455. {
  3456. Status = STATUS_INVALID_PARAMETER;
  3457. goto Cleanup;
  3458. }
  3459. //
  3460. // Normalize the strings
  3461. //
  3462. NULL_RELOCATE_ONE( &RetrieveRequest->TargetName );
  3463. //
  3464. // Find the callers logon id & TCB status
  3465. //
  3466. Status = LsaFunctions->GetClientInfo( &ClientInfo );
  3467. if (!NT_SUCCESS(Status))
  3468. {
  3469. goto Cleanup;
  3470. }
  3471. //
  3472. // If the caller did not provide a logon id, use the caller's logon id.
  3473. //
  3474. if ( (RetrieveRequest->CacheOptions & KERB_RETRIEVE_TICKET_USE_CREDHANDLE) != 0)
  3475. {
  3476. //
  3477. // Get the associated credential
  3478. //
  3479. Status = KerbReferenceCredential(
  3480. RetrieveRequest->CredentialsHandle.dwUpper,
  3481. KERB_CRED_OUTBOUND | KERB_CRED_TGT_AVAIL,
  3482. FALSE,
  3483. &Credential);
  3484. if (!NT_SUCCESS(Status))
  3485. {
  3486. DebugLog(( DEB_WARN, "Failed to locate credential: 0x%x\n", Status ));
  3487. goto Cleanup;
  3488. }
  3489. //
  3490. // Get the logon id from the credentials so we can locate the
  3491. // logon session.
  3492. //
  3493. DummyLogonId = Credential->LogonId;
  3494. LogonId = &DummyLogonId;
  3495. }
  3496. else if ( RtlIsZeroLuid( &RetrieveRequest->LogonId ) )
  3497. {
  3498. LogonId = &ClientInfo.LogonId;
  3499. }
  3500. else if ( !ClientInfo.HasTcbPrivilege )
  3501. {
  3502. //
  3503. // The caller must have TCB privilege in order to access someone
  3504. // elses ticket cache.
  3505. //
  3506. Status = STATUS_PRIVILEGE_NOT_HELD;
  3507. goto Cleanup;
  3508. } else {
  3509. LogonId = &RetrieveRequest->LogonId;
  3510. }
  3511. LogonSession = KerbReferenceLogonSession(
  3512. LogonId,
  3513. FALSE // don't unlink
  3514. );
  3515. if (LogonSession == NULL)
  3516. {
  3517. Status = STATUS_NO_SUCH_LOGON_SESSION;
  3518. goto Cleanup;
  3519. }
  3520. //
  3521. // Process the target names
  3522. //
  3523. Status = KerbProcessTargetNames(
  3524. &RetrieveRequest->TargetName,
  3525. NULL, // no supp target name
  3526. 0, // no flags
  3527. &Flags,
  3528. &TargetName,
  3529. &TargetRealm
  3530. );
  3531. if (!NT_SUCCESS(Status))
  3532. {
  3533. goto Cleanup;
  3534. }
  3535. //
  3536. // Check the TGT cache, as KerbGetServiceTicket doesn't look there
  3537. //
  3538. if ((RetrieveRequest->CacheOptions & KERB_RETRIEVE_TICKET_DONT_USE_CACHE) == 0)
  3539. {
  3540. KerbReadLockLogonSessions(LogonSession);
  3541. //
  3542. // Pick which ticket cache to use
  3543. //
  3544. if ((Credential != NULL) && (Credential->SuppliedCredentials != NULL))
  3545. {
  3546. PrimaryCreds = Credential->SuppliedCredentials;
  3547. }
  3548. else
  3549. {
  3550. PrimaryCreds = &LogonSession->PrimaryCredentials;
  3551. }
  3552. CacheEntry = KerbLocateTicketCacheEntry(
  3553. &PrimaryCreds->AuthenticationTicketCache,
  3554. TargetName,
  3555. &TargetRealm
  3556. );
  3557. if (CacheEntry == NULL)
  3558. {
  3559. //
  3560. // If the tgt cache failed, check the normal cache
  3561. //
  3562. CacheEntry = KerbLocateTicketCacheEntry(
  3563. &PrimaryCreds->ServerTicketCache,
  3564. TargetName,
  3565. &TargetRealm
  3566. );
  3567. }
  3568. //
  3569. // Check if this is a TGT
  3570. //
  3571. if (CacheEntry == NULL)
  3572. {
  3573. if ((TargetName->NameCount == 2) &&
  3574. RtlEqualUnicodeString(
  3575. &TargetName->Names[0],
  3576. &KerbGlobalKdcServiceName,
  3577. TRUE // case insensitive
  3578. ))
  3579. {
  3580. //
  3581. // If the tgt cache failed, check the normal cache
  3582. //
  3583. CacheEntry = KerbLocateTicketCacheEntryByRealm(
  3584. &PrimaryCreds->AuthenticationTicketCache,
  3585. &TargetRealm,
  3586. KERB_TICKET_CACHE_PRIMARY_TGT
  3587. );
  3588. if (CacheEntry != NULL)
  3589. {
  3590. //
  3591. // Make sure the name matches
  3592. //
  3593. KerbReadLockTicketCache();
  3594. if ( !KerbEqualKdcNames(
  3595. TargetName,
  3596. CacheEntry->ServiceName
  3597. ))
  3598. {
  3599. //
  3600. // We must unlock the ticket cache before dereferencing
  3601. //
  3602. KerbUnlockTicketCache();
  3603. KerbDereferenceTicketCacheEntry( CacheEntry );
  3604. CacheEntry = NULL;
  3605. }
  3606. else
  3607. {
  3608. KerbUnlockTicketCache();
  3609. }
  3610. }
  3611. }
  3612. }
  3613. //
  3614. // If we found a ticket, make sure it has the right flags &
  3615. // encryption type
  3616. //
  3617. if (CacheEntry != NULL)
  3618. {
  3619. ULONG TicketFlags;
  3620. ULONG CacheTicketFlags;
  3621. LONG CacheEncryptionType;
  3622. //
  3623. // Check if the flags are present
  3624. //
  3625. KerbReadLockTicketCache();
  3626. CacheTicketFlags = CacheEntry->TicketFlags;
  3627. CacheEncryptionType = CacheEntry->Ticket.encrypted_part.encryption_type;
  3628. KerbUnlockTicketCache();
  3629. TicketFlags = KerbConvertKdcOptionsToTicketFlags( RetrieveRequest->TicketFlags );
  3630. //
  3631. // Verify the flags
  3632. //
  3633. if ((( CacheTicketFlags & TicketFlags ) != TicketFlags) ||
  3634. ((RetrieveRequest->EncryptionType != KERB_ETYPE_DEFAULT) && (CacheEncryptionType != RetrieveRequest->EncryptionType)))
  3635. {
  3636. //
  3637. // Something doesn't match, so throw away the entry
  3638. //
  3639. KerbDereferenceTicketCacheEntry( CacheEntry );
  3640. CacheEntry = NULL;
  3641. }
  3642. }
  3643. KerbUnlockLogonSessions(LogonSession);
  3644. }
  3645. else
  3646. {
  3647. Flags |= KERB_GET_TICKET_NO_CACHE;
  3648. }
  3649. if (CacheEntry == NULL)
  3650. {
  3651. //
  3652. // If we aren't supposed to get a new ticket, return a failure now.
  3653. //
  3654. if ((RetrieveRequest->CacheOptions & KERB_RETRIEVE_TICKET_USE_CACHE_ONLY) != 0)
  3655. {
  3656. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  3657. goto Cleanup;
  3658. }
  3659. //
  3660. // Now get a ticket
  3661. //
  3662. Status = KerbGetServiceTicket(
  3663. LogonSession,
  3664. Credential,
  3665. NULL,
  3666. TargetName,
  3667. &TargetRealm,
  3668. Flags,
  3669. RetrieveRequest->TicketFlags,
  3670. RetrieveRequest->EncryptionType,
  3671. NULL, // no error message
  3672. NULL, // no authorization data
  3673. NULL, // no tgt reply
  3674. &CacheEntry,
  3675. NULL // don't return logon guid
  3676. );
  3677. if (!NT_SUCCESS(Status))
  3678. {
  3679. DebugLog((DEB_WARN, "KerbRetrieveEncodedTicket failed to get outbound ticket: KerbGetServiceTicket failed with 0x%x\n",Status));
  3680. goto Cleanup;
  3681. }
  3682. }
  3683. //
  3684. // Encode the ticket or kerb_cred
  3685. //
  3686. KerbReadLockTicketCache();
  3687. Status = KerbPackExternalTicket(
  3688. CacheEntry,
  3689. RetrieveRequest->CacheOptions & KERB_RETRIEVE_TICKET_AS_KERB_CRED,
  3690. ( ClientInfo.HasTcbPrivilege || KerbGlobalAllowTgtSessionKey ),
  3691. &ResponseSize,
  3692. &ClientResponse
  3693. );
  3694. KerbUnlockTicketCache();
  3695. if (!NT_SUCCESS(Status))
  3696. {
  3697. goto Cleanup;
  3698. }
  3699. *ProtocolReturnBuffer = ClientResponse;
  3700. ClientResponse = NULL;
  3701. *ReturnBufferLength = ResponseSize;
  3702. Cleanup:
  3703. if (CacheEntry != NULL)
  3704. {
  3705. KerbDereferenceTicketCacheEntry( CacheEntry );
  3706. }
  3707. if (LogonSession != NULL)
  3708. {
  3709. KerbDereferenceLogonSession( LogonSession );
  3710. }
  3711. if (Credential != NULL)
  3712. {
  3713. KerbDereferenceCredential( Credential );
  3714. }
  3715. KerbFree( RetrieveResponse );
  3716. if (ClientResponse != NULL)
  3717. {
  3718. LsaFunctions->FreeClientBuffer(
  3719. NULL,
  3720. ClientResponse
  3721. );
  3722. }
  3723. KerbFreeString( &TargetRealm );
  3724. KerbFreeKdcName( &TargetName );
  3725. *ProtocolStatus = Status;
  3726. return STATUS_SUCCESS;
  3727. }
  3728. #if 0
  3729. //+-------------------------------------------------------------------------
  3730. //
  3731. // Function: KerbRetrieveEncodedTicketEx
  3732. //
  3733. // Synopsis: Retrieves an asn.1 encoded ticket from the ticket cache
  3734. // specified.
  3735. //
  3736. // Effects:
  3737. //
  3738. // Arguments: Same as Callpackage
  3739. //
  3740. // Requires:
  3741. //
  3742. // Returns:
  3743. //
  3744. // Notes:
  3745. //
  3746. //
  3747. //--------------------------------------------------------------------------
  3748. NTSTATUS NTAPI
  3749. KerbRetrieveEncodedTicketEx(
  3750. IN PLSA_CLIENT_REQUEST ClientRequest,
  3751. IN PVOID ProtocolSubmitBuffer,
  3752. IN PVOID ClientBufferBase,
  3753. IN ULONG SubmitBufferSize,
  3754. OUT PVOID *ProtocolReturnBuffer,
  3755. OUT PULONG ReturnBufferLength,
  3756. OUT PNTSTATUS ProtocolStatus
  3757. )
  3758. {
  3759. NTSTATUS Status;
  3760. SECPKG_CLIENT_INFO ClientInfo;
  3761. ULONG StructureSize = sizeof( KERB_RETRIEVE_TKT_EX_REQUEST );
  3762. PKERB_RETRIEVE_TKT_EX_REQUEST RetrieveRequest = ( PKERB_RETRIEVE_TKT_EX_REQUEST )ProtocolSubmitBuffer;
  3763. PKERB_RETRIEVE_TKT_EX_RESPONSE RetrieveResponse = NULL;
  3764. PKERB_CREDENTIAL Credential = NULL;
  3765. LUID DummyLogonId, *LogonId;
  3766. PKERB_LOGON_SESSION LogonSession = NULL;
  3767. ULONG Flags = 0;
  3768. PKERB_INTERNAL_NAME TargetName = NULL;
  3769. UNICODE_STRING TargetRealm = {0};
  3770. PBYTE ClientResponse = NULL;
  3771. ULONG ResponseSize;
  3772. //
  3773. // Verify the request
  3774. //
  3775. D_DebugLog(( DEB_TRACE, "Retrieving encoded ticket ex\n" ));
  3776. #if _WIN64
  3777. SECPKG_CALL_INFO CallInfo;
  3778. //
  3779. // Return 32-bit cache entries if this is a WOW caller
  3780. //
  3781. if( !LsaFunctions->GetCallInfo( &CallInfo )) {
  3782. Status = STATUS_INTERNAL_ERROR;
  3783. goto Cleanup;
  3784. }
  3785. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) {
  3786. StructureSize = sizeof( KERB_RETRIEVE_TKT_EX_REQUEST_WOW64 );
  3787. }
  3788. #endif // _WIN64
  3789. if ( SubmitBufferSize < StructureSize ) {
  3790. Status = STATUS_INVALID_PARAMETER;
  3791. goto Cleanup;
  3792. }
  3793. #if _WIN64
  3794. KERB_RETRIEVE_TKT_EX_REQUEST LocalRetrieveRequest;
  3795. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) {
  3796. //
  3797. // Thunk 32-bit pointers if this is a WOW caller
  3798. //
  3799. PKERB_RETRIEVE_TKT_EX_REQUEST_WOW64 RetrieveRequestWOW =
  3800. ( PKERB_RETRIEVE_TKT_EX_REQUEST_WOW64 )RetrieveRequest;
  3801. LocalRetrieveRequest.MessageType = RetrieveRequestWOW->MessageType;
  3802. LocalRetrieveRequest.LogonId = RetrieveRequestWOW->LogonId;
  3803. UNICODE_STRING_FROM_WOW_STRING(
  3804. &LocalRetrieveRequest.TicketTemplate.ClientName,
  3805. &RetrieveRequestWOW->TicketTemplate.ClientName );
  3806. UNICODE_STRING_FROM_WOW_STRING(
  3807. &LocalRetrieveRequest.TicketTemplate.ClientRealm,
  3808. &RetrieveRequestWOW->TicketTemplate.ClientRealm );
  3809. UNICODE_STRING_FROM_WOW_STRING(
  3810. &LocalRetrieveRequest.TicketTemplate.ServerName,
  3811. &RetrieveRequestWOW->TicketTemplate.ServerName );
  3812. UNICODE_STRING_FROM_WOW_STRING(
  3813. &LocalRetrieveRequest.TicketTemplate.ServerRealm,
  3814. &RetrieveRequestWOW->TicketTemplate.ServerRealm );
  3815. LocalRetrieveRequest.TicketTemplate.StartTime = RetrieveRequestWOW->TicketTemplate.StartTime;
  3816. LocalRetrieveRequest.TicketTemplate.EndTime = RetrieveRequestWOW->TicketTemplate.EndTime;
  3817. LocalRetrieveRequest.TicketTemplate.RenewTime = RetrieveRequestWOW->TicketTemplate.RenewTime;
  3818. LocalRetrieveRequest.TicketTemplate.EncryptionType = RetrieveRequestWOW->TicketTemplate.EncryptionType;
  3819. LocalRetrieveRequest.TicketTemplate.TicketFlags = RetrieveRequestWOW->TicketTemplate.TicketFlags;
  3820. LocalRetrieveRequest.CacheOptions = RetrieveRequestWOW->CacheOptions;
  3821. LocalRetrieveRequest.CredentialsHandle = RetrieveRequestWOW->CredentialsHandle;
  3822. //
  3823. // TODO: take care of SecondTicket, UserAuthData and Addresses
  3824. //
  3825. LocalRetrieveRequest.SecondTicket = NULL;
  3826. LocalRetrieveRequest.UserAuthData = NULL;
  3827. LocalRetrieveRequest.Addresses = NULL;
  3828. RetrieveRequest = &LocalRetrieveRequest;
  3829. }
  3830. #endif
  3831. //
  3832. // Normalize the strings
  3833. //
  3834. NULL_RELOCATE_ONE( &RetrieveRequest->TicketTemplate.ClientName );
  3835. NULL_RELOCATE_ONE( &RetrieveRequest->TicketTemplate.ClientRealm );
  3836. NULL_RELOCATE_ONE( &RetrieveRequest->TicketTemplate.ServerName );
  3837. NULL_RELOCATE_ONE( &RetrieveRequest->TicketTemplate.ServerRealm );
  3838. //
  3839. // TODO: take care of SecondTicket, UserAuthData and Addresses
  3840. //
  3841. if ( RetrieveRequest->SecondTicket != NULL ||
  3842. RetrieveRequest->UserAuthData != NULL ||
  3843. RetrieveRequest->Addresses != NULL ) {
  3844. Status = STATUS_NOT_SUPPORTED;
  3845. goto Cleanup;
  3846. }
  3847. //
  3848. // Find the callers logon id & TCB status
  3849. //
  3850. Status = LsaFunctions->GetClientInfo( &ClientInfo );
  3851. if ( !NT_SUCCESS( Status )) {
  3852. goto Cleanup;
  3853. }
  3854. //
  3855. // If the caller did not provide a logon id, user the caller's logon id
  3856. //
  3857. if ( RetrieveRequest->CacheOptions & KERB_RETRIEVE_TICKET_USE_CREDHANDLE ) {
  3858. //
  3859. // Get the associated credential
  3860. //
  3861. Status = KerbReferenceCredential(
  3862. RetrieveRequest->CredentialsHandle.dwUpper,
  3863. KERB_CRED_OUTBOUND | KERB_CRED_TGT_AVAIL,
  3864. FALSE,
  3865. &Credential
  3866. );
  3867. if ( !NT_SUCCESS( Status )) {
  3868. DebugLog(( DEB_WARN, "Failed to locate credential: 0x%x\n", Status ));
  3869. goto Cleanup;
  3870. }
  3871. //
  3872. // Get the logon id from the credentials so we can locate the logon session
  3873. //
  3874. DummyLogonId = Credential->LogonId;
  3875. LogonId = &DummyLogonId;
  3876. } else if ( RtlIsZeroLuid( &RetrieveRequest->LogonId )) {
  3877. LogonId = &ClientInfo.LogonId;
  3878. } else if ( !ClientInfo.HasTcbPrivilege ) {
  3879. //
  3880. // The caller must have TCB privilege in order to access someone else's
  3881. // ticket cache
  3882. //
  3883. Status = STATUS_PRIVILEGE_NOT_HELD;
  3884. goto Cleanup;
  3885. } else {
  3886. LogonId = &RetrieveRequest->LogonId;
  3887. }
  3888. LogonSession = KerbReferenceLogonSession(
  3889. LogonId,
  3890. FALSE
  3891. );
  3892. if ( LogonSession == NULL ) {
  3893. Status = STATUS_NO_SUCH_LOGON_SESSION;
  3894. goto Cleanup;
  3895. }
  3896. *ProtocolReturnBuffer = ClientResponse;
  3897. ClientResponse = NULL;
  3898. *ReturnBufferLength = ResponseSize;
  3899. Cleanup:
  3900. if ( LogonSession != NULL ) {
  3901. KerbDereferenceLogonSession( LogonSession );
  3902. }
  3903. if ( Credential != NULL ) {
  3904. KerbDereferenceCredential( Credential );
  3905. }
  3906. KerbFree( RetrieveResponse );
  3907. if ( ClientResponse != NULL ) {
  3908. LsaFunctions->FreeClientBuffer(
  3909. NULL,
  3910. ClientResponse
  3911. );
  3912. }
  3913. *ProtocolStatus = Status;
  3914. return STATUS_SUCCESS;
  3915. }
  3916. #endif // 0
  3917. //+-------------------------------------------------------------------------
  3918. //
  3919. // Function: KerbDecryptMessage
  3920. //
  3921. // Synopsis: Decrypts a buffer with either the specified key or the d
  3922. // primary key from the specified logon session.
  3923. //
  3924. // Effects:
  3925. //
  3926. // Arguments: Same as Callpackage
  3927. //
  3928. // Requires:
  3929. //
  3930. // Returns:
  3931. //
  3932. // Notes:
  3933. //
  3934. //
  3935. //--------------------------------------------------------------------------
  3936. NTSTATUS NTAPI
  3937. KerbDecryptMessage(
  3938. IN PLSA_CLIENT_REQUEST ClientRequest,
  3939. IN PVOID ProtocolSubmitBuffer,
  3940. IN PVOID ClientBufferBase,
  3941. IN ULONG SubmitBufferSize,
  3942. OUT PVOID *ProtocolReturnBuffer,
  3943. OUT PULONG ReturnBufferLength,
  3944. OUT PNTSTATUS ProtocolStatus
  3945. )
  3946. {
  3947. NTSTATUS Status;
  3948. SECPKG_CLIENT_INFO ClientInfo;
  3949. PLUID LogonId;
  3950. PKERB_LOGON_SESSION LogonSession = NULL;
  3951. PKERB_DECRYPT_REQUEST DecryptRequest;
  3952. PBYTE DecryptResponse = NULL;
  3953. ULONG ResponseLength = 0;
  3954. PBYTE ClientResponse = NULL;
  3955. PKERB_ENCRYPTION_KEY KeyToUse = NULL;
  3956. KERB_ENCRYPTION_KEY SuppliedKey = {0};
  3957. BOOLEAN FreeKey = FALSE;
  3958. PCRYPTO_SYSTEM CryptoSystem = NULL;
  3959. PCRYPT_STATE_BUFFER CryptBuffer = NULL;
  3960. //
  3961. // Verify the request.
  3962. //
  3963. D_DebugLog((DEB_TRACE, "Decrypting Message\n"));
  3964. if (SubmitBufferSize < sizeof(KERB_DECRYPT_REQUEST))
  3965. {
  3966. Status = STATUS_INVALID_PARAMETER;
  3967. goto Cleanup;
  3968. }
  3969. DecryptRequest = (PKERB_DECRYPT_REQUEST) ProtocolSubmitBuffer;
  3970. //
  3971. // Validate the pointers
  3972. //
  3973. if (DecryptRequest->InitialVector != NULL)
  3974. {
  3975. if (DecryptRequest->InitialVector - (PUCHAR) ClientBufferBase + DecryptRequest->InitialVectorSize > SubmitBufferSize)
  3976. {
  3977. DebugLog((DEB_ERROR,"InitialVector end pass end of buffer\n"));
  3978. Status = STATUS_INVALID_PARAMETER;
  3979. goto Cleanup;
  3980. }
  3981. if (DecryptRequest->InitialVector < (PUCHAR) ClientBufferBase + sizeof(KERB_DECRYPT_REQUEST))
  3982. {
  3983. DebugLog((DEB_ERROR,"InitialVector begin before end of DECRYPT_REQUEST\n"));
  3984. Status = STATUS_INVALID_PARAMETER;
  3985. goto Cleanup;
  3986. }
  3987. DecryptRequest->InitialVector = DecryptRequest->InitialVector - (PUCHAR) ClientBufferBase + (PUCHAR) ProtocolSubmitBuffer;
  3988. }
  3989. else
  3990. {
  3991. if (DecryptRequest->InitialVectorSize != 0)
  3992. {
  3993. DebugLog((DEB_ERROR,"Non-zero vector size with null vector\n"));
  3994. Status = STATUS_INVALID_PARAMETER;
  3995. goto Cleanup;
  3996. }
  3997. }
  3998. if (DecryptRequest->EncryptedData - (PUCHAR) ClientBufferBase + DecryptRequest->EncryptedDataSize > SubmitBufferSize)
  3999. {
  4000. DebugLog((DEB_ERROR,"EncryptedData end past end of request buffer\n"));
  4001. Status = STATUS_INVALID_PARAMETER;
  4002. goto Cleanup;
  4003. }
  4004. if (DecryptRequest->EncryptedData < (PUCHAR) ClientBufferBase + sizeof(KERB_DECRYPT_REQUEST))
  4005. {
  4006. DebugLog((DEB_ERROR,"EncryptedData begin before end of DECRYPT_REQUEST\n"));
  4007. Status = STATUS_INVALID_PARAMETER;
  4008. goto Cleanup;
  4009. }
  4010. DecryptRequest->EncryptedData = DecryptRequest->EncryptedData - (PUCHAR) ClientBufferBase + (PUCHAR) ProtocolSubmitBuffer;
  4011. //
  4012. // If the caller wants the default key, then open the specified logon
  4013. // session and get out the key.
  4014. //
  4015. if (DecryptRequest->Flags & KERB_DECRYPT_FLAG_DEFAULT_KEY)
  4016. {
  4017. //
  4018. // Find the callers logon id & TCB status
  4019. //
  4020. Status = LsaFunctions->GetClientInfo(&ClientInfo);
  4021. if (!NT_SUCCESS(Status))
  4022. {
  4023. goto Cleanup;
  4024. }
  4025. //
  4026. // If the caller did not provide a logon id, use the caller's logon id.
  4027. //
  4028. if ( RtlIsZeroLuid( &DecryptRequest->LogonId ) )
  4029. {
  4030. LogonId = &ClientInfo.LogonId;
  4031. }
  4032. else
  4033. {
  4034. //
  4035. // Verify the caller has TCB privilege if they want access to someone
  4036. // elses ticket cache.
  4037. //
  4038. if (!ClientInfo.HasTcbPrivilege)
  4039. {
  4040. Status = STATUS_PRIVILEGE_NOT_HELD;
  4041. goto Cleanup;
  4042. }
  4043. LogonId = &DecryptRequest->LogonId;
  4044. }
  4045. LogonSession = KerbReferenceLogonSession(
  4046. LogonId,
  4047. FALSE // don't unlink
  4048. );
  4049. if (LogonSession == NULL)
  4050. {
  4051. Status = STATUS_NO_SUCH_LOGON_SESSION;
  4052. goto Cleanup;
  4053. }
  4054. //
  4055. // Get the key from the logon session
  4056. //
  4057. KerbReadLockLogonSessions(LogonSession);
  4058. if (LogonSession->PrimaryCredentials.Passwords != NULL)
  4059. {
  4060. KeyToUse = KerbGetKeyFromList(
  4061. LogonSession->PrimaryCredentials.Passwords,
  4062. DecryptRequest->CryptoType
  4063. );
  4064. if (KeyToUse != NULL)
  4065. {
  4066. KERBERR KerbErr;
  4067. KerbErr = KerbDuplicateKey(
  4068. &SuppliedKey,
  4069. KeyToUse
  4070. );
  4071. KeyToUse = NULL;
  4072. Status = KerbMapKerbError(KerbErr);
  4073. }
  4074. else
  4075. {
  4076. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  4077. }
  4078. }
  4079. else
  4080. {
  4081. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  4082. }
  4083. KerbUnlockLogonSessions(LogonSession);
  4084. if (!NT_SUCCESS(Status))
  4085. {
  4086. goto Cleanup;
  4087. }
  4088. KeyToUse = &SuppliedKey;
  4089. FreeKey = TRUE;
  4090. }
  4091. else
  4092. {
  4093. if (DecryptRequest->Key.Value - (PUCHAR) ClientBufferBase + DecryptRequest->Key.Length > SubmitBufferSize)
  4094. {
  4095. DebugLog((DEB_ERROR,"End of supplied key past end of request buffer\n"));
  4096. Status = STATUS_INVALID_PARAMETER;
  4097. goto Cleanup;
  4098. }
  4099. if (DecryptRequest->Key.Value < (PUCHAR) ClientBufferBase + sizeof(KERB_DECRYPT_REQUEST))
  4100. {
  4101. DebugLog((DEB_ERROR,"Begin of supplied key before end of DECRYPT_REQUEST\n"));
  4102. Status = STATUS_INVALID_PARAMETER;
  4103. goto Cleanup;
  4104. }
  4105. DecryptRequest->Key.Value = DecryptRequest->Key.Value - (PUCHAR) ClientBufferBase + (PUCHAR) ProtocolSubmitBuffer;
  4106. SuppliedKey.keytype = DecryptRequest->Key.KeyType;
  4107. SuppliedKey.keyvalue.value = DecryptRequest->Key.Value;
  4108. SuppliedKey.keyvalue.length = DecryptRequest->Key.Length;
  4109. KeyToUse = &SuppliedKey;
  4110. }
  4111. //
  4112. // Now do the decryption
  4113. //
  4114. SafeAllocaAllocate(DecryptResponse, DecryptRequest->EncryptedDataSize);
  4115. if (DecryptResponse == NULL)
  4116. {
  4117. Status = STATUS_INSUFFICIENT_RESOURCES;
  4118. goto Cleanup;
  4119. }
  4120. ResponseLength = DecryptRequest->EncryptedDataSize;
  4121. Status = CDLocateCSystem(
  4122. DecryptRequest->CryptoType,
  4123. &CryptoSystem
  4124. );
  4125. if (!NT_SUCCESS(Status))
  4126. {
  4127. goto Cleanup;
  4128. }
  4129. //
  4130. // The crypt system must be integrity protected - otherwise it may be
  4131. // used as a general purpose encryption/decryption technique.
  4132. //
  4133. if ((CryptoSystem->Attributes & CSYSTEM_INTEGRITY_PROTECTED) == 0)
  4134. {
  4135. DebugLog((DEB_ERROR,"Trying to decrypt with non-integrity protected crypt system (%d)\n",
  4136. CryptoSystem->EncryptionType));
  4137. Status = STATUS_INVALID_PARAMETER;
  4138. goto Cleanup;
  4139. }
  4140. Status = CryptoSystem->Initialize(
  4141. KeyToUse->keyvalue.value,
  4142. KeyToUse->keyvalue.length,
  4143. DecryptRequest->KeyUsage,
  4144. &CryptBuffer
  4145. );
  4146. if (!NT_SUCCESS(Status))
  4147. {
  4148. goto Cleanup;
  4149. }
  4150. //
  4151. // If there was an initial vector, use it now
  4152. //
  4153. if (DecryptRequest->InitialVectorSize != 0)
  4154. {
  4155. Status = CryptoSystem->Control(
  4156. CRYPT_CONTROL_SET_INIT_VECT,
  4157. CryptBuffer,
  4158. DecryptRequest->InitialVector,
  4159. DecryptRequest->InitialVectorSize
  4160. );
  4161. if (!NT_SUCCESS(Status))
  4162. {
  4163. goto Cleanup;
  4164. }
  4165. }
  4166. //
  4167. // Decrypt
  4168. //
  4169. Status = CryptoSystem->Decrypt(
  4170. CryptBuffer,
  4171. DecryptRequest->EncryptedData,
  4172. DecryptRequest->EncryptedDataSize,
  4173. DecryptResponse,
  4174. &ResponseLength
  4175. );
  4176. if (!NT_SUCCESS(Status))
  4177. {
  4178. goto Cleanup;
  4179. }
  4180. //
  4181. // Return the decrypted data to the client
  4182. //
  4183. Status = LsaFunctions->AllocateClientBuffer(
  4184. NULL,
  4185. ResponseLength,
  4186. (PVOID *) &ClientResponse
  4187. );
  4188. if (!NT_SUCCESS(Status))
  4189. {
  4190. goto Cleanup;
  4191. }
  4192. Status = LsaFunctions->CopyToClientBuffer(
  4193. NULL,
  4194. ResponseLength,
  4195. ClientResponse,
  4196. DecryptResponse
  4197. );
  4198. if (!NT_SUCCESS(Status))
  4199. {
  4200. goto Cleanup;
  4201. }
  4202. *ProtocolReturnBuffer = ClientResponse;
  4203. ClientResponse = NULL;
  4204. *ReturnBufferLength = ResponseLength;
  4205. Cleanup:
  4206. if ((CryptoSystem != NULL) && (CryptBuffer != NULL))
  4207. {
  4208. CryptoSystem->Discard(&CryptBuffer);
  4209. }
  4210. if (FreeKey)
  4211. {
  4212. KerbFreeKey(&SuppliedKey);
  4213. }
  4214. if (LogonSession != NULL)
  4215. {
  4216. KerbDereferenceLogonSession(LogonSession);
  4217. }
  4218. SafeAllocaFree(DecryptResponse);
  4219. if (ClientResponse != NULL)
  4220. {
  4221. LsaFunctions->FreeClientBuffer(
  4222. NULL,
  4223. ClientResponse
  4224. );
  4225. }
  4226. *ProtocolStatus = Status;
  4227. return(STATUS_SUCCESS);
  4228. }
  4229. //+-------------------------------------------------------------------------
  4230. //
  4231. // Function: KerbAddBindingCacheEntry
  4232. //
  4233. // Synopsis: Adds an entry to the binding cache
  4234. //
  4235. // Effects:
  4236. //
  4237. // Arguments: Same as Callpackage
  4238. //
  4239. // Requires:
  4240. //
  4241. // Returns:
  4242. //
  4243. // Notes:
  4244. //
  4245. //
  4246. //--------------------------------------------------------------------------
  4247. NTSTATUS NTAPI
  4248. KerbAddBindingCacheEntry(
  4249. IN PLSA_CLIENT_REQUEST ClientRequest,
  4250. IN PVOID ProtocolSubmitBuffer,
  4251. IN PVOID ClientBufferBase,
  4252. IN ULONG SubmitBufferSize,
  4253. OUT PVOID *ProtocolReturnBuffer,
  4254. OUT PULONG ReturnBufferLength,
  4255. OUT PNTSTATUS ProtocolStatus
  4256. )
  4257. {
  4258. NTSTATUS Status;
  4259. SECPKG_CLIENT_INFO ClientInfo;
  4260. PKERB_ADD_BINDING_CACHE_ENTRY_REQUEST BindingRequest = ( PKERB_ADD_BINDING_CACHE_ENTRY_REQUEST )ProtocolSubmitBuffer;
  4261. PKERB_BINDING_CACHE_ENTRY CacheEntry = NULL;
  4262. ULONG StructureSize = sizeof( KERB_ADD_BINDING_CACHE_ENTRY_REQUEST );
  4263. //
  4264. // Verify the request.
  4265. //
  4266. D_DebugLog(( DEB_TRACE, "Addding binding cache entry\n" ));
  4267. #if _WIN64
  4268. SECPKG_CALL_INFO CallInfo;
  4269. //
  4270. // Return 32-bit cache entries if this is a WOW caller
  4271. //
  4272. if(!LsaFunctions->GetCallInfo( &CallInfo ))
  4273. {
  4274. Status = STATUS_INTERNAL_ERROR;
  4275. goto Cleanup;
  4276. }
  4277. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) {
  4278. StructureSize = sizeof( KERB_ADD_BINDING_CACHE_ENTRY_REQUEST_WOW64 );
  4279. }
  4280. #endif // _WIN64
  4281. if ( SubmitBufferSize < StructureSize ) {
  4282. Status = STATUS_INVALID_PARAMETER;
  4283. goto Cleanup;
  4284. }
  4285. #if _WIN64
  4286. KERB_ADD_BINDING_CACHE_ENTRY_REQUEST LocalBindingRequest;
  4287. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) {
  4288. //
  4289. // Thunk 32-bit pointers if this is a WOW caller
  4290. //
  4291. PKERB_ADD_BINDING_CACHE_ENTRY_REQUEST_WOW64 BindingRequestWOW =
  4292. ( PKERB_ADD_BINDING_CACHE_ENTRY_REQUEST_WOW64 )BindingRequest;
  4293. LocalBindingRequest.MessageType = BindingRequestWOW->MessageType;
  4294. UNICODE_STRING_FROM_WOW_STRING(
  4295. &LocalBindingRequest.RealmName,
  4296. &BindingRequestWOW->RealmName );
  4297. UNICODE_STRING_FROM_WOW_STRING(
  4298. &LocalBindingRequest.KdcAddress,
  4299. &BindingRequestWOW->KdcAddress );
  4300. LocalBindingRequest.AddressType = BindingRequestWOW->AddressType;
  4301. BindingRequest = &LocalBindingRequest;
  4302. }
  4303. #endif // _WIN64
  4304. //
  4305. // Normalize the strings
  4306. //
  4307. NULL_RELOCATE_ONE( &BindingRequest->RealmName );
  4308. NULL_RELOCATE_ONE( &BindingRequest->KdcAddress );
  4309. //
  4310. // Find the callers logon id & TCB status
  4311. //
  4312. Status = LsaFunctions->GetClientInfo( &ClientInfo );
  4313. if ( !NT_SUCCESS( Status )) {
  4314. goto Cleanup;
  4315. }
  4316. //
  4317. // Require the caller to have TCB.
  4318. //
  4319. if ( !ClientInfo.HasTcbPrivilege ) {
  4320. Status = STATUS_PRIVILEGE_NOT_HELD;
  4321. goto Cleanup;
  4322. }
  4323. Status = KerbCacheBinding(
  4324. &BindingRequest->RealmName,
  4325. &BindingRequest->KdcAddress,
  4326. BindingRequest->AddressType,
  4327. 0,
  4328. 0,
  4329. 0,
  4330. &CacheEntry
  4331. );
  4332. Cleanup:
  4333. if ( CacheEntry != NULL ) {
  4334. KerbDereferenceBindingCacheEntry( CacheEntry );
  4335. }
  4336. *ProtocolReturnBuffer = NULL;
  4337. *ReturnBufferLength = 0;
  4338. *ProtocolStatus = Status;
  4339. return STATUS_SUCCESS;
  4340. }
  4341. NTSTATUS
  4342. VerifyCredentials(
  4343. IN PUNICODE_STRING UserName,
  4344. IN PUNICODE_STRING DomainName,
  4345. IN PUNICODE_STRING Password
  4346. )
  4347. {
  4348. SAMPR_HANDLE UserHandle = NULL;
  4349. PSAMPR_USER_INFO_BUFFER UserAllInfo = NULL;
  4350. PSAMPR_USER_ALL_INFORMATION UserAll;
  4351. SID_AND_ATTRIBUTES_LIST GroupMembership;
  4352. NT_OWF_PASSWORD NtOwfPassword;
  4353. BOOLEAN UpdateLogonStats = FALSE;
  4354. NTSTATUS Status = STATUS_LOGON_FAILURE;
  4355. GroupMembership.SidAndAttributes = NULL;
  4356. //
  4357. // lazy initialization of SAM handles.
  4358. //
  4359. if( KerbGlobalDomainHandle == NULL )
  4360. {
  4361. SAMPR_HANDLE SamHandle = NULL;
  4362. SAMPR_HANDLE DomainHandle = NULL;
  4363. PLSAPR_POLICY_INFORMATION PolicyInfo = NULL;
  4364. //
  4365. // Open SAM to get the account information
  4366. //
  4367. Status = SamIConnect(
  4368. NULL, // no server name
  4369. &SamHandle,
  4370. 0, // no desired access
  4371. TRUE // trusted caller
  4372. );
  4373. if (!NT_SUCCESS(Status))
  4374. {
  4375. goto Cleanup;
  4376. }
  4377. if(InterlockedCompareExchangePointer(
  4378. &KerbGlobalSamHandle,
  4379. SamHandle,
  4380. NULL
  4381. ) != NULL)
  4382. {
  4383. SamrCloseHandle( &SamHandle );
  4384. }
  4385. Status = LsaIQueryInformationPolicyTrusted(
  4386. PolicyAccountDomainInformation,
  4387. &PolicyInfo
  4388. );
  4389. if (!NT_SUCCESS(Status))
  4390. {
  4391. goto Cleanup;
  4392. }
  4393. Status = SamrOpenDomain(
  4394. KerbGlobalSamHandle,
  4395. 0, // no desired access
  4396. (PRPC_SID) PolicyInfo->PolicyAccountDomainInfo.DomainSid,
  4397. &DomainHandle
  4398. );
  4399. LsaIFree_LSAPR_POLICY_INFORMATION(
  4400. PolicyAccountDomainInformation,
  4401. PolicyInfo
  4402. );
  4403. if (!NT_SUCCESS(Status))
  4404. {
  4405. goto Cleanup;
  4406. }
  4407. if(InterlockedCompareExchangePointer(
  4408. &KerbGlobalDomainHandle,
  4409. DomainHandle,
  4410. NULL
  4411. ) != NULL)
  4412. {
  4413. SamrCloseHandle( &DomainHandle );
  4414. }
  4415. }
  4416. //
  4417. // try by DN first, then by UPN/SAM accountname.
  4418. //
  4419. Status = SamIGetUserLogonInformationEx(
  4420. KerbGlobalDomainHandle,
  4421. SAM_OPEN_BY_DN | SAM_NO_MEMBERSHIPS,
  4422. UserName,
  4423. USER_ALL_OWFPASSWORD | // OWFs
  4424. USER_ALL_NTPASSWORDPRESENT | // OWF present bits.
  4425. USER_ALL_LMPASSWORDPRESENT | // OWF present bits.
  4426. USER_ALL_BADPASSWORDCOUNT | // bad password count.
  4427. USER_ALL_USERACCOUNTCONTROL, // UserAccountControl - account disabled/etc.
  4428. &UserAllInfo,
  4429. &GroupMembership,
  4430. &UserHandle
  4431. );
  4432. if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
  4433. Status == STATUS_OBJECT_NAME_INVALID)
  4434. {
  4435. Status = SamIGetUserLogonInformationEx(
  4436. KerbGlobalDomainHandle,
  4437. SAM_OPEN_BY_UPN_OR_ACCOUNTNAME | SAM_NO_MEMBERSHIPS,
  4438. UserName,
  4439. USER_ALL_OWFPASSWORD | // OWFs
  4440. USER_ALL_NTPASSWORDPRESENT | // OWF present bits.
  4441. USER_ALL_LMPASSWORDPRESENT | // OWF present bits.
  4442. USER_ALL_BADPASSWORDCOUNT | // bad password count.
  4443. USER_ALL_USERACCOUNTCONTROL, // UserAccountControl - account disabled/etc.
  4444. &UserAllInfo,
  4445. &GroupMembership,
  4446. &UserHandle
  4447. );
  4448. }
  4449. if ( !NT_SUCCESS(Status) ) {
  4450. goto Cleanup;
  4451. }
  4452. UserAll = &UserAllInfo->All;
  4453. Status = RtlCalculateNtOwfPassword(
  4454. Password,
  4455. &NtOwfPassword
  4456. );
  4457. if( !NT_SUCCESS(Status) )
  4458. {
  4459. goto Cleanup;
  4460. }
  4461. Status = STATUS_LOGON_FAILURE;
  4462. if (UserAll->UserAccountControl & USER_ACCOUNT_DISABLED)
  4463. {
  4464. goto Cleanup;
  4465. }
  4466. if (UserAll->UserAccountControl & USER_ACCOUNT_AUTO_LOCKED)
  4467. {
  4468. goto Cleanup;
  4469. }
  4470. if ( !UserAll->NtPasswordPresent )
  4471. {
  4472. if( UserAll->LmPasswordPresent )
  4473. {
  4474. goto Cleanup;
  4475. }
  4476. if (RtlCompareMemory(
  4477. &NtOwfPassword,
  4478. &KerbGlobalNullNtOwfPassword,
  4479. NT_OWF_PASSWORD_LENGTH
  4480. ) != NT_OWF_PASSWORD_LENGTH)
  4481. {
  4482. UpdateLogonStats = TRUE;
  4483. goto Cleanup;
  4484. }
  4485. } else {
  4486. if (RtlCompareMemory(
  4487. &NtOwfPassword,
  4488. UserAll->NtOwfPassword.Buffer,
  4489. NT_OWF_PASSWORD_LENGTH
  4490. ) != NT_OWF_PASSWORD_LENGTH)
  4491. {
  4492. UpdateLogonStats = TRUE;
  4493. goto Cleanup;
  4494. }
  4495. }
  4496. //
  4497. // success!
  4498. //
  4499. if ( UserAll->BadPasswordCount )
  4500. {
  4501. //
  4502. // successful logon, insure logon status gets updated for the lockout/bad password case.
  4503. //
  4504. UpdateLogonStats = TRUE;
  4505. }
  4506. Status = STATUS_SUCCESS;
  4507. Cleanup:
  4508. ZeroMemory( &NtOwfPassword, sizeof(NtOwfPassword) );
  4509. if( UserAllInfo != NULL )
  4510. {
  4511. //
  4512. // SamIFree zeroes the sensitive fields.
  4513. //
  4514. SamIFree_SAMPR_USER_INFO_BUFFER( UserAllInfo, UserAllInformation );
  4515. }
  4516. if( UpdateLogonStats )
  4517. {
  4518. SAM_LOGON_STATISTICS LogonStats;
  4519. RtlZeroMemory(&LogonStats, sizeof(LogonStats));
  4520. if( NT_SUCCESS(Status) )
  4521. {
  4522. LogonStats.StatisticsToApply = USER_LOGON_INTER_SUCCESS_LOGON;
  4523. } else {
  4524. LogonStats.StatisticsToApply = USER_LOGON_BAD_PASSWORD;
  4525. }
  4526. SamIUpdateLogonStatistics( UserHandle, &LogonStats );
  4527. }
  4528. if (UserHandle != NULL)
  4529. {
  4530. SamrCloseHandle( &UserHandle );
  4531. }
  4532. if (GroupMembership.SidAndAttributes != NULL)
  4533. {
  4534. SamIFreeSidAndAttributesList(&GroupMembership);
  4535. }
  4536. return Status;
  4537. }
  4538. NTSTATUS NTAPI
  4539. KerbVerifyCredentials(
  4540. IN PLSA_CLIENT_REQUEST ClientRequest,
  4541. IN PVOID ProtocolSubmitBuffer,
  4542. IN PVOID ClientBufferBase,
  4543. IN ULONG SubmitBufferSize,
  4544. OUT PVOID *ProtocolReturnBuffer,
  4545. OUT PULONG ReturnBufferLength,
  4546. OUT PNTSTATUS ProtocolStatus
  4547. )
  4548. {
  4549. PKERB_VERIFY_CREDENTIALS_REQUEST VerifyRequest = NULL;
  4550. NTSTATUS Status = STATUS_LOGON_FAILURE;
  4551. //
  4552. // Verify the request.
  4553. //
  4554. D_DebugLog((DEB_TRACE, "KerbVerifyCredentials\n"));
  4555. //
  4556. // only support in proc use of this interface.
  4557. //
  4558. if( ClientRequest != NULL )
  4559. {
  4560. Status = STATUS_INVALID_PARAMETER;
  4561. goto Cleanup;
  4562. }
  4563. if (SubmitBufferSize < sizeof(KERB_VERIFY_CREDENTIALS_REQUEST))
  4564. {
  4565. Status = STATUS_INVALID_PARAMETER;
  4566. goto Cleanup;
  4567. }
  4568. VerifyRequest = (PKERB_VERIFY_CREDENTIALS_REQUEST) ProtocolSubmitBuffer;
  4569. #if 0 // only needed if out-proc supported.
  4570. //
  4571. // Normalize the strings
  4572. //
  4573. if( ClientRequest != NULL )
  4574. {
  4575. NULL_RELOCATE_ONE(&VerifyRequest->UserName);
  4576. NULL_RELOCATE_ONE(&VerifyRequest->DomainName);
  4577. NULL_RELOCATE_ONE(&VerifyRequest->Password);
  4578. }
  4579. #endif
  4580. *ProtocolReturnBuffer = NULL;
  4581. *ReturnBufferLength = 0;
  4582. Status = VerifyCredentials(
  4583. &VerifyRequest->UserName,
  4584. &VerifyRequest->DomainName,
  4585. &VerifyRequest->Password
  4586. );
  4587. Cleanup:
  4588. *ProtocolStatus = Status;
  4589. return(STATUS_SUCCESS);
  4590. }