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.

1628 lines
57 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 2000
  6. //
  7. // File: credapi.cxx
  8. //
  9. // Contents: Code for credentials APIs for the NtDigest package
  10. // Main entry points into this dll:
  11. // SpAcceptCredentials
  12. // SpAcquireCredentialsHandle
  13. // SpFreeCredentialsHandle
  14. // SpQueryCredentialsAttributes
  15. // SpSaveCredentials
  16. // SpGetCredentials
  17. // SpDeleteCredentials
  18. //
  19. // Helper functions:
  20. // CopyClientString
  21. //
  22. // History: ChandanS 26-Jul-1996 Stolen from kerberos\client2\credapi.cxx
  23. // KDamour 16Mar00 Stolen from NTLM
  24. //
  25. //------------------------------------------------------------------------
  26. #define NTDIGEST_CREDAPI
  27. #include <global.h>
  28. extern BOOL g_bCredentialsInitialized;
  29. //+-------------------------------------------------------------------------
  30. //
  31. // Function: SpAcceptCredentials
  32. //
  33. // Synopsis: This routine is called after another package has logged
  34. // a user on. The other package provides a user name and
  35. // password and the package will create a logon
  36. // session for this user.
  37. //
  38. // Effects: Creates a logon session
  39. //
  40. // Arguments: LogonType - Type of logon, such as network or interactive
  41. // Accountname - Name of the account that logged on
  42. // PrimaryCredentials - Primary credentials for the account,
  43. // containing a domain name, password, SID, etc.
  44. // SupplementalCredentials - NtLm -Specific blob not used
  45. //
  46. // Returns: None
  47. //
  48. // Notes:
  49. //
  50. //-------------------------------------------------------------------------- ok
  51. NTSTATUS NTAPI
  52. SpAcceptCredentials(
  53. IN SECURITY_LOGON_TYPE LogonType,
  54. IN PUNICODE_STRING AccountName,
  55. IN PSECPKG_PRIMARY_CRED PrimaryCredentials,
  56. IN PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials
  57. )
  58. {
  59. NTSTATUS Status = STATUS_SUCCESS;
  60. PDIGEST_LOGONSESSION pNewLogonSession = NULL;
  61. UNICODE_STRING ustrTempPasswd;
  62. ZeroMemory(&ustrTempPasswd, sizeof(UNICODE_STRING));
  63. DebugLog((DEB_TRACE_FUNC, "SpAcceptCredentials: Entering\n"));
  64. DebugLog((DEB_TRACE, "SpAcceptCredentials: Credential: LogonType %d\n", LogonType));
  65. if (AccountName)
  66. {
  67. DebugLog((DEB_TRACE,"SpAcceptCredentials: Entering AccountName %wZ\n",
  68. AccountName));
  69. }
  70. else
  71. {
  72. DebugLog((DEB_TRACE,"SpAcceptCredentials: No AccountName provided\n"));
  73. }
  74. if (PrimaryCredentials)
  75. {
  76. DebugLog((DEB_TRACE,"SpAcceptCredentials: DomainName\\DownlevelName %wZ\\%wZ\n",
  77. &PrimaryCredentials->DomainName,
  78. &PrimaryCredentials->DownlevelName));
  79. DebugLog((DEB_TRACE,"SpAcceptCredentials: UPN@DnsDomainName %wZ@%wZ\n",
  80. &PrimaryCredentials->Upn,
  81. &PrimaryCredentials->DnsDomainName));
  82. DebugLog((DEB_TRACE,"SpAcceptCredentials: LogonID (%x:%lx) Flags 0x%x\n",
  83. PrimaryCredentials->LogonId.HighPart,
  84. PrimaryCredentials->LogonId.LowPart,
  85. PrimaryCredentials->Flags));
  86. }
  87. else
  88. {
  89. DebugLog((DEB_TRACE,"SpAcceptCredentials: No PrimaryCredentials provided\n"));
  90. goto CleanUp;
  91. }
  92. if (SupplementalCredentials)
  93. {
  94. DebugLog((DEB_TRACE,"SpAcceptCredentials: Supplemental Creds Size %d\n",
  95. SupplementalCredentials->CredentialSize));
  96. }
  97. else
  98. {
  99. DebugLog((DEB_TRACE,"SpAcceptCredentials: No Supplemental Credentials provided\n"));
  100. }
  101. // If there is no cleartext password then can not do any operations - just leave
  102. if (!(PrimaryCredentials->Flags & PRIMARY_CRED_CLEAR_PASSWORD))
  103. {
  104. DebugLog((DEB_TRACE,"SpAcceptCredentials: No Primary ClearText Password - no active logon created\n"));
  105. Status = STATUS_SUCCESS;
  106. goto CleanUp;
  107. }
  108. //
  109. // If this is an update, just change the password
  110. //
  111. if ((PrimaryCredentials->Flags & PRIMARY_CRED_UPDATE) != 0)
  112. {
  113. // Make a copy of the password and encrypt it
  114. Status = UnicodeStringDuplicatePassword(&ustrTempPasswd, &PrimaryCredentials->Password);
  115. if (!NT_SUCCESS(Status))
  116. {
  117. DebugLog((DEB_ERROR, "SpAcceptCredentials: Error in dup password, status 0x%0x\n", Status ));
  118. goto CleanUp;
  119. }
  120. if (ustrTempPasswd.MaximumLength != 0)
  121. {
  122. g_LsaFunctions->LsaProtectMemory(ustrTempPasswd.Buffer, (ULONG)(ustrTempPasswd.MaximumLength));
  123. }
  124. // Check to see if this LogonId is already in the list and update password
  125. Status = LogSessHandlerPasswdSet(&PrimaryCredentials->LogonId, &ustrTempPasswd);
  126. if (!NT_SUCCESS(Status))
  127. {
  128. DebugLog((DEB_ERROR, "SpAcceptCredentials: Failed to update LogonSession Password\n"));
  129. }
  130. else
  131. {
  132. DebugLog((DEB_TRACE, "SpAcceptCredentials: Updated Password for LogonSession\n"));
  133. }
  134. }
  135. else
  136. {
  137. DebugLog((DEB_TRACE, "SpAcceptCredentials: Create New LogonSession - not an update\n"));
  138. // This is a new entry into the list so create a LogonSession listing
  139. pNewLogonSession = (PDIGEST_LOGONSESSION)DigestAllocateMemory(sizeof(DIGEST_LOGONSESSION));
  140. if (!pNewLogonSession)
  141. {
  142. Status = SEC_E_INSUFFICIENT_MEMORY;
  143. DebugLog((DEB_ERROR, "SpAcceptCredentials: Could not allocate memory for logonsession, error 0x%x\n", Status));
  144. goto CleanUp;
  145. }
  146. LogonSessionInit(pNewLogonSession);
  147. pNewLogonSession->LogonType = LogonType;
  148. pNewLogonSession->LogonId = PrimaryCredentials->LogonId;
  149. UnicodeStringDuplicate(&(pNewLogonSession->ustrAccountName), AccountName);
  150. UnicodeStringDuplicate(&(pNewLogonSession->ustrDomainName), &(PrimaryCredentials->DomainName));
  151. UnicodeStringDuplicate(&(pNewLogonSession->ustrDownlevelName), &(PrimaryCredentials->DownlevelName));
  152. UnicodeStringDuplicate(&(pNewLogonSession->ustrDnsDomainName), &(PrimaryCredentials->DnsDomainName));
  153. UnicodeStringDuplicate(&(pNewLogonSession->ustrUpn), &(PrimaryCredentials->Upn));
  154. UnicodeStringDuplicate(&(pNewLogonSession->ustrLogonServer), &(PrimaryCredentials->LogonServer));
  155. Status = UnicodeStringDuplicatePassword(&(pNewLogonSession->ustrPassword), &(PrimaryCredentials->Password));
  156. if (!NT_SUCCESS(Status))
  157. {
  158. DebugLog((DEB_ERROR, "SpAcceptCredentials: Error in dup password, status 0x%0x\n", Status ));
  159. goto CleanUp;
  160. }
  161. if (pNewLogonSession->ustrPassword.MaximumLength != 0)
  162. {
  163. g_LsaFunctions->LsaProtectMemory(pNewLogonSession->ustrPassword.Buffer,
  164. (ULONG)(pNewLogonSession->ustrPassword.MaximumLength));
  165. }
  166. DebugLog((DEB_TRACE, "SpAcceptCredentials: Added new logonsession into list, handle 0x%x\n", pNewLogonSession));
  167. LogSessHandlerInsert(pNewLogonSession);
  168. pNewLogonSession = NULL; // Turned over memory to LogSessHandler
  169. }
  170. CleanUp:
  171. if (ustrTempPasswd.Buffer && ustrTempPasswd.MaximumLength)
  172. { // Zero out password info just to be safe
  173. ZeroMemory(ustrTempPasswd.Buffer, ustrTempPasswd.MaximumLength);
  174. }
  175. UnicodeStringFree(&ustrTempPasswd);
  176. DebugLog((DEB_TRACE_FUNC, "SpAcceptCredentials: Leaving status 0x%x\n", Status));
  177. return(Status);
  178. }
  179. //+-------------------------------------------------------------------------
  180. //
  181. // Function: SpAcquireCredentialsHandle
  182. //
  183. // Synopsis: Contains Digest Server Code for AcquireCredentialsHandle which
  184. // creates a Credential associated with a logon session.
  185. //
  186. // Effects: Creates a DIGEST_CREDENTIAL
  187. //
  188. // Arguments: PrincipalName - Name of logon session for which to create credential
  189. // CredentialUseFlags - Flags indicating whether the credentials
  190. // is for inbound or outbound use.
  191. // LogonId - The logon ID of logon session for which to create
  192. // a credential.
  193. // AuthorizationData - Optional username, domain, password info
  194. // GetKeyFunction - Unused function to retrieve a session key
  195. // GetKeyArgument - Unused Argument for GetKeyFunction
  196. // CredentialHandle - Receives handle to new credential
  197. // ExpirationTime - Receives expiration time for credential
  198. //
  199. // Returns:
  200. // STATUS_SUCCESS -- Call completed successfully
  201. // SEC_E_NO_SPM -- Security Support Provider is not running
  202. // SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
  203. // SEC_E_PRINCIPAL_UNKNOWN -- No such principal
  204. // SEC_E_NOT_OWNER -- caller does not own the specified credentials
  205. // SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
  206. // SEC_E_NOT_SUPPORTED - CredentialUse must be Outbound (Inbound once client code added)
  207. //
  208. // Notes:
  209. //
  210. //--------------------------------------------------------------------------
  211. NTSTATUS NTAPI
  212. SpAcquireCredentialsHandle(
  213. IN OPTIONAL PUNICODE_STRING pPrincipalName,
  214. IN ULONG CredentialUseFlags,
  215. IN OPTIONAL PLUID pLogonId,
  216. IN OPTIONAL PVOID pAuthorizationData,
  217. IN PVOID pGetKeyFunction,
  218. IN PVOID pGetKeyArgument,
  219. OUT PULONG_PTR ppCredentialHandle,
  220. OUT PTimeStamp pExpirationTime
  221. )
  222. {
  223. NTSTATUS Status = STATUS_SUCCESS;
  224. PDIGEST_CREDENTIAL pTmpCred = NULL;
  225. PDIGEST_CREDENTIAL pCredential = NULL;
  226. PDIGEST_LOGONSESSION pLogonSession = NULL;
  227. PDIGEST_CONTEXT pContext = NULL; // for delegation info lookup
  228. ULONG NewCredentialUseFlags = CredentialUseFlags;
  229. UNICODE_STRING AuthzUserName;
  230. UNICODE_STRING AuthzDomainName;
  231. UNICODE_STRING AuthzPassword;
  232. UNICODE_STRING ustrTempPasswd;
  233. SECPKG_CLIENT_INFO ClientInfo;
  234. SECPKG_CALL_INFO CallInfo;
  235. PLUID pLogonIdToUse = NULL;
  236. UNICODE_STRING CapturedPrincipalName = {0};
  237. ULONG CredentialFlags = 0;
  238. BOOL bAuthzDataProvided = FALSE;
  239. DebugLog((DEB_TRACE_FUNC, "SpAcquireCredentialsHandle: Entering\n"));
  240. // Initialize structures
  241. ZeroMemory(&AuthzUserName, sizeof(UNICODE_STRING));
  242. ZeroMemory(&AuthzDomainName, sizeof(UNICODE_STRING));
  243. ZeroMemory(&AuthzPassword, sizeof(UNICODE_STRING));
  244. ZeroMemory(&ustrTempPasswd, sizeof(UNICODE_STRING));
  245. if (!ppCredentialHandle)
  246. {
  247. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: Invalid arg to ACH (possible NULL pointer)\n"));
  248. return STATUS_INVALID_PARAMETER;
  249. }
  250. *ppCredentialHandle = NULL;
  251. if (pExpirationTime)
  252. {
  253. *pExpirationTime = g_TimeForever; // Never times out credential
  254. DebugLog((DEB_TRACE, "SpAcquireCredentialsHandle: Expiration TimeStamp high/low 0x%x/0x%x\n",
  255. pExpirationTime->HighPart, pExpirationTime->LowPart));
  256. }
  257. // This should really not happen - just a quick check
  258. ASSERT(g_bCredentialsInitialized);
  259. if (!g_bCredentialsInitialized)
  260. {
  261. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle credential manager not initialized\n"));
  262. return SEC_E_NO_SPM;
  263. }
  264. // Allow only INBOUND or OUTBOUND (not DEFAULT or Reserved)
  265. if ( (CredentialUseFlags & (DIGEST_CRED_OUTBOUND | DIGEST_CRED_INBOUND)) == 0)
  266. {
  267. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: Credential flag not supported\n"));
  268. Status = SEC_E_NOT_SUPPORTED;
  269. goto CleanUp;
  270. }
  271. //
  272. // First get information about the caller.
  273. //
  274. Status = g_LsaFunctions->GetClientInfo(&ClientInfo);
  275. if (!NT_SUCCESS(Status))
  276. {
  277. DebugLog((DEB_ERROR,"SpAcquireCredentialsHandle: Failed to get client information: 0x%x\n",Status));
  278. goto CleanUp;
  279. }
  280. Status = g_LsaFunctions->GetCallInfo(&CallInfo);
  281. if (!NT_SUCCESS(Status))
  282. {
  283. DebugLog((DEB_ERROR,"SpAcquireCredentialsHandle: Failed to get call information: 0x%x\n",Status));
  284. goto CleanUp;
  285. }
  286. // Check if acting as the server (Inbound creds)
  287. if (NewCredentialUseFlags & DIGEST_CRED_INBOUND)
  288. {
  289. DebugLog((DEB_TRACE, "SpAcquireCredentialsHandle: Creating an Inbound Credential\n"));
  290. // Allocate a credential block and initialize it.
  291. pTmpCred = (PDIGEST_CREDENTIAL)DigestAllocateMemory(sizeof(DIGEST_CREDENTIAL) );
  292. if (!pTmpCred)
  293. {
  294. Status = SEC_E_INSUFFICIENT_MEMORY; // Out of memory return error
  295. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle Out of Memory\n"));
  296. goto CleanUp;
  297. }
  298. Status = CredentialInit(pTmpCred);
  299. if (!NT_SUCCESS (Status))
  300. {
  301. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: CredentialInit error 0x%x\n", Status));
  302. goto CleanUp;
  303. }
  304. pTmpCred->CredentialUseFlags = NewCredentialUseFlags;
  305. memcpy(&(pTmpCred->LogonId), &ClientInfo.LogonId, sizeof(LUID));
  306. pTmpCred->ClientProcessID = ClientInfo.ProcessID;
  307. //
  308. // Add it to the list of valid credential handles.
  309. //
  310. pTmpCred->lReferences = 1;
  311. (void)CredPrint(pTmpCred);
  312. CredHandlerInsertCred(pTmpCred);
  313. *ppCredentialHandle = (LSA_SEC_HANDLE) pTmpCred; // link to the output
  314. DebugLog((DEB_TRACE, "SpAcquireCredentialsHandle: Added Credential 0x%lx\n", pCredential));
  315. pTmpCred = NULL; // We do not own this memory anymore
  316. }
  317. else
  318. { // Called by a client for Outbound direction
  319. // Locate the LogonSession to utilize for the credential
  320. // If the caller is a system process with the SE_TCB_NAME privilege, and the caller provides
  321. // both the name and logon identifier, the function verifies that they match before returning
  322. // the credentials. If only one is provided, the function returns a handle to that identifier.
  323. // A caller that is not a system process can only obtain a handle to the credentials under
  324. // which it is running. The caller can provide the name or the logon identifier, but it must
  325. // be for the current session or the request fails.
  326. DebugLog((DEB_TRACE,"SpAcquireCredentialsHandle: Have Outbound Credential request\n"));
  327. if (ARGUMENT_PRESENT(pLogonId) && ((pLogonId->LowPart != 0) || (pLogonId->HighPart != 0)))
  328. {
  329. // If the LUID of request not equal to Client LUID then must have TCBPrivilege, else rejest request
  330. if (((pLogonId->LowPart != ClientInfo.LogonId.LowPart) ||
  331. (pLogonId->HighPart != ClientInfo.LogonId.HighPart)) &&
  332. !ClientInfo.HasTcbPrivilege)
  333. {
  334. Status = STATUS_PRIVILEGE_NOT_HELD;
  335. DebugLog((DEB_ERROR,"SpAcquireCredentialsHandle: LoginID change forbidden\n"));
  336. goto CleanUp;
  337. }
  338. DebugLog((DEB_TRACE, "SpAcquireCredentialsHandle: Using pLogonID luid (%x:%lx)\n",
  339. pLogonId->HighPart, pLogonId->LowPart));
  340. Status = LogSessHandlerLogonIdToPtr(pLogonId, FALSE, &pLogonSession);
  341. if (!NT_SUCCESS (Status))
  342. { // Could not find the LogonID so fail
  343. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: could not find LogonID status 0x%x\n", Status));
  344. Status = STATUS_NO_SUCH_LOGON_SESSION;
  345. goto CleanUp;
  346. }
  347. pLogonIdToUse = pLogonId;
  348. // If Principal name supplied, make sure they match with the loginsession
  349. if (ARGUMENT_PRESENT(pPrincipalName) && pPrincipalName->Length)
  350. {
  351. if (!RtlEqualUnicodeString(pPrincipalName,&(pLogonSession->ustrAccountName),TRUE))
  352. {
  353. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: PrincipalName does not match LogonSession\n"));
  354. Status = STATUS_NO_SUCH_LOGON_SESSION;
  355. goto CleanUp;
  356. }
  357. }
  358. }
  359. else if (ARGUMENT_PRESENT(pPrincipalName) && (pPrincipalName->Length))
  360. {
  361. // Given only the principal name to lookup
  362. DebugLog((DEB_TRACE, "SpAcquireCredentialsHandle: logonsession principal name lookup %wZ\n", pPrincipalName));
  363. Status = LogSessHandlerAccNameToPtr(pPrincipalName, &pLogonSession);
  364. if (!NT_SUCCESS (Status))
  365. {
  366. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: principal name not in logon list error 0x%x\n", Status));
  367. Status = STATUS_NO_SUCH_LOGON_SESSION;
  368. goto CleanUp;
  369. }
  370. // If make sure we have TCB if logonID are different
  371. if ((((pLogonSession->LogonId).LowPart != ClientInfo.LogonId.LowPart) ||
  372. ((pLogonSession->LogonId).HighPart != ClientInfo.LogonId.HighPart)) &&
  373. !ClientInfo.HasTcbPrivilege)
  374. {
  375. Status = STATUS_PRIVILEGE_NOT_HELD;
  376. DebugLog((DEB_ERROR,"SpAcquireCredentialsHandle: PrincipalName selection forbidden, LoginID differs\n"));
  377. goto CleanUp;
  378. }
  379. // pLogonIdToUse = &ClientInfo.LogonId;
  380. pLogonIdToUse = &(pLogonSession->LogonId);
  381. }
  382. else
  383. {
  384. // No LoginID or Principal name provided
  385. // Use the callers logon id.
  386. DebugLog((DEB_TRACE, "SpAcquireCredentialsHandle: Using callers Logon (%x:%lx)\n",
  387. ClientInfo.LogonId.HighPart,
  388. ClientInfo.LogonId.LowPart));
  389. Status = LogSessHandlerLogonIdToPtr(&ClientInfo.LogonId, FALSE, &pLogonSession);
  390. if (!NT_SUCCESS (Status))
  391. {
  392. // Could not find the LogonID so fail
  393. Status = STATUS_NO_SUCH_LOGON_SESSION;
  394. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: could not find caller's LogonSession status 0x%x\n", Status));
  395. goto CleanUp;
  396. }
  397. pLogonIdToUse = &ClientInfo.LogonId;
  398. }
  399. // We now must have a pLogonSession - this conditional is not needed after testing completed
  400. if (!pLogonSession)
  401. {
  402. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: Must have LogonSession\n"));
  403. Status = STATUS_NO_SUCH_LOGON_SESSION;
  404. goto CleanUp;
  405. }
  406. if (pAuthorizationData)
  407. {
  408. Status = CredAuthzData(pAuthorizationData,
  409. &CallInfo,
  410. &NewCredentialUseFlags,
  411. &AuthzUserName,
  412. &AuthzDomainName,
  413. &AuthzPassword);
  414. if (!NT_SUCCESS(Status))
  415. {
  416. DebugLog((DEB_ERROR,"SpAcquireCredentialsHandle: CredAuthzData error in reading authdata status 0x%x\n", Status));
  417. }
  418. else
  419. bAuthzDataProvided = TRUE;
  420. DebugLog((DEB_TRACE,"SpAcquireCredentialsHandle: AuthData provided Username=%wZ DomainName=%wZ\n",
  421. &AuthzUserName, &AuthzDomainName));
  422. }
  423. DebugLog((DEB_TRACE, "SpAcquireCredentialsHandle: Using LogonSession Handle 0x%lx\n", pLogonSession));
  424. DebugLog((DEB_TRACE, "SpAcquireCredentialsHandle: Logon luid (%x:%lx)\n",
  425. (pLogonSession->LogonId).HighPart,
  426. (pLogonSession->LogonId).LowPart));
  427. if (!bAuthzDataProvided)
  428. { // If no authz data then see if it matches with a
  429. DebugLog((DEB_TRACE, "SpAcquireCredentialsHandle: Check to see if cred exists\n"));
  430. Status = CredHandlerLocatePtr(pLogonIdToUse, NewCredentialUseFlags, &pCredential);
  431. }
  432. else
  433. Status = SEC_E_NO_CREDENTIALS; // passed creds - need to create new context
  434. if (NT_SUCCESS(Status))
  435. {
  436. // We currently have a credential for this ProcessID, LogonId - just make any updates
  437. DebugLog((DEB_TRACE, "SpAcquireCredentialsHandle: We currently have existing Credentials at 0x%x\n", pCredential));
  438. Status = LogSessHandlerPasswdGet(pLogonSession, &(ustrTempPasswd));
  439. if (!NT_SUCCESS(Status))
  440. {
  441. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: Error LogSess get TempPasswd Status 0x%x\n", Status));
  442. goto CleanUp;
  443. }
  444. Status = CredHandlerPasswdSet(pCredential, &(ustrTempPasswd));
  445. if (!NT_SUCCESS(Status))
  446. {
  447. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: Errors in Passwd set Status 0x%x\n", Status));
  448. goto CleanUp;
  449. }
  450. *ppCredentialHandle = (LSA_SEC_HANDLE) pCredential; // link to the output
  451. pCredential = NULL; // Reference for this context owned by system
  452. }
  453. else
  454. {
  455. // We need to create a new Credential
  456. Status = STATUS_SUCCESS; // there is no error right now
  457. DebugLog((DEB_TRACE, "SpAcquireCredentialsHandle: Creating an Outbound Credential\n"));
  458. // Allocate a credential block and initialize it.
  459. pTmpCred = (PDIGEST_CREDENTIAL)DigestAllocateMemory(sizeof(DIGEST_CREDENTIAL) );
  460. if (!pTmpCred)
  461. {
  462. Status = SEC_E_INSUFFICIENT_MEMORY;
  463. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle Out of Memory\n"));
  464. goto CleanUp;
  465. }
  466. Status = CredentialInit(pTmpCred);
  467. if (!NT_SUCCESS (Status))
  468. {
  469. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: CredentialInit error 0x%x\n", Status));
  470. goto CleanUp;
  471. }
  472. pTmpCred->CredentialUseFlags = NewCredentialUseFlags;
  473. memcpy(&(pTmpCred->LogonId), &(pLogonSession->LogonId), sizeof(LUID));
  474. pTmpCred->ClientProcessID = ClientInfo.ProcessID;
  475. // Copy over the account & password info
  476. // Some of these might not be utilized in client - may remove as appropriate
  477. if (!bAuthzDataProvided)
  478. {
  479. Status = UnicodeStringDuplicate(&(pTmpCred->ustrAccountName), &(pLogonSession->ustrAccountName));
  480. if (pLogonSession->ustrDnsDomainName.Length)
  481. {
  482. Status = UnicodeStringDuplicate(&(pTmpCred->ustrDnsDomainName), &(pLogonSession->ustrDnsDomainName));
  483. }
  484. else
  485. { // No DNSDomainName filled in - use NT's DomainName
  486. Status = UnicodeStringDuplicate(&(pTmpCred->ustrDnsDomainName), &(pLogonSession->ustrDomainName));
  487. }
  488. Status = UnicodeStringDuplicate(&(pTmpCred->ustrDomainName), &(pLogonSession->ustrDomainName));
  489. Status = UnicodeStringDuplicate(&(pTmpCred->ustrDownlevelName), &(pLogonSession->ustrDownlevelName));
  490. Status = UnicodeStringDuplicate(&(pTmpCred->ustrLogonServer), &(pLogonSession->ustrLogonServer));
  491. Status = UnicodeStringDuplicate(&(pTmpCred->ustrUpn), &(pLogonSession->ustrUpn));
  492. Status = LogSessHandlerPasswdGet(pLogonSession, &(pTmpCred->ustrPassword));
  493. if (!NT_SUCCESS(Status))
  494. {
  495. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: Error LogSess get Passwd Status 0x%x\n", Status));
  496. goto CleanUp;
  497. }
  498. }
  499. else
  500. {
  501. // Force in the Authz creds provided
  502. Status = UnicodeStringDuplicate(&(pTmpCred->ustrAccountName), &AuthzUserName);
  503. Status = UnicodeStringDuplicate(&(pTmpCred->ustrDomainName), &AuthzDomainName);
  504. Status = UnicodeStringDuplicate(&(pTmpCred->ustrDnsDomainName), &AuthzDomainName);
  505. Status = UnicodeStringDuplicatePassword(&(pTmpCred->ustrPassword), &AuthzPassword);
  506. if (!NT_SUCCESS(Status))
  507. {
  508. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: Authz string copies error 0x%x\n", Status));
  509. goto CleanUp;
  510. }
  511. // Since Auth data is cleartext password MUST encrypt since always keep in encrypted format
  512. if (pTmpCred->ustrPassword.MaximumLength != 0)
  513. {
  514. g_LsaFunctions->LsaProtectMemory(pTmpCred->ustrPassword.Buffer,
  515. (ULONG)(pTmpCred->ustrPassword.MaximumLength));
  516. }
  517. }
  518. pTmpCred->lReferences = 1;
  519. (void)CredPrint(pTmpCred);
  520. // Add it to the list of valid credential handles.
  521. CredHandlerInsertCred(pTmpCred);
  522. *ppCredentialHandle = (LSA_SEC_HANDLE) pTmpCred; // link to the output
  523. pTmpCred = NULL; // We do not own this memory anymore
  524. // pLogonSession = NULL; // The Cred has ownership of ref count for logonsession
  525. DebugLog((DEB_TRACE, "SpAcquireCredentialsHandle: Added Credential 0x%lx\n", *ppCredentialHandle));
  526. }
  527. }
  528. CleanUp:
  529. UnicodeStringFree(&AuthzUserName);
  530. UnicodeStringFree(&AuthzDomainName);
  531. if (AuthzPassword.Buffer && AuthzPassword.MaximumLength)
  532. { // Zero out password info just to be safe
  533. ZeroMemory(AuthzPassword.Buffer, AuthzPassword.MaximumLength);
  534. }
  535. UnicodeStringFree(&AuthzPassword);
  536. if (ustrTempPasswd.Buffer && ustrTempPasswd.MaximumLength)
  537. { // Zero out password info just to be safe
  538. ZeroMemory(ustrTempPasswd.Buffer, ustrTempPasswd.MaximumLength);
  539. }
  540. UnicodeStringFree(&ustrTempPasswd);
  541. if (pTmpCred)
  542. {
  543. CredentialFree(pTmpCred);
  544. pTmpCred = NULL;
  545. }
  546. if (pLogonSession)
  547. {
  548. LogSessHandlerRelease(pLogonSession);
  549. }
  550. if (pCredential)
  551. {
  552. CredHandlerRelease(pCredential);
  553. }
  554. if (pContext)
  555. {
  556. CtxtHandlerRelease(pContext);
  557. }
  558. DebugLog((DEB_TRACE_FUNC, "SpAcquireCredentialsHandle: Leaving Status 0x%x\n", Status));
  559. return(Status);
  560. }
  561. //+-------------------------------------------------------------------------
  562. //
  563. // Function: SpFreeCredentialsHandle
  564. //
  565. // Synopsis: Frees a credential created by AcquireCredentialsHandle.
  566. //
  567. // Effects: Dereferences the credential in the global list..
  568. //
  569. // Arguments: CredentialHandle - Handle to the credential to free
  570. // (acquired through AcquireCredentialsHandle)
  571. //
  572. // Requires:
  573. //
  574. // Returns: STATUS_SUCCESS on success,
  575. // SEC_E_INVALID_HANDLE if the handle is not valid
  576. //
  577. // Notes:
  578. //
  579. //
  580. //--------------------------------------------------------------------------
  581. NTSTATUS NTAPI
  582. SpFreeCredentialsHandle(
  583. IN ULONG_PTR CredentialHandle
  584. )
  585. {
  586. NTSTATUS Status = STATUS_SUCCESS;
  587. PDIGEST_CREDENTIAL pDigestCred = NULL;
  588. DebugLog((DEB_TRACE_FUNC, "SpFreeCredentialsHandle: Entering Handle 0x%x\n", CredentialHandle));
  589. Status = CredHandlerHandleToPtr(CredentialHandle, TRUE, &pDigestCred); // unlink from list
  590. if (!NT_SUCCESS(Status))
  591. {
  592. Status = SEC_E_INVALID_HANDLE;
  593. DebugLog((DEB_ERROR, "SpFreeCredentialsHandle: Can not find ContextHandle in list Status 0x%x\n", Status));
  594. goto CleanUp;
  595. }
  596. // Now check if we should release the memory
  597. ASSERT(pDigestCred);
  598. DebugLog((DEB_TRACE, "SpFreeCredentialsHandle: FreeCredHandle 0x%x ReferenceCount is %d\n",
  599. pDigestCred, pDigestCred->lReferences));
  600. // Dereference the credential, it will also unlink from list if necessary
  601. Status = CredHandlerRelease(pDigestCred);
  602. if (!NT_SUCCESS(Status))
  603. {
  604. DebugLog((DEB_ERROR, "SpFreeCredentialsHandle: Error in Releasing Credential Status 0x%x\n", Status));
  605. }
  606. CleanUp:
  607. DebugLog((DEB_TRACE_FUNC, "SpFreeCredentialsHandle: Leaving Handle 0x%x Status 0x%x\n", CredentialHandle, Status));
  608. return(Status);
  609. }
  610. //+-------------------------------------------------------------------------
  611. //
  612. // Function: SpQueryCredentialsAttributes
  613. //
  614. // Synopsis: retrieves the attributes of a credential, such as the name associated with the credential.
  615. //
  616. // Effects: Dereferences the credential in the global list..
  617. //
  618. // Arguments: CredentialHandle - Handle of the credentials to be queried
  619. // CredentialAttribute - Specifies the attribute to query. This parameter can be any of the following attributes
  620. // SECPKG_CRED_ATTR_NAMES
  621. // SECPKG_ATTR_SUPPORTED_ALGS
  622. // SECPKG_ATTR_CIPHER_STRENGTHS
  623. // SECPKG_ATTR_SUPPORTED_PROTOCOLS
  624. // Buffer - Pointer to a buffer that receives the requested attribute
  625. //
  626. // Requires:
  627. //
  628. // Returns: STATUS_SUCCESS on success,
  629. // SEC_E_INVALID_HANDLE if the handle is not valid
  630. //
  631. // Notes:
  632. // The caller must allocate the structure pointed to by the pBuffer parameter.
  633. // The security package allocates the buffer for any pointer returned in the pBuffer structure
  634. // The caller can call the FreeContextBuffer function to free any pointers allocated by the security package.
  635. //
  636. //--------------------------------------------------------------------------
  637. NTSTATUS NTAPI
  638. SpQueryCredentialsAttributes(
  639. IN LSA_SEC_HANDLE CredentialHandle,
  640. IN ULONG CredentialAttribute,
  641. IN OUT PVOID Buffer
  642. )
  643. {
  644. NTSTATUS Status = STATUS_SUCCESS;
  645. NTSTATUS TempStatus = STATUS_SUCCESS;
  646. PDIGEST_CREDENTIAL pDigestCred = NULL;
  647. SECPKG_CALL_INFO CallInfo;
  648. SecPkgCredentials_NamesW Names;
  649. LPWSTR ContextNames = NULL;
  650. LPWSTR Where = NULL;
  651. DWORD cchUserName = 0;
  652. DWORD cchDomainName = 0;
  653. ULONG Length = 0;
  654. DebugLog((DEB_TRACE_FUNC, "SpQueryCredentialsAttributes: Entering Handle 0x%x\n", CredentialHandle));
  655. Names.sUserName = NULL;
  656. Status = g_LsaFunctions->GetCallInfo(&CallInfo);
  657. if (!NT_SUCCESS(Status))
  658. {
  659. DebugLog((DEB_ERROR,"SpQueryCredentialsAttributes: Failed to get call information: 0x%x\n",Status));
  660. goto CleanUp;
  661. }
  662. if (CredentialAttribute != SECPKG_CRED_ATTR_NAMES)
  663. {
  664. DebugLog((DEB_WARN, "SpQueryCredentialsAttributes: Invalid Request Attribute %d\n", CredentialAttribute));
  665. Status = SEC_E_UNSUPPORTED_FUNCTION;
  666. goto CleanUp;
  667. }
  668. Status = CredHandlerHandleToPtr(CredentialHandle, FALSE, &pDigestCred); // unlink from list
  669. if (!NT_SUCCESS(Status))
  670. {
  671. Status = SEC_E_INVALID_HANDLE;
  672. DebugLog((DEB_ERROR, "SpQueryCredentialsAttributes: Can not find ContextHandle in list Status 0x%x\n", Status));
  673. goto CleanUp;
  674. }
  675. //
  676. // specified creds.
  677. //
  678. Length = pDigestCred->ustrAccountName.Length + pDigestCred->ustrDomainName.Length + (2 * sizeof(WCHAR));
  679. ContextNames = (LPWSTR)DigestAllocateMemory( Length );
  680. if( ContextNames == NULL ) {
  681. Status = SEC_E_INSUFFICIENT_MEMORY;
  682. DebugLog((DEB_ERROR, "SpQueryCredentialsAttributes: Internal Allocate failed Status 0x%x\n", Status));
  683. goto CleanUp;
  684. }
  685. Where = ContextNames;
  686. if(pDigestCred->ustrDomainName.Length) {
  687. RtlCopyMemory( ContextNames, pDigestCred->ustrDomainName.Buffer, pDigestCred->ustrDomainName.Length);
  688. cchDomainName = pDigestCred->ustrDomainName.Length / sizeof(WCHAR);
  689. ContextNames[ cchDomainName ] = L'\\';
  690. Where += (cchDomainName+1);
  691. }
  692. if(pDigestCred->ustrAccountName.Length) {
  693. RtlCopyMemory( Where, pDigestCred->ustrAccountName.Buffer, pDigestCred->ustrAccountName.Length);
  694. }
  695. cchUserName = pDigestCred->ustrAccountName.Length / sizeof(WCHAR);
  696. Where[ cchUserName ] = L'\0';
  697. //
  698. // Allocate memory in the client's address space
  699. //
  700. Status = g_LsaFunctions->AllocateClientBuffer(
  701. NULL,
  702. Length,
  703. (PVOID *) &Names.sUserName
  704. );
  705. if (!NT_SUCCESS(Status))
  706. {
  707. DebugLog((DEB_ERROR, "SpQueryCredentialsAttributes: AllocateClientBuffer failed Status 0x%x\n", Status));
  708. goto CleanUp;
  709. }
  710. //
  711. // Copy the string there
  712. //
  713. Status = g_LsaFunctions->CopyToClientBuffer(
  714. NULL,
  715. Length,
  716. Names.sUserName,
  717. ContextNames
  718. );
  719. if (!NT_SUCCESS(Status))
  720. {
  721. DebugLog((DEB_ERROR, "SpQueryCredentialsAttributes: CopyToClientBuffer string failed Status 0x%x\n", Status));
  722. goto CleanUp;
  723. }
  724. //
  725. // Now copy the address of the string there
  726. //
  727. if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT )
  728. { // Write out only a 32bit value
  729. Status = g_LsaFunctions->CopyToClientBuffer(
  730. NULL,
  731. sizeof(ULONG),
  732. Buffer,
  733. &Names
  734. );
  735. }
  736. else
  737. {
  738. Status = g_LsaFunctions->CopyToClientBuffer(
  739. NULL,
  740. sizeof(Names),
  741. Buffer,
  742. &Names
  743. );
  744. }
  745. if (!NT_SUCCESS(Status))
  746. {
  747. DebugLog((DEB_ERROR, "SpQueryCredentialsAttributes: CopyToClientBuffer string address failed Status 0x%x\n", Status));
  748. goto CleanUp;
  749. }
  750. CleanUp:
  751. // Dereference the credential
  752. if (pDigestCred)
  753. {
  754. TempStatus = CredHandlerRelease(pDigestCred);
  755. if (!NT_SUCCESS(Status))
  756. {
  757. DebugLog((DEB_ERROR, "SpQueryCredentialsAttributes: Error in Releasing Credential Status 0x%x\n", TempStatus));
  758. }
  759. }
  760. if (!NT_SUCCESS(Status))
  761. {
  762. if (Names.sUserName != NULL)
  763. {
  764. (VOID) g_LsaFunctions->FreeClientBuffer(
  765. NULL,
  766. Names.sUserName
  767. );
  768. }
  769. Names.sUserName = NULL;
  770. }
  771. if( ContextNames ) {
  772. DigestFreeMemory( ContextNames );
  773. }
  774. DebugLog((DEB_TRACE_FUNC, "SpQueryCredentialsAttributes: Leaving Handle 0x%x Status 0x%x\n", CredentialHandle, Status));
  775. return(Status);
  776. }
  777. NTSTATUS NTAPI
  778. SpSaveCredentials(
  779. IN ULONG_PTR CredentialHandle,
  780. IN PSecBuffer Credentials
  781. )
  782. {
  783. UNREFERENCED_PARAMETER(CredentialHandle);
  784. UNREFERENCED_PARAMETER(Credentials);
  785. DebugLog((DEB_TRACE_FUNC, "SpSaveCredentials: Entering/Leaving\n"));
  786. return(SEC_E_UNSUPPORTED_FUNCTION);
  787. }
  788. NTSTATUS NTAPI
  789. SpGetCredentials(
  790. IN ULONG_PTR CredentialHandle,
  791. IN OUT PSecBuffer Credentials
  792. )
  793. {
  794. UNREFERENCED_PARAMETER(CredentialHandle);
  795. UNREFERENCED_PARAMETER(Credentials);
  796. DebugLog((DEB_TRACE_FUNC, "SpGetCredentials: Entering/Leaving\n"));
  797. return(SEC_E_UNSUPPORTED_FUNCTION);
  798. }
  799. // Function not implemented. ok
  800. NTSTATUS NTAPI
  801. SpDeleteCredentials(
  802. IN ULONG_PTR CredentialHandle,
  803. IN PSecBuffer Key
  804. )
  805. {
  806. UNREFERENCED_PARAMETER(Key);
  807. DebugLog((DEB_TRACE_FUNC, "SpDeleteCredentials: Entering/Leaving CredentialHandle 0x%x\n", CredentialHandle));
  808. return(SEC_E_UNSUPPORTED_FUNCTION);
  809. }
  810. /*++
  811. Routine Description:
  812. Duplicates a token
  813. Arguments:
  814. OriginalToken - Token to duplicate
  815. DuplicatedToken - Receives handle to duplicated token
  816. Return Value:
  817. Any error from NtDuplicateToken
  818. --*/
  819. SECURITY_STATUS
  820. SspDuplicateToken(
  821. IN HANDLE OriginalToken,
  822. IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
  823. OUT PHANDLE DuplicatedToken
  824. )
  825. {
  826. NTSTATUS Status;
  827. OBJECT_ATTRIBUTES ObjectAttributes;
  828. SECURITY_QUALITY_OF_SERVICE QualityOfService;
  829. InitializeObjectAttributes(
  830. &ObjectAttributes,
  831. NULL,
  832. 0,
  833. NULL,
  834. NULL
  835. );
  836. QualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  837. QualityOfService.EffectiveOnly = FALSE;
  838. QualityOfService.ContextTrackingMode = SECURITY_STATIC_TRACKING;
  839. QualityOfService.ImpersonationLevel = ImpersonationLevel;
  840. ObjectAttributes.SecurityQualityOfService = &QualityOfService;
  841. Status = NtDuplicateToken(
  842. OriginalToken,
  843. SSP_TOKEN_ACCESS,
  844. &ObjectAttributes,
  845. FALSE,
  846. TokenImpersonation,
  847. DuplicatedToken
  848. );
  849. return Status;
  850. }
  851. NTSTATUS
  852. SspGetToken (
  853. OUT PHANDLE ReturnedTokenHandle)
  854. {
  855. HANDLE TokenHandle = NULL;
  856. NTSTATUS Status = STATUS_SUCCESS;
  857. HANDLE TmpHandle = NULL;
  858. SECURITY_IMPERSONATION_LEVEL SecImpLevel = SecurityImpersonation;
  859. Status = g_LsaFunctions->ImpersonateClient();
  860. if (!NT_SUCCESS (Status))
  861. {
  862. goto CleanUp;
  863. }
  864. // get the token
  865. // note: there MUST be an impersonation token.
  866. // LsaFunctions->ImpersonateClient will call ImpersonateSelf() when necessary
  867. Status = NtOpenThreadToken(NtCurrentThread(),
  868. TOKEN_DUPLICATE |
  869. TOKEN_QUERY |
  870. WRITE_DAC,
  871. TRUE,
  872. &TokenHandle);
  873. if (!NT_SUCCESS (Status))
  874. {
  875. goto CleanUp;
  876. }
  877. Status = SspDuplicateToken(TokenHandle,
  878. SecImpLevel,
  879. &TmpHandle);
  880. if (!NT_SUCCESS (Status))
  881. {
  882. goto CleanUp;
  883. }
  884. CleanUp:
  885. if (ReturnedTokenHandle != NULL)
  886. {
  887. if (!NT_SUCCESS (Status))
  888. {
  889. *ReturnedTokenHandle = NULL;
  890. }
  891. else
  892. {
  893. *ReturnedTokenHandle = TmpHandle;
  894. TmpHandle = NULL;
  895. }
  896. }
  897. if (TokenHandle != NULL)
  898. {
  899. NtClose(TokenHandle);
  900. }
  901. if (TmpHandle != NULL)
  902. {
  903. NtClose(TmpHandle);
  904. }
  905. // ignore return value, we may not have impersonated successfully..
  906. RevertToSelf();
  907. return Status;
  908. }
  909. NTSTATUS
  910. CredPrint(PDIGEST_CREDENTIAL pCredential)
  911. {
  912. NTSTATUS Status = STATUS_SUCCESS;
  913. if (!pCredential)
  914. {
  915. return (STATUS_INVALID_PARAMETER);
  916. }
  917. DebugLog((DEB_TRACE, "CredPrint: Credential 0x%x \n", pCredential));
  918. if (pCredential->CredentialUseFlags & DIGEST_CRED_INBOUND)
  919. {
  920. DebugLog((DEB_TRACE, "CredPrint: INBOUND Session Credential \n"));
  921. }
  922. else
  923. {
  924. DebugLog((DEB_TRACE, "CredPrint: OUTBOUND Session Credential \n"));
  925. }
  926. DebugLog((DEB_TRACE, "CredPrint: AccountName %wZ \n", &(pCredential->ustrAccountName)));
  927. // DebugLog((DEB_TRACE, "CredPrint: Password %wZ \n", &(pCredential->ustrPassword)));
  928. DebugLog((DEB_TRACE, "CredPrint: DnsDomainName %wZ \n", &(pCredential->ustrDnsDomainName)));
  929. DebugLog((DEB_TRACE, "CredPrint: Upn %wZ \n", &(pCredential->ustrUpn)));
  930. DebugLog((DEB_TRACE, "CredPrint: DownlevelName %wZ \n", &(pCredential->ustrDownlevelName)));
  931. DebugLog((DEB_TRACE, "CredPrint: DomainName %wZ \n", &(pCredential->ustrDomainName)));
  932. DebugLog((DEB_TRACE, "CredPrint: LogonServer %wZ \n", &(pCredential->ustrLogonServer)));
  933. DebugLog((DEB_TRACE, "CredPrint: References %ld \n", pCredential->lReferences));
  934. return(Status);
  935. }
  936. //+-------------------------------------------------------------------------
  937. //
  938. // Function: CredAuthData
  939. //
  940. // Synopsis: Copy over supplied auth data.
  941. //
  942. // Effects: Fills in string values - calling function must free.
  943. //
  944. // Arguments:
  945. //
  946. // Requires:
  947. //
  948. // Returns: STATUS_SUCCESS on success,
  949. // SEC_E_INVALID_HANDLE if the handle is not valid
  950. //
  951. // Notes:
  952. //
  953. //
  954. //--------------------------------------------------------------------------
  955. NTSTATUS
  956. CredAuthzData(
  957. IN PVOID AuthorizationData,
  958. IN PSECPKG_CALL_INFO pCallInfo,
  959. IN OUT PULONG NewCredentialUseFlags,
  960. IN OUT PUNICODE_STRING pUserName,
  961. IN OUT PUNICODE_STRING pDomainName,
  962. IN OUT PUNICODE_STRING pPassword
  963. )
  964. {
  965. UNICODE_STRING UserName;
  966. UNICODE_STRING DomainName;
  967. UNICODE_STRING Password;
  968. PSEC_WINNT_AUTH_IDENTITY pAuthIdentity = NULL;
  969. BOOLEAN DoUnicode = TRUE;
  970. PSEC_WINNT_AUTH_IDENTITY_EXW pAuthIdentityEx = NULL;
  971. PSEC_WINNT_AUTH_IDENTITY_W TmpCredentials = NULL;
  972. ULONG CredSize = 0;
  973. ULONG Offset = 0;
  974. ULONG ulBuffSize = 0;
  975. SEC_WINNT_AUTH_IDENTITY32 Cred32 ;
  976. SEC_WINNT_AUTH_IDENTITY_EX32 CredEx32 ;
  977. NTSTATUS Status = STATUS_SUCCESS;
  978. //
  979. // Copy over the authorization data into out address
  980. // space and make a local copy of the strings.
  981. //
  982. DebugLog((DEB_TRACE_FUNC, "CredAuthzData: Entering\n"));
  983. RtlInitUnicodeString(&UserName, NULL);
  984. RtlInitUnicodeString(&DomainName, NULL);
  985. RtlInitUnicodeString(&Password, NULL);
  986. ZeroMemory(&Cred32, sizeof(SEC_WINNT_AUTH_IDENTITY32));
  987. ZeroMemory(&CredEx32, sizeof(SEC_WINNT_AUTH_IDENTITY_EX32));
  988. ASSERT(pCallInfo);
  989. if (AuthorizationData != NULL)
  990. {
  991. ulBuffSize = ((sizeof(SEC_WINNT_AUTH_IDENTITY_EXW) > sizeof(SEC_WINNT_AUTH_IDENTITY32)) ?
  992. sizeof(SEC_WINNT_AUTH_IDENTITY_EXW) : sizeof(SEC_WINNT_AUTH_IDENTITY32));
  993. pAuthIdentityEx = (PSEC_WINNT_AUTH_IDENTITY_EXW) DigestAllocateMemory(ulBuffSize);
  994. if (pAuthIdentityEx != NULL)
  995. {
  996. if ( pCallInfo->Attributes & SECPKG_CALL_WOWCLIENT )
  997. {
  998. Status = g_LsaFunctions->CopyFromClientBuffer(
  999. NULL,
  1000. sizeof( Cred32 ),
  1001. pAuthIdentityEx,
  1002. AuthorizationData );
  1003. if ( NT_SUCCESS( Status ) )
  1004. {
  1005. RtlCopyMemory( &Cred32, pAuthIdentityEx, sizeof( Cred32 ) );
  1006. }
  1007. }
  1008. else
  1009. {
  1010. Status = g_LsaFunctions->CopyFromClientBuffer(
  1011. NULL,
  1012. sizeof(SEC_WINNT_AUTH_IDENTITY),
  1013. pAuthIdentityEx,
  1014. AuthorizationData);
  1015. }
  1016. if (!NT_SUCCESS(Status))
  1017. {
  1018. DebugLog((DEB_ERROR, "CredAuthzData: Error from LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status));
  1019. goto CleanUp;
  1020. }
  1021. }
  1022. else
  1023. {
  1024. Status = STATUS_INSUFFICIENT_RESOURCES;
  1025. DebugLog((DEB_ERROR, "CredAuthzData: Error from Digest Allocate is 0x%lx\n", Status));
  1026. goto CleanUp;
  1027. }
  1028. //
  1029. // Check for the ex version
  1030. //
  1031. if (pAuthIdentityEx->Version == SEC_WINNT_AUTH_IDENTITY_VERSION)
  1032. {
  1033. //
  1034. // It's an EX structure.
  1035. //
  1036. if ( pCallInfo->Attributes & SECPKG_CALL_WOWCLIENT )
  1037. {
  1038. Status = g_LsaFunctions->CopyFromClientBuffer(
  1039. NULL,
  1040. sizeof( CredEx32 ),
  1041. &CredEx32,
  1042. AuthorizationData );
  1043. if ( NT_SUCCESS( Status ) )
  1044. {
  1045. pAuthIdentityEx->Version = CredEx32.Version ;
  1046. pAuthIdentityEx->Length = (CredEx32.Length < sizeof( SEC_WINNT_AUTH_IDENTITY_EX ) ?
  1047. sizeof( SEC_WINNT_AUTH_IDENTITY_EX ) : CredEx32.Length );
  1048. pAuthIdentityEx->User = (PWSTR) UlongToPtr( CredEx32.User );
  1049. pAuthIdentityEx->UserLength = CredEx32.UserLength ;
  1050. pAuthIdentityEx->Domain = (PWSTR) UlongToPtr( CredEx32.Domain );
  1051. pAuthIdentityEx->DomainLength = CredEx32.DomainLength ;
  1052. pAuthIdentityEx->Password = (PWSTR) UlongToPtr( CredEx32.Password );
  1053. pAuthIdentityEx->PasswordLength = CredEx32.PasswordLength ;
  1054. pAuthIdentityEx->Flags = CredEx32.Flags ;
  1055. pAuthIdentityEx->PackageList = (PWSTR) UlongToPtr( CredEx32.PackageList );
  1056. pAuthIdentityEx->PackageListLength = CredEx32.PackageListLength ;
  1057. }
  1058. }
  1059. else
  1060. {
  1061. Status = g_LsaFunctions->CopyFromClientBuffer(
  1062. NULL,
  1063. sizeof(SEC_WINNT_AUTH_IDENTITY_EXW),
  1064. pAuthIdentityEx,
  1065. AuthorizationData);
  1066. }
  1067. if (!NT_SUCCESS(Status))
  1068. {
  1069. DebugLog((DEB_ERROR, "CredAuthzData: Error from LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status));
  1070. goto CleanUp;
  1071. }
  1072. pAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY) &pAuthIdentityEx->User;
  1073. CredSize = pAuthIdentityEx->Length;
  1074. Offset = FIELD_OFFSET(SEC_WINNT_AUTH_IDENTITY_EXW, User);
  1075. }
  1076. else
  1077. {
  1078. pAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY_W) pAuthIdentityEx;
  1079. if ( pCallInfo->Attributes & SECPKG_CALL_WOWCLIENT )
  1080. {
  1081. pAuthIdentity->User = (PWSTR) UlongToPtr( Cred32.User );
  1082. pAuthIdentity->UserLength = Cred32.UserLength ;
  1083. pAuthIdentity->Domain = (PWSTR) UlongToPtr( Cred32.Domain );
  1084. pAuthIdentity->DomainLength = Cred32.DomainLength ;
  1085. pAuthIdentity->Password = (PWSTR) UlongToPtr( Cred32.Password );
  1086. pAuthIdentity->PasswordLength = Cred32.PasswordLength ;
  1087. pAuthIdentity->Flags = Cred32.Flags ;
  1088. }
  1089. CredSize = sizeof(SEC_WINNT_AUTH_IDENTITY_W);
  1090. }
  1091. if ((pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
  1092. {
  1093. DoUnicode = FALSE;
  1094. //
  1095. // Turn off the marshalled flag because we don't support marshalling
  1096. // with ansi.
  1097. //
  1098. pAuthIdentity->Flags &= ~SEC_WINNT_AUTH_IDENTITY_MARSHALLED;
  1099. }
  1100. else if ((pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) == 0)
  1101. {
  1102. Status = SEC_E_INVALID_TOKEN;
  1103. DebugLog((DEB_ERROR, "CredAuthzData: Error from pAuthIdentity->Flags is 0x%lx\n", pAuthIdentity->Flags));
  1104. goto CleanUp;
  1105. }
  1106. // This is the only place where we can figure out whether null
  1107. // session was requested
  1108. if ((pAuthIdentity->UserLength == 0) &&
  1109. (pAuthIdentity->DomainLength == 0) &&
  1110. (pAuthIdentity->PasswordLength == 0) &&
  1111. (pAuthIdentity->User != NULL) &&
  1112. (pAuthIdentity->Domain != NULL) &&
  1113. (pAuthIdentity->Password != NULL))
  1114. {
  1115. *NewCredentialUseFlags |= DIGEST_CRED_NULLSESSION;
  1116. }
  1117. //
  1118. // Copy over the strings
  1119. //
  1120. if( (pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_MARSHALLED) != 0 ) {
  1121. ULONG TmpCredentialSize;
  1122. ULONG_PTR EndOfCreds;
  1123. ULONG_PTR TmpUser;
  1124. ULONG_PTR TmpDomain;
  1125. ULONG_PTR TmpPassword;
  1126. if( pAuthIdentity->UserLength > UNLEN ||
  1127. pAuthIdentity->PasswordLength > PWLEN ||
  1128. pAuthIdentity->DomainLength > DNS_MAX_NAME_LENGTH ) {
  1129. DebugLog((DEB_ERROR, "CredAuthzData: Supplied credentials illegal length.\n"));
  1130. Status = STATUS_INVALID_PARAMETER;
  1131. goto CleanUp;
  1132. }
  1133. //
  1134. // The callers can set the length of field to n chars, but they
  1135. // will really occupy n+1 chars (null-terminator).
  1136. //
  1137. TmpCredentialSize = CredSize +
  1138. ( pAuthIdentity->UserLength +
  1139. pAuthIdentity->DomainLength +
  1140. pAuthIdentity->PasswordLength +
  1141. (((pAuthIdentity->User != NULL) ? 1 : 0) +
  1142. ((pAuthIdentity->Domain != NULL) ? 1 : 0) +
  1143. ((pAuthIdentity->Password != NULL) ? 1 : 0)) ) * sizeof(WCHAR);
  1144. EndOfCreds = (ULONG_PTR) AuthorizationData + TmpCredentialSize;
  1145. //
  1146. // Verify that all the offsets are valid and no overflow will happen
  1147. //
  1148. TmpUser = (ULONG_PTR) pAuthIdentity->User;
  1149. if ((TmpUser != NULL) &&
  1150. ( (TmpUser < (ULONG_PTR) AuthorizationData) ||
  1151. (TmpUser > EndOfCreds) ||
  1152. ((TmpUser + (pAuthIdentity->UserLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  1153. ((TmpUser + (pAuthIdentity->UserLength * sizeof(WCHAR))) < TmpUser)))
  1154. {
  1155. DebugLog((DEB_ERROR, "CredAuthzData: Username in supplied credentials has invalid pointer or length.\n"));
  1156. Status = STATUS_INVALID_PARAMETER;
  1157. goto CleanUp;
  1158. }
  1159. TmpDomain = (ULONG_PTR) pAuthIdentity->Domain;
  1160. if ((TmpDomain != NULL) &&
  1161. ( (TmpDomain < (ULONG_PTR) AuthorizationData) ||
  1162. (TmpDomain > EndOfCreds) ||
  1163. ((TmpDomain + (pAuthIdentity->DomainLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  1164. ((TmpDomain + (pAuthIdentity->DomainLength * sizeof(WCHAR))) < TmpDomain)))
  1165. {
  1166. DebugLog((DEB_ERROR, "CredAuthzData: Domainname in supplied credentials has invalid pointer or length.\n"));
  1167. Status = STATUS_INVALID_PARAMETER;
  1168. goto CleanUp;
  1169. }
  1170. TmpPassword = (ULONG_PTR) pAuthIdentity->Password;
  1171. if ((TmpPassword != NULL) &&
  1172. ( (TmpPassword < (ULONG_PTR) AuthorizationData) ||
  1173. (TmpPassword > EndOfCreds) ||
  1174. ((TmpPassword + (pAuthIdentity->PasswordLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  1175. ((TmpPassword + (pAuthIdentity->PasswordLength * sizeof(WCHAR))) < TmpPassword)))
  1176. {
  1177. DebugLog((DEB_ERROR, "CredAuthzData: Password in supplied credentials has invalid pointer or length.\n"));
  1178. Status = STATUS_INVALID_PARAMETER;
  1179. goto CleanUp;
  1180. }
  1181. //
  1182. // Allocate a chunk of memory for the credentials
  1183. //
  1184. TmpCredentials = (PSEC_WINNT_AUTH_IDENTITY_W) DigestAllocateMemory(TmpCredentialSize - Offset);
  1185. if (TmpCredentials == NULL)
  1186. {
  1187. Status = STATUS_INSUFFICIENT_RESOURCES;
  1188. goto CleanUp;
  1189. }
  1190. //
  1191. // Copy the credentials from the client
  1192. //
  1193. Status = g_LsaFunctions->CopyFromClientBuffer(
  1194. NULL,
  1195. TmpCredentialSize - Offset,
  1196. TmpCredentials,
  1197. (PUCHAR) AuthorizationData + Offset
  1198. );
  1199. if (!NT_SUCCESS(Status))
  1200. {
  1201. DebugLog((DEB_ERROR, "CredAuthzData: Failed to copy whole auth identity\n"));
  1202. goto CleanUp;
  1203. }
  1204. //
  1205. // Now convert all the offsets to pointers.
  1206. //
  1207. if (TmpCredentials->User != NULL)
  1208. {
  1209. USHORT cbUser;
  1210. TmpCredentials->User = (LPWSTR) RtlOffsetToPointer(
  1211. TmpCredentials->User,
  1212. (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset
  1213. );
  1214. ASSERT( (TmpCredentials->UserLength*sizeof(WCHAR)) <= 0xFFFF );
  1215. cbUser = (USHORT)(TmpCredentials->UserLength * sizeof(WCHAR));
  1216. UserName.Buffer = (PWSTR)DigestAllocateMemory( cbUser );
  1217. if (UserName.Buffer == NULL ) {
  1218. Status = STATUS_INSUFFICIENT_RESOURCES;
  1219. goto CleanUp;
  1220. }
  1221. CopyMemory( UserName.Buffer, TmpCredentials->User, cbUser );
  1222. UserName.Length = cbUser;
  1223. UserName.MaximumLength = cbUser;
  1224. }
  1225. if (TmpCredentials->Domain != NULL)
  1226. {
  1227. USHORT cbDomain;
  1228. TmpCredentials->Domain = (LPWSTR) RtlOffsetToPointer(
  1229. TmpCredentials->Domain,
  1230. (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset
  1231. );
  1232. ASSERT( (TmpCredentials->DomainLength*sizeof(WCHAR)) <= 0xFFFF );
  1233. cbDomain = (USHORT)(TmpCredentials->DomainLength * sizeof(WCHAR));
  1234. DomainName.Buffer = (PWSTR)DigestAllocateMemory( cbDomain );
  1235. if (DomainName.Buffer == NULL ) {
  1236. Status = STATUS_INSUFFICIENT_RESOURCES;
  1237. goto CleanUp;
  1238. }
  1239. CopyMemory( DomainName.Buffer, TmpCredentials->Domain, cbDomain );
  1240. DomainName.Length = cbDomain;
  1241. DomainName.MaximumLength = cbDomain;
  1242. }
  1243. if (TmpCredentials->Password != NULL)
  1244. {
  1245. USHORT cbPassword;
  1246. TmpCredentials->Password = (LPWSTR) RtlOffsetToPointer(
  1247. TmpCredentials->Password,
  1248. (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset
  1249. );
  1250. ASSERT( (TmpCredentials->PasswordLength*sizeof(WCHAR)) <= 0xFFFF );
  1251. cbPassword = (USHORT)(TmpCredentials->PasswordLength * sizeof(WCHAR));
  1252. Password.Buffer = (PWSTR)DigestAllocateMemory( cbPassword );
  1253. if (Password.Buffer == NULL ) {
  1254. ZeroMemory( TmpCredentials->Password, cbPassword );
  1255. Status = STATUS_INSUFFICIENT_RESOURCES;
  1256. goto CleanUp;
  1257. }
  1258. CopyMemory( Password.Buffer, TmpCredentials->Password, cbPassword );
  1259. Password.Length = cbPassword;
  1260. Password.MaximumLength = cbPassword;
  1261. ZeroMemory( TmpCredentials->Password, cbPassword );
  1262. }
  1263. } else {
  1264. if (pAuthIdentity->Password != NULL)
  1265. {
  1266. Status = CopyClientString(
  1267. pAuthIdentity->Password,
  1268. pAuthIdentity->PasswordLength,
  1269. DoUnicode,
  1270. &Password
  1271. );
  1272. if (!NT_SUCCESS(Status))
  1273. {
  1274. DebugLog((DEB_ERROR, "CredAuthzData: Error from CopyClientString is 0x%lx\n", Status));
  1275. goto CleanUp;
  1276. }
  1277. }
  1278. if (pAuthIdentity->User != NULL)
  1279. {
  1280. Status = CopyClientString(
  1281. pAuthIdentity->User,
  1282. pAuthIdentity->UserLength,
  1283. DoUnicode,
  1284. &UserName
  1285. );
  1286. if (!NT_SUCCESS(Status))
  1287. {
  1288. DebugLog((DEB_ERROR, "CredAuthzData: Error from CopyClientString is 0x%lx\n", Status));
  1289. goto CleanUp;
  1290. }
  1291. }
  1292. if (pAuthIdentity->Domain != NULL)
  1293. {
  1294. Status = CopyClientString(
  1295. pAuthIdentity->Domain,
  1296. pAuthIdentity->DomainLength,
  1297. DoUnicode,
  1298. &DomainName
  1299. );
  1300. if (!NT_SUCCESS(Status))
  1301. {
  1302. DebugLog((DEB_ERROR, "CredAuthzData: Error from CopyClientString is 0x%lx\n", Status));
  1303. goto CleanUp;
  1304. }
  1305. //
  1306. // Make sure that the domain name length is not greater
  1307. // than the allowed dns domain name
  1308. //
  1309. if (DomainName.Length > DNS_MAX_NAME_LENGTH * sizeof(WCHAR))
  1310. {
  1311. DebugLog((DEB_ERROR, "CredAuthzData: Invalid supplied domain name %wZ\n",
  1312. &DomainName ));
  1313. Status = SEC_E_UNKNOWN_CREDENTIALS;
  1314. goto CleanUp;
  1315. }
  1316. }
  1317. }
  1318. } // AuthorizationData != NULL
  1319. pUserName->Buffer = UserName.Buffer;
  1320. pUserName->Length = UserName.Length;
  1321. pUserName->MaximumLength = UserName.MaximumLength;
  1322. UserName.Buffer = NULL; // give memory to calling process
  1323. pDomainName->Buffer = DomainName.Buffer;
  1324. pDomainName->Length = DomainName.Length;
  1325. pDomainName->MaximumLength = DomainName.MaximumLength;
  1326. DomainName.Buffer = NULL; // give memory to calling process
  1327. pPassword->Buffer = Password.Buffer;
  1328. pPassword->Length = Password.Length;
  1329. pPassword->MaximumLength = Password.MaximumLength;
  1330. Password.Buffer = NULL; // give memory to calling process
  1331. CleanUp:
  1332. if (pAuthIdentityEx != NULL)
  1333. {
  1334. DigestFreeMemory(pAuthIdentityEx);
  1335. }
  1336. if (TmpCredentials != NULL)
  1337. {
  1338. DigestFreeMemory(TmpCredentials);
  1339. }
  1340. if (DomainName.Buffer != NULL)
  1341. {
  1342. DigestFreeMemory(DomainName.Buffer);
  1343. }
  1344. if (UserName.Buffer != NULL)
  1345. {
  1346. DigestFreeMemory(UserName.Buffer);
  1347. }
  1348. if (Password.Buffer != NULL)
  1349. {
  1350. ZeroMemory(Password.Buffer, Password.Length);
  1351. DigestFreeMemory(Password.Buffer);
  1352. }
  1353. DebugLog((DEB_TRACE_FUNC, "CredAuthzData: Leaving Status 0x%x\n", Status));
  1354. return (Status);
  1355. }