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.

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