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

4563 lines
137 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 <utils.hxx>
  22. extern "C"
  23. {
  24. #include <md5.h>
  25. }
  26. #include "fileno.h"
  27. #define FILENO FILENO_GETAS
  28. // Local prototypes
  29. NTSTATUS
  30. AsNegCacheCheck(
  31. IN PVOID Buffer,
  32. IN ULONG BufferLength,
  33. IN OPTIONAL PVOID OptionalBuffer,
  34. IN OPTIONAL ULONG OptionalBufferLength,
  35. OUT PBOOLEAN pfAvoidSendToPDC
  36. );
  37. NTSTATUS
  38. AsNegCacheUpdate(
  39. IN PVOID Buffer,
  40. IN ULONG BufferLength,
  41. IN OPTIONAL PVOID OptionalBuffer,
  42. IN OPTIONAL ULONG OptionalBufferLength,
  43. IN NTSTATUS StatusPdcAuth
  44. );
  45. NTSTATUS
  46. AsNegCacheDelete(
  47. IN PVOID Buffer,
  48. IN ULONG BufferLength,
  49. IN OPTIONAL PVOID OptionalBuffer,
  50. IN OPTIONAL ULONG OptionalBufferLength
  51. );
  52. // Negative Cache data stucts
  53. RTL_CRITICAL_SECTION l_ApNegCacheCritSect;
  54. LIST_ENTRY l_ApNegCacheList;
  55. BOOLEAN g_fApNegCacheInitialized = FALSE; // Simple variable to make sure that the package was initialize
  56. #define KERB_AP_NEGATIVE_MAX_LOGON_COUNT 10 // number of failed auth attempts to PDC before imposing 5 minute waits
  57. #define KERB_MAX_FAILED_LIST_ENTRIES 50 // max number of entries in the negative cache list table
  58. #define KERB_5_MINUTES_100NANO 3000000000 // number of 100 Nanoseconds in 5 minutes
  59. typedef struct _NEGATIVE_CACHE {
  60. LIST_ENTRY Next;
  61. ULONG lBadLogonCount;
  62. LARGE_INTEGER TimeLastPDCContact;
  63. char digest[MD5DIGESTLEN]; // md5 signature of the AS request info
  64. } NEGATIVE_CACHE, *PNEGATIVE_CACHE;
  65. LARGE_INTEGER tsInfinity = {0xffffffff,0x7fffffff};
  66. LONG lInfinity = 0x7fffffff;
  67. enum {
  68. SubAuthUnknown,
  69. SubAuthNoFilter,
  70. SubAuthYesFilter
  71. } KdcSubAuthFilterPresent = SubAuthUnknown;
  72. extern "C"
  73. NTSTATUS NTAPI
  74. Msv1_0ExportSubAuthenticationRoutine(
  75. IN NETLOGON_LOGON_INFO_CLASS LogonLevel,
  76. IN PVOID LogonInformation,
  77. IN ULONG Flags,
  78. IN ULONG DllNumber,
  79. IN PUSER_ALL_INFORMATION UserAll,
  80. OUT PULONG WhichFields,
  81. OUT PULONG UserFlags,
  82. OUT PBOOLEAN Authoritative,
  83. OUT PLARGE_INTEGER LogoffTime,
  84. OUT PLARGE_INTEGER KickoffTime
  85. );
  86. extern "C"
  87. BOOLEAN NTAPI
  88. Msv1_0SubAuthenticationPresent(
  89. IN ULONG DllNumber
  90. );
  91. ULONG
  92. NetpDcElapsedTime(
  93. IN ULONG StartTime
  94. )
  95. /*++
  96. Routine Description:
  97. Returns the time (in milliseconds) that has elapsed is StartTime.
  98. Arguments:
  99. StartTime - A time stamp from GetTickCount()
  100. Return Value:
  101. Returns the time (in milliseconds) that has elapsed is StartTime.
  102. --*/
  103. {
  104. ULONG CurrentTime;
  105. //
  106. // If time has has wrapped,
  107. // account for it.
  108. //
  109. CurrentTime = GetTickCount();
  110. if ( CurrentTime >= StartTime ) {
  111. return CurrentTime - StartTime;
  112. } else {
  113. return (0xFFFFFFFF-StartTime) + CurrentTime;
  114. }
  115. }
  116. //+-------------------------------------------------------------------------
  117. //
  118. // Function: KdcForwardLogonToPDC
  119. //
  120. // Synopsis: Forwards a failed-password logon to the PDC.
  121. //
  122. // Effects:
  123. //
  124. // Arguments:
  125. //
  126. // Requires:
  127. //
  128. // Returns:
  129. //
  130. // Notes:
  131. //
  132. //
  133. //--------------------------------------------------------------------------
  134. KERBERR
  135. KdcForwardLogonToPDC(
  136. IN PKERB_MESSAGE_BUFFER InputMessage,
  137. IN PKERB_MESSAGE_BUFFER OutputMessage
  138. )
  139. {
  140. KERBERR KerbErr = KDC_ERR_NONE;
  141. NTSTATUS Status;
  142. BOOLEAN CalledPDC;
  143. KERB_MESSAGE_BUFFER Reply = {0};
  144. DOMAIN_SERVER_ROLE ServerRole;
  145. Status = SamIQueryServerRole(
  146. GlobalAccountDomainHandle,
  147. &ServerRole
  148. );
  149. if (!KdcGlobalAvoidPdcOnWan &&
  150. NT_SUCCESS(Status) &&
  151. (ServerRole == DomainServerRoleBackup))
  152. {
  153. Status = KerbMakeKdcCall(
  154. SecData.KdcDnsRealmName(),
  155. NULL, // no account name
  156. TRUE, // call the PDC
  157. TRUE, // use TCP/IP, not UDP
  158. InputMessage,
  159. &Reply,
  160. 0, // no additional flags
  161. &CalledPDC
  162. );
  163. if (!NT_SUCCESS(Status))
  164. {
  165. KerbErr = KRB_ERR_GENERIC;
  166. }
  167. else
  168. {
  169. OutputMessage->Buffer = (PBYTE) MIDL_user_allocate(Reply.BufferSize);
  170. if (OutputMessage->Buffer != NULL)
  171. {
  172. OutputMessage->BufferSize = Reply.BufferSize;
  173. RtlCopyMemory(
  174. OutputMessage->Buffer,
  175. Reply.Buffer,
  176. OutputMessage->BufferSize
  177. );
  178. }
  179. else
  180. {
  181. KerbErr = KRB_ERR_GENERIC;
  182. }
  183. KerbFree(Reply.Buffer);
  184. }
  185. }
  186. else
  187. {
  188. KerbErr = KRB_ERR_GENERIC;
  189. }
  190. return(KerbErr);
  191. }
  192. //+---------------------------------------------------------------------------
  193. //
  194. // Function: KdcVerifyKdcAsRep
  195. //
  196. // Synopsis: Verifies that our AS_REP came from a KDC, as opposed to a malicious
  197. // attacker by evaluating the TGT embedded in response
  198. //
  199. // Arguments: Reply PKERB_KDC_REPLY
  200. //
  201. // Returns: Boolean to client.
  202. //
  203. // History: 12-June-2000 Todds Created
  204. //
  205. //----------------------------------------------------------------------------
  206. BOOLEAN
  207. KdcVerifyKdcAsRep(
  208. PKERB_KDC_REPLY Reply,
  209. PKERB_PRINCIPAL_NAME RequestBodyClientName
  210. )
  211. {
  212. BOOLEAN fRet = FALSE;
  213. KERBERR KerbErr;
  214. KDC_TICKET_INFO KrbtgtTicketInfo = {0};
  215. UNICODE_STRING ServerNames[3];
  216. UNICODE_STRING ClientName;
  217. ULONG NameType;
  218. PKERB_ENCRYPTION_KEY EncryptionKey = NULL;
  219. PKERB_ENCRYPTED_TICKET DecryptedTicket = NULL;
  220. KERB_REALM LocalRealm;
  221. // Get the server key for krbtgt
  222. KerbErr = SecData.GetKrbtgtTicketInfo(&KrbtgtTicketInfo);
  223. if (!KERB_SUCCESS(KerbErr))
  224. {
  225. D_DebugLog((DEB_WARN, "SecData.Getkrbtgtticketinfo failed!\n"));
  226. goto Cleanup;
  227. }
  228. ServerNames[0] = *SecData.KdcFullServiceKdcName();
  229. ServerNames[1] = *SecData.KdcFullServiceDnsName();
  230. ServerNames[2] = *SecData.KdcFullServiceName();
  231. LocalRealm = SecData.KdcKerbDnsRealmName();
  232. //
  233. // Verify the realm of the ticket
  234. //
  235. if (!KerbCompareRealmNames(
  236. &LocalRealm,
  237. &Reply->ticket.realm
  238. ))
  239. {
  240. D_DebugLog((DEB_ERROR,"KLIN(%x) Tgt reply is not for our realm: %s instead of %s\n",
  241. KLIN(FILENO, __LINE__), Reply->ticket.realm, LocalRealm));
  242. KerbErr = KRB_AP_ERR_NOT_US;
  243. goto Cleanup;
  244. }
  245. EncryptionKey = KerbGetKeyFromList(
  246. KrbtgtTicketInfo.Passwords,
  247. Reply->ticket.encrypted_part.encryption_type
  248. );
  249. if (EncryptionKey == NULL)
  250. {
  251. D_DebugLog((DEB_ERROR, "Couldn't get key for decrypting krbtgt\n"));
  252. KerbErr = KRB_AP_ERR_NOKEY;
  253. goto Cleanup;
  254. }
  255. KerbErr = KerbVerifyTicket(
  256. &Reply->ticket,
  257. 3, // 3 names
  258. ServerNames,
  259. SecData.KdcDnsRealmName(),
  260. EncryptionKey,
  261. &SkewTime,
  262. &DecryptedTicket
  263. );
  264. if (!KERB_SUCCESS(KerbErr))
  265. {
  266. D_DebugLog((DEB_ERROR, "KLIN(%x) Failed to verify ticket - %x\n",
  267. KLIN(FILENO, __LINE__),KerbErr));
  268. goto Cleanup;
  269. }
  270. //
  271. // Verify the realm of the client is the same as our realm
  272. //
  273. if (!KerbCompareRealmNames(
  274. &LocalRealm,
  275. &DecryptedTicket->client_realm
  276. ))
  277. {
  278. D_DebugLog((DEB_ERROR,"KLIN(%x) Verified ticket client realm is wrong: %s instead of %s\n",
  279. KLIN(FILENO, __LINE__),DecryptedTicket->client_realm, LocalRealm));
  280. KerbErr = KRB_AP_ERR_NOT_US;
  281. goto Cleanup;
  282. }
  283. fRet = TRUE;
  284. Cleanup:
  285. if (DecryptedTicket != NULL)
  286. {
  287. KerbFreeTicket(DecryptedTicket);
  288. }
  289. if (!fRet && KerbErr == KRB_AP_ERR_MODIFIED)
  290. {
  291. ClientName.Buffer = NULL;
  292. KerbConvertPrincipalNameToString(
  293. &ClientName,
  294. &NameType,
  295. RequestBodyClientName
  296. );
  297. ReportServiceEvent(
  298. EVENTLOG_ERROR_TYPE,
  299. KDCEVENT_INVALID_FORWARDED_AS_REQ,
  300. sizeof(ULONG),
  301. &KerbErr,
  302. 1, // number of strings
  303. ClientName.Buffer
  304. );
  305. if (ClientName.Buffer != NULL)
  306. {
  307. MIDL_user_free(ClientName.Buffer);
  308. }
  309. }
  310. return fRet;
  311. }
  312. //+---------------------------------------------------------------------------
  313. //
  314. // Function: FailedLogon
  315. //
  316. // Synopsis: Processes a failed logon. This is to be called on a failed auth
  317. // attempt on the BDC. A series of rules will be applied to see if the request
  318. // should be forwarded to the PDC>
  319. //
  320. // Effects: May raise an exception, audit, event, lockout, etc.
  321. // Will increment the bad password count if Reason is KDC_ERR_PREAUTH_FAILED
  322. //
  323. // Arguments: [UserHandle] -- [in] Client who didn't log on.
  324. // [ClientAddress] -- Address of client making request
  325. // [Client] -- [in optional] Sid of the client requesting logon
  326. // [ClientSize] -- [in] Length of the sid
  327. // [Reason] -- [in] the reason this logon failed.
  328. // [UsedOldPassword] -- [in] caller used old password to log on;
  329. // do not increment the account lockout count
  330. //
  331. // Requires:
  332. //
  333. // Returns: VOID - any message from PDC is sent in outputmessage
  334. //
  335. // Algorithm:
  336. //
  337. // History: 03-May-94 wader Created
  338. //
  339. // Notes: This usually returns hrReason, but it may map it to
  340. // something else.
  341. //
  342. //----------------------------------------------------------------------------
  343. VOID
  344. FailedLogon( IN SAMPR_HANDLE UserHandle,
  345. IN OPTIONAL PSOCKADDR ClientAddress,
  346. IN PKERB_PRINCIPAL_NAME RequestBodyClientName,
  347. IN OPTIONAL UCHAR *Client,
  348. IN ULONG ClientSize,
  349. IN PKDC_TICKET_INFO ClientTicketInfo,
  350. IN PKERB_MESSAGE_BUFFER InputMessage,
  351. IN PKERB_MESSAGE_BUFFER OutputMessage,
  352. IN PUNICODE_STRING ClientNetbiosAddress,
  353. IN KERBERR Reason,
  354. IN NTSTATUS LogonStatus,
  355. IN BOOLEAN UsedOldPassword
  356. )
  357. {
  358. NTSTATUS Status = STATUS_SUCCESS;
  359. NTSTATUS StatusTemp = STATUS_SUCCESS;
  360. SAM_LOGON_STATISTICS LogonStats;
  361. LARGE_INTEGER CurrentTime;
  362. PKERB_ERROR ErrorMessage = NULL;
  363. PKERB_KDC_REPLY Reply = NULL;
  364. BOOLEAN LockoutEnabled = FALSE;
  365. PKERB_EXT_ERROR pExtendedError = NULL;
  366. BOOLEAN fAvoidSend = FALSE; // Should be avoid sending to the PDC ?
  367. BOOLEAN fForwardedToPDC = FALSE;
  368. DOMAIN_SERVER_ROLE ServerRole;
  369. TRACE(KDC, FailedLogon, DEB_FUNCTION);
  370. // If we are the PDC, then goto cleanup - no need for negative cache processing
  371. Status = SamIQueryServerRole(
  372. GlobalAccountDomainHandle,
  373. &ServerRole
  374. );
  375. if (NT_SUCCESS(Status) &&
  376. (ServerRole == DomainServerRolePrimary))
  377. {
  378. goto Cleanup;
  379. }
  380. GetSystemTimeAsFileTime((PFILETIME)&CurrentTime);
  381. //
  382. // It's important to know why the logon can fail. For each possible
  383. // reason, decide if that is a reason to lock out the account.
  384. //
  385. //
  386. // Check to see if we've seen this request before recently
  387. //
  388. if (KDC_ERR_NONE == ReplayDetect->Check(
  389. InputMessage->Buffer,
  390. InputMessage->BufferSize,
  391. NULL,
  392. 0,
  393. &CurrentTime,
  394. TRUE,
  395. FALSE,
  396. TRUE))
  397. {
  398. KERBERR KerbErr;
  399. KERBERR ForwardKerbErr;
  400. //
  401. // If the password was bad then we want to update the sam information
  402. // Check w/ the PDC for account & pwd errors
  403. //
  404. if ((Reason == KDC_ERR_PREAUTH_FAILED) ||
  405. (LogonStatus == STATUS_PASSWORD_EXPIRED) ||
  406. (LogonStatus == STATUS_PASSWORD_MUST_CHANGE) ||
  407. (LogonStatus == STATUS_ACCOUNT_LOCKED_OUT))
  408. {
  409. // Check to see if we should forward the request to the PDC
  410. Status = AsNegCacheCheck(
  411. Client,
  412. ClientSize,
  413. ClientNetbiosAddress->Buffer,
  414. ClientNetbiosAddress->Length,
  415. &fAvoidSend);
  416. if (!NT_SUCCESS(Status) || (fAvoidSend == TRUE))
  417. {
  418. D_DebugLog((DEB_WARN, "<CACHE> NOT fwding to PDC r(0x%x) ls(0x%x)\n", Reason, LogonStatus));
  419. goto Cleanup;
  420. }
  421. //
  422. // Pass this request to the KDC
  423. //
  424. D_DebugLog((DEB_TRACE,"KLIN(%x) sending request to PDC for updated info\n",
  425. KLIN(FILENO,__LINE__)));
  426. KerbErr = KdcForwardLogonToPDC(
  427. InputMessage,
  428. OutputMessage
  429. );
  430. //
  431. // Return an better error if it wasn't generic.
  432. //
  433. if (KERB_SUCCESS(KerbErr))
  434. {
  435. ForwardKerbErr = KerbUnpackKerbError(
  436. OutputMessage->Buffer,
  437. OutputMessage->BufferSize,
  438. &ErrorMessage
  439. );
  440. if (KERB_SUCCESS(ForwardKerbErr))
  441. {
  442. NTSTATUS StatusPDC = STATUS_INTERNAL_ERROR;
  443. if (ErrorMessage->bit_mask & error_data_present)
  444. {
  445. KerbErr = KerbUnpackErrorData(
  446. ErrorMessage,
  447. &pExtendedError
  448. );
  449. if (KERB_SUCCESS(KerbErr) && (EXT_CLIENT_INFO_PRESENT(pExtendedError)))
  450. {
  451. StatusPDC = pExtendedError->status;
  452. D_DebugLog((DEB_TRACE,"KLIN(%x) info from PDC StatusPDC 0x%x\n",
  453. KLIN(FILENO,__LINE__), StatusPDC));
  454. }
  455. }
  456. Reason = ErrorMessage->error_code; // PDC kerb error takes priority
  457. fForwardedToPDC = TRUE;
  458. // Update the list of forwarded failed user auth
  459. // If the lockout policy is enabled, we should continue to forward auth requests to
  460. // the PDC (i.e. we should not cache this failure), to keep the right lockout count
  461. // until the account becomes locked on the PDC
  462. // We need to also increment if an older password is used. This is because the negative
  463. // cache logic is not incremented for use of an older password (1st or 2nd in history).
  464. if (ClientTicketInfo->LockoutThreshold)
  465. {
  466. LockoutEnabled = TRUE; // account can be locked out
  467. D_DebugLog((DEB_TRACE, "FailedLogon: Account lockout policy is enabled\n"));
  468. }
  469. if (!LockoutEnabled ||
  470. (StatusPDC == STATUS_ACCOUNT_LOCKED_OUT) ||
  471. UsedOldPassword)
  472. {
  473. StatusTemp = AsNegCacheUpdate(
  474. Client,
  475. ClientSize,
  476. ClientNetbiosAddress->Buffer,
  477. ClientNetbiosAddress->Length,
  478. StatusPDC
  479. );
  480. }
  481. } else {
  482. //
  483. // This may have been a successful, forwarded AS_REQ. If so,
  484. // reset bad password count on this BDC...
  485. //
  486. ForwardKerbErr = KerbUnpackAsReply(
  487. OutputMessage->Buffer,
  488. OutputMessage->BufferSize,
  489. &Reply
  490. );
  491. if (KERB_SUCCESS(ForwardKerbErr) &&
  492. KdcVerifyKdcAsRep(
  493. Reply,
  494. RequestBodyClientName
  495. ))
  496. {
  497. D_DebugLog((DEB_TRACE,"KLIN(%x) Successful AS-REP from PDC\n",
  498. KLIN(FILENO,__LINE__)));
  499. Reason = KDC_ERR_NONE; // PDC kerb error takes priority
  500. fForwardedToPDC = TRUE;
  501. RtlZeroMemory(&LogonStats, sizeof(LogonStats));
  502. LogonStats.StatisticsToApply =
  503. USER_LOGON_INTER_SUCCESS_LOGON |
  504. USER_LOGON_PDC_RETRY_SUCCESS |
  505. USER_LOGON_TYPE_KERBEROS;
  506. if ( (ClientAddress == NULL)
  507. || (ClientAddress->sa_family == AF_INET) )
  508. {
  509. LogonStats.ClientInfo.Type = SamClientIpAddr;
  510. LogonStats.ClientInfo.Data.IpAddr = *((ULONG*)GET_CLIENT_ADDRESS(ClientAddress));
  511. }
  512. Status = SamIUpdateLogonStatistics(
  513. UserHandle,
  514. &LogonStats
  515. );
  516. if (!NT_SUCCESS(Status))
  517. {
  518. D_DebugLog((DEB_ERROR,"Could not reset user bad pwd count - %x\n", Status));
  519. }
  520. D_DebugLog((DEB_TRACE,"KLIN(%x) SamIUpdate successful forward to PDC StatsApply 0x%x.\n",
  521. KLIN(FILENO,__LINE__), LogonStats.StatisticsToApply));
  522. StatusTemp = AsNegCacheDelete(
  523. Client,
  524. ClientSize,
  525. ClientNetbiosAddress->Buffer,
  526. ClientNetbiosAddress->Length
  527. );
  528. D_DebugLog((DEB_ERROR, "KLIN(%x) Purged entry due to valid fwd'd response\n",
  529. KLIN(FILENO,__LINE__)));
  530. } else {
  531. DebugLog((DEB_ERROR, "KLIN(%x) Got reply from fwd'd request to PDC, but wasn't valid!\n",
  532. KLIN(FILENO,__LINE__)));
  533. if (KerbErr != KRB_ERR_GENERIC)
  534. {
  535. Reason = KerbErr;
  536. fForwardedToPDC = TRUE;
  537. }
  538. }
  539. }
  540. }
  541. }
  542. }
  543. Cleanup:
  544. if (NULL != ErrorMessage)
  545. {
  546. KerbFreeKerbError(ErrorMessage);
  547. }
  548. if (NULL != Reply)
  549. {
  550. KerbFreeAsReply(Reply);
  551. }
  552. if (NULL != pExtendedError)
  553. {
  554. MIDL_user_free(pExtendedError);
  555. }
  556. if (Reason == KDC_ERR_PREAUTH_FAILED) // tests for LogonStatus == STATUS_WRONG_PASSWORD
  557. {
  558. RtlZeroMemory(&LogonStats, sizeof(LogonStats));
  559. LogonStats.StatisticsToApply =
  560. USER_LOGON_BAD_PASSWORD_WKSTA |
  561. USER_LOGON_TYPE_KERBEROS;
  562. // Indicate wrong password used but not if previous password matches
  563. if (!UsedOldPassword)
  564. {
  565. LogonStats.StatisticsToApply |= USER_LOGON_BAD_PASSWORD;
  566. }
  567. LogonStats.Workstation = *ClientNetbiosAddress;
  568. if ( (ClientAddress == NULL)
  569. || (ClientAddress->sa_family == AF_INET) )
  570. {
  571. LogonStats.ClientInfo.Type = SamClientIpAddr;
  572. LogonStats.ClientInfo.Data.IpAddr = *((ULONG*)GET_CLIENT_ADDRESS(ClientAddress));
  573. }
  574. Status = SamIUpdateLogonStatistics(
  575. UserHandle,
  576. &LogonStats
  577. );
  578. if (!NT_SUCCESS(Status))
  579. {
  580. D_DebugLog((DEB_ERROR, "SamIUpdateLogonStatistics failed - %x\n", Status ));
  581. }
  582. D_DebugLog((DEB_TRACE,"KLIN(%x) SamIUpdate Preauth failure StatsApply 0x%x.\n",
  583. KLIN(FILENO,__LINE__), LogonStats.StatisticsToApply));
  584. }
  585. else if (Reason == KDC_ERR_KEY_EXPIRED) // tests for ((LogonStatus == STATUS_PASSWORD_MUST_CHANGE) ||
  586. { // (LogonStatus == STATUS_PASSWORD_EXPIRED))
  587. RtlZeroMemory(&LogonStats, sizeof(LogonStats));
  588. LogonStats.StatisticsToApply =
  589. USER_LOGON_STAT_BAD_PWD_COUNT |
  590. (fForwardedToPDC ? USER_LOGON_PDC_RETRY_SUCCESS : 0) |
  591. USER_LOGON_TYPE_KERBEROS;
  592. LogonStats.Workstation = *ClientNetbiosAddress;
  593. if ( (ClientAddress == NULL)
  594. || (ClientAddress->sa_family == AF_INET) )
  595. {
  596. LogonStats.ClientInfo.Type = SamClientIpAddr;
  597. LogonStats.ClientInfo.Data.IpAddr = *((ULONG*)GET_CLIENT_ADDRESS(ClientAddress));
  598. }
  599. Status = SamIUpdateLogonStatistics(
  600. UserHandle,
  601. &LogonStats
  602. );
  603. if (!NT_SUCCESS(Status))
  604. {
  605. D_DebugLog((DEB_ERROR, "SamIUpdateLogonStatistics failed - %x\n", Status ));
  606. }
  607. D_DebugLog((DEB_TRACE,"KLIN(%x) SamIUpdate KeyExpire failure StatsApply 0x%x.\n",
  608. KLIN(FILENO,__LINE__), LogonStats.StatisticsToApply));
  609. }
  610. }
  611. //+---------------------------------------------------------------------------
  612. //
  613. // Function: KdcHandleNoLogonServers
  614. //
  615. // Synopsis: If a password has verified, and we've got no GCs against which
  616. // to validate logon restrictions, then go ahead and set the
  617. // sam info level to include the new USER_LOGON_NO_LOGON_SERVERS
  618. // flag
  619. //
  620. // Effects:
  621. //
  622. // Arguments: [UserHandle] -- Client who logged on.
  623. // [ClientAddress] -- Address of client making request
  624. //
  625. //
  626. // Algorithm:
  627. //
  628. // History: 24-Aug-2000 Todds Created
  629. //
  630. // Notes: On successful logon w/ no GC, update SAM user flag
  631. //
  632. //----------------------------------------------------------------------------
  633. KERBERR
  634. KdcHandleNoLogonServers(
  635. SAMPR_HANDLE UserHandle,
  636. PSOCKADDR ClientAddress OPTIONAL
  637. )
  638. {
  639. SAM_LOGON_STATISTICS LogonStats;
  640. TRACE(KDC, KdcHandleNoLogonServers, DEB_FUNCTION);
  641. RtlZeroMemory(&LogonStats, sizeof(LogonStats));
  642. LogonStats.StatisticsToApply =
  643. USER_LOGON_NO_LOGON_SERVERS | USER_LOGON_TYPE_KERBEROS;
  644. if ( (ClientAddress == NULL)
  645. || (ClientAddress->sa_family == AF_INET) ) {
  646. // Set to local address (known to be 4 bytes) or IP address
  647. LogonStats.ClientInfo.Type = SamClientIpAddr;
  648. LogonStats.ClientInfo.Data.IpAddr = *((ULONG*)GET_CLIENT_ADDRESS(ClientAddress));
  649. }
  650. (VOID) SamIUpdateLogonStatistics(
  651. UserHandle,
  652. &LogonStats
  653. );
  654. return(KDC_ERR_NONE);
  655. }
  656. //+---------------------------------------------------------------------------
  657. //
  658. // Function: SuccessfulLogon
  659. //
  660. // Synopsis: Processes a successful logon.
  661. //
  662. // Effects: May raise an event, create an audit, throw a party.
  663. //
  664. // Arguments: [UserHandle] -- Client who logged on.
  665. //
  666. //
  667. // Algorithm:
  668. //
  669. // History: 03-May-94 wader Created
  670. //
  671. // Notes: On successful logon, we discard the history of failed logons
  672. // (as far as lockout is concerned).
  673. //
  674. //----------------------------------------------------------------------------
  675. KERBERR
  676. SuccessfulLogon(
  677. IN SAMPR_HANDLE UserHandle,
  678. IN OPTIONAL PSOCKADDR ClientAddress,
  679. IN UCHAR *Client,
  680. IN ULONG ClientSize,
  681. IN PKERB_MESSAGE_BUFFER Request,
  682. IN PUNICODE_STRING ClientNetbiosAddress,
  683. IN PUSER_INTERNAL6_INFORMATION UserInfo
  684. )
  685. {
  686. SAM_LOGON_STATISTICS LogonStats;
  687. KERB_MESSAGE_BUFFER Reply = {0};
  688. NTSTATUS Status = STATUS_UNKNOWN_REVISION;
  689. DOMAIN_SERVER_ROLE ServerRole;
  690. TRACE(KDC, SuccessfulLogon, DEB_FUNCTION);
  691. RtlZeroMemory(&LogonStats, sizeof(LogonStats));
  692. LogonStats.StatisticsToApply =
  693. USER_LOGON_INTER_SUCCESS_LOGON | USER_LOGON_TYPE_KERBEROS;
  694. if ( (ClientAddress == NULL)
  695. || (ClientAddress->sa_family == AF_INET) ) {
  696. // Set to local address (known to be 4 bytes) or IP address
  697. LogonStats.ClientInfo.Type = SamClientIpAddr;
  698. LogonStats.ClientInfo.Data.IpAddr = *((ULONG*)GET_CLIENT_ADDRESS(ClientAddress));
  699. }
  700. (VOID) SamIUpdateLogonStatistics(
  701. UserHandle,
  702. &LogonStats
  703. );
  704. D_DebugLog((DEB_TRACE,"KLIN(%x) SamIUpdate Successfullogon StatsApply 0x%x.\n",
  705. KLIN(FILENO,__LINE__), LogonStats.StatisticsToApply));
  706. Status = SamIQueryServerRole(
  707. GlobalAccountDomainHandle,
  708. &ServerRole
  709. );
  710. if (NT_SUCCESS(Status) &&
  711. (ServerRole == DomainServerRoleBackup))
  712. {
  713. //
  714. // if this logon reset the bad password count, notify the PDC
  715. //
  716. if (UserInfo->I1.BadPasswordCount != 0)
  717. {
  718. Status = SamIResetBadPwdCountOnPdc(UserHandle);
  719. if (!NT_SUCCESS(Status))
  720. {
  721. if (Status == STATUS_UNKNOWN_REVISION)
  722. {
  723. D_DebugLog((DEB_ERROR, "SamIResetBadPwdCount not implemented on pdc.\n"));
  724. // W2k behavior, in case we have an old PDC
  725. (VOID) KdcForwardLogonToPDC(
  726. Request,
  727. &Reply
  728. );
  729. if (Reply.Buffer != NULL)
  730. {
  731. MIDL_user_free(Reply.Buffer);
  732. }
  733. }
  734. else
  735. {
  736. D_DebugLog((DEB_ERROR, "SamIResetBadPwdCount failed - %x.\n", Status));
  737. }
  738. }
  739. }
  740. // Clear any negative cache entry (Forward to PDC)
  741. (void)AsNegCacheDelete(
  742. Client,
  743. ClientSize,
  744. ClientNetbiosAddress->Buffer,
  745. ClientNetbiosAddress->Length
  746. );
  747. }
  748. return(KDC_ERR_NONE);
  749. }
  750. //+-------------------------------------------------------------------------
  751. //
  752. // Function: IsSubAuthFilterPresent
  753. //
  754. // Synopsis: Figures out whether the MSV1_0 subauthentication filter is present
  755. //
  756. // Effects:
  757. //
  758. // Arguments:
  759. //
  760. // Requires:
  761. //
  762. // Returns: TRUE or FALSE
  763. //
  764. // Notes:
  765. //
  766. //
  767. //--------------------------------------------------------------------------
  768. BOOLEAN
  769. IsSubAuthFilterPresent()
  770. {
  771. if ( KdcSubAuthFilterPresent == SubAuthUnknown ) {
  772. if ( Msv1_0SubAuthenticationPresent( KERB_SUBAUTHENTICATION_FLAG )) {
  773. KdcSubAuthFilterPresent = SubAuthYesFilter;
  774. } else {
  775. KdcSubAuthFilterPresent = SubAuthNoFilter;
  776. }
  777. }
  778. if ( KdcSubAuthFilterPresent == SubAuthNoFilter ) {
  779. return FALSE;
  780. }
  781. return TRUE;
  782. }
  783. //+-------------------------------------------------------------------------
  784. //
  785. // Function: KdcCallSubAuthRoutine
  786. //
  787. // Synopsis: Calls the MSV1_0 subauthentication filter, if it is present
  788. //
  789. // Effects: If the filter returns an error, returns that error
  790. //
  791. // Arguments:
  792. //
  793. // Requires:
  794. //
  795. // Returns:
  796. //
  797. // Notes:
  798. //
  799. //
  800. //--------------------------------------------------------------------------
  801. KERBERR
  802. KdcCallSubAuthRoutine(
  803. IN PKDC_TICKET_INFO TicketInfo,
  804. IN PUSER_INTERNAL6_INFORMATION UserInfo,
  805. IN PUNICODE_STRING ClientNetbiosAddress,
  806. OUT PLARGE_INTEGER LogoffTime,
  807. OUT PKERB_EXT_ERROR pExtendedError
  808. )
  809. {
  810. NTSTATUS Status = STATUS_SUCCESS;
  811. KERBERR KerbErr = KDC_ERR_NONE;
  812. NETLOGON_INTERACTIVE_INFO LogonInfo = {0};
  813. //
  814. // Subauth parameters
  815. //
  816. ULONG WhichFields = 0;
  817. ULONG UserFlags = 0;
  818. BOOLEAN Authoritative = TRUE;
  819. LARGE_INTEGER KickoffTime;
  820. PUSER_ALL_INFORMATION UserAll = &UserInfo->I1;
  821. //
  822. // Check if Msv1_0 has a subauth filter loaded
  823. //
  824. if ( !IsSubAuthFilterPresent()) {
  825. return KDC_ERR_NONE;
  826. }
  827. LogonInfo.Identity.LogonDomainName = *SecData.KdcRealmName();
  828. LogonInfo.Identity.ParameterControl = 0; // this can be set to use a particular package
  829. LogonInfo.Identity.UserName = TicketInfo->AccountName;
  830. LogonInfo.Identity.Workstation = *ClientNetbiosAddress;
  831. //
  832. // Leave logon id field blank
  833. //
  834. if (UserAll->NtPassword.Length == NT_OWF_PASSWORD_LENGTH)
  835. {
  836. RtlCopyMemory(
  837. &LogonInfo.NtOwfPassword,
  838. UserAll->NtPassword.Buffer,
  839. NT_OWF_PASSWORD_LENGTH
  840. );
  841. }
  842. if (UserAll->LmPassword.Length == LM_OWF_PASSWORD_LENGTH)
  843. {
  844. RtlCopyMemory(
  845. &LogonInfo.LmOwfPassword,
  846. UserAll->LmPassword.Buffer,
  847. NT_OWF_PASSWORD_LENGTH
  848. );
  849. }
  850. //
  851. // Make sure logoff time is intialized to something interesting
  852. //
  853. *LogoffTime = KickoffTime = UserAll->AccountExpires;
  854. //
  855. // Make the call
  856. //
  857. Status = Msv1_0ExportSubAuthenticationRoutine(
  858. NetlogonInteractiveInformation,
  859. &LogonInfo,
  860. MSV1_0_PASSTHRU,
  861. KERB_SUBAUTHENTICATION_FLAG,
  862. UserAll,
  863. &WhichFields,
  864. &UserFlags,
  865. &Authoritative,
  866. LogoffTime,
  867. &KickoffTime
  868. );
  869. //
  870. // If the kickoff time is more restrictive, use it.
  871. //
  872. if (KickoffTime.QuadPart < LogoffTime->QuadPart)
  873. {
  874. LogoffTime->QuadPart = KickoffTime.QuadPart;
  875. }
  876. //
  877. // Map the error code
  878. //
  879. if (!NT_SUCCESS(Status))
  880. {
  881. DebugLog((DEB_WARN,
  882. "(KLIN:%x) Subauth failed the logon: 0x%x\n",
  883. KLIN(FILENO, __LINE__),
  884. Status));
  885. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  886. KerbErr = KDC_ERR_POLICY;
  887. }
  888. return(KerbErr);
  889. }
  890. //+-------------------------------------------------------------------------
  891. //
  892. // Function: KdcBuildEtypeInfo
  893. //
  894. // Synopsis: Builds a list of supported etypes & salts
  895. //
  896. // Effects:
  897. //
  898. // Arguments: TicketInfo - client's ticket info
  899. // OutputPreAuth - receives any preauth data to return to client
  900. //
  901. // Requires:
  902. //
  903. // Returns: kerberr
  904. //
  905. // Notes:
  906. //
  907. //
  908. //--------------------------------------------------------------------------
  909. KERBERR
  910. KdcBuildEtypeInfo(
  911. IN PKDC_TICKET_INFO TicketInfo,
  912. IN PKERB_KDC_REQUEST_BODY RequestBody,
  913. OUT PKERB_PA_DATA_LIST * OutputPreAuth
  914. )
  915. {
  916. KERBERR KerbErr = KDC_ERR_NONE;
  917. BOOLEAN FoundEtype = FALSE;
  918. ULONG Index;
  919. PKERB_ETYPE_INFO NextEntry = NULL;
  920. PKERB_ETYPE_INFO EtypeInfo = NULL;
  921. PKERB_PA_DATA_LIST OutputList = NULL;
  922. UNICODE_STRING TempSalt = {0};
  923. STRING TempString = {0};
  924. *OutputPreAuth = NULL;
  925. //
  926. // Build the array of etypes, in reverse order because we are adding
  927. // to the front of the list
  928. //
  929. for ( Index = TicketInfo->Passwords->CredentialCount; Index > 0; Index-- )
  930. {
  931. //
  932. // Only return types that the client supports.
  933. //
  934. if (!KdcCheckForEtype(
  935. RequestBody->encryption_type,
  936. TicketInfo->Passwords->Credentials[Index-1].Key.keytype
  937. ))
  938. {
  939. continue;
  940. }
  941. FoundEtype = TRUE;
  942. NextEntry = (PKERB_ETYPE_INFO) MIDL_user_allocate(sizeof(KERB_ETYPE_INFO));
  943. if (NextEntry == NULL)
  944. {
  945. KerbErr = KRB_ERR_GENERIC;
  946. goto Cleanup;
  947. }
  948. RtlZeroMemory(
  949. NextEntry,
  950. sizeof(KERB_ETYPE_INFO)
  951. );
  952. //
  953. // Copy in the etype
  954. //
  955. NextEntry->value.encryption_type =
  956. TicketInfo->Passwords->Credentials[Index-1].Key.keytype;
  957. //
  958. // add the salt - check the per-key salt and then the default salt.
  959. //
  960. if (TicketInfo->Passwords->Credentials[Index-1].Salt.Buffer != NULL)
  961. {
  962. TempSalt = TicketInfo->Passwords->Credentials[Index-1].Salt;
  963. }
  964. else if (TicketInfo->Passwords->DefaultSalt.Buffer != NULL)
  965. {
  966. TempSalt = TicketInfo->Passwords->DefaultSalt;
  967. }
  968. else
  969. {
  970. TempSalt.Buffer = NULL ;
  971. TempSalt.Length = 0 ;
  972. TempSalt.MaximumLength = 0 ;
  973. }
  974. //
  975. // If we have a salt, convert it to ansi & return it.
  976. //
  977. if (TempSalt.Buffer != NULL)
  978. {
  979. TempString.Buffer = NULL;
  980. TempString.Length = 0;
  981. TempString.MaximumLength = 0;
  982. KerbErr = KerbUnicodeStringToKerbString(
  983. &TempString,
  984. &TempSalt
  985. );
  986. if (!KERB_SUCCESS(KerbErr))
  987. {
  988. MIDL_user_free(NextEntry);
  989. goto Cleanup;
  990. }
  991. NextEntry->value.bit_mask |= salt_present;
  992. NextEntry->value.salt.length = TempString.Length;
  993. NextEntry->value.salt.value = (PUCHAR) TempString.Buffer;
  994. }
  995. NextEntry->next = EtypeInfo;
  996. EtypeInfo = NextEntry;
  997. }
  998. //
  999. // If we can't find a matching etype, then we've got to return an error
  1000. // to the client...
  1001. if (FoundEtype)
  1002. {
  1003. OutputList = (PKERB_PA_DATA_LIST) MIDL_user_allocate(sizeof(KERB_PA_DATA_LIST));
  1004. if (OutputList == NULL)
  1005. {
  1006. KerbErr = KRB_ERR_GENERIC;
  1007. goto Cleanup;
  1008. }
  1009. RtlZeroMemory(
  1010. OutputList,
  1011. sizeof(KERB_PA_DATA_LIST)
  1012. );
  1013. OutputList->value.preauth_data_type = KRB5_PADATA_ETYPE_INFO;
  1014. OutputList->next = NULL;
  1015. KerbErr = KerbPackData(
  1016. &EtypeInfo,
  1017. PKERB_ETYPE_INFO_PDU,
  1018. (PULONG) &OutputList->value.preauth_data.length,
  1019. &OutputList->value.preauth_data.value
  1020. );
  1021. if (!KERB_SUCCESS(KerbErr))
  1022. {
  1023. goto Cleanup;
  1024. }
  1025. *OutputPreAuth = OutputList;
  1026. OutputList = NULL;
  1027. }
  1028. else // did not find etype from request that we support, warn the admin
  1029. {
  1030. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  1031. DebugLog((DEB_ERROR, "KdcCheckForEtype no intersection between client and server Etypes!\n"));
  1032. KdcReportKeyError(
  1033. &(TicketInfo->AccountName),
  1034. NULL,
  1035. KDC_KEY_ID_AS_BUILD_ETYPE_INFO,
  1036. KDCEVENT_NO_KEY_INTERSECTION_AS,
  1037. RequestBody->encryption_type,
  1038. TicketInfo
  1039. );
  1040. }
  1041. Cleanup:
  1042. //
  1043. // Cleanup the etype list, as it is returned in marshalled form.
  1044. //
  1045. while (EtypeInfo != NULL)
  1046. {
  1047. NextEntry = EtypeInfo->next;
  1048. if (EtypeInfo->value.salt.value != NULL)
  1049. {
  1050. TempString.Buffer = (PCHAR) EtypeInfo->value.salt.value;
  1051. TempString.Length = (USHORT) EtypeInfo->value.salt.length;
  1052. KerbFreeString((PUNICODE_STRING) &TempString);
  1053. }
  1054. MIDL_user_free(EtypeInfo);
  1055. EtypeInfo = NextEntry;
  1056. }
  1057. if (OutputList != NULL)
  1058. {
  1059. KerbFreePreAuthData( OutputList);
  1060. }
  1061. return KerbErr;
  1062. }
  1063. //+-------------------------------------------------------------------------
  1064. //
  1065. // Function: KdcBuildPreauthTypeList
  1066. //
  1067. // Synopsis: For returning with a PREAUTH-REQUIRED message
  1068. //
  1069. // Effects:
  1070. //
  1071. // Arguments:
  1072. //
  1073. // Requires:
  1074. //
  1075. // Returns:
  1076. //
  1077. // Notes:
  1078. //
  1079. //
  1080. //--------------------------------------------------------------------------
  1081. KERBERR
  1082. KdcBuildPreauthTypeList(
  1083. OUT PKERB_PA_DATA_LIST * PreauthTypeList
  1084. )
  1085. {
  1086. PKERB_PA_DATA_LIST DataList = NULL;
  1087. KERBERR KerbErr = KDC_ERR_NONE;
  1088. //
  1089. // Allocate and fill in the first item
  1090. //
  1091. DataList = (PKERB_PA_DATA_LIST) MIDL_user_allocate(sizeof(KERB_PA_DATA_LIST));
  1092. if (DataList == NULL)
  1093. {
  1094. KerbErr = KRB_ERR_GENERIC;
  1095. goto Cleanup;
  1096. }
  1097. RtlZeroMemory(
  1098. DataList,
  1099. sizeof(KERB_PA_DATA_LIST)
  1100. );
  1101. DataList->value.preauth_data_type = KRB5_PADATA_ENC_TIMESTAMP;
  1102. //
  1103. // Even if we fail the allocation, we can still return this value.
  1104. //
  1105. *PreauthTypeList = DataList;
  1106. DataList->next = (PKERB_PA_DATA_LIST) MIDL_user_allocate(sizeof(KERB_PA_DATA_LIST));
  1107. if (DataList->next == NULL)
  1108. {
  1109. KerbErr = KRB_ERR_GENERIC;
  1110. goto Cleanup;
  1111. }
  1112. RtlZeroMemory(
  1113. DataList->next,
  1114. sizeof(KERB_PA_DATA_LIST)
  1115. );
  1116. DataList = DataList->next;
  1117. DataList->value.preauth_data_type = KRB5_PADATA_PK_AS_REP;
  1118. Cleanup:
  1119. return(KerbErr);
  1120. }
  1121. //+-------------------------------------------------------------------------
  1122. //
  1123. // Function: KdcBuildPwSalt
  1124. //
  1125. // Synopsis: builds the pw-salt pa data type
  1126. //
  1127. // Effects:
  1128. //
  1129. // Arguments:
  1130. //
  1131. // Requires:
  1132. //
  1133. // Returns:
  1134. //
  1135. // Notes:
  1136. //
  1137. //
  1138. //--------------------------------------------------------------------------
  1139. KERBERR
  1140. KdcBuildPwSalt(
  1141. IN PKERB_STORED_CREDENTIAL Passwords,
  1142. IN PKERB_ENCRYPTION_KEY ReplyKey,
  1143. IN OUT PKERB_PA_DATA_LIST * OutputPreAuthData
  1144. )
  1145. {
  1146. KERBERR KerbErr = KDC_ERR_NONE;
  1147. PKERB_PA_DATA_LIST DataList = NULL;
  1148. PKERB_KEY_DATA KeyData = NULL;
  1149. STRING Salt = {0};
  1150. UNICODE_STRING SaltUsed = {0};
  1151. ULONG Index;
  1152. //
  1153. // Find the key use for encryption.
  1154. //
  1155. for (Index = 0; Index < Passwords->CredentialCount ; Index++ )
  1156. {
  1157. if (Passwords->Credentials[Index].Key.keytype == (int) ReplyKey->keytype)
  1158. {
  1159. KeyData = &Passwords->Credentials[Index];
  1160. break;
  1161. }
  1162. }
  1163. if (KeyData == NULL)
  1164. {
  1165. goto Cleanup;
  1166. }
  1167. //
  1168. // Locate the salt used
  1169. //
  1170. switch ( ReplyKey->keytype )
  1171. {
  1172. case KERB_ETYPE_RC4_HMAC_NT:
  1173. case KERB_ETYPE_RC4_HMAC_NT_EXP:
  1174. case KERB_ETYPE_RC4_HMAC_OLD:
  1175. case KERB_ETYPE_RC4_MD4:
  1176. //
  1177. // These etypes don't use salt - don't send it.
  1178. //
  1179. goto Cleanup;
  1180. case KERB_ETYPE_DES_CBC_MD5:
  1181. case KERB_ETYPE_DES_CBC_CRC:
  1182. if (KeyData->Salt.Buffer != NULL)
  1183. {
  1184. SaltUsed = KeyData->Salt;
  1185. }
  1186. else if (Passwords->DefaultSalt.Buffer != NULL)
  1187. {
  1188. SaltUsed = Passwords->DefaultSalt;
  1189. }
  1190. break;
  1191. default:
  1192. //
  1193. // Don't fail on unknown etypes - just don't send papwsalt.
  1194. //
  1195. D_DebugLog(( DEB_WARN, "Trying to salt %x etype, which we don't know\n", ReplyKey->keytype ));
  1196. goto Cleanup;
  1197. }
  1198. //
  1199. // Convert the salt to a kerb string
  1200. //
  1201. KerbErr = KerbUnicodeStringToKerbString(
  1202. &Salt,
  1203. &SaltUsed
  1204. );
  1205. if (!KERB_SUCCESS(KerbErr))
  1206. {
  1207. goto Cleanup;
  1208. }
  1209. //
  1210. // Allocate and fill in the first item
  1211. //
  1212. DataList = (PKERB_PA_DATA_LIST) MIDL_user_allocate(sizeof(KERB_PA_DATA_LIST));
  1213. if (DataList == NULL)
  1214. {
  1215. KerbErr = KRB_ERR_GENERIC;
  1216. goto Cleanup;
  1217. }
  1218. RtlZeroMemory(
  1219. DataList,
  1220. sizeof(KERB_PA_DATA_LIST)
  1221. );
  1222. DataList->value.preauth_data_type = KRB5_PADATA_PW_SALT;
  1223. DataList->value.preauth_data.length = Salt.Length;
  1224. DataList->value.preauth_data.value = (PUCHAR) Salt.Buffer;
  1225. Salt.Buffer = NULL;
  1226. DataList->next = *OutputPreAuthData;
  1227. *OutputPreAuthData = DataList;
  1228. DataList = NULL;
  1229. Cleanup:
  1230. if (DataList != NULL)
  1231. {
  1232. KerbFreePreAuthData((PKERB_PA_DATA_LIST)DataList);
  1233. }
  1234. if (Salt.Buffer != NULL)
  1235. {
  1236. MIDL_user_free(Salt.Buffer);
  1237. }
  1238. return(KerbErr);
  1239. }
  1240. //+-------------------------------------------------------------------------
  1241. //
  1242. // Function: KdcVerifyEncryptedTimeStamp
  1243. //
  1244. // Synopsis: Verifies an encrypted time stamp pre-auth data
  1245. //
  1246. // Effects:
  1247. //
  1248. // Arguments: PreAuthData - preauth data from client
  1249. // TicketInfo - client's ticket info
  1250. // UserHandle - handle to client's account
  1251. // OutputPreAuth - receives any preauth data to return to client
  1252. //
  1253. // Requires:
  1254. //
  1255. // Returns: KDC_ERR_PREAUTH_FAILED - the password was bad
  1256. // Other errors - preauth failed but shouldn't trigger lockout
  1257. //
  1258. // Notes:
  1259. //
  1260. //
  1261. //--------------------------------------------------------------------------
  1262. KERBERR
  1263. KdcVerifyEncryptedTimeStamp(
  1264. IN PKERB_PA_DATA_LIST PreAuthData,
  1265. IN PKDC_TICKET_INFO TicketInfo,
  1266. IN PKERB_KDC_REQUEST_BODY RequestBody,
  1267. IN SAMPR_HANDLE UserHandle,
  1268. OUT PKERB_PA_DATA_LIST * OutputPreAuth,
  1269. OUT PBOOLEAN UsedOldPassword
  1270. )
  1271. {
  1272. KERBERR KerbErr;
  1273. PKERB_ENCRYPTED_DATA EncryptedData = NULL;
  1274. PKERB_ENCRYPTED_TIMESTAMP EncryptedTime = NULL;
  1275. PKERB_ENCRYPTION_KEY UserKey = NULL;
  1276. LARGE_INTEGER CurrentTime;
  1277. LARGE_INTEGER ClientTime;
  1278. if ((TicketInfo->UserAccountControl & USER_ACCOUNT_DISABLED))
  1279. {
  1280. KerbErr = KDC_ERR_CLIENT_REVOKED;
  1281. goto Cleanup;
  1282. }
  1283. //
  1284. // Unpack the pre-auth data into an encrypted data first.
  1285. //
  1286. KerbErr = KerbUnpackEncryptedData(
  1287. PreAuthData->value.preauth_data.value,
  1288. PreAuthData->value.preauth_data.length,
  1289. &EncryptedData
  1290. );
  1291. if (!KERB_SUCCESS(KerbErr))
  1292. {
  1293. goto Cleanup;
  1294. }
  1295. //
  1296. // Now decrypt the encrypted data (in place)
  1297. //
  1298. UserKey = KerbGetKeyFromList(
  1299. TicketInfo->Passwords,
  1300. EncryptedData->encryption_type
  1301. );
  1302. if (UserKey == NULL)
  1303. {
  1304. // fakeit
  1305. KERB_CRYPT_LIST FakeList;
  1306. DebugLog((DEB_ERROR, "KdcVerifyEncryptedTimeStamp found no key %#x for %wZ, account control %#x\n",
  1307. EncryptedData->encryption_type, &TicketInfo->AccountName, TicketInfo->UserAccountControl));
  1308. FakeList.next = NULL;
  1309. FakeList.value = EncryptedData->encryption_type ;
  1310. //
  1311. // do not report an error if this is an DES only user and the preauth
  1312. // etype is RC4_HMAC_NT: the client can remove this error by setting
  1313. // DefaultEncryptionType registry key and this is a common error
  1314. // (although invalid)
  1315. //
  1316. if ( !( (TicketInfo->UserAccountControl & USER_USE_DES_KEY_ONLY)
  1317. && (EncryptedData->encryption_type == KERB_ETYPE_RC4_HMAC_NT) ) )
  1318. {
  1319. KdcReportKeyError(
  1320. &(TicketInfo->AccountName),
  1321. NULL,
  1322. KDC_KEY_ID_AS_VERIFY_PREAUTH,
  1323. KDCEVENT_NO_KEY_INTERSECTION_AS,
  1324. &FakeList,
  1325. TicketInfo
  1326. );
  1327. }
  1328. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  1329. goto Cleanup;
  1330. }
  1331. KerbErr = KerbDecryptDataEx(
  1332. EncryptedData,
  1333. UserKey,
  1334. KERB_ENC_TIMESTAMP_SALT,
  1335. (PULONG) &EncryptedData->cipher_text.length,
  1336. EncryptedData->cipher_text.value
  1337. );
  1338. if (!KERB_SUCCESS(KerbErr))
  1339. {
  1340. KERBERR KerbErr2;
  1341. ULONG ulIndex = 0;
  1342. //
  1343. // Bug #450148: Do not increment account lockout count when logging
  1344. // on with old password
  1345. //
  1346. // Attempt to decrypt the data using the old password to see if that
  1347. // is what is going on
  1348. // We will check the previous password and the one before that (second previous)
  1349. // password should it exist.
  1350. //
  1351. //
  1352. // Original EncryptedData has been trashed by in-proc decryption;
  1353. // must re-generate
  1354. //
  1355. KerbFreeEncryptedData(EncryptedData);
  1356. EncryptedData = NULL;
  1357. UserKey = NULL;
  1358. KerbErr2 = KerbUnpackEncryptedData(
  1359. PreAuthData->value.preauth_data.value,
  1360. PreAuthData->value.preauth_data.length,
  1361. &EncryptedData
  1362. );
  1363. if ( KERB_SUCCESS( KerbErr2 ))
  1364. {
  1365. UserKey = KerbGetKeyFromListByIndex(
  1366. TicketInfo->OldPasswords,
  1367. EncryptedData->encryption_type,
  1368. &ulIndex
  1369. );
  1370. }
  1371. if (UserKey != NULL)
  1372. {
  1373. KerbErr2 = KerbDecryptDataEx(
  1374. EncryptedData,
  1375. UserKey,
  1376. KERB_ENC_TIMESTAMP_SALT,
  1377. (PULONG) &EncryptedData->cipher_text.length,
  1378. EncryptedData->cipher_text.value
  1379. );
  1380. }
  1381. else
  1382. {
  1383. KerbErr2 = KDC_ERR_ETYPE_NOTSUPP;
  1384. }
  1385. if ( KERB_SUCCESS( KerbErr2 ))
  1386. {
  1387. D_DebugLog((DEB_WARN,
  1388. "KLIN(%x) Pre-auth data encrypted with old password\n",
  1389. KLIN(FILENO,__LINE__)));
  1390. *UsedOldPassword = TRUE;
  1391. }
  1392. else
  1393. {
  1394. D_DebugLog((DEB_WARN,
  1395. "KLIN(%x) Failed to decrypt timestamp pre-auth data with previous old password: 0x%x\n",
  1396. KLIN(FILENO,__LINE__),
  1397. KerbErr2));
  1398. // Now see if the password before that (second previous) password matches
  1399. // This is necessary to hanlde the cases where an account is locked out and
  1400. // then the password is reset and change password on next login is selected.
  1401. // This requires a test of the previous 2 passwords in history
  1402. //
  1403. // Original EncryptedData has been trashed by in-proc decryption;
  1404. // must re-generate
  1405. //
  1406. KerbFreeEncryptedData(EncryptedData);
  1407. EncryptedData = NULL;
  1408. UserKey = NULL;
  1409. KerbErr2 = KerbUnpackEncryptedData(
  1410. PreAuthData->value.preauth_data.value,
  1411. PreAuthData->value.preauth_data.length,
  1412. &EncryptedData
  1413. );
  1414. if ( KERB_SUCCESS( KerbErr2 ))
  1415. {
  1416. UserKey = KerbGetKeyFromListByIndex(
  1417. TicketInfo->OldPasswords,
  1418. EncryptedData->encryption_type,
  1419. &ulIndex
  1420. );
  1421. }
  1422. if (UserKey != NULL)
  1423. {
  1424. KerbErr2 = KerbDecryptDataEx(
  1425. EncryptedData,
  1426. UserKey,
  1427. KERB_ENC_TIMESTAMP_SALT,
  1428. (PULONG) &EncryptedData->cipher_text.length,
  1429. EncryptedData->cipher_text.value
  1430. );
  1431. }
  1432. else
  1433. {
  1434. KerbErr2 = KDC_ERR_ETYPE_NOTSUPP;
  1435. }
  1436. if ( KERB_SUCCESS( KerbErr2 ))
  1437. {
  1438. D_DebugLog((DEB_WARN,
  1439. "KLIN(%x) Pre-auth data encrypted with second old password\n",
  1440. KLIN(FILENO,__LINE__)));
  1441. *UsedOldPassword = TRUE;
  1442. }
  1443. else
  1444. {
  1445. D_DebugLog((DEB_WARN,
  1446. "KLIN(%x) Failed to decrypt timestamp pre-auth data with second previous old password: 0x%x\n",
  1447. KLIN(FILENO,__LINE__),
  1448. KerbErr2));
  1449. }
  1450. }
  1451. KerbErr = KDC_ERR_PREAUTH_FAILED;
  1452. goto Cleanup;
  1453. }
  1454. //
  1455. // unpack the decrypted data into a KERB_ENCRYPTED_TIMESTAMP
  1456. //
  1457. KerbErr = KerbUnpackData(
  1458. EncryptedData->cipher_text.value,
  1459. EncryptedData->cipher_text.length,
  1460. KERB_ENCRYPTED_TIMESTAMP_PDU,
  1461. (PVOID *) &EncryptedTime
  1462. );
  1463. if (!KERB_SUCCESS(KerbErr))
  1464. {
  1465. D_DebugLog((DEB_WARN,"KLIN(%x) Failed to unpack preauth data to encrpyted_time\n",
  1466. KLIN(FILENO,__LINE__)));
  1467. goto Cleanup;
  1468. }
  1469. //
  1470. // Now verify the time.
  1471. //
  1472. KerbConvertGeneralizedTimeToLargeInt(
  1473. &ClientTime,
  1474. &EncryptedTime->timestamp,
  1475. ((EncryptedTime->bit_mask & KERB_ENCRYPTED_TIMESTAMP_usec_present) != 0) ?
  1476. EncryptedTime->KERB_ENCRYPTED_TIMESTAMP_usec : 0
  1477. );
  1478. GetSystemTimeAsFileTime(
  1479. (PFILETIME) &CurrentTime
  1480. );
  1481. //
  1482. // We don't want to check too closely, so allow for skew
  1483. //
  1484. if ((CurrentTime.QuadPart + SkewTime.QuadPart < ClientTime.QuadPart) ||
  1485. (CurrentTime.QuadPart - SkewTime.QuadPart > ClientTime.QuadPart))
  1486. {
  1487. D_DebugLog((DEB_ERROR, "KLIN(%x) Client %wZ time is incorrect:\n",
  1488. KLIN(FILENO,__LINE__),
  1489. &TicketInfo->AccountName));
  1490. PrintTime(DEB_ERROR, "Client Time is", &ClientTime );
  1491. PrintTime(DEB_ERROR, "KDC Time is", &CurrentTime );
  1492. //
  1493. // We don't want to lockout the account if the time is off
  1494. //
  1495. KerbErr = KRB_AP_ERR_SKEW;
  1496. goto Cleanup;
  1497. }
  1498. KerbErr = KDC_ERR_NONE;
  1499. Cleanup:
  1500. //
  1501. // Build an ETYPE_INFO structure to return
  1502. //
  1503. if ((KerbErr == KDC_ERR_PREAUTH_FAILED) || (KerbErr == KDC_ERR_ETYPE_NOTSUPP))
  1504. {
  1505. KERBERR TmpErr;
  1506. TmpErr = KdcBuildEtypeInfo(
  1507. TicketInfo,
  1508. RequestBody,
  1509. OutputPreAuth
  1510. );
  1511. //
  1512. // In this case, we can't find any ETypes that both the client and
  1513. // server support, so we've got to bail w/ proper error
  1514. // message...
  1515. //
  1516. if (TmpErr == KDC_ERR_ETYPE_NOTSUPP)
  1517. {
  1518. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  1519. }
  1520. }
  1521. if (EncryptedData != NULL)
  1522. {
  1523. KerbFreeEncryptedData(EncryptedData);
  1524. }
  1525. if (EncryptedTime != NULL)
  1526. {
  1527. KerbFreeData(KERB_ENCRYPTED_TIMESTAMP_PDU, EncryptedTime);
  1528. }
  1529. return(KerbErr);
  1530. }
  1531. typedef enum _BUILD_PAC_OPTIONS {
  1532. IncludePac,
  1533. DontIncludePac,
  1534. DontCare
  1535. } BUILD_PAC_OPTIONS, *PBUILD_PAC_OPTIONS;
  1536. //+-------------------------------------------------------------------------
  1537. //
  1538. // Function: KdcCheckPacRequestPreAuthData
  1539. //
  1540. // Synopsis: Gets the status of whether the client wants a PAC from the
  1541. // pre-auth data
  1542. //
  1543. // Effects:
  1544. //
  1545. // Arguments:
  1546. //
  1547. // Requires:
  1548. //
  1549. // Returns:
  1550. //
  1551. // Notes:
  1552. //
  1553. //
  1554. //--------------------------------------------------------------------------
  1555. KERBERR
  1556. KdcCheckPacRequestPreAuthData(
  1557. IN PKERB_PA_DATA_LIST PreAuthData,
  1558. IN OUT PBUILD_PAC_OPTIONS BuildPac
  1559. )
  1560. {
  1561. PKERB_PA_PAC_REQUEST PacRequest = NULL;
  1562. KERBERR KerbErr = KDC_ERR_NONE;
  1563. DsysAssert(PreAuthData->value.preauth_data_type == KRB5_PADATA_PAC_REQUEST);
  1564. KerbErr = KerbUnpackData(
  1565. PreAuthData->value.preauth_data.value,
  1566. PreAuthData->value.preauth_data.length,
  1567. KERB_PA_PAC_REQUEST_PDU,
  1568. (PVOID *) &PacRequest
  1569. );
  1570. if (!KERB_SUCCESS(KerbErr))
  1571. {
  1572. goto Cleanup;
  1573. }
  1574. if (PacRequest->include_pac)
  1575. {
  1576. *BuildPac = IncludePac;
  1577. }
  1578. else
  1579. {
  1580. *BuildPac = DontIncludePac;
  1581. }
  1582. D_DebugLog((DEB_T_TICKETS,"Setting BuildPac from pa-data to %d\n",*BuildPac));
  1583. Cleanup:
  1584. if (PacRequest != NULL)
  1585. {
  1586. KerbFreeData(
  1587. KERB_PA_PAC_REQUEST_PDU,
  1588. PacRequest
  1589. );
  1590. }
  1591. return(KerbErr);
  1592. }
  1593. //+-------------------------------------------------------------------------
  1594. //
  1595. // Function: KdcCheckPreAuthData
  1596. //
  1597. // Synopsis: Checks the pre-auth data in an AS request. This routine
  1598. // may return pre-auth data to caller on both success and
  1599. // failure.
  1600. //
  1601. // Effects:
  1602. //
  1603. // Arguments: ClientTicketInfo - client account's ticket info
  1604. // UserHandle - Handle to client's user object
  1605. // PreAuthData - Pre-auth data supplied by client
  1606. // PreAuthType - The type of pre-auth used
  1607. // OutputPreAuthData - pre-auth data to return to client
  1608. // BuildPac - TRUE if we should build a PAC for this client
  1609. //
  1610. //
  1611. // Requires:
  1612. //
  1613. // Returns: KDC_ERR_PREAUTH_REQUIRED, KDC_ERR_PREAUTH_FAILED
  1614. //
  1615. // Notes: This routine should be more extensible - at some point
  1616. // it should allow DLLs to be plugged in that implement
  1617. // preauth.
  1618. //
  1619. //
  1620. //--------------------------------------------------------------------------
  1621. KERBERR
  1622. KdcCheckPreAuthData(
  1623. IN PKDC_TICKET_INFO ClientTicketInfo,
  1624. IN SAMPR_HANDLE UserHandle,
  1625. IN PUSER_INTERNAL6_INFORMATION UserInfo,
  1626. IN OPTIONAL PKERB_PA_DATA_LIST PreAuthData,
  1627. IN PKERB_KDC_REQUEST_BODY RequestBody,
  1628. OUT PULONG PreAuthType,
  1629. OUT PKERB_PA_DATA_LIST * OutputPreAuthData,
  1630. OUT PBOOLEAN BuildPac,
  1631. OUT PULONG Nonce,
  1632. OUT PKERB_ENCRYPTION_KEY EncryptionKey,
  1633. OUT PUNICODE_STRING TransitedRealms,
  1634. OUT PKDC_PKI_AUDIT_INFO PkiAuditInfo,
  1635. OUT PKERB_MESSAGE_BUFFER ErrorData,
  1636. OUT PKERB_EXT_ERROR pExtendedError,
  1637. OUT PBOOLEAN UsedOldPassword
  1638. )
  1639. {
  1640. KERBERR KerbErr = KDC_ERR_NONE;
  1641. PKERB_PA_DATA_LIST OutputElement = NULL;
  1642. PKERB_PA_DATA_LIST ListElement = NULL;
  1643. BOOLEAN ValidPreauthPresent = FALSE;
  1644. BUILD_PAC_OPTIONS PacOptions = DontCare;
  1645. *OutputPreAuthData = NULL;
  1646. *BuildPac = FALSE;
  1647. *UsedOldPassword = FALSE;
  1648. //
  1649. // Loop through the supplied pre-auth data elements and handle each one
  1650. //
  1651. for (ListElement = PreAuthData;
  1652. ListElement != NULL ;
  1653. ListElement = ListElement->next )
  1654. {
  1655. switch(ListElement->value.preauth_data_type) {
  1656. case KRB5_PADATA_ENC_TIMESTAMP:
  1657. *PreAuthType = ListElement->value.preauth_data_type;
  1658. KerbErr = KdcVerifyEncryptedTimeStamp(
  1659. ListElement,
  1660. ClientTicketInfo,
  1661. RequestBody,
  1662. UserHandle,
  1663. &OutputElement,
  1664. UsedOldPassword
  1665. );
  1666. if (KERB_SUCCESS(KerbErr))
  1667. {
  1668. ValidPreauthPresent = TRUE;
  1669. }
  1670. break;
  1671. case KRB5_PADATA_PK_AS_REP:
  1672. *PreAuthType = ListElement->value.preauth_data_type;
  1673. KerbErr = KdcCheckPkinitPreAuthData(
  1674. ClientTicketInfo,
  1675. UserHandle,
  1676. ListElement,
  1677. RequestBody,
  1678. &OutputElement,
  1679. Nonce,
  1680. EncryptionKey,
  1681. TransitedRealms,
  1682. PkiAuditInfo,
  1683. pExtendedError
  1684. );
  1685. if (KERB_SUCCESS(KerbErr))
  1686. {
  1687. ValidPreauthPresent = TRUE;
  1688. }
  1689. break;
  1690. case KRB5_PADATA_PAC_REQUEST:
  1691. KerbErr = KdcCheckPacRequestPreAuthData(
  1692. ListElement,
  1693. &PacOptions
  1694. );
  1695. break;
  1696. default:
  1697. break;
  1698. } // switch
  1699. if (OutputElement != NULL)
  1700. {
  1701. OutputElement->next = *OutputPreAuthData;
  1702. *OutputPreAuthData = OutputElement;
  1703. OutputElement = NULL;
  1704. }
  1705. if (!KERB_SUCCESS(KerbErr))
  1706. {
  1707. goto Cleanup;
  1708. }
  1709. } // for
  1710. // We need to check preauth data by default, unless, the account tells
  1711. // us not to.
  1712. //
  1713. if (!(UserInfo->I1.UserAccountControl & USER_DONT_REQUIRE_PREAUTH) &&
  1714. !ValidPreauthPresent &&
  1715. KERB_SUCCESS(KerbErr))
  1716. {
  1717. KerbErr = KDC_ERR_PREAUTH_REQUIRED;
  1718. //
  1719. // Return the list of supported types, if we don't have other
  1720. // data to return.
  1721. //
  1722. if (*OutputPreAuthData == NULL)
  1723. {
  1724. (VOID) KdcBuildPreauthTypeList(OutputPreAuthData);
  1725. if (*OutputPreAuthData != NULL)
  1726. {
  1727. PKERB_PA_DATA_LIST EtypeInfo = NULL;
  1728. KERBERR TmpErr;
  1729. TmpErr = KdcBuildEtypeInfo(
  1730. ClientTicketInfo,
  1731. RequestBody,
  1732. &EtypeInfo
  1733. );
  1734. //
  1735. // In this case, we can't find any ETypes that both the client and
  1736. // server support, so we've got to bail w/ proper error
  1737. // message...
  1738. //
  1739. if (TmpErr == KDC_ERR_ETYPE_NOTSUPP)
  1740. {
  1741. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  1742. }
  1743. if (EtypeInfo != NULL)
  1744. {
  1745. EtypeInfo->next = *OutputPreAuthData;
  1746. *OutputPreAuthData = EtypeInfo;
  1747. EtypeInfo = NULL;
  1748. }
  1749. }
  1750. }
  1751. }
  1752. //
  1753. // Set the final option for including the pac- if the pac_request was
  1754. // included, honor it. Otherwise build the pac if valid preauth
  1755. // was supplied.
  1756. //
  1757. switch(PacOptions) {
  1758. case DontCare:
  1759. *BuildPac = ValidPreauthPresent;
  1760. break;
  1761. case IncludePac:
  1762. *BuildPac = TRUE;
  1763. break;
  1764. case DontIncludePac:
  1765. *BuildPac = FALSE;
  1766. break;
  1767. }
  1768. Cleanup:
  1769. return(KerbErr);
  1770. }
  1771. //+---------------------------------------------------------------------------
  1772. //
  1773. // Function: BuildTicketAS
  1774. //
  1775. // Synopsis: Builds an AS ticket, including filling inthe name fields
  1776. // and flag fields.
  1777. //
  1778. // Arguments: [ClientTicketInfo] -- client asking for the ticket
  1779. // [ClientName] -- name of client
  1780. // [ServiceTicketInfo] -- service ticket is for
  1781. // [ServerName] -- name of service
  1782. // [RequestBody] -- ticket request
  1783. // [NewTicket] -- (out) ticket
  1784. //
  1785. // History: 24-May-93 WadeR Created
  1786. //
  1787. // Notes: See 3.1.3, A.2 of the Kerberos V5 R5.2 spec
  1788. //
  1789. //----------------------------------------------------------------------------
  1790. KERBERR
  1791. BuildTicketAS(
  1792. IN PKDC_TICKET_INFO ClientTicketInfo,
  1793. IN PKERB_PRINCIPAL_NAME ClientName,
  1794. IN PKDC_TICKET_INFO ServiceTicketInfo,
  1795. IN PKERB_PRINCIPAL_NAME ServerName,
  1796. IN OPTIONAL PKERB_HOST_ADDRESSES HostAddresses,
  1797. IN PLARGE_INTEGER LogoffTime,
  1798. IN PLARGE_INTEGER AccountExpiry,
  1799. IN PKERB_KDC_REQUEST_BODY RequestBody,
  1800. IN ULONG CommonEType,
  1801. IN ULONG PreAuthType,
  1802. IN PUNICODE_STRING TransitedRealm,
  1803. OUT PKERB_TICKET NewTicket,
  1804. OUT PKERB_EXT_ERROR pExtendedError
  1805. )
  1806. {
  1807. KERBERR Status = KDC_ERR_NONE;
  1808. PKERB_ENCRYPTED_TICKET EncryptedTicket = NULL;
  1809. LARGE_INTEGER TicketLifespan;
  1810. LARGE_INTEGER TicketRenewspan;
  1811. ULONG KdcOptions = 0;
  1812. BOOLEAN fKpasswd = FALSE;
  1813. TRACE(KDC, BuildTicketAS, DEB_FUNCTION);
  1814. EncryptedTicket = (PKERB_ENCRYPTED_TICKET) NewTicket->encrypted_part.cipher_text.value;
  1815. KdcOptions = KerbConvertFlagsToUlong(&RequestBody->kdc_options);
  1816. NewTicket->ticket_version = KERBEROS_VERSION;
  1817. D_DebugLog((DEB_T_TICKETS, "Building an AS ticket to cname %wZ for sname %wZ\n",
  1818. &ClientTicketInfo->AccountName, &ServiceTicketInfo->AccountName));
  1819. //
  1820. // Since this is the AS ticket, we fake the TGTFlags parameter to be the
  1821. // maximum the client is allowed to have.
  1822. //
  1823. // Check to see if the request is for kadmin/changepw service, in which
  1824. // case, we only want the ticket to be good for 2 minutes
  1825. //
  1826. Status = KerbCompareKdcNameToPrincipalName(
  1827. ServerName,
  1828. GlobalKpasswdName,
  1829. &fKpasswd
  1830. );
  1831. if (!KERB_SUCCESS(Status))
  1832. {
  1833. D_DebugLog((DEB_TRACE,"KLIN(%x) Failed to check server name against GlobalKpasswdName: 0x%x\n",
  1834. KLIN(FILENO,__LINE__), Status));
  1835. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1836. goto Cleanup;
  1837. }
  1838. if (fKpasswd)
  1839. {
  1840. D_DebugLog((DEB_TRACE, "Restricting service ticket life time for kadmin/changepw\n"));
  1841. TicketLifespan.QuadPart = (LONGLONG) 10000000 * 60 * 2;
  1842. TicketRenewspan.QuadPart = (LONGLONG) 10000000 * 60 * 2;
  1843. }
  1844. else
  1845. {
  1846. TicketLifespan = SecData.KdcTgtTicketLifespan();
  1847. TicketRenewspan = SecData.KdcTicketRenewSpan();
  1848. }
  1849. Status = KdcBuildTicketTimesAndFlags(
  1850. ClientTicketInfo->fTicketOpts,
  1851. ServiceTicketInfo->fTicketOpts,
  1852. &TicketLifespan,
  1853. &TicketRenewspan,
  1854. NULL, // no s4u info
  1855. LogoffTime,
  1856. AccountExpiry,
  1857. RequestBody,
  1858. NULL, // no source ticket
  1859. EncryptedTicket,
  1860. pExtendedError
  1861. );
  1862. if (!KERB_SUCCESS(Status))
  1863. {
  1864. D_DebugLog((DEB_TRACE,"KLIN(%x) Failed to build ticket times and flags: 0x%x\n",
  1865. KLIN(FILENO,__LINE__), Status));
  1866. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1867. goto Cleanup;
  1868. }
  1869. *((PULONG)EncryptedTicket->flags.value) |= KerbConvertUlongToFlagUlong(KERB_TICKET_FLAGS_initial);
  1870. //
  1871. // Turn on preauth flag if necessary
  1872. //
  1873. if (PreAuthType != 0)
  1874. {
  1875. *((PULONG)EncryptedTicket->flags.value) |= KerbConvertUlongToFlagUlong(KERB_TICKET_FLAGS_pre_authent);
  1876. }
  1877. Status = KerbMakeKey(
  1878. CommonEType,
  1879. &EncryptedTicket->key
  1880. );
  1881. if (!KERB_SUCCESS(Status))
  1882. {
  1883. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1884. goto Cleanup;
  1885. }
  1886. //
  1887. // Insert the service names. If the client requested canoncalization,
  1888. // return our realm name & sam account name. Otherwise copy what the
  1889. // client requested
  1890. //
  1891. if (((KdcOptions & KERB_KDC_OPTIONS_name_canonicalize) != 0) &&
  1892. ((ServiceTicketInfo->UserAccountControl & USER_USE_DES_KEY_ONLY) == 0))
  1893. {
  1894. PKERB_INTERNAL_NAME TempServiceName = NULL;
  1895. //
  1896. // Build the service name for the ticket. For interdomain trust
  1897. // accounts, this is "krbtgt / domain name"
  1898. //
  1899. if (ServiceTicketInfo->UserId == DOMAIN_USER_RID_KRBTGT)
  1900. {
  1901. Status = KerbBuildFullServiceKdcName(
  1902. SecData.KdcDnsRealmName(),
  1903. SecData.KdcServiceName(),
  1904. KRB_NT_SRV_INST,
  1905. &TempServiceName
  1906. );
  1907. if (!KERB_SUCCESS(Status))
  1908. {
  1909. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1910. goto Cleanup;
  1911. }
  1912. Status = KerbConvertKdcNameToPrincipalName(
  1913. &NewTicket->server_name,
  1914. TempServiceName
  1915. );
  1916. KerbFreeKdcName(&TempServiceName);
  1917. if (!KERB_SUCCESS(Status))
  1918. {
  1919. goto Cleanup;
  1920. }
  1921. }
  1922. else if ((ServiceTicketInfo->UserAccountControl & USER_INTERDOMAIN_TRUST_ACCOUNT) != 0)
  1923. {
  1924. Status = KerbBuildFullServiceKdcName(
  1925. &ServiceTicketInfo->AccountName,
  1926. SecData.KdcServiceName(),
  1927. KRB_NT_SRV_INST,
  1928. &TempServiceName
  1929. );
  1930. if (!KERB_SUCCESS(Status))
  1931. {
  1932. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1933. goto Cleanup;
  1934. }
  1935. Status = KerbConvertKdcNameToPrincipalName(
  1936. &NewTicket->server_name,
  1937. TempServiceName
  1938. );
  1939. KerbFreeKdcName(&TempServiceName);
  1940. if (!KERB_SUCCESS(Status))
  1941. {
  1942. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1943. goto Cleanup;
  1944. }
  1945. }
  1946. else
  1947. {
  1948. Status = KerbConvertStringToPrincipalName(
  1949. &NewTicket->server_name,
  1950. &ServiceTicketInfo->AccountName,
  1951. KRB_NT_PRINCIPAL
  1952. );
  1953. if (!KERB_SUCCESS(Status))
  1954. {
  1955. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1956. goto Cleanup;
  1957. }
  1958. }
  1959. }
  1960. else
  1961. {
  1962. //
  1963. // No canonicalzation, so copy in all the names as the client
  1964. // requested them.
  1965. //
  1966. Status = KerbDuplicatePrincipalName(
  1967. &NewTicket->server_name,
  1968. ServerName
  1969. );
  1970. if (!KERB_SUCCESS(Status))
  1971. {
  1972. goto Cleanup;
  1973. }
  1974. }
  1975. NewTicket->realm = SecData.KdcKerbDnsRealmName();
  1976. //
  1977. // Insert the client names. If the client requested canoncalization,
  1978. // return our realm name & sam account name. Otherwise copy what the
  1979. // client requested
  1980. //
  1981. if ((ClientName->name_type == KRB_NT_ENTERPRISE_PRINCIPAL) &&
  1982. ((ClientTicketInfo->UserAccountControl & USER_USE_DES_KEY_ONLY) == 0))
  1983. {
  1984. Status = KerbConvertStringToPrincipalName(
  1985. &EncryptedTicket->client_name,
  1986. &ClientTicketInfo->AccountName,
  1987. KRB_NT_PRINCIPAL
  1988. );
  1989. if (!KERB_SUCCESS(Status))
  1990. {
  1991. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1992. goto Cleanup;
  1993. }
  1994. }
  1995. else
  1996. {
  1997. Status = KerbDuplicatePrincipalName(
  1998. &EncryptedTicket->client_name,
  1999. ClientName
  2000. );
  2001. if (!KERB_SUCCESS(Status))
  2002. {
  2003. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  2004. goto Cleanup;
  2005. }
  2006. }
  2007. Status = KerbDuplicateRealm(
  2008. &EncryptedTicket->client_realm,
  2009. SecData.KdcKerbDnsRealmName()
  2010. );
  2011. if (!KERB_SUCCESS(Status))
  2012. {
  2013. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  2014. goto Cleanup;
  2015. }
  2016. if (HostAddresses != NULL)
  2017. {
  2018. EncryptedTicket->bit_mask |= KERB_ENCRYPTED_TICKET_client_addresses_present;
  2019. EncryptedTicket->KERB_ENCRYPTED_TICKET_client_addresses = HostAddresses;
  2020. }
  2021. else
  2022. {
  2023. EncryptedTicket->bit_mask &= ~KERB_ENCRYPTED_TICKET_client_addresses_present;
  2024. EncryptedTicket->KERB_ENCRYPTED_TICKET_client_addresses = NULL;
  2025. }
  2026. if (TransitedRealm->Length > 0)
  2027. {
  2028. STRING TempString;
  2029. Status = KerbUnicodeStringToKerbString(
  2030. &TempString,
  2031. TransitedRealm
  2032. );
  2033. if (!KERB_SUCCESS(Status))
  2034. {
  2035. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  2036. goto Cleanup;
  2037. }
  2038. EncryptedTicket->transited.transited_type = DOMAIN_X500_COMPRESS;
  2039. EncryptedTicket->transited.contents.value = (PUCHAR) TempString.Buffer;
  2040. EncryptedTicket->transited.contents.length = (int) TempString.Length;
  2041. }
  2042. else
  2043. {
  2044. RtlZeroMemory(
  2045. &EncryptedTicket->transited,
  2046. sizeof(KERB_TRANSITED_ENCODING)
  2047. );
  2048. }
  2049. EncryptedTicket->KERB_ENCRYPTED_TICKET_authorization_data = NULL;
  2050. #if DBG
  2051. PrintTicket( DEB_T_TICKETS, "BuildTicketAS: Final ticket", NewTicket );
  2052. #endif
  2053. Cleanup:
  2054. if (!KERB_SUCCESS(Status))
  2055. {
  2056. KdcFreeInternalTicket(NewTicket);
  2057. }
  2058. return(Status);
  2059. }
  2060. //+-------------------------------------------------------------------------
  2061. //
  2062. // Function: KerbCheckIfSPNIsChangePW
  2063. //
  2064. // Synopsis: Check if the service name is kadmin/changepw.
  2065. //
  2066. // Arguments: pServerName - Contains the service name
  2067. // pLogonRestrictionsFlags - Output flags value.
  2068. //
  2069. // Requires:
  2070. //
  2071. // Returns:
  2072. //
  2073. // Notes:
  2074. //
  2075. //
  2076. //--------------------------------------------------------------------------
  2077. VOID
  2078. KerbCheckIfSPNIsChangePW(
  2079. IN PKERB_INTERNAL_NAME ServerName,
  2080. IN ULONG *pLogonRestrictionsFlags
  2081. )
  2082. {
  2083. if (KerbEqualKdcNames(
  2084. ServerName,
  2085. GlobalKpasswdName
  2086. ))
  2087. {
  2088. *pLogonRestrictionsFlags |= KDC_RESTRICT_IGNORE_PW_EXPIRATION;
  2089. }
  2090. return;
  2091. }
  2092. //+-------------------------------------------------------------------------
  2093. //
  2094. // Function: I_GetASTicket
  2095. //
  2096. // Synopsis: Gets an authentication service ticket to the requested
  2097. // service.
  2098. //
  2099. // Effects: Allocates and encrypts a KDC reply
  2100. //
  2101. // Arguments: RequestMessage - Contains the AS request message
  2102. // InputMessage - buffer client sent, used for replay detection
  2103. // OutputMessage - Contains the AS reply message
  2104. // ErrorData - contains any error data for an error message
  2105. //
  2106. // Requires:
  2107. //
  2108. // Returns: KDC_ERR_ or KRB_AP_ERR errors only
  2109. //
  2110. // Notes:
  2111. //
  2112. //
  2113. //--------------------------------------------------------------------------
  2114. KERBERR
  2115. I_GetASTicket(
  2116. IN OPTIONAL PSOCKADDR ClientAddress,
  2117. IN PKERB_AS_REQUEST RequestMessage,
  2118. IN PUNICODE_STRING RequestRealm,
  2119. IN PKERB_MESSAGE_BUFFER InputMessage,
  2120. OUT PKERB_MESSAGE_BUFFER OutputMessage,
  2121. OUT PKERB_MESSAGE_BUFFER ErrorData,
  2122. OUT PKERB_EXT_ERROR pExtendedError,
  2123. OUT PUNICODE_STRING ClientRealm,
  2124. OUT PUNICODE_STRING ClientStringName,
  2125. OUT PUNICODE_STRING ServerStringName
  2126. )
  2127. {
  2128. KERBERR KerbErr = KDC_ERR_NONE;
  2129. NTSTATUS LogonStatus = STATUS_SUCCESS;
  2130. KDC_TICKET_INFO ClientTicketInfo = {0};
  2131. KDC_TICKET_INFO ServiceTicketInfo = {0};
  2132. SAMPR_HANDLE UserHandle = NULL;
  2133. PUSER_INTERNAL6_INFORMATION UserInfo = NULL;
  2134. SID_AND_ATTRIBUTES_LIST GroupMembership = {0};
  2135. KERB_ENCRYPTION_KEY EncryptionKey = {0};
  2136. PKERB_ENCRYPTION_KEY ServerKey = NULL;
  2137. PKERB_ENCRYPTION_KEY ClientKey = NULL;
  2138. ULONG CommonEType = KERB_ETYPE_DEFAULT;
  2139. KERB_TICKET Ticket = {0};
  2140. KERB_ENCRYPTED_TICKET EncryptedTicket = {0};
  2141. KERB_ENCRYPTED_KDC_REPLY ReplyBody = {0};
  2142. KERB_KDC_REPLY Reply = {0};
  2143. PKERB_KDC_REQUEST_BODY RequestBody = NULL;
  2144. PKERB_AUTHORIZATION_DATA PacAuthData = NULL;
  2145. PKERB_PA_DATA_LIST OutputPreAuthData = NULL;
  2146. PPKERB_HOST_ADDRESSES EffectiveAddresses = NULL;
  2147. KDC_PKI_AUDIT_INFO PkiAuditInfo = {0};
  2148. PKERB_INTERNAL_NAME ClientName = NULL;
  2149. PKERB_INTERNAL_NAME ServerName = NULL;
  2150. UNICODE_STRING ClientNetbiosAddress = {0};
  2151. UNICODE_STRING ServerRealm = {0};
  2152. UNICODE_STRING MappedClientName = {0};
  2153. UNICODE_STRING TransitedRealm = {0};
  2154. LARGE_INTEGER LogoffTime;
  2155. LARGE_INTEGER AccountExpiry;
  2156. ULONG NameFlags = 0;
  2157. ULONG PreAuthType = 0;
  2158. ULONG KdcOptions = 0;
  2159. ULONG TicketFlags = 0;
  2160. ULONG ReplyTicketFlags = 0;
  2161. ULONG Nonce = 0;
  2162. ULONG LogonRestrictionsFlags = 0;
  2163. ULONG WhichFields = 0;
  2164. BOOLEAN AuditedFailure = FALSE;
  2165. BOOLEAN BuildPac = FALSE;
  2166. BOOLEAN ClientReferral = FALSE;
  2167. BOOLEAN ServerReferral = FALSE;
  2168. BOOLEAN LoggedFailure = FALSE;
  2169. BOOLEAN ClientInfoPresent = FALSE;
  2170. BOOLEAN UsedOldPassword = FALSE;
  2171. BOOLEAN bRestrictUserAccounts = FALSE;
  2172. KDC_AS_EVENT_INFO ASEventTraceInfo = {0};
  2173. TRACE(KDC, I_GetASTicket, DEB_FUNCTION);
  2174. //
  2175. // Initialize local variables
  2176. //
  2177. EncryptedTicket.flags.value = (PUCHAR) &TicketFlags;
  2178. EncryptedTicket.flags.length = sizeof(ULONG) * 8;
  2179. ReplyBody.flags.value = (PUCHAR) &ReplyTicketFlags;
  2180. ReplyBody.flags.length = sizeof(ULONG) * 8;
  2181. RtlInitUnicodeString( ClientRealm, NULL );
  2182. Ticket.encrypted_part.cipher_text.value = (PUCHAR) &EncryptedTicket;
  2183. //
  2184. // Assume that this isn't a logon request. If we manage to fail before
  2185. // we've determined it's a logon attempt, we won't mark it as a failed
  2186. // logon.
  2187. //
  2188. RequestBody = &RequestMessage->request_body;
  2189. //
  2190. // There are many options that are invalid for an AS ticket.
  2191. //
  2192. KdcOptions = KerbConvertFlagsToUlong(&RequestBody->kdc_options);
  2193. //
  2194. // Start event tracing (capture error cases too)
  2195. //
  2196. if (KdcEventTraceFlag){
  2197. ASEventTraceInfo.EventTrace.Guid = KdcGetASTicketGuid;
  2198. ASEventTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_START;
  2199. ASEventTraceInfo.EventTrace.Flags = WNODE_FLAG_TRACED_GUID;
  2200. ASEventTraceInfo.EventTrace.Size = sizeof (EVENT_TRACE_HEADER) + sizeof (ULONG);
  2201. ASEventTraceInfo.KdcOptions = KdcOptions;
  2202. TraceEvent(
  2203. KdcTraceLoggerHandle,
  2204. (PEVENT_TRACE_HEADER)&ASEventTraceInfo
  2205. );
  2206. }
  2207. if (KdcOptions &
  2208. (KERB_KDC_OPTIONS_forwarded |
  2209. KERB_KDC_OPTIONS_proxy |
  2210. KERB_KDC_OPTIONS_unused7 |
  2211. KERB_KDC_OPTIONS_unused9 |
  2212. KERB_KDC_OPTIONS_renew |
  2213. KERB_KDC_OPTIONS_validate |
  2214. KERB_KDC_OPTIONS_reserved |
  2215. KERB_KDC_OPTIONS_enc_tkt_in_skey ) )
  2216. {
  2217. KerbErr = KDC_ERR_BADOPTION;
  2218. goto Cleanup;
  2219. }
  2220. if (( RequestBody->bit_mask & addresses_present ) &&
  2221. ( RequestBody->addresses == NULL ))
  2222. {
  2223. KerbErr = KDC_ERR_BADOPTION;
  2224. goto Cleanup;
  2225. }
  2226. //
  2227. // Make sure a client name was supplied
  2228. //
  2229. if ((RequestBody->bit_mask & KERB_KDC_REQUEST_BODY_client_name_present) != 0)
  2230. {
  2231. KerbErr = KerbConvertPrincipalNameToKdcName(
  2232. &ClientName,
  2233. &RequestBody->KERB_KDC_REQUEST_BODY_client_name
  2234. );
  2235. if (!KERB_SUCCESS(KerbErr))
  2236. {
  2237. goto Cleanup;
  2238. }
  2239. KerbErr = KerbConvertKdcNameToString(
  2240. ClientStringName,
  2241. ClientName,
  2242. NULL
  2243. );
  2244. if (!KERB_SUCCESS(KerbErr))
  2245. {
  2246. goto Cleanup;
  2247. }
  2248. }
  2249. else
  2250. {
  2251. D_DebugLog((DEB_ERROR,"KLIN(%x) No principal name supplied to AS request - not allowed\n", KLIN(FILENO,__LINE__)));
  2252. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  2253. goto Cleanup;
  2254. }
  2255. //
  2256. // Copy out the service name. This is not an optional field.
  2257. //
  2258. if ((RequestBody->bit_mask & KERB_KDC_REQUEST_BODY_server_name_present) == 0)
  2259. {
  2260. D_DebugLog((DEB_ERROR, "I_GetASTicket KLIN(%x) Client %wZ sent AS request with no server name\n",
  2261. KLIN(FILENO, __LINE__),
  2262. &ClientStringName));
  2263. FILL_EXT_ERROR(pExtendedError, STATUS_KDC_INVALID_REQUEST, FILENO, __LINE__);
  2264. KerbErr = KDC_ERR_BADOPTION;
  2265. goto Cleanup;
  2266. }
  2267. KerbErr = KerbConvertPrincipalNameToKdcName(
  2268. &ServerName,
  2269. &RequestBody->KERB_KDC_REQUEST_BODY_server_name
  2270. );
  2271. if (!KERB_SUCCESS(KerbErr))
  2272. {
  2273. goto Cleanup;
  2274. }
  2275. KerbErr = KerbConvertKdcNameToString(
  2276. ServerStringName,
  2277. ServerName,
  2278. NULL
  2279. );
  2280. if (!KERB_SUCCESS(KerbErr))
  2281. {
  2282. goto Cleanup;
  2283. }
  2284. //
  2285. // Check if the client said to canonicalize the name -- this is
  2286. // determined by the name type for AS_REQ.
  2287. //
  2288. if((KdcOptions & KERB_KDC_OPTIONS_name_canonicalize) != 0)
  2289. {
  2290. NameFlags |= KDC_NAME_CHECK_GC;
  2291. }
  2292. else
  2293. {
  2294. //
  2295. // canonicalize bit is not set so we want to check if the service
  2296. // name is kadmin/changepw, if it is we set the flag to indicate
  2297. // that we will ignore password expiration checking
  2298. //
  2299. KerbCheckIfSPNIsChangePW(
  2300. ServerName,
  2301. &LogonRestrictionsFlags);
  2302. }
  2303. D_DebugLog((DEB_TRACE, "I_GetASTicket getting an AS ticket to server "));
  2304. D_KerbPrintKdcName((DEB_TRACE, ServerName));
  2305. D_DebugLog((DEB_TRACE, "I_GetASTicket for client "));
  2306. D_KerbPrintKdcName((DEB_TRACE, ClientName));
  2307. //
  2308. // Get the client's NETBIOS address.
  2309. //
  2310. if ((RequestBody->bit_mask & addresses_present) != 0)
  2311. {
  2312. KerbErr = KerbGetClientNetbiosAddress(
  2313. &ClientNetbiosAddress,
  2314. RequestBody->addresses
  2315. );
  2316. if (!KERB_SUCCESS(KerbErr))
  2317. {
  2318. goto Cleanup;
  2319. }
  2320. }
  2321. //
  2322. // Normalize the client name.
  2323. //
  2324. if ( !IsSubAuthFilterPresent()) {
  2325. WhichFields = USER_ALL_KERB_CHECK_LOGON_RESTRICTIONS |
  2326. USER_ALL_KDC_CHECK_PREAUTH_DATA |
  2327. USER_ALL_ACCOUNTEXPIRES |
  2328. USER_ALL_KDC_GET_PAC_AUTH_DATA |
  2329. USER_ALL_SUCCESSFUL_LOGON;
  2330. } else {
  2331. //
  2332. // We do not know what the subauth routine needs, so get everything
  2333. //
  2334. WhichFields = 0xFFFFFFFF & ~USER_ALL_UNDEFINED_MASK;
  2335. }
  2336. //
  2337. // If there's no pre-auth, this could be an S4u location call.
  2338. // This will trigger alt_sec_id lookups.
  2339. //
  2340. if (KerbFindPreAuthDataEntry(
  2341. KRB5_PADATA_ENC_TIMESTAMP,
  2342. RequestMessage->KERB_KDC_REQUEST_preauth_data) == NULL)
  2343. {
  2344. NameFlags |= KDC_NAME_S4U_CLIENT;
  2345. }
  2346. KerbErr = KdcNormalize(
  2347. ClientName,
  2348. NULL,
  2349. RequestRealm,
  2350. NULL, // no source ticket
  2351. NameFlags | KDC_NAME_CLIENT | KDC_NAME_FOLLOW_REFERRALS | KDC_NAME_CHECK_GC,
  2352. FALSE, // do not restrict user accounts (user2user)
  2353. &ClientReferral,
  2354. ClientRealm,
  2355. &ClientTicketInfo,
  2356. pExtendedError,
  2357. &UserHandle,
  2358. WhichFields,
  2359. 0L,
  2360. &UserInfo,
  2361. &GroupMembership
  2362. );
  2363. if (!KERB_SUCCESS(KerbErr))
  2364. {
  2365. DebugLog((DEB_ERROR, "I_GetASTicket KLIN(%x) failed to normalize name %#x: ", KLIN(FILENO, __LINE__), KerbErr));
  2366. KerbPrintKdcName(DEB_ERROR, ClientName);
  2367. goto Cleanup;
  2368. }
  2369. if (ClientTicketInfo.Passwords != NULL)
  2370. {
  2371. ClientInfoPresent = TRUE;
  2372. // If Credential count is zero and there was no error, we do not have
  2373. // NT_OWF info so return Error since Kerb can not auth
  2374. if (ClientTicketInfo.Passwords->CredentialCount <= CRED_ONLY_LM_OWF)
  2375. {
  2376. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  2377. DebugLog((DEB_ERROR,"KLIN(%x) Failed to normalize name - no creds ", KLIN(FILENO, __LINE__)));
  2378. KerbPrintKdcName(DEB_ERROR,ClientName);
  2379. goto Cleanup;
  2380. }
  2381. }
  2382. // If the UserHandle was NULL and there was no error, this must be
  2383. // a cross realm trust account logon. Fail it, we have no account
  2384. // to work with.
  2385. if (!UserHandle || !UserInfo)
  2386. {
  2387. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  2388. D_DebugLog((DEB_ERROR,"KLIN(%x) Failed to normalize name", KLIN(FILENO,__LINE__)));
  2389. D_KerbPrintKdcName((DEB_ERROR, ClientName));
  2390. goto Cleanup;
  2391. }
  2392. //
  2393. // If this is a referral, return an error and the true realm name
  2394. // of the client
  2395. //
  2396. if (ClientReferral)
  2397. {
  2398. KerbErr = KDC_ERR_WRONG_REALM;
  2399. D_DebugLog((DEB_WARN,
  2400. "KLIN(%x) Client tried to logon to account in another realm\n",
  2401. KLIN(FILENO,__LINE__)));
  2402. goto Cleanup;
  2403. }
  2404. if (!KERB_SUCCESS(KerbErr))
  2405. {
  2406. DebugLog((DEB_ERROR, "KLIN(%x) Error getting client ticket info for %wZ: 0x%x \n",
  2407. KLIN(FILENO,__LINE__), &MappedClientName, KerbErr));
  2408. goto Cleanup;
  2409. }
  2410. //
  2411. // The below function will return true for pkinit
  2412. //
  2413. if (KerbFindPreAuthDataEntry(
  2414. KRB5_PADATA_PK_AS_REP,
  2415. RequestMessage->KERB_KDC_REQUEST_preauth_data) != NULL)
  2416. {
  2417. LogonRestrictionsFlags = KDC_RESTRICT_PKINIT_USED;
  2418. }
  2419. //
  2420. // The order to check information on an account is:
  2421. // STATUS_ACCOUNT_LOCKED_OUT
  2422. // STATUS_WRONG_PASSWORD
  2423. // STATUS_PASSWORD_MUST_CHANGE/STATUS_PASSWORD_EXPIRED
  2424. // Note that you check for a bad password before the last two conditions
  2425. //
  2426. // Check logon restrictions before preauth data, so we don't accidentally
  2427. // leak information about the password if account is locked out.
  2428. // LogonStatus will have which Account restriction failed, KerbErr has the category of failure
  2429. //
  2430. KerbErr = KerbCheckLogonRestrictions(
  2431. UserHandle,
  2432. &ClientNetbiosAddress,
  2433. &UserInfo->I1,
  2434. LogonRestrictionsFlags,
  2435. &LogoffTime,
  2436. &LogonStatus
  2437. );
  2438. if (!KERB_SUCCESS(KerbErr))
  2439. {
  2440. DebugLog((DEB_WARN , "LogonRestriction check failed: LogonStatus: 0x%x KRB: 0x%x\n",
  2441. LogonStatus, KerbErr));
  2442. if ((LogonStatus == STATUS_ACCOUNT_LOCKED_OUT) || // Same as KerbErr == KDC_ERR_KEY_EXPIRED
  2443. (LogonStatus == STATUS_PASSWORD_MUST_CHANGE) ||
  2444. (LogonStatus == STATUS_PASSWORD_EXPIRED) ||
  2445. (LogonStatus == STATUS_NO_LOGON_SERVERS))
  2446. {
  2447. KERBERR PreAuthKerbErr;
  2448. BYTE ClientSid[MAX_SID_LEN];
  2449. RtlZeroMemory(ClientSid, MAX_SID_LEN);
  2450. KdcMakeAccountSid(ClientSid, ClientTicketInfo.UserId);
  2451. //
  2452. // Unpack the pre-auth data -- needed to check if wrong password and secondarily for auditing purposes
  2453. //
  2454. PreAuthKerbErr = KdcCheckPreAuthData(
  2455. &ClientTicketInfo,
  2456. UserHandle,
  2457. UserInfo,
  2458. RequestMessage->KERB_KDC_REQUEST_preauth_data,
  2459. RequestBody,
  2460. &PreAuthType,
  2461. &OutputPreAuthData,
  2462. &BuildPac,
  2463. &Nonce,
  2464. &EncryptionKey,
  2465. &TransitedRealm,
  2466. &PkiAuditInfo,
  2467. ErrorData,
  2468. pExtendedError,
  2469. &UsedOldPassword
  2470. );
  2471. if (!KERB_SUCCESS(PreAuthKerbErr))
  2472. {
  2473. //
  2474. // For account lockout, don't give the "attacker" extra info
  2475. // about bad password
  2476. // For PASSWORD_MUST_CHANGE and PASSWORD_EXPIRE check for good password otherwise,
  2477. // replace with STATUS_WRONG_PASSWORD
  2478. //
  2479. //
  2480. // We need to make sure we free up the error data
  2481. // and pa data to be returned from the client,
  2482. // but we really need to return the above error
  2483. // as long as the account is not Locked out.
  2484. //
  2485. if (LogonStatus != STATUS_ACCOUNT_LOCKED_OUT)
  2486. {
  2487. KerbErr = PreAuthKerbErr;
  2488. }
  2489. else if ( OutputPreAuthData != NULL )
  2490. {
  2491. KerbFreePreAuthData( OutputPreAuthData );
  2492. OutputPreAuthData = NULL;
  2493. }
  2494. // Audit the Pre-auth failure
  2495. D_DebugLog((DEB_WARN , "KLIN(%x) PreAuthData Check failed: LogonStatus: 0x%x KRB: 0x%x\n",
  2496. KLIN(FILENO,__LINE__), LogonStatus, KerbErr));
  2497. if (SecData.AuditKdcEvent(KDC_AUDIT_AS_FAILURE))
  2498. {
  2499. KdcLsaIAuditAsEvent(
  2500. SE_AUDITID_PREAUTH_FAILURE,
  2501. &ClientTicketInfo.AccountName,
  2502. NULL, // no domain name
  2503. ClientSid,
  2504. ServerStringName,
  2505. NULL, // no server sid
  2506. &PreAuthType,
  2507. (PULONG) &KerbErr,
  2508. NULL,
  2509. NULL,
  2510. GET_CLIENT_ADDRESS(ClientAddress),
  2511. &PkiAuditInfo.CertIssuerName,
  2512. &PkiAuditInfo.CertSerialNumber,
  2513. &PkiAuditInfo.CertThumbprint
  2514. );
  2515. AuditedFailure = TRUE;
  2516. }
  2517. }
  2518. //
  2519. // Only handle failed logon if pre-auth fails. Otherwise the error
  2520. // was something the client couldn't control, such as memory
  2521. // allocation or clock skew.
  2522. //
  2523. if ((KerbErr == KDC_ERR_PREAUTH_FAILED) || // tests for STATUS_WRONG_PASSWORD
  2524. (LogonStatus == STATUS_PASSWORD_MUST_CHANGE) ||
  2525. (LogonStatus == STATUS_PASSWORD_EXPIRED) ||
  2526. (LogonStatus == STATUS_ACCOUNT_LOCKED_OUT) )
  2527. {
  2528. D_DebugLog((DEB_WARN , "KLIN(%x) Calling Failedlogon: LogonStatus: 0x%x KRB: 0x%x PreAuthKRB: 0x%x\n",
  2529. KLIN(FILENO,__LINE__), LogonStatus, KerbErr, PreAuthKerbErr));
  2530. FailedLogon(
  2531. UserHandle,
  2532. ClientAddress,
  2533. &RequestBody->KERB_KDC_REQUEST_BODY_client_name,
  2534. ClientSid,
  2535. MAX_SID_LEN,
  2536. &ClientTicketInfo,
  2537. InputMessage,
  2538. OutputMessage,
  2539. &ClientNetbiosAddress,
  2540. KerbErr,
  2541. LogonStatus,
  2542. UsedOldPassword
  2543. );
  2544. LoggedFailure = TRUE;
  2545. //
  2546. // If there was a message form the PDC, then outputmessage will be non-NULL. This will always override any
  2547. // value specified in KerbErr or LogonStatus
  2548. // A NULL outputmessage indicates that we are on a PDC. And we create an error return based on LogonStatus
  2549. // Fill the extended error w/ status from acct. restrictions.
  2550. //
  2551. if ((OutputMessage->Buffer == NULL) && !NT_SUCCESS(LogonStatus))
  2552. {
  2553. FILL_EXT_ERROR_EX(pExtendedError, LogonStatus, FILENO, __LINE__);
  2554. D_DebugLog((DEB_TRACE, "KLIN(%x) setting error return based on logonstatus\n",
  2555. KLIN(FILENO,__LINE__)));
  2556. }
  2557. goto Cleanup;
  2558. }
  2559. else if (LogonStatus == STATUS_NO_LOGON_SERVERS)
  2560. {
  2561. D_DebugLog((DEB_WARN, "KLIN(%x) Logon Restriction check failed due to no logon servers\n",
  2562. KLIN(FILENO,__LINE__)));
  2563. KdcHandleNoLogonServers(UserHandle,
  2564. ClientAddress);
  2565. goto Cleanup;
  2566. }
  2567. else
  2568. {
  2569. DebugLog((DEB_WARN,"KLIN(%x) Logon restriction check failed: LogonStatus: 0x%x KRB: 0x%x\n",
  2570. KLIN(FILENO,__LINE__), LogonStatus, KerbErr));
  2571. FILL_EXT_ERROR_EX(pExtendedError, LogonStatus, FILENO, __LINE__);
  2572. goto Cleanup;
  2573. }
  2574. }
  2575. else
  2576. { // Catch all of the AccountRestrictions not possibly passed to PDC
  2577. DebugLog((DEB_WARN,"KLIN(%x) Logon restriction check failed: LogonStatus: 0x%x KRB: 0x%x\n",
  2578. KLIN(FILENO,__LINE__),LogonStatus, KerbErr));
  2579. // Here's one case where we want to return errors to the client, so use EX
  2580. FILL_EXT_ERROR_EX(pExtendedError, LogonStatus, FILENO, __LINE__);
  2581. }
  2582. goto Cleanup;
  2583. } // End Logon Restriction Processing
  2584. //
  2585. // There was no Account Restrictions so continue processing. Check for correct password.
  2586. // Unpack the pre-auth data.
  2587. //
  2588. KerbErr = KdcCheckPreAuthData(
  2589. &ClientTicketInfo,
  2590. UserHandle,
  2591. UserInfo,
  2592. RequestMessage->KERB_KDC_REQUEST_preauth_data,
  2593. RequestBody,
  2594. &PreAuthType,
  2595. &OutputPreAuthData,
  2596. &BuildPac,
  2597. &Nonce,
  2598. &EncryptionKey,
  2599. &TransitedRealm,
  2600. &PkiAuditInfo,
  2601. ErrorData,
  2602. pExtendedError,
  2603. &UsedOldPassword
  2604. );
  2605. if (!KERB_SUCCESS(KerbErr))
  2606. {
  2607. BYTE ClientSid[MAX_SID_LEN];
  2608. RtlZeroMemory(ClientSid, MAX_SID_LEN);
  2609. KdcMakeAccountSid(ClientSid, ClientTicketInfo.UserId);
  2610. if (SecData.AuditKdcEvent(KDC_AUDIT_AS_FAILURE))
  2611. {
  2612. KdcLsaIAuditAsEvent(
  2613. SE_AUDITID_PREAUTH_FAILURE,
  2614. &ClientTicketInfo.AccountName,
  2615. NULL, // no domain name
  2616. ClientSid,
  2617. ServerStringName,
  2618. NULL, // no server sid
  2619. &PreAuthType,
  2620. (PULONG) &KerbErr,
  2621. NULL,
  2622. NULL,
  2623. GET_CLIENT_ADDRESS(ClientAddress),
  2624. &PkiAuditInfo.CertIssuerName,
  2625. &PkiAuditInfo.CertSerialNumber,
  2626. &PkiAuditInfo.CertThumbprint
  2627. );
  2628. AuditedFailure = TRUE;
  2629. }
  2630. //
  2631. // Only handle failed logon if pre-auth fails. Otherwise the error
  2632. // was something the client couldn't control, such as memory
  2633. // allocation or clock skew.
  2634. //
  2635. if (KerbErr == KDC_ERR_PREAUTH_FAILED)
  2636. {
  2637. D_DebugLog((DEB_WARN , "KLIN(%x) Calling Failedlogon: LogonStatus: 0x%x KRB: 0x%x\n",
  2638. KLIN(FILENO,__LINE__), LogonStatus, KerbErr));
  2639. FailedLogon(
  2640. UserHandle,
  2641. ClientAddress,
  2642. &RequestBody->KERB_KDC_REQUEST_BODY_client_name,
  2643. ClientSid,
  2644. MAX_SID_LEN,
  2645. &ClientTicketInfo,
  2646. InputMessage,
  2647. OutputMessage,
  2648. &ClientNetbiosAddress,
  2649. KerbErr,
  2650. LogonStatus,
  2651. UsedOldPassword
  2652. );
  2653. }
  2654. LoggedFailure = TRUE;
  2655. DebugLog((DEB_ERROR,"KLIN(%x) Failed to check pre-auth data: 0x%x\n",
  2656. KLIN(FILENO,__LINE__), KerbErr));
  2657. goto Cleanup;
  2658. }
  2659. //
  2660. // Check for subauthentication
  2661. //
  2662. KerbErr = KdcCallSubAuthRoutine(
  2663. &ClientTicketInfo,
  2664. UserInfo,
  2665. &ClientNetbiosAddress,
  2666. &LogoffTime,
  2667. pExtendedError
  2668. );
  2669. if (!KERB_SUCCESS(KerbErr))
  2670. {
  2671. DebugLog((DEB_WARN,"KLIN(%x) Subuath restriction check failed: 0x%x\n",
  2672. KLIN(FILENO,__LINE__), KerbErr));
  2673. goto Cleanup;
  2674. }
  2675. //
  2676. // do not restrict user accounts (user2user) if the first part of server
  2677. // name is "krbtgt"
  2678. //
  2679. bRestrictUserAccounts = LsaINoMoreWin2KDomain()
  2680. && !( (ServerName->NameCount >= 1)
  2681. && RtlEqualUnicodeString(
  2682. &ServerName->Names[0],
  2683. SecData.KdcServiceName(),
  2684. TRUE) );
  2685. //
  2686. // Figure out who the ticket is for. First break the name into
  2687. // a local name and a referral realm
  2688. //
  2689. //
  2690. // Note: We don't allow referrals here, because we should only get AS
  2691. // requests for our realm, and the krbtgt\server should always be
  2692. // in our realm.
  2693. KerbErr = KdcNormalize(
  2694. ServerName,
  2695. NULL,
  2696. NULL, // don't use requested realm for the server - use our realm
  2697. NULL,
  2698. NameFlags | KDC_NAME_SERVER,
  2699. bRestrictUserAccounts, // restrict user accounts (user2user)
  2700. &ServerReferral,
  2701. &ServerRealm,
  2702. &ServiceTicketInfo,
  2703. pExtendedError,
  2704. NULL, // no user handle
  2705. 0L, // no additional fields to fetch
  2706. bRestrictUserAccounts ? USER_EXTENDED_FIELD_SPN : 0, // no extended fields
  2707. NULL, // no user all
  2708. NULL // no membership
  2709. );
  2710. if (!KERB_SUCCESS(KerbErr))
  2711. {
  2712. DebugLog((DEB_ERROR, "I_GetASTicket KLIN(%x) failed to normalize name %#x: ", KLIN(FILENO, __LINE__), KerbErr ));
  2713. KerbPrintKdcName(DEB_ERROR, ServerName);
  2714. goto Cleanup;
  2715. }
  2716. //
  2717. // find supported etype for session keys
  2718. //
  2719. KerbErr = KerbFindCommonCryptSystemForSKey(
  2720. RequestBody->encryption_type,
  2721. ServiceTicketInfo.UserAccountControl & USER_USE_DES_KEY_ONLY ?
  2722. kdc_pMitPrincipalPreferredCryptList : kdc_pPreferredCryptList,
  2723. &CommonEType
  2724. );
  2725. if (!KERB_SUCCESS(KerbErr))
  2726. {
  2727. if (KDC_ERR_ETYPE_NOTSUPP == KerbErr)
  2728. {
  2729. KdcReportKeyError(
  2730. ClientStringName,
  2731. ServerStringName,
  2732. KDC_KEY_ID_AS_SKEY,
  2733. KDCEVENT_NO_KEY_INTERSECTION_AS,
  2734. RequestBody->encryption_type,
  2735. &ServiceTicketInfo
  2736. );
  2737. }
  2738. DebugLog((DEB_ERROR, "I_GetASTicket KLIN(%x) Failed to find common ETYPE: 0x%x\n",
  2739. KLIN(FILENO, __LINE__), KerbErr));
  2740. goto Cleanup;
  2741. }
  2742. //
  2743. // Find a common crypto system. Do it now in case we need
  2744. // to return the password for a service.
  2745. //
  2746. if (EncryptionKey.keyvalue.value == NULL)
  2747. {
  2748. KerbErr = KerbFindCommonCryptSystem(
  2749. RequestBody->encryption_type,
  2750. ClientTicketInfo.Passwords,
  2751. NULL,
  2752. &ClientKey
  2753. );
  2754. if (!KERB_SUCCESS(KerbErr))
  2755. {
  2756. if (KDC_ERR_ETYPE_NOTSUPP == KerbErr)
  2757. {
  2758. KdcReportKeyError(
  2759. ClientStringName,
  2760. ServerStringName,
  2761. KDC_KEY_ID_AS_KDC_REPLY,
  2762. KDCEVENT_NO_KEY_INTERSECTION_AS,
  2763. RequestBody->encryption_type,
  2764. &ClientTicketInfo
  2765. );
  2766. }
  2767. DebugLog((DEB_ERROR, "KLIN(%x) Failed to find common ETYPE: 0x%x\n",
  2768. KLIN(FILENO,__LINE__), KerbErr));
  2769. goto Cleanup;
  2770. }
  2771. }
  2772. //
  2773. // Get the etype to use for the ticket itself from the server's
  2774. // list of keys
  2775. //
  2776. KerbErr = KerbFindCommonCryptSystem(
  2777. ServiceTicketInfo.UserAccountControl & USER_USE_DES_KEY_ONLY ?
  2778. kdc_pMitPrincipalPreferredCryptList : kdc_pPreferredCryptList,
  2779. ServiceTicketInfo.Passwords,
  2780. NULL, // no additional passwords
  2781. &ServerKey
  2782. );
  2783. if (!KERB_SUCCESS(KerbErr))
  2784. {
  2785. if (KDC_ERR_ETYPE_NOTSUPP == KerbErr)
  2786. {
  2787. KdcReportKeyError(
  2788. ClientStringName,
  2789. ServerStringName,
  2790. KDC_KEY_ID_AS_TICKET,
  2791. KDCEVENT_NO_KEY_INTERSECTION_AS,
  2792. ServiceTicketInfo.UserAccountControl & USER_USE_DES_KEY_ONLY ?
  2793. kdc_pMitPrincipalPreferredCryptList : kdc_pPreferredCryptList,
  2794. &ServiceTicketInfo
  2795. );
  2796. }
  2797. DebugLog((DEB_ERROR, "KLIN(%x) Failed to find common ETYPE: 0x%x\n", KLIN(FILENO, __LINE__), KerbErr));
  2798. goto Cleanup;
  2799. }
  2800. //
  2801. // We need to save the full domain name of the service regardless
  2802. // of whether it was provided or not. This is so name changes
  2803. // can be detected. Instead of creating a mess of trying to figure out
  2804. // which deallocator to use, allocate new memory and copy data.
  2805. //
  2806. AccountExpiry = UserInfo->I1.AccountExpires;
  2807. //
  2808. // Bug 460108: only propagate the addresses if there is an IPv4
  2809. // address in the list
  2810. //
  2811. if ( KdcUseClientAddresses ) {
  2812. PKERB_HOST_ADDRESSES CurrentAddress = RequestBody->addresses;
  2813. while ( CurrentAddress != NULL ) {
  2814. if ( CurrentAddress->value.address_type == KERB_ADDRTYPE_INET ) {
  2815. EffectiveAddresses = RequestBody->addresses;
  2816. break;
  2817. }
  2818. CurrentAddress = CurrentAddress->next;
  2819. }
  2820. }
  2821. KerbErr = BuildTicketAS(
  2822. &ClientTicketInfo,
  2823. &RequestBody->KERB_KDC_REQUEST_BODY_client_name,
  2824. &ServiceTicketInfo,
  2825. &RequestBody->KERB_KDC_REQUEST_BODY_server_name,
  2826. EffectiveAddresses,
  2827. &LogoffTime,
  2828. &AccountExpiry,
  2829. RequestBody,
  2830. CommonEType,
  2831. PreAuthType,
  2832. &TransitedRealm,
  2833. &Ticket,
  2834. pExtendedError
  2835. );
  2836. if (!KERB_SUCCESS(KerbErr))
  2837. {
  2838. D_DebugLog((DEB_WARN , "KLIN(%x) Failed to build AS ticket: 0x%x\n",
  2839. KLIN(FILENO,__LINE__), KerbErr));
  2840. goto Cleanup;
  2841. }
  2842. //
  2843. // If the user requested a PAC (via pre-auth data) build one now.
  2844. //
  2845. if (BuildPac)
  2846. {
  2847. //
  2848. // Now build a PAC to stick in the authorization data
  2849. //
  2850. DebugLog((DEB_T_PAC, "I_GetASTicket KLIN(%x) build Pac\n", KLIN(FILENO, __LINE__)));
  2851. KerbErr = KdcGetPacAuthData(
  2852. UserInfo,
  2853. &GroupMembership,
  2854. ServerKey,
  2855. &EncryptionKey,
  2856. ((ServiceTicketInfo.UserAccountControl & USER_INTERDOMAIN_TRUST_ACCOUNT) == 0) &&
  2857. (ServiceTicketInfo.UserId != DOMAIN_USER_RID_KRBTGT),
  2858. // add resource groups if server is not an interdomain trust account
  2859. &EncryptedTicket,
  2860. NULL, // no S4U info here...
  2861. &PacAuthData,
  2862. pExtendedError
  2863. );
  2864. if (!KERB_SUCCESS(KerbErr))
  2865. {
  2866. D_DebugLog((DEB_ERROR, "KLIN(%x) Failed to get pac auth data for %wZ : 0x%x\n",
  2867. KLIN(FILENO, __LINE__), &ClientTicketInfo.AccountName, KerbErr));
  2868. goto Cleanup;
  2869. }
  2870. //
  2871. // Stick the auth data into the AS ticket
  2872. //
  2873. EncryptedTicket.KERB_ENCRYPTED_TICKET_authorization_data = PacAuthData;
  2874. PacAuthData = NULL;
  2875. EncryptedTicket.bit_mask |= KERB_ENCRYPTED_TICKET_authorization_data_present;
  2876. }
  2877. //
  2878. // Now build the reply
  2879. //
  2880. KerbErr = BuildReply(
  2881. &ClientTicketInfo,
  2882. (Nonce != 0) ? Nonce : RequestBody->nonce,
  2883. &Ticket.server_name,
  2884. Ticket.realm,
  2885. ((RequestBody->bit_mask & addresses_present) != 0) ? RequestBody->addresses : NULL,
  2886. &Ticket,
  2887. &ReplyBody
  2888. );
  2889. if (!KERB_SUCCESS(KerbErr))
  2890. {
  2891. goto Cleanup;
  2892. }
  2893. //
  2894. // Now build the real reply and return it.
  2895. //
  2896. Reply.version = KERBEROS_VERSION;
  2897. Reply.message_type = KRB_AS_REP;
  2898. Reply.KERB_KDC_REPLY_preauth_data = NULL;
  2899. Reply.bit_mask = 0;
  2900. Reply.client_realm = EncryptedTicket.client_realm;
  2901. //
  2902. // Build pw-salt if we used a user's key
  2903. //
  2904. if (ClientKey != NULL)
  2905. {
  2906. KerbErr = KdcBuildPwSalt(
  2907. ClientTicketInfo.Passwords,
  2908. ClientKey,
  2909. &OutputPreAuthData
  2910. );
  2911. if (!KERB_SUCCESS(KerbErr))
  2912. {
  2913. goto Cleanup;
  2914. }
  2915. }
  2916. if (OutputPreAuthData != NULL)
  2917. {
  2918. Reply.bit_mask |= KERB_KDC_REPLY_preauth_data_present;
  2919. Reply.KERB_KDC_REPLY_preauth_data = (PKERB_REPLY_PA_DATA_LIST) OutputPreAuthData;
  2920. //
  2921. // Zero this out so we don't free the preauth data twice
  2922. //
  2923. OutputPreAuthData = NULL;
  2924. }
  2925. //
  2926. // Copy in the ticket
  2927. //
  2928. KerbErr = KerbPackTicket(
  2929. &Ticket,
  2930. ServerKey,
  2931. ServiceTicketInfo.PasswordVersion,
  2932. &Reply.ticket
  2933. );
  2934. D_DebugLog((DEB_T_KEY, "I_GetASTicket: KerbPackTicket ServiceKeyVersion 0x%x CommonEType %#x, KerbErr %#x\n",
  2935. ServiceTicketInfo.PasswordVersion, KerbErr));
  2936. if (!KERB_SUCCESS(KerbErr))
  2937. {
  2938. D_DebugLog((DEB_ERROR, "KLIN(%x) Failed to pack ticket: 0x%x\n", KLIN(FILENO, __LINE__), KerbErr));
  2939. goto Cleanup;
  2940. }
  2941. //
  2942. // Note: these are freed elsewhere, so zero them out after
  2943. // using them
  2944. //
  2945. Reply.client_name = EncryptedTicket.client_name;
  2946. //
  2947. // Copy in the client info & encrypt in client's key (or Encryption key if supplied in pre-auth data)
  2948. //
  2949. KerbErr = KerbPackKdcReplyBody(
  2950. &ReplyBody,
  2951. (EncryptionKey.keyvalue.value != NULL) ? &EncryptionKey : ClientKey,
  2952. (EncryptionKey.keyvalue.value != NULL) ? KERB_NO_KEY_VERSION : ClientTicketInfo.PasswordVersion,
  2953. KERB_TGS_REP_SALT, // should be KERB_AS_REP_SALT see raid 502476
  2954. KERB_ENCRYPTED_AS_REPLY_PDU, // was Pdu,
  2955. &Reply.encrypted_part
  2956. );
  2957. if (!KERB_SUCCESS(KerbErr))
  2958. {
  2959. D_DebugLog((DEB_ERROR, "KLIN(%x) Failed to pack KDC reply body: 0x%x\n", KLIN(FILENO, __LINE__), KerbErr));
  2960. goto Cleanup;
  2961. }
  2962. //
  2963. // Add in PW-SALT if we used a client key
  2964. //
  2965. if (SecData.AuditKdcEvent(KDC_AUDIT_AS_SUCCESS))
  2966. {
  2967. BYTE ClientSid[MAX_SID_LEN];
  2968. BYTE ServerSid[MAX_SID_LEN];
  2969. KdcMakeAccountSid(ClientSid, ClientTicketInfo.UserId);
  2970. KdcMakeAccountSid(ServerSid, ServiceTicketInfo.UserId);
  2971. KdcLsaIAuditAsEvent(
  2972. SE_AUDITID_AS_TICKET,
  2973. &ClientTicketInfo.AccountName,
  2974. RequestRealm,
  2975. ClientSid,
  2976. &ServiceTicketInfo.AccountName,
  2977. ServerSid,
  2978. (PULONG) &KdcOptions,
  2979. NULL, // success
  2980. &CommonEType,
  2981. &PreAuthType,
  2982. GET_CLIENT_ADDRESS(ClientAddress),
  2983. &PkiAuditInfo.CertIssuerName,
  2984. &PkiAuditInfo.CertSerialNumber,
  2985. &PkiAuditInfo.CertThumbprint
  2986. );
  2987. }
  2988. //
  2989. // Pack the reply
  2990. //
  2991. KerbErr = KerbPackData(
  2992. &Reply,
  2993. KERB_AS_REPLY_PDU, // was ReplyPdu,
  2994. &OutputMessage->BufferSize,
  2995. &OutputMessage->Buffer
  2996. );
  2997. if (!KERB_SUCCESS(KerbErr))
  2998. {
  2999. goto Cleanup;
  3000. }
  3001. Cleanup:
  3002. if (!KERB_SUCCESS(KerbErr))
  3003. {
  3004. DsysAssert(RequestBody != NULL);
  3005. if (!AuditedFailure && SecData.AuditKdcEvent(KDC_AUDIT_AS_FAILURE))
  3006. {
  3007. if (ClientName != NULL)
  3008. {
  3009. KdcLsaIAuditAsEvent(
  3010. SE_AUDITID_AS_TICKET,
  3011. &ClientName->Names[0],
  3012. RequestRealm,
  3013. NULL,
  3014. ServerStringName,
  3015. NULL,
  3016. &KdcOptions,
  3017. (PULONG) &KerbErr, // failure
  3018. NULL, // no common etype
  3019. NULL, // no preauth type
  3020. GET_CLIENT_ADDRESS(ClientAddress),
  3021. &PkiAuditInfo.CertIssuerName,
  3022. &PkiAuditInfo.CertSerialNumber,
  3023. &PkiAuditInfo.CertThumbprint
  3024. );
  3025. }
  3026. }
  3027. //
  3028. // If there was any preath data to return, pack it for return now.
  3029. //
  3030. if (OutputPreAuthData != NULL)
  3031. {
  3032. if (ErrorData->Buffer != NULL)
  3033. {
  3034. D_DebugLog((DEB_ERROR,
  3035. "KLIN(%x) Freeing return error data to return preauth data\n",
  3036. KLIN(FILENO,__LINE__)));
  3037. MIDL_user_free(ErrorData->Buffer);
  3038. ErrorData->Buffer = NULL;
  3039. ErrorData->BufferSize = 0;
  3040. }
  3041. (VOID) KerbPackData(
  3042. &OutputPreAuthData,
  3043. PKERB_PREAUTH_DATA_LIST_PDU,
  3044. &ErrorData->BufferSize,
  3045. &ErrorData->Buffer
  3046. );
  3047. }
  3048. }
  3049. if (UserHandle != NULL)
  3050. {
  3051. if (!KERB_SUCCESS(KerbErr))
  3052. {
  3053. if (!LoggedFailure && ClientInfoPresent)
  3054. {
  3055. BYTE ClientSid[MAX_SID_LEN];
  3056. RtlZeroMemory(ClientSid, MAX_SID_LEN);
  3057. KdcMakeAccountSid(ClientSid, ClientTicketInfo.UserId);
  3058. D_DebugLog((DEB_WARN , "KLIN(%x) Calling Failedlogon: LogonStatus: 0x%x KRB: 0x%x\n",
  3059. KLIN(FILENO,__LINE__), LogonStatus, KerbErr));
  3060. FailedLogon(
  3061. UserHandle,
  3062. ClientAddress,
  3063. &RequestBody->KERB_KDC_REQUEST_BODY_client_name,
  3064. ClientSid,
  3065. MAX_SID_LEN,
  3066. &ClientTicketInfo,
  3067. InputMessage,
  3068. OutputMessage,
  3069. &ClientNetbiosAddress,
  3070. KerbErr,
  3071. LogonStatus,
  3072. UsedOldPassword
  3073. );
  3074. }
  3075. }
  3076. else
  3077. {
  3078. BYTE ClientSid[MAX_SID_LEN];
  3079. RtlZeroMemory(ClientSid, MAX_SID_LEN);
  3080. KdcMakeAccountSid(ClientSid, ClientTicketInfo.UserId);
  3081. D_DebugLog((DEB_TRACE, "I_GetASTicket calling SuccessfulLogon\n"));
  3082. SuccessfulLogon(
  3083. UserHandle,
  3084. ClientAddress,
  3085. ClientSid,
  3086. MAX_SID_LEN,
  3087. InputMessage,
  3088. &ClientNetbiosAddress,
  3089. UserInfo
  3090. );
  3091. }
  3092. SamrCloseHandle(&UserHandle);
  3093. }
  3094. //
  3095. // Complete the WMI event
  3096. //
  3097. if (KdcEventTraceFlag)
  3098. {
  3099. //These variables point to either a unicode string struct containing
  3100. //the corresponding string or a pointer to KdcNullString
  3101. PUNICODE_STRING pStringToCopy;
  3102. WCHAR UnicodeNullChar = 0;
  3103. UNICODE_STRING UnicodeEmptyString = {sizeof(WCHAR),sizeof(WCHAR),&UnicodeNullChar};
  3104. ASEventTraceInfo.EventTrace.Class.Type = EVENT_TRACE_TYPE_END;
  3105. ASEventTraceInfo.EventTrace.Flags = WNODE_FLAG_USE_MOF_PTR |
  3106. WNODE_FLAG_TRACED_GUID;
  3107. // Always output error code. KdcOptions was captured on the start event
  3108. ASEventTraceInfo.eventInfo[0].DataPtr = (ULONGLONG) &KerbErr;
  3109. ASEventTraceInfo.eventInfo[0].Length = sizeof(ULONG);
  3110. ASEventTraceInfo.EventTrace.Size =
  3111. sizeof (EVENT_TRACE_HEADER) + sizeof(MOF_FIELD);
  3112. // Build counted MOF strings from the unicode strings
  3113. if (ClientStringName->Buffer != NULL &&
  3114. ClientStringName->Length > 0)
  3115. {
  3116. pStringToCopy = ClientStringName;
  3117. }
  3118. else {
  3119. pStringToCopy = &UnicodeEmptyString;
  3120. }
  3121. ASEventTraceInfo.eventInfo[1].DataPtr =
  3122. (ULONGLONG) &pStringToCopy->Length;
  3123. ASEventTraceInfo.eventInfo[1].Length =
  3124. sizeof(pStringToCopy->Length);
  3125. ASEventTraceInfo.eventInfo[2].DataPtr =
  3126. (ULONGLONG) pStringToCopy->Buffer;
  3127. ASEventTraceInfo.eventInfo[2].Length =
  3128. pStringToCopy->Length;
  3129. ASEventTraceInfo.EventTrace.Size += sizeof(MOF_FIELD)*2;
  3130. if (ServerStringName->Buffer != NULL &&
  3131. ServerStringName->Length > 0)
  3132. {
  3133. pStringToCopy = ServerStringName;
  3134. }
  3135. else
  3136. {
  3137. pStringToCopy = &UnicodeEmptyString;
  3138. }
  3139. ASEventTraceInfo.eventInfo[3].DataPtr =
  3140. (ULONGLONG) &pStringToCopy->Length;
  3141. ASEventTraceInfo.eventInfo[3].Length =
  3142. sizeof(pStringToCopy->Length);
  3143. ASEventTraceInfo.eventInfo[4].DataPtr =
  3144. (ULONGLONG) pStringToCopy->Buffer;
  3145. ASEventTraceInfo.eventInfo[4].Length =
  3146. pStringToCopy->Length;
  3147. ASEventTraceInfo.EventTrace.Size += sizeof(MOF_FIELD)*2;
  3148. if (RequestRealm->Buffer != NULL &&
  3149. RequestRealm->Length > 0)
  3150. {
  3151. pStringToCopy = RequestRealm;
  3152. }
  3153. else
  3154. {
  3155. pStringToCopy = &UnicodeEmptyString;
  3156. }
  3157. ASEventTraceInfo.eventInfo[5].DataPtr =
  3158. (ULONGLONG) &(pStringToCopy->Length);
  3159. ASEventTraceInfo.eventInfo[5].Length =
  3160. sizeof(pStringToCopy->Length);
  3161. ASEventTraceInfo.eventInfo[6].DataPtr =
  3162. (ULONGLONG) (pStringToCopy->Buffer);
  3163. ASEventTraceInfo.eventInfo[6].Length =
  3164. (pStringToCopy->Length);
  3165. ASEventTraceInfo.EventTrace.Size += sizeof(MOF_FIELD)*2;
  3166. TraceEvent(
  3167. KdcTraceLoggerHandle,
  3168. (PEVENT_TRACE_HEADER)&ASEventTraceInfo
  3169. );
  3170. }
  3171. SamIFree_UserInternal6Information( UserInfo );
  3172. SamIFreeSidAndAttributesList( &GroupMembership );
  3173. KerbFreeAuthData( PacAuthData );
  3174. FreeTicketInfo( &ClientTicketInfo );
  3175. FreeTicketInfo( &ServiceTicketInfo );
  3176. KdcFreePkiAuditInfo( &PkiAuditInfo );
  3177. KdcFreeInternalTicket( &Ticket );
  3178. KerbFreeKey( &EncryptionKey );
  3179. KerbFreeKdcName( &ClientName );
  3180. KerbFreeString( &TransitedRealm );
  3181. KerbFreeString( &ServerRealm );
  3182. KerbFreeKdcName( &ServerName );
  3183. KerbFreeString( &ClientNetbiosAddress );
  3184. KdcFreeKdcReplyBody( &ReplyBody );
  3185. KdcFreeKdcReply( &Reply );
  3186. KerbFreePreAuthData( OutputPreAuthData );
  3187. D_DebugLog((DEB_T_PAPI, "I_GetASTicket returning %#x\n", KerbErr));
  3188. return KerbErr;
  3189. }
  3190. //+-------------------------------------------------------------------------
  3191. //
  3192. // Function: KdcGetTicket
  3193. //
  3194. // Synopsis: Generic ticket getting entrypoint to get a ticket from the KDC
  3195. //
  3196. // Effects:
  3197. //
  3198. // Arguments: Context - ATQ context - only present for TCP/IP callers
  3199. // ClientAddress - Client's IP addresses. Only present for UDP & TPC callers
  3200. // ServerAddress - address the client used to contact this KDC.
  3201. // Only present for UDP & TPC callers
  3202. // InputMessage - the input KDC request message, in ASN.1 format
  3203. // OutputMessage - Receives the KDC reply message, allocated by
  3204. // the KDC.
  3205. //
  3206. // Requires:
  3207. //
  3208. // Returns:
  3209. //
  3210. // Notes: This routine is exported from the DLL and called from the
  3211. // client dll.
  3212. //
  3213. //
  3214. //--------------------------------------------------------------------------
  3215. extern "C"
  3216. KERBERR
  3217. KdcGetTicket(
  3218. IN OPTIONAL PVOID Context,
  3219. IN OPTIONAL PSOCKADDR ClientAddress,
  3220. IN OPTIONAL PSOCKADDR ServerAddress,
  3221. IN PKERB_MESSAGE_BUFFER InputMessage,
  3222. OUT PKERB_MESSAGE_BUFFER OutputMessage
  3223. )
  3224. {
  3225. KERBERR KerbErr;
  3226. KERB_EXT_ERROR ExtendedError = {0,0};
  3227. PKERB_EXT_ERROR pExtendedError = &ExtendedError; // needed for macro
  3228. PKERB_KDC_REQUEST RequestMessage = NULL;
  3229. KERB_KDC_REPLY ReplyMessage = {0};
  3230. KERB_MESSAGE_BUFFER ErrorData = {0};
  3231. ULONG InputPdu = KERB_TGS_REQUEST_PDU;
  3232. UNICODE_STRING RequestRealm = {0};
  3233. PKERB_INTERNAL_NAME RequestServer = NULL;
  3234. UNICODE_STRING ClientRealm = {0};
  3235. PUNICODE_STRING ExtendedErrorServerRealm = SecData.KdcDnsRealmName();
  3236. PKERB_INTERNAL_NAME ExtendedErrorServerName = SecData.KdcInternalName();
  3237. TYPED_DATA_Element* TypedDataList = NULL;
  3238. KERB_MESSAGE_BUFFER PreApendedErrorData = {0};
  3239. KERB_MESSAGE_BUFFER* ErrorDataToUse = NULL;
  3240. UNICODE_STRING ClientStringName = {0};
  3241. UNICODE_STRING ServerStringName = {0};
  3242. #if DBG
  3243. DWORD StartTime = 0;
  3244. #endif
  3245. TRACE(KDC, KdcGetTicket, DEB_FUNCTION );
  3246. //
  3247. // Make sure we are allowed to execute
  3248. //
  3249. if (!NT_SUCCESS(EnterApiCall()))
  3250. {
  3251. return(KDC_ERR_NOT_RUNNING);
  3252. }
  3253. RtlZeroMemory(
  3254. &ReplyMessage,
  3255. sizeof(KERB_KDC_REPLY)
  3256. );
  3257. //
  3258. // First initialize the return parameters.
  3259. //
  3260. OutputMessage->Buffer = NULL;
  3261. OutputMessage->BufferSize = 0;
  3262. //
  3263. // Check the first byte of the message to indicate the type of message
  3264. //
  3265. if ((InputMessage->BufferSize > 0) && (
  3266. (InputMessage->Buffer[0] & KERB_BER_APPLICATION_TAG) != 0))
  3267. {
  3268. if ((InputMessage->Buffer[0] & KERB_BER_APPLICATION_MASK) == KERB_AS_REQ_TAG)
  3269. {
  3270. InputPdu = KERB_AS_REQUEST_PDU;
  3271. }
  3272. else if ((InputMessage->Buffer[0] & KERB_BER_APPLICATION_MASK) != KERB_TGS_REQ_TAG)
  3273. {
  3274. D_DebugLog((DEB_T_SOCK,
  3275. "KLIN(%x) Bad message sent to KDC - not AS or TGS request\n",
  3276. KLIN(FILENO,__LINE__)));
  3277. KerbErr = KRB_ERR_FIELD_TOOLONG;
  3278. goto NoMsgCleanup;
  3279. }
  3280. }
  3281. else
  3282. {
  3283. D_DebugLog((DEB_T_SOCK,"KLIN(%x) Bad message sent to KDC - length to short or bad first byte\n",
  3284. KLIN(FILENO,__LINE__)));
  3285. KerbErr = KRB_ERR_FIELD_TOOLONG;
  3286. goto NoMsgCleanup;
  3287. }
  3288. //
  3289. // First decode the input message
  3290. //
  3291. KerbErr = (KERBERR) KerbUnpackData(
  3292. InputMessage->Buffer,
  3293. InputMessage->BufferSize,
  3294. InputPdu,
  3295. (PVOID *) &RequestMessage
  3296. );
  3297. if (KerbErr == KDC_ERR_MORE_DATA)
  3298. {
  3299. KerbErr = KRB_ERR_FIELD_TOOLONG;
  3300. goto Cleanup;
  3301. }
  3302. if (!KERB_SUCCESS(KerbErr))
  3303. {
  3304. D_DebugLog((DEB_ERROR,"KLIN(%x) Failed to unpack KDC request: 0x%x\n",
  3305. KLIN(FILENO,__LINE__),KerbErr));
  3306. //
  3307. // We don't want to return an error on a badly formed
  3308. // packet,as it can be used to set up a flood attack
  3309. //
  3310. goto NoMsgCleanup;
  3311. }
  3312. //
  3313. // First check the version of the request.
  3314. //
  3315. if (RequestMessage->version != KERBEROS_VERSION)
  3316. {
  3317. D_DebugLog((DEB_ERROR,"KLIN(%x) Bad request version: 0x%x\n",
  3318. KLIN(FILENO,__LINE__), RequestMessage->version));
  3319. KerbErr = KRB_AP_ERR_BADVERSION;
  3320. goto Cleanup;
  3321. }
  3322. //
  3323. // now call the internal version to do all the hard work
  3324. //
  3325. //
  3326. // Verify the realm name in the request
  3327. //
  3328. KerbErr = KerbConvertRealmToUnicodeString(
  3329. &RequestRealm,
  3330. &RequestMessage->request_body.realm
  3331. );
  3332. if (!KERB_SUCCESS(KerbErr))
  3333. {
  3334. goto Cleanup;
  3335. }
  3336. KerbErr = KerbConvertPrincipalNameToKdcName(
  3337. &RequestServer,
  3338. &RequestMessage->request_body.server_name
  3339. );
  3340. if ( !KERB_SUCCESS(KerbErr))
  3341. {
  3342. goto Cleanup;
  3343. }
  3344. //
  3345. // Now that we have the request realm and request server, any subsequent
  3346. // error will result in those values being placed into the extended error
  3347. //
  3348. ExtendedErrorServerRealm = &RequestRealm;
  3349. ExtendedErrorServerName = RequestServer;
  3350. if (!SecData.IsOurRealm(
  3351. &RequestRealm
  3352. ))
  3353. {
  3354. D_DebugLog((DEB_ERROR,"KLIN(%x) Request sent for wrong realm: %wZ\n",
  3355. KLIN(FILENO,__LINE__), &RequestRealm));
  3356. KerbErr = KDC_ERR_WRONG_REALM;
  3357. goto Cleanup;
  3358. }
  3359. if (RequestMessage->message_type == KRB_AS_REQ)
  3360. {
  3361. if (InputPdu != KERB_AS_REQUEST_PDU) {
  3362. KerbErr = KRB_ERR_FIELD_TOOLONG;
  3363. FILL_EXT_ERROR(pExtendedError, STATUS_KDC_INVALID_REQUEST,FILENO,__LINE__);
  3364. goto Cleanup;
  3365. }
  3366. SamIIncrementPerformanceCounter(
  3367. KdcAsReqCounter
  3368. );
  3369. //
  3370. // If WMI event tracing is enabled, notify it of the begin and end
  3371. // of the ticket request
  3372. //
  3373. #if DBG
  3374. StartTime = GetTickCount();
  3375. #endif
  3376. KerbErr = I_GetASTicket(
  3377. ClientAddress,
  3378. RequestMessage,
  3379. &RequestRealm,
  3380. InputMessage,
  3381. OutputMessage,
  3382. &ErrorData,
  3383. &ExtendedError,
  3384. &ClientRealm,
  3385. &ClientStringName,
  3386. &ServerStringName
  3387. );
  3388. #if DBG
  3389. D_DebugLog((DEB_T_PERF_STATS, "I_GetASTicket took %d m seconds\n", NetpDcElapsedTime(StartTime)));
  3390. #endif
  3391. }
  3392. else if (RequestMessage->message_type == KRB_TGS_REQ)
  3393. {
  3394. SamIIncrementPerformanceCounter(
  3395. KdcTgsReqCounter
  3396. );
  3397. #if DBG
  3398. StartTime = GetTickCount();
  3399. #endif
  3400. KerbErr = HandleTGSRequest(
  3401. ClientAddress,
  3402. RequestMessage,
  3403. &RequestRealm,
  3404. OutputMessage,
  3405. &ExtendedError,
  3406. &ClientStringName,
  3407. &ServerStringName
  3408. );
  3409. #if DBG
  3410. D_DebugLog((DEB_T_PERF_STATS, "HandleTGSRequest took %d m seconds\n", NetpDcElapsedTime(StartTime)));
  3411. #endif
  3412. }
  3413. else
  3414. {
  3415. D_DebugLog((DEB_ERROR,"KLIN(%x) Invalid message type: %d\n",
  3416. KLIN(FILENO,__LINE__),
  3417. RequestMessage->message_type));
  3418. FILL_EXT_ERROR(pExtendedError, STATUS_KDC_INVALID_REQUEST,FILENO,__LINE__);
  3419. KerbErr = KRB_AP_ERR_MSG_TYPE;
  3420. goto Cleanup;
  3421. }
  3422. //
  3423. // If the response is too big and we are using UDP, make the client
  3424. // change transports. We can tell the caller is UDP because it doesn't
  3425. // have an ATQ context but it does provide the client address.
  3426. //
  3427. if ((Context == NULL) && (ClientAddress != NULL))
  3428. {
  3429. if (OutputMessage->BufferSize >= KdcGlobalMaxDatagramReplySize)
  3430. {
  3431. LARGE_INTEGER CurrentTime;
  3432. D_DebugLog((DEB_WARN,"KLIN(%x) KDC response too big for UDP datagram (max size %d): %d bytes in message\n",
  3433. KLIN(FILENO,__LINE__), KdcGlobalMaxDatagramReplySize, OutputMessage->BufferSize ));
  3434. KerbErr = KRB_ERR_RESPONSE_TOO_BIG;
  3435. MIDL_user_free(OutputMessage->Buffer);
  3436. OutputMessage->Buffer = NULL;
  3437. OutputMessage->BufferSize = 0;
  3438. // purge the replay detection entry, otherwise when the client
  3439. // retries with TCP we will fail because of replay detection
  3440. GetSystemTimeAsFileTime((PFILETIME)&CurrentTime);
  3441. ReplayDetect->Check(
  3442. InputMessage->Buffer,
  3443. InputMessage->BufferSize,
  3444. NULL,
  3445. 0,
  3446. &CurrentTime,
  3447. FALSE, // insert
  3448. TRUE, // purge
  3449. TRUE ); // check replay cache
  3450. DebugLog((DEB_WARN, "Purged replay detection cache entry for UDP failover to TCP\n" ));
  3451. // we don't need to check if that failed (e.g. if the entry
  3452. // didn't exist)
  3453. }
  3454. }
  3455. Cleanup:
  3456. // TBD: Put in extended error return goo here for client
  3457. if (!KERB_SUCCESS(KerbErr) && (KDC_ERR_NO_RESPONSE != KerbErr))
  3458. {
  3459. //
  3460. // We may have a message built by someone else - the PDC
  3461. //
  3462. if (OutputMessage->Buffer == NULL)
  3463. {
  3464. //
  3465. // map KDC_ERR_MUST_USE_USER2USER to KDC_ERR_S_PRINCIPAL_UNKNOWN so
  3466. // down-level clients won't chuck
  3467. //
  3468. if (KDC_ERR_MUST_USE_USER2USER == KerbErr)
  3469. {
  3470. KERB_TYPED_DATA Data = {0};
  3471. DebugLog((DEB_T_U2U, "KLIN(%x) mapping KDC_ERR_MUST_USE_USER2USER to KDC_ERR_S_PRINCIPAL_UNKNOWN, ErrorData.Buffer %p\n",
  3472. KLIN(FILENO, __LINE__), ErrorData.Buffer));
  3473. Data.data_type = TD_MUST_USE_USER2USER;
  3474. if (ErrorData.Buffer && ErrorData.BufferSize)
  3475. {
  3476. DebugLog((DEB_WARN, "KLIN(%x) KdcGetTicket received non-empty error data\n",
  3477. KLIN(FILENO, __LINE__)));
  3478. KerbErr = KerbUnpackData(
  3479. ErrorData.Buffer,
  3480. ErrorData.BufferSize,
  3481. TYPED_DATA_PDU,
  3482. (PVOID*)&TypedDataList
  3483. );
  3484. if (!KERB_SUCCESS(KerbErr))
  3485. {
  3486. DebugLog((DEB_ERROR, "KLIN(%x) KdcGetTicket failed to unpack typed data %#x\n",
  3487. KLIN(FILENO, __LINE__), KerbErr));
  3488. goto NoMsgCleanup;
  3489. }
  3490. }
  3491. KerbErr = TypedDataListPushFront(
  3492. TypedDataList,
  3493. &Data,
  3494. &PreApendedErrorData.BufferSize,
  3495. &PreApendedErrorData.Buffer
  3496. );
  3497. if (!KERB_SUCCESS(KerbErr))
  3498. {
  3499. DebugLog((DEB_ERROR, "KLIN(%x) KdcGetTicket failed to pushfront typed data %#x\n",
  3500. KLIN(FILENO, __LINE__), KerbErr));
  3501. goto NoMsgCleanup;
  3502. }
  3503. ErrorDataToUse = &PreApendedErrorData;
  3504. KerbErr = KDC_ERR_S_PRINCIPAL_UNKNOWN;
  3505. //
  3506. // now report an event
  3507. //
  3508. KdcReportPolicyErrorEvent(
  3509. EVENTLOG_INFORMATION_TYPE,
  3510. KDCEVENT_POLICY_USER2USER_REQUIRED,
  3511. &ClientStringName,
  3512. &ServerStringName,
  3513. STATUS_USER2USER_REQUIRED,
  3514. 0, // raw data size
  3515. NULL // no raw data
  3516. );
  3517. }
  3518. else if ((ErrorData.Buffer == NULL)
  3519. && !EXT_ERROR_SUCCESS((ExtendedError))) // if ((ErrorData.Buffer == NULL) && (KDC_ERR_PREAUTH_FAILED == KerbErr) && (EXT_CLIENT_INFO_PRESENT((&ExtendedError))))
  3520. {
  3521. KERB_ERROR_METHOD_DATA ErrorMethodData = {0};
  3522. KERBERR KerbErrSaved = KerbErr;
  3523. ErrorMethodData.data_type = KERB_ERR_TYPE_EXTENDED;
  3524. ErrorMethodData.bit_mask |= data_value_present;
  3525. ErrorMethodData.data_value.value = (PBYTE) &ExtendedError;
  3526. ErrorMethodData.data_value.length = sizeof(KERB_EXT_ERROR);
  3527. KerbErr = KerbPackData(
  3528. &ErrorMethodData,
  3529. KERB_ERROR_METHOD_DATA_PDU,
  3530. &ErrorData.BufferSize,
  3531. &ErrorData.Buffer
  3532. );
  3533. if (!KERB_SUCCESS(KerbErr))
  3534. {
  3535. DebugLog((DEB_ERROR, "KLIN(%x) KdcGetTicket failed to pack error data %#x\n",
  3536. KLIN(FILENO, __LINE__), KerbErr));
  3537. goto NoMsgCleanup;
  3538. }
  3539. ErrorDataToUse = &ErrorData;
  3540. KerbErr = KerbErrSaved;
  3541. }
  3542. else
  3543. {
  3544. ErrorDataToUse = &ErrorData;
  3545. }
  3546. KerbBuildErrorMessageEx(
  3547. KerbErr,
  3548. &ExtendedError,
  3549. ExtendedErrorServerRealm,
  3550. ExtendedErrorServerName,
  3551. &ClientRealm,
  3552. ErrorDataToUse->Buffer,
  3553. ErrorDataToUse->BufferSize,
  3554. &OutputMessage->BufferSize,
  3555. &OutputMessage->Buffer
  3556. );
  3557. }
  3558. }
  3559. NoMsgCleanup:
  3560. KerbFreeString(&ClientRealm);
  3561. KerbFreeString(&RequestRealm);
  3562. KerbFreeString(&ClientStringName);
  3563. KerbFreeString(&ServerStringName);
  3564. MIDL_user_free(RequestServer);
  3565. if (RequestMessage != NULL)
  3566. {
  3567. KerbFreeData(InputPdu, RequestMessage);
  3568. }
  3569. if (ErrorData.Buffer != NULL)
  3570. {
  3571. MIDL_user_free(ErrorData.Buffer);
  3572. }
  3573. if (PreApendedErrorData.Buffer != NULL)
  3574. {
  3575. MIDL_user_free(PreApendedErrorData.Buffer);
  3576. }
  3577. if (TypedDataList)
  3578. {
  3579. KerbFreeData(TYPED_DATA_PDU, TypedDataList);
  3580. }
  3581. LeaveApiCall();
  3582. return(KerbErr);
  3583. }
  3584. // Routines to handle the Negative Cache to PDC from BDC
  3585. // Initialization routines - must be called in single threaded mode and only once
  3586. NTSTATUS
  3587. AsNegCacheInit()
  3588. {
  3589. NTSTATUS Status = STATUS_SUCCESS;
  3590. //
  3591. // Initialize the Credential list to be empty.
  3592. //
  3593. if (g_fApNegCacheInitialized == TRUE)
  3594. {
  3595. goto CleanUp; // already initialized
  3596. }
  3597. Status = RtlInitializeCriticalSection(&l_ApNegCacheCritSect);
  3598. if (!NT_SUCCESS(Status))
  3599. {
  3600. goto CleanUp;
  3601. }
  3602. InitializeListHead( &l_ApNegCacheList );
  3603. // Simple variable test to make sure all initialized;
  3604. g_fApNegCacheInitialized = TRUE;
  3605. CleanUp:
  3606. return Status;
  3607. }
  3608. // This function will check if we should send the failed auth request to the PDC
  3609. // The return value only indicates if the function worked properly. The result of the function is
  3610. // is kept in pfAvoidSendToPDC (if True then do not send requst to PDC)
  3611. NTSTATUS
  3612. AsNegCacheCheck(
  3613. IN PVOID Buffer,
  3614. IN ULONG BufferLength,
  3615. IN OPTIONAL PVOID OptionalBuffer,
  3616. IN OPTIONAL ULONG OptionalBufferLength,
  3617. OUT PBOOLEAN pfAvoidSendToPDC)
  3618. {
  3619. NTSTATUS Status = STATUS_SUCCESS;
  3620. PLIST_ENTRY ListEntry = NULL;
  3621. PNEGATIVE_CACHE pApNegEntry = NULL;
  3622. MD5_CTX Md5Context;
  3623. LARGE_INTEGER CurrentTime;
  3624. LARGE_INTEGER Time5Minutes;
  3625. ASSERT(pfAvoidSendToPDC);
  3626. if (g_fApNegCacheInitialized == FALSE)
  3627. {
  3628. return STATUS_APP_INIT_FAILURE;
  3629. }
  3630. GetSystemTimeAsFileTime((PFILETIME)&CurrentTime);
  3631. *pfAvoidSendToPDC = FALSE;
  3632. Time5Minutes.QuadPart = (LONGLONG)KERB_5_MINUTES_100NANO;
  3633. // Compute the md5 signature of the request
  3634. MD5Init(
  3635. &Md5Context
  3636. );
  3637. MD5Update(
  3638. &Md5Context,
  3639. (PBYTE) Buffer,
  3640. BufferLength
  3641. );
  3642. if ((OptionalBuffer != NULL) && (OptionalBufferLength != 0))
  3643. {
  3644. MD5Update(
  3645. &Md5Context,
  3646. (PBYTE) OptionalBuffer,
  3647. OptionalBufferLength
  3648. );
  3649. }
  3650. MD5Final(
  3651. &Md5Context
  3652. );
  3653. //
  3654. // Acquire exclusive access to the Credential list
  3655. //
  3656. RtlEnterCriticalSection( &l_ApNegCacheCritSect );
  3657. //
  3658. // Now walk the list of Credentials looking for a match.
  3659. //
  3660. for ( ListEntry = l_ApNegCacheList.Flink;
  3661. ListEntry != &l_ApNegCacheList;
  3662. ListEntry = ListEntry->Flink )
  3663. {
  3664. pApNegEntry = CONTAINING_RECORD( ListEntry, NEGATIVE_CACHE, Next );
  3665. // Check if the md5 signature matches
  3666. // if this entry is for this user's request (on the workstation), check if it's time to forward
  3667. // this logon to the PDC. In any case, remove this entry from the list and then insert it at the
  3668. // front so that the list stays sorted by the entry access time.
  3669. if (RtlEqualMemory(Md5Context.digest, pApNegEntry->digest, MD5DIGESTLEN))
  3670. {
  3671. if ((pApNegEntry->lBadLogonCount > KERB_AP_NEGATIVE_MAX_LOGON_COUNT) &&
  3672. (CurrentTime.QuadPart < (pApNegEntry->TimeLastPDCContact.QuadPart + Time5Minutes.QuadPart)))
  3673. {
  3674. *pfAvoidSendToPDC = TRUE;
  3675. DebugLog((DEB_TRACE , "getas:AsNegCacheCheck(%d) no send to PDC: Entry 0x%x\n", __LINE__, Md5Context.digest));
  3676. }
  3677. RemoveEntryList(&(pApNegEntry->Next));
  3678. break;
  3679. }
  3680. pApNegEntry = NULL;
  3681. }
  3682. if (pApNegEntry)
  3683. {
  3684. InsertHeadList(&l_ApNegCacheList, &(pApNegEntry->Next));
  3685. }
  3686. RtlLeaveCriticalSection( &l_ApNegCacheCritSect );
  3687. return Status;
  3688. }
  3689. // This function will update an entry (or create a new one) in the negative cache
  3690. // Update the list of forwarded failed user logons
  3691. //
  3692. // If the lockout policy is enabled we should continue
  3693. // to forward logons to PDC (i.e. we should not cache
  3694. // this failure) to keep the right lockout count until
  3695. // the account becomes locked on the PDC.
  3696. //
  3697. NTSTATUS
  3698. AsNegCacheUpdate(
  3699. IN PVOID Buffer,
  3700. IN ULONG BufferLength,
  3701. IN OPTIONAL PVOID OptionalBuffer,
  3702. IN OPTIONAL ULONG OptionalBufferLength,
  3703. IN NTSTATUS StatusPdcAuth)
  3704. {
  3705. NTSTATUS Status = STATUS_SUCCESS;
  3706. PLIST_ENTRY ListEntry = NULL;
  3707. PNEGATIVE_CACHE pApNegEntry = NULL;
  3708. MD5_CTX Md5Context;
  3709. ULONG FailedUserCount = 0;
  3710. if (g_fApNegCacheInitialized == FALSE)
  3711. {
  3712. return STATUS_APP_INIT_FAILURE;
  3713. }
  3714. // Compute the md5 signature of the request
  3715. MD5Init(
  3716. &Md5Context
  3717. );
  3718. MD5Update(
  3719. &Md5Context,
  3720. (PBYTE) Buffer,
  3721. BufferLength
  3722. );
  3723. if ((OptionalBuffer != NULL) && (OptionalBufferLength != 0))
  3724. {
  3725. MD5Update(
  3726. &Md5Context,
  3727. (PBYTE) OptionalBuffer,
  3728. OptionalBufferLength
  3729. );
  3730. }
  3731. MD5Final(
  3732. &Md5Context
  3733. );
  3734. //
  3735. // Acquire exclusive access to the Credential list
  3736. //
  3737. RtlEnterCriticalSection( &l_ApNegCacheCritSect );
  3738. //
  3739. // Now walk the list of Credentials looking for a match.
  3740. //
  3741. for ( ListEntry = l_ApNegCacheList.Flink;
  3742. ListEntry != &l_ApNegCacheList;
  3743. ListEntry = ListEntry->Flink )
  3744. {
  3745. pApNegEntry = CONTAINING_RECORD( ListEntry, NEGATIVE_CACHE, Next );
  3746. // Check if the md5 signature matches
  3747. // if this entry is for this user's request (on the workstation), remove it from the list.
  3748. // If it stays on the list, we will re-insert it at the front so that the list
  3749. // stays sorted by the entry access time.
  3750. if (RtlEqualMemory(Md5Context.digest, pApNegEntry->digest, MD5DIGESTLEN))
  3751. {
  3752. RemoveEntryList(&(pApNegEntry->Next));
  3753. break;
  3754. }
  3755. pApNegEntry = NULL;
  3756. FailedUserCount++;
  3757. }
  3758. // Process if PDC auth called failed
  3759. if (!(NT_SUCCESS(StatusPdcAuth)))
  3760. {
  3761. // If there is no entry for this user, allocate one
  3762. if (pApNegEntry == NULL)
  3763. {
  3764. pApNegEntry = (PNEGATIVE_CACHE) MIDL_user_allocate(sizeof(NEGATIVE_CACHE));
  3765. if (pApNegEntry == NULL)
  3766. {
  3767. Status = STATUS_NO_MEMORY;
  3768. goto CleanUp;
  3769. }
  3770. // Fill in data structure
  3771. RtlCopyMemory(
  3772. pApNegEntry->digest,
  3773. Md5Context.digest,
  3774. MD5DIGESTLEN
  3775. );
  3776. pApNegEntry->lBadLogonCount = 0;
  3777. D_DebugLog((DEB_TRACE , "getas:AsNegCacheUpdate(%d) new cache: Entry 0x%x\n", __LINE__, Md5Context.digest));
  3778. // If we have too many entries, remove the least recently used one and free it
  3779. if (FailedUserCount > KERB_MAX_FAILED_LIST_ENTRIES)
  3780. {
  3781. PLIST_ENTRY LastEntry = RemoveTailList(&l_ApNegCacheList);
  3782. PNEGATIVE_CACHE pLastApNegEntry = CONTAINING_RECORD( LastEntry, NEGATIVE_CACHE, Next );
  3783. if (pLastApNegEntry)
  3784. {
  3785. MIDL_user_free(pLastApNegEntry);
  3786. }
  3787. }
  3788. }
  3789. // Update the last time we contacted the PDC
  3790. GetSystemTimeAsFileTime((PFILETIME)&(pApNegEntry->TimeLastPDCContact));
  3791. pApNegEntry->lBadLogonCount++;
  3792. D_DebugLog((DEB_TRACE , "getas:AsNegCacheUpdate(%d) increment: Entry 0x%x Count %d\n",
  3793. __LINE__, Md5Context.digest, pApNegEntry->lBadLogonCount));
  3794. // Place it back to the front of the list
  3795. InsertHeadList(&l_ApNegCacheList, &(pApNegEntry->Next));
  3796. }
  3797. else
  3798. {
  3799. // we succeeded at the PDC so free unlinked neg cache entry if found
  3800. if (pApNegEntry)
  3801. {
  3802. D_DebugLog((DEB_TRACE , "getas:AsNegCacheUpdate(%d) succeeded at PDC so remove: Entry 0x%x\n", __LINE__, Md5Context.digest));
  3803. MIDL_user_free(pApNegEntry);
  3804. }
  3805. }
  3806. CleanUp:
  3807. RtlLeaveCriticalSection( &l_ApNegCacheCritSect );
  3808. return Status;
  3809. }
  3810. // This function will remove an entry from the Negative Cache
  3811. NTSTATUS
  3812. AsNegCacheDelete(
  3813. IN PVOID Buffer,
  3814. IN ULONG BufferLength,
  3815. IN OPTIONAL PVOID OptionalBuffer,
  3816. IN OPTIONAL ULONG OptionalBufferLength)
  3817. {
  3818. NTSTATUS Status = STATUS_SUCCESS;
  3819. PLIST_ENTRY ListEntry = NULL;
  3820. PNEGATIVE_CACHE pApNegEntry = NULL;
  3821. MD5_CTX Md5Context;
  3822. if (g_fApNegCacheInitialized == FALSE)
  3823. {
  3824. return STATUS_APP_INIT_FAILURE;
  3825. }
  3826. // Compute the md5 signature of the request
  3827. MD5Init(
  3828. &Md5Context
  3829. );
  3830. MD5Update(
  3831. &Md5Context,
  3832. (PBYTE) Buffer,
  3833. BufferLength
  3834. );
  3835. if ((OptionalBuffer != NULL) && (OptionalBufferLength != 0))
  3836. {
  3837. MD5Update(
  3838. &Md5Context,
  3839. (PBYTE) OptionalBuffer,
  3840. OptionalBufferLength
  3841. );
  3842. }
  3843. MD5Final(
  3844. &Md5Context
  3845. );
  3846. //
  3847. // Acquire exclusive access to the Credential list
  3848. //
  3849. RtlEnterCriticalSection( &l_ApNegCacheCritSect );
  3850. //
  3851. // Now walk the list of Credentials looking for a match.
  3852. //
  3853. for ( ListEntry = l_ApNegCacheList.Flink;
  3854. ListEntry != &l_ApNegCacheList;
  3855. ListEntry = ListEntry->Flink )
  3856. {
  3857. pApNegEntry = CONTAINING_RECORD( ListEntry, NEGATIVE_CACHE, Next );
  3858. // Check if the md5 signature matches
  3859. // if this entry is for this user's request (on the workstation), remove this entry from the list.
  3860. if (RtlEqualMemory(Md5Context.digest, pApNegEntry->digest, MD5DIGESTLEN))
  3861. {
  3862. D_DebugLog((DEB_TRACE , "getas:AsNegCacheDelete(%d) remove cache: Entry 0x%x\n", __LINE__, Md5Context.digest));
  3863. RemoveEntryList(&(pApNegEntry->Next));
  3864. break;
  3865. }
  3866. pApNegEntry = NULL;
  3867. }
  3868. if (pApNegEntry)
  3869. {
  3870. MIDL_user_free(pApNegEntry);
  3871. }
  3872. RtlLeaveCriticalSection( &l_ApNegCacheCritSect );
  3873. return Status;
  3874. }