Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

938 lines
21 KiB

  1. //
  2. // systok.cpp
  3. //
  4. // Copyright (c) Microsoft Corp, 1998
  5. //
  6. // This file contains source code for testing protected storage's key
  7. // backup and recovery capabilities under a real world scenario, by creating
  8. // a local user account, performing a data protection operation, and then
  9. // change the pwd, then performing data unprotect, and comparing the data.
  10. //
  11. // History:
  12. //
  13. // Todds 8/15/98 Created
  14. //
  15. #include <windows.h>
  16. #include <winbase.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <wincrypt.h>
  20. #include <userenv.h>
  21. #include <lm.h>
  22. #include <psapi.h>
  23. #include "switches.h"
  24. #define TERROR(msg) LogError(__FILE__, __LINE__, msg)
  25. #define TERRORVAL(msg, val) LogErrorVal(__FILE__, __LINE__, msg, val)
  26. #define TCOMMENT(msg) LogComment(msg)
  27. #define MyAlloc(cb) HeapAlloc(GetProcessHeap(), 0, cb)
  28. #define MyFree(pv) HeapFree(GetProcessHeap(), 0, pv)
  29. #define WSZ_BYTECOUNT(s) (2 * wcslen(s) + 2)
  30. #define CHECK_NULL(s) if (s == NULL) \
  31. LogError(__FILE__, __LINE__, L"## CHECK_NULL ##")
  32. #define MAX_BLOBS 20
  33. #define MAX_PROCESSES 200
  34. #define MAX_SD 2048
  35. #define BLOB_INCREMENT 0x4001 // 1 page + 1 byte...
  36. //
  37. // Error Logging Functions # defined as follows to include
  38. // Line and FILE macros:
  39. //
  40. // TERROR - LogError()
  41. // TERRORVAL - LogErrorVal()
  42. //
  43. //
  44. void
  45. LogError(LPSTR szFile,
  46. int iLine,
  47. LPWSTR wszMsg)
  48. {
  49. //
  50. // Event log or testutil logging later...
  51. //
  52. WCHAR buffer[512];
  53. swprintf(buffer, L"ERROR Line: %i -> %s\n", iLine, wszMsg);
  54. OutputDebugStringW(buffer);
  55. wprintf(buffer);
  56. }
  57. void
  58. LogErrorVal(LPSTR szFile,
  59. int iLine,
  60. LPWSTR wszMsg,
  61. DWORD dwVal)
  62. {
  63. WCHAR buffer[256]; // this should be adequate.
  64. swprintf(buffer, L"%s Error:: %x", wszMsg, dwVal);
  65. LogError(szFile, iLine, buffer);
  66. }
  67. void
  68. LogComment(LPWSTR wszMsg)
  69. {
  70. //
  71. // Event log or testutil logging later...
  72. //
  73. WCHAR buffer[512];
  74. OutputDebugStringW(wszMsg);
  75. wprintf(wszMsg);
  76. }
  77. void
  78. DumpBin(CRYPT_DATA_BLOB hash)
  79. {
  80. WCHAR buff[256], out[256];
  81. ULONG cb;
  82. swprintf(out, L"");
  83. while (hash.cbData > 0) {
  84. cb = min(4, hash.cbData);
  85. hash.cbData -= cb;
  86. for (; cb > 0; cb--, hash.pbData++) {
  87. swprintf(buff, L"%02X", *hash.pbData);
  88. wcscat(out, buff);
  89. }
  90. wcscat(out, L" ");
  91. }
  92. wcscat(out, L"\n");
  93. TCOMMENT(out);
  94. }
  95. //
  96. // SetSidOnAcl
  97. //
  98. BOOL
  99. SetSidOnAcl(
  100. PSID pSid,
  101. PACL pAclSource,
  102. PACL *pAclDestination,
  103. DWORD AccessMask,
  104. BYTE AceFlags,
  105. BOOL bAddSid
  106. )
  107. {
  108. ACL_SIZE_INFORMATION AclInfo;
  109. DWORD dwNewAclSize, dwErr = S_OK;
  110. LPVOID pAce;
  111. DWORD AceCounter;
  112. BOOL bSuccess=FALSE; // assume this function will fail
  113. //
  114. // If we were given a NULL Acl, just provide a NULL Acl
  115. //
  116. if(pAclSource == NULL) {
  117. *pAclDestination = NULL;
  118. return TRUE;
  119. }
  120. if(!IsValidSid(pSid)) return FALSE;
  121. if(!GetAclInformation(
  122. pAclSource,
  123. &AclInfo,
  124. sizeof(ACL_SIZE_INFORMATION),
  125. AclSizeInformation
  126. )) return FALSE;
  127. //
  128. // compute size for new Acl, based on addition or subtraction of Ace
  129. //
  130. if(bAddSid) {
  131. dwNewAclSize=AclInfo.AclBytesInUse +
  132. sizeof(ACCESS_ALLOWED_ACE) +
  133. GetLengthSid(pSid) -
  134. sizeof(DWORD) ;
  135. }
  136. else {
  137. dwNewAclSize=AclInfo.AclBytesInUse -
  138. sizeof(ACCESS_ALLOWED_ACE) -
  139. GetLengthSid(pSid) +
  140. sizeof(DWORD) ;
  141. }
  142. *pAclDestination = (PACL)MyAlloc(dwNewAclSize);
  143. if(*pAclDestination == NULL)
  144. {
  145. TERRORVAL(L"Alloc failed!", E_OUTOFMEMORY);
  146. return FALSE;
  147. }
  148. //
  149. // initialize new Acl
  150. //
  151. if(!InitializeAcl(
  152. *pAclDestination,
  153. dwNewAclSize,
  154. ACL_REVISION
  155. )){
  156. dwErr = GetLastError();
  157. TERRORVAL(L"InitilizeAcl failed!", dwErr);
  158. goto ret;
  159. }
  160. //
  161. // if appropriate, add ace representing pSid
  162. //
  163. if(bAddSid) {
  164. PACCESS_ALLOWED_ACE pNewAce;
  165. if(!AddAccessAllowedAce(
  166. *pAclDestination,
  167. ACL_REVISION,
  168. AccessMask,
  169. pSid
  170. )) {
  171. dwErr = GetLastError();
  172. TERRORVAL(L"AddAccessAllowedAce failed!", dwErr);
  173. goto ret;
  174. }
  175. //
  176. // get pointer to ace we just added, so we can change the AceFlags
  177. //
  178. if(!GetAce(
  179. *pAclDestination,
  180. 0, // this is the first ace in the Acl
  181. (void**) &pNewAce
  182. )){
  183. dwErr = GetLastError();
  184. TERRORVAL(L"GetAce failed!", dwErr);
  185. goto ret;
  186. }
  187. pNewAce->Header.AceFlags = AceFlags;
  188. }
  189. //
  190. // copy existing aces to new Acl
  191. //
  192. for(AceCounter = 0 ; AceCounter < AclInfo.AceCount ; AceCounter++) {
  193. //
  194. // fetch existing ace
  195. //
  196. if(!GetAce(pAclSource, AceCounter, &pAce)){
  197. dwErr = GetLastError();
  198. TERRORVAL(L"GetAce failed!", dwErr);
  199. goto ret;
  200. }
  201. //
  202. // check to see if we are removing the Ace
  203. //
  204. if(!bAddSid) {
  205. //
  206. // we only care about ACCESS_ALLOWED aces
  207. //
  208. if((((PACE_HEADER)pAce)->AceType) == ACCESS_ALLOWED_ACE_TYPE) {
  209. PSID pTempSid=(PSID)&((PACCESS_ALLOWED_ACE)pAce)->SidStart;
  210. //
  211. // if the Sid matches, skip adding this Sid
  212. //
  213. if(EqualSid(pSid, pTempSid)) continue;
  214. }
  215. }
  216. //
  217. // append ace to Acl
  218. //
  219. if(!AddAce(
  220. *pAclDestination,
  221. ACL_REVISION,
  222. MAXDWORD, // maintain Ace order
  223. pAce,
  224. ((PACE_HEADER)pAce)->AceSize
  225. )) {
  226. dwErr = GetLastError();
  227. TERRORVAL(L"AddAccessAllowedAce failed!", dwErr);
  228. goto ret;
  229. }
  230. }
  231. bSuccess=TRUE; // indicate success
  232. ret:
  233. //
  234. // free memory if an error occurred
  235. //
  236. if(!bSuccess) {
  237. if(*pAclDestination != NULL)
  238. MyFree(*pAclDestination);
  239. }
  240. return bSuccess;
  241. }
  242. //
  243. // AddSIDToKernelObject()
  244. //
  245. // This function takes a given SID and dwAccess and adds it to a given token.
  246. //
  247. // ** Be sure to restore old kernel object
  248. // ** using call to GetKernelObjectSecurity()
  249. //
  250. BOOL
  251. AddSIDToKernelObjectDacl(PSID pSid,
  252. DWORD dwAccess,
  253. HANDLE OriginalToken,
  254. PSECURITY_DESCRIPTOR* ppSDOld)
  255. {
  256. PSECURITY_DESCRIPTOR pSD = NULL;
  257. SECURITY_DESCRIPTOR sdNew;
  258. DWORD cbByte = MAX_SD, cbNeeded = 0, dwErr = 0;
  259. PACL pOldDacl = NULL, pNewDacl = NULL;
  260. BOOL fDaclPresent, fDaclDefaulted, fRet = FALSE;
  261. pSD = (PSECURITY_DESCRIPTOR) MyAlloc(cbByte);
  262. if (NULL == pSD) {
  263. TERRORVAL(L"Alloc failed!", E_OUTOFMEMORY);
  264. return FALSE;
  265. }
  266. if (!InitializeSecurityDescriptor(
  267. &sdNew,
  268. SECURITY_DESCRIPTOR_REVISION
  269. )) {
  270. dwErr = GetLastError();
  271. TERRORVAL(L"InitializeSecurityDescriptor failed!", dwErr);
  272. goto ret;
  273. }
  274. if (!GetKernelObjectSecurity(
  275. OriginalToken,
  276. DACL_SECURITY_INFORMATION,
  277. pSD,
  278. cbByte,
  279. &cbNeeded
  280. )) {
  281. dwErr = GetLastError();
  282. if (cbNeeded > MAX_SD && dwErr == ERROR_MORE_DATA) {
  283. MyFree(pSD);
  284. pSD = NULL;
  285. pSD = (PSECURITY_DESCRIPTOR) MyAlloc(cbNeeded);
  286. if (NULL == pSD) {
  287. TERRORVAL(L"Alloc failed!", E_OUTOFMEMORY);
  288. dwErr = E_OUTOFMEMORY;
  289. goto ret;
  290. }
  291. dwErr = S_OK;
  292. if (!GetKernelObjectSecurity(
  293. OriginalToken,
  294. DACL_SECURITY_INFORMATION,
  295. pSD,
  296. cbNeeded,
  297. &cbNeeded
  298. )) {
  299. dwErr = GetLastError();
  300. }
  301. }
  302. if (dwErr != S_OK) {
  303. TERRORVAL(L"GetKernelObjectSecurity failed!", dwErr);
  304. goto ret;
  305. }
  306. }
  307. if (!GetSecurityDescriptorDacl(
  308. pSD,
  309. &fDaclPresent,
  310. &pOldDacl,
  311. &fDaclDefaulted
  312. )) {
  313. dwErr = GetLastError();
  314. TERRORVAL(L"GetSecurityDescriptorDacl failed!", dwErr);
  315. goto ret;
  316. }
  317. if (!SetSidOnAcl(
  318. pSid,
  319. pOldDacl,
  320. &pNewDacl,
  321. dwAccess,
  322. 0,
  323. TRUE
  324. )) {
  325. goto ret;
  326. }
  327. if (!SetSecurityDescriptorDacl(
  328. &sdNew,
  329. TRUE,
  330. pNewDacl,
  331. FALSE
  332. )) {
  333. dwErr = GetLastError();
  334. TERRORVAL(L"SetSecurityDescriptorDacl failed!", dwErr);
  335. goto ret;
  336. }
  337. if (!SetKernelObjectSecurity(
  338. OriginalToken,
  339. DACL_SECURITY_INFORMATION,
  340. &sdNew
  341. )) {
  342. dwErr = GetLastError();
  343. TERRORVAL(L"SetKernelObjectSecurity failed!", dwErr);
  344. goto ret;
  345. }
  346. *ppSDOld = pSD;
  347. fRet = TRUE;
  348. ret:
  349. if (NULL != pNewDacl) {
  350. MyFree(pNewDacl);
  351. }
  352. if (!fRet) {
  353. if (NULL != pSD) {
  354. MyFree(pSD);
  355. *ppSDOld = NULL;
  356. }
  357. }
  358. return fRet;
  359. }
  360. //
  361. // DataFree()
  362. //
  363. // Utility for freeing array of DATA_BLOB structs
  364. //
  365. void
  366. DataFree(DATA_BLOB* arDataBlob,
  367. BOOL fCryptAlloc)
  368. {
  369. if (arDataBlob == NULL) return; // not alloc'd
  370. for (DWORD i = 0; i < MAX_BLOBS;i++) {
  371. if (arDataBlob[i].pbData != NULL) {
  372. if (!fCryptAlloc) {
  373. MyFree(arDataBlob[i].pbData);
  374. } else { // Data member alloc'd by DataProtect call
  375. LocalFree(arDataBlob[i].pbData);
  376. }
  377. }
  378. }
  379. MyFree(arDataBlob);
  380. }
  381. BOOL
  382. SetPrivilege(
  383. HANDLE hToken, // token handle
  384. LPCTSTR Privilege, // Privilege to enable/disable
  385. BOOL bEnablePrivilege // to enable or disable privilege
  386. )
  387. {
  388. TOKEN_PRIVILEGES tp;
  389. LUID luid;
  390. TOKEN_PRIVILEGES tpPrevious;
  391. DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);
  392. if(!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE;
  393. //
  394. // first pass. get current privilege setting
  395. //
  396. tp.PrivilegeCount = 1;
  397. tp.Privileges[0].Luid = luid;
  398. tp.Privileges[0].Attributes = 0;
  399. AdjustTokenPrivileges(
  400. hToken,
  401. FALSE,
  402. &tp,
  403. sizeof(TOKEN_PRIVILEGES),
  404. &tpPrevious,
  405. &cbPrevious
  406. );
  407. if (GetLastError() != ERROR_SUCCESS) return FALSE;
  408. //
  409. // second pass. set privilege based on previous setting
  410. //
  411. tpPrevious.PrivilegeCount = 1;
  412. tpPrevious.Privileges[0].Luid = luid;
  413. if(bEnablePrivilege) {
  414. tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
  415. }
  416. else {
  417. tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
  418. tpPrevious.Privileges[0].Attributes);
  419. }
  420. AdjustTokenPrivileges(
  421. hToken,
  422. FALSE,
  423. &tpPrevious,
  424. cbPrevious,
  425. NULL,
  426. NULL
  427. );
  428. if (GetLastError() != ERROR_SUCCESS) return FALSE;
  429. return TRUE;
  430. }
  431. BOOL
  432. SetCurrentPrivilege(
  433. LPCTSTR Privilege, // Privilege to enable/disable
  434. BOOL bEnablePrivilege // to enable or disable privilege
  435. )
  436. {
  437. BOOL bSuccess=FALSE; // assume failure
  438. HANDLE hToken;
  439. if (!OpenThreadToken(
  440. GetCurrentThread(),
  441. TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  442. FALSE,
  443. &hToken)){
  444. if(!OpenProcessToken(
  445. GetCurrentProcess(),
  446. TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  447. &hToken
  448. )) return FALSE;
  449. }
  450. if(SetPrivilege(hToken, Privilege, bEnablePrivilege)) bSuccess=TRUE;
  451. CloseHandle(hToken);
  452. return bSuccess;
  453. }
  454. //
  455. // GetUserSid
  456. //
  457. // This function takes a token, and returns the user SID from that token.
  458. //
  459. // Note: SID must be freed by MyFree()
  460. // hToken is optional... NULL means we'll grab it.
  461. //
  462. extern "C" BOOL
  463. GetUserSid(HANDLE hClientToken,
  464. PSID* ppSid,
  465. DWORD* lpcbSid)
  466. {
  467. DWORD cbUserInfo = 0;
  468. PTOKEN_USER pUserInfo = NULL;
  469. PUCHAR pnSubAuthorityCount = 0;
  470. DWORD cbSid = 0;
  471. BOOL fRet = FALSE;
  472. HANDLE hToken = hClientToken;
  473. *ppSid = NULL;
  474. if (NULL == hClientToken) {
  475. if (!OpenThreadToken(
  476. GetCurrentThread(),
  477. TOKEN_QUERY,
  478. FALSE,
  479. &hToken
  480. )) {
  481. // not impersonating, use process token...
  482. if (!OpenProcessToken(
  483. GetCurrentProcess(),
  484. TOKEN_QUERY,
  485. &hToken
  486. )) {
  487. TERRORVAL(L"OpenProcessToken failed!", GetLastError());
  488. return FALSE;
  489. }
  490. }
  491. }
  492. // this will fail, usually w/ ERROR_INSUFFICIENT_BUFFER
  493. GetTokenInformation(
  494. hToken,
  495. TokenUser,
  496. NULL,
  497. 0,
  498. &cbUserInfo
  499. );
  500. pUserInfo = (PTOKEN_USER) MyAlloc(cbUserInfo);
  501. if (NULL == pUserInfo) {
  502. TERRORVAL(L"ALLOC FAILURE!", E_OUTOFMEMORY);
  503. return FALSE;
  504. }
  505. if (!GetTokenInformation(
  506. hToken,
  507. TokenUser,
  508. pUserInfo,
  509. cbUserInfo,
  510. &cbUserInfo
  511. )) {
  512. TERRORVAL(L"GetTokenInformation failed!", GetLastError());
  513. goto ret;
  514. }
  515. //
  516. // Now that we've got the SID AND ATTRIBUTES struct, get the SID lenght,
  517. // alloc room, and return *just the SID*
  518. //
  519. if (!IsValidSid(pUserInfo->User.Sid)) goto ret;
  520. pnSubAuthorityCount = GetSidSubAuthorityCount(pUserInfo->User.Sid);
  521. cbSid = GetSidLengthRequired(*pnSubAuthorityCount);
  522. *ppSid = (PSID) MyAlloc(cbSid);
  523. if (NULL == *ppSid ) {
  524. TERRORVAL(L"Alloc failed!", E_OUTOFMEMORY);
  525. goto ret;
  526. }
  527. if (!CopySid(
  528. cbSid,
  529. *ppSid,
  530. pUserInfo->User.Sid
  531. )) {
  532. TERRORVAL(L"CopySid failed!", GetLastError());
  533. goto copyerr;
  534. }
  535. *lpcbSid = cbSid; // may be useful later on...
  536. fRet = TRUE;
  537. ret:
  538. if (NULL == hClientToken && NULL != hToken) { // supplied our own
  539. CloseHandle(hToken);
  540. }
  541. if (NULL != pUserInfo) {
  542. MyFree(pUserInfo);
  543. }
  544. return fRet;
  545. copyerr:
  546. if (NULL != *ppSid) {
  547. MyFree(*ppSid);
  548. *ppSid = NULL;
  549. }
  550. goto ret;
  551. }
  552. //
  553. // IsLocalSystem()
  554. // This function makes the determination if the given process token
  555. // is running as local system.
  556. //
  557. BOOL
  558. IsLocalSystem(HANDLE hToken)
  559. {
  560. PSID pLocalSid = NULL, pTokenSid = NULL;
  561. SID_IDENTIFIER_AUTHORITY IDAuthorityNT = SECURITY_NT_AUTHORITY;
  562. DWORD cbSid = 0;
  563. BOOL fRet = FALSE;
  564. if (!GetUserSid(
  565. hToken,
  566. &pTokenSid,
  567. &cbSid
  568. )) {
  569. goto ret;
  570. }
  571. if (!AllocateAndInitializeSid(
  572. &IDAuthorityNT,
  573. 1,
  574. SECURITY_LOCAL_SYSTEM_RID,
  575. 0,0,0,0,0,0,0,
  576. &pLocalSid
  577. )) {
  578. TERRORVAL(L"AllocateAndInitializeSid failed!", GetLastError());
  579. goto ret;
  580. }
  581. if (EqualSid(pLocalSid, pTokenSid)) {
  582. fRet = TRUE; // got one!
  583. }
  584. ret:
  585. if (NULL != pTokenSid) {
  586. MyFree(pTokenSid);
  587. }
  588. if (NULL != pLocalSid) {
  589. FreeSid(pLocalSid);
  590. }
  591. return fRet;
  592. }
  593. //
  594. // GetLocalSystemToken()
  595. //
  596. // This function grabs a process token from a LOCAL SYSTEM process and uses it
  597. // to run as local system for the duration of the test
  598. //
  599. extern "C" DWORD
  600. GetLocalSystemToken(HANDLE* phRet)
  601. {
  602. HANDLE hProcess = NULL;
  603. HANDLE hPToken = NULL, hPTokenNew = NULL, hPDupToken = NULL;
  604. DWORD rgPIDs[MAX_PROCESSES], cbNeeded = 0, dwErr = S_OK, i = 0;
  605. DWORD cbrgPIDs = sizeof(DWORD) * MAX_PROCESSES;
  606. PSECURITY_DESCRIPTOR pSD = NULL;
  607. PSID pSid = NULL;
  608. DWORD cbSid = 0;
  609. BOOL fSet = FALSE;
  610. // SLOW BUFFERs
  611. BYTE rgByte[MAX_SD], rgByte2[MAX_SD];
  612. DWORD cbByte = MAX_SD, cbByte2 = MAX_SD;
  613. *phRet = NULL;
  614. if(!SetCurrentPrivilege(SE_DEBUG_NAME, TRUE)) {
  615. TERROR(L"SetCurrentPrivilege (debug) failed!");
  616. return E_FAIL;
  617. }
  618. if(!SetCurrentPrivilege(SE_TAKE_OWNERSHIP_NAME, TRUE)) {
  619. TERROR(L"SetCurrentPrivilege (to) failed!");
  620. return E_FAIL;
  621. }
  622. if (!EnumProcesses(
  623. rgPIDs,
  624. cbrgPIDs,
  625. &cbNeeded
  626. )) {
  627. dwErr = GetLastError();
  628. TERRORVAL(L"EnumProcesses failed!", dwErr);
  629. goto ret;
  630. }
  631. //
  632. // Get current user's sid for use in expanding SD.
  633. //
  634. if (!GetUserSid(
  635. NULL,
  636. &pSid,
  637. &cbSid
  638. )) {
  639. goto ret;
  640. }
  641. //
  642. // Walk processes until we find one that's running as
  643. // local system
  644. //
  645. for (i = 1; i < (cbNeeded / sizeof(DWORD)); i++) {
  646. hProcess = OpenProcess(
  647. PROCESS_ALL_ACCESS,
  648. FALSE,
  649. rgPIDs[i]
  650. );
  651. if (NULL == hProcess) {
  652. dwErr = GetLastError();
  653. TERRORVAL(L"OpenProcess failed!", dwErr);
  654. goto ret;
  655. }
  656. if (!OpenProcessToken(
  657. hProcess,
  658. READ_CONTROL | WRITE_DAC,
  659. &hPToken
  660. )) {
  661. dwErr = GetLastError();
  662. TERRORVAL(L"OpenProcessToken failed!", dwErr);
  663. goto ret;
  664. }
  665. //
  666. // We've got a token, but we can't use it for
  667. // TOKEN_DUPLICATE access. So, instead, we'll go
  668. // ahead and whack the DACL on the object to grant us
  669. // this access, and get a new token.
  670. // **** BE SURE TO RESTORE hProcess to Original SD!!! ****
  671. //
  672. if (!AddSIDToKernelObjectDacl(
  673. pSid,
  674. TOKEN_DUPLICATE,
  675. hPToken,
  676. &pSD
  677. )) {
  678. goto ret;
  679. }
  680. fSet = TRUE;
  681. if (!OpenProcessToken(
  682. hProcess,
  683. TOKEN_DUPLICATE,
  684. &hPTokenNew
  685. )) {
  686. dwErr = GetLastError();
  687. TERRORVAL(L"OpenProcessToken failed!", dwErr);
  688. goto ret;
  689. }
  690. //
  691. // Duplicate the token
  692. //
  693. if (!DuplicateTokenEx(
  694. hPTokenNew,
  695. TOKEN_ALL_ACCESS,
  696. NULL,
  697. SecurityImpersonation,
  698. TokenPrimary,
  699. &hPDupToken
  700. )) {
  701. dwErr = GetLastError();
  702. TERRORVAL(L"DuplicateToken failed!", dwErr);
  703. goto ret;
  704. }
  705. if (IsLocalSystem(hPDupToken)) {
  706. *phRet = hPDupToken;
  707. break; // found a local system token
  708. }
  709. // Loop cleanup
  710. if (!SetKernelObjectSecurity(
  711. hPToken,
  712. DACL_SECURITY_INFORMATION,
  713. pSD
  714. )) {
  715. dwErr = GetLastError();
  716. TERRORVAL(L"SetKernelObjectSecurity failed!", dwErr);
  717. goto ret;
  718. }
  719. fSet = FALSE;
  720. if (NULL != hPDupToken) {
  721. CloseHandle(hPDupToken);
  722. hPDupToken = NULL;
  723. }
  724. if (NULL != pSD) {
  725. MyFree(pSD);
  726. pSD = NULL;
  727. }
  728. if (NULL != hPToken) {
  729. CloseHandle(hPToken);
  730. hPToken = NULL;
  731. }
  732. if (NULL != hProcess) {
  733. CloseHandle(hProcess);
  734. hProcess = NULL;
  735. }
  736. } // ** FOR **
  737. ret:
  738. //***** REMEMBER TO RESTORE ORIGINAL SD TO OBJECT*****
  739. if (fSet) {
  740. if (!SetKernelObjectSecurity(
  741. hPToken,
  742. DACL_SECURITY_INFORMATION,
  743. pSD
  744. )) {
  745. dwErr = GetLastError();
  746. TERRORVAL(L"SetKernelObjectSecurity failed (cleanup)!", dwErr);
  747. }
  748. }
  749. if (NULL != pSid) {
  750. MyFree(pSid);
  751. }
  752. if (NULL != hPToken) {
  753. CloseHandle(hPToken);
  754. }
  755. if (NULL != pSD) {
  756. MyFree(pSD);
  757. }
  758. if (NULL != hProcess) {
  759. CloseHandle(hProcess);
  760. }
  761. return dwErr;
  762. }