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.

4788 lines
148 KiB

  1. // File: secmgr.cxx
  2. //
  3. // Contents: This file implements the base IInternetSecurityManager interface
  4. //
  5. // Classes: CSecurityManager
  6. //
  7. // Functions:
  8. //
  9. // History:
  10. //
  11. //----------------------------------------------------------------------------
  12. #include "zonepch.h" // PCH HEADER FILE, DON'T INCLUDE ANYTHING ABOVE
  13. #include <commctrl.h>
  14. #include "shfusion.h"
  15. #include "advpub.h"
  16. PerfDbgTag(tagCSecurityManager, "Urlmon", "Log Security Mgr", DEB_SESSION)
  17. PerfDbgTag(tagZONEMAP_COMPONENTS, "Urlmon", "Log Security URL parser", DEB_SESSION)
  18. #define PRIVATE static
  19. #define ZERO TEXT('0')
  20. #define NINE TEXT('9')
  21. #define DOT TEXT('.')
  22. #define SLASH TEXT('/')
  23. #define BACKSLASH TEXT('\\')
  24. #define COLON TEXT(':')
  25. #define WILDCARD TEXT('*')
  26. #define SPACE TEXT(' ')
  27. #define HYPHEN TEXT('-')
  28. #define BAR TEXT('|')
  29. #define AT TEXT('@')
  30. #define PERCENT TEXT('%')
  31. extern const LPWSTR RtlpWin32NtRoot = L"\\\\?";
  32. extern const LPWSTR RtlpWin32NtUncRoot = L"\\\\?\\UNC";
  33. #define MAX_IPRANGE 32
  34. extern BOOL g_bUseImprovedZoneCheck;
  35. extern IInternetSecurityManager* g_pSecurityManager;
  36. HRESULT EnsureSecurityManager ();
  37. BOOL CSecurityManager::s_bIPInit = FALSE;
  38. BYTE * CSecurityManager::s_pRanges = NULL;
  39. DWORD CSecurityManager::s_cNumRanges = 0;
  40. DWORD CSecurityManager::s_cbRangeItem = 0;
  41. DWORD CSecurityManager::s_dwNextRangeIndex = 0;
  42. PRIVATE TCHAR chWildCard = WILDCARD;
  43. CSecurityManager::CSecMgrCache CSecurityManager::s_smcache;
  44. BOOL CSecurityManager::s_bcsectInit = FALSE;
  45. CRITICAL_SECTION CSecurityManager::s_csectIP;
  46. HANDLE CSecurityManager::CSecMgrCache::s_hMutexCounter;
  47. CLSID * CSecurityManager::s_clsidAllowedList = NULL;
  48. CRITICAL_SECTION CSecurityManager::s_csectAList;
  49. DWORD CSecurityManager::s_dwNumAllowedControls;
  50. // HACK: See assert below. We have to parse '*' as a valid scheme for wildcarding purposes.
  51. // The big number is to avoid collisions with the pre-defined URL_SCHEME_* numbers that start
  52. // at 0 and go up sequentially.
  53. #define URL_SCHEME_WILDCARD (0x0000FFFF)
  54. #define SAFEREGOPERATION(dw, r) \
  55. dw = r; \
  56. if(dw == ERROR_KEY_DELETED) \
  57. {\
  58. dw = m_regZoneMap.Open (NULL, SZZONEMAP, KEY_READ); \
  59. if( dw == ERROR_SUCCESS) \
  60. dw = r; \
  61. }
  62. #ifndef ARRAY_ELEMENTS
  63. #define ARRAY_ELEMENTS(array) \
  64. (sizeof(array)/sizeof((array)[0]))
  65. #endif
  66. typedef DWORD (APIENTRY *WNETGETCONNECTION) (LPSTR, LPSTR, LPDWORD);
  67. // Simple class to force freeing of memory pointer.
  68. class CFreeStrPtr
  69. {
  70. public:
  71. CFreeStrPtr(LPWSTR pwsz) { m_pwsz = pwsz; }
  72. ~CFreeStrPtr() { delete [] m_pwsz; }
  73. private:
  74. LPWSTR m_pwsz;
  75. };
  76. #ifdef UNICODE
  77. #define IsSpace IsCharSpaceW
  78. #else
  79. #define IsSpace isspace
  80. #endif
  81. // Scans a string for number from 0 to 255 inclusive.
  82. PRIVATE BOOL ScanByte (LPCTSTR& psz, BYTE *bOut)
  83. {
  84. DWORD dw;
  85. // first char
  86. if (*psz < ZERO || *psz > NINE)
  87. return FALSE;
  88. dw = *psz++ - ZERO;
  89. // second char
  90. if (*psz < ZERO || *psz > NINE)
  91. goto done;
  92. dw = 10 * dw + *psz++ - ZERO;
  93. // third char
  94. if (*psz < ZERO || *psz > NINE)
  95. goto done;
  96. dw = 10 * dw + *psz++ - ZERO;
  97. if (dw > 255)
  98. return FALSE;
  99. done:
  100. *bOut = (BYTE) dw;
  101. return TRUE;
  102. }
  103. // Scans a string for a range, wrapping ScanByte
  104. PRIVATE BOOL ScanRange (LPCTSTR& psz, BYTE* pbLow, BYTE* pbHigh)
  105. {
  106. if (*psz == WILDCARD)
  107. {
  108. *pbLow = 0;
  109. *pbHigh = 255;
  110. psz++; // move past *
  111. return TRUE;
  112. }
  113. if (!ScanByte (psz, pbLow))
  114. return FALSE;
  115. while (*psz == SPACE)
  116. psz++; // trim whitespace
  117. if (*psz != HYPHEN)
  118. {
  119. *pbHigh = *pbLow;
  120. return TRUE;
  121. }
  122. else
  123. {
  124. psz++; // move past -
  125. while (*psz == SPACE)
  126. psz++; // trim whitespace
  127. return ScanByte (psz, pbHigh);
  128. }
  129. }
  130. PRIVATE BOOL ReadIPRule (LPCTSTR psz, BYTE *pbLow, BYTE *pbHigh)
  131. {
  132. // Note: ScanRange first param passed by reference.
  133. return
  134. ( ScanRange (psz, pbLow++, pbHigh++)
  135. && *psz++ == DOT
  136. && ScanRange (psz, pbLow++, pbHigh++)
  137. && *psz++ == DOT
  138. && ScanRange (psz, pbLow++, pbHigh++)
  139. && *psz++ == DOT
  140. && ScanRange (psz, pbLow++, pbHigh++)
  141. );
  142. }
  143. // This function is copied here from the network stack code because we don't want to
  144. // link urlmon with winsock. Urlmon is pulled in by the shell even in cases where there
  145. // is no network connection.
  146. /*
  147. * Internet address interpretation routine.
  148. * All the network library routines call this
  149. * routine to interpret entries in the data bases
  150. * which are expected to be an address.
  151. * The value returned is in network order.
  152. */
  153. PRIVATE ULONG
  154. inet_addr(
  155. IN const TCHAR *cp
  156. )
  157. /*++
  158. Routine Description:
  159. This function interprets the character string specified by the cp
  160. parameter. This string represents a numeric Internet address
  161. expressed in the Internet standard ".'' notation. The value
  162. returned is a number suitable for use as an Internet address. All
  163. Internet addresses are returned in network order (bytes ordered from
  164. left to right).
  165. Internet Addresses
  166. Values specified using the "." notation take one of the following
  167. forms:
  168. a.b.c.d a.b.c a.b a
  169. When four parts are specified, each is interpreted as a byte of data
  170. and assigned, from left to right, to the four bytes of an Internet
  171. address. Note that when an Internet address is viewed as a 32-bit
  172. integer quantity on the Intel architecture, the bytes referred to
  173. above appear as "d.c.b.a''. That is, the bytes on an Intel
  174. processor are ordered from right to left.
  175. Note: The following notations are only used by Berkeley, and nowhere
  176. else on the Internet. In the interests of compatibility with their
  177. software, they are supported as specified.
  178. When a three part address is specified, the last part is interpreted
  179. as a 16-bit quantity and placed in the right most two bytes of the
  180. network address. This makes the three part address format
  181. convenient for specifying Class B network addresses as
  182. "128.net.host''.
  183. When a two part address is specified, the last part is interpreted
  184. as a 24-bit quantity and placed in the right most three bytes of the
  185. network address. This makes the two part address format convenient
  186. for specifying Class A network addresses as "net.host''.
  187. When only one part is given, the value is stored directly in the
  188. network address without any byte rearrangement.
  189. Arguments:
  190. cp - A character string representing a number expressed in the
  191. Internet standard "." notation.
  192. Return Value:
  193. If no error occurs, inet_addr() returns an in_addr structure
  194. containing a suitable binary representation of the Internet address
  195. given. Otherwise, it returns the value INADDR_NONE.
  196. --*/
  197. {
  198. register unsigned long val, base, n;
  199. register TCHAR c;
  200. unsigned long parts[4], *pp = parts;
  201. const unsigned long INADDR_NONE = -1;
  202. again:
  203. /*
  204. * Collect number up to ``.''.
  205. * Values are specified as for C:
  206. * 0x=hex, 0=octal, other=decimal.
  207. */
  208. val = 0; base = 10;
  209. if (*cp == '0') {
  210. base = 8, cp++;
  211. if (*cp == 'x' || *cp == 'X')
  212. base = 16, cp++;
  213. }
  214. while (c = *cp) {
  215. // If it is a decimal digit..
  216. if (c <= NINE && c >= ZERO) {
  217. val = (val * base) + (c - '0');
  218. cp++;
  219. continue;
  220. }
  221. // If we are base 16 and it is a hex digit...
  222. if ( base == 16 &&
  223. ( (c >= TEXT('a') && c <= TEXT('f')) ||
  224. (c >= TEXT('A') && c <= TEXT('F'))
  225. )
  226. )
  227. {
  228. val = (val << 4) + (c + 10 - (islower(c) ? TEXT('a') : TEXT('A')));
  229. cp++;
  230. continue;
  231. }
  232. break;
  233. }
  234. if (*cp == '.') {
  235. /*
  236. * Internet format:
  237. * a.b.c.d
  238. * a.b.c (with c treated as 16-bits)
  239. * a.b (with b treated as 24 bits)
  240. */
  241. /* GSS - next line was corrected on 8/5/89, was 'parts + 4' */
  242. if (pp >= parts + 3) {
  243. return ((unsigned long) -1);
  244. }
  245. *pp++ = val, cp++;
  246. goto again;
  247. }
  248. /*
  249. * Check for trailing characters.
  250. */
  251. if (*cp && !IsSpace(*cp)) {
  252. return (INADDR_NONE);
  253. }
  254. *pp++ = val;
  255. /*
  256. * Concoct the address according to
  257. * the number of parts specified.
  258. */
  259. n = (unsigned long)(pp-parts);
  260. switch ((int) n) {
  261. case 1: /* a -- 32 bits */
  262. val = parts[0];
  263. break;
  264. case 2: /* a.b -- 8.24 bits */
  265. if ((parts[0] > 0xff) || (parts[1] > 0xffffff)) {
  266. return(INADDR_NONE);
  267. }
  268. val = (parts[0] << 24) | (parts[1] & 0xffffff);
  269. break;
  270. case 3: /* a.b.c -- 8.8.16 bits */
  271. if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
  272. (parts[2] > 0xffff)) {
  273. return(INADDR_NONE);
  274. }
  275. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  276. (parts[2] & 0xffff);
  277. break;
  278. case 4: /* a.b.c.d -- 8.8.8.8 bits */
  279. if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
  280. (parts[2] > 0xff) || (parts[3] > 0xff)) {
  281. return(INADDR_NONE);
  282. }
  283. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  284. ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
  285. break;
  286. default:
  287. return (INADDR_NONE);
  288. }
  289. #if defined(UNIX) && defined(BIG_ENDIAN)
  290. // IEUNIX: Dont swap on BIG_ENDIAN Unix m/c.
  291. return (val);
  292. #else
  293. val = (val & 0xff000000) >> 24 |
  294. (val & 0x00ff0000) >> 8 |
  295. (val & 0x0000ff00) << 8 |
  296. (val & 0x000000ff) << 24;
  297. return (val);
  298. #endif
  299. }
  300. // Checks if site is in form of IP address.
  301. PRIVATE BOOL ReadAddress (LPCTSTR pwszSite, BYTE *pb)
  302. {
  303. ULONG ipaddr = inet_addr(pwszSite);
  304. if (ipaddr != -1)
  305. {
  306. #ifndef UNIX
  307. *(ULONG*)pb = ipaddr;
  308. #else
  309. memcpy(pb, &ipaddr, sizeof(ULONG));
  310. #endif /* UNIX */
  311. return TRUE;
  312. }
  313. return FALSE;
  314. }
  315. const TCHAR cszFileProt[] = TEXT("file");
  316. struct ZONEMAP_COMPONENTS
  317. {
  318. // pointers into buffer passed to Crack
  319. LPCTSTR pszProtocol, pszSite, pszDomain;
  320. DWORD cchProtocol, cchSite, cchDomain;
  321. DWORD nScheme; // One of URL_SCHEME_*
  322. BOOL fAddr:1; // whether name is in form of IP address
  323. BOOL fIPRange:1; // whether name is in form of an IP Range.
  324. BYTE bAddr[4]; // if IP address, components of IP address
  325. RANGE_ITEM rangeItem; // If IP Range, components of IP Range.
  326. BOOL fDrive; // URL corresponds to a drive letter that couldn't be mapped to a network share name.
  327. DWORD dwDriveType; // if so, drive type
  328. TCHAR szProtBuf[INTERNET_MAX_SCHEME_LENGTH];
  329. TCHAR szSiteBuf[MAX_PATH]; // used for remote drives
  330. TCHAR szIPAddr[16]; // room for 255.255.255.255 + NULL
  331. HRESULT Crack (LPCTSTR pwszUrl, DWORD dwFlags, BOOL bIPRange = FALSE);
  332. BOOL SetUNC (LPSTR pszUNC);
  333. };
  334. BOOL ZONEMAP_COMPONENTS::SetUNC (LPSTR pszUNC)
  335. {
  336. PerfDbgLog(tagZONEMAP_COMPONENTS, this, "+ZONEMAP_COMPONENTS::SetUNC");
  337. // Verify and strip leading backslashes.
  338. if (pszUNC[0] != '\\' || pszUNC[1] != '\\')
  339. return FALSE;
  340. pszUNC += 2;
  341. // Strip the share name from the host.
  342. LPSTR pszSlash = StrChrA (pszUNC, '\\');
  343. if (!pszSlash)
  344. return FALSE;
  345. *pszSlash = 0;
  346. DWORD cchUNC = (DWORD) (pszSlash - pszUNC);
  347. // Convert back to unicode.
  348. cchSite = MultiByteToWideChar
  349. (CP_ACP, 0, pszUNC, cchUNC, szSiteBuf, MAX_PATH);
  350. szSiteBuf[cchSite] = 0;
  351. pszSite = szSiteBuf;
  352. PerfDbgLog(tagZONEMAP_COMPONENTS, this, "-ZONEMAP_COMPONENTS::SetUNC");
  353. return TRUE;
  354. }
  355. // Helper functions to help with URL cracking.
  356. inline BOOL IsDosPath(LPCTSTR p)
  357. {
  358. #ifndef unix
  359. return (*p == BACKSLASH
  360. ||
  361. /* it starts with "x:" where x is from the English alphabet */
  362. ( (*p) &&
  363. ((*p >= TEXT('a') && *p <= TEXT('z')) || (*p >= TEXT('A') && *p <= TEXT('Z'))) &&
  364. p[1] == COLON) );
  365. #else
  366. return (*p == SLASH);
  367. #endif /* unix */
  368. }
  369. inline BOOL IsDrive(LPCTSTR p)
  370. {
  371. #ifndef unix
  372. return (*p && (p[1] == COLON || p[1] == BAR));
  373. #else
  374. return (*p == SLASH);
  375. #endif /* unix */
  376. }
  377. inline BOOL IsWildcardScheme(LPCTSTR p, BOOL &bImplicit)
  378. {
  379. BOOL bRet = FALSE;
  380. if ( p && *p )
  381. {
  382. if (*p == WILDCARD && p[1] == COLON)
  383. {
  384. bRet = TRUE;
  385. bImplicit = FALSE;
  386. }
  387. else if (StrChr(p, COLON) == NULL)
  388. {
  389. // If there is no Colon in the string the user didn't specify a scheme
  390. // and we will assume it is a wildcard.
  391. // i.e *:*.microsoft.com is treated the same as *.microsoft.com
  392. bRet = TRUE;
  393. bImplicit = TRUE;
  394. }
  395. }
  396. return bRet;
  397. }
  398. // A scheme is opaque if we cannot interpret the URL after the scheme.
  399. inline BOOL IsOpaqueScheme(DWORD dwScheme)
  400. {
  401. return (dwScheme != URL_SCHEME_FILE && dwScheme != URL_SCHEME_WILDCARD && !IsHierarchicalScheme(dwScheme));
  402. }
  403. // Global Init functions.
  404. BOOL CSecurityManager::GlobalInit( )
  405. {
  406. InitializeCriticalSection(&s_csectIP);
  407. InitializeCriticalSection(&s_csectAList);
  408. CSecurityManager::s_bcsectInit = TRUE;
  409. return TRUE;
  410. }
  411. BOOL CSecurityManager::GlobalCleanup( )
  412. {
  413. delete [] s_pRanges;
  414. s_pRanges = NULL;
  415. if(s_clsidAllowedList)
  416. {
  417. delete [] s_clsidAllowedList;
  418. s_clsidAllowedList = NULL;
  419. }
  420. if ( s_bcsectInit )
  421. {
  422. DeleteCriticalSection(&s_csectIP) ;
  423. DeleteCriticalSection(&s_csectAList);
  424. }
  425. return TRUE;
  426. }
  427. VOID CSecurityManager::IncrementGlobalCounter( )
  428. {
  429. CSecurityManager::CSecMgrCache::IncrementGlobalCounter( );
  430. }
  431. // Helper functions to deal with caching MapUrlToZone results.
  432. HRESULT ZONEMAP_COMPONENTS::Crack (LPCTSTR pszScan, DWORD dwFlags, BOOL bIPRange /* = FALSE*/)
  433. {
  434. PerfDbgLog(tagZONEMAP_COMPONENTS, this, "+ZONEMAP_COMPONENTS::Crack");
  435. fDrive = FALSE;
  436. fAddr = FALSE;
  437. fIPRange = FALSE;
  438. LPCTSTR pszSiteUrl = pszScan;
  439. nScheme = URL_SCHEME_INVALID;
  440. if (IsDosPath(pszScan))
  441. dwFlags |= PUAF_ISFILE;
  442. if (dwFlags & PUAF_ISFILE)
  443. {
  444. pszProtocol = cszFileProt;
  445. cchProtocol = CSTRLENW(cszFileProt);
  446. nScheme = URL_SCHEME_FILE;
  447. }
  448. else
  449. {
  450. PARSEDURL pu;
  451. pu.cbSize = sizeof(pu);
  452. BOOL bImplicit = FALSE;
  453. if ( (dwFlags & PUAF_ACCEPT_WILDCARD_SCHEME) &&
  454. IsWildcardScheme(pszScan, bImplicit)
  455. )
  456. {
  457. nScheme = URL_SCHEME_WILDCARD;
  458. pszProtocol = &chWildCard;
  459. cchProtocol = 1;
  460. // Skip over the *: if the user entered this explicity.
  461. if (!bImplicit)
  462. pszScan += 2;
  463. }
  464. else
  465. {
  466. HRESULT hr = ParseURL(pszScan, &pu);
  467. if (SUCCEEDED(hr))
  468. {
  469. nScheme = pu.nScheme;
  470. pszProtocol = pu.pszProtocol;
  471. cchProtocol = pu.cchProtocol;
  472. pszScan = pu.pszSuffix;
  473. }
  474. else
  475. {
  476. return hr;
  477. }
  478. }
  479. // Copy protocol to null terminate it.
  480. if (cchProtocol >= INTERNET_MAX_SCHEME_LENGTH)
  481. return E_INVALIDARG;
  482. else
  483. {
  484. memcpy (szProtBuf, pszProtocol, sizeof(TCHAR) * cchProtocol);
  485. szProtBuf[cchProtocol] = 0;
  486. pszProtocol = szProtBuf;
  487. }
  488. }
  489. // Opaque URLs - We cannot interpret anything besides the scheme.
  490. // Just Treat the rest of the string as the Site.
  491. if (IsOpaqueScheme(nScheme))
  492. {
  493. pszSite = pszScan;
  494. cchSite = lstrlen(pszSite);
  495. pszDomain = NULL;
  496. cchDomain = 0;
  497. }
  498. else
  499. {
  500. #ifndef unix
  501. if(nScheme == URL_SCHEME_FILE)
  502. {
  503. const TCHAR UncRoot1[] = TEXT("\\\\?\\");
  504. const TCHAR UncRoot2[] = TEXT("\\\\.\\");
  505. const TCHAR szUnc[] = TEXT("UNC\\");
  506. if (0 == StrCmpNICW(pszScan, UncRoot1, ARRAYSIZE(UncRoot1)-1) ||
  507. 0 == StrCmpNICW(pszScan, UncRoot2, ARRAYSIZE(UncRoot2)-1))
  508. {
  509. // If the url starts with \\?\ or \\.\ .
  510. pszScan += ARRAYSIZE(UncRoot1) - 1;
  511. // First check if it is in the form of \\?\c:. If it is, don't move pszScan
  512. if (pszScan[0] == 0)
  513. return E_INVALIDARG;
  514. else if (pszScan[1] != TEXT(':'))
  515. {
  516. if (0 == StrCmpNICW(pszScan, szUnc, ARRAYSIZE(szUnc) - 1))
  517. pszScan += ARRAYSIZE(szUnc) - 1;
  518. else
  519. return E_INVALIDARG;
  520. }
  521. }
  522. else
  523. {
  524. DWORD dwSize = ARRAYSIZE(szSiteBuf);
  525. HRESULT hr = PathCreateFromUrl( pszSiteUrl, szSiteBuf, &dwSize, NULL);
  526. if(SUCCEEDED(hr))
  527. {
  528. pszScan = szSiteBuf;
  529. }
  530. }
  531. }
  532. // Scan past leading '/' and '\' before site.
  533. while (*pszScan == SLASH || *pszScan == BACKSLASH)
  534. pszScan++;
  535. #endif /* unix */
  536. pszSite = pszScan;
  537. // Is this a drive letter. If so we need to figure out whether it is local or remote.
  538. if (nScheme == URL_SCHEME_FILE && pszSite[0] != WILDCARD && IsDrive(pszSite))
  539. {
  540. fDrive = TRUE;
  541. char szDriveRoot[4];
  542. szDriveRoot[0] = (BYTE) pszSite[0];
  543. #ifndef unix
  544. szDriveRoot[1] = ':';
  545. szDriveRoot[2] = '\\';
  546. szDriveRoot[3] = 0;
  547. #else
  548. szDriveRoot[1] = 0;
  549. #endif /* unix */
  550. dwDriveType = GetDriveTypeFromCacheA (szDriveRoot);
  551. if (dwDriveType == DRIVE_REMOTE)
  552. {
  553. // Strip the trailing backslash.
  554. szDriveRoot[2] = 0;
  555. char szUNC[MAX_PATH];
  556. DWORD cchUNC;
  557. cchUNC = MAX_PATH;
  558. if (NO_ERROR == WNetGetConnectionA(szDriveRoot, szUNC, &cchUNC))
  559. {
  560. fDrive = FALSE;
  561. SetUNC (szUNC);
  562. }
  563. }
  564. }
  565. // SetUNC might have come back with a new site.
  566. pszScan = pszSite;
  567. if (fDrive)
  568. {
  569. // Just start using the drive as is.
  570. cchSite = lstrlen(pszSite);
  571. cchDomain = 0;
  572. pszDomain = NULL;
  573. }
  574. else
  575. {
  576. // Scan for characters which delimit site.
  577. while (1)
  578. {
  579. switch (*pszScan)
  580. {
  581. case 0:
  582. case SLASH:
  583. case BACKSLASH:
  584. break;
  585. case TEXT('@'):
  586. // This happens with custom protocols. Remove assert.
  587. // TransAssert(FALSE);
  588. default:
  589. pszScan++;
  590. continue;
  591. }
  592. break;
  593. }
  594. cchSite = (DWORD) (pszScan - pszSite);
  595. pszDomain = NULL;
  596. cchDomain = 0;
  597. // Check for IP ranges if we are asked to first.
  598. if (bIPRange)
  599. {
  600. fIPRange = ReadIPRule(pszSite, rangeItem.bLow, rangeItem.bHigh);
  601. if (fIPRange)
  602. return S_OK;
  603. }
  604. // Windows Bug# 553626:
  605. // Note: IP address can be expressed in octal or hex, but we don't support them:
  606. if(cchSite < ( sizeof(szIPAddr) / sizeof(TCHAR) ))
  607. {
  608. StrCpyNW(szIPAddr, pszSite, cchSite + 1);
  609. // Check for names that are form of an IP address.
  610. fAddr = ReadAddress (szIPAddr, bAddr);
  611. if (fAddr)
  612. {
  613. cchSite = wnsprintf(szIPAddr, ARRAYSIZE(szIPAddr), TEXT("%d.%d.%d.%d"), bAddr[0], bAddr[1], bAddr[2], bAddr[3]);
  614. pszSite = szIPAddr;
  615. return S_OK;
  616. }
  617. }
  618. // Scan backward for second '.' indicating domain,
  619. // ignoring two-char int'l domains like "co.uk" etc.
  620. DWORD cDot = 0;
  621. LPCTSTR pszDot = NULL;
  622. while (pszScan > pszSite)
  623. {
  624. if ( (*pszScan == DOT) && (pszScan < pszSite + cchSite - 2) )
  625. {
  626. ++cDot;
  627. if (cDot == 1)
  628. {
  629. pszDot = pszScan;
  630. }
  631. else if ( cDot == 2
  632. && pszDot // Non-null only the 1st time
  633. && pszDot == pszSite + cchSite - 3 // Only check .?? ending
  634. && pszScan + 3 >= pszDot) // Check distance between the dots
  635. {
  636. // The distance between the 2 dots is less than 3 chars (.?? or smaller),
  637. // so don't count this as a dot and don't check again.
  638. --cDot;
  639. pszDot = NULL;
  640. }
  641. else
  642. {
  643. pszDomain = pszScan + 1;
  644. cchDomain = (DWORD) (pszSite + cchSite - pszDomain);
  645. cchSite = (DWORD) (pszScan - pszSite);
  646. break;
  647. }
  648. }
  649. pszScan--;
  650. }
  651. }
  652. }
  653. PerfDbgLog(tagZONEMAP_COMPONENTS, this, "-ZONEMAP_COMPONENTS::Crack");
  654. return S_OK;
  655. }
  656. // Function to get a new IInternetSecurityManager from outside. We might replace this
  657. // with a standard class factory eventually.
  658. STDAPI
  659. InternetCreateSecurityManager
  660. (
  661. IUnknown * pUnkOuter,
  662. REFIID riid,
  663. void **ppvObj,
  664. DWORD dwReserved
  665. )
  666. {
  667. PerfDbgLog(tagCSecurityManager, NULL, "+InternetCreateSecurityManager");
  668. HRESULT hr = S_OK;
  669. *ppvObj = NULL;
  670. if ( !IsZonesInitialized() )
  671. return E_UNEXPECTED;
  672. if (dwReserved != 0 || !ppvObj || (pUnkOuter && riid != IID_IUnknown))
  673. {
  674. // If the object has to be aggregated the caller can only ask
  675. // for an IUnknown back.
  676. hr = E_INVALIDARG;
  677. }
  678. else
  679. {
  680. CSecurityManager * pSecMgr = new CSecurityManager(pUnkOuter, (IUnknown **)ppvObj);
  681. if ( pSecMgr )
  682. {
  683. if (riid == IID_IUnknown || riid == IID_IInternetSecurityManager)
  684. {
  685. // The correct pointer is in ppvObj
  686. *ppvObj = (IInternetSecurityManager *)pSecMgr;
  687. }
  688. else
  689. {
  690. hr = E_NOINTERFACE;
  691. }
  692. }
  693. else
  694. {
  695. hr = E_OUTOFMEMORY;
  696. }
  697. }
  698. PerfDbgLog1(tagCSecurityManager, NULL, "-InternetCreateSecurityManager (hr:%lx)", hr);
  699. return hr;
  700. }
  701. // Class Initialization-Destruction.
  702. CSecurityManager::CSecurityManager(IUnknown *pUnkOuter, IUnknown** ppUnkInner)
  703. {
  704. PerfDbgLog(tagCSecurityManager, this, "+CSecurityManager::CSecurityManager");
  705. DllAddRef();
  706. m_pSite = NULL;
  707. m_pDelegateSecMgr = NULL;
  708. m_pZoneManager = NULL;
  709. if (!pUnkOuter)
  710. {
  711. pUnkOuter = &m_Unknown;
  712. }
  713. else
  714. {
  715. TransAssert(ppUnkInner);
  716. if (ppUnkInner)
  717. {
  718. *ppUnkInner = &m_Unknown;
  719. m_ref = 0;
  720. }
  721. }
  722. m_pUnkOuter = pUnkOuter;
  723. m_fHardened = IEHardened();
  724. if (ERROR_SUCCESS != m_regZoneMap.Open (NULL, SZZONEMAP, KEY_READ))
  725. goto done;
  726. EnterCriticalSection(&s_csectIP);
  727. if (!s_bIPInit)
  728. {
  729. ReadAllIPRules();
  730. s_bIPInit = TRUE;
  731. }
  732. LeaveCriticalSection(&s_csectIP);
  733. done:
  734. PerfDbgLog(tagCSecurityManager, this, "-CSecurityManager::CSecurityManager");
  735. return;
  736. }
  737. CSecurityManager::~CSecurityManager()
  738. {
  739. // Due to a circular dependency between wininet and urlmon, this function
  740. // could get called after the dlls global uninit has happened. PerfDbgLog depends on
  741. // some global Mutext objects and fails because of this reason.
  742. // PerfDbgLog(tagCSecurityManager, this, "+~CSecurityManager::CSecurityManager");
  743. if (m_pZoneManager != NULL)
  744. m_pZoneManager->Release();
  745. if (m_pSite != NULL)
  746. m_pSite->Release();
  747. if (m_pDelegateSecMgr != NULL)
  748. m_pDelegateSecMgr->Release();
  749. DllRelease();
  750. // PerfDbgLog(tagCSecurityManager, this, "-~CSecurityManager::CSecurityManager");
  751. }
  752. BOOL CSecurityManager::EnsureZoneManager()
  753. {
  754. if (m_pZoneManager == NULL)
  755. {
  756. if (SUCCEEDED(InternetCreateZoneManager(NULL,
  757. IID_IInternetZoneManager, (void **)&m_pZoneManager, NULL)))
  758. {
  759. TransAssert(m_pZoneManager != NULL);
  760. }
  761. }
  762. return (m_pZoneManager != NULL);
  763. }
  764. STDMETHODIMP CSecurityManager::CPrivUnknown::QueryInterface(REFIID riid, void** ppvObj)
  765. {
  766. HRESULT hr = S_OK;
  767. *ppvObj = NULL;
  768. CSecurityManager * pSecurityManager = GETPPARENT(this, CSecurityManager, m_Unknown);
  769. if (riid == IID_IUnknown || riid == IID_IInternetSecurityManager)
  770. {
  771. *ppvObj = (IInternetSecurityManager *)pSecurityManager;
  772. pSecurityManager->AddRef();
  773. }
  774. else
  775. {
  776. hr = E_NOINTERFACE;
  777. }
  778. return hr;
  779. }
  780. STDMETHODIMP_(ULONG) CSecurityManager::CPrivUnknown::AddRef()
  781. {
  782. LONG lRet = ++m_ref;
  783. return lRet;
  784. }
  785. STDMETHODIMP_(ULONG) CSecurityManager::CPrivUnknown::Release()
  786. {
  787. CSecurityManager *pSecurityManager = GETPPARENT(this, CSecurityManager, m_Unknown);
  788. LONG lRet = --m_ref;
  789. if (lRet == 0)
  790. {
  791. delete pSecurityManager;
  792. }
  793. return lRet;
  794. }
  795. HRESULT ReduceUrl(LPWSTR pwszSecUrl)
  796. {
  797. HRESULT hr = S_OK;
  798. // Reduce the URL here. Need to do this up to two times.
  799. for (int i = 1; i <= 2; i++)
  800. {
  801. if (StrChr(pwszSecUrl, PERCENT))
  802. {
  803. DWORD dwSecUrl = lstrlenW(pwszSecUrl) + 1;
  804. UrlUnescapeW(pwszSecUrl, NULL, 0, URL_UNESCAPE_INPLACE);
  805. if (g_bUseImprovedZoneCheck
  806. && (i == 1)
  807. && (!StrCmpNIW(pwszSecUrl, L"http:", 5)
  808. || !StrCmpNIW(pwszSecUrl, L"https:", 6)))
  809. {
  810. //For Windows 546559
  811. //Imitate wininet behavior
  812. DWORD cchIn = dwSecUrl +2; //two for the "//"
  813. LPWSTR pwzTemp = new WCHAR[cchIn];
  814. if (!pwzTemp)
  815. {
  816. hr = E_OUTOFMEMORY;
  817. goto quit;
  818. }
  819. CFreeStrPtr freeStr(pwzTemp);
  820. WCHAR ch;
  821. int j=0;
  822. do
  823. {
  824. ch = (pwzTemp[j] = pwszSecUrl[j]);
  825. ++j;
  826. }
  827. while (ch != L':');
  828. if (StrCmpNIW(pwszSecUrl+j, L"//", 2))
  829. StrCpyNW(pwzTemp+j, L"//", cchIn-j);
  830. else
  831. pwzTemp[j] = L'\0';
  832. StrCatBuffW(pwzTemp, pwszSecUrl+j, cchIn);
  833. HRESULT hrLocal = UrlGetPartW(pwzTemp, pwszSecUrl, &dwSecUrl, URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME);
  834. DEBUG_PRINT(19,
  835. INFO,
  836. ("called UrlGetPartW %.100wq, %.100wq, hrLocal=0x%x\n",
  837. pwzTemp, pwszSecUrl, hrLocal
  838. ));
  839. if (FAILED(hrLocal))
  840. {
  841. hr = hrLocal;
  842. goto quit;
  843. }
  844. }
  845. }
  846. else
  847. break;
  848. }
  849. quit:
  850. return hr;
  851. }
  852. HRESULT CSecurityManager::WrapMapUrlToZone(LPCWSTR pwszSecUrl, ZONEMAP_COMPONENTS* pzc, DWORD* pdwZone, DWORD dwFlags,
  853. BOOL *pfMarked, LPWSTR *ppszMarkURL)
  854. {
  855. DEBUG_ENTER((DBG_API,
  856. Hresult,
  857. "CSecurityManager::WrapMapUrlToZone",
  858. "%.100wq, %#x, *pdwZone=%#x, dwFlags=%#x",
  859. pwszSecUrl, (pdwZone ? *pdwZone: 0), dwFlags
  860. ));
  861. HRESULT hr = S_OK;
  862. TransAssert (hr == S_OK);
  863. if (g_bUseImprovedZoneCheck
  864. && StrChr(pwszSecUrl, PERCENT)
  865. && (!StrCmpNIW(pwszSecUrl, L"http:", 5)
  866. || !StrCmpNIW(pwszSecUrl, L"https:", 6)))
  867. {
  868. //NOTICE: Windows 555438
  869. //Find the zone of twice unescaped url
  870. //to prevent zone inconsistencies,
  871. //between this and MapUrlToZone codepath
  872. ZONEMAP_COMPONENTS zc2;
  873. LPWSTR pwszRedSecUrl;
  874. DWORD dwSecUrl = lstrlenW(pwszSecUrl);
  875. pwszRedSecUrl = new WCHAR[dwSecUrl+1];
  876. StrCpyW(pwszRedSecUrl, pwszSecUrl);
  877. if (!pwszRedSecUrl)
  878. {
  879. DEBUG_LEAVE(E_OUTOFMEMORY);
  880. return E_OUTOFMEMORY;
  881. }
  882. CFreeStrPtr freeStr(pwszRedSecUrl);
  883. hr = ReduceUrl(pwszRedSecUrl);
  884. if (FAILED(hr))
  885. {
  886. DEBUG_LEAVE(hr);
  887. return hr;
  888. }
  889. hr = zc2.Crack(pwszRedSecUrl, dwFlags);
  890. if (FAILED(hr))
  891. {
  892. //consistent with behavior in GetSecurityId.
  893. DEBUG_LEAVE(E_INVALIDARG);
  894. return E_INVALIDARG;
  895. }
  896. hr = MapUrlToZone (&zc2, pdwZone, dwFlags, pfMarked, ppszMarkURL);
  897. TransAssert (hr == S_OK);
  898. }
  899. else
  900. {
  901. hr = MapUrlToZone (pzc, pdwZone, dwFlags, pfMarked, ppszMarkURL);
  902. TransAssert (hr == S_OK);
  903. }
  904. DEBUG_LEAVE(((hr == S_OK) ? *pdwZone : hr));
  905. return hr;
  906. }
  907. // IUnknown methods
  908. STDMETHODIMP CSecurityManager::QueryInterface(REFIID riid, void **ppvObj)
  909. {
  910. PerfDbgLog(tagCSecurityManager, this, "+CSecurityManager::QueryInterface");
  911. HRESULT hr = E_NOINTERFACE;
  912. *ppvObj = NULL;
  913. if (riid == IID_IUnknown || riid == IID_IInternetSecurityManager)
  914. {
  915. *ppvObj = (IInternetSecurityManager *)this;
  916. }
  917. if (*ppvObj != NULL)
  918. {
  919. ((IUnknown *)*ppvObj)->AddRef();
  920. hr = S_OK;
  921. }
  922. PerfDbgLog1(tagCSecurityManager, this, "-CSecurityManager::QueryInterface (hr:%lx)", hr);
  923. return hr;
  924. }
  925. STDMETHODIMP_(ULONG) CSecurityManager::AddRef()
  926. {
  927. LONG lRet = m_pUnkOuter->AddRef();
  928. return lRet;
  929. }
  930. STDMETHODIMP_(ULONG) CSecurityManager::Release()
  931. {
  932. LONG lRet = m_pUnkOuter->Release();
  933. // Controlling Unknown will delete the object if reqd.
  934. return lRet;
  935. }
  936. // IInternetSecurityManager methods
  937. STDMETHODIMP
  938. CSecurityManager::MapUrlToZone
  939. (
  940. LPCWSTR pwszUrl,
  941. DWORD *pdwZone,
  942. DWORD dwFlags
  943. )
  944. {
  945. DEBUG_ENTER((DBG_TRANS,
  946. Hresult,
  947. "CSecurityManager::MapUrlToZone",
  948. "%.100wq, %#x, *pdwZone=%#x, dwFlags=%#x",
  949. pwszUrl, (pdwZone ? *pdwZone: 0), dwFlags
  950. ));
  951. PerfDbgLog(tagCSecurityManager, this, "+CSecurityManager::MapUrlToZone");
  952. HRESULT hr = INET_E_DEFAULT_ACTION;
  953. if (m_pDelegateSecMgr)
  954. {
  955. hr = m_pDelegateSecMgr->MapUrlToZone(pwszUrl, pdwZone, dwFlags);
  956. }
  957. // Check the cache to see if we already know the answer.
  958. /* BUGBUG - why are we stomping the delegate's result if we have a cache value?
  959. if ((NULL != m_pszPrevUrl) && (0 == StrCmpI(m_pszPrevUrl, pwszUrl)) && IsCounterEqual())
  960. {
  961. hr = S_OK;
  962. *pdwZone = m_dwPrevZone;
  963. }
  964. */
  965. if (hr == INET_E_DEFAULT_ACTION)
  966. {
  967. LPWSTR pwszSecUrl = NULL;
  968. if (pdwZone == NULL || pwszUrl == NULL)
  969. {
  970. hr = E_INVALIDARG;
  971. }
  972. if (dwFlags & MUTZ_ENFORCERESTRICTED)
  973. {
  974. *pdwZone = URLZONE_UNTRUSTED;
  975. hr = S_OK;
  976. }
  977. else if (!s_smcache.Lookup(pwszUrl, pdwZone))
  978. {
  979. hr = CoInternetGetSecurityUrl(pwszUrl, &pwszSecUrl, PSU_DEFAULT, 0);
  980. if (SUCCEEDED(hr))
  981. {
  982. TransAssert(pwszSecUrl);
  983. CFreeStrPtr freeStr(pwszSecUrl);
  984. hr = ReduceUrl(pwszSecUrl);
  985. if (FAILED(hr))
  986. {
  987. goto quit;
  988. }
  989. ZONEMAP_COMPONENTS zc;
  990. if (SUCCEEDED(hr = zc.Crack (pwszSecUrl, dwFlags)))
  991. {
  992. BOOL fMarked;
  993. hr = MapUrlToZone (&zc, pdwZone, dwFlags, &fMarked);
  994. if (hr == S_OK && !(dwFlags & MUTZ_NOCACHE))
  995. {
  996. s_smcache.Add(pwszUrl, *pdwZone, fMarked );
  997. }
  998. }
  999. }
  1000. }
  1001. else
  1002. {
  1003. hr = S_OK;
  1004. }
  1005. }
  1006. quit:
  1007. PerfDbgLog1(tagCSecurityManager, this, "-CSecurityManager::MapUrlToZone (hr:%lx)", hr);
  1008. DEBUG_LEAVE( (SUCCEEDED(hr) ? *pdwZone : hr));
  1009. return hr;
  1010. }
  1011. VOID
  1012. CSecurityManager::PickZCString(ZONEMAP_COMPONENTS *pzc, LPCWSTR *ppwsz, DWORD *pcch, LPCWSTR pwszDocDomain)
  1013. {
  1014. if (pzc->cchDomain)
  1015. {
  1016. TransAssert (!pzc->fDrive);
  1017. // We should use the whole site even if we were able to get the
  1018. // primary domain. i.e. security id for http://www.microsoft.com
  1019. // should be http:www.microsoft.com and NOT http:microsoft.com
  1020. // We will use the fact that the domain and site are actually
  1021. // pointing into one contiguous string to get back at the
  1022. // whole string.
  1023. TransAssert((pzc->cchSite + 1) == (DWORD)(pzc->pszDomain - pzc->pszSite));
  1024. TransAssert(pzc->pszSite[pzc->cchSite] == DOT);
  1025. *ppwsz = pzc->pszSite;
  1026. *pcch = pzc->cchSite + pzc->cchDomain + 1;
  1027. }
  1028. else if (pzc->fDrive && pzc->dwDriveType != DRIVE_REMOTE)
  1029. {
  1030. *ppwsz = TEXT("");
  1031. *pcch = 0;
  1032. }
  1033. else if (pzc->nScheme == URL_SCHEME_FILE)
  1034. {
  1035. // For URL's of the nature \\server\sharename we want to include both the server and sharename in
  1036. // the security ID. This permits me from looking at \\server\private by putting up a page on
  1037. // \\server\public At thuis point pzc->pszSite should point to the string "server\private\foo.htm"
  1038. LPCTSTR lpszCurr = pzc->pszSite;
  1039. BOOL bFoundFirstSlash = FALSE;
  1040. for (; *lpszCurr != NULL ; lpszCurr++)
  1041. {
  1042. if (*lpszCurr == SLASH || *lpszCurr == BACKSLASH)
  1043. {
  1044. if (bFoundFirstSlash)
  1045. {
  1046. // This is the second slash we are done.
  1047. break;
  1048. }
  1049. else
  1050. {
  1051. bFoundFirstSlash = TRUE;
  1052. }
  1053. }
  1054. }
  1055. *ppwsz = pzc->pszSite;
  1056. if (lpszCurr != NULL)
  1057. {
  1058. *pcch = (DWORD)(lpszCurr - pzc->pszSite);
  1059. }
  1060. else
  1061. {
  1062. TransAssert(FALSE);
  1063. *pcch = pzc->cchSite;
  1064. }
  1065. }
  1066. else
  1067. {
  1068. TransAssert (!pzc->pszDomain && !pzc->cchDomain);
  1069. *ppwsz = pzc->pszSite;
  1070. *pcch = pzc->cchSite;
  1071. }
  1072. // If the domain string passed is a suffix of the site string we will
  1073. // use that string instead.
  1074. if (*pcch && pwszDocDomain != 0)
  1075. {
  1076. DWORD cchDocDomain = lstrlenW(pwszDocDomain);
  1077. if (*pcch > cchDocDomain &&
  1078. (0 == StrCmpNICW(pwszDocDomain, &((*ppwsz)[*pcch - cchDocDomain]), cchDocDomain)))
  1079. {
  1080. *ppwsz = pwszDocDomain;
  1081. *pcch = cchDocDomain;
  1082. }
  1083. }
  1084. }
  1085. STDMETHODIMP
  1086. CSecurityManager::GetSecurityId
  1087. (
  1088. /* [in] */ LPCWSTR pwszUrl,
  1089. /* [size_is][out] */ BYTE* pbSecurityId,
  1090. /* [out][in] */ DWORD *pcbSecurityId,
  1091. /* [in] */ DWORD_PTR dwReserved
  1092. )
  1093. {
  1094. DEBUG_ENTER((DBG_API,
  1095. Hresult,
  1096. "CSecurityManager::GetSecurityId",
  1097. "%.100wq",
  1098. pwszUrl
  1099. ));
  1100. PerfDbgLog(tagCSecurityManager, this, "Called CSecurityManager::GetSecurityId");
  1101. HRESULT hr = INET_E_DEFAULT_ACTION;
  1102. DWORD dwZone;
  1103. // Check args ...
  1104. if (pwszUrl == NULL || !pwszUrl[0] || !pcbSecurityId )
  1105. {
  1106. DEBUG_LEAVE(E_INVALIDARG);
  1107. return E_INVALIDARG;
  1108. }
  1109. if (m_pDelegateSecMgr)
  1110. {
  1111. hr = m_pDelegateSecMgr->GetSecurityId(pwszUrl, pbSecurityId, pcbSecurityId, dwReserved);
  1112. }
  1113. if (hr == INET_E_DEFAULT_ACTION)
  1114. {
  1115. BOOL fFoundInCache;
  1116. BOOL fMarked = FALSE;
  1117. DWORD cbSecurityID = *pcbSecurityId;
  1118. fFoundInCache = s_smcache.Lookup(pwszUrl, &dwZone, &fMarked, pbSecurityId, &cbSecurityID, (LPCWSTR)dwReserved);
  1119. // if it wasn't in the cache, or the url and zone were there, but not the security ID,
  1120. // then we still need to do some work.
  1121. if ( !fFoundInCache || cbSecurityID == 0 )
  1122. {
  1123. LPWSTR pwszSecUrl = NULL;
  1124. DWORD dwFlags = 0;
  1125. hr = CoInternetGetSecurityUrl(pwszUrl, &pwszSecUrl, PSU_DEFAULT, 0);
  1126. if (SUCCEEDED(hr))
  1127. {
  1128. TransAssert(pwszSecUrl != NULL);
  1129. CFreeStrPtr freeStr(pwszSecUrl);
  1130. // Crack the URL.
  1131. ZONEMAP_COMPONENTS zc;
  1132. LPWSTR pwszMarkURL = NULL;
  1133. LPWSTR pwszSecUrl2 = NULL;
  1134. if (S_OK != zc.Crack (pwszSecUrl, dwFlags))
  1135. {
  1136. DEBUG_LEAVE(E_INVALIDARG);
  1137. return E_INVALIDARG;
  1138. }
  1139. // Select middle portion of Id.
  1140. LPCWSTR psz2;
  1141. DWORD cch2;
  1142. PickZCString(&zc, &psz2, &cch2, (LPCWSTR)dwReserved);
  1143. // Identify the zone and determine if the ID will bear the
  1144. // Mark of the Web.
  1145. // if the url was found in the cache, the an earlier MapUrlToZone
  1146. // put it there with its zone and Marked flag,
  1147. if (!fFoundInCache || fMarked)
  1148. {
  1149. hr = WrapMapUrlToZone (pwszSecUrl, &zc, &dwZone, 0, &fMarked, &pwszMarkURL);
  1150. if (hr != S_OK)
  1151. {
  1152. DEBUG_LEAVE(hr);
  1153. return hr;
  1154. }
  1155. // If the Mark of the Web is present, then take the Mark URL
  1156. // and substitute it for the original one in the zc, this will
  1157. // allow us to create a security ID that embodies the original
  1158. // domain, which in turn allows us to recreate the cross-domain
  1159. // frame security. The '*' we add to the end will prevent a
  1160. // potentially compromised page on the user's disk from accessing
  1161. // frames of the live, original site if the two should wind up
  1162. // in the same frameset.
  1163. if (fMarked)
  1164. {
  1165. TransAssert(pwszMarkURL != NULL);
  1166. hr = CoInternetGetSecurityUrl(pwszMarkURL, &pwszSecUrl2, PSU_DEFAULT, 0);
  1167. if (SUCCEEDED(hr))
  1168. {
  1169. TransAssert(pwszSecUrl2 != NULL);
  1170. if(SUCCEEDED(zc.Crack (pwszSecUrl2, dwFlags)))
  1171. PickZCString(&zc, &psz2, &cch2, (LPCWSTR)dwReserved);
  1172. else
  1173. {
  1174. if (pwszSecUrl2) delete [] pwszSecUrl2;
  1175. if (pwszMarkURL) LocalFree(pwszMarkURL);
  1176. DEBUG_LEAVE(E_INVALIDARG);
  1177. return E_INVALIDARG;
  1178. }
  1179. }
  1180. }
  1181. }
  1182. // Calculate required size of buffer.
  1183. DWORD cbTail = sizeof(DWORD) + ((fMarked)? sizeof(CHAR) : 0);
  1184. DWORD cbSite = 0;
  1185. if (cch2 != 0)
  1186. {
  1187. cbSite = WideCharToMultiByte(CP_ACP, 0, psz2, cch2,
  1188. NULL, 0, NULL, NULL);
  1189. if (cbSite == 0)
  1190. {
  1191. hr = HRESULT_FROM_WIN32(GetLastError());
  1192. DEBUG_LEAVE(hr);
  1193. return hr;
  1194. }
  1195. }
  1196. DWORD cbRequired = zc.cchProtocol + 1 + cbSite + cbTail;
  1197. if (*pcbSecurityId < cbRequired)
  1198. {
  1199. *pcbSecurityId = cbRequired;
  1200. hr = HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER);
  1201. DEBUG_LEAVE(hr);
  1202. return hr;
  1203. }
  1204. // Emit the protocol in ANSI.
  1205. DWORD cbOut;
  1206. cbOut = WideCharToMultiByte (CP_ACP, 0, zc.pszProtocol, zc.cchProtocol,
  1207. (LPSTR) pbSecurityId, *pcbSecurityId, NULL, NULL);
  1208. if (cbOut != zc.cchProtocol)
  1209. {
  1210. DEBUG_LEAVE(E_INVALIDARG);
  1211. return E_INVALIDARG; // non-ascii chars illegal in URL scheme
  1212. }
  1213. pbSecurityId[cbOut++] = ':';
  1214. // Emit the site/domain in ANSI.
  1215. if (cch2 != 0)
  1216. {
  1217. cbSite = WideCharToMultiByte (CP_ACP, 0, psz2, cch2,
  1218. (LPSTR) pbSecurityId + cbOut, *pcbSecurityId - cbOut, NULL, NULL);
  1219. }
  1220. // HACK: Need to figure out a better way to fix this.
  1221. // File: url's can come in with slashes and backslashes as seperators.
  1222. // To prevent things from breaking we replace any slashes in the
  1223. // pbSecurityId with a backslash.
  1224. if (zc.nScheme == URL_SCHEME_FILE && cch2 != 0)
  1225. {
  1226. LPSTR lpszStart = (LPSTR)pbSecurityId + cbOut;
  1227. LPSTR lpsz = lpszStart;
  1228. while (lpsz < lpszStart + cbSite)
  1229. {
  1230. if (*lpsz == '/')
  1231. *lpsz = '\\';
  1232. lpsz = CharNextA(lpsz);
  1233. }
  1234. }
  1235. cbOut += cbSite;
  1236. // Downcase the buffer.
  1237. pbSecurityId[cbOut] = 0;
  1238. CharLowerA ((LPSTR) pbSecurityId);
  1239. // Add the zone.
  1240. memcpy(pbSecurityId + cbOut, &dwZone, sizeof(DWORD));
  1241. if (fMarked)
  1242. {
  1243. CHAR chMark = WILDCARD;
  1244. memcpy(pbSecurityId + cbOut + sizeof(DWORD), &chMark, sizeof(CHAR));
  1245. }
  1246. // Report the output data size.
  1247. *pcbSecurityId = cbRequired;
  1248. // Now that we have all the pieces, (re)add it to the cache
  1249. s_smcache.Add(pwszUrl, dwZone, fMarked, pbSecurityId, cbRequired, (LPCWSTR)dwReserved);
  1250. if (pwszSecUrl2)
  1251. delete [] pwszSecUrl2 ;
  1252. if (pwszMarkURL)
  1253. LocalFree(pwszMarkURL);
  1254. } // got security URL
  1255. } // got security URL
  1256. else
  1257. {
  1258. // Got it from the cache.
  1259. *pcbSecurityId = cbSecurityID;
  1260. hr = S_OK;
  1261. }
  1262. } // delegate missing or wants us to do the work
  1263. DEBUG_LEAVE(((hr == S_OK)? dwZone : hr));
  1264. return hr;
  1265. }
  1266. // Helper functions to do generic UI from within ProcessUrlAction.
  1267. struct ActionStrIDMap
  1268. {
  1269. DWORD dwAction;
  1270. DWORD dwStrID;
  1271. };
  1272. ActionStrIDMap actionAlertIDMap [ ] =
  1273. {
  1274. { URLACTION_DOWNLOAD_SIGNED_ACTIVEX, IDS_ACTION_DL_SIGNED_ACTIVEX },
  1275. { URLACTION_DOWNLOAD_UNSIGNED_ACTIVEX, IDS_ACTION_DL_ACTIVEX },
  1276. { URLACTION_ACTIVEX_RUN, IDS_ACTION_AX_RUN },
  1277. { URLACTION_ACTIVEX_OVERRIDE_OBJECT_SAFETY, IDS_ACTION_AX_OVERRIDE_SAFETY },
  1278. { URLACTION_ACTIVEX_OVERRIDE_DATA_SAFETY, IDS_ACTION_AX_OVERRIDE_DATA_SAFETY },
  1279. { URLACTION_ACTIVEX_OVERRIDE_SCRIPT_SAFETY, IDS_ACTION_AX_OVERRIDE_SCRIPT_SAFETY},
  1280. { URLACTION_ACTIVEX_CONFIRM_NOOBJECTSAFETY, IDS_ACTION_AX_CONFIRM_NOSAFETY },
  1281. { URLACTION_SCRIPT_RUN, IDS_ACTION_SCRIPT_RUN },
  1282. { URLACTION_SCRIPT_OVERRIDE_SAFETY, IDS_ACTION_SCRIPT_OVERRIDE_SAFETY },
  1283. { URLACTION_SCRIPT_JAVA_USE, IDS_ACTION_SCRIPT_JAVA },
  1284. { URLACTION_SCRIPT_SAFE_ACTIVEX, IDS_ACTION_SCRIPT_SAFE_ACTIVEX },
  1285. { URLACTION_CROSS_DOMAIN_DATA, IDS_ACTION_CROSS_DOMAIN_DATA },
  1286. { URLACTION_SCRIPT_PASTE, IDS_ACTION_SCRIPT_PASTE },
  1287. { URLACTION_HTML_SUBMIT_FORMS, IDS_ACTION_HTML_FORMS },
  1288. { URLACTION_HTML_SUBMIT_FORMS_FROM, IDS_ACTION_HTML_FORMS },
  1289. { URLACTION_HTML_SUBMIT_FORMS_TO, IDS_ACTION_HTML_FORMS },
  1290. { URLACTION_HTML_FONT_DOWNLOAD, IDS_ACTION_HTML_FONT_DL },
  1291. { URLACTION_HTML_JAVA_RUN, IDS_ACTION_HTML_JAVA },
  1292. { URLACTION_HTML_USERDATA_SAVE, IDS_ACTION_HTML_USERDATA },
  1293. { URLACTION_HTML_SUBFRAME_NAVIGATE, IDS_ACTION_HTML_SUBFRAME_NAVIGATE },
  1294. { URLACTION_HTML_META_REFRESH, IDS_ACTION_HTML_META_REFRESH },
  1295. { URLACTION_HTML_MIXED_CONTENT, IDS_ACTION_HTML_MIXED_CONTENT },
  1296. { URLACTION_SHELL_INSTALL_DTITEMS, IDS_ACTION_SHELL_INSTALL_DTITEMS },
  1297. { URLACTION_SHELL_MOVE_OR_COPY, IDS_ACTION_SHELL_MOVE_OR_COPY },
  1298. { URLACTION_SHELL_FILE_DOWNLOAD, IDS_ACTION_SHELL_FILE_DL },
  1299. { URLACTION_SHELL_VERB, IDS_ACTION_SHELL_VERB },
  1300. { URLACTION_SHELL_WEBVIEW_VERB, IDS_ACTION_SHELL_WEBVIEW_VERB },
  1301. { URLACTION_CREDENTIALS_USE, IDS_ACTION_NW_CREDENTIALS },
  1302. { URLACTION_AUTHENTICATE_CLIENT, IDS_ACTION_NW_AUTH_CLIENT },
  1303. { URLACTION_COOKIES, IDS_ACTION_NW_COOKIES },
  1304. { URLACTION_COOKIES_SESSION, IDS_ACTION_NW_COOKIES_SESSION },
  1305. { URLACTION_CLIENT_CERT_PROMPT, IDS_ACTION_NW_CLIENT_CERT_PROMPT },
  1306. { URLACTION_COOKIES_THIRD_PARTY, IDS_ACTION_NW_COOKIES_THIRD_PARTY },
  1307. { URLACTION_COOKIES_SESSION_THIRD_PARTY, IDS_ACTION_NW_COOKIES_SESSION_THIRD_PARTY },
  1308. };
  1309. ActionStrIDMap actionWarnIDMap [ ] =
  1310. {
  1311. { URLACTION_SHELL_INSTALL_DTITEMS, IDS_WARN_SHELL_INSTALL_DTITEMS },
  1312. { URLACTION_SHELL_MOVE_OR_COPY, IDS_WARN_SHELL_MOVE_OR_COPY },
  1313. { URLACTION_SHELL_FILE_DOWNLOAD, IDS_WARN_SHELL_FILE_DL },
  1314. { URLACTION_SHELL_VERB, IDS_WARN_SHELL_VERB },
  1315. { URLACTION_SHELL_WEBVIEW_VERB, IDS_WARN_SHELL_WEBVIEW_VERB },
  1316. { URLACTION_HTML_SUBMIT_FORMS, IDS_WARN_HTML_FORMS },
  1317. { URLACTION_HTML_SUBMIT_FORMS_FROM, IDS_WARN_HTML_FORMS },
  1318. { URLACTION_HTML_SUBMIT_FORMS_TO, IDS_WARN_HTML_FORMS },
  1319. };
  1320. STDMETHODIMP_(DWORD)
  1321. CSecurityManager::GetAlertIdForAction(DWORD dwAction)
  1322. {
  1323. // The action should exist in our map.
  1324. int count = ARRAYSIZE(actionAlertIDMap);
  1325. for ( int i = 0 ; i < count ; i++ )
  1326. {
  1327. if (actionAlertIDMap[i].dwAction == dwAction)
  1328. {
  1329. return actionAlertIDMap[i].dwStrID;
  1330. }
  1331. }
  1332. // If we get here the Action was invalid or we are missing an
  1333. // entry in the map.
  1334. TransAssert(FALSE);
  1335. return IDS_ACTION_UNKNOWN;
  1336. }
  1337. STDMETHODIMP_(DWORD)
  1338. CSecurityManager::GetWarnIdForAction(DWORD dwAction)
  1339. {
  1340. // The action should exist in our map.
  1341. int count = ARRAYSIZE(actionWarnIDMap);
  1342. for ( int i = 0 ; i < count ; i++ )
  1343. {
  1344. if (actionWarnIDMap[i].dwAction == dwAction)
  1345. {
  1346. return actionWarnIDMap[i].dwStrID;
  1347. }
  1348. }
  1349. // If we get here the Action was invalid or we are missing an
  1350. // entry in the map.
  1351. TransAssert(FALSE);
  1352. return IDS_WARN_UNKNOWN;
  1353. }
  1354. // INFRASTRUCTURE FOR REMEMBERING ANSWERS.
  1355. // Are the answers for this action supposed to persist. i.e. if the user says 'Yes' or 'No' for
  1356. // these actions we will not requery them for the same URL for the duration of the security
  1357. // manager.
  1358. BOOL
  1359. CSecurityManager::CPersistAnswers::IsPersistentAnswerAction(DWORD dwAction)
  1360. {
  1361. switch (dwAction)
  1362. {
  1363. case URLACTION_ACTIVEX_RUN:
  1364. // This shouldn't happen because it is an aggregator
  1365. case URLACTION_ACTIVEX_OVERRIDE_OBJECT_SAFETY:
  1366. // These should never get called because of KludgeMapAggregatePolicy
  1367. case URLACTION_ACTIVEX_OVERRIDE_DATA_SAFETY:
  1368. case URLACTION_ACTIVEX_OVERRIDE_SCRIPT_SAFETY:
  1369. case URLACTION_SCRIPT_OVERRIDE_SAFETY:
  1370. case URLACTION_ACTIVEX_CONFIRM_NOOBJECTSAFETY:
  1371. case URLACTION_SCRIPT_RUN:
  1372. case URLACTION_SCRIPT_JAVA_USE:
  1373. case URLACTION_HTML_FONT_DOWNLOAD:
  1374. case URLACTION_SCRIPT_SAFE_ACTIVEX:
  1375. case URLACTION_CROSS_DOMAIN_DATA:
  1376. return TRUE;
  1377. default:
  1378. return FALSE;
  1379. }
  1380. }
  1381. // CAnswerEntry methods.
  1382. CSecurityManager::CPersistAnswers::CAnswerEntry::CAnswerEntry(LPCWSTR pszUrl, DWORD dwAction, BOOL iAnswer)
  1383. {
  1384. m_pNext = NULL;
  1385. m_dwAction = dwAction;
  1386. m_iAnswer = iAnswer;
  1387. m_pszUrl = StrDup(pszUrl);
  1388. }
  1389. CSecurityManager::CPersistAnswers::CAnswerEntry::~CAnswerEntry( )
  1390. {
  1391. if (m_pszUrl)
  1392. LocalFree(m_pszUrl);
  1393. }
  1394. BOOL CSecurityManager::CPersistAnswers::CAnswerEntry::MatchEntry(LPCWSTR pszUrl, DWORD dwAction)
  1395. {
  1396. return (dwAction == m_dwAction && (0 == StrCmp(pszUrl, m_pszUrl)));
  1397. }
  1398. // CPersistAnswers methods.
  1399. CSecurityManager::CPersistAnswers::~CPersistAnswers( )
  1400. {
  1401. // go through the CAnswerEntries and free them up.
  1402. CAnswerEntry * pEntry = m_pAnswerEntry;
  1403. while ( pEntry )
  1404. {
  1405. CAnswerEntry * pDelete = pEntry;
  1406. pEntry = pEntry->GetNext( );
  1407. delete pDelete;
  1408. }
  1409. }
  1410. // Returns TRUE if the user already answered this questions. FALSE otherwise.
  1411. //
  1412. BOOL CSecurityManager::CPersistAnswers::GetPrevAnswer(LPCWSTR pszUrl, DWORD dwAction, INT* piAnswer)
  1413. {
  1414. BOOL bReturn = FALSE;
  1415. CAnswerEntry * pAnswerEntry;
  1416. if (!IsPersistentAnswerAction(dwAction))
  1417. return FALSE;
  1418. for (pAnswerEntry = m_pAnswerEntry ; pAnswerEntry != NULL; pAnswerEntry = pAnswerEntry->GetNext())
  1419. {
  1420. if (pAnswerEntry->MatchEntry(pszUrl, dwAction))
  1421. {
  1422. if (piAnswer)
  1423. *piAnswer = pAnswerEntry->GetAnswer( );
  1424. bReturn = TRUE;
  1425. break;
  1426. }
  1427. }
  1428. return bReturn;
  1429. }
  1430. VOID CSecurityManager::CPersistAnswers::RememberAnswer(LPCWSTR pszUrl, DWORD dwAction, BOOL iAnswer)
  1431. {
  1432. // Nothing to do if we are not supposed to be persisted.
  1433. if (!IsPersistentAnswerAction(dwAction))
  1434. return;
  1435. TransAssert(!GetPrevAnswer(pszUrl, dwAction, NULL));
  1436. CAnswerEntry * pNew = new CAnswerEntry(pszUrl, dwAction, iAnswer);
  1437. // Just don't persist answers if we don't have memory.
  1438. if (pNew == NULL || pNew->GetUrl() == NULL)
  1439. return;
  1440. pNew->SetNext(m_pAnswerEntry);
  1441. m_pAnswerEntry = pNew;
  1442. return;
  1443. }
  1444. BOOL
  1445. CSecurityManager::IsScriptOrActiveXHardenedInternet(DWORD dwAction, DWORD dwPermissions, DWORD dwZone)
  1446. {
  1447. if
  1448. (
  1449. IEHardened() &&
  1450. (dwAction == URLACTION_ACTIVEX_RUN || dwAction == URLACTION_SCRIPT_RUN) &&
  1451. dwPermissions == URLPOLICY_DISALLOW &&
  1452. dwZone == URLZONE_INTERNET
  1453. )
  1454. {
  1455. // check if trust dialog enabled:
  1456. DWORD dwValue = TRUE; // default value of TRUSTDLG is TRUE
  1457. HKEY hKeyIE = 0;
  1458. // For applications, check only machine key:
  1459. if (RegOpenKeyEx(IsBrowserHosted()? HKEY_CURRENT_USER: HKEY_LOCAL_MACHINE,
  1460. REGSTR_PATH_IE_MAIN, 0, KEY_READ, &hKeyIE) == ERROR_SUCCESS)
  1461. {
  1462. DWORD dwLen = sizeof(dwValue);
  1463. RegQueryValueEx(hKeyIE, REGVAL_TRUSTDLG_ENABLED, NULL,
  1464. NULL, (LPBYTE)&dwValue, &dwLen);
  1465. RegCloseKey(hKeyIE);
  1466. }
  1467. return dwValue;
  1468. }
  1469. return FALSE;
  1470. }
  1471. BOOL
  1472. CSecurityManager::IsSiteInZone(LPCWSTR pszUrl, DWORD dwZone, IInternetSecurityManager *pSecMgr)
  1473. {
  1474. BOOL fRet = FALSE;
  1475. DWORD dwMappedZone;
  1476. if (pSecMgr && SUCCEEDED(pSecMgr->MapUrlToZone(pszUrl, &dwMappedZone, 0)))
  1477. {
  1478. fRet = (dwZone == dwMappedZone);
  1479. }
  1480. return fRet;
  1481. }
  1482. BOOL
  1483. CSecurityManager::ShowAddToSitesList(HWND hwnd, LPCWSTR pszUrl, DWORD dwZone)
  1484. {
  1485. BOOL fRet = FALSE;
  1486. HMODULE hmod = LoadLibrary(TEXT("inetcpl.cpl"));
  1487. if(hmod)
  1488. {
  1489. BOOL (*pfnAddSitesDlg)(HWND, DWORD, LPCWSTR) =
  1490. (BOOL (*)(HWND, DWORD, LPCWSTR))GetProcAddress(hmod, "LaunchAddSitesDialog");
  1491. if(pfnAddSitesDlg)
  1492. {
  1493. fRet = pfnAddSitesDlg(hwnd, dwZone, pszUrl);
  1494. }
  1495. FreeLibrary(hmod);
  1496. }
  1497. return fRet;
  1498. }
  1499. BOOL
  1500. GetAddSitesDisplayUrl(LPCWSTR pszUrl, LPWSTR pszUrlDisplay, DWORD cchUrlDisplay)
  1501. {
  1502. BOOL fRet = FALSE;
  1503. HMODULE hmod = LoadLibrary(TEXT("inetcpl.cpl"));
  1504. if(hmod)
  1505. {
  1506. BOOL (*pfnGetAddSitesDisplayUrl)(LPCWSTR, LPWSTR, DWORD) =
  1507. (BOOL (*)(LPCWSTR, LPWSTR, DWORD))GetProcAddress(hmod, "GetAddSitesDisplayUrl");
  1508. if(pfnGetAddSitesDisplayUrl)
  1509. {
  1510. fRet = pfnGetAddSitesDisplayUrl(pszUrl, pszUrlDisplay, cchUrlDisplay);
  1511. }
  1512. FreeLibrary(hmod);
  1513. }
  1514. return fRet;
  1515. }
  1516. // Encapsulate common functionality:
  1517. HWND CSecurityManager::SetControlText(HWND hDlg, UINT ctrlID, DWORD dwStrId, LPCWSTR pszDomain)
  1518. {
  1519. WCHAR rgszAlert[MAX_ALERT_SIZE];
  1520. if (::LoadStringWrapW(g_hInst, dwStrId, rgszAlert, MAX_ALERT_SIZE) == 0)
  1521. {
  1522. TransAssert(FALSE);
  1523. ::LoadStringWrapW(g_hInst, IDS_ACTION_UNKNOWN, rgszAlert, MAX_ALERT_SIZE);
  1524. }
  1525. if(pszDomain != NULL)
  1526. {
  1527. WCHAR rgszAlert2[MAX_ALERT_SIZE];
  1528. wcsncpy(rgszAlert2, rgszAlert, ARRAYSIZE(rgszAlert2) - 1);
  1529. wnsprintf(rgszAlert, ARRAYSIZE(rgszAlert) - 1, rgszAlert2, pszDomain);
  1530. }
  1531. HWND hwndAlertText = ::GetDlgItem(hDlg, ctrlID);
  1532. TransAssert(hwndAlertText != NULL);
  1533. ::SetWindowTextWrapW(hwndAlertText, rgszAlert);
  1534. return hwndAlertText;
  1535. }
  1536. BOOL CSecurityManager::IsBrowserHosted()
  1537. {
  1538. return (GetModuleHandle(TEXT("iexplore.exe")) != NULL
  1539. || GetModuleHandle(TEXT("explorer.exe")) != NULL);
  1540. }
  1541. void
  1542. CSecurityManager::ShowUrlInNewBrowserInstance(LPCWSTR pwszUrl)
  1543. {
  1544. SHOWURLINNEWBROWSERINSTANCE pfSHOWURLINNEWBROWSERINSTANCE = NULL;
  1545. HINSTANCE hShdocvwLib;
  1546. if ( ( hShdocvwLib = LoadLibrary( L"shdocvw.dll" ) ) != NULL )
  1547. {
  1548. if ( pfSHOWURLINNEWBROWSERINSTANCE = (SHOWURLINNEWBROWSERINSTANCE)
  1549. GetProcAddress( hShdocvwLib, (LPSTR)SHOWURLINNEWBROWSERINSTANCE_ORDINAL) )
  1550. {
  1551. pfSHOWURLINNEWBROWSERINSTANCE(pwszUrl);
  1552. }
  1553. FreeLibrary( hShdocvwLib );
  1554. }
  1555. }
  1556. INT_PTR
  1557. CSecurityManager::TrustAlertDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
  1558. {
  1559. LPDLGDATA lpDlgData;
  1560. HKEY hKeyIE = 0;
  1561. switch (iMsg)
  1562. {
  1563. case WM_INITDIALOG:
  1564. {
  1565. lpDlgData = (LPDLGDATA)lParam;
  1566. TransAssert(lpDlgData != NULL);
  1567. // Squirrel away the DlgData for later use as initialization data for the Trusted Sites dialog
  1568. SetWindowLongPtr(
  1569. hDlg,
  1570. DWLP_USER,
  1571. (LONG_PTR)lpDlgData);
  1572. UINT uID;
  1573. BOOL bShowCheckbox;
  1574. if(IsBrowserHosted())
  1575. {
  1576. if(!lpDlgData->bFromShdocvw)
  1577. {
  1578. uID = IDS_TRUST_DLG_MSG_STRING_URLMON_IE_1;
  1579. // checkbox always checked:
  1580. bShowCheckbox = TRUE;
  1581. }
  1582. else
  1583. {
  1584. // browser hosted shdocvw:
  1585. uID = IDS_TRUST_DLG_MSG_STRING_SHDOCVW_IE_1;
  1586. // Hide the checkbox:
  1587. bShowCheckbox = FALSE;
  1588. }
  1589. }
  1590. else // Non-browser hosted weboc:
  1591. {
  1592. TransAssert(!lpDlgData->bFromShdocvw);
  1593. uID = IDS_TRUST_DLG_MSG_STRING_URLMON_NONIE_1;
  1594. // Hide the checkbox:
  1595. bShowCheckbox = FALSE;
  1596. }
  1597. SetControlText(hDlg, IDC_TRUSTDLGTEXT1, uID);
  1598. if(bShowCheckbox)
  1599. {
  1600. CheckDlgButton(hDlg, IDC_ENABLE_TRUSTDLG, BST_CHECKED);
  1601. }
  1602. else
  1603. {
  1604. ShowWindow(GetDlgItem(hDlg, IDC_ENABLE_TRUSTDLG), SW_HIDE);
  1605. }
  1606. SetControlText(hDlg, IDC_TRUSTDLGTEXT2, IDS_TRUST_DLG_MSG_STRING_URLMON_SHDOCVW_IE_NONIE_2);
  1607. SetControlText(hDlg, IDC_TRUSTDLGTEXT3, IDS_TRUST_DLG_MSG_STRING_URLMON_SHDOCVW_IE_NONIE_WARNING);
  1608. SetControlText(hDlg, IDC_URL, IDS_TRUST_DLG_MSG_STRING_URLMON_SHDOCVW_IE_NONIE_URL, lpDlgData->pstr);
  1609. if(g_bUseHKLMOnly)
  1610. {
  1611. BOOL fEnable = TRUE;
  1612. HINSTANCE hinstAdvPack = LoadLibraryA("ADVPACK.DLL");
  1613. if (hinstAdvPack)
  1614. {
  1615. ISNTADMIN pfnIsNTAdmin = (ISNTADMIN)GetProcAddress(hinstAdvPack, achISNTADMIN);
  1616. if (pfnIsNTAdmin)
  1617. {
  1618. fEnable = pfnIsNTAdmin(0, NULL);
  1619. }
  1620. FreeLibrary(hinstAdvPack);
  1621. }
  1622. EnableWindow(GetDlgItem(hDlg, IDC_ADD_TRUSTED_SITES), fEnable);
  1623. }
  1624. if (lpDlgData->dwFlags & PUAF_FORCEUI_FOREGROUND)
  1625. {
  1626. SetForegroundWindow(hDlg);
  1627. }
  1628. // ensure that this window is topmost
  1629. SetWindowPos(hDlg, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
  1630. return TRUE;
  1631. }
  1632. case WM_NOTIFY:
  1633. if (IDC_ESC_HELP == LOWORD(wParam))
  1634. {
  1635. NMHDR *pnmh = (NMHDR*) lParam;
  1636. if ((NM_CLICK == pnmh->code) || (NM_RETURN == pnmh->code))
  1637. {
  1638. ShowUrlInNewBrowserInstance(L"res://shdoclc.dll/IESechelp.htm");
  1639. }
  1640. }
  1641. break;
  1642. case WM_COMMAND:
  1643. switch (LOWORD(wParam))
  1644. {
  1645. case IDOK:
  1646. case IDCANCEL:
  1647. if( IsWindowVisible(GetDlgItem(hDlg, IDC_ENABLE_TRUSTDLG)) )
  1648. {
  1649. // persist value in registry:
  1650. hKeyIE = 0;
  1651. if (RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_IE_MAIN, 0, KEY_SET_VALUE, &hKeyIE) == ERROR_SUCCESS)
  1652. {
  1653. DWORD dwValue = IsDlgButtonChecked(hDlg, IDC_ENABLE_TRUSTDLG) == BST_CHECKED;
  1654. RegSetValueEx(hKeyIE, REGVAL_TRUSTDLG_ENABLED, NULL,
  1655. REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
  1656. RegCloseKey(hKeyIE);
  1657. }
  1658. }
  1659. // Check if site added to trusted list, if so return ZALERT_YES, to allow URLAction to succeed:
  1660. lpDlgData = (LPDLGDATA)GetWindowLongPtr(hDlg, DWLP_USER);
  1661. TransAssert(NULL != lpDlgData && NULL != lpDlgData->pstr && (lpDlgData->bFromShdocvw || NULL != lpDlgData->pSecurityManager));
  1662. EndDialog(hDlg,
  1663. // check if the site was actually added to the trusted zone:
  1664. IsSiteInZone(lpDlgData->pstr, URLZONE_TRUSTED, lpDlgData->pSecurityManager)?
  1665. ZALERT_YES: ZALERT_NO);
  1666. return TRUE;
  1667. case IDC_ADD_TRUSTED_SITES:
  1668. // Show Trusted Sites dialog.
  1669. lpDlgData = (LPDLGDATA)GetWindowLongPtr(hDlg, DWLP_USER);
  1670. TransAssert(NULL != lpDlgData && NULL != lpDlgData->pstr);
  1671. ShowAddToSitesList(hDlg, lpDlgData->pstr, URLZONE_TRUSTED);
  1672. // check if the site was actually added to the trusted zone:
  1673. if (IsSiteInZone(lpDlgData->pstr, URLZONE_TRUSTED, lpDlgData->pSecurityManager))
  1674. {
  1675. EndDialog(hDlg, ZALERT_YES);
  1676. }
  1677. return TRUE;
  1678. }
  1679. break;
  1680. } /* end switch */
  1681. return FALSE;
  1682. }
  1683. STDAPI_(int)
  1684. ShowTrustAlertDialog(HWND hwndParent, IInternetSecurityManager *pSecurityManager, LPVOID lpDlgDataIn, LPCWSTR pwszUrl )
  1685. {
  1686. LPDLGDATA lpDlgData;
  1687. DlgData dlgData;
  1688. int nRet;
  1689. WCHAR szUrl[MAX_ZONE_PATH];
  1690. if(!lpDlgDataIn)
  1691. {
  1692. ZeroMemory(&dlgData, sizeof(dlgData));
  1693. lpDlgData = &dlgData;
  1694. }
  1695. else
  1696. {
  1697. lpDlgData = (LPDLGDATA)lpDlgDataIn;
  1698. }
  1699. if (!pSecurityManager && SUCCEEDED(EnsureSecurityManager()) )
  1700. pSecurityManager = g_pSecurityManager;
  1701. lpDlgData->pSecurityManager = pSecurityManager;
  1702. lpDlgData->bFromShdocvw = !lpDlgDataIn;
  1703. if (GetAddSitesDisplayUrl(pwszUrl, szUrl, ARRAYSIZE(szUrl)))
  1704. {
  1705. lpDlgData->pstr = szUrl;
  1706. }
  1707. else
  1708. {
  1709. // Should never reach here
  1710. TransAssert(FALSE);
  1711. lpDlgData->pstr = L"";
  1712. }
  1713. ULONG_PTR uCookie = 0;
  1714. SHActivateContext(&uCookie);
  1715. nRet = (int) ::DialogBoxParamWrapW (
  1716. g_hInst,
  1717. MAKEINTRESOURCEW(IDD_TRUST_ALERT),
  1718. hwndParent,
  1719. CSecurityManager::TrustAlertDialogProc,
  1720. (LPARAM)lpDlgData
  1721. );
  1722. if (uCookie)
  1723. {
  1724. SHDeactivateContext(uCookie);
  1725. }
  1726. return nRet;
  1727. }
  1728. // This is the dialog proc for the generic Zones Alert dialog.
  1729. // IMPORTANT: This is an ANSI function in an otherwise unicode world.
  1730. // BE EXTREMELY CAREFUL WHEN CALLING WINDOWS API FUNCTIONS.
  1731. INT_PTR
  1732. CSecurityManager::ZonesAlertDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
  1733. {
  1734. switch (iMsg)
  1735. {
  1736. case WM_INITDIALOG:
  1737. {
  1738. WCHAR rgszAlert[MAX_ALERT_SIZE];
  1739. LPDLGDATA lpDlgData = (LPDLGDATA)lParam;
  1740. TransAssert(lpDlgData != NULL);
  1741. SetControlText(hDlg, IDC_ZONEALERTTEXT, GetAlertIdForAction(lpDlgData->dwAction));
  1742. if (lpDlgData->dwFlags & PUAF_FORCEUI_FOREGROUND)
  1743. {
  1744. SetForegroundWindow(hDlg);
  1745. }
  1746. // ensure that this window is topmost
  1747. SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
  1748. return TRUE;
  1749. }
  1750. case WM_COMMAND:
  1751. switch (LOWORD(wParam))
  1752. {
  1753. case IDOK:
  1754. EndDialog(hDlg, ZALERT_YES);
  1755. return TRUE;
  1756. case IDCANCEL:
  1757. EndDialog(hDlg, ZALERT_NO);
  1758. return TRUE;
  1759. }
  1760. break;
  1761. } /* end switch */
  1762. return FALSE;
  1763. }
  1764. // This is the dialog proc for the Alert displayed when information is posted over the net.
  1765. // This is a special case, since it is the only dialog where we let the user persist their change.
  1766. // DO NOT START ADDING OTHER SPECIAL CASES TO THIS. IF YOU NEED TO, CONSIDER CHANGING THE
  1767. // THE TEMPLATE POLICY FOR THE ZONE TO BE "CUSTOM" BECAUSE THE ZONE WILL START DIVERGING FROM
  1768. // THE TEMPLATE IT IS SUPPOSED TO BE BASED ON.
  1769. BOOL
  1770. CSecurityManager::IsFormsSubmitAction(DWORD dwAction)
  1771. {
  1772. return (dwAction == URLACTION_HTML_SUBMIT_FORMS ||
  1773. dwAction == URLACTION_HTML_SUBMIT_FORMS_FROM ||
  1774. dwAction == URLACTION_HTML_SUBMIT_FORMS_TO
  1775. );
  1776. }
  1777. INT_PTR
  1778. CSecurityManager::FormsAlertDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
  1779. {
  1780. switch (iMsg)
  1781. {
  1782. case WM_INITDIALOG:
  1783. {
  1784. LPDLGDATA lpDlgData = (LPDLGDATA)lParam;
  1785. TransAssert(lpDlgData != NULL);
  1786. LPCWSTR pstr = lpDlgData->pstr;
  1787. if (pstr != NULL)
  1788. {
  1789. HWND hwnd = ::GetDlgItem(hDlg, IDC_ZONEALERTTEXT);
  1790. TransAssert(hwnd != NULL);
  1791. ::SetWindowTextWrapW(hwnd, pstr);
  1792. }
  1793. if (lpDlgData->dwFlags & PUAF_FORCEUI_FOREGROUND)
  1794. {
  1795. SetForegroundWindow(hDlg);
  1796. }
  1797. if(!(lpDlgData->dwFlags & PUAF_DONTCHECKBOXINDIALOG))
  1798. {
  1799. CheckDlgButton(hDlg, IDC_DONT_WANT_WARNING, BST_CHECKED);
  1800. }
  1801. return TRUE;
  1802. }
  1803. case WM_COMMAND:
  1804. switch (LOWORD(wParam))
  1805. {
  1806. case IDOK:
  1807. case IDYES:
  1808. {
  1809. DWORD dwRet;
  1810. if (IsDlgButtonChecked(hDlg, IDC_DONT_WANT_WARNING) == BST_CHECKED)
  1811. dwRet = ZALERT_YESPERSIST;
  1812. else
  1813. dwRet = ZALERT_YES;
  1814. EndDialog(hDlg, dwRet);
  1815. return TRUE;
  1816. }
  1817. case IDCANCEL:
  1818. case IDNO:
  1819. EndDialog(hDlg, ZALERT_NO);
  1820. return TRUE;
  1821. }
  1822. break;
  1823. } /* end switch */
  1824. return FALSE;
  1825. }
  1826. INT
  1827. CSecurityManager::ShowFormsAlertDialog(HWND hwndParent, LPDLGDATA lpDlgData )
  1828. {
  1829. int nRet;
  1830. TransAssert(lpDlgData != NULL);
  1831. TransAssert(IsFormsSubmitAction(lpDlgData->dwAction));
  1832. // Compose the dialog string.
  1833. LPWSTR pstr = NULL;
  1834. WCHAR rgch[MAX_ALERT_SIZE];
  1835. ZONEATTRIBUTES zc;
  1836. zc.cbSize = sizeof(zc);
  1837. if (SUCCEEDED(m_pZoneManager->GetZoneAttributes(lpDlgData->dwZone, &zc)))
  1838. {
  1839. WCHAR rgchStr[MAX_ALERT_SIZE];
  1840. UINT uID = (lpDlgData->dwAction == URLACTION_HTML_SUBMIT_FORMS_FROM) ? IDS_ACTION_POST_FROM : IDS_ACTION_FORMS_POST;
  1841. if (::LoadStringWrapW(g_hInst, uID, rgchStr, MAX_ALERT_SIZE) != 0)
  1842. {
  1843. if (wnsprintfW(rgch, MAX_ALERT_SIZE, rgchStr, zc.szDisplayName) != 0)
  1844. pstr = rgch;
  1845. }
  1846. }
  1847. lpDlgData->pstr = pstr;
  1848. ULONG_PTR uCookie = 0;
  1849. SHActivateContext(&uCookie);
  1850. nRet = (int) ::DialogBoxParamWrapW (
  1851. g_hInst,
  1852. MAKEINTRESOURCEW(IDD_WARN_ON_POST),
  1853. hwndParent,
  1854. CSecurityManager::FormsAlertDialogProc,
  1855. (LPARAM)lpDlgData
  1856. );
  1857. if (uCookie)
  1858. {
  1859. SHDeactivateContext(uCookie);
  1860. }
  1861. return nRet;
  1862. }
  1863. INT_PTR
  1864. CSecurityManager::ZonesWarnDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
  1865. {
  1866. switch (iMsg)
  1867. {
  1868. case WM_INITDIALOG:
  1869. {
  1870. WCHAR rgszWarn[MAX_ALERT_SIZE];
  1871. LPDLGDATA lpDlgData = (LPDLGDATA)lParam;
  1872. TransAssert(lpDlgData != NULL);
  1873. DWORD dwAction = lpDlgData->dwAction;
  1874. SetControlText(hDlg, IDC_ZONEALERTTEXT, GetWarnIdForAction(dwAction));
  1875. if (lpDlgData->dwFlags & PUAF_FORCEUI_FOREGROUND)
  1876. {
  1877. SetForegroundWindow(hDlg);
  1878. }
  1879. return TRUE;
  1880. }
  1881. case WM_COMMAND:
  1882. switch (LOWORD(wParam))
  1883. {
  1884. case IDOK:
  1885. case IDCANCEL:
  1886. EndDialog(hDlg, ZALERT_YES);
  1887. return TRUE;
  1888. }
  1889. break;
  1890. } /* end switch */
  1891. return FALSE;
  1892. }
  1893. // INETCPL calls this during _GetAddSitesDisplayUrl
  1894. // to get the correct file://UNC URL domain
  1895. // NOTE: The input URL pszUrl has to be atleast MAX_ZONE_PATH in size
  1896. STDAPI GetAddSitesFileUrl(LPWSTR /* [in, out] */ pszUrl)
  1897. {
  1898. HRESULT hr = S_FALSE;
  1899. ZONEMAP_COMPONENTS zc;
  1900. // Conversion for UNC paths:
  1901. if(SUCCEEDED(zc.Crack (pszUrl, 0 /* dwFlags */)) && zc.nScheme == URL_SCHEME_FILE
  1902. && !zc.cchDomain && !zc.fDrive && zc.pszSite && zc.cchSite
  1903. )
  1904. {
  1905. // Guard against buffer overflow.
  1906. if (ARRAYSIZE(L"file://") + zc.cchSite >= MAX_ZONE_PATH)
  1907. {
  1908. hr = E_INVALIDARG;
  1909. }
  1910. else
  1911. {
  1912. // ZONEMAP_COMPONENTS components could be pointing directly into pszUrl,
  1913. // so create a new string to hold the result:
  1914. DWORD nSizeNewFileUrl = ARRAYSIZE(L"file://") + zc.cchSite + 1;
  1915. LPWSTR pwzNewFileUrl = new WCHAR [nSizeNewFileUrl];
  1916. if ( pwzNewFileUrl != NULL )
  1917. {
  1918. // convert to the form file://UNC
  1919. StrCpyNW(pwzNewFileUrl, L"file://", ARRAYSIZE(L"file://") /* No of chars to copy incl NULL */);
  1920. StrNCatW(pwzNewFileUrl, zc.pszSite, zc.cchSite + 1 /* Incl NULL */);
  1921. StrCpyNW(pszUrl, pwzNewFileUrl, nSizeNewFileUrl /* No of chars to copy incl NULL */);
  1922. delete [] pwzNewFileUrl;
  1923. hr = S_OK;
  1924. }
  1925. else
  1926. {
  1927. hr = E_OUTOFMEMORY;
  1928. }
  1929. }
  1930. }
  1931. return hr;
  1932. }
  1933. STDMETHODIMP
  1934. CSecurityManager::ProcessUrlAction
  1935. (
  1936. LPCWSTR pwszUrl,
  1937. DWORD dwAction,
  1938. BYTE * pPolicy,
  1939. DWORD cbPolicy,
  1940. BYTE * pContext,
  1941. DWORD cbContext,
  1942. DWORD dwFlags,
  1943. DWORD dwReserved
  1944. )
  1945. {
  1946. DEBUG_ENTER((DBG_API,
  1947. Hresult,
  1948. "CSecurityManager::ProcessUrlAction",
  1949. "%.100wq, %#x, dwFlags=%#x, dwReserved=%#x",
  1950. pwszUrl, dwAction, dwFlags, dwReserved
  1951. ));
  1952. PerfDbgLog(tagCSecurityManager, this, "+CSecurityManager::ProcessUrlAction");
  1953. HRESULT hr = INET_E_DEFAULT_ACTION;
  1954. DWORD dwZone = ZONEID_INVALID;
  1955. // First check if the delegation interface wants to handle this.
  1956. if (m_pDelegateSecMgr)
  1957. {
  1958. if (pwszUrl && wcsncmp(pwszUrl, L"about:security_", 15) == 0)
  1959. {
  1960. hr = m_pDelegateSecMgr->ProcessUrlAction(L"about:blank", dwAction, pPolicy, cbPolicy, pContext, cbContext, dwFlags, dwReserved);
  1961. }
  1962. else
  1963. {
  1964. hr = m_pDelegateSecMgr->ProcessUrlAction(pwszUrl, dwAction, pPolicy, cbPolicy, pContext, cbContext, dwFlags, dwReserved);
  1965. }
  1966. }
  1967. if (hr != INET_E_DEFAULT_ACTION)
  1968. {
  1969. // Delegation interface processed the request.
  1970. DEBUG_LEAVE(hr);
  1971. return hr;
  1972. }
  1973. if (!EnsureZoneManager())
  1974. {
  1975. DEBUG_LEAVE(E_UNEXPECTED);
  1976. return E_UNEXPECTED;
  1977. }
  1978. // Increment our refcount so we don't get destroyed for the duration of this
  1979. // function.
  1980. AddRef();
  1981. if (dwFlags & PUAF_ENFORCERESTRICTED)
  1982. {
  1983. dwZone = URLZONE_UNTRUSTED;
  1984. hr = S_OK;
  1985. }
  1986. else
  1987. {
  1988. hr = MapUrlToZone(pwszUrl, &dwZone, dwFlags);
  1989. }
  1990. if (SUCCEEDED(hr))
  1991. {
  1992. DWORD dwPolicy;
  1993. hr = m_pZoneManager->GetZoneActionPolicy(dwZone, dwAction, (BYTE *)&dwPolicy, sizeof(dwPolicy), URLZONEREG_DEFAULT);
  1994. if (SUCCEEDED(hr))
  1995. {
  1996. DWORD dwPermissions = GetUrlPolicyPermissions(dwPolicy);
  1997. BOOL isScriptOrActiveXHardenedInternet = IsScriptOrActiveXHardenedInternet(dwAction, dwPermissions, dwZone);
  1998. if(isScriptOrActiveXHardenedInternet)
  1999. {
  2000. // Make it a query:
  2001. dwPermissions = URLPOLICY_QUERY;
  2002. }
  2003. // Are we supposed to be showing any UI here?
  2004. if ( (( dwPermissions == URLPOLICY_QUERY && ( dwFlags & PUAF_NOUI) == 0 ) ||
  2005. ( dwPermissions == URLPOLICY_DISALLOW && ( dwFlags & PUAF_WARN_IF_DENIED) != 0))
  2006. && HIWORD(dwPolicy) == 0)
  2007. {
  2008. HWND hwndParent = NULL;
  2009. // Show UI unless the host indicates otherwise.
  2010. BOOL bShowUI = TRUE;
  2011. if (m_pSite != NULL)
  2012. {
  2013. HRESULT hrGetWnd = m_pSite->GetWindow(&hwndParent);
  2014. // Host doesn't want us to show UI.
  2015. if (hrGetWnd == S_FALSE && hwndParent == INVALID_HANDLE_VALUE)
  2016. bShowUI = FALSE;
  2017. else if (FAILED(hrGetWnd))
  2018. hwndParent = NULL;
  2019. // Disable any modeless dialog boxes
  2020. m_pSite->EnableModeless(FALSE);
  2021. }
  2022. int nRet = -1;
  2023. BOOL fRememberAnswer = FALSE;
  2024. // structure used to pass information to the dialog proc's.
  2025. DlgData dlgData;
  2026. dlgData.dwAction = dwAction;
  2027. dlgData.dwZone = dwZone;
  2028. dlgData.pstr = NULL;
  2029. dlgData.dwFlags = dwFlags | ((dwPolicy & URLPOLICY_DONTCHECKDLGBOX) ? PUAF_DONTCHECKBOXINDIALOG : 0);
  2030. dwPolicy = dwPolicy & ~URLPOLICY_DONTCHECKDLGBOX;
  2031. if ( dwPermissions == URLPOLICY_QUERY )
  2032. {
  2033. // First check to see if the user already answered this question once.
  2034. if (!m_persistAnswers.GetPrevAnswer(pwszUrl, dwAction, &nRet))
  2035. {
  2036. fRememberAnswer = TRUE;
  2037. if (!bShowUI)
  2038. {
  2039. // If we can't show UI just act as if the user said No.
  2040. nRet = ZALERT_NO;
  2041. }
  2042. else if (IsFormsSubmitAction(dwAction))
  2043. {
  2044. nRet = ShowFormsAlertDialog(hwndParent, &dlgData);
  2045. }
  2046. else
  2047. {
  2048. if(isScriptOrActiveXHardenedInternet)
  2049. {
  2050. nRet = ShowTrustAlertDialog(hwndParent, (IInternetSecurityManager *)this, &dlgData, pwszUrl );
  2051. }
  2052. else
  2053. {
  2054. ULONG_PTR uCookie = 0;
  2055. SHActivateContext(&uCookie);
  2056. nRet = (int) ::DialogBoxParamWrapW (
  2057. g_hInst,
  2058. MAKEINTRESOURCEW(IDD_ZONE_ALERT),
  2059. hwndParent,
  2060. CSecurityManager::ZonesAlertDialogProc,
  2061. (LPARAM)&dlgData
  2062. );
  2063. if (uCookie)
  2064. {
  2065. SHDeactivateContext(uCookie);
  2066. }
  2067. }
  2068. }
  2069. }
  2070. }
  2071. else
  2072. {
  2073. TransAssert(dwPermissions == URLPOLICY_DISALLOW);
  2074. if (bShowUI)
  2075. {
  2076. ULONG_PTR uCookie = 0;
  2077. SHActivateContext(&uCookie);
  2078. nRet = (int) ::DialogBoxParamWrapW (
  2079. g_hInst,
  2080. MAKEINTRESOURCEW(IDD_WARN_ALERT),
  2081. hwndParent,
  2082. CSecurityManager::ZonesWarnDialogProc,
  2083. (LPARAM)&dlgData
  2084. );
  2085. if (uCookie)
  2086. {
  2087. SHDeactivateContext(uCookie);
  2088. }
  2089. }
  2090. }
  2091. // If we failed to show the dialog we should just return
  2092. // the policies unmodified.
  2093. if (dwPermissions == URLPOLICY_QUERY && nRet != -1 )
  2094. {
  2095. // Change the policy to reflect the users choice.
  2096. DWORD dwYesOnlyPolicy;
  2097. dwYesOnlyPolicy = dwPolicy | URLPOLICY_DONTCHECKDLGBOX; // copy old policy before it is changed
  2098. SetUrlPolicyPermissions(dwPolicy, nRet ? URLPOLICY_ALLOW : URLPOLICY_DISALLOW);
  2099. if (fRememberAnswer)
  2100. m_persistAnswers.RememberAnswer(pwszUrl, dwAction, nRet);
  2101. // The only case where we should change the policy is we have a checkbox on the dialog
  2102. // we popped up that says "Don't ask me again". Today the only thing that does that is
  2103. // the forms submit form.
  2104. // TODO: create a more generic category name "CanDlgChangePolicy" or something like that
  2105. // instead of the specific IsFormsSubmitAction.
  2106. if (IsFormsSubmitAction(dwAction) && ((nRet == ZALERT_YESPERSIST) || (nRet == ZALERT_YES)))
  2107. {
  2108. m_pZoneManager->SetZoneActionPolicy(dwZone, dwAction,
  2109. (BYTE *)((nRet == ZALERT_YESPERSIST) ? &dwPolicy : &dwYesOnlyPolicy),
  2110. sizeof(dwPolicy), URLZONEREG_DEFAULT);
  2111. }
  2112. }
  2113. if (m_pSite != NULL)
  2114. {
  2115. m_pSite->EnableModeless(TRUE);
  2116. }
  2117. }
  2118. TransAssert(cbPolicy == 0 || cbPolicy >= sizeof(DWORD));
  2119. if (cbPolicy >= sizeof(DWORD) && pPolicy != NULL)
  2120. *(DWORD *)pPolicy = dwPolicy;
  2121. // Code to check for allowed list of directx objects
  2122. // for URLACTION_ACTIVEX_RUN
  2123. if(dwAction == URLACTION_ACTIVEX_RUN &&
  2124. dwPolicy == URLPOLICY_ACTIVEX_CHECK_LIST)
  2125. {
  2126. DWORD dwValue = 0;
  2127. hr = CSecurityManager::GetActiveXRunPermissions(pContext, dwValue);
  2128. *(DWORD *)pPolicy = dwValue;
  2129. }
  2130. // normal allowed permissions
  2131. else if(GetUrlPolicyPermissions(dwPolicy) == URLPOLICY_ALLOW)
  2132. {
  2133. hr = S_OK ;
  2134. }
  2135. else
  2136. {
  2137. hr = S_FALSE;
  2138. }
  2139. }
  2140. }
  2141. Release();
  2142. DEBUG_LEAVE( (SUCCEEDED(hr) ? *((DWORD*)pPolicy) : hr) );
  2143. return hr;
  2144. }
  2145. STDMETHODIMP
  2146. CSecurityManager::QueryCustomPolicy
  2147. (
  2148. LPCWSTR pwszUrl,
  2149. REFGUID guidKey,
  2150. BYTE **ppPolicy,
  2151. DWORD *pcbPolicy,
  2152. BYTE *pContext,
  2153. DWORD cbContext,
  2154. DWORD dwReserved
  2155. )
  2156. {
  2157. PerfDbgLog(tagCSecurityManager, this, "+CSecurityManager::QueryCustomPolicy");
  2158. HRESULT hr = INET_E_DEFAULT_ACTION;
  2159. DWORD dwZone = ZONEID_INVALID;
  2160. if (m_pDelegateSecMgr)
  2161. {
  2162. hr = m_pDelegateSecMgr->QueryCustomPolicy(pwszUrl, guidKey, ppPolicy, pcbPolicy, pContext, cbContext, dwReserved);
  2163. }
  2164. if (hr == INET_E_DEFAULT_ACTION)
  2165. {
  2166. if (!EnsureZoneManager())
  2167. {
  2168. return E_UNEXPECTED;
  2169. }
  2170. if (SUCCEEDED(hr = MapUrlToZone(pwszUrl, &dwZone, NULL)))
  2171. {
  2172. hr = m_pZoneManager->GetZoneCustomPolicy(dwZone, guidKey, ppPolicy, pcbPolicy, URLZONEREG_DEFAULT);
  2173. }
  2174. else
  2175. {
  2176. hr = E_UNEXPECTED;
  2177. }
  2178. }
  2179. return hr;
  2180. }
  2181. STDMETHODIMP
  2182. CSecurityManager::GetSecuritySite
  2183. (
  2184. IInternetSecurityMgrSite **ppSite
  2185. )
  2186. {
  2187. if (ppSite)
  2188. {
  2189. if (m_pSite)
  2190. m_pSite->AddRef();
  2191. *ppSite = m_pSite;
  2192. }
  2193. return S_OK;
  2194. }
  2195. STDMETHODIMP
  2196. CSecurityManager::SetSecuritySite
  2197. (
  2198. IInternetSecurityMgrSite *pSite
  2199. )
  2200. {
  2201. if (m_pSite)
  2202. {
  2203. m_pSite->Release();
  2204. }
  2205. if (m_pDelegateSecMgr)
  2206. {
  2207. m_pDelegateSecMgr->Release();
  2208. m_pDelegateSecMgr = NULL;
  2209. }
  2210. m_pSite = pSite;
  2211. if (m_pSite)
  2212. {
  2213. m_pSite->AddRef();
  2214. IServiceProvider * pServiceProvider = NULL;
  2215. if (SUCCEEDED(m_pSite->QueryInterface(IID_IServiceProvider, (void **)&pServiceProvider)))
  2216. {
  2217. TransAssert(pServiceProvider != NULL);
  2218. if (SUCCEEDED(pServiceProvider->QueryService(
  2219. SID_SInternetSecurityManager,
  2220. IID_IInternetSecurityManager,
  2221. (void **)&m_pDelegateSecMgr)))
  2222. {
  2223. TransAssert(m_pDelegateSecMgr != NULL);
  2224. }
  2225. else
  2226. {
  2227. m_pDelegateSecMgr = NULL;
  2228. }
  2229. pServiceProvider->Release();
  2230. }
  2231. }
  2232. return S_OK;
  2233. }
  2234. // Mapping related functions
  2235. HRESULT
  2236. CSecurityManager::SetZoneMapping
  2237. (
  2238. DWORD dwZone,
  2239. LPCWSTR pszPattern,
  2240. DWORD dwFlags
  2241. )
  2242. {
  2243. PerfDbgLog(tagCSecurityManager, this, "+CSecurityManager::SetZoneMapping");
  2244. HRESULT hr = INET_E_DEFAULT_ACTION;
  2245. // Increment the counter so any cached url to zone mappings are invalidated.
  2246. IncrementGlobalCounter( );
  2247. if (m_pDelegateSecMgr)
  2248. {
  2249. hr = m_pDelegateSecMgr->SetZoneMapping(dwZone, pszPattern, dwFlags);
  2250. }
  2251. if (hr == INET_E_DEFAULT_ACTION)
  2252. {
  2253. BOOL bUseHardenedZone;
  2254. if(bUseHardenedZone = (URLZONE_ESC_FLAG & dwZone) )
  2255. {
  2256. // Remove the special ESC flag bit to convert it to a regular URLZONE_XXX:
  2257. dwZone &= ~URLZONE_ESC_FLAG;
  2258. }
  2259. LPWSTR pwszSecPattern = NULL;
  2260. hr = CoInternetGetSecurityUrl(pszPattern, &pwszSecPattern, PSU_DEFAULT, 0);
  2261. if (SUCCEEDED(hr))
  2262. {
  2263. CFreeStrPtr freeStr(pwszSecPattern);
  2264. ZONEMAP_COMPONENTS zc;
  2265. hr = zc.Crack (pwszSecPattern, PUAF_ACCEPT_WILDCARD_SCHEME, TRUE);
  2266. if (hr != S_OK)
  2267. return hr;
  2268. ZONEATTRIBUTES za;
  2269. za.cbSize = sizeof(za);
  2270. if (!EnsureZoneManager())
  2271. return E_OUTOFMEMORY;
  2272. // IEHardening workaround: The "Flags" for the Trusted zone require "Server Authentication" by default for softened mode.
  2273. // In other words, only HTTPS sites can be added. But the default is to _not_ require https for hardened mode.
  2274. // Since we don't have 2 sets of flags, and since the zone template is not readily accessible, we assume that
  2275. // http sites can in fact be added for URLZONE_ESC_FLAG | URLZONE_TRUSTED cases
  2276. // Don't allow adding not https entries if the zone requires server verification.
  2277. if( !(bUseHardenedZone && URLZONE_TRUSTED == dwZone && !IEHardened()) )
  2278. {
  2279. if (!(dwFlags & SZM_DELETE) && SUCCEEDED(m_pZoneManager->GetZoneAttributes(dwZone, &za)))
  2280. {
  2281. if (za.dwFlags & ZAFLAGS_REQUIRE_VERIFICATION)
  2282. {
  2283. if (zc.nScheme != URL_SCHEME_HTTPS)
  2284. {
  2285. return E_ACCESSDENIED ;
  2286. }
  2287. }
  2288. }
  2289. }
  2290. if (zc.fIPRange)
  2291. {
  2292. hr = AddDeleteIPRule(&zc, dwZone, dwFlags);
  2293. return hr;
  2294. }
  2295. // Zone mappings for drive letters are hardcoded
  2296. if (zc.fDrive)
  2297. return E_INVALIDARG;
  2298. TCHAR szKeyName[MAX_PATH];
  2299. DWORD cchKeyName = CSTRLENW(SZDOMAINS);
  2300. if(bUseHardenedZone || m_fHardened)
  2301. {
  2302. cchKeyName = CSTRLENW(SZHARDENEDDOMAINS);
  2303. memcpy (szKeyName, SZHARDENEDDOMAINS, sizeof(TCHAR) * cchKeyName);
  2304. }
  2305. else
  2306. {
  2307. cchKeyName = CSTRLENW(SZDOMAINS);
  2308. memcpy (szKeyName, SZDOMAINS, sizeof(TCHAR) * cchKeyName);
  2309. }
  2310. // Guard against buffer overflow.
  2311. if (cchKeyName + zc.cchDomain + 1 + zc.cchSite + 1 >= MAX_PATH)
  2312. return E_INVALIDARG;
  2313. if ((zc.cchDomain == 0 && zc.cchSite == 0) || (zc.cchProtocol == 0))
  2314. {
  2315. return E_INVALIDARG;
  2316. }
  2317. if (zc.pszDomain)
  2318. {
  2319. memcpy (szKeyName + cchKeyName,
  2320. zc.pszDomain, sizeof(TCHAR) * zc.cchDomain);
  2321. // Null terminate for strchr.
  2322. szKeyName[cchKeyName + zc.cchDomain] = TEXT('\0');
  2323. if (StrChr(szKeyName + cchKeyName, WILDCARD) != NULL)
  2324. return E_INVALIDARG;
  2325. cchKeyName += zc.cchDomain;
  2326. }
  2327. else
  2328. {
  2329. /*We need to catch the following here:
  2330. 1. *.com
  2331. 2. www.*
  2332. 3. www.*.*
  2333. 4. *.co.uk
  2334. All these show up if zc.pszDomain is NULL.
  2335. */
  2336. if (StrChr(zc.pszSite, WILDCARD) != NULL)
  2337. return E_INVALIDARG;
  2338. }
  2339. // Check for the simple wildcard case.
  2340. // patterns such as *.microsoft.com where the only thing
  2341. // after a * is the second-level domain.
  2342. if (zc.pszSite[0] == WILDCARD && zc.cchSite == 1)
  2343. {
  2344. if (!zc.pszDomain)
  2345. return E_INVALIDARG;
  2346. }
  2347. else
  2348. {
  2349. // Wildcards are only permitted at the begining of pattern.
  2350. // So patterns such as *.foo.*.microsoft.com are invalid.
  2351. if (zc.pszSite[0] == WILDCARD)
  2352. {
  2353. // We already know that zc.cchSite is greater than 1
  2354. // because we would have caught it in the outer 'if' clause
  2355. // otherwise.
  2356. if (zc.pszSite[1] != DOT)
  2357. {
  2358. return E_INVALIDARG;
  2359. }
  2360. // Skip over the leading *. and make sure there are no
  2361. // other *'s in the string.
  2362. if (StrRChr(zc.pszSite + 2, zc.pszSite + zc.cchSite, WILDCARD) != NULL)
  2363. {
  2364. return E_INVALIDARG;
  2365. }
  2366. }
  2367. if (zc.pszDomain) // Add seperator only if we added a domain name.
  2368. {
  2369. szKeyName[cchKeyName++] = BACKSLASH;
  2370. }
  2371. else if (!IsOpaqueScheme(zc.nScheme) &&
  2372. (zc.pszSite[zc.cchSite - 1] == DOT ||
  2373. zc.pszSite[0] == DOT)
  2374. )
  2375. {
  2376. // Catches invalid cases such as http://ohserv. or http://.inetsdk.
  2377. return E_INVALIDARG;
  2378. }
  2379. memcpy (szKeyName + cchKeyName,
  2380. zc.pszSite, sizeof(TCHAR) * zc.cchSite);
  2381. if (!IsOpaqueScheme(zc.nScheme))
  2382. {
  2383. szKeyName[cchKeyName + zc.cchSite] = TEXT('\0');
  2384. }
  2385. cchKeyName += zc.cchSite;
  2386. }
  2387. szKeyName[cchKeyName] = 0;
  2388. CRegKey regMap;
  2389. DWORD dwErr;
  2390. if (dwFlags & SZM_DELETE)
  2391. {
  2392. // Delete mapping if one exists.
  2393. if (ERROR_FILE_NOT_FOUND == regMap.Open (m_regZoneMap, szKeyName, KEY_WRITE))
  2394. return S_OK; // nothing to delete
  2395. if ((dwErr = regMap.DeleteValue (zc.pszProtocol)) == ERROR_SUCCESS)
  2396. {
  2397. // Try reclaiming any registry key's which might be empty.
  2398. regMap.Close();
  2399. m_regZoneMap.DeleteEmptyKey(szKeyName);
  2400. if (zc.pszDomain)
  2401. {
  2402. DWORD cch;
  2403. if(bUseHardenedZone || m_fHardened)
  2404. {
  2405. cch = CSTRLENW(SZHARDENEDDOMAINS) + zc.cchDomain;
  2406. }
  2407. else
  2408. {
  2409. cch = CSTRLENW(SZDOMAINS) + zc.cchDomain;
  2410. }
  2411. szKeyName[cch] = TEXT('\0');
  2412. m_regZoneMap.DeleteEmptyKey(szKeyName);
  2413. }
  2414. return S_OK;
  2415. }
  2416. else
  2417. {
  2418. hr = HRESULT_FROM_WIN32(dwErr);
  2419. }
  2420. }
  2421. else
  2422. {
  2423. // Creates new mapping.
  2424. if ((dwErr = regMap.Create (m_regZoneMap, szKeyName, KEY_READ | KEY_WRITE)) == ERROR_SUCCESS)
  2425. {
  2426. regMap.Close();
  2427. if ((dwErr = regMap.Open(m_regZoneMap, szKeyName, KEY_READ | KEY_WRITE)) != ERROR_SUCCESS)
  2428. {
  2429. return HRESULT_FROM_WIN32(GetLastError());
  2430. }
  2431. DWORD dwZoneEntry;
  2432. if (regMap.QueryValue(&dwZoneEntry, zc.pszProtocol) == ERROR_SUCCESS)
  2433. {
  2434. hr = HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
  2435. }
  2436. else if ((dwErr = regMap.SetValue (dwZone, zc.pszProtocol)) == ERROR_SUCCESS)
  2437. {
  2438. return S_OK;
  2439. }
  2440. else
  2441. {
  2442. hr = HRESULT_FROM_WIN32(dwErr);
  2443. }
  2444. }
  2445. else
  2446. {
  2447. hr = HRESULT_FROM_WIN32(dwErr);
  2448. }
  2449. }
  2450. }
  2451. }
  2452. return hr;
  2453. }
  2454. // Helper functions for GetZoneMappings
  2455. // Given a site name and a domain name composes the string
  2456. // site.domain.com
  2457. HRESULT
  2458. CSecurityManager::ComposeUrlSansProtocol
  2459. (
  2460. LPCTSTR pszDomain,
  2461. int cchDomain,
  2462. LPCTSTR pszSite,
  2463. int cchSite,
  2464. LPTSTR *ppszRet,
  2465. int *pcchUrlSansProtocol
  2466. )
  2467. {
  2468. if (ppszRet == NULL)
  2469. {
  2470. return E_INVALIDARG;
  2471. }
  2472. int cchUrlSansProtocol = cchSite + 1 /* . */ + cchDomain ;
  2473. // Create the part of the string without the protocol
  2474. LPTSTR szUrlSansProtocol = new TCHAR [cchUrlSansProtocol + 1];
  2475. if ( szUrlSansProtocol == NULL )
  2476. {
  2477. *ppszRet = NULL;
  2478. if (pcchUrlSansProtocol)
  2479. *pcchUrlSansProtocol = 0;
  2480. return E_OUTOFMEMORY;
  2481. }
  2482. LPTSTR szCurrent = szUrlSansProtocol;
  2483. // Copy over the specific parts of the name.
  2484. if (pszSite != NULL)
  2485. {
  2486. memcpy(szCurrent, pszSite, cchSite * sizeof(TCHAR));
  2487. szCurrent += cchSite;
  2488. memcpy(szCurrent, TEXT("."), 1 * sizeof(TCHAR));
  2489. szCurrent += 1;
  2490. }
  2491. memcpy(szCurrent, pszDomain, cchDomain * sizeof(TCHAR));
  2492. szCurrent += cchDomain;
  2493. // Finally copy over the trailing zero.
  2494. szCurrent[0] = TEXT('\0');
  2495. *ppszRet = szUrlSansProtocol;
  2496. if (pcchUrlSansProtocol)
  2497. *pcchUrlSansProtocol = cchUrlSansProtocol;
  2498. return S_OK;
  2499. }
  2500. HRESULT
  2501. CSecurityManager::ComposeUrl
  2502. (
  2503. LPCTSTR pszUrlSansProt,
  2504. int cchUrlSansProt,
  2505. LPCTSTR pszProtocol,
  2506. int cchProtocol,
  2507. BOOL bAddWildCard,
  2508. LPTSTR * ppszUrl,
  2509. int *pcchUrl
  2510. )
  2511. {
  2512. if (ppszUrl == NULL)
  2513. {
  2514. return E_INVALIDARG;
  2515. }
  2516. BOOL bWildCardScheme = FALSE;
  2517. BOOL bOpaqueScheme = FALSE;
  2518. if (cchProtocol == 1 && pszProtocol[0] == WILDCARD)
  2519. {
  2520. bWildCardScheme = TRUE;
  2521. bOpaqueScheme = FALSE;
  2522. }
  2523. else
  2524. {
  2525. // Figure out if this is an an opaque scheme.
  2526. LPWSTR pszTemp = (LPWSTR)_alloca((cchProtocol + 2) * sizeof(TCHAR));
  2527. memcpy(pszTemp, pszProtocol, cchProtocol * sizeof(TCHAR));
  2528. pszTemp[cchProtocol] = TEXT(':');
  2529. pszTemp[cchProtocol + 1] = TEXT('\0');
  2530. PARSEDURL pu;
  2531. pu.cbSize = sizeof(pu);
  2532. HRESULT hr = ParseURL(pszTemp, &pu);
  2533. if (SUCCEEDED(hr))
  2534. {
  2535. bOpaqueScheme = IsOpaqueScheme(pu.nScheme);
  2536. }
  2537. else
  2538. {
  2539. bOpaqueScheme = TRUE;
  2540. }
  2541. }
  2542. // cchUrl will have the eventual length of the string we will send out
  2543. int cchUrl = cchUrlSansProt;
  2544. if (bOpaqueScheme)
  2545. {
  2546. cchUrl += cchProtocol + 1; // we have to add prot: to the URL
  2547. }
  2548. else if (bWildCardScheme)
  2549. {
  2550. // If the scheme is a wildcard we don't add it to the eventual display.
  2551. }
  2552. else
  2553. {
  2554. cchUrl += cchProtocol + 3; // we have to add prot:// to the url.
  2555. }
  2556. // If we are not an opaque schema, we might need to add a wildcard character as well.
  2557. if (!bOpaqueScheme && bAddWildCard)
  2558. {
  2559. cchUrl += 2; /* for *. */
  2560. }
  2561. LPTSTR szUrl = new TCHAR [cchUrl + 1];
  2562. if (szUrl == NULL)
  2563. {
  2564. *ppszUrl = NULL;
  2565. if (pcchUrl)
  2566. *pcchUrl = 0;
  2567. return E_OUTOFMEMORY;
  2568. }
  2569. LPTSTR szCurrent = szUrl;
  2570. // if the scheme is wildcard we don't want to display the scheme at all.
  2571. // i.e we will show *.microsoft.com and *:*.microsoft.com
  2572. if (bWildCardScheme)
  2573. {
  2574. if (bAddWildCard)
  2575. {
  2576. memcpy(szCurrent, TEXT("*."), 2 * sizeof(TCHAR));
  2577. szCurrent += 2;
  2578. }
  2579. }
  2580. else
  2581. {
  2582. memcpy(szCurrent, pszProtocol, cchProtocol * sizeof(TCHAR));
  2583. szCurrent += cchProtocol;
  2584. if (bOpaqueScheme)
  2585. {
  2586. memcpy(szCurrent, TEXT(":"), 1 * sizeof(TCHAR));
  2587. szCurrent += 1;
  2588. }
  2589. else
  2590. {
  2591. memcpy(szCurrent, TEXT("://"), 3 * sizeof(TCHAR));
  2592. szCurrent += 3;
  2593. if (bAddWildCard)
  2594. {
  2595. memcpy(szCurrent, TEXT("*."), 2 * sizeof(TCHAR));
  2596. szCurrent += 2;
  2597. }
  2598. }
  2599. }
  2600. memcpy(szCurrent, pszUrlSansProt, cchUrlSansProt * sizeof(TCHAR));
  2601. szCurrent += cchUrlSansProt;
  2602. szCurrent[0] = TEXT('\0');
  2603. *ppszUrl = szUrl;
  2604. if (pcchUrl)
  2605. *pcchUrl = cchUrl;
  2606. return S_OK;
  2607. }
  2608. HRESULT
  2609. CSecurityManager::AddIPRulesToEnum
  2610. (
  2611. DWORD dwZone,
  2612. CEnumString *pEnumString
  2613. )
  2614. {
  2615. HRESULT hr = NOERROR;
  2616. if ((HUSKEY)m_regZoneMap == NULL)
  2617. return E_UNEXPECTED;
  2618. CRegKey regRanges;
  2619. DWORD cNumRanges = 0;
  2620. TCHAR szKeyName[MAX_PATH] = SZRANGES;
  2621. if(m_fHardened)
  2622. {
  2623. StrCpy(szKeyName, SZESCRANGES);
  2624. }
  2625. if ( ERROR_SUCCESS != regRanges.Open(m_regZoneMap, szKeyName, KEY_READ)
  2626. || ERROR_SUCCESS != regRanges.QuerySubKeyInfo(&cNumRanges, NULL, NULL)
  2627. )
  2628. {
  2629. return S_OK; // Nothing to add if we can't open the key.
  2630. }
  2631. if (cNumRanges == 0)
  2632. return S_OK;
  2633. DWORD cchMaxKey = 20;
  2634. TCHAR rgchSansProtocol[MAX_PATH];
  2635. DWORD iItem;
  2636. for (iItem = 0 ; iItem < cNumRanges ; iItem++ )
  2637. {
  2638. DWORD cbName, cbRange;
  2639. CRegKey regItem;
  2640. cbName = cchMaxKey;
  2641. cbRange = sizeof(rgchSansProtocol) - 3 * sizeof(TCHAR);
  2642. if ( ERROR_SUCCESS == regRanges.EnumKey(iItem, szKeyName, &cbName)
  2643. && ERROR_SUCCESS == regItem.Open(regRanges, szKeyName, KEY_READ)
  2644. && ERROR_SUCCESS == regItem.QueryValue(rgchSansProtocol, SZRANGE, &cbRange)
  2645. )
  2646. {
  2647. LONG lRetProtocol = NOERROR;
  2648. TCHAR rgchProtocol[MAX_PATH];
  2649. DWORD dwZoneRead = ZONEID_INVALID;
  2650. DWORD dwType;
  2651. for ( DWORD dwIdxProt = 0 , cchP = ARRAYSIZE(rgchProtocol), dwSizeZoneId = sizeof(dwZoneRead);
  2652. (((lRetProtocol = regItem.EnumValue(dwIdxProt, rgchProtocol, &cchP, &dwType, &dwZoneRead, &dwSizeZoneId)) != ERROR_NO_MORE_ITEMS)
  2653. && (hr == NOERROR));
  2654. dwIdxProt++, cchP = ARRAYSIZE(rgchProtocol), dwSizeZoneId = sizeof(dwZoneRead), dwZoneRead = ZONEID_INVALID
  2655. )
  2656. {
  2657. #ifdef unix
  2658. if (lRetProtocol == ERROR_MORE_DATA)
  2659. continue;
  2660. #endif /* unix */
  2661. if (lRetProtocol != NOERROR)
  2662. break;
  2663. if (dwSizeZoneId == 0 || cchP == 0 || rgchProtocol[0] == TEXT('\0')
  2664. || dwType != REG_DWORD || dwZoneRead == ZONEID_INVALID)
  2665. continue;
  2666. if (dwZone == dwZoneRead)
  2667. {
  2668. int cchProtocol = lstrlen(rgchProtocol);
  2669. int cchRange = lstrlen(rgchSansProtocol);
  2670. LPTSTR szUrl = NULL;
  2671. if ( (SUCCEEDED(ComposeUrl(rgchSansProtocol, cchRange, rgchProtocol, cchProtocol, FALSE, &szUrl, NULL)))
  2672. && (SUCCEEDED(pEnumString->AddString(szUrl))))
  2673. {
  2674. if (szUrl != NULL)
  2675. delete [] szUrl;
  2676. }
  2677. else
  2678. {
  2679. if (szUrl != NULL)
  2680. delete [] szUrl;
  2681. hr = E_OUTOFMEMORY;
  2682. break;
  2683. }
  2684. }
  2685. } /* for each protocol */
  2686. }
  2687. } /* for each range entry */
  2688. return hr;
  2689. }
  2690. // Given a Registry key and a part to the URL, this function looks through the
  2691. // 'values' in the registry looking for a zone match. When it finds one it adds the
  2692. // strings to the CEnumString class that is passed in.
  2693. HRESULT
  2694. CSecurityManager::AddUrlsToEnum
  2695. (
  2696. CRegKey * pRegKey,
  2697. DWORD dwZone,
  2698. LPCTSTR pszUrlSansProt,
  2699. int cchUrlSansProt,
  2700. BOOL bAddWildCard,
  2701. CEnumString *pEnumString
  2702. )
  2703. {
  2704. HRESULT hr = NOERROR;
  2705. // Iterate over the values and make up the strings we need.
  2706. LONG lRetProtocol = NOERROR;
  2707. TCHAR rgszProtocol[MAX_PATH];
  2708. DWORD dwZoneRead = ZONEID_INVALID;
  2709. DWORD dwType;
  2710. for ( DWORD dwIdxProt = 0 , cchP = sizeof(rgszProtocol)/sizeof(TCHAR), dwSizeZoneId = sizeof(dwZoneRead);
  2711. (((lRetProtocol = pRegKey->EnumValue(dwIdxProt, rgszProtocol, &cchP, &dwType, &dwZoneRead, &dwSizeZoneId)) != ERROR_NO_MORE_ITEMS)
  2712. && (hr == NOERROR));
  2713. dwIdxProt++, cchP = sizeof(rgszProtocol)/sizeof(TCHAR), dwSizeZoneId = sizeof(dwZoneRead), dwZoneRead = ZONEID_INVALID
  2714. )
  2715. {
  2716. if (lRetProtocol != NO_ERROR)
  2717. {
  2718. // Break out of this loop but keep trying other sites.
  2719. break;
  2720. }
  2721. if ( dwSizeZoneId == 0 || cchP == 0 || rgszProtocol[0] == TEXT('\0')
  2722. || dwType != REG_DWORD || dwZoneRead == ZONEID_INVALID)
  2723. continue;
  2724. // Yippeee, finally found a match.
  2725. if (dwZone == dwZoneRead)
  2726. {
  2727. int cchProtocol = lstrlen(rgszProtocol);
  2728. LPTSTR szUrl = NULL;
  2729. // Compose the name of the URL.
  2730. if ( (SUCCEEDED(ComposeUrl(pszUrlSansProt, cchUrlSansProt, rgszProtocol, cchProtocol, bAddWildCard, &szUrl, NULL)))
  2731. && (SUCCEEDED(pEnumString->AddString(szUrl))))
  2732. {
  2733. // Both succeeded we have added this string to the enumeration.
  2734. // Just free up the memory and move on.
  2735. if (szUrl != NULL)
  2736. delete [] szUrl;
  2737. }
  2738. else
  2739. {
  2740. if (szUrl != NULL)
  2741. delete [] szUrl;
  2742. hr = E_OUTOFMEMORY;
  2743. break;
  2744. }
  2745. }
  2746. } /* for each protocol */
  2747. return hr;
  2748. }
  2749. HRESULT
  2750. CSecurityManager::GetZoneMappings
  2751. (
  2752. DWORD dwZone,
  2753. IEnumString **ppEnumString,
  2754. DWORD dwFlags
  2755. )
  2756. {
  2757. PerfDbgLog(tagCSecurityManager, this, "+CSecurityManager::GetZoneMappings");
  2758. HRESULT hr = NOERROR;
  2759. CEnumString *pEnumString = NULL;
  2760. pEnumString = new CEnumString( );
  2761. if (pEnumString == NULL)
  2762. return E_OUTOFMEMORY;
  2763. CRegKey regDomainRoot;
  2764. // We setup three loops below.
  2765. //
  2766. // for each domain name
  2767. // for each site
  2768. // for each protocol.
  2769. // The one twist is that for each domain we also have to enumerate the sites
  2770. // to deal with wildcards such as http://*.microsoft.com
  2771. //
  2772. // BUGBUG: MAX_PATH is a safe assumption, but we should change this to get the
  2773. // memory dynamically.
  2774. TCHAR rgszDomain[MAX_PATH];
  2775. TCHAR rgszSite[MAX_PATH];
  2776. TCHAR rgszProtocol[MAX_PATH];
  2777. LONG lRetDomain = NOERROR;
  2778. TCHAR szKeyName[MAX_PATH];
  2779. if(m_fHardened)
  2780. {
  2781. lstrcpy (szKeyName, SZHARDENEDDOMAINS);
  2782. }
  2783. else
  2784. {
  2785. lstrcpy (szKeyName, SZDOMAINS);
  2786. }
  2787. if ( ((HUSKEY)m_regZoneMap != NULL) &&
  2788. (regDomainRoot.Open(m_regZoneMap, szKeyName, KEY_READ) == NOERROR)
  2789. )
  2790. {
  2791. // If we couldn't open the root, then no rules exist for any zone.
  2792. // Return an empty enumerator
  2793. for ( DWORD dwIdxDomain = 0, cchD = sizeof(rgszDomain)/sizeof(TCHAR) ;
  2794. (((lRetDomain = regDomainRoot.EnumKey(dwIdxDomain, rgszDomain, &cchD)) != ERROR_NO_MORE_ITEMS)
  2795. && (hr == NOERROR));
  2796. dwIdxDomain++ , cchD = sizeof(rgszDomain)/sizeof(TCHAR)
  2797. )
  2798. {
  2799. if (lRetDomain != NOERROR)
  2800. {
  2801. TransAssert(lRetDomain != ERROR_MORE_DATA);
  2802. break;
  2803. }
  2804. TCHAR rgszSite[MAX_PATH];
  2805. LONG lRetSite = NOERROR;
  2806. // Open the key to the domain.
  2807. CRegKey regDomain;
  2808. if (regDomain.Open(regDomainRoot, rgszDomain, KEY_READ) != NOERROR )
  2809. {
  2810. // We couldn't open this domain for some reason, but we will
  2811. // keep trying the other domains.
  2812. continue;
  2813. }
  2814. int cchDomain = lstrlen(rgszDomain);
  2815. TransAssert((HUSKEY)regDomain != NULL);
  2816. for ( DWORD dwIdxSite = 0 , cchS = sizeof(rgszSite)/sizeof(TCHAR) ;
  2817. (((lRetSite = regDomain.EnumKey(dwIdxSite, rgszSite, &cchS)) != ERROR_NO_MORE_ITEMS)
  2818. && (hr == NOERROR));
  2819. dwIdxSite++ , cchS = sizeof(rgszSite)/sizeof(TCHAR)
  2820. )
  2821. {
  2822. if (lRetSite != NOERROR)
  2823. {
  2824. TransAssert(lRetSite != ERROR_MORE_DATA);
  2825. break; // We will break out of this loop but keep trying other domains.
  2826. }
  2827. CRegKey regSite;
  2828. if (regSite.Open(regDomain, rgszSite, KEY_READ) != NOERROR )
  2829. {
  2830. // Couldn't open the site but try other sites anyway.
  2831. continue;
  2832. }
  2833. int cchSite = lstrlen(rgszSite);
  2834. LPTSTR szUrlSansProtocol = NULL;
  2835. int cchUrlSansProtocol = 0;
  2836. // Get everything about the name figured out
  2837. if ((FAILED(ComposeUrlSansProtocol(rgszDomain, cchDomain, rgszSite, cchSite, &szUrlSansProtocol, &cchUrlSansProtocol)))
  2838. || szUrlSansProtocol == NULL )
  2839. {
  2840. hr = E_OUTOFMEMORY;
  2841. break;
  2842. }
  2843. TransAssert(cchUrlSansProtocol != 0);
  2844. hr = AddUrlsToEnum(&regSite, dwZone, szUrlSansProtocol, cchUrlSansProtocol, FALSE, pEnumString);
  2845. // Free up the memory we just allocated.
  2846. delete [] szUrlSansProtocol;
  2847. } /* for each site */
  2848. // At the domain level we need to look for any protocol defaults
  2849. // An example string would look like http://*.microsoft.com
  2850. LPTSTR szSiteWildCard = NULL;
  2851. int cchSiteWildCard = 0;
  2852. // If the string doesn't contain any .'s we didn't break it out as a domain/site
  2853. // in the first place. We shouldn't add a *. wildcard in this case.
  2854. BOOL bAddWildCard = (StrChr(rgszDomain, DOT) != NULL);
  2855. if ((FAILED(ComposeUrlSansProtocol(rgszDomain, cchDomain, NULL, 0, &szSiteWildCard, &cchSiteWildCard)))
  2856. || szSiteWildCard == NULL)
  2857. {
  2858. hr = E_OUTOFMEMORY;
  2859. break;
  2860. }
  2861. TransAssert(cchSiteWildCard != 0);
  2862. hr = AddUrlsToEnum(&regDomain, dwZone, szSiteWildCard, cchSiteWildCard, bAddWildCard, pEnumString);
  2863. delete [] szSiteWildCard;
  2864. }
  2865. }// opened domains root key
  2866. // Finally add all the IP range entries to the structure.
  2867. if (hr == NOERROR)
  2868. {
  2869. hr = AddIPRulesToEnum(dwZone, pEnumString);
  2870. }
  2871. // Finally call the strings
  2872. if ( hr == NOERROR )
  2873. {
  2874. // Pass back the Enumeration to the caller.
  2875. if (ppEnumString)
  2876. *ppEnumString = pEnumString;
  2877. }
  2878. else
  2879. {
  2880. // We need to free the object and return NULL to the caller.
  2881. if (ppEnumString)
  2882. *ppEnumString = NULL;
  2883. delete pEnumString;
  2884. }
  2885. return hr;
  2886. }
  2887. //
  2888. // MapUrlToZone helper methods return S_OK if match found
  2889. //
  2890. // RETURN value is ONLY S_OK.
  2891. // Be careful about returning anything else since some calling functions assume this is the only return value.
  2892. HRESULT
  2893. CSecurityManager::MapUrlToZone (ZONEMAP_COMPONENTS* pzc, DWORD* pdwZone, DWORD dwFlags,
  2894. BOOL *pfMarked, LPWSTR *ppszMarkURL)
  2895. {
  2896. HRESULT hr;
  2897. CRegKey regProtocols;
  2898. BOOL fMarked = FALSE;
  2899. if (dwFlags & MUTZ_ENFORCERESTRICTED)
  2900. {
  2901. *pdwZone = URLZONE_UNTRUSTED;
  2902. hr = S_OK;
  2903. goto done;
  2904. }
  2905. // Guard against buffer overflow.
  2906. DWORD dwLength = CSTRLENW(SZDOMAINS);
  2907. if(m_fHardened)
  2908. {
  2909. dwLength = CSTRLENW(SZHARDENEDDOMAINS);
  2910. }
  2911. if (dwLength + pzc->cchDomain + 1 + pzc->cchSite + 1 >= MAX_PATH)
  2912. goto default_zone;
  2913. if (pzc->fDrive)
  2914. {
  2915. switch (pzc->dwDriveType)
  2916. {
  2917. case DRIVE_UNKNOWN:
  2918. case DRIVE_NO_ROOT_DIR:
  2919. break;
  2920. case DRIVE_REMOTE:
  2921. TransAssert(FALSE);
  2922. *pdwZone = URLZONE_INTRANET;
  2923. goto done;
  2924. default:
  2925. {
  2926. BOOL bCacheFile = IsFileInCacheDir(pzc->pszSite);
  2927. *pdwZone = bCacheFile ? URLZONE_INTERNET : URLZONE_LOCAL_MACHINE;
  2928. if(bCacheFile)
  2929. goto done;
  2930. bCacheFile = IsFileInCookieDir(pzc->pszSite);
  2931. *pdwZone = bCacheFile ? URLZONE_UNTRUSTED : URLZONE_LOCAL_MACHINE;
  2932. if(bCacheFile)
  2933. goto done;
  2934. // do the Mark of the Web stuff, if we have a local non-cache file:
  2935. LPWSTR pwszMarkURL = NULL;
  2936. TCHAR *pszExt = PathFindExtension(pzc->pszSite);
  2937. LPCTSTR pszPath = pzc->pszSite;
  2938. // Don't look for the mark if flags say not to.
  2939. // We only want to pursue the Mark of the Web for htm(l) files.
  2940. // If Marked, we want to be sure we're not chasing our tail recursively.
  2941. if ( !(dwFlags & MUTZ_NOSAVEDFILECHECK) &&
  2942. (StrCmpI(pszExt,TEXT(".htm")) == 0 || StrCmpI(pszExt,TEXT(".html")) == 0) &&
  2943. FileBearsMarkOfTheWeb(pszPath, &pwszMarkURL) &&
  2944. StrCmp(pszPath, pwszMarkURL) != 0)
  2945. {
  2946. MapUrlToZone( pwszMarkURL, pdwZone, dwFlags | MUTZ_NOSAVEDFILECHECK | MUTZ_NOCACHE );
  2947. fMarked = TRUE;
  2948. if (ppszMarkURL)
  2949. {
  2950. *ppszMarkURL = pwszMarkURL;
  2951. pwszMarkURL = NULL; // give mark string to caller, don't free
  2952. }
  2953. }
  2954. if (pwszMarkURL)
  2955. LocalFree(pwszMarkURL);
  2956. goto done;
  2957. }
  2958. }
  2959. }
  2960. else if (IsOpaqueScheme(pzc->nScheme))
  2961. {
  2962. if(m_fHardened)
  2963. {
  2964. if (S_OK == CheckSiteAndDomainMappings (pzc, pdwZone, pzc->pszProtocol, TRUE))
  2965. goto done;
  2966. }
  2967. else
  2968. {
  2969. if (S_OK == CheckSiteAndDomainMappings (pzc, pdwZone, pzc->pszProtocol))
  2970. goto done;
  2971. }
  2972. if (S_OK == CheckMKURL(pzc, pdwZone, pzc->pszProtocol))
  2973. goto done;
  2974. }
  2975. else
  2976. {
  2977. if (pzc->fAddr)
  2978. {
  2979. // Check name in form of IP address against range rules.
  2980. if (S_OK == CheckAddressAgainstRanges (pzc, pdwZone, pzc->pszProtocol))
  2981. goto done;
  2982. }
  2983. if ((HUSKEY) m_regZoneMap)
  2984. {
  2985. // Check for a mapping for the site (or domain, if applicable)
  2986. if(m_fHardened)
  2987. {
  2988. if (S_OK == CheckSiteAndDomainMappings (pzc, pdwZone, pzc->pszProtocol, TRUE))
  2989. goto done;
  2990. }
  2991. else
  2992. {
  2993. if (S_OK == CheckSiteAndDomainMappings (pzc, pdwZone, pzc->pszProtocol))
  2994. goto done;
  2995. }
  2996. if (S_OK == CheckUNCAsIntranet(pzc, pdwZone, pzc->pszProtocol))
  2997. goto done;
  2998. // Check for Local Intranet name rules.
  2999. if (S_OK == CheckIntranetName (pzc, pdwZone, pzc->pszProtocol))
  3000. goto done;
  3001. // Check for proxy bypass rule.
  3002. if (S_OK == CheckProxyBypassRule (pzc, pdwZone, pzc->pszProtocol))
  3003. goto done;
  3004. }
  3005. }
  3006. // Check for protocol defaults.
  3007. if ( ERROR_SUCCESS == regProtocols.Open (m_regZoneMap, SZPROTOCOLS, KEY_READ)
  3008. && ERROR_SUCCESS == regProtocols.QueryValueOrWild (pdwZone, pzc->pszProtocol)
  3009. )
  3010. {
  3011. goto done;
  3012. }
  3013. default_zone:
  3014. *pdwZone = URLZONE_INTERNET;
  3015. done:
  3016. if (pfMarked)
  3017. *pfMarked = fMarked;
  3018. hr = S_OK;
  3019. return hr;
  3020. }
  3021. HRESULT
  3022. CSecurityManager::ReadAllIPRules( )
  3023. {
  3024. DWORD* pdwIndexes = NULL;
  3025. EnterCriticalSection(&s_csectIP);
  3026. if (s_pRanges != NULL)
  3027. {
  3028. delete [] s_pRanges;
  3029. s_pRanges = NULL;
  3030. s_cNumRanges = 0;
  3031. }
  3032. // We always start with the key "Range1" if nothing is found.
  3033. s_dwNextRangeIndex = 1;
  3034. CRegKey regRanges, regItem;
  3035. if ((HUSKEY)m_regZoneMap == NULL)
  3036. {
  3037. if (ERROR_SUCCESS != m_regZoneMap.Open (NULL, SZZONEMAP, KEY_READ))
  3038. goto done;
  3039. }
  3040. DWORD cchMaxKey;
  3041. TCHAR szKeyName[MAX_PATH];
  3042. if(m_fHardened)
  3043. {
  3044. StrCpy (szKeyName, SZESCRANGES);
  3045. }
  3046. else
  3047. {
  3048. StrCpy (szKeyName, SZRANGES);
  3049. }
  3050. // Read in ranges from registry.
  3051. if ( ERROR_SUCCESS != regRanges.Open (m_regZoneMap, szKeyName, KEY_READ)
  3052. || ERROR_SUCCESS != regRanges.QuerySubKeyInfo (&s_cNumRanges, &cchMaxKey, NULL)
  3053. || 0 == s_cNumRanges
  3054. )
  3055. {
  3056. goto done;
  3057. }
  3058. // BUGBUG: TODO: Figure out why QuerySubKeyInfo is returning the wrong information.
  3059. cchMaxKey = 20;
  3060. // Calculate size of range item and allocate array (no alignment padding)
  3061. s_cbRangeItem = sizeof(RANGE_ITEM) + sizeof(TCHAR) * (cchMaxKey + 1);
  3062. s_pRanges = new BYTE [s_cbRangeItem * s_cNumRanges];
  3063. pdwIndexes = new DWORD[s_cNumRanges];
  3064. if (!s_pRanges || !pdwIndexes)
  3065. {
  3066. s_cNumRanges = 0;
  3067. goto done;
  3068. }
  3069. // Loop through the ranges.
  3070. TCHAR szRange[MAX_IPRANGE]; // 4x "###-###."
  3071. RANGE_ITEM* pItem;
  3072. DWORD iItem, cItem;
  3073. pItem = (RANGE_ITEM *) s_pRanges;
  3074. cItem = s_cNumRanges;
  3075. s_cNumRanges = 0;
  3076. for (iItem = 0; iItem < cItem; iItem++)
  3077. {
  3078. // Reset output buffer sizes.
  3079. DWORD cbName, cbRange;
  3080. cbName = cchMaxKey;
  3081. cbRange = sizeof(szRange);
  3082. // Get range from next key.
  3083. if ( ERROR_SUCCESS != regRanges.EnumKey (iItem, pItem->szName, &cbName)
  3084. || ERROR_SUCCESS != regItem.Open (regRanges, pItem->szName, KEY_READ)
  3085. || ERROR_SUCCESS != regItem.QueryValue (szRange, SZRANGE, &cbRange)
  3086. )
  3087. {
  3088. break;
  3089. }
  3090. // Figure out the index for the named Range entry. Ignore it is not of the
  3091. // form Range followed by Number. Range####
  3092. DWORD chRange = lstrlen(SZRANGEPREFIX);
  3093. if (0 == StrCmpNI(pItem->szName, SZRANGEPREFIX, chRange))
  3094. {
  3095. pdwIndexes[iItem] = StrToInt(pItem->szName + chRange);
  3096. }
  3097. if (!ReadIPRule (szRange, pItem->bLow, pItem->bHigh))
  3098. continue;
  3099. // Advance to next range item in array.
  3100. pItem = (RANGE_ITEM*) (((LPBYTE) pItem) + s_cbRangeItem);
  3101. s_cNumRanges++;
  3102. }
  3103. // Find an empty slot or if we don't find one
  3104. for (s_dwNextRangeIndex = 1 ; s_dwNextRangeIndex <= cItem; s_dwNextRangeIndex++)
  3105. {
  3106. DWORD i;
  3107. // Go through the entries and see if the index exists.
  3108. for (i = 0; i < cItem ; i++ )
  3109. {
  3110. if (pdwIndexes[i] == s_dwNextRangeIndex)
  3111. break;
  3112. }
  3113. if (i == cItem) // This range item is available.
  3114. break;
  3115. }
  3116. TransAssert(s_dwNextRangeIndex >= 1 && s_dwNextRangeIndex <= (cItem + 1));
  3117. delete [] pdwIndexes;
  3118. done:
  3119. LeaveCriticalSection(&s_csectIP);
  3120. return S_OK;
  3121. }
  3122. HRESULT
  3123. CSecurityManager::AddDeleteIPRule
  3124. (ZONEMAP_COMPONENTS* pzc, DWORD dwZone, DWORD dwFlags)
  3125. {
  3126. HRESULT hr = S_OK;
  3127. DWORD dwError = ERROR_SUCCESS;
  3128. BOOL bFoundItem = FALSE;
  3129. TCHAR szItemName[MAX_PATH];
  3130. TransAssert(s_dwNextRangeIndex != 0);
  3131. TransAssert(pzc->fIPRange);
  3132. if (s_dwNextRangeIndex == 0)
  3133. return E_UNEXPECTED;
  3134. EnterCriticalSection(&s_csectIP);
  3135. RANGE_ITEM *pItem = (RANGE_ITEM *)s_pRanges;
  3136. // First figure out if this item already exists in our list.
  3137. // This is useful in both the delete and add case.
  3138. for (DWORD iRange = 0;
  3139. iRange < s_cNumRanges ;
  3140. iRange++, pItem = (RANGE_ITEM*) (((LPBYTE) pItem) + s_cbRangeItem))
  3141. {
  3142. if ( ( 0 == memcmp(pItem->bLow, pzc->rangeItem.bLow, sizeof(pItem->bLow)))
  3143. && (0 == memcmp(pItem->bHigh, pzc->rangeItem.bHigh, sizeof(pItem->bHigh)))
  3144. )
  3145. {
  3146. break;
  3147. }
  3148. }
  3149. // If we have a valid "named" entry in the registry.
  3150. if (iRange < s_cNumRanges && pItem->szName[0] != TEXT('\0'))
  3151. {
  3152. bFoundItem = TRUE;
  3153. if(m_fHardened)
  3154. {
  3155. StrCpy(szItemName, SZESCRANGES);
  3156. }
  3157. else
  3158. {
  3159. StrCpy(szItemName, SZRANGES);
  3160. }
  3161. StrCat(szItemName, pItem->szName);
  3162. }
  3163. else
  3164. {
  3165. bFoundItem = FALSE;
  3166. pItem = NULL;
  3167. }
  3168. // Are we trying to do an add or a delete.
  3169. if (dwFlags & SZM_DELETE)
  3170. {
  3171. // If we have a valid "named" entry in the registry delete it now.
  3172. if (bFoundItem)
  3173. {
  3174. TransAssert(pItem != NULL);
  3175. CRegKey regItem;
  3176. if ((dwError = regItem.Open(m_regZoneMap, szItemName, KEY_READ | KEY_WRITE)) != ERROR_SUCCESS)
  3177. {
  3178. hr = HRESULT_FROM_WIN32(dwError);
  3179. }
  3180. else
  3181. {
  3182. // Get the protocol name and delete the protocol related value.
  3183. if ((dwError = regItem.DeleteValue (pzc->pszProtocol)) == ERROR_SUCCESS)
  3184. {
  3185. DWORD dwNumValues = 0;
  3186. // Is this the last entry for this range? If so delete the range & nuke the key.
  3187. if (ERROR_SUCCESS == regItem.QuerySubKeyInfo(NULL, NULL, &dwNumValues) &&
  3188. dwNumValues == 1 &&
  3189. ERROR_SUCCESS == regItem.DeleteValue(SZRANGE)
  3190. )
  3191. {
  3192. regItem.Close();
  3193. m_regZoneMap.DeleteEmptyKey(szItemName);
  3194. }
  3195. }
  3196. else
  3197. {
  3198. hr = HRESULT_FROM_WIN32(dwError);
  3199. }
  3200. }
  3201. }
  3202. else
  3203. {
  3204. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  3205. }
  3206. }
  3207. else
  3208. {
  3209. if (bFoundItem)
  3210. {
  3211. TransAssert(pItem != NULL);
  3212. // See if an entry with the given name already
  3213. CRegKey regItem;
  3214. if ((dwError = regItem.Open(m_regZoneMap, szItemName, KEY_READ | KEY_WRITE)) != ERROR_SUCCESS)
  3215. {
  3216. hr = HRESULT_FROM_WIN32(dwError);
  3217. }
  3218. else
  3219. {
  3220. DWORD dwZoneExists;
  3221. // If we were able to read the value, fail because entry already exists.
  3222. if (regItem.QueryValue(&dwZoneExists, pzc->pszProtocol) == ERROR_SUCCESS)
  3223. {
  3224. hr = HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
  3225. }
  3226. }
  3227. }
  3228. else
  3229. {
  3230. // Create the new item name.
  3231. DWORD dwLen = 0;
  3232. if(m_fHardened)
  3233. {
  3234. StrCpy(szItemName, SZESCRANGES);
  3235. dwLen = lstrlen(SZESCRANGES);
  3236. }
  3237. else
  3238. {
  3239. StrCpy(szItemName, SZRANGES);
  3240. dwLen = lstrlen(SZRANGES);
  3241. }
  3242. StrCat(szItemName, SZRANGEPREFIX);
  3243. if (!DwToWchar(s_dwNextRangeIndex, szItemName + dwLen + lstrlen(SZRANGEPREFIX), 10))
  3244. {
  3245. TransAssert(FALSE);
  3246. hr = E_UNEXPECTED;
  3247. }
  3248. }
  3249. // Okay to go ahead and create the entry.
  3250. if (SUCCEEDED(hr))
  3251. {
  3252. TCHAR szIPRule[MAX_IPRANGE];
  3253. // We shouldn't have any domain part for IP Rules.
  3254. TransAssert(pzc->pszDomain == NULL);
  3255. memcpy(szIPRule, pzc->pszSite, sizeof(TCHAR) * pzc->cchSite);
  3256. szIPRule[pzc->cchSite] = TEXT('\0');
  3257. CRegKey regMap;
  3258. // Now add the entry to the registry.
  3259. if ( ((dwError = regMap.Create(m_regZoneMap, szItemName, KEY_WRITE)) == ERROR_SUCCESS) &&
  3260. ((dwError = regMap.SetValue(dwZone, pzc->pszProtocol)) == ERROR_SUCCESS) &&
  3261. ((dwError = regMap.SetValue(szIPRule, SZRANGE)) == ERROR_SUCCESS)
  3262. )
  3263. {
  3264. hr = S_OK;
  3265. }
  3266. else
  3267. {
  3268. hr = HRESULT_FROM_WIN32(dwError);
  3269. }
  3270. }
  3271. }
  3272. if (SUCCEEDED(hr))
  3273. {
  3274. hr = ReadAllIPRules();
  3275. }
  3276. LeaveCriticalSection(&s_csectIP);
  3277. return hr;
  3278. }
  3279. HRESULT
  3280. CSecurityManager::CheckAddressAgainstRanges
  3281. (ZONEMAP_COMPONENTS* pzc, DWORD* pdwZone, LPCTSTR pszProt)
  3282. {
  3283. TCHAR szKeyName[MAX_PATH];
  3284. const DWORD cchRanges = m_fHardened? CSTRLENW(SZESCRANGES) : CSTRLENW(SZRANGES);
  3285. if(m_fHardened)
  3286. {
  3287. memcpy (szKeyName, SZESCRANGES, sizeof(TCHAR) * cchRanges);
  3288. }
  3289. else
  3290. {
  3291. memcpy (szKeyName, SZRANGES, sizeof(TCHAR) * cchRanges);
  3292. }
  3293. CRegKey regItem;
  3294. EnterCriticalSection(&s_csectIP);
  3295. RANGE_ITEM* pItem = (RANGE_ITEM *) s_pRanges;
  3296. for (DWORD iRange=0; iRange < s_cNumRanges; iRange++)
  3297. {
  3298. for (DWORD iByte=0; iByte<4; iByte++)
  3299. {
  3300. if ( pzc->bAddr[iByte] < pItem->bLow[iByte]
  3301. || pzc->bAddr[iByte] > pItem->bHigh[iByte]
  3302. )
  3303. {
  3304. goto next_range; // much cleaner than a break and test
  3305. }
  3306. }
  3307. StrCpyW (szKeyName + cchRanges, pItem->szName);
  3308. if ( ERROR_SUCCESS == regItem.Open (m_regZoneMap, szKeyName, KEY_READ)
  3309. && ERROR_SUCCESS == regItem.QueryValueOrWild (pdwZone, pszProt)
  3310. )
  3311. {
  3312. LeaveCriticalSection(&s_csectIP);
  3313. return S_OK;
  3314. }
  3315. next_range:
  3316. pItem = (RANGE_ITEM*) (((LPBYTE) pItem) + s_cbRangeItem);
  3317. }
  3318. LeaveCriticalSection(&s_csectIP);
  3319. return S_FALSE;
  3320. }
  3321. HRESULT CSecurityManager::CheckSiteAndDomainMappings
  3322. (ZONEMAP_COMPONENTS* pzc, DWORD* pdwZone, LPCTSTR pszProt, BOOL fCheckHardenKey)
  3323. {
  3324. CRegKey regDomain, regSite;
  3325. DWORD dwRegErr;
  3326. TCHAR szKeyName[MAX_PATH];
  3327. DWORD cchKeyName;
  3328. if(fCheckHardenKey)
  3329. {
  3330. cchKeyName = CSTRLENW(SZHARDENEDDOMAINS);
  3331. memcpy (szKeyName, SZHARDENEDDOMAINS, sizeof(TCHAR) * cchKeyName);
  3332. }
  3333. else
  3334. {
  3335. cchKeyName = CSTRLENW(SZDOMAINS);
  3336. memcpy (szKeyName, SZDOMAINS, sizeof(TCHAR) * cchKeyName);
  3337. }
  3338. TransAssert(!pzc->fDrive);
  3339. if (pzc->pszDomain)
  3340. {
  3341. // First, look for domain rule.
  3342. memcpy (szKeyName + cchKeyName, pzc->pszDomain, sizeof(TCHAR) * pzc->cchDomain);
  3343. szKeyName[cchKeyName + pzc->cchDomain] = 0;
  3344. SAFEREGOPERATION(dwRegErr, regDomain.Open (m_regZoneMap, szKeyName, KEY_READ));
  3345. if ((dwRegErr != ERROR_SUCCESS)
  3346. && (szKeyName[cchKeyName + pzc->cchDomain -1] == DOT)//check if this is a terminal-dotted-site
  3347. && ((pzc->nScheme == URL_SCHEME_HTTP)
  3348. || (pzc->nScheme == URL_SCHEME_HTTPS)
  3349. || (pzc->nScheme == URL_SCHEME_FILE)))
  3350. {
  3351. szKeyName[cchKeyName + pzc->cchDomain -1] = 0;
  3352. dwRegErr = regDomain.Open(m_regZoneMap, szKeyName, KEY_READ);
  3353. }
  3354. if(dwRegErr != ERROR_SUCCESS)
  3355. return S_FALSE;
  3356. // Now add the site.
  3357. memcpy (szKeyName, pzc->pszSite, sizeof(TCHAR) * pzc->cchSite);
  3358. szKeyName[pzc->cchSite] = 0;
  3359. dwRegErr = regSite.Open (regDomain, szKeyName, KEY_READ);
  3360. // For IE5.0 we support wildcard's beyond the second level domain.
  3361. // For example if you had an intranet address www.internal.mycorp.com
  3362. // you can specify a zone mapping for *.internal.mycorp.com.
  3363. // In IE4 we would have flagged this as an error because we allowed
  3364. // wildcards only at the second level domain.
  3365. // IE5 since we lifted this restriction, we have to search the sub-keys
  3366. // and look for strings such as "*.internal" under the mycorp.com key.
  3367. // If we find one we see if the wildcard pattern matches the site whose
  3368. // zone we are trying to determine.
  3369. if (dwRegErr != ERROR_SUCCESS)
  3370. {
  3371. TCHAR rgchSubKeyName[MAX_PATH];
  3372. LONG lRet = NOERROR;
  3373. for ( DWORD dwIndex = 0 , cchSubKey = ARRAYSIZE(rgchSubKeyName) ;
  3374. ((lRet = regDomain.EnumKey(dwIndex, rgchSubKeyName, &cchSubKey)) != ERROR_NO_MORE_ITEMS) ;
  3375. dwIndex++ , cchSubKey = ARRAYSIZE(rgchSubKeyName)
  3376. )
  3377. {
  3378. if (lRet != NOERROR)
  3379. {
  3380. TransAssert(lRet != ERROR_MORE_DATA);
  3381. break;
  3382. }
  3383. // For patterns that finish with a *. we will do a suffix
  3384. // match to see if the wildcard sequence is valid.
  3385. if (cchSubKey > 2 && rgchSubKeyName[0] == WILDCARD && rgchSubKeyName[1] == DOT)
  3386. {
  3387. // First condition
  3388. // for xyz.foo.microsoft.com to match *.foo.microsoft.com
  3389. // www.foo has to be greater than or equal to foo.microsoft.com
  3390. // note that we allow just foo.microsoft.com as well.
  3391. // Second condition
  3392. // cchSubkey is the length of *.foo, therefore the last
  3393. // cchSubKey - 2 characters of the two strings should match.
  3394. if (pzc->cchSite >= (cchSubKey - 2) &&
  3395. ( StrCmpNI (rgchSubKeyName + 2, /* skip *. */
  3396. pzc->pszSite + pzc->cchSite - cchSubKey + 2,
  3397. cchSubKey - 2
  3398. ) == 0
  3399. )
  3400. )
  3401. {
  3402. dwRegErr = regSite.Open(regDomain, rgchSubKeyName, KEY_READ);
  3403. break;
  3404. }
  3405. }
  3406. }
  3407. }
  3408. }
  3409. else
  3410. {
  3411. // There was no domain. Look for a site rule.
  3412. memcpy (szKeyName + cchKeyName, pzc->pszSite, sizeof(TCHAR) * pzc->cchSite);
  3413. szKeyName[cchKeyName + pzc->cchSite] = 0;
  3414. SAFEREGOPERATION(dwRegErr, regSite.Open (m_regZoneMap, szKeyName, KEY_READ));
  3415. if ((dwRegErr != ERROR_SUCCESS)
  3416. && (szKeyName[cchKeyName + pzc->cchSite -1] == DOT) //check if this is a terminal-dotted-site
  3417. && ((pzc->nScheme == URL_SCHEME_HTTP)
  3418. || (pzc->nScheme == URL_SCHEME_HTTPS)
  3419. || (pzc->nScheme == URL_SCHEME_FILE)))
  3420. {
  3421. szKeyName[cchKeyName + pzc->cchSite -1] = 0;
  3422. dwRegErr = regSite.Open(m_regZoneMap, szKeyName, KEY_READ);
  3423. }
  3424. }
  3425. // Look for matching protocols under site key.
  3426. if ( ERROR_SUCCESS == dwRegErr
  3427. && ERROR_SUCCESS == regSite.QueryValueOrWild (pdwZone, pszProt)
  3428. )
  3429. {
  3430. return S_OK;
  3431. }
  3432. // Now fall back to domain if there was one.
  3433. else if ( pzc->pszDomain
  3434. && ERROR_SUCCESS == regDomain.QueryValueOrWild (pdwZone, pszProt)
  3435. )
  3436. {
  3437. return S_OK;
  3438. }
  3439. else return S_FALSE;
  3440. }
  3441. HRESULT CSecurityManager::CheckUNCAsIntranet
  3442. (ZONEMAP_COMPONENTS* pzc, DWORD* pdwZone, LPCTSTR pszProt)
  3443. {
  3444. HRESULT hr = S_FALSE;
  3445. DWORD dwUNCAsIntranet;
  3446. DWORD dwRegErr;
  3447. TransAssert(!pzc->fDrive);
  3448. TransAssert(!pzc->fIPRange);
  3449. if (pzc->fAddr || pzc->nScheme != URL_SCHEME_FILE)
  3450. return hr;
  3451. SAFEREGOPERATION(dwRegErr, m_regZoneMap.QueryValue(&dwUNCAsIntranet, SZUNCASINTRANET));
  3452. if(ERROR_SUCCESS != dwRegErr)
  3453. return hr;
  3454. if (dwUNCAsIntranet == 0)
  3455. {
  3456. hr = S_OK;
  3457. if (pdwZone)
  3458. *pdwZone = URLZONE_INTERNET;
  3459. }
  3460. return hr;
  3461. }
  3462. HRESULT CSecurityManager::CheckIntranetName
  3463. (ZONEMAP_COMPONENTS* pzc, DWORD* pdwZone, LPCTSTR pszProt)
  3464. {
  3465. HRESULT hr = S_FALSE;
  3466. DWORD dwZone = ZONEID_INVALID;
  3467. DWORD dwRegErr;
  3468. TransAssert(!pzc->fDrive);
  3469. TransAssert(!pzc->fIPRange);
  3470. if (pzc->fAddr)
  3471. return hr;
  3472. // Check if there is a local intranet rule.
  3473. SAFEREGOPERATION(dwRegErr, m_regZoneMap.QueryValue(&dwZone, SZINTRANETNAME));
  3474. if(ERROR_SUCCESS != dwRegErr)
  3475. return hr;
  3476. if (dwZone != URLZONE_INTRANET)
  3477. {
  3478. TransAssert(FALSE);
  3479. if(pdwZone)
  3480. {
  3481. *pdwZone = URLZONE_INTERNET;
  3482. }
  3483. hr = E_FAIL;
  3484. return hr;
  3485. }
  3486. if (pzc->pszSite && !pzc->pszDomain)
  3487. {
  3488. BOOL bFoundDot = FALSE;
  3489. for (DWORD dwIndex = 0 ; dwIndex < pzc->cchSite ; dwIndex++ )
  3490. {
  3491. if (pzc->pszSite[dwIndex] == DOT)
  3492. {
  3493. bFoundDot = TRUE;
  3494. break;
  3495. }
  3496. }
  3497. hr = bFoundDot ? S_FALSE : S_OK;
  3498. }
  3499. if (hr == S_OK && pdwZone)
  3500. *pdwZone = dwZone;
  3501. return hr;
  3502. }
  3503. HRESULT CSecurityManager::CheckProxyBypassRule
  3504. (ZONEMAP_COMPONENTS* pzc, DWORD* pdwZone, LPCTSTR pszProt)
  3505. {
  3506. TransAssert(!pzc->fDrive);
  3507. DWORD dwRegErr;
  3508. DWORD dwValue = 0;
  3509. // Check if there is a proxy bypass rule.
  3510. SAFEREGOPERATION(dwRegErr, m_regZoneMap.QueryValue(&dwValue, SZPROXYBYPASS));
  3511. if(ERROR_SUCCESS != dwRegErr || !dwValue)
  3512. return S_FALSE;
  3513. *pdwZone = URLZONE_INTRANET;
  3514. // Calculate length of hostname = site (+ . + domain)
  3515. DWORD cchTotal;
  3516. cchTotal = pzc->cchSite;
  3517. if (pzc->cchDomain)
  3518. cchTotal += 1 + pzc->cchDomain;
  3519. // Convert from unicode to ansi.
  3520. char szHost[MAX_PATH];
  3521. DWORD cbHost;
  3522. cbHost = WideCharToMultiByte
  3523. (CP_ACP, 0, pzc->pszSite, cchTotal, szHost, sizeof(szHost), NULL, NULL);
  3524. if (!cbHost)
  3525. return S_FALSE;
  3526. // WideCharToMultiByte won't null terminate szHost,
  3527. // IsHostInProxyBypassList shouldn't need it,
  3528. // but just do it anyway to play it safe.
  3529. szHost[cbHost] = 0;
  3530. INTERNET_SCHEME tScheme;
  3531. BOOL bCheckByPassRules = TRUE;
  3532. switch(pzc->nScheme)
  3533. {
  3534. case URL_SCHEME_HTTP:
  3535. tScheme = INTERNET_SCHEME_HTTP;
  3536. break;
  3537. case URL_SCHEME_HTTPS:
  3538. tScheme = INTERNET_SCHEME_HTTPS;
  3539. break;
  3540. case URL_SCHEME_GOPHER:
  3541. tScheme = INTERNET_SCHEME_GOPHER;
  3542. break;
  3543. case URL_SCHEME_FTP:
  3544. tScheme = INTERNET_SCHEME_FTP;
  3545. break;
  3546. default:
  3547. bCheckByPassRules = FALSE;
  3548. break;
  3549. }
  3550. return bCheckByPassRules && IsHostInProxyBypassList (tScheme, szHost, cbHost) ? S_OK : S_FALSE;
  3551. }
  3552. HRESULT CSecurityManager::CheckMKURL
  3553. (ZONEMAP_COMPONENTS* pzc, DWORD* pdwZone, LPCTSTR pszProt)
  3554. {
  3555. HRESULT hr = S_FALSE;
  3556. DWORD dwZone = ZONEID_INVALID;
  3557. TransAssert(!pzc->fDrive);
  3558. // First check if it looks like a valid mk: string.
  3559. if (pzc->nScheme == URL_SCHEME_MK &&
  3560. pzc->pszDomain == NULL &&
  3561. pzc->pszSite != NULL &&
  3562. pzc->pszSite[0] == AT)
  3563. {
  3564. // look for a : in the domain string.
  3565. LPTSTR pszColon = StrChr(pzc->pszSite, COLON);
  3566. if ( pszColon != NULL)
  3567. {
  3568. CRegKey regProtocols;
  3569. *pszColon = TEXT('\0'); // Temporarily overwrite the colon.
  3570. if ((ERROR_SUCCESS == regProtocols.Open(m_regZoneMap, SZPROTOCOLS, KEY_READ)) &&
  3571. (ERROR_SUCCESS == regProtocols.QueryValue(&dwZone, pzc->pszSite))
  3572. )
  3573. {
  3574. *pdwZone = dwZone;
  3575. hr = S_OK;
  3576. }
  3577. *pszColon = COLON; // Set the domain string back to its original state.
  3578. }
  3579. }
  3580. return hr;
  3581. }
  3582. CSecurityManager::CSecMgrCache::CSecMgrCache(void)
  3583. {
  3584. InitializeCriticalSection(&m_csectZoneCache);
  3585. // single static object, so this only gets inited once per
  3586. // process.
  3587. s_hMutexCounter = CreateMutexA(NULL, FALSE, "ZonesCounterMutex");
  3588. m_iAdd = 0;
  3589. }
  3590. CSecurityManager::CSecMgrCache::~CSecMgrCache(void)
  3591. {
  3592. Flush();
  3593. DeleteCriticalSection(&m_csectZoneCache) ;
  3594. CloseHandle(s_hMutexCounter);
  3595. }
  3596. BOOL
  3597. CSecurityManager::CSecMgrCache::Lookup(LPCWSTR pwszURL,
  3598. DWORD *pdwZone,
  3599. BOOL *pfMarked,
  3600. BYTE* pbSecurityID,
  3601. DWORD *pcbSecurityID,
  3602. LPCWSTR pwszDocDomain)
  3603. {
  3604. BOOL fFound = FALSE;
  3605. EnterCriticalSection(&m_csectZoneCache);
  3606. if ( !IsCounterEqual() )
  3607. {
  3608. Flush();
  3609. }
  3610. else
  3611. {
  3612. int i;
  3613. fFound = FindCacheEntry( pwszURL, i );
  3614. if (fFound)
  3615. {
  3616. if ( pbSecurityID )
  3617. {
  3618. TransAssert(pcbSecurityID);
  3619. if ( m_asmce[i].m_pbSecurityID &&
  3620. ( (m_asmce[i].m_pwszDocDomain == NULL && pwszDocDomain == NULL) || /* both are NULL */
  3621. ( m_asmce[i].m_pwszDocDomain && pwszDocDomain &&
  3622. (0 == StrCmpW(m_asmce[i].m_pwszDocDomain, pwszDocDomain)) /* the strings match */
  3623. )
  3624. ) &&
  3625. m_asmce[i].m_cbSecurityID <= *pcbSecurityID)
  3626. {
  3627. memcpy( pbSecurityID, m_asmce[i].m_pbSecurityID, m_asmce[i].m_cbSecurityID );
  3628. *pcbSecurityID = m_asmce[i].m_cbSecurityID;
  3629. }
  3630. else
  3631. *pcbSecurityID = 0;
  3632. }
  3633. if (pdwZone)
  3634. {
  3635. *pdwZone = m_asmce[i].m_dwZone;
  3636. if (pfMarked)
  3637. *pfMarked = m_asmce[i].m_fMarked;
  3638. }
  3639. }
  3640. }
  3641. LeaveCriticalSection(&m_csectZoneCache);
  3642. return fFound;
  3643. }
  3644. void
  3645. CSecurityManager::CSecMgrCache::Add(LPCWSTR pwszURL,
  3646. DWORD dwZone,
  3647. BOOL fMarked,
  3648. const BYTE *pbSecurityID,
  3649. const DWORD cbSecurityID,
  3650. LPCWSTR pwszDocDomain)
  3651. {
  3652. int i;
  3653. BOOL fFound;
  3654. EnterCriticalSection(&m_csectZoneCache);
  3655. if ( !IsCounterEqual() )
  3656. Flush();
  3657. fFound = FindCacheEntry( pwszURL, i ); // found or not, i will be the right place to set it.
  3658. m_asmce[i].Set(pwszURL, dwZone, fMarked, pbSecurityID, cbSecurityID, pwszDocDomain);
  3659. if (!fFound)
  3660. m_iAdd = (m_iAdd + 1) % MAX_SEC_MGR_CACHE;
  3661. SetToCurrentCounter(); // validate this cache.
  3662. LeaveCriticalSection(&m_csectZoneCache);
  3663. }
  3664. void
  3665. CSecurityManager::CSecMgrCache::Flush(void)
  3666. {
  3667. int i;
  3668. EnterCriticalSection(&m_csectZoneCache);
  3669. for ( i = 0; i < MAX_SEC_MGR_CACHE; i++ )
  3670. m_asmce[i].Flush();
  3671. m_iAdd = 0;
  3672. LeaveCriticalSection(&m_csectZoneCache);
  3673. }
  3674. // Is the counter we saved with the cache entry, equal to the current counter.
  3675. BOOL
  3676. CSecurityManager::CSecMgrCache::IsCounterEqual( ) const
  3677. {
  3678. CExclusiveLock lock(s_hMutexCounter);
  3679. LPDWORD lpdwCounter = (LPDWORD) g_SharedMem.GetPtr(SM_SECMGRCHANGE_COUNTER);
  3680. // If we couldn't create the shared memory for some reason, we just assume our cache is up to date.
  3681. if (lpdwCounter == NULL)
  3682. return TRUE;
  3683. return (m_dwPrevCounter == *lpdwCounter);
  3684. }
  3685. VOID
  3686. CSecurityManager::CSecMgrCache::SetToCurrentCounter( )
  3687. {
  3688. CExclusiveLock lock(s_hMutexCounter);
  3689. LPDWORD lpdwCounter = (LPDWORD) g_SharedMem.GetPtr(SM_SECMGRCHANGE_COUNTER);
  3690. if (lpdwCounter == NULL)
  3691. return;
  3692. m_dwPrevCounter = *lpdwCounter;
  3693. }
  3694. VOID
  3695. CSecurityManager::CSecMgrCache::IncrementGlobalCounter( )
  3696. {
  3697. CExclusiveLock lock(s_hMutexCounter);
  3698. LPDWORD lpdwCounter = (LPDWORD) g_SharedMem.GetPtr(SM_SECMGRCHANGE_COUNTER);
  3699. if (lpdwCounter == NULL)
  3700. return;
  3701. (*lpdwCounter)++;
  3702. }
  3703. BOOL
  3704. CSecurityManager::CSecMgrCache::FindCacheEntry( LPCWSTR pwszURL, int& riEntry )
  3705. {
  3706. BOOL fFound = FALSE;
  3707. riEntry = m_iAdd - 1 % MAX_SEC_MGR_CACHE;
  3708. // our cache is a circular buffer. We scan it from the last entry
  3709. // we added backwards to the next slot to add to, createing a quasi-
  3710. // MRU.
  3711. if ( riEntry < 0 )
  3712. riEntry = MAX_SEC_MGR_CACHE + riEntry;
  3713. // check below us, starting with the most recent addition, if any.
  3714. for ( ; riEntry >= 0; riEntry-- )
  3715. {
  3716. if ( m_asmce[riEntry].m_pwszURL &&
  3717. StrCmpW( m_asmce[riEntry].m_pwszURL, pwszURL ) == 0 )
  3718. {
  3719. fFound = TRUE;
  3720. break;
  3721. }
  3722. }
  3723. if (!fFound)
  3724. {
  3725. for ( riEntry = MAX_SEC_MGR_CACHE - 1; riEntry >= m_iAdd; riEntry-- )
  3726. {
  3727. if (m_asmce[riEntry].m_pwszURL == NULL)
  3728. break; // hasn't been used yet.
  3729. else if ( m_asmce[riEntry].m_pwszURL &&
  3730. StrCmpW( m_asmce[riEntry].m_pwszURL, pwszURL ) == 0 )
  3731. {
  3732. fFound = TRUE;
  3733. break;
  3734. }
  3735. }
  3736. }
  3737. if (!fFound)
  3738. riEntry = m_iAdd;
  3739. return fFound;
  3740. }
  3741. void
  3742. CSecurityManager::CSecMgrCache::CSecMgrCacheEntry::Set(LPCWSTR pwszURL,
  3743. DWORD dwZone,
  3744. BOOL fMarked,
  3745. const BYTE *pbSecurityID,
  3746. DWORD cbSecurityID,
  3747. LPCWSTR pwszDocDomain)
  3748. {
  3749. if ( pwszURL )
  3750. {
  3751. // Only replace if the string has changed.
  3752. // We may see the same string if the entry is
  3753. // set by MapUrlToZone before GetSecurityID is called.
  3754. if (m_pwszURL && StrCmpW(pwszURL, m_pwszURL))
  3755. {
  3756. delete [] m_pwszURL;
  3757. m_pwszURL = NULL;
  3758. }
  3759. if (!m_pwszURL)
  3760. {
  3761. int cchURL = lstrlenW( pwszURL );
  3762. m_pwszURL = new WCHAR[cchURL+1];
  3763. if ( m_pwszURL )
  3764. StrCpyW( m_pwszURL, pwszURL );
  3765. else
  3766. return;
  3767. }
  3768. }
  3769. // We always set the url zone mark first, then come back later and
  3770. // add the security ID, than means that on any set operation, we're
  3771. // either changing the url or adding the security ID. Either way, if
  3772. // we have a security ID, its invalid now, so flush it.
  3773. if (m_pbSecurityID)
  3774. {
  3775. delete [] m_pbSecurityID;
  3776. m_pbSecurityID = NULL;
  3777. m_cbSecurityID = 0;
  3778. }
  3779. if (m_pwszDocDomain)
  3780. {
  3781. delete [] m_pwszDocDomain;
  3782. m_pwszDocDomain = NULL;
  3783. }
  3784. if ( pbSecurityID )
  3785. {
  3786. m_pbSecurityID = new BYTE[cbSecurityID];
  3787. if ( m_pbSecurityID )
  3788. {
  3789. memcpy( m_pbSecurityID, pbSecurityID, cbSecurityID );
  3790. if (pwszDocDomain)
  3791. {
  3792. m_pwszDocDomain = new WCHAR[lstrlenW(pwszDocDomain) + 1];
  3793. if (m_pwszDocDomain != NULL)
  3794. {
  3795. StrCpyW(m_pwszDocDomain, pwszDocDomain);
  3796. }
  3797. else
  3798. {
  3799. // If we don't have memory for the Document's domain property
  3800. // we better not remember the security ID either.
  3801. delete [] m_pbSecurityID;
  3802. m_pbSecurityID = NULL;
  3803. cbSecurityID = 0;
  3804. }
  3805. }
  3806. }
  3807. else
  3808. {
  3809. cbSecurityID = 0;
  3810. }
  3811. m_cbSecurityID = cbSecurityID;
  3812. }
  3813. if (dwZone != URLZONE_INVALID)
  3814. {
  3815. m_dwZone = dwZone;
  3816. m_fMarked = fMarked;
  3817. }
  3818. }
  3819. void
  3820. CSecurityManager::CSecMgrCache::CSecMgrCacheEntry::Flush(void)
  3821. {
  3822. if (m_pwszURL)
  3823. delete[] m_pwszURL;
  3824. m_pwszURL = NULL;
  3825. if (m_pbSecurityID)
  3826. delete[] m_pbSecurityID;
  3827. m_pbSecurityID = NULL;
  3828. m_cbSecurityID = 0;
  3829. if (m_pwszDocDomain)
  3830. {
  3831. delete [] m_pwszDocDomain;
  3832. m_pwszDocDomain = NULL;
  3833. }
  3834. m_dwZone = URLZONE_INVALID;
  3835. m_fMarked = FALSE;
  3836. }
  3837. BOOL
  3838. CSecurityManager::EnsureListReady(BOOL bForce)
  3839. // Make sure the list of allowed controls is ready
  3840. // Returns whether or not the list had to be made
  3841. // bForce is whether to force a reinitialization
  3842. {
  3843. if(CSecurityManager::s_clsidAllowedList == NULL || bForce == TRUE)
  3844. {
  3845. CSecurityManager::IntializeAllowedControls();
  3846. return TRUE;
  3847. }
  3848. else
  3849. return FALSE;
  3850. }
  3851. void
  3852. CSecurityManager::IntializeAllowedControls()
  3853. {
  3854. DWORD i = 0;
  3855. DWORD dwNumKeys=0;
  3856. DWORD dwMaxLen=0;
  3857. DWORD dwNumValues=0;
  3858. // this buffer size should be long enough to hold a string-form
  3859. // CLSID, plus the two end braces, plus a null terminator
  3860. TCHAR szValueName[40];
  3861. DWORD dwNameLength = 40;
  3862. DWORD dwType = 0;
  3863. DWORD dwData = 0;
  3864. DWORD dwDataLength = sizeof(DWORD);
  3865. // In case we somehow get multiply initialized
  3866. if(CSecurityManager::s_clsidAllowedList != NULL)
  3867. {
  3868. delete [] CSecurityManager::s_clsidAllowedList;
  3869. CSecurityManager::s_clsidAllowedList = NULL;
  3870. }
  3871. CSecurityManager::s_dwNumAllowedControls = 0;
  3872. //open key
  3873. // look at HKLM only, first
  3874. CRegKey * prkey_AllowedControls;
  3875. CRegKey rkey_AllowedControls(TRUE);
  3876. CRegKey rkey_AllowedControlsCU(FALSE);
  3877. LONG lRes = rkey_AllowedControls.Open(NULL, ALLOWED_CONTROLS_KEY, KEY_READ);
  3878. if(lRes != ERROR_SUCCESS)
  3879. {
  3880. // List not found in HKLM, check HKCU
  3881. lRes = rkey_AllowedControlsCU.Open(NULL, ALLOWED_CONTROLS_KEY, KEY_READ);
  3882. if(lRes != ERROR_SUCCESS)
  3883. {
  3884. // AllowedControls Key not able to be opened
  3885. return;
  3886. }
  3887. else
  3888. {
  3889. prkey_AllowedControls = &rkey_AllowedControlsCU;
  3890. }
  3891. }
  3892. else
  3893. {
  3894. prkey_AllowedControls = &rkey_AllowedControls;
  3895. }
  3896. lRes = prkey_AllowedControls->QuerySubKeyInfo(&dwNumKeys, &dwMaxLen, &dwNumValues);
  3897. if(lRes != ERROR_SUCCESS)
  3898. return;
  3899. // prepare space in data structure
  3900. // array will not need to be resized, since the maximum number of allowed
  3901. // CLSIDs is the number of values in the key
  3902. CSecurityManager::s_clsidAllowedList = new CLSID[dwNumValues];
  3903. if(CSecurityManager::s_clsidAllowedList == NULL) // new failed
  3904. return;
  3905. // loop through all values in the key
  3906. for(i = 0; i < dwNumValues; i++)
  3907. {
  3908. // at every loop, these values get changed and must be reset to the
  3909. // length of the name and data buffers, respectively
  3910. dwNameLength = ARRAYSIZE(szValueName);
  3911. dwDataLength = sizeof(DWORD);
  3912. // Get the (DWORD) value for the current value name
  3913. LONG lResult = prkey_AllowedControls->EnumValue(i, szValueName, &dwNameLength,
  3914. &dwType, &dwData, &dwDataLength);
  3915. if(lResult == ERROR_SUCCESS && dwType == REG_DWORD
  3916. && GetUrlPolicyPermissions(dwData) == URLPOLICY_ALLOW)
  3917. {
  3918. // found a value for the CLSID given, and it is set to allow the CLSID
  3919. // add the CLSID to the list
  3920. CLSID * p_id = CSecurityManager::s_clsidAllowedList + //pointer +
  3921. CSecurityManager::s_dwNumAllowedControls;//offset
  3922. HRESULT hr = CLSIDFromString(szValueName, p_id);
  3923. if(hr != NOERROR)
  3924. continue;
  3925. CSecurityManager::s_dwNumAllowedControls++;
  3926. }
  3927. }
  3928. }
  3929. HRESULT
  3930. CSecurityManager::GetControlPermissions(BYTE * raw_CLSID, DWORD & dwPerm)
  3931. {
  3932. CLSID * id = (CLSID *)(raw_CLSID);
  3933. dwPerm = 0;
  3934. // If the list is not initialized (something's wrong) leave function
  3935. if(CSecurityManager::s_clsidAllowedList == NULL)
  3936. {
  3937. return E_UNEXPECTED;
  3938. }
  3939. DWORD index = 0;
  3940. // Search for the given CLSID in the list of allowed Controls
  3941. for(index = 0; index < CSecurityManager::s_dwNumAllowedControls; index++)
  3942. {
  3943. if(*id == (CSecurityManager::s_clsidAllowedList[index]))
  3944. {
  3945. dwPerm = URLPOLICY_ALLOW; // not necesarry, since currently only allowed controls
  3946. // are in the list, but this may change later
  3947. return S_OK;
  3948. }
  3949. }
  3950. // Not found, return false to indicate not in list
  3951. return S_FALSE;
  3952. }
  3953. HRESULT
  3954. CSecurityManager::GetActiveXRunPermissions(BYTE * raw_CLSID, DWORD & dwPerm)
  3955. {
  3956. HRESULT hr = S_FALSE;
  3957. DWORD dwValue;
  3958. EnterCriticalSection(&s_csectAList);
  3959. // Initialize the Allowed Controls list if it is not already
  3960. CSecurityManager::EnsureListReady(FALSE);
  3961. // get the list permission for pContext, if it is in the list
  3962. HRESULT permHR = CSecurityManager::GetControlPermissions(raw_CLSID,dwValue);
  3963. LeaveCriticalSection(&s_csectAList);
  3964. // interpret results, (zone dependent interpretation not yet implemented)
  3965. if(SUCCEEDED(permHR))
  3966. {
  3967. if(permHR == S_OK) // found in list
  3968. {
  3969. if(dwValue == URLPOLICY_ALLOW)
  3970. {
  3971. hr = S_OK;
  3972. dwPerm = URLPOLICY_ALLOW;
  3973. }
  3974. else
  3975. {
  3976. hr = S_FALSE;
  3977. dwPerm = URLPOLICY_DISALLOW;
  3978. }
  3979. }
  3980. else // not in list; default is to disallow
  3981. {
  3982. hr = S_FALSE;
  3983. dwPerm = URLPOLICY_DISALLOW;
  3984. }
  3985. }
  3986. else // Unknown error. Disallow by default
  3987. {
  3988. hr = S_FALSE;
  3989. dwPerm = URLPOLICY_DISALLOW;
  3990. }
  3991. return hr;
  3992. }