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

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