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

2002 lines
48 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // File: pac.cxx
  4. //
  5. // Contents: KDC Pac generation code.
  6. //
  7. //
  8. // History: 16-Jan-93 WadeR Created.
  9. //
  10. //------------------------------------------------------------------------
  11. #include "kdcsvr.hxx"
  12. #include <pac.hxx>
  13. #include "kdctrace.h"
  14. #include "fileno.h"
  15. #include <userall.h>
  16. #define FILENO FILENO_GETAS
  17. SECURITY_DESCRIPTOR AuthenticationSD;
  18. #ifndef DONT_SUPPORT_OLD_TYPES
  19. #define KDC_PAC_KEYTYPE KERB_ETYPE_RC4_HMAC_OLD
  20. #define KDC_PAC_CHECKSUM KERB_CHECKSUM_HMAC_MD5
  21. #else
  22. #define KDC_PAC_KEYTYPE KERB_ETYPE_RC4_HMAC
  23. #define KDC_PAC_CHECKSUM KERB_CHECKSUM_HMAC_MD5
  24. #endif
  25. //+-------------------------------------------------------------------------
  26. //
  27. // Function: EnterApiCall
  28. //
  29. // Synopsis: Makes sure that the KDC service is initialized and running
  30. // and won't terminate during the call.
  31. //
  32. // Effects: increments the CurrentApiCallers count.
  33. //
  34. // Arguments:
  35. //
  36. // Requires:
  37. //
  38. // Returns: STATUS_INVALID_SERVER_STATE - the KDC service is not
  39. // running
  40. //
  41. // Notes:
  42. //
  43. //
  44. //--------------------------------------------------------------------------
  45. NTSTATUS
  46. EnterApiCall(
  47. VOID
  48. )
  49. {
  50. NTSTATUS hrRet = STATUS_SUCCESS;
  51. EnterCriticalSection(&ApiCriticalSection);
  52. if (KdcState != Stopped)
  53. {
  54. CurrentApiCallers++;
  55. }
  56. else
  57. {
  58. hrRet = STATUS_INVALID_SERVER_STATE;
  59. }
  60. LeaveCriticalSection(&ApiCriticalSection);
  61. return(hrRet);
  62. }
  63. //+-------------------------------------------------------------------------
  64. //
  65. // Function: LeaveApiCall
  66. //
  67. // Synopsis: Decrements the count of active calls and if the KDC is
  68. // shutting down sets an event to let it continue.
  69. //
  70. // Effects: Deccrements the CurrentApiCallers count.
  71. //
  72. // Arguments:
  73. //
  74. // Requires:
  75. //
  76. // Returns: Nothing
  77. //
  78. // Notes:
  79. //
  80. //
  81. //--------------------------------------------------------------------------
  82. VOID
  83. LeaveApiCall(
  84. VOID
  85. )
  86. {
  87. NTSTATUS hrRet = S_OK;
  88. EnterCriticalSection(&ApiCriticalSection);
  89. CurrentApiCallers--;
  90. if (KdcState == Stopped)
  91. {
  92. if (CurrentApiCallers == 0)
  93. {
  94. if (!SetEvent(hKdcShutdownEvent))
  95. {
  96. D_DebugLog((DEB_ERROR,"Failed to set shutdown event from LeaveApiCall: 0x%d\n",GetLastError()));
  97. }
  98. else
  99. {
  100. UpdateStatus(SERVICE_STOP_PENDING);
  101. }
  102. //
  103. // Free any DS libraries in use
  104. //
  105. SecData.Cleanup();
  106. if (KdcTraceRegistrationHandle != (TRACEHANDLE)0)
  107. {
  108. UnregisterTraceGuids( KdcTraceRegistrationHandle );
  109. }
  110. }
  111. }
  112. LeaveCriticalSection(&ApiCriticalSection);
  113. }
  114. //+-------------------------------------------------------------------------
  115. //
  116. // Function: KdcInsertPacIntoAuthData
  117. //
  118. // Synopsis: Inserts the PAC into the auth data in the two places
  119. // it lives - in the IF_RELEVANT portion & in the outer body
  120. //
  121. // Effects:
  122. //
  123. // Arguments:
  124. //
  125. // Requires:
  126. //
  127. // Returns:
  128. //
  129. // Notes:
  130. //
  131. //
  132. //--------------------------------------------------------------------------
  133. KERBERR
  134. KdcInsertPacIntoAuthData(
  135. IN PKERB_AUTHORIZATION_DATA AuthData,
  136. IN PKERB_IF_RELEVANT_AUTH_DATA IfRelevantData,
  137. IN PKERB_AUTHORIZATION_DATA PacAuthData,
  138. OUT PKERB_AUTHORIZATION_DATA * UpdatedAuthData
  139. )
  140. {
  141. KERBERR KerbErr = KDC_ERR_NONE;
  142. PKERB_AUTHORIZATION_DATA LocalAuthData = NULL;
  143. PKERB_AUTHORIZATION_DATA LocalIfRelevantData = NULL;
  144. PKERB_AUTHORIZATION_DATA NewIfRelevantData = NULL;
  145. PKERB_AUTHORIZATION_DATA NewPacData = NULL;
  146. KERB_AUTHORIZATION_DATA TempPacData = {0};
  147. PKERB_AUTHORIZATION_DATA NewAuthData = NULL;
  148. KERB_AUTHORIZATION_DATA TempOldPac = {0};
  149. PKERB_AUTHORIZATION_DATA TempNextPointer,NextPointer;
  150. NewPacData = (PKERB_AUTHORIZATION_DATA) MIDL_user_allocate(sizeof(KERB_AUTHORIZATION_DATA));
  151. NewIfRelevantData = (PKERB_AUTHORIZATION_DATA) MIDL_user_allocate(sizeof(KERB_AUTHORIZATION_DATA));
  152. if ((NewPacData == NULL) || (NewIfRelevantData == NULL))
  153. {
  154. KerbErr = KRB_ERR_GENERIC;
  155. goto Cleanup;
  156. }
  157. RtlZeroMemory(
  158. NewPacData,
  159. sizeof(KERB_AUTHORIZATION_DATA)
  160. );
  161. RtlZeroMemory(
  162. NewIfRelevantData,
  163. sizeof(KERB_AUTHORIZATION_DATA)
  164. );
  165. //
  166. // First build the IfRelevantData
  167. //
  168. // The general idea is to replace, in line, the relevant authorization
  169. // data. This means (a) putting it into the IfRelevantData or making
  170. // the IfRelevantData be PacAuthData, and (b) putting it into AuthData
  171. // as well as changing the IfRelevant portions of that data
  172. //
  173. if (IfRelevantData != NULL)
  174. {
  175. LocalAuthData = KerbFindAuthDataEntry(
  176. KERB_AUTH_DATA_PAC,
  177. IfRelevantData
  178. );
  179. if (LocalAuthData == NULL)
  180. {
  181. LocalIfRelevantData = PacAuthData;
  182. PacAuthData->next = IfRelevantData;
  183. }
  184. else
  185. {
  186. //
  187. // Replace the pac in the if-relevant list with the
  188. // new one.
  189. //
  190. TempOldPac = *LocalAuthData;
  191. LocalAuthData->value.auth_data.value = PacAuthData->value.auth_data.value;
  192. LocalAuthData->value.auth_data.length = PacAuthData->value.auth_data.length;
  193. LocalIfRelevantData = IfRelevantData;
  194. }
  195. }
  196. else
  197. {
  198. //
  199. // build a new if-relevant data
  200. //
  201. TempPacData = *PacAuthData;
  202. TempPacData.next = NULL;
  203. LocalIfRelevantData = &TempPacData;
  204. }
  205. //
  206. // Build a local if-relevant auth data
  207. //
  208. KerbErr = KerbPackData(
  209. &LocalIfRelevantData,
  210. PKERB_IF_RELEVANT_AUTH_DATA_PDU,
  211. (PULONG) &NewIfRelevantData->value.auth_data.length,
  212. &NewIfRelevantData->value.auth_data.value
  213. );
  214. //
  215. // fixup the old if-relevant list, if necessary
  216. //
  217. if (TempOldPac.value.auth_data.value != NULL)
  218. {
  219. *LocalAuthData = TempOldPac;
  220. }
  221. if (!KERB_SUCCESS(KerbErr))
  222. {
  223. goto Cleanup;
  224. }
  225. NewIfRelevantData->value.auth_data_type = KERB_AUTH_DATA_IF_RELEVANT;
  226. *NewPacData = *PacAuthData;
  227. //
  228. // Zero this out so the old data doesn't get used
  229. //
  230. PacAuthData->value.auth_data.value = NULL;
  231. PacAuthData->value.auth_data.length = 0;
  232. //
  233. // Now we have a new if_relevant & a new pac for the outer auth-data list.
  234. //
  235. NewAuthData = NewIfRelevantData;
  236. NewIfRelevantData->next = NULL;
  237. NewIfRelevantData = NULL;
  238. //
  239. // Start building the list, first putting the non-pac entries at the end
  240. //
  241. NextPointer = AuthData;
  242. while (NextPointer != NULL)
  243. {
  244. if ((NextPointer->value.auth_data_type != KERB_AUTH_DATA_IF_RELEVANT) &&
  245. (NextPointer->value.auth_data_type != KERB_AUTH_DATA_PAC))
  246. {
  247. TempNextPointer = NextPointer->next;
  248. NextPointer->next = NULL;
  249. KerbErr = KerbCopyAndAppendAuthData(
  250. &NewAuthData,
  251. NextPointer
  252. );
  253. NextPointer->next = TempNextPointer;
  254. if (!KERB_SUCCESS(KerbErr))
  255. {
  256. goto Cleanup;
  257. }
  258. }
  259. NextPointer = NextPointer->next;
  260. }
  261. *UpdatedAuthData = NewAuthData;
  262. NewAuthData = NULL;
  263. Cleanup:
  264. if (NewPacData != NULL)
  265. {
  266. KerbFreeAuthData(NewPacData);
  267. }
  268. if (NewIfRelevantData != NULL)
  269. {
  270. KerbFreeAuthData(NewIfRelevantData);
  271. }
  272. if (NewAuthData != NULL)
  273. {
  274. KerbFreeAuthData(NewAuthData);
  275. }
  276. return(KerbErr);
  277. }
  278. //+-------------------------------------------------------------------------
  279. //
  280. // Function: KdcBuildPacSidList
  281. //
  282. // Synopsis: Builds a list of SIDs in the PAC
  283. //
  284. // Effects:
  285. //
  286. // Arguments:
  287. //
  288. // Requires:
  289. //
  290. // Returns:
  291. //
  292. // Notes:
  293. //
  294. //
  295. //--------------------------------------------------------------------------
  296. KERBERR
  297. KdcBuildPacSidList(
  298. IN PNETLOGON_VALIDATION_SAM_INFO3 UserInfo,
  299. OUT PSAMPR_PSID_ARRAY Sids
  300. )
  301. {
  302. KERBERR KerbErr = KDC_ERR_NONE;
  303. ULONG Size = 0, i;
  304. Sids->Count = 0;
  305. Sids->Sids = NULL;
  306. if (UserInfo->UserId != 0)
  307. {
  308. Size += sizeof(SAMPR_SID_INFORMATION);
  309. }
  310. Size += UserInfo->GroupCount * (ULONG)sizeof(SAMPR_SID_INFORMATION);
  311. //
  312. // If there are extra SIDs, add space for them
  313. //
  314. if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
  315. Size += UserInfo->SidCount * (ULONG)sizeof(SAMPR_SID_INFORMATION);
  316. }
  317. Sids->Sids = (PSAMPR_SID_INFORMATION) MIDL_user_allocate( Size );
  318. if ( Sids->Sids == NULL ) {
  319. KerbErr = KRB_ERR_GENERIC;
  320. goto Cleanup;
  321. }
  322. RtlZeroMemory(
  323. Sids->Sids,
  324. Size
  325. );
  326. //
  327. // Start copying SIDs into the structure
  328. //
  329. i = 0;
  330. //
  331. // If the UserId is non-zero, then it contians the users RID.
  332. //
  333. if ( UserInfo->UserId ) {
  334. Sids->Sids[0].SidPointer = (PRPC_SID)
  335. KerbMakeDomainRelativeSid( UserInfo->LogonDomainId,
  336. UserInfo->UserId );
  337. if( Sids->Sids[0].SidPointer == NULL ) {
  338. KerbErr = KRB_ERR_GENERIC;
  339. goto Cleanup;
  340. }
  341. Sids->Count++;
  342. }
  343. //
  344. // Copy over all the groups passed as RIDs
  345. //
  346. for ( i=0; i < UserInfo->GroupCount; i++ ) {
  347. Sids->Sids[Sids->Count].SidPointer = (PRPC_SID)
  348. KerbMakeDomainRelativeSid(
  349. UserInfo->LogonDomainId,
  350. UserInfo->GroupIds[i].RelativeId );
  351. if( Sids->Sids[Sids->Count].SidPointer == NULL ) {
  352. KerbErr = KRB_ERR_GENERIC;
  353. goto Cleanup;
  354. }
  355. Sids->Count++;
  356. }
  357. //
  358. // Add in the extra SIDs
  359. //
  360. //
  361. // No need to allocate these, but...
  362. //
  363. if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
  364. for ( i = 0; i < UserInfo->SidCount; i++ ) {
  365. if (!NT_SUCCESS(KerbDuplicateSid(
  366. (PSID *) &Sids->Sids[Sids->Count].SidPointer,
  367. UserInfo->ExtraSids[i].Sid
  368. )))
  369. {
  370. KerbErr = KRB_ERR_GENERIC;
  371. goto Cleanup;
  372. }
  373. Sids->Count++;
  374. }
  375. }
  376. //
  377. // Deallocate any memory we've allocated
  378. //
  379. Cleanup:
  380. if (!KERB_SUCCESS(KerbErr))
  381. {
  382. if (Sids->Sids != NULL)
  383. {
  384. for (i = 0; i < Sids->Count ;i++ )
  385. {
  386. if (Sids->Sids[i].SidPointer != NULL)
  387. {
  388. MIDL_user_free(Sids->Sids[i].SidPointer);
  389. }
  390. }
  391. MIDL_user_free(Sids->Sids);
  392. Sids->Sids = NULL;
  393. Sids->Count = 0;
  394. }
  395. }
  396. return KerbErr;
  397. }
  398. //+-------------------------------------------------------------------------
  399. //
  400. // Function: KdcAddResourceGroupsToPac
  401. //
  402. // Synopsis: Queries SAM for resources grousp and builds a new PAC with
  403. // those groups
  404. //
  405. // Effects:
  406. //
  407. // Arguments:
  408. //
  409. // Requires:
  410. //
  411. // Returns:
  412. //
  413. // Notes:
  414. //
  415. //
  416. //--------------------------------------------------------------------------
  417. KERBERR
  418. KdcAddResourceGroupsToPac(
  419. IN PPACTYPE OldPac,
  420. IN ULONG ChecksumSize,
  421. OUT PPACTYPE * NewPac
  422. )
  423. {
  424. NTSTATUS Status;
  425. KERBERR KerbErr = KDC_ERR_NONE;
  426. PPAC_INFO_BUFFER LogonInfo;
  427. ULONG Index;
  428. PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo = NULL;
  429. SAMPR_PSID_ARRAY SidList = {0};
  430. PSAMPR_PSID_ARRAY ResourceGroups = NULL;
  431. //
  432. // First, find the logon information
  433. //
  434. LogonInfo = PAC_Find(
  435. OldPac,
  436. PAC_LOGON_INFO,
  437. NULL
  438. );
  439. if (LogonInfo == NULL)
  440. {
  441. D_DebugLog((DEB_WARN,"No logon info for PAC - not adding resource groups\n"));
  442. goto Cleanup;
  443. }
  444. //
  445. // Now unmarshall the validation information and build a list of sids
  446. //
  447. if (!NT_SUCCESS(PAC_UnmarshallValidationInfo(
  448. &ValidationInfo,
  449. LogonInfo->Data,
  450. LogonInfo->cbBufferSize)))
  451. {
  452. D_DebugLog((DEB_ERROR,"Failed to unmarshall validation info!\n"));
  453. KerbErr = KRB_ERR_GENERIC;
  454. goto Cleanup;
  455. }
  456. KerbErr = KdcBuildPacSidList(
  457. ValidationInfo,
  458. &SidList
  459. );
  460. if (!KERB_SUCCESS(KerbErr))
  461. {
  462. goto Cleanup;
  463. }
  464. //
  465. // Call SAM to get the sids
  466. //
  467. Status = SamIGetResourceGroupMembershipsTransitive(
  468. GlobalAccountDomainHandle,
  469. &SidList,
  470. 0, // no flags
  471. &ResourceGroups
  472. );
  473. if (!NT_SUCCESS(Status))
  474. {
  475. DebugLog((DEB_ERROR,"Failed to get resource groups: 0x%x\n",Status));
  476. KerbErr = KRB_ERR_GENERIC;
  477. goto Cleanup;
  478. }
  479. //
  480. // Now build a new pac
  481. //
  482. Status = PAC_InitAndUpdateGroups(
  483. ValidationInfo,
  484. ResourceGroups,
  485. OldPac,
  486. NewPac
  487. );
  488. if (!NT_SUCCESS(Status))
  489. {
  490. KerbErr = KRB_ERR_GENERIC;
  491. goto Cleanup;
  492. }
  493. Cleanup:
  494. if (ValidationInfo != NULL)
  495. {
  496. MIDL_user_free(ValidationInfo);
  497. }
  498. if (SidList.Sids != NULL)
  499. {
  500. for (Index = 0; Index < SidList.Count ;Index++ )
  501. {
  502. if (SidList.Sids[Index].SidPointer != NULL)
  503. {
  504. MIDL_user_free(SidList.Sids[Index].SidPointer);
  505. }
  506. }
  507. MIDL_user_free(SidList.Sids);
  508. }
  509. SamIFreeSidArray(
  510. ResourceGroups
  511. );
  512. return(KerbErr);
  513. }
  514. //+-------------------------------------------------------------------------
  515. //
  516. // Function: KdcSignPac
  517. //
  518. // Synopsis: Signs a PAC by first checksumming it with the
  519. // server's key and then signing that with the KDC key.
  520. //
  521. // Effects: Modifies the server sig & privsvr sig fields of the PAC
  522. //
  523. // Arguments: ServerInfo - Ticket info for the server, used
  524. // for the initial signature
  525. // PacData - An marshalled PAC.
  526. //
  527. // Requires:
  528. //
  529. // Returns:
  530. //
  531. // Notes:
  532. //
  533. //
  534. //--------------------------------------------------------------------------
  535. KERBERR
  536. KdcSignPac(
  537. IN PKERB_ENCRYPTION_KEY ServerKey,
  538. IN BOOLEAN AddResourceGroups,
  539. IN OUT PUCHAR * PacData,
  540. IN PULONG PacSize
  541. )
  542. {
  543. NTSTATUS Status;
  544. KERBERR KerbErr = KDC_ERR_NONE;
  545. PCHECKSUM_FUNCTION Check = NULL ;
  546. PCHECKSUM_BUFFER CheckBuffer = NULL;
  547. PPAC_INFO_BUFFER ServerBuffer;
  548. PPAC_INFO_BUFFER PrivSvrBuffer;
  549. PPAC_SIGNATURE_DATA ServerSignature;
  550. PPAC_SIGNATURE_DATA PrivSvrSignature;
  551. PKERB_ENCRYPTION_KEY EncryptionKey;
  552. PPACTYPE Pac, NewPac = NULL;
  553. ULONG LocalPacSize;
  554. KDC_TICKET_INFO KdcTicketInfo = {0};
  555. TRACE(KDC, KdcSignPac, DEB_FUNCTION);
  556. KerbErr = SecData.GetKrbtgtTicketInfo(&KdcTicketInfo);
  557. if (!KERB_SUCCESS(KerbErr))
  558. {
  559. Status = KerbMapKerbError(KerbErr);
  560. goto Cleanup;
  561. }
  562. //
  563. // Locate the checksum used to sign the PAC.
  564. //
  565. Status = CDLocateCheckSum(
  566. KDC_PAC_CHECKSUM,
  567. &Check
  568. );
  569. if (!NT_SUCCESS(Status))
  570. {
  571. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  572. goto Cleanup;
  573. }
  574. //
  575. // Unmarshal the PAC in place so we can locate the signatuer buffers
  576. //
  577. Pac = (PPACTYPE) *PacData;
  578. LocalPacSize = *PacSize;
  579. if (PAC_UnMarshal(Pac, LocalPacSize) == 0)
  580. {
  581. D_DebugLog((DEB_ERROR,"Failed to unmarshal pac\n"));
  582. KerbErr = KRB_ERR_GENERIC;
  583. goto Cleanup;
  584. }
  585. //
  586. // If we are to add local groups, do so now
  587. //
  588. if (AddResourceGroups)
  589. {
  590. KerbErr = KdcAddResourceGroupsToPac(
  591. Pac,
  592. Check->CheckSumSize,
  593. &NewPac
  594. );
  595. if (!KERB_SUCCESS(KerbErr))
  596. {
  597. goto Cleanup;
  598. }
  599. Pac = NewPac;
  600. LocalPacSize = PAC_GetSize(Pac);
  601. }
  602. //
  603. // Locate the signature buffers so the signature fields can be zeroed out
  604. // before computing the checksum.
  605. //
  606. ServerBuffer = PAC_Find(Pac, PAC_SERVER_CHECKSUM, NULL );
  607. DsysAssert(ServerBuffer != NULL);
  608. if (ServerBuffer == NULL)
  609. {
  610. KerbErr = KRB_ERR_GENERIC;
  611. goto Cleanup;
  612. }
  613. ServerSignature = (PPAC_SIGNATURE_DATA) ServerBuffer->Data;
  614. ServerSignature->SignatureType = KDC_PAC_CHECKSUM;
  615. RtlZeroMemory(
  616. ServerSignature->Signature,
  617. PAC_CHECKSUM_SIZE(ServerBuffer->cbBufferSize)
  618. );
  619. PrivSvrBuffer = PAC_Find(Pac, PAC_PRIVSVR_CHECKSUM, NULL );
  620. DsysAssert(PrivSvrBuffer != NULL);
  621. if (PrivSvrBuffer == NULL)
  622. {
  623. KerbErr = KRB_ERR_GENERIC;
  624. goto Cleanup;
  625. }
  626. PrivSvrSignature = (PPAC_SIGNATURE_DATA) PrivSvrBuffer->Data;
  627. PrivSvrSignature->SignatureType = KDC_PAC_CHECKSUM;
  628. RtlZeroMemory(
  629. PrivSvrSignature->Signature,
  630. PAC_CHECKSUM_SIZE(PrivSvrBuffer->cbBufferSize)
  631. );
  632. //
  633. // Now remarshall the PAC to compute the checksum.
  634. //
  635. if (!PAC_ReMarshal(Pac, LocalPacSize))
  636. {
  637. DsysAssert(!"PAC_Remarshal Failed");
  638. KerbErr = KRB_ERR_GENERIC;
  639. goto Cleanup;
  640. }
  641. //
  642. // Now compute the signatures on the PAC. First we compute the checksum
  643. // of the whole PAC.
  644. //
  645. if (NULL != Check->InitializeEx2)
  646. {
  647. Status = Check->InitializeEx2(
  648. ServerKey->keyvalue.value,
  649. ServerKey->keyvalue.length,
  650. NULL,
  651. KERB_NON_KERB_CKSUM_SALT,
  652. &CheckBuffer
  653. );
  654. }
  655. else
  656. {
  657. Status = Check->InitializeEx(
  658. ServerKey->keyvalue.value,
  659. ServerKey->keyvalue.length,
  660. KERB_NON_KERB_CKSUM_SALT,
  661. &CheckBuffer
  662. );
  663. }
  664. if (!NT_SUCCESS(Status))
  665. {
  666. KerbErr = KRB_ERR_GENERIC;
  667. goto Cleanup;
  668. }
  669. Check->Sum(
  670. CheckBuffer,
  671. LocalPacSize,
  672. (PUCHAR) Pac
  673. );
  674. Check->Finalize(
  675. CheckBuffer,
  676. ServerSignature->Signature
  677. );
  678. Check->Finish(
  679. &CheckBuffer
  680. );
  681. //
  682. // Now we've compute the server checksum - next compute the checksum
  683. // of the server checksum using the KDC account.
  684. //
  685. //
  686. // Get the key used to sign pacs.
  687. //
  688. EncryptionKey = KerbGetKeyFromList(
  689. KdcTicketInfo.Passwords,
  690. KDC_PAC_KEYTYPE
  691. );
  692. if (EncryptionKey == NULL)
  693. {
  694. Status = SEC_E_ETYPE_NOT_SUPP;
  695. goto Cleanup;
  696. }
  697. if (NULL != Check->InitializeEx2)
  698. {
  699. Status = Check->InitializeEx2(
  700. EncryptionKey->keyvalue.value,
  701. EncryptionKey->keyvalue.length,
  702. NULL,
  703. KERB_NON_KERB_CKSUM_SALT,
  704. &CheckBuffer
  705. );
  706. }
  707. else
  708. {
  709. Status = Check->InitializeEx(
  710. EncryptionKey->keyvalue.value,
  711. EncryptionKey->keyvalue.length,
  712. KERB_NON_KERB_CKSUM_SALT,
  713. &CheckBuffer
  714. );
  715. }
  716. if (!NT_SUCCESS(Status))
  717. {
  718. KerbErr = KRB_ERR_GENERIC;
  719. goto Cleanup;
  720. }
  721. Check->Sum(
  722. CheckBuffer,
  723. Check->CheckSumSize,
  724. ServerSignature->Signature
  725. );
  726. Check->Finalize(
  727. CheckBuffer,
  728. PrivSvrSignature->Signature
  729. );
  730. Check->Finish(
  731. &CheckBuffer
  732. );
  733. if (*PacData != (PBYTE) Pac)
  734. {
  735. MIDL_user_free(*PacData);
  736. *PacData = (PBYTE) Pac;
  737. *PacSize = LocalPacSize;
  738. }
  739. Cleanup:
  740. if ( ( CheckBuffer != NULL ) &&
  741. ( Check != NULL ) )
  742. {
  743. Check->Finish(&CheckBuffer);
  744. }
  745. if (!KERB_SUCCESS(KerbErr) && (NewPac != NULL))
  746. {
  747. MIDL_user_free(NewPac);
  748. }
  749. FreeTicketInfo(&KdcTicketInfo);
  750. return(KerbErr);
  751. }
  752. //+-------------------------------------------------------------------------
  753. //
  754. // Function: KdcVerifyPacSignature
  755. //
  756. // Synopsis: Verifies a PAC by checksumming it and comparing the result
  757. // with the server checksum. In addition, if the pac wasn't
  758. // created by another realm (server ticket info is not
  759. // an interdomain account) verify the KDC signature on the
  760. // pac.
  761. //
  762. // Effects:
  763. //
  764. // Arguments: ServerInfo - Ticket info for the server, used
  765. // for the initial signature
  766. // Pac - An unmarshalled PAC.
  767. //
  768. // Requires:
  769. //
  770. // Returns:
  771. //
  772. // Notes:
  773. //
  774. //
  775. //--------------------------------------------------------------------------
  776. KERBERR
  777. KdcVerifyPacSignature(
  778. IN PKERB_ENCRYPTION_KEY ServerKey,
  779. IN PKDC_TICKET_INFO ServerInfo,
  780. IN ULONG PacSize,
  781. IN PUCHAR PacData
  782. )
  783. {
  784. NTSTATUS Status;
  785. KERBERR KerbErr = KDC_ERR_NONE;
  786. PCHECKSUM_FUNCTION Check = NULL ;
  787. PCHECKSUM_BUFFER CheckBuffer = NULL;
  788. PKERB_ENCRYPTION_KEY EncryptionKey = NULL;
  789. PPAC_INFO_BUFFER ServerBuffer;
  790. PPAC_INFO_BUFFER PrivSvrBuffer;
  791. PPAC_SIGNATURE_DATA ServerSignature;
  792. PPAC_SIGNATURE_DATA PrivSvrSignature;
  793. PPAC_INFO_BUFFER LogonInfo;
  794. UCHAR LocalChecksum[20];
  795. UCHAR LocalServerChecksum[20];
  796. UCHAR LocalPrivSvrChecksum[20];
  797. PPACTYPE Pac;
  798. KDC_TICKET_INFO KdcTicketInfo = {0};
  799. TRACE(KDC, KdcVerifyPacSignature, DEB_FUNCTION);
  800. Pac = (PPACTYPE) PacData;
  801. if (PAC_UnMarshal(Pac, PacSize) == 0)
  802. {
  803. D_DebugLog((DEB_ERROR,"Failed to unmarshal pac\n"));
  804. KerbErr = KRB_ERR_GENERIC;
  805. goto Cleanup;
  806. }
  807. KerbErr = SecData.GetKrbtgtTicketInfo(&KdcTicketInfo);
  808. if (!KERB_SUCCESS(KerbErr))
  809. {
  810. Status = KerbMapKerbError(KerbErr);
  811. goto Cleanup;
  812. }
  813. //
  814. // Locate the two signatures, copy the checksum, and zero the value
  815. // so the checksum won't include the old checksums.
  816. //
  817. ServerBuffer = PAC_Find(Pac, PAC_SERVER_CHECKSUM, NULL );
  818. DsysAssert(ServerBuffer != NULL);
  819. if ((ServerBuffer == NULL) || (ServerBuffer->cbBufferSize < PAC_SIGNATURE_SIZE(0)))
  820. {
  821. KerbErr = KRB_ERR_GENERIC;
  822. goto Cleanup;
  823. }
  824. ServerSignature = (PPAC_SIGNATURE_DATA) ServerBuffer->Data;
  825. RtlCopyMemory(
  826. LocalServerChecksum,
  827. ServerSignature->Signature,
  828. PAC_CHECKSUM_SIZE(ServerBuffer->cbBufferSize)
  829. );
  830. RtlZeroMemory(
  831. ServerSignature->Signature,
  832. PAC_CHECKSUM_SIZE(ServerBuffer->cbBufferSize)
  833. );
  834. PrivSvrBuffer = PAC_Find(Pac, PAC_PRIVSVR_CHECKSUM, NULL );
  835. DsysAssert(PrivSvrBuffer != NULL);
  836. if ((PrivSvrBuffer == NULL) || (PrivSvrBuffer->cbBufferSize < PAC_SIGNATURE_SIZE(0)))
  837. {
  838. KerbErr = KRB_ERR_GENERIC;
  839. goto Cleanup;
  840. }
  841. PrivSvrSignature = (PPAC_SIGNATURE_DATA) PrivSvrBuffer->Data;
  842. RtlCopyMemory(
  843. LocalPrivSvrChecksum,
  844. PrivSvrSignature->Signature,
  845. PAC_CHECKSUM_SIZE(PrivSvrBuffer->cbBufferSize)
  846. );
  847. RtlZeroMemory(
  848. PrivSvrSignature->Signature,
  849. PAC_CHECKSUM_SIZE(PrivSvrBuffer->cbBufferSize)
  850. );
  851. //
  852. // Remarshal the pac so we can checksum it.
  853. //
  854. if (!PAC_ReMarshal(Pac, PacSize))
  855. {
  856. DsysAssert(!"PAC_Remarshal Failed");
  857. KerbErr = KRB_ERR_GENERIC;
  858. goto Cleanup;
  859. }
  860. //
  861. // Now compute the signatures on the PAC. First we compute the checksum
  862. // of the validation information using the server's key.
  863. //
  864. //
  865. // Locate the checksum used to sign the PAC.
  866. //
  867. Status = CDLocateCheckSum(
  868. ServerSignature->SignatureType,
  869. &Check
  870. );
  871. if (!NT_SUCCESS(Status))
  872. {
  873. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  874. goto Cleanup;
  875. }
  876. if (Check->CheckSumSize > sizeof(LocalChecksum)) {
  877. DsysAssert(Check->CheckSumSize <= sizeof(LocalChecksum));
  878. KerbErr = KRB_ERR_GENERIC;
  879. goto Cleanup;
  880. }
  881. //
  882. // if available use the Ex2 version for keyed checksums where checksum
  883. // must be passed in on verification
  884. //
  885. if (NULL != Check->InitializeEx2)
  886. {
  887. Status = Check->InitializeEx2(
  888. ServerKey->keyvalue.value,
  889. ServerKey->keyvalue.length,
  890. LocalServerChecksum,
  891. KERB_NON_KERB_CKSUM_SALT,
  892. &CheckBuffer
  893. );
  894. }
  895. else
  896. {
  897. Status = Check->InitializeEx(
  898. ServerKey->keyvalue.value,
  899. ServerKey->keyvalue.length,
  900. KERB_NON_KERB_CKSUM_SALT,
  901. &CheckBuffer
  902. );
  903. }
  904. if (!NT_SUCCESS(Status))
  905. {
  906. KerbErr = KRB_ERR_GENERIC;
  907. goto Cleanup;
  908. }
  909. Check->Sum(
  910. CheckBuffer,
  911. PacSize,
  912. PacData
  913. );
  914. Check->Finalize(
  915. CheckBuffer,
  916. LocalChecksum
  917. );
  918. Check->Finish(
  919. &CheckBuffer
  920. );
  921. if (Check->CheckSumSize != PAC_CHECKSUM_SIZE(ServerBuffer->cbBufferSize) ||
  922. !RtlEqualMemory(
  923. LocalChecksum,
  924. LocalServerChecksum,
  925. Check->CheckSumSize))
  926. {
  927. DebugLog((DEB_ERROR, "Pac was modified - server checksum doesn't match\n"));
  928. KerbErr = KRB_AP_ERR_MODIFIED;
  929. goto Cleanup;
  930. }
  931. //
  932. // If the service wasn't the KDC and it wasn't an interdomain account
  933. // verify the KDC checksum.
  934. //
  935. if ((ServerInfo->UserId == DOMAIN_USER_RID_KRBTGT) ||
  936. ((ServerInfo->UserAccountControl & USER_INTERDOMAIN_TRUST_ACCOUNT) != 0))
  937. {
  938. goto Cleanup;
  939. }
  940. //
  941. // Get the key used to sign pacs.
  942. //
  943. EncryptionKey = KerbGetKeyFromList(
  944. KdcTicketInfo.Passwords,
  945. KDC_PAC_KEYTYPE
  946. );
  947. if (EncryptionKey == NULL)
  948. {
  949. Status = SEC_E_ETYPE_NOT_SUPP;
  950. goto Cleanup;
  951. }
  952. //
  953. // Locate the checksum used to sign the PAC.
  954. //
  955. Status = CDLocateCheckSum(
  956. PrivSvrSignature->SignatureType,
  957. &Check
  958. );
  959. if (!NT_SUCCESS(Status))
  960. {
  961. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  962. goto Cleanup;
  963. }
  964. //
  965. // if available use the Ex2 version for keyed checksums where checksum
  966. // must be passed in on verification
  967. //
  968. if (NULL != Check->InitializeEx2)
  969. {
  970. Status = Check->InitializeEx2(
  971. EncryptionKey->keyvalue.value,
  972. EncryptionKey->keyvalue.length,
  973. LocalPrivSvrChecksum,
  974. KERB_NON_KERB_CKSUM_SALT,
  975. &CheckBuffer
  976. );
  977. }
  978. else
  979. {
  980. Status = Check->InitializeEx(
  981. EncryptionKey->keyvalue.value,
  982. EncryptionKey->keyvalue.length,
  983. KERB_NON_KERB_CKSUM_SALT,
  984. &CheckBuffer
  985. );
  986. }
  987. if (!NT_SUCCESS(Status))
  988. {
  989. KerbErr = KRB_ERR_GENERIC;
  990. goto Cleanup;
  991. }
  992. Check->Sum(
  993. CheckBuffer,
  994. Check->CheckSumSize,
  995. ServerSignature->Signature
  996. );
  997. Check->Finalize(
  998. CheckBuffer,
  999. LocalChecksum
  1000. );
  1001. Check->Finish(
  1002. &CheckBuffer
  1003. );
  1004. if ((Check->CheckSumSize != PAC_CHECKSUM_SIZE(PrivSvrBuffer->cbBufferSize)) ||
  1005. !RtlEqualMemory(
  1006. LocalChecksum,
  1007. LocalPrivSvrChecksum,
  1008. Check->CheckSumSize))
  1009. {
  1010. DebugLog((DEB_ERROR, "Pac was modified - privsvr checksum doesn't match\n"));
  1011. KerbErr = KRB_AP_ERR_MODIFIED;
  1012. goto Cleanup;
  1013. }
  1014. Cleanup:
  1015. if (KerbErr == KRB_AP_ERR_MODIFIED)
  1016. {
  1017. LPWSTR AccountName = NULL;
  1018. AccountName = (LPWSTR) MIDL_user_allocate(ServerInfo->AccountName.Length + sizeof(WCHAR));
  1019. //
  1020. // if the allocation fails don't log the name (leave it NULL)
  1021. //
  1022. if (NULL != AccountName)
  1023. {
  1024. RtlCopyMemory(
  1025. AccountName,
  1026. ServerInfo->AccountName.Buffer,
  1027. ServerInfo->AccountName.Length
  1028. );
  1029. }
  1030. ReportServiceEvent(
  1031. EVENTLOG_ERROR_TYPE,
  1032. KDCEVENT_PAC_VERIFICATION_FAILURE,
  1033. sizeof(ULONG),
  1034. &KerbErr,
  1035. 1,
  1036. AccountName
  1037. );
  1038. if (NULL != AccountName)
  1039. {
  1040. MIDL_user_free(AccountName);
  1041. }
  1042. }
  1043. if ( ( CheckBuffer != NULL ) &&
  1044. ( Check != NULL ) )
  1045. {
  1046. Check->Finish(&CheckBuffer);
  1047. }
  1048. FreeTicketInfo(&KdcTicketInfo);
  1049. return(KerbErr);
  1050. }
  1051. //+---------------------------------------------------------------------------
  1052. //
  1053. // Name: KdcGetPacAuthData
  1054. //
  1055. // Synopsis: Creates a PAC for the specified client, encrypts it with the
  1056. // server's key, and packs it into a KERB_AUTHORIZATON_DATA
  1057. //
  1058. // Arguments: UserInfo - Information about user
  1059. // GroupMembership - Users group memberships
  1060. // ServerKey - Key of server, used for signing
  1061. // CredentialKey - if present & valid, used to encrypt supp. creds
  1062. // AddResourceGroups - if TRUE, resources groups will be included
  1063. // EncryptedTicket - Optional ticke to tie PAC to
  1064. // PacAuthData - Receives a KERB_AUTHORIZATION_DATA of type
  1065. // KERB_AUTH_DATA_PAC, containing a PAC.
  1066. //
  1067. // Notes: PacAuthData should be freed with KerbFreeAuthorizationData.
  1068. //
  1069. //+---------------------------------------------------------------------------
  1070. KERBERR
  1071. KdcGetPacAuthData(
  1072. IN PUSER_INTERNAL6_INFORMATION UserInfo,
  1073. IN PSID_AND_ATTRIBUTES_LIST GroupMembership,
  1074. IN PKERB_ENCRYPTION_KEY ServerKey,
  1075. IN PKERB_ENCRYPTION_KEY CredentialKey,
  1076. IN BOOLEAN AddResourceGroups,
  1077. IN PKERB_ENCRYPTED_TICKET EncryptedTicket,
  1078. IN OPTIONAL PKERB_INTERNAL_NAME S4UClientName,
  1079. OUT PKERB_AUTHORIZATION_DATA * PacAuthData,
  1080. OUT PKERB_EXT_ERROR pExtendedError
  1081. )
  1082. {
  1083. KERBERR KerbErr = KDC_ERR_NONE;
  1084. PACTYPE *pNewPac = NULL;
  1085. KERB_AUTHORIZATION_DATA AuthorizationData = {0};
  1086. ULONG PacSize, NameType;
  1087. PCHECKSUM_FUNCTION Check;
  1088. NTSTATUS Status;
  1089. UNICODE_STRING ClientName = {0};
  1090. PKERB_INTERNAL_NAME KdcName = NULL;
  1091. TimeStamp ClientId;
  1092. TRACE(KDC, KdcGetPacAuthData, DEB_FUNCTION);
  1093. Status = CDLocateCheckSum(
  1094. KDC_PAC_CHECKSUM,
  1095. &Check
  1096. );
  1097. if (!NT_SUCCESS(Status))
  1098. {
  1099. KerbErr = KDC_ERR_ETYPE_NOTSUPP;
  1100. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1101. goto Cleanup;
  1102. }
  1103. KerbConvertGeneralizedTimeToLargeInt(
  1104. &ClientId,
  1105. &EncryptedTicket->authtime,
  1106. 0 // no usec
  1107. );
  1108. //
  1109. // Put the S4U client in the pac verifier.
  1110. //
  1111. if (ARGUMENT_PRESENT(S4UClientName))
  1112. {
  1113. KerbErr = KerbConvertKdcNameToString(
  1114. &ClientName,
  1115. S4UClientName,
  1116. NULL
  1117. );
  1118. }
  1119. else // use the ticket
  1120. {
  1121. KerbErr = KerbConvertPrincipalNameToString(
  1122. &ClientName,
  1123. &NameType,
  1124. &EncryptedTicket->client_name
  1125. );
  1126. }
  1127. if (!KERB_SUCCESS(KerbErr))
  1128. {
  1129. goto Cleanup;
  1130. }
  1131. KerbErr = GetPacAndSuppCred(
  1132. UserInfo,
  1133. GroupMembership,
  1134. Check->CheckSumSize, // leave space for signature
  1135. CredentialKey,
  1136. &ClientId,
  1137. &ClientName,
  1138. &pNewPac,
  1139. pExtendedError
  1140. );
  1141. if (!KERB_SUCCESS(KerbErr))
  1142. {
  1143. D_DebugLog(( DEB_WARN,
  1144. "GetPAC: Can't get PAC or supp creds: 0x%x \n", KerbErr ));
  1145. goto Cleanup;
  1146. }
  1147. //
  1148. // The PAC is going to be double-encrypted. This is done by having the
  1149. // PAC in an EncryptedData, and having that EncryptedData in a AuthData
  1150. // as part of an AuthDataList (along with the rest of the supp creds).
  1151. // Finally, the entire list is encrypted.
  1152. //
  1153. // KERB_AUTHORIZATION_DATA containing {
  1154. // PAC
  1155. //
  1156. // }
  1157. //
  1158. //
  1159. // First build inner encrypted data
  1160. //
  1161. PacSize = PAC_GetSize( pNewPac );
  1162. AuthorizationData.value.auth_data_type = KERB_AUTH_DATA_PAC;
  1163. AuthorizationData.value.auth_data.length = PacSize;
  1164. AuthorizationData.value.auth_data.value = (PUCHAR) MIDL_user_allocate(PacSize);
  1165. if (AuthorizationData.value.auth_data.value == NULL)
  1166. {
  1167. KerbErr = KRB_ERR_GENERIC;
  1168. goto Cleanup;
  1169. }
  1170. PAC_Marshal( pNewPac, PacSize, AuthorizationData.value.auth_data.value );
  1171. //
  1172. // Compute the signatures
  1173. //
  1174. KerbErr = KdcSignPac(
  1175. ServerKey,
  1176. AddResourceGroups,
  1177. &AuthorizationData.value.auth_data.value,
  1178. (PULONG) &AuthorizationData.value.auth_data.length
  1179. );
  1180. if (!KERB_SUCCESS(KerbErr))
  1181. {
  1182. goto Cleanup;
  1183. }
  1184. //
  1185. // Create the auth data to return
  1186. //
  1187. KerbErr = KdcInsertPacIntoAuthData(
  1188. NULL, // no original auth data
  1189. NULL, // no if-relevant auth data
  1190. &AuthorizationData,
  1191. PacAuthData
  1192. );
  1193. if (!KERB_SUCCESS(KerbErr))
  1194. {
  1195. DebugLog((DEB_ERROR,"Failed to insert pac into new auth data: 0x%x\n",
  1196. KerbErr));
  1197. goto Cleanup;
  1198. }
  1199. Cleanup:
  1200. if (AuthorizationData.value.auth_data.value != NULL)
  1201. {
  1202. MIDL_user_free(AuthorizationData.value.auth_data.value);
  1203. }
  1204. if (pNewPac != NULL)
  1205. {
  1206. MIDL_user_free(pNewPac);
  1207. }
  1208. KerbFreeString(&ClientName);
  1209. KerbFreeKdcName(&KdcName);
  1210. return(KerbErr);
  1211. }
  1212. //+-------------------------------------------------------------------------
  1213. //
  1214. // Function: KdcGetUserPac
  1215. //
  1216. // Synopsis: Function for external users to get the PAC for a user
  1217. //
  1218. //
  1219. // Effects:
  1220. //
  1221. // Arguments:
  1222. //
  1223. // Requires:
  1224. //
  1225. // Returns:
  1226. //
  1227. // Notes:
  1228. //
  1229. //
  1230. //--------------------------------------------------------------------------
  1231. extern "C"
  1232. NTSTATUS
  1233. KdcGetUserPac(
  1234. IN PUNICODE_STRING UserName,
  1235. OUT PPACTYPE * Pac,
  1236. OUT PUCHAR * SupplementalCredentials,
  1237. OUT PULONG SupplementalCredSize,
  1238. OUT PKERB_EXT_ERROR pExtendedError
  1239. )
  1240. {
  1241. KDC_TICKET_INFO TicketInfo;
  1242. PUSER_INTERNAL6_INFORMATION UserInfo = NULL;
  1243. SID_AND_ATTRIBUTES_LIST GroupMembership;
  1244. NTSTATUS Status;
  1245. KERBERR KerbErr;
  1246. TRACE(KDC, KdcGetUserPac, DEB_FUNCTION);
  1247. *SupplementalCredentials = NULL;
  1248. *SupplementalCredSize = 0;
  1249. RtlZeroMemory(
  1250. &TicketInfo,
  1251. sizeof(KDC_TICKET_INFO)
  1252. );
  1253. RtlZeroMemory(
  1254. &GroupMembership,
  1255. sizeof(SID_AND_ATTRIBUTES_LIST)
  1256. );
  1257. Status = EnterApiCall();
  1258. if (!NT_SUCCESS(Status))
  1259. {
  1260. return(Status);
  1261. }
  1262. //
  1263. // Get the account information
  1264. //
  1265. KerbErr = KdcGetTicketInfo(
  1266. UserName,
  1267. 0, // no flags
  1268. NULL, // no principal name
  1269. NULL, // no realm
  1270. &TicketInfo,
  1271. pExtendedError,
  1272. NULL, // no user handle
  1273. USER_ALL_GET_PAC_AND_SUPP_CRED,
  1274. 0L, // no extended fields
  1275. &UserInfo,
  1276. &GroupMembership
  1277. );
  1278. if (!KERB_SUCCESS(KerbErr))
  1279. {
  1280. DebugLog((DEB_WARN,"Failed to get ticket info for user %wZ: 0x%x\n",
  1281. UserName->Buffer, KerbErr));
  1282. Status = KerbMapKerbError(KerbErr);
  1283. goto Cleanup;
  1284. }
  1285. //
  1286. // Now get the PAC and supplemental credentials
  1287. //
  1288. KerbErr = GetPacAndSuppCred(
  1289. UserInfo,
  1290. &GroupMembership,
  1291. 0, // no signature space
  1292. NULL, // no credential key
  1293. NULL, // no client ID
  1294. NULL, // no client name
  1295. Pac,
  1296. pExtendedError
  1297. );
  1298. if (!KERB_SUCCESS(KerbErr))
  1299. {
  1300. DebugLog((DEB_ERROR,"Failed to get PAC for user %wZ : 0x%x\n",
  1301. UserName->Buffer,KerbErr));
  1302. Status = KerbMapKerbError(KerbErr);
  1303. goto Cleanup;
  1304. }
  1305. Cleanup:
  1306. SamIFree_UserInternal6Information( UserInfo );
  1307. SamIFreeSidAndAttributesList(&GroupMembership);
  1308. FreeTicketInfo(&TicketInfo);
  1309. LeaveApiCall();
  1310. return Status;
  1311. }
  1312. //+-------------------------------------------------------------------------
  1313. //
  1314. // Function: KdcVerifyPac
  1315. //
  1316. // Synopsis: Function for kerberos to pass through a pac signature
  1317. // to be verified.
  1318. //
  1319. //
  1320. // Effects:
  1321. //
  1322. // Arguments:
  1323. //
  1324. // Requires:
  1325. //
  1326. // Returns:
  1327. //
  1328. // Notes:
  1329. //
  1330. //
  1331. //--------------------------------------------------------------------------
  1332. extern "C"
  1333. NTSTATUS
  1334. KdcVerifyPac(
  1335. IN ULONG ChecksumSize,
  1336. IN PUCHAR Checksum,
  1337. IN ULONG SignatureType,
  1338. IN ULONG SignatureSize,
  1339. IN PUCHAR Signature
  1340. )
  1341. {
  1342. NTSTATUS Status;
  1343. KERBERR KerbErr;
  1344. PCHECKSUM_FUNCTION Check;
  1345. PCHECKSUM_BUFFER CheckBuffer = NULL;
  1346. UCHAR LocalChecksum[20];
  1347. PKERB_ENCRYPTION_KEY EncryptionKey = NULL;
  1348. KDC_TICKET_INFO KdcTicketInfo = {0};
  1349. TRACE(KDC, KdcVerifyPac, DEB_FUNCTION);
  1350. Status = EnterApiCall();
  1351. if (!NT_SUCCESS(Status))
  1352. {
  1353. return(Status);
  1354. }
  1355. KerbErr = SecData.GetKrbtgtTicketInfo(&KdcTicketInfo);
  1356. if (!KERB_SUCCESS(KerbErr))
  1357. {
  1358. Status = KerbMapKerbError(KerbErr);
  1359. goto Cleanup;
  1360. }
  1361. //
  1362. // Get the key used to sign pacs.
  1363. //
  1364. EncryptionKey = KerbGetKeyFromList(
  1365. KdcTicketInfo.Passwords,
  1366. KDC_PAC_KEYTYPE
  1367. );
  1368. if (EncryptionKey == NULL)
  1369. {
  1370. Status = SEC_E_ETYPE_NOT_SUPP;
  1371. goto Cleanup;
  1372. }
  1373. Status = CDLocateCheckSum(
  1374. SignatureType,
  1375. &Check
  1376. );
  1377. if (!NT_SUCCESS(Status))
  1378. {
  1379. goto Cleanup;
  1380. }
  1381. if (Check->CheckSumSize > sizeof(LocalChecksum)) {
  1382. DsysAssert(Check->CheckSumSize <= sizeof(LocalChecksum));
  1383. Status = STATUS_INVALID_PARAMETER;
  1384. goto Cleanup;
  1385. }
  1386. //
  1387. // if available use the Ex2 version for keyed checksums where checksum
  1388. // must be passed in on verification
  1389. //
  1390. if (NULL != Check->InitializeEx2)
  1391. {
  1392. Status = Check->InitializeEx2(
  1393. EncryptionKey->keyvalue.value,
  1394. EncryptionKey->keyvalue.length,
  1395. Signature,
  1396. KERB_NON_KERB_CKSUM_SALT,
  1397. &CheckBuffer
  1398. );
  1399. }
  1400. else
  1401. {
  1402. Status = Check->InitializeEx(
  1403. EncryptionKey->keyvalue.value,
  1404. EncryptionKey->keyvalue.length,
  1405. KERB_NON_KERB_CKSUM_SALT,
  1406. &CheckBuffer
  1407. );
  1408. }
  1409. if (!NT_SUCCESS(Status))
  1410. {
  1411. goto Cleanup;
  1412. }
  1413. Check->Sum(
  1414. CheckBuffer,
  1415. ChecksumSize,
  1416. Checksum
  1417. );
  1418. Check->Finalize(
  1419. CheckBuffer,
  1420. LocalChecksum
  1421. );
  1422. Check->Finish(&CheckBuffer);
  1423. //
  1424. // Now compare the local checksum to the supplied checksum.
  1425. //
  1426. if (Check->CheckSumSize != SignatureSize)
  1427. {
  1428. Status = STATUS_LOGON_FAILURE;
  1429. goto Cleanup;
  1430. }
  1431. if (!RtlEqualMemory(
  1432. LocalChecksum,
  1433. Signature,
  1434. Check->CheckSumSize
  1435. ))
  1436. {
  1437. DebugLog((DEB_ERROR,"Checksum on the PAC does not match!\n"));
  1438. Status = STATUS_LOGON_FAILURE;
  1439. goto Cleanup;
  1440. }
  1441. Cleanup:
  1442. if (Status == STATUS_LOGON_FAILURE)
  1443. {
  1444. PUNICODE_STRING OwnName = NULL;
  1445. //
  1446. // since this call should only be made by pass through callback
  1447. // this signature should be our own
  1448. //
  1449. OwnName = SecData.KdcFullServiceDnsName();
  1450. ReportServiceEvent(
  1451. EVENTLOG_ERROR_TYPE,
  1452. KDCEVENT_PAC_VERIFICATION_FAILURE,
  1453. 0,
  1454. NULL,
  1455. 1, // number of strings
  1456. OwnName->Buffer
  1457. );
  1458. }
  1459. FreeTicketInfo(&KdcTicketInfo);
  1460. LeaveApiCall();
  1461. return(Status);
  1462. }
  1463. //+-------------------------------------------------------------------------
  1464. //
  1465. // Function: KdcCheckPacForSidFiltering
  1466. //
  1467. // Synopsis: If the server ticket info has a TDOSid then the function
  1468. // makes a check to make sure the SID from the TDO matches
  1469. // the client's home domain SID. A call to LsaIFilterSids
  1470. // is made to do the check. If this function fails with
  1471. // STATUS_TRUST_FAILURE then an audit log is generated.
  1472. // Otherwise the function succeeds but SIDs are filtered
  1473. // from the PAC.
  1474. //
  1475. // Effects:
  1476. //
  1477. // Arguments:
  1478. //
  1479. // Requires:
  1480. //
  1481. // Returns:
  1482. //
  1483. // Notes:
  1484. //
  1485. //
  1486. //--------------------------------------------------------------------------
  1487. KERBERR
  1488. KdcCheckPacForSidFiltering(
  1489. IN PKDC_TICKET_INFO ServerInfo,
  1490. IN OUT PUCHAR *PacData,
  1491. IN OUT PULONG PacSize
  1492. )
  1493. {
  1494. NTSTATUS Status;
  1495. KERBERR KerbErr = KDC_ERR_NONE;
  1496. PPAC_INFO_BUFFER LogonInfo;
  1497. PPACTYPE OldPac;
  1498. ULONG OldPacSize;
  1499. PPACTYPE NewPac = NULL;
  1500. ULONG LocalPacSize;
  1501. PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo = NULL;
  1502. SAMPR_PSID_ARRAY ZeroResourceGroups;
  1503. PUNICODE_STRING TrustedForest = NULL;
  1504. if (NULL != ServerInfo->TrustSid)
  1505. {
  1506. OldPac = (PPACTYPE) *PacData;
  1507. OldPacSize = *PacSize;
  1508. if (PAC_UnMarshal(OldPac, OldPacSize) == 0)
  1509. {
  1510. D_DebugLog((DEB_ERROR,"Failed to unmarshal pac\n"));
  1511. KerbErr = KRB_ERR_GENERIC;
  1512. goto Cleanup;
  1513. }
  1514. RtlZeroMemory(
  1515. &ZeroResourceGroups,
  1516. sizeof(ZeroResourceGroups)); // allows us to use PAC_InitAndUpdateGroups to remarshal the PAC
  1517. //
  1518. // First, find the logon information
  1519. //
  1520. LogonInfo = PAC_Find(
  1521. OldPac,
  1522. PAC_LOGON_INFO,
  1523. NULL
  1524. );
  1525. if (LogonInfo == NULL)
  1526. {
  1527. D_DebugLog((DEB_WARN,"No logon info for PAC - not making SID filtering check\n"));
  1528. goto Cleanup;
  1529. }
  1530. //
  1531. // Now unmarshall the validation information and build a list of sids
  1532. //
  1533. if (!NT_SUCCESS(PAC_UnmarshallValidationInfo(
  1534. &ValidationInfo,
  1535. LogonInfo->Data,
  1536. LogonInfo->cbBufferSize)))
  1537. {
  1538. D_DebugLog((DEB_ERROR,"Failed to unmarshall validation info!\n"));
  1539. KerbErr = KRB_ERR_GENERIC;
  1540. goto Cleanup;
  1541. }
  1542. //
  1543. // Assumption is that if the Trust SID is in the ServerInfo then this is an
  1544. // outbound trust with the TRUST_ATTRIBUTE_FILTER_SIDS bit set.
  1545. //
  1546. if ((ServerInfo->TrustAttributes & TRUST_ATTRIBUTE_FOREST_TRANSITIVE) != 0)
  1547. {
  1548. TrustedForest = &(ServerInfo->TrustedForest);
  1549. DebugLog((DEB_TRACE, "Filtering Sids for forest %wZ\n", TrustedForest));
  1550. }
  1551. Status = LsaIFilterSids(
  1552. TrustedForest, // Pass domain name here
  1553. TRUST_DIRECTION_OUTBOUND,
  1554. TRUST_TYPE_UPLEVEL,
  1555. ServerInfo->TrustAttributes,
  1556. ServerInfo->TrustSid,
  1557. NetlogonValidationSamInfo2,
  1558. ValidationInfo
  1559. );
  1560. if (!NT_SUCCESS(Status))
  1561. {
  1562. //
  1563. // Create an audit log if it looks like the SID has been tampered with
  1564. //
  1565. if ((STATUS_DOMAIN_TRUST_INCONSISTENT == Status) &&
  1566. SecData.AuditKdcEvent(KDC_AUDIT_TGS_FAILURE))
  1567. {
  1568. DWORD Dummy = 0;
  1569. KdcLsaIAuditKdcEvent(
  1570. SE_AUDITID_TGS_TICKET_REQUEST,
  1571. &ValidationInfo->EffectiveName,
  1572. &ValidationInfo->LogonDomainName,
  1573. NULL,
  1574. &ServerInfo->AccountName,
  1575. NULL,
  1576. &Dummy,
  1577. (PULONG) &Status,
  1578. NULL,
  1579. NULL, // no preauth type
  1580. GET_CLIENT_ADDRESS(NULL),
  1581. NULL // no logon guid
  1582. );
  1583. }
  1584. DebugLog((DEB_ERROR,"Failed to filter SIDS (LsaIFilterSids): 0x%x\n",Status));
  1585. KerbErr = KRB_ERR_GENERIC;
  1586. goto Cleanup;
  1587. }
  1588. //
  1589. // Now build a new pac
  1590. //
  1591. Status = PAC_InitAndUpdateGroups(
  1592. ValidationInfo,
  1593. &ZeroResourceGroups,
  1594. OldPac,
  1595. &NewPac
  1596. );
  1597. if (!NT_SUCCESS(Status))
  1598. {
  1599. KerbErr = KRB_ERR_GENERIC;
  1600. goto Cleanup;
  1601. }
  1602. LocalPacSize = PAC_GetSize(NewPac);
  1603. if (!PAC_ReMarshal(NewPac, LocalPacSize))
  1604. {
  1605. DsysAssert(!"PAC_Remarshal Failed");
  1606. KerbErr = KRB_ERR_GENERIC;
  1607. goto Cleanup;
  1608. }
  1609. if (*PacData != (PBYTE)NewPac)
  1610. {
  1611. MIDL_user_free(*PacData);
  1612. *PacData = (PBYTE) NewPac;
  1613. NewPac = NULL;
  1614. *PacSize = LocalPacSize;
  1615. }
  1616. }
  1617. Cleanup:
  1618. if (NewPac != NULL)
  1619. {
  1620. MIDL_user_free(NewPac);
  1621. }
  1622. if (ValidationInfo != NULL)
  1623. {
  1624. MIDL_user_free(ValidationInfo);
  1625. }
  1626. return(KerbErr);
  1627. }
  1628. //+-------------------------------------------------------------------------
  1629. //
  1630. // Function: KdcVerifyAndResignPac
  1631. //
  1632. // Synopsis: Verifies the signature on a PAC and re-signs it with the
  1633. // new servers & kdc's key
  1634. //
  1635. // Effects:
  1636. //
  1637. // Arguments:
  1638. //
  1639. // Requires:
  1640. //
  1641. // Returns:
  1642. //
  1643. // Notes:
  1644. //
  1645. //
  1646. //--------------------------------------------------------------------------
  1647. KERBERR
  1648. KdcVerifyAndResignPac(
  1649. IN PKERB_ENCRYPTION_KEY OldKey,
  1650. IN PKERB_ENCRYPTION_KEY NewKey,
  1651. IN PKDC_TICKET_INFO OldServerInfo,
  1652. IN BOOLEAN AddResourceGroups,
  1653. IN OUT PKERB_AUTHORIZATION_DATA PacAuthData
  1654. )
  1655. {
  1656. PPAC_SIGNATURE_DATA ServerSignature;
  1657. ULONG ServerSiganatureSize;
  1658. PPAC_SIGNATURE_DATA PrivSvrSignature;
  1659. ULONG PrivSvrSiganatureSize;
  1660. KERBERR KerbErr = KDC_ERR_NONE;
  1661. TRACE(KDC, KdcVerifyAndResignPac, DEB_FUNCTION);
  1662. //
  1663. // Now verify the existing signature
  1664. //
  1665. KerbErr = KdcVerifyPacSignature(
  1666. OldKey,
  1667. OldServerInfo,
  1668. PacAuthData->value.auth_data.length,
  1669. PacAuthData->value.auth_data.value
  1670. );
  1671. if (!KERB_SUCCESS(KerbErr))
  1672. {
  1673. goto Cleanup;
  1674. }
  1675. //
  1676. // Perform SID filtering if necessary
  1677. //
  1678. KerbErr = KdcCheckPacForSidFiltering(
  1679. OldServerInfo,
  1680. &PacAuthData->value.auth_data.value,
  1681. (PULONG) &PacAuthData->value.auth_data.length
  1682. );
  1683. if (!KERB_SUCCESS(KerbErr))
  1684. {
  1685. goto Cleanup;
  1686. }
  1687. //
  1688. // Now resign the PAC. If we add new sig algs, then we may need to
  1689. // address growing sigs, but for now, its all KDC_PAC_CHECKSUM
  1690. //
  1691. KerbErr = KdcSignPac(
  1692. NewKey,
  1693. AddResourceGroups,
  1694. &PacAuthData->value.auth_data.value,
  1695. (PULONG) &PacAuthData->value.auth_data.length
  1696. );
  1697. if (!KERB_SUCCESS(KerbErr))
  1698. {
  1699. goto Cleanup;
  1700. }
  1701. Cleanup:
  1702. return(KerbErr);
  1703. }