Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

587 lines
19 KiB

  1. //*********************************************************************
  2. //* Microsoft Windows **
  3. //* Copyright(c) Microsoft Corp., 1996 **
  4. //*********************************************************************
  5. /*Included Files------------------------------------------------------------*/
  6. #include "msrating.h"
  7. #include "ratings.h"
  8. #include <ratingsp.h>
  9. #include <npassert.h>
  10. #include <npstring.h>
  11. #include "mslubase.h"
  12. #include "roll.h"
  13. #include "rors.h"
  14. #include "picsrule.h"
  15. #include "parselbl.h"
  16. #include "debug.h"
  17. typedef HRESULT (STDAPICALLTYPE *PFNCoInitialize)(LPVOID pvReserved);
  18. typedef void (STDAPICALLTYPE *PFNCoUninitialize)(void);
  19. typedef HRESULT (STDAPICALLTYPE *PFNCoGetMalloc)(
  20. DWORD dwMemContext, LPMALLOC FAR* ppMalloc);
  21. typedef HRESULT (STDAPICALLTYPE *PFNCoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter,
  22. DWORD dwClsContext, REFIID riid, LPVOID FAR* ppv);
  23. typedef HRESULT (STDAPICALLTYPE *PFNCLSIDFromString)(LPOLESTR lpsz, LPCLSID pclsid);
  24. PFNCoInitialize pfnCoInitialize = NULL;
  25. PFNCoUninitialize pfnCoUninitialize = NULL;
  26. PFNCoGetMalloc pfnCoGetMalloc = NULL;
  27. PFNCoCreateInstance pfnCoCreateInstance = NULL;
  28. PFNCLSIDFromString pfnCLSIDFromString = NULL;
  29. #undef CoInitialize
  30. #undef CoUninitialize
  31. #undef CoGetMalloc
  32. #undef CoCreateInstance
  33. #undef CLSIDFromString
  34. #define CoInitialize pfnCoInitialize
  35. #define CoUninitialize pfnCoUninitialize
  36. #define CoGetMalloc pfnCoGetMalloc
  37. #define CoCreateInstance pfnCoCreateInstance
  38. #define CLSIDFromString pfnCLSIDFromString
  39. struct {
  40. FARPROC *ppfn;
  41. LPCSTR pszName;
  42. } aOLEImports[] = {
  43. { (FARPROC *)&pfnCoInitialize, "CoInitialize" },
  44. { (FARPROC *)&pfnCoUninitialize, "CoUninitialize" },
  45. { (FARPROC *)&pfnCoGetMalloc, "CoGetMalloc" },
  46. { (FARPROC *)&pfnCoCreateInstance, "CoCreateInstance" },
  47. { (FARPROC *)&pfnCLSIDFromString, "CLSIDFromString" },
  48. };
  49. const UINT cOLEImports = sizeof(aOLEImports) / sizeof(aOLEImports[0]);
  50. HINSTANCE hOLE32 = NULL;
  51. BOOL fTriedOLELoad = FALSE;
  52. BOOL LoadOLE(void)
  53. {
  54. if (fTriedOLELoad)
  55. return (hOLE32 != NULL);
  56. fTriedOLELoad = TRUE;
  57. hOLE32 = ::LoadLibrary("OLE32.DLL");
  58. if (hOLE32 == NULL)
  59. return FALSE;
  60. for (UINT i=0; i<cOLEImports; i++) {
  61. *(aOLEImports[i].ppfn) = ::GetProcAddress(hOLE32, aOLEImports[i].pszName);
  62. if (*(aOLEImports[i].ppfn) == NULL) {
  63. CleanupOLE();
  64. return FALSE;
  65. }
  66. }
  67. return TRUE;
  68. }
  69. void CleanupOLE(void)
  70. {
  71. if (hOLE32 != NULL) {
  72. for (UINT i=0; i<cOLEImports; i++) {
  73. *(aOLEImports[i].ppfn) = NULL;
  74. }
  75. ::FreeLibrary(hOLE32);
  76. hOLE32 = NULL;
  77. }
  78. }
  79. /*Obtain Rating Data--------------------------------------------------------*/
  80. class RatingObtainData
  81. {
  82. public:
  83. NLS_STR nlsTargetUrl;
  84. HANDLE hAbortEvent;
  85. DWORD dwUserData;
  86. void (*fCallback)(DWORD dwUserData, HRESULT hr, LPCTSTR pszRating, LPVOID lpvRatingDetails) ;
  87. RatingObtainData(LPCTSTR pszTargetUrl);
  88. ~RatingObtainData();
  89. };
  90. RatingObtainData::RatingObtainData(LPCTSTR pszTargetUrl)
  91. : nlsTargetUrl(pszTargetUrl)
  92. {
  93. hAbortEvent = NULL;
  94. dwUserData = 0;
  95. fCallback = NULL;
  96. }
  97. RatingObtainData::~RatingObtainData()
  98. {
  99. if (hAbortEvent) CloseHandle(hAbortEvent);
  100. }
  101. struct RatingHelper {
  102. CLSID clsid;
  103. DWORD dwSort;
  104. };
  105. array<RatingHelper> *paRatingHelpers = NULL;
  106. CustomRatingHelper *g_pCustomRatingHelperList;
  107. BOOL fTriedLoadingHelpers = FALSE;
  108. void InitRatingHelpers()
  109. {
  110. BOOL fCOMInitialized = FALSE;
  111. RatingHelper helper;
  112. if (fTriedLoadingHelpers || !LoadOLE())
  113. {
  114. TraceMsg( TF_WARNING, "InitRatingHelpers() - Tried Loading Helpers or OLE Load Failed!");
  115. return;
  116. }
  117. fTriedLoadingHelpers = TRUE;
  118. paRatingHelpers = new array<RatingHelper>;
  119. if (paRatingHelpers == NULL)
  120. {
  121. TraceMsg( TF_ERROR, "InitRatingHelpers() - Failed to Create paRatingHelpers!");
  122. return;
  123. }
  124. CRegKey key;
  125. /* REARCHITECT - should this be in the policy file? it shouldn't be per-user, that's for sure. */
  126. if ( key.Open( HKEY_LOCAL_MACHINE, szRATINGHELPERS, KEY_READ ) != ERROR_SUCCESS )
  127. {
  128. TraceMsg( TF_WARNING, "InitRatingHelpers() - Failed to Open key szRATINGHELPERS='%s'!", szRATINGHELPERS );
  129. return;
  130. }
  131. UINT iValue = 0;
  132. LONG err = ERROR_SUCCESS;
  133. char szValue[39]; /* just big enough for a null-terminated GUID string */
  134. WCHAR wszValue[39]; /* unicode version */
  135. // YANGXU : 11/15/1999
  136. // under custom mode, if we have a bureau string, load the bureau
  137. // rating helper, but do not load any other rating helpers
  138. if (g_fIsRunningUnderCustom)
  139. {
  140. if (gPRSI->etstrRatingBureau.fIsInit())
  141. {
  142. ASSERT(FALSE == fCOMInitialized);
  143. if (SUCCEEDED(CoInitialize(NULL)))
  144. {
  145. fCOMInitialized = TRUE;
  146. IObtainRating *pHelper;
  147. helper.clsid = CLSID_RemoteSite;
  148. if (SUCCEEDED(CoCreateInstance(helper.clsid, NULL,
  149. CLSCTX_INPROC_SERVER,
  150. IID_IObtainRating,
  151. (LPVOID *)&pHelper)))
  152. {
  153. helper.dwSort = pHelper->GetSortOrder();
  154. if (!paRatingHelpers->Append(helper))
  155. {
  156. err = ERROR_NOT_ENOUGH_MEMORY;
  157. }
  158. pHelper->Release();
  159. #ifdef DEBUG
  160. pHelper = NULL;
  161. #endif
  162. }
  163. }
  164. }
  165. }
  166. else
  167. {
  168. /* Note, special care is taken to make sure that we only CoInitialize for
  169. * as long as we need to, and CoUninitialize when we're done. We cannot
  170. * CoUninitialize on a different thread than we initialized on, nor do we
  171. * want to call CoUninitialize at thread-detach time (would require using
  172. * TLS). This is done here and in the asynchronous thread that actually
  173. * calls into the rating helpers to get ratings.
  174. */
  175. do
  176. {
  177. DWORD cchValue = sizeof(szValue);
  178. err = RegEnumValue( key.m_hKey, iValue, szValue, &cchValue, NULL, NULL, NULL, NULL);
  179. if (err == ERROR_SUCCESS)
  180. {
  181. if (!fCOMInitialized)
  182. {
  183. if (FAILED(CoInitialize(NULL)))
  184. {
  185. break;
  186. }
  187. fCOMInitialized = TRUE;
  188. }
  189. if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szValue, -1, wszValue, ARRAYSIZE(wszValue))) {
  190. if (SUCCEEDED(CLSIDFromString(wszValue, &helper.clsid)))
  191. {
  192. IObtainRating *pHelper;
  193. if (SUCCEEDED(CoCreateInstance(helper.clsid, NULL,
  194. CLSCTX_INPROC_SERVER,
  195. IID_IObtainRating,
  196. (LPVOID *)&pHelper)))
  197. {
  198. helper.dwSort = pHelper->GetSortOrder();
  199. if (!paRatingHelpers->Append(helper))
  200. {
  201. err = ERROR_NOT_ENOUGH_MEMORY;
  202. }
  203. pHelper->Release();
  204. #ifdef DEBUG
  205. pHelper = NULL;
  206. #endif
  207. }
  208. }
  209. }
  210. }
  211. iValue++;
  212. } while (ERROR_SUCCESS == err);
  213. }
  214. if (fCOMInitialized)
  215. {
  216. CoUninitialize();
  217. }
  218. /* If more than one helper, sort them by their reported sort orders.
  219. * We will rarely have more than two or three of these guys, and this
  220. * is one time code, so we don't need a super-slick sort algorithm.
  221. *
  222. * CODEWORK: could modify array<> template to support an Insert()
  223. * method which reallocates the buffer like Append() does, but inserts
  224. * at a specific location.
  225. */
  226. if (paRatingHelpers->Length() > 1)
  227. {
  228. for (INT i=0; i < paRatingHelpers->Length() - 1; i++)
  229. {
  230. for (INT j=i+1; j < paRatingHelpers->Length(); j++)
  231. {
  232. if ((*paRatingHelpers)[i].dwSort > (*paRatingHelpers)[j].dwSort)
  233. {
  234. RatingHelper temp = (*paRatingHelpers)[i];
  235. (*paRatingHelpers)[i] = (*paRatingHelpers)[j];
  236. (*paRatingHelpers)[j] = temp;
  237. }
  238. }
  239. }
  240. }
  241. }
  242. void CleanupRatingHelpers(void)
  243. {
  244. if (paRatingHelpers != NULL) {
  245. delete paRatingHelpers;
  246. paRatingHelpers = NULL;
  247. }
  248. fTriedLoadingHelpers = FALSE;
  249. }
  250. /*
  251. This procedure runs on its own thread (1 per request).
  252. This cycles through all the helper DLLs looking for a ratings.
  253. It goes on down the list one at a time until either a rating
  254. is found, or the this is aborted by the programmer.
  255. */
  256. DWORD __stdcall RatingCycleThread(LPVOID pData)
  257. {
  258. RatingObtainData *pOrd = (RatingObtainData*) pData;
  259. LPVOID lpvRatingDetails = NULL;
  260. HRESULT hrRet = E_FAIL;
  261. int nProc;
  262. BOOL fAbort = FALSE;
  263. BOOL fFoundWithCustomHelper = FALSE;
  264. IMalloc *pAllocator = NULL;
  265. LPSTR pszRating = NULL;
  266. LPSTR pszRatingName = NULL;
  267. LPSTR pszRatingReason = NULL;
  268. BOOL fCOMInitialized = FALSE;
  269. CustomRatingHelper* pmrhCurrent = NULL;
  270. ASSERT(pOrd);
  271. //
  272. // Check the Custom Helpers first
  273. //
  274. if(g_pCustomRatingHelperList)
  275. {
  276. // we should only have custom rating helpers under custom mode
  277. ASSERT(g_fIsRunningUnderCustom);
  278. if(SUCCEEDED(CoInitialize(NULL)))
  279. {
  280. fCOMInitialized = TRUE;
  281. // get a cotaskmem allocator
  282. hrRet = CoGetMalloc(MEMCTX_TASK, &pAllocator);
  283. if (SUCCEEDED(hrRet))
  284. {
  285. pmrhCurrent = g_pCustomRatingHelperList;
  286. while(pmrhCurrent)
  287. {
  288. HRESULT (* pfn)(REFCLSID, REFIID, LPVOID *) = NULL;
  289. ICustomRatingHelper* pCustomHelper = NULL;
  290. IClassFactory* pFactory = NULL;
  291. ASSERT(pmrhCurrent->hLibrary);
  292. *(FARPROC *) &pfn = GetProcAddress(pmrhCurrent->hLibrary, "DllGetClassObject");
  293. if (pfn)
  294. {
  295. hrRet = pfn(pmrhCurrent->clsid, IID_IClassFactory, (void**)&pFactory);
  296. if (SUCCEEDED(hrRet))
  297. {
  298. hrRet = pFactory->CreateInstance(NULL, IID_ICustomRatingHelper, (void**)&pCustomHelper);
  299. if (SUCCEEDED(hrRet))
  300. {
  301. hrRet = pCustomHelper->ObtainCustomRating(pOrd->nlsTargetUrl.QueryPch(),
  302. pOrd->hAbortEvent,
  303. pAllocator,
  304. &pszRating,
  305. &pszRatingName,
  306. &pszRatingReason);
  307. pCustomHelper->Release();
  308. pCustomHelper = NULL;
  309. fAbort = (WAIT_OBJECT_0 == WaitForSingleObject(pOrd->hAbortEvent, 0));
  310. if (fAbort || SUCCEEDED(hrRet))
  311. break;
  312. }
  313. pFactory->Release();
  314. } // if (SUCCEEDED(pfn(pmrhCurrent->clsid, IID_ICustomRatingHelper, (void**)&pCustomHelper)))
  315. } // if (pfn)
  316. else
  317. {
  318. hrRet = E_UNEXPECTED;
  319. }
  320. pmrhCurrent = pmrhCurrent->pNextHelper;
  321. }
  322. }
  323. }
  324. }
  325. if(SUCCEEDED(hrRet))
  326. {
  327. fFoundWithCustomHelper = TRUE;
  328. }
  329. if(paRatingHelpers && paRatingHelpers->Length()>0 && !SUCCEEDED(hrRet) && !fAbort)
  330. {
  331. /* Note that CoInitialize and CoUninitialize must be done once per thread. */
  332. if(!fCOMInitialized)
  333. {
  334. if(SUCCEEDED(CoInitialize(NULL)))
  335. {
  336. fCOMInitialized = TRUE;
  337. }
  338. }
  339. if (fCOMInitialized) {
  340. if (!pAllocator)
  341. {
  342. hrRet = CoGetMalloc(MEMCTX_TASK, &pAllocator);
  343. }
  344. if (pAllocator) {
  345. //Cycle through list of rating procs till one gives us the answer, we abort, or there are no more
  346. int nRatingHelperProcs = ::paRatingHelpers->Length();
  347. for (nProc = 0; nProc < nRatingHelperProcs; ++nProc)
  348. {
  349. IObtainRating *pHelper;
  350. if (SUCCEEDED(CoCreateInstance((*paRatingHelpers)[nProc].clsid, NULL,
  351. CLSCTX_INPROC_SERVER,
  352. IID_IObtainRating,
  353. (LPVOID *)&pHelper))) {
  354. hrRet = pHelper->ObtainRating(pOrd->nlsTargetUrl.QueryPch(),
  355. pOrd->hAbortEvent, pAllocator, &pszRating);
  356. pHelper->Release();
  357. #ifdef DEBUG
  358. pHelper = NULL;
  359. #endif
  360. }
  361. fAbort = (WAIT_OBJECT_0 == WaitForSingleObject(pOrd->hAbortEvent, 0));
  362. if (fAbort || SUCCEEDED(hrRet)) break;
  363. }
  364. }
  365. }
  366. else
  367. hrRet = E_RATING_NOT_FOUND;
  368. }
  369. /*return results to user*/
  370. if (!fAbort)
  371. {
  372. /*
  373. * If one of the providers found a rating, we must call CheckUserAccess
  374. * and tell the client whether the user has access or not. If we did
  375. * not find a rating, then we tell the client that, by passing the
  376. * callback a code of E_RATING_NOT_FOUND.
  377. *
  378. * The provider may also return S_RATING_ALLOW or S_RATING_DENY, which
  379. * means that it has already checked the user's access (for example,
  380. * against a system-wide exclusion list).
  381. */
  382. if (hrRet == S_RATING_FOUND)
  383. {
  384. hrRet = RatingCheckUserAccess(NULL, pOrd->nlsTargetUrl.QueryPch(),
  385. pszRating, NULL, PICS_LABEL_FROM_BUREAU,
  386. &lpvRatingDetails);
  387. }
  388. else
  389. {
  390. if(S_RATING_DENY == hrRet && g_fIsRunningUnderCustom)
  391. {
  392. lpvRatingDetails = (LPVOID)(new CParsedLabelList);
  393. if (lpvRatingDetails)
  394. {
  395. ((CParsedLabelList*)lpvRatingDetails)->m_fDenied = TRUE;
  396. ((CParsedLabelList*)lpvRatingDetails)->m_pszURL = StrDup(pOrd->nlsTargetUrl.QueryPch());
  397. }
  398. else
  399. {
  400. hrRet = E_OUTOFMEMORY;
  401. }
  402. }
  403. }
  404. if (S_RATING_DENY == hrRet && g_fIsRunningUnderCustom)
  405. {
  406. // lpvRatingDetails should be non NULL at this point
  407. ASSERT(lpvRatingDetails);
  408. ((CParsedLabelList*)lpvRatingDetails)->m_fIsHelper = TRUE;
  409. if(fFoundWithCustomHelper)
  410. {
  411. ((CParsedLabelList*)lpvRatingDetails)->m_fIsCustomHelper = TRUE;
  412. if (pszRatingName)
  413. {
  414. if(((CParsedLabelList*)lpvRatingDetails)->m_pszRatingName = new char[strlen(pszRatingName)+1])
  415. {
  416. strcpyf(((CParsedLabelList*)lpvRatingDetails)->m_pszRatingName,pszRatingName);
  417. } // if(((CParsedLabelList*)lpvRatingDetails)->m_pszRatingName = new char[strlen(pszRatingName)+1])
  418. }
  419. if (pszRatingReason)
  420. {
  421. if(((CParsedLabelList*)lpvRatingDetails)->m_pszRatingReason = new char[strlen(pszRatingReason)+1])
  422. {
  423. strcpyf(((CParsedLabelList*)lpvRatingDetails)->m_pszRatingReason, pszRatingReason);
  424. } // if(((CParsedLabelList*)lpvRatingDetails)->m_pszRatingReason = new char[strlen(pszRatingReason)+1])
  425. }
  426. }
  427. }
  428. /* Range-check other success codes to make sure they're not anything
  429. * that the browser callback isn't expecting.
  430. */
  431. if (SUCCEEDED(hrRet) && (hrRet != S_RATING_ALLOW && hrRet != S_RATING_DENY))
  432. hrRet = E_RATING_NOT_FOUND;
  433. (*pOrd->fCallback)(pOrd->dwUserData, hrRet, pszRating, (LPVOID) lpvRatingDetails);
  434. }
  435. /*cleanup*/
  436. delete pOrd;
  437. pOrd = NULL;
  438. if (pAllocator != NULL) {
  439. pAllocator->Free(pszRating);
  440. if(pszRatingName)
  441. {
  442. pAllocator->Free(pszRatingName);
  443. }
  444. if(pszRatingReason)
  445. {
  446. pAllocator->Free(pszRatingReason);
  447. }
  448. pAllocator->Release();
  449. }
  450. if (fCOMInitialized)
  451. CoUninitialize();
  452. return (DWORD) fAbort;
  453. }
  454. /*Public Functions----------------------------------------------------------*/
  455. //Startup thread that finds rating, return immediately
  456. HRESULT WINAPI RatingObtainQuery(LPCTSTR pszTargetUrl, DWORD dwUserData, void (*fCallback)(DWORD dwUserData, HRESULT hr, LPCTSTR pszRating, LPVOID lpvRatingDetails), HANDLE *phRatingObtainQuery)
  457. {
  458. RatingObtainData *pOrd;
  459. HANDLE hThread;
  460. DWORD dwThid;
  461. CheckGlobalInfoRev();
  462. if (!g_fIsRunningUnderCustom)
  463. {
  464. if (::RatingEnabledQuery() != S_OK ||
  465. !gPRSI->fSettingsValid) /* ratings not enabled? fail immediately. */
  466. return E_RATING_NOT_FOUND;
  467. }
  468. InitRatingHelpers();
  469. if (NULL == g_pCustomRatingHelperList
  470. && (::paRatingHelpers == NULL || ::paRatingHelpers->Length() < 1)) {
  471. return E_RATING_NOT_FOUND;
  472. }
  473. if (fCallback && pszTargetUrl)
  474. {
  475. pOrd = new RatingObtainData(pszTargetUrl);
  476. if (pOrd)
  477. {
  478. if (pOrd->nlsTargetUrl.QueryError() == ERROR_SUCCESS) {
  479. pOrd->dwUserData = dwUserData;
  480. pOrd->fCallback = fCallback;
  481. pOrd->hAbortEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  482. if (pOrd->hAbortEvent)
  483. {
  484. hThread = CreateThread(NULL, 0, RatingCycleThread, (LPVOID) pOrd, 0, &dwThid);
  485. if (hThread)
  486. {
  487. CloseHandle(hThread);
  488. if (phRatingObtainQuery) *phRatingObtainQuery = pOrd->hAbortEvent;
  489. return NOERROR;
  490. }
  491. CloseHandle(pOrd->hAbortEvent);
  492. }
  493. }
  494. delete pOrd;
  495. pOrd = NULL;
  496. }
  497. }
  498. return E_FAIL;
  499. }
  500. //Cancel an existing query
  501. HRESULT WINAPI RatingObtainCancel(HANDLE hRatingObtainQuery)
  502. {
  503. //what happens if hRatingObtainQuery has already been closed?!?!
  504. if (hRatingObtainQuery)
  505. {
  506. if (SetEvent(hRatingObtainQuery)) return NOERROR;
  507. }
  508. return E_HANDLE;
  509. }