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.

1261 lines
37 KiB

  1. /********************************************************************
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. util.cpp
  5. Abstract:
  6. utility functions implementation
  7. Revision History:
  8. DerekM created 05/01/99
  9. ********************************************************************/
  10. #include "stdafx.h"
  11. #include "util.h"
  12. #include <ercommon.h>
  13. #include <strsafe.h>
  14. const WCHAR c_wszRKSetup[] = L"System\\Setup";
  15. const WCHAR c_wszRVSetupNow[] = L"SystemSetupInProgress";
  16. const WCHAR c_wszRVMiniSetupNow[] = L"MiniSetupInProgress";
  17. const WCHAR c_wszRVOOBESetupNow[] = L"OobeInProgress";
  18. /////////////////////////////////////////////////////////////////////////////
  19. // tracing
  20. #ifdef THIS_FILE
  21. #undef THIS_FILE
  22. #endif
  23. static char __szTraceSourceFile[] = __FILE__;
  24. #define THIS_FILE __szTraceSourceFile
  25. HANDLE g_hPFPrivateHeap = NULL;
  26. struct SLangCodepage
  27. {
  28. WORD wLanguage;
  29. WORD wCodePage;
  30. };
  31. DWORD SetupIsInProgress(void)
  32. {
  33. DWORD retval = SIIP_NO_SETUP;
  34. HRESULT hr;
  35. HKEY hkey = NULL;
  36. DWORD dw;
  37. USE_TRACING("SetupIsInProgress");
  38. TESTERR(hr, RegOpenKeyExW(HKEY_LOCAL_MACHINE, c_wszRKSetup, 0, KEY_READ,
  39. &hkey));
  40. if (SUCCEEDED(hr))
  41. {
  42. DWORD cbData;
  43. DWORD dwData;
  44. // Are we in GUI mode setup?
  45. cbData = sizeof(dwData);
  46. dwData = 0;
  47. dw = RegQueryValueExW(hkey, c_wszRVSetupNow, NULL, NULL,
  48. (LPBYTE)&dwData, &cbData);
  49. if (dw == ERROR_SUCCESS && dwData != 0)
  50. {
  51. retval = SIIP_GUI_SETUP;
  52. // make certain this is not the OEM mini setup?
  53. cbData = sizeof(dwData);
  54. dwData = 0;
  55. dw = RegQueryValueExW(hkey, c_wszRVMiniSetupNow, NULL, NULL,
  56. (LPBYTE)&dwData, &cbData);
  57. if (dw == ERROR_SUCCESS && dwData != 0)
  58. retval=SIIP_OOBE_SETUP;
  59. }
  60. else
  61. {
  62. /*
  63. * We are not in GUI mode, but it might be the OOBE movie
  64. * or the activation that faulted, and we don't want the DW-UI
  65. * then either as it will halt unattended setup.
  66. */
  67. cbData = sizeof(dwData);
  68. dwData = 0;
  69. dw = RegQueryValueExW(hkey, c_wszRVOOBESetupNow, NULL, NULL,
  70. (LPBYTE)&dwData, &cbData);
  71. if (dw == ERROR_SUCCESS || dwData != 0)
  72. retval=SIIP_OOBE_SETUP;
  73. }
  74. RegCloseKey(hkey);
  75. }
  76. DBG_MSG(retval ? "Setup in progress" : "Setup not running");
  77. return retval;
  78. }
  79. //////////////////////////////////////////////////////////////////////////////
  80. // string stuff
  81. // ***************************************************************************
  82. WCHAR *MyStrStrIW(const WCHAR *wcs1, const WCHAR *wcs2)
  83. {
  84. WCHAR *cp = (WCHAR *)wcs1;
  85. WCHAR *s1, *s2;
  86. while (*cp != '\0')
  87. {
  88. s1 = cp;
  89. s2 = (WCHAR *) wcs2;
  90. while (*s1 != '\0' && *s2 !='\0' && (towlower(*s1) - towlower(*s2)) == 0)
  91. s1++, s2++;
  92. if (*s2 == '\0')
  93. return(cp);
  94. cp++;
  95. }
  96. return(NULL);
  97. }
  98. // ***************************************************************************
  99. CHAR *MyStrStrIA(const CHAR *cs1, const CHAR *cs2)
  100. {
  101. CHAR *cp = (CHAR *)cs1;
  102. CHAR *s1, *s2;
  103. while (*cp != '\0')
  104. {
  105. s1 = cp;
  106. s2 = (CHAR *) cs2;
  107. while (*s1 != '\0' && *s2 !='\0' && (tolower(*s1) - tolower(*s2)) == 0)
  108. s1++, s2++;
  109. if (*s2 == '\0')
  110. return(cp);
  111. cp++;
  112. }
  113. return(NULL);
  114. }
  115. ////////////////////////////////////////////////////////////////////////////
  116. // temp file stuff
  117. // ***************************************************************************
  118. BOOL DeleteTempDirAndFile(LPCWSTR wszPath, BOOL fFilePresent)
  119. {
  120. LPWSTR wszPathToDel = NULL, pwsz;
  121. DWORD cchPath;
  122. BOOL fRet = FALSE;
  123. if (wszPath == NULL)
  124. {
  125. SetLastError(ERROR_INVALID_PARAMETER);
  126. goto done;
  127. }
  128. cchPath = wcslen(wszPath);
  129. __try { wszPathToDel = (LPWSTR)_alloca((cchPath+1) * sizeof(WCHAR)); }
  130. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { wszPathToDel = NULL; }
  131. if (wszPathToDel == NULL)
  132. {
  133. SetLastError(ERROR_OUTOFMEMORY);
  134. goto done;
  135. }
  136. StringCchCopyW(wszPathToDel, cchPath+1, wszPath);
  137. // XXX can hang for up to 25m. In the case of a service, it could prevent its restart for 25m, thus creating a potential vulnerability.
  138. // delete the actual file
  139. if (fFilePresent)
  140. {
  141. if (!DeleteFileW(wszPathToDel))
  142. {
  143. int i=0;
  144. while (i < 300)
  145. {
  146. if (!DeleteFileW(wszPathToDel))
  147. {
  148. Sleep(5000);
  149. i++;
  150. }
  151. else
  152. {
  153. i = 5000;
  154. }
  155. }
  156. }
  157. // next, delete the directory that we put it in
  158. for(pwsz = wszPathToDel + cchPath - 1;
  159. *pwsz != L'\\' && pwsz > wszPathToDel;
  160. pwsz--);
  161. if (*pwsz != L'\\' || pwsz <= wszPathToDel)
  162. goto done;
  163. }
  164. else
  165. {
  166. pwsz = wszPathToDel + cchPath;
  167. }
  168. *pwsz = L'\0';
  169. RemoveDirectoryW(wszPathToDel);
  170. for(pwsz = pwsz - 1;
  171. *pwsz != L'.' && pwsz > wszPathToDel;
  172. pwsz--);
  173. if (*pwsz == L'.' && pwsz > wszPathToDel)
  174. {
  175. *pwsz = L'\0';
  176. DeleteFileW(wszPathToDel);
  177. }
  178. fRet = TRUE;
  179. done:
  180. return fRet;
  181. }
  182. // ***************************************************************************
  183. DWORD CreateTempDirAndFile(LPCWSTR wszTempDir, LPCWSTR wszName,
  184. LPWSTR *pwszPath)
  185. {
  186. LPWSTR wszFilePath = NULL;
  187. WCHAR *wszTemp = NULL;
  188. DWORD cch = 0, cchDir = 0, iSuffix = 0, cSuffix = 0, cFilePathLength;
  189. WCHAR wsz[1024];
  190. BOOL fRet = FALSE;
  191. if (pwszPath == NULL)
  192. {
  193. SetLastError(ERROR_INVALID_PARAMETER);
  194. goto done;
  195. }
  196. *pwszPath = NULL;
  197. if (wszTempDir != NULL)
  198. cch = wcslen(wszTempDir);
  199. if (cch == 0)
  200. {
  201. cch = GetTempPathW(0, NULL);
  202. if (cch == 0)
  203. goto done;
  204. }
  205. // compute the size of the buffer for the string we're going
  206. // to generate. The 20 includes the following:
  207. // max size of the temp filename
  208. // extra space for the NULL terminator.
  209. cch += (16 + sizeofSTRW(c_wszDirSuffix));
  210. if (wszName != NULL)
  211. cch += wcslen(wszName);
  212. // ok, so GetTempFileName likes to write MAX_PATH characters to the buffer,
  213. // so make sure it's at least MAX_PATH in size...
  214. cFilePathLength = cch = MyMax(cch, MAX_PATH + 1);
  215. wszFilePath = (LPWSTR)MyAlloc(cch * sizeof(WCHAR));
  216. if (wszFilePath == NULL)
  217. {
  218. SetLastError(ERROR_OUTOFMEMORY);
  219. goto done;
  220. }
  221. if (wszTempDir != NULL && wszTempDir[0] != L'\0')
  222. {
  223. cch = wcslen(wszTempDir);
  224. wszTemp = (LPWSTR)wszTempDir;
  225. }
  226. else
  227. {
  228. cch = GetTempPathW(cch, wszFilePath);
  229. if (cch == 0)
  230. goto done;
  231. cch++;
  232. // create the temp dir (in case it is not)
  233. // ignoring the result (bug 526753)
  234. CreateDirectoryW(wszFilePath, NULL);
  235. __try { wszTemp = (WCHAR *)_alloca(cch * sizeof(WCHAR)); }
  236. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { wszTemp = NULL; }
  237. if (wszTemp == NULL)
  238. {
  239. SetLastError(ERROR_OUTOFMEMORY);
  240. goto done;
  241. }
  242. StringCchCopyW(wszTemp, cch, wszFilePath);
  243. }
  244. cch = GetTempFileNameW(wszTemp, L"WER", 0, wszFilePath);
  245. if (cch == 0)
  246. goto done;
  247. cch = wcslen(wszFilePath);
  248. if (cch >= cFilePathLength)
  249. {
  250. goto done;
  251. }
  252. StringCchCopyW(&wszFilePath[cch], cFilePathLength - cch, c_wszDirSuffix);
  253. // iSuffix points to the first digit of the '00' at the end of
  254. // c_wszDirSuffix
  255. iSuffix = cch + sizeofSTRW(c_wszDirSuffix) - 3;
  256. cSuffix = 1;
  257. do
  258. {
  259. fRet = CreateDirectoryW(wszFilePath, NULL);
  260. if (fRet)
  261. break;
  262. wszFilePath[iSuffix] = L'0' + (WCHAR)(cSuffix / 10);
  263. wszFilePath[iSuffix + 1] = L'0' + (WCHAR)(cSuffix % 10);
  264. cSuffix++;
  265. }
  266. while (cSuffix <= 100);
  267. // hmm, couldn't create the directory...
  268. if (cSuffix > 100)
  269. {
  270. cchDir = cch;
  271. cch = 0;
  272. goto done;
  273. }
  274. cch += (sizeofSTRW(c_wszDirSuffix) - 1);
  275. if (wszName != NULL && cch < cFilePathLength)
  276. {
  277. wszFilePath[cch++] = L'\\';
  278. StringCchCopyW(&wszFilePath[cch], cFilePathLength - cch, wszName);
  279. cch += wcslen(wszName);
  280. }
  281. *pwszPath = wszFilePath;
  282. wszFilePath = NULL;
  283. fRet = TRUE;
  284. done:
  285. if (wszFilePath != NULL)
  286. {
  287. if (cchDir > 0)
  288. {
  289. wszFilePath[cchDir] = L'\0';
  290. DeleteFileW(wszFilePath);
  291. }
  292. MyFree(wszFilePath);
  293. }
  294. return cch;
  295. }
  296. BOOL
  297. DeleteFullAndTriageMiniDumps(
  298. LPCWSTR wszPath
  299. )
  300. //
  301. // We create a FullMinidump file along with triage minidump in the same dir
  302. // This routine cleans up both those files
  303. //
  304. {
  305. LPWSTR wszFullMinidump = NULL;
  306. DWORD cch;
  307. BOOL fRet;
  308. fRet = DeleteFileW(wszPath);
  309. cch = wcslen(wszPath) + sizeofSTRW(c_wszHeapDumpSuffix);
  310. __try { wszFullMinidump = (WCHAR *)_alloca(cch * sizeof(WCHAR)); }
  311. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { wszFullMinidump = NULL; }
  312. if (wszFullMinidump)
  313. {
  314. LPWSTR wszFileExt = NULL;
  315. // Build Dump-with-heap path
  316. StringCchCopyW(wszFullMinidump, cch, wszPath);
  317. wszFileExt = wszFullMinidump + wcslen(wszFullMinidump) - sizeofSTRW(c_wszDumpSuffix) + 1;
  318. if (!wcscmp(wszFileExt, c_wszDumpSuffix))
  319. {
  320. *wszFileExt = L'\0';
  321. }
  322. StringCchCatW(wszFullMinidump, cch, c_wszHeapDumpSuffix);
  323. fRet = DeleteFileW(wszFullMinidump);
  324. } else
  325. {
  326. fRet = FALSE;
  327. }
  328. return fRet;
  329. }
  330. ////////////////////////////////////////////////////////////////////////////
  331. // File mapping
  332. // **************************************************************************
  333. HRESULT OpenFileMapped(LPWSTR wszFile, LPVOID *ppvFile, DWORD *pcbFile)
  334. {
  335. USE_TRACING("OpenFileMapped");
  336. HRESULT hr = NOERROR;
  337. HANDLE hMMF = NULL;
  338. HANDLE hFile = INVALID_HANDLE_VALUE;
  339. LPVOID pvFile = NULL;
  340. DWORD cbFile = 0;
  341. VALIDATEPARM(hr, (wszFile == NULL || ppvFile == NULL));
  342. if (FAILED(hr))
  343. goto done;
  344. *ppvFile = NULL;
  345. if (pcbFile != NULL)
  346. *pcbFile = 0;
  347. hFile = CreateFileW(wszFile, GENERIC_READ, FILE_SHARE_READ, NULL,
  348. OPEN_EXISTING, 0, NULL);
  349. TESTBOOL(hr, (hFile != INVALID_HANDLE_VALUE));
  350. if (FAILED(hr))
  351. goto done;
  352. cbFile = GetFileSize(hFile, NULL);
  353. TESTBOOL(hr, (cbFile != (DWORD)-1));
  354. if (FAILED(hr))
  355. goto done;
  356. hMMF = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, cbFile, NULL);
  357. TESTBOOL(hr, (hMMF != NULL));
  358. if (FAILED(hr))
  359. goto done;
  360. pvFile = MapViewOfFile(hMMF, FILE_MAP_READ, 0, 0, 0);
  361. TESTBOOL(hr, (pvFile != NULL));
  362. if (FAILED(hr))
  363. goto done;
  364. *ppvFile = pvFile;
  365. if (pcbFile != NULL)
  366. *pcbFile = cbFile;
  367. done:
  368. if (hMMF != NULL)
  369. CloseHandle(hMMF);
  370. if (hFile != NULL)
  371. CloseHandle(hFile);
  372. return hr;
  373. }
  374. // **************************************************************************
  375. HRESULT DeleteTempFile(LPWSTR wszFile)
  376. {
  377. USE_TRACING("DeleteTempFile");
  378. HRESULT hr = NOERROR;
  379. WCHAR *pwsz;
  380. if (wszFile == NULL)
  381. return NOERROR;
  382. // strip off the extension at the end (if it's not a .tmp)
  383. for(pwsz = wszFile + wcslen(wszFile); *pwsz != L'.' && pwsz > wszFile; pwsz--);
  384. if (pwsz > wszFile && _wcsicmp(pwsz, L".tmp") != 0)
  385. *pwsz = L'\0';
  386. if (DeleteFileW(wszFile) == FALSE)
  387. hr = Err2HR(GetLastError());
  388. // can do this even if the extension was a tmp since the value pointed to
  389. // by pwsz is '.' if it's greater than wszFile...
  390. if (pwsz > wszFile)
  391. *pwsz = L'.';
  392. return hr;
  393. }
  394. // **************************************************************************
  395. HRESULT MyCallNamedPipe(LPCWSTR wszPipe, LPVOID pvIn, DWORD cbIn,
  396. LPVOID pvOut, DWORD cbOut, DWORD *pcbRead,
  397. DWORD dwWaitPipe, DWORD dwWaitRead)
  398. {
  399. HRESULT hr = NOERROR;
  400. HANDLE hPipe = INVALID_HANDLE_VALUE;
  401. HANDLE hev = NULL;
  402. DWORD dwStart = GetTickCount(), dwNow, dw;
  403. BOOL fRet;
  404. USE_TRACING("MyCallNamedPipe");
  405. VALIDATEPARM(hr, (wszPipe == NULL || pvIn == NULL || pvOut == NULL || pcbRead == NULL));
  406. if (FAILED(hr))
  407. {
  408. SetLastError(ERROR_INVALID_PARAMETER);
  409. hr = E_INVALIDARG;
  410. goto done;
  411. }
  412. *pcbRead = 0;
  413. for(;;)
  414. {
  415. hPipe = CreateFileW(wszPipe, GENERIC_READ | GENERIC_WRITE,
  416. FILE_SHARE_READ | FILE_SHARE_WRITE,
  417. NULL, OPEN_EXISTING,
  418. FILE_FLAG_OVERLAPPED | SECURITY_IDENTIFICATION |
  419. SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING,
  420. NULL);
  421. if (hPipe != INVALID_HANDLE_VALUE)
  422. break;
  423. // if we get ACCESS_DENIED to the above, then WaitNamedPipe will
  424. // return SUCCESS, so we get stuck until the timeout expires. Better
  425. // to just bail now.
  426. if (GetLastError() == ERROR_ACCESS_DENIED)
  427. goto done;
  428. TESTBOOL(hr, WaitNamedPipeW(wszPipe, dwWaitPipe));
  429. if (FAILED(hr))
  430. goto done;
  431. dwNow = GetTickCount();
  432. if (dwNow < dwStart)
  433. dw = ((DWORD)-1 - dwStart) + dwNow;
  434. else
  435. dw = dwNow - dwStart;
  436. if (dw >= dwWaitPipe)
  437. dwWaitPipe = 0;
  438. else
  439. dwWaitPipe -= dw;
  440. if (dwWaitPipe == 0)
  441. {
  442. SetLastError(ERROR_TIMEOUT);
  443. goto done;
  444. }
  445. }
  446. __try
  447. {
  448. OVERLAPPED ol;
  449. DWORD dwMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
  450. DWORD cbRead = 0;
  451. // Default open is readmode byte stream- change to message mode.
  452. TESTBOOL(hr, SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL))
  453. if (FAILED(hr))
  454. __leave;
  455. // we need an event for the overlapped structure
  456. hev = CreateEventW(NULL, TRUE, FALSE, NULL);
  457. TESTBOOL(hr, (hev != NULL));
  458. if (FAILED(hr))
  459. __leave;
  460. // populate the overlapped stuff
  461. ZeroMemory(&ol, sizeof(ol));
  462. ol.hEvent = hev;
  463. fRet = TransactNamedPipe(hPipe, pvIn, cbIn, pvOut, cbOut, &cbRead,
  464. &ol);
  465. if (GetLastError() != ERROR_IO_PENDING)
  466. {
  467. if (fRet)
  468. {
  469. SetEvent(hev);
  470. }
  471. else
  472. {
  473. hr = Err2HR(GetLastError());
  474. __leave;
  475. }
  476. }
  477. dw = WaitForSingleObject(hev, dwWaitRead);
  478. if (dw != WAIT_OBJECT_0)
  479. {
  480. hr = (dw == WAIT_TIMEOUT) ? Err2HR(WAIT_TIMEOUT) :
  481. Err2HR(GetLastError());
  482. __leave;
  483. }
  484. TESTBOOL(hr, GetOverlappedResult(hPipe, &ol, &cbRead, FALSE));
  485. if (FAILED(hr))
  486. __leave;
  487. *pcbRead = cbRead;
  488. hr = NOERROR;
  489. }
  490. __finally
  491. {
  492. }
  493. done:
  494. dw = GetLastError();
  495. if (hPipe != INVALID_HANDLE_VALUE)
  496. CloseHandle(hPipe);
  497. if (hev != NULL)
  498. CloseHandle(hev);
  499. SetLastError(dw);
  500. return hr;
  501. }
  502. //////////////////////////////////////////////////////////////////////////////
  503. // Security stuff
  504. // ***************************************************************************
  505. #define MEMBER_ACCESS 1
  506. BOOL IsUserAnAdmin(HANDLE hToken)
  507. {
  508. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  509. SECURITY_DESCRIPTOR *psdAdm = NULL;
  510. GENERIC_MAPPING gm;
  511. PRIVILEGE_SET *pPS;
  512. HANDLE hTokenImp = NULL;
  513. DWORD cbSD, cbPS, dwGranted = 0;
  514. BYTE rgBuf[sizeof(PRIVILEGE_SET) + 3 * sizeof(LUID_AND_ATTRIBUTES)];
  515. BOOL fRet = FALSE, fStatus;
  516. PSID psidAdm = NULL;
  517. PACL pACL = NULL;
  518. HRESULT hr;
  519. ULONG IsMember;
  520. USE_TRACING("IsUserAnAdmin");
  521. gm.GenericRead = GENERIC_READ;
  522. gm.GenericWrite = GENERIC_WRITE;
  523. gm.GenericExecute = GENERIC_EXECUTE;
  524. gm.GenericAll = GENERIC_ALL;
  525. pPS = (PRIVILEGE_SET *)rgBuf;
  526. cbPS = sizeof(rgBuf);
  527. // AccessCheck() reqires an impersonation token...
  528. TESTBOOL(hr, DuplicateToken(hToken, SecurityImpersonation, &hTokenImp));
  529. if (FAILED(hr))
  530. goto done;
  531. // construct a SID that contains the administrator's group.
  532. TESTBOOL(hr, AllocateAndInitializeSid(&sia, 2, SECURITY_BUILTIN_DOMAIN_RID,
  533. DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
  534. 0, &psidAdm));
  535. if (FAILED(hr))
  536. goto done;
  537. #if 0
  538. // XXX - a simpler way??
  539. if (CheckTokenMembership(hToken, psidAdm, &IsMember))
  540. {
  541. return IsMember;
  542. }
  543. #endif
  544. cbSD = sizeof(SECURITY_DESCRIPTOR) + sizeof(ACCESS_ALLOWED_ACE) +
  545. sizeof(ACL) + 3 * GetLengthSid(psidAdm);
  546. __try { psdAdm = (SECURITY_DESCRIPTOR *)_alloca(cbSD); }
  547. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { psdAdm = NULL; }
  548. if (psdAdm == NULL)
  549. goto done;
  550. ZeroMemory(psdAdm, cbSD);
  551. pACL = (PACL)(psdAdm + 1);
  552. TESTBOOL(hr, InitializeSecurityDescriptor(psdAdm, SECURITY_DESCRIPTOR_REVISION));
  553. if (FAILED(hr))
  554. goto done;
  555. TESTBOOL(hr, SetSecurityDescriptorOwner(psdAdm, psidAdm, FALSE));
  556. if (FAILED(hr))
  557. goto done;
  558. TESTBOOL(hr, SetSecurityDescriptorGroup(psdAdm, psidAdm, FALSE));
  559. if (FAILED(hr))
  560. goto done;
  561. TESTBOOL(hr, InitializeAcl(pACL, cbSD - sizeof(SECURITY_DESCRIPTOR), ACL_REVISION));
  562. if (FAILED(hr))
  563. goto done;
  564. TESTBOOL(hr, AddAccessAllowedAce(pACL, ACL_REVISION, MEMBER_ACCESS, psidAdm));
  565. if (FAILED(hr))
  566. goto done;
  567. TESTBOOL(hr, SetSecurityDescriptorDacl(psdAdm, TRUE, pACL, FALSE));
  568. if (FAILED(hr))
  569. goto done;
  570. TESTBOOL(hr, AccessCheck(psdAdm, hTokenImp, MEMBER_ACCESS, &gm, pPS, &cbPS,
  571. &dwGranted, &fStatus));
  572. if (FAILED(hr))
  573. goto done;
  574. fRet = (fStatus && dwGranted == MEMBER_ACCESS);
  575. done:
  576. if (psidAdm != NULL)
  577. FreeSid(psidAdm);
  578. if (hTokenImp != NULL)
  579. CloseHandle(hTokenImp);
  580. return fRet;
  581. }
  582. // ***************************************************************************
  583. BOOL AllocSD(SECURITY_DESCRIPTOR *psd, DWORD dwOLs, DWORD dwAd, DWORD dwWA)
  584. {
  585. SID_IDENTIFIER_AUTHORITY siaCreate = SECURITY_CREATOR_SID_AUTHORITY;
  586. SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY;
  587. SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY;
  588. DWORD cb, dw;
  589. PACL pacl = NULL;
  590. PSID psidOwner = NULL;
  591. PSID psidLS = NULL;
  592. PSID psidWorld = NULL;
  593. PSID psidAnon = NULL;
  594. PSID psidAdm = NULL;
  595. BOOL fRet = FALSE;
  596. if (psd == NULL)
  597. {
  598. SetLastError(ERROR_INVALID_PARAMETER);
  599. goto done;
  600. }
  601. fRet = InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
  602. if (fRet == FALSE)
  603. goto done;
  604. // get the SID for local system acct
  605. fRet = AllocateAndInitializeSid(&siaNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0,
  606. 0, 0, 0, 0, 0, &psidLS);
  607. if (fRet == FALSE)
  608. goto done;
  609. // get the SID for the creator
  610. fRet = AllocateAndInitializeSid(&siaCreate, 1, SECURITY_CREATOR_OWNER_RID,
  611. 0, 0, 0, 0, 0, 0, 0, &psidOwner);
  612. if (fRet == FALSE)
  613. goto done;
  614. cb = sizeof(ACL) + GetLengthSid(psidLS) + GetLengthSid(psidOwner) +
  615. 2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD));
  616. // if we have an access mask to apply for the administrators group, then
  617. // we need it's SID.
  618. if (dwAd != 0)
  619. {
  620. // get the SID for the local administrators group
  621. fRet = AllocateAndInitializeSid(&siaNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
  622. DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
  623. 0, &psidAdm);
  624. if (fRet == FALSE)
  625. goto done;
  626. cb += (GetLengthSid(psidAdm) + sizeof(ACCESS_ALLOWED_ACE) -
  627. sizeof(DWORD));
  628. }
  629. // if we have an access mask to apply for world / anonymous, then we need
  630. // their SIDs
  631. if (dwWA != 0)
  632. {
  633. // get the SID for the world (everyone)
  634. fRet = AllocateAndInitializeSid(&siaNT, 1, SECURITY_ANONYMOUS_LOGON_RID,
  635. 0, 0, 0, 0, 0, 0, 0, &psidWorld);
  636. // get the SID for the anonymous users acct
  637. fRet = AllocateAndInitializeSid(&siaWorld, 1, SECURITY_WORLD_RID,
  638. 0, 0, 0, 0, 0, 0, 0, &psidAnon);
  639. if (fRet == FALSE)
  640. goto done;
  641. cb += GetLengthSid(psidWorld) + GetLengthSid(psidAnon) +
  642. 2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD));
  643. }
  644. // make the DACL
  645. pacl = (PACL)MyAlloc(cb);
  646. if (pacl == NULL)
  647. {
  648. SetLastError(ERROR_OUTOFMEMORY);
  649. fRet = FALSE;
  650. goto done;
  651. }
  652. fRet = InitializeAcl(pacl, cb, ACL_REVISION);
  653. if (fRet == FALSE)
  654. goto done;
  655. fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwOLs, psidOwner);
  656. if (fRet == FALSE)
  657. goto done;
  658. fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwOLs, psidLS);
  659. if (fRet == FALSE)
  660. goto done;
  661. // if we have an administrator access mask, then apply it
  662. if (dwAd != 0)
  663. {
  664. fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwAd, psidAdm);
  665. if (fRet == FALSE)
  666. goto done;
  667. }
  668. // if we have a world / anonymous access mask, then apply it
  669. if (dwWA != 0)
  670. {
  671. fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwWA, psidWorld);
  672. if (fRet == FALSE)
  673. goto done;
  674. fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwWA, psidAnon);
  675. if (fRet == FALSE)
  676. goto done;
  677. }
  678. // set the SD dacl
  679. fRet = SetSecurityDescriptorDacl(psd, TRUE, pacl, FALSE);
  680. if (fRet == FALSE)
  681. goto done;
  682. pacl = NULL;
  683. done:
  684. dw = GetLastError();
  685. if (psidLS != NULL)
  686. FreeSid(psidLS);
  687. if (psidWorld != NULL)
  688. FreeSid(psidWorld);
  689. if (psidAnon != NULL)
  690. FreeSid(psidAnon);
  691. if (psidAdm != NULL)
  692. FreeSid(psidAdm);
  693. if (psidOwner != NULL)
  694. FreeSid(psidOwner);
  695. if (pacl != NULL)
  696. MyFree(pacl);
  697. SetLastError(dw);
  698. return fRet;
  699. }
  700. // ***************************************************************************
  701. void FreeSD(SECURITY_DESCRIPTOR *psd)
  702. {
  703. PSID psid = NULL;
  704. PACL pacl = NULL;
  705. BOOL f, f2;
  706. if (psd == NULL)
  707. return;
  708. if (GetSecurityDescriptorDacl(psd, &f, &pacl, &f2) && pacl != NULL)
  709. MyFree(pacl);
  710. }
  711. //////////////////////////////////////////////////////////////////////////////
  712. // Registry stuff
  713. // **************************************************************************
  714. HRESULT OpenRegKey(HKEY hkeyMain, LPCWSTR wszSubKey, DWORD dwOpt,
  715. HKEY *phkey)
  716. {
  717. USE_TRACING("OpenRegKey");
  718. HRESULT hr = NOERROR;
  719. REGSAM samDesired;
  720. DWORD dwErr;
  721. VALIDATEPARM(hr, (hkeyMain == NULL || wszSubKey == NULL || phkey == NULL));
  722. if (FAILED(hr))
  723. goto done;
  724. *phkey = NULL;
  725. samDesired = ((dwOpt & orkWantWrite) != 0) ? KEY_ALL_ACCESS : KEY_READ;
  726. samDesired |= ((dwOpt & orkUseWOW64) != 0) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
  727. // first try calling RegCreateKeyEx to make sure we create the key if
  728. // it doesn't exist
  729. TESTERR(hr, RegCreateKeyExW(hkeyMain, wszSubKey, 0, NULL, 0, samDesired,
  730. NULL, phkey, NULL));
  731. if (FAILED(hr))
  732. {
  733. // ok, that didn't work, so try opening the key instead
  734. TESTERR(hr, RegOpenKeyExW(hkeyMain, wszSubKey, 0, samDesired, phkey));
  735. }
  736. ErrorTrace(0, "OpenRegKey = [%S], %s", wszSubKey, FAILED(hr) ? "fail": "success");
  737. done:
  738. return hr;
  739. }
  740. // **************************************************************************
  741. HRESULT ReadRegEntry(HKEY hkey, LPCWSTR wszValName, DWORD *pdwType,
  742. PBYTE pbBuffer, DWORD *pcbBuffer, PBYTE pbDefault,
  743. DWORD cbDefault)
  744. {
  745. USE_TRACING("ReadRegEntry");
  746. HRESULT hr = NOERROR;
  747. DWORD dwErr;
  748. VALIDATEPARM(hr, (hkey == NULL || wszValName == NULL));
  749. if (FAILED(hr))
  750. goto done;
  751. // ErrorTrace(0, "ReadRegEntry = %S", wszValName);
  752. dwErr = RegQueryValueExW(hkey, wszValName, 0, pdwType, pbBuffer,
  753. pcbBuffer);
  754. VALIDATEEXPR(hr, (dwErr != ERROR_PATH_NOT_FOUND &&
  755. dwErr != ERROR_FILE_NOT_FOUND &&
  756. dwErr != ERROR_SUCCESS), Err2HR(dwErr));
  757. if (FAILED(hr))
  758. goto done;
  759. if (dwErr != ERROR_SUCCESS && pbDefault != NULL)
  760. {
  761. VALIDATEPARM(hr, (pcbBuffer == NULL && pbBuffer != NULL));
  762. if (FAILED(hr))
  763. goto done;
  764. // if the receiving buffer is NULL, just return the error that
  765. // RegQueryValueEx gave us cuz the user doesn't really want the
  766. // value anyway
  767. VALIDATEEXPR(hr, (pcbBuffer == NULL), Err2HR(dwErr));
  768. if (FAILED(hr))
  769. goto done;
  770. if (pbBuffer == NULL)
  771. {
  772. *pcbBuffer = cbDefault;
  773. hr = NOERROR;
  774. goto done;
  775. }
  776. else if (cbDefault > *pcbBuffer)
  777. {
  778. *pcbBuffer = cbDefault;
  779. hr = Err2HR(ERROR_MORE_DATA);
  780. goto done;
  781. }
  782. CopyMemory(pbBuffer, pbDefault, cbDefault);
  783. *pcbBuffer = cbDefault;
  784. if (pdwType != NULL)
  785. *pdwType = REG_BINARY;
  786. hr = NOERROR;
  787. goto done;
  788. }
  789. done:
  790. return hr;
  791. }
  792. // **************************************************************************
  793. HRESULT ReadRegEntry(HKEY *rghkey, DWORD cKeys, LPCWSTR wszValName,
  794. DWORD *pdwType, PBYTE pbBuffer, DWORD *pcbBuffer,
  795. PBYTE pbDefault, DWORD cbDefault, DWORD *piKey)
  796. {
  797. USE_TRACING("ReadRegEntryPolicy");
  798. HRESULT hr = NOERROR;
  799. DWORD dwErr=ERROR_SUCCESS, i;
  800. VALIDATEPARM(hr, (rghkey == NULL || wszValName == NULL));
  801. if (FAILED(hr))
  802. goto done;
  803. // ErrorTrace(0, "ReadRegEntryPolicy = %S", wszValName);
  804. for(i = 0; i < cKeys; i++)
  805. {
  806. dwErr = RegQueryValueExW(rghkey[i], wszValName, 0, pdwType, pbBuffer,
  807. pcbBuffer);
  808. VALIDATEEXPR(hr, (dwErr != ERROR_PATH_NOT_FOUND &&
  809. dwErr != ERROR_FILE_NOT_FOUND &&
  810. dwErr != ERROR_SUCCESS), Err2HR(dwErr));
  811. if (FAILED(hr))
  812. goto done;
  813. if (dwErr == ERROR_SUCCESS)
  814. {
  815. if (piKey != NULL)
  816. *piKey = i;
  817. // ErrorTrace(0, " found value [0x%x] in %s", (DWORD*) *pbDefault, i?"registry" : "policy");
  818. break;
  819. }
  820. }
  821. if (dwErr != ERROR_SUCCESS && pbDefault != NULL)
  822. {
  823. VALIDATEPARM(hr, (pcbBuffer == NULL && pbBuffer != NULL));
  824. if (FAILED(hr))
  825. goto done;
  826. // if the receiving buffer is NULL, just return the error that
  827. // RegQueryValueEx gave us cuz the user doesn't really want the
  828. // value anyway
  829. VALIDATEEXPR(hr, (pcbBuffer == NULL), Err2HR(dwErr));
  830. if (FAILED(hr))
  831. goto done;
  832. if (pbBuffer == NULL)
  833. {
  834. *pcbBuffer = cbDefault;
  835. hr = NOERROR;
  836. goto done;
  837. }
  838. else if (cbDefault > *pcbBuffer)
  839. {
  840. *pcbBuffer = cbDefault;
  841. hr = Err2HR(ERROR_MORE_DATA);
  842. goto done;
  843. }
  844. CopyMemory(pbBuffer, pbDefault, cbDefault);
  845. *pcbBuffer = cbDefault;
  846. if (pdwType != NULL)
  847. *pdwType = REG_BINARY;
  848. if (piKey != NULL)
  849. *piKey = cKeys;
  850. hr = NOERROR;
  851. // ErrorTrace(0, " not found, applying default [0x%x]", (DWORD*) *pbDefault);
  852. goto done;
  853. }
  854. done:
  855. return hr;
  856. }
  857. //////////////////////////////////////////////////////////////////////////////
  858. // version info stuff
  859. // **************************************************************************
  860. DWORD IsMicrosoftApp(LPWSTR wszAppPath, PBYTE pbAppInfo, DWORD cbAppInfo)
  861. {
  862. USE_TRACING("IsMicrosoftApp");
  863. SLangCodepage *plc;
  864. HRESULT hr = NOERROR;
  865. LPWSTR pwszName, pwszNameK32, wszModK32;
  866. WCHAR wszQueryString[128];
  867. DWORD cbFVI, cbFVIK32, dwJunk, dwRet = 0;
  868. PBYTE pbFVI = NULL, pbFVIK32 = NULL;
  869. UINT cb, cbVerInfo, i, cchNeed, cch;
  870. VALIDATEPARM(hr, (wszAppPath == NULL &&
  871. (pbAppInfo == NULL || cbAppInfo == 0)));
  872. if (FAILED(hr))
  873. goto done;
  874. if (pbAppInfo == NULL)
  875. {
  876. // dwJunk is a useful parameter. Gotta pass it in so the function call
  877. // set it to 0. Gee this would make a great (tho non-efficient)
  878. // way to set DWORDs to 0. Much better than saying dwJunk = 0 by itself.
  879. cbFVI = GetFileVersionInfoSizeW(wszAppPath, &dwJunk);
  880. TESTBOOL(hr, (cbFVI != 0))
  881. if (FAILED(hr))
  882. {
  883. ErrorTrace(0, " failed to find module \'%s\', hr=", wszAppPath, hr);
  884. // if it fails, assume the file doesn't have any version info &
  885. // return S_FALSE
  886. hr = S_FALSE;
  887. goto done;
  888. }
  889. // alloca only throws exceptions so gotta catch 'em here....
  890. __try { pbFVI = (PBYTE)_alloca(cbFVI); }
  891. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { pbFVI = NULL; }
  892. VALIDATEEXPR(hr, (pbFVI == NULL), E_OUTOFMEMORY);
  893. if (FAILED(hr))
  894. goto done;
  895. cb = cbFVI;
  896. TESTBOOL(hr, GetFileVersionInfoW(wszAppPath, 0, cbFVI, (LPVOID *)pbFVI));
  897. if (FAILED(hr))
  898. {
  899. // if it fails, assume the file doesn't have any version info &
  900. // return S_FALSE
  901. hr = S_FALSE;
  902. goto done;
  903. }
  904. }
  905. else
  906. {
  907. pbFVI = pbAppInfo;
  908. cbFVI = cbAppInfo;
  909. }
  910. // get the info for kernel32.dll
  911. cchNeed = GetSystemDirectoryW(NULL, 0);
  912. if (cchNeed == 0)
  913. goto done;
  914. cchNeed += (sizeofSTRW(L"\\kernel32.dll") + 1);
  915. __try { wszModK32 = (LPWSTR)_alloca(cchNeed * sizeof(WCHAR)); }
  916. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { wszModK32 = NULL; }
  917. VALIDATEEXPR(hr, (wszModK32 == NULL), E_OUTOFMEMORY);
  918. if (FAILED(hr))
  919. goto done;
  920. // get the info for kernel32.dll
  921. cch = GetSystemDirectoryW(wszModK32, cchNeed);
  922. if (cch == 0)
  923. goto done;
  924. if (*(wszModK32 + cch - 1) == L'\\')
  925. *(wszModK32 + cch - 1) = L'\0';
  926. StringCchCatW(wszModK32, cchNeed, L"\\kernel32.dll");
  927. // dwJunk is a useful parameter. Gotta pass it in so the function call
  928. // set it to 0. Gee this would make a great (tho non-efficient)
  929. // way to set DWORDs to 0. Much better than saying dwJunk = 0 by itself.
  930. cbFVIK32 = GetFileVersionInfoSizeW(wszModK32, &dwJunk);
  931. TESTBOOL(hr, (cbFVIK32 != 0));
  932. if (FAILED(hr))
  933. {
  934. ErrorTrace(0, " failed to find module \'%s\', hr=", wszAppPath, hr);
  935. // if it fails, assume the file doesn't have any version info &
  936. // return S_FALSE
  937. hr = S_FALSE;
  938. goto done;
  939. }
  940. // alloca only throws exceptions so gotta catch 'em here....
  941. __try { pbFVIK32 = (PBYTE)_alloca(cbFVIK32); }
  942. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { pbFVIK32 = NULL; }
  943. VALIDATEEXPR(hr, (pbFVIK32 == NULL), E_OUTOFMEMORY);
  944. if (FAILED(hr))
  945. goto done;
  946. cb = cbFVI;
  947. TESTBOOL(hr, GetFileVersionInfoW(wszModK32, 0, cbFVIK32, (LPVOID *)pbFVIK32));
  948. if (FAILED(hr))
  949. {
  950. // if it fails, assume the file doesn't have any version info &
  951. // return S_FALSE
  952. hr = S_FALSE;
  953. goto done;
  954. }
  955. // Ok, since we can have any number of languages in the module, gotta
  956. // grep thru all of them & see if the company name field includes
  957. // 'Microsoft'.
  958. TESTBOOL(hr, VerQueryValueW(pbFVI, L"\\VarFileInfo\\Translation",
  959. (LPVOID *)&plc, &cbVerInfo));
  960. if (FAILED(hr))
  961. {
  962. // if it fails, assume the file doesn't have any version info &
  963. // return S_FALSE
  964. hr = S_FALSE;
  965. goto done;
  966. }
  967. // Read the file description for each language and code page.
  968. for(i = 0; i < (cbVerInfo / sizeof(SLangCodepage)); i++)
  969. {
  970. StringCchPrintfW(wszQueryString, sizeof(wszQueryString)/sizeof(WCHAR),
  971. L"\\StringFileInfo\\%04x%04x\\CompanyName",
  972. plc[i].wLanguage, plc[i].wCodePage);
  973. // Retrieve file description for language and code page "i".
  974. TESTBOOL(hr, VerQueryValueW(pbFVI, wszQueryString,
  975. (LPVOID *)&pwszName, &cb));
  976. if (FAILED(hr))
  977. continue;
  978. // see if the string contains the word 'Microsoft'
  979. if (MyStrStrIW(pwszName, L"Microsoft") != NULL)
  980. {
  981. dwRet |= APP_MSAPP;
  982. goto doneCompany;
  983. }
  984. // ok, didn't match the word 'Microsoft', so instead, see if it matches
  985. // the string in kernel32.dll
  986. TESTBOOL(hr, VerQueryValueW(pbFVIK32, wszQueryString,
  987. (LPVOID *)&pwszNameK32, &cb));
  988. if (FAILED(hr))
  989. continue;
  990. if (CompareStringW(MAKELCID(plc[i].wLanguage, SORT_DEFAULT),
  991. NORM_IGNORECASE | NORM_IGNOREKANATYPE |
  992. NORM_IGNOREWIDTH | SORT_STRINGSORT,
  993. pwszName, -1, pwszNameK32, -1) == CSTR_EQUAL)
  994. dwRet |= APP_MSAPP;
  995. else
  996. continue;
  997. doneCompany:
  998. StringCchPrintfW(wszQueryString, sizeof(wszQueryString)/sizeof(WCHAR),
  999. L"\\StringFileInfo\\%04x%04x\\ProductName",
  1000. plc[i].wLanguage, plc[i].wCodePage);
  1001. // Retrieve file description for language and code page "i".
  1002. TESTBOOL(hr, VerQueryValueW(pbFVI, wszQueryString,
  1003. (LPVOID *)&pwszName, &cb));
  1004. if (FAILED(hr))
  1005. continue;
  1006. // see if the string contains the words 'Microsoft� Windows�'
  1007. if (MyStrStrIW(pwszName, L"Microsoft� Windows�") != NULL)
  1008. {
  1009. dwRet |= APP_WINCOMP;
  1010. break;
  1011. }
  1012. // ok, didn't match the words 'Microsoft� Windows�', so instead, see if
  1013. // it matches the string in kernel32.dll
  1014. TESTBOOL(hr, VerQueryValueW(pbFVIK32, wszQueryString,
  1015. (LPVOID *)&pwszNameK32, &cb));
  1016. if (FAILED(hr))
  1017. continue;
  1018. if (CompareStringW(MAKELCID(plc[i].wLanguage, SORT_DEFAULT),
  1019. NORM_IGNORECASE | NORM_IGNOREKANATYPE |
  1020. NORM_IGNOREWIDTH | SORT_STRINGSORT,
  1021. pwszName, -1, pwszNameK32, -1) == CSTR_EQUAL)
  1022. {
  1023. dwRet |= APP_WINCOMP;
  1024. break;
  1025. }
  1026. }
  1027. hr = S_FALSE;
  1028. done:
  1029. ErrorTrace(0, "results for module \'%S\', dwRet=%d", wszAppPath, dwRet);
  1030. return dwRet;
  1031. }