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

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