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

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