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

2093 lines
62 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: credapi.cxx
  8. //
  9. // Contents: Code for credentials APIs for the Kerberos package
  10. //
  11. //
  12. // History: 16-April-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. #ifdef RETAIL_LOG_SUPPORT
  20. static TCHAR THIS_FILE[]=TEXT(__FILE__);
  21. #endif
  22. #define FILENO FILENO_CREDAPI
  23. //+-------------------------------------------------------------------------
  24. //
  25. // Function: KerbCopyClientString
  26. //
  27. // Synopsis: Copies a string from the client and if necessary converts
  28. // from ansi to unicode
  29. //
  30. // Effects: allocates output with either KerbAllocate (unicode)
  31. // or RtlAnsiStringToUnicodeString
  32. //
  33. // Arguments: StringPointer - address of string in client process
  34. // StringLength - Lenght (in characters) of string
  35. // AnsiString - if TRUE, string is ansi
  36. // LocalString - receives allocated string
  37. //
  38. // Requires:
  39. //
  40. // Returns:
  41. //
  42. // Notes:
  43. //
  44. //
  45. //--------------------------------------------------------------------------
  46. NTSTATUS
  47. KerbCopyClientString(
  48. IN PVOID StringPointer,
  49. IN ULONG StringLength,
  50. IN BOOLEAN AnsiString,
  51. OUT PUNICODE_STRING LocalString,
  52. IN ULONG MaxLength
  53. )
  54. {
  55. NTSTATUS Status = STATUS_SUCCESS;
  56. PVOID LocalBuffer = NULL;
  57. ULONG CharSize = sizeof(WCHAR);
  58. if (AnsiString)
  59. {
  60. CharSize = sizeof(CHAR);
  61. }
  62. if (StringLength > MaxLength)
  63. {
  64. Status = STATUS_INVALID_PARAMETER;
  65. goto Cleanup;
  66. }
  67. LocalBuffer = KerbAllocate(StringLength * CharSize);
  68. if (LocalBuffer == NULL)
  69. {
  70. Status = STATUS_INSUFFICIENT_RESOURCES;
  71. goto Cleanup;
  72. }
  73. Status = LsaFunctions->CopyFromClientBuffer(
  74. NULL,
  75. StringLength * CharSize,
  76. LocalBuffer,
  77. StringPointer
  78. );
  79. if (!NT_SUCCESS(Status))
  80. {
  81. goto Cleanup;
  82. }
  83. if (AnsiString)
  84. {
  85. ANSI_STRING TempString;
  86. UNICODE_STRING TempOutputString = {0};
  87. TempString.Buffer = (PCHAR) LocalBuffer;
  88. TempString.MaximumLength = TempString.Length = (USHORT) StringLength;
  89. Status = RtlAnsiStringToUnicodeString(
  90. &TempOutputString,
  91. &TempString,
  92. TRUE // allocate destination
  93. );
  94. if (!NT_SUCCESS(Status))
  95. {
  96. goto Cleanup;
  97. }
  98. *LocalString = TempOutputString;
  99. }
  100. else
  101. {
  102. LocalString->Buffer = (LPWSTR) LocalBuffer;
  103. LocalString->Length = (USHORT) StringLength * sizeof(WCHAR);
  104. LocalString->MaximumLength = LocalString->Length;
  105. LocalBuffer = NULL;
  106. }
  107. Cleanup:
  108. if (LocalBuffer)
  109. {
  110. KerbFree(LocalBuffer);
  111. }
  112. return(Status);
  113. }
  114. //+-------------------------------------------------------------------------
  115. //
  116. // Function: KerbInitPrimaryCreds
  117. //
  118. // Synopsis: Allocates and initializes a PKERB_PRIMARY_CREDENTIAL
  119. // structure.
  120. //
  121. // Effects:
  122. //
  123. // Arguments:
  124. //
  125. // Requires:
  126. //
  127. // Returns:
  128. //
  129. // Notes:
  130. //
  131. //
  132. //--------------------------------------------------------------------------
  133. NTSTATUS
  134. KerbInitPrimaryCreds(
  135. IN PKERB_LOGON_SESSION LogonSession,
  136. IN PUNICODE_STRING UserString,
  137. IN PUNICODE_STRING DomainString,
  138. IN OPTIONAL PUNICODE_STRING PrincipalName,
  139. IN PUNICODE_STRING PasswordString, // either the password or if pin
  140. IN BOOLEAN PubKeyCreds,
  141. IN OPTIONAL PCERT_CONTEXT pCertContext,
  142. OUT PKERB_PRIMARY_CREDENTIAL * PrimaryCreds
  143. )
  144. {
  145. NTSTATUS Status = STATUS_SUCCESS;
  146. PUCHAR Where;
  147. PKERB_PRIMARY_CREDENTIAL NewCreds = NULL;
  148. KERBEROS_MACHINE_ROLE Role;
  149. // allocate the primary cred structure
  150. NewCreds = (PKERB_PRIMARY_CREDENTIAL) KerbAllocate(sizeof(KERB_PRIMARY_CREDENTIAL));
  151. if (NewCreds == NULL)
  152. {
  153. Status = STATUS_INSUFFICIENT_RESOURCES;
  154. goto Cleanup;
  155. }
  156. KerbInitTicketCache(
  157. &NewCreds->ServerTicketCache
  158. );
  159. KerbInitTicketCache(
  160. &NewCreds->AuthenticationTicketCache
  161. );
  162. KerbInitTicketCache(
  163. &NewCreds->S4UTicketCache
  164. );
  165. //
  166. // Fill in the fields
  167. //
  168. Status = KerbDuplicateString(
  169. &NewCreds->UserName,
  170. UserString
  171. );
  172. if (!NT_SUCCESS(Status))
  173. {
  174. goto Cleanup;
  175. }
  176. Status = KerbDuplicateString(
  177. &NewCreds->OldUserName,
  178. UserString
  179. );
  180. if (!NT_SUCCESS(Status))
  181. {
  182. goto Cleanup;
  183. }
  184. Status = KerbDuplicateString(
  185. &NewCreds->DomainName,
  186. DomainString
  187. );
  188. if (!NT_SUCCESS(Status))
  189. {
  190. goto Cleanup;
  191. }
  192. Status = KerbDuplicateString(
  193. &NewCreds->OldDomainName,
  194. DomainString
  195. );
  196. if (!NT_SUCCESS(Status))
  197. {
  198. goto Cleanup;
  199. }
  200. if (!PubKeyCreds)
  201. {
  202. if (PasswordString->Buffer != NULL)
  203. {
  204. Status = KerbDuplicatePassword(
  205. &NewCreds->ClearPassword,
  206. PasswordString
  207. );
  208. if (!NT_SUCCESS(Status))
  209. {
  210. goto Cleanup;
  211. }
  212. KerbHidePassword(
  213. &NewCreds->ClearPassword
  214. );
  215. RtlCalculateNtOwfPassword(
  216. &NewCreds->ClearPassword,
  217. &NewCreds->OldHashPassword
  218. );
  219. }
  220. if (PasswordString->Buffer != NULL)
  221. {
  222. Status = KerbBuildPasswordList(
  223. PasswordString,
  224. UserString,
  225. DomainString,
  226. NULL, // no supplied salt
  227. NULL, // no old password list
  228. PrincipalName,
  229. UserAccount,
  230. PRIMARY_CRED_CLEAR_PASSWORD,
  231. &NewCreds->Passwords
  232. );
  233. if (!NT_SUCCESS(Status))
  234. {
  235. goto Cleanup;
  236. }
  237. }
  238. else
  239. {
  240. ULONG PasswordSize;
  241. ULONG Index;
  242. //
  243. // Compute the size of the passwords, which are assumed to be
  244. // marshalled in order.
  245. //
  246. if (LogonSession->PrimaryCredentials.Passwords != NULL)
  247. {
  248. PasswordSize = sizeof(KERB_STORED_CREDENTIAL) - sizeof(KERB_KEY_DATA) * ANYSIZE_ARRAY +
  249. LogonSession->PrimaryCredentials.Passwords->CredentialCount * sizeof(KERB_KEY_DATA);
  250. for (Index = 0; Index < LogonSession->PrimaryCredentials.Passwords->CredentialCount ; Index++ )
  251. {
  252. PasswordSize += LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keyvalue.length;
  253. }
  254. NewCreds->Passwords = (PKERB_STORED_CREDENTIAL) KerbAllocate(PasswordSize);
  255. if (NewCreds->Passwords == NULL)
  256. {
  257. Status = STATUS_INSUFFICIENT_RESOURCES;
  258. goto Cleanup;
  259. }
  260. NewCreds->Passwords->Revision = KERB_PRIMARY_CRED_REVISION;
  261. NewCreds->Passwords->Flags = 0;
  262. NewCreds->Passwords->OldCredentialCount = 0;
  263. //
  264. // Zero the salt so we don't accidentally re-use it.
  265. //
  266. RtlInitUnicodeString(
  267. &NewCreds->Passwords->DefaultSalt,
  268. NULL
  269. );
  270. NewCreds->Passwords->CredentialCount = LogonSession->PrimaryCredentials.Passwords->CredentialCount;
  271. Where = (PUCHAR) &NewCreds->Passwords->Credentials[NewCreds->Passwords->CredentialCount];
  272. //
  273. // Copy all the old passwords.
  274. //
  275. for (Index = 0;
  276. Index < (USHORT) (NewCreds->Passwords->CredentialCount) ;
  277. Index++ )
  278. {
  279. RtlInitUnicodeString(
  280. &NewCreds->Passwords->Credentials[Index].Salt,
  281. NULL
  282. );
  283. NewCreds->Passwords->Credentials[Index].Key =
  284. LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key;
  285. NewCreds->Passwords->Credentials[Index].Key.keyvalue.value = Where;
  286. RtlCopyMemory(
  287. Where,
  288. LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keyvalue.value,
  289. LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keyvalue.length
  290. );
  291. Where += LogonSession->PrimaryCredentials.Passwords->Credentials[Index].Key.keyvalue.length;
  292. }
  293. }
  294. else
  295. {
  296. D_DebugLog((DEB_ERROR,"Didn't supply enough credentials - no password available. %ws, line %d\n", THIS_FILE, __LINE__));
  297. Status = SEC_E_NO_CREDENTIALS;
  298. goto Cleanup;
  299. }
  300. }
  301. }
  302. else
  303. {
  304. // allocate the memory for the public key creds
  305. NewCreds->PublicKeyCreds = (PKERB_PUBLIC_KEY_CREDENTIALS) KerbAllocate(sizeof(KERB_PUBLIC_KEY_CREDENTIALS));
  306. if (NULL == NewCreds->PublicKeyCreds)
  307. {
  308. D_DebugLog((DEB_ERROR,"Couldn't allocate public key creds\n"));
  309. Status = STATUS_INSUFFICIENT_RESOURCES;
  310. goto Cleanup;
  311. }
  312. // the password is now considered the pin for the smartcard
  313. if (NULL == pCertContext)
  314. {
  315. D_DebugLog((DEB_ERROR,"Didn't supply enough credentials - no cert context available. %ws, line %d\n", THIS_FILE, __LINE__));
  316. Status = SEC_E_NO_CREDENTIALS;
  317. goto Cleanup;
  318. }
  319. (NewCreds->PublicKeyCreds)->CertContext = CertDuplicateCertificateContext(pCertContext);
  320. if (NULL == (NewCreds->PublicKeyCreds)->CertContext)
  321. {
  322. Status = STATUS_UNSUCCESSFUL;
  323. goto Cleanup;
  324. }
  325. if (PasswordString->Buffer != NULL)
  326. {
  327. Status = KerbDuplicatePassword(
  328. &NewCreds->PublicKeyCreds->Pin,
  329. PasswordString
  330. );
  331. if (!NT_SUCCESS(Status))
  332. {
  333. goto Cleanup;
  334. }
  335. KerbHidePassword(
  336. &NewCreds->PublicKeyCreds->Pin
  337. );
  338. }
  339. //
  340. // For non-joined machines, we have to make an assumption about the "best"
  341. // domain to try when we're getting a TGT. Normally, UPNs are cracked at
  342. // the workstation's realm. In this case, we formulate a guess from the DN
  343. // portion of the subject name.
  344. //
  345. // W/o this information, we should fail right here and log an event.
  346. //
  347. Role = KerbGetGlobalRole();
  348. if (Role == KerbRoleRealmlessWksta)
  349. {
  350. if (!KerbRetrieveDomainFromDn(
  351. pCertContext,
  352. &((NewCreds->PublicKeyCreds)->AlternateDomainName)
  353. ))
  354. {
  355. Status = STATUS_INVALID_ACCOUNT_NAME;
  356. goto Cleanup;
  357. }
  358. }
  359. }
  360. *PrimaryCreds = NewCreds;
  361. NewCreds = NULL;
  362. Status = STATUS_SUCCESS;
  363. Cleanup:
  364. if (NewCreds != NULL)
  365. {
  366. KerbFreePrimaryCredentials( NewCreds, TRUE );
  367. }
  368. return(Status);
  369. }
  370. //+-------------------------------------------------------------------------
  371. //
  372. // Function: KerbCaptureSuppliedCreds
  373. //
  374. // Synopsis: Captures a SEC_WINNT_AUTH_IDENTITY structure from
  375. // the client
  376. //
  377. // Effects:
  378. //
  379. // Arguments: LogonSession - Logon session that supplies the missing
  380. // elements of the supplied creds.
  381. // AuthorizationData - Client address of auth data
  382. // SuppliedCreds - Returns constructed credentials, NULL for
  383. // null session credentials.
  384. //
  385. // Requires:
  386. //
  387. // Returns:
  388. //
  389. // Notes:
  390. //
  391. //
  392. //--------------------------------------------------------------------------
  393. NTSTATUS
  394. KerbCaptureSuppliedCreds(
  395. IN PKERB_LOGON_SESSION LogonSession,
  396. IN OPTIONAL PVOID AuthorizationData,
  397. IN OPTIONAL PUNICODE_STRING PrincipalName,
  398. OUT PKERB_PRIMARY_CREDENTIAL * SuppliedCreds,
  399. OUT PULONG Flags
  400. )
  401. {
  402. NTSTATUS Status = STATUS_SUCCESS;
  403. PSEC_WINNT_AUTH_IDENTITY_EXW IdentityEx = NULL;
  404. SEC_WINNT_AUTH_IDENTITY_W LocalIdentity = {0};
  405. PSEC_WINNT_AUTH_IDENTITY_W AuthIdentity = NULL;
  406. PSEC_WINNT_AUTH_IDENTITY_W Credentials = NULL;
  407. BOOLEAN LogonSessionsLocked = FALSE;
  408. UNICODE_STRING UserString = {0};
  409. UNICODE_STRING DomainString = {0};
  410. UNICODE_STRING PasswordString = {0};
  411. BOOLEAN AnsiCreds = FALSE;
  412. BOOLEAN Marshalled = FALSE;
  413. ULONG CredSize;
  414. ULONG CredentialSize = 0;
  415. ULONG Offset = 0;
  416. PCERT_CONTEXT CertContext = NULL;
  417. BOOLEAN fSuppliedCertCred = FALSE;
  418. LUID SystemLogonId = SYSTEM_LUID;
  419. // WOW64
  420. SEC_WINNT_AUTH_IDENTITY32 Cred32 = {0};
  421. SEC_WINNT_AUTH_IDENTITY_EX32 CredEx32 = {0};
  422. HANDLE TokenHandle = NULL;
  423. ULONG CallInfoAttributes = 0;
  424. #if _WIN64
  425. SECPKG_CALL_INFO CallInfo;
  426. LsaFunctions->GetCallInfo( &CallInfo );
  427. CallInfoAttributes = CallInfo.Attributes;
  428. #endif
  429. *SuppliedCreds = NULL;
  430. *Flags = 0;
  431. if (ARGUMENT_PRESENT(AuthorizationData))
  432. {
  433. SafeAllocaAllocate(IdentityEx, sizeof(SEC_WINNT_AUTH_IDENTITY_EXW));
  434. if (IdentityEx != NULL)
  435. {
  436. // We're being called from a WOW client! Wow!
  437. if (CallInfoAttributes & SECPKG_CALL_WOWCLIENT)
  438. {
  439. Status = LsaFunctions->CopyFromClientBuffer(
  440. NULL,
  441. sizeof(Cred32),
  442. IdentityEx,
  443. AuthorizationData
  444. );
  445. if (!NT_SUCCESS(Status))
  446. {
  447. D_DebugLog((DEB_ERROR, "Failed to capture WOW64 supplied cred structure - %x\n", Status));
  448. goto Cleanup;
  449. }
  450. else
  451. {
  452. RtlCopyMemory(&Cred32, IdentityEx, sizeof(Cred32));
  453. }
  454. }
  455. else
  456. {
  457. Status = LsaFunctions->CopyFromClientBuffer(
  458. NULL,
  459. sizeof(SEC_WINNT_AUTH_IDENTITY),
  460. IdentityEx,
  461. AuthorizationData
  462. );
  463. if (!NT_SUCCESS(Status))
  464. {
  465. D_DebugLog((DEB_ERROR, "Failed to copy auth data from %p client address: 0x%x. KLIN(%x)\n",
  466. AuthorizationData, Status, KLIN(FILENO, __LINE__ )));
  467. goto Cleanup;
  468. }
  469. }
  470. }
  471. else
  472. {
  473. Status = STATUS_INSUFFICIENT_RESOURCES;
  474. D_DebugLog((DEB_ERROR, "KLIN(%x) - Failed allocate\n", KLIN(FILENO, __LINE__)));
  475. goto Cleanup;
  476. }
  477. //
  478. // Check for extended structures
  479. //
  480. if (IdentityEx->Version == SEC_WINNT_AUTH_IDENTITY_VERSION)
  481. {
  482. if (CallInfoAttributes & SECPKG_CALL_WOWCLIENT)
  483. {
  484. Status = LsaFunctions->CopyFromClientBuffer(
  485. NULL,
  486. sizeof(CredEx32),
  487. &CredEx32,
  488. AuthorizationData
  489. );
  490. if (NT_SUCCESS(Status))
  491. {
  492. IdentityEx->Version = CredEx32.Version;
  493. IdentityEx->Length = (CredEx32.Length < sizeof(SEC_WINNT_AUTH_IDENTITY_EX) ?
  494. (ULONG) sizeof(SEC_WINNT_AUTH_IDENTITY_EX) : CredEx32.Length);
  495. IdentityEx->UserLength = CredEx32.UserLength;
  496. IdentityEx->User = (PWSTR) UlongToPtr(CredEx32.User);
  497. IdentityEx->DomainLength = CredEx32.DomainLength ;
  498. IdentityEx->Domain = (PWSTR) UlongToPtr( CredEx32.Domain );
  499. IdentityEx->PasswordLength = CredEx32.PasswordLength ;
  500. IdentityEx->Password = (PWSTR) UlongToPtr( CredEx32.Password );
  501. IdentityEx->Flags = CredEx32.Flags ;
  502. IdentityEx->PackageListLength = CredEx32.PackageListLength ;
  503. IdentityEx->PackageList = (PWSTR) UlongToPtr( CredEx32.PackageList );
  504. }
  505. else
  506. {
  507. D_DebugLog((DEB_ERROR, "Failed to capture WOW64 supplied credEX structure - %x\n", Status));
  508. goto Cleanup;
  509. }
  510. }
  511. else // not WOW64
  512. {
  513. Status = LsaFunctions->CopyFromClientBuffer(
  514. NULL,
  515. sizeof(SEC_WINNT_AUTH_IDENTITY_EXW),
  516. IdentityEx,
  517. AuthorizationData
  518. );
  519. if (!NT_SUCCESS(Status))
  520. {
  521. D_DebugLog((DEB_ERROR, "Failed to capture supplied EX structure - %x\n", Status));
  522. goto Cleanup;
  523. }
  524. }
  525. AuthIdentity = (PSEC_WINNT_AUTH_IDENTITY) &IdentityEx->User ;
  526. CredSize = IdentityEx->Length ;
  527. Offset = FIELD_OFFSET(SEC_WINNT_AUTH_IDENTITY_EXW, User);
  528. }
  529. else // not Extended version
  530. {
  531. AuthIdentity = (PSEC_WINNT_AUTH_IDENTITY) IdentityEx ;
  532. if (CallInfoAttributes & SECPKG_CALL_WOWCLIENT)
  533. {
  534. AuthIdentity->User = (PWSTR) UlongToPtr(Cred32.User);
  535. AuthIdentity->UserLength = Cred32.UserLength;
  536. AuthIdentity->Domain = (PWSTR) UlongToPtr(Cred32.Domain);
  537. AuthIdentity->DomainLength = Cred32.DomainLength ;
  538. AuthIdentity->Password = (PWSTR) UlongToPtr(Cred32.Password);
  539. AuthIdentity->PasswordLength = Cred32.PasswordLength ;
  540. AuthIdentity->Flags = Cred32.Flags ;
  541. }
  542. CredSize = sizeof(SEC_WINNT_AUTH_IDENTITY_W);
  543. }
  544. //
  545. // Check for the no-pac flag
  546. //
  547. if ((AuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_ONLY) != 0)
  548. {
  549. //
  550. // This may mean that we need to get a new TGT even though
  551. // we really just need to drop the PAC from an existing one.
  552. // This could cause problems in the smart card case
  553. // MMS 6/1/98
  554. //
  555. *Flags |= KERB_CRED_NO_PAC;
  556. }
  557. //
  558. // Check for ANSI structures.
  559. //
  560. if ((AuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
  561. {
  562. AnsiCreds = TRUE;
  563. //
  564. // Turn off the marshalled flag because we don't support marshalling
  565. // with ansi.
  566. //
  567. AuthIdentity->Flags &= ~SEC_WINNT_AUTH_IDENTITY_MARSHALLED;
  568. }
  569. else if ((AuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) == 0)
  570. {
  571. Status = STATUS_INVALID_PARAMETER;
  572. goto Cleanup;
  573. }
  574. //
  575. // Check to see if this is a null session request.
  576. //
  577. if ((AuthIdentity->UserLength == 0) &&
  578. (AuthIdentity->DomainLength == 0) &&
  579. (AuthIdentity->PasswordLength == 0) )
  580. {
  581. if ((AuthIdentity->User != NULL) &&
  582. (AuthIdentity->Domain != NULL) &&
  583. (AuthIdentity->Password != NULL) )
  584. {
  585. //
  586. // Return NULL credentials in this case.
  587. //
  588. *Flags |= KERB_CRED_NULL_SESSION;
  589. Status = STATUS_SUCCESS;
  590. goto Cleanup;
  591. }
  592. if ((AuthIdentity->User == NULL) &&
  593. (AuthIdentity->Domain == NULL) &&
  594. (AuthIdentity->Password == NULL) &&
  595. (*Flags == 0))
  596. {
  597. //
  598. // Use default credentials
  599. //
  600. Status = STATUS_SUCCESS;
  601. D_DebugLog((DEB_TRACE_CRED, "Using default credentials\n"));
  602. goto Cleanup;
  603. }
  604. }
  605. //
  606. // If the identity is marshalled, copy it all at once.
  607. //
  608. if ((AuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_MARSHALLED) != 0)
  609. {
  610. ULONG_PTR EndOfCreds;
  611. Marshalled = TRUE;
  612. //
  613. // Check for validity of the sizes.
  614. //
  615. if(
  616. // may be a marshalled username cred > UNLEN
  617. (AuthIdentity->UserLength > 0xFFFC) || // MAX_USHORT - NULL
  618. (AuthIdentity->DomainLength > DNS_MAX_NAME_LENGTH) ||
  619. (AuthIdentity->PasswordLength > PWLEN))
  620. {
  621. D_DebugLog((DEB_ERROR, "Either UserLength, DomainLength pr PasswordLength in supplied credentials has invalid length. %ws, line %d\n", THIS_FILE, __LINE__));
  622. Status = STATUS_INVALID_PARAMETER;
  623. goto Cleanup;
  624. }
  625. //
  626. // The callers can set the length of field to n chars, but they
  627. // will really occupy n+1 chars (null-terminator).
  628. //
  629. CredentialSize = CredSize +
  630. ( AuthIdentity->UserLength +
  631. AuthIdentity->DomainLength +
  632. AuthIdentity->PasswordLength +
  633. (((AuthIdentity->User != NULL) ? 1 : 0) +
  634. ((AuthIdentity->Domain != NULL) ? 1 : 0) +
  635. ((AuthIdentity->Password != NULL) ? 1 : 0)) ) * (ULONG) sizeof(WCHAR);
  636. EndOfCreds = (ULONG_PTR) AuthorizationData + CredentialSize;
  637. //
  638. // Verify that all the offsets are valid and no overflow will happen
  639. //
  640. ULONG_PTR TmpUser = (ULONG_PTR) AuthIdentity->User;
  641. if ((TmpUser != NULL) &&
  642. ( (TmpUser < (ULONG_PTR) AuthorizationData) ||
  643. (TmpUser > EndOfCreds) ||
  644. ((TmpUser + (AuthIdentity->UserLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  645. ((TmpUser + (AuthIdentity->UserLength * sizeof(WCHAR))) < TmpUser)))
  646. {
  647. D_DebugLog((DEB_ERROR, "Username in supplied credentials has invalid pointer or length. %ws, line %d\n", THIS_FILE, __LINE__));
  648. Status = STATUS_INVALID_PARAMETER;
  649. goto Cleanup;
  650. }
  651. ULONG_PTR TmpDomain = (ULONG_PTR) AuthIdentity->Domain;
  652. if ((TmpDomain != NULL) &&
  653. ( (TmpDomain < (ULONG_PTR) AuthorizationData) ||
  654. (TmpDomain > EndOfCreds) ||
  655. ((TmpDomain + (AuthIdentity->DomainLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  656. ((TmpDomain + (AuthIdentity->DomainLength * sizeof(WCHAR))) < TmpDomain)))
  657. {
  658. D_DebugLog((DEB_ERROR, "Domainname in supplied credentials has invalid pointer or length. %ws, line %d\n", THIS_FILE, __LINE__));
  659. Status = STATUS_INVALID_PARAMETER;
  660. goto Cleanup;
  661. }
  662. ULONG_PTR TmpPassword = (ULONG_PTR) AuthIdentity->Password;
  663. if ((TmpPassword != NULL) &&
  664. ( (TmpPassword < (ULONG_PTR) AuthorizationData) ||
  665. (TmpPassword > EndOfCreds) ||
  666. ((TmpPassword + (AuthIdentity->PasswordLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  667. ((TmpPassword + (AuthIdentity->PasswordLength * sizeof(WCHAR))) < TmpPassword)))
  668. {
  669. D_DebugLog((DEB_ERROR, "Password in supplied credentials has invalid pointer or length. %ws, line %d\n", THIS_FILE, __LINE__));
  670. Status = STATUS_INVALID_PARAMETER;
  671. goto Cleanup;
  672. }
  673. //
  674. // Allocate a chunk of memory for the credentials
  675. //
  676. SafeAllocaAllocate(Credentials, CredentialSize - Offset);
  677. if (Credentials == NULL)
  678. {
  679. Status = STATUS_INSUFFICIENT_RESOURCES;
  680. goto Cleanup;
  681. }
  682. RtlCopyMemory(
  683. Credentials,
  684. AuthIdentity,
  685. sizeof(SEC_WINNT_AUTH_IDENTITY_W)
  686. );
  687. //
  688. // Copy the credentials from the client
  689. //
  690. Status = LsaFunctions->CopyFromClientBuffer(
  691. NULL,
  692. CredentialSize - (Offset + sizeof(SEC_WINNT_AUTH_IDENTITY_W)),
  693. (PUCHAR) Credentials + sizeof(SEC_WINNT_AUTH_IDENTITY_W),
  694. (PUCHAR) AuthorizationData + Offset + sizeof(SEC_WINNT_AUTH_IDENTITY_W)
  695. );
  696. if (!NT_SUCCESS(Status))
  697. {
  698. D_DebugLog((DEB_ERROR, "Failed to copy whole auth identity: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  699. goto Cleanup;
  700. }
  701. //
  702. // Now convert all the offsets to pointers.
  703. //
  704. if (Credentials->User != NULL)
  705. {
  706. Credentials->User = (LPWSTR) RtlOffsetToPointer(
  707. Credentials->User,
  708. (PUCHAR) Credentials - (PUCHAR) AuthorizationData - Offset
  709. );
  710. UserString.Buffer = Credentials->User;
  711. UserString.Length = UserString.MaximumLength =
  712. (USHORT) Credentials->UserLength * sizeof(WCHAR);
  713. }
  714. if (Credentials->Domain != NULL)
  715. {
  716. Credentials->Domain = (LPWSTR) RtlOffsetToPointer(
  717. Credentials->Domain,
  718. (PUCHAR) Credentials - (PUCHAR) AuthorizationData - Offset
  719. );
  720. DomainString.Buffer = Credentials->Domain;
  721. DomainString.Length = DomainString.MaximumLength = (USHORT) Credentials->DomainLength * sizeof(WCHAR);
  722. }
  723. if (Credentials->Password != NULL)
  724. {
  725. Credentials->Password = (LPWSTR) RtlOffsetToPointer(
  726. Credentials->Password,
  727. (PUCHAR) Credentials - (PUCHAR) AuthorizationData - Offset
  728. );
  729. PasswordString.Buffer = Credentials->Password;
  730. PasswordString.Length = PasswordString.MaximumLength = (USHORT)
  731. Credentials->PasswordLength * sizeof(WCHAR);
  732. }
  733. }
  734. else
  735. {
  736. //
  737. // Here we need to copy the pointer individually
  738. //
  739. if (AuthIdentity->User != NULL)
  740. {
  741. Status = KerbCopyClientString(
  742. AuthIdentity->User,
  743. AuthIdentity->UserLength,
  744. AnsiCreds,
  745. &UserString,
  746. AuthIdentity->UserLength // may be marshalled username > UNLEN
  747. );
  748. if (!NT_SUCCESS(Status))
  749. {
  750. D_DebugLog((DEB_ERROR, "Failed to copy client user name. %ws, line %d\n", THIS_FILE, __LINE__));
  751. goto Cleanup;
  752. }
  753. }
  754. if (AuthIdentity->Domain != NULL)
  755. {
  756. Status = KerbCopyClientString(
  757. AuthIdentity->Domain,
  758. AuthIdentity->DomainLength,
  759. AnsiCreds,
  760. &DomainString,
  761. DNS_MAX_NAME_LENGTH
  762. );
  763. if (!NT_SUCCESS(Status))
  764. {
  765. D_DebugLog((DEB_ERROR, "Failed to copy client Domain name. %ws, line %d\n", THIS_FILE, __LINE__));
  766. goto Cleanup;
  767. }
  768. }
  769. if (AuthIdentity->Password != NULL)
  770. {
  771. Status = KerbCopyClientString(
  772. AuthIdentity->Password,
  773. AuthIdentity->PasswordLength,
  774. AnsiCreds,
  775. &PasswordString,
  776. PWLEN
  777. );
  778. if (!NT_SUCCESS(Status))
  779. {
  780. D_DebugLog((DEB_ERROR, "Failed to copy client Password name. %ws, line %d\n", THIS_FILE, __LINE__));
  781. goto Cleanup;
  782. }
  783. }
  784. Credentials = AuthIdentity;
  785. }
  786. }
  787. else
  788. {
  789. Credentials = &LocalIdentity;
  790. RtlZeroMemory(
  791. Credentials,
  792. sizeof(SEC_WINNT_AUTH_IDENTITY_W)
  793. );
  794. }
  795. //
  796. // Now build the supplied credentials.
  797. //
  798. DsysAssert( !LogonSessionsLocked );
  799. KerbReadLockLogonSessions(LogonSession);
  800. LogonSessionsLocked = TRUE;
  801. //
  802. // Compute the size of the new credentials
  803. //
  804. //
  805. // If a field is not present, use the field from the logon session
  806. //
  807. if (Credentials->User == NULL)
  808. {
  809. UserString = LogonSession->PrimaryCredentials.UserName;
  810. }
  811. D_DebugLog((DEB_TRACE_CRED, "Using user %wZ\n", &UserString));
  812. if (Credentials->Domain == NULL)
  813. {
  814. ULONG Index;
  815. BOOLEAN Upn = FALSE;
  816. //
  817. // if it's a UPN and domain was NULL, supply an empty domain
  818. // rather than filling in the default.
  819. //
  820. for( Index = 0 ; Index < (UserString.Length/sizeof(WCHAR)) ; Index++ )
  821. {
  822. if( UserString.Buffer[ Index ] == L'@' )
  823. {
  824. Upn = TRUE;
  825. break;
  826. }
  827. }
  828. if( !Upn )
  829. {
  830. DomainString = LogonSession->PrimaryCredentials.DomainName;
  831. } else {
  832. RtlInitUnicodeString( &DomainString, L"" );
  833. }
  834. }
  835. else
  836. {
  837. if ((DomainString.Length > sizeof(WCHAR)) &&
  838. (DomainString.Buffer[-1 + DomainString.Length / sizeof(WCHAR)] == L'.') )
  839. {
  840. DomainString.Length -= sizeof(WCHAR);
  841. }
  842. }
  843. D_DebugLog((DEB_TRACE_CRED, "Using domain %wZ\n", &DomainString));
  844. //
  845. // Special case when no password is supplied, so its copied from
  846. // the logon session.
  847. //
  848. if (Credentials->Password == NULL)
  849. {
  850. //
  851. // The password stored in the logon session is not a string
  852. // so don't copy it here.
  853. //
  854. PasswordString.Buffer = NULL;
  855. PasswordString.Length = 0;
  856. //
  857. // Special case hack for some apps using NTLM hack of machinename$.
  858. // This allows us to use default creds after they've been changed, and
  859. // is a one-off piece of functionality for .Net - make a better sol'n
  860. // with credential reworking in Longhorn.
  861. //
  862. if ( RtlEqualLuid( &LogonSession->LogonId, &SystemLogonId ) &&
  863. RtlEqualUnicodeString( &KerbGlobalMachineServiceName, &UserString, TRUE ))
  864. {
  865. D_DebugLog((DEB_TRACE_CRED, "Getting cred handle for LS$ special case\n"));
  866. *Flags |= KERB_CRED_LS_DEFAULT;
  867. }
  868. }
  869. //
  870. // Check if the user name holds a cert context thumbprint
  871. //
  872. Status = KerbCheckUserNameForCert(
  873. &LogonSession->LogonId,
  874. FALSE,
  875. &UserString,
  876. &CertContext
  877. );
  878. if (NT_SUCCESS(Status))
  879. {
  880. if (NULL != CertContext)
  881. {
  882. fSuppliedCertCred = TRUE;
  883. }
  884. }
  885. else
  886. {
  887. goto Cleanup;
  888. }
  889. if (fSuppliedCertCred)
  890. {
  891. //
  892. // Generate the PK credentials for a smart card cert
  893. //
  894. Status = KerbAddCertCredToPrimaryCredential(
  895. LogonSession,
  896. PrincipalName,
  897. CertContext,
  898. &PasswordString,
  899. CONTEXT_INITIALIZED_WITH_ACH,
  900. SuppliedCreds
  901. );
  902. if (NT_SUCCESS(Status))
  903. {
  904. goto Cleanup;
  905. }
  906. }
  907. else
  908. {
  909. // setup the primary creds structure
  910. Status = KerbInitPrimaryCreds(
  911. LogonSession,
  912. &UserString,
  913. &DomainString,
  914. PrincipalName,
  915. &PasswordString,
  916. FALSE,
  917. NULL,
  918. SuppliedCreds);
  919. if (!NT_SUCCESS(Status))
  920. {
  921. goto Cleanup;
  922. }
  923. }
  924. Cleanup:
  925. if (NULL != CertContext)
  926. {
  927. CertFreeCertificateContext(CertContext);
  928. }
  929. if (LogonSessionsLocked)
  930. {
  931. KerbUnlockLogonSessions(LogonSession);
  932. }
  933. //
  934. // Zero the password
  935. //
  936. if (PasswordString.Buffer != NULL)
  937. {
  938. RtlSecureZeroMemory(
  939. PasswordString.Buffer,
  940. PasswordString.Length
  941. );
  942. }
  943. if (AuthIdentity != NULL)
  944. {
  945. if (AnsiCreds)
  946. {
  947. if ((AuthIdentity->Password != NULL) && (PasswordString.Buffer != NULL))
  948. {
  949. RtlSecureZeroMemory(
  950. PasswordString.Buffer,
  951. PasswordString.Length
  952. );
  953. RtlFreeUnicodeString(&PasswordString);
  954. }
  955. if ((AuthIdentity->User != NULL) && (UserString.Buffer != NULL))
  956. {
  957. RtlFreeUnicodeString(&UserString);
  958. }
  959. if ((AuthIdentity->Domain != NULL) && (DomainString.Buffer != NULL))
  960. {
  961. RtlFreeUnicodeString(&DomainString);
  962. }
  963. }
  964. else if (!Marshalled)
  965. {
  966. if ((AuthIdentity->Password != NULL) && (PasswordString.Buffer != NULL))
  967. {
  968. KerbFree(PasswordString.Buffer);
  969. }
  970. if ((AuthIdentity->User != NULL) && (UserString.Buffer != NULL))
  971. {
  972. KerbFree(UserString.Buffer);
  973. }
  974. if ((AuthIdentity->Domain != NULL) && (DomainString.Buffer != NULL))
  975. {
  976. KerbFree(DomainString.Buffer);
  977. }
  978. }
  979. }
  980. if ((Credentials != NULL)
  981. && (Credentials != AuthIdentity)
  982. && (Credentials != &LocalIdentity))
  983. {
  984. SafeAllocaFree(Credentials);
  985. }
  986. SafeAllocaFree(IdentityEx);
  987. if ( TokenHandle != NULL )
  988. {
  989. CloseHandle( TokenHandle );
  990. }
  991. return(Status);
  992. }
  993. //+-------------------------------------------------------------------------
  994. //
  995. // Function: SpAcceptCredentials
  996. //
  997. // Synopsis: This routine is called after another package has logged
  998. // a user on. The other package provides a user name and
  999. // password and the Kerberos package will create a logon
  1000. // session for this user.
  1001. //
  1002. // Effects: Creates a logon session
  1003. //
  1004. // Arguments: LogonType - Type of logon, such as network or interactive
  1005. // Accountname - Name of the account that logged on
  1006. // PrimaryCredentials - Primary Credentials for the account,
  1007. // containing a domain name, password, SID, etc.
  1008. // SupplementalCredentials - Kerberos-Specific blob of
  1009. // supplemental Credentials.
  1010. //
  1011. // Requires:
  1012. //
  1013. // Returns:
  1014. //
  1015. // Notes:
  1016. //
  1017. //
  1018. //--------------------------------------------------------------------------
  1019. NTSTATUS NTAPI
  1020. SpAcceptCredentials(
  1021. IN SECURITY_LOGON_TYPE LogonType,
  1022. IN PUNICODE_STRING AccountName,
  1023. IN PSECPKG_PRIMARY_CRED PrimaryCredentials,
  1024. IN PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials
  1025. )
  1026. {
  1027. NTSTATUS Status = STATUS_SUCCESS;
  1028. PKERB_LOGON_SESSION LogonSession = NULL;
  1029. KERBERR KerbErr = KDC_ERR_NONE;
  1030. PUNICODE_STRING RealmName;
  1031. PUNICODE_STRING UserName;
  1032. UNICODE_STRING TempRealm = {0};
  1033. UNICODE_STRING TempUser = {0};
  1034. PKERB_MIT_REALM MitRealm = NULL;
  1035. BOOLEAN UsedAlternateName = FALSE;
  1036. LUID SystemLogonId = SYSTEM_LUID;
  1037. LUID NetworkServiceLogonId = NETWORKSERVICE_LUID;
  1038. D_DebugLog((DEB_TRACE_API, "SpAcceptCredentials called\n"));
  1039. if (!KerbGlobalInitialized)
  1040. {
  1041. Status = STATUS_INVALID_SERVER_STATE;
  1042. goto Cleanup;
  1043. }
  1044. D_DebugLog((DEB_TRACE_CRED,
  1045. "SpAcceptCredentials accepting credentials for %#x:%#x, flag %#x, "
  1046. "logon type %#x, %wZ\\%wZ or %wZ at %wZ\n",
  1047. PrimaryCredentials->LogonId.HighPart, PrimaryCredentials->LogonId.LowPart,
  1048. PrimaryCredentials->Flags,
  1049. LogonType,
  1050. &PrimaryCredentials->DomainName,
  1051. &PrimaryCredentials->DownlevelName,
  1052. &PrimaryCredentials->Upn,
  1053. &PrimaryCredentials->DnsDomainName));
  1054. LogonSession = KerbReferenceLogonSession(
  1055. &PrimaryCredentials->LogonId,
  1056. FALSE // don't unlink
  1057. );
  1058. //
  1059. // If this is an update, locate the credentials & update the password
  1060. //
  1061. if ((PrimaryCredentials->Flags & PRIMARY_CRED_UPDATE) != 0)
  1062. {
  1063. KERB_ACCOUNT_TYPE AccountType;
  1064. LUID SystemLuid = SYSTEM_LUID;
  1065. if (LogonSession == NULL)
  1066. {
  1067. goto Cleanup;
  1068. }
  1069. if(RtlEqualLuid(&PrimaryCredentials->LogonId, &SystemLuid))
  1070. {
  1071. AccountType = MachineAccount;
  1072. } else {
  1073. AccountType = UserAccount;
  1074. }
  1075. KerbWriteLockLogonSessions(LogonSession);
  1076. Status = KerbChangeCredentialsPassword(
  1077. &LogonSession->PrimaryCredentials,
  1078. &PrimaryCredentials->Password,
  1079. NULL, // no etype info
  1080. AccountType,
  1081. PrimaryCredentials->Flags
  1082. );
  1083. if(NT_SUCCESS(Status))
  1084. {
  1085. if( AccountType == MachineAccount )
  1086. {
  1087. LogonSession->LogonSessionFlags &= ~(KERB_LOGON_LOCAL_ONLY | KERB_LOGON_NO_PASSWORD);
  1088. }
  1089. }
  1090. KerbUnlockLogonSessions(LogonSession);
  1091. goto Cleanup;
  1092. }
  1093. //
  1094. // This is not an update. If we got a Logon session back from the
  1095. // reference call, bail out now. This is an extra call because we
  1096. // are doing an MIT logon
  1097. //
  1098. if ( LogonSession )
  1099. {
  1100. if (RtlEqualLuid(&PrimaryCredentials->LogonId, &SystemLogonId))
  1101. {
  1102. D_DebugLog(( DEB_ERROR, "Somebody created a logon session for machine account\n"));
  1103. }
  1104. D_DebugLog(( DEB_TRACE_CRED, "Skipping AcceptCred for %wZ\\%wZ (%x:%x)\n",
  1105. &PrimaryCredentials->DomainName,
  1106. &PrimaryCredentials->DownlevelName,
  1107. PrimaryCredentials->LogonId.HighPart,
  1108. PrimaryCredentials->LogonId.LowPart ));
  1109. goto Cleanup;
  1110. }
  1111. //
  1112. // Check to see if the domain is an alias for another realm.
  1113. //
  1114. if (RtlEqualLuid(&PrimaryCredentials->LogonId, &SystemLogonId)
  1115. || RtlEqualLuid(&PrimaryCredentials->LogonId, &NetworkServiceLogonId))
  1116. {
  1117. KerbGlobalReadLock();
  1118. if (KerbLookupMitRealm(
  1119. &KerbGlobalDnsDomainName,
  1120. &MitRealm,
  1121. &UsedAlternateName))
  1122. {
  1123. KerbErr = KerbConvertKdcNameToString(
  1124. &TempUser,
  1125. KerbGlobalMitMachineServiceName,
  1126. NULL
  1127. );
  1128. KerbGlobalReleaseLock();
  1129. if (!KERB_SUCCESS(KerbErr))
  1130. {
  1131. Status = KerbMapKerbError(KerbErr);
  1132. goto Cleanup;
  1133. }
  1134. UserName = &TempUser;
  1135. RealmName = &MitRealm->RealmName;
  1136. }
  1137. else
  1138. {
  1139. KerbGlobalReleaseLock();
  1140. UserName = &PrimaryCredentials->DownlevelName;
  1141. Status = KerbGetOurDomainName(
  1142. &TempRealm
  1143. );
  1144. if (!NT_SUCCESS(Status))
  1145. {
  1146. goto Cleanup;
  1147. }
  1148. if (TempRealm.Length != 0)
  1149. {
  1150. RealmName = &TempRealm;
  1151. }
  1152. else
  1153. {
  1154. RealmName = &PrimaryCredentials->DomainName;
  1155. }
  1156. }
  1157. }
  1158. else
  1159. {
  1160. if (PrimaryCredentials->Upn.Length != 0)
  1161. {
  1162. // UPNs can't have a realm in credential.
  1163. RealmName = &TempRealm;
  1164. UserName = &PrimaryCredentials->Upn;
  1165. }
  1166. else
  1167. {
  1168. RealmName = &PrimaryCredentials->DomainName;
  1169. UserName = &PrimaryCredentials->DownlevelName;
  1170. }
  1171. }
  1172. Status = KerbCreateLogonSession(
  1173. &PrimaryCredentials->LogonId,
  1174. UserName,
  1175. RealmName,
  1176. &PrimaryCredentials->Password,
  1177. &PrimaryCredentials->OldPassword,
  1178. PrimaryCredentials->Flags,
  1179. LogonType == NewCredentials ? KERB_LOGON_NEW_CREDENTIALS : 0,
  1180. FALSE,
  1181. &LogonSession
  1182. );
  1183. if (!NT_SUCCESS(Status))
  1184. {
  1185. //
  1186. // If we know about the logon session, that is o.k. because we
  1187. // probably handled the logon.
  1188. //
  1189. if (Status == STATUS_OBJECT_NAME_EXISTS)
  1190. {
  1191. Status = STATUS_SUCCESS;
  1192. if (RtlEqualLuid(&PrimaryCredentials->LogonId,&SystemLogonId))
  1193. {
  1194. D_DebugLog(( DEB_ERROR, "Somebody called AcquireCredentialsHandle before AcceptCredentials completed.\n"));
  1195. }
  1196. }
  1197. goto Cleanup;
  1198. }
  1199. Cleanup:
  1200. if (LogonSession != NULL)
  1201. {
  1202. KerbDereferenceLogonSession(LogonSession);
  1203. }
  1204. KerbFreeString(&TempRealm);
  1205. KerbFreeString(&TempUser);
  1206. D_DebugLog((DEB_TRACE_API, "SpAcceptCredentials returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  1207. return(KerbMapKerbNtStatusToNtStatus(Status));
  1208. }
  1209. //+-------------------------------------------------------------------------
  1210. //
  1211. // Function: SpAcquireCredentialsHandle
  1212. //
  1213. // Synopsis: Contains Kerberos Code for AcquireCredentialsHandle which
  1214. // creates a Credential associated with a logon session.
  1215. //
  1216. // Effects: Creates a KERB_CREDENTIAL
  1217. //
  1218. // Arguments: PrincipalName - Name of logon session for which to create credential
  1219. // CredentialUseFlags - Flags indicating whether the Credentials
  1220. // is for inbound or outbound use.
  1221. // LogonId - The logon ID of logon session for which to create
  1222. // a credential.
  1223. // AuthorizationData - Unused blob of Kerberos-specific data
  1224. // GetKeyFunction - Unused function to retrieve a session key
  1225. // GetKeyArgument - Argument for GetKeyFunction
  1226. // CredentialHandle - Receives handle to new credential
  1227. // ExpirationTime - Receives expiration time for credential
  1228. //
  1229. // Requires:
  1230. //
  1231. // Returns:
  1232. //
  1233. // Notes:
  1234. //
  1235. //
  1236. //--------------------------------------------------------------------------
  1237. NTSTATUS NTAPI
  1238. SpAcquireCredentialsHandle(
  1239. IN OPTIONAL PUNICODE_STRING PrincipalName,
  1240. IN ULONG CredentialUseFlags,
  1241. IN OPTIONAL PLUID LogonId,
  1242. IN PVOID AuthorizationData,
  1243. IN PVOID GetKeyFunction,
  1244. IN PVOID GetKeyArgument,
  1245. OUT PLSA_SEC_HANDLE CredentialHandle,
  1246. OUT PTimeStamp ExpirationTime
  1247. )
  1248. {
  1249. NTSTATUS Status = STATUS_SUCCESS;
  1250. SECPKG_CLIENT_INFO ClientInfo;
  1251. PLUID LogonIdToUse = NULL;
  1252. PKERB_LOGON_SESSION LogonSession = NULL;
  1253. PKERB_CREDENTIAL Credential = NULL;
  1254. PKERB_PRIMARY_CREDENTIAL SuppliedCreds = NULL;
  1255. UNICODE_STRING CapturedPrincipalName = {0};
  1256. ULONG CredentialFlags = 0;
  1257. LUID SystemLogonId = SYSTEM_LUID;
  1258. LUID AnonymousLogonId = ANONYMOUS_LOGON_LUID;
  1259. LUID LocalServiceLogonId = LOCALSERVICE_LUID;
  1260. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
  1261. BOOLEAN Impersonating = FALSE;
  1262. HANDLE hProcess = NULL;
  1263. if (!KerbGlobalInitialized)
  1264. {
  1265. Status = STATUS_INVALID_SERVER_STATE;
  1266. ClientInfo.ProcessID = 0;
  1267. goto Cleanup;
  1268. }
  1269. //
  1270. // Kerberos does not support acquiring Credentials handle by name
  1271. // so first locate the logon session to use.
  1272. //
  1273. //
  1274. // First get information about the caller.
  1275. //
  1276. Status = LsaFunctions->GetClientInfo(&ClientInfo);
  1277. if (!NT_SUCCESS(Status))
  1278. {
  1279. D_DebugLog((DEB_ERROR, "Failed to get client information: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1280. goto Cleanup;
  1281. }
  1282. else if ((ClientInfo.ClientFlags & SECPKG_CLIENT_THREAD_TERMINATED) != 0)
  1283. {
  1284. Status = STATUS_ACCESS_DENIED;
  1285. goto Cleanup;
  1286. }
  1287. //
  1288. // If the caller supplied a logon ID they must have the TCB privilege
  1289. //
  1290. if (ARGUMENT_PRESENT(LogonId) && ((LogonId->LowPart != 0) || (LogonId->HighPart != 0)))
  1291. {
  1292. if (!ClientInfo.HasTcbPrivilege)
  1293. {
  1294. Status = STATUS_PRIVILEGE_NOT_HELD;
  1295. goto Cleanup;
  1296. }
  1297. LogonIdToUse = LogonId;
  1298. }
  1299. else
  1300. {
  1301. //
  1302. // Use the callers logon id.
  1303. //
  1304. LogonIdToUse = &ClientInfo.LogonId;
  1305. }
  1306. ImpersonationLevel = ClientInfo.ImpersonationLevel;
  1307. Impersonating = ClientInfo.Impersonating;
  1308. hProcess = (HANDLE) LongToHandle(ClientInfo.ProcessID);
  1309. D_DebugLog((DEB_TRACE_API, "SpAcquireCredentialsHandle for pid 0x%x, luid (%x:%x) called\n", ClientInfo.ProcessID,
  1310. ((LogonIdToUse==NULL) ? 0xffffffff : LogonIdToUse->HighPart),
  1311. ((LogonIdToUse==NULL) ? 0xffffffff : LogonIdToUse->LowPart)));
  1312. //
  1313. // Now try to reference the logon session with this logon id.
  1314. //
  1315. LogonSession = KerbReferenceLogonSession(
  1316. LogonIdToUse,
  1317. FALSE // don't unlink
  1318. );
  1319. if (LogonSession == NULL)
  1320. {
  1321. //
  1322. // Enforce that the caller has > Impersonation level token.
  1323. // This is because we don't have an S4U Logon session, which is
  1324. // the only way we can try for S4UProxy w/o having TCB.
  1325. //
  1326. if (ClientInfo.ImpersonationLevel <= SecurityIdentification)
  1327. {
  1328. DebugLog((DEB_ERROR, "Trying to acquire credentials with an token no better than SecurityIdentification\n"));
  1329. Status = SEC_E_NO_CREDENTIALS;
  1330. goto Cleanup;
  1331. }
  1332. //
  1333. // If we're getting called from anonymous, local service, or deferred
  1334. // local system logon, fail here. Additionally, if we're missing a given
  1335. // logon session, && we're not impersonating, then there's something
  1336. // wrong as processes need to have a logon session that we should have
  1337. // been informed of.
  1338. //
  1339. if ((( RtlEqualLuid(LogonIdToUse,&SystemLogonId) ) ||
  1340. ( RtlEqualLuid(LogonIdToUse, &AnonymousLogonId) ) ||
  1341. ( RtlEqualLuid(LogonIdToUse, &LocalServiceLogonId) ) ||
  1342. !Impersonating ) && AuthorizationData == NULL)
  1343. {
  1344. D_DebugLog((DEB_TRACE_CRED,
  1345. "SpAcquireCredentialsHandle called for unknown logon session %#x:%#x, Impersonating ? %s, AuthorizationData %p\n",
  1346. LogonIdToUse->HighPart, LogonIdToUse->LowPart, Impersonating ? "true" : "false", AuthorizationData));
  1347. Status = STATUS_NO_SUCH_LOGON_SESSION;
  1348. goto Cleanup;
  1349. }
  1350. //
  1351. // This is a logon session that we don't know about - rather than creating
  1352. // a dummy logon session for "every ASC", we let the lsa keep track,
  1353. // then we create a new one, if needed.
  1354. //
  1355. Status = KerbCreateDummyLogonSession(
  1356. LogonIdToUse,
  1357. &LogonSession,
  1358. ImpersonationLevel,
  1359. Impersonating,
  1360. hProcess
  1361. );
  1362. if (!NT_SUCCESS( Status ))
  1363. {
  1364. Status = STATUS_NO_SUCH_LOGON_SESSION;
  1365. goto Cleanup;
  1366. }
  1367. }
  1368. else if (ClientInfo.ImpersonationLevel <= SecurityIdentification)
  1369. {
  1370. D_DebugLog((DEB_TRACE_CRED, "Got identify token on ls %p\n", LogonSession));
  1371. //
  1372. // If we have supplied authorization data, fail the request in the "old"
  1373. // way - e.g. we only allow logon sessions originating from S4USelf to
  1374. // be used with an identify level token. This is the way things behaved
  1375. // in previous releases.
  1376. //
  1377. KerbReadLockLogonSessions(LogonSession);
  1378. if ( AuthorizationData != NULL ||
  1379. (( LogonSession->LogonSessionFlags & KERB_LOGON_S4U_SESSION ) == 0))
  1380. {
  1381. DebugLog((DEB_ERROR, "ACH called w identify + !s4u or w pvauth\n"));
  1382. KerbUnlockLogonSessions(LogonSession);
  1383. Status = SEC_E_NO_CREDENTIALS;
  1384. goto Cleanup;
  1385. }
  1386. KerbUnlockLogonSessions(LogonSession);
  1387. }
  1388. #if DBG
  1389. KerbReadLockLogonSessions(LogonSession);
  1390. D_DebugLog((DEB_TRACE_CTXT, "SpAcquireCredHandle: Acquiring creds for %wZ\\%wZ\n",
  1391. &LogonSession->PrimaryCredentials.DomainName,
  1392. &LogonSession->PrimaryCredentials.UserName ));
  1393. KerbUnlockLogonSessions(LogonSession);
  1394. #endif
  1395. //
  1396. // Check for supplied Credentials
  1397. //
  1398. if (ARGUMENT_PRESENT(AuthorizationData))
  1399. {
  1400. Status = KerbCaptureSuppliedCreds(
  1401. LogonSession,
  1402. AuthorizationData,
  1403. PrincipalName,
  1404. &SuppliedCreds,
  1405. &CredentialFlags
  1406. );
  1407. if (!NT_SUCCESS(Status))
  1408. {
  1409. DebugLog((DEB_ERROR, "Failed to capture auth data: 0x%x. %ws, line %d\n", Status, THIS_FILE, __LINE__));
  1410. goto Cleanup;
  1411. }
  1412. if ((SuppliedCreds == NULL) && RtlEqualLuid(LogonIdToUse, &AnonymousLogonId))
  1413. {
  1414. D_DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle can not have anonymous with no explicit creds: %ws, line %d\n", THIS_FILE, __LINE__));
  1415. Status = STATUS_NO_SUCH_LOGON_SESSION;
  1416. goto Cleanup;
  1417. }
  1418. }
  1419. //
  1420. // if there was a supplied principal name, put it into the credential
  1421. //
  1422. if (ARGUMENT_PRESENT(PrincipalName) && (PrincipalName->Length != 0))
  1423. {
  1424. Status = KerbDuplicateString(
  1425. &CapturedPrincipalName,
  1426. PrincipalName
  1427. );
  1428. if (!NT_SUCCESS(Status))
  1429. {
  1430. goto Cleanup;
  1431. }
  1432. }
  1433. //
  1434. // We found the logon session. Good. Now create a new Credentials.
  1435. //
  1436. Status = KerbCreateCredential(
  1437. LogonIdToUse,
  1438. LogonSession,
  1439. CredentialUseFlags,
  1440. &SuppliedCreds,
  1441. CredentialFlags,
  1442. &CapturedPrincipalName,
  1443. &Credential,
  1444. ExpirationTime
  1445. );
  1446. if (!NT_SUCCESS(Status))
  1447. {
  1448. D_DebugLog((DEB_WARN,"Failed to create credential: 0x%x\n",Status));
  1449. goto Cleanup;
  1450. }
  1451. CapturedPrincipalName.Buffer = NULL;
  1452. //
  1453. // If the client is a restricted token, observe that here
  1454. // Note: This has been punted to Blackcomb
  1455. #ifdef RESTRICTED_TOKEN
  1456. if (ClientInfo.Restricted)
  1457. {
  1458. Credential->CredentialFlags |= KERB_CRED_RESTRICTED;
  1459. D_DebugLog((DEB_TRACE_API,"Adding token restrictions\n"));
  1460. //
  1461. // We don't let restricted processes accept connections
  1462. //
  1463. if ((CredentialUseFlags & SECPKG_CRED_INBOUND) != 0)
  1464. {
  1465. DebugLog((DEB_ERROR,"Restricted token trying to acquire inbound credentials - denied\n"));
  1466. Status = STATUS_ACCESS_DENIED;
  1467. goto Cleanup;
  1468. }
  1469. Status = KerbAddRestrictionsToCredential(
  1470. LogonSession,
  1471. Credential
  1472. );
  1473. if (!NT_SUCCESS(Status))
  1474. {
  1475. DebugLog((DEB_ERROR,"Failed to add restrictions to credential: 0x%x\n",Status));
  1476. goto Cleanup;
  1477. }
  1478. }
  1479. #endif
  1480. *CredentialHandle = KerbGetCredentialHandle(Credential);
  1481. KerbUtcTimeToLocalTime(
  1482. ExpirationTime,
  1483. ExpirationTime
  1484. );
  1485. D_DebugLog((DEB_TRACE_API, "SpAcquireCredentialsHandle returning success, handle = 0x%x\n",*CredentialHandle));
  1486. Cleanup:
  1487. if (LogonSession != NULL)
  1488. {
  1489. KerbDereferenceLogonSession(LogonSession);
  1490. }
  1491. if (Credential != NULL)
  1492. {
  1493. KerbDereferenceCredential(Credential);
  1494. }
  1495. if (SuppliedCreds != NULL)
  1496. {
  1497. KerbFreePrimaryCredentials( SuppliedCreds, TRUE );
  1498. }
  1499. KerbFreeString(&CapturedPrincipalName);
  1500. D_DebugLog((DEB_TRACE_API, "SpAcquireCredentialsHandle for pid 0x%x, luid (%x:%x) returned 0x%x\n",
  1501. ClientInfo.ProcessID,
  1502. ((LogonIdToUse==NULL) ? 0xffffffff : LogonIdToUse->HighPart),
  1503. ((LogonIdToUse == NULL) ? 0xffffffff : LogonIdToUse->LowPart), KerbMapKerbNtStatusToNtStatus(Status)));
  1504. return(KerbMapKerbNtStatusToNtStatus(Status));
  1505. }
  1506. //+-------------------------------------------------------------------------
  1507. //
  1508. // Function: SpFreeCredentialsHandle
  1509. //
  1510. // Synopsis: Frees a credential created by AcquireCredentialsHandle.
  1511. //
  1512. // Effects: Unlinks the credential from the global list and the list
  1513. // for this client.
  1514. //
  1515. // Arguments: CredentialHandle - Handle to the credential to free
  1516. //
  1517. // Requires:
  1518. //
  1519. // Returns: STATUS_SUCCESS on success,
  1520. // SEC_E_INVALID_HANDLE if the handle is not valid
  1521. //
  1522. // Notes:
  1523. //
  1524. //
  1525. //--------------------------------------------------------------------------
  1526. NTSTATUS NTAPI
  1527. SpFreeCredentialsHandle(
  1528. IN LSA_SEC_HANDLE CredentialHandle
  1529. )
  1530. {
  1531. NTSTATUS Status;
  1532. PKERB_CREDENTIAL Credential;
  1533. D_DebugLog((DEB_TRACE_API,"SpFreeCredentialsHandle 0x%x called\n",CredentialHandle));
  1534. if (!KerbGlobalInitialized)
  1535. {
  1536. Status = STATUS_INVALID_SERVER_STATE;
  1537. goto Cleanup;
  1538. }
  1539. Status = KerbReferenceCredential(
  1540. CredentialHandle,
  1541. 0, // no flags
  1542. TRUE, // unlink handle
  1543. &Credential
  1544. );
  1545. if (!NT_SUCCESS(Status))
  1546. {
  1547. D_DebugLog((DEB_ERROR,"SpFreeCredentialsHandle: Failed to reference credential 0x%0x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1548. goto Cleanup;
  1549. }
  1550. //
  1551. // Now dereference the credential. If nobody else is using this credential
  1552. // currently it will be freed.
  1553. //
  1554. KerbDereferenceCredential(Credential);
  1555. Status = STATUS_SUCCESS;
  1556. Cleanup:
  1557. D_DebugLog((DEB_TRACE_API, "SpFreeCredentialsHandle returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  1558. return(KerbMapKerbNtStatusToNtStatus(Status));
  1559. }
  1560. //+-------------------------------------------------------------------------
  1561. //
  1562. // Function: SpQueryCredentialsAttributes
  1563. //
  1564. // Synopsis: Returns attributes of a credential
  1565. //
  1566. // Effects: allocate memory in client address space
  1567. //
  1568. // Arguments: CredentialHandle - handle to query
  1569. // CredentialAttribute - Attribute to query:
  1570. // SECPKG_CRED_ATTR_NAMES - returns credential name
  1571. // Buffer - points to structure in client's address space
  1572. //
  1573. // Requires:
  1574. //
  1575. // Returns:
  1576. //
  1577. // Notes:
  1578. //
  1579. //
  1580. //--------------------------------------------------------------------------
  1581. NTSTATUS NTAPI
  1582. SpQueryCredentialsAttributes(
  1583. IN LSA_SEC_HANDLE CredentialHandle,
  1584. IN ULONG CredentialAttribute,
  1585. IN OUT PVOID Buffer
  1586. )
  1587. {
  1588. NTSTATUS Status = STATUS_SUCCESS;
  1589. PKERB_CREDENTIAL Credential = NULL;
  1590. PKERB_LOGON_SESSION LogonSession = NULL;
  1591. PKERB_PRIMARY_CREDENTIAL PrimaryCredentials;
  1592. LUID LogonId;
  1593. UNICODE_STRING FullServiceName = { 0 } ;
  1594. SecPkgCredentials_NamesW Names;
  1595. #if _WIN64
  1596. SECPKG_CALL_INFO CallInfo;
  1597. #endif
  1598. Names.sUserName = NULL;
  1599. if (!KerbGlobalInitialized)
  1600. {
  1601. Status = STATUS_INVALID_SERVER_STATE;
  1602. goto Cleanup;
  1603. }
  1604. D_DebugLog((DEB_TRACE_API,"SpQueryCredentialsAttributes Called\n"));
  1605. Status = KerbReferenceCredential(
  1606. CredentialHandle,
  1607. 0, // no flags
  1608. FALSE, // don't unlink
  1609. &Credential
  1610. );
  1611. if (!NT_SUCCESS(Status))
  1612. {
  1613. goto Cleanup;
  1614. }
  1615. #if _WIN64
  1616. if(!LsaFunctions->GetCallInfo( &CallInfo ))
  1617. {
  1618. Status = STATUS_INTERNAL_ERROR;
  1619. DebugLog((DEB_ERROR, "SpQueryCredentialsAttributes, failed to get callinfo 0x%lx\n", Status));
  1620. goto Cleanup;
  1621. }
  1622. #endif
  1623. //
  1624. // The logon id of the credential is constant, so it is o.k.
  1625. // to use it without locking the credential
  1626. //
  1627. LogonId = Credential->LogonId;
  1628. //
  1629. // Get the associated logon session to get the name
  1630. //
  1631. LogonSession = KerbReferenceLogonSession(
  1632. &LogonId,
  1633. FALSE // don't unlink
  1634. );
  1635. if (LogonSession == NULL)
  1636. {
  1637. DebugLog((DEB_ERROR,"Failed to locate logon session for Credential. %ws, line %d\n", THIS_FILE, __LINE__));
  1638. Status = SEC_E_NO_CREDENTIALS;
  1639. goto Cleanup;
  1640. }
  1641. if (CredentialAttribute != SECPKG_CRED_ATTR_NAMES)
  1642. {
  1643. D_DebugLog((DEB_WARN, "Asked for illegal info level in QueryCredAttr: %d\n",
  1644. CredentialAttribute));
  1645. Status = STATUS_INVALID_PARAMETER;
  1646. goto Cleanup;
  1647. }
  1648. KerbReadLockLogonSessions(LogonSession);
  1649. //
  1650. // Figure out which credentials to use
  1651. //
  1652. if (Credential->SuppliedCredentials != NULL)
  1653. {
  1654. PrimaryCredentials = Credential->SuppliedCredentials;
  1655. }
  1656. else
  1657. {
  1658. PrimaryCredentials = &LogonSession->PrimaryCredentials;
  1659. }
  1660. //
  1661. // Build the full service name
  1662. //
  1663. if (!KERB_SUCCESS(KerbBuildEmailName(
  1664. &PrimaryCredentials->DomainName,
  1665. &PrimaryCredentials->UserName,
  1666. &FullServiceName
  1667. )))
  1668. {
  1669. Status = STATUS_INSUFFICIENT_RESOURCES;
  1670. }
  1671. KerbUnlockLogonSessions(LogonSession);
  1672. if (!NT_SUCCESS(Status))
  1673. {
  1674. goto Cleanup;
  1675. }
  1676. //
  1677. // Allocate memory in the client's address space
  1678. //
  1679. Status = LsaFunctions->AllocateClientBuffer(
  1680. NULL,
  1681. FullServiceName.MaximumLength,
  1682. (PVOID *) &Names.sUserName
  1683. );
  1684. if (!NT_SUCCESS(Status))
  1685. {
  1686. goto Cleanup;
  1687. }
  1688. //
  1689. // Copy the string there
  1690. //
  1691. Status = LsaFunctions->CopyToClientBuffer(
  1692. NULL,
  1693. FullServiceName.MaximumLength,
  1694. Names.sUserName,
  1695. FullServiceName.Buffer
  1696. );
  1697. if (!NT_SUCCESS(Status))
  1698. {
  1699. goto Cleanup;
  1700. }
  1701. //
  1702. // Now copy the address of the string there
  1703. //
  1704. #if _WIN64
  1705. if( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT )
  1706. {
  1707. Status = LsaFunctions->CopyToClientBuffer(
  1708. NULL,
  1709. sizeof(ULONG),
  1710. Buffer,
  1711. &Names
  1712. );
  1713. } else {
  1714. Status = LsaFunctions->CopyToClientBuffer(
  1715. NULL,
  1716. sizeof(Names),
  1717. Buffer,
  1718. &Names
  1719. );
  1720. }
  1721. #else
  1722. Status = LsaFunctions->CopyToClientBuffer(
  1723. NULL,
  1724. sizeof(Names),
  1725. Buffer,
  1726. &Names
  1727. );
  1728. #endif
  1729. if (!NT_SUCCESS(Status))
  1730. {
  1731. goto Cleanup;
  1732. }
  1733. Cleanup:
  1734. if (Credential != NULL)
  1735. {
  1736. KerbDereferenceCredential(Credential);
  1737. }
  1738. if (LogonSession != NULL)
  1739. {
  1740. KerbDereferenceLogonSession(LogonSession);
  1741. }
  1742. KerbFreeString(
  1743. &FullServiceName
  1744. );
  1745. if (!NT_SUCCESS(Status))
  1746. {
  1747. if (Names.sUserName != NULL)
  1748. {
  1749. (VOID) LsaFunctions->FreeClientBuffer(
  1750. NULL,
  1751. Names.sUserName
  1752. );
  1753. }
  1754. }
  1755. D_DebugLog((DEB_TRACE_API, "SpQueryCredentialsAttribute returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  1756. return(KerbMapKerbNtStatusToNtStatus(Status));
  1757. }
  1758. NTSTATUS NTAPI
  1759. SpSaveCredentials(
  1760. IN LSA_SEC_HANDLE CredentialHandle,
  1761. IN PSecBuffer Credentials
  1762. )
  1763. {
  1764. NTSTATUS Status = STATUS_NOT_SUPPORTED;
  1765. D_DebugLog((DEB_TRACE_API,"SpSaveCredentials Called\n"));
  1766. D_DebugLog((DEB_TRACE_API,"SpSaveCredentials returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  1767. return(KerbMapKerbNtStatusToNtStatus(Status));
  1768. }
  1769. NTSTATUS NTAPI
  1770. SpGetCredentials(
  1771. IN LSA_SEC_HANDLE CredentialHandle,
  1772. IN OUT PSecBuffer Credentials
  1773. )
  1774. {
  1775. NTSTATUS Status = STATUS_NOT_SUPPORTED;
  1776. D_DebugLog((DEB_TRACE_API,"SpGetCredentials Called\n"));
  1777. D_DebugLog((DEB_TRACE_API,"SpGetCredentials returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  1778. return(KerbMapKerbNtStatusToNtStatus(Status));
  1779. }
  1780. NTSTATUS NTAPI
  1781. SpDeleteCredentials(
  1782. IN LSA_SEC_HANDLE CredentialHandle,
  1783. IN PSecBuffer Key
  1784. )
  1785. {
  1786. NTSTATUS Status = STATUS_NOT_SUPPORTED;
  1787. D_DebugLog((DEB_TRACE_API,"SpDeleteCredentials Called\n"));
  1788. D_DebugLog((DEB_TRACE_API,"SpDeleteCredentials returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  1789. return(KerbMapKerbNtStatusToNtStatus(Status));
  1790. }