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.

1391 lines
34 KiB

  1. #include "advapi.h"
  2. #include <nt.h>
  3. #include <ntrtl.h>
  4. #include <nturtl.h>
  5. #include <aclapi.h>
  6. #include <windows.h>
  7. #include <wincrypt.h>
  8. #include <sitesids.h>
  9. #include <malloc.h>
  10. #include <urlmon.h>
  11. RTL_CRITICAL_SECTION SiteSidCacheLock;
  12. // internal function declarations
  13. HRESULT MakeSidFromHash(PSID *ppSid, BYTE *pbBuffer, DWORD cbBuffer);
  14. void UpdateSiteSidUsage(
  15. HKEY hCacheKey,
  16. LPCWSTR lpwszSiteSid,
  17. LPWSTR lpwszSite,
  18. UINT cbSiteBuffer);
  19. void Base32Encode(LPVOID pvData, UINT cbData, LPWSTR pchData);
  20. typedef HRESULT (STDAPICALLTYPE CREATESECURITYMANAGER) (
  21. IServiceProvider *pSP, IInternetSecurityManager **ppSM, DWORD dwReserved);
  22. CREATESECURITYMANAGER *pfnCoInternetCreateSecurityManager = CoInternetCreateSecurityManager;
  23. HMODULE hUrlMon = 0;
  24. PSID
  25. APIENTRY
  26. GetSiteSidFromToken(
  27. IN HANDLE TokenHandle
  28. )
  29. {
  30. PTOKEN_GROUPS RestrictedSids = NULL;
  31. ULONG ReturnLength;
  32. NTSTATUS Status;
  33. PSID psSiteSid = NULL;
  34. Status = NtQueryInformationToken(
  35. TokenHandle,
  36. TokenRestrictedSids,
  37. NULL,
  38. 0,
  39. &ReturnLength
  40. );
  41. if (Status != STATUS_BUFFER_TOO_SMALL)
  42. {
  43. BaseSetLastNTError(Status);
  44. return NULL;
  45. }
  46. RestrictedSids = (PTOKEN_GROUPS) RtlAllocateHeap(RtlProcessHeap(), 0, ReturnLength);
  47. if (RestrictedSids == NULL)
  48. {
  49. SetLastError(ERROR_OUTOFMEMORY);
  50. return NULL;
  51. }
  52. Status = NtQueryInformationToken(
  53. TokenHandle,
  54. TokenRestrictedSids,
  55. RestrictedSids,
  56. ReturnLength,
  57. &ReturnLength
  58. );
  59. if (NT_SUCCESS(Status))
  60. {
  61. UINT i;
  62. SID_IDENTIFIER_AUTHORITY InternetSiteAuthority = SECURITY_INTERNETSITE_AUTHORITY;
  63. for (i = 0; i < RestrictedSids->GroupCount; i++) {
  64. if (RtlCompareMemory((PVOID) &((SID *) RestrictedSids->Groups[i].Sid)->IdentifierAuthority,
  65. (PVOID) &InternetSiteAuthority,
  66. sizeof(SID_IDENTIFIER_AUTHORITY)) == sizeof(SID_IDENTIFIER_AUTHORITY))
  67. {
  68. psSiteSid = RtlAllocateHeap(RtlProcessHeap(), 0, RtlLengthSid((RestrictedSids->Groups[i]).Sid));
  69. if (psSiteSid == NULL) {
  70. SetLastError(ERROR_OUTOFMEMORY);
  71. }
  72. else {
  73. RtlCopySid(RtlLengthSid((RestrictedSids->Groups[i]).Sid), psSiteSid, (RestrictedSids->Groups[i]).Sid);
  74. }
  75. break;
  76. }
  77. }
  78. }
  79. else
  80. {
  81. BaseSetLastNTError(Status);
  82. }
  83. RtlFreeHeap(RtlProcessHeap(), 0, RestrictedSids);
  84. return psSiteSid;
  85. }
  86. HRESULT GetRestrictedSids(
  87. LPCWSTR pszSite,
  88. SID_AND_ATTRIBUTES *pSidToRestrict,
  89. ULONG *pCount)
  90. {
  91. HRESULT hr = S_OK;
  92. ULONG i = 0;
  93. long error;
  94. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  95. *pCount = 0;
  96. pSidToRestrict[0].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED;
  97. pSidToRestrict[1].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED;
  98. pSidToRestrict[2].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED;
  99. //Get the site SID.
  100. pSidToRestrict[0].Sid = GetSiteSidFromUrl(pszSite);
  101. if(!pSidToRestrict[0].Sid)
  102. {
  103. return HRESULT_FROM_WIN32(GetLastError());
  104. }
  105. i++;
  106. //BUGBUG: Get the zone SID.
  107. //Get the restricted SID.
  108. error = RtlAllocateAndInitializeSid(&NtAuthority,
  109. 1,
  110. SECURITY_RESTRICTED_CODE_RID,
  111. 0, 0, 0, 0, 0, 0, 0,
  112. &pSidToRestrict[i].Sid);
  113. if(!error)
  114. {
  115. i++;
  116. }
  117. else
  118. {
  119. hr = HRESULT_FROM_WIN32( GetLastError() );
  120. }
  121. if(FAILED(hr))
  122. {
  123. return hr;
  124. }
  125. *pCount = i;
  126. return hr;
  127. }
  128. HRESULT
  129. APIENTRY
  130. GetSiteNameFromSid(PSID pSid, LPWSTR *pwsSite)
  131. {
  132. HRESULT hr = S_OK;
  133. WCHAR wsValueNameBuffer[MAX_MANGLED_SITE];
  134. LPWSTR wsValueName = wsValueNameBuffer;
  135. HKEY hCacheKey;
  136. DWORD dwDisposition;
  137. WCHAR *wszValue;
  138. ULONG ulValueSize;
  139. DWORD error;
  140. *pwsSite = NULL;
  141. error = RegCreateKeyExW(HKEY_LOCAL_MACHINE, SITE_SID_CACHE_REG_KEY,
  142. 0, NULL, 0, KEY_ALL_ACCESS,
  143. NULL, &hCacheKey, &dwDisposition);
  144. if (ERROR_SUCCESS != error)
  145. {
  146. // Can't write, try read-only. We won't be able to update the cache,
  147. // but we might be able to return the site name
  148. error = RegCreateKeyExW(HKEY_LOCAL_MACHINE, SITE_SID_CACHE_REG_KEY,
  149. 0, NULL, 0, KEY_QUERY_VALUE,
  150. NULL, &hCacheKey, &dwDisposition);
  151. if (ERROR_SUCCESS != error) {
  152. return HRESULT_FROM_WIN32(error);
  153. }
  154. }
  155. GetMangledSiteSid(pSid, MAX_MANGLED_SITE, &wsValueName);
  156. ASSERT(wsValueName == wsValueNameBuffer);
  157. //Get the size and allocate memory for the site name.
  158. error = RegQueryValueExW(
  159. hCacheKey,
  160. wsValueName,
  161. NULL,
  162. NULL,
  163. NULL,
  164. &ulValueSize);
  165. if (ERROR_SUCCESS != error) {
  166. RegCloseKey(hCacheKey);
  167. return HRESULT_FROM_WIN32(error);
  168. }
  169. wszValue = (WCHAR *) LocalAlloc(0, ulValueSize);
  170. if (wszValue != NULL)
  171. {
  172. error = RegQueryValueExW(
  173. hCacheKey,
  174. wsValueName,
  175. NULL,
  176. NULL,
  177. (BYTE *) wszValue,
  178. &ulValueSize);
  179. if (ERROR_SUCCESS == error)
  180. {
  181. *pwsSite = wszValue;
  182. UpdateSiteSidUsage(hCacheKey, wsValueName, wszValue, ulValueSize);
  183. }
  184. else
  185. {
  186. hr = HRESULT_FROM_WIN32(error);
  187. LocalFree(wszValue);
  188. }
  189. }
  190. else
  191. {
  192. hr = E_OUTOFMEMORY;
  193. }
  194. RegCloseKey(hCacheKey);
  195. return hr;
  196. }
  197. PSID APIENTRY
  198. GetSiteSidFromUrl(LPCWSTR wsUrl)
  199. {
  200. HRESULT hr;
  201. PSID pSid = NULL;
  202. IInternetSecurityManager *pIScManager;
  203. DWORD cbSecurityId = lstrlenW(wsUrl) * sizeof(WCHAR) + sizeof(DWORD);
  204. BYTE *pbSecurityId = (BYTE *) alloca(cbSecurityId);
  205. HCRYPTPROV hProv;
  206. HCRYPTHASH hHash;
  207. DWORD dwCount;
  208. DWORD dwHashLen;
  209. BYTE *pbBuffer;
  210. HKEY hCacheKey;
  211. DWORD dwDisposition;
  212. WCHAR wsValueNameBuffer[MAX_MANGLED_SITE];
  213. LPWSTR wsValueName = wsValueNameBuffer;
  214. ULONG ulValueSize = (lstrlenW(wsUrl) + 1) * sizeof(WCHAR);
  215. WCHAR *wsValue;
  216. NTSTATUS Status;
  217. DWORD error;
  218. //Crack the URL to get the site name.
  219. hr = (*pfnCoInternetCreateSecurityManager)(NULL, &pIScManager, 0);
  220. if(SUCCEEDED(hr))
  221. {
  222. hr = pIScManager->GetSecurityId(wsUrl, pbSecurityId, &cbSecurityId, 0);
  223. if(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr)
  224. {
  225. pbSecurityId = (BYTE *) alloca(cbSecurityId);
  226. hr = pIScManager->GetSecurityId(wsUrl, pbSecurityId, &cbSecurityId, 0);
  227. }
  228. //Remove the dwZone from the end of the pbSecurityId.
  229. cbSecurityId -= sizeof(DWORD);
  230. pIScManager->Release();
  231. }
  232. if(FAILED(hr))
  233. {
  234. SetLastError(hr);
  235. return NULL;
  236. }
  237. // acquire security context - if this is unsuccessful,
  238. // the hashing functions cannot be called
  239. if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
  240. return NULL;
  241. if (!CryptCreateHash(hProv, SITE_SID_HASH_ALGORITHM, 0, 0, &hHash))
  242. {
  243. CryptReleaseContext(hProv, 0);
  244. return NULL;
  245. }
  246. // hash the site name
  247. if (!CryptHashData(hHash, pbSecurityId, cbSecurityId, 0))
  248. {
  249. CryptDestroyHash(hHash);
  250. CryptReleaseContext(hProv, 0);
  251. return NULL;
  252. }
  253. // TODO: salt? - with local machine name?
  254. // get size of the hash value - for memory allocation
  255. dwCount = sizeof(DWORD);
  256. if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *) &dwHashLen, &dwCount, 0))
  257. {
  258. CryptDestroyHash(hHash);
  259. CryptReleaseContext(hProv, 0);
  260. return NULL;
  261. }
  262. pbBuffer = (BYTE *) LocalAlloc(0, dwHashLen);
  263. if (pbBuffer == NULL)
  264. {
  265. //out of memory
  266. CryptDestroyHash(hHash);
  267. CryptReleaseContext(hProv, 0);
  268. SetLastError(ERROR_OUTOFMEMORY);
  269. return NULL;
  270. }
  271. if (!CryptGetHashParam(hHash, HP_HASHVAL, pbBuffer, &dwHashLen, 0))
  272. {
  273. LocalFree(pbBuffer);
  274. CryptDestroyHash(hHash);
  275. CryptReleaseContext(hProv, 0);
  276. return NULL;
  277. }
  278. CryptDestroyHash(hHash);
  279. CryptReleaseContext(hProv, 0);
  280. // make SID from the hash value in pbBuffer
  281. hr = MakeSidFromHash(&pSid, pbBuffer, dwHashLen);
  282. if (FAILED(hr))
  283. {
  284. LocalFree(pbBuffer);
  285. SetLastError(hr);
  286. return NULL;
  287. }
  288. // check if the SID is already in the SID cache
  289. // if it is, update the time of last use
  290. // if not, insert it into the cache, deleting the LRU
  291. // item if the cache is already full
  292. // whatever happens here, we already have the mapping
  293. // from URL to SID that we wanted, so we always return
  294. // success
  295. //
  296. // Convert the cracked site name to Unicode
  297. //
  298. __try
  299. {
  300. wsUrl = (WCHAR *) alloca(ulValueSize);
  301. }
  302. __except (EXCEPTION_EXECUTE_HANDLER)
  303. {
  304. return pSid; // alloca failed
  305. }
  306. Status = RtlMultiByteToUnicodeN((WCHAR *) wsUrl, ulValueSize, &dwCount, (char *) pbSecurityId, cbSecurityId);
  307. if (!(NT_SUCCESS(Status)))
  308. {
  309. return pSid;
  310. }
  311. ((WCHAR *)wsUrl)[dwCount / sizeof(WCHAR)] = L'\0';
  312. hCacheKey = NULL;
  313. if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, SITE_SID_CACHE_REG_KEY, 0, NULL, 0,
  314. KEY_ALL_ACCESS, NULL, &hCacheKey, &dwDisposition) != ERROR_SUCCESS)
  315. {
  316. // cannot open/create the cache registry key
  317. return pSid;
  318. }
  319. GetMangledSiteSid(pSid, MAX_MANGLED_SITE, &wsValueName);
  320. ASSERT(wsValueName == wsValueNameBuffer);
  321. __try
  322. {
  323. wsValue = (WCHAR *) alloca(ulValueSize);
  324. }
  325. __except (EXCEPTION_EXECUTE_HANDLER)
  326. {
  327. RegCloseKey(hCacheKey); // alloca failed
  328. return pSid;
  329. }
  330. error = RegQueryValueExW(
  331. hCacheKey,
  332. wsValueName,
  333. NULL,
  334. NULL,
  335. (BYTE *) wsValue,
  336. &ulValueSize);
  337. if (ERROR_SUCCESS == error) {
  338. // this SID is already there in the cache
  339. // check for collision
  340. // if wsValue is "", we already know of a collision
  341. if (wsValue[0] != L'\0') {
  342. if (wcscmp(wsUrl, wsValue) != 0) {
  343. // COLLISION !!!
  344. // we handle collision by retaining the SID in
  345. // the cache and setting the site name to ""
  346. // so the wrong site name cannot be returned
  347. DbgPrint("Site SID Collision:\n\t%ws\n\t%ws\n", wsUrl,wsValue);
  348. WCHAR wcNull = L'\0';
  349. RegSetValueExW(hCacheKey, wsValueName, 0, REG_BINARY,
  350. (CONST BYTE *) &wcNull, sizeof(WCHAR));
  351. }
  352. else {
  353. UpdateSiteSidUsage(
  354. hCacheKey,
  355. wsValueName,
  356. wsValue,
  357. ulValueSize);
  358. }
  359. }
  360. }
  361. else if (ERROR_FILE_NOT_FOUND == error) {
  362. UpdateSiteSidUsage(hCacheKey, wsValueName, (WCHAR *) wsUrl, 0);
  363. }
  364. RegCloseKey(hCacheKey);
  365. return pSid;
  366. }
  367. void UpdateSiteSidUsage(
  368. HKEY hCacheKey,
  369. LPCWSTR lpwszSiteSid,
  370. LPWSTR lpwszSite,
  371. UINT cbSiteBuffer)
  372. {
  373. UINT cbSite = wcslen(lpwszSite)*sizeof(WCHAR) + sizeof(L'\0');
  374. UINT cbRequiredBuffer = cbSite + sizeof(LARGE_INTEGER);
  375. BOOL bCheckOverflow = (0 == cbSiteBuffer);
  376. LARGE_INTEGER Now;
  377. if (cbSiteBuffer < cbRequiredBuffer)
  378. {
  379. // Either this is a new cache entry or somebody mucked with the
  380. // cache data
  381. LPWSTR lpwsz;
  382. __try
  383. {
  384. lpwsz = (LPWSTR) alloca(cbRequiredBuffer);
  385. }
  386. __except (EXCEPTION_EXECUTE_HANDLER)
  387. {
  388. return; // alloca failed
  389. }
  390. wcscpy(lpwsz, lpwszSite);
  391. cbSiteBuffer = cbRequiredBuffer;
  392. lpwszSite = lpwsz;
  393. }
  394. // Tack the current time after the end of the string and write it out
  395. NtQuerySystemTime(&Now);
  396. * (UNALIGNED LARGE_INTEGER *) (((BYTE *) lpwszSite) + cbSite) = Now;
  397. RegSetValueExW(
  398. hCacheKey,
  399. lpwszSiteSid,
  400. NULL,
  401. REG_BINARY,
  402. (BYTE *) lpwszSite,
  403. cbSiteBuffer);
  404. if (!bCheckOverflow)
  405. return;
  406. // Check for cache overflow
  407. #define _PTIME(i) ((__int64 *) (pEntryInfo + i * cbEntryInfo))
  408. #define _PVALUE(i) ((WCHAR *) (_PTIME(i) + 1))
  409. static volatile LONG lFlushing = 0;
  410. DWORD error;
  411. DWORD cEntries;
  412. DWORD cTotalEntries;
  413. DWORD cbEntryValue;
  414. DWORD cbMaxEntryValue;
  415. BYTE *pEntryValue;
  416. DWORD cbMaxEntryName;
  417. DWORD cbEntryInfo;
  418. BYTE *pEntryInfo;
  419. UINT iFreeEntry;
  420. UINT iNewestEntry;
  421. UINT i;
  422. DWORD cb;
  423. error = RegQueryInfoKeyW(hCacheKey, NULL, NULL, NULL, NULL, NULL, NULL,
  424. &cEntries, &cbMaxEntryName, &cbMaxEntryValue,
  425. NULL, NULL);
  426. if (ERROR_SUCCESS != error
  427. || cEntries < SITE_SID_CACHE_SIZE_HIGH
  428. || 1 == InterlockedExchange((LONG *) &lFlushing, 1))
  429. {
  430. return; // Cache is under limit or we are already flushing
  431. }
  432. cbMaxEntryName = (cbMaxEntryName + 1) * sizeof(WCHAR);
  433. cTotalEntries = cEntries - SITE_SID_CACHE_SIZE_LOW + 1;
  434. cbEntryInfo = sizeof(LARGE_INTEGER) + cbMaxEntryName;
  435. // Allocate space for the largest value size
  436. __try
  437. {
  438. pEntryValue = (BYTE *) alloca(cbMaxEntryValue);
  439. }
  440. __except (EXCEPTION_EXECUTE_HANDLER)
  441. {
  442. return;
  443. }
  444. // Allocate space to hold the cache entries to delete (+1)
  445. do
  446. {
  447. pEntryInfo = (BYTE *) LocalAlloc(0, cbEntryInfo * cTotalEntries);
  448. if (NULL == pEntryInfo)
  449. {
  450. cTotalEntries = cTotalEntries / 2;
  451. if (cTotalEntries < 2)
  452. {
  453. lFlushing = 0;
  454. return;
  455. }
  456. }
  457. }
  458. while (NULL == pEntryInfo);
  459. iFreeEntry = 0;
  460. iNewestEntry = 0;
  461. i = 0;
  462. cb = cbEntryInfo - sizeof(LARGE_INTEGER);
  463. cEntries = 1;
  464. BOOL bNewNewest = FALSE;
  465. cbEntryValue = cbMaxEntryValue;
  466. while (ERROR_SUCCESS == RegEnumValueW(
  467. hCacheKey,
  468. i,
  469. _PVALUE(iFreeEntry),
  470. &cb,
  471. NULL,
  472. NULL,
  473. pEntryValue,
  474. &cbEntryValue))
  475. {
  476. ++i;
  477. cb = cbEntryInfo - sizeof(LARGE_INTEGER);
  478. cbEntryValue = cbMaxEntryValue;
  479. * _PTIME(iFreeEntry) = * (__int64 *) (wcschr((WCHAR *) pEntryValue, L'\0') + 1);
  480. if (cEntries < cTotalEntries)
  481. {
  482. ++cEntries;
  483. ++iFreeEntry;
  484. if (cEntries == cTotalEntries)
  485. bNewNewest = TRUE;
  486. }
  487. else if (*_PTIME(iFreeEntry) < *_PTIME(iNewestEntry))
  488. {
  489. UINT t = iNewestEntry;
  490. iNewestEntry = iFreeEntry;
  491. iFreeEntry = t;
  492. bNewNewest = TRUE;
  493. }
  494. if (bNewNewest)
  495. {
  496. bNewNewest = FALSE;
  497. for (DWORD j = 0; j < cEntries; j++)
  498. {
  499. if (j != iFreeEntry)
  500. if (*_PTIME(j) > *_PTIME(iNewestEntry))
  501. iNewestEntry = j;
  502. }
  503. }
  504. }
  505. if (i >= SITE_SID_CACHE_SIZE_HIGH)
  506. {
  507. for (DWORD j = 0; j < cEntries; j++)
  508. {
  509. if (j != iFreeEntry)
  510. RegDeleteValueW(hCacheKey, _PVALUE(j));
  511. }
  512. }
  513. LocalFree(pEntryInfo);
  514. lFlushing = 0;
  515. #undef _PVALUE
  516. #undef _PTIME
  517. }
  518. HRESULT MakeSidFromHash(PSID *ppSid, BYTE *pbBuffer, DWORD cbBuffer)
  519. {
  520. HRESULT hr = S_OK;
  521. long error;
  522. DWORD aSubAuthorities[8];
  523. SID_IDENTIFIER_AUTHORITY siaAuthority = SITE_SID_CACHE_AUTHORITY;
  524. *ppSid = NULL;
  525. if(cbBuffer > sizeof(aSubAuthorities))
  526. {
  527. return E_INVALIDARG;
  528. }
  529. memset(aSubAuthorities, 0, sizeof(aSubAuthorities));
  530. memcpy(aSubAuthorities, pbBuffer, cbBuffer);
  531. error = RtlAllocateAndInitializeSid(&siaAuthority,
  532. (BYTE) ((cbBuffer + 3) / sizeof(DWORD)),
  533. aSubAuthorities[0],
  534. aSubAuthorities[1],
  535. aSubAuthorities[2],
  536. aSubAuthorities[3],
  537. aSubAuthorities[4],
  538. aSubAuthorities[5],
  539. aSubAuthorities[6],
  540. aSubAuthorities[7],
  541. ppSid);
  542. if(error)
  543. {
  544. hr = HRESULT_FROM_WIN32(error);
  545. }
  546. return hr;
  547. }
  548. HRESULT
  549. APIENTRY
  550. GetMangledSiteSid(PSID pSid, ULONG cchMangledSite, LPWSTR *ppwszMangledSite)
  551. {
  552. SID_IDENTIFIER_AUTHORITY InternetSiteAuthority = SECURITY_INTERNETSITE_AUTHORITY;
  553. SID_IDENTIFIER_AUTHORITY *InAuthority;
  554. InAuthority = RtlIdentifierAuthoritySid(pSid);
  555. if (NULL == InAuthority)
  556. return HRESULT_FROM_WIN32(ERROR_INVALID_SID);
  557. if (0 != memcmp(
  558. InAuthority,
  559. &InternetSiteAuthority,
  560. sizeof(InternetSiteAuthority)))
  561. {
  562. return HRESULT_FROM_WIN32(ERROR_INVALID_SID);
  563. }
  564. if (cchMangledSite < MAX_MANGLED_SITE)
  565. {
  566. *ppwszMangledSite = (WCHAR *) LocalAlloc(
  567. 0,
  568. MAX_MANGLED_SITE * sizeof(WCHAR));
  569. if (NULL == *ppwszMangledSite)
  570. return E_OUTOFMEMORY;
  571. }
  572. // The value of MAX_MANGLED_SITE assumes 4 dwords
  573. ASSERT(4 == *RtlSubAuthorityCountSid(pSid));
  574. Base32Encode(
  575. RtlSubAuthoritySid(pSid, 0),
  576. *RtlSubAuthorityCountSid(pSid) * sizeof(DWORD),
  577. *ppwszMangledSite);
  578. // The output string should always be MAX_MANGLED_SITE - 1 chars long
  579. ASSERT(MAX_MANGLED_SITE - 1 == lstrlenW(*ppwszMangledSite));
  580. return S_OK;
  581. }
  582. ULONG
  583. APIENTRY
  584. GetSiteDirectoryA(
  585. HANDLE hToken,
  586. LPSTR lpBuffer,
  587. ULONG nBufferLength
  588. )
  589. /*++
  590. Routine Description:
  591. ANSI thunk to GetSiteDirectoryW
  592. --*/
  593. {
  594. PUNICODE_STRING Unicode;
  595. ANSI_STRING AnsiString;
  596. NTSTATUS Status;
  597. DWORD ReturnValue;
  598. #if defined (FE_SB) // GetSiteDirectoryA(); local variable
  599. ULONG cbAnsiString;
  600. #endif // FE_SB
  601. if ( nBufferLength > MAXUSHORT ) {
  602. nBufferLength = MAXUSHORT-2;
  603. }
  604. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  605. Unicode->Length = (USHORT)GetSiteDirectoryW(
  606. hToken,
  607. Unicode->Buffer,
  608. Unicode->MaximumLength
  609. );
  610. #if defined (FE_SB) // GetSiteDirectoryA(): bug fix
  611. //
  612. // Unicode->Length contains the byte count of unicode string.
  613. // Original code does "UnicodeLength / sizeof(WCHAR)" to
  614. // get the size of corresponding ansi string.
  615. // This is correct in SBCS environment. However in DBCS
  616. // environment, it's definitely WRONG.
  617. //
  618. Status = RtlUnicodeToMultiByteSize( &cbAnsiString, Unicode->Buffer, Unicode->Length );
  619. if ( !NT_SUCCESS(Status) ) {
  620. BaseSetLastNTError(Status);
  621. ReturnValue = 0;
  622. }
  623. else {
  624. if ( nBufferLength > (DWORD)(cbAnsiString ) ) {
  625. AnsiString.Buffer = lpBuffer;
  626. AnsiString.MaximumLength = (USHORT)(nBufferLength+1);
  627. Status = BasepUnicodeStringTo8BitString(&AnsiString,Unicode,FALSE);
  628. if ( !NT_SUCCESS(Status) ) {
  629. BaseSetLastNTError(Status);
  630. ReturnValue = 0;
  631. }
  632. else {
  633. ReturnValue = AnsiString.Length;
  634. }
  635. }
  636. else {
  637. //
  638. // current spec says the length doesn't
  639. // include null terminate character.
  640. // this may be a bug but I would like
  641. // to make this same as US (see US original code).
  642. //
  643. ReturnValue = cbAnsiString + 1;
  644. }
  645. }
  646. #else
  647. if ( nBufferLength > (DWORD)(Unicode->Length>>1) ) {
  648. AnsiString.Buffer = lpBuffer;
  649. AnsiString.MaximumLength = (USHORT)(nBufferLength+1);
  650. Status = RtlUnicodeStringToAnsiString(&AnsiString,Unicode,FALSE);
  651. if ( !NT_SUCCESS(Status) ) {
  652. BaseSetLastNTError(Status);
  653. ReturnValue = 0;
  654. }
  655. else {
  656. ReturnValue = AnsiString.Length;
  657. }
  658. }
  659. else {
  660. ReturnValue = ((Unicode->Length)>>1)+1;
  661. }
  662. #endif // FE_SB
  663. return ReturnValue;
  664. }
  665. /***************************************************************************\
  666. * GetUserSid
  667. *
  668. * Allocs space for the user sid, fills it in and returns a pointer. Caller
  669. * The sid should be freed by calling DeleteUserSid.
  670. *
  671. * Note the sid returned is the user's real sid, not the per-logon sid.
  672. *
  673. * Returns pointer to sid or NULL on failure.
  674. *
  675. * History:
  676. * 26-Aug-92 Davidc Created.
  677. \***************************************************************************/
  678. PSID GetUserSid (HANDLE UserToken)
  679. {
  680. PTOKEN_USER pUser;
  681. PSID pSid;
  682. DWORD BytesRequired = 200;
  683. NTSTATUS status;
  684. //
  685. // Allocate space for the user info
  686. //
  687. pUser = (PTOKEN_USER)LocalAlloc(LMEM_FIXED, BytesRequired);
  688. if (pUser == NULL) {
  689. // DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to allocate %d bytes"),
  690. // BytesRequired));
  691. return NULL;
  692. }
  693. //
  694. // Read in the UserInfo
  695. //
  696. status = NtQueryInformationToken(
  697. UserToken, // Handle
  698. TokenUser, // TokenInformationClass
  699. pUser, // TokenInformation
  700. BytesRequired, // TokenInformationLength
  701. &BytesRequired // ReturnLength
  702. );
  703. if (status == STATUS_BUFFER_TOO_SMALL) {
  704. //
  705. // Allocate a bigger buffer and try again.
  706. //
  707. HLOCAL realloc = LocalReAlloc(pUser, BytesRequired, LMEM_MOVEABLE);
  708. if (NULL == realloc) {
  709. // DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to allocate %d bytes"),
  710. // BytesRequired));
  711. LocalFree(pUser);
  712. return NULL;
  713. }
  714. pUser = (PTOKEN_USER) realloc;
  715. status = NtQueryInformationToken(
  716. UserToken, // Handle
  717. TokenUser, // TokenInformationClass
  718. pUser, // TokenInformation
  719. BytesRequired, // TokenInformationLength
  720. &BytesRequired // ReturnLength
  721. );
  722. }
  723. if (!NT_SUCCESS(status)) {
  724. // DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to query user info from user token, status = 0x%x"),
  725. // status));
  726. LocalFree(pUser);
  727. return NULL;
  728. }
  729. BytesRequired = RtlLengthSid(pUser->User.Sid);
  730. pSid = LocalAlloc(LMEM_FIXED, BytesRequired);
  731. if (pSid == NULL) {
  732. // DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to allocate %d bytes"),
  733. // BytesRequired));
  734. LocalFree(pUser);
  735. return NULL;
  736. }
  737. status = RtlCopySid(BytesRequired, pSid, pUser->User.Sid);
  738. LocalFree(pUser);
  739. if (!NT_SUCCESS(status)) {
  740. // DebugMsg((DM_WARNING, TEXT("GetUserSid: RtlCopySid Failed. status = %d"),
  741. // status));
  742. LocalFree(pSid);
  743. pSid = NULL;
  744. }
  745. return pSid;
  746. }
  747. BOOL
  748. CreateSiteDirectory(
  749. LPCWSTR pszSiteDirectory,
  750. PSID psidUser,
  751. PSID psidSite)
  752. {
  753. BOOL bRetVal = FALSE;
  754. SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
  755. PACL pAcl = NULL;
  756. PSID psidSystem = NULL;
  757. PSID psidAdmin = NULL;
  758. DWORD cbAcl, AceIndex, dwDisp;
  759. ACE_HEADER * lpAceHeader;
  760. SECURITY_DESCRIPTOR sd;
  761. SECURITY_ATTRIBUTES saSite;
  762. //
  763. // Get the system sid
  764. //
  765. if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID,
  766. 0, 0, 0, 0, 0, 0, 0, &psidSystem)) {
  767. goto Exit;
  768. }
  769. //
  770. // Get the admin sid
  771. //
  772. if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
  773. DOMAIN_ALIAS_RID_ADMINS, 0, 0,
  774. 0, 0, 0, 0, &psidAdmin)) {
  775. goto Exit;
  776. }
  777. //
  778. // Allocate space for the ACL
  779. //
  780. cbAcl = (2 * GetLengthSid (psidUser)) + (2 * GetLengthSid (psidSystem)) +
  781. (2 * GetLengthSid (psidAdmin)) + (2 * GetLengthSid (psidSite)) +
  782. sizeof(ACL) +
  783. (8 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
  784. pAcl = (PACL) GlobalAlloc(GMEM_FIXED, cbAcl);
  785. if (!pAcl) {
  786. goto Exit;
  787. }
  788. if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) {
  789. goto Exit;
  790. }
  791. //
  792. // Add Aces for User, System, and Admin. Non-inheritable ACEs first
  793. //
  794. AceIndex = 0;
  795. if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidUser)) {
  796. goto Exit;
  797. }
  798. AceIndex++;
  799. if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidSystem)) {
  800. goto Exit;
  801. }
  802. AceIndex++;
  803. if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidAdmin)) {
  804. goto Exit;
  805. }
  806. AceIndex++;
  807. if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidSite)) {
  808. goto Exit;
  809. }
  810. //
  811. // Now the inheritable ACEs
  812. //
  813. AceIndex++;
  814. if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidUser)) {
  815. goto Exit;
  816. }
  817. if (!GetAce(pAcl, AceIndex, (void **)&lpAceHeader)) {
  818. goto Exit;
  819. }
  820. lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
  821. AceIndex++;
  822. if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidSystem)) {
  823. goto Exit;
  824. }
  825. if (!GetAce(pAcl, AceIndex, (void **)&lpAceHeader)) {
  826. goto Exit;
  827. }
  828. lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
  829. AceIndex++;
  830. if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidAdmin)) {
  831. goto Exit;
  832. }
  833. if (!GetAce(pAcl, AceIndex, (void **)&lpAceHeader)) {
  834. goto Exit;
  835. }
  836. lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
  837. AceIndex++;
  838. if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidSite)) {
  839. goto Exit;
  840. }
  841. if (!GetAce(pAcl, AceIndex, (void **)&lpAceHeader)) {
  842. goto Exit;
  843. }
  844. lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
  845. //
  846. // Put together the security descriptor
  847. //
  848. if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
  849. goto Exit;
  850. }
  851. if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) {
  852. goto Exit;
  853. }
  854. //
  855. // Add the security descriptor to the sa structure
  856. //
  857. saSite.nLength = sizeof(SECURITY_ATTRIBUTES);
  858. saSite.lpSecurityDescriptor = &sd;
  859. saSite.bInheritHandle = FALSE;
  860. //
  861. // Attempt to create the directory
  862. //
  863. bRetVal = CreateDirectoryW(pszSiteDirectory, &saSite);
  864. Exit:
  865. //
  866. // Free the sids and acl
  867. //
  868. if (psidSystem) {
  869. FreeSid(psidSystem);
  870. }
  871. if (psidAdmin) {
  872. FreeSid(psidAdmin);
  873. }
  874. if (pAcl) {
  875. GlobalFree (pAcl);
  876. }
  877. return bRetVal;
  878. }
  879. ULONG
  880. APIENTRY
  881. GetSiteDirectoryW(
  882. HANDLE hToken,
  883. LPWSTR pszSiteDirectory,
  884. ULONG uSize)
  885. {
  886. ULONG cb = 0;
  887. PSID psidUser = 0;
  888. PSID psidSite = 0;
  889. WCHAR szProfile[MAX_PATH + 1];
  890. LPWSTR pszProfile = szProfile;
  891. HANDLE hProcessToken = 0;
  892. long error = 0;
  893. //Get the process token.
  894. if(!hToken)
  895. {
  896. if(OpenProcessToken(GetCurrentProcess(),
  897. TOKEN_QUERY,
  898. &hProcessToken))
  899. {
  900. hToken = hProcessToken;
  901. }
  902. else
  903. {
  904. return 0;
  905. }
  906. }
  907. //Get the path to the user profile directory.
  908. psidUser = GetUserSid(hToken);
  909. if(psidUser != NULL)
  910. {
  911. UNICODE_STRING wstrUserSid = {0, 0, 0};
  912. error = RtlConvertSidToUnicodeString(&wstrUserSid,
  913. psidUser,
  914. TRUE);
  915. if(!error)
  916. {
  917. HKEY hkUserProfile;
  918. //Read the registry key.
  919. lstrcpyW(szProfile, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\");
  920. lstrcatW(szProfile, wstrUserSid.Buffer);
  921. error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  922. szProfile,
  923. 0,
  924. KEY_READ,
  925. &hkUserProfile);
  926. if(!error)
  927. {
  928. DWORD dwType;
  929. DWORD dwSize = sizeof(szProfile);
  930. error = RegQueryValueExW(hkUserProfile,
  931. L"ProfileImagePath",
  932. NULL,
  933. &dwType,
  934. (BYTE*)szProfile,
  935. &dwSize );
  936. if(!error)
  937. {
  938. if ( dwType == REG_EXPAND_SZ )
  939. {
  940. pszProfile = (LPWSTR) alloca((MAX_PATH + 1) * sizeof(WCHAR));
  941. ExpandEnvironmentStringsW(szProfile,
  942. pszProfile,
  943. MAX_PATH);
  944. }
  945. }
  946. RegCloseKey(hkUserProfile);
  947. }
  948. RtlFreeUnicodeString(&wstrUserSid);
  949. }
  950. }
  951. else
  952. {
  953. error = GetLastError();
  954. }
  955. //Get the path to the site directory.
  956. if(!error)
  957. {
  958. psidSite = GetSiteSidFromToken(hToken);
  959. if(psidSite != NULL)
  960. {
  961. WCHAR wszSiteNameBuffer[MAX_MANGLED_SITE];
  962. LPWSTR wszSiteName = wszSiteNameBuffer;
  963. GetMangledSiteSid(psidSite, MAX_MANGLED_SITE, &wszSiteName);
  964. ASSERT(wszSiteName == wszSiteNameBuffer);
  965. cb = sizeof(WCHAR) * (lstrlenW(pszProfile)
  966. + sizeof('\\')
  967. + lstrlenW(wszSiteName)
  968. + sizeof('\0'));
  969. if(uSize * 2 < cb)
  970. {
  971. return cb/2;
  972. }
  973. else
  974. {
  975. lstrcpyW(pszSiteDirectory, pszProfile);
  976. lstrcatW(pszSiteDirectory, L"\\");
  977. lstrcatW(pszSiteDirectory, wszSiteName);
  978. //Check if the directory already exists.
  979. if(GetFileAttributesW(pszSiteDirectory) == -1)
  980. {
  981. CreateSiteDirectory(pszSiteDirectory, psidUser, psidSite);
  982. }
  983. }
  984. RtlFreeSid(psidSite);
  985. }
  986. else
  987. {
  988. error = GetLastError();
  989. }
  990. }
  991. if(error)
  992. {
  993. SetLastError(error);
  994. }
  995. if(hProcessToken)
  996. {
  997. CloseHandle(hProcessToken);
  998. }
  999. if(psidUser)
  1000. {
  1001. RtlFreeSid(psidUser);
  1002. }
  1003. return cb;
  1004. }
  1005. BOOL APIENTRY
  1006. IsProcessRestricted(void)
  1007. /*++
  1008. Routine Description:
  1009. Checks if the current process is a restricted process.
  1010. Arguments:
  1011. None.
  1012. Return Value:
  1013. TRUE if the current process is a restricted process.
  1014. FALSE if it isn't, or if the handle of the current process
  1015. cannot be obtained
  1016. Notes:
  1017. --*/
  1018. {
  1019. static long fIsRestricted = -1;
  1020. if(-1 == fIsRestricted)
  1021. {
  1022. HANDLE hToken;
  1023. if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken))
  1024. {
  1025. fIsRestricted = IsTokenRestricted(hToken);
  1026. CloseHandle(hToken);
  1027. }
  1028. else
  1029. {
  1030. fIsRestricted = 0;
  1031. }
  1032. }
  1033. return fIsRestricted;
  1034. }
  1035. WINADVAPI
  1036. BOOL
  1037. WINAPI IsInSandbox(VOID)
  1038. {
  1039. return IsProcessRestricted();
  1040. }
  1041. //+-------------------------------------------------------------------
  1042. //
  1043. // Function: CoInternetCreateSecurityManager
  1044. //
  1045. // Synopsis: Loads urlmon.dll and calls CoInternetCreateSecurityManager.
  1046. //
  1047. // Returns: S_OK, ERROR_MOD_NOT_FOUND
  1048. //
  1049. //--------------------------------------------------------------------
  1050. STDAPI CoInternetCreateSecurityManager(
  1051. IN IServiceProvider *pSP,
  1052. OUT IInternetSecurityManager **ppSM,
  1053. IN DWORD dwReserved)
  1054. {
  1055. HRESULT hr = E_FAIL;
  1056. if(!hUrlMon)
  1057. {
  1058. hUrlMon = LoadLibraryA("urlmon.dll");
  1059. }
  1060. if(hUrlMon != 0)
  1061. {
  1062. void *pfn = GetProcAddress(hUrlMon, "CoInternetCreateSecurityManager");
  1063. if(pfn != NULL)
  1064. {
  1065. pfnCoInternetCreateSecurityManager = (CREATESECURITYMANAGER *) pfn;
  1066. hr = (*pfnCoInternetCreateSecurityManager)(pSP, ppSM, dwReserved);
  1067. }
  1068. else
  1069. {
  1070. hr = HRESULT_FROM_WIN32(GetLastError());
  1071. }
  1072. }
  1073. else
  1074. {
  1075. hr = HRESULT_FROM_WIN32(GetLastError());
  1076. }
  1077. return hr;
  1078. }
  1079. //+----------------------------------------------------------------------------
  1080. //
  1081. // Function: Base32Encode
  1082. //
  1083. // Synopsis: Convert the given data to base32
  1084. //
  1085. // Notes: Adapted from Mim64Encode in the mshtml project.
  1086. //
  1087. // For 128 bit input (4 DWORDs) the output string will be
  1088. // 27 chars long (including the null terminator)
  1089. //
  1090. //-----------------------------------------------------------------------------
  1091. void Base32Encode(LPVOID pvData, UINT cbData, LPWSTR pchData)
  1092. {
  1093. static const WCHAR alphabet[32] =
  1094. { L'a', L'b', L'c', L'd', L'e', L'f', L'g', L'h',
  1095. L'i', L'j', L'k', L'l', L'm', L'n', L'o', L'p',
  1096. L'q', L'r', L's', L't', L'u', L'v', L'w', L'x',
  1097. L'y', L'z', L'0', L'1', L'2', L'3', L'4', L'5' };
  1098. int shift = 0; // The # of unprocessed bits in accum
  1099. ULONG accum = 0; // The unprocessed bits
  1100. ULONG value;
  1101. BYTE *pData = (BYTE *) pvData;
  1102. // For each byte...
  1103. while (cbData)
  1104. {
  1105. // Move the byte into the low bits of the accumulator
  1106. accum = (accum << 8) | *pData++;
  1107. shift += 8;
  1108. --cbData;
  1109. // Lop off the high 5 or 10 bits and write them out
  1110. while ( shift >= 5 )
  1111. {
  1112. shift -= 5;
  1113. value = (accum >> shift) & 0x1Fl;
  1114. *pchData++ = alphabet[value];
  1115. }
  1116. }
  1117. // If there are any remaining bits, push out one more char padded with 0's
  1118. if (shift)
  1119. {
  1120. value = (accum << (5 - shift)) & 0x1Fl;
  1121. *pchData++ = alphabet[value];
  1122. }
  1123. *pchData = L'\0';
  1124. }