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.

936 lines
21 KiB

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