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.

4236 lines
112 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. #include <sddl.h>
  17. #include <utils.hxx>
  18. #define FILENO FILENO_GETAS
  19. SECURITY_DESCRIPTOR AuthenticationSD;
  20. #ifndef DONT_SUPPORT_OLD_TYPES
  21. #define KDC_PAC_KEYTYPE KERB_ETYPE_RC4_HMAC_OLD
  22. #define KDC_PAC_CHECKSUM KERB_CHECKSUM_HMAC_MD5
  23. #else
  24. #define KDC_PAC_KEYTYPE KERB_ETYPE_RC4_HMAC
  25. #define KDC_PAC_CHECKSUM KERB_CHECKSUM_HMAC_MD5
  26. #endif
  27. //+-------------------------------------------------------------------------
  28. //
  29. // Function: EnterApiCall
  30. //
  31. // Synopsis: Makes sure that the KDC service is initialized and running
  32. // and won't terminate during the call.
  33. //
  34. // Effects: increments the CurrentApiCallers count.
  35. //
  36. // Arguments:
  37. //
  38. // Requires:
  39. //
  40. // Returns: STATUS_INVALID_SERVER_STATE - the KDC service is not
  41. // running
  42. //
  43. // Notes:
  44. //
  45. //
  46. //--------------------------------------------------------------------------
  47. NTSTATUS
  48. EnterApiCall(
  49. VOID
  50. )
  51. {
  52. NTSTATUS hrRet = STATUS_SUCCESS;
  53. EnterCriticalSection(&ApiCriticalSection);
  54. if (KdcState != Stopped)
  55. {
  56. CurrentApiCallers++;
  57. }
  58. else
  59. {
  60. hrRet = STATUS_INVALID_SERVER_STATE;
  61. }
  62. LeaveCriticalSection(&ApiCriticalSection);
  63. return(hrRet);
  64. }
  65. //+-------------------------------------------------------------------------
  66. //
  67. // Function: LeaveApiCall
  68. //
  69. // Synopsis: Decrements the count of active calls and if the KDC is
  70. // shutting down sets an event to let it continue.
  71. //
  72. // Effects: Deccrements the CurrentApiCallers count.
  73. //
  74. // Arguments:
  75. //
  76. // Requires:
  77. //
  78. // Returns: Nothing
  79. //
  80. // Notes:
  81. //
  82. //
  83. //--------------------------------------------------------------------------
  84. VOID
  85. LeaveApiCall(
  86. VOID
  87. )
  88. {
  89. EnterCriticalSection(&ApiCriticalSection);
  90. CurrentApiCallers--;
  91. if (KdcState == Stopped)
  92. {
  93. if (CurrentApiCallers == 0)
  94. {
  95. if (!SetEvent(hKdcShutdownEvent))
  96. {
  97. D_DebugLog((DEB_ERROR,"Failed to set shutdown event from LeaveApiCall: 0x%d\n",GetLastError()));
  98. }
  99. else
  100. {
  101. UpdateStatus(SERVICE_STOP_PENDING);
  102. }
  103. //
  104. // Free any DS libraries in use
  105. //
  106. SecData.Cleanup();
  107. if (KdcTraceRegistrationHandle != (TRACEHANDLE)0)
  108. {
  109. UnregisterTraceGuids( KdcTraceRegistrationHandle );
  110. KdcTraceRegistrationHandle = (TRACEHANDLE)0;
  111. }
  112. }
  113. }
  114. LeaveCriticalSection(&ApiCriticalSection);
  115. }
  116. //+-------------------------------------------------------------------------
  117. //
  118. // Function: KdcInsertPacIntoAuthData
  119. //
  120. // Synopsis: Inserts the PAC into the auth data in the two places
  121. // it lives - in the IF_RELEVANT portion & in the outer body
  122. //
  123. // Effects:
  124. //
  125. // Arguments:
  126. //
  127. // Requires:
  128. //
  129. // Returns:
  130. //
  131. // Notes:
  132. //
  133. //
  134. //--------------------------------------------------------------------------
  135. KERBERR
  136. KdcInsertPacIntoAuthData(
  137. IN PKERB_AUTHORIZATION_DATA AuthData,
  138. IN PKERB_IF_RELEVANT_AUTH_DATA IfRelevantData,
  139. IN PKERB_AUTHORIZATION_DATA PacAuthData,
  140. OUT PKERB_AUTHORIZATION_DATA * UpdatedAuthData
  141. )
  142. {
  143. KERBERR KerbErr = KDC_ERR_NONE;
  144. PKERB_AUTHORIZATION_DATA LocalAuthData = NULL;
  145. PKERB_AUTHORIZATION_DATA LocalIfRelevantData = NULL;
  146. PKERB_AUTHORIZATION_DATA NewIfRelevantData = NULL;
  147. PKERB_AUTHORIZATION_DATA NewPacData = NULL;
  148. KERB_AUTHORIZATION_DATA TempPacData = {0};
  149. PKERB_AUTHORIZATION_DATA NewAuthData = NULL;
  150. KERB_AUTHORIZATION_DATA TempOldPac = {0};
  151. PKERB_AUTHORIZATION_DATA TempNextPointer,NextPointer;
  152. NewPacData = (PKERB_AUTHORIZATION_DATA) MIDL_user_allocate(sizeof(KERB_AUTHORIZATION_DATA));
  153. NewIfRelevantData = (PKERB_AUTHORIZATION_DATA) MIDL_user_allocate(sizeof(KERB_AUTHORIZATION_DATA));
  154. if ((NewPacData == NULL) || (NewIfRelevantData == NULL))
  155. {
  156. KerbErr = KRB_ERR_GENERIC;
  157. goto Cleanup;
  158. }
  159. RtlZeroMemory(
  160. NewPacData,
  161. sizeof(KERB_AUTHORIZATION_DATA)
  162. );
  163. RtlZeroMemory(
  164. NewIfRelevantData,
  165. sizeof(KERB_AUTHORIZATION_DATA)
  166. );
  167. //
  168. // First build the IfRelevantData
  169. //
  170. // The general idea is to replace, in line, the relevant authorization
  171. // data. This means (a) putting it into the IfRelevantData or making
  172. // the IfRelevantData be PacAuthData, and (b) putting it into AuthData
  173. // as well as changing the IfRelevant portions of that data
  174. //
  175. if (IfRelevantData != NULL)
  176. {
  177. LocalAuthData = KerbFindAuthDataEntry(
  178. KERB_AUTH_DATA_PAC,
  179. IfRelevantData
  180. );
  181. if (LocalAuthData == NULL)
  182. {
  183. LocalIfRelevantData = PacAuthData;
  184. PacAuthData->next = IfRelevantData;
  185. }
  186. else
  187. {
  188. //
  189. // Replace the pac in the if-relevant list with the
  190. // new one.
  191. //
  192. TempOldPac = *LocalAuthData;
  193. LocalAuthData->value.auth_data.value = PacAuthData->value.auth_data.value;
  194. LocalAuthData->value.auth_data.length = PacAuthData->value.auth_data.length;
  195. LocalIfRelevantData = IfRelevantData;
  196. }
  197. }
  198. else
  199. {
  200. //
  201. // build a new if-relevant data
  202. //
  203. TempPacData = *PacAuthData;
  204. TempPacData.next = NULL;
  205. LocalIfRelevantData = &TempPacData;
  206. }
  207. //
  208. // Build a local if-relevant auth data
  209. //
  210. KerbErr = KerbPackData(
  211. &LocalIfRelevantData,
  212. PKERB_IF_RELEVANT_AUTH_DATA_PDU,
  213. (PULONG) &NewIfRelevantData->value.auth_data.length,
  214. &NewIfRelevantData->value.auth_data.value
  215. );
  216. //
  217. // fixup the old if-relevant list, if necessary
  218. //
  219. if (TempOldPac.value.auth_data.value != NULL)
  220. {
  221. *LocalAuthData = TempOldPac;
  222. }
  223. if (!KERB_SUCCESS(KerbErr))
  224. {
  225. goto Cleanup;
  226. }
  227. NewIfRelevantData->value.auth_data_type = KERB_AUTH_DATA_IF_RELEVANT;
  228. *NewPacData = *PacAuthData;
  229. //
  230. // Zero this out so the old data doesn't get used
  231. //
  232. PacAuthData->value.auth_data.value = NULL;
  233. PacAuthData->value.auth_data.length = 0;
  234. //
  235. // Now we have a new if_relevant & a new pac for the outer auth-data list.
  236. //
  237. NewAuthData = NewIfRelevantData;
  238. NewIfRelevantData->next = NULL;
  239. NewIfRelevantData = NULL;
  240. //
  241. // Start building the list, first putting the non-pac entries at the end
  242. //
  243. NextPointer = AuthData;
  244. while (NextPointer != NULL)
  245. {
  246. if ((NextPointer->value.auth_data_type != KERB_AUTH_DATA_IF_RELEVANT) &&
  247. (NextPointer->value.auth_data_type != KERB_AUTH_DATA_PAC))
  248. {
  249. TempNextPointer = NextPointer->next;
  250. NextPointer->next = NULL;
  251. KerbErr = KerbCopyAndAppendAuthData(
  252. &NewAuthData,
  253. NextPointer
  254. );
  255. NextPointer->next = TempNextPointer;
  256. if (!KERB_SUCCESS(KerbErr))
  257. {
  258. goto Cleanup;
  259. }
  260. }
  261. NextPointer = NextPointer->next;
  262. }
  263. *UpdatedAuthData = NewAuthData;
  264. NewAuthData = NULL;
  265. Cleanup:
  266. if (NewPacData != NULL)
  267. {
  268. KerbFreeAuthData(NewPacData);
  269. }
  270. if (NewIfRelevantData != NULL)
  271. {
  272. KerbFreeAuthData(NewIfRelevantData);
  273. }
  274. if (NewAuthData != NULL)
  275. {
  276. KerbFreeAuthData(NewAuthData);
  277. }
  278. return(KerbErr);
  279. }
  280. //+-------------------------------------------------------------------------
  281. //
  282. // Function: KdcBuildPacSidList
  283. //
  284. // Synopsis: Builds a list of SIDs in the PAC
  285. //
  286. // Effects:
  287. //
  288. // Arguments: UserInfo - validation information
  289. // AddEveryone - add "Everyone" and "Authenticated User" SIDs?
  290. // CrossOrganization - add "Other Org" SID?
  291. // Sids - used to return the resulting SIDs
  292. //
  293. // Requires:
  294. //
  295. // Returns:
  296. //
  297. // Notes:
  298. //
  299. //
  300. //--------------------------------------------------------------------------
  301. KERBERR
  302. KdcBuildPacSidList(
  303. IN PNETLOGON_VALIDATION_SAM_INFO3 UserInfo,
  304. IN BOOLEAN AddEveryone,
  305. IN BOOLEAN CrossOrganization,
  306. OUT PSAMPR_PSID_ARRAY Sids
  307. )
  308. {
  309. KERBERR KerbErr = KDC_ERR_NONE;
  310. ULONG Size = 0, i;
  311. Sids->Count = 0;
  312. Sids->Sids = NULL;
  313. if (UserInfo->UserId != 0)
  314. {
  315. Size += sizeof(SAMPR_SID_INFORMATION);
  316. }
  317. if (AddEveryone)
  318. {
  319. Size += (sizeof(SAMPR_SID_INFORMATION) * 2);
  320. }
  321. if (CrossOrganization)
  322. {
  323. Size += sizeof(SAMPR_SID_INFORMATION);
  324. }
  325. Size += UserInfo->GroupCount * (ULONG)sizeof(SAMPR_SID_INFORMATION);
  326. //
  327. // If there are extra SIDs, add space for them
  328. //
  329. if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
  330. Size += UserInfo->SidCount * (ULONG)sizeof(SAMPR_SID_INFORMATION);
  331. }
  332. Sids->Sids = (PSAMPR_SID_INFORMATION) MIDL_user_allocate( Size );
  333. if ( Sids->Sids == NULL ) {
  334. KerbErr = KRB_ERR_GENERIC;
  335. goto Cleanup;
  336. }
  337. RtlZeroMemory(
  338. Sids->Sids,
  339. Size
  340. );
  341. //
  342. // Start copying SIDs into the structure
  343. //
  344. i = 0;
  345. //
  346. // If the UserId is non-zero, then it contians the users RID.
  347. //
  348. if ( UserInfo->UserId ) {
  349. Sids->Sids[0].SidPointer = (PRPC_SID)
  350. KerbMakeDomainRelativeSid( UserInfo->LogonDomainId,
  351. UserInfo->UserId );
  352. if( Sids->Sids[0].SidPointer == NULL ) {
  353. KerbErr = KRB_ERR_GENERIC;
  354. goto Cleanup;
  355. }
  356. Sids->Count++;
  357. }
  358. //
  359. // Copy over all the groups passed as RIDs
  360. //
  361. for ( i=0; i < UserInfo->GroupCount; i++ ) {
  362. Sids->Sids[Sids->Count].SidPointer = (PRPC_SID)
  363. KerbMakeDomainRelativeSid(
  364. UserInfo->LogonDomainId,
  365. UserInfo->GroupIds[i].RelativeId );
  366. if( Sids->Sids[Sids->Count].SidPointer == NULL ) {
  367. KerbErr = KRB_ERR_GENERIC;
  368. goto Cleanup;
  369. }
  370. Sids->Count++;
  371. }
  372. //
  373. // Add in the extra SIDs
  374. //
  375. //
  376. // No need to allocate these, but...
  377. //
  378. if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
  379. for ( i = 0; i < UserInfo->SidCount; i++ ) {
  380. if (!NT_SUCCESS(KerbDuplicateSid(
  381. (PSID *) &Sids->Sids[Sids->Count].SidPointer,
  382. UserInfo->ExtraSids[i].Sid
  383. )))
  384. {
  385. KerbErr = KRB_ERR_GENERIC;
  386. goto Cleanup;
  387. }
  388. Sids->Count++;
  389. }
  390. }
  391. //
  392. // Add in everyone, and authenticated users.
  393. //
  394. if ( AddEveryone )
  395. {
  396. if (!NT_SUCCESS(KerbDuplicateSid(
  397. (PSID*) &Sids->Sids[Sids->Count].SidPointer,
  398. GlobalEveryoneSid
  399. )))
  400. {
  401. KerbErr = KRB_ERR_GENERIC;
  402. goto Cleanup;
  403. }
  404. Sids->Count++;
  405. if (!NT_SUCCESS(KerbDuplicateSid(
  406. (PSID*) &Sids->Sids[Sids->Count].SidPointer,
  407. GlobalAuthenticatedUserSid
  408. )))
  409. {
  410. KerbErr = KRB_ERR_GENERIC;
  411. goto Cleanup;
  412. }
  413. Sids->Count++;
  414. }
  415. //
  416. // Add in the "Other Organization" SID
  417. //
  418. if ( CrossOrganization )
  419. {
  420. if (!NT_SUCCESS(KerbDuplicateSid(
  421. (PSID*) &Sids->Sids[Sids->Count].SidPointer,
  422. GlobalOtherOrganizationSid )))
  423. {
  424. KerbErr = KRB_ERR_GENERIC;
  425. goto Cleanup;
  426. }
  427. Sids->Count++;
  428. }
  429. Cleanup:
  430. if (!KERB_SUCCESS(KerbErr))
  431. {
  432. if (Sids->Sids != NULL)
  433. {
  434. for (i = 0; i < Sids->Count ;i++ )
  435. {
  436. if (Sids->Sids[i].SidPointer != NULL)
  437. {
  438. MIDL_user_free(Sids->Sids[i].SidPointer);
  439. }
  440. }
  441. MIDL_user_free(Sids->Sids);
  442. Sids->Sids = NULL;
  443. Sids->Count = 0;
  444. }
  445. }
  446. return KerbErr;
  447. }
  448. //+-------------------------------------------------------------------------
  449. //
  450. // Function: KdcAddResourceGroupsToPac
  451. //
  452. // Synopsis: Queries SAM for resources groups and builds a new PAC with
  453. // those groups
  454. //
  455. // Effects: Adds Domain Local and Universal groups **IN NATIVE MODE ONLY**
  456. // Only called when you reach domain of target service.
  457. //
  458. // Arguments:
  459. //
  460. // Requires:
  461. //
  462. // Returns:
  463. //
  464. // Notes:
  465. //
  466. //
  467. //--------------------------------------------------------------------------
  468. KERBERR
  469. KdcAddResourceGroupsToPac(
  470. IN PPACTYPE OldPac,
  471. IN BOOLEAN DcTarget,
  472. IN ULONG ChecksumSize,
  473. OUT PPACTYPE * NewPac
  474. )
  475. {
  476. NTSTATUS Status;
  477. KERBERR KerbErr = KDC_ERR_NONE;
  478. PPAC_INFO_BUFFER LogonInfo;
  479. ULONG Index;
  480. PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo = NULL;
  481. SAMPR_PSID_ARRAY SidList = {0};
  482. PSAMPR_PSID_ARRAY ResourceGroups = NULL;
  483. //
  484. // First, find the logon information
  485. //
  486. LogonInfo = PAC_Find(
  487. OldPac,
  488. PAC_LOGON_INFO,
  489. NULL
  490. );
  491. if (LogonInfo == NULL)
  492. {
  493. D_DebugLog((DEB_WARN,"No logon info for PAC - not adding resource groups\n"));
  494. KerbErr = KRB_ERR_GENERIC;
  495. goto Cleanup;
  496. }
  497. //
  498. // Now unmarshall the validation information and build a list of sids
  499. //
  500. if (!NT_SUCCESS(PAC_UnmarshallValidationInfo(
  501. &ValidationInfo,
  502. LogonInfo->Data,
  503. LogonInfo->cbBufferSize)))
  504. {
  505. D_DebugLog((DEB_ERROR,"Failed to unmarshall validation info!\n"));
  506. KerbErr = KRB_ERR_GENERIC;
  507. goto Cleanup;
  508. }
  509. KerbErr = KdcBuildPacSidList(
  510. ValidationInfo,
  511. FALSE,
  512. FALSE,
  513. &SidList
  514. );
  515. if (!KERB_SUCCESS(KerbErr))
  516. {
  517. goto Cleanup;
  518. }
  519. //
  520. // Call SAM to get the sids
  521. //
  522. Status = SamIGetResourceGroupMembershipsTransitive(
  523. GlobalAccountDomainHandle,
  524. &SidList,
  525. (DcTarget ? SAM_SERVICE_TARGET_IS_DC : 0),
  526. &ResourceGroups
  527. );
  528. if (!NT_SUCCESS(Status))
  529. {
  530. DebugLog((DEB_ERROR,"Failed to get resource groups: 0x%x\n",Status));
  531. KerbErr = KRB_ERR_GENERIC;
  532. goto Cleanup;
  533. }
  534. //
  535. // Now build a new pac
  536. //
  537. Status = PAC_InitAndUpdateGroups(
  538. ValidationInfo,
  539. ResourceGroups,
  540. OldPac,
  541. NewPac
  542. );
  543. if (!NT_SUCCESS(Status))
  544. {
  545. KerbErr = KRB_ERR_GENERIC;
  546. goto Cleanup;
  547. }
  548. Cleanup:
  549. if (ValidationInfo != NULL)
  550. {
  551. MIDL_user_free(ValidationInfo);
  552. }
  553. if (SidList.Sids != NULL)
  554. {
  555. for (Index = 0; Index < SidList.Count ;Index++ )
  556. {
  557. if (SidList.Sids[Index].SidPointer != NULL)
  558. {
  559. MIDL_user_free(SidList.Sids[Index].SidPointer);
  560. }
  561. }
  562. MIDL_user_free(SidList.Sids);
  563. }
  564. SamIFreeSidArray(
  565. ResourceGroups
  566. );
  567. return(KerbErr);
  568. }
  569. //+-------------------------------------------------------------------------
  570. //
  571. // Function: KdcSignPac
  572. //
  573. // Synopsis: Signs a PAC by first checksumming it with the
  574. // server's key and then signing that with the KDC key.
  575. //
  576. // Effects: Modifies the server sig & privsvr sig fields of the PAC
  577. //
  578. // Arguments: ServerInfo - Ticket info for the server, used
  579. // for the initial signature
  580. // PacData - An marshalled PAC.
  581. //
  582. // Requires:
  583. //
  584. // Returns:
  585. //
  586. // Notes:
  587. //
  588. //
  589. //--------------------------------------------------------------------------
  590. KERBERR
  591. KdcSignPac(
  592. IN PKERB_ENCRYPTION_KEY ServerKey,
  593. IN BOOLEAN AddResourceGroups,
  594. IN BOOLEAN DCTarget,
  595. IN OUT PUCHAR * PacData,
  596. IN PULONG PacSize
  597. )
  598. {
  599. NTSTATUS Status;
  600. KERBERR KerbErr = KDC_ERR_NONE;
  601. PCHECKSUM_FUNCTION Check = NULL ;
  602. PCHECKSUM_BUFFER CheckBuffer = NULL;
  603. PPAC_INFO_BUFFER ServerBuffer;
  604. PPAC_INFO_BUFFER PrivSvrBuffer;
  605. PPAC_SIGNATURE_DATA ServerSignature;
  606. PPAC_SIGNATURE_DATA PrivSvrSignature;
  607. PKERB_ENCRYPTION_KEY EncryptionKey;
  608. PPACTYPE Pac = NULL, NewPac = NULL;
  609. ULONG LocalPacSize = 0;
  610. KDC_TICKET_INFO KdcTicketInfo = {0};
  611. BOOL PacUnmarshalled = FALSE;
  612. TRACE(KDC, KdcSignPac, DEB_FUNCTION);
  613. KerbErr = SecData.GetKrbtgtTicketInfo(&KdcTicketInfo);
  614. if (!KERB_SUCCESS(KerbErr))
  615. {
  616. Status = KerbMapKerbError(KerbErr);
  617. goto Cleanup;
  618. }
  619. //
  620. // Locate the checksum used to sign the PAC.
  621. //
  622. Status = CDLocateCheckSum(
  623. (ULONG) KDC_PAC_CHECKSUM,
  624. &Check
  625. );
  626. if (!NT_SUCCESS(Status))
  627. {
  628. KerbErr = KDC_ERR_SUMTYPE_NOSUPP;
  629. goto Cleanup;
  630. }
  631. //
  632. // Unmarshal the PAC in place so we can locate the signatuer buffers
  633. //
  634. Pac = (PPACTYPE) *PacData;
  635. LocalPacSize = *PacSize;
  636. if (PAC_UnMarshal(Pac, LocalPacSize) == 0)
  637. {
  638. D_DebugLog((DEB_ERROR,"Failed to unmarshal pac\n"));
  639. KerbErr = KRB_ERR_GENERIC;
  640. goto Cleanup;
  641. }
  642. PacUnmarshalled = TRUE;
  643. //
  644. // If we are to add local groups, do so now
  645. //
  646. if (AddResourceGroups)
  647. {
  648. KerbErr = KdcAddResourceGroupsToPac(
  649. Pac,
  650. DCTarget,
  651. Check->CheckSumSize,
  652. &NewPac
  653. );
  654. if (!KERB_SUCCESS(KerbErr))
  655. {
  656. goto Cleanup;
  657. }
  658. Pac = NewPac;
  659. LocalPacSize = PAC_GetSize(Pac);
  660. }
  661. //
  662. // Locate the signature buffers so the signature fields can be zeroed out
  663. // before computing the checksum.
  664. //
  665. ServerBuffer = PAC_Find(Pac, PAC_SERVER_CHECKSUM, NULL );
  666. DsysAssert(ServerBuffer != NULL);
  667. if (ServerBuffer == NULL)
  668. {
  669. KerbErr = KRB_ERR_GENERIC;
  670. goto Cleanup;
  671. }
  672. ServerSignature = (PPAC_SIGNATURE_DATA) ServerBuffer->Data;
  673. ServerSignature->SignatureType = (ULONG) KDC_PAC_CHECKSUM;
  674. RtlZeroMemory(
  675. ServerSignature->Signature,
  676. PAC_CHECKSUM_SIZE(ServerBuffer->cbBufferSize)
  677. );
  678. PrivSvrBuffer = PAC_Find(Pac, PAC_PRIVSVR_CHECKSUM, NULL );
  679. DsysAssert(PrivSvrBuffer != NULL);
  680. if (PrivSvrBuffer == NULL)
  681. {
  682. KerbErr = KRB_ERR_GENERIC;
  683. goto Cleanup;
  684. }
  685. PrivSvrSignature = (PPAC_SIGNATURE_DATA) PrivSvrBuffer->Data;
  686. PrivSvrSignature->SignatureType = (ULONG) KDC_PAC_CHECKSUM;
  687. RtlZeroMemory(
  688. PrivSvrSignature->Signature,
  689. PAC_CHECKSUM_SIZE(PrivSvrBuffer->cbBufferSize)
  690. );
  691. //
  692. // Now remarshall the PAC to compute the checksum.
  693. //
  694. if (!PAC_ReMarshal(Pac, LocalPacSize))
  695. {
  696. DsysAssert(!"PAC_Remarshal Failed");
  697. KerbErr = KRB_ERR_GENERIC;
  698. goto Cleanup;
  699. }
  700. PacUnmarshalled = FALSE;
  701. //
  702. // Now compute the signatures on the PAC. First we compute the checksum
  703. // of the whole PAC.
  704. //
  705. if (NULL != Check->InitializeEx2)
  706. {
  707. Status = Check->InitializeEx2(
  708. ServerKey->keyvalue.value,
  709. ServerKey->keyvalue.length,
  710. NULL,
  711. KERB_NON_KERB_CKSUM_SALT,
  712. &CheckBuffer
  713. );
  714. }
  715. else
  716. {
  717. Status = Check->InitializeEx(
  718. ServerKey->keyvalue.value,
  719. ServerKey->keyvalue.length,
  720. KERB_NON_KERB_CKSUM_SALT,
  721. &CheckBuffer
  722. );
  723. }
  724. if (!NT_SUCCESS(Status))
  725. {
  726. KerbErr = KRB_ERR_GENERIC;
  727. goto Cleanup;
  728. }
  729. Check->Sum(
  730. CheckBuffer,
  731. LocalPacSize,
  732. (PUCHAR) Pac
  733. );
  734. Check->Finalize(
  735. CheckBuffer,
  736. ServerSignature->Signature
  737. );
  738. Check->Finish(
  739. &CheckBuffer
  740. );
  741. //
  742. // Now we've compute the server checksum - next compute the checksum
  743. // of the server checksum using the KDC account.
  744. //
  745. //
  746. // Get the key used to sign pacs.
  747. //
  748. EncryptionKey = KerbGetKeyFromList(
  749. KdcTicketInfo.Passwords,
  750. (ULONG) KDC_PAC_KEYTYPE
  751. );
  752. if (EncryptionKey == NULL)
  753. {
  754. Status = SEC_E_ETYPE_NOT_SUPP;
  755. goto Cleanup;
  756. }
  757. if (NULL != Check->InitializeEx2)
  758. {
  759. Status = Check->InitializeEx2(
  760. EncryptionKey->keyvalue.value,
  761. EncryptionKey->keyvalue.length,
  762. NULL,
  763. KERB_NON_KERB_CKSUM_SALT,
  764. &CheckBuffer
  765. );
  766. }
  767. else
  768. {
  769. Status = Check->InitializeEx(
  770. EncryptionKey->keyvalue.value,
  771. EncryptionKey->keyvalue.length,
  772. KERB_NON_KERB_CKSUM_SALT,
  773. &CheckBuffer
  774. );
  775. }
  776. if (!NT_SUCCESS(Status))
  777. {
  778. KerbErr = KRB_ERR_GENERIC;
  779. goto Cleanup;
  780. }
  781. Check->Sum(
  782. CheckBuffer,
  783. Check->CheckSumSize,
  784. ServerSignature->Signature
  785. );
  786. Check->Finalize(
  787. CheckBuffer,
  788. PrivSvrSignature->Signature
  789. );
  790. Check->Finish(
  791. &CheckBuffer
  792. );
  793. if (*PacData != (PBYTE) Pac)
  794. {
  795. MIDL_user_free(*PacData);
  796. *PacData = (PBYTE) Pac;
  797. *PacSize = LocalPacSize;
  798. }
  799. Cleanup:
  800. if ( PacUnmarshalled )
  801. {
  802. if (!PAC_ReMarshal(Pac, LocalPacSize))
  803. {
  804. DsysAssert(!"PAC_Remarshal Failed");
  805. KerbErr = KRB_ERR_GENERIC;
  806. }
  807. }
  808. if ( ( CheckBuffer != NULL ) &&
  809. ( Check != NULL ) )
  810. {
  811. Check->Finish(&CheckBuffer);
  812. }
  813. if (!KERB_SUCCESS(KerbErr) && (NewPac != NULL))
  814. {
  815. MIDL_user_free(NewPac);
  816. }
  817. FreeTicketInfo(&KdcTicketInfo);
  818. return(KerbErr);
  819. }
  820. //+-------------------------------------------------------------------------
  821. //
  822. // Function: KdcVerifyPacSignature
  823. //
  824. // Synopsis: Verifies a PAC by checksumming it and comparing the result
  825. // with the server checksum. In addition, if the pac wasn't
  826. // created by another realm (server ticket info is not
  827. // an interdomain account) verify the KDC signature on the
  828. // pac.
  829. //
  830. // Effects:
  831. //
  832. // Arguments: ServerInfo - Ticket info for the server, used
  833. // for the initial signature
  834. // Pac - An unmarshalled PAC.
  835. //
  836. // Requires:
  837. //
  838. // Returns:
  839. //
  840. // Notes:
  841. //
  842. //
  843. //--------------------------------------------------------------------------
  844. KERBERR
  845. KdcVerifyPacSignature(
  846. IN PKERB_ENCRYPTION_KEY ServerKey,
  847. IN PKDC_TICKET_INFO ServerInfo,
  848. IN ULONG PacSize,
  849. IN PUCHAR PacData
  850. )
  851. {
  852. NTSTATUS Status;
  853. KERBERR KerbErr = KDC_ERR_NONE;
  854. PCHECKSUM_FUNCTION Check = NULL ;
  855. PCHECKSUM_BUFFER CheckBuffer = NULL;
  856. PKERB_ENCRYPTION_KEY EncryptionKey = NULL;
  857. PPAC_INFO_BUFFER ServerBuffer;
  858. PPAC_INFO_BUFFER PrivSvrBuffer;
  859. PPAC_SIGNATURE_DATA ServerSignature;
  860. PPAC_SIGNATURE_DATA PrivSvrSignature;
  861. UCHAR LocalChecksum[20];
  862. UCHAR LocalServerChecksum[20];
  863. UCHAR LocalPrivSvrChecksum[20];
  864. PPACTYPE Pac;
  865. KDC_TICKET_INFO KdcTicketInfo = {0};
  866. BOOL PacUnmarshalled = FALSE;
  867. TRACE(KDC, KdcVerifyPacSignature, DEB_FUNCTION);
  868. Pac = (PPACTYPE) PacData;
  869. if (PAC_UnMarshal(Pac, PacSize) == 0)
  870. {
  871. D_DebugLog((DEB_ERROR,"Failed to unmarshal pac\n"));
  872. KerbErr = KRB_ERR_GENERIC;
  873. goto Cleanup;
  874. }
  875. PacUnmarshalled = TRUE;
  876. KerbErr = SecData.GetKrbtgtTicketInfo(&KdcTicketInfo);
  877. if (!KERB_SUCCESS(KerbErr))
  878. {
  879. Status = KerbMapKerbError(KerbErr);
  880. goto Cleanup;
  881. }
  882. //
  883. // Locate the two signatures, copy the checksum, and zero the value
  884. // so the checksum won't include the old checksums.
  885. //
  886. ServerBuffer = PAC_Find(Pac, PAC_SERVER_CHECKSUM, NULL );
  887. DsysAssert(ServerBuffer != NULL);
  888. if ((ServerBuffer == NULL) || (ServerBuffer->cbBufferSize < PAC_SIGNATURE_SIZE(0)))
  889. {
  890. KerbErr = KRB_ERR_GENERIC;
  891. goto Cleanup;
  892. }
  893. ServerSignature = (PPAC_SIGNATURE_DATA) ServerBuffer->Data;
  894. RtlCopyMemory(
  895. LocalServerChecksum,
  896. ServerSignature->Signature,
  897. PAC_CHECKSUM_SIZE(ServerBuffer->cbBufferSize)
  898. );
  899. RtlZeroMemory(
  900. ServerSignature->Signature,
  901. PAC_CHECKSUM_SIZE(ServerBuffer->cbBufferSize)
  902. );
  903. PrivSvrBuffer = PAC_Find(Pac, PAC_PRIVSVR_CHECKSUM, NULL );
  904. DsysAssert(PrivSvrBuffer != NULL);
  905. if ((PrivSvrBuffer == NULL) || (PrivSvrBuffer->cbBufferSize < PAC_SIGNATURE_SIZE(0)))
  906. {
  907. KerbErr = KRB_ERR_GENERIC;
  908. goto Cleanup;
  909. }
  910. PrivSvrSignature = (PPAC_SIGNATURE_DATA) PrivSvrBuffer->Data;
  911. RtlCopyMemory(
  912. LocalPrivSvrChecksum,
  913. PrivSvrSignature->Signature,
  914. PAC_CHECKSUM_SIZE(PrivSvrBuffer->cbBufferSize)
  915. );
  916. RtlZeroMemory(
  917. PrivSvrSignature->Signature,
  918. PAC_CHECKSUM_SIZE(PrivSvrBuffer->cbBufferSize)
  919. );
  920. //
  921. // Remarshal the pac so we can checksum it.
  922. //
  923. if (!PAC_ReMarshal(Pac, PacSize))
  924. {
  925. DsysAssert(!"PAC_Remarshal Failed");
  926. KerbErr = KRB_ERR_GENERIC;
  927. goto Cleanup;
  928. }
  929. PacUnmarshalled = FALSE;
  930. //
  931. // Now compute the signatures on the PAC. First we compute the checksum
  932. // of the validation information using the server's key.
  933. //
  934. //
  935. // Locate the checksum used to sign the PAC.
  936. //
  937. Status = CDLocateCheckSum(
  938. ServerSignature->SignatureType,
  939. &Check
  940. );
  941. if (!NT_SUCCESS(Status))
  942. {
  943. KerbErr = KDC_ERR_SUMTYPE_NOSUPP;
  944. goto Cleanup;
  945. }
  946. if (Check->CheckSumSize > sizeof(LocalChecksum)) {
  947. DsysAssert(Check->CheckSumSize <= sizeof(LocalChecksum));
  948. KerbErr = KRB_ERR_GENERIC;
  949. goto Cleanup;
  950. }
  951. //
  952. // if available use the Ex2 version for keyed checksums where checksum
  953. // must be passed in on verification
  954. //
  955. if (NULL != Check->InitializeEx2)
  956. {
  957. Status = Check->InitializeEx2(
  958. ServerKey->keyvalue.value,
  959. ServerKey->keyvalue.length,
  960. LocalServerChecksum,
  961. KERB_NON_KERB_CKSUM_SALT,
  962. &CheckBuffer
  963. );
  964. }
  965. else
  966. {
  967. Status = Check->InitializeEx(
  968. ServerKey->keyvalue.value,
  969. ServerKey->keyvalue.length,
  970. KERB_NON_KERB_CKSUM_SALT,
  971. &CheckBuffer
  972. );
  973. }
  974. if (!NT_SUCCESS(Status))
  975. {
  976. KerbErr = KRB_ERR_GENERIC;
  977. goto Cleanup;
  978. }
  979. Check->Sum(
  980. CheckBuffer,
  981. PacSize,
  982. PacData
  983. );
  984. Check->Finalize(
  985. CheckBuffer,
  986. LocalChecksum
  987. );
  988. Check->Finish(
  989. &CheckBuffer
  990. );
  991. if (Check->CheckSumSize != PAC_CHECKSUM_SIZE(ServerBuffer->cbBufferSize) ||
  992. !RtlEqualMemory(
  993. LocalChecksum,
  994. LocalServerChecksum,
  995. Check->CheckSumSize))
  996. {
  997. DebugLog((DEB_ERROR, "Pac was modified - server checksum doesn't match\n"));
  998. KerbErr = KRB_AP_ERR_MODIFIED;
  999. goto Cleanup;
  1000. }
  1001. //
  1002. // If the service wasn't the KDC and it wasn't an interdomain account
  1003. // verify the KDC checksum.
  1004. //
  1005. if ((ServerInfo->UserId == DOMAIN_USER_RID_KRBTGT) ||
  1006. ((ServerInfo->UserAccountControl & USER_INTERDOMAIN_TRUST_ACCOUNT) != 0))
  1007. {
  1008. goto Cleanup;
  1009. }
  1010. //
  1011. // Get the key used to sign pacs.
  1012. //
  1013. EncryptionKey = KerbGetKeyFromList(
  1014. KdcTicketInfo.Passwords,
  1015. (ULONG) KDC_PAC_KEYTYPE
  1016. );
  1017. if (EncryptionKey == NULL)
  1018. {
  1019. Status = SEC_E_ETYPE_NOT_SUPP;
  1020. goto Cleanup;
  1021. }
  1022. //
  1023. // Locate the checksum used to sign the PAC.
  1024. //
  1025. Status = CDLocateCheckSum(
  1026. PrivSvrSignature->SignatureType,
  1027. &Check
  1028. );
  1029. if (!NT_SUCCESS(Status))
  1030. {
  1031. KerbErr = KDC_ERR_SUMTYPE_NOSUPP;
  1032. goto Cleanup;
  1033. }
  1034. //
  1035. // if available use the Ex2 version for keyed checksums where checksum
  1036. // must be passed in on verification
  1037. //
  1038. if (NULL != Check->InitializeEx2)
  1039. {
  1040. Status = Check->InitializeEx2(
  1041. EncryptionKey->keyvalue.value,
  1042. EncryptionKey->keyvalue.length,
  1043. LocalPrivSvrChecksum,
  1044. KERB_NON_KERB_CKSUM_SALT,
  1045. &CheckBuffer
  1046. );
  1047. }
  1048. else
  1049. {
  1050. Status = Check->InitializeEx(
  1051. EncryptionKey->keyvalue.value,
  1052. EncryptionKey->keyvalue.length,
  1053. KERB_NON_KERB_CKSUM_SALT,
  1054. &CheckBuffer
  1055. );
  1056. }
  1057. if (!NT_SUCCESS(Status))
  1058. {
  1059. KerbErr = KRB_ERR_GENERIC;
  1060. goto Cleanup;
  1061. }
  1062. Check->Sum(
  1063. CheckBuffer,
  1064. Check->CheckSumSize,
  1065. LocalServerChecksum
  1066. );
  1067. Check->Finalize(
  1068. CheckBuffer,
  1069. LocalChecksum
  1070. );
  1071. Check->Finish(
  1072. &CheckBuffer
  1073. );
  1074. if ((Check->CheckSumSize != PAC_CHECKSUM_SIZE(PrivSvrBuffer->cbBufferSize)) ||
  1075. !RtlEqualMemory(
  1076. LocalChecksum,
  1077. LocalPrivSvrChecksum,
  1078. Check->CheckSumSize))
  1079. {
  1080. DebugLog((DEB_ERROR, "Pac was modified - privsvr checksum doesn't match\n"));
  1081. KerbErr = KRB_AP_ERR_MODIFIED;
  1082. goto Cleanup;
  1083. }
  1084. Cleanup:
  1085. if ( PacUnmarshalled )
  1086. {
  1087. if (!PAC_ReMarshal(Pac, PacSize))
  1088. {
  1089. DsysAssert(!"PAC_Remarshal Failed");
  1090. KerbErr = KRB_ERR_GENERIC;
  1091. }
  1092. }
  1093. if (KerbErr == KRB_AP_ERR_MODIFIED)
  1094. {
  1095. LPWSTR AccountName = NULL;
  1096. AccountName = (LPWSTR) MIDL_user_allocate(ServerInfo->AccountName.Length + sizeof(WCHAR));
  1097. //
  1098. // if the allocation fails don't log the name (leave it NULL)
  1099. //
  1100. if (NULL != AccountName)
  1101. {
  1102. RtlCopyMemory(
  1103. AccountName,
  1104. ServerInfo->AccountName.Buffer,
  1105. ServerInfo->AccountName.Length
  1106. );
  1107. }
  1108. ReportServiceEvent(
  1109. EVENTLOG_ERROR_TYPE,
  1110. KDCEVENT_PAC_VERIFICATION_FAILURE,
  1111. sizeof(ULONG),
  1112. &KerbErr,
  1113. 1,
  1114. AccountName
  1115. );
  1116. if (NULL != AccountName)
  1117. {
  1118. MIDL_user_free(AccountName);
  1119. }
  1120. }
  1121. if ( ( CheckBuffer != NULL ) &&
  1122. ( Check != NULL ) )
  1123. {
  1124. Check->Finish(&CheckBuffer);
  1125. }
  1126. FreeTicketInfo(&KdcTicketInfo);
  1127. return(KerbErr);
  1128. }
  1129. //+---------------------------------------------------------------------------
  1130. //
  1131. // Name: KdcGetPacAuthData
  1132. //
  1133. // Synopsis: Creates a PAC for the specified client, encrypts it with the
  1134. // server's key, and packs it into a KERB_AUTHORIZATON_DATA
  1135. //
  1136. // Arguments: UserInfo - Information about user
  1137. // GroupMembership - Users group memberships
  1138. // ServerKey - Key of server, used for signing
  1139. // CredentialKey - if present & valid, used to encrypt supp. creds
  1140. // AddResourceGroups - if TRUE, resources groups will be included
  1141. // EncryptedTicket - Optional ticke to tie PAC to
  1142. // S4UTicketInfo - used only when inserting initial S4U2self auth
  1143. // data into the ticket. causes the S4U2self
  1144. // target to be stored inside the PAC
  1145. // PacAuthData - Receives a KERB_AUTHORIZATION_DATA of type
  1146. // KERB_AUTH_DATA_PAC, containing a PAC.
  1147. //
  1148. // Notes: PacAuthData should be freed with KerbFreeAuthorizationData.
  1149. //
  1150. //+---------------------------------------------------------------------------
  1151. KERBERR
  1152. KdcGetPacAuthData(
  1153. IN PUSER_INTERNAL6_INFORMATION UserInfo,
  1154. IN PSID_AND_ATTRIBUTES_LIST GroupMembership,
  1155. IN PKERB_ENCRYPTION_KEY ServerKey,
  1156. IN PKERB_ENCRYPTION_KEY CredentialKey,
  1157. IN BOOLEAN AddResourceGroups,
  1158. IN PKERB_ENCRYPTED_TICKET EncryptedTicket,
  1159. IN OPTIONAL PKDC_S4U_TICKET_INFO S4UClientInfo,
  1160. OUT PKERB_AUTHORIZATION_DATA * PacAuthData,
  1161. OUT PKERB_EXT_ERROR pExtendedError
  1162. )
  1163. {
  1164. KERBERR KerbErr = KDC_ERR_NONE;
  1165. PACTYPE *pNewPac = NULL;
  1166. KERB_AUTHORIZATION_DATA AuthorizationData = {0};
  1167. ULONG PacSize, NameType;
  1168. PCHECKSUM_FUNCTION Check;
  1169. NTSTATUS Status;
  1170. UNICODE_STRING ClientName = {0};
  1171. PKERB_INTERNAL_NAME KdcName = NULL;
  1172. TimeStamp ClientId;
  1173. TRACE(KDC, KdcGetPacAuthData, DEB_FUNCTION);
  1174. Status = CDLocateCheckSum(
  1175. (ULONG) KDC_PAC_CHECKSUM,
  1176. &Check
  1177. );
  1178. if (!NT_SUCCESS(Status))
  1179. {
  1180. KerbErr = KDC_ERR_SUMTYPE_NOSUPP;
  1181. FILL_EXT_ERROR(pExtendedError, Status, FILENO, __LINE__);
  1182. goto Cleanup;
  1183. }
  1184. KerbConvertGeneralizedTimeToLargeInt(
  1185. &ClientId,
  1186. &EncryptedTicket->authtime,
  1187. 0 // no usec
  1188. );
  1189. //
  1190. // Put the S4U client in the pac verifier. For S4USelf, we use
  1191. // user@domain to keep W2K servers / kdcs from allowing xrealm tgts
  1192. // w/ s4u pacs
  1193. //
  1194. if (ARGUMENT_PRESENT(S4UClientInfo))
  1195. {
  1196. KerbErr = KerbConvertKdcNameToString(
  1197. &ClientName,
  1198. S4UClientInfo->PACCName,
  1199. (((S4UClientInfo->Flags & TI_REQUESTOR_THIS_REALM) != 0) ? NULL : &S4UClientInfo->PACCRealm )
  1200. );
  1201. }
  1202. else // use the ticket
  1203. {
  1204. KerbErr = KerbConvertPrincipalNameToString(
  1205. &ClientName,
  1206. &NameType,
  1207. &EncryptedTicket->client_name
  1208. );
  1209. }
  1210. if (!KERB_SUCCESS(KerbErr))
  1211. {
  1212. goto Cleanup;
  1213. }
  1214. KerbErr = GetPacAndSuppCred(
  1215. UserInfo,
  1216. GroupMembership,
  1217. Check->CheckSumSize, // leave space for signature
  1218. CredentialKey,
  1219. &ClientId,
  1220. &ClientName,
  1221. &pNewPac,
  1222. pExtendedError
  1223. );
  1224. if (!KERB_SUCCESS(KerbErr))
  1225. {
  1226. D_DebugLog(( DEB_WARN,
  1227. "GetPAC: Can't get PAC or supp creds: 0x%x \n", KerbErr ));
  1228. goto Cleanup;
  1229. }
  1230. //
  1231. // The PAC is going to be double-encrypted. This is done by having the
  1232. // PAC in an EncryptedData, and having that EncryptedData in a AuthData
  1233. // as part of an AuthDataList (along with the rest of the supp creds).
  1234. // Finally, the entire list is encrypted.
  1235. //
  1236. // KERB_AUTHORIZATION_DATA containing {
  1237. // PAC
  1238. //
  1239. // }
  1240. //
  1241. //
  1242. // First build inner encrypted data
  1243. //
  1244. PacSize = PAC_GetSize( pNewPac );
  1245. AuthorizationData.value.auth_data_type = KERB_AUTH_DATA_PAC;
  1246. AuthorizationData.value.auth_data.length = PacSize;
  1247. AuthorizationData.value.auth_data.value = (PUCHAR) MIDL_user_allocate(PacSize);
  1248. if (AuthorizationData.value.auth_data.value == NULL)
  1249. {
  1250. KerbErr = KRB_ERR_GENERIC;
  1251. goto Cleanup;
  1252. }
  1253. PAC_Marshal( pNewPac, PacSize, AuthorizationData.value.auth_data.value );
  1254. //
  1255. // Compute the signatures
  1256. //
  1257. KerbErr = KdcSignPac(
  1258. ServerKey,
  1259. AddResourceGroups,
  1260. FALSE, // this is a TGT...
  1261. &AuthorizationData.value.auth_data.value,
  1262. (PULONG) &AuthorizationData.value.auth_data.length
  1263. );
  1264. if (!KERB_SUCCESS(KerbErr))
  1265. {
  1266. goto Cleanup;
  1267. }
  1268. //
  1269. // Create the auth data to return
  1270. //
  1271. KerbErr = KdcInsertPacIntoAuthData(
  1272. NULL, // no original auth data
  1273. NULL, // no if-relevant auth data
  1274. &AuthorizationData,
  1275. PacAuthData
  1276. );
  1277. if (!KERB_SUCCESS(KerbErr))
  1278. {
  1279. DebugLog((DEB_ERROR,"Failed to insert pac into new auth data: 0x%x\n",
  1280. KerbErr));
  1281. goto Cleanup;
  1282. }
  1283. Cleanup:
  1284. if (AuthorizationData.value.auth_data.value != NULL)
  1285. {
  1286. MIDL_user_free(AuthorizationData.value.auth_data.value);
  1287. }
  1288. if (pNewPac != NULL)
  1289. {
  1290. MIDL_user_free(pNewPac);
  1291. }
  1292. KerbFreeString(&ClientName);
  1293. KerbFreeKdcName(&KdcName);
  1294. return(KerbErr);
  1295. }
  1296. //+-------------------------------------------------------------------------
  1297. //
  1298. // Function: KdcGetUserPac
  1299. //
  1300. // Synopsis: Function for external users to get the PAC for a user
  1301. //
  1302. //
  1303. // Effects:
  1304. //
  1305. // Arguments:
  1306. //
  1307. // Requires:
  1308. //
  1309. // Returns:
  1310. //
  1311. // Notes:
  1312. //
  1313. //
  1314. //--------------------------------------------------------------------------
  1315. extern "C"
  1316. NTSTATUS
  1317. KdcGetUserPac(
  1318. IN PUNICODE_STRING UserName,
  1319. OUT PPACTYPE * Pac,
  1320. OUT PUCHAR * SupplementalCredentials,
  1321. OUT PULONG SupplementalCredSize,
  1322. OUT PKERB_EXT_ERROR pExtendedError
  1323. )
  1324. {
  1325. KDC_TICKET_INFO TicketInfo;
  1326. PUSER_INTERNAL6_INFORMATION UserInfo = NULL;
  1327. SID_AND_ATTRIBUTES_LIST GroupMembership;
  1328. NTSTATUS Status;
  1329. KERBERR KerbErr;
  1330. TRACE(KDC, KdcGetUserPac, DEB_FUNCTION);
  1331. *SupplementalCredentials = NULL;
  1332. *SupplementalCredSize = 0;
  1333. RtlZeroMemory(
  1334. &TicketInfo,
  1335. sizeof(KDC_TICKET_INFO)
  1336. );
  1337. RtlZeroMemory(
  1338. &GroupMembership,
  1339. sizeof(SID_AND_ATTRIBUTES_LIST)
  1340. );
  1341. Status = EnterApiCall();
  1342. if (!NT_SUCCESS(Status))
  1343. {
  1344. return(Status);
  1345. }
  1346. //
  1347. // Get the account information
  1348. //
  1349. KerbErr = KdcGetTicketInfo(
  1350. UserName,
  1351. 0, // no flags
  1352. FALSE, // do not restrict user accounts (user2user)
  1353. NULL, // no principal name
  1354. NULL, // no realm
  1355. &TicketInfo,
  1356. pExtendedError,
  1357. NULL, // no user handle
  1358. USER_ALL_GET_PAC_AND_SUPP_CRED,
  1359. 0L, // no extended fields
  1360. &UserInfo,
  1361. &GroupMembership
  1362. );
  1363. if (!KERB_SUCCESS(KerbErr))
  1364. {
  1365. DebugLog((DEB_WARN,"Failed to get ticket info for user %wZ: 0x%x\n",
  1366. UserName->Buffer, KerbErr));
  1367. Status = KerbMapKerbError(KerbErr);
  1368. goto Cleanup;
  1369. }
  1370. //
  1371. // Now get the PAC and supplemental credentials
  1372. //
  1373. KerbErr = GetPacAndSuppCred(
  1374. UserInfo,
  1375. &GroupMembership,
  1376. 0, // no signature space
  1377. NULL, // no credential key
  1378. NULL, // no client ID
  1379. NULL, // no client name
  1380. Pac,
  1381. pExtendedError
  1382. );
  1383. if (!KERB_SUCCESS(KerbErr))
  1384. {
  1385. DebugLog((DEB_ERROR,"Failed to get PAC for user %wZ : 0x%x\n",
  1386. UserName->Buffer,KerbErr));
  1387. Status = KerbMapKerbError(KerbErr);
  1388. goto Cleanup;
  1389. }
  1390. Cleanup:
  1391. SamIFree_UserInternal6Information( UserInfo );
  1392. SamIFreeSidAndAttributesList(&GroupMembership);
  1393. FreeTicketInfo(&TicketInfo);
  1394. LeaveApiCall();
  1395. return Status;
  1396. }
  1397. //+-------------------------------------------------------------------------
  1398. //
  1399. // Function: KdcVerifyPac
  1400. //
  1401. // Synopsis: Function for kerberos to pass through a pac signature
  1402. // to be verified.
  1403. //
  1404. //
  1405. // Effects:
  1406. //
  1407. // Arguments:
  1408. //
  1409. // Requires:
  1410. //
  1411. // Returns:
  1412. //
  1413. // Notes:
  1414. //
  1415. //
  1416. //--------------------------------------------------------------------------
  1417. extern "C"
  1418. NTSTATUS
  1419. KdcVerifyPac(
  1420. IN ULONG ChecksumSize,
  1421. IN PUCHAR Checksum,
  1422. IN ULONG SignatureType,
  1423. IN ULONG SignatureSize,
  1424. IN PUCHAR Signature
  1425. )
  1426. {
  1427. NTSTATUS Status;
  1428. KERBERR KerbErr;
  1429. PCHECKSUM_FUNCTION Check;
  1430. PCHECKSUM_BUFFER CheckBuffer = NULL;
  1431. UCHAR LocalChecksum[20];
  1432. PKERB_ENCRYPTION_KEY EncryptionKey = NULL;
  1433. KDC_TICKET_INFO KdcTicketInfo = {0};
  1434. TRACE(KDC, KdcVerifyPac, DEB_FUNCTION);
  1435. Status = EnterApiCall();
  1436. if (!NT_SUCCESS(Status))
  1437. {
  1438. return(Status);
  1439. }
  1440. KerbErr = SecData.GetKrbtgtTicketInfo(&KdcTicketInfo);
  1441. if (!KERB_SUCCESS(KerbErr))
  1442. {
  1443. Status = KerbMapKerbError(KerbErr);
  1444. goto Cleanup;
  1445. }
  1446. //
  1447. // Get the key used to sign pacs.
  1448. //
  1449. EncryptionKey = KerbGetKeyFromList(
  1450. KdcTicketInfo.Passwords,
  1451. (ULONG) KDC_PAC_KEYTYPE
  1452. );
  1453. if (EncryptionKey == NULL)
  1454. {
  1455. Status = SEC_E_ETYPE_NOT_SUPP;
  1456. goto Cleanup;
  1457. }
  1458. Status = CDLocateCheckSum(
  1459. SignatureType,
  1460. &Check
  1461. );
  1462. if (!NT_SUCCESS(Status))
  1463. {
  1464. goto Cleanup;
  1465. }
  1466. if (Check->CheckSumSize > sizeof(LocalChecksum)) {
  1467. DsysAssert(Check->CheckSumSize <= sizeof(LocalChecksum));
  1468. Status = STATUS_INVALID_PARAMETER;
  1469. goto Cleanup;
  1470. }
  1471. //
  1472. // if available use the Ex2 version for keyed checksums where checksum
  1473. // must be passed in on verification
  1474. //
  1475. if (NULL != Check->InitializeEx2)
  1476. {
  1477. Status = Check->InitializeEx2(
  1478. EncryptionKey->keyvalue.value,
  1479. EncryptionKey->keyvalue.length,
  1480. Signature,
  1481. KERB_NON_KERB_CKSUM_SALT,
  1482. &CheckBuffer
  1483. );
  1484. }
  1485. else
  1486. {
  1487. Status = Check->InitializeEx(
  1488. EncryptionKey->keyvalue.value,
  1489. EncryptionKey->keyvalue.length,
  1490. KERB_NON_KERB_CKSUM_SALT,
  1491. &CheckBuffer
  1492. );
  1493. }
  1494. if (!NT_SUCCESS(Status))
  1495. {
  1496. goto Cleanup;
  1497. }
  1498. Check->Sum(
  1499. CheckBuffer,
  1500. ChecksumSize,
  1501. Checksum
  1502. );
  1503. Check->Finalize(
  1504. CheckBuffer,
  1505. LocalChecksum
  1506. );
  1507. Check->Finish(&CheckBuffer);
  1508. //
  1509. // Now compare the local checksum to the supplied checksum.
  1510. //
  1511. if (Check->CheckSumSize != SignatureSize)
  1512. {
  1513. Status = STATUS_LOGON_FAILURE;
  1514. goto Cleanup;
  1515. }
  1516. if (!RtlEqualMemory(
  1517. LocalChecksum,
  1518. Signature,
  1519. Check->CheckSumSize
  1520. ))
  1521. {
  1522. DebugLog((DEB_ERROR,"Checksum on the PAC does not match!\n"));
  1523. Status = STATUS_LOGON_FAILURE;
  1524. goto Cleanup;
  1525. }
  1526. Cleanup:
  1527. if (Status == STATUS_LOGON_FAILURE)
  1528. {
  1529. PUNICODE_STRING OwnName = NULL;
  1530. //
  1531. // since this call should only be made by pass through callback
  1532. // this signature should be our own
  1533. //
  1534. OwnName = SecData.KdcFullServiceDnsName();
  1535. ReportServiceEvent(
  1536. EVENTLOG_ERROR_TYPE,
  1537. KDCEVENT_PAC_VERIFICATION_FAILURE,
  1538. 0,
  1539. NULL,
  1540. 1, // number of strings
  1541. OwnName->Buffer
  1542. );
  1543. }
  1544. FreeTicketInfo(&KdcTicketInfo);
  1545. LeaveApiCall();
  1546. return(Status);
  1547. }
  1548. //+-------------------------------------------------------------------------
  1549. //
  1550. // Function: KdcUpdateAndValidateS4UProxyPAC
  1551. //
  1552. // Synopsis: Validates your target name from original pac, and updates
  1553. // existing info.
  1554. //
  1555. // Effects:
  1556. //
  1557. // Arguments:
  1558. // CLientId - Auth time of ticket.
  1559. // CName - Client name to put into verifier.
  1560. // Pac - **UNMARSHALLED** PAC, freed in this function, and
  1561. // rebuilt.
  1562. //
  1563. // Requires:
  1564. //
  1565. // Returns:
  1566. //
  1567. // Notes:
  1568. //
  1569. //
  1570. //--------------------------------------------------------------------------
  1571. NTSTATUS
  1572. KdcReplacePacVerifier(
  1573. PTimeStamp ClientId,
  1574. PUNICODE_STRING CName,
  1575. IN PPACTYPE OldPac,
  1576. OUT PPACTYPE *NewPac
  1577. )
  1578. {
  1579. ULONG cbBytes = 0;
  1580. ULONG cPacBuffers = 0;
  1581. PPAC_INFO_BUFFER Verifier = NULL;
  1582. PPACTYPE pNewPac = NULL;
  1583. PBYTE pDataStore;
  1584. NTSTATUS Status = STATUS_SUCCESS;
  1585. ULONG Index, iBuffer = 0;
  1586. *NewPac = NULL;
  1587. for (Index = 0; Index < OldPac->cBuffers ; Index++ )
  1588. {
  1589. if (OldPac->Buffers[Index].ulType != PAC_CLIENT_INFO_TYPE)
  1590. {
  1591. cbBytes += ROUND_UP_COUNT(OldPac->Buffers[Index].cbBufferSize,ALIGN_QUAD);
  1592. cPacBuffers++;
  1593. }
  1594. }
  1595. Status = KdcBuildPacVerifier(
  1596. ClientId,
  1597. CName,
  1598. &Verifier
  1599. );
  1600. if (!NT_SUCCESS(Status))
  1601. {
  1602. DebugLog((DEB_ERROR, "BuildPacVerifier failed\n"));
  1603. goto Cleanup;
  1604. }
  1605. cPacBuffers++;
  1606. cbBytes += ROUND_UP_COUNT(Verifier->cbBufferSize, ALIGN_QUAD);
  1607. //
  1608. // We need space for the PAC structure itself. Because the PAC_INFO_BUFFER
  1609. // is defined to be an array, a sizeof(PAC) already includes the
  1610. // size of ANYSIZE_ARRAY PAC_INFO_BUFFERs so we can subtract some bytes off.
  1611. //
  1612. cbBytes += sizeof(PACTYPE) +
  1613. (cPacBuffers - ANYSIZE_ARRAY) * sizeof(PAC_INFO_BUFFER);
  1614. cbBytes = ROUND_UP_COUNT( cbBytes, ALIGN_QUAD );
  1615. pNewPac = (PPACTYPE) MIDL_user_allocate( cbBytes );
  1616. if (pNewPac == NULL)
  1617. {
  1618. Status = STATUS_NO_MEMORY;
  1619. goto Cleanup;
  1620. }
  1621. pNewPac->cBuffers = cPacBuffers;
  1622. pDataStore = (PBYTE)&(pNewPac->Buffers[pNewPac->cBuffers]);
  1623. pDataStore = (PBYTE) ROUND_UP_POINTER( pDataStore, ALIGN_QUAD );
  1624. //
  1625. // Copy the data over
  1626. //
  1627. for (Index = 0; Index < OldPac->cBuffers ; Index++ )
  1628. {
  1629. if (OldPac->Buffers[Index].ulType != PAC_CLIENT_INFO_TYPE)
  1630. {
  1631. pNewPac->Buffers[iBuffer].ulType = OldPac->Buffers[Index].ulType;
  1632. pNewPac->Buffers[iBuffer].cbBufferSize = OldPac->Buffers[Index].cbBufferSize;
  1633. pNewPac->Buffers[iBuffer].Data = pDataStore;
  1634. RtlCopyMemory(
  1635. pDataStore,
  1636. OldPac->Buffers[Index].Data,
  1637. OldPac->Buffers[Index].cbBufferSize
  1638. );
  1639. pDataStore += pNewPac->Buffers[iBuffer].cbBufferSize;
  1640. pDataStore = (PBYTE) ROUND_UP_POINTER( pDataStore, ALIGN_QUAD );
  1641. iBuffer ++;
  1642. }
  1643. }
  1644. //
  1645. // Finally copy over the pac verifier.
  1646. //
  1647. pNewPac->Buffers[iBuffer].ulType = PAC_CLIENT_INFO_TYPE;
  1648. pNewPac->Buffers[iBuffer].cbBufferSize = Verifier->cbBufferSize;
  1649. pNewPac->Buffers[iBuffer].Data = pDataStore;
  1650. RtlCopyMemory(
  1651. pDataStore,
  1652. Verifier->Data,
  1653. Verifier->cbBufferSize
  1654. );
  1655. *NewPac = pNewPac;
  1656. pNewPac = NULL;
  1657. Cleanup:
  1658. if ( pNewPac )
  1659. {
  1660. MIDL_user_free( pNewPac);
  1661. }
  1662. return Status;
  1663. }
  1664. //+-------------------------------------------------------------------------
  1665. //
  1666. // Function: KdcUpdateAndValidateS4UProxyPAC
  1667. //
  1668. // Synopsis: Validates your target name from original pac, and updates
  1669. // existing info.
  1670. //
  1671. // Effects:
  1672. //
  1673. // Arguments:
  1674. //
  1675. // Requires:
  1676. //
  1677. // Returns:
  1678. //
  1679. // Notes:
  1680. //
  1681. //
  1682. //--------------------------------------------------------------------------
  1683. #define DEB_TEST_CODE 0xff000000
  1684. #define DEB_TEST_CODE2 0x00ff0000
  1685. KERBERR
  1686. KdcUpdateAndVerifyS4UPacVerifier(
  1687. IN PKDC_S4U_TICKET_INFO S4UTicketInfo,
  1688. IN OUT PUCHAR *PacData,
  1689. IN OUT PULONG PacSize
  1690. )
  1691. {
  1692. PPAC_INFO_BUFFER Verifier = NULL;
  1693. PPACTYPE OldPac;
  1694. ULONG OldPacSize;
  1695. PPACTYPE NewPac = NULL;
  1696. NTSTATUS Status;
  1697. KERBERR KerbErr = KDC_ERR_NONE;
  1698. PPAC_CLIENT_INFO ClientInfo = NULL;
  1699. TimeStamp ClientId;
  1700. UNICODE_STRING VerifierNames = {0};
  1701. UNICODE_STRING VerifierCName = {0};
  1702. UNICODE_STRING PreauthCName = {0};
  1703. UNICODE_STRING VerifierCRealm = {0};
  1704. PWSTR Realm = NULL;
  1705. PWSTR CName = NULL;
  1706. PPACTYPE RemarshalPac = NULL;
  1707. ULONG RemarshalPacSize = 0;
  1708. LONG i;
  1709. OldPac = (PPACTYPE) *PacData;
  1710. OldPacSize = *PacSize;
  1711. if (PAC_UnMarshal(OldPac, OldPacSize) == 0)
  1712. {
  1713. D_DebugLog((DEB_ERROR,"Failed to unmarshal pac\n"));
  1714. KerbErr = KDC_ERR_POLICY;
  1715. goto Cleanup;
  1716. }
  1717. //
  1718. // Must remember to remarshal the PAC prior to returning
  1719. //
  1720. RemarshalPac = OldPac;
  1721. RemarshalPacSize = OldPacSize;
  1722. Verifier = PAC_Find(
  1723. OldPac,
  1724. PAC_CLIENT_INFO_TYPE,
  1725. NULL
  1726. );
  1727. if ( Verifier == NULL )
  1728. {
  1729. DebugLog((DEB_ERROR, "Missing PAC verifier in S4U Tickets\n"));
  1730. DsysAssert(FALSE);
  1731. KerbErr = KDC_ERR_POLICY;
  1732. goto Cleanup;
  1733. }
  1734. if ( Verifier->cbBufferSize < sizeof(PAC_CLIENT_INFO) )
  1735. {
  1736. D_DebugLog((DEB_ERROR, "Clientinfo is too small: %d instead of %d\n", Verifier->cbBufferSize, sizeof(PAC_CLIENT_INFO)));
  1737. KerbErr = KDC_ERR_POLICY;
  1738. goto Cleanup;
  1739. }
  1740. ClientInfo = (PPAC_CLIENT_INFO) Verifier->Data;
  1741. if ((ClientInfo->NameLength - ANYSIZE_ARRAY * sizeof(WCHAR) + sizeof(PPAC_CLIENT_INFO)) > Verifier->cbBufferSize)
  1742. {
  1743. KerbErr = KDC_ERR_POLICY;
  1744. goto Cleanup;
  1745. }
  1746. KerbConvertGeneralizedTimeToLargeInt(
  1747. &ClientId,
  1748. &S4UTicketInfo->EvidenceTicket->authtime,
  1749. 0 // no usec
  1750. );
  1751. if (!RtlEqualMemory(
  1752. &ClientId,
  1753. &ClientInfo->ClientId,
  1754. sizeof(TimeStamp)
  1755. ))
  1756. {
  1757. D_DebugLog((DEB_ERROR, "Client IDs don't match.\n"));
  1758. KerbErr = KDC_ERR_POLICY;
  1759. goto Cleanup;
  1760. }
  1761. //
  1762. // Check the name now - for s4uself requests, the name is going
  1763. // to be cname@crealm. This was inserted by the KDC of crealm during
  1764. // the initial processing of the pa-for-user.
  1765. //
  1766. // Now, we have to substite in the "w2k" version of the pac verifier,
  1767. // as we're granting a service ticket to a s4uself request from our realm.
  1768. // So, there are a couple of checks to be done here:
  1769. //
  1770. //
  1771. // 1. Does the PA-FOR-USER cname match that in the verifier?
  1772. // 2. Does the PA-FOR-USER crealm match that in the verifier?
  1773. // 3. Does the validation info (PAC) cname match that in the verifier?
  1774. //
  1775. // If so, add in a W2K pac verfier.
  1776. //
  1777. VerifierNames.Length = ClientInfo->NameLength;
  1778. VerifierNames.MaximumLength = ClientInfo->NameLength + sizeof(WCHAR);
  1779. SafeAllocaAllocate( VerifierNames.Buffer, VerifierNames.MaximumLength);
  1780. if ( VerifierNames.Buffer == NULL )
  1781. {
  1782. KerbErr = KRB_ERR_GENERIC;
  1783. goto Cleanup;
  1784. }
  1785. RtlCopyMemory(
  1786. VerifierNames.Buffer,
  1787. ClientInfo->Name,
  1788. VerifierNames.Length
  1789. );
  1790. VerifierNames.Buffer[(VerifierNames.Length / sizeof(WCHAR))] = L'\0';
  1791. //
  1792. // Find the @ sign, and split. Search from the end of the string.
  1793. //
  1794. i = VerifierNames.Length / sizeof(WCHAR);
  1795. while (i > 0)
  1796. {
  1797. if (VerifierNames.Buffer[i] == L'@')
  1798. {
  1799. VerifierNames.Buffer[i] = L'\0';
  1800. if ( i < (LONG) (VerifierNames.Length / sizeof(WCHAR)) )
  1801. {
  1802. Realm = &VerifierNames.Buffer[i + 1];
  1803. CName = VerifierNames.Buffer;
  1804. break;
  1805. }
  1806. }
  1807. i--;
  1808. }
  1809. if ( Realm == NULL )
  1810. {
  1811. DebugLog((DEB_ERROR, "S4U Pac verifier missing @ sign\n"));
  1812. DsysAssert(FALSE);
  1813. KerbErr = KDC_ERR_POLICY;
  1814. goto Cleanup;
  1815. }
  1816. RtlInitUnicodeString(
  1817. &VerifierCRealm,
  1818. Realm
  1819. );
  1820. RtlInitUnicodeString(
  1821. &VerifierCName,
  1822. CName
  1823. );
  1824. if (!RtlEqualUnicodeString(
  1825. &VerifierCRealm,
  1826. &S4UTicketInfo->PACCRealm,
  1827. TRUE
  1828. ))
  1829. {
  1830. DebugLog((DEB_ERROR, "pa-for-user != pac verfier realm\n"));
  1831. DsysAssert(FALSE);
  1832. KerbErr = KDC_ERR_POLICY;
  1833. goto Cleanup;
  1834. }
  1835. KerbErr = KerbConvertKdcNameToString(
  1836. &PreauthCName,
  1837. S4UTicketInfo->PACCName,
  1838. NULL
  1839. );
  1840. if (!KERB_SUCCESS( KerbErr ))
  1841. {
  1842. goto Cleanup;
  1843. }
  1844. if (!RtlEqualUnicodeString(
  1845. &PreauthCName,
  1846. &VerifierCName,
  1847. TRUE
  1848. ))
  1849. {
  1850. DebugLog((DEB_ERROR, "pa-for-user != pac verifier cname\n"));
  1851. DsysAssert(FALSE);
  1852. KerbErr = KDC_ERR_POLICY;
  1853. goto Cleanup;
  1854. }
  1855. //
  1856. // Now check the validation information. Fester - netbios and dns names preclude this from
  1857. // working...
  1858. //
  1859. /*LogonInfo = PAC_Find(
  1860. OldPac,
  1861. PAC_LOGON_INFO,
  1862. NULL
  1863. );
  1864. if ( LogonInfo == NULL )
  1865. {
  1866. KerbErr = KRB_ERR_GENERIC;
  1867. Status = STATUS_INVALID_PARAMETER;
  1868. goto Cleanup;
  1869. }
  1870. Status = PAC_UnmarshallValidationInfo(
  1871. &LocalValidationInfo,
  1872. LogonInfo->Data,
  1873. LogonInfo->cbBufferSize
  1874. );
  1875. if ( !NT_SUCCESS( Status ))
  1876. {
  1877. KerbErr = KRB_ERR_GENERIC;
  1878. goto Cleanup;
  1879. }
  1880. if (!RtlEqualUnicodeString(
  1881. &LocalValidationInfo->EffectiveName,
  1882. &VerifierCName,
  1883. TRUE
  1884. ))
  1885. {
  1886. DebugLog((DEB_ERROR, "pa-for-user != logon info cname\n"));
  1887. DsysAssert(FALSE);
  1888. KerbErr = KDC_ERR_POLICY;
  1889. goto Cleanup;
  1890. }
  1891. //
  1892. // Fester - how do we use the Netbios domain name in Validation info
  1893. // to validate S4U Pac verifier?
  1894. // */
  1895. //
  1896. // Cool - everything looks good. Now remove the S4U pac verifier, and
  1897. // add in the W2K style verfier.
  1898. //
  1899. Status = KdcReplacePacVerifier(
  1900. &ClientId,
  1901. &VerifierCName,
  1902. OldPac,
  1903. &NewPac
  1904. );
  1905. if (!KERB_SUCCESS( KerbErr ))
  1906. {
  1907. DebugLog((DEB_ERROR, "KdcAddPacVerifier failed\n"));
  1908. DsysAssert(FALSE);
  1909. goto Cleanup;
  1910. }
  1911. MIDL_user_free( OldPac );
  1912. RemarshalPacSize = PAC_GetSize(NewPac);
  1913. RemarshalPac = NewPac;
  1914. NewPac = NULL;
  1915. Cleanup:
  1916. if ( RemarshalPac != NULL )
  1917. {
  1918. if (!PAC_ReMarshal(RemarshalPac, RemarshalPacSize))
  1919. {
  1920. DsysAssert(!"PAC_Remarshal Failed");
  1921. KerbErr = KRB_ERR_GENERIC;
  1922. }
  1923. *PacData = (PBYTE) RemarshalPac;
  1924. *PacSize = RemarshalPacSize;
  1925. }
  1926. SafeAllocaFree( VerifierNames.Buffer );
  1927. if (NewPac != NULL)
  1928. {
  1929. MIDL_user_free(NewPac);
  1930. }
  1931. KerbFreeString(&PreauthCName);
  1932. return KerbErr;
  1933. }
  1934. //+-------------------------------------------------------------------------
  1935. //
  1936. // Function: KdcUpdateAndValidateS4UProxyPAC
  1937. //
  1938. // Synopsis: Validates your target name from original pac, and updates
  1939. // existing info.
  1940. //
  1941. // Effects:
  1942. //
  1943. // Arguments:
  1944. //
  1945. // Requires:
  1946. //
  1947. // Returns:
  1948. //
  1949. // Notes:
  1950. //
  1951. //
  1952. //--------------------------------------------------------------------------
  1953. KERBERR
  1954. KdcUpdateAndValidateS4UProxyPAC(
  1955. IN PKDC_S4U_TICKET_INFO S4UTicketInfo,
  1956. IN OUT PUCHAR *PacData,
  1957. IN OUT PULONG PacSize,
  1958. OUT OPTIONAL PS4U_DELEGATION_INFO* S4UDelegationInfo
  1959. )
  1960. {
  1961. PPAC_INFO_BUFFER MarshalledDelegationInfo;
  1962. PS4U_DELEGATION_INFO DelegationInfo = NULL;
  1963. S4U_DELEGATION_INFO NewDelegInfo = {0};
  1964. BYTE* FinalDelegInfoMarshalled = NULL;
  1965. ULONG FinalDelegInfoMarshalledSize = 0;
  1966. PPACTYPE OldPac;
  1967. ULONG OldPacSize;
  1968. PPACTYPE NewPac = NULL;
  1969. ULONG NewPacSize = NULL;
  1970. PUNICODE_STRING TransittedService = NULL;
  1971. UNICODE_STRING tmpstring = {0};
  1972. PUNICODE_STRING NewTargetName = NULL;
  1973. NTSTATUS Status;
  1974. KERBERR KerbErr = KDC_ERR_NONE;
  1975. OldPac = (PPACTYPE) *PacData;
  1976. OldPacSize = *PacSize;
  1977. if (PAC_UnMarshal(OldPac, OldPacSize) == 0)
  1978. {
  1979. D_DebugLog((DEB_ERROR,"Failed to unmarshal pac\n"));
  1980. KerbErr = KRB_ERR_GENERIC;
  1981. goto Cleanup;
  1982. }
  1983. MarshalledDelegationInfo = PAC_Find(
  1984. OldPac,
  1985. PAC_DELEGATION_INFO,
  1986. NULL
  1987. );
  1988. if ( MarshalledDelegationInfo == NULL )
  1989. {
  1990. //
  1991. // If this is using S4U, and we don't have delegation info, bomb out
  1992. // here - someone's ripped out the delegation info while we were transiting.
  1993. //
  1994. if (( S4UTicketInfo->Flags & TI_PRXY_REQUESTOR_THIS_REALM) == 0 )
  1995. {
  1996. DebugLog((DEB_ERROR, "Missing delegation info while transitting %p\n", S4UTicketInfo));
  1997. DsysAssert(FALSE);
  1998. KerbErr = KDC_ERR_PATH_NOT_ACCEPTED;
  1999. goto Cleanup;
  2000. }
  2001. //
  2002. // Time to create one.
  2003. //
  2004. if (!NT_SUCCESS(KerbDuplicateString(
  2005. &NewDelegInfo.S4U2proxyTarget,
  2006. &S4UTicketInfo->TargetName
  2007. )))
  2008. {
  2009. KerbErr = KRB_ERR_GENERIC;
  2010. goto Cleanup;
  2011. }
  2012. DelegationInfo = &NewDelegInfo;
  2013. D_DebugLog((DEB_T_PAC, "KdcUpdateAndValidateS4UProxyPAC create new S4uDelegateInfo: target %wZ\n", &NewDelegInfo.S4U2proxyTarget));
  2014. }
  2015. else
  2016. {
  2017. if (!NT_SUCCESS( PAC_UnmarshallS4UDelegationInfo(
  2018. &DelegationInfo,
  2019. MarshalledDelegationInfo->Data,
  2020. MarshalledDelegationInfo->cbBufferSize
  2021. )))
  2022. {
  2023. D_DebugLog((DEB_ERROR, "Failed to unmarshall S4U delgation info\n"));
  2024. KerbErr = KRB_ERR_GENERIC;
  2025. goto Cleanup;
  2026. }
  2027. //
  2028. // If the target's in our realm, we need to verify that the target name
  2029. // in the PAC == the target name being requested.
  2030. //
  2031. // However, this only applies to validating the PAC in xrealm TGTs.
  2032. // If the requestor is in our realm, we need to create a targetname entry.
  2033. //
  2034. if (( S4UTicketInfo->Flags & TI_PRXY_REQUESTOR_THIS_REALM ) != 0 )
  2035. {
  2036. NewTargetName = &S4UTicketInfo->TargetName;
  2037. }
  2038. else if (( S4UTicketInfo->Flags & TI_TARGET_OUR_REALM ) != 0 )
  2039. {
  2040. if (!RtlEqualUnicodeString(
  2041. &S4UTicketInfo->TargetName,
  2042. &DelegationInfo->S4U2proxyTarget,
  2043. TRUE
  2044. ))
  2045. {
  2046. D_DebugLog((DEB_ERROR, "Wrong S4UProxytarget %wZ %wZ\n", &S4UTicketInfo->TargetName, &DelegationInfo->S4U2proxyTarget));
  2047. KerbErr = KDC_ERR_S_PRINCIPAL_UNKNOWN;
  2048. goto Cleanup;
  2049. }
  2050. }
  2051. D_DebugLog((DEB_T_PAC, "KdcUpdateAndValidateS4UProxyPAC add S4uDelegateInfo: target %wZ, flags %#x\n", NewTargetName, S4UTicketInfo->Flags));
  2052. }
  2053. //
  2054. // We're in the S4U requestor's realm - add in requestor's name into
  2055. // PAC.
  2056. //
  2057. if (( S4UTicketInfo->Flags & TI_PRXY_REQUESTOR_THIS_REALM) != 0 )
  2058. {
  2059. KerbErr = KerbConvertKdcNameToString(
  2060. &tmpstring,
  2061. S4UTicketInfo->RequestorServiceName,
  2062. ((S4UTicketInfo->RequestorServiceName->NameType == KRB_NT_ENTERPRISE_PRINCIPAL) && (S4UTicketInfo->RequestorServiceName->NameCount == 1))
  2063. ? NULL : &S4UTicketInfo->RequestorServiceRealm
  2064. );
  2065. if (!KERB_SUCCESS(KerbErr))
  2066. {
  2067. goto Cleanup;
  2068. }
  2069. TransittedService = &tmpstring;
  2070. D_DebugLog((DEB_T_PAC, "KdcUpdateAndValidateS4UProxyPAC add ts %wZ\n", TransittedService));
  2071. }
  2072. #if DBG
  2073. if (DelegationInfo)
  2074. {
  2075. D_DebugLog((DEB_T_PAC, "KdcUpdateAndValidateS4UProxyPAC target %wZ\n", &DelegationInfo->S4U2proxyTarget));
  2076. for ( ULONG i = 0; i < DelegationInfo->TransitedListSize; i++ )
  2077. {
  2078. D_DebugLog((DEB_T_PAC, "KdcUpdateAndValidateS4UProxyPAC existing ts %#x: %wZ\n", i, &DelegationInfo->S4UTransitedServices[i]));
  2079. }
  2080. }
  2081. #endif // DBG
  2082. Status = PAC_InitAndUpdateTransitedService(
  2083. DelegationInfo,
  2084. TransittedService,
  2085. NewTargetName,
  2086. OldPac,
  2087. &NewPac,
  2088. &FinalDelegInfoMarshalledSize,
  2089. &FinalDelegInfoMarshalled
  2090. );
  2091. if (!NT_SUCCESS( Status ))
  2092. {
  2093. KerbErr = KRB_ERR_GENERIC;
  2094. D_DebugLog((DEB_ERROR, "PacInit&UPdatedTransitedService fail - %x\n", Status));
  2095. goto Cleanup;
  2096. }
  2097. NewPacSize = PAC_GetSize(NewPac);
  2098. if (!PAC_ReMarshal(NewPac, NewPacSize))
  2099. {
  2100. DsysAssert(!"PAC_Remarshal Failed");
  2101. KerbErr = KRB_ERR_GENERIC;
  2102. goto Cleanup;
  2103. }
  2104. if (S4UDelegationInfo)
  2105. {
  2106. Status = UnmarshalS4UDelegationInformation(
  2107. FinalDelegInfoMarshalledSize,
  2108. FinalDelegInfoMarshalled,
  2109. S4UDelegationInfo
  2110. );
  2111. if (!NT_SUCCESS(Status))
  2112. {
  2113. KerbErr = KRB_ERR_GENERIC;
  2114. DebugLog((DEB_ERROR, "KdcUpdateAndValidateS4UProxyPAC failed to unmarshall S4U delgation info %#x\n", Status));
  2115. goto Cleanup;
  2116. }
  2117. }
  2118. if (*PacData != (PBYTE)NewPac)
  2119. {
  2120. MIDL_user_free(*PacData);
  2121. *PacData = (PBYTE) NewPac;
  2122. NewPac = NULL;
  2123. *PacSize = NewPacSize;
  2124. }
  2125. Cleanup:
  2126. KerbFreeString(&NewDelegInfo.S4U2proxyTarget);
  2127. if (( DelegationInfo != NULL ) &&
  2128. ( DelegationInfo != &NewDelegInfo ))
  2129. {
  2130. MIDL_user_free( DelegationInfo );
  2131. }
  2132. if (FinalDelegInfoMarshalled != NULL)
  2133. {
  2134. MIDL_user_free(FinalDelegInfoMarshalled);
  2135. }
  2136. KerbFreeString( &tmpstring );
  2137. if (NewPac != NULL)
  2138. {
  2139. MIDL_user_free(NewPac);
  2140. }
  2141. return (KerbErr);
  2142. }
  2143. //+-------------------------------------------------------------------------
  2144. //
  2145. // Function: KdcFilterSids
  2146. //
  2147. // Synopsis: Function that just call LsaIFilterSids. Pulled into this function
  2148. // for more widespread use than KdcCheckPacForSidFiltering.
  2149. //
  2150. // Effects:
  2151. //
  2152. // Arguments: ServerInfo structure containing attributes of the trust
  2153. // ValidationInfo authorization information to filter
  2154. //
  2155. // Requires:
  2156. //
  2157. // Returns: See LsaIFilterSids
  2158. //
  2159. // Notes:
  2160. //
  2161. //
  2162. //--------------------------------------------------------------------------
  2163. NTSTATUS
  2164. KdcFilterSids(
  2165. IN PKDC_TICKET_INFO ServerInfo,
  2166. IN PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo
  2167. )
  2168. {
  2169. NTSTATUS Status = STATUS_SUCCESS;
  2170. PUNICODE_STRING TrustedForest = NULL;
  2171. if ((ServerInfo->TrustAttributes & TRUST_ATTRIBUTE_FOREST_TRANSITIVE) != 0)
  2172. {
  2173. TrustedForest = &(ServerInfo->TrustedForest);
  2174. D_DebugLog((DEB_TRACE, "Filtering Sids for forest %wZ\n", TrustedForest));
  2175. }
  2176. if ( ServerInfo->TrustSid != NULL ||
  2177. ServerInfo->TrustType == TRUST_TYPE_MIT ||
  2178. ( ServerInfo->TrustAttributes & TRUST_ATTRIBUTE_CROSS_ORGANIZATION ) != 0 )
  2179. {
  2180. Status = LsaIFilterSids(
  2181. TrustedForest, // Pass domain name here
  2182. TRUST_DIRECTION_OUTBOUND,
  2183. ServerInfo->TrustType,
  2184. ServerInfo->TrustAttributes,
  2185. ServerInfo->TrustSid,
  2186. NetlogonValidationSamInfo2,
  2187. ValidationInfo,
  2188. NULL,
  2189. NULL,
  2190. NULL
  2191. );
  2192. if (!NT_SUCCESS(Status))
  2193. {
  2194. //
  2195. // Create an audit log if it looks like the SID has been tampered with
  2196. //
  2197. if ((STATUS_DOMAIN_TRUST_INCONSISTENT == Status) &&
  2198. SecData.AuditKdcEvent(KDC_AUDIT_TGS_FAILURE))
  2199. {
  2200. DWORD Dummy = 0;
  2201. KdcLsaIAuditTgsEvent(
  2202. SE_AUDITID_TGS_TICKET_REQUEST,
  2203. &ValidationInfo->EffectiveName,
  2204. &ValidationInfo->LogonDomainName,
  2205. NULL,
  2206. &ServerInfo->AccountName,
  2207. NULL,
  2208. &Dummy,
  2209. (PULONG) &Status,
  2210. NULL,
  2211. NULL, // no preauth type
  2212. GET_CLIENT_ADDRESS(NULL),
  2213. NULL, // no logon guid
  2214. NULL
  2215. );
  2216. }
  2217. DebugLog((DEB_ERROR,"Failed to filter SIDS (LsaIFilterSids): 0x%x\n",Status));
  2218. }
  2219. }
  2220. return Status;
  2221. }
  2222. //+-------------------------------------------------------------------------
  2223. //
  2224. // Function: KdcFilterNamespace
  2225. //
  2226. // Synopsis: Function that just call lsaifiltersids. Pulled into this function
  2227. // for more widespread use than KdcCheckPacForSidFiltering.
  2228. //
  2229. // Effects:
  2230. //
  2231. // Arguments: ServerInfo structure containing attributes of the trust
  2232. // ClientRealm namespace to filter
  2233. //
  2234. // Requires:
  2235. //
  2236. // Returns: KDC_ERR_NONE namespace is good to go
  2237. // KDC_ERR_POLICY filtering policy rejects this namespace
  2238. // KDC_ERR_GENERIC unexpected error (out of memory, etc)
  2239. //
  2240. // Notes:
  2241. //
  2242. //
  2243. //--------------------------------------------------------------------------
  2244. KERBERR
  2245. KdcFilterNamespace(
  2246. IN PKDC_TICKET_INFO ServerInfo,
  2247. IN KERB_REALM ClientRealm,
  2248. OUT PKERB_EXT_ERROR pExtendedError
  2249. )
  2250. {
  2251. NTSTATUS Status;
  2252. KERBERR KerbErr;
  2253. UNICODE_STRING ClientRealmU = {0};
  2254. if ( ServerInfo == NULL ||
  2255. ServerInfo->TrustType == 0 ||
  2256. ( ServerInfo->TrustSid == NULL && ServerInfo->TrustType != TRUST_TYPE_MIT ))
  2257. {
  2258. //
  2259. // Not going over a trust, simply succeed
  2260. //
  2261. return KDC_ERR_NONE;
  2262. }
  2263. //
  2264. // We can only digest Unicode strings below
  2265. //
  2266. KerbErr = KerbConvertRealmToUnicodeString(
  2267. &ClientRealmU,
  2268. &ClientRealm
  2269. );
  2270. if ( !KERB_SUCCESS( KerbErr ))
  2271. {
  2272. return KerbErr;
  2273. }
  2274. //
  2275. // Let LSA policy logic decide what's kosher
  2276. //
  2277. Status = LsaIFilterNamespace(
  2278. &ServerInfo->AccountName, // misnomer - contains DNS domain name
  2279. TRUST_DIRECTION_OUTBOUND,
  2280. ServerInfo->TrustType,
  2281. ServerInfo->TrustAttributes,
  2282. &ClientRealmU
  2283. );
  2284. KerbFreeString( &ClientRealmU );
  2285. switch ( Status )
  2286. {
  2287. case STATUS_SUCCESS:
  2288. return KDC_ERR_NONE;
  2289. case STATUS_DOMAIN_TRUST_INCONSISTENT:
  2290. FILL_EXT_ERROR_EX2( pExtendedError, STATUS_DOMAIN_TRUST_INCONSISTENT, FILENO, __LINE__ );
  2291. return KDC_ERR_POLICY;
  2292. case STATUS_INSUFFICIENT_RESOURCES:
  2293. default:
  2294. FILL_EXT_ERROR( pExtendedError, Status, FILENO, __LINE__ );
  2295. return KRB_ERR_GENERIC;
  2296. }
  2297. }
  2298. //+-------------------------------------------------------------------------
  2299. //
  2300. // Function: KdcCheckPacForSidFiltering
  2301. //
  2302. // Synopsis: If the server ticket info has a TDOSid then the function
  2303. // makes a check to make sure the SID from the TDO matches
  2304. // the client's home domain SID. A call to LsaIFilterSids
  2305. // is made to do the check. If this function fails with
  2306. // STATUS_TRUST_FAILURE then an audit log is generated.
  2307. // Otherwise the function succeeds but SIDs are filtered
  2308. // from the PAC.
  2309. //
  2310. // Effects:
  2311. //
  2312. // Arguments:
  2313. //
  2314. // Requires:
  2315. //
  2316. // Returns:
  2317. //
  2318. // Notes:
  2319. //
  2320. //
  2321. //--------------------------------------------------------------------------
  2322. KERBERR
  2323. KdcCheckPacForSidFiltering(
  2324. IN PKDC_TICKET_INFO ServerInfo,
  2325. IN OUT PUCHAR *PacData,
  2326. IN OUT PULONG PacSize
  2327. )
  2328. {
  2329. NTSTATUS Status;
  2330. KERBERR KerbErr = KDC_ERR_NONE;
  2331. PPAC_INFO_BUFFER LogonInfo;
  2332. PPACTYPE OldPac;
  2333. ULONG OldPacSize;
  2334. PPACTYPE NewPac = NULL;
  2335. PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo = NULL;
  2336. SAMPR_PSID_ARRAY ZeroResourceGroups;
  2337. ULONG OldExtraSidCount;
  2338. PNETLOGON_SID_AND_ATTRIBUTES SavedExtraSids = NULL;
  2339. PPACTYPE RemarshalPac = NULL;
  2340. ULONG RemarshalPacSize = 0;
  2341. OldPac = (PPACTYPE) *PacData;
  2342. OldPacSize = *PacSize;
  2343. if (PAC_UnMarshal(OldPac, OldPacSize) == 0)
  2344. {
  2345. D_DebugLog((DEB_ERROR,"Failed to unmarshal pac\n"));
  2346. KerbErr = KRB_ERR_GENERIC;
  2347. goto Cleanup;
  2348. }
  2349. //
  2350. // Must remember to remarshal the PAC prior to returning
  2351. //
  2352. RemarshalPac = OldPac;
  2353. RemarshalPacSize = OldPacSize;
  2354. RtlZeroMemory(
  2355. &ZeroResourceGroups,
  2356. sizeof(ZeroResourceGroups)); // allows us to use PAC_InitAndUpdateGroups to remarshal the PAC
  2357. //
  2358. // First, find the logon information
  2359. //
  2360. LogonInfo = PAC_Find(
  2361. OldPac,
  2362. PAC_LOGON_INFO,
  2363. NULL
  2364. );
  2365. if (LogonInfo == NULL)
  2366. {
  2367. D_DebugLog((DEB_WARN,"No logon info for PAC - not making SID filtering check\n"));
  2368. KerbErr = KRB_ERR_GENERIC;
  2369. goto Cleanup;
  2370. }
  2371. //
  2372. // Now unmarshall the validation information and build a list of sids
  2373. //
  2374. if (!NT_SUCCESS(PAC_UnmarshallValidationInfo(
  2375. &ValidationInfo,
  2376. LogonInfo->Data,
  2377. LogonInfo->cbBufferSize)))
  2378. {
  2379. D_DebugLog((DEB_ERROR,"Failed to unmarshall validation info!\n"));
  2380. KerbErr = KRB_ERR_GENERIC;
  2381. goto Cleanup;
  2382. }
  2383. //
  2384. // Save the old extra SID count (so that if KdcFilterSids compresses
  2385. // the SID array, we can avoid allocating memory for the other-org SID later)
  2386. //
  2387. OldExtraSidCount = ValidationInfo->SidCount;
  2388. //
  2389. // Call lsaifiltersids().
  2390. //
  2391. Status = KdcFilterSids(
  2392. ServerInfo,
  2393. ValidationInfo
  2394. );
  2395. if (!NT_SUCCESS(Status))
  2396. {
  2397. KerbErr = KDC_ERR_POLICY;
  2398. goto Cleanup;
  2399. }
  2400. //
  2401. // If we're crossing an organization boundary, add the "other organization"
  2402. // SID to the PAC.
  2403. //
  2404. // NOTE: for efficiency reasons, no check is made for whether the
  2405. // SID is already in the PAC. The hope is that adding a duplicate
  2406. // SID will not cause problems.
  2407. //
  2408. if ( ServerInfo->TrustAttributes & TRUST_ATTRIBUTE_CROSS_ORGANIZATION )
  2409. {
  2410. if ( ValidationInfo->SidCount >= OldExtraSidCount )
  2411. {
  2412. SavedExtraSids = ValidationInfo->ExtraSids;
  2413. SafeAllocaAllocate(
  2414. ValidationInfo->ExtraSids,
  2415. sizeof( SID_AND_ATTRIBUTES ) * ( ValidationInfo->SidCount + 1 )
  2416. );
  2417. if ( ValidationInfo->ExtraSids == NULL )
  2418. {
  2419. ValidationInfo->ExtraSids = SavedExtraSids;
  2420. SavedExtraSids = NULL;
  2421. KerbErr = KRB_ERR_GENERIC;
  2422. goto Cleanup;
  2423. }
  2424. RtlCopyMemory(
  2425. ValidationInfo->ExtraSids,
  2426. SavedExtraSids,
  2427. sizeof( SID_AND_ATTRIBUTES ) * ValidationInfo->SidCount
  2428. );
  2429. }
  2430. ValidationInfo->ExtraSids[ValidationInfo->SidCount].Sid =
  2431. GlobalOtherOrganizationSid;
  2432. ValidationInfo->ExtraSids[ValidationInfo->SidCount].Attributes =
  2433. SE_GROUP_MANDATORY |
  2434. SE_GROUP_ENABLED_BY_DEFAULT |
  2435. SE_GROUP_ENABLED;
  2436. ValidationInfo->SidCount += 1;
  2437. }
  2438. //
  2439. // Now build a new pac
  2440. //
  2441. Status = PAC_InitAndUpdateGroups(
  2442. ValidationInfo,
  2443. &ZeroResourceGroups,
  2444. OldPac,
  2445. &NewPac
  2446. );
  2447. if (!NT_SUCCESS(Status))
  2448. {
  2449. KerbErr = KRB_ERR_GENERIC;
  2450. goto Cleanup;
  2451. }
  2452. RemarshalPacSize = PAC_GetSize(NewPac);
  2453. RemarshalPac = NewPac;
  2454. Cleanup:
  2455. if ( RemarshalPac != NULL )
  2456. {
  2457. if (!PAC_ReMarshal(RemarshalPac, RemarshalPacSize))
  2458. {
  2459. DsysAssert(!"PAC_Remarshal Failed");
  2460. KerbErr = KRB_ERR_GENERIC;
  2461. }
  2462. else if ( NewPac != NULL &&
  2463. *PacData != (PBYTE)NewPac )
  2464. {
  2465. MIDL_user_free(*PacData);
  2466. *PacData = (PBYTE) NewPac;
  2467. NewPac = NULL;
  2468. *PacSize = RemarshalPacSize;
  2469. }
  2470. }
  2471. if (NewPac != NULL)
  2472. {
  2473. MIDL_user_free(NewPac);
  2474. }
  2475. if ( SavedExtraSids != NULL )
  2476. {
  2477. SafeAllocaFree( ValidationInfo->ExtraSids );
  2478. ValidationInfo->ExtraSids = SavedExtraSids;
  2479. ValidationInfo->SidCount -= 1;
  2480. }
  2481. if (ValidationInfo != NULL)
  2482. {
  2483. MIDL_user_free(ValidationInfo);
  2484. }
  2485. return(KerbErr);
  2486. }
  2487. #ifdef ROGUE_DC
  2488. #pragma message( "COMPILING A ROGUE DC!!!" )
  2489. #pragma message( "MUST NOT SHIP THIS BUILD!!!" )
  2490. extern HKEY hKdcRogueKey;
  2491. KERBERR
  2492. KdcInstrumentRoguePac(
  2493. IN OUT PKERB_AUTHORIZATION_DATA PacAuthData
  2494. )
  2495. {
  2496. KERBERR KerbErr;
  2497. NTSTATUS Status;
  2498. PNETLOGON_VALIDATION_SAM_INFO3 OldValidationInfo = NULL;
  2499. NETLOGON_VALIDATION_SAM_INFO3 NewValidationInfo = {0};
  2500. SAMPR_PSID_ARRAY ZeroResourceGroups = {0};
  2501. PPACTYPE NewPac = NULL;
  2502. ULONG NewPacSize;
  2503. PPAC_INFO_BUFFER LogonInfo;
  2504. PSID LogonDomainId = NULL;
  2505. PSID ResourceGroupDomainSid = NULL;
  2506. PGROUP_MEMBERSHIP GroupIds = NULL;
  2507. PGROUP_MEMBERSHIP ResourceGroupIds = NULL;
  2508. PNETLOGON_SID_AND_ATTRIBUTES ExtraSids = NULL;
  2509. BYTE FullUserSidBuffer[MAX_SID_LEN];
  2510. SID * FullUserSid = ( SID * )FullUserSidBuffer;
  2511. CHAR * FullUserSidText = NULL;
  2512. DWORD dwType;
  2513. DWORD cbData = 0;
  2514. PCHAR Buffer;
  2515. PCHAR Value = NULL;
  2516. BOOLEAN PacChanged = FALSE;
  2517. //
  2518. // Optimization: no "rogue" key in registry - nothing for us to do
  2519. //
  2520. if ( hKdcRogueKey == NULL )
  2521. {
  2522. return STATUS_SUCCESS;
  2523. }
  2524. //
  2525. // Unmarshall the old PAC
  2526. //
  2527. if ( PAC_UnMarshal(
  2528. (PPACTYPE)PacAuthData->value.auth_data.value,
  2529. PacAuthData->value.auth_data.length) == 0 )
  2530. {
  2531. DebugLog((DEB_ERROR, "ROGUE: Unable to unmarshal the PAC\n"));
  2532. KerbErr = KRB_ERR_GENERIC;
  2533. goto Cleanup;
  2534. }
  2535. //
  2536. // First, find the logon information
  2537. //
  2538. LogonInfo = PAC_Find(
  2539. (PPACTYPE)PacAuthData->value.auth_data.value,
  2540. PAC_LOGON_INFO,
  2541. NULL
  2542. );
  2543. if ( LogonInfo == NULL )
  2544. {
  2545. DebugLog((DEB_ERROR, "ROGUE: No logon info on PAC - not performing substitution\n"));
  2546. KerbErr = KDC_ERR_NONE;
  2547. goto Error;
  2548. }
  2549. //
  2550. // Now unmarshall the validation information and build a list of sids
  2551. //
  2552. if ( !NT_SUCCESS(PAC_UnmarshallValidationInfo(
  2553. &OldValidationInfo,
  2554. LogonInfo->Data,
  2555. LogonInfo->cbBufferSize )))
  2556. {
  2557. DebugLog((DEB_ERROR, "ROGUE: Unable to unmarshal validation info\n"));
  2558. KerbErr = KRB_ERR_GENERIC;
  2559. goto Error;
  2560. }
  2561. //
  2562. // Construct the text form of the full user's SID (logon domain ID + user ID)
  2563. //
  2564. DsysAssert( sizeof( FullUserSidBuffer ) >= MAX_SID_LEN );
  2565. RtlCopySid(
  2566. sizeof( FullUserSidBuffer ),
  2567. FullUserSid,
  2568. OldValidationInfo->LogonDomainId
  2569. );
  2570. FullUserSid->SubAuthority[FullUserSid->SubAuthorityCount] = OldValidationInfo->UserId;
  2571. FullUserSid->SubAuthorityCount += 1;
  2572. if ( FALSE == ConvertSidToStringSidA(
  2573. FullUserSid,
  2574. &FullUserSidText ))
  2575. {
  2576. DebugLog((DEB_ERROR, "ROGUE: Unable to convert user's SID\n"));
  2577. KerbErr = KRB_ERR_GENERIC;
  2578. goto Error;
  2579. }
  2580. //
  2581. // Now look in the registry for the SID matching the validation info
  2582. //
  2583. if ( ERROR_SUCCESS != RegQueryValueExA(
  2584. hKdcRogueKey,
  2585. FullUserSidText,
  2586. NULL,
  2587. &dwType,
  2588. NULL,
  2589. &cbData ) ||
  2590. dwType != REG_MULTI_SZ ||
  2591. cbData <= 1 )
  2592. {
  2593. DebugLog((DEB_ERROR, "ROGUE: No substitution info available for %s\n", FullUserSidText));
  2594. KerbErr = KDC_ERR_NONE;
  2595. goto Error;
  2596. }
  2597. SafeAllocaAllocate( Value, cbData );
  2598. if ( Value == NULL )
  2599. {
  2600. DebugLog((DEB_ERROR, "ROGUE: Out of memory allocating substitution buffer\n", FullUserSidText));
  2601. KerbErr = KRB_ERR_GENERIC;
  2602. goto Error;
  2603. }
  2604. if ( ERROR_SUCCESS != RegQueryValueExA(
  2605. hKdcRogueKey,
  2606. FullUserSidText,
  2607. NULL,
  2608. &dwType,
  2609. (PBYTE)Value,
  2610. &cbData ) ||
  2611. dwType != REG_MULTI_SZ ||
  2612. cbData <= 1 )
  2613. {
  2614. DebugLog((DEB_ERROR, "ROGUE: Error reading from registry\n"));
  2615. KerbErr = KRB_ERR_GENERIC;
  2616. goto Error;
  2617. }
  2618. DebugLog((DEB_ERROR, "ROGUE: Substituting the PAC for %s\n", FullUserSidText));
  2619. if ( _stricmp( Value, "xPAC" ) == 0 )
  2620. {
  2621. //
  2622. // This means that the logon info should be stripped from the PAC
  2623. //
  2624. Status = PAC_RemoveSection(
  2625. (PPACTYPE)PacAuthData->value.auth_data.value,
  2626. PAC_LOGON_INFO,
  2627. &NewPac
  2628. );
  2629. if ( NT_SUCCESS( Status ))
  2630. {
  2631. NewPacSize = PAC_GetSize( NewPac );
  2632. if (!PAC_ReMarshal(NewPac, NewPacSize))
  2633. {
  2634. DsysAssert(!"PAC_Remarshal Failed");
  2635. KerbErr = KRB_ERR_GENERIC;
  2636. goto Error;
  2637. }
  2638. MIDL_user_free( PacAuthData->value.auth_data.value );
  2639. PacAuthData->value.auth_data.value = (PBYTE) NewPac;
  2640. NewPac = NULL;
  2641. PacAuthData->value.auth_data.length = NewPacSize;
  2642. }
  2643. else
  2644. {
  2645. DebugLog((DEB_ERROR, "ROGUE: Unable to strip PAC_LOGON_INFO\n"));
  2646. }
  2647. KerbErr = KDC_ERR_NONE;
  2648. goto Cleanup;
  2649. }
  2650. Buffer = Value;
  2651. //
  2652. // New validation info will be overloaded with stuff from the file
  2653. //
  2654. NewValidationInfo = *OldValidationInfo;
  2655. //
  2656. // Read the input file one line at a time
  2657. //
  2658. while ( *Buffer != '\0' )
  2659. {
  2660. switch( Buffer[0] )
  2661. {
  2662. case 'l':
  2663. case 'L': // logon domain ID
  2664. if ( LogonDomainId != NULL )
  2665. {
  2666. DebugLog((DEB_ERROR, "ROGUE: Logon domain ID specified more than once - only first one kept\n"));
  2667. break;
  2668. }
  2669. DebugLog((DEB_ERROR, "ROGUE: Substituting logon domain ID by %s\n", &Buffer[1]));
  2670. if ( FALSE == ConvertStringSidToSidA(
  2671. &Buffer[1],
  2672. &LogonDomainId ))
  2673. {
  2674. DebugLog((DEB_ERROR, "ROGUE: Unable to convert SID\n"));
  2675. KerbErr = KRB_ERR_GENERIC;
  2676. goto Error;
  2677. }
  2678. if ( LogonDomainId == NULL )
  2679. {
  2680. DebugLog((DEB_ERROR, "ROGUE: Out of memory allocating LogonDomainId\n"));
  2681. KerbErr = KRB_ERR_GENERIC;
  2682. goto Error;
  2683. }
  2684. NewValidationInfo.LogonDomainId = LogonDomainId;
  2685. LogonDomainId = NULL;
  2686. PacChanged = TRUE;
  2687. break;
  2688. case 'd':
  2689. case 'D': // resource group domain SID
  2690. if ( ResourceGroupDomainSid != NULL )
  2691. {
  2692. DebugLog((DEB_ERROR, "ROGUE: Resource group domain SID specified more than once - only first one kept\n"));
  2693. break;
  2694. }
  2695. DebugLog((DEB_ERROR, "ROGUE: Substituting resource group domain SID by %s\n", &Buffer[1]));
  2696. if ( FALSE == ConvertStringSidToSidA(
  2697. &Buffer[1],
  2698. &ResourceGroupDomainSid ))
  2699. {
  2700. DebugLog((DEB_ERROR, "ROGUE: Unable to convert SID\n"));
  2701. KerbErr = KRB_ERR_GENERIC;
  2702. goto Error;
  2703. }
  2704. if ( ResourceGroupDomainSid == NULL )
  2705. {
  2706. DebugLog((DEB_ERROR, "ROGUE: Out of memory allocating ResourceGroupDomainSid\n"));
  2707. KerbErr = KRB_ERR_GENERIC;
  2708. goto Error;
  2709. }
  2710. NewValidationInfo.ResourceGroupDomainSid = ResourceGroupDomainSid;
  2711. ResourceGroupDomainSid = NULL;
  2712. PacChanged = TRUE;
  2713. break;
  2714. case 'p':
  2715. case 'P': // primary group ID
  2716. DebugLog((DEB_ERROR, "ROGUE: Substituting primary group ID by %s\n", &Buffer[1]));
  2717. NewValidationInfo.PrimaryGroupId = atoi(&Buffer[1]);
  2718. PacChanged = TRUE;
  2719. break;
  2720. case 'u':
  2721. case 'U': // User ID
  2722. DebugLog((DEB_ERROR, "ROGUE: Substituting user ID by %s\n", &Buffer[1]));
  2723. NewValidationInfo.UserId = atoi(&Buffer[1]);
  2724. PacChanged = TRUE;
  2725. break;
  2726. case 'e':
  2727. case 'E': // Extra SID
  2728. DebugLog((DEB_ERROR, "ROGUE: Adding an ExtraSid: %s\n", &Buffer[1]));
  2729. if ( ExtraSids == NULL )
  2730. {
  2731. NewValidationInfo.ExtraSids = NULL;
  2732. NewValidationInfo.SidCount = 0;
  2733. ExtraSids = ( PNETLOGON_SID_AND_ATTRIBUTES )HeapAlloc(
  2734. GetProcessHeap(),
  2735. 0,
  2736. sizeof( NETLOGON_SID_AND_ATTRIBUTES )
  2737. );
  2738. }
  2739. else
  2740. {
  2741. ExtraSids = ( PNETLOGON_SID_AND_ATTRIBUTES )HeapReAlloc(
  2742. GetProcessHeap(),
  2743. 0,
  2744. NewValidationInfo.ExtraSids,
  2745. ( NewValidationInfo.SidCount + 1 ) * sizeof( NETLOGON_SID_AND_ATTRIBUTES )
  2746. );
  2747. }
  2748. if ( ExtraSids == NULL )
  2749. {
  2750. DebugLog((DEB_ERROR, "ROGUE: Out of memory allocating ExtraSids\n"));
  2751. ExtraSids = NewValidationInfo.ExtraSids;
  2752. KerbErr = KRB_ERR_GENERIC;
  2753. goto Error;
  2754. }
  2755. //
  2756. // Read the actual SID
  2757. //
  2758. NewValidationInfo.ExtraSids = ExtraSids;
  2759. if ( FALSE == ConvertStringSidToSidA(
  2760. &Buffer[1],
  2761. &NewValidationInfo.ExtraSids[NewValidationInfo.SidCount].Sid ))
  2762. {
  2763. DebugLog((DEB_ERROR, "ROGUE: Unable to convert SID\n"));
  2764. KerbErr = KRB_ERR_GENERIC;
  2765. goto Error;
  2766. }
  2767. if ( NewValidationInfo.ExtraSids[NewValidationInfo.SidCount].Sid == NULL )
  2768. {
  2769. DebugLog((DEB_ERROR, "ROGUE: Out of memory allocating an extra SID\n"));
  2770. KerbErr = KRB_ERR_GENERIC;
  2771. goto Error;
  2772. }
  2773. NewValidationInfo.ExtraSids[NewValidationInfo.SidCount].Attributes =
  2774. SE_GROUP_MANDATORY |
  2775. SE_GROUP_ENABLED_BY_DEFAULT |
  2776. SE_GROUP_ENABLED;
  2777. NewValidationInfo.SidCount += 1;
  2778. PacChanged = TRUE;
  2779. break;
  2780. case 'g':
  2781. case 'G': // Group ID
  2782. DebugLog((DEB_ERROR, "ROGUE: Adding a GroupId: %s\n", &Buffer[1]));
  2783. if ( GroupIds == NULL )
  2784. {
  2785. NewValidationInfo.GroupIds = NULL;
  2786. NewValidationInfo.GroupCount = 0;
  2787. GroupIds = ( PGROUP_MEMBERSHIP )HeapAlloc(
  2788. GetProcessHeap(),
  2789. 0,
  2790. sizeof( GROUP_MEMBERSHIP )
  2791. );
  2792. }
  2793. else
  2794. {
  2795. GroupIds = ( PGROUP_MEMBERSHIP )HeapReAlloc(
  2796. GetProcessHeap(),
  2797. 0,
  2798. NewValidationInfo.GroupIds,
  2799. ( NewValidationInfo.GroupCount + 1 ) * sizeof( GROUP_MEMBERSHIP )
  2800. );
  2801. }
  2802. if ( GroupIds == NULL )
  2803. {
  2804. DebugLog((DEB_ERROR, "ROGUE: Out of memory allocating Group IDs\n"));
  2805. GroupIds = NewValidationInfo.GroupIds;
  2806. KerbErr = KRB_ERR_GENERIC;
  2807. goto Error;
  2808. }
  2809. //
  2810. // Read the actual ID
  2811. //
  2812. NewValidationInfo.GroupIds = GroupIds;
  2813. NewValidationInfo.GroupIds[NewValidationInfo.GroupCount].RelativeId = atoi(&Buffer[1]);
  2814. NewValidationInfo.GroupIds[NewValidationInfo.GroupCount].Attributes =
  2815. SE_GROUP_MANDATORY |
  2816. SE_GROUP_ENABLED_BY_DEFAULT |
  2817. SE_GROUP_ENABLED;
  2818. NewValidationInfo.GroupCount += 1;
  2819. PacChanged = TRUE;
  2820. break;
  2821. case 'r':
  2822. case 'R': // Resource groups
  2823. DebugLog((DEB_ERROR, "ROGUE: Adding a ResourceGroupId: %s\n", &Buffer[1]));
  2824. if ( ResourceGroupIds == NULL )
  2825. {
  2826. NewValidationInfo.ResourceGroupIds = NULL;
  2827. NewValidationInfo.ResourceGroupCount = 0;
  2828. ResourceGroupIds = ( PGROUP_MEMBERSHIP )HeapAlloc(
  2829. GetProcessHeap(),
  2830. 0,
  2831. sizeof( GROUP_MEMBERSHIP )
  2832. );
  2833. }
  2834. else
  2835. {
  2836. ResourceGroupIds = ( PGROUP_MEMBERSHIP )HeapReAlloc(
  2837. GetProcessHeap(),
  2838. 0,
  2839. NewValidationInfo.ResourceGroupIds,
  2840. ( NewValidationInfo.ResourceGroupCount + 1 ) * sizeof( GROUP_MEMBERSHIP )
  2841. );
  2842. }
  2843. if ( ResourceGroupIds == NULL )
  2844. {
  2845. DebugLog((DEB_ERROR, "ROGUE: Out of memory allocating Resource Group IDs\n"));
  2846. ResourceGroupIds = NewValidationInfo.ResourceGroupIds;
  2847. KerbErr = KRB_ERR_GENERIC;
  2848. goto Error;
  2849. }
  2850. //
  2851. // Read the actual ID
  2852. //
  2853. NewValidationInfo.ResourceGroupIds = ResourceGroupIds;
  2854. NewValidationInfo.ResourceGroupIds[NewValidationInfo.ResourceGroupCount].RelativeId = atoi(&Buffer[1]);
  2855. NewValidationInfo.ResourceGroupIds[NewValidationInfo.ResourceGroupCount].Attributes =
  2856. SE_GROUP_MANDATORY |
  2857. SE_GROUP_ENABLED_BY_DEFAULT |
  2858. SE_GROUP_ENABLED;
  2859. NewValidationInfo.ResourceGroupCount += 1;
  2860. PacChanged = TRUE;
  2861. break;
  2862. default: // unrecognized
  2863. DebugLog((DEB_ERROR, "ROGUE: Entry \'%c\' unrecognized\n", Buffer[0]));
  2864. break;
  2865. }
  2866. //
  2867. // Move to the next line
  2868. //
  2869. while (*Buffer++ != '\0');
  2870. }
  2871. if ( !PacChanged )
  2872. {
  2873. DebugLog((DEB_ERROR, "ROGUE: Nothing to substitute for %s\n", FullUserSidText));
  2874. KerbErr = KDC_ERR_NONE;
  2875. goto Error;
  2876. }
  2877. //
  2878. // If resource group IDs were added, indicate that by setting the corresponding flag
  2879. //
  2880. if ( ResourceGroupIds )
  2881. {
  2882. NewValidationInfo.UserFlags |= LOGON_RESOURCE_GROUPS;
  2883. }
  2884. //
  2885. // If extra SIDs were added, indicate that by setting the corresponding flag
  2886. //
  2887. if ( ExtraSids )
  2888. {
  2889. NewValidationInfo.UserFlags |= LOGON_EXTRA_SIDS;
  2890. }
  2891. //
  2892. // Now build a new pac
  2893. //
  2894. Status = PAC_InitAndUpdateGroups(
  2895. &NewValidationInfo,
  2896. &ZeroResourceGroups,
  2897. (PPACTYPE)PacAuthData->value.auth_data.value,
  2898. &NewPac
  2899. );
  2900. if ( !NT_SUCCESS( Status ))
  2901. {
  2902. DebugLog((DEB_ERROR, "ROGUE: Error 0x%x from PAC_InitAndUpdateGroups\n"));
  2903. KerbErr = KRB_ERR_GENERIC;
  2904. goto Error;
  2905. }
  2906. NewPacSize = PAC_GetSize( NewPac );
  2907. if (!PAC_ReMarshal(NewPac, NewPacSize))
  2908. {
  2909. DsysAssert(!"PAC_Remarshal Failed");
  2910. KerbErr = KRB_ERR_GENERIC;
  2911. goto Error;
  2912. }
  2913. MIDL_user_free( PacAuthData->value.auth_data.value );
  2914. PacAuthData->value.auth_data.value = (PBYTE) NewPac;
  2915. NewPac = NULL;
  2916. PacAuthData->value.auth_data.length = NewPacSize;
  2917. KerbErr = KDC_ERR_NONE;
  2918. Cleanup:
  2919. MIDL_user_free( OldValidationInfo );
  2920. LocalFree( FullUserSidText );
  2921. LocalFree( ResourceGroupDomainSid );
  2922. LocalFree( LogonDomainId );
  2923. HeapFree( GetProcessHeap(), 0, ResourceGroupIds );
  2924. HeapFree( GetProcessHeap(), 0, GroupIds );
  2925. if ( ExtraSids )
  2926. {
  2927. for ( ULONG i = 0; i < NewValidationInfo.SidCount; i++ )
  2928. {
  2929. HeapFree( GetProcessHeap(), 0, ExtraSids[i].Sid );
  2930. }
  2931. HeapFree( GetProcessHeap(), 0, ExtraSids );
  2932. }
  2933. MIDL_user_free( NewPac );
  2934. SafeAllocaFree( Value );
  2935. return KerbErr;
  2936. Error:
  2937. if ( !KERB_SUCCESS( KerbErr ))
  2938. {
  2939. DebugLog((DEB_ERROR, "ROGUE: Substitution encountered an error, not performed\n"));
  2940. }
  2941. if ( !PAC_ReMarshal(
  2942. (PPACTYPE)PacAuthData->value.auth_data.value,
  2943. PacAuthData->value.auth_data.length ))
  2944. {
  2945. DsysAssert(!"PAC_Remarshal Failed");
  2946. KerbErr = KRB_ERR_GENERIC;
  2947. }
  2948. goto Cleanup;
  2949. }
  2950. #endif
  2951. //+-------------------------------------------------------------------------
  2952. //
  2953. // Function: KdcVerifyAndResignPac
  2954. //
  2955. // Synopsis: Verifies the signature on a PAC and re-signs it with the
  2956. // new servers & kdc's key
  2957. //
  2958. // Effects:
  2959. //
  2960. // Arguments:
  2961. //
  2962. // Requires:
  2963. //
  2964. // Returns:
  2965. //
  2966. // Notes:
  2967. //
  2968. //
  2969. //--------------------------------------------------------------------------
  2970. KERBERR
  2971. KdcCheckForDelegationInfo(
  2972. IN OUT PUCHAR PacData,
  2973. IN OUT ULONG PacSize,
  2974. IN OUT PBOOLEAN InfoPresent
  2975. )
  2976. {
  2977. KERBERR KerbErr = KDC_ERR_NONE;
  2978. PPAC_INFO_BUFFER DelegationInfo = NULL;
  2979. PPACTYPE Pac;
  2980. ULONG Size;
  2981. *InfoPresent = FALSE;
  2982. Pac = (PPACTYPE) PacData;
  2983. Size = PacSize;
  2984. if (PAC_UnMarshal(Pac, Size) == 0)
  2985. {
  2986. D_DebugLog((DEB_ERROR,"Failed to unmarshal pac\n"));
  2987. return KRB_ERR_GENERIC;
  2988. }
  2989. DelegationInfo = PAC_Find(
  2990. Pac,
  2991. PAC_DELEGATION_INFO,
  2992. NULL
  2993. );
  2994. if (!PAC_ReMarshal(Pac, Size))
  2995. {
  2996. DsysAssert(!"PAC_Remarshal Failed");
  2997. return KRB_ERR_GENERIC;
  2998. }
  2999. *InfoPresent = (DelegationInfo != NULL);
  3000. return KerbErr;
  3001. }
  3002. //+-------------------------------------------------------------------------
  3003. //
  3004. // Function: KdcVerifyAndResignPac
  3005. //
  3006. // Synopsis: Verifies the signature on a PAC and re-signs it with the
  3007. // new servers & kdc's key
  3008. //
  3009. // Effects:
  3010. //
  3011. // Arguments:
  3012. //
  3013. // Requires:
  3014. //
  3015. // Returns:
  3016. //
  3017. // Notes:
  3018. //
  3019. //
  3020. //--------------------------------------------------------------------------
  3021. KERBERR
  3022. KdcVerifyAndResignPac(
  3023. IN PKERB_ENCRYPTION_KEY OldKey,
  3024. IN PKERB_ENCRYPTION_KEY NewKey,
  3025. IN PKDC_TICKET_INFO OldServerInfo,
  3026. IN OPTIONAL PKDC_TICKET_INFO TargetServiceInfo,
  3027. IN OPTIONAL PKDC_S4U_TICKET_INFO S4UTicketInfo,
  3028. IN OPTIONAL PKERB_ENCRYPTED_TICKET FinalTicket,
  3029. IN BOOLEAN AddResourceGroups,
  3030. IN PKERB_EXT_ERROR ExtendedError,
  3031. IN OUT PKERB_AUTHORIZATION_DATA PacAuthData,
  3032. OUT OPTIONAL PS4U_DELEGATION_INFO* S4UDelegationInfo
  3033. )
  3034. {
  3035. KERBERR KerbErr = KDC_ERR_NONE;
  3036. BOOLEAN InfoPresent = FALSE;
  3037. BOOLEAN DCTarget = FALSE;
  3038. TRACE(KDC, KdcVerifyAndResignPac, DEB_FUNCTION);
  3039. PKDC_TICKET_INFO LocalServerInfo = OldServerInfo;
  3040. //
  3041. // If the TI_PRXY_REQUESTOR_THIS_REALM bit is set, then
  3042. // the evidence ticket is encrypted in the requestor's key.
  3043. //
  3044. if (( ARGUMENT_PRESENT( S4UTicketInfo ) ) &&
  3045. ( S4UTicketInfo->Flags & TI_S4UPROXY_INFO ))
  3046. {
  3047. LocalServerInfo = &S4UTicketInfo->RequestorTicketInfo;
  3048. }
  3049. if (ARGUMENT_PRESENT( TargetServiceInfo ))
  3050. {
  3051. DCTarget = ((TargetServiceInfo->UserAccountControl & USER_SERVER_TRUST_ACCOUNT ) != 0);
  3052. }
  3053. //
  3054. // Delegation info in PAC? Then it better not be interdomain, as
  3055. // constrained delegation (S4UProxy) only works in a single
  3056. // domain. Reject the request.
  3057. //
  3058. if ( OldServerInfo->UserId == DOMAIN_USER_RID_KRBTGT &&
  3059. ( OldServerInfo->UserAccountControl & USER_INTERDOMAIN_TRUST_ACCOUNT ))
  3060. {
  3061. KerbErr = KdcCheckForDelegationInfo(
  3062. PacAuthData->value.auth_data.value,
  3063. PacAuthData->value.auth_data.length,
  3064. &InfoPresent
  3065. );
  3066. if ( InfoPresent )
  3067. {
  3068. DebugLog((DEB_ERROR, "Attempting XRealm S4UProxy Inbound\n"));
  3069. KerbErr = KDC_ERR_POLICY;
  3070. FILL_EXT_ERROR_EX2( ExtendedError, STATUS_CROSSREALM_DELEGATION_FAILURE, FILENO, __LINE__ );
  3071. goto Cleanup;
  3072. }
  3073. else if (!KERB_SUCCESS(KerbErr))
  3074. {
  3075. goto Cleanup;
  3076. }
  3077. }
  3078. //
  3079. // Now verify the existing signature
  3080. //
  3081. KerbErr = KdcVerifyPacSignature(
  3082. OldKey,
  3083. LocalServerInfo,
  3084. PacAuthData->value.auth_data.length,
  3085. PacAuthData->value.auth_data.value
  3086. );
  3087. if (!KERB_SUCCESS(KerbErr))
  3088. {
  3089. goto Cleanup;
  3090. }
  3091. //
  3092. // Perform SID filtering if necessary
  3093. //
  3094. KerbErr = KdcCheckPacForSidFiltering(
  3095. OldServerInfo,
  3096. &PacAuthData->value.auth_data.value,
  3097. (PULONG) &PacAuthData->value.auth_data.length
  3098. );
  3099. if (!KERB_SUCCESS(KerbErr))
  3100. {
  3101. goto Cleanup;
  3102. }
  3103. //
  3104. // See if this is an S4U variant, and fill in the interesting pac sections.
  3105. //
  3106. if (ARGUMENT_PRESENT( S4UTicketInfo ))
  3107. {
  3108. if (( S4UTicketInfo->Flags & TI_S4UPROXY_INFO ) != 0)
  3109. {
  3110. //
  3111. // S4UProxy
  3112. // 2 courses of action here.
  3113. // 1. If this is for a server in our realm, then we need to insert the
  3114. // target into the S4U_DELEGATION_INFO.
  3115. // 2. If we're transitting, validate the target name vs. what's in the PAC,
  3116. // and continue on.
  3117. //
  3118. KerbErr = KdcUpdateAndValidateS4UProxyPAC(
  3119. S4UTicketInfo,
  3120. &PacAuthData->value.auth_data.value,
  3121. (PULONG) &PacAuthData->value.auth_data.length,
  3122. S4UDelegationInfo
  3123. );
  3124. if (!KERB_SUCCESS(KerbErr))
  3125. {
  3126. DebugLog((DEB_ERROR, "KdcUpdateAndValidateS4UProxyInfo failed - %x\n", KerbErr));
  3127. goto Cleanup;
  3128. }
  3129. }
  3130. else if (( S4UTicketInfo->Flags & TI_REQUESTOR_THIS_REALM ) != 0)
  3131. {
  3132. //
  3133. // S4USelf - replace the pac verifier w/ one that is acceptable to the
  3134. // destination server.
  3135. //
  3136. KerbErr = KdcUpdateAndVerifyS4UPacVerifier(
  3137. S4UTicketInfo,
  3138. &PacAuthData->value.auth_data.value,
  3139. (PULONG) &PacAuthData->value.auth_data.length
  3140. );
  3141. if (!KERB_SUCCESS(KerbErr))
  3142. {
  3143. DebugLog((DEB_ERROR, "KdcVerifyS4UPacVerifier failed - %x\n", KerbErr));
  3144. goto Cleanup;
  3145. }
  3146. }
  3147. }
  3148. #ifdef ROGUE_DC
  3149. KerbErr = KdcInstrumentRoguePac( PacAuthData );
  3150. if ( !KERB_SUCCESS( KerbErr ))
  3151. {
  3152. DebugLog((DEB_ERROR, "KdcInstrumentRoguePac failed\n"));
  3153. }
  3154. #endif
  3155. //
  3156. // Now resign the PAC. If we add new sig algs, then we may need to
  3157. // address growing sigs, but for now, its all KDC_PAC_CHECKSUM
  3158. //
  3159. KerbErr = KdcSignPac(
  3160. NewKey,
  3161. AddResourceGroups,
  3162. DCTarget,
  3163. &PacAuthData->value.auth_data.value,
  3164. (PULONG) &PacAuthData->value.auth_data.length
  3165. );
  3166. if (!KERB_SUCCESS(KerbErr))
  3167. {
  3168. goto Cleanup;
  3169. }
  3170. Cleanup:
  3171. return(KerbErr);
  3172. }
  3173. //+-------------------------------------------------------------------------
  3174. //
  3175. // Function: KdcFreeAuthzInfo
  3176. //
  3177. // Synopsis: Used to free buffers / handles from KdcGetValidationInfoFromTgt.
  3178. // Allows us to use allocated buffers w/o copy overhead.
  3179. // Effects:
  3180. //
  3181. // Arguments:
  3182. //
  3183. // Requires:
  3184. //
  3185. // Returns:
  3186. //
  3187. // Notes:
  3188. //
  3189. //
  3190. //--------------------------------------------------------------------------
  3191. VOID
  3192. KdcFreeAuthzInfo(
  3193. IN PKDC_AUTHZ_GROUP_BUFFERS InfoToFree
  3194. )
  3195. {
  3196. if (InfoToFree->BuiltInSids)
  3197. {
  3198. MIDL_user_free(InfoToFree->BuiltInSids);
  3199. }
  3200. if (InfoToFree->PacGroups.Sids != NULL)
  3201. {
  3202. for (ULONG Index = 0; Index < InfoToFree->PacGroups.Count ;Index++ )
  3203. {
  3204. if (InfoToFree->PacGroups.Sids[Index].SidPointer != NULL)
  3205. {
  3206. MIDL_user_free(InfoToFree->PacGroups.Sids[Index].SidPointer);
  3207. }
  3208. }
  3209. MIDL_user_free(InfoToFree->PacGroups.Sids);
  3210. }
  3211. SamIFree_SAMPR_ULONG_ARRAY( &InfoToFree->AliasGroups );
  3212. SamIFreeSidArray( InfoToFree->ResourceGroups );
  3213. if ( InfoToFree->SidAndAttributes )
  3214. {
  3215. MIDL_user_free(InfoToFree->SidAndAttributes);
  3216. }
  3217. if ( InfoToFree->ValidationInfo )
  3218. {
  3219. MIDL_user_free( InfoToFree->ValidationInfo );
  3220. }
  3221. RtlZeroMemory(
  3222. InfoToFree,
  3223. sizeof(KDC_AUTHZ_GROUP_BUFFERS)
  3224. );
  3225. }
  3226. //+-------------------------------------------------------------------------
  3227. //
  3228. // Function: KdcGetSidsFromTgt
  3229. //
  3230. // Synopsis: Takes a TGT, grabs the PAC from the authorization data, and
  3231. // extracts the validation info, builds groups up.
  3232. //
  3233. // Effects:
  3234. //
  3235. // Arguments:
  3236. //
  3237. // Requires:
  3238. //
  3239. // Returns:
  3240. //
  3241. // Notes:
  3242. //
  3243. //
  3244. //--------------------------------------------------------------------------
  3245. KERBERR
  3246. KdcGetSidsFromTgt(
  3247. IN PKERB_ENCRYPTED_TICKET EncryptedTicket,
  3248. IN OPTIONAL PKERB_ENCRYPTION_KEY EncryptedTicketKey,
  3249. IN ULONG EncryptionType,
  3250. IN PKDC_TICKET_INFO TgtAccountInfo,
  3251. IN OUT PKDC_AUTHZ_INFO AuthzInfo,
  3252. IN OUT PKDC_AUTHZ_GROUP_BUFFERS InfoToFree,
  3253. OUT NTSTATUS * pStatus
  3254. )
  3255. {
  3256. KERBERR KerbErr;
  3257. NTSTATUS Status = STATUS_SUCCESS;
  3258. PKERB_AUTHORIZATION_DATA SourceAuthData = NULL;
  3259. PKERB_IF_RELEVANT_AUTH_DATA * IfRelevantData = NULL;
  3260. PKERB_AUTHORIZATION_DATA PacAuthData = NULL;
  3261. PKERB_ENCRYPTION_KEY KdcKey = EncryptedTicketKey;
  3262. PPAC_INFO_BUFFER LogonInfo;
  3263. PPACTYPE Pac;
  3264. ULONG PacSize;
  3265. PNETLOGON_VALIDATION_SAM_INFO3 LocalValidationInfo = NULL;
  3266. SAMPR_PSID_ARRAY SidList = {0};
  3267. PSAMPR_PSID_ARRAY ResourceGroups = NULL;
  3268. SAMPR_ULONG_ARRAY BuiltinGroups = {0, NULL};
  3269. PSID SidBuffer = NULL;
  3270. PNETLOGON_SID_AND_ATTRIBUTES SidAndAttributes = NULL;
  3271. ULONG Index, Index2, GroupCount = 0, SidSize = 0;
  3272. RtlZeroMemory(
  3273. InfoToFree,
  3274. sizeof(KDC_AUTHZ_GROUP_BUFFERS)
  3275. );
  3276. if (EncryptedTicket->bit_mask & KERB_ENCRYPTED_TICKET_authorization_data_present)
  3277. {
  3278. DsysAssert(EncryptedTicket->KERB_ENCRYPTED_TICKET_authorization_data != NULL);
  3279. SourceAuthData = EncryptedTicket->KERB_ENCRYPTED_TICKET_authorization_data;
  3280. }
  3281. else
  3282. {
  3283. DsysAssert(FALSE);
  3284. *pStatus = STATUS_INVALID_PARAMETER;
  3285. return KRB_ERR_GENERIC;
  3286. }
  3287. KerbErr = KerbGetPacFromAuthData(
  3288. SourceAuthData,
  3289. &IfRelevantData,
  3290. &PacAuthData
  3291. );
  3292. if ( PacAuthData == NULL )
  3293. {
  3294. KerbErr = KRB_ERR_GENERIC;
  3295. }
  3296. if (!KERB_SUCCESS(KerbErr))
  3297. {
  3298. Status = STATUS_NO_MEMORY; // difficult to figure out exactly what it was
  3299. goto Cleanup;
  3300. }
  3301. //
  3302. // Verify the signature, using Krbtgt key.
  3303. //
  3304. if ( KdcKey == NULL )
  3305. {
  3306. KdcKey = KerbGetKeyFromList(
  3307. TgtAccountInfo->Passwords,
  3308. EncryptionType
  3309. );
  3310. if ( KdcKey == NULL )
  3311. {
  3312. DebugLog((DEB_ERROR, "Can't find key for PAC (%x)\n", EncryptionType ));
  3313. KerbErr = KRB_ERR_GENERIC;
  3314. Status = STATUS_NO_KERB_KEY;
  3315. goto Cleanup;
  3316. }
  3317. }
  3318. KerbErr = KdcVerifyPacSignature(
  3319. KdcKey,
  3320. TgtAccountInfo,
  3321. PacAuthData->value.auth_data.length,
  3322. PacAuthData->value.auth_data.value
  3323. );
  3324. if (!KERB_SUCCESS( KerbErr ))
  3325. {
  3326. DebugLog((DEB_ERROR,"PAC signature didn't verify\n"));
  3327. Status = KerbMapKerbError( KerbErr );
  3328. goto Cleanup;
  3329. }
  3330. Pac = (PPACTYPE) PacAuthData->value.auth_data.value;
  3331. PacSize = PacAuthData->value.auth_data.length;
  3332. if (PAC_UnMarshal(Pac, PacSize) == 0)
  3333. {
  3334. D_DebugLog((DEB_ERROR,"Failed to unmarshal pac\n"));
  3335. KerbErr = KRB_ERR_GENERIC;
  3336. Status = STATUS_INVALID_PARAMETER; // better error code?
  3337. goto Cleanup;
  3338. }
  3339. LogonInfo = PAC_Find(
  3340. Pac,
  3341. PAC_LOGON_INFO,
  3342. NULL
  3343. );
  3344. if ( LogonInfo == NULL )
  3345. {
  3346. KerbErr = KRB_ERR_GENERIC;
  3347. Status = STATUS_INVALID_PARAMETER;
  3348. goto Cleanup;
  3349. }
  3350. Status = PAC_UnmarshallValidationInfo(
  3351. &LocalValidationInfo,
  3352. LogonInfo->Data,
  3353. LogonInfo->cbBufferSize
  3354. );
  3355. if ( !NT_SUCCESS( Status ))
  3356. {
  3357. KerbErr = KRB_ERR_GENERIC;
  3358. goto Cleanup;
  3359. }
  3360. //
  3361. // Filter the sids. If trust sid is present, this is an inbound TGT. We
  3362. // don't do this for TGTs from our own domain.
  3363. //
  3364. if (NULL != TgtAccountInfo->TrustSid)
  3365. {
  3366. Status = KdcFilterSids(
  3367. TgtAccountInfo,
  3368. LocalValidationInfo
  3369. );
  3370. if ( !NT_SUCCESS( Status ))
  3371. {
  3372. KerbErr = KDC_ERR_POLICY;
  3373. goto Cleanup;
  3374. }
  3375. }
  3376. //
  3377. // Make a sid list from the validation info
  3378. //
  3379. KerbErr = KdcBuildPacSidList(
  3380. LocalValidationInfo,
  3381. TRUE, // Add everyone and authenticated user sids.
  3382. (( TgtAccountInfo->TrustAttributes & TRUST_ATTRIBUTE_CROSS_ORGANIZATION ) != 0 ),
  3383. &SidList
  3384. );
  3385. if (!KERB_SUCCESS(KerbErr))
  3386. {
  3387. Status = STATUS_NO_MEMORY;
  3388. goto Cleanup;
  3389. }
  3390. RtlCopyMemory(
  3391. &InfoToFree->PacGroups,
  3392. &SidList,
  3393. sizeof(SAMPR_PSID_ARRAY)
  3394. );
  3395. //
  3396. // Call SAM to get the sids for resource groups and built-in groups
  3397. //
  3398. Status = SamIGetResourceGroupMembershipsTransitive(
  3399. GlobalAccountDomainHandle,
  3400. &SidList,
  3401. 0, // no flags
  3402. &ResourceGroups
  3403. );
  3404. if (!NT_SUCCESS(Status))
  3405. {
  3406. DebugLog((DEB_ERROR,"Failed to get resource groups: 0x%x\n",Status));
  3407. KerbErr = KRB_ERR_GENERIC;
  3408. goto Cleanup;
  3409. }
  3410. InfoToFree->ResourceGroups = ResourceGroups;
  3411. Status = SamIGetAliasMembership(
  3412. GlobalBuiltInDomainHandle,
  3413. &SidList,
  3414. &BuiltinGroups
  3415. );
  3416. if (!NT_SUCCESS(Status))
  3417. {
  3418. DebugLog((DEB_ERROR,"Failed to get ALIAS MEMBERSHIP groups: 0x%x\n",Status));
  3419. KerbErr = KRB_ERR_GENERIC;
  3420. goto Cleanup;
  3421. }
  3422. RtlCopyMemory(
  3423. &InfoToFree->AliasGroups,
  3424. &BuiltinGroups,
  3425. sizeof(SAMPR_ULONG_ARRAY)
  3426. );
  3427. GroupCount = BuiltinGroups.Count + ResourceGroups->Count + SidList.Count;
  3428. //
  3429. // Enumerate and allocate the groups sids...
  3430. //
  3431. if (GroupCount != 0)
  3432. {
  3433. SidAndAttributes = (PNETLOGON_SID_AND_ATTRIBUTES) MIDL_user_allocate(sizeof(NETLOGON_SID_AND_ATTRIBUTES) * GroupCount);
  3434. if (SidAndAttributes == NULL)
  3435. {
  3436. KerbErr = KRB_ERR_GENERIC;
  3437. goto Cleanup;
  3438. }
  3439. InfoToFree->SidAndAttributes = SidAndAttributes;
  3440. //
  3441. // Add in all the extra sids that are not resource groups
  3442. //
  3443. Index2 = 0;
  3444. for (Index = 0; Index < SidList.Count; Index++ )
  3445. {
  3446. SidAndAttributes[Index2].Sid = SidList.Sids[Index].SidPointer;
  3447. SidAndAttributes[Index2].Attributes = SE_GROUP_MANDATORY |
  3448. SE_GROUP_ENABLED |
  3449. SE_GROUP_ENABLED_BY_DEFAULT;
  3450. Index2++;
  3451. }
  3452. //
  3453. // Copy all the resource group SIDs
  3454. //
  3455. for (Index = 0; Index < ResourceGroups->Count ; Index++ )
  3456. {
  3457. SidAndAttributes[Index2].Sid = ResourceGroups->Sids[Index].SidPointer;
  3458. SidAndAttributes[Index2].Attributes = SE_GROUP_MANDATORY |
  3459. SE_GROUP_ENABLED |
  3460. SE_GROUP_ENABLED_BY_DEFAULT |
  3461. SE_GROUP_RESOURCE;
  3462. Index2++;
  3463. }
  3464. //
  3465. // Copy in the builtin group sids.
  3466. //
  3467. SidSize = RtlLengthSid(GlobalBuiltInSid) + sizeof(ULONG);
  3468. SidBuffer = (PSID) MIDL_user_allocate(SidSize * BuiltinGroups.Count);
  3469. if (SidBuffer == NULL)
  3470. {
  3471. KerbErr = KRB_ERR_GENERIC;
  3472. goto Cleanup;
  3473. }
  3474. InfoToFree->BuiltInSids = SidBuffer;
  3475. PBYTE Current = (PBYTE) SidBuffer;
  3476. for (Index = 0; Index < BuiltinGroups.Count ; Index++ )
  3477. {
  3478. RtlCopySid(
  3479. RtlLengthSid(GlobalBuiltInSid),
  3480. Current,
  3481. GlobalBuiltInSid
  3482. );
  3483. //
  3484. // The final value is just a ULONG - appended to the right place.
  3485. //
  3486. (*RtlSubAuthoritySid(
  3487. Current,
  3488. ((ULONG) (*RtlSubAuthorityCountSid(GlobalBuiltInSid)) - 1)
  3489. )) = BuiltinGroups.Element[Index];
  3490. SidAndAttributes[Index2].Sid = Current;
  3491. SidAndAttributes[Index2].Attributes = SE_GROUP_MANDATORY |
  3492. SE_GROUP_ENABLED |
  3493. SE_GROUP_ENABLED_BY_DEFAULT;
  3494. Index2++;
  3495. Current += SidSize;
  3496. }
  3497. }
  3498. InfoToFree->ValidationInfo = LocalValidationInfo;
  3499. LocalValidationInfo = NULL;
  3500. AuthzInfo->SidCount = GroupCount;
  3501. AuthzInfo->SidAndAttributes = SidAndAttributes;
  3502. SidAndAttributes = NULL;
  3503. Cleanup:
  3504. if (LocalValidationInfo)
  3505. {
  3506. MIDL_user_free(LocalValidationInfo);
  3507. }
  3508. if (!KERB_SUCCESS(KerbErr))
  3509. {
  3510. KdcFreeAuthzInfo(InfoToFree);
  3511. }
  3512. if (IfRelevantData)
  3513. {
  3514. KerbFreeData(PKERB_IF_RELEVANT_AUTH_DATA_PDU, IfRelevantData);
  3515. }
  3516. *pStatus = Status;
  3517. return KerbErr;
  3518. }