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.

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