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

3555 lines
98 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: getas.cxx
  7. //
  8. // Contents: GetASTicket and support functions
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 04-Mar-94 wader Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include "kdcsvr.hxx"
  18. #include "kdctrace.h"
  19. #include "krb5p.h"
  20. #include <userall.h>
  21. #include "fileno.h"
  22. #define FILENO FILENO_GETAS
  23. LARGE_INTEGER tsInfinity = {0xffffffff,0x7fffffff};
  24. LONG lInfinity = 0x7fffffff;
  25. enum {
  26. SubAuthUnknown,
  27. SubAuthNoFilter,
  28. SubAuthYesFilter
  29. } KdcSubAuthFilterPresent = SubAuthUnknown;
  30. extern "C"
  31. NTSTATUS NTAPI
  32. Msv1_0ExportSubAuthenticationRoutine(
  33. IN NETLOGON_LOGON_INFO_CLASS LogonLevel,
  34. IN PVOID LogonInformation,
  35. IN ULONG Flags,
  36. IN ULONG DllNumber,
  37. IN PUSER_ALL_INFORMATION UserAll,
  38. OUT PULONG WhichFields,
  39. OUT PULONG UserFlags,
  40. OUT PBOOLEAN Authoritative,
  41. OUT PLARGE_INTEGER LogoffTime,
  42. OUT PLARGE_INTEGER KickoffTime
  43. );
  44. extern "C"
  45. BOOLEAN NTAPI
  46. Msv1_0SubAuthenticationPresent(
  47. IN ULONG DllNumber
  48. );
  49. ULONG
  50. NetpDcElapsedTime(
  51. IN ULONG StartTime
  52. )
  53. /*++
  54. Routine Description:
  55. Returns the time (in milliseconds) that has elapsed is StartTime.
  56. Arguments:
  57. StartTime - A time stamp from GetTickCount()
  58. Return Value:
  59. Returns the time (in milliseconds) that has elapsed is StartTime.
  60. --*/
  61. {
  62. ULONG CurrentTime;
  63. //
  64. // If time has has wrapped,
  65. // account for it.
  66. //
  67. CurrentTime = GetTickCount();
  68. if ( CurrentTime >= StartTime ) {
  69. return CurrentTime - StartTime;
  70. } else {
  71. return (0xFFFFFFFF-StartTime) + CurrentTime;
  72. }
  73. }
  74. //+-------------------------------------------------------------------------
  75. //
  76. // Function: KdcForwardLogonToPDC
  77. //
  78. // Synopsis: Forwards a failed-password logon to the PDC.
  79. //
  80. // Effects:
  81. //
  82. // Arguments:
  83. //
  84. // Requires:
  85. //
  86. // Returns:
  87. //
  88. // Notes:
  89. //
  90. //
  91. //--------------------------------------------------------------------------
  92. KERBERR
  93. KdcForwardLogonToPDC(
  94. IN PKERB_MESSAGE_BUFFER InputMessage,
  95. IN PKERB_MESSAGE_BUFFER OutputMessage
  96. )
  97. {
  98. KERBERR KerbErr = KDC_ERR_NONE;
  99. NTSTATUS Status;
  100. BOOLEAN CalledPDC;
  101. KERB_MESSAGE_BUFFER Reply = {0};
  102. DOMAIN_SERVER_ROLE ServerRole;
  103. Status = SamIQueryServerRole(
  104. GlobalAccountDomainHandle,
  105. &ServerRole
  106. );
  107. if (!KdcGlobalAvoidPdcOnWan &&
  108. NT_SUCCESS(Status) &&
  109. (ServerRole == DomainServerRoleBackup))
  110. {
  111. Status = KerbMakeKdcCall(
  112. SecData.KdcDnsRealmName(),
  113. NULL, // no account name
  114. TRUE, // call the PDC
  115. TRUE, // use TCP/IP, not UDP
  116. InputMessage,
  117. &Reply,
  118. 0, // no additional flags
  119. &CalledPDC
  120. );
  121. if (!NT_SUCCESS(Status))
  122. {
  123. KerbErr = KRB_ERR_GENERIC;
  124. }
  125. else
  126. {
  127. OutputMessage->Buffer = (PBYTE) MIDL_user_allocate(Reply.BufferSize);
  128. if (OutputMessage->Buffer != NULL)
  129. {
  130. OutputMessage->BufferSize = Reply.BufferSize;
  131. RtlCopyMemory(
  132. OutputMessage->Buffer,
  133. Reply.Buffer,
  134. OutputMessage->BufferSize
  135. );
  136. }
  137. else
  138. {
  139. KerbErr = KRB_ERR_GENERIC;
  140. }
  141. KerbFree(Reply.Buffer);
  142. }
  143. }
  144. else
  145. {
  146. KerbErr = KRB_ERR_GENERIC;
  147. }
  148. return(KerbErr);
  149. }
  150. //+---------------------------------------------------------------------------
  151. //
  152. // Function: KdcVerifyKdcAsRep
  153. //
  154. // Synopsis: Verifies that our AS_REP came from a KDC, as opposed to a malicious
  155. // attacker by evaluating the TGT embedded in response
  156. //
  157. // Arguments: Reply PKERB_KDC_REPLY
  158. //
  159. // Returns: Boolean to client.
  160. //
  161. // History: 12-June-2000 Todds Created
  162. //
  163. //----------------------------------------------------------------------------
  164. BOOLEAN
  165. KdcVerifyKdcAsRep(
  166. PKERB_KDC_REPLY Reply,
  167. PKERB_PRINCIPAL_NAME RequestBodyClientName
  168. )
  169. {
  170. BOOLEAN fRet = FALSE;
  171. KERBERR KerbErr;
  172. KERB_EXT_ERROR ExtendedError;
  173. KDC_TICKET_INFO KrbtgtTicketInfo = {0};
  174. UNICODE_STRING ServerNames[3];
  175. UNICODE_STRING ClientName;
  176. ULONG NameType;
  177. PKERB_ENCRYPTION_KEY EncryptionKey = NULL;
  178. PKERB_ENCRYPTED_TICKET DecryptedTicket = NULL;
  179. KERB_REALM LocalRealm;
  180. PKERB_INTERNAL_NAME ReplyClientName = NULL;
  181. PKERB_INTERNAL_NAME TicketClientName = NULL;
  182. // Get the server key for krbtgt
  183. KerbErr = SecData.GetKrbtgtTicketInfo(&KrbtgtTicketInfo);
  184. if (!KERB_SUCCESS(KerbErr))
  185. {
  186. D_DebugLog((DEB_WARN, "SecData.Getkrbtgtticketinfo failed!\n"));
  187. goto Cleanup;
  188. }
  189. ServerNames[0] = *SecData.KdcFullServiceKdcName();
  190. ServerNames[1] = *SecData.KdcFullServiceDnsName();
  191. ServerNames[2] = *SecData.KdcFullServiceName();
  192. LocalRealm = SecData.KdcKerbDnsRealmName();
  193. //
  194. // Verify the realm of the ticket
  195. //
  196. if (!KerbCompareRealmNames(
  197. &LocalRealm,
  198. &Reply->ticket.realm
  199. ))
  200. {
  201. D_DebugLog((DEB_ERROR,"KLIN(%x) Tgt reply is not for our realm: %s instead of %s\n",
  202. KLIN(FILENO, __LINE__), Reply->ticket.realm, LocalRealm));
  203. KerbErr = KRB_AP_ERR_NOT_US;
  204. goto Cleanup;
  205. }
  206. EncryptionKey = KerbGetKeyFromList(
  207. KrbtgtTicketInfo.Passwords,
  208. Reply->ticket.encrypted_part.encryption_type
  209. );
  210. if (EncryptionKey == NULL)
  211. {
  212. D_DebugLog((DEB_ERROR, "Couldn't get key for decrypting krbtgt\n"));
  213. KerbErr = KRB_AP_ERR_NOKEY;
  214. goto Cleanup;
  215. }
  216. KerbErr = KerbVerifyTicket(
  217. &Reply->ticket,
  218. 3, // 3 names
  219. ServerNames,
  220. SecData.KdcDnsRealmName(),
  221. EncryptionKey,
  222. &SkewTime,
  223. &DecryptedTicket
  224. );
  225. if (!KERB_SUCCESS(KerbErr))
  226. {
  227. D_DebugLog((DEB_ERROR, "KLIN(%x) Failed to verify ticket - %x\n",
  228. KLIN(FILENO, __LINE__),KerbErr));
  229. goto Cleanup;
  230. }
  231. //
  232. // Verify the realm of the client is the same as our realm
  233. //
  234. if (!KerbCompareRealmNames(
  235. &LocalRealm,
  236. &DecryptedTicket->client_realm
  237. ))
  238. {
  239. D_DebugLog((DEB_ERROR,"KLIN(%x) Verified ticket client realm is wrong: %s instead of %s\n",
  240. KLIN(FILENO, __LINE__),DecryptedTicket->client_realm, LocalRealm));
  241. KerbErr = KRB_AP_ERR_NOT_US;
  242. goto Cleanup;
  243. }
  244. //
  245. // Verify the client name in the ticket matches the request body, and
  246. // reply body.
  247. //
  248. if (!KerbComparePrincipalNames(
  249. &DecryptedTicket->client_name,
  250. RequestBodyClientName
  251. ) ||
  252. !KerbComparePrincipalNames(
  253. &Reply->client_name,
  254. RequestBodyClientName
  255. ))
  256. {
  257. D_DebugLog((DEB_ERROR, "KLIN(%x) Client name AS_REP from PDC doesn't match request\n",
  258. KLIN(FILENO,__LINE__)));
  259. KerbErr = KRB_AP_ERR_MODIFIED;
  260. goto Cleanup;
  261. }
  262. fRet = TRUE;
  263. Cleanup:
  264. if (DecryptedTicket != NULL)
  265. {
  266. KerbFreeTicket(DecryptedTicket);
  267. }
  268. if (!fRet)
  269. {
  270. ClientName.Buffer = NULL;
  271. KerbConvertPrincipalNameToString(
  272. &ClientName,
  273. &NameType,
  274. RequestBodyClientName
  275. );
  276. ReportServiceEvent(
  277. EVENTLOG_ERROR_TYPE,
  278. KDCEVENT_INVALID_FORWARDED_AS_REQ,
  279. sizeof(ULONG),
  280. &KerbErr,
  281. 1, // number of strings
  282. ClientName.Buffer
  283. );
  284. if (ClientName.Buffer != NULL)
  285. {
  286. MIDL_user_free(ClientName.Buffer);
  287. }
  288. }
  289. return fRet;
  290. }
  291. //+---------------------------------------------------------------------------
  292. //
  293. // Function: FailedLogon
  294. //
  295. // Synopsis: Processes a failed logon.
  296. //
  297. // Effects: May raise an exception, audit, event, lockout, etc.
  298. //
  299. // Arguments: [UserHandle] -- [in] Client who didn't log on.
  300. // [ClientAddress] -- Address of client making request
  301. // [Client] -- [in optional] Sid of the client requesting logon
  302. // [ClientSize] -- [in] Length of the sid
  303. // [Reason] -- [in] the reason this logon failed.
  304. //
  305. // Requires:
  306. //
  307. // Returns: HRESULT to return to client.
  308. //
  309. // Algorithm:
  310. //
  311. // History: 03-May-94 wader Created
  312. //
  313. // Notes: This usually returns hrReason, but it may map it to
  314. // something else.
  315. //
  316. //----------------------------------------------------------------------------
  317. KERBERR
  318. FailedLogon( IN SAMPR_HANDLE UserHandle,
  319. IN OPTIONAL PSOCKADDR ClientAddress,
  320. IN PKERB_PRINCIPAL_NAME RequestBodyClientName,
  321. IN OPTIONAL UCHAR *Client,
  322. IN ULONG ClientSize,
  323. IN PKERB_MESSAGE_BUFFER InputMessage,
  324. IN PKERB_MESSAGE_BUFFER OutputMessage,
  325. IN PUNICODE_STRING ClientNetbiosAddress,
  326. IN KERBERR Reason )
  327. {
  328. NTSTATUS Status;
  329. SAM_LOGON_STATISTICS LogonStats;
  330. LARGE_INTEGER CurrentTime;
  331. PKERB_ERROR ErrorMessage = NULL;
  332. PKERB_KDC_REPLY Reply = NULL;
  333. TRACE(KDC, FailedLogon, DEB_FUNCTION);
  334. GetSystemTimeAsFileTime((PFILETIME)&CurrentTime);
  335. //
  336. // It's important to know why the logon can fail. For each possible
  337. // reason, decide if that is a reason to lock out the account.
  338. //
  339. //
  340. // Check to see if we've seen this request before recently
  341. //
  342. if (KDC_ERR_NONE == FailedRequests->Check(
  343. InputMessage->Buffer,
  344. InputMessage->BufferSize,
  345. NULL,
  346. 0,
  347. &CurrentTime,
  348. TRUE))
  349. {
  350. KERBERR KerbErr;
  351. KERBERR ForwardKerbErr;
  352. //
  353. // If the password was bad then we want to update the sam information
  354. //
  355. if (Reason == KDC_ERR_PREAUTH_FAILED)
  356. {
  357. RtlZeroMemory(&LogonStats, sizeof(LogonStats));
  358. LogonStats.StatisticsToApply =
  359. USER_LOGON_BAD_PASSWORD | USER_LOGON_BAD_PASSWORD_WKSTA | USER_LOGON_TYPE_KERBEROS;
  360. LogonStats.Workstation = *ClientNetbiosAddress;
  361. if ( (ClientAddress == NULL)
  362. || (ClientAddress->sa_family == AF_INET) ) {
  363. // Set to local address (known to be 4 bytes) or IP address
  364. LogonStats.ClientInfo.Type = SamClientIpAddr;
  365. LogonStats.ClientInfo.Data.IpAddr = *((ULONG*)GET_CLIENT_ADDRESS(ClientAddress));
  366. }
  367. Status = SamIUpdateLogonStatistics(
  368. UserHandle,
  369. &LogonStats
  370. );
  371. if ((NULL == Client) || (0 == ClientSize) ||
  372. (KDC_ERR_NONE == FailedRequests->Check(
  373. Client,
  374. ClientSize,
  375. ClientNetbiosAddress->Buffer,
  376. ClientNetbiosAddress->Length,
  377. &CurrentTime,
  378. FALSE)))
  379. {
  380. //
  381. // Pass this request to the KDC
  382. //
  383. KerbErr = KdcForwardLogonToPDC(
  384. InputMessage,
  385. OutputMessage
  386. );
  387. //
  388. // Return an better error if it wasn't generic.
  389. //
  390. if (KERB_SUCCESS(KerbErr))
  391. {
  392. ForwardKerbErr = KerbUnpackKerbError(
  393. OutputMessage->Buffer,
  394. OutputMessage->BufferSize,
  395. &ErrorMessage
  396. );
  397. if (KERB_SUCCESS(ForwardKerbErr))
  398. {
  399. if (ErrorMessage->error_code == KDC_ERR_PREAUTH_FAILED)
  400. {
  401. FailedRequests->Check(
  402. Client,
  403. ClientSize,
  404. ClientNetbiosAddress->Buffer,
  405. ClientNetbiosAddress->Length,
  406. &CurrentTime,
  407. TRUE
  408. );
  409. }
  410. } else {
  411. //
  412. // This may have been a successful, forwarded AS_REQ. If so,
  413. // reset bad password count on this BDC...
  414. //
  415. ForwardKerbErr = KerbUnpackAsReply(
  416. OutputMessage->Buffer,
  417. OutputMessage->BufferSize,
  418. &Reply
  419. );
  420. if (KERB_SUCCESS(ForwardKerbErr) && KdcVerifyKdcAsRep(
  421. Reply,
  422. RequestBodyClientName
  423. ))
  424. {
  425. RtlZeroMemory(&LogonStats, sizeof(LogonStats));
  426. LogonStats.StatisticsToApply =
  427. USER_LOGON_INTER_SUCCESS_LOGON | USER_LOGON_TYPE_KERBEROS;
  428. if ( (ClientAddress == NULL)
  429. || (ClientAddress->sa_family == AF_INET) ) {
  430. // Set to local address (known to be 4 bytes) or IP address
  431. LogonStats.ClientInfo.Type = SamClientIpAddr;
  432. LogonStats.ClientInfo.Data.IpAddr = *((ULONG*)GET_CLIENT_ADDRESS(ClientAddress));
  433. }
  434. Status = SamIUpdateLogonStatistics(
  435. UserHandle,
  436. &LogonStats
  437. );
  438. if (!NT_SUCCESS(Status))
  439. {
  440. D_DebugLog((DEB_ERROR,"Could not reset user bad pwd count - %x\n", Status));
  441. }
  442. } else {
  443. DebugLog((DEB_ERROR, "Got reply from fwd'd request to PDC, but wasn't valid!\n"));
  444. }
  445. }
  446. }
  447. else
  448. {
  449. if (KerbErr != KRB_ERR_GENERIC)
  450. {
  451. Reason = KerbErr;
  452. goto Cleanup;
  453. }
  454. }
  455. }
  456. }
  457. }
  458. Cleanup:
  459. if (NULL != ErrorMessage)
  460. {
  461. KerbFreeKerbError(ErrorMessage);
  462. }
  463. if (NULL != Reply)
  464. {
  465. KerbFreeAsReply(Reply);
  466. }
  467. return(Reason);
  468. }
  469. //+---------------------------------------------------------------------------
  470. //
  471. // Function: KdcHandleNoLogonServers
  472. //
  473. // Synopsis: If a password has verified, and we've got no GCs against which
  474. // to validate logon restrictions, then go ahead and set the
  475. // sam info level to include the new USER_LOGON_NO_LOGON_SERVERS
  476. // flag
  477. //
  478. // Effects:
  479. //
  480. // Arguments: [UserHandle] -- Client who logged on.
  481. // [ClientAddress] -- Address of client making request
  482. //
  483. //
  484. // Algorithm:
  485. //
  486. // History: 24-Aug-2000 Todds Created
  487. //
  488. // Notes: On successful logon w/ no GC, update SAM user flag
  489. //
  490. //----------------------------------------------------------------------------
  491. KERBERR
  492. KdcHandleNoLogonServers(
  493. SAMPR_HANDLE UserHandle,
  494. PSOCKADDR ClientAddress OPTIONAL
  495. )
  496. {
  497. SAM_LOGON_STATISTICS LogonStats;
  498. TRACE(KDC, KdcHandleNoLogonServers, DEB_FUNCTION);
  499. RtlZeroMemory(&LogonStats, sizeof(LogonStats));
  500. LogonStats.StatisticsToApply =
  501. USER_LOGON_NO_LOGON_SERVERS | USER_LOGON_TYPE_KERBEROS;
  502. if ( (ClientAddress == NULL)
  503. || (ClientAddress->sa_family == AF_INET) ) {
  504. // Set to local address (known to be 4 bytes) or IP address
  505. LogonStats.ClientInfo.Type = SamClientIpAddr;
  506. LogonStats.ClientInfo.Data.IpAddr = *((ULONG*)GET_CLIENT_ADDRESS(ClientAddress));
  507. }
  508. (VOID) SamIUpdateLogonStatistics(
  509. UserHandle,
  510. &LogonStats
  511. );
  512. return(KDC_ERR_NONE);
  513. }
  514. //+---------------------------------------------------------------------------
  515. //
  516. // Function: SuccessfulLogon
  517. //
  518. // Synopsis: Processes a successful logon.
  519. //
  520. // Effects: May raise an event, create an audit, throw a party.
  521. //
  522. // Arguments: [UserHandle] -- Client who logged on.
  523. // [ClientAddress] -- Address of client making request
  524. //
  525. //
  526. // Algorithm:
  527. //
  528. // History: 03-May-94 wader Created
  529. //
  530. // Notes: On successful logon, we discard the history of failed logons
  531. // (as far as lockout is concerned).
  532. //
  533. //----------------------------------------------------------------------------
  534. KERBERR
  535. SuccessfulLogon(
  536. IN SAMPR_HANDLE UserHandle,
  537. PSOCKADDR OPTIONAL ClientAddress,
  538. IN PKERB_MESSAGE_BUFFER Request,
  539. IN PUSER_INTERNAL6_INFORMATION UserInfo
  540. )
  541. {
  542. SAM_LOGON_STATISTICS LogonStats;
  543. KERB_MESSAGE_BUFFER Reply = {0};
  544. NTSTATUS Status = STATUS_UNKNOWN_REVISION;
  545. TRACE(KDC, SuccessfulLogon, DEB_FUNCTION);
  546. RtlZeroMemory(&LogonStats, sizeof(LogonStats));
  547. LogonStats.StatisticsToApply =
  548. USER_LOGON_INTER_SUCCESS_LOGON | USER_LOGON_TYPE_KERBEROS;
  549. if ( (ClientAddress == NULL)
  550. || (ClientAddress->sa_family == AF_INET) ) {
  551. // Set to local address (known to be 4 bytes) or IP address
  552. LogonStats.ClientInfo.Type = SamClientIpAddr;
  553. LogonStats.ClientInfo.Data.IpAddr = *((ULONG*)GET_CLIENT_ADDRESS(ClientAddress));
  554. }
  555. (VOID) SamIUpdateLogonStatistics(
  556. UserHandle,
  557. &LogonStats
  558. );
  559. //
  560. // if this logon reset the bad password count, notify the PDC
  561. //
  562. if (UserInfo->I1.BadPasswordCount != 0)
  563. {
  564. Status = SamIResetBadPwdCountOnPdc(UserHandle);
  565. if (!NT_SUCCESS(Status))
  566. {
  567. if (Status == STATUS_UNKNOWN_REVISION)
  568. {
  569. D_DebugLog((DEB_ERROR, "SamIResetBadPwdCount not implemented on pdc.\n"));
  570. // W2k behavior, in case we have an old PDC
  571. (VOID) KdcForwardLogonToPDC(
  572. Request,
  573. &Reply
  574. );
  575. if (Reply.Buffer != NULL)
  576. {
  577. MIDL_user_free(Reply.Buffer);
  578. }
  579. }
  580. else
  581. {
  582. D_DebugLog((DEB_ERROR, "SamIResetBadPwdCount failed - %x.\n", Status));
  583. }
  584. }
  585. }
  586. return(KDC_ERR_NONE);
  587. }
  588. //+-------------------------------------------------------------------------
  589. //
  590. // Function: IsSubAuthFilterPresent
  591. //
  592. // Synopsis: Figures out whether the MSV1_0 subauthentication filter is present
  593. //
  594. // Effects:
  595. //
  596. // Arguments:
  597. //
  598. // Requires:
  599. //
  600. // Returns: TRUE or FALSE
  601. //
  602. // Notes:
  603. //
  604. //
  605. //--------------------------------------------------------------------------
  606. BOOLEAN
  607. IsSubAuthFilterPresent()
  608. {
  609. if ( KdcSubAuthFilterPresent == SubAuthUnknown ) {
  610. if ( Msv1_0SubAuthenticationPresent( KERB_SUBAUTHENTICATION_FLAG )) {
  611. KdcSubAuthFilterPresent = SubAuthYesFilter;
  612. } else {
  613. KdcSubAuthFilterPresent = SubAuthNoFilter;
  614. }
  615. }
  616. if ( KdcSubAuthFilterPresent == SubAuthNoFilter ) {
  617. return FALSE;
  618. }
  619. return TRUE;
  620. }
  621. //+-------------------------------------------------------------------------
  622. //
  623. // Function: KdcCallSubAuthRoutine
  624. //
  625. // Synopsis: Calls the MSV1_0 subauthentication filter, if it is present
  626. //
  627. // Effects: If the filter returns an error, returns that error
  628. //
  629. // Arguments:
  630. //
  631. // Requires:
  632. //
  633. // Returns:
  634. //
  635. // Notes:
  636. //
  637. //
  638. //--------------------------------------------------------------------------
  639. KERBERR
  640. KdcCallSubAuthRoutine(
  641. IN PKDC_TICKET_INFO TicketInfo,
  642. IN PUSER_INTERNAL6_INFORMATION UserInfo,
  643. IN PUNICODE_STRING ClientNetbiosAddress,
  644. OUT PLARGE_INTEGER LogoffTime,
  645. OUT PKERB_EXT_ERROR pExtendedError
  646. )
  647. {
  648. NTSTATUS Status = STATUS_SUCCESS;
  649. KERBERR KerbErr = KDC_ERR_NONE;
  650. NETLOGON_INTERACTIVE_INFO LogonInfo = {0};
  651. //
  652. // Subauth parameters
  653. //
  654. ULONG WhichFields = 0;
  655. ULONG UserFlags = 0;
  656. BOOLEAN Authoritative = TRUE;
  657. LARGE_INTEGER KickoffTime;
  658. PUSER_ALL_INFORMATION UserAll = &UserInfo->I1;
  659. //
  660. // Check if Msv1_0 has a subauth filter loaded
  661. //
  662. if ( !IsSubAuthFilterPresent()) {
  663. return KDC_ERR_NONE;
  664. }
  665. LogonInfo.Identity.LogonDomainName = *SecData.KdcRealmName();
  666. LogonInfo.Identity.ParameterControl = 0; // this can be set to use a particular package
  667. LogonInfo.Identity.UserName = TicketInfo->AccountName;
  668. LogonInfo.Identity.Workstation = *ClientNetbiosAddress;
  669. //
  670. // Leave logon id field blank
  671. //
  672. if (UserAll->NtPassword.Length == NT_OWF_PASSWORD_LENGTH)
  673. {
  674. RtlCopyMemory(
  675. &LogonInfo.NtOwfPassword,
  676. UserAll->NtPassword.Buffer,
  677. NT_OWF_PASSWORD_LENGTH
  678. );
  679. }
  680. if (UserAll->LmPassword.Length == LM_OWF_PASSWORD_LENGTH)
  681. {
  682. RtlCopyMemory(
  683. &LogonInfo.LmOwfPassword,
  684. UserAll->LmPassword.Buffer,
  685. NT_OWF_PASSWORD_LENGTH
  686. );
  687. }
  688. //
  689. // Make sure logoff time is intialized to something interesting
  690. //
  691. *LogoffTime = KickoffTime = UserAll->AccountExpires;
  692. //
  693. // Make the call
  694. //
  695. Status = Msv1_0ExportSubAuthenticationRoutine(
  696. NetlogonInteractiveInformation,
  697. &LogonInfo,
  698. MSV1_0_PASSTHRU,
  699. KERB_SUBAUTHENTICATION_FLAG,
  700. UserAll,
  701. &WhichFields,
  702. &UserFlags,
  703. &Authoritative,
  704. LogoffTime,
  705. &KickoffTime
  706. );
  707. //
  708. // If the kickoff time is more restrictive, use it.
  709. //
  710. if (KickoffTime.QuadPart < LogoffTime->QuadPart)
  711. {
  712. LogoffTime->QuadPart = KickoffTime.QuadPart;
  713. }
  714. //
  715. // Map the error code
  716. //
  717. if (!NT_SUCCESS(Status))
  718. {
  719. DebugLog((DEB_WARN,
  720. "(KLIN:%x) Subauth failed the logon: 0x%x\n",
  721. KLIN(FILENO, __LINE__),
  722. Status));
  723. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  724. KerbErr = KDC_ERR_POLICY;
  725. }
  726. return(KerbErr);
  727. }
  728. //+-------------------------------------------------------------------------
  729. //
  730. // Function: KdcBuildEtypeInfo
  731. //
  732. // Synopsis: Builds a list of supported etypes & salts
  733. //
  734. // Effects:
  735. //
  736. // Arguments: TicketInfo - client's ticket info
  737. // OutputPreAuth - receives any preauth data to return to client
  738. //
  739. // Requires:
  740. //
  741. // Returns: kerberr
  742. //
  743. // Notes:
  744. //
  745. //
  746. //--------------------------------------------------------------------------
  747. KERBERR
  748. KdcBuildEtypeInfo(
  749. IN PKDC_TICKET_INFO TicketInfo,
  750. IN PKERB_KDC_REQUEST_BODY RequestBody,
  751. OUT PKERB_PA_DATA_LIST * OutputPreAuth
  752. )
  753. {
  754. KERBERR KerbErr = KDC_ERR_NONE;
  755. BOOLEAN FoundEtype = FALSE;
  756. ULONG Index;
  757. PKERB_ETYPE_INFO NextEntry = NULL;
  758. PKERB_ETYPE_INFO EtypeInfo = NULL;
  759. PKERB_PA_DATA_LIST OutputList = NULL;
  760. UNICODE_STRING TempSalt = {0};
  761. STRING TempString = {0};
  762. *OutputPreAuth = NULL;
  763. //
  764. // Build the array of etypes, in reverse order because we are adding
  765. // to the front of the list
  766. //
  767. for ( Index = TicketInfo->Passwords->CredentialCount; Index > 0; Index-- )
  768. {
  769. //
  770. // Only return types that the client supports.
  771. //
  772. if (!KdcCheckForEtype(
  773. RequestBody->encryption_type,
  774. TicketInfo->Passwords->Credentials[Index-1].Key.keytype
  775. ))
  776. {
  777. continue;
  778. }
  779. FoundEtype = TRUE;
  780. NextEntry = (PKERB_ETYPE_INFO) MIDL_user_allocate(sizeof(KERB_ETYPE_INFO));
  781. if (NextEntry == NULL)
  782. {
  783. KerbErr = KRB_ERR_GENERIC;
  784. goto Cleanup;
  785. }
  786. RtlZeroMemory(
  787. NextEntry,
  788. sizeof(KERB_ETYPE_INFO)
  789. );
  790. //
  791. // Copy in the etype
  792. //
  793. NextEntry->value.encryption_type =
  794. TicketInfo->Passwords->Credentials[Index-1].Key.keytype;
  795. //
  796. // add the salt - check the per-key salt and then the default salt.
  797. //
  798. if (TicketInfo->Passwords->Credentials[Index-1].Salt.Buffer != NULL)
  799. {
  800. TempSalt = TicketInfo->Passwords->Credentials[Index-1].Salt;
  801. }
  802. else if (TicketInfo->Passwords->DefaultSalt.Buffer != NULL)
  803. {
  804. TempSalt = TicketInfo->Passwords->DefaultSalt;
  805. }
  806. else
  807. {
  808. TempSalt.Buffer = NULL ;
  809. TempSalt.Length = 0 ;
  810. TempSalt.MaximumLength = 0 ;
  811. }
  812. //
  813. // If we have a salt, convert it to ansi & return it.
  814. //
  815. if (TempSalt.Buffer != NULL)
  816. {
  817. TempString.Buffer = NULL;
  818. TempString.Length = 0;
  819. TempString.MaximumLength = 0;
  820. KerbErr = KerbUnicodeStringToKerbString(
  821. &TempString,
  822. &TempSalt
  823. );
  824. if (!KERB_SUCCESS(KerbErr))
  825. {
  826. goto Cleanup;
  827. }
  828. NextEntry->value.bit_mask |= salt_present;
  829. NextEntry->value.salt.length = TempString.Length;
  830. NextEntry->value.salt.value = (PUCHAR) TempString.Buffer;
  831. }
  832. NextEntry->next = EtypeInfo;
  833. EtypeInfo = NextEntry;
  834. }
  835. //
  836. // If we can't find a matching etype, then we've got to return an error
  837. // to the client...
  838. if (FoundEtype)
  839. {
  840. OutputList = (PKERB_PA_DATA_LIST) MIDL_user_allocate(sizeof(KERB_PA_DATA_LIST));
  841. if (OutputList == NULL)
  842. {
  843. KerbErr = KRB_ERR_GENERIC;
  844. goto Cleanup;
  845. }
  846. RtlZeroMemory(
  847. OutputList,
  848. sizeof(KERB_PA_DATA_LIST)
  849. );
  850. OutputList->value.preauth_data_type = KRB5_PADATA_ETYPE_INFO;
  851. OutputList->next = NULL;
  852. KerbErr = KerbPackData(
  853. &EtypeInfo,
  854. PKERB_ETYPE_INFO_PDU,
  855. (PULONG) &OutputList->value.preauth_data.length,
  856. &OutputList->value.preauth_data.value
  857. );
  858. if (!KERB_SUCCESS(KerbErr))
  859. {
  860. goto Cleanup;
  861. }
  862. *OutputPreAuth = OutputList;
  863. OutputList = NULL;
  864. }
  865. else // did not find etype from request that we support, warn the admin
  866. {
  867. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  868. DebugLog((DEB_ERROR,"There is no union between client and server Etypes!\n"));
  869. KdcReportKeyError(
  870. &(TicketInfo->AccountName),
  871. NULL,
  872. KDCEVENT_NO_KEY_UNION_AS,
  873. RequestBody->encryption_type,
  874. TicketInfo->Passwords
  875. );
  876. }
  877. Cleanup:
  878. //
  879. // Cleanup the etype list, as it is returned in marshalled form.
  880. //
  881. while (EtypeInfo != NULL)
  882. {
  883. NextEntry = EtypeInfo->next;
  884. if (EtypeInfo->value.salt.value != NULL)
  885. {
  886. TempString.Buffer = (PCHAR) EtypeInfo->value.salt.value;
  887. TempString.Length = (USHORT) EtypeInfo->value.salt.length;
  888. KerbFreeString((PUNICODE_STRING) &TempString);
  889. }
  890. MIDL_user_free(EtypeInfo);
  891. EtypeInfo = NextEntry;
  892. }
  893. if (OutputList != NULL)
  894. {
  895. KerbFreePreAuthData( OutputList);
  896. }
  897. return KerbErr;
  898. }
  899. //+-------------------------------------------------------------------------
  900. //
  901. // Function: KdcBuildPreauthTypeList
  902. //
  903. // Synopsis: For returning with a PREAUTH-REQUIRED message
  904. //
  905. // Effects:
  906. //
  907. // Arguments:
  908. //
  909. // Requires:
  910. //
  911. // Returns:
  912. //
  913. // Notes:
  914. //
  915. //
  916. //--------------------------------------------------------------------------
  917. KERBERR
  918. KdcBuildPreauthTypeList(
  919. OUT PKERB_PA_DATA_LIST * PreauthTypeList
  920. )
  921. {
  922. PKERB_PA_DATA_LIST DataList = NULL;
  923. KERBERR KerbErr = KDC_ERR_NONE;
  924. //
  925. // Allocate and fill in the first item
  926. //
  927. DataList = (PKERB_PA_DATA_LIST) MIDL_user_allocate(sizeof(KERB_PA_DATA_LIST));
  928. if (DataList == NULL)
  929. {
  930. KerbErr = KRB_ERR_GENERIC;
  931. goto Cleanup;
  932. }
  933. RtlZeroMemory(
  934. DataList,
  935. sizeof(KERB_PA_DATA_LIST)
  936. );
  937. DataList->value.preauth_data_type = KRB5_PADATA_ENC_TIMESTAMP;
  938. //
  939. // Even if we fail the allocation, we can still return this value.
  940. //
  941. *PreauthTypeList = DataList;
  942. DataList->next = (PKERB_PA_DATA_LIST) MIDL_user_allocate(sizeof(KERB_PA_DATA_LIST));
  943. if (DataList->next == NULL)
  944. {
  945. KerbErr = KRB_ERR_GENERIC;
  946. goto Cleanup;
  947. }
  948. RtlZeroMemory(
  949. DataList->next,
  950. sizeof(KERB_PA_DATA_LIST)
  951. );
  952. DataList = DataList->next;
  953. DataList->value.preauth_data_type = KRB5_PADATA_PK_AS_REP;
  954. Cleanup:
  955. return(KerbErr);
  956. }
  957. //+-------------------------------------------------------------------------
  958. //
  959. // Function: KdcBuildPwSalt
  960. //
  961. // Synopsis: builds the pw-salt pa data type
  962. //
  963. // Effects:
  964. //
  965. // Arguments:
  966. //
  967. // Requires:
  968. //
  969. // Returns:
  970. //
  971. // Notes:
  972. //
  973. //
  974. //--------------------------------------------------------------------------
  975. KERBERR
  976. KdcBuildPwSalt(
  977. IN PKERB_STORED_CREDENTIAL Passwords,
  978. IN PKERB_ENCRYPTION_KEY ReplyKey,
  979. IN OUT PKERB_PA_DATA_LIST * OutputPreAuthData
  980. )
  981. {
  982. KERBERR KerbErr = KDC_ERR_NONE;
  983. PKERB_PA_DATA_LIST DataList = NULL;
  984. PKERB_KEY_DATA KeyData = NULL;
  985. STRING Salt = {0};
  986. UNICODE_STRING SaltUsed = {0};
  987. ULONG Index;
  988. //
  989. // Find the key use for encryption.
  990. //
  991. for (Index = 0; Index < Passwords->CredentialCount ; Index++ )
  992. {
  993. if (Passwords->Credentials[Index].Key.keytype == (int) ReplyKey->keytype)
  994. {
  995. KeyData = &Passwords->Credentials[Index];
  996. break;
  997. }
  998. }
  999. if (KeyData == NULL)
  1000. {
  1001. goto Cleanup;
  1002. }
  1003. //
  1004. // Locate the salt used
  1005. //
  1006. if (KeyData->Salt.Buffer != NULL)
  1007. {
  1008. SaltUsed = KeyData->Salt;
  1009. }
  1010. else if (Passwords->DefaultSalt.Buffer != NULL)
  1011. {
  1012. SaltUsed = Passwords->DefaultSalt;
  1013. }
  1014. //
  1015. // Convert the salt to a kerb string
  1016. //
  1017. KerbErr = KerbUnicodeStringToKerbString(
  1018. &Salt,
  1019. &SaltUsed
  1020. );
  1021. if (!KERB_SUCCESS(KerbErr))
  1022. {
  1023. goto Cleanup;
  1024. }
  1025. //
  1026. // Allocate and fill in the first item
  1027. //
  1028. DataList = (PKERB_PA_DATA_LIST) MIDL_user_allocate(sizeof(KERB_PA_DATA_LIST));
  1029. if (DataList == NULL)
  1030. {
  1031. KerbErr = KRB_ERR_GENERIC;
  1032. goto Cleanup;
  1033. }
  1034. RtlZeroMemory(
  1035. DataList,
  1036. sizeof(KERB_PA_DATA_LIST)
  1037. );
  1038. DataList->value.preauth_data_type = KRB5_PADATA_PW_SALT;
  1039. DataList->value.preauth_data.length = Salt.Length;
  1040. DataList->value.preauth_data.value = (PUCHAR) Salt.Buffer;
  1041. Salt.Buffer = NULL;
  1042. DataList->next = *OutputPreAuthData;
  1043. *OutputPreAuthData = DataList;
  1044. DataList = NULL;
  1045. Cleanup:
  1046. if (DataList != NULL)
  1047. {
  1048. KerbFreePreAuthData((PKERB_PA_DATA_LIST)DataList);
  1049. }
  1050. if (Salt.Buffer != NULL)
  1051. {
  1052. MIDL_user_free(Salt.Buffer);
  1053. }
  1054. return(KerbErr);
  1055. }
  1056. //+-------------------------------------------------------------------------
  1057. //
  1058. // Function: KdcVerifyEncryptedTimeStamp
  1059. //
  1060. // Synopsis: Verifies an encrypted time stamp pre-auth data
  1061. //
  1062. // Effects:
  1063. //
  1064. // Arguments: PreAuthData - preauth data from client
  1065. // TicketInfo - client's ticket info
  1066. // UserHandle - handle to client's account
  1067. // OutputPreAuth - receives any preauth data to return to client
  1068. //
  1069. // Requires:
  1070. //
  1071. // Returns: KDC_ERR_PREAUTH_FAILED - the password was bad
  1072. // Other errors - preauth failed but shouldn't trigger lockout
  1073. //
  1074. // Notes:
  1075. //
  1076. //
  1077. //--------------------------------------------------------------------------
  1078. KERBERR
  1079. KdcVerifyEncryptedTimeStamp(
  1080. IN PKERB_PA_DATA_LIST PreAuthData,
  1081. IN PKDC_TICKET_INFO TicketInfo,
  1082. IN PKERB_KDC_REQUEST_BODY RequestBody,
  1083. IN SAMPR_HANDLE UserHandle,
  1084. OUT PKERB_PA_DATA_LIST * OutputPreAuth
  1085. )
  1086. {
  1087. KERBERR KerbErr;
  1088. PKERB_ENCRYPTED_DATA EncryptedData = NULL;
  1089. PKERB_ENCRYPTED_TIMESTAMP EncryptedTime = NULL;
  1090. PKERB_ENCRYPTION_KEY UserKey = NULL;
  1091. LARGE_INTEGER CurrentTime;
  1092. LARGE_INTEGER ClientTime;
  1093. if ((TicketInfo->UserAccountControl & USER_ACCOUNT_DISABLED))
  1094. {
  1095. KerbErr = KDC_ERR_CLIENT_REVOKED;
  1096. goto Cleanup;
  1097. }
  1098. //
  1099. // Unpack the pre-auth data into an encrypted data first.
  1100. //
  1101. KerbErr = KerbUnpackEncryptedData(
  1102. PreAuthData->value.preauth_data.value,
  1103. PreAuthData->value.preauth_data.length,
  1104. &EncryptedData
  1105. );
  1106. if (!KERB_SUCCESS(KerbErr))
  1107. {
  1108. goto Cleanup;
  1109. }
  1110. //
  1111. // Now decrypt the encrypted data (in place)
  1112. //
  1113. UserKey = KerbGetKeyFromList(
  1114. TicketInfo->Passwords,
  1115. EncryptedData->encryption_type
  1116. );
  1117. if (UserKey == NULL)
  1118. {
  1119. // fakeit
  1120. KERB_CRYPT_LIST FakeList;
  1121. FakeList.next = NULL;
  1122. FakeList.value = EncryptedData->encryption_type ;
  1123. KdcReportKeyError(
  1124. &(TicketInfo->AccountName),
  1125. NULL,
  1126. KDCEVENT_NO_KEY_UNION_AS,
  1127. &FakeList,
  1128. TicketInfo->Passwords
  1129. );
  1130. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  1131. goto Cleanup;
  1132. }
  1133. KerbErr = KerbDecryptDataEx(
  1134. EncryptedData,
  1135. UserKey,
  1136. KERB_ENC_TIMESTAMP_SALT,
  1137. (PULONG) &EncryptedData->cipher_text.length,
  1138. EncryptedData->cipher_text.value
  1139. );
  1140. if (!KERB_SUCCESS(KerbErr))
  1141. {
  1142. D_DebugLog((DEB_WARN,
  1143. "KLIN(%x) Failed to decrypt timestamp pre-auth data: 0x%x\n",
  1144. KLIN(FILENO,__LINE__),
  1145. KerbErr));
  1146. KerbErr = KDC_ERR_PREAUTH_FAILED;
  1147. goto Cleanup;
  1148. }
  1149. //
  1150. // unpack the decrypted data into a KERB_ENCRYPTED_TIMESTAMP
  1151. //
  1152. KerbErr = KerbUnpackData(
  1153. EncryptedData->cipher_text.value,
  1154. EncryptedData->cipher_text.length,
  1155. KERB_ENCRYPTED_TIMESTAMP_PDU,
  1156. (PVOID *) &EncryptedTime
  1157. );
  1158. if (!KERB_SUCCESS(KerbErr))
  1159. {
  1160. D_DebugLog((DEB_WARN,"KLIN(%x) Failed to unpack preauth data to encrpyted_time\n",
  1161. KLIN(FILENO,__LINE__)));
  1162. goto Cleanup;
  1163. }
  1164. //
  1165. // Now verify the time.
  1166. //
  1167. KerbConvertGeneralizedTimeToLargeInt(
  1168. &ClientTime,
  1169. &EncryptedTime->timestamp,
  1170. ((EncryptedTime->bit_mask & KERB_ENCRYPTED_TIMESTAMP_usec_present) != 0) ?
  1171. EncryptedTime->KERB_ENCRYPTED_TIMESTAMP_usec : 0
  1172. );
  1173. GetSystemTimeAsFileTime(
  1174. (PFILETIME) &CurrentTime
  1175. );
  1176. //
  1177. // We don't want to check too closely, so allow for skew
  1178. //
  1179. if ((CurrentTime.QuadPart + SkewTime.QuadPart < ClientTime.QuadPart) ||
  1180. (CurrentTime.QuadPart - SkewTime.QuadPart > ClientTime.QuadPart))
  1181. {
  1182. D_DebugLog((DEB_ERROR, "KLIN(%x) Client %wZ time is incorrect:\n",
  1183. KLIN(FILENO,__LINE__),
  1184. &TicketInfo->AccountName));
  1185. PrintTime(DEB_ERROR, "Client Time is", &ClientTime );
  1186. PrintTime(DEB_ERROR, "KDC Time is", &CurrentTime );
  1187. //
  1188. // We don't want to lockout the account if the time is off
  1189. //
  1190. KerbErr = KRB_AP_ERR_SKEW;
  1191. goto Cleanup;
  1192. }
  1193. KerbErr = KDC_ERR_NONE;
  1194. Cleanup:
  1195. //
  1196. // Build an ETYPE_INFO structure to return
  1197. //
  1198. if ((KerbErr == KDC_ERR_PREAUTH_FAILED) || (KerbErr == KDC_ERR_ETYPE_NOTSUPP))
  1199. {
  1200. KERBERR TmpErr;
  1201. TmpErr = KdcBuildEtypeInfo(
  1202. TicketInfo,
  1203. RequestBody,
  1204. OutputPreAuth
  1205. );
  1206. //
  1207. // In this case, we can't find any ETypes that both the client and
  1208. // server support, so we've got to bail w/ proper error
  1209. // message...
  1210. //
  1211. if (TmpErr == KDC_ERR_ETYPE_NOTSUPP)
  1212. {
  1213. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  1214. }
  1215. }
  1216. if (EncryptedData != NULL)
  1217. {
  1218. KerbFreeEncryptedData(EncryptedData);
  1219. }
  1220. if (EncryptedTime != NULL)
  1221. {
  1222. KerbFreeData(KERB_ENCRYPTED_TIMESTAMP_PDU, EncryptedTime);
  1223. }
  1224. return(KerbErr);
  1225. }
  1226. typedef enum _BUILD_PAC_OPTIONS {
  1227. IncludePac,
  1228. DontIncludePac,
  1229. DontCare
  1230. } BUILD_PAC_OPTIONS, *PBUILD_PAC_OPTIONS;
  1231. //+-------------------------------------------------------------------------
  1232. //
  1233. // Function: KdcCheckPacRequestPreAuthData
  1234. //
  1235. // Synopsis: Gets the status of whether the client wants a PAC from the
  1236. // pre-auth data
  1237. //
  1238. // Effects:
  1239. //
  1240. // Arguments:
  1241. //
  1242. // Requires:
  1243. //
  1244. // Returns:
  1245. //
  1246. // Notes:
  1247. //
  1248. //
  1249. //--------------------------------------------------------------------------
  1250. KERBERR
  1251. KdcCheckPacRequestPreAuthData(
  1252. IN PKERB_PA_DATA_LIST PreAuthData,
  1253. IN OUT PBUILD_PAC_OPTIONS BuildPac
  1254. )
  1255. {
  1256. PKERB_PA_PAC_REQUEST PacRequest = NULL;
  1257. KERBERR KerbErr = KDC_ERR_NONE;
  1258. DsysAssert(PreAuthData->value.preauth_data_type == KRB5_PADATA_PAC_REQUEST);
  1259. KerbErr = KerbUnpackData(
  1260. PreAuthData->value.preauth_data.value,
  1261. PreAuthData->value.preauth_data.length,
  1262. KERB_PA_PAC_REQUEST_PDU,
  1263. (PVOID *) &PacRequest
  1264. );
  1265. if (!KERB_SUCCESS(KerbErr))
  1266. {
  1267. goto Cleanup;
  1268. }
  1269. if (PacRequest->include_pac)
  1270. {
  1271. *BuildPac = IncludePac;
  1272. }
  1273. else
  1274. {
  1275. *BuildPac = DontIncludePac;
  1276. }
  1277. D_DebugLog((DEB_T_TICKETS,"Setting BuildPac from pa-data to %d\n",*BuildPac));
  1278. Cleanup:
  1279. if (PacRequest != NULL)
  1280. {
  1281. KerbFreeData(
  1282. KERB_PA_PAC_REQUEST_PDU,
  1283. PacRequest
  1284. );
  1285. }
  1286. return(KerbErr);
  1287. }
  1288. //+-------------------------------------------------------------------------
  1289. //
  1290. // Function: KdcCheckPreAuthData
  1291. //
  1292. // Synopsis: Checks the pre-auth data in an AS request. This routine
  1293. // may return pre-auth data to caller on both success and
  1294. // failure.
  1295. //
  1296. // Effects:
  1297. //
  1298. // Arguments: ClientTicketInfo - client account's ticket info
  1299. // UserHandle - Handle to client's user object
  1300. // PreAuthData - Pre-auth data supplied by client
  1301. // PreAuthType - The type of pre-auth used
  1302. // OutputPreAuthData - pre-auth data to return to client
  1303. // BuildPac - TRUE if we should build a PAC for this client
  1304. //
  1305. //
  1306. // Requires:
  1307. //
  1308. // Returns: KDC_ERR_PREAUTH_REQUIRED, KDC_ERR_PREAUTH_FAILED
  1309. //
  1310. // Notes: This routine should be more extensible - at some point
  1311. // it should allow DLLs to be plugged in that implement
  1312. // preauth.
  1313. //
  1314. //
  1315. //--------------------------------------------------------------------------
  1316. KERBERR
  1317. KdcCheckPreAuthData(
  1318. IN PKDC_TICKET_INFO ClientTicketInfo,
  1319. IN SAMPR_HANDLE UserHandle,
  1320. IN PUSER_INTERNAL6_INFORMATION UserInfo,
  1321. IN OPTIONAL PKERB_PA_DATA_LIST PreAuthData,
  1322. IN PKERB_KDC_REQUEST_BODY RequestBody,
  1323. OUT PULONG PreAuthType,
  1324. OUT PKERB_PA_DATA_LIST * OutputPreAuthData,
  1325. OUT PBOOLEAN BuildPac,
  1326. OUT PULONG Nonce,
  1327. OUT PKERB_ENCRYPTION_KEY EncryptionKey,
  1328. OUT PUNICODE_STRING TransitedRealms,
  1329. OUT PKERB_MESSAGE_BUFFER ErrorData,
  1330. OUT PKERB_EXT_ERROR pExtendedError
  1331. )
  1332. {
  1333. KERBERR KerbErr = KDC_ERR_NONE;
  1334. PKERB_PA_DATA_LIST OutputElement = NULL;
  1335. PKERB_PA_DATA_LIST ListElement = NULL;
  1336. BOOLEAN ValidPreauthPresent = FALSE;
  1337. BUILD_PAC_OPTIONS PacOptions = DontCare;
  1338. *OutputPreAuthData = NULL;
  1339. *BuildPac = FALSE;
  1340. //
  1341. // Loop through the supplied pre-auth data elements and handle each one
  1342. //
  1343. for (ListElement = PreAuthData;
  1344. ListElement != NULL ;
  1345. ListElement = ListElement->next )
  1346. {
  1347. switch(ListElement->value.preauth_data_type) {
  1348. case KRB5_PADATA_ENC_TIMESTAMP:
  1349. *PreAuthType = ListElement->value.preauth_data_type;
  1350. KerbErr = KdcVerifyEncryptedTimeStamp(
  1351. ListElement,
  1352. ClientTicketInfo,
  1353. RequestBody,
  1354. UserHandle,
  1355. &OutputElement
  1356. );
  1357. if (KERB_SUCCESS(KerbErr))
  1358. {
  1359. ValidPreauthPresent = TRUE;
  1360. }
  1361. break;
  1362. case KRB5_PADATA_PK_AS_REP:
  1363. *PreAuthType = ListElement->value.preauth_data_type;
  1364. KerbErr = KdcCheckPkinitPreAuthData(
  1365. ClientTicketInfo,
  1366. UserHandle,
  1367. ListElement,
  1368. RequestBody,
  1369. &OutputElement,
  1370. Nonce,
  1371. EncryptionKey,
  1372. TransitedRealms,
  1373. pExtendedError
  1374. );
  1375. if (KERB_SUCCESS(KerbErr))
  1376. {
  1377. ValidPreauthPresent = TRUE;
  1378. }
  1379. break;
  1380. case KRB5_PADATA_PAC_REQUEST:
  1381. KerbErr = KdcCheckPacRequestPreAuthData(
  1382. ListElement,
  1383. &PacOptions
  1384. );
  1385. break;
  1386. default:
  1387. break;
  1388. } // switch
  1389. if (OutputElement != NULL)
  1390. {
  1391. OutputElement->next = *OutputPreAuthData;
  1392. *OutputPreAuthData = OutputElement;
  1393. OutputElement = NULL;
  1394. }
  1395. if (!KERB_SUCCESS(KerbErr))
  1396. {
  1397. goto Cleanup;
  1398. }
  1399. } // for
  1400. // We need to check preauth data by default, unless, the account tells
  1401. // us not to.
  1402. //
  1403. if (!(UserInfo->I1.UserAccountControl & USER_DONT_REQUIRE_PREAUTH) &&
  1404. !ValidPreauthPresent &&
  1405. KERB_SUCCESS(KerbErr))
  1406. {
  1407. KerbErr = KDC_ERR_PREAUTH_REQUIRED;
  1408. //
  1409. // Return the list of supported types, if we don't have other
  1410. // data to return.
  1411. //
  1412. if (*OutputPreAuthData == NULL)
  1413. {
  1414. (VOID) KdcBuildPreauthTypeList(OutputPreAuthData);
  1415. if (*OutputPreAuthData != NULL)
  1416. {
  1417. PKERB_PA_DATA_LIST EtypeInfo = NULL;
  1418. KERBERR TmpErr;
  1419. TmpErr = KdcBuildEtypeInfo(
  1420. ClientTicketInfo,
  1421. RequestBody,
  1422. &EtypeInfo
  1423. );
  1424. //
  1425. // In this case, we can't find any ETypes that both the client and
  1426. // server support, so we've got to bail w/ proper error
  1427. // message...
  1428. //
  1429. if (TmpErr == KDC_ERR_ETYPE_NOTSUPP)
  1430. {
  1431. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  1432. }
  1433. if (EtypeInfo != NULL)
  1434. {
  1435. EtypeInfo->next = *OutputPreAuthData;
  1436. *OutputPreAuthData = EtypeInfo;
  1437. EtypeInfo = NULL;
  1438. }
  1439. }
  1440. }
  1441. }
  1442. //
  1443. // Set the final option for including the pac- if the pac_request was
  1444. // included, honor it. Otherwise build the pac if valid preauth
  1445. // was supplied.
  1446. //
  1447. switch(PacOptions) {
  1448. case DontCare:
  1449. *BuildPac = ValidPreauthPresent;
  1450. break;
  1451. case IncludePac:
  1452. *BuildPac = TRUE;
  1453. break;
  1454. case DontIncludePac:
  1455. *BuildPac = FALSE;
  1456. break;
  1457. }
  1458. Cleanup:
  1459. return(KerbErr);
  1460. }
  1461. //+---------------------------------------------------------------------------
  1462. //
  1463. // Function: BuildTicketAS
  1464. //
  1465. // Synopsis: Builds an AS ticket, including filling inthe name fields
  1466. // and flag fields.
  1467. //
  1468. // Arguments: [ClientTicketInfo] -- client asking for the ticket
  1469. // [ClientName] -- name of client
  1470. // [ServiceTicketInfo] -- service ticket is for
  1471. // [ServerName] -- name of service
  1472. // [RequestBody] -- ticket request
  1473. // [NewTicket] -- (out) ticket
  1474. //
  1475. // History: 24-May-93 WadeR Created
  1476. //
  1477. // Notes: See 3.1.3, A.2 of the Kerberos V5 R5.2 spec
  1478. //
  1479. //----------------------------------------------------------------------------
  1480. KERBERR
  1481. BuildTicketAS(
  1482. IN PKDC_TICKET_INFO ClientTicketInfo,
  1483. IN PKERB_PRINCIPAL_NAME ClientName,
  1484. IN PKDC_TICKET_INFO ServiceTicketInfo,
  1485. IN PKERB_PRINCIPAL_NAME ServerName,
  1486. IN OPTIONAL PKERB_HOST_ADDRESSES HostAddresses,
  1487. IN PLARGE_INTEGER LogoffTime,
  1488. IN PLARGE_INTEGER AccountExpiry,
  1489. IN PKERB_KDC_REQUEST_BODY RequestBody,
  1490. IN ULONG CommonEType,
  1491. IN ULONG PreAuthType,
  1492. IN PUNICODE_STRING TransitedRealm,
  1493. OUT PKERB_TICKET NewTicket,
  1494. OUT PKERB_EXT_ERROR pExtendedError
  1495. )
  1496. {
  1497. KERBERR Status = KDC_ERR_NONE;
  1498. PKERB_ENCRYPTED_TICKET EncryptedTicket = NULL;
  1499. LARGE_INTEGER TicketLifespan;
  1500. LARGE_INTEGER TicketRenewspan;
  1501. ULONG KdcOptions = 0;
  1502. TRACE(KDC, BuildTicketAS, DEB_FUNCTION);
  1503. EncryptedTicket = (PKERB_ENCRYPTED_TICKET) NewTicket->encrypted_part.cipher_text.value;
  1504. KdcOptions = KerbConvertFlagsToUlong(&RequestBody->kdc_options);
  1505. NewTicket->ticket_version = KERBEROS_VERSION;
  1506. D_DebugLog(( DEB_T_TICKETS, "Building an AS ticket to %wZ for %wZ\n",
  1507. &ClientTicketInfo->AccountName, &ServiceTicketInfo->AccountName ));
  1508. // Since this is the AS ticket, we fake the TGTFlags parameter to be the
  1509. // maximum the client is allowed to have.
  1510. TicketLifespan = SecData.KdcTgtTicketLifespan();
  1511. TicketRenewspan = SecData.KdcTicketRenewSpan();
  1512. Status = KdcBuildTicketTimesAndFlags(
  1513. ClientTicketInfo->fTicketOpts,
  1514. ServiceTicketInfo->fTicketOpts,
  1515. &TicketLifespan,
  1516. &TicketRenewspan,
  1517. LogoffTime,
  1518. AccountExpiry,
  1519. RequestBody,
  1520. NULL, // no source ticket
  1521. EncryptedTicket,
  1522. pExtendedError
  1523. );
  1524. if (!KERB_SUCCESS(Status))
  1525. {
  1526. D_DebugLog((DEB_TRACE,"KLIN(%x) Failed to build ticket times and flags: 0x%x\n",
  1527. KLIN(FILENO,__LINE__), Status));
  1528. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1529. goto Cleanup;
  1530. }
  1531. *((PULONG)EncryptedTicket->flags.value) |= KerbConvertUlongToFlagUlong(KERB_TICKET_FLAGS_initial);
  1532. //
  1533. // Turn on preauth flag if necessary
  1534. //
  1535. if (PreAuthType != 0)
  1536. {
  1537. *((PULONG)EncryptedTicket->flags.value) |= KerbConvertUlongToFlagUlong(KERB_TICKET_FLAGS_pre_authent);
  1538. }
  1539. Status = KerbMakeKey(
  1540. CommonEType,
  1541. &EncryptedTicket->key
  1542. );
  1543. if (!KERB_SUCCESS(Status))
  1544. {
  1545. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1546. goto Cleanup;
  1547. }
  1548. //
  1549. // Insert the service names. If the client requested canoncalization,
  1550. // return our realm name & sam account name. Otherwise copy what the
  1551. // client requested
  1552. //
  1553. if (((KdcOptions & KERB_KDC_OPTIONS_name_canonicalize) != 0) &&
  1554. ((ServiceTicketInfo->UserAccountControl & USER_USE_DES_KEY_ONLY) == 0))
  1555. {
  1556. PKERB_INTERNAL_NAME TempServiceName = NULL;
  1557. //
  1558. // Build the service name for the ticket. For interdomain trust
  1559. // accounts, this is "krbtgt / domain name"
  1560. //
  1561. if (ServiceTicketInfo->UserId == DOMAIN_USER_RID_KRBTGT)
  1562. {
  1563. Status = KerbBuildFullServiceKdcName(
  1564. SecData.KdcDnsRealmName(),
  1565. SecData.KdcServiceName(),
  1566. KRB_NT_SRV_INST,
  1567. &TempServiceName
  1568. );
  1569. if (!KERB_SUCCESS(Status))
  1570. {
  1571. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1572. goto Cleanup;
  1573. }
  1574. Status = KerbConvertKdcNameToPrincipalName(
  1575. &NewTicket->server_name,
  1576. TempServiceName
  1577. );
  1578. KerbFreeKdcName(&TempServiceName);
  1579. if (!KERB_SUCCESS(Status))
  1580. {
  1581. goto Cleanup;
  1582. }
  1583. }
  1584. else if ((ServiceTicketInfo->UserAccountControl & USER_INTERDOMAIN_TRUST_ACCOUNT) != 0)
  1585. {
  1586. Status = KerbBuildFullServiceKdcName(
  1587. &ServiceTicketInfo->AccountName,
  1588. SecData.KdcServiceName(),
  1589. KRB_NT_SRV_INST,
  1590. &TempServiceName
  1591. );
  1592. if (!KERB_SUCCESS(Status))
  1593. {
  1594. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1595. goto Cleanup;
  1596. }
  1597. Status = KerbConvertKdcNameToPrincipalName(
  1598. &NewTicket->server_name,
  1599. TempServiceName
  1600. );
  1601. KerbFreeKdcName(&TempServiceName);
  1602. if (!KERB_SUCCESS(Status))
  1603. {
  1604. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1605. goto Cleanup;
  1606. }
  1607. }
  1608. else
  1609. {
  1610. Status = KerbConvertStringToPrincipalName(
  1611. &NewTicket->server_name,
  1612. &ServiceTicketInfo->AccountName,
  1613. KRB_NT_PRINCIPAL
  1614. );
  1615. if (!KERB_SUCCESS(Status))
  1616. {
  1617. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1618. goto Cleanup;
  1619. }
  1620. }
  1621. }
  1622. else
  1623. {
  1624. //
  1625. // No canonicalzation, so copy in all the names as the client
  1626. // requested them.
  1627. //
  1628. Status = KerbDuplicatePrincipalName(
  1629. &NewTicket->server_name,
  1630. ServerName
  1631. );
  1632. if (!KERB_SUCCESS(Status))
  1633. {
  1634. goto Cleanup;
  1635. }
  1636. }
  1637. NewTicket->realm = SecData.KdcKerbDnsRealmName();
  1638. //
  1639. // Insert the client names. If the client requested canoncalization,
  1640. // return our realm name & sam account name. Otherwise copy what the
  1641. // client requested
  1642. //
  1643. if (((KdcOptions & KERB_KDC_OPTIONS_name_canonicalize) != 0) &&
  1644. ((ClientTicketInfo->UserAccountControl & USER_USE_DES_KEY_ONLY) == 0))
  1645. {
  1646. Status = KerbConvertStringToPrincipalName(
  1647. &EncryptedTicket->client_name,
  1648. &ClientTicketInfo->AccountName,
  1649. KRB_NT_PRINCIPAL
  1650. );
  1651. if (!KERB_SUCCESS(Status))
  1652. {
  1653. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1654. goto Cleanup;
  1655. }
  1656. }
  1657. else
  1658. {
  1659. Status = KerbDuplicatePrincipalName(
  1660. &EncryptedTicket->client_name,
  1661. ClientName
  1662. );
  1663. if (!KERB_SUCCESS(Status))
  1664. {
  1665. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1666. goto Cleanup;
  1667. }
  1668. }
  1669. EncryptedTicket->client_realm = SecData.KdcKerbDnsRealmName();
  1670. if (HostAddresses != NULL)
  1671. {
  1672. EncryptedTicket->bit_mask |= KERB_ENCRYPTED_TICKET_client_addresses_present;
  1673. EncryptedTicket->KERB_ENCRYPTED_TICKET_client_addresses = HostAddresses;
  1674. }
  1675. else
  1676. {
  1677. EncryptedTicket->bit_mask &= ~KERB_ENCRYPTED_TICKET_client_addresses_present;
  1678. EncryptedTicket->KERB_ENCRYPTED_TICKET_client_addresses = NULL;
  1679. }
  1680. if (TransitedRealm->Length > 0)
  1681. {
  1682. STRING TempString;
  1683. Status = KerbUnicodeStringToKerbString(
  1684. &TempString,
  1685. TransitedRealm
  1686. );
  1687. if (!KERB_SUCCESS(Status))
  1688. {
  1689. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1690. goto Cleanup;
  1691. }
  1692. EncryptedTicket->transited.transited_type = DOMAIN_X500_COMPRESS;
  1693. EncryptedTicket->transited.contents.value = (PUCHAR) TempString.Buffer;
  1694. EncryptedTicket->transited.contents.length = (int) TempString.Length;
  1695. }
  1696. else
  1697. {
  1698. RtlZeroMemory(
  1699. &EncryptedTicket->transited,
  1700. sizeof(KERB_TRANSITED_ENCODING)
  1701. );
  1702. }
  1703. EncryptedTicket->KERB_ENCRYPTED_TICKET_authorization_data = NULL;
  1704. #if DBG
  1705. PrintTicket( DEB_T_TICKETS, "BuildTicketAS: Final ticket", NewTicket );
  1706. #endif
  1707. Cleanup:
  1708. if (!KERB_SUCCESS(Status))
  1709. {
  1710. KdcFreeInternalTicket(NewTicket);
  1711. }
  1712. return(Status);
  1713. }
  1714. //
  1715. // String defines of the service names for the change PW SPNs
  1716. // for use with the KerbCheckIfSPNIsChangePW function
  1717. //
  1718. #define KERB_KADMIN_CHG_PW L"kadmin/changepw"
  1719. //+-------------------------------------------------------------------------
  1720. //
  1721. // Function: KerbCheckIfSPNIsChangePW
  1722. //
  1723. // Synopsis: Check if the service name is kadmin/changepw.
  1724. //
  1725. // Arguments: pServerName - Contains the service name
  1726. // pLogonRestrictionsFlags - Output flags value.
  1727. //
  1728. // Requires:
  1729. //
  1730. // Returns:
  1731. //
  1732. // Notes:
  1733. //
  1734. //
  1735. //--------------------------------------------------------------------------
  1736. VOID
  1737. KerbCheckIfSPNIsChangePW(
  1738. IN PUNICODE_STRING pServerName,
  1739. IN ULONG *pLogonRestrictionsFlags)
  1740. {
  1741. if ((pServerName->Length == (sizeof(KERB_KADMIN_CHG_PW) - sizeof(WCHAR))) &&
  1742. RtlCompareMemory(pServerName->Buffer,
  1743. KERB_KADMIN_CHG_PW,
  1744. sizeof(KERB_KADMIN_CHG_PW) - sizeof(WCHAR)))
  1745. {
  1746. *pLogonRestrictionsFlags |= KDC_RESTRICT_IGNORE_PW_EXPIRATION;
  1747. }
  1748. return;
  1749. }
  1750. //+-------------------------------------------------------------------------
  1751. //
  1752. // Function: I_GetASTicket
  1753. //
  1754. // Synopsis: Gets an authentication service ticket to the requested
  1755. // service.
  1756. //
  1757. // Effects: Allocates and encrypts a KDC reply
  1758. //
  1759. // Arguments: RequestMessage - Contains the AS request message
  1760. // Pdu - PDU to pack the reply body with.
  1761. // InputMessage - buffer client sent, used for replay detection
  1762. // OutputMessage - Contains the AS reply message
  1763. // ErrorData - contains any error data for an error message
  1764. //
  1765. // Requires:
  1766. //
  1767. // Returns: KDC_ERR_ or KRB_AP_ERR errors only
  1768. //
  1769. // Notes:
  1770. //
  1771. //
  1772. //--------------------------------------------------------------------------
  1773. KERBERR
  1774. I_GetASTicket(
  1775. IN OPTIONAL PSOCKADDR ClientAddress,
  1776. IN PKERB_AS_REQUEST RequestMessage,
  1777. IN PUNICODE_STRING RequestRealm,
  1778. IN ULONG Pdu,
  1779. IN ULONG ReplyPdu,
  1780. IN PKERB_MESSAGE_BUFFER InputMessage,
  1781. OUT PKERB_MESSAGE_BUFFER OutputMessage,
  1782. OUT PKERB_MESSAGE_BUFFER ErrorData,
  1783. OUT PKERB_EXT_ERROR pExtendedError,
  1784. OUT PUNICODE_STRING ClientRealm
  1785. )
  1786. {
  1787. KERBERR KerbErr = KDC_ERR_NONE;
  1788. NTSTATUS LogonStatus = STATUS_SUCCESS;
  1789. KDC_TICKET_INFO ClientTicketInfo = {0};
  1790. KDC_TICKET_INFO ServiceTicketInfo = {0};
  1791. SAMPR_HANDLE UserHandle = NULL;
  1792. PUSER_INTERNAL6_INFORMATION UserInfo = NULL;
  1793. SID_AND_ATTRIBUTES_LIST GroupMembership = {0};
  1794. KERB_ENCRYPTION_KEY EncryptionKey = {0};
  1795. PKERB_ENCRYPTION_KEY ServerKey = NULL;
  1796. PKERB_ENCRYPTION_KEY ClientKey = NULL ;
  1797. KERB_TICKET Ticket = {0};
  1798. KERB_ENCRYPTED_TICKET EncryptedTicket = {0};
  1799. KERB_ENCRYPTED_KDC_REPLY ReplyBody = {0};
  1800. KERB_KDC_REPLY Reply = {0};
  1801. PKERB_KDC_REQUEST_BODY RequestBody = NULL;
  1802. PKERB_AUTHORIZATION_DATA PacAuthData = NULL;
  1803. PKERB_PA_DATA_LIST OutputPreAuthData = NULL;
  1804. PKERB_INTERNAL_NAME ClientName = NULL;
  1805. PKERB_INTERNAL_NAME ServerName = NULL;
  1806. UNICODE_STRING ClientNetbiosAddress = {0};
  1807. UNICODE_STRING ServerStringName = {0};
  1808. UNICODE_STRING ClientStringName = {0};
  1809. UNICODE_STRING ServerRealm = {0};
  1810. UNICODE_STRING MappedClientName = {0};
  1811. UNICODE_STRING TransitedRealm = {0};
  1812. LARGE_INTEGER LogoffTime;
  1813. LARGE_INTEGER AccountExpiry;
  1814. ULONG NameFlags = 0;
  1815. ULONG PreAuthType = 0;
  1816. ULONG KdcOptions = 0;
  1817. ULONG TicketFlags = 0;
  1818. ULONG ReplyTicketFlags = 0;
  1819. ULONG CommonEType;
  1820. ULONG ClientEType;
  1821. ULONG Nonce = 0;
  1822. ULONG LogonRestrictionsFlags = 0;
  1823. ULONG WhichFields = 0;
  1824. BOOLEAN AuditedFailure = FALSE;
  1825. BOOLEAN BuildPac = FALSE;
  1826. BOOLEAN ClientReferral = FALSE;
  1827. BOOLEAN ServerReferral = FALSE;
  1828. BOOLEAN LoggedFailure = FALSE;
  1829. BOOLEAN PasswordCorrect = FALSE;
  1830. KDC_AS_EVENT_INFO ASEventTraceInfo = {0};
  1831. TRACE(KDC, I_GetASTicket, DEB_FUNCTION);
  1832. //
  1833. // Initialize local variables
  1834. //
  1835. EncryptedTicket.flags.value = (PUCHAR) &TicketFlags;
  1836. EncryptedTicket.flags.length = sizeof(ULONG) * 8;
  1837. ReplyBody.flags.value = (PUCHAR) &ReplyTicketFlags;
  1838. ReplyBody.flags.length = sizeof(ULONG) * 8;
  1839. RtlInitUnicodeString( ClientRealm, NULL );
  1840. Ticket.encrypted_part.cipher_text.value = (PUCHAR) &EncryptedTicket;
  1841. //
  1842. // Assume that this isn't a logon request. If we manage to fail before
  1843. // we've determined it's a logon attempt, we won't mark it as a failed
  1844. // logon.
  1845. //
  1846. RequestBody = &RequestMessage->request_body;
  1847. //
  1848. // There are many options that are invalid for an AS ticket.
  1849. //
  1850. KdcOptions = KerbConvertFlagsToUlong(&RequestBody->kdc_options);
  1851. //
  1852. // Start event tracing (capture error cases too)
  1853. //
  1854. if (KdcEventTraceFlag){
  1855. ASEventTraceInfo.EventTrace.Guid = KdcGetASTicketGuid;
  1856. ASEventTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_START;
  1857. ASEventTraceInfo.EventTrace.Flags = WNODE_FLAG_TRACED_GUID;
  1858. ASEventTraceInfo.EventTrace.Size = sizeof (EVENT_TRACE_HEADER) + sizeof (ULONG);
  1859. ASEventTraceInfo.KdcOptions = KdcOptions;
  1860. TraceEvent(
  1861. KdcTraceLoggerHandle,
  1862. (PEVENT_TRACE_HEADER)&ASEventTraceInfo
  1863. );
  1864. }
  1865. if (KdcOptions &
  1866. (KERB_KDC_OPTIONS_forwarded |
  1867. KERB_KDC_OPTIONS_proxy |
  1868. KERB_KDC_OPTIONS_unused7 |
  1869. KERB_KDC_OPTIONS_unused9 |
  1870. KERB_KDC_OPTIONS_renew |
  1871. KERB_KDC_OPTIONS_validate |
  1872. KERB_KDC_OPTIONS_reserved |
  1873. KERB_KDC_OPTIONS_enc_tkt_in_skey ) )
  1874. {
  1875. KerbErr = KDC_ERR_BADOPTION;
  1876. goto Cleanup;
  1877. }
  1878. if (( RequestBody->bit_mask & addresses_present ) &&
  1879. ( RequestBody->addresses == NULL ))
  1880. {
  1881. KerbErr = KDC_ERR_BADOPTION;
  1882. goto Cleanup;
  1883. }
  1884. //
  1885. // Make sure a client name was supplied
  1886. //
  1887. if ((RequestBody->bit_mask & KERB_KDC_REQUEST_BODY_client_name_present) != 0)
  1888. {
  1889. KerbErr = KerbConvertPrincipalNameToKdcName(
  1890. &ClientName,
  1891. &RequestBody->KERB_KDC_REQUEST_BODY_client_name
  1892. );
  1893. if (!KERB_SUCCESS(KerbErr))
  1894. {
  1895. goto Cleanup;
  1896. }
  1897. KerbErr = KerbConvertKdcNameToString(
  1898. &ClientStringName,
  1899. ClientName,
  1900. NULL
  1901. );
  1902. if (!KERB_SUCCESS(KerbErr))
  1903. {
  1904. goto Cleanup;
  1905. }
  1906. }
  1907. else
  1908. {
  1909. D_DebugLog((DEB_ERROR,"KLIN(%x) No principal name supplied to AS request - not allowed\n",
  1910. KLIN(FILENO,__LINE__)));
  1911. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  1912. goto Cleanup;
  1913. }
  1914. //
  1915. // Copy out the service name. This is not an optional field.
  1916. //
  1917. if ((RequestBody->bit_mask & KERB_KDC_REQUEST_BODY_server_name_present) == 0)
  1918. {
  1919. D_DebugLog((DEB_ERROR,"KLIN(%x) Client %wZ sent AS request with no server name\n",
  1920. KLIN(FILENO,__LINE__),
  1921. &ClientStringName));
  1922. FILL_EXT_ERROR(pExtendedError, STATUS_KDC_INVALID_REQUEST, FILENO, __LINE__);
  1923. KerbErr = KDC_ERR_BADOPTION;
  1924. goto Cleanup;
  1925. }
  1926. KerbErr = KerbConvertPrincipalNameToKdcName(
  1927. &ServerName,
  1928. &RequestBody->KERB_KDC_REQUEST_BODY_server_name
  1929. );
  1930. if (!KERB_SUCCESS(KerbErr))
  1931. {
  1932. goto Cleanup;
  1933. }
  1934. KerbErr = KerbConvertKdcNameToString(
  1935. &ServerStringName,
  1936. ServerName,
  1937. NULL
  1938. );
  1939. if (!KERB_SUCCESS(KerbErr))
  1940. {
  1941. goto Cleanup;
  1942. }
  1943. //
  1944. // Check if the client said to canonicalize the name
  1945. //
  1946. if ((KdcOptions & KERB_KDC_OPTIONS_name_canonicalize) != 0)
  1947. {
  1948. NameFlags |= KDC_NAME_CHECK_GC;
  1949. }
  1950. else
  1951. {
  1952. //
  1953. // canonicalize bit is not set so we want to check if the service
  1954. // name is kadmin/changepw, if it is we set the flag to indicate
  1955. // that we will ignore password expiration checking
  1956. //
  1957. KerbCheckIfSPNIsChangePW(
  1958. &ServerStringName,
  1959. &LogonRestrictionsFlags);
  1960. }
  1961. D_DebugLog((DEB_TRACE, "Getting an AS ticket to "));
  1962. D_KerbPrintKdcName( DEB_TRACE, ServerName );
  1963. D_DebugLog((DEB_TRACE, "\tfor " ));
  1964. D_KerbPrintKdcName( DEB_TRACE, ClientName );
  1965. //
  1966. // Get the client's NETBIOS address.
  1967. //
  1968. if ((RequestBody->bit_mask & addresses_present) != 0)
  1969. {
  1970. KerbErr = KerbGetClientNetbiosAddress(
  1971. &ClientNetbiosAddress,
  1972. RequestBody->addresses
  1973. );
  1974. if (!KERB_SUCCESS(KerbErr))
  1975. {
  1976. goto Cleanup;
  1977. }
  1978. }
  1979. //
  1980. // Normalize the client name.
  1981. //
  1982. if ( !IsSubAuthFilterPresent()) {
  1983. WhichFields = USER_ALL_KERB_CHECK_LOGON_RESTRICTIONS |
  1984. USER_ALL_KDC_CHECK_PREAUTH_DATA |
  1985. USER_ALL_ACCOUNTEXPIRES |
  1986. USER_ALL_KDC_GET_PAC_AUTH_DATA |
  1987. USER_ALL_SUCCESSFUL_LOGON;
  1988. } else {
  1989. //
  1990. // We do not know what the subauth routine needs, so get everything
  1991. //
  1992. WhichFields = 0xFFFFFFFF & ~USER_ALL_UNDEFINED_MASK;
  1993. }
  1994. KerbErr = KdcNormalize(
  1995. ClientName,
  1996. NULL,
  1997. RequestRealm,
  1998. NameFlags | KDC_NAME_CLIENT | KDC_NAME_FOLLOW_REFERRALS,
  1999. &ClientReferral,
  2000. ClientRealm,
  2001. &ClientTicketInfo,
  2002. pExtendedError,
  2003. &UserHandle,
  2004. WhichFields,
  2005. 0L,
  2006. &UserInfo,
  2007. &GroupMembership
  2008. );
  2009. if (!KERB_SUCCESS(KerbErr))
  2010. {
  2011. DebugLog((DEB_ERROR,"KLIN(%x) Failed to normalize name ",KLIN(FILENO,__LINE__)));
  2012. KerbPrintKdcName(DEB_ERROR,ClientName);
  2013. goto Cleanup;
  2014. }
  2015. // If Credential count is zero and there was no error, we do not have
  2016. // NT_OWF info so return Error since Kerb can not auth
  2017. if (ClientTicketInfo.Passwords->CredentialCount <= CRED_ONLY_LM_OWF)
  2018. {
  2019. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  2020. DebugLog((DEB_ERROR,"KLIN(%x) Failed to normalize name - no creds ", KLIN(FILENO,__LINE__)));
  2021. KerbPrintKdcName(DEB_ERROR,ClientName);
  2022. goto Cleanup;
  2023. }
  2024. // If the UserHandle was NULL and there was no error, this must be
  2025. // a cross realm trust account logon. Fail it, we have no account
  2026. // to work with.
  2027. if (!UserHandle || !UserInfo)
  2028. {
  2029. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  2030. D_DebugLog((DEB_ERROR,"KLIN(%x) Failed to normalize name", KLIN(FILENO,__LINE__)));
  2031. KerbPrintKdcName(DEB_ERROR,ClientName);
  2032. goto Cleanup;
  2033. }
  2034. //
  2035. // If this is a referral, return an error and the true realm name
  2036. // of the client
  2037. //
  2038. if (ClientReferral)
  2039. {
  2040. KerbErr = KDC_ERR_WRONG_REALM;
  2041. D_DebugLog((DEB_WARN,
  2042. "KLIN(%x) Client tried to logon to account in another realm\n",
  2043. KLIN(FILENO,__LINE__)));
  2044. goto Cleanup;
  2045. }
  2046. if (!KERB_SUCCESS(KerbErr))
  2047. {
  2048. DebugLog((DEB_ERROR, "KLIN(%x) Error getting client ticket info for %wZ: 0x%x \n",
  2049. KLIN(FILENO,__LINE__), &MappedClientName, KerbErr));
  2050. goto Cleanup;
  2051. }
  2052. //
  2053. // The below function will return true for pkinit
  2054. //
  2055. if (KerbFindPreAuthDataEntry(
  2056. KRB5_PADATA_PK_AS_REP,
  2057. RequestMessage->KERB_KDC_REQUEST_preauth_data) != NULL)
  2058. {
  2059. LogonRestrictionsFlags = KDC_RESTRICT_PKINIT_USED | KDC_RESTRICT_IGNORE_PW_EXPIRATION;
  2060. }
  2061. //
  2062. // Check logon restrictions before preauth data, so we don't accidentally
  2063. // leak information about the password.
  2064. //
  2065. KerbErr = KerbCheckLogonRestrictions(
  2066. UserHandle,
  2067. &ClientNetbiosAddress,
  2068. &UserInfo->I1,
  2069. LogonRestrictionsFlags,
  2070. &LogoffTime,
  2071. &LogonStatus
  2072. );
  2073. if (!KERB_SUCCESS(KerbErr))
  2074. {
  2075. if (KDC_ERR_KEY_EXPIRED == KerbErr || LogonStatus == STATUS_NO_LOGON_SERVERS)
  2076. {
  2077. KERBERR TmpKerbErr;
  2078. //
  2079. // Unpack the pre-auth data.
  2080. //
  2081. TmpKerbErr = KdcCheckPreAuthData(
  2082. &ClientTicketInfo,
  2083. UserHandle,
  2084. UserInfo,
  2085. RequestMessage->KERB_KDC_REQUEST_preauth_data,
  2086. RequestBody,
  2087. &PreAuthType,
  2088. &OutputPreAuthData,
  2089. &BuildPac,
  2090. &Nonce,
  2091. &EncryptionKey,
  2092. &TransitedRealm,
  2093. ErrorData,
  2094. pExtendedError
  2095. );
  2096. if (!KERB_SUCCESS(TmpKerbErr))
  2097. {
  2098. BYTE ClientSid[MAX_SID_LEN];
  2099. KerbErr = TmpKerbErr;
  2100. RtlZeroMemory(ClientSid, MAX_SID_LEN);
  2101. KdcMakeAccountSid(ClientSid, ClientTicketInfo.UserId);
  2102. if (SecData.AuditKdcEvent(KDC_AUDIT_AS_FAILURE))
  2103. {
  2104. KdcLsaIAuditKdcEvent(
  2105. SE_AUDITID_PREAUTH_FAILURE,
  2106. &ClientTicketInfo.AccountName,
  2107. NULL, // no domain name
  2108. ClientSid,
  2109. &ServerStringName,
  2110. NULL, // no server sid
  2111. &PreAuthType,
  2112. (PULONG) &KerbErr,
  2113. NULL,
  2114. NULL,
  2115. GET_CLIENT_ADDRESS(ClientAddress),
  2116. NULL // no logon guid
  2117. );
  2118. AuditedFailure = TRUE;
  2119. }
  2120. //
  2121. // Only handle failed logon if pre-auth fails. Otherwise the error
  2122. // was something the client couldn't control, such as memory
  2123. // allocation or clock skew.
  2124. //
  2125. if (KerbErr == KDC_ERR_PREAUTH_FAILED)
  2126. {
  2127. FailedLogon(
  2128. UserHandle,
  2129. ClientAddress,
  2130. &RequestBody->KERB_KDC_REQUEST_BODY_client_name,
  2131. ClientSid,
  2132. MAX_SID_LEN,
  2133. InputMessage,
  2134. OutputMessage,
  2135. &ClientNetbiosAddress,
  2136. KerbErr
  2137. );
  2138. }
  2139. LoggedFailure = TRUE;
  2140. DebugLog((DEB_ERROR,"KLIN(%x) Failed to check pre-auth data: 0x%x\n",
  2141. KLIN(FILENO,__LINE__), KerbErr));
  2142. goto Cleanup;
  2143. }
  2144. else if (LogonStatus == STATUS_NO_LOGON_SERVERS)
  2145. {
  2146. D_DebugLog((DEB_WARN, "KLIN(%x) Logon Restriction check failed due to no logon servers\n",
  2147. KLIN(FILENO,__LINE__)));
  2148. KdcHandleNoLogonServers(UserHandle,
  2149. ClientAddress);
  2150. goto Cleanup;
  2151. }
  2152. else
  2153. {
  2154. DebugLog((DEB_WARN,"KLIN(%x) Logon restriction check failed: NTSTATUS: 0x%x KRB: 0x%x\n",
  2155. KLIN(FILENO,__LINE__),LogonStatus, KerbErr));
  2156. // Here's one case where we want to return errors to the client, so use EX
  2157. FILL_EXT_ERROR_EX(pExtendedError, LogonStatus, FILENO, __LINE__);
  2158. goto Cleanup;
  2159. }
  2160. }
  2161. else
  2162. {
  2163. DebugLog((DEB_WARN,"KLIN(%x) Logon restriction check failed: NTSTATUS: 0x%x KRB: 0x%x\n",
  2164. KLIN(FILENO,__LINE__),LogonStatus, KerbErr));
  2165. // Here' s one case where we want to return errors to the client, so use EX
  2166. FILL_EXT_ERROR_EX(pExtendedError, LogonStatus, FILENO, __LINE__);
  2167. }
  2168. goto Cleanup;
  2169. }
  2170. //
  2171. // Unpack the pre-auth data.
  2172. //
  2173. KerbErr = KdcCheckPreAuthData(
  2174. &ClientTicketInfo,
  2175. UserHandle,
  2176. UserInfo,
  2177. RequestMessage->KERB_KDC_REQUEST_preauth_data,
  2178. RequestBody,
  2179. &PreAuthType,
  2180. &OutputPreAuthData,
  2181. &BuildPac,
  2182. &Nonce,
  2183. &EncryptionKey,
  2184. &TransitedRealm,
  2185. ErrorData,
  2186. pExtendedError
  2187. );
  2188. if (!KERB_SUCCESS(KerbErr))
  2189. {
  2190. BYTE ClientSid[MAX_SID_LEN];
  2191. RtlZeroMemory(ClientSid, MAX_SID_LEN);
  2192. KdcMakeAccountSid(ClientSid, ClientTicketInfo.UserId);
  2193. if (SecData.AuditKdcEvent(KDC_AUDIT_AS_FAILURE))
  2194. {
  2195. KdcLsaIAuditKdcEvent(
  2196. SE_AUDITID_PREAUTH_FAILURE,
  2197. &ClientTicketInfo.AccountName,
  2198. NULL, // no domain name
  2199. ClientSid,
  2200. &ServerStringName,
  2201. NULL, // no server sid
  2202. &PreAuthType,
  2203. (PULONG) &KerbErr,
  2204. NULL,
  2205. NULL,
  2206. GET_CLIENT_ADDRESS(ClientAddress),
  2207. NULL // no logon guid
  2208. );
  2209. AuditedFailure = TRUE;
  2210. }
  2211. //
  2212. // Only handle failed logon if pre-auth fails. Otherwise the error
  2213. // was something the client couldn't control, such as memory
  2214. // allocation or clock skew.
  2215. //
  2216. if (KerbErr == KDC_ERR_PREAUTH_FAILED)
  2217. {
  2218. FailedLogon(
  2219. UserHandle,
  2220. ClientAddress,
  2221. &RequestBody->KERB_KDC_REQUEST_BODY_client_name,
  2222. ClientSid,
  2223. MAX_SID_LEN,
  2224. InputMessage,
  2225. OutputMessage,
  2226. &ClientNetbiosAddress,
  2227. KerbErr
  2228. );
  2229. }
  2230. LoggedFailure = TRUE;
  2231. DebugLog((DEB_ERROR,"KLIN(%x) Failed to check pre-auth data: 0x%x\n",
  2232. KLIN(FILENO,__LINE__), KerbErr));
  2233. goto Cleanup;
  2234. }
  2235. //
  2236. // Check for subauthentication
  2237. //
  2238. KerbErr = KdcCallSubAuthRoutine(
  2239. &ClientTicketInfo,
  2240. UserInfo,
  2241. &ClientNetbiosAddress,
  2242. &LogoffTime,
  2243. pExtendedError
  2244. );
  2245. if (!KERB_SUCCESS(KerbErr))
  2246. {
  2247. DebugLog((DEB_WARN,"KLIN(%x) Subuath restriction check failed: 0x%x\n",
  2248. KLIN(FILENO,__LINE__), KerbErr));
  2249. goto Cleanup;
  2250. }
  2251. //
  2252. // Figure out who the ticket is for. First break the name into
  2253. // a local name and a referral realm
  2254. //
  2255. //
  2256. // Note: We don't allow referrals here, because we should only get AS
  2257. // requests for our realm, and the krbtgt\server should always be
  2258. // in our realm.
  2259. KerbErr = KdcNormalize(
  2260. ServerName,
  2261. NULL,
  2262. NULL, // don't use requested realm for the server - use our realm
  2263. NameFlags | KDC_NAME_SERVER,
  2264. &ServerReferral,
  2265. &ServerRealm,
  2266. &ServiceTicketInfo,
  2267. pExtendedError,
  2268. NULL, // no user handle
  2269. 0L, // no additional fields to fetch
  2270. 0L, // no extended fields
  2271. NULL, // no user all
  2272. NULL // no membership
  2273. );
  2274. if (!KERB_SUCCESS(KerbErr))
  2275. {
  2276. DebugLog((DEB_ERROR,"KLIN(%x) Failed to normalize name 0x%x ",
  2277. KLIN(FILENO,__LINE__), KerbErr ));
  2278. KerbPrintKdcName(DEB_ERROR, ServerName);
  2279. goto Cleanup;
  2280. }
  2281. //
  2282. // Find a common crypto system. Do it now in case we need
  2283. // to return the password for a service.
  2284. //
  2285. if (EncryptionKey.keyvalue.value == NULL)
  2286. {
  2287. KerbErr = KerbFindCommonCryptSystem(
  2288. RequestBody->encryption_type,
  2289. ClientTicketInfo.Passwords,
  2290. NULL, //ServiceTicketInfo.Passwords,
  2291. &ClientEType,
  2292. &ClientKey
  2293. );
  2294. if (!KERB_SUCCESS(KerbErr))
  2295. {
  2296. KdcReportKeyError(
  2297. &ClientTicketInfo.AccountName,
  2298. NULL,
  2299. KDCEVENT_NO_KEY_UNION_AS,
  2300. RequestBody->encryption_type,
  2301. ClientTicketInfo.Passwords
  2302. );
  2303. DebugLog((DEB_ERROR,"KLIN(%x) Failed to find common ETYPE: 0x%x\n",
  2304. KLIN(FILENO,__LINE__),KerbErr));
  2305. goto Cleanup;
  2306. }
  2307. }
  2308. else
  2309. {
  2310. //
  2311. // BUG 453284: this doesn't take into account the service ticket
  2312. // info. If the PKINIT code generated a key that the service
  2313. // doesn't suport, this key may not be usable by the client &
  2314. // server. However, in the pkinit code it is hard to know what
  2315. // types the server supports.
  2316. //
  2317. ClientEType = EncryptionKey.keytype;
  2318. }
  2319. //
  2320. // Get the etype to use for the ticket itself from the server's
  2321. // list of keys
  2322. //
  2323. KerbErr = KerbFindCommonCryptSystem(
  2324. RequestBody->encryption_type,
  2325. ServiceTicketInfo.Passwords,
  2326. NULL, // no additional passwords
  2327. &CommonEType,
  2328. &ServerKey
  2329. );
  2330. if (!KERB_SUCCESS(KerbErr))
  2331. {
  2332. KdcReportKeyError(
  2333. &ServiceTicketInfo.AccountName,
  2334. NULL,
  2335. KDCEVENT_NO_KEY_UNION_AS,
  2336. RequestBody->encryption_type,
  2337. ServiceTicketInfo.Passwords
  2338. );
  2339. DebugLog((DEB_ERROR,"KLIN(%x) Failed to find common ETYPE: 0x%x\n",
  2340. KLIN(FILENO,__LINE__), KerbErr));
  2341. goto Cleanup;
  2342. }
  2343. //
  2344. // We need to save the full domain name of the service regardless
  2345. // of whether it was provided or not. This is so name changes
  2346. // can be detected. Instead of creating a mess of trying to figure out
  2347. // which deallocator to use, allocate new memory and copy data.
  2348. //
  2349. AccountExpiry = UserInfo->I1.AccountExpires;
  2350. KerbErr = BuildTicketAS(
  2351. &ClientTicketInfo,
  2352. &RequestBody->KERB_KDC_REQUEST_BODY_client_name,
  2353. &ServiceTicketInfo,
  2354. &RequestBody->KERB_KDC_REQUEST_BODY_server_name,
  2355. ((RequestBody->bit_mask & addresses_present) != 0) ? RequestBody->addresses : NULL,
  2356. &LogoffTime,
  2357. &AccountExpiry,
  2358. RequestBody,
  2359. CommonEType,
  2360. PreAuthType,
  2361. &TransitedRealm,
  2362. &Ticket,
  2363. pExtendedError
  2364. );
  2365. if (!KERB_SUCCESS(KerbErr))
  2366. {
  2367. D_DebugLog((DEB_WARN , "KLIN(%x) Failed to build AS ticket: 0x%x\n",
  2368. KLIN(FILENO,__LINE__),KerbErr));
  2369. goto Cleanup;
  2370. }
  2371. //
  2372. // If the user requested a PAC (via pre-auth data) build one now.
  2373. //
  2374. if (BuildPac)
  2375. {
  2376. //
  2377. // Now build a PAC to stick in the authorization data
  2378. //
  2379. KerbErr = KdcGetPacAuthData(
  2380. UserInfo,
  2381. &GroupMembership,
  2382. ServerKey,
  2383. &EncryptionKey,
  2384. ((ServiceTicketInfo.UserAccountControl & USER_INTERDOMAIN_TRUST_ACCOUNT) == 0) &&
  2385. (ServiceTicketInfo.UserId != DOMAIN_USER_RID_KRBTGT),
  2386. // add resource groups if server is not an interdomain trust account
  2387. &EncryptedTicket,
  2388. NULL, // no S4U info here...
  2389. &PacAuthData,
  2390. pExtendedError
  2391. );
  2392. if (!KERB_SUCCESS(KerbErr))
  2393. {
  2394. D_DebugLog((DEB_ERROR,"KLIN(%x) Failed to get pac auth data for %wZ : 0x%x\n",
  2395. KLIN(FILENO,__LINE__),&ClientTicketInfo.AccountName,KerbErr));
  2396. goto Cleanup;
  2397. }
  2398. //
  2399. // Stick the auth data into the AS ticket
  2400. //
  2401. EncryptedTicket.KERB_ENCRYPTED_TICKET_authorization_data = PacAuthData;
  2402. PacAuthData = NULL;
  2403. EncryptedTicket.bit_mask |= KERB_ENCRYPTED_TICKET_authorization_data_present;
  2404. }
  2405. //
  2406. // Now build the reply
  2407. //
  2408. KerbErr = BuildReply(
  2409. &ClientTicketInfo,
  2410. (Nonce != 0) ? Nonce : RequestBody->nonce,
  2411. &Ticket.server_name,
  2412. Ticket.realm,
  2413. ((RequestBody->bit_mask & addresses_present) != 0) ? RequestBody->addresses : NULL,
  2414. &Ticket,
  2415. &ReplyBody
  2416. );
  2417. if (!KERB_SUCCESS(KerbErr))
  2418. {
  2419. goto Cleanup;
  2420. }
  2421. //
  2422. // Now build the real reply and return it.
  2423. //
  2424. Reply.version = KERBEROS_VERSION;
  2425. Reply.message_type = KRB_AS_REP;
  2426. Reply.KERB_KDC_REPLY_preauth_data = NULL;
  2427. Reply.bit_mask = 0;
  2428. Reply.client_realm = EncryptedTicket.client_realm;
  2429. //
  2430. // Build pw-salt if we used a user's key
  2431. //
  2432. if (ClientKey != NULL)
  2433. {
  2434. KerbErr = KdcBuildPwSalt(
  2435. ClientTicketInfo.Passwords,
  2436. ClientKey,
  2437. &OutputPreAuthData
  2438. );
  2439. if (!KERB_SUCCESS(KerbErr))
  2440. {
  2441. goto Cleanup;
  2442. }
  2443. }
  2444. if (OutputPreAuthData != NULL)
  2445. {
  2446. Reply.bit_mask |= KERB_KDC_REPLY_preauth_data_present;
  2447. Reply.KERB_KDC_REPLY_preauth_data = (PKERB_REPLY_PA_DATA_LIST) OutputPreAuthData;
  2448. //
  2449. // Zero this out so we don't free the preauth data twice
  2450. //
  2451. OutputPreAuthData = NULL;
  2452. }
  2453. //
  2454. // Copy in the ticket
  2455. //
  2456. KerbErr = KerbPackTicket(
  2457. &Ticket,
  2458. ServerKey,
  2459. CommonEType,
  2460. &Reply.ticket
  2461. );
  2462. if (!KERB_SUCCESS(KerbErr))
  2463. {
  2464. D_DebugLog((DEB_ERROR,"KLIN(%x) Failed to pack ticket: 0x%x\n",
  2465. KLIN(FILENO,__LINE__), KerbErr));
  2466. goto Cleanup;
  2467. }
  2468. //
  2469. // Note: these are freed elsewhere, so zero them out after
  2470. // using them
  2471. //
  2472. Reply.client_name = EncryptedTicket.client_name;
  2473. //
  2474. // Copy in the encrypted part
  2475. //
  2476. KerbErr = KerbPackKdcReplyBody(
  2477. &ReplyBody,
  2478. (EncryptionKey.keyvalue.value != NULL) ? &EncryptionKey : ClientKey,
  2479. ClientEType,
  2480. Pdu,
  2481. &Reply.encrypted_part
  2482. );
  2483. if (!KERB_SUCCESS(KerbErr))
  2484. {
  2485. D_DebugLog((DEB_ERROR,"KLIN(%x) Failed to pack KDC reply body: 0x%x\n",
  2486. KLIN(FILENO,__LINE__), KerbErr));
  2487. goto Cleanup;
  2488. }
  2489. //
  2490. // Add in PW-SALT if we used a client key
  2491. //
  2492. if (SecData.AuditKdcEvent(KDC_AUDIT_AS_SUCCESS))
  2493. {
  2494. BYTE ClientSid[MAX_SID_LEN];
  2495. BYTE ServerSid[MAX_SID_LEN];
  2496. KdcMakeAccountSid(ClientSid, ClientTicketInfo.UserId);
  2497. KdcMakeAccountSid(ServerSid, ServiceTicketInfo.UserId);
  2498. KdcLsaIAuditKdcEvent(
  2499. SE_AUDITID_AS_TICKET,
  2500. &ClientTicketInfo.AccountName,
  2501. RequestRealm,
  2502. ClientSid,
  2503. &ServiceTicketInfo.AccountName,
  2504. ServerSid,
  2505. (PULONG) &KdcOptions,
  2506. NULL, // success
  2507. &CommonEType,
  2508. &PreAuthType,
  2509. GET_CLIENT_ADDRESS(ClientAddress),
  2510. NULL // no logon guid
  2511. );
  2512. }
  2513. //
  2514. // Pack the reply
  2515. //
  2516. KerbErr = KerbPackData(
  2517. &Reply,
  2518. ReplyPdu,
  2519. &OutputMessage->BufferSize,
  2520. &OutputMessage->Buffer
  2521. );
  2522. if (!KERB_SUCCESS(KerbErr))
  2523. {
  2524. goto Cleanup;
  2525. }
  2526. Cleanup:
  2527. if (!KERB_SUCCESS(KerbErr))
  2528. {
  2529. DsysAssert(RequestBody != NULL);
  2530. if (!AuditedFailure && SecData.AuditKdcEvent(KDC_AUDIT_AS_FAILURE))
  2531. {
  2532. if (ClientName != NULL)
  2533. {
  2534. KdcLsaIAuditKdcEvent(
  2535. SE_AUDITID_AS_TICKET,
  2536. &ClientName->Names[0],
  2537. RequestRealm,
  2538. NULL,
  2539. &ServerStringName,
  2540. NULL,
  2541. &KdcOptions,
  2542. (PULONG) &KerbErr, // failure
  2543. NULL, // no common etype
  2544. NULL, // no preauth type
  2545. GET_CLIENT_ADDRESS(ClientAddress),
  2546. NULL // no logon guid
  2547. );
  2548. }
  2549. }
  2550. //
  2551. // If there was any preath data to return, pack it for return now.
  2552. //
  2553. if (OutputPreAuthData != NULL)
  2554. {
  2555. if (ErrorData->Buffer != NULL)
  2556. {
  2557. D_DebugLog((DEB_ERROR,
  2558. "KLIN(%x) Freeing return error data to return preauth data\n",
  2559. KLIN(FILENO,__LINE__)));
  2560. MIDL_user_free(ErrorData->Buffer);
  2561. ErrorData->Buffer = NULL;
  2562. ErrorData->BufferSize = 0;
  2563. }
  2564. (VOID) KerbPackData(
  2565. &OutputPreAuthData,
  2566. PKERB_PREAUTH_DATA_LIST_PDU,
  2567. &ErrorData->BufferSize,
  2568. &ErrorData->Buffer
  2569. );
  2570. }
  2571. }
  2572. if (UserHandle != NULL)
  2573. {
  2574. if (!KERB_SUCCESS(KerbErr))
  2575. {
  2576. if (!LoggedFailure)
  2577. {
  2578. KerbErr = FailedLogon(
  2579. UserHandle,
  2580. ClientAddress,
  2581. &RequestBody->KERB_KDC_REQUEST_BODY_client_name,
  2582. NULL,
  2583. 0,
  2584. InputMessage,
  2585. OutputMessage,
  2586. &ClientNetbiosAddress,
  2587. KerbErr
  2588. );
  2589. }
  2590. }
  2591. else
  2592. {
  2593. SuccessfulLogon(
  2594. UserHandle,
  2595. ClientAddress,
  2596. InputMessage,
  2597. UserInfo
  2598. );
  2599. }
  2600. SamrCloseHandle(&UserHandle);
  2601. }
  2602. //
  2603. // Complete the WMI event
  2604. //
  2605. if (KdcEventTraceFlag){
  2606. //These variables point to either a unicode string struct containing
  2607. //the corresponding string or a pointer to KdcNullString
  2608. PUNICODE_STRING pStringToCopy;
  2609. WCHAR UnicodeNullChar = 0;
  2610. UNICODE_STRING UnicodeEmptyString = {sizeof(WCHAR),sizeof(WCHAR),&UnicodeNullChar};
  2611. ASEventTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_END;
  2612. ASEventTraceInfo.EventTrace.Flags = WNODE_FLAG_USE_MOF_PTR |
  2613. WNODE_FLAG_TRACED_GUID;
  2614. // Always output error code. KdcOptions was captured on the start event
  2615. ASEventTraceInfo.eventInfo[0].DataPtr = (ULONGLONG) &KerbErr;
  2616. ASEventTraceInfo.eventInfo[0].Length = sizeof(ULONG);
  2617. ASEventTraceInfo.EventTrace.Size =
  2618. sizeof (EVENT_TRACE_HEADER) + sizeof(MOF_FIELD);
  2619. // Build counted MOF strings from the unicode strings
  2620. if (ClientStringName.Buffer != NULL &&
  2621. ClientStringName.Length > 0)
  2622. {
  2623. pStringToCopy = &ClientStringName;
  2624. }
  2625. else {
  2626. pStringToCopy = &UnicodeEmptyString;
  2627. }
  2628. ASEventTraceInfo.eventInfo[1].DataPtr =
  2629. (ULONGLONG) &pStringToCopy->Length;
  2630. ASEventTraceInfo.eventInfo[1].Length =
  2631. sizeof(pStringToCopy->Length);
  2632. ASEventTraceInfo.eventInfo[2].DataPtr =
  2633. (ULONGLONG) pStringToCopy->Buffer;
  2634. ASEventTraceInfo.eventInfo[2].Length =
  2635. pStringToCopy->Length;
  2636. ASEventTraceInfo.EventTrace.Size += sizeof(MOF_FIELD)*2;
  2637. if (ServerStringName.Buffer != NULL &&
  2638. ServerStringName.Length > 0)
  2639. {
  2640. pStringToCopy = &ServerStringName;
  2641. }
  2642. else
  2643. {
  2644. pStringToCopy = &UnicodeEmptyString;
  2645. }
  2646. ASEventTraceInfo.eventInfo[3].DataPtr =
  2647. (ULONGLONG) &pStringToCopy->Length;
  2648. ASEventTraceInfo.eventInfo[3].Length =
  2649. sizeof(pStringToCopy->Length);
  2650. ASEventTraceInfo.eventInfo[4].DataPtr =
  2651. (ULONGLONG) pStringToCopy->Buffer;
  2652. ASEventTraceInfo.eventInfo[4].Length =
  2653. pStringToCopy->Length;
  2654. ASEventTraceInfo.EventTrace.Size += sizeof(MOF_FIELD)*2;
  2655. if (RequestRealm->Buffer != NULL &&
  2656. RequestRealm->Length > 0)
  2657. {
  2658. pStringToCopy = RequestRealm;
  2659. }
  2660. else
  2661. {
  2662. pStringToCopy = &UnicodeEmptyString;
  2663. }
  2664. ASEventTraceInfo.eventInfo[5].DataPtr =
  2665. (ULONGLONG) &(pStringToCopy->Length);
  2666. ASEventTraceInfo.eventInfo[5].Length =
  2667. sizeof(pStringToCopy->Length);
  2668. ASEventTraceInfo.eventInfo[6].DataPtr =
  2669. (ULONGLONG) (pStringToCopy->Buffer);
  2670. ASEventTraceInfo.eventInfo[6].Length =
  2671. (pStringToCopy->Length);
  2672. ASEventTraceInfo.EventTrace.Size += sizeof(MOF_FIELD)*2;
  2673. TraceEvent(
  2674. KdcTraceLoggerHandle,
  2675. (PEVENT_TRACE_HEADER)&ASEventTraceInfo
  2676. );
  2677. }
  2678. SamIFree_UserInternal6Information( UserInfo );
  2679. SamIFreeSidAndAttributesList( &GroupMembership );
  2680. KerbFreeAuthData( PacAuthData );
  2681. FreeTicketInfo( &ClientTicketInfo );
  2682. FreeTicketInfo( &ServiceTicketInfo );
  2683. KdcFreeInternalTicket( &Ticket );
  2684. KerbFreeKey( &EncryptionKey );
  2685. KerbFreeKdcName( &ClientName );
  2686. KerbFreeString( &ClientStringName );
  2687. KerbFreeString( &TransitedRealm );
  2688. KerbFreeString( &ServerStringName );
  2689. KerbFreeString( &ServerRealm );
  2690. KerbFreeKdcName( &ServerName );
  2691. KerbFreeString( &ClientNetbiosAddress );
  2692. KdcFreeKdcReplyBody( &ReplyBody );
  2693. KdcFreeKdcReply( &Reply );
  2694. KerbFreePreAuthData( OutputPreAuthData );
  2695. D_DebugLog(( DEB_TRACE, "I_GetASTicket() returning 0x%x\n", KerbErr ));
  2696. return KerbErr;
  2697. }
  2698. //+-------------------------------------------------------------------------
  2699. //
  2700. // Function: KdcGetTicket
  2701. //
  2702. // Synopsis: Generic ticket getting entrypoint to get a ticket from the KDC
  2703. //
  2704. // Effects:
  2705. //
  2706. // Arguments: Context - ATQ context - only present for TCP/IP callers
  2707. // ClientAddress - Client's IP addresses. Only present for UDP & TPC callers
  2708. // ServerAddress - address the client used to contact this KDC.
  2709. // Only present for UDP & TPC callers
  2710. // InputMessage - the input KDC request message, in ASN.1 format
  2711. // OutputMessage - Receives the KDC reply message, allocated by
  2712. // the KDC.
  2713. //
  2714. // Requires:
  2715. //
  2716. // Returns:
  2717. //
  2718. // Notes: This routine is exported from the DLL and called from the
  2719. // client dll.
  2720. //
  2721. //
  2722. //--------------------------------------------------------------------------
  2723. extern "C"
  2724. KERBERR
  2725. KdcGetTicket(
  2726. IN OPTIONAL PVOID Context,
  2727. IN OPTIONAL PSOCKADDR ClientAddress,
  2728. IN OPTIONAL PSOCKADDR ServerAddress,
  2729. IN PKERB_MESSAGE_BUFFER InputMessage,
  2730. OUT PKERB_MESSAGE_BUFFER OutputMessage
  2731. )
  2732. {
  2733. KERBERR KerbErr;
  2734. KERB_EXT_ERROR ExtendedError = {0,0};
  2735. PKERB_EXT_ERROR pExtendedError = &ExtendedError; // needed for macro
  2736. PKERB_KDC_REQUEST RequestMessage = NULL;
  2737. KERB_KDC_REPLY ReplyMessage = {0};
  2738. PKERB_ERROR ErrorMessage = NULL;
  2739. PKERB_MESSAGE_BUFFER Response = NULL;
  2740. KERB_MESSAGE_BUFFER ErrorData = {0};
  2741. ULONG InputPdu = KERB_TGS_REQUEST_PDU;
  2742. ULONG OutputPdu = KERB_TGS_REPLY_PDU;
  2743. ULONG InnerPdu = KERB_ENCRYPTED_TGS_REPLY_PDU;
  2744. UNICODE_STRING RequestRealm = {0};
  2745. PKERB_INTERNAL_NAME RequestServer = NULL;
  2746. UNICODE_STRING ClientRealm = {0};
  2747. PUNICODE_STRING ExtendedErrorServerRealm = SecData.KdcDnsRealmName();
  2748. PKERB_INTERNAL_NAME ExtendedErrorServerName = SecData.KdcInternalName();
  2749. #if DBG
  2750. DWORD StartTime = 0;
  2751. #endif
  2752. TRACE(KDC, KdcGetTicket, DEB_FUNCTION );
  2753. //
  2754. // Make sure we are allowed to execute
  2755. //
  2756. if (!NT_SUCCESS(EnterApiCall()))
  2757. {
  2758. return(KDC_ERR_NOT_RUNNING);
  2759. }
  2760. RtlZeroMemory(
  2761. &ReplyMessage,
  2762. sizeof(KERB_KDC_REPLY)
  2763. );
  2764. //
  2765. // First initialize the return parameters.
  2766. //
  2767. OutputMessage->Buffer = NULL;
  2768. OutputMessage->BufferSize = 0;
  2769. //
  2770. // Check the first byte of the message to indicate the type of message
  2771. //
  2772. if ((InputMessage->BufferSize > 0) && (
  2773. (InputMessage->Buffer[0] & KERB_BER_APPLICATION_TAG) != 0))
  2774. {
  2775. if ((InputMessage->Buffer[0] & KERB_BER_APPLICATION_MASK) == KERB_AS_REQ_TAG)
  2776. {
  2777. InputPdu = KERB_AS_REQUEST_PDU;
  2778. OutputPdu = KERB_AS_REPLY_PDU;
  2779. InnerPdu = KERB_ENCRYPTED_AS_REPLY_PDU;
  2780. }
  2781. else if ((InputMessage->Buffer[0] & KERB_BER_APPLICATION_MASK) != KERB_TGS_REQ_TAG)
  2782. {
  2783. D_DebugLog((DEB_T_SOCK,
  2784. "KLIN(%x) Bad message sent to KDC - not AS or TGS request\n",
  2785. KLIN(FILENO,__LINE__)));
  2786. KerbErr = KRB_ERR_FIELD_TOOLONG;
  2787. goto NoMsgCleanup;
  2788. }
  2789. }
  2790. else
  2791. {
  2792. D_DebugLog((DEB_T_SOCK,"KLIN(%x) Bad message sent to KDC - length to short or bad first byte\n",
  2793. KLIN(FILENO,__LINE__)));
  2794. KerbErr = KRB_ERR_FIELD_TOOLONG;
  2795. goto NoMsgCleanup;
  2796. }
  2797. //
  2798. // First decode the input message
  2799. //
  2800. KerbErr = (KERBERR) KerbUnpackData(
  2801. InputMessage->Buffer,
  2802. InputMessage->BufferSize,
  2803. InputPdu,
  2804. (PVOID *) &RequestMessage
  2805. );
  2806. if (KerbErr == KDC_ERR_MORE_DATA)
  2807. {
  2808. //
  2809. // Reallocate an retry the read from the socket
  2810. //
  2811. if (Context != NULL)
  2812. {
  2813. KerbErr = KdcAtqRetrySocketRead(
  2814. (PKDC_ATQ_CONTEXT *) Context,
  2815. InputMessage
  2816. );
  2817. //
  2818. // On success, just return so that the read continues. On failure,
  2819. // post cleanup and send an error response.
  2820. //
  2821. if (KERB_SUCCESS(KerbErr))
  2822. {
  2823. LeaveApiCall();
  2824. return(KerbErr);
  2825. }
  2826. else
  2827. {
  2828. goto NoMsgCleanup;
  2829. }
  2830. }
  2831. else
  2832. {
  2833. D_DebugLog((DEB_ERROR, "KLIN(%x) Datagram context with not enough data!\n",
  2834. KLIN(FILENO,__LINE__)));
  2835. KerbErr = KRB_ERR_FIELD_TOOLONG;
  2836. goto Cleanup;
  2837. }
  2838. }
  2839. if (!KERB_SUCCESS(KerbErr))
  2840. {
  2841. D_DebugLog((DEB_ERROR,"KLIN(%x) Failed to unpack KDC request: 0x%x\n",
  2842. KLIN(FILENO,__LINE__),KerbErr));
  2843. //
  2844. // We don't want to return an error on a badly formed
  2845. // packet,as it can be used to set up a flood attack
  2846. //
  2847. goto NoMsgCleanup;
  2848. }
  2849. //
  2850. // First check the version of the request.
  2851. //
  2852. if (RequestMessage->version != KERBEROS_VERSION)
  2853. {
  2854. D_DebugLog((DEB_ERROR,"KLIN(%x) Bad request version: 0x%x\n",
  2855. KLIN(FILENO,__LINE__), RequestMessage->version));
  2856. KerbErr = KRB_AP_ERR_BADVERSION;
  2857. goto Cleanup;
  2858. }
  2859. //
  2860. // now call the internal version to do all the hard work
  2861. //
  2862. //
  2863. // Verify the realm name in the request
  2864. //
  2865. KerbErr = KerbConvertRealmToUnicodeString(
  2866. &RequestRealm,
  2867. &RequestMessage->request_body.realm
  2868. );
  2869. if (!KERB_SUCCESS(KerbErr))
  2870. {
  2871. goto Cleanup;
  2872. }
  2873. KerbErr = KerbConvertPrincipalNameToKdcName(
  2874. &RequestServer,
  2875. &RequestMessage->request_body.server_name
  2876. );
  2877. if ( !KERB_SUCCESS(KerbErr))
  2878. {
  2879. goto Cleanup;
  2880. }
  2881. //
  2882. // Now that we have the request realm and request server, any subsequent
  2883. // error will result in those values being placed into the extended error
  2884. //
  2885. ExtendedErrorServerRealm = &RequestRealm;
  2886. ExtendedErrorServerName = RequestServer;
  2887. if (!SecData.IsOurRealm(
  2888. &RequestRealm
  2889. ))
  2890. {
  2891. D_DebugLog((DEB_ERROR,"KLIN(%x) Request sent for wrong realm: %wZ\n",
  2892. KLIN(FILENO,__LINE__), &RequestRealm));
  2893. KerbErr = KDC_ERR_WRONG_REALM;
  2894. goto Cleanup;
  2895. }
  2896. if (RequestMessage->message_type == KRB_AS_REQ)
  2897. {
  2898. if (InputPdu != KERB_AS_REQUEST_PDU) {
  2899. KerbErr = KRB_ERR_FIELD_TOOLONG;
  2900. FILL_EXT_ERROR(pExtendedError, STATUS_KDC_INVALID_REQUEST,FILENO,__LINE__);
  2901. goto Cleanup;
  2902. }
  2903. SamIIncrementPerformanceCounter(
  2904. KdcAsReqCounter
  2905. );
  2906. //
  2907. // If WMI event tracing is enabled, notify it of the begin and end
  2908. // of the ticket request
  2909. //
  2910. #if DBG
  2911. StartTime = GetTickCount();
  2912. #endif
  2913. KerbErr = I_GetASTicket(
  2914. ClientAddress,
  2915. RequestMessage,
  2916. &RequestRealm,
  2917. InnerPdu,
  2918. OutputPdu,
  2919. InputMessage,
  2920. OutputMessage,
  2921. &ErrorData,
  2922. &ExtendedError,
  2923. &ClientRealm
  2924. );
  2925. #if DBG
  2926. D_DebugLog((DEB_T_PERF_STATS, "I_GetASTicket took %d m seconds\n", NetpDcElapsedTime(StartTime)));
  2927. #endif
  2928. }
  2929. else if (RequestMessage->message_type == KRB_TGS_REQ)
  2930. {
  2931. SamIIncrementPerformanceCounter(
  2932. KdcTgsReqCounter
  2933. );
  2934. #if DBG
  2935. StartTime = GetTickCount();
  2936. #endif
  2937. KerbErr = HandleTGSRequest(
  2938. ClientAddress,
  2939. RequestMessage,
  2940. &RequestRealm,
  2941. OutputMessage,
  2942. &ExtendedError
  2943. );
  2944. #if DBG
  2945. D_DebugLog((DEB_T_PERF_STATS, "HandleTGSRequest took %d m seconds\n", NetpDcElapsedTime(StartTime)));
  2946. #endif
  2947. }
  2948. else
  2949. {
  2950. D_DebugLog((DEB_ERROR,"KLIN(%x) Invalid message type: %d\n",
  2951. KLIN(FILENO,__LINE__),
  2952. RequestMessage->message_type));
  2953. FILL_EXT_ERROR(pExtendedError, STATUS_KDC_INVALID_REQUEST,FILENO,__LINE__);
  2954. KerbErr = KRB_AP_ERR_MSG_TYPE;
  2955. goto Cleanup;
  2956. }
  2957. //
  2958. // If the response is too big and we are using UDP, make the client
  2959. // change transports. We can tell the caller is UDP because it doesn't
  2960. // have an ATQ context but it does provide the client address.
  2961. //
  2962. if ((Context == NULL) && (ClientAddress != NULL))
  2963. {
  2964. if (OutputMessage->BufferSize >= KERB_MAX_KDC_RESPONSE_SIZE)
  2965. {
  2966. D_DebugLog((DEB_WARN,"KLIN(%x) KDC response too big for UDP: %d bytes\n",
  2967. KLIN(FILENO,__LINE__), OutputMessage->BufferSize ));
  2968. KerbErr = KRB_ERR_RESPONSE_TOO_BIG;
  2969. MIDL_user_free(OutputMessage->Buffer);
  2970. OutputMessage->Buffer = NULL;
  2971. OutputMessage->BufferSize = 0;
  2972. }
  2973. }
  2974. Cleanup:
  2975. // TBD: Put in extended error return goo here for client
  2976. if (!KERB_SUCCESS(KerbErr))
  2977. {
  2978. //
  2979. // We may have a message built by someone else - the PDC
  2980. //
  2981. if (OutputMessage->Buffer == NULL)
  2982. {
  2983. KerbBuildErrorMessageEx(
  2984. KerbErr,
  2985. &ExtendedError,
  2986. ExtendedErrorServerRealm,
  2987. ExtendedErrorServerName,
  2988. &ClientRealm,
  2989. ErrorData.Buffer,
  2990. ErrorData.BufferSize,
  2991. &OutputMessage->BufferSize,
  2992. &OutputMessage->Buffer
  2993. );
  2994. }
  2995. }
  2996. NoMsgCleanup:
  2997. KerbFreeString(&RequestRealm);
  2998. MIDL_user_free(RequestServer);
  2999. if (RequestMessage != NULL)
  3000. {
  3001. KerbFreeData(InputPdu,RequestMessage);
  3002. }
  3003. if (ErrorData.Buffer != NULL)
  3004. {
  3005. MIDL_user_free(ErrorData.Buffer);
  3006. }
  3007. LeaveApiCall();
  3008. return(KerbErr);
  3009. }