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.

4307 lines
124 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: token.cxx
  8. //
  9. // Contents: Routines building access tokens
  10. //
  11. //
  12. // History: 1-May-1996 Created MikeSw
  13. // 26-Sep-1998 ChandanS
  14. // Added more debugging support etc.
  15. //
  16. //------------------------------------------------------------------------
  17. #include <kerb.hxx>
  18. #include <kerbp.h>
  19. #include <pac.hxx>
  20. #include <utils.hxx>
  21. #ifdef DEBUG_SUPPORT
  22. static TCHAR THIS_FILE[]=TEXT(__FILE__);
  23. #endif
  24. //+-------------------------------------------------------------------------
  25. //
  26. // Function: KerbVerifyAuthData
  27. //
  28. // Synopsis: Verifies that we should not be rejecting the auth data
  29. // Accepted auth data is anything we know about and even values
  30. // Odd values and unknown auth data is rejected
  31. //
  32. // Effects:
  33. //
  34. // Arguments:
  35. //
  36. // Requires:
  37. //
  38. // Returns:
  39. //
  40. // Notes:
  41. //
  42. //
  43. //--------------------------------------------------------------------------
  44. BOOLEAN
  45. KerbVerifyAuthData(
  46. IN PKERB_AUTHORIZATION_DATA AuthData
  47. )
  48. {
  49. PKERB_AUTHORIZATION_DATA TempData = AuthData;
  50. while (TempData != NULL)
  51. {
  52. if ((TempData->value.auth_data_type & 1) != 0)
  53. {
  54. switch(TempData->value.auth_data_type)
  55. {
  56. case KERB_AUTH_OSF_DCE:
  57. case KERB_AUTH_SESAME:
  58. case KERB_AUTH_DATA_PAC:
  59. case -KERB_AUTH_DATA_PAC: // obsolete pac id
  60. case KERB_AUTH_PROXY_ANNOTATION:
  61. case KERB_AUTH_DATA_IF_RELEVANT:
  62. case KERB_AUTH_DATA_KDC_ISSUED:
  63. #ifdef RESTRICTED_TOKEN
  64. case KERB_AUTH_DATA_TOKEN_RESTRICTIONS:
  65. #endif
  66. break;
  67. default:
  68. D_DebugLog((DEB_ERROR,"Unknown auth type: %d\n",TempData->value.auth_data_type));
  69. return(FALSE);
  70. }
  71. }
  72. TempData = TempData->next;
  73. }
  74. return(TRUE);
  75. }
  76. //+-------------------------------------------------------------------------
  77. //
  78. // Function: KerbApplyTokenRestrictions
  79. //
  80. // Synopsis: Applies restrictions to a fresh token
  81. //
  82. // Effects:
  83. //
  84. // Arguments:
  85. //
  86. // Requires:
  87. //
  88. // Returns:
  89. //
  90. // Notes:
  91. //
  92. //
  93. //--------------------------------------------------------------------------
  94. NTSTATUS
  95. KerbApplyTokenRestrictions(
  96. IN PKERB_AUTHORIZATION_DATA AuthData,
  97. IN OUT PHANDLE TokenHandle
  98. )
  99. {
  100. PKERB_TOKEN_RESTRICTIONS Restrictions = NULL;
  101. HANDLE RestrictedToken = NULL;
  102. NTSTATUS Status = STATUS_SUCCESS;
  103. Status = PAC_DecodeTokenRestrictions(
  104. AuthData->value.auth_data.value,
  105. AuthData->value.auth_data.length,
  106. &Restrictions
  107. );
  108. if (!NT_SUCCESS(Status))
  109. {
  110. D_DebugLog((DEB_ERROR,"Failed to decode token restrictions: 0x%x\n",Status));
  111. goto Cleanup;
  112. }
  113. //
  114. // If there are any restrictions, apply them here.
  115. //
  116. if (Restrictions->Flags != 0)
  117. {
  118. Status = NtFilterToken(
  119. *TokenHandle,
  120. 0, // no flags,
  121. (Restrictions->Flags & KERB_TOKEN_RESTRICTION_DISABLE_GROUPS) != 0 ? (PTOKEN_GROUPS) Restrictions->GroupsToDisable : NULL,
  122. (Restrictions->Flags & KERB_TOKEN_RESTRICTION_DELETE_PRIVS) != 0 ? (PTOKEN_PRIVILEGES) Restrictions->PrivilegesToDelete : NULL,
  123. (Restrictions->Flags & KERB_TOKEN_RESTRICTION_RESTRICT_SIDS) != 0 ? (PTOKEN_GROUPS) Restrictions->RestrictedSids : NULL,
  124. &RestrictedToken
  125. );
  126. if (!NT_SUCCESS(Status))
  127. {
  128. D_DebugLog((DEB_ERROR,"Failed to filter token: 0x%x\n",Status));
  129. goto Cleanup;
  130. }
  131. NtClose(*TokenHandle);
  132. *TokenHandle = RestrictedToken;
  133. RestrictedToken = NULL;
  134. }
  135. Cleanup:
  136. if (Restrictions != NULL)
  137. {
  138. MIDL_user_free(Restrictions);
  139. }
  140. if (RestrictedToken != NULL)
  141. {
  142. NtClose(RestrictedToken);
  143. }
  144. return(Status);
  145. }
  146. #ifdef RESTRICTED_TOKEN
  147. //+-------------------------------------------------------------------------
  148. //
  149. // Function: KerbApplyAuthDataRestrictions
  150. //
  151. // Synopsis: Applies any restrictions from the auth data to the to token
  152. // and logon session.
  153. //
  154. // Effects:
  155. //
  156. // Arguments:
  157. //
  158. // Requires:
  159. //
  160. // Returns:
  161. //
  162. // Notes:
  163. //
  164. //
  165. //--------------------------------------------------------------------------
  166. NTSTATUS
  167. KerbApplyAuthDataRestrictions(
  168. IN OUT PHANDLE TokenHandle,
  169. IN PKERB_AUTHORIZATION_DATA AuthData
  170. )
  171. {
  172. NTSTATUS Status = STATUS_SUCCESS;
  173. PKERB_AUTHORIZATION_DATA TempData = AuthData;
  174. while (TempData != NULL)
  175. {
  176. if ((TempData->value.auth_data_type & 1) != 0)
  177. {
  178. switch(TempData->value.auth_data_type)
  179. {
  180. case KERB_AUTH_DATA_TOKEN_RESTRICTIONS:
  181. Status = KerbApplyTokenRestrictions(
  182. TempData,
  183. TokenHandle
  184. );
  185. if (!NT_SUCCESS(Status))
  186. {
  187. D_DebugLog((DEB_ERROR,"Failed to apply token restrictions: 0x%x\n",Status));
  188. goto Cleanup;
  189. break;
  190. }
  191. default:
  192. break;
  193. }
  194. }
  195. TempData = TempData->next;
  196. }
  197. Cleanup:
  198. return(Status);
  199. }
  200. #endif
  201. //+-------------------------------------------------------------------------
  202. //
  203. // Function: KerbVerifyPacSignature
  204. //
  205. // Synopsis: Verifies the server signature on a PAC and if necessary
  206. // calls the KDC to verify the KDC signature.
  207. //
  208. // Effects:
  209. //
  210. // Arguments: Pac - an unmarshalled pac
  211. // EncryptionKey - Key used to decrypt the ticket & verify the pac
  212. //
  213. //
  214. // Requires:
  215. //
  216. // Returns:
  217. //
  218. // Notes: No locks should be held while calling this function
  219. //
  220. //
  221. //--------------------------------------------------------------------------
  222. NTSTATUS
  223. KerbVerifyPacSignature(
  224. IN PUNICODE_STRING ServiceDomain,
  225. IN PPACTYPE Pac,
  226. IN ULONG PacSize,
  227. IN PKERB_ENCRYPTION_KEY EncryptionKey,
  228. IN PKERB_ENCRYPTED_TICKET Ticket,
  229. IN BOOLEAN CheckKdcSignature,
  230. OUT PNETLOGON_VALIDATION_SAM_INFO3 * ValidationInfo,
  231. OUT OPTIONAL PS4U_DELEGATION_INFO* S4uDelegationInfo
  232. )
  233. {
  234. NTSTATUS Status = STATUS_SUCCESS;
  235. NTSTATUS SubStatus;
  236. PKERB_VERIFY_PAC_REQUEST VerifyRequest = NULL;
  237. PMSV1_0_PASSTHROUGH_REQUEST PassthroughRequest = NULL;
  238. PMSV1_0_PASSTHROUGH_RESPONSE PassthroughResponse = NULL;
  239. ULONG RequestSize;
  240. ULONG ResponseSize;
  241. PCHECKSUM_FUNCTION Check = NULL ;
  242. PCHECKSUM_BUFFER CheckBuffer = NULL;
  243. PPAC_SIGNATURE_DATA ServerSignature = NULL;
  244. PPAC_SIGNATURE_DATA PrivSvrSignature = NULL;
  245. PPAC_INFO_BUFFER ServerBuffer = NULL;
  246. PPAC_INFO_BUFFER PrivSvrBuffer = NULL;
  247. PPAC_INFO_BUFFER LogonInfo = NULL;
  248. PPAC_INFO_BUFFER ExtraLogonInfo = NULL;
  249. PPAC_INFO_BUFFER ClientBuffer = NULL;
  250. PPAC_INFO_BUFFER DelegationInfoBuffer = NULL;
  251. PPAC_CLIENT_INFO ClientInfo = NULL;
  252. UCHAR LocalChecksum[20];
  253. UCHAR LocalServerChecksum[20];
  254. UCHAR LocalPrivSvrChecksum[20];
  255. SECPKG_CLIENT_INFO LsaClientInfo;
  256. ULONG SignatureSize;
  257. PUCHAR Where;
  258. UNICODE_STRING MsvPackageName = CONSTANT_UNICODE_STRING(TEXT(MSV1_0_PACKAGE_NAME));
  259. ULONG NameType;
  260. UNICODE_STRING ClientName = {0};
  261. *ValidationInfo = NULL;
  262. //
  263. // Get the various pieces we need out of the PAC - the logon information
  264. // and the two signatures.
  265. //
  266. LogonInfo = PAC_Find(
  267. Pac,
  268. PAC_LOGON_INFO,
  269. NULL
  270. );
  271. if (LogonInfo == NULL)
  272. {
  273. D_DebugLog((DEB_ERROR,"Failed to find logon info! %ws, line %d\n", THIS_FILE, __LINE__));
  274. Status = STATUS_INVALID_PARAMETER;
  275. goto Cleanup;
  276. }
  277. //
  278. // Verify that we don't have multiple pacs.
  279. //
  280. ExtraLogonInfo = PAC_Find(
  281. Pac,
  282. PAC_LOGON_INFO,
  283. LogonInfo
  284. );
  285. if ( ExtraLogonInfo )
  286. {
  287. DsysAssert(FALSE);
  288. DebugLog((DEB_ERROR, "We have multiple PAC entries \n"));
  289. Status = STATUS_LOGON_FAILURE;
  290. goto Cleanup;
  291. }
  292. //
  293. // See if the delegation info is in the PAC
  294. //
  295. DelegationInfoBuffer = PAC_Find(
  296. Pac,
  297. PAC_DELEGATION_INFO,
  298. NULL
  299. );
  300. //
  301. // Get the PAC signature(s)
  302. //
  303. ServerBuffer = PAC_Find(
  304. Pac,
  305. PAC_SERVER_CHECKSUM,
  306. NULL
  307. );
  308. PrivSvrBuffer = PAC_Find(
  309. Pac,
  310. PAC_PRIVSVR_CHECKSUM,
  311. NULL
  312. );
  313. if ((ServerBuffer == NULL) || (PrivSvrBuffer == NULL))
  314. {
  315. D_DebugLog((DEB_ERROR, "Pac found with no signature!\n"));
  316. return(STATUS_LOGON_FAILURE);
  317. }
  318. //
  319. // Now verify the server checksum. First compute the checksum
  320. // over the logon info.
  321. //
  322. ServerSignature = (PPAC_SIGNATURE_DATA) ServerBuffer->Data;
  323. if ((sizeof(*ServerSignature) > ServerBuffer->cbBufferSize) ||
  324. (PAC_CHECKSUM_SIZE(ServerBuffer->cbBufferSize) > sizeof(LocalServerChecksum)))
  325. {
  326. Status = STATUS_INVALID_PARAMETER;
  327. goto Cleanup;
  328. }
  329. PrivSvrSignature = (PPAC_SIGNATURE_DATA) PrivSvrBuffer->Data;
  330. if ((sizeof(*PrivSvrSignature) > PrivSvrBuffer->cbBufferSize) ||
  331. (PAC_CHECKSUM_SIZE(PrivSvrBuffer->cbBufferSize) > sizeof(LocalPrivSvrChecksum)))
  332. {
  333. Status = STATUS_INVALID_PARAMETER;
  334. goto Cleanup;
  335. }
  336. //
  337. // Copy out the signature so we can zero the signature fields before
  338. // checksumming
  339. //
  340. RtlCopyMemory(
  341. LocalServerChecksum,
  342. ServerSignature->Signature,
  343. PAC_CHECKSUM_SIZE(ServerBuffer->cbBufferSize)
  344. );
  345. RtlZeroMemory(
  346. ServerSignature->Signature,
  347. PAC_CHECKSUM_SIZE(ServerBuffer->cbBufferSize)
  348. );
  349. RtlCopyMemory(
  350. LocalPrivSvrChecksum,
  351. PrivSvrSignature->Signature,
  352. PAC_CHECKSUM_SIZE(PrivSvrBuffer->cbBufferSize)
  353. );
  354. RtlZeroMemory(
  355. PrivSvrSignature->Signature,
  356. PAC_CHECKSUM_SIZE(PrivSvrBuffer->cbBufferSize)
  357. );
  358. //
  359. // Now remarshal the PAC before checksumming.
  360. //
  361. if (!PAC_ReMarshal(Pac,PacSize))
  362. {
  363. DsysAssert(!"PAC_Remarhsal failed");
  364. Status = STATUS_INTERNAL_ERROR;
  365. goto Cleanup;
  366. }
  367. //
  368. // Locate the checksum of the logon info & compute it.
  369. //
  370. Status = CDLocateCheckSum(
  371. ServerSignature->SignatureType,
  372. &Check
  373. );
  374. if (!NT_SUCCESS(Status))
  375. {
  376. goto Cleanup;
  377. }
  378. if (Check->CheckSumSize > sizeof(LocalChecksum)) {
  379. DsysAssert(Check->CheckSumSize > sizeof(LocalChecksum));
  380. Status = STATUS_INVALID_PARAMETER;
  381. goto Cleanup;
  382. }
  383. //
  384. // if available use the Ex2 version for keyed checksums where checksum
  385. // must be passed in on verification
  386. //
  387. if (NULL != Check->InitializeEx2)
  388. {
  389. Status = Check->InitializeEx2(
  390. EncryptionKey->keyvalue.value,
  391. EncryptionKey->keyvalue.length,
  392. LocalServerChecksum,
  393. KERB_NON_KERB_CKSUM_SALT,
  394. &CheckBuffer
  395. );
  396. }
  397. else
  398. {
  399. Status = Check->InitializeEx(
  400. EncryptionKey->keyvalue.value,
  401. EncryptionKey->keyvalue.length,
  402. KERB_NON_KERB_CKSUM_SALT,
  403. &CheckBuffer
  404. );
  405. }
  406. if (!NT_SUCCESS(Status))
  407. {
  408. goto Cleanup;
  409. }
  410. Check->Sum(
  411. CheckBuffer,
  412. PacSize,
  413. (PUCHAR) Pac
  414. );
  415. Check->Finalize(
  416. CheckBuffer,
  417. LocalChecksum
  418. );
  419. Check->Finish(&CheckBuffer);
  420. //
  421. // Now compare the local checksum to the supplied checksum.
  422. //
  423. if (Check->CheckSumSize != PAC_CHECKSUM_SIZE(ServerBuffer->cbBufferSize))
  424. {
  425. Status = STATUS_LOGON_FAILURE;
  426. goto Cleanup;
  427. }
  428. if (!RtlEqualMemory(
  429. LocalChecksum,
  430. LocalServerChecksum,
  431. Check->CheckSumSize
  432. ))
  433. {
  434. DebugLog((DEB_ERROR, "Checksum on the PAC does not match! %ws, line %d\n", THIS_FILE, __LINE__));
  435. Status = STATUS_LOGON_FAILURE;
  436. goto Cleanup;
  437. }
  438. //
  439. // Now unmarshal the PAC so that the caller will have it back the
  440. // way they started.
  441. //
  442. if (!PAC_UnMarshal(Pac,PacSize))
  443. {
  444. DsysAssert(!"PAC_UnMarshal failed");
  445. Status = STATUS_INTERNAL_ERROR;
  446. goto Cleanup;
  447. }
  448. //
  449. // Check the client info, if present,
  450. //
  451. ClientBuffer = PAC_Find(
  452. Pac,
  453. PAC_CLIENT_INFO_TYPE,
  454. NULL
  455. );
  456. if (ClientBuffer != NULL)
  457. {
  458. TimeStamp ClientId;
  459. UNICODE_STRING PacClientName = {0};
  460. if (ClientBuffer->cbBufferSize < sizeof(PAC_CLIENT_INFO))
  461. {
  462. D_DebugLog((DEB_ERROR, "Clientinfo is too small: %d instead of %d. %ws, line %d\n",
  463. ClientBuffer->cbBufferSize, sizeof(PAC_CLIENT_INFO), THIS_FILE, __LINE__));
  464. Status = STATUS_INTERNAL_ERROR;
  465. goto Cleanup;
  466. }
  467. ClientInfo = (PPAC_CLIENT_INFO) ClientBuffer->Data;
  468. if ((ClientInfo->NameLength - ANYSIZE_ARRAY * sizeof(WCHAR) + sizeof(PPAC_CLIENT_INFO)) > ClientBuffer->cbBufferSize)
  469. {
  470. Status = STATUS_INTERNAL_ERROR;
  471. goto Cleanup;
  472. }
  473. KerbConvertGeneralizedTimeToLargeInt(
  474. &ClientId,
  475. &Ticket->authtime,
  476. 0 // no usec
  477. );
  478. if (!RtlEqualMemory(
  479. &ClientId,
  480. &ClientInfo->ClientId,
  481. sizeof(TimeStamp)
  482. ))
  483. {
  484. D_DebugLog((DEB_ERROR, "Client IDs don't match. %ws, line %d\n", THIS_FILE, __LINE__));
  485. Status = STATUS_LOGON_FAILURE;
  486. goto Cleanup;
  487. }
  488. //
  489. // Check the name now
  490. //
  491. PacClientName.Buffer = ClientInfo->Name;
  492. PacClientName.Length = PacClientName.MaximumLength = ClientInfo->NameLength;
  493. if (KERB_SUCCESS(KerbConvertPrincipalNameToString(
  494. &ClientName,
  495. &NameType,
  496. &Ticket->client_name
  497. )))
  498. {
  499. if (!RtlEqualUnicodeString(
  500. &ClientName,
  501. &PacClientName,
  502. TRUE))
  503. {
  504. D_DebugLog((DEB_ERROR,"Client names don't match: %wZ vs %wZ. %ws, line %d\n",
  505. &PacClientName, &ClientName, THIS_FILE, __LINE__ ));
  506. Status = STATUS_LOGON_FAILURE;
  507. goto Cleanup;
  508. }
  509. }
  510. else
  511. {
  512. Status = STATUS_INSUFFICIENT_RESOURCES;
  513. goto Cleanup;
  514. }
  515. }
  516. else
  517. {
  518. //
  519. // We *MUST* have a client info segment. This keeps people from mis-using the pac
  520. //
  521. DebugLog((DEB_ERROR, "Missing client info!\n"));
  522. DsysAssert(FALSE);
  523. Status = STATUS_LOGON_FAILURE;
  524. goto Cleanup;
  525. }
  526. //
  527. // Unmarshall the logon info. We need to do this to get the logon domain
  528. // out to use for the pass-through.
  529. //
  530. Status = PAC_UnmarshallValidationInfo(
  531. ValidationInfo,
  532. LogonInfo->Data,
  533. LogonInfo->cbBufferSize
  534. );
  535. if (!NT_SUCCESS(Status))
  536. {
  537. goto Cleanup;
  538. }
  539. if (S4uDelegationInfo && DelegationInfoBuffer)
  540. {
  541. Status = UnmarshalS4UDelegationInformation(
  542. DelegationInfoBuffer->cbBufferSize,
  543. DelegationInfoBuffer->Data,
  544. S4uDelegationInfo
  545. );
  546. if (!NT_SUCCESS(Status))
  547. {
  548. DebugLog((DEB_ERROR, "KerbVerifyPacSignature failed to unmarshall S4U delgation info %#x\n", Status));
  549. goto Cleanup;
  550. }
  551. }
  552. //
  553. // If we don't need to check the KDC signature, bail now. This is for
  554. // tokens that can't be used for impersonation
  555. //
  556. if (!CheckKdcSignature)
  557. {
  558. goto Cleanup;
  559. }
  560. //
  561. // Now check to see if the client has TCB privilege. It it does, we
  562. // are done. Otherwise we need to call the KDC to verify the PAC.
  563. //
  564. Status = LsaFunctions->GetClientInfo(&LsaClientInfo);
  565. if (!NT_SUCCESS(Status))
  566. {
  567. goto Cleanup;
  568. }
  569. if (LsaClientInfo.HasTcbPrivilege)
  570. {
  571. goto Cleanup;
  572. }
  573. //
  574. // also let networkservice through.
  575. //
  576. {
  577. LUID NetworkServiceLuid = NETWORKSERVICE_LUID;
  578. if( RtlEqualLuid( &NetworkServiceLuid, &LsaClientInfo.LogonId ) )
  579. {
  580. goto Cleanup;
  581. }
  582. }
  583. //
  584. // We have to pass off to the DC so build the request.
  585. //
  586. SignatureSize = PAC_CHECKSUM_SIZE(PrivSvrBuffer->cbBufferSize);
  587. RequestSize = sizeof(MSV1_0_PASSTHROUGH_REQUEST) +
  588. ROUND_UP_COUNT(ServiceDomain->Length, ALIGN_LPTSTR) +
  589. ROUND_UP_COUNT(KerbPackageName.Length, ALIGN_LPTSTR) +
  590. sizeof(KERB_VERIFY_PAC_REQUEST) - sizeof(UCHAR) * ANYSIZE_ARRAY +
  591. Check->CheckSumSize +
  592. SignatureSize;
  593. SafeAllocaAllocate(PassthroughRequest, RequestSize);
  594. if (PassthroughRequest == NULL)
  595. {
  596. Status = STATUS_INSUFFICIENT_RESOURCES;
  597. goto Cleanup;
  598. }
  599. Where = (PUCHAR) (PassthroughRequest + 1);
  600. PassthroughRequest->MessageType = MsV1_0GenericPassthrough;
  601. PassthroughRequest->DomainName = *ServiceDomain;
  602. PassthroughRequest->DomainName.Buffer = (LPWSTR) Where;
  603. RtlCopyMemory(
  604. Where,
  605. ServiceDomain->Buffer,
  606. ServiceDomain->Length
  607. );
  608. Where += ROUND_UP_COUNT(ServiceDomain->Length, ALIGN_LPTSTR);
  609. PassthroughRequest->PackageName = KerbPackageName;
  610. PassthroughRequest->PackageName.Buffer = (LPWSTR) Where;
  611. RtlCopyMemory(
  612. Where,
  613. KerbPackageName.Buffer,
  614. KerbPackageName.Length
  615. );
  616. Where += ROUND_UP_COUNT(KerbPackageName.Length, ALIGN_LPTSTR);
  617. PassthroughRequest->LogonData = Where;
  618. PassthroughRequest->DataLength = sizeof(KERB_VERIFY_PAC_REQUEST) - sizeof(UCHAR) * ANYSIZE_ARRAY +
  619. Check->CheckSumSize +
  620. SignatureSize;
  621. VerifyRequest = (PKERB_VERIFY_PAC_REQUEST) PassthroughRequest->LogonData;
  622. VerifyRequest->MessageType = KerbVerifyPacMessage;
  623. VerifyRequest->ChecksumLength = Check->CheckSumSize;
  624. VerifyRequest->SignatureType = PrivSvrSignature->SignatureType;
  625. VerifyRequest->SignatureLength = SignatureSize;
  626. RtlCopyMemory(
  627. VerifyRequest->ChecksumAndSignature,
  628. LocalChecksum,
  629. Check->CheckSumSize
  630. );
  631. RtlCopyMemory(
  632. VerifyRequest->ChecksumAndSignature + Check->CheckSumSize,
  633. LocalPrivSvrChecksum,
  634. SignatureSize
  635. );
  636. //
  637. // We've build the buffer, now call NTLM to pass it through.
  638. //
  639. Status = LsaFunctions->CallPackage(
  640. &MsvPackageName,
  641. PassthroughRequest,
  642. RequestSize,
  643. (PVOID *) &PassthroughResponse,
  644. &ResponseSize,
  645. &SubStatus
  646. );
  647. if (!NT_SUCCESS(Status))
  648. {
  649. DebugLog((DEB_ERROR, "Failed to call MSV package to verify PAC: 0x%x. %ws, line %d\n", Status, THIS_FILE, __LINE__));
  650. if (Status == STATUS_INVALID_INFO_CLASS)
  651. {
  652. Status = STATUS_LOGON_FAILURE;
  653. }
  654. goto Cleanup;
  655. }
  656. if (!NT_SUCCESS(SubStatus))
  657. {
  658. Status = SubStatus;
  659. DebugLog((DEB_ERROR, "KDC failed to verify PAC signature: 0x%x. %ws, line %d\n", Status, THIS_FILE, __LINE__));
  660. if ((Status == STATUS_INVALID_INFO_CLASS) ||
  661. (Status == STATUS_INVALID_SERVER_STATE) ||
  662. (Status == STATUS_NO_SUCH_USER))
  663. {
  664. Status = STATUS_PRIVILEGE_NOT_HELD;
  665. }
  666. goto Cleanup;
  667. }
  668. Cleanup:
  669. KerbFreeString(&ClientName);
  670. if ( ( CheckBuffer != NULL ) &&
  671. ( Check != NULL ) )
  672. {
  673. Check->Finish(&CheckBuffer);
  674. }
  675. SafeAllocaFree(PassthroughRequest);
  676. if (PassthroughResponse != NULL)
  677. {
  678. LsaFunctions->FreeReturnBuffer(PassthroughResponse);
  679. }
  680. return(Status);
  681. }
  682. //+-------------------------------------------------------------------------
  683. //
  684. // Function: KerbPutClientString
  685. //
  686. // Synopsis: Copies a string into a buffer that will be copied to the
  687. // client's address space
  688. //
  689. // Effects:
  690. //
  691. // Arguments: Where - Location in local buffer to place string.
  692. // Delta - Difference in addresses of local and client buffers.
  693. // OutString - Receives 'put' string
  694. // InString - String to 'put'
  695. //
  696. // Requires:
  697. //
  698. // Returns:
  699. //
  700. // Notes: This code is (effectively) duplicated in
  701. // KerbPutWOWClientString. Make sure any
  702. // changes made here are applied there as well.
  703. //
  704. //--------------------------------------------------------------------------
  705. VOID
  706. KerbPutClientString(
  707. IN OUT PUCHAR * Where,
  708. IN LONG_PTR Delta,
  709. IN PUNICODE_STRING OutString,
  710. IN PUNICODE_STRING InString
  711. )
  712. {
  713. if (InString->Length == 0)
  714. {
  715. OutString->Buffer = NULL;
  716. OutString->Length = OutString->MaximumLength = 0;
  717. }
  718. else
  719. {
  720. RtlCopyMemory(
  721. *Where,
  722. InString->Buffer,
  723. InString->Length
  724. );
  725. OutString->Buffer = (LPWSTR) (*Where + Delta);
  726. OutString->Length = InString->Length;
  727. *Where += InString->Length;
  728. *(LPWSTR) (*Where) = L'\0';
  729. *Where += sizeof(WCHAR);
  730. OutString->MaximumLength = OutString->Length + sizeof(WCHAR);
  731. }
  732. }
  733. //+-------------------------------------------------------------------------
  734. //
  735. // Function: KerbAllocateInteractiveProfile
  736. //
  737. // Synopsis: This allocates and fills in the clients interactive profile.
  738. //
  739. // Effects:
  740. //
  741. // Arguments:
  742. //
  743. // ProfileBuffer - Is used to return the address of the profile
  744. // buffer in the client process. This routine is
  745. // responsible for allocating and returning the profile buffer
  746. // within the client process. However, if the caller subsequently
  747. // encounters an error which prevents a successful logon, then
  748. // then it will take care of deallocating the buffer. This
  749. // buffer is allocated with the AllocateClientBuffer() service.
  750. //
  751. // ProfileBufferSize - Receives the Size (in bytes) of the
  752. // returned profile buffer.
  753. //
  754. // NlpUser - Contains the validation information which is
  755. // to be copied in the ProfileBuffer.
  756. //
  757. // LogonSession - Logon session structure containing certificate
  758. // context for smart card logons.
  759. //
  760. // Requires:
  761. //
  762. // Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
  763. //
  764. // Notes: stolen from private\lsa\msv1_0\nlp.c
  765. //
  766. // Some of this code is (effectively) duplicated in
  767. // KerbAllocateInteractiveWOWBuffer. Make sure any
  768. // changes made here are applied there as well.
  769. //
  770. //--------------------------------------------------------------------------
  771. NTSTATUS
  772. KerbAllocateInteractiveProfile (
  773. OUT PKERB_INTERACTIVE_PROFILE *ProfileBuffer,
  774. OUT PULONG ProfileBufferSize,
  775. IN PNETLOGON_VALIDATION_SAM_INFO3 UserInfo,
  776. IN PKERB_LOGON_SESSION LogonSession,
  777. IN OPTIONAL PKERB_ENCRYPTED_TICKET LogonTicket,
  778. IN OPTIONAL PKERB_INTERACTIVE_LOGON KerbLogonInfo
  779. )
  780. {
  781. NTSTATUS Status;
  782. PKERB_INTERACTIVE_PROFILE LocalProfileBuffer = NULL;
  783. PKERB_SMART_CARD_PROFILE SmartCardProfile = NULL;
  784. PKERB_TICKET_PROFILE TicketProfile = NULL;
  785. PUCHAR ClientBufferBase = NULL;
  786. PUCHAR Where = NULL;
  787. LONG_PTR Delta = 0;
  788. BOOLEAN BuildSmartCardProfile = FALSE;
  789. BOOLEAN BuildTicketProfile = FALSE;
  790. //
  791. // Alocate the profile buffer to return to the client
  792. //
  793. KerbReadLockLogonSessions( LogonSession );
  794. #if _WIN64
  795. SECPKG_CALL_INFO CallInfo;
  796. if(!LsaFunctions->GetCallInfo(&CallInfo))
  797. {
  798. Status = STATUS_INTERNAL_ERROR;
  799. goto Cleanup;
  800. }
  801. #endif // _WIN64
  802. *ProfileBuffer = NULL;
  803. if ((LogonSession->PrimaryCredentials.PublicKeyCreds != NULL) &&
  804. (LogonSession->PrimaryCredentials.PublicKeyCreds->CertContext != NULL))
  805. {
  806. BuildSmartCardProfile = TRUE;
  807. }
  808. else if (ARGUMENT_PRESENT(KerbLogonInfo) &&
  809. (KerbLogonInfo->MessageType == KerbTicketLogon) ||
  810. (KerbLogonInfo->MessageType == KerbTicketUnlockLogon))
  811. {
  812. DsysAssert(ARGUMENT_PRESENT(LogonTicket));
  813. BuildTicketProfile = TRUE;
  814. KerbReadLockTicketCache();
  815. }
  816. //
  817. // NOTE: The 64-bit code below is (effectively) duplicated in
  818. // the WOW helper routine. If modifying one, make sure
  819. // to apply the change(s) to the other as well.
  820. //
  821. #if _WIN64
  822. if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
  823. {
  824. Status = KerbAllocateInteractiveWOWBuffer(&LocalProfileBuffer,
  825. ProfileBufferSize,
  826. UserInfo,
  827. LogonSession,
  828. LogonTicket,
  829. KerbLogonInfo,
  830. &ClientBufferBase,
  831. BuildSmartCardProfile,
  832. BuildTicketProfile);
  833. if (!NT_SUCCESS(Status))
  834. {
  835. goto Cleanup;
  836. }
  837. }
  838. else
  839. {
  840. #endif // _WIN64
  841. if (BuildSmartCardProfile)
  842. {
  843. *ProfileBufferSize = sizeof(KERB_SMART_CARD_PROFILE) +
  844. LogonSession->PrimaryCredentials.PublicKeyCreds->CertContext->cbCertEncoded;
  845. }
  846. else if (BuildTicketProfile)
  847. {
  848. *ProfileBufferSize = sizeof(KERB_TICKET_PROFILE) +
  849. LogonTicket->key.keyvalue.length;
  850. }
  851. else
  852. {
  853. *ProfileBufferSize = sizeof(KERB_INTERACTIVE_PROFILE);
  854. }
  855. *ProfileBufferSize +=
  856. UserInfo->LogonScript.Length + sizeof(WCHAR) +
  857. UserInfo->HomeDirectory.Length + sizeof(WCHAR) +
  858. UserInfo->HomeDirectoryDrive.Length + sizeof(WCHAR) +
  859. UserInfo->FullName.Length + sizeof(WCHAR) +
  860. UserInfo->ProfilePath.Length + sizeof(WCHAR) +
  861. UserInfo->LogonServer.Length + sizeof(WCHAR);
  862. SafeAllocaAllocate(LocalProfileBuffer, *ProfileBufferSize);
  863. if (LocalProfileBuffer == NULL)
  864. {
  865. Status = STATUS_INSUFFICIENT_RESOURCES;
  866. goto Cleanup;
  867. }
  868. Status = LsaFunctions->AllocateClientBuffer(
  869. NULL,
  870. *ProfileBufferSize,
  871. (PVOID *) &ClientBufferBase
  872. );
  873. if ( !NT_SUCCESS( Status ) ) {
  874. goto Cleanup;
  875. }
  876. Delta = (LONG_PTR) (ClientBufferBase - (PUCHAR) LocalProfileBuffer) ;
  877. //
  878. // Don't walk over smart card data
  879. //
  880. if (BuildSmartCardProfile)
  881. {
  882. Where = (PUCHAR) ((PKERB_SMART_CARD_PROFILE) LocalProfileBuffer + 1);
  883. }
  884. else if (BuildTicketProfile)
  885. {
  886. Where = (PUCHAR) ((PKERB_TICKET_PROFILE) LocalProfileBuffer + 1);
  887. }
  888. else
  889. {
  890. Where = (PUCHAR) (LocalProfileBuffer + 1);
  891. }
  892. //
  893. // Copy the scalar fields into the profile buffer.
  894. //
  895. LocalProfileBuffer->MessageType = KerbInteractiveProfile;
  896. LocalProfileBuffer->LogonCount = UserInfo->LogonCount;
  897. LocalProfileBuffer->BadPasswordCount= UserInfo->BadPasswordCount;
  898. OLD_TO_NEW_LARGE_INTEGER( UserInfo->LogonTime,
  899. LocalProfileBuffer->LogonTime );
  900. OLD_TO_NEW_LARGE_INTEGER( UserInfo->LogoffTime,
  901. LocalProfileBuffer->LogoffTime );
  902. OLD_TO_NEW_LARGE_INTEGER( UserInfo->KickOffTime,
  903. LocalProfileBuffer->KickOffTime );
  904. OLD_TO_NEW_LARGE_INTEGER( UserInfo->PasswordLastSet,
  905. LocalProfileBuffer->PasswordLastSet );
  906. OLD_TO_NEW_LARGE_INTEGER( UserInfo->PasswordCanChange,
  907. LocalProfileBuffer->PasswordCanChange );
  908. OLD_TO_NEW_LARGE_INTEGER( UserInfo->PasswordMustChange,
  909. LocalProfileBuffer->PasswordMustChange );
  910. LocalProfileBuffer->UserFlags = UserInfo->UserFlags;
  911. //
  912. // Copy the Unicode strings into the profile buffer.
  913. //
  914. KerbPutClientString(&Where,
  915. Delta,
  916. &LocalProfileBuffer->LogonScript,
  917. &UserInfo->LogonScript );
  918. KerbPutClientString(&Where,
  919. Delta,
  920. &LocalProfileBuffer->HomeDirectory,
  921. &UserInfo->HomeDirectory );
  922. KerbPutClientString(&Where,
  923. Delta,
  924. &LocalProfileBuffer->HomeDirectoryDrive,
  925. &UserInfo->HomeDirectoryDrive );
  926. KerbPutClientString(&Where,
  927. Delta,
  928. &LocalProfileBuffer->FullName,
  929. &UserInfo->FullName );
  930. KerbPutClientString(&Where,
  931. Delta,
  932. &LocalProfileBuffer->ProfilePath,
  933. &UserInfo->ProfilePath );
  934. KerbPutClientString(&Where,
  935. Delta,
  936. &LocalProfileBuffer->LogonServer,
  937. &UserInfo->LogonServer );
  938. if (BuildSmartCardProfile)
  939. {
  940. LocalProfileBuffer->MessageType = KerbSmartCardProfile;
  941. SmartCardProfile = (PKERB_SMART_CARD_PROFILE) LocalProfileBuffer;
  942. SmartCardProfile->CertificateSize = LogonSession->PrimaryCredentials.PublicKeyCreds->CertContext->cbCertEncoded;
  943. SmartCardProfile->CertificateData = (PUCHAR) Where + Delta;
  944. RtlCopyMemory(
  945. Where,
  946. LogonSession->PrimaryCredentials.PublicKeyCreds->CertContext->pbCertEncoded,
  947. SmartCardProfile->CertificateSize
  948. );
  949. Where += SmartCardProfile->CertificateSize;
  950. }
  951. else if (BuildTicketProfile)
  952. {
  953. LocalProfileBuffer->MessageType = KerbTicketProfile;
  954. TicketProfile = (PKERB_TICKET_PROFILE) LocalProfileBuffer;
  955. //
  956. // If the key is exportable or we are domestic, return the key
  957. //
  958. TicketProfile->SessionKey.KeyType = LogonTicket->key.keytype;
  959. TicketProfile->SessionKey.Length = LogonTicket->key.keyvalue.length;
  960. TicketProfile->SessionKey.Value = (PUCHAR) Where + Delta;
  961. RtlCopyMemory(
  962. Where,
  963. LogonTicket->key.keyvalue.value,
  964. LogonTicket->key.keyvalue.length
  965. );
  966. Where += TicketProfile->SessionKey.Length;
  967. }
  968. #if _WIN64
  969. }
  970. #endif // _WIN64
  971. //
  972. // Flush the buffer to the client's address space.
  973. //
  974. Status = LsaFunctions->CopyToClientBuffer(
  975. NULL,
  976. *ProfileBufferSize,
  977. ClientBufferBase,
  978. LocalProfileBuffer
  979. );
  980. if (!NT_SUCCESS(Status))
  981. {
  982. goto Cleanup;
  983. }
  984. *ProfileBuffer = (PKERB_INTERACTIVE_PROFILE) ClientBufferBase;
  985. Cleanup:
  986. if (BuildTicketProfile)
  987. {
  988. KerbUnlockTicketCache();
  989. }
  990. KerbUnlockLogonSessions( LogonSession );
  991. //
  992. // If the copy wasn't successful,
  993. // cleanup resources we would have returned to the caller.
  994. //
  995. if ( !NT_SUCCESS(Status) )
  996. {
  997. LsaFunctions->FreeClientBuffer( NULL, ClientBufferBase );
  998. }
  999. #if _WIN64
  1000. if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
  1001. {
  1002. KerbFree(LocalProfileBuffer);
  1003. }
  1004. else
  1005. {
  1006. #endif // _WIN64
  1007. SafeAllocaFree(LocalProfileBuffer);
  1008. #if _WIN64
  1009. }
  1010. #endif // _WIN64
  1011. return(Status);
  1012. }
  1013. //+-------------------------------------------------------------------------
  1014. //
  1015. // Function: KerbMakeTokenInformationV2
  1016. //
  1017. // Synopsis: This routine makes copies of all the pertinent
  1018. // information from the UserInfo and generates a
  1019. // LSA_TOKEN_INFORMATION_V2 data structure.
  1020. //
  1021. // Effects:
  1022. //
  1023. // Arguments:
  1024. //
  1025. // UserInfo - Contains the validation information which is
  1026. // to be copied into the TokenInformation.
  1027. //
  1028. // TokenInformation - Returns a pointer to a properly Version 1 token
  1029. // information structures. The structure and individual fields are
  1030. // allocated properly as described in ntlsa.h.
  1031. //
  1032. // Requires:
  1033. //
  1034. // Returns: STATUS_SUCCESS - Indicates the service completed successfully.
  1035. //
  1036. // STATUS_INSUFFICIENT_RESOURCES - This error indicates that
  1037. // the logon could not be completed because the client
  1038. // does not have sufficient quota to allocate the return
  1039. // buffer.
  1040. //
  1041. // Notes: stolen from msv1_0\nlp.c:NlpMakeTokenInformationV1
  1042. //
  1043. //
  1044. //--------------------------------------------------------------------------
  1045. NTSTATUS
  1046. KerbMakeTokenInformationV2(
  1047. IN PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo,
  1048. IN BOOLEAN LocalSystem,
  1049. OUT PLSA_TOKEN_INFORMATION_V2 *TokenInformation
  1050. )
  1051. {
  1052. PNETLOGON_VALIDATION_SAM_INFO3 UserInfo = ValidationInfo;
  1053. NTSTATUS Status;
  1054. PLSA_TOKEN_INFORMATION_V2 V2 = NULL;
  1055. ULONG Size, i;
  1056. BYTE SidBuffer[sizeof(SID) + sizeof(ULONG)];
  1057. SID LocalSystemSid = {SID_REVISION,1,SECURITY_NT_AUTHORITY,SECURITY_LOCAL_SYSTEM_RID};
  1058. PSID AdminsSid = SidBuffer;
  1059. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1060. DWORD NumGroups = 0;
  1061. PBYTE CurrentSid = NULL;
  1062. ULONG SidLength = 0;
  1063. KERBEROS_MACHINE_ROLE MachineRole;
  1064. //
  1065. // Filter the SIDs in the "member-to-DC" trust mode
  1066. //
  1067. KerbGlobalReadLock();
  1068. MachineRole = KerbGlobalRole;
  1069. KerbGlobalReleaseLock();
  1070. //
  1071. // If we are on a workstation, filter the SIDs that came from the DC
  1072. // on a member-to-DC boundary policy (passing NULL SID to LsaIFilterSids)
  1073. //
  1074. if ( MachineRole == KerbRoleWorkstation ||
  1075. MachineRole == KerbRoleDomainController )
  1076. {
  1077. //
  1078. // Servers in KerbRoleStandalone and KerbRoleRealmlessWksta states
  1079. // never receive Kerberos requests (as there are no local system keys
  1080. // to decrypt service tickets, due to the fact that the machine aren't
  1081. // joined to any domains).
  1082. //
  1083. Status = LsaIFilterSids(
  1084. NULL,
  1085. 0,
  1086. 0,
  1087. 0,
  1088. NULL,
  1089. NetlogonValidationSamInfo2,
  1090. UserInfo,
  1091. UserInfo->ResourceGroupDomainSid,
  1092. &UserInfo->ResourceGroupCount,
  1093. UserInfo->ResourceGroupIds
  1094. );
  1095. if ( !NT_SUCCESS( Status )) {
  1096. return Status;
  1097. }
  1098. }
  1099. //
  1100. // For local system, add in administrators & set user id to local system
  1101. //
  1102. if (LocalSystem)
  1103. {
  1104. RtlInitializeSid(
  1105. AdminsSid,
  1106. &NtAuthority,
  1107. 2
  1108. );
  1109. *RtlSubAuthoritySid(AdminsSid,0) = SECURITY_BUILTIN_DOMAIN_RID;
  1110. *RtlSubAuthoritySid(AdminsSid,1) = DOMAIN_ALIAS_RID_ADMINS;
  1111. }
  1112. //
  1113. // Allocate the structure itself
  1114. //
  1115. Size = (ULONG)sizeof(LSA_TOKEN_INFORMATION_V2);
  1116. //
  1117. // Allocate an array to hold the groups
  1118. //
  1119. Size += sizeof(TOKEN_GROUPS);
  1120. // Add room for groups passed as RIDS
  1121. NumGroups = UserInfo->GroupCount;
  1122. if(UserInfo->GroupCount)
  1123. {
  1124. Size += UserInfo->GroupCount * (RtlLengthSid(UserInfo->LogonDomainId) + sizeof(ULONG));
  1125. }
  1126. //
  1127. // If there are extra SIDs, add space for them
  1128. //
  1129. if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
  1130. ULONG i = 0;
  1131. NumGroups += UserInfo->SidCount;
  1132. // Add room for the sid's themselves
  1133. for(i=0; i < UserInfo->SidCount; i++)
  1134. {
  1135. Size += RtlLengthSid(UserInfo->ExtraSids[i].Sid);
  1136. }
  1137. }
  1138. //
  1139. // If there are resource groups, add space for them
  1140. //
  1141. if (UserInfo->UserFlags & LOGON_RESOURCE_GROUPS) {
  1142. NumGroups += UserInfo->ResourceGroupCount;
  1143. if ((UserInfo->ResourceGroupCount != 0) &&
  1144. ((UserInfo->ResourceGroupIds == NULL) ||
  1145. (UserInfo->ResourceGroupDomainSid == NULL)))
  1146. {
  1147. Status = STATUS_INVALID_PARAMETER;
  1148. goto Cleanup;
  1149. }
  1150. // Allocate space for the sids
  1151. if(UserInfo->ResourceGroupCount)
  1152. {
  1153. Size += UserInfo->ResourceGroupCount * (RtlLengthSid(UserInfo->ResourceGroupDomainSid) + sizeof(ULONG));
  1154. }
  1155. }
  1156. //
  1157. // If this is local system, add space for User & Administrators
  1158. //
  1159. if (!LocalSystem)
  1160. {
  1161. if( UserInfo->UserId )
  1162. {
  1163. Size += 2*(RtlLengthSid(UserInfo->LogonDomainId) + sizeof(ULONG));
  1164. }
  1165. else
  1166. {
  1167. if ( UserInfo->SidCount <= 0 ) {
  1168. Status = STATUS_INSUFFICIENT_LOGON_INFO;
  1169. goto Cleanup;
  1170. }
  1171. Size += (RtlLengthSid(UserInfo->LogonDomainId) + sizeof(ULONG)) + RtlLengthSid(UserInfo->ExtraSids[0].Sid);
  1172. }
  1173. }
  1174. else
  1175. {
  1176. NumGroups += 2;
  1177. // Allocate sid space for LocalSystem, Administrators
  1178. Size += sizeof(LocalSystemSid) + RtlLengthSid(AdminsSid);
  1179. // Add space for the user sid
  1180. if( UserInfo->UserId )
  1181. {
  1182. Size += (RtlLengthSid(UserInfo->LogonDomainId) + sizeof(ULONG));
  1183. }
  1184. }
  1185. Size += (NumGroups - ANYSIZE_ARRAY)*sizeof(SID_AND_ATTRIBUTES);
  1186. V2 = (PLSA_TOKEN_INFORMATION_V2) KerbAllocate( Size );
  1187. if ( V2 == NULL ) {
  1188. return STATUS_INSUFFICIENT_RESOURCES;
  1189. }
  1190. RtlZeroMemory((PVOID)V2, Size);
  1191. V2->Groups = (PTOKEN_GROUPS)(V2+1);
  1192. V2->Groups->GroupCount = 0;
  1193. CurrentSid = (PBYTE)&V2->Groups->Groups[NumGroups];
  1194. OLD_TO_NEW_LARGE_INTEGER( UserInfo->KickOffTime, V2->ExpirationTime );
  1195. if (!LocalSystem)
  1196. {
  1197. //
  1198. // If the UserId is non-zero, then it contians the users RID.
  1199. //
  1200. if ( UserInfo->UserId ) {
  1201. V2->User.User.Sid = (PSID)CurrentSid;
  1202. CurrentSid += KerbCopyDomainRelativeSid((PSID)CurrentSid, UserInfo->LogonDomainId, UserInfo->UserId);
  1203. }
  1204. //
  1205. // Make a copy of the primary group (a required field).
  1206. //
  1207. V2->PrimaryGroup.PrimaryGroup = (PSID)CurrentSid;
  1208. CurrentSid += KerbCopyDomainRelativeSid((PSID)CurrentSid, UserInfo->LogonDomainId, UserInfo->PrimaryGroupId );
  1209. }
  1210. else
  1211. {
  1212. //
  1213. // For local system, the user sid is LocalSystem and the primary
  1214. // group is LocalSystem
  1215. //
  1216. V2->User.User.Sid = (PSID)CurrentSid;
  1217. RtlCopySid(sizeof(LocalSystemSid), (PSID)CurrentSid, &LocalSystemSid);
  1218. CurrentSid += sizeof(LocalSystemSid);
  1219. //
  1220. // The real system token has LocalSystem for the primary
  1221. // group. However, the LSA will add the primary group to the
  1222. // list of groups if it isn't listed as a group, and since
  1223. // LocalSystem is the user sid, we don't want that.
  1224. //
  1225. V2->PrimaryGroup.PrimaryGroup = (PSID)CurrentSid;
  1226. SidLength = RtlLengthSid(AdminsSid);
  1227. RtlCopySid(SidLength, (PSID)CurrentSid, AdminsSid);
  1228. CurrentSid += SidLength;
  1229. //
  1230. // If there is a user sid, add it as a group id.
  1231. //
  1232. if ( UserInfo->UserId ) {
  1233. V2->Groups->Groups[V2->Groups->GroupCount].Attributes =
  1234. SE_GROUP_MANDATORY |
  1235. SE_GROUP_ENABLED|
  1236. SE_GROUP_ENABLED_BY_DEFAULT;
  1237. V2->Groups->Groups[V2->Groups->GroupCount].Sid = (PSID)CurrentSid;
  1238. CurrentSid += KerbCopyDomainRelativeSid((PSID)CurrentSid, UserInfo->LogonDomainId, UserInfo->UserId);
  1239. V2->Groups->GroupCount++;
  1240. }
  1241. //
  1242. // Add builtin administrators. This is not mandatory
  1243. //
  1244. V2->Groups->Groups[V2->Groups->GroupCount].Attributes =
  1245. SE_GROUP_ENABLED|
  1246. SE_GROUP_OWNER|
  1247. SE_GROUP_ENABLED_BY_DEFAULT;
  1248. V2->Groups->Groups[V2->Groups->GroupCount].Sid = V2->PrimaryGroup.PrimaryGroup;
  1249. V2->Groups->GroupCount++;
  1250. }
  1251. //
  1252. // Copy over all the groups passed as RIDs
  1253. //
  1254. for ( i=0; i < UserInfo->GroupCount; i++ ) {
  1255. V2->Groups->Groups[V2->Groups->GroupCount].Attributes = UserInfo->GroupIds[i].Attributes;
  1256. V2->Groups->Groups[V2->Groups->GroupCount].Sid = (PSID)CurrentSid;
  1257. CurrentSid += KerbCopyDomainRelativeSid((PSID)CurrentSid, UserInfo->LogonDomainId, UserInfo->GroupIds[i].RelativeId);
  1258. V2->Groups->GroupCount++;
  1259. }
  1260. //
  1261. // Add in the extra SIDs
  1262. //
  1263. if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
  1264. ULONG index = 0;
  1265. //
  1266. // If the user SID wasn't passed as a RID, it is the first
  1267. // SID.
  1268. //
  1269. if ( !V2->User.User.Sid ) {
  1270. V2->User.User.Sid = (PSID)CurrentSid;
  1271. SidLength = RtlLengthSid(UserInfo->ExtraSids[index].Sid);
  1272. RtlCopySid(SidLength, (PSID)CurrentSid, UserInfo->ExtraSids[index].Sid);
  1273. CurrentSid += SidLength;
  1274. index++;
  1275. }
  1276. //
  1277. // Copy over all additional SIDs as groups.
  1278. //
  1279. for ( ; index < UserInfo->SidCount; index++ ) {
  1280. V2->Groups->Groups[V2->Groups->GroupCount].Attributes =
  1281. UserInfo->ExtraSids[index].Attributes;
  1282. V2->Groups->Groups[V2->Groups->GroupCount].Sid= (PSID)CurrentSid;
  1283. SidLength = RtlLengthSid(UserInfo->ExtraSids[index].Sid);
  1284. RtlCopySid(SidLength, (PSID)CurrentSid, UserInfo->ExtraSids[index].Sid);
  1285. CurrentSid += SidLength;
  1286. V2->Groups->GroupCount++;
  1287. }
  1288. }
  1289. //
  1290. // Check to see if any resouce groups exist
  1291. //
  1292. if (UserInfo->UserFlags & LOGON_RESOURCE_GROUPS) {
  1293. for ( i=0; i < UserInfo->ResourceGroupCount; i++ ) {
  1294. V2->Groups->Groups[V2->Groups->GroupCount].Attributes = UserInfo->ResourceGroupIds[i].Attributes;
  1295. V2->Groups->Groups[V2->Groups->GroupCount].Sid= (PSID)CurrentSid;
  1296. CurrentSid += KerbCopyDomainRelativeSid((PSID)CurrentSid, UserInfo->ResourceGroupDomainSid, UserInfo->ResourceGroupIds[i].RelativeId);
  1297. V2->Groups->GroupCount++;
  1298. }
  1299. }
  1300. ASSERT( ((PBYTE)V2 + Size) == CurrentSid );
  1301. if (!V2->User.User.Sid) {
  1302. Status = STATUS_INSUFFICIENT_LOGON_INFO;
  1303. goto Cleanup;
  1304. }
  1305. //
  1306. // There are no default privileges supplied.
  1307. // We don't have an explicit owner SID.
  1308. // There is no default DACL.
  1309. //
  1310. V2->Privileges = NULL;
  1311. V2->Owner.Owner = NULL;
  1312. V2->DefaultDacl.DefaultDacl = NULL;
  1313. //
  1314. // Return the Validation Information to the caller.
  1315. //
  1316. *TokenInformation = V2;
  1317. return STATUS_SUCCESS;
  1318. //
  1319. // Deallocate any memory we've allocated
  1320. //
  1321. Cleanup:
  1322. KerbFree( V2 );
  1323. return Status;
  1324. }
  1325. //+-------------------------------------------------------------------------
  1326. //
  1327. // Function: KerbCreateDelegationLogonSession
  1328. //
  1329. // Synopsis: Creates a logon session from the delegation information
  1330. // in the GSS checksum
  1331. //
  1332. // Effects:
  1333. //
  1334. // Arguments: LogonId - The logon id for the AP request, which will be used
  1335. // for the new logon session.
  1336. // Ticket - The ticket used for the AP request, containing the
  1337. // session key to decrypt the KERB_CRED
  1338. // GssChecksum - Checksum containing the delegation information
  1339. //
  1340. // Requires:
  1341. //
  1342. // Returns: NTSTATUS codes
  1343. //
  1344. // Notes:
  1345. //
  1346. //
  1347. //--------------------------------------------------------------------------
  1348. NTSTATUS
  1349. KerbCreateDelegationLogonSession(
  1350. IN PLUID LogonId,
  1351. IN PKERB_ENCRYPTED_TICKET Ticket,
  1352. IN PKERB_GSS_CHECKSUM GssChecksum
  1353. )
  1354. {
  1355. NTSTATUS Status = STATUS_SUCCESS;
  1356. PKERB_CRED KerbCred = NULL;
  1357. PKERB_ENCRYPTED_CRED EncryptedCred = NULL;
  1358. PKERB_LOGON_SESSION LogonSession = NULL;
  1359. KERBERR KerbErr;
  1360. D_DebugLog((DEB_TRACE, "Building delegation logon session\n"));
  1361. if (GssChecksum->Delegation != 1)
  1362. {
  1363. D_DebugLog((DEB_ERROR, "Asked for GSS_C_DELEG_FLAG but Delegation != 1 = 0x%x. %ws, line %d\n",
  1364. GssChecksum->Delegation, THIS_FILE, __LINE__ ));
  1365. Status = STATUS_INVALID_PARAMETER;
  1366. goto Cleanup;
  1367. }
  1368. if (!KERB_SUCCESS(KerbUnpackKerbCred(
  1369. GssChecksum->DelegationInfo,
  1370. GssChecksum->DelegationLength,
  1371. &KerbCred
  1372. )))
  1373. {
  1374. D_DebugLog((DEB_WARN, "Failed to unpack kerb cred\n"));
  1375. Status = STATUS_INSUFFICIENT_RESOURCES;
  1376. goto Cleanup;
  1377. }
  1378. //
  1379. // Now decrypt the encrypted part of the KerbCred.
  1380. //
  1381. KerbErr = KerbDecryptDataEx(
  1382. &KerbCred->encrypted_part,
  1383. &Ticket->key,
  1384. KERB_CRED_SALT,
  1385. (PULONG) &KerbCred->encrypted_part.cipher_text.length,
  1386. KerbCred->encrypted_part.cipher_text.value
  1387. );
  1388. if (!KERB_SUCCESS(KerbErr))
  1389. {
  1390. D_DebugLog((DEB_ERROR,"Failed to decrypt KERB_CRED: 0x%x. %ws, line %d\n",KerbErr, THIS_FILE, __LINE__));
  1391. if (KerbErr == KRB_ERR_GENERIC)
  1392. {
  1393. Status = STATUS_INSUFFICIENT_RESOURCES;
  1394. goto Cleanup;
  1395. }
  1396. else
  1397. {
  1398. Status = STATUS_LOGON_FAILURE;
  1399. //
  1400. // MIT clients don't encrypt the encrypted part, so drop through
  1401. //
  1402. }
  1403. }
  1404. //
  1405. // Now unpack the encrypted part.
  1406. //
  1407. if (!KERB_SUCCESS(KerbUnpackEncryptedCred(
  1408. KerbCred->encrypted_part.cipher_text.value,
  1409. KerbCred->encrypted_part.cipher_text.length,
  1410. &EncryptedCred
  1411. )))
  1412. {
  1413. //
  1414. // Use the old status if it is available.
  1415. //
  1416. if (NT_SUCCESS(Status))
  1417. {
  1418. Status = STATUS_INSUFFICIENT_RESOURCES;
  1419. }
  1420. D_DebugLog((DEB_WARN, "Failed to unpack encrypted cred\n"));
  1421. goto Cleanup;
  1422. }
  1423. //
  1424. // Now build a logon session.
  1425. //
  1426. Status = KerbCreateLogonSessionFromKerbCred(
  1427. LogonId,
  1428. Ticket,
  1429. KerbCred,
  1430. EncryptedCred,
  1431. &LogonSession
  1432. );
  1433. if (!NT_SUCCESS(Status))
  1434. {
  1435. DebugLog((DEB_ERROR,"Failed to create logon session from kerb cred: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1436. goto Cleanup;
  1437. }
  1438. KerbWriteLockLogonSessions(LogonSession);
  1439. LogonSession->LogonSessionFlags |= KERB_LOGON_DELEGATED ;
  1440. KerbUnlockLogonSessions(LogonSession);
  1441. KerbDereferenceLogonSession( LogonSession );
  1442. Cleanup:
  1443. if (EncryptedCred != NULL)
  1444. {
  1445. KerbFreeEncryptedCred(EncryptedCred);
  1446. }
  1447. if (KerbCred != NULL)
  1448. {
  1449. KerbFreeKerbCred(KerbCred);
  1450. }
  1451. return(Status);
  1452. }
  1453. //+-------------------------------------------------------------------------
  1454. //
  1455. // Function: KerbCreateTokenFromTicket
  1456. //
  1457. // Synopsis: Pulls the PAC out of a ticket and
  1458. //
  1459. // Effects: Creates a logon session and a token
  1460. //
  1461. // Arguments: InternalTicket - The ticket off of which to base the
  1462. // token.
  1463. // Authenticator - Authenticator from the AP request,
  1464. // which may contain delegation information.
  1465. // NewLogonId - Receives the logon ID of the new logon session
  1466. // UserSid - Receives user's sid.
  1467. // NewTokenHandle - Receives the newly created token handle.
  1468. //
  1469. // Requires:
  1470. //
  1471. // Returns:
  1472. //
  1473. // Notes:
  1474. //
  1475. //
  1476. //--------------------------------------------------------------------------
  1477. NTSTATUS
  1478. KerbCreateTokenFromTicket(
  1479. IN OPTIONAL PLUID AcceptingLogonId,
  1480. IN OPTIONAL PKERB_AP_REQUEST Request,
  1481. IN PKERB_ENCRYPTED_TICKET InternalTicket,
  1482. IN OPTIONAL PKERB_AUTHENTICATOR Authenticator,
  1483. IN ULONG ContextFlags,
  1484. IN PKERB_ENCRYPTION_KEY TicketKey,
  1485. IN PUNICODE_STRING ServiceDomain,
  1486. IN KERB_ENCRYPTION_KEY* pSessionKey,
  1487. OUT PLUID NewLogonId,
  1488. OUT PSID * UserSid,
  1489. OUT PHANDLE NewTokenHandle,
  1490. OUT PUNICODE_STRING ClientName,
  1491. OUT PUNICODE_STRING ClientDomain,
  1492. OUT PUNICODE_STRING ClientNetbiosDomain,
  1493. OUT OPTIONAL PS4U_DELEGATION_INFO* S4uDelegationInfo
  1494. )
  1495. {
  1496. NTSTATUS Status = STATUS_SUCCESS;
  1497. KERBERR KerbErr = KDC_ERR_NONE;
  1498. PPACTYPE Pac = NULL;
  1499. PKERB_AUTHORIZATION_DATA PacAuthData = NULL;
  1500. PKERB_AUTHORIZATION_DATA AuthData = NULL;
  1501. PKERB_IF_RELEVANT_AUTH_DATA * IfRelevantData = NULL;
  1502. PPAC_INFO_BUFFER LogonInfo = NULL;
  1503. PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo = NULL;
  1504. PLSA_TOKEN_INFORMATION_V2 TokenInformation = NULL;
  1505. PLSA_TOKEN_INFORMATION_NULL TokenNull = NULL;
  1506. LSA_TOKEN_INFORMATION_TYPE TokenType = LsaTokenInformationNull;
  1507. PVOID LsaTokenInformation = NULL;
  1508. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel = SecurityImpersonation;
  1509. ULONG NameType;
  1510. BOOLEAN BuildNullToken = FALSE;
  1511. LUID LogonId;
  1512. LUID BaseLuid = (*AcceptingLogonId);
  1513. LUID SystemLogonId = SYSTEM_LUID;
  1514. UNICODE_STRING Workstation = NULL_UNICODE_STRING;
  1515. UNICODE_STRING TempUserName;
  1516. UNICODE_STRING TempDomainName;
  1517. PKERB_GSS_CHECKSUM GssChecksum;
  1518. BOOLEAN IsLocalSystem = FALSE;
  1519. NTSTATUS SubStatus;
  1520. HANDLE TokenHandle = NULL;
  1521. BOOLEAN FreePac = FALSE;
  1522. ULONG TicketOptions = 0;
  1523. SECPKG_PRIMARY_CRED PrimaryCredentials;
  1524. DsysAssert(AcceptingLogonId->LowPart != 0);
  1525. RtlZeroMemory(
  1526. &PrimaryCredentials,
  1527. sizeof(SECPKG_PRIMARY_CRED)
  1528. );
  1529. LogonId.HighPart = 0;
  1530. LogonId.LowPart = 0;
  1531. *UserSid = NULL;
  1532. *NewLogonId = LogonId;
  1533. //
  1534. // Check to see if this was NULL session
  1535. //
  1536. if (ARGUMENT_PRESENT(InternalTicket))
  1537. {
  1538. TicketOptions = KerbConvertFlagsToUlong(&InternalTicket->flags);
  1539. if (!KERB_SUCCESS(KerbConvertPrincipalNameToString(
  1540. ClientName,
  1541. &NameType,
  1542. &InternalTicket->client_name
  1543. )))
  1544. {
  1545. Status = STATUS_INSUFFICIENT_RESOURCES;
  1546. goto Cleanup;
  1547. }
  1548. if (!KERB_SUCCESS(KerbConvertRealmToUnicodeString(
  1549. ClientDomain,
  1550. &InternalTicket->client_realm
  1551. )))
  1552. {
  1553. Status = STATUS_INSUFFICIENT_RESOURCES;
  1554. goto Cleanup;
  1555. }
  1556. //
  1557. // Convert the principal name into just a user name
  1558. //
  1559. (VOID) KerbSplitFullServiceName(
  1560. ClientName,
  1561. &TempDomainName,
  1562. &TempUserName
  1563. );
  1564. TokenType = LsaTokenInformationV2;
  1565. //
  1566. // Make sure there is some authorization data
  1567. //
  1568. if (((InternalTicket->bit_mask & KERB_ENCRYPTED_TICKET_authorization_data_present) != 0) &&
  1569. (InternalTicket->KERB_ENCRYPTED_TICKET_authorization_data != NULL))
  1570. {
  1571. AuthData = InternalTicket->KERB_ENCRYPTED_TICKET_authorization_data;
  1572. //
  1573. // Verify the auth data is valid
  1574. //
  1575. if (!KerbVerifyAuthData(
  1576. InternalTicket->KERB_ENCRYPTED_TICKET_authorization_data
  1577. ))
  1578. {
  1579. Status = STATUS_LOGON_FAILURE;
  1580. goto Cleanup;
  1581. }
  1582. //
  1583. // Get the PAC out of the authorization data
  1584. //
  1585. KerbErr = KerbGetPacFromAuthData(
  1586. InternalTicket->KERB_ENCRYPTED_TICKET_authorization_data,
  1587. &IfRelevantData,
  1588. &PacAuthData
  1589. );
  1590. if (!KERB_SUCCESS(KerbErr))
  1591. {
  1592. Status = KerbMapKerbError(KerbErr);
  1593. goto Cleanup;
  1594. }
  1595. if (PacAuthData != NULL)
  1596. {
  1597. //
  1598. // Unmarshall the PAC
  1599. //
  1600. Pac = (PPACTYPE) PacAuthData->value.auth_data.value;
  1601. if (PAC_UnMarshal(Pac, PacAuthData->value.auth_data.length) == 0)
  1602. {
  1603. D_DebugLog((DEB_ERROR,"Failed to unmarshal pac. %ws, line %d\n", THIS_FILE, __LINE__));
  1604. Status = STATUS_INVALID_PARAMETER;
  1605. goto Cleanup;
  1606. }
  1607. //
  1608. // Verify the signature on the pac
  1609. //
  1610. Status = KerbVerifyPacSignature(
  1611. ServiceDomain,
  1612. Pac,
  1613. PacAuthData->value.auth_data.length,
  1614. TicketKey,
  1615. InternalTicket,
  1616. TRUE,
  1617. &ValidationInfo,
  1618. S4uDelegationInfo
  1619. );
  1620. if (!NT_SUCCESS(Status))
  1621. {
  1622. KerbReportPACError(
  1623. ClientName,
  1624. ClientDomain,
  1625. Status
  1626. );
  1627. DebugLog((DEB_ERROR, "Pac signature did not verify: domain %wZ, status %x\n", ServiceDomain, Status));
  1628. goto Cleanup;
  1629. }
  1630. }
  1631. }
  1632. //
  1633. // If we didn't find a PAC, try to build one locally
  1634. //
  1635. if (Pac == NULL)
  1636. {
  1637. PKERB_INTERNAL_NAME ClientKdcName = NULL;
  1638. NTSTATUS TempStatus;
  1639. //
  1640. // Convert the client's name into a usable format
  1641. //
  1642. if (!KERB_SUCCESS(KerbConvertPrincipalNameToKdcName(
  1643. &ClientKdcName,
  1644. &InternalTicket->client_name
  1645. )))
  1646. {
  1647. Status = STATUS_INSUFFICIENT_RESOURCES;
  1648. goto Cleanup;
  1649. }
  1650. TempStatus = KerbCreatePacForKerbClient(
  1651. &Pac,
  1652. ClientKdcName,
  1653. ClientDomain,
  1654. NULL
  1655. );
  1656. KerbFreeKdcName(&ClientKdcName);
  1657. if (!NT_SUCCESS(TempStatus))
  1658. {
  1659. //
  1660. // Reuse the error from above, it is is available.
  1661. //
  1662. if ((TempStatus == STATUS_NO_SUCH_USER) ||
  1663. (TempStatus == STATUS_PRIVILEGE_NOT_HELD))
  1664. {
  1665. D_DebugLog((DEB_TRACE,"Failed to create local pac for client : 0x%x\n",TempStatus));
  1666. BuildNullToken = TRUE;
  1667. Status = STATUS_SUCCESS;
  1668. }
  1669. else
  1670. {
  1671. if (NT_SUCCESS(Status))
  1672. {
  1673. Status = TempStatus;
  1674. }
  1675. DebugLog((DEB_ERROR,"Failed to create local pac for client : 0x%x\n",Status));
  1676. goto Cleanup;
  1677. }
  1678. }
  1679. //
  1680. // If we have a PAC, build everything else we need now
  1681. //
  1682. if (!BuildNullToken)
  1683. {
  1684. FreePac = TRUE;
  1685. KerbFreeString( ClientDomain );
  1686. KerbGlobalReadLock();
  1687. Status = KerbDuplicateString(
  1688. ClientDomain,
  1689. &KerbGlobalMachineName
  1690. );
  1691. KerbGlobalReleaseLock();
  1692. if (!NT_SUCCESS(Status))
  1693. {
  1694. goto Cleanup;
  1695. }
  1696. //
  1697. // Find the SAM validation info
  1698. //
  1699. LogonInfo = PAC_Find(
  1700. Pac,
  1701. PAC_LOGON_INFO,
  1702. NULL
  1703. );
  1704. if (LogonInfo == NULL)
  1705. {
  1706. DebugLog((DEB_ERROR,"Failed to find logon info! %ws, line %d\n", THIS_FILE, __LINE__));
  1707. Status = STATUS_INVALID_PARAMETER;
  1708. goto Cleanup;
  1709. }
  1710. //
  1711. // Now unmarshall the validation info
  1712. //
  1713. Status = PAC_UnmarshallValidationInfo(
  1714. &ValidationInfo,
  1715. LogonInfo->Data,
  1716. LogonInfo->cbBufferSize
  1717. );
  1718. if (!NT_SUCCESS(Status))
  1719. {
  1720. DebugLog((DEB_ERROR,"Failed to unmarshall validation info: 0x%x. %ws, line %d\n",
  1721. Status, THIS_FILE, __LINE__));
  1722. goto Cleanup;
  1723. }
  1724. }
  1725. }
  1726. if (!BuildNullToken)
  1727. {
  1728. //
  1729. // Check to see if the caller is local system on this
  1730. // machine
  1731. //
  1732. if (RtlEqualUnicodeString(
  1733. ClientName,
  1734. &KerbGlobalMachineServiceName,
  1735. TRUE) &&
  1736. KerbIsThisOurDomain(
  1737. ClientDomain
  1738. ))
  1739. {
  1740. //
  1741. // check for local loopback case: if the session key entry
  1742. // exists, it is localsystem loopback
  1743. //
  1744. Status = KerbDoesSKeyExist(pSessionKey, &IsLocalSystem);
  1745. D_DebugLog((DEB_TRACE_LOOPBACK, "KerbCreateTokenFromTicket, KerbDoesSKeyExist Status %#x, IsLocalSystem? %s\n",
  1746. Status, (IsLocalSystem ? "true" : "false")));
  1747. KerbDeleteSKeyEntry(pSessionKey);
  1748. if (!NT_SUCCESS(Status))
  1749. {
  1750. DebugLog((DEB_ERROR, "Failed to detect local loopback: 0x%x. %ws, line %d\n",
  1751. Status, THIS_FILE, __LINE__));
  1752. goto Cleanup;
  1753. }
  1754. }
  1755. //
  1756. // Now we need to build a LSA_TOKEN_INFORMATION_V2 from the validation
  1757. // information
  1758. //
  1759. Status = KerbMakeTokenInformationV2(
  1760. ValidationInfo,
  1761. IsLocalSystem,
  1762. &TokenInformation
  1763. );
  1764. if (!NT_SUCCESS(Status))
  1765. {
  1766. DebugLog((DEB_ERROR,"Failed to make token information v2: 0x%x. %ws, line %d\n",
  1767. Status, THIS_FILE, __LINE__));
  1768. goto Cleanup;
  1769. }
  1770. //
  1771. // Copy out the NT4 user name & domain name to give to the LSA. It
  1772. // requres the names from SAM because it generates the output of
  1773. // GetUserName.
  1774. //
  1775. // However, we only need to do this for MIT logons, otherwise, we
  1776. // should use the name in the ticket...
  1777. //
  1778. if (RtlEqualUnicodeString(ClientName, &ValidationInfo->EffectiveName, TRUE))
  1779. {
  1780. KerbFreeString( ClientName );
  1781. Status = KerbDuplicateString(
  1782. ClientName,
  1783. &ValidationInfo->EffectiveName
  1784. );
  1785. if (!NT_SUCCESS(Status))
  1786. {
  1787. goto Cleanup;
  1788. }
  1789. D_DebugLog((DEB_TRACE_LOGON, "CreateToken : ClientName - %wZ\n", ClientName));
  1790. Status = KerbDuplicateString(
  1791. ClientNetbiosDomain,
  1792. &ValidationInfo->LogonDomainName
  1793. );
  1794. if (!NT_SUCCESS(Status))
  1795. {
  1796. goto Cleanup;
  1797. }
  1798. D_DebugLog((DEB_TRACE_LOGON, "CreateToken : ClientSamDomain - %wZ\n", ClientNetbiosDomain));
  1799. }
  1800. //
  1801. // Now create the token.
  1802. //
  1803. LsaTokenInformation = TokenInformation;
  1804. Status = KerbDuplicateSid(
  1805. UserSid,
  1806. TokenInformation->User.User.Sid
  1807. );
  1808. if (!NT_SUCCESS(Status))
  1809. {
  1810. goto Cleanup;
  1811. }
  1812. }
  1813. }
  1814. else
  1815. {
  1816. BuildNullToken = TRUE;
  1817. }
  1818. if (BuildNullToken)
  1819. {
  1820. SID AnonymousSid = {SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_ANONYMOUS_LOGON_RID };
  1821. TokenNull = (PLSA_TOKEN_INFORMATION_NULL) KerbAllocate(sizeof(LSA_TOKEN_INFORMATION_NULL));
  1822. if (TokenNull == NULL)
  1823. {
  1824. Status = STATUS_INSUFFICIENT_RESOURCES;
  1825. goto Cleanup;
  1826. }
  1827. LsaTokenInformation = TokenNull;
  1828. TokenNull->Groups = NULL;
  1829. TokenNull->ExpirationTime = KerbGlobalWillNeverTime;
  1830. TokenType = LsaTokenInformationNull;
  1831. Status = KerbDuplicateSid(
  1832. UserSid,
  1833. &AnonymousSid
  1834. );
  1835. if (!NT_SUCCESS(Status))
  1836. {
  1837. goto Cleanup;
  1838. }
  1839. }
  1840. //
  1841. // Create a logon session.
  1842. //
  1843. NtAllocateLocallyUniqueId(&LogonId);
  1844. Status = LsaFunctions->CreateLogonSession(&LogonId);
  1845. if (!NT_SUCCESS(Status))
  1846. {
  1847. D_DebugLog((DEB_ERROR, "Failed to create logon session: 0x%x. %ws, line %d\n", Status, THIS_FILE, __LINE__));
  1848. goto Cleanup;
  1849. }
  1850. //
  1851. // Add additional names to the logon session name map. Ignore failure
  1852. // as that just means GetUserNameEx calls for these name formats later
  1853. // on will be satisfied by hitting the wire.
  1854. //
  1855. if (ValidationInfo && ValidationInfo->FullName.Length)
  1856. {
  1857. I_LsaIAddNameToLogonSession(&LogonId, NameDisplay, &ValidationInfo->FullName);
  1858. }
  1859. if (ClientDomain->Length && ClientDomain->Buffer)
  1860. {
  1861. I_LsaIAddNameToLogonSession(&LogonId, NameDnsDomain, ClientDomain);
  1862. }
  1863. //
  1864. // If the caller wanted an identify or delegate level token, duplicate the token
  1865. // now.
  1866. //
  1867. if ((ContextFlags & ISC_RET_IDENTIFY) != 0)
  1868. {
  1869. ImpersonationLevel = SecurityIdentification;
  1870. }
  1871. else if ((ContextFlags & ISC_RET_DELEGATE) != 0)
  1872. {
  1873. ImpersonationLevel = SecurityDelegation;
  1874. }
  1875. if(ClientName->Length && ClientName->Buffer)
  1876. {
  1877. PrimaryCredentials.DownlevelName.Buffer = (PWSTR)LsaFunctions->AllocateLsaHeap(ClientName->Length);
  1878. if (PrimaryCredentials.DownlevelName.Buffer == NULL) {
  1879. Status = STATUS_INSUFFICIENT_RESOURCES;
  1880. goto Cleanup;
  1881. }
  1882. PrimaryCredentials.DownlevelName.Length =
  1883. PrimaryCredentials.DownlevelName.MaximumLength = ClientName->Length;
  1884. RtlCopyMemory(
  1885. PrimaryCredentials.DownlevelName.Buffer,
  1886. ClientName->Buffer,
  1887. ClientName->Length
  1888. );
  1889. }
  1890. if ( ClientNetbiosDomain->Length && ClientNetbiosDomain->Buffer )
  1891. {
  1892. PrimaryCredentials.DomainName.Buffer = (PWSTR)LsaFunctions->AllocateLsaHeap( ClientNetbiosDomain->Length );
  1893. if (PrimaryCredentials.DomainName.Buffer == NULL) {
  1894. Status = STATUS_INSUFFICIENT_RESOURCES;
  1895. goto Cleanup;
  1896. }
  1897. PrimaryCredentials.DomainName.Length =
  1898. PrimaryCredentials.DomainName.MaximumLength = ClientNetbiosDomain->Length;
  1899. RtlCopyMemory(
  1900. PrimaryCredentials.DomainName.Buffer,
  1901. ClientNetbiosDomain->Buffer,
  1902. ClientNetbiosDomain->Length
  1903. );
  1904. }
  1905. else
  1906. {
  1907. //
  1908. // Huh? No pac validation info - use the DNS name ...
  1909. //
  1910. Status = KerbDuplicateString(
  1911. ClientNetbiosDomain,
  1912. ClientDomain
  1913. );
  1914. if (!NT_SUCCESS( Status ))
  1915. {
  1916. goto Cleanup;
  1917. }
  1918. }
  1919. DebugLog((DEB_TRACE, "KerbCreateTokenFromTicket for %wZ\\%wZ, %wZ\n", &PrimaryCredentials.DomainName, &PrimaryCredentials.DownlevelName, &PrimaryCredentials.Upn));
  1920. Status = LsaFunctions->CreateTokenEx(
  1921. &LogonId,
  1922. &KerberosSource,
  1923. Network,
  1924. ImpersonationLevel,
  1925. TokenType,
  1926. LsaTokenInformation,
  1927. NULL, // no token groups
  1928. &Workstation,
  1929. (ValidationInfo == NULL ? NULL : &ValidationInfo->ProfilePath),
  1930. &PrimaryCredentials,
  1931. SecSessionPrimaryCred,
  1932. &TokenHandle,
  1933. &SubStatus
  1934. );
  1935. // LsapCreateToken frees the TokenInformation structure for us, so
  1936. // we don't need these pointers anymore.
  1937. TokenInformation = NULL;
  1938. TokenNull = NULL;
  1939. if (!NT_SUCCESS(Status))
  1940. {
  1941. DebugLog((DEB_ERROR,"Failed to create token: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1942. goto Cleanup;
  1943. }
  1944. if (!NT_SUCCESS(SubStatus))
  1945. {
  1946. DebugLog((DEB_ERROR,"Failed to create token, substatus = 0x%x. %ws, line %d\n",SubStatus, THIS_FILE, __LINE__));
  1947. Status = SubStatus;
  1948. goto Cleanup;
  1949. }
  1950. //
  1951. // Check the delegation information to see if we need to create
  1952. // a logon session for this.
  1953. //
  1954. // For impersonated contexts, we'll also create a logon session, but
  1955. // there won't be much extra information in it.
  1956. //
  1957. if ((ContextFlags & ISC_RET_DELEGATE) != 0)
  1958. {
  1959. DsysAssert(ARGUMENT_PRESENT(Authenticator));
  1960. GssChecksum = (PKERB_GSS_CHECKSUM) Authenticator->checksum.checksum.value;
  1961. DsysAssert(GssChecksum != 0);
  1962. Status = KerbCreateDelegationLogonSession(
  1963. &LogonId,
  1964. InternalTicket,
  1965. GssChecksum
  1966. );
  1967. if (!NT_SUCCESS(Status))
  1968. {
  1969. D_DebugLog((DEB_ERROR,"Failed to create delgation logon session: 0x%x. %ws, line %d\n",
  1970. Status, THIS_FILE, __LINE__ ));
  1971. goto Cleanup;
  1972. }
  1973. }
  1974. else if (ARGUMENT_PRESENT(Request))
  1975. {
  1976. Status = KerbCreateLogonSessionFromTicket(
  1977. &LogonId,
  1978. &BaseLuid,
  1979. ClientName,
  1980. ClientDomain,
  1981. Request,
  1982. InternalTicket,
  1983. NULL
  1984. );
  1985. if (!NT_SUCCESS( Status ))
  1986. {
  1987. DebugLog((DEB_ERROR, "Failed to create ASC logon session %x\n", Status));
  1988. goto Cleanup;
  1989. }
  1990. }
  1991. //
  1992. //
  1993. //
  1994. // Apply any restrictions from the auth data
  1995. // Note: Punted until Blackcomb
  1996. //
  1997. #ifdef RESTRICTED_TOKEN
  1998. if (AuthData != NULL)
  1999. {
  2000. Status = KerbApplyAuthDataRestrictions(
  2001. &TokenHandle,
  2002. AuthData
  2003. );
  2004. if (!NT_SUCCESS(Status))
  2005. {
  2006. goto Cleanup;
  2007. }
  2008. }
  2009. #endif
  2010. *NewLogonId = LogonId;
  2011. *NewTokenHandle = TokenHandle;
  2012. Cleanup:
  2013. if(PrimaryCredentials.DownlevelName.Buffer)
  2014. {
  2015. LsaFunctions->FreeLsaHeap(PrimaryCredentials.DownlevelName.Buffer);
  2016. }
  2017. if(PrimaryCredentials.DomainName.Buffer)
  2018. {
  2019. LsaFunctions->FreeLsaHeap(PrimaryCredentials.DomainName.Buffer);
  2020. }
  2021. if(PrimaryCredentials.LogonServer.Buffer)
  2022. {
  2023. LsaFunctions->FreeLsaHeap(PrimaryCredentials.LogonServer.Buffer);
  2024. }
  2025. if(PrimaryCredentials.UserSid)
  2026. {
  2027. LsaFunctions->FreeLsaHeap(PrimaryCredentials.UserSid);
  2028. }
  2029. if(PrimaryCredentials.LogonServer.Buffer)
  2030. {
  2031. LsaFunctions->FreeLsaHeap(PrimaryCredentials.LogonServer.Buffer);
  2032. }
  2033. if(PrimaryCredentials.UserSid)
  2034. {
  2035. LsaFunctions->FreeLsaHeap(PrimaryCredentials.UserSid);
  2036. }
  2037. if (TokenInformation != NULL)
  2038. {
  2039. KerbFree( TokenInformation );
  2040. }
  2041. if (TokenNull != NULL)
  2042. {
  2043. KerbFree(TokenNull);
  2044. }
  2045. if (!NT_SUCCESS(Status))
  2046. {
  2047. //
  2048. // Note: if we have created a token, we don't want to delete
  2049. // the logon session here because we will end up dereferencing
  2050. // the logon session twice.
  2051. //
  2052. if (TokenHandle != NULL)
  2053. {
  2054. NtClose(TokenHandle);
  2055. }
  2056. else if ((LogonId.LowPart != 0) || (LogonId.HighPart != 0))
  2057. {
  2058. if (!RtlEqualLuid(
  2059. &LogonId,
  2060. &SystemLogonId
  2061. ))
  2062. {
  2063. LsaFunctions->DeleteLogonSession(&LogonId);
  2064. }
  2065. }
  2066. if (*UserSid != NULL)
  2067. {
  2068. KerbFree(*UserSid);
  2069. *UserSid = NULL;
  2070. }
  2071. }
  2072. if (FreePac && (Pac != NULL))
  2073. {
  2074. MIDL_user_free(Pac);
  2075. }
  2076. if (ValidationInfo != NULL)
  2077. {
  2078. MIDL_user_free(ValidationInfo);
  2079. }
  2080. if (IfRelevantData != NULL)
  2081. {
  2082. KerbFreeData(
  2083. PKERB_IF_RELEVANT_AUTH_DATA_PDU,
  2084. IfRelevantData
  2085. );
  2086. }
  2087. return(Status);
  2088. }
  2089. //+-------------------------------------------------------------------------
  2090. //
  2091. // Function: KerbExtractCachedCreds
  2092. //
  2093. // Synopsis: Extracts the cached credentials from a logon ticket
  2094. //
  2095. // Effects:
  2096. //
  2097. // Arguments:
  2098. //
  2099. // Requires:
  2100. //
  2101. // Returns:
  2102. //
  2103. // Notes:
  2104. //
  2105. //
  2106. //--------------------------------------------------------------------------
  2107. NTSTATUS
  2108. KerbExtractCachedCreds(
  2109. IN PPACTYPE Pac,
  2110. IN PKERB_ENCRYPTION_KEY CredentialKey,
  2111. OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY * CachedCredentials
  2112. )
  2113. {
  2114. NTSTATUS Status = STATUS_SUCCESS;
  2115. KERBERR KerbErr;
  2116. PPAC_INFO_BUFFER CredBuffer = NULL;
  2117. PPAC_CREDENTIAL_INFO CredInfo = NULL;
  2118. PBYTE CredData = NULL;
  2119. ULONG CredDataSize = 0;
  2120. PSECPKG_SUPPLEMENTAL_CRED_ARRAY DecodedCreds = NULL;
  2121. KERB_ENCRYPTED_DATA EncryptedData = {0};
  2122. *CachedCredentials = NULL;
  2123. //
  2124. // If we don't have a key to obtain credentials, o.k.
  2125. //
  2126. if (!ARGUMENT_PRESENT(CredentialKey) ||
  2127. (CredentialKey->keyvalue.value == NULL))
  2128. {
  2129. goto Cleanup;
  2130. }
  2131. CredBuffer = PAC_Find(
  2132. Pac,
  2133. PAC_CREDENTIAL_TYPE,
  2134. NULL // no previous instance
  2135. );
  2136. if (CredBuffer == NULL)
  2137. {
  2138. //
  2139. // We have no credentials. O.k.
  2140. //
  2141. goto Cleanup;
  2142. }
  2143. //
  2144. // Build an encrypted data structure so we can decrypt the response
  2145. //
  2146. CredInfo = (PPAC_CREDENTIAL_INFO) CredBuffer->Data;
  2147. if (CredBuffer->cbBufferSize < sizeof(PAC_CREDENTIAL_INFO))
  2148. {
  2149. Status = STATUS_INVALID_PARAMETER;
  2150. goto Cleanup;
  2151. }
  2152. EncryptedData.version = CredInfo->Version;
  2153. EncryptedData.encryption_type = CredInfo->EncryptionType;
  2154. EncryptedData.cipher_text.value = CredInfo->Data;
  2155. CredDataSize = CredBuffer->cbBufferSize -
  2156. FIELD_OFFSET(PAC_CREDENTIAL_INFO, Data);
  2157. EncryptedData.cipher_text.length = CredDataSize;
  2158. //
  2159. // Decrypt in place
  2160. //
  2161. CredData = CredInfo->Data;
  2162. KerbErr = KerbDecryptDataEx(
  2163. &EncryptedData,
  2164. CredentialKey,
  2165. KERB_NON_KERB_SALT,
  2166. &CredDataSize,
  2167. (PBYTE) CredData
  2168. );
  2169. if (!KERB_SUCCESS(KerbErr))
  2170. {
  2171. Status = KerbMapKerbError(KerbErr);
  2172. D_DebugLog((DEB_ERROR,"Failed to decrypt credentials: 0x%x. %ws, line %d\n",KerbErr, THIS_FILE, __LINE__));
  2173. goto Cleanup;
  2174. }
  2175. //
  2176. // Now build the return credentials
  2177. //
  2178. //
  2179. // Now unmarshall the credential data
  2180. //
  2181. Status = PAC_UnmarshallCredentials(
  2182. &DecodedCreds,
  2183. CredData,
  2184. CredDataSize
  2185. );
  2186. if (!NT_SUCCESS(Status))
  2187. {
  2188. goto Cleanup;
  2189. }
  2190. *CachedCredentials = DecodedCreds;
  2191. DecodedCreds = NULL;
  2192. Cleanup:
  2193. if (DecodedCreds != NULL)
  2194. {
  2195. MIDL_user_free(DecodedCreds);
  2196. }
  2197. return(Status);
  2198. }
  2199. //+-------------------------------------------------------------------------
  2200. //
  2201. // Function: KerbCacheLogonInformation
  2202. //
  2203. // Synopsis: Calls MSV1_0 to cache logon information. This routine
  2204. // converts the pac into MSV1_0 compatible data and
  2205. // makes a call to MSV1_0 to store it.
  2206. //
  2207. // Effects:
  2208. //
  2209. // Arguments:
  2210. //
  2211. // Requires:
  2212. //
  2213. // Returns:
  2214. //
  2215. // Notes:
  2216. //
  2217. //
  2218. //--------------------------------------------------------------------------
  2219. VOID
  2220. KerbCacheLogonInformation(
  2221. IN PUNICODE_STRING LogonUserName,
  2222. IN PUNICODE_STRING LogonDomainName,
  2223. IN OPTIONAL PUNICODE_STRING Password,
  2224. IN OPTIONAL PUNICODE_STRING DnsDomainName,
  2225. IN OPTIONAL PUNICODE_STRING Upn,
  2226. IN OPTIONAL KERB_LOGON_SESSION* LogonSession,
  2227. IN ULONG Flags,
  2228. IN OPTIONAL PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo,
  2229. IN OPTIONAL PVOID SupplementalCreds,
  2230. IN OPTIONAL ULONG SupplementalCredSize
  2231. )
  2232. {
  2233. NETLOGON_VALIDATION_SAM_INFO4 ValidationInfoToUse = {0};
  2234. NETLOGON_INTERACTIVE_INFO MsvLogonInfo = {0};
  2235. MSV1_0_CACHE_LOGON_REQUEST CacheRequest;
  2236. UNICODE_STRING MsvPackageName = CONSTANT_UNICODE_STRING(TEXT(MSV1_0_PACKAGE_NAME));
  2237. PVOID OutputBuffer = NULL;
  2238. ULONG OutputBufferSize;
  2239. NTSTATUS Status,TempStatus, SubStatus;
  2240. UNICODE_STRING LocalMachineName;
  2241. UNICODE_STRING DummyString;
  2242. PBYTE Tmp, Tmp2;
  2243. ULONG NewGroupCount = 0, Index = 0, Index2 = 0;
  2244. PVOID SupplementalMitCreds = NULL;
  2245. ULONG SupplementalMitCredSize = 0;
  2246. BOOL MitLogon = LogonSession ? ((LogonSession->LogonSessionFlags & KERB_LOGON_MIT_REALM) != 0) : FALSE;
  2247. NETLOGON_VALIDATION_SAM_INFO3 TempValidation = {0};
  2248. PNETLOGON_SID_AND_ATTRIBUTES NewGroups = NULL;
  2249. BOOL fUseTemp = FALSE;
  2250. LocalMachineName.Buffer = NULL;
  2251. if (KerbGetGlobalRole() == KerbRoleRealmlessWksta)
  2252. {
  2253. D_DebugLog((DEB_WARN, "KerbCacheLogonInformation does not support cached logon for reamless workstation\n"));
  2254. Status = STATUS_NOT_SUPPORTED;
  2255. goto Cleanup;
  2256. }
  2257. //
  2258. // Cram resource groups into extra sids, as INFO4 doesn't support
  2259. // them.
  2260. //
  2261. if ( ARGUMENT_PRESENT(ValidationInfo) &&
  2262. ((ValidationInfo->UserFlags & LOGON_RESOURCE_GROUPS) != 0))
  2263. {
  2264. D_DebugLog((DEB_TRACE, "Found resource groups in PAC\n"));
  2265. if (ValidationInfo->ResourceGroupCount != 0)
  2266. {
  2267. DebugLog((DEB_ERROR, " Expanding resource groups\n"));
  2268. //
  2269. // Build a new structure that contains the resource groups
  2270. //
  2271. RtlCopyMemory(
  2272. &TempValidation,
  2273. ValidationInfo,
  2274. sizeof(NETLOGON_VALIDATION_SAM_INFO3)
  2275. );
  2276. NewGroupCount = ValidationInfo->SidCount + ValidationInfo->ResourceGroupCount;
  2277. NewGroups = (PNETLOGON_SID_AND_ATTRIBUTES) KerbAllocate(sizeof(NETLOGON_SID_AND_ATTRIBUTES) * NewGroupCount);
  2278. if (NewGroups == NULL)
  2279. {
  2280. Status= STATUS_INSUFFICIENT_RESOURCES;
  2281. goto Cleanup;
  2282. }
  2283. //
  2284. // Add in all the extra sids
  2285. //
  2286. RtlCopyMemory(
  2287. NewGroups,
  2288. ValidationInfo->ExtraSids,
  2289. ValidationInfo->SidCount * sizeof(NETLOGON_SID_AND_ATTRIBUTES)
  2290. );
  2291. Index2 = ValidationInfo->SidCount;
  2292. for (Index = 0; Index < ValidationInfo->ResourceGroupCount ; Index++)
  2293. {
  2294. NewGroups[Index2].Attributes = ValidationInfo->ResourceGroupIds[Index].Attributes;
  2295. NewGroups[Index2].Sid = KerbMakeDomainRelativeSid(
  2296. ValidationInfo->ResourceGroupDomainSid,
  2297. ValidationInfo->ResourceGroupIds[Index].RelativeId );
  2298. if ( NewGroups[Index2].Sid == NULL )
  2299. {
  2300. Status = STATUS_INSUFFICIENT_RESOURCES;
  2301. goto Cleanup;
  2302. }
  2303. Index2++;
  2304. }
  2305. DsysAssert(NewGroupCount == Index2);
  2306. TempValidation.UserFlags |= LOGON_EXTRA_SIDS;
  2307. TempValidation.SidCount = NewGroupCount;
  2308. TempValidation.ExtraSids = NewGroups;
  2309. fUseTemp = TRUE;
  2310. }
  2311. }
  2312. //
  2313. // Build up the NETLOGON_VALIDATION_SAM_INFO4 structure to pass to NTLM
  2314. //
  2315. if (ARGUMENT_PRESENT(ValidationInfo))
  2316. {
  2317. RtlCopyMemory(&ValidationInfoToUse,
  2318. (fUseTemp ? &TempValidation : ValidationInfo),
  2319. sizeof(NETLOGON_VALIDATION_SAM_INFO2));
  2320. if (ARGUMENT_PRESENT(DnsDomainName))
  2321. {
  2322. ValidationInfoToUse.DnsLogonDomainName = *DnsDomainName;
  2323. }
  2324. }
  2325. MsvLogonInfo.Identity.LogonDomainName = *LogonDomainName;
  2326. MsvLogonInfo.Identity.UserName = *LogonUserName;
  2327. CacheRequest.RequestFlags = Flags;
  2328. //
  2329. // If this was a logon to an MIT realm that we know about,
  2330. // then add the MIT username (upn?) & realm to the supplemental data
  2331. //
  2332. if (MitLogon)
  2333. {
  2334. D_DebugLog((DEB_TRACE, "KerbCacheLogonInformation caching MIT princ: logon %wZ\\%wZ, account %wZ\\%wZ, cred %wZ\\%wZ\n",
  2335. LogonDomainName, LogonUserName,
  2336. &ValidationInfoToUse.LogonDomainName, &ValidationInfoToUse.EffectiveName,
  2337. &LogonSession->PrimaryCredentials.DomainName, &LogonSession->PrimaryCredentials.UserName));
  2338. CacheRequest.RequestFlags |= MSV1_0_CACHE_LOGON_REQUEST_MIT_LOGON;
  2339. //
  2340. // Marshall the MIT info into the supplemental creds.
  2341. //
  2342. SupplementalMitCredSize =
  2343. (2* sizeof(UNICODE_STRING)) +
  2344. ROUND_UP_COUNT(LogonSession->PrimaryCredentials.UserName.Length, ALIGN_LONG) +
  2345. ROUND_UP_COUNT(LogonSession->PrimaryCredentials.DomainName.Length, ALIGN_LONG);
  2346. SafeAllocaAllocate(SupplementalMitCreds, SupplementalMitCredSize);
  2347. if (NULL == SupplementalMitCreds)
  2348. {
  2349. Status = STATUS_INSUFFICIENT_RESOURCES;
  2350. goto Cleanup;
  2351. }
  2352. DummyString.Length = DummyString.MaximumLength = LogonSession->PrimaryCredentials.UserName.Length;
  2353. Tmp = (PBYTE) (SupplementalMitCreds) + sizeof(UNICODE_STRING);
  2354. if (DummyString.Length > 0)
  2355. {
  2356. RtlCopyMemory(
  2357. Tmp,
  2358. LogonSession->PrimaryCredentials.UserName.Buffer,
  2359. LogonSession->PrimaryCredentials.UserName.Length
  2360. );
  2361. DummyString.Buffer = (PWSTR) UlongToPtr(RtlPointerToOffset(SupplementalMitCreds, Tmp));
  2362. }
  2363. else
  2364. {
  2365. DummyString.Buffer = NULL;
  2366. }
  2367. RtlCopyMemory(
  2368. SupplementalMitCreds,
  2369. &DummyString,
  2370. sizeof(UNICODE_STRING)
  2371. );
  2372. Tmp2 = Tmp + ROUND_UP_COUNT(DummyString.Length, ALIGN_LONG);
  2373. Tmp += ROUND_UP_COUNT(DummyString.Length, ALIGN_LONG) + sizeof(UNICODE_STRING);
  2374. DummyString.Length = DummyString.MaximumLength = LogonSession->PrimaryCredentials.DomainName.Length;
  2375. if (DummyString.Length > 0)
  2376. {
  2377. RtlCopyMemory(
  2378. Tmp,
  2379. LogonSession->PrimaryCredentials.DomainName.Buffer,
  2380. LogonSession->PrimaryCredentials.DomainName.Length
  2381. );
  2382. DummyString.Buffer = (PWSTR) UlongToPtr(RtlPointerToOffset(SupplementalMitCreds, Tmp));
  2383. }
  2384. else
  2385. {
  2386. DummyString.Buffer = NULL;
  2387. }
  2388. RtlCopyMemory(
  2389. Tmp2,
  2390. &DummyString,
  2391. sizeof(UNICODE_STRING)
  2392. );
  2393. CacheRequest.SupplementalCacheData = SupplementalMitCreds;
  2394. CacheRequest.SupplementalCacheDataLength = SupplementalMitCredSize;
  2395. }
  2396. else
  2397. {
  2398. CacheRequest.RequestFlags = Flags;
  2399. CacheRequest.SupplementalCacheData = SupplementalCreds;
  2400. CacheRequest.SupplementalCacheDataLength = SupplementalCredSize;
  2401. }
  2402. //
  2403. // Store the originating package of the logon
  2404. //
  2405. MsvLogonInfo.Identity.ParameterControl = RPC_C_AUTHN_GSS_KERBEROS;
  2406. KerbGlobalReadLock();
  2407. Status = KerbDuplicateString( &LocalMachineName, &KerbGlobalMachineName );
  2408. KerbGlobalReleaseLock();
  2409. if(!NT_SUCCESS(Status))
  2410. {
  2411. D_DebugLog((DEB_ERROR, "Failed to duplicate KerbGlobalMachineName\n"));
  2412. goto Cleanup;
  2413. }
  2414. MsvLogonInfo.Identity.Workstation = LocalMachineName;
  2415. if (ARGUMENT_PRESENT(Password))
  2416. {
  2417. Status = RtlCalculateNtOwfPassword(
  2418. Password,
  2419. &MsvLogonInfo.NtOwfPassword
  2420. );
  2421. if (!NT_SUCCESS(Status))
  2422. {
  2423. D_DebugLog((DEB_ERROR,"Failed to calculate NT OWF for %wZ. %ws, line %d\n",Password, THIS_FILE, __LINE__));
  2424. goto Cleanup;
  2425. }
  2426. }
  2427. CacheRequest.MessageType = MsV1_0CacheLogon;
  2428. CacheRequest.LogonInformation = &MsvLogonInfo;
  2429. CacheRequest.ValidationInformation = &ValidationInfoToUse;
  2430. //
  2431. // tell NTLM it's a INFO4 structure.
  2432. //
  2433. CacheRequest.RequestFlags |= MSV1_0_CACHE_LOGON_REQUEST_INFO4;
  2434. TempStatus = LsaFunctions->CallPackage(
  2435. &MsvPackageName,
  2436. &CacheRequest,
  2437. sizeof(CacheRequest),
  2438. &OutputBuffer,
  2439. &OutputBufferSize,
  2440. &SubStatus
  2441. );
  2442. if (!NT_SUCCESS(TempStatus) || !NT_SUCCESS(SubStatus))
  2443. {
  2444. DebugLog((DEB_ERROR, "KerbCacheLogonInformation failed to cache credentials: 0x%x, 0x%x. %ws, line %d\n", TempStatus, SubStatus, THIS_FILE, __LINE__));
  2445. }
  2446. Cleanup:
  2447. KerbFreeString( &LocalMachineName );
  2448. if (NewGroups != NULL)
  2449. {
  2450. for (Index = ValidationInfo->SidCount; Index < NewGroupCount ; Index++ )
  2451. {
  2452. if (NewGroups[Index].Sid != 0)
  2453. {
  2454. KerbFree(NewGroups[Index].Sid);
  2455. }
  2456. }
  2457. KerbFree(NewGroups);
  2458. }
  2459. SafeAllocaFree(SupplementalMitCreds);
  2460. }
  2461. //+-------------------------------------------------------------------------
  2462. //
  2463. // Function: KerbGetCredsFromU2UTicket
  2464. //
  2465. // Synopsis: Verifies the ticket, and gets the credentials from the PAC
  2466. //
  2467. // Effects:
  2468. //
  2469. // Arguments:
  2470. //
  2471. // Requires:
  2472. //
  2473. // Returns:
  2474. //
  2475. // Notes:
  2476. //
  2477. //
  2478. //-----
  2479. NTSTATUS
  2480. KerbGetCredsFromU2UTicket(
  2481. IN PKERB_TICKET_CACHE_ENTRY U2UTicket,
  2482. IN PKERB_TICKET_CACHE_ENTRY Tgt,
  2483. IN OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY * OutputCreds,
  2484. OUT PNETLOGON_VALIDATION_SAM_INFO3* ValidationInfo
  2485. )
  2486. {
  2487. KERBERR KerbErr = KDC_ERR_NONE;
  2488. NTSTATUS Status = STATUS_SUCCESS;
  2489. PPACTYPE Pac = NULL;
  2490. PKERB_AUTHORIZATION_DATA PacAuthData = NULL;
  2491. PKERB_AUTHORIZATION_DATA AuthData = NULL;
  2492. PKERB_IF_RELEVANT_AUTH_DATA * IfRelevantData = NULL;
  2493. PKERB_ENCRYPTED_TICKET EncryptedTicket = NULL;
  2494. PSECPKG_SUPPLEMENTAL_CRED_ARRAY LocalCreds = NULL;
  2495. *OutputCreds = NULL;
  2496. //
  2497. // Validate the ticket
  2498. //
  2499. KerbErr = KerbVerifyTicket(
  2500. &U2UTicket->Ticket,
  2501. 0,
  2502. NULL,
  2503. NULL,
  2504. &Tgt->SessionKey,
  2505. NULL,
  2506. &EncryptedTicket
  2507. );
  2508. if (!KERB_SUCCESS(KerbErr))
  2509. {
  2510. DebugLog((DEB_ERROR, "KerbVerifyTicket failed - %x\n", KerbErr));
  2511. goto Cleanup;
  2512. }
  2513. //
  2514. // Extract the PAC
  2515. //
  2516. if (((EncryptedTicket->bit_mask & KERB_ENCRYPTED_TICKET_authorization_data_present) == 0) ||
  2517. (EncryptedTicket->KERB_ENCRYPTED_TICKET_authorization_data == NULL))
  2518. {
  2519. D_DebugLog((DEB_ERROR, "No authdata!\n"));
  2520. DsysAssert(FALSE);
  2521. Status = STATUS_LOGON_FAILURE;
  2522. goto Cleanup;
  2523. }
  2524. AuthData = EncryptedTicket->KERB_ENCRYPTED_TICKET_authorization_data;
  2525. //
  2526. // Verify the auth data is valid
  2527. //
  2528. if (!KerbVerifyAuthData( AuthData ))
  2529. {
  2530. Status = STATUS_LOGON_FAILURE;
  2531. goto Cleanup;
  2532. }
  2533. //
  2534. // Get the PAC out of the authorization data
  2535. //
  2536. KerbErr = KerbGetPacFromAuthData(
  2537. AuthData,
  2538. &IfRelevantData,
  2539. &PacAuthData
  2540. );
  2541. if (!KERB_SUCCESS(KerbErr))
  2542. {
  2543. Status = KerbMapKerbError(KerbErr);
  2544. goto Cleanup;
  2545. }
  2546. if ( PacAuthData == NULL )
  2547. {
  2548. D_DebugLog((DEB_ERROR, "No PAC!\n"));
  2549. Status = STATUS_LOGON_FAILURE;
  2550. goto Cleanup;
  2551. }
  2552. //
  2553. // Unmarshall the PAC
  2554. //
  2555. Pac = (PPACTYPE) PacAuthData->value.auth_data.value;
  2556. if (PAC_UnMarshal(Pac, PacAuthData->value.auth_data.length) == 0)
  2557. {
  2558. D_DebugLog((DEB_ERROR, "Failed to unmarshal pac. %ws, line %d\n", THIS_FILE, __LINE__));
  2559. Status = STATUS_INVALID_PARAMETER;
  2560. goto Cleanup;
  2561. }
  2562. //
  2563. // Verify the signature on the pac
  2564. //
  2565. Status = KerbVerifyPacSignature(
  2566. &Tgt->ClientDomainName,
  2567. Pac,
  2568. PacAuthData->value.auth_data.length,
  2569. &Tgt->SessionKey,
  2570. EncryptedTicket,
  2571. FALSE,
  2572. ValidationInfo,
  2573. NULL
  2574. );
  2575. if (!NT_SUCCESS(Status))
  2576. {
  2577. DebugLog((DEB_WARN,"Pac signature did not verify %x\n", Status));
  2578. DsysAssert(FALSE);
  2579. goto Cleanup;
  2580. }
  2581. Status = KerbExtractCachedCreds(
  2582. Pac,
  2583. &Tgt->CredentialKey,
  2584. &LocalCreds
  2585. );
  2586. if (!NT_SUCCESS( Status ))
  2587. {
  2588. DebugLog((DEB_ERROR, "KerbExtractCachedCreds failed %x\n", Status));
  2589. goto Cleanup;
  2590. }
  2591. *OutputCreds = LocalCreds;
  2592. LocalCreds = NULL;
  2593. Cleanup:
  2594. if (!KERB_SUCCESS(KerbErr))
  2595. {
  2596. Status = KerbMapKerbError( KerbErr );
  2597. }
  2598. if ( LocalCreds )
  2599. {
  2600. MIDL_user_free( LocalCreds );
  2601. }
  2602. if (IfRelevantData != NULL)
  2603. {
  2604. KerbFreeData(
  2605. PKERB_IF_RELEVANT_AUTH_DATA_PDU,
  2606. IfRelevantData
  2607. );
  2608. }
  2609. if ( EncryptedTicket )
  2610. {
  2611. KerbFreeTicket( EncryptedTicket );
  2612. }
  2613. return (Status);
  2614. }
  2615. //+-------------------------------------------------------------------------
  2616. //
  2617. // Function: KerbCreateTokenFromLogonTicket
  2618. //
  2619. // Synopsis: Creates a token from a ticket to the workstation
  2620. //
  2621. // Effects:
  2622. //
  2623. // Arguments:
  2624. //
  2625. // Requires:
  2626. //
  2627. // Returns:
  2628. //
  2629. // Notes:
  2630. //
  2631. //
  2632. //--------------------------------------------------------------------------
  2633. NTSTATUS
  2634. KerbCreateTokenFromLogonTicket(
  2635. IN OPTIONAL PKERB_TICKET_CACHE_ENTRY LogonTicket,
  2636. IN PLUID LogonId,
  2637. IN PKERB_INTERACTIVE_LOGON KerbLogonInfo,
  2638. IN BOOLEAN RealmlessWkstaLogon,
  2639. IN SECURITY_LOGON_TYPE LogonType,
  2640. IN OPTIONAL PKERB_ENCRYPTION_KEY CredentialKey,
  2641. IN OPTIONAL PKERB_MESSAGE_BUFFER ForwardedTgt,
  2642. IN OPTIONAL PUNICODE_STRING MappedName,
  2643. IN OPTIONAL PKERB_INTERNAL_NAME S4UClient,
  2644. IN OPTIONAL PUNICODE_STRING S4URealm,
  2645. IN OPTIONAL PLUID AlternateLuid,
  2646. IN PKERB_LOGON_SESSION LogonSession,
  2647. OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
  2648. OUT PVOID *NewTokenInformation,
  2649. OUT PULONG ProfileBufferLength,
  2650. OUT PVOID * ProfileBuffer,
  2651. OUT PSECPKG_PRIMARY_CRED PrimaryCredentials,
  2652. OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY * CachedCredentials,
  2653. OUT PNETLOGON_VALIDATION_SAM_INFO4 * ppValidationInfo
  2654. )
  2655. {
  2656. NTSTATUS Status = STATUS_SUCCESS;
  2657. PKERB_LOGON_SESSION SystemLogonSession = NULL;
  2658. LUID SystemLogonId = SYSTEM_LUID;
  2659. BOOLEAN TicketCacheLocked = FALSE;
  2660. BOOLEAN LogonSessionsLocked = FALSE;
  2661. PKERB_ENCRYPTED_TICKET Ticket = NULL;
  2662. PPACTYPE Pac = NULL;
  2663. PKERB_AUTHORIZATION_DATA PacAuthData = NULL;
  2664. PKERB_IF_RELEVANT_AUTH_DATA * IfRelevantData = NULL;
  2665. PPAC_INFO_BUFFER LogonInfo = NULL;
  2666. PNETLOGON_VALIDATION_SAM_INFO3 ValidationInfo = NULL;
  2667. PNETLOGON_VALIDATION_SAM_INFO4 ValidationInfo4 = NULL;
  2668. PLSA_TOKEN_INFORMATION_V2 TokenInformation = NULL;
  2669. PKERB_ENCRYPTION_KEY WkstaKey = NULL;
  2670. BOOLEAN FreePac = FALSE;
  2671. KERBERR KerbErr;
  2672. UNICODE_STRING LocalDnsDomain = {0};
  2673. LPWSTR lpDnsDomainName;
  2674. UNICODE_STRING CRealm = {0};
  2675. UNICODE_STRING CName = {0};
  2676. UNICODE_STRING WkstaDomain = {0};
  2677. ULONG NameType;
  2678. // cache interactive logons only
  2679. BOOLEAN CacheLogon = (LogonType == Interactive || LogonType == Service ||
  2680. LogonType == Batch || LogonType == RemoteInteractive );
  2681. BOOLEAN AllowWorkstationLogon = (LogonType == Network || LogonType == NetworkCleartext);
  2682. BOOLEAN CheckIdentify = ((KerbLogonInfo->MessageType == KerbTicketLogon) ||
  2683. (KerbLogonInfo->MessageType == KerbTicketUnlockLogon) ||
  2684. (KerbLogonInfo->MessageType == KerbS4ULogon));
  2685. *ProfileBuffer = NULL;
  2686. *NewTokenInformation = NULL;
  2687. *ppValidationInfo = NULL;
  2688. //
  2689. // If you're not on a "joined" wksta, you don't need to use the
  2690. // system key. Otherwise, locate the sytem logon session, which contains the key
  2691. // to decrypt the ticket
  2692. //
  2693. if (!RealmlessWkstaLogon)
  2694. {
  2695. //
  2696. // S4U Logons will take place in the caller's context, and tickets
  2697. // will be given directly to caller.
  2698. //
  2699. if (KerbLogonInfo->MessageType == KerbS4ULogon)
  2700. {
  2701. SystemLogonSession = KerbReferenceLogonSession(
  2702. AlternateLuid,
  2703. FALSE
  2704. );
  2705. DsysAssert(SystemLogonSession != NULL);
  2706. if (SystemLogonSession == NULL)
  2707. {
  2708. Status = STATUS_NO_SUCH_LOGON_SESSION;
  2709. goto Cleanup;
  2710. }
  2711. DsysAssert( !LogonSessionsLocked );
  2712. KerbReadLockLogonSessions(SystemLogonSession);
  2713. LogonSessionsLocked = TRUE;
  2714. DsysAssert( !TicketCacheLocked );
  2715. KerbReadLockTicketCache();
  2716. TicketCacheLocked = TRUE;
  2717. Status = KerbDuplicateString(
  2718. &LocalDnsDomain,
  2719. &SystemLogonSession->PrimaryCredentials.DomainName
  2720. );
  2721. if (!NT_SUCCESS(Status))
  2722. {
  2723. goto Cleanup;
  2724. }
  2725. if (LogonTicket && (LogonTicket->CacheFlags & KERB_TICKET_CACHE_TKT_ENC_IN_SKEY))
  2726. {
  2727. D_DebugLog((DEB_TRACE, "KerbCreateTokenFromLogonTicket using LogonTicketKey supplied\n"));
  2728. WkstaKey = &LogonTicket->SessionKey; // use supplied logon ticket key
  2729. }
  2730. }
  2731. else
  2732. {
  2733. SystemLogonSession = KerbReferenceLogonSession(
  2734. &SystemLogonId,
  2735. FALSE
  2736. );
  2737. DsysAssert(SystemLogonSession != NULL);
  2738. if (SystemLogonSession == NULL)
  2739. {
  2740. Status = STATUS_NO_SUCH_LOGON_SESSION;
  2741. goto Cleanup;
  2742. }
  2743. DsysAssert((SystemLogonSession->LogonSessionFlags & KERB_LOGON_NO_PASSWORD) == 0);
  2744. Status = KerbGetOurDomainName(
  2745. &LocalDnsDomain
  2746. );
  2747. if (!NT_SUCCESS(Status))
  2748. {
  2749. goto Cleanup;
  2750. }
  2751. DsysAssert( !LogonSessionsLocked );
  2752. KerbReadLockLogonSessions(SystemLogonSession);
  2753. LogonSessionsLocked = TRUE;
  2754. DsysAssert( !TicketCacheLocked );
  2755. KerbReadLockTicketCache();
  2756. TicketCacheLocked = TRUE;
  2757. }
  2758. //
  2759. // Decrypt the ticket
  2760. //
  2761. //
  2762. // Get the appropriate key
  2763. //
  2764. if (!WkstaKey)
  2765. {
  2766. D_DebugLog((DEB_TRACE, "KerbCreateTokenFromLogonTicket getting WkstaKey from SystemLogonSession\n"));
  2767. WkstaKey = KerbGetKeyFromList(
  2768. SystemLogonSession->PrimaryCredentials.Passwords,
  2769. LogonTicket->Ticket.encrypted_part.encryption_type
  2770. );
  2771. if (WkstaKey == NULL)
  2772. {
  2773. D_DebugLog((DEB_ERROR, "Couldn't find correct key type: 0x%x. %ws, line %d\n",
  2774. LogonTicket->Ticket.encrypted_part.encryption_type, THIS_FILE, __LINE__ ));
  2775. Status = STATUS_LOGON_FAILURE;
  2776. goto Cleanup;
  2777. }
  2778. }
  2779. KerbErr = KerbVerifyTicket(
  2780. &LogonTicket->Ticket,
  2781. 1,
  2782. &KerbGlobalMachineServiceName,
  2783. &LocalDnsDomain,
  2784. WkstaKey,
  2785. NULL, // don't check time
  2786. &Ticket
  2787. );
  2788. //
  2789. // Check that expired ticket for ticket logon are handled properly.
  2790. // The client may pass a flag to explicitly allow an expired ticket.
  2791. // This ticket makes the logon fail if the ticket is not expired.
  2792. //
  2793. if ((KerbLogonInfo->MessageType == KerbTicketLogon) ||
  2794. (KerbLogonInfo->MessageType == KerbTicketUnlockLogon))
  2795. {
  2796. BOOLEAN AllowExpired = FALSE;
  2797. PKERB_TICKET_LOGON TicketLogon = (PKERB_TICKET_LOGON) KerbLogonInfo;
  2798. if ((TicketLogon->Flags & KERB_LOGON_FLAG_ALLOW_EXPIRED_TICKET) != 0)
  2799. {
  2800. AllowExpired = TRUE;
  2801. }
  2802. if (AllowExpired)
  2803. {
  2804. if (KerbErr == KDC_ERR_NONE)
  2805. {
  2806. Status = STATUS_INVALID_PARAMETER;
  2807. D_DebugLog((DEB_ERROR,"Can't allow expired ticket on a non-expired ticket\n"));
  2808. goto Cleanup;
  2809. }
  2810. else if (KerbErr == KRB_AP_ERR_TKT_EXPIRED)
  2811. {
  2812. KerbErr = KDC_ERR_NONE;
  2813. }
  2814. }
  2815. }
  2816. if (!KERB_SUCCESS(KerbErr))
  2817. {
  2818. DebugLog((DEB_ERROR,"Failed to decrypt workstation ticket: 0x%x. %ws, line %d\n",KerbErr, THIS_FILE, __LINE__));
  2819. if (KerbErr == KRB_AP_ERR_MODIFIED)
  2820. {
  2821. Status = STATUS_TRUSTED_RELATIONSHIP_FAILURE;
  2822. }
  2823. else
  2824. {
  2825. Status = KerbMapKerbError(KerbErr);
  2826. }
  2827. }
  2828. //
  2829. // If that failed, try again using the old password of the server
  2830. //
  2831. if ((Status == STATUS_TRUSTED_RELATIONSHIP_FAILURE) &&
  2832. (SystemLogonSession->PrimaryCredentials.OldPasswords != NULL))
  2833. {
  2834. DebugLog((DEB_TRACE,"Current system password failed, trying old password\n"));
  2835. //
  2836. // Get the appropriate key
  2837. //
  2838. WkstaKey = KerbGetKeyFromList(
  2839. SystemLogonSession->PrimaryCredentials.OldPasswords,
  2840. LogonTicket->Ticket.encrypted_part.encryption_type
  2841. );
  2842. if (WkstaKey == NULL)
  2843. {
  2844. DebugLog((DEB_ERROR,"Couldn't find correct key type: 0x%x. %ws, line %d\n",
  2845. LogonTicket->Ticket.encrypted_part.encryption_type, THIS_FILE, __LINE__ ));
  2846. Status = STATUS_LOGON_FAILURE;
  2847. goto Cleanup;
  2848. }
  2849. KerbErr = KerbVerifyTicket(
  2850. &LogonTicket->Ticket,
  2851. 1,
  2852. &KerbGlobalMachineServiceName,
  2853. &LocalDnsDomain,
  2854. WkstaKey,
  2855. NULL, // don't check time
  2856. &Ticket
  2857. );
  2858. if (!KERB_SUCCESS(KerbErr))
  2859. {
  2860. DebugLog((DEB_ERROR,"Failed to decrypt workstation ticket. %ws, line %d\n", THIS_FILE, __LINE__));
  2861. if (KerbErr == KRB_AP_ERR_MODIFIED)
  2862. {
  2863. Status = STATUS_TRUSTED_RELATIONSHIP_FAILURE;
  2864. }
  2865. else
  2866. {
  2867. Status = KerbMapKerbError(KerbErr);
  2868. }
  2869. }
  2870. else
  2871. {
  2872. Status = STATUS_SUCCESS;
  2873. }
  2874. }
  2875. if (!NT_SUCCESS(Status))
  2876. {
  2877. goto Cleanup;
  2878. }
  2879. //
  2880. // Check out the client name in the ticket. It must match, exactly,
  2881. // what was requested.
  2882. //
  2883. if (KerbLogonInfo->MessageType == KerbS4ULogon)
  2884. {
  2885. BOOLEAN Result = FALSE;
  2886. DsysAssert(ARGUMENT_PRESENT(S4UClient));
  2887. DsysAssert(ARGUMENT_PRESENT(S4URealm));
  2888. KerbErr = KerbCompareKdcNameToPrincipalName(
  2889. &Ticket->client_name,
  2890. S4UClient,
  2891. &Result
  2892. );
  2893. if (!KERB_SUCCESS(KerbErr))
  2894. {
  2895. Status = STATUS_INSUFFICIENT_RESOURCES;
  2896. goto Cleanup;
  2897. }
  2898. else if (!Result)
  2899. {
  2900. //
  2901. // TBD: Audit?
  2902. //
  2903. DebugLog((DEB_ERROR, "S4UClient name != ticket CLIENTNAME\n"));
  2904. Status = STATUS_LOGON_FAILURE;
  2905. DsysAssert(FALSE);
  2906. goto Cleanup;
  2907. }
  2908. KerbErr = KerbCompareUnicodeRealmToKerbRealm(
  2909. &Ticket->client_realm,
  2910. S4URealm,
  2911. &Result
  2912. );
  2913. if (!KERB_SUCCESS(KerbErr))
  2914. {
  2915. Status = STATUS_INSUFFICIENT_RESOURCES;
  2916. goto Cleanup;
  2917. }
  2918. else if (!Result)
  2919. {
  2920. //
  2921. // TBD: Audit?
  2922. //
  2923. DebugLog((DEB_ERROR, "S4UClient REALM != ticket REALM\n"));
  2924. Status = STATUS_LOGON_FAILURE;
  2925. DsysAssert(FALSE);
  2926. goto Cleanup;
  2927. }
  2928. }
  2929. //
  2930. // Make sure there is some authorization data
  2931. //
  2932. if (((Ticket->bit_mask & KERB_ENCRYPTED_TICKET_authorization_data_present) != 0) &&
  2933. (Ticket->KERB_ENCRYPTED_TICKET_authorization_data != NULL))
  2934. {
  2935. KERB_ENCRYPTION_KEY LocalKey = {0};
  2936. //
  2937. // Verify the auth data is valid
  2938. //
  2939. if (!KerbVerifyAuthData(
  2940. Ticket->KERB_ENCRYPTED_TICKET_authorization_data
  2941. ))
  2942. {
  2943. D_DebugLog((DEB_ERROR,"Failed to verify auth data\n"));
  2944. Status = STATUS_LOGON_FAILURE;
  2945. goto Cleanup;
  2946. }
  2947. //
  2948. // Get the PAC out of the authorization data
  2949. //
  2950. KerbErr = KerbGetPacFromAuthData(
  2951. Ticket->KERB_ENCRYPTED_TICKET_authorization_data,
  2952. &IfRelevantData,
  2953. &PacAuthData
  2954. );
  2955. if (!KERB_SUCCESS(KerbErr))
  2956. {
  2957. Status = KerbMapKerbError(KerbErr);
  2958. goto Cleanup;
  2959. }
  2960. if (PacAuthData != NULL)
  2961. {
  2962. //
  2963. // Unmarshall the PAC
  2964. //
  2965. Pac = (PPACTYPE) PacAuthData->value.auth_data.value;
  2966. if (PAC_UnMarshal(Pac, PacAuthData->value.auth_data.length) == 0)
  2967. {
  2968. D_DebugLog((DEB_ERROR,"Failed to unmarshal pac. %ws, line %d\n", THIS_FILE, __LINE__));
  2969. Status = STATUS_INVALID_PARAMETER;
  2970. goto Cleanup;
  2971. }
  2972. //
  2973. // Copy state from the system logon session so we don't
  2974. // leave it locked while verifying the PAC.
  2975. //
  2976. Status = KerbDuplicateString(
  2977. &WkstaDomain,
  2978. &SystemLogonSession->PrimaryCredentials.DomainName
  2979. );
  2980. if (!NT_SUCCESS(Status))
  2981. {
  2982. goto Cleanup;
  2983. }
  2984. if (!KERB_SUCCESS(KerbDuplicateKey(
  2985. &LocalKey,
  2986. WkstaKey)))
  2987. {
  2988. Status = STATUS_INSUFFICIENT_RESOURCES;
  2989. goto Cleanup;
  2990. }
  2991. if (TicketCacheLocked)
  2992. {
  2993. KerbUnlockTicketCache();
  2994. TicketCacheLocked = FALSE;
  2995. }
  2996. if (LogonSessionsLocked)
  2997. {
  2998. KerbUnlockLogonSessions(SystemLogonSession);
  2999. LogonSessionsLocked = FALSE;
  3000. }
  3001. Status = KerbVerifyPacSignature(
  3002. &WkstaDomain,
  3003. Pac,
  3004. PacAuthData->value.auth_data.length,
  3005. &LocalKey,
  3006. Ticket,
  3007. FALSE, // don't bother verifying at KDC, because we obtained the ticket
  3008. &ValidationInfo,
  3009. NULL // not interested in S4U delegation info
  3010. );
  3011. KerbFreeKey( &LocalKey );
  3012. if (!NT_SUCCESS(Status))
  3013. {
  3014. DebugLog((DEB_WARN,"Pac signature did not verify %x.\n", Status));
  3015. if (ARGUMENT_PRESENT(LogonTicket))
  3016. {
  3017. if (!KERB_SUCCESS(KerbConvertPrincipalNameToString( &CName, &NameType, &Ticket->client_name )))
  3018. {
  3019. Status = STATUS_INSUFFICIENT_RESOURCES;
  3020. goto Cleanup;
  3021. }
  3022. if (!KERB_SUCCESS(KerbConvertRealmToUnicodeString( &CRealm, &Ticket->client_realm )))
  3023. {
  3024. Status = STATUS_INSUFFICIENT_RESOURCES;
  3025. goto Cleanup;
  3026. }
  3027. KerbReportPACError(
  3028. &CName,
  3029. &CRealm,
  3030. Status
  3031. );
  3032. }
  3033. //
  3034. // DOA Leave now...
  3035. //
  3036. goto Cleanup;
  3037. }
  3038. DsysAssert( !LogonSessionsLocked );
  3039. KerbReadLockLogonSessions(SystemLogonSession); // nothing can change
  3040. LogonSessionsLocked = TRUE;
  3041. }
  3042. }
  3043. }
  3044. //
  3045. // If we didn't find a PAC, try to build one locally
  3046. //
  3047. if (RealmlessWkstaLogon || Pac == NULL)
  3048. {
  3049. PKERB_INTERNAL_NAME ClientName = NULL;
  3050. NTSTATUS TempStatus;
  3051. DebugLog((DEB_WARN,"No authorization data in ticket - trying local\n"));
  3052. // if we don't have a name, make one, but only if we have a service ticket
  3053. if (ARGUMENT_PRESENT(LogonTicket))
  3054. {
  3055. if (!KERB_SUCCESS(KerbConvertRealmToUnicodeString(
  3056. &CRealm,
  3057. &Ticket->client_realm
  3058. )))
  3059. {
  3060. Status = STATUS_INSUFFICIENT_RESOURCES;
  3061. goto Cleanup;
  3062. }
  3063. //
  3064. // Convert the client's name into a usable format
  3065. //
  3066. if (!KERB_SUCCESS(KerbConvertPrincipalNameToKdcName(
  3067. &ClientName,
  3068. &Ticket->client_name
  3069. )))
  3070. {
  3071. Status = STATUS_INSUFFICIENT_RESOURCES;
  3072. goto Cleanup;
  3073. }
  3074. }
  3075. //
  3076. // We don't have any information to do the mapping. Return
  3077. else if (MappedName->Buffer == NULL)
  3078. {
  3079. D_DebugLog((DEB_ERROR, "We don't have any information for creating a token!\n"));
  3080. Status = STATUS_LOGON_FAILURE;
  3081. goto Cleanup;
  3082. }
  3083. TempStatus = KerbCreatePacForKerbClient(
  3084. &Pac,
  3085. ClientName,
  3086. &CRealm,
  3087. MappedName
  3088. );
  3089. KerbFreeKdcName(&ClientName);
  3090. if (!NT_SUCCESS(TempStatus))
  3091. {
  3092. DebugLog((DEB_ERROR,"Failed to create local pac for client: 0x%x\n",TempStatus));
  3093. //
  3094. // Return the original error if we failed to build a pac
  3095. //
  3096. if (NT_SUCCESS(Status))
  3097. {
  3098. Status = TempStatus;
  3099. }
  3100. goto Cleanup;
  3101. }
  3102. FreePac = TRUE;
  3103. //
  3104. // Find the SAM validation info
  3105. //
  3106. LogonInfo = PAC_Find(
  3107. Pac,
  3108. PAC_LOGON_INFO,
  3109. NULL
  3110. );
  3111. if (LogonInfo == NULL)
  3112. {
  3113. D_DebugLog((DEB_ERROR,"Failed to find logon info! %ws, line %d\n", THIS_FILE, __LINE__));
  3114. Status = STATUS_INVALID_PARAMETER;
  3115. goto Cleanup;
  3116. }
  3117. //
  3118. // Now unmarshall the validation info
  3119. //
  3120. Status = PAC_UnmarshallValidationInfo(
  3121. &ValidationInfo,
  3122. LogonInfo->Data,
  3123. LogonInfo->cbBufferSize
  3124. );
  3125. if (!NT_SUCCESS(Status))
  3126. {
  3127. D_DebugLog((DEB_ERROR,"Failed to unmarshall validation info: 0x%x. %ws, line %d\n",
  3128. Status, THIS_FILE, __LINE__));
  3129. goto Cleanup;
  3130. }
  3131. }
  3132. //
  3133. // Check to see if this is a non-user account. If so, don't allow the logon
  3134. // unless its network, or network-cleartext.
  3135. //
  3136. if (((ValidationInfo->ExpansionRoom[SAMINFO_USER_ACCOUNT_CONTROL] & USER_MACHINE_ACCOUNT_MASK) != 0) &&
  3137. ( !AllowWorkstationLogon ))
  3138. {
  3139. DebugLog((DEB_ERROR,"Logons to non-user accounts not allowed. UserAccountControl = 0x%x. %ws, line %d\n",
  3140. ValidationInfo->ExpansionRoom[SAMINFO_USER_ACCOUNT_CONTROL], THIS_FILE, __LINE__ ));
  3141. Status = STATUS_LOGON_TYPE_NOT_GRANTED;
  3142. goto Cleanup;
  3143. }
  3144. //
  3145. // Now we need to build a LSA_TOKEN_INFORMATION_V2 from the validation
  3146. // information
  3147. //
  3148. Status = KerbMakeTokenInformationV2(
  3149. ValidationInfo,
  3150. FALSE, // not local system
  3151. &TokenInformation
  3152. );
  3153. if (!NT_SUCCESS(Status))
  3154. {
  3155. DebugLog((DEB_ERROR,"Failed to make token informatin v1: 0x%x. %ws, line %d\n",
  3156. Status, THIS_FILE, __LINE__));
  3157. goto Cleanup;
  3158. }
  3159. //
  3160. // unlock ticket cache
  3161. //
  3162. // KerbAllocateInteractiveProfile will lock logon session and ticket cache
  3163. //
  3164. if (TicketCacheLocked)
  3165. {
  3166. KerbUnlockTicketCache();
  3167. TicketCacheLocked = FALSE;
  3168. }
  3169. //
  3170. // Allocate the client profile
  3171. //
  3172. Status = KerbAllocateInteractiveProfile(
  3173. (PKERB_INTERACTIVE_PROFILE *) ProfileBuffer,
  3174. ProfileBufferLength,
  3175. ValidationInfo,
  3176. LogonSession,
  3177. Ticket,
  3178. KerbLogonInfo
  3179. );
  3180. if (!KERB_SUCCESS(Status))
  3181. {
  3182. goto Cleanup;
  3183. }
  3184. //
  3185. // Build the primary credential. We let someone else fill in the
  3186. // password.
  3187. //
  3188. PrimaryCredentials->LogonId = *LogonId;
  3189. Status = KerbDuplicateString(
  3190. &PrimaryCredentials->DownlevelName,
  3191. &ValidationInfo->EffectiveName
  3192. );
  3193. if (!NT_SUCCESS(Status))
  3194. {
  3195. goto Cleanup;
  3196. }
  3197. Status = KerbDuplicateString(
  3198. &PrimaryCredentials->DomainName,
  3199. &ValidationInfo->LogonDomainName
  3200. );
  3201. if (!NT_SUCCESS(Status))
  3202. {
  3203. goto Cleanup;
  3204. }
  3205. Status = KerbDuplicateString(
  3206. &PrimaryCredentials->LogonServer,
  3207. &ValidationInfo->LogonServer
  3208. );
  3209. if (!NT_SUCCESS(Status))
  3210. {
  3211. goto Cleanup;
  3212. }
  3213. Status = KerbDuplicateSid(
  3214. &PrimaryCredentials->UserSid,
  3215. TokenInformation->User.User.Sid
  3216. );
  3217. if (!NT_SUCCESS(Status))
  3218. {
  3219. goto Cleanup;
  3220. }
  3221. PrimaryCredentials->Flags = 0;
  3222. if ( CheckIdentify )
  3223. {
  3224. //
  3225. // Do TCB check to see if we need an identify or impersonation
  3226. // level token.
  3227. //
  3228. SECPKG_CLIENT_INFO ClientInfo;
  3229. Status = LsaFunctions->GetClientInfo(&ClientInfo);
  3230. if (!NT_SUCCESS(Status))
  3231. {
  3232. goto Cleanup;
  3233. }
  3234. if (!ClientInfo.HasTcbPrivilege)
  3235. {
  3236. D_DebugLog((DEB_TRACE, "Building identify token\n"));
  3237. PrimaryCredentials->Flags |= PRIMARY_CRED_LOGON_NO_TCB;
  3238. }
  3239. }
  3240. //
  3241. // Get supplemental credentials out of the pac
  3242. //
  3243. Status = KerbExtractCachedCreds(
  3244. Pac,
  3245. CredentialKey,
  3246. CachedCredentials
  3247. );
  3248. if (!NT_SUCCESS(Status))
  3249. {
  3250. goto Cleanup;
  3251. }
  3252. //
  3253. // We're using the validation_info4 struct to pass appropriate information
  3254. // back to caller for use in Lsa GetUserName(). We don't really use all
  3255. // of this information, however, so only copy over interesting fields
  3256. //
  3257. ValidationInfo4 = (PNETLOGON_VALIDATION_SAM_INFO4) KerbAllocate(sizeof(NETLOGON_VALIDATION_SAM_INFO4));
  3258. if (NULL == ValidationInfo4)
  3259. {
  3260. Status = STATUS_INSUFFICIENT_RESOURCES;
  3261. goto Cleanup;
  3262. }
  3263. if (ValidationInfo->FullName.Length)
  3264. {
  3265. Status = KerbDuplicateString(
  3266. &ValidationInfo4->FullName,
  3267. &ValidationInfo->FullName
  3268. );
  3269. if (!NT_SUCCESS(Status))
  3270. {
  3271. goto Cleanup;
  3272. }
  3273. }
  3274. KerbReadLockLogonSessions(LogonSession);
  3275. if (LogonSession->PrimaryCredentials.DomainName.Length)
  3276. {
  3277. D_DebugLog((DEB_TRACE_LOGON, "DomainName %wZ\n", &LogonSession->PrimaryCredentials.DomainName));
  3278. Status = KerbDuplicateString(
  3279. &ValidationInfo4->DnsLogonDomainName,
  3280. &LogonSession->PrimaryCredentials.DomainName
  3281. );
  3282. if (!NT_SUCCESS(Status))
  3283. {
  3284. KerbUnlockLogonSessions(LogonSession);
  3285. goto Cleanup;
  3286. }
  3287. ValidationInfo4->Upn.Length = LogonSession->PrimaryCredentials.UserName.Length
  3288. + LogonSession->PrimaryCredentials.DomainName.Length
  3289. +sizeof(WCHAR);
  3290. ValidationInfo4->Upn.MaximumLength = ValidationInfo4->Upn.Length + sizeof(WCHAR);
  3291. ValidationInfo4->Upn.Buffer = (LPWSTR) KerbAllocate(ValidationInfo4->Upn.MaximumLength);
  3292. if ( ValidationInfo4->Upn.Buffer == NULL)
  3293. {
  3294. Status = STATUS_INSUFFICIENT_RESOURCES;
  3295. KerbUnlockLogonSessions(LogonSession);
  3296. goto Cleanup;
  3297. }
  3298. RtlCopyMemory(
  3299. ValidationInfo4->Upn.Buffer,
  3300. LogonSession->PrimaryCredentials.UserName.Buffer,
  3301. LogonSession->PrimaryCredentials.UserName.Length
  3302. );
  3303. ValidationInfo4->Upn.Buffer[LogonSession->PrimaryCredentials.UserName.Length/ sizeof(WCHAR)] = L'@';
  3304. lpDnsDomainName = ValidationInfo4->Upn.Buffer +
  3305. LogonSession->PrimaryCredentials.UserName.Length / sizeof(WCHAR) + 1;
  3306. RtlCopyMemory(
  3307. lpDnsDomainName,
  3308. LogonSession->PrimaryCredentials.DomainName.Buffer,
  3309. LogonSession->PrimaryCredentials.DomainName.Length
  3310. );
  3311. D_DebugLog((DEB_TRACE_LOGON, "KerbCreateTokenFromLogonTicket built UPN %wZ\n", &ValidationInfo4->Upn));
  3312. }
  3313. KerbUnlockLogonSessions(LogonSession);
  3314. //
  3315. // Cache the logon info in MSV
  3316. //
  3317. if (CacheLogon)
  3318. {
  3319. if ( (KerbLogonInfo->MessageType == KerbInteractiveLogon)
  3320. || (KerbLogonInfo->MessageType == KerbWorkstationUnlockLogon) )
  3321. {
  3322. //
  3323. // Hold no locks when leaving this dll
  3324. //
  3325. if (TicketCacheLocked)
  3326. {
  3327. KerbUnlockTicketCache();
  3328. TicketCacheLocked = FALSE;
  3329. }
  3330. if (LogonSessionsLocked)
  3331. {
  3332. KerbUnlockLogonSessions(SystemLogonSession);
  3333. LogonSessionsLocked = FALSE;
  3334. }
  3335. KerbCacheLogonInformation(
  3336. &KerbLogonInfo->UserName,
  3337. &KerbLogonInfo->LogonDomainName,
  3338. &KerbLogonInfo->Password,
  3339. ((ValidationInfo4->DnsLogonDomainName.Length) ? &ValidationInfo4->DnsLogonDomainName : NULL),
  3340. NULL, //((ValidationInfo4->Upn.Length) ? &ValidationInfo4->Upn : NULL),
  3341. LogonSession,
  3342. 0, // no special flags
  3343. ValidationInfo,
  3344. NULL, // no supplemental creds
  3345. 0
  3346. );
  3347. }
  3348. else if ((KerbLogonInfo->MessageType == KerbSmartCardLogon)
  3349. || (KerbLogonInfo->MessageType == KerbSmartCardUnlockLogon))
  3350. {
  3351. KerbCacheSmartCardLogon(
  3352. ValidationInfo,
  3353. ((ValidationInfo4->DnsLogonDomainName.Length) ? &ValidationInfo4->DnsLogonDomainName : NULL),
  3354. NULL, //((ValidationInfo4->Upn.Length) ? &ValidationInfo4->Upn : NULL),
  3355. LogonSession,
  3356. *CachedCredentials
  3357. );
  3358. }
  3359. else
  3360. {
  3361. D_DebugLog((DEB_WARN,"CacheLogon requested but logon type not cacheable\n"));
  3362. }
  3363. }
  3364. //
  3365. // If we were supplied a TGT for this logon, stick it in the logon session
  3366. //
  3367. if (ARGUMENT_PRESENT(ForwardedTgt) && (ForwardedTgt->BufferSize != 0))
  3368. {
  3369. Status = KerbExtractForwardedTgt(
  3370. LogonSession,
  3371. ForwardedTgt,
  3372. Ticket
  3373. );
  3374. if (!NT_SUCCESS(Status))
  3375. {
  3376. goto Cleanup;
  3377. }
  3378. }
  3379. *NewTokenInformation = TokenInformation;
  3380. *TokenInformationType = LsaTokenInformationV2;
  3381. *ppValidationInfo = ValidationInfo4;
  3382. ValidationInfo4 = NULL;
  3383. Cleanup:
  3384. KerbFreeString(&LocalDnsDomain);
  3385. KerbFreeString( &CName );
  3386. KerbFreeString( &CRealm );
  3387. KerbFreeString( &WkstaDomain );
  3388. if (TicketCacheLocked)
  3389. {
  3390. KerbUnlockTicketCache();
  3391. }
  3392. if (LogonSessionsLocked)
  3393. {
  3394. KerbUnlockLogonSessions(SystemLogonSession);
  3395. }
  3396. if (!NT_SUCCESS(Status))
  3397. {
  3398. if (TokenInformation != NULL)
  3399. {
  3400. KerbFree( TokenInformation );
  3401. }
  3402. if (*ProfileBuffer != NULL)
  3403. {
  3404. LsaFunctions->FreeClientBuffer(NULL, *ProfileBuffer);
  3405. *ProfileBuffer = NULL;
  3406. }
  3407. KerbFreeString(
  3408. &PrimaryCredentials->DownlevelName
  3409. );
  3410. KerbFreeString(
  3411. &PrimaryCredentials->DomainName
  3412. );
  3413. KerbFreeString(
  3414. &PrimaryCredentials->LogonServer
  3415. );
  3416. if (PrimaryCredentials->UserSid != NULL)
  3417. {
  3418. KerbFree(PrimaryCredentials->UserSid);
  3419. PrimaryCredentials->UserSid = NULL;
  3420. }
  3421. }
  3422. if (Ticket != NULL)
  3423. {
  3424. KerbFreeTicket(Ticket);
  3425. }
  3426. if (FreePac && (Pac != NULL))
  3427. {
  3428. MIDL_user_free(Pac);
  3429. }
  3430. if (IfRelevantData != NULL)
  3431. {
  3432. KerbFreeData(
  3433. PKERB_IF_RELEVANT_AUTH_DATA_PDU,
  3434. IfRelevantData
  3435. );
  3436. }
  3437. if (ValidationInfo != NULL)
  3438. {
  3439. MIDL_user_free(ValidationInfo);
  3440. }
  3441. if (ValidationInfo4)
  3442. {
  3443. KerbFreeString(&ValidationInfo4->DnsLogonDomainName);
  3444. KerbFreeString(&ValidationInfo4->Upn);
  3445. KerbFreeString(&ValidationInfo4->FullName);
  3446. KerbFree(ValidationInfo4);
  3447. }
  3448. return(Status);
  3449. }
  3450. //+-------------------------------------------------------------------------
  3451. //
  3452. // Function: KerbBuildLocalAccountToken
  3453. //
  3454. // Synopsis: Creates a token from a mapped kerberos principal
  3455. //
  3456. // Effects:
  3457. //
  3458. // Arguments:
  3459. //
  3460. // Requires:
  3461. //
  3462. // Returns:
  3463. //
  3464. // Notes:
  3465. //
  3466. //
  3467. //--------------------------------------------------------------------------
  3468. /*
  3469. NTSTATUS
  3470. KerbBuildLocalAccountToken(
  3471. IN PKERB_LOGON_SESSION LogonSession,
  3472. IN PLUID LogonId,
  3473. IN PUNICODE_STRING MappedClientName,
  3474. IN PKERB_INTERACTIVE_LOGON KerbLogonInfo,
  3475. OUT PLSA_TOKEN_INFORMATION_TYPE LogonSession,
  3476. OUT PVOID * NewTokenInformation,
  3477. OUT PULONG ProfileBufferLength,
  3478. OUT PVOID * ProfileBuffer,
  3479. OUT PSECPKG_PRIMARY_CRED PrimaryCredentials,
  3480. OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY * CachedCreds
  3481. )
  3482. {
  3483. NTSTATUS Status = STATUS_SUCCESS;
  3484. SECPKG_CLIENT_INFO ClientInfo;
  3485. PLSAPR_POLICY_INFORMATION PolicyInfo = NULL;
  3486. SAMPR_HANDLE SamHandle = NULL;
  3487. SAMPR_HANDLE DomainHandle = NULL;
  3488. SAMPR_HANDLE UserHandle = NULL;
  3489. PSAMPR_GET_GROUPS_BUFFER Groups = NULL;
  3490. SID_AND_ATTRIBUTES_LIST TransitiveGroups = {0};
  3491. PSAMPR_USER_INFO_BUFFER UserInfo = NULL;
  3492. PPACTYPE LocalPac = NULL;
  3493. SAMPR_ULONG_ARRAY RidArray;
  3494. SAMPR_ULONG_ARRAY UseArray;
  3495. *ProfileBuffer = NULL;
  3496. *NewTokenInformation = NULL;
  3497. //
  3498. // Verify that the caller has TCB privilege. Otherwise anyone can forge
  3499. // a ticket to themselves to logon with any name in the list.
  3500. //
  3501. Status = LsaFunctions->GetClientInfo(&ClientInfo);
  3502. if (!NT_SUCCESS(Status))
  3503. {
  3504. return(Status);
  3505. }
  3506. if (!ClientInfo.HasTcbPrivilege)
  3507. {
  3508. return(STATUS_PRIVILEGE_NOT_HELD);
  3509. }
  3510. //
  3511. // Call the LSA to get our domain sid
  3512. //
  3513. Status = LsaIQueryInformationPolicyTrusted(
  3514. PolicyAccountDomainInformation,
  3515. &PolicyInfo
  3516. );
  3517. if (!NT_SUCCESS(Status))
  3518. {
  3519. DebugLog((DEB_ERROR, "LsaIQueryInformationPolicyTrusted failed - %x\n", Status));
  3520. goto Cleanup;
  3521. }
  3522. //
  3523. // Open SAM to get the account information
  3524. //
  3525. Status = SamIConnect(
  3526. NULL, // no server name
  3527. &SamHandle,
  3528. 0, // no desired access
  3529. TRUE // trusted caller
  3530. );
  3531. if (!NT_SUCCESS(Status))
  3532. {
  3533. DebugLog((DEB_ERROR, "SamIConnectFailed - %x\n", Status));
  3534. goto Cleanup;
  3535. }
  3536. Status = SamrOpenDomain(
  3537. SamHandle,
  3538. 0, // no desired access
  3539. (PRPC_SID) PolicyInfo->PolicyAccountDomainInfo.DomainSid,
  3540. &DomainHandle
  3541. );
  3542. if (!NT_SUCCESS(Status))
  3543. {
  3544. DebugLog((DEB_ERROR, "SamrOpenDomain failed - %x\n", Status));
  3545. goto Cleanup;
  3546. }
  3547. Status = SamrLookupNamesInDomain(
  3548. DomainHandle,
  3549. 1,
  3550. (PRPC_UNICODE_STRING) MappedClientName,
  3551. &RidArray,
  3552. &UseArray
  3553. );
  3554. if (!NT_SUCCESS(Status))
  3555. {
  3556. DebugLog((DEB_ERROR, "SamrOpenDomain failed - %x\n", Status));
  3557. goto Cleanup;
  3558. }
  3559. if ((UseArray.Element[0] != SidTypeUser) &&
  3560. (UseArray.Element[0] != SidTypeComputer))
  3561. {
  3562. Status = STATUS_NONE_MAPPED;
  3563. goto Cleanup;
  3564. }
  3565. Status = SamrOpenUser(
  3566. DomainHandle,
  3567. 0, // no desired access,
  3568. RidArray.Element[0],
  3569. &UserHandle
  3570. );
  3571. if (!NT_SUCCESS(Status))
  3572. {
  3573. goto Cleanup;
  3574. }
  3575. Status = SamrQueryInformationUser(
  3576. UserHandle,
  3577. UserAllInformation,
  3578. &UserInfo
  3579. );
  3580. if (!NT_SUCCESS(Status))
  3581. {
  3582. goto Cleanup;
  3583. }
  3584. Status = SamrGetGroupsForUser(
  3585. UserHandle,
  3586. &Groups
  3587. );
  3588. if (!NT_SUCCESS(Status))
  3589. {
  3590. goto Cleanup;
  3591. }
  3592. KerbGlobalReadLock();
  3593. Status = KerbDuplicateString(
  3594. &LocalMachineName,
  3595. &KerbGlobalMachineName
  3596. );
  3597. KerbGlobalReleaseLock();
  3598. if(!NT_SUCCESS(Status))
  3599. {
  3600. DebugLog((DEB_ERROR, "Failed to duplicate KerbGlobalMachineName\n"));
  3601. goto Cleanup;
  3602. }
  3603. //
  3604. // Set the password must changes time to inifinite because we don't
  3605. // want spurious password must change popups
  3606. //
  3607. UserInfo->All.PasswordMustChange = *(POLD_LARGE_INTEGER) &KerbGlobalWillNeverTime;
  3608. //
  3609. // *Don't build a PAC, that's extra effort in marshalling unmarshalling
  3610. // data we can just convert over from Samuserall to Netlogon_Validation_Info
  3611. //
  3612. } */