diff options
Diffstat (limited to 'components/parentalcontrols')
5 files changed, 583 insertions, 0 deletions
diff --git a/components/parentalcontrols/moz.build b/components/parentalcontrols/moz.build new file mode 100644 index 000000000..6c8bd9a8c --- /dev/null +++ b/components/parentalcontrols/moz.build @@ -0,0 +1,16 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +XPIDL_SOURCES += ['nsIParentalControlsService.idl'] + +XPIDL_MODULE = 'parentalcontrols' + +if not CONFIG['MOZ_DISABLE_PARENTAL_CONTROLS']: + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': + SOURCES += ['nsParentalControlsServiceWin.cpp'] + else: + SOURCES += ['nsParentalControlsServiceDefault.cpp'] + +FINAL_LIBRARY = 'xul' diff --git a/components/parentalcontrols/nsIParentalControlsService.idl b/components/parentalcontrols/nsIParentalControlsService.idl new file mode 100644 index 000000000..b9d49131f --- /dev/null +++ b/components/parentalcontrols/nsIParentalControlsService.idl @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +#include "nsISupports.idl" + +interface nsIURI; +interface nsIFile; +interface nsIInterfaceRequestor; +interface nsIArray; + +[scriptable, uuid(2e97e5dd-467b-4aea-a1bb-6773c0f2beb0)] +interface nsIParentalControlsService : nsISupports +{ + /** + * Action types that can be blocked for users. + */ + const short DOWNLOAD = 1; // Downloading files + const short INSTALL_EXTENSION = 2; // Installing extensions + const short INSTALL_APP = 3; // Installing webapps + const short BROWSE = 4; // Opening specific urls + const short SHARE = 5; // Sharing + const short BOOKMARK = 6; // Creating bookmarks + const short ADD_CONTACT = 7; // Add contacts to the system database + const short SET_IMAGE = 8; // Setting images as wall paper + const short MODIFY_ACCOUNTS = 9; // Modifying system accounts + const short REMOTE_DEBUGGING = 10; // Remote debugging + const short IMPORT_SETTINGS = 11; // Importing settings from other apps + const short PRIVATE_BROWSING = 12; // Disallow usage of private browsing + const short DATA_CHOICES = 13; // Choose whether or not to send usage information + const short CLEAR_HISTORY = 14; // Clear browsing history + const short MASTER_PASSWORD = 15; // Setting master password for logins + const short GUEST_BROWSING = 16; // Disallow usage of guest browsing + const short ADVANCED_SETTINGS = 17; // Advanced settings + const short CAMERA_MICROPHONE = 18; // Camera and microphone (WebRTC) + const short BLOCK_LIST = 19; // Block websites that include sensitive content + // 20 and 21 are unused. Was: Telemetry, FHR + const short DEFAULT_THEME = 22; // Use default theme or a special parental controls theme + + /** + * @returns true if the current user account has parental controls + * restrictions enabled. + */ + readonly attribute boolean parentalControlsEnabled; + + /** + * @returns true if the current user account parental controls + * restrictions include the blocking of all file downloads. + */ + readonly attribute boolean blockFileDownloadsEnabled; + + /** + * Check if the user can do the prescibed action for this uri. + * + * @param aAction Action being performed + * @param aUri The uri requesting this action + * @param aWindow The window generating this event. + */ + boolean isAllowed(in short aAction, [optional] in nsIURI aUri); + + /** + * Request that blocked URI(s) be allowed through parental + * control filters. Returns true if the URI was successfully + * overriden. Note, may block while native UI is shown. + * + * @param aTarget(s) URI to be overridden. In the case of + * multiple URI, the first URI in the array + * should be the root URI of the site. + * @param window Window that generates the event. + */ + boolean requestURIOverride(in nsIURI aTarget, [optional] in nsIInterfaceRequestor aWindowContext); + boolean requestURIOverrides(in nsIArray aTargets, [optional] in nsIInterfaceRequestor aWindowContext); + + /** + * @returns true if the current user account has parental controls + * logging enabled. If true, applications should log relevent events + * using 'log'. + */ + readonly attribute boolean loggingEnabled; + + /** + * Log entry types. Additional types can be defined and implemented + * as needed. Other possible event types might include email events, + * media related events, and IM events. + */ + const short ePCLog_URIVisit = 1; /* Web content */ + const short ePCLog_FileDownload = 2; /* File downloads */ + + /** + * Log an application specific parental controls + * event. + * + * @param aEntryType Constant defining the type of event. + * @param aFlag A flag indicating if the subject content + * was blocked. + * @param aSource The URI source of the subject content. + * @param aTarget The location the content was saved to if + * no blocking occurred. + */ + void log(in short aEntryType, in boolean aFlag, in nsIURI aSource, [optional] in nsIFile aTarget); +}; diff --git a/components/parentalcontrols/nsParentalControlsService.h b/components/parentalcontrols/nsParentalControlsService.h new file mode 100644 index 000000000..a0dc9c2db --- /dev/null +++ b/components/parentalcontrols/nsParentalControlsService.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsParentalControlsService_h__ +#define nsParentalControlsService_h__ + +#include "nsIParentalControlsService.h" +#include "nsCOMPtr.h" +#include "nsAutoPtr.h" +#include "nsIURI.h" + +#if defined(XP_WIN) +// wpcevents.h requires this be elevated +#if (WINVER < 0x0600) +# undef WINVER +# define WINVER 0x0600 +#endif +#include <wpcapi.h> +#include <wpcevent.h> +#endif + +class nsParentalControlsService : public nsIParentalControlsService +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPARENTALCONTROLSSERVICE + + nsParentalControlsService(); + +protected: + virtual ~nsParentalControlsService(); + +private: + bool mEnabled; +#if defined(XP_WIN) + REGHANDLE mProvider; + IWindowsParentalControls * mPC; + void LogFileDownload(bool blocked, nsIURI *aSource, nsIFile *aTarget); +#endif +}; + +#endif /* nsParentalControlsService_h__ */ diff --git a/components/parentalcontrols/nsParentalControlsServiceDefault.cpp b/components/parentalcontrols/nsParentalControlsServiceDefault.cpp new file mode 100644 index 000000000..5d97b6f1b --- /dev/null +++ b/components/parentalcontrols/nsParentalControlsServiceDefault.cpp @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsParentalControlsService.h" +#include "nsString.h" +#include "nsIFile.h" +#include "mozilla/Unused.h" + +NS_IMPL_ISUPPORTS(nsParentalControlsService, nsIParentalControlsService) + +nsParentalControlsService::nsParentalControlsService() : + mEnabled(false) +{ + mozilla::Unused << mEnabled; +} + +nsParentalControlsService::~nsParentalControlsService() +{ +} + +NS_IMETHODIMP +nsParentalControlsService::GetParentalControlsEnabled(bool *aResult) +{ + *aResult = false; + return NS_OK; +} + +NS_IMETHODIMP +nsParentalControlsService::GetBlockFileDownloadsEnabled(bool *aResult) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsParentalControlsService::GetLoggingEnabled(bool *aResult) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsParentalControlsService::Log(int16_t aEntryType, + bool blocked, + nsIURI *aSource, + nsIFile *aTarget) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsParentalControlsService::RequestURIOverride(nsIURI *aTarget, + nsIInterfaceRequestor *aWindowContext, + bool *_retval) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsParentalControlsService::RequestURIOverrides(nsIArray *aTargets, + nsIInterfaceRequestor *aWindowContext, + bool *_retval) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsParentalControlsService::IsAllowed(int16_t aAction, + nsIURI *aUri, + bool *_retval) +{ + return NS_ERROR_NOT_AVAILABLE; +} diff --git a/components/parentalcontrols/nsParentalControlsServiceWin.cpp b/components/parentalcontrols/nsParentalControlsServiceWin.cpp new file mode 100644 index 000000000..e73bb097a --- /dev/null +++ b/components/parentalcontrols/nsParentalControlsServiceWin.cpp @@ -0,0 +1,347 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsParentalControlsService.h" +#include "nsString.h" +#include "nsIArray.h" +#include "nsIWidget.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIFile.h" +#include "nsILocalFileWin.h" +#include "nsArrayUtils.h" +#include "nsIXULAppInfo.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/WindowsVersion.h" + +using namespace mozilla; + +static const CLSID CLSID_WinParentalControls = {0xE77CC89B,0x7401,0x4C04,{0x8C,0xED,0x14,0x9D,0xB3,0x5A,0xDD,0x04}}; +static const IID IID_IWinParentalControls = {0x28B4D88B,0xE072,0x49E6,{0x80,0x4D,0x26,0xED,0xBE,0x21,0xA7,0xB9}}; + +NS_IMPL_ISUPPORTS(nsParentalControlsService, nsIParentalControlsService) + +static HINSTANCE gAdvAPIDLLInst = nullptr; + +decltype(EventWrite)* gEventWrite = nullptr; +decltype(EventRegister)* gEventRegister = nullptr; +decltype(EventUnregister)* gEventUnregister = nullptr; + +nsParentalControlsService::nsParentalControlsService() : + mEnabled(false) +, mProvider(0) +, mPC(nullptr) +{ + HRESULT hr; + CoInitialize(nullptr); + hr = CoCreateInstance(CLSID_WinParentalControls, nullptr, CLSCTX_INPROC, + IID_IWinParentalControls, (void**)&mPC); + if (FAILED(hr)) + return; + + RefPtr<IWPCSettings> wpcs; + if (FAILED(mPC->GetUserSettings(nullptr, getter_AddRefs(wpcs)))) { + // Not available on this os or not enabled for this user account or we're running as admin + mPC->Release(); + mPC = nullptr; + return; + } + + DWORD settings = 0; + wpcs->GetRestrictions(&settings); + + // If we can't determine specifically whether Web Filtering is on/off (i.e. + // we're on Windows < 8), then assume it's on unless no restrictions are set. + bool enable = IsWin8OrLater() ? settings & WPCFLAG_WEB_FILTERED + : settings != WPCFLAG_NO_RESTRICTION; + + if (enable) { + gAdvAPIDLLInst = ::LoadLibrary("Advapi32.dll"); + if(gAdvAPIDLLInst) + { + gEventWrite = (decltype(EventWrite)*) GetProcAddress(gAdvAPIDLLInst, "EventWrite"); + gEventRegister = (decltype(EventRegister)*) GetProcAddress(gAdvAPIDLLInst, "EventRegister"); + gEventUnregister = (decltype(EventUnregister)*) GetProcAddress(gAdvAPIDLLInst, "EventUnregister"); + } + mEnabled = true; + } +} + +nsParentalControlsService::~nsParentalControlsService() +{ + if (mPC) + mPC->Release(); + + if (gEventUnregister && mProvider) + gEventUnregister(mProvider); + + if (gAdvAPIDLLInst) + ::FreeLibrary(gAdvAPIDLLInst); +} + +//------------------------------------------------------------------------ + +NS_IMETHODIMP +nsParentalControlsService::GetParentalControlsEnabled(bool *aResult) +{ + *aResult = false; + + if (mEnabled) + *aResult = true; + + return NS_OK; +} + +NS_IMETHODIMP +nsParentalControlsService::GetBlockFileDownloadsEnabled(bool *aResult) +{ + *aResult = false; + + if (!mEnabled) + return NS_ERROR_NOT_AVAILABLE; + + RefPtr<IWPCWebSettings> wpcws; + if (SUCCEEDED(mPC->GetWebSettings(nullptr, getter_AddRefs(wpcws)))) { + DWORD settings = 0; + wpcws->GetSettings(&settings); + if (settings == WPCFLAG_WEB_SETTING_DOWNLOADSBLOCKED) + *aResult = true; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsParentalControlsService::GetLoggingEnabled(bool *aResult) +{ + *aResult = false; + + if (!mEnabled) + return NS_ERROR_NOT_AVAILABLE; + + // Check the general purpose logging flag + RefPtr<IWPCSettings> wpcs; + if (SUCCEEDED(mPC->GetUserSettings(nullptr, getter_AddRefs(wpcs)))) { + BOOL enabled = FALSE; + wpcs->IsLoggingRequired(&enabled); + if (enabled) + *aResult = true; + } + + return NS_OK; +} + +// Post a log event to the system +NS_IMETHODIMP +nsParentalControlsService::Log(int16_t aEntryType, bool blocked, nsIURI *aSource, nsIFile *aTarget) +{ + if (!mEnabled) + return NS_ERROR_NOT_AVAILABLE; + + NS_ENSURE_ARG_POINTER(aSource); + + // Confirm we should be logging + bool enabled; + GetLoggingEnabled(&enabled); + if (!enabled) + return NS_ERROR_NOT_AVAILABLE; + + // Register a Vista log event provider associated with the parental controls channel. + if (!mProvider) { + if (!gEventRegister) + return NS_ERROR_NOT_AVAILABLE; + if (gEventRegister(&WPCPROV, nullptr, nullptr, &mProvider) != ERROR_SUCCESS) + return NS_ERROR_OUT_OF_MEMORY; + } + + switch(aEntryType) { + case ePCLog_URIVisit: + // Not needed, Vista's web content filter handles this for us + break; + case ePCLog_FileDownload: + LogFileDownload(blocked, aSource, aTarget); + break; + default: + break; + } + + return NS_OK; +} + +// Override a single URI +NS_IMETHODIMP +nsParentalControlsService::RequestURIOverride(nsIURI *aTarget, nsIInterfaceRequestor *aWindowContext, bool *_retval) +{ + *_retval = false; + + if (!mEnabled) + return NS_ERROR_NOT_AVAILABLE; + + NS_ENSURE_ARG_POINTER(aTarget); + + nsAutoCString spec; + aTarget->GetSpec(spec); + if (spec.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + HWND hWnd = nullptr; + // If we have a native window, use its handle instead + nsCOMPtr<nsIWidget> widget(do_GetInterface(aWindowContext)); + if (widget) + hWnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW); + if (hWnd == nullptr) + hWnd = GetDesktopWindow(); + + BOOL ret; + RefPtr<IWPCWebSettings> wpcws; + if (SUCCEEDED(mPC->GetWebSettings(nullptr, getter_AddRefs(wpcws)))) { + wpcws->RequestURLOverride(hWnd, NS_ConvertUTF8toUTF16(spec).get(), + 0, nullptr, &ret); + *_retval = ret; + } + + + return NS_OK; +} + +// Override a web page +NS_IMETHODIMP +nsParentalControlsService::RequestURIOverrides(nsIArray *aTargets, nsIInterfaceRequestor *aWindowContext, bool *_retval) +{ + *_retval = false; + + if (!mEnabled) + return NS_ERROR_NOT_AVAILABLE; + + NS_ENSURE_ARG_POINTER(aTargets); + + uint32_t arrayLength = 0; + aTargets->GetLength(&arrayLength); + if (!arrayLength) + return NS_ERROR_INVALID_ARG; + + if (arrayLength == 1) { + nsCOMPtr<nsIURI> uri = do_QueryElementAt(aTargets, 0); + if (!uri) + return NS_ERROR_INVALID_ARG; + return RequestURIOverride(uri, aWindowContext, _retval); + } + + HWND hWnd = nullptr; + // If we have a native window, use its handle instead + nsCOMPtr<nsIWidget> widget(do_GetInterface(aWindowContext)); + if (widget) + hWnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW); + if (hWnd == nullptr) + hWnd = GetDesktopWindow(); + + // The first entry should be the root uri + nsAutoCString rootSpec; + nsCOMPtr<nsIURI> rootURI = do_QueryElementAt(aTargets, 0); + if (!rootURI) + return NS_ERROR_INVALID_ARG; + + rootURI->GetSpec(rootSpec); + if (rootSpec.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + // Allocate an array of sub uri + int32_t count = arrayLength - 1; + auto arrUrls = MakeUnique<LPCWSTR[]>(count); + + uint32_t uriIdx = 0, idx; + for (idx = 1; idx < arrayLength; idx++) + { + nsCOMPtr<nsIURI> uri = do_QueryElementAt(aTargets, idx); + if (!uri) + continue; + + nsAutoCString subURI; + if (NS_FAILED(uri->GetSpec(subURI))) + continue; + + arrUrls[uriIdx] = (LPCWSTR)UTF8ToNewUnicode(subURI); // allocation + if (!arrUrls[uriIdx]) + continue; + + uriIdx++; + } + + if (!uriIdx) + return NS_ERROR_INVALID_ARG; + + BOOL ret; + RefPtr<IWPCWebSettings> wpcws; + if (SUCCEEDED(mPC->GetWebSettings(nullptr, getter_AddRefs(wpcws)))) { + wpcws->RequestURLOverride(hWnd, NS_ConvertUTF8toUTF16(rootSpec).get(), + uriIdx, (LPCWSTR*)arrUrls.get(), &ret); + *_retval = ret; + } + + // Free up the allocated strings in our array + for (idx = 0; idx < uriIdx; idx++) + free((void*)arrUrls[idx]); + + return NS_OK; +} + +//------------------------------------------------------------------------ + +// Sends a file download event to the Vista Event Log +void +nsParentalControlsService::LogFileDownload(bool blocked, nsIURI *aSource, nsIFile *aTarget) +{ + nsAutoCString curi; + + if (!gEventWrite) + return; + + // Note, EventDataDescCreate is a macro defined in the headers, not a function + + aSource->GetSpec(curi); + nsAutoString uri = NS_ConvertUTF8toUTF16(curi); + + // Get the name of the currently running process + nsCOMPtr<nsIXULAppInfo> appInfo = do_GetService("@mozilla.org/xre/app-info;1"); + nsAutoCString asciiAppName; + if (appInfo) + appInfo->GetName(asciiAppName); + nsAutoString appName = NS_ConvertUTF8toUTF16(asciiAppName); + + static const WCHAR fill[] = L""; + + // See wpcevent.h and msdn for event formats + EVENT_DATA_DESCRIPTOR eventData[WPC_ARGS_FILEDOWNLOADEVENT_CARGS]; + DWORD dwBlocked = blocked; + + EventDataDescCreate(&eventData[WPC_ARGS_FILEDOWNLOADEVENT_URL], (const void*)uri.get(), + ((ULONG)uri.Length()+1)*sizeof(WCHAR)); + EventDataDescCreate(&eventData[WPC_ARGS_FILEDOWNLOADEVENT_APPNAME], (const void*)appName.get(), + ((ULONG)appName.Length()+1)*sizeof(WCHAR)); + EventDataDescCreate(&eventData[WPC_ARGS_FILEDOWNLOADEVENT_VERSION], (const void*)fill, sizeof(fill)); + EventDataDescCreate(&eventData[WPC_ARGS_FILEDOWNLOADEVENT_BLOCKED], (const void*)&dwBlocked, + sizeof(dwBlocked)); + + nsCOMPtr<nsILocalFileWin> local(do_QueryInterface(aTarget)); // May be null + if (local) { + nsAutoString path; + local->GetCanonicalPath(path); + EventDataDescCreate(&eventData[WPC_ARGS_FILEDOWNLOADEVENT_PATH], (const void*)path.get(), + ((ULONG)path.Length()+1)*sizeof(WCHAR)); + } + else { + EventDataDescCreate(&eventData[WPC_ARGS_FILEDOWNLOADEVENT_PATH], (const void*)fill, sizeof(fill)); + } + + gEventWrite(mProvider, &WPCEVENT_WEB_FILEDOWNLOAD, ARRAYSIZE(eventData), eventData); +} + +NS_IMETHODIMP +nsParentalControlsService::IsAllowed(int16_t aAction, + nsIURI *aUri, + bool *_retval) +{ + return NS_ERROR_NOT_AVAILABLE; +} |