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.

2119 lines
55 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: lsa.cxx
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions: None.
  13. //
  14. // History: 15-May-96 MarkBl Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include "..\pch\headers.hxx"
  18. #pragma hdrstop
  19. #include <ntsecapi.h>
  20. #include <mstask.h>
  21. #include <msterr.h>
  22. #include "lsa.hxx"
  23. #include "debug.hxx"
  24. BYTE grgbDeletedEntryMarker[] =
  25. { 'D', 'E', 'L', 'E', 'T', 'E', 'D', '_', 'E', 'N', 'T', 'R', 'Y' };
  26. static WCHAR gwszSAI[] = L"SAI";
  27. static WCHAR gwszSAC[] = L"SAC";
  28. //+---------------------------------------------------------------------------
  29. //
  30. // Function: ReadSecurityDBase
  31. //
  32. // Synopsis:
  33. //
  34. // Arguments: [pcbSAI] --
  35. // [ppbSAI] --
  36. // [pcbSAC] --
  37. // [ppbSAC] --
  38. //
  39. // Notes: None.
  40. //
  41. //----------------------------------------------------------------------------
  42. HRESULT
  43. ReadSecurityDBase(
  44. DWORD * pcbSAI,
  45. BYTE ** ppbSAI,
  46. DWORD * pcbSAC,
  47. BYTE ** ppbSAC)
  48. {
  49. HRESULT hr;
  50. *ppbSAI = *ppbSAC = NULL;
  51. // Read the SAC.
  52. //
  53. hr = ReadLsaData(sizeof(gwszSAC), gwszSAC, pcbSAC, ppbSAC);
  54. if (SUCCEEDED(hr))
  55. {
  56. // Read the SAI.
  57. //
  58. hr = ReadLsaData(sizeof(gwszSAI), gwszSAI, pcbSAI, ppbSAI);
  59. }
  60. if (SUCCEEDED(hr))
  61. {
  62. //
  63. // Check the sizes. For sizes greater than zero, but less than the
  64. // header size, deallocate the memory and zero the returned sizes,
  65. // ptrs.
  66. //
  67. // This seems inefficient, but it saves quite a few checks in the
  68. // SAC/SAI API.
  69. //
  70. if (*pcbSAI && *pcbSAI <= SAI_HEADER_SIZE)
  71. {
  72. *pcbSAI = 0;
  73. LocalFree(*ppbSAI);
  74. *ppbSAI = NULL;
  75. }
  76. if (*pcbSAC && *pcbSAC <= SAC_HEADER_SIZE)
  77. {
  78. *pcbSAC = 0;
  79. LocalFree(*ppbSAC);
  80. *ppbSAC = NULL;
  81. }
  82. //
  83. // Ensure the databases are in sync. The first DWORD is a USN (Update
  84. // Sequence Number). Its value increases monotonically for every
  85. // write to the LSA. The SAI & SAC USN values must be equal. If not,
  86. // they are out of sync with each other - an unrecoverable problem.
  87. // Also check the SAI SetArrayCount vs. the SAC CredentialCount as
  88. // these values must also be equal or the they are out of sync.
  89. //
  90. if (((*ppbSAI != NULL && *ppbSAC == NULL) ||
  91. (*ppbSAI == NULL && *ppbSAC != NULL)) ||
  92. (*ppbSAI != NULL && *ppbSAC != NULL &&
  93. ((DWORD)**ppbSAI != (DWORD)**ppbSAC || (DWORD)*(*ppbSAI + USN_SIZE) != (DWORD)*(*ppbSAC + USN_SIZE))
  94. )
  95. )
  96. {
  97. schAssert(0 && "Scheduling Agent security database out of sync!");
  98. hr = SCHED_E_ACCOUNT_DBASE_CORRUPT;
  99. }
  100. }
  101. if (FAILED(hr))
  102. {
  103. if (*ppbSAI != NULL) LocalFree(*ppbSAI);
  104. if (*ppbSAC != NULL) LocalFree(*ppbSAC);
  105. *ppbSAI = *ppbSAC = NULL;
  106. }
  107. return(hr);
  108. }
  109. //+---------------------------------------------------------------------------
  110. //
  111. // Function: WriteSecurityDBase
  112. //
  113. // Synopsis:
  114. //
  115. // Arguments: [cbSAI] --
  116. // [pbSAI] --
  117. // [cbSAC] --
  118. // [pbSAC] --
  119. //
  120. // Notes: None.
  121. //
  122. //----------------------------------------------------------------------------
  123. HRESULT
  124. WriteSecurityDBase(
  125. DWORD cbSAI,
  126. BYTE * pbSAI,
  127. DWORD cbSAC,
  128. BYTE * pbSAC)
  129. {
  130. HRESULT hr;
  131. //
  132. // Just in case...
  133. //
  134. if (!pbSAI || !pbSAC)
  135. {
  136. schAssert(0 && "NULL pointers passed to WriteSecurityDBase!");
  137. return(E_FAIL);
  138. }
  139. //
  140. // If the secrets are out-of-sync, don't write them -- this will help preserve the integrity of the db.
  141. // Assert on checked builds so we know there still is a problem that leads to out-of-sync condition.
  142. //
  143. if ((DWORD)*(pbSAI + USN_SIZE) != (DWORD)*(pbSAC + USN_SIZE))
  144. {
  145. schAssert(0 && "Scheduling Agent security database SetArrayCount and CredentialCount out of sync!");
  146. return(E_FAIL);
  147. }
  148. // read the previous SAI so that we can put it back in case of failure
  149. DWORD cbSAIold;
  150. BYTE* pbSAIold = NULL;
  151. hr = ReadLsaData(sizeof(gwszSAI), gwszSAI, &cbSAIold, &pbSAIold);
  152. if (FAILED(hr))
  153. return hr;
  154. //
  155. // Advance the USN (Update Sequence Numbers) on the SAI & SAC. They
  156. // should always remain equal. Otherwise, they'll be out of sync
  157. // with each other - an unrecoverable problem.
  158. //
  159. (DWORD)(*pbSAI)++;
  160. (DWORD)(*pbSAC)++;
  161. // Write the SAI.
  162. //
  163. hr = WriteLsaData(sizeof(gwszSAI), gwszSAI, cbSAI, pbSAI);
  164. if (SUCCEEDED(hr))
  165. {
  166. // Write the SAC.
  167. //
  168. hr = WriteLsaData(sizeof(gwszSAC), gwszSAC, cbSAC, pbSAC);
  169. // attempt to put it back in case of failure.
  170. // if this fails, there's not much we can do; the db is invalid either way
  171. // if it succeeds, then we've got a good db again
  172. // even though this *function* has failed to record the updated db
  173. if (FAILED(hr))
  174. WriteLsaData(sizeof(gwszSAI), gwszSAI, cbSAIold, pbSAIold);
  175. }
  176. if (pbSAIold)
  177. LocalFree(pbSAIold);
  178. return(hr);
  179. }
  180. //+---------------------------------------------------------------------------
  181. //
  182. // Function: ReadLsaData
  183. //
  184. // Synopsis:
  185. //
  186. // Arguments: [cbKey] --
  187. // [pwszKey] --
  188. // [pcbData] --
  189. // [ppbData] --
  190. //
  191. // Notes: None.
  192. //
  193. //----------------------------------------------------------------------------
  194. HRESULT
  195. ReadLsaData(WORD cbKey, LPCWSTR pwszKey, DWORD * pcbData, BYTE ** ppbData)
  196. {
  197. LSA_OBJECT_ATTRIBUTES ObjectAttributes = {
  198. sizeof(LSA_OBJECT_ATTRIBUTES),
  199. NULL,
  200. NULL,
  201. 0L,
  202. NULL,
  203. NULL
  204. };
  205. HANDLE hPolicy = NULL;
  206. LSA_UNICODE_STRING sKey;
  207. PLSA_UNICODE_STRING psData;
  208. NTSTATUS Status;
  209. //
  210. // UNICODE_STRING length fields are in bytes and include the NULL
  211. // terminator
  212. //
  213. sKey.Length = cbKey;
  214. sKey.MaximumLength = cbKey;
  215. sKey.Buffer = (LPWSTR)pwszKey;
  216. //
  217. // Open the LSA.
  218. //
  219. Status = LsaOpenPolicy(NULL,
  220. &ObjectAttributes,
  221. POLICY_GET_PRIVATE_INFORMATION,
  222. &hPolicy);
  223. if (!(Status >= 0))
  224. {
  225. return(E_FAIL);
  226. }
  227. //
  228. // Retrieve the LSA data associated with the key passed.
  229. //
  230. Status = LsaRetrievePrivateData(hPolicy, &sKey, &psData);
  231. if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
  232. (Status >= 0 && psData == NULL))
  233. {
  234. LsaClose(hPolicy);
  235. *pcbData = 0;
  236. *ppbData = NULL;
  237. return(S_FALSE);
  238. }
  239. else if (!(Status >= 0))
  240. {
  241. LsaClose(hPolicy);
  242. return(E_FAIL);
  243. }
  244. LsaClose(hPolicy);
  245. //
  246. // Create a copy of the LSA data to return. Why? The LSA private data
  247. // is callee allocated, so we are not free to reallocate the memory
  248. // as-needed.
  249. //
  250. BYTE * pbData = (BYTE *)LocalAlloc(LMEM_FIXED, psData->Length);
  251. if (pbData == NULL)
  252. {
  253. LsaFreeMemory(psData);
  254. return(E_OUTOFMEMORY);
  255. }
  256. HRESULT hr = S_OK;
  257. //
  258. // Wrapping in a try/except in case the data read from the LSA is bad.
  259. //
  260. __try
  261. {
  262. CopyMemory(pbData, psData->Buffer, psData->Length);
  263. //
  264. // Update out ptrs.
  265. //
  266. // NB : Making the assignment in here to save on an rc check.
  267. //
  268. *pcbData = psData->Length;
  269. *ppbData = pbData;
  270. }
  271. __except(EXCEPTION_EXECUTE_HANDLER)
  272. {
  273. schAssert(0 &&
  274. "Exception reading Scheduling Agent security database!");
  275. hr = SCHED_E_ACCOUNT_DBASE_CORRUPT;
  276. }
  277. LsaFreeMemory(psData);
  278. return(hr);
  279. }
  280. //+---------------------------------------------------------------------------
  281. //
  282. // Function: WriteLsaData
  283. //
  284. // Synopsis:
  285. //
  286. // Arguments: [cbKey] --
  287. // [pwszKey] --
  288. // [cbData] --
  289. // [pbData] --
  290. //
  291. // Notes: None.
  292. //
  293. //----------------------------------------------------------------------------
  294. HRESULT
  295. WriteLsaData(WORD cbKey, LPCWSTR pwszKey, DWORD cbData, BYTE * pbData)
  296. {
  297. LSA_OBJECT_ATTRIBUTES ObjectAttributes = {
  298. sizeof(LSA_OBJECT_ATTRIBUTES),
  299. NULL,
  300. NULL,
  301. 0L,
  302. NULL,
  303. NULL
  304. };
  305. HANDLE hPolicy = NULL;
  306. LSA_UNICODE_STRING sKey;
  307. LSA_UNICODE_STRING sData;
  308. NTSTATUS Status;
  309. //
  310. // UNICODE_STRING length fields are in bytes and include the NULL
  311. // terminator
  312. //
  313. sKey.Length = cbKey;
  314. sKey.MaximumLength = cbKey;
  315. sKey.Buffer = (LPWSTR)pwszKey;
  316. sData.Length = (WORD)cbData;
  317. sData.MaximumLength = (WORD)cbData;
  318. sData.Buffer = (WCHAR *)pbData;
  319. //
  320. // Open the LSA.
  321. //
  322. Status = LsaOpenPolicy(NULL,
  323. &ObjectAttributes,
  324. POLICY_CREATE_SECRET,
  325. &hPolicy);
  326. if (!(Status >= 0))
  327. {
  328. return(E_FAIL);
  329. }
  330. //
  331. // Write the LSA data associated with the key passed.
  332. //
  333. Status = LsaStorePrivateData(hPolicy, &sKey, &sData);
  334. if (!(Status >= 0))
  335. {
  336. LsaClose(hPolicy);
  337. return(E_FAIL);
  338. }
  339. LsaClose(hPolicy);
  340. return(S_OK);
  341. }
  342. //+---------------------------------------------------------------------------
  343. //
  344. // Function: DeleteLsaData
  345. //
  346. // Synopsis:
  347. //
  348. // Arguments: [cbKey] --
  349. // [pwszKey] --
  350. //
  351. //----------------------------------------------------------------------------
  352. HRESULT
  353. DeleteLsaData(WORD cbKey, LPCWSTR pwszKey)
  354. {
  355. LSA_OBJECT_ATTRIBUTES ObjectAttributes = {
  356. sizeof(LSA_OBJECT_ATTRIBUTES),
  357. NULL,
  358. NULL,
  359. 0L,
  360. NULL,
  361. NULL
  362. };
  363. HANDLE hPolicy = NULL;
  364. LSA_UNICODE_STRING sKey;
  365. NTSTATUS Status;
  366. //
  367. // UNICODE_STRING length fields are in bytes and include the NULL
  368. // terminator
  369. //
  370. sKey.Length = cbKey;
  371. sKey.MaximumLength = cbKey;
  372. sKey.Buffer = (LPWSTR)pwszKey;
  373. //
  374. // Open the LSA.
  375. //
  376. Status = LsaOpenPolicy(NULL,
  377. &ObjectAttributes,
  378. POLICY_CREATE_SECRET,
  379. &hPolicy);
  380. if (!(Status >= 0))
  381. {
  382. return(E_FAIL);
  383. }
  384. //
  385. // Specifying NULL as the data causes LSA to delete the secret for that key
  386. //
  387. Status = LsaStorePrivateData(hPolicy, &sKey, NULL);
  388. if (!(Status >= 0))
  389. {
  390. LsaClose(hPolicy);
  391. return(E_FAIL);
  392. }
  393. LsaClose(hPolicy);
  394. return(S_OK);
  395. }
  396. //+---------------------------------------------------------------------------
  397. //
  398. // Function: SACAddCredential
  399. //
  400. // Synopsis:
  401. //
  402. // Arguments: [pbCredentialIdentity] --
  403. // [cbCredential] --
  404. // [pbCredential] --
  405. // [pcbSAC] --
  406. // [ppbSAC] --
  407. //
  408. // Notes: try/except unnecessary here. Memory writes are guaranteed to
  409. // remain within the buffer allocated.
  410. //
  411. //----------------------------------------------------------------------------
  412. HRESULT
  413. SACAddCredential(
  414. BYTE * pbCredentialIdentity,
  415. DWORD cbEncryptedData,
  416. BYTE * pbEncryptedData,
  417. DWORD * pcbSAC,
  418. BYTE ** ppbSAC)
  419. {
  420. DWORD dwCredentialCount = 1;
  421. DWORD cbCredentialSize = HASH_DATA_SIZE + cbEncryptedData;
  422. //
  423. // Make room for the new credential.
  424. //
  425. DWORD cbSACNew;
  426. BYTE * pbSACNew;
  427. cbSACNew = *pcbSAC + sizeof(cbCredentialSize) + cbCredentialSize;
  428. //
  429. // Check for maximum size. The LSA handles at most 64K.
  430. //
  431. if (cbSACNew > MAX_SECRET_SIZE)
  432. {
  433. // BUGBUG : Create a new error code for this error, something like
  434. // SCHED_E_CRED_LIMIT_EXCEEDED: "The system limit on the storage space
  435. // for task account information has been reached."
  436. return(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
  437. }
  438. if (*pcbSAC == 0)
  439. {
  440. cbSACNew += SAC_HEADER_SIZE;
  441. pbSACNew = (BYTE *)LocalAlloc(LMEM_FIXED, cbSACNew);
  442. if (pbSACNew == NULL)
  443. {
  444. return(E_OUTOFMEMORY);
  445. }
  446. //
  447. // Zero out the header.
  448. //
  449. SecureZeroMemory(pbSACNew, SAC_HEADER_SIZE);
  450. }
  451. else
  452. {
  453. pbSACNew = (BYTE *)LocalReAlloc(*ppbSAC, cbSACNew, LMEM_MOVEABLE);
  454. if (pbSACNew == NULL)
  455. {
  456. return(E_OUTOFMEMORY);
  457. }
  458. }
  459. //
  460. // Adjust total credential count & prepare to write the credential.
  461. //
  462. BYTE * pbCredentialSizePos;
  463. if (*pcbSAC == 0)
  464. {
  465. //
  466. // First entry.
  467. // - Write entry after header.
  468. // - Initialize credential count to one (in declaration above).
  469. //
  470. pbCredentialSizePos = pbSACNew + SAC_HEADER_SIZE;
  471. }
  472. else
  473. {
  474. //
  475. // Append entry.
  476. // - Append after last credential entry.
  477. // - Increase credential count by one.
  478. //
  479. pbCredentialSizePos = pbSACNew + *pcbSAC;
  480. CopyMemory(&dwCredentialCount, pbSACNew + USN_SIZE,
  481. sizeof(dwCredentialCount));
  482. dwCredentialCount++;
  483. }
  484. BYTE * pbCredentialIdentityPos;
  485. pbCredentialIdentityPos = pbCredentialSizePos + sizeof(cbCredentialSize);
  486. //
  487. // Update total credential count.
  488. //
  489. CopyMemory(pbSACNew + USN_SIZE, &dwCredentialCount,
  490. sizeof(dwCredentialCount));
  491. // Write total credential size, excluding the size value itself.
  492. //
  493. CopyMemory(pbCredentialSizePos, &cbCredentialSize,
  494. sizeof(cbCredentialSize));
  495. // Write credential identity.
  496. //
  497. CopyMemory(pbCredentialIdentityPos, pbCredentialIdentity,
  498. HASH_DATA_SIZE);
  499. // Finally, write encrypted credentials.
  500. //
  501. CopyMemory(pbCredentialIdentityPos + HASH_DATA_SIZE, pbEncryptedData,
  502. cbEncryptedData);
  503. // Update out pointers.
  504. //
  505. *pcbSAC = cbSACNew;
  506. *ppbSAC = pbSACNew;
  507. return(S_OK);
  508. }
  509. //+---------------------------------------------------------------------------
  510. //
  511. // Function: SACIndexCredential
  512. //
  513. // Synopsis:
  514. //
  515. // Arguments: [dwCredentialIndex] --
  516. // [cbSAC] --
  517. // [pbSAC] --
  518. // [pcbCredential] --
  519. // [ppbFoundCredential] --
  520. //
  521. // Notes: try/except unnecesssary here as checks exist to ensure we
  522. // remain within the buffer passed.
  523. //
  524. //----------------------------------------------------------------------------
  525. HRESULT
  526. SACIndexCredential(
  527. DWORD dwCredentialIndex,
  528. DWORD cbSAC,
  529. BYTE * pbSAC,
  530. DWORD * pcbCredential,
  531. BYTE ** ppbFoundCredential)
  532. {
  533. HRESULT hr = S_FALSE;
  534. if (ppbFoundCredential != NULL) *ppbFoundCredential = NULL;
  535. if (cbSAC <= SAC_HEADER_SIZE || pbSAC == NULL)
  536. {
  537. return(hr);
  538. }
  539. BYTE * pbSACEnd = pbSAC + cbSAC;
  540. BYTE * pb = pbSAC + USN_SIZE; // Advance past USN.
  541. //
  542. // Read credential count.
  543. //
  544. DWORD dwCredentialCount;
  545. CopyMemory(&dwCredentialCount, pb, sizeof(dwCredentialCount));
  546. pb += sizeof(dwCredentialCount);
  547. //
  548. // Seek to credential index within the credential array.
  549. //
  550. DWORD cbCredentialSize;
  551. for (DWORD i = 0; (i < dwCredentialIndex) && (i < dwCredentialCount) &&
  552. ((DWORD)(pb - pbSAC) < cbSAC); i++)
  553. {
  554. //
  555. // Advance to next credential.
  556. //
  557. // First, ensure sufficient space remains in the buffer.
  558. //
  559. if ((pb + sizeof(cbCredentialSize)) > pbSACEnd)
  560. {
  561. ASSERT_SECURITY_DBASE_CORRUPT();
  562. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  563. }
  564. CopyMemory(&cbCredentialSize, pb, sizeof(cbCredentialSize));
  565. pb += sizeof(cbCredentialSize) + cbCredentialSize;
  566. }
  567. if ((i == dwCredentialIndex) && (i < dwCredentialCount) &&
  568. ((DWORD)(pb - pbSAC) < cbSAC))
  569. {
  570. //
  571. // Found it, but ensure the contents referenced are valid.
  572. // Do so by checking remaining size.
  573. //
  574. CopyMemory(&cbCredentialSize, pb, sizeof(cbCredentialSize));
  575. pb += sizeof(cbCredentialSize);
  576. if ((pb + cbCredentialSize) <= (pbSAC + cbSAC))
  577. {
  578. // Set the credential & credential size return ptrs.
  579. //
  580. *pcbCredential = cbCredentialSize;
  581. // Optionally return a ptr to the credential.
  582. //
  583. if (ppbFoundCredential != NULL)
  584. {
  585. *ppbFoundCredential = pb;
  586. }
  587. hr = S_OK;
  588. }
  589. else
  590. {
  591. ASSERT_SECURITY_DBASE_CORRUPT();
  592. hr = SCHED_E_ACCOUNT_DBASE_CORRUPT;
  593. }
  594. }
  595. else if ((i != dwCredentialCount) || ((DWORD)(pb - pbSAC) != cbSAC))
  596. {
  597. //
  598. // The database appears to be truncated.
  599. //
  600. ASSERT_SECURITY_DBASE_CORRUPT();
  601. hr = SCHED_E_ACCOUNT_DBASE_CORRUPT;
  602. }
  603. return(hr);
  604. }
  605. //+---------------------------------------------------------------------------
  606. //
  607. // Function: SACFindCredential
  608. //
  609. // Synopsis:
  610. //
  611. // Arguments: [pbCredentialIdentity] --
  612. // [cbSAC] --
  613. // [pbSAC] --
  614. // [pdwCredentialIndex] --
  615. // [pcbEncryptedData] --
  616. // [ppbFoundCredential] --
  617. //
  618. // Notes: try/except unnecesssary here as checks exist to ensure we
  619. // remain within the buffer passed.
  620. //
  621. //----------------------------------------------------------------------------
  622. HRESULT
  623. SACFindCredential(
  624. BYTE * pbCredentialIdentity,
  625. DWORD cbSAC,
  626. BYTE * pbSAC,
  627. DWORD * pdwCredentialIndex,
  628. DWORD * pcbEncryptedData,
  629. BYTE ** ppbFoundCredential)
  630. {
  631. HRESULT hr = S_FALSE;
  632. if (ppbFoundCredential != NULL) *ppbFoundCredential = NULL;
  633. if (cbSAC <= SAC_HEADER_SIZE || pbSAC == NULL)
  634. {
  635. return(hr);
  636. }
  637. BYTE * pbSACEnd = pbSAC + cbSAC;
  638. BYTE * pb = pbSAC + USN_SIZE; // Advance past USN.
  639. //
  640. // Read credential count.
  641. //
  642. DWORD dwCredentialCount;
  643. CopyMemory(&dwCredentialCount, pb, sizeof(dwCredentialCount));
  644. pb += sizeof(dwCredentialCount);
  645. //
  646. // Iterate the SAC credentials for a match against the passed credential
  647. // identity.
  648. //
  649. DWORD cbCredentialSize;
  650. for (DWORD i = 0; (i < dwCredentialCount) &&
  651. ((DWORD)(pb - pbSAC) < cbSAC); i++)
  652. {
  653. //
  654. // Ensure sufficient space remains in the buffer.
  655. //
  656. if ((pb + sizeof(cbCredentialSize)) > pbSACEnd)
  657. {
  658. ASSERT_SECURITY_DBASE_CORRUPT();
  659. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  660. }
  661. CopyMemory(&cbCredentialSize, pb, sizeof(cbCredentialSize));
  662. pb += sizeof(cbCredentialSize);
  663. //
  664. // Check remaining buffer size prior to the comparison.
  665. //
  666. if ((pb + HASH_DATA_SIZE) > pbSACEnd)
  667. {
  668. ASSERT_SECURITY_DBASE_CORRUPT();
  669. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  670. }
  671. BOOL fFound;
  672. fFound = (memcmp(pb, pbCredentialIdentity, HASH_DATA_SIZE) == 0);
  673. pb += HASH_DATA_SIZE;
  674. cbCredentialSize -= HASH_DATA_SIZE; // Subtract identity size.
  675. // Equals the encrypted data
  676. // size.
  677. if (fFound)
  678. {
  679. //
  680. // Found it, but ensure the contents referenced are valid.
  681. // Do so by checking remaining size.
  682. //
  683. if ((pb + cbCredentialSize) > pbSACEnd)
  684. {
  685. ASSERT_SECURITY_DBASE_CORRUPT();
  686. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  687. }
  688. *pcbEncryptedData = cbCredentialSize;
  689. *pdwCredentialIndex = i;
  690. if (ppbFoundCredential != NULL)
  691. {
  692. *ppbFoundCredential = pb;
  693. }
  694. return(S_OK);
  695. }
  696. //
  697. // Advance to next credential.
  698. //
  699. pb += cbCredentialSize;
  700. }
  701. if ((i == dwCredentialCount) && ((DWORD)(pb - pbSAC) != cbSAC) ||
  702. (i != dwCredentialCount) && ((DWORD)(pb - pbSAC) > cbSAC))
  703. {
  704. //
  705. // The database appears to be truncated.
  706. //
  707. ASSERT_SECURITY_DBASE_CORRUPT();
  708. hr = SCHED_E_ACCOUNT_DBASE_CORRUPT;
  709. }
  710. return(hr);
  711. }
  712. //+---------------------------------------------------------------------------
  713. //
  714. // Function: SACRemoveCredential
  715. //
  716. // Synopsis:
  717. //
  718. // Arguments: [CredentialIndex] --
  719. // [pcbSAC] --
  720. // [ppbSAC] --
  721. //
  722. // Returns: TBD
  723. //
  724. // Notes: try/except unnecessary here since SACIndexCredential will
  725. // return only valid buffer ptrs.
  726. //
  727. //----------------------------------------------------------------------------
  728. HRESULT
  729. SACRemoveCredential(
  730. DWORD CredentialIndex,
  731. DWORD * pcbSAC,
  732. BYTE ** ppbSAC)
  733. {
  734. DWORD cbCredential;
  735. BYTE * pbCredential;
  736. HRESULT hr;
  737. //
  738. // Index the credential in the SAC.
  739. //
  740. hr = SACIndexCredential(CredentialIndex, *pcbSAC, *ppbSAC, &cbCredential,
  741. &pbCredential);
  742. if (hr == S_FALSE)
  743. {
  744. return(SCHED_E_ACCOUNT_INFORMATION_NOT_SET);
  745. }
  746. else if (FAILED(hr))
  747. {
  748. return(hr);
  749. }
  750. // Overwrite credential with SAC remaining buffer.
  751. //
  752. BYTE * pbDest = pbCredential - sizeof(cbCredential);
  753. BYTE * pbSrc = pbCredential + cbCredential;
  754. MoveMemory(pbDest, pbSrc, (*ppbSAC + *pcbSAC) - pbSrc);
  755. // Decrement SAC credential count.
  756. //
  757. DWORD dwCredentialCount;
  758. CopyMemory(&dwCredentialCount, *ppbSAC + USN_SIZE,
  759. sizeof(dwCredentialCount));
  760. --dwCredentialCount;
  761. CopyMemory(*ppbSAC + USN_SIZE, &dwCredentialCount,
  762. sizeof(dwCredentialCount));
  763. DWORD cbSACNew = *pcbSAC - (cbCredential + sizeof(cbCredential));
  764. // Shrink SAC buffer memory with a realloc.
  765. //
  766. BYTE * pbSACNew = (BYTE *)LocalReAlloc(*ppbSAC, cbSACNew, LMEM_MOVEABLE);
  767. if (pbSACNew == NULL)
  768. {
  769. return(E_OUTOFMEMORY);
  770. }
  771. // Update return ptrs.
  772. //
  773. *pcbSAC = cbSACNew;
  774. *ppbSAC = pbSACNew;
  775. return(hr);
  776. }
  777. //+---------------------------------------------------------------------------
  778. //
  779. // Function: SACUpdateCredential
  780. //
  781. // Synopsis:
  782. //
  783. // Arguments: [cbEncryptedData] --
  784. // [pbEncryptedData] --
  785. // [cbPrevCredential] --
  786. // [pbPrevCredential] --
  787. // [pcbSAC] --
  788. // [ppbSAC] --
  789. //
  790. // Notes: try/except unnecesssary here as checks exist to ensure we
  791. // remain within the buffer passed.
  792. //
  793. //----------------------------------------------------------------------------
  794. HRESULT
  795. SACUpdateCredential(
  796. DWORD cbEncryptedData,
  797. BYTE * pbEncryptedData,
  798. DWORD cbPrevCredential,
  799. BYTE * pbPrevCredential, // Indexes *ppbSAC.
  800. DWORD * pcbSAC,
  801. BYTE ** ppbSAC)
  802. {
  803. DWORD cbNewCredential = HASH_DATA_SIZE + cbEncryptedData;
  804. BYTE * pbSACNew;
  805. //
  806. // Ensure the prev credential ptr is within the buffer boundaries.
  807. // This is probably a redundant check since this ptr was most likely
  808. // obtained from a call to SACIndex/FindCredential.
  809. //
  810. if (*pcbSAC < SAC_HEADER_SIZE ||
  811. pbPrevCredential < (*ppbSAC + SAC_HEADER_SIZE +
  812. sizeof(cbNewCredential)) ||
  813. (pbPrevCredential + cbPrevCredential) > (*ppbSAC + *pcbSAC))
  814. {
  815. ASSERT_SECURITY_DBASE_CORRUPT();
  816. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  817. }
  818. if (cbNewCredential != cbPrevCredential)
  819. {
  820. //
  821. // Reallocate to either shrink or grow the SAC data.
  822. //
  823. DWORD cbSACNew;
  824. BYTE * pbDest;
  825. BYTE * pbSrc;
  826. if (cbNewCredential > cbPrevCredential)
  827. {
  828. //
  829. // Credential is larger than the previous. Grow the
  830. // buffer. Must reallocate the buffer FIRST, then
  831. // relocate contents.
  832. //
  833. cbSACNew = *pcbSAC + (cbNewCredential - cbPrevCredential);
  834. //
  835. // Keep SAC size in check.
  836. //
  837. if (cbSACNew > MAX_SECRET_SIZE)
  838. {
  839. // BUGBUG : use new SCHED_E_CRED_LIMIT_EXCEEDED, as above
  840. return(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
  841. }
  842. //
  843. // Save the linear offset to the previous credential
  844. // from SAC start, in case realloc changes our ptr.
  845. //
  846. DWORD cbPrevCredentialOffset;
  847. cbPrevCredentialOffset = (DWORD)(pbPrevCredential - *ppbSAC);
  848. pbSACNew = (BYTE *)LocalReAlloc(*ppbSAC, cbSACNew, LMEM_MOVEABLE);
  849. if (pbSACNew == NULL)
  850. {
  851. return(E_OUTOFMEMORY);
  852. }
  853. pbPrevCredential = pbSACNew + cbPrevCredentialOffset;
  854. //
  855. // Compute start and ending block ptrs for subsequent
  856. // move.
  857. //
  858. pbDest = pbPrevCredential + cbNewCredential;
  859. pbSrc = pbPrevCredential + cbPrevCredential;
  860. //
  861. // Move remaining buffer up.
  862. //
  863. BYTE * pbSACEnd = pbSACNew + *pcbSAC;
  864. if (pbDest < pbSACEnd)
  865. {
  866. MoveMemory(pbDest, pbSrc, pbSACEnd - pbSrc);
  867. }
  868. }
  869. else
  870. {
  871. //
  872. // Credential is smaller than the previous. Shrink the
  873. // buffer. Must relocate buffer contents FIRST, then
  874. // realloc.
  875. //
  876. cbSACNew = *pcbSAC - (cbPrevCredential - cbNewCredential);
  877. //
  878. // Compute start and ending block ptrs for subsequent
  879. // move.
  880. //
  881. pbDest = pbPrevCredential + cbNewCredential;
  882. pbSrc = pbPrevCredential + cbPrevCredential;
  883. //
  884. // Move remaining buffer down.
  885. //
  886. MoveMemory(pbDest, pbSrc, (*ppbSAC + *pcbSAC) - pbSrc);
  887. pbSACNew = (BYTE *)LocalReAlloc(*ppbSAC, cbSACNew, LMEM_MOVEABLE);
  888. if (pbSACNew == NULL)
  889. {
  890. return(E_OUTOFMEMORY);
  891. }
  892. }
  893. // Update out pointers.
  894. //
  895. *pcbSAC = cbSACNew;
  896. *ppbSAC = pbSACNew;
  897. }
  898. //
  899. // Finally, update the credential.
  900. //
  901. // Write the credential size.
  902. //
  903. CopyMemory(pbPrevCredential - sizeof(cbNewCredential), &cbNewCredential,
  904. sizeof(cbNewCredential));
  905. // No need to update the credential identity. It has not changed.
  906. //
  907. // Write the encrypted bits.
  908. //
  909. CopyMemory(pbPrevCredential + HASH_DATA_SIZE, pbEncryptedData,
  910. cbEncryptedData);
  911. return(S_OK);
  912. }
  913. //+---------------------------------------------------------------------------
  914. //
  915. // Function: SAIAddIdentity
  916. //
  917. // Synopsis:
  918. //
  919. // Arguments: [pbIdentity] --
  920. // [pcbSAI] --
  921. // [ppbSAI] --
  922. //
  923. // Notes: try/except unnecessary here. Memory writes are guaranteed to
  924. // remain within the buffer allocated.
  925. //
  926. //----------------------------------------------------------------------------
  927. HRESULT
  928. SAIAddIdentity(
  929. BYTE * pbIdentity,
  930. DWORD * pcbSAI,
  931. BYTE ** ppbSAI)
  932. {
  933. //
  934. // Make room for the new identity.
  935. //
  936. DWORD dwSetArrayCount = 1;
  937. DWORD dwSetSubCount = 1; // Equal to one in the case of addition.
  938. DWORD cbSAINew;
  939. BYTE * pbSAINew;
  940. cbSAINew = *pcbSAI + sizeof(dwSetSubCount) + HASH_DATA_SIZE;
  941. //
  942. // Check for maximum size. The LSA handles at most 64K.
  943. //
  944. if (cbSAINew > MAX_SECRET_SIZE)
  945. {
  946. // BUGBUG : use new SCHED_E_CRED_LIMIT_EXCEEDED, as above
  947. return(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
  948. }
  949. if (*pcbSAI == 0)
  950. {
  951. cbSAINew += SAI_HEADER_SIZE;
  952. pbSAINew = (BYTE *)LocalAlloc(LMEM_FIXED, cbSAINew);
  953. if (pbSAINew == NULL)
  954. {
  955. return(E_OUTOFMEMORY);
  956. }
  957. //
  958. // Zero out the header.
  959. //
  960. SecureZeroMemory(pbSAINew, SAI_HEADER_SIZE);
  961. }
  962. else
  963. {
  964. pbSAINew = (BYTE *)LocalReAlloc(*ppbSAI, cbSAINew, LMEM_MOVEABLE);
  965. if (pbSAINew == NULL)
  966. {
  967. return(E_OUTOFMEMORY);
  968. }
  969. }
  970. //
  971. // Write identity set subcount of one & write identity.
  972. //
  973. BYTE * pbSetSubCount;
  974. if (*pcbSAI == 0)
  975. {
  976. //
  977. // First entry.
  978. // - Write entry after header.
  979. // - Initialize set array count to one.
  980. //
  981. pbSetSubCount = pbSAINew + SAI_HEADER_SIZE;
  982. CopyMemory(pbSAINew + USN_SIZE, &dwSetArrayCount,
  983. sizeof(dwSetArrayCount));
  984. }
  985. else
  986. {
  987. //
  988. // Append entry.
  989. // - Append after last identity array entry.
  990. // - Increase set array count by one.
  991. //
  992. pbSetSubCount = pbSAINew + *pcbSAI;
  993. CopyMemory(&dwSetArrayCount, pbSAINew + USN_SIZE,
  994. sizeof(dwSetArrayCount));
  995. dwSetArrayCount++;
  996. CopyMemory(pbSAINew + USN_SIZE, &dwSetArrayCount,
  997. sizeof(dwSetArrayCount));
  998. }
  999. CopyMemory(pbSetSubCount, &dwSetSubCount, sizeof(dwSetSubCount));
  1000. CopyMemory(pbSetSubCount + sizeof(dwSetSubCount), pbIdentity,
  1001. HASH_DATA_SIZE);
  1002. // Update out ptrs.
  1003. //
  1004. *pcbSAI = cbSAINew;
  1005. *ppbSAI = pbSAINew;
  1006. return(S_OK);
  1007. }
  1008. //+---------------------------------------------------------------------------
  1009. //
  1010. // Function: SAIFindIdentity
  1011. //
  1012. // Synopsis:
  1013. //
  1014. // Arguments: [pbIdentity] --
  1015. // [cbSAI] --
  1016. // [pbSAI] --
  1017. // [pdwCredentialIndex] --
  1018. // [pfIsPasswordNull] --
  1019. // [ppbFoundIdentity] --
  1020. // [pdwSetSubCount] --
  1021. // [ppbSet] --
  1022. //
  1023. // Notes: try/except unnecesssary here as checks exist to ensure we
  1024. // remain within the buffer passed.
  1025. //
  1026. //----------------------------------------------------------------------------
  1027. HRESULT
  1028. SAIFindIdentity(
  1029. BYTE * pbIdentity,
  1030. DWORD cbSAI,
  1031. BYTE * pbSAI,
  1032. DWORD * pdwCredentialIndex,
  1033. BOOL * pfIsPasswordNull,
  1034. BYTE ** ppbFoundIdentity,
  1035. DWORD * pdwSetSubCount,
  1036. BYTE ** ppbSet)
  1037. {
  1038. HRESULT hr = S_FALSE;
  1039. if (ppbFoundIdentity != NULL) *ppbFoundIdentity = NULL;
  1040. if (cbSAI <= SAI_HEADER_SIZE || pbSAI == NULL)
  1041. {
  1042. return(hr);
  1043. }
  1044. *pdwCredentialIndex = 0;
  1045. if (pdwSetSubCount != NULL) *pdwSetSubCount = 0;
  1046. if (ppbSet != NULL) *ppbSet = NULL;
  1047. BYTE * pbSAIEnd = pbSAI + cbSAI;
  1048. BYTE * pb = pbSAI + USN_SIZE; // Advance past USN.
  1049. //
  1050. // Read identity set array count.
  1051. //
  1052. DWORD dwSetArrayCount;
  1053. CopyMemory(&dwSetArrayCount, pb, sizeof(dwSetArrayCount));
  1054. pb += sizeof(dwSetArrayCount);
  1055. //
  1056. // Iterative identity comparison.
  1057. //
  1058. DWORD dwSetSubCount;
  1059. for (DWORD i = 0;
  1060. (i < dwSetArrayCount) && ((DWORD)(pb - pbSAI) < cbSAI);
  1061. i++)
  1062. {
  1063. //
  1064. // Read identity set subcount.
  1065. //
  1066. // First, ensure sufficient space remains in the buffer.
  1067. //
  1068. if ((pb + sizeof(dwSetSubCount)) > pbSAIEnd)
  1069. {
  1070. ASSERT_SECURITY_DBASE_CORRUPT();
  1071. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1072. }
  1073. BYTE * pbSet;
  1074. CopyMemory(&dwSetSubCount, pb, sizeof(dwSetSubCount));
  1075. pbSet = (pb += sizeof(dwSetSubCount));
  1076. for (DWORD j = 0;
  1077. (j < dwSetSubCount) && ((DWORD)(pb - pbSAI) < cbSAI);
  1078. j++, pb += HASH_DATA_SIZE)
  1079. {
  1080. //
  1081. // Check remaining buffer size prior to the comparison.
  1082. //
  1083. if ((pb + HASH_DATA_SIZE) > pbSAIEnd)
  1084. {
  1085. ASSERT_SECURITY_DBASE_CORRUPT();
  1086. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1087. }
  1088. //
  1089. // We consider the hashed data to be equal even if the last bit
  1090. // is different
  1091. //
  1092. if (memcmp(pb, pbIdentity, HASH_DATA_SIZE - 1) == 0 &&
  1093. ((LAST_HASH_BYTE(pb) ^ LAST_HASH_BYTE(pbIdentity)) & 0xFE) == 0)
  1094. {
  1095. //
  1096. // Found it. No need to further check return ptrs. The
  1097. // buffer size check above accomplished this.
  1098. //
  1099. *pdwCredentialIndex = i;
  1100. if (pfIsPasswordNull != NULL)
  1101. {
  1102. // Unequal last bits denote a NULL password
  1103. *pfIsPasswordNull = LAST_HASH_BYTE(pb) ^ LAST_HASH_BYTE(pbIdentity);
  1104. }
  1105. if (pdwSetSubCount != NULL)
  1106. {
  1107. *pdwSetSubCount = dwSetSubCount;
  1108. }
  1109. if (ppbSet != NULL)
  1110. {
  1111. *ppbSet = pbSet;
  1112. }
  1113. if (ppbFoundIdentity != NULL)
  1114. {
  1115. *ppbFoundIdentity = pb;
  1116. }
  1117. return(S_OK);
  1118. }
  1119. }
  1120. //
  1121. // Check for database truncation.
  1122. //
  1123. if ((j != dwSetSubCount) || ((DWORD)(pb - pbSAI) > cbSAI))
  1124. {
  1125. ASSERT_SECURITY_DBASE_CORRUPT();
  1126. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1127. }
  1128. }
  1129. //
  1130. // Check for database truncation.
  1131. //
  1132. if ((i != dwSetArrayCount) || ((DWORD)(pb - pbSAI) != cbSAI))
  1133. {
  1134. ASSERT_SECURITY_DBASE_CORRUPT();
  1135. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1136. }
  1137. return(hr);
  1138. }
  1139. //+---------------------------------------------------------------------------
  1140. //
  1141. // Function: SAIIndexIdentity
  1142. //
  1143. // Synopsis:
  1144. //
  1145. // Arguments: [cbSAI] --
  1146. // [pbSAI] --
  1147. // [dwSetArrayIndex] --
  1148. // [dwSetIndex] --
  1149. // [pdwSetSubCount] --
  1150. // [ppbSet] --
  1151. //
  1152. // Notes: try/except unnecesssary here as checks exist to ensure we
  1153. // remain within the buffer passed.
  1154. //
  1155. //----------------------------------------------------------------------------
  1156. HRESULT
  1157. SAIIndexIdentity(
  1158. DWORD cbSAI,
  1159. BYTE * pbSAI,
  1160. DWORD dwSetArrayIndex,
  1161. DWORD dwSetIndex,
  1162. BYTE ** ppbFoundIdentity,
  1163. DWORD * pdwSetSubCount,
  1164. BYTE ** ppbSet)
  1165. {
  1166. HRESULT hr = S_FALSE;
  1167. if (ppbFoundIdentity != NULL) *ppbFoundIdentity = NULL;
  1168. if (cbSAI <= SAI_HEADER_SIZE || pbSAI == NULL)
  1169. {
  1170. return(hr);
  1171. }
  1172. if (pdwSetSubCount != NULL) *pdwSetSubCount = 0;
  1173. if (ppbSet != NULL) *ppbSet = NULL;
  1174. BYTE * pbSAIEnd = pbSAI + cbSAI;
  1175. BYTE * pb = pbSAI + USN_SIZE; // Advance past USN.
  1176. //
  1177. // Read identity array count.
  1178. //
  1179. DWORD dwSetArrayCount;
  1180. CopyMemory(&dwSetArrayCount, pb, sizeof(dwSetArrayCount));
  1181. pb += sizeof(dwSetArrayCount);
  1182. //
  1183. // Iterative identity comparison.
  1184. //
  1185. for (DWORD i = 0; (i < dwSetArrayCount) &&
  1186. ((DWORD)(pb - pbSAI) < cbSAI); i++)
  1187. {
  1188. DWORD dwSetSubCount;
  1189. //
  1190. // Read identity set subcount.
  1191. // Note, this value may not be on an aligned boundary.
  1192. //
  1193. // First, ensure sufficient space remains in the buffer.
  1194. //
  1195. if ((pb + sizeof(dwSetSubCount)) > pbSAIEnd)
  1196. {
  1197. ASSERT_SECURITY_DBASE_CORRUPT();
  1198. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1199. }
  1200. BYTE * pbSet;
  1201. CopyMemory(&dwSetSubCount, pb, sizeof(dwSetSubCount));
  1202. pbSet = (pb += sizeof(dwSetSubCount));
  1203. DWORD j;
  1204. for (j = 0; (j < dwSetSubCount) && ((DWORD)(pb - pbSAI) < cbSAI);
  1205. j++, pb += HASH_DATA_SIZE)
  1206. {
  1207. if (i == dwSetArrayIndex && j == dwSetIndex)
  1208. {
  1209. //
  1210. // Found it, but ensure the contents referenced are valid.
  1211. // Do so by checking remaining size.
  1212. //
  1213. if ((pb + HASH_DATA_SIZE) > pbSAIEnd)
  1214. {
  1215. ASSERT_SECURITY_DBASE_CORRUPT();
  1216. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1217. }
  1218. if (pdwSetSubCount != NULL)
  1219. {
  1220. *pdwSetSubCount = dwSetSubCount;
  1221. }
  1222. if (ppbSet != NULL)
  1223. {
  1224. *ppbSet = pbSet;
  1225. }
  1226. if (ppbFoundIdentity != NULL)
  1227. {
  1228. *ppbFoundIdentity = pb;
  1229. }
  1230. return(S_OK);
  1231. }
  1232. }
  1233. //
  1234. // Check for database truncation.
  1235. //
  1236. if ((j != dwSetSubCount) || ((DWORD)(pb - pbSAI) > cbSAI))
  1237. {
  1238. ASSERT_SECURITY_DBASE_CORRUPT();
  1239. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1240. }
  1241. }
  1242. //
  1243. // Check for database truncation.
  1244. //
  1245. if ((i != dwSetArrayCount) || ((DWORD)(pb - pbSAI) != cbSAI))
  1246. {
  1247. ASSERT_SECURITY_DBASE_CORRUPT();
  1248. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1249. }
  1250. return(hr);
  1251. }
  1252. //+---------------------------------------------------------------------------
  1253. //
  1254. // Function: SAIInsertIdentity
  1255. //
  1256. // Synopsis:
  1257. //
  1258. // Arguments: [pbIdentity] --
  1259. // [pbSAIIndex] --
  1260. // [pcbSAI] --
  1261. // [ppbSAI] --
  1262. //
  1263. // Notes: try/except unnecesssary here as checks exist to ensure we
  1264. // remain within the buffer passed.
  1265. //
  1266. //----------------------------------------------------------------------------
  1267. HRESULT
  1268. SAIInsertIdentity(
  1269. BYTE * pbIdentity,
  1270. BYTE * pbSAIIndex, // Indexes *ppbSAI.
  1271. DWORD * pcbSAI,
  1272. BYTE ** ppbSAI)
  1273. {
  1274. DWORD dwSetSubCount;
  1275. //
  1276. // Check index boundary.
  1277. //
  1278. if (pbSAIIndex < (*ppbSAI + SAI_HEADER_SIZE + sizeof(dwSetSubCount)) ||
  1279. (pbSAIIndex + HASH_DATA_SIZE) > (*ppbSAI + *pcbSAI))
  1280. {
  1281. ASSERT_SECURITY_DBASE_CORRUPT();
  1282. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1283. }
  1284. //
  1285. // Save the linear offset to the identity insertion point from SAI start,
  1286. // in case realloc changes our ptr.
  1287. //
  1288. DWORD cbInsertionOffset = (DWORD)(pbSAIIndex - *ppbSAI);
  1289. //
  1290. // Make room for the new identity.
  1291. //
  1292. DWORD cbSAINew = *pcbSAI + HASH_DATA_SIZE;
  1293. BYTE * pbSAINew;
  1294. //
  1295. // Check for maximum size. The LSA handles at most 64K.
  1296. //
  1297. if (cbSAINew > MAX_SECRET_SIZE)
  1298. {
  1299. // BUGBUG : use new SCHED_E_CRED_LIMIT_EXCEEDED, as above
  1300. return(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
  1301. }
  1302. if (*pcbSAI == 0)
  1303. {
  1304. cbSAINew += SAI_HEADER_SIZE;
  1305. pbSAINew = (BYTE *)LocalAlloc(LMEM_FIXED, cbSAINew);
  1306. if (pbSAINew == NULL)
  1307. {
  1308. return(E_OUTOFMEMORY);
  1309. }
  1310. //
  1311. // Zero out the header.
  1312. //
  1313. SecureZeroMemory(pbSAINew, SAI_HEADER_SIZE);
  1314. }
  1315. else
  1316. {
  1317. pbSAINew = (BYTE *)LocalReAlloc(*ppbSAI, cbSAINew, LMEM_MOVEABLE);
  1318. if (pbSAINew == NULL)
  1319. {
  1320. return(E_OUTOFMEMORY);
  1321. }
  1322. }
  1323. pbSAIIndex = pbSAINew + cbInsertionOffset;
  1324. //
  1325. // Move buffer content down.
  1326. //
  1327. BYTE * pbSetSubCount = pbSAIIndex - sizeof(dwSetSubCount);
  1328. BYTE * pbIdentityStart = pbSAIIndex;
  1329. MoveMemory(pbIdentityStart + HASH_DATA_SIZE, pbIdentityStart,
  1330. (pbSAINew + *pcbSAI) - pbIdentityStart);
  1331. //
  1332. // Update identity count & write new identity.
  1333. //
  1334. CopyMemory(&dwSetSubCount, pbSetSubCount, sizeof(dwSetSubCount));
  1335. dwSetSubCount++;
  1336. CopyMemory(pbSetSubCount, &dwSetSubCount, sizeof(dwSetSubCount));
  1337. CopyMemory(pbIdentityStart, pbIdentity, HASH_DATA_SIZE);
  1338. // Update out ptrs.
  1339. //
  1340. *pcbSAI = cbSAINew;
  1341. *ppbSAI = pbSAINew;
  1342. return(S_OK);
  1343. }
  1344. //+---------------------------------------------------------------------------
  1345. //
  1346. // Function: SAIRemoveIdentity
  1347. //
  1348. // Synopsis:
  1349. //
  1350. // Arguments: [pbIdentity] --
  1351. // [pbSet] --
  1352. // [pcbSAI] --
  1353. // [ppbSAI] --
  1354. // [CredentialIndex] --
  1355. // [pcbSAC] --
  1356. // [ppbSAC] --
  1357. //
  1358. // Returns: TBD
  1359. //
  1360. // Notes:
  1361. //
  1362. //----------------------------------------------------------------------------
  1363. HRESULT
  1364. SAIRemoveIdentity(
  1365. BYTE * pbIdentity,
  1366. BYTE * pbSet,
  1367. DWORD * pcbSAI,
  1368. BYTE ** ppbSAI,
  1369. DWORD CredentialIndex,
  1370. DWORD * pcbSAC,
  1371. BYTE ** ppbSAC)
  1372. {
  1373. HRESULT hr = S_OK;
  1374. DWORD dwSetSubCount;
  1375. //
  1376. // Check identity, set ptr values. If this fails, it is either a developer
  1377. // error (hence, the assertion) or the database is hosed. In either case,
  1378. // return an error vs. writing blindly to memory.
  1379. //
  1380. if ((pbSet > pbIdentity) ||
  1381. (pbSet < (*ppbSAI + SAI_HEADER_SIZE + sizeof(dwSetSubCount))) ||
  1382. ((pbIdentity + HASH_DATA_SIZE) > (*ppbSAI + *pcbSAI)))
  1383. {
  1384. ASSERT_SECURITY_DBASE_CORRUPT();
  1385. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1386. }
  1387. BYTE * pbSetSubCount;
  1388. //
  1389. // Read and decrement identity array count.
  1390. //
  1391. pbSetSubCount = pbSet - sizeof(dwSetSubCount);
  1392. CopyMemory(&dwSetSubCount, pbSetSubCount, sizeof(dwSetSubCount));
  1393. --dwSetSubCount;
  1394. //
  1395. // If this is the last identity in the set,
  1396. // overwrite the set count value & the identity with remaining SAI
  1397. // buffer content;
  1398. // remove associated credential from the SAC.
  1399. // If this is not the last entry,
  1400. // overwrite the identity with the remaining SAI buffer content &
  1401. // decrement the identity set count.
  1402. //
  1403. BYTE * pbDest, * pbSrc;
  1404. DWORD cbSAINew;
  1405. if (dwSetSubCount == 0) // Last entry.
  1406. {
  1407. // Remove associated credential in the SAC.
  1408. //
  1409. hr = SACRemoveCredential(CredentialIndex, pcbSAC, ppbSAC);
  1410. if (SUCCEEDED(hr))
  1411. {
  1412. // Overwrite identity set with SAI remaining buffer.
  1413. // Includes the set array count and the single identity
  1414. // element. Actual move accomplished following this condition.
  1415. //
  1416. pbDest = pbSetSubCount;
  1417. pbSrc = pbSet + HASH_DATA_SIZE;
  1418. cbSAINew = *pcbSAI - (HASH_DATA_SIZE + sizeof(dwSetSubCount));
  1419. // Decrement SAI identity set count. That is, the count of
  1420. // identity sets in the SAI. Note, overloading dwSetSubCount.
  1421. //
  1422. CopyMemory(&dwSetSubCount, *ppbSAI + USN_SIZE,
  1423. sizeof(dwSetSubCount));
  1424. --dwSetSubCount;
  1425. CopyMemory(*ppbSAI + USN_SIZE, &dwSetSubCount,
  1426. sizeof(dwSetSubCount));
  1427. }
  1428. }
  1429. else // More entries remain.
  1430. {
  1431. // Overwrite identity with SAI remaining buffer.
  1432. // Actual move accomplished following this condition.
  1433. //
  1434. pbDest = pbIdentity;
  1435. pbSrc = pbIdentity + HASH_DATA_SIZE;
  1436. cbSAINew = *pcbSAI - HASH_DATA_SIZE;
  1437. // Update identity set array count to reflect removed entry.
  1438. //
  1439. CopyMemory(pbSetSubCount, &dwSetSubCount, sizeof(dwSetSubCount));
  1440. }
  1441. if (SUCCEEDED(hr))
  1442. {
  1443. MoveMemory(pbDest, pbSrc, (*ppbSAI + *pcbSAI) - pbSrc);
  1444. // Shrink SAI buffer memory with a realloc.
  1445. //
  1446. BYTE * pbSAINew = (BYTE *)LocalReAlloc(*ppbSAI, cbSAINew,
  1447. LMEM_MOVEABLE);
  1448. if (pbSAINew != NULL)
  1449. {
  1450. // Update return ptrs.
  1451. //
  1452. *pcbSAI = cbSAINew;
  1453. *ppbSAI = pbSAINew;
  1454. }
  1455. else
  1456. {
  1457. hr = E_OUTOFMEMORY;
  1458. }
  1459. }
  1460. return(hr);
  1461. }
  1462. //+---------------------------------------------------------------------------
  1463. //
  1464. // Function: SAIUpdateIdentity
  1465. //
  1466. // Synopsis: Updates the hash data stored for a job in place.
  1467. //
  1468. // Arguments: [pbNewIdentity] -- the new hash data to be stored
  1469. // [pbFoundIdentity] -- pointer to the previously found hash data
  1470. // [cbSAI] --
  1471. // [pbSAI] --
  1472. //
  1473. // Returns: S_OK
  1474. // E_OUTOFMEMORY
  1475. // SCHED_E_ACCOUNT_DBASE_CORRUPT
  1476. //
  1477. // Notes: None.
  1478. //
  1479. //----------------------------------------------------------------------------
  1480. HRESULT
  1481. SAIUpdateIdentity(
  1482. const BYTE * pbNewIdentity,
  1483. BYTE * pbFoundIdentity,
  1484. DWORD cbSAI,
  1485. BYTE * pbSAI)
  1486. {
  1487. schAssert(pbSAI <= pbFoundIdentity && pbFoundIdentity < pbSAI + cbSAI);
  1488. UNREFERENCED_PARAMETER(cbSAI);
  1489. UNREFERENCED_PARAMETER(pbSAI);
  1490. CopyMemory(pbFoundIdentity, pbNewIdentity, HASH_DATA_SIZE);
  1491. return S_OK;
  1492. }
  1493. //+---------------------------------------------------------------------------
  1494. //
  1495. // Function: SAICoalesceDeletedEntries
  1496. //
  1497. // Synopsis: Removed entries marked for deletion and reallocate the buffer.
  1498. //
  1499. // Arguments: [pcbSAI] --
  1500. // [ppbSAI] --
  1501. //
  1502. // Returns: S_OK
  1503. // E_OUTOFMEMORY
  1504. // SCHED_E_ACCOUNT_DBASE_CORRUPT
  1505. //
  1506. // Notes: None.
  1507. //
  1508. //----------------------------------------------------------------------------
  1509. HRESULT
  1510. SAICoalesceDeletedEntries(
  1511. DWORD * pcbSAI,
  1512. BYTE ** ppbSAI)
  1513. {
  1514. schAssert(pcbSAI != NULL && ppbSAI != NULL && *ppbSAI != NULL);
  1515. if (*pcbSAI <= SAI_HEADER_SIZE)
  1516. {
  1517. //
  1518. // Nothing to do.
  1519. //
  1520. return(S_OK);
  1521. }
  1522. //
  1523. // Read set array count.
  1524. //
  1525. DWORD cbSAINew = *pcbSAI;
  1526. DWORD cSetsRemoved = 0;
  1527. DWORD dwSetArrayCount;
  1528. DWORD dwSetSubCount;
  1529. DWORD cEntriesDeleted;
  1530. BYTE * pb;
  1531. BYTE * pbSetArrayCount;
  1532. BYTE * pbSAIEnd = *ppbSAI + *pcbSAI;
  1533. BYTE * pbSAINew;
  1534. BYTE * pbDest;
  1535. BYTE * pbSrc;
  1536. pb = pbSetArrayCount = *ppbSAI + USN_SIZE;
  1537. CopyMemory(&dwSetArrayCount, pbSetArrayCount, sizeof(dwSetArrayCount));
  1538. pb += sizeof(dwSetArrayCount);
  1539. for (DWORD i = 0; i < dwSetArrayCount && pb < pbSAIEnd; i++)
  1540. {
  1541. if ((pb + sizeof(dwSetSubCount)) > pbSAIEnd)
  1542. {
  1543. ASSERT_SECURITY_DBASE_CORRUPT();
  1544. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1545. }
  1546. CopyMemory(&dwSetSubCount, pb, sizeof(dwSetSubCount));
  1547. pbDest = pb;
  1548. pb += sizeof(dwSetSubCount);
  1549. pbSrc = pb;
  1550. //
  1551. // Must scan the set to see if all entries are to be removed.
  1552. // To know if the set subcount can be removed as well.
  1553. //
  1554. cEntriesDeleted = 0;
  1555. for (DWORD j = 0; j < dwSetSubCount && pbSrc < pbSAIEnd; j++)
  1556. {
  1557. //
  1558. // Deleted entry marker size is less than HASH_DATA_SIZE.
  1559. //
  1560. if ((pbSrc + HASH_DATA_SIZE) > pbSAIEnd)
  1561. {
  1562. ASSERT_SECURITY_DBASE_CORRUPT();
  1563. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1564. }
  1565. if (DELETED_ENTRY(pbSrc))
  1566. {
  1567. cEntriesDeleted++;
  1568. }
  1569. pbSrc += HASH_DATA_SIZE;
  1570. }
  1571. //
  1572. // Anything to remove?
  1573. //
  1574. if (cEntriesDeleted != 0)
  1575. {
  1576. //
  1577. // Reduce SAI size by the total no. of deleted entries.
  1578. // After the above, we can safely dispense with buffer boundary
  1579. // checks.
  1580. //
  1581. DWORD cbBytesDeleted = (HASH_DATA_SIZE * cEntriesDeleted);
  1582. if (cEntriesDeleted == dwSetSubCount)
  1583. {
  1584. //
  1585. // Removing entire set.
  1586. // Update total no. of sets removed.
  1587. //
  1588. cSetsRemoved++;
  1589. cbBytesDeleted += sizeof(dwSetSubCount);
  1590. MoveMemory(pbDest, pbSrc, pbSAIEnd - pbSrc);
  1591. }
  1592. else
  1593. {
  1594. //
  1595. // Removing individual set entries.
  1596. // First, update the set array count.
  1597. // pbDest is positioned on the set subcount, pb just after it.
  1598. //
  1599. dwSetSubCount -= cEntriesDeleted;
  1600. CopyMemory(pbDest, &dwSetSubCount, sizeof(dwSetSubCount));
  1601. pbDest = pbSrc = pb;
  1602. for ( ; cEntriesDeleted && pbSrc < pbSAIEnd; )
  1603. {
  1604. pbSrc += HASH_DATA_SIZE;
  1605. if (DELETED_ENTRY(pbDest))
  1606. {
  1607. cEntriesDeleted--;
  1608. MoveMemory(pbDest, pbSrc, pbSAIEnd - pbSrc);
  1609. pbSrc = pbDest;
  1610. }
  1611. pbDest = pbSrc;
  1612. }
  1613. //
  1614. // Advance to next set.
  1615. //
  1616. pbDest = pb + (HASH_DATA_SIZE * dwSetSubCount);
  1617. }
  1618. cbSAINew -= cbBytesDeleted;
  1619. pbSAIEnd -= cbBytesDeleted;
  1620. }
  1621. else
  1622. {
  1623. //
  1624. // Advance to next set.
  1625. //
  1626. pbDest += (HASH_DATA_SIZE * dwSetSubCount) +
  1627. sizeof(dwSetSubCount);
  1628. }
  1629. pb = pbDest;
  1630. }
  1631. //
  1632. // Fix up set array count to reflect removed sets.
  1633. //
  1634. dwSetArrayCount -= cSetsRemoved;
  1635. CopyMemory(pbSetArrayCount, &dwSetArrayCount, sizeof(dwSetArrayCount));
  1636. //
  1637. // Finally, reallocate the array. That is, if it changed.
  1638. //
  1639. if (*pcbSAI != cbSAINew)
  1640. {
  1641. pbSAINew = (BYTE *)LocalReAlloc(*ppbSAI, cbSAINew, LMEM_MOVEABLE);
  1642. if (pbSAINew != NULL)
  1643. {
  1644. // Update return ptrs.
  1645. //
  1646. *pcbSAI = cbSAINew;
  1647. *ppbSAI = pbSAINew;
  1648. }
  1649. else
  1650. {
  1651. return(E_OUTOFMEMORY);
  1652. }
  1653. }
  1654. return(S_OK);
  1655. }
  1656. //+---------------------------------------------------------------------------
  1657. //
  1658. // Function: SACCoalesceDeletedEntries
  1659. //
  1660. // Synopsis: Removed entries marked for deletion and reallocate the buffer.
  1661. //
  1662. // Arguments: [pcbSAC] --
  1663. // [ppbSAC] --
  1664. //
  1665. // Returns: S_OK
  1666. // E_OUTOFMEMORY
  1667. // SCHED_E_ACCOUNT_DBASE_CORRUPT
  1668. //
  1669. // Notes: None.
  1670. //
  1671. //----------------------------------------------------------------------------
  1672. HRESULT
  1673. SACCoalesceDeletedEntries(
  1674. DWORD * pcbSAC,
  1675. BYTE ** ppbSAC)
  1676. {
  1677. schAssert(pcbSAC != NULL && ppbSAC != NULL && *ppbSAC != NULL);
  1678. if (*pcbSAC <= SAC_HEADER_SIZE)
  1679. {
  1680. //
  1681. // Nothing to do.
  1682. //
  1683. return(S_OK);
  1684. }
  1685. BYTE * pb;
  1686. BYTE * pbCredentialCount;
  1687. DWORD dwCredentialCount;
  1688. DWORD cbCredentialSize;
  1689. DWORD cCredentialsRemoved = 0;
  1690. DWORD cbSACNew = *pcbSAC;
  1691. BYTE * pbSACNew;
  1692. BYTE * pbSACEnd = *ppbSAC + *pcbSAC;
  1693. BYTE * pbSrc;
  1694. BYTE * pbDest;
  1695. BYTE * pbNext;
  1696. DWORD cbBytesDeleted;
  1697. //
  1698. // Read credential count.
  1699. //
  1700. pb = pbCredentialCount = *ppbSAC + USN_SIZE;
  1701. CopyMemory(&dwCredentialCount, pbCredentialCount,
  1702. sizeof(dwCredentialCount));
  1703. pb += sizeof(dwCredentialCount);
  1704. for (DWORD i = 0; i < dwCredentialCount && pb < pbSACEnd; i++)
  1705. {
  1706. if ((pb + sizeof(cbCredentialSize)) > pbSACEnd)
  1707. {
  1708. ASSERT_SECURITY_DBASE_CORRUPT();
  1709. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1710. }
  1711. cbBytesDeleted = 0;
  1712. pbDest = pbSrc = pb;
  1713. //
  1714. // Move consecutive entries.
  1715. //
  1716. for ( ; i < dwCredentialCount && pb < pbSACEnd; i++)
  1717. {
  1718. CopyMemory(&cbCredentialSize, pb, sizeof(cbCredentialSize));
  1719. pb += sizeof(cbCredentialSize);
  1720. pbNext = pb + cbCredentialSize;
  1721. //
  1722. // A credential could never be less than the deleted entry size,
  1723. // unless it is bogus.
  1724. //
  1725. if (cbCredentialSize < DELETED_ENTRY_MARKER_SIZE ||
  1726. (pb + DELETED_ENTRY_MARKER_SIZE) > pbSACEnd)
  1727. {
  1728. ASSERT_SECURITY_DBASE_CORRUPT();
  1729. return(SCHED_E_ACCOUNT_DBASE_CORRUPT);
  1730. }
  1731. if (DELETED_ENTRY(pb))
  1732. {
  1733. //
  1734. // Update the new SAC size to reflect the removed entry.
  1735. // Also update the total no. of credentials removed.
  1736. //
  1737. cbBytesDeleted += sizeof(cbCredentialSize) + cbCredentialSize;
  1738. cCredentialsRemoved++;
  1739. pbSrc = pb = pbNext;
  1740. }
  1741. else
  1742. {
  1743. pb = pbNext;
  1744. break;
  1745. }
  1746. }
  1747. if (pbDest != pbSrc)
  1748. {
  1749. MoveMemory(pbDest, pbSrc, pbSACEnd - pbSrc);
  1750. pb = pbDest + sizeof(cbCredentialSize) + cbCredentialSize;
  1751. cbSACNew -= cbBytesDeleted;
  1752. pbSACEnd -= cbBytesDeleted;
  1753. }
  1754. }
  1755. //
  1756. // Fix up credential count to reflect removed sets.
  1757. //
  1758. dwCredentialCount -= cCredentialsRemoved;
  1759. CopyMemory(pbCredentialCount, &dwCredentialCount,
  1760. sizeof(dwCredentialCount));
  1761. //
  1762. // Finally, reallocate the array. That is, if it changed.
  1763. //
  1764. if (*pcbSAC != cbSACNew)
  1765. {
  1766. pbSACNew = (BYTE *)LocalReAlloc(*ppbSAC, cbSACNew, LMEM_MOVEABLE);
  1767. if (pbSACNew != NULL)
  1768. {
  1769. // Update return ptrs.
  1770. //
  1771. *pcbSAC = cbSACNew;
  1772. *ppbSAC = pbSACNew;
  1773. }
  1774. else
  1775. {
  1776. return(E_OUTOFMEMORY);
  1777. }
  1778. }
  1779. return(S_OK);
  1780. }