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

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