diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /dom/plugins/ipc/FunctionBroker.cpp | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/plugins/ipc/FunctionBroker.cpp')
-rw-r--r-- | dom/plugins/ipc/FunctionBroker.cpp | 1429 |
1 files changed, 1429 insertions, 0 deletions
diff --git a/dom/plugins/ipc/FunctionBroker.cpp b/dom/plugins/ipc/FunctionBroker.cpp new file mode 100644 index 0000000000..9068cf322d --- /dev/null +++ b/dom/plugins/ipc/FunctionBroker.cpp @@ -0,0 +1,1429 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "FunctionBroker.h" +#include "FunctionBrokerParent.h" +#include "PluginQuirks.h" + +#if defined(XP_WIN) +# include <commdlg.h> +# include <schannel.h> +# include <sddl.h> +#endif // defined(XP_WIN) + +using namespace mozilla; +using namespace mozilla::ipc; +using namespace mozilla::plugins; + +namespace mozilla::plugins { + +template <int QuirkFlag> +static bool CheckQuirks(int aQuirks) { + return static_cast<bool>(aQuirks & QuirkFlag); +} + +void FreeDestructor(void* aObj) { free(aObj); } + +#if defined(XP_WIN) + +// Specialization of EndpointHandlers for Flash file dialog brokering. +struct FileDlgEHContainer { + template <Endpoint e> + struct EndpointHandler; +}; + +template <> +struct FileDlgEHContainer::EndpointHandler<CLIENT> + : public BaseEndpointHandler<CLIENT, + FileDlgEHContainer::EndpointHandler<CLIENT>> { + using BaseEndpointHandler<CLIENT, EndpointHandler<CLIENT>>::Copy; + + inline static void Copy(OpenFileNameIPC& aDest, const LPOPENFILENAMEW& aSrc) { + aDest.CopyFromOfn(aSrc); + } + inline static void Copy(LPOPENFILENAMEW& aDest, + const OpenFileNameRetIPC& aSrc) { + aSrc.AddToOfn(aDest); + } +}; + +template <> +struct FileDlgEHContainer::EndpointHandler<SERVER> + : public BaseEndpointHandler<SERVER, + FileDlgEHContainer::EndpointHandler<SERVER>> { + using BaseEndpointHandler<SERVER, EndpointHandler<SERVER>>::Copy; + + inline static void Copy(OpenFileNameRetIPC& aDest, + const LPOPENFILENAMEW& aSrc) { + aDest.CopyFromOfn(aSrc); + } + inline static void Copy(ServerCallData* aScd, LPOPENFILENAMEW& aDest, + const OpenFileNameIPC& aSrc) { + MOZ_ASSERT(!aDest); + ServerCallData::DestructorType* destructor = [](void* aObj) { + OpenFileNameIPC::FreeOfnStrings(static_cast<LPOPENFILENAMEW>(aObj)); + DeleteDestructor<OPENFILENAMEW>(aObj); + }; + aDest = aScd->Allocate<OPENFILENAMEW>(destructor); + aSrc.AllocateOfnStrings(aDest); + aSrc.AddToOfn(aDest); + } +}; + +// FunctionBroker type that uses FileDlgEHContainer +template <FunctionHookId functionId, typename FunctionType> +using FileDlgFunctionBroker = + FunctionBroker<functionId, FunctionType, FileDlgEHContainer>; + +// Specialization of EndpointHandlers for Flash SSL brokering. +struct SslEHContainer { + template <Endpoint e> + struct EndpointHandler; +}; + +template <> +struct SslEHContainer::EndpointHandler<CLIENT> + : public BaseEndpointHandler<CLIENT, + SslEHContainer::EndpointHandler<CLIENT>> { + using BaseEndpointHandler<CLIENT, EndpointHandler<CLIENT>>::Copy; + + inline static void Copy(uint64_t& aDest, const PSecHandle& aSrc) { + MOZ_ASSERT((aSrc->dwLower == aSrc->dwUpper) && IsOdd(aSrc->dwLower)); + aDest = static_cast<uint64_t>(aSrc->dwLower); + } + inline static void Copy(PSecHandle& aDest, const uint64_t& aSrc) { + MOZ_ASSERT(IsOdd(aSrc)); + aDest->dwLower = static_cast<ULONG_PTR>(aSrc); + aDest->dwUpper = static_cast<ULONG_PTR>(aSrc); + } + inline static void Copy(IPCSchannelCred& aDest, const PSCHANNEL_CRED& aSrc) { + if (aSrc) { + aDest.CopyFrom(aSrc); + } + } + inline static void Copy(IPCInternetBuffers& aDest, + const LPINTERNET_BUFFERSA& aSrc) { + aDest.CopyFrom(aSrc); + } +}; + +template <> +struct SslEHContainer::EndpointHandler<SERVER> + : public BaseEndpointHandler<SERVER, + SslEHContainer::EndpointHandler<SERVER>> { + using BaseEndpointHandler<SERVER, EndpointHandler<SERVER>>::Copy; + + // PSecHandle is the same thing as PCtxtHandle and PCredHandle. + inline static void Copy(uint64_t& aDest, const PSecHandle& aSrc) { + // If the SecHandle was an error then don't store it. + if (!aSrc) { + aDest = 0; + return; + } + + static uint64_t sNextVal = 1; + UlongPair key(aSrc->dwLower, aSrc->dwUpper); + // Fetch val by reference to update the value in the map + uint64_t& val = sPairToIdMap[key]; + if (val == 0) { + MOZ_ASSERT(IsOdd(sNextVal)); + val = sNextVal; + sIdToPairMap[val] = key; + sNextVal += 2; + } + aDest = val; + } + + // HANDLEs and HINTERNETs marshal with obfuscation (for return values) + inline static void Copy(uint64_t& aDest, void* const& aSrc) { + // If the HANDLE/HINTERNET was an error then don't store it. + if (!aSrc) { + aDest = 0; + return; + } + + static uint64_t sNextVal = 1; + // Fetch val by reference to update the value in the map + uint64_t& val = sPtrToIdMap[aSrc]; + if (val == 0) { + MOZ_ASSERT(IsOdd(sNextVal)); + val = sNextVal; + sIdToPtrMap[val] = aSrc; + sNextVal += 2; + } + aDest = val; + } + + // HANDLEs and HINTERNETs unmarshal with obfuscation + inline static void Copy(void*& aDest, const uint64_t& aSrc) { + aDest = nullptr; + MOZ_RELEASE_ASSERT(IsOdd(aSrc)); + + // If the src is not found in the map then we get aDest == 0 + void* ptr = sIdToPtrMap[aSrc]; + aDest = reinterpret_cast<void*>(ptr); + MOZ_RELEASE_ASSERT(aDest); + } + + inline static void Copy(PSCHANNEL_CRED& aDest, const IPCSchannelCred& aSrc) { + if (aDest) { + aSrc.CopyTo(aDest); + } + } + + inline static void Copy(ServerCallData* aScd, PSecHandle& aDest, + const uint64_t& aSrc) { + MOZ_ASSERT(!aDest); + MOZ_RELEASE_ASSERT(IsOdd(aSrc)); + + // If the src is not found in the map then we get the pair { 0, 0 } + aDest = aScd->Allocate<SecHandle>(); + const UlongPair& pair = sIdToPairMap[aSrc]; + MOZ_RELEASE_ASSERT(pair.first || pair.second); + aDest->dwLower = pair.first; + aDest->dwUpper = pair.second; + } + + inline static void Copy(ServerCallData* aScd, PSCHANNEL_CRED& aDest, + const IPCSchannelCred& aSrc) { + MOZ_ASSERT(!aDest); + aDest = aScd->Allocate<SCHANNEL_CRED>(); + Copy(aDest, aSrc); + } + + inline static void Copy(ServerCallData* aScd, LPINTERNET_BUFFERSA& aDest, + const IPCInternetBuffers& aSrc) { + MOZ_ASSERT(!aDest); + aSrc.CopyTo(aDest); + ServerCallData::DestructorType* destructor = [](void* aObj) { + LPINTERNET_BUFFERSA inetBuf = static_cast<LPINTERNET_BUFFERSA>(aObj); + IPCInternetBuffers::FreeBuffers(inetBuf); + FreeDestructor(inetBuf); + }; + aScd->PostDestructor(aDest, destructor); + } +}; + +// FunctionBroker type that uses SslEHContainer +template <FunctionHookId functionId, typename FunctionType> +using SslFunctionBroker = + FunctionBroker<functionId, FunctionType, SslEHContainer>; + +/* GetKeyState */ + +typedef FunctionBroker<ID_GetKeyState, decltype(GetKeyState)> GetKeyStateFB; + +template <> +ShouldHookFunc* const GetKeyStateFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_GETKEYSTATE>; + +/* SetCursorPos */ + +typedef FunctionBroker<ID_SetCursorPos, decltype(SetCursorPos)> SetCursorPosFB; + +/* GetSaveFileNameW */ + +typedef FileDlgFunctionBroker<ID_GetSaveFileNameW, decltype(GetSaveFileNameW)> + GetSaveFileNameWFB; + +// Remember files granted access in the chrome process +static void GrantFileAccess(base::ProcessId aClientId, LPOPENFILENAME& aLpofn, + bool isSave) { +# if defined(MOZ_SANDBOX) + if (aLpofn->Flags & OFN_ALLOWMULTISELECT) { + // We only support multiselect with the OFN_EXPLORER flag. + // This guarantees that ofn.lpstrFile follows the pattern below. + MOZ_ASSERT(aLpofn->Flags & OFN_EXPLORER); + + // lpstrFile is one of two things: + // 1. A null terminated full path to a file, or + // 2. A path to a folder, followed by a NULL, followed by a + // list of file names, each NULL terminated, followed by an + // additional NULL (so it is also double-NULL terminated). + std::wstring path = std::wstring(aLpofn->lpstrFile); + MOZ_ASSERT(aLpofn->nFileOffset > 0); + // For condition #1, nFileOffset points to the file name in the path. + // It will be preceeded by a non-NULL character from the path. + if (aLpofn->lpstrFile[aLpofn->nFileOffset - 1] != L'\0') { + FunctionBrokerParent::GetSandboxPermissions()->GrantFileAccess( + aClientId, path.c_str(), isSave); + } else { + // This is condition #2 + wchar_t* nextFile = aLpofn->lpstrFile + path.size() + 1; + while (*nextFile != L'\0') { + std::wstring nextFileStr(nextFile); + std::wstring fullPath = path + std::wstring(L"\\") + nextFileStr; + FunctionBrokerParent::GetSandboxPermissions()->GrantFileAccess( + aClientId, fullPath.c_str(), isSave); + nextFile += nextFileStr.size() + 1; + } + } + } else { + FunctionBrokerParent::GetSandboxPermissions()->GrantFileAccess( + aClientId, aLpofn->lpstrFile, isSave); + } +# else + MOZ_ASSERT_UNREACHABLE( + "GetFileName IPC message is only available on " + "Windows builds with sandbox."); +# endif +} + +template <> +template <> +BROKER_DISABLE_CFGUARD BOOL GetSaveFileNameWFB::RunFunction( + GetSaveFileNameWFB::FunctionType* aOrigFunction, base::ProcessId aClientId, + LPOPENFILENAMEW& aLpofn) const { + BOOL result = aOrigFunction(aLpofn); + if (result) { + // Record any file access permission that was just granted. + GrantFileAccess(aClientId, aLpofn, true); + } + return result; +} + +template <> +template <> +struct GetSaveFileNameWFB::Response::Info::ShouldMarshal<0> { + static const bool value = true; +}; + +/* GetOpenFileNameW */ + +typedef FileDlgFunctionBroker<ID_GetOpenFileNameW, decltype(GetOpenFileNameW)> + GetOpenFileNameWFB; + +template <> +template <> +BROKER_DISABLE_CFGUARD BOOL GetOpenFileNameWFB::RunFunction( + GetOpenFileNameWFB::FunctionType* aOrigFunction, base::ProcessId aClientId, + LPOPENFILENAMEW& aLpofn) const { + BOOL result = aOrigFunction(aLpofn); + if (result) { + // Record any file access permission that was just granted. + GrantFileAccess(aClientId, aLpofn, false); + } + return result; +} + +template <> +template <> +struct GetOpenFileNameWFB::Response::Info::ShouldMarshal<0> { + static const bool value = true; +}; + +/* InternetOpenA */ + +typedef SslFunctionBroker<ID_InternetOpenA, decltype(InternetOpenA)> + InternetOpenAFB; + +template <> +ShouldHookFunc* const InternetOpenAFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +/* InternetConnectA */ + +typedef SslFunctionBroker<ID_InternetConnectA, decltype(InternetConnectA)> + InternetConnectAFB; + +template <> +ShouldHookFunc* const InternetConnectAFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef InternetConnectAFB::Request ICAReqHandler; + +template <> +bool ICAReqHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h, + const LPCSTR& srv, const INTERNET_PORT& port, + const LPCSTR& user, const LPCSTR& pass, + const DWORD& svc, const DWORD& flags, + const DWORD_PTR& cxt) { + return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h)); +} + +/* InternetCloseHandle */ + +typedef SslFunctionBroker<ID_InternetCloseHandle, decltype(InternetCloseHandle)> + InternetCloseHandleFB; + +template <> +ShouldHookFunc* const InternetCloseHandleFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef InternetCloseHandleFB::Request ICHReqHandler; + +template <> +bool ICHReqHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h) { + // If we are server side then we were already validated since we had to be + // looked up in the "uint64_t <-> HINTERNET" hashtable. + // In the client, we check that this is a dummy handle. + return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h)); +} + +/* InternetQueryDataAvailable */ + +typedef SslFunctionBroker<ID_InternetQueryDataAvailable, + decltype(InternetQueryDataAvailable)> + InternetQueryDataAvailableFB; + +template <> +ShouldHookFunc* const InternetQueryDataAvailableFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef InternetQueryDataAvailableFB::Request IQDAReq; +typedef InternetQueryDataAvailableFB::RequestDelegate<BOOL HOOK_CALL(HINTERNET)> + IQDADelegateReq; + +template <> +void IQDAReq::Marshal(IpdlTuple& aTuple, const HINTERNET& file, + const LPDWORD& nBytes, const DWORD& flags, + const DWORD_PTR& cxt) { + IQDADelegateReq::Marshal(aTuple, file); +} + +template <> +bool IQDAReq::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, + HINTERNET& file, LPDWORD& nBytes, DWORD& flags, + DWORD_PTR& cxt) { + bool success = IQDADelegateReq::Unmarshal(aScd, aTuple, file); + if (!success) { + return false; + } + flags = 0; + cxt = 0; + nBytes = aScd.Allocate<DWORD>(); + return true; +} + +template <> +bool IQDAReq::ShouldBroker(Endpoint endpoint, const HINTERNET& file, + const LPDWORD& nBytes, const DWORD& flags, + const DWORD_PTR& cxt) { + // If we are server side then we were already validated since we had to be + // looked up in the "uint64_t <-> HINTERNET" hashtable. + // In the client, we check that this is a dummy handle. + return (endpoint == SERVER) || ((flags == 0) && (cxt == 0) && + IsOdd(reinterpret_cast<uint64_t>(file))); +} + +template <> +template <> +struct InternetQueryDataAvailableFB::Response::Info::ShouldMarshal<1> { + static const bool value = true; +}; + +/* InternetReadFile */ + +typedef SslFunctionBroker<ID_InternetReadFile, decltype(InternetReadFile)> + InternetReadFileFB; + +template <> +ShouldHookFunc* const InternetReadFileFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef InternetReadFileFB::Request IRFRequestHandler; +typedef InternetReadFileFB::RequestDelegate<BOOL HOOK_CALL(HINTERNET, DWORD)> + IRFDelegateReq; + +template <> +void IRFRequestHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h, + const LPVOID& buf, const DWORD& nBytesToRead, + const LPDWORD& nBytesRead) { + IRFDelegateReq::Marshal(aTuple, h, nBytesToRead); +} + +template <> +bool IRFRequestHandler::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, + HINTERNET& h, LPVOID& buf, + DWORD& nBytesToRead, LPDWORD& nBytesRead) { + bool ret = IRFDelegateReq::Unmarshal(aScd, aTuple, h, nBytesToRead); + if (!ret) { + return false; + } + + nBytesRead = aScd.Allocate<DWORD>(); + MOZ_ASSERT(nBytesToRead > 0); + aScd.AllocateMemory(nBytesToRead, buf); + return true; +} + +template <> +bool IRFRequestHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h, + const LPVOID& buf, + const DWORD& nBytesToRead, + const LPDWORD& nBytesRead) { + // For server-side validation, the HINTERNET deserialization will have + // required it to already be looked up in the IdToPtrMap. At that point, + // any call is valid. + return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h)); +} + +typedef InternetReadFileFB::Response IRFResponseHandler; +typedef InternetReadFileFB::ResponseDelegate<BOOL HOOK_CALL( + nsDependentCSubstring)> + IRFDelegateResponseHandler; + +// Marshal the output parameter that we sent to the response delegate. +template <> +template <> +struct IRFResponseHandler::Info::ShouldMarshal<0> { + static const bool value = true; +}; + +template <> +void IRFResponseHandler::Marshal(IpdlTuple& aTuple, const BOOL& ret, + const HINTERNET& h, const LPVOID& buf, + const DWORD& nBytesToRead, + const LPDWORD& nBytesRead) { + nsDependentCSubstring str; + if (*nBytesRead) { + str.Assign(static_cast<const char*>(buf), *nBytesRead); + } + IRFDelegateResponseHandler::Marshal(aTuple, ret, str); +} + +template <> +bool IRFResponseHandler::Unmarshal(const IpdlTuple& aTuple, BOOL& ret, + HINTERNET& h, LPVOID& buf, + DWORD& nBytesToRead, LPDWORD& nBytesRead) { + nsDependentCSubstring str; + bool success = IRFDelegateResponseHandler::Unmarshal(aTuple, ret, str); + if (!success) { + return false; + } + + if (str.Length()) { + memcpy(buf, str.Data(), str.Length()); + *nBytesRead = str.Length(); + } + return true; +} + +/* InternetWriteFile */ + +typedef SslFunctionBroker<ID_InternetWriteFile, decltype(InternetWriteFile)> + InternetWriteFileFB; + +template <> +ShouldHookFunc* const InternetWriteFileFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef InternetWriteFileFB::Request IWFReqHandler; +typedef InternetWriteFileFB::RequestDelegate<int HOOK_CALL( + HINTERNET, nsDependentCSubstring)> + IWFDelegateReqHandler; + +template <> +void IWFReqHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& file, + const LPCVOID& buf, const DWORD& nToWrite, + const LPDWORD& nWritten) { + MOZ_ASSERT(nWritten); + IWFDelegateReqHandler::Marshal( + aTuple, file, + nsDependentCSubstring(static_cast<const char*>(buf), nToWrite)); +} + +template <> +bool IWFReqHandler::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, + HINTERNET& file, LPCVOID& buf, DWORD& nToWrite, + LPDWORD& nWritten) { + nsDependentCSubstring str; + if (!IWFDelegateReqHandler::Unmarshal(aScd, aTuple, file, str)) { + return false; + } + + aScd.AllocateString(str, buf, false); + nToWrite = str.Length(); + nWritten = aScd.Allocate<DWORD>(); + return true; +} + +template <> +bool IWFReqHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& file, + const LPCVOID& buf, const DWORD& nToWrite, + const LPDWORD& nWritten) { + // For server-side validation, the HINTERNET deserialization will have + // required it to already be looked up in the IdToPtrMap. At that point, + // any call is valid. + return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(file)); +} + +template <> +template <> +struct InternetWriteFileFB::Response::Info::ShouldMarshal<3> { + static const bool value = true; +}; + +/* InternetSetOptionA */ + +typedef SslFunctionBroker<ID_InternetSetOptionA, decltype(InternetSetOptionA)> + InternetSetOptionAFB; + +template <> +ShouldHookFunc* const InternetSetOptionAFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef InternetSetOptionAFB::Request ISOAReqHandler; +typedef InternetSetOptionAFB::RequestDelegate<BOOL HOOK_CALL( + HINTERNET, DWORD, nsDependentCSubstring)> + ISOADelegateReqHandler; + +template <> +void ISOAReqHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h, + const DWORD& opt, const LPVOID& buf, + const DWORD& bufLen) { + ISOADelegateReqHandler::Marshal( + aTuple, h, opt, + nsDependentCSubstring(static_cast<const char*>(buf), bufLen)); +} + +template <> +bool ISOAReqHandler::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, + HINTERNET& h, DWORD& opt, LPVOID& buf, + DWORD& bufLen) { + nsDependentCSubstring str; + if (!ISOADelegateReqHandler::Unmarshal(aScd, aTuple, h, opt, str)) { + return false; + } + + aScd.AllocateString(str, buf, false); + bufLen = str.Length(); + return true; +} + +template <> +bool ISOAReqHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h, + const DWORD& opt, const LPVOID& buf, + const DWORD& bufLen) { + // For server-side validation, the HINTERNET deserialization will have + // required it to already be looked up in the IdToPtrMap. At that point, + // any call is valid. + return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h)); +} + +/* HttpAddRequestHeadersA */ + +typedef SslFunctionBroker<ID_HttpAddRequestHeadersA, + decltype(HttpAddRequestHeadersA)> + HttpAddRequestHeadersAFB; + +template <> +ShouldHookFunc* const HttpAddRequestHeadersAFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef HttpAddRequestHeadersAFB::Request HARHAReqHandler; + +template <> +bool HARHAReqHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h, + const LPCSTR& head, const DWORD& headLen, + const DWORD& mods) { + // For server-side validation, the HINTERNET deserialization will have + // required it to already be looked up in the IdToPtrMap. At that point, + // any call is valid. + return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h)); +} + +/* HttpOpenRequestA */ + +typedef SslFunctionBroker<ID_HttpOpenRequestA, decltype(HttpOpenRequestA)> + HttpOpenRequestAFB; + +template <> +ShouldHookFunc* const HttpOpenRequestAFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef HttpOpenRequestAFB::Request HORAReqHandler; +typedef HttpOpenRequestAFB::RequestDelegate<HINTERNET HOOK_CALL( + HINTERNET, LPCSTR, LPCSTR, LPCSTR, LPCSTR, CopyableTArray<nsCString>, DWORD, + DWORD_PTR)> + HORADelegateReqHandler; + +template <> +void HORAReqHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h, + const LPCSTR& verb, const LPCSTR& obj, + const LPCSTR& ver, const LPCSTR& ref, + LPCSTR* const& acceptTypes, const DWORD& flags, + const DWORD_PTR& cxt) { + CopyableTArray<nsCString> arrayAcceptTypes; + LPCSTR* curAcceptType = acceptTypes; + if (curAcceptType) { + while (*curAcceptType) { + arrayAcceptTypes.AppendElement(nsCString(*curAcceptType)); + ++curAcceptType; + } + } + // XXX Could we move arrayAcceptTypes here? + HORADelegateReqHandler::Marshal(aTuple, h, verb, obj, ver, ref, + arrayAcceptTypes, flags, cxt); +} + +template <> +bool HORAReqHandler::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, + HINTERNET& h, LPCSTR& verb, LPCSTR& obj, + LPCSTR& ver, LPCSTR& ref, LPCSTR*& acceptTypes, + DWORD& flags, DWORD_PTR& cxt) { + CopyableTArray<nsCString> arrayAcceptTypes; + if (!HORADelegateReqHandler::Unmarshal(aScd, aTuple, h, verb, obj, ver, ref, + arrayAcceptTypes, flags, cxt)) { + return false; + } + if (arrayAcceptTypes.Length() == 0) { + acceptTypes = nullptr; + } else { + aScd.AllocateMemory((arrayAcceptTypes.Length() + 1) * sizeof(LPCSTR), + acceptTypes); + for (size_t i = 0; i < arrayAcceptTypes.Length(); ++i) { + aScd.AllocateString(arrayAcceptTypes[i], acceptTypes[i]); + } + acceptTypes[arrayAcceptTypes.Length()] = nullptr; + } + return true; +} + +template <> +bool HORAReqHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h, + const LPCSTR& verb, const LPCSTR& obj, + const LPCSTR& ver, const LPCSTR& ref, + LPCSTR* const& acceptTypes, + const DWORD& flags, const DWORD_PTR& cxt) { + // For the server-side test, the HINTERNET deserialization will have + // required it to already be looked up in the IdToPtrMap. At that point, + // any call is valid. + return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h)); +} + +/* HttpQueryInfoA */ + +typedef SslFunctionBroker<ID_HttpQueryInfoA, decltype(HttpQueryInfoA)> + HttpQueryInfoAFB; + +template <> +ShouldHookFunc* const HttpQueryInfoAFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef HttpQueryInfoAFB::Request HQIARequestHandler; +typedef HttpQueryInfoAFB::RequestDelegate<BOOL HOOK_CALL(HINTERNET, DWORD, BOOL, + DWORD, BOOL, DWORD)> + HQIADelegateRequestHandler; + +template <> +void HQIARequestHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h, + const DWORD& lvl, const LPVOID& buf, + const LPDWORD& bufLen, const LPDWORD& idx) { + HQIADelegateRequestHandler::Marshal(aTuple, h, lvl, bufLen != nullptr, + bufLen ? *bufLen : 0, idx != nullptr, + idx ? *idx : 0); +} + +template <> +bool HQIARequestHandler::Unmarshal(ServerCallData& aScd, + const IpdlTuple& aTuple, HINTERNET& h, + DWORD& lvl, LPVOID& buf, LPDWORD& bufLen, + LPDWORD& idx) { + BOOL hasBufLen, hasIdx; + DWORD tempBufLen, tempIdx; + bool success = HQIADelegateRequestHandler::Unmarshal( + aScd, aTuple, h, lvl, hasBufLen, tempBufLen, hasIdx, tempIdx); + if (!success) { + return false; + } + + bufLen = nullptr; + if (hasBufLen) { + aScd.AllocateMemory(tempBufLen, buf, bufLen); + } + + idx = nullptr; + if (hasIdx) { + idx = aScd.Allocate<DWORD>(tempIdx); + } + + return true; +} + +template <> +bool HQIARequestHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h, + const DWORD& lvl, const LPVOID& buf, + const LPDWORD& bufLen, + const LPDWORD& idx) { + return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h)); +} + +// Marshal all of the output parameters that we sent to the response delegate. +template <> +template <> +struct HttpQueryInfoAFB::Response::Info::ShouldMarshal<0> { + static const bool value = true; +}; +template <> +template <> +struct HttpQueryInfoAFB::Response::Info::ShouldMarshal<1> { + static const bool value = true; +}; +template <> +template <> +struct HttpQueryInfoAFB::Response::Info::ShouldMarshal<2> { + static const bool value = true; +}; + +typedef HttpQueryInfoAFB::Response HQIAResponseHandler; +typedef HttpQueryInfoAFB::ResponseDelegate<BOOL HOOK_CALL(nsDependentCSubstring, + DWORD, DWORD)> + HQIADelegateResponseHandler; + +template <> +void HQIAResponseHandler::Marshal(IpdlTuple& aTuple, const BOOL& ret, + const HINTERNET& h, const DWORD& lvl, + const LPVOID& buf, const LPDWORD& bufLen, + const LPDWORD& idx) { + nsDependentCSubstring str; + if (buf && ret) { + MOZ_ASSERT(bufLen); + str.Assign(static_cast<const char*>(buf), *bufLen); + } + // Note that we send the bufLen separately to handle the case where buf wasn't + // allocated or large enough to hold the entire return value. bufLen is then + // the required buffer size. + HQIADelegateResponseHandler::Marshal(aTuple, ret, str, bufLen ? *bufLen : 0, + idx ? *idx : 0); +} + +template <> +bool HQIAResponseHandler::Unmarshal(const IpdlTuple& aTuple, BOOL& ret, + HINTERNET& h, DWORD& lvl, LPVOID& buf, + LPDWORD& bufLen, LPDWORD& idx) { + DWORD totalBufLen = *bufLen; + nsDependentCSubstring str; + DWORD tempBufLen, tempIdx; + bool success = HQIADelegateResponseHandler::Unmarshal(aTuple, ret, str, + tempBufLen, tempIdx); + if (!success) { + return false; + } + + if (bufLen) { + *bufLen = tempBufLen; + } + if (idx) { + *idx = tempIdx; + } + + if (buf && ret) { + // When HttpQueryInfo returns strings, the buffer length will not include + // the null terminator. Rather than (brittle-y) trying to determine if the + // return buffer is a string, we always tack on a null terminator if the + // buffer has room for it. + MOZ_ASSERT(str.Length() == *bufLen); + memcpy(buf, str.Data(), str.Length()); + if (str.Length() < totalBufLen) { + char* cbuf = static_cast<char*>(buf); + cbuf[str.Length()] = '\0'; + } + } + return true; +} + +/* HttpSendRequestA */ + +typedef SslFunctionBroker<ID_HttpSendRequestA, decltype(HttpSendRequestA)> + HttpSendRequestAFB; + +template <> +ShouldHookFunc* const HttpSendRequestAFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef HttpSendRequestAFB::Request HSRARequestHandler; +typedef HttpSendRequestAFB::RequestDelegate<BOOL HOOK_CALL( + HINTERNET, nsDependentCSubstring, nsDependentCSubstring)> + HSRADelegateRequestHandler; + +template <> +void HSRARequestHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h, + const LPCSTR& head, const DWORD& headLen, + const LPVOID& opt, const DWORD& optLen) { + nsDependentCSubstring headStr; + headStr.SetIsVoid(head == nullptr); + if (head) { + // HttpSendRequest allows headLen == -1L for length of a null terminated + // string. + DWORD ncHeadLen = headLen; + if (ncHeadLen == -1L) { + ncHeadLen = strlen(head); + } + headStr.Rebind(head, ncHeadLen); + } + nsDependentCSubstring optStr; + optStr.SetIsVoid(opt == nullptr); + if (opt) { + optStr.Rebind(static_cast<const char*>(opt), optLen); + } + HSRADelegateRequestHandler::Marshal(aTuple, h, headStr, optStr); +} + +template <> +bool HSRARequestHandler::Unmarshal(ServerCallData& aScd, + const IpdlTuple& aTuple, HINTERNET& h, + LPCSTR& head, DWORD& headLen, LPVOID& opt, + DWORD& optLen) { + nsDependentCSubstring headStr; + nsDependentCSubstring optStr; + bool success = + HSRADelegateRequestHandler::Unmarshal(aScd, aTuple, h, headStr, optStr); + if (!success) { + return false; + } + + if (headStr.IsVoid()) { + head = nullptr; + MOZ_ASSERT(headLen == 0); + } else { + aScd.AllocateString(headStr, head, false); + headLen = headStr.Length(); + } + + if (optStr.IsVoid()) { + opt = nullptr; + MOZ_ASSERT(optLen == 0); + } else { + aScd.AllocateString(optStr, opt, false); + optLen = optStr.Length(); + } + return true; +} + +template <> +bool HSRARequestHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h, + const LPCSTR& head, const DWORD& headLen, + const LPVOID& opt, const DWORD& optLen) { + // If we are server side then we were already validated since we had to be + // looked up in the "uint64_t <-> HINTERNET" hashtable. + // In the client, we check that this is a dummy handle. + return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h)); +} + +/* HttpSendRequestExA */ + +typedef SslFunctionBroker<ID_HttpSendRequestExA, decltype(HttpSendRequestExA)> + HttpSendRequestExAFB; + +template <> +ShouldHookFunc* const HttpSendRequestExAFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef RequestInfo<ID_HttpSendRequestExA> HSRExAReqInfo; + +template <> +template <> +struct HSRExAReqInfo::FixedValue<2> { + static const LPINTERNET_BUFFERSA value; +}; +const LPINTERNET_BUFFERSA HSRExAReqInfo::FixedValue<2>::value = nullptr; + +// Docs for HttpSendRequestExA say this parameter 'must' be zero but Flash +// passes other values. +// template<> template<> +// struct HSRExAReqInfo::FixedValue<3> { static const DWORD value = 0; }; + +template <> +template <> +struct HSRExAReqInfo::FixedValue<4> { + static const DWORD_PTR value; +}; +const DWORD_PTR HSRExAReqInfo::FixedValue<4>::value = 0; + +/* HttpEndRequestA */ + +typedef SslFunctionBroker<ID_HttpEndRequestA, decltype(HttpEndRequestA)> + HttpEndRequestAFB; + +template <> +ShouldHookFunc* const HttpEndRequestAFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef RequestInfo<ID_HttpEndRequestA> HERAReqInfo; + +template <> +template <> +struct HERAReqInfo::FixedValue<1> { + static const LPINTERNET_BUFFERSA value; +}; +const LPINTERNET_BUFFERSA HERAReqInfo::FixedValue<1>::value = nullptr; + +template <> +template <> +struct HERAReqInfo::FixedValue<2> { + static const DWORD value; +}; +const DWORD HERAReqInfo::FixedValue<2>::value = 0; + +template <> +template <> +struct HERAReqInfo::FixedValue<3> { + static const DWORD_PTR value; +}; +const DWORD_PTR HERAReqInfo::FixedValue<3>::value = 0; + +/* InternetQueryOptionA */ + +typedef SslFunctionBroker<ID_InternetQueryOptionA, + decltype(InternetQueryOptionA)> + InternetQueryOptionAFB; + +template <> +ShouldHookFunc* const InternetQueryOptionAFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef InternetQueryOptionAFB::Request IQOARequestHandler; +typedef InternetQueryOptionAFB::RequestDelegate<BOOL HOOK_CALL(HINTERNET, DWORD, + DWORD)> + IQOADelegateRequestHandler; + +template <> +void IQOARequestHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h, + const DWORD& opt, const LPVOID& buf, + const LPDWORD& bufLen) { + MOZ_ASSERT(bufLen); + IQOADelegateRequestHandler::Marshal(aTuple, h, opt, buf ? *bufLen : 0); +} + +template <> +bool IQOARequestHandler::Unmarshal(ServerCallData& aScd, + const IpdlTuple& aTuple, HINTERNET& h, + DWORD& opt, LPVOID& buf, LPDWORD& bufLen) { + DWORD tempBufLen; + bool success = + IQOADelegateRequestHandler::Unmarshal(aScd, aTuple, h, opt, tempBufLen); + if (!success) { + return false; + } + + aScd.AllocateMemory(tempBufLen, buf, bufLen); + return true; +} + +template <> +bool IQOARequestHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h, + const DWORD& opt, const LPVOID& buf, + const LPDWORD& bufLen) { + // If we are server side then we were already validated since we had to be + // looked up in the "uint64_t <-> HINTERNET" hashtable. + // In the client, we check that this is a dummy handle. + return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h)); +} + +// Marshal all of the output parameters that we sent to the response delegate. +template <> +template <> +struct InternetQueryOptionAFB::Response::Info::ShouldMarshal<0> { + static const bool value = true; +}; +template <> +template <> +struct InternetQueryOptionAFB::Response::Info::ShouldMarshal<1> { + static const bool value = true; +}; + +typedef InternetQueryOptionAFB::Response IQOAResponseHandler; +typedef InternetQueryOptionAFB::ResponseDelegate<BOOL HOOK_CALL( + nsDependentCSubstring, DWORD)> + IQOADelegateResponseHandler; + +template <> +void IQOAResponseHandler::Marshal(IpdlTuple& aTuple, const BOOL& ret, + const HINTERNET& h, const DWORD& opt, + const LPVOID& buf, const LPDWORD& bufLen) { + nsDependentCSubstring str; + if (buf && ret) { + MOZ_ASSERT(*bufLen); + str.Assign(static_cast<const char*>(buf), *bufLen); + } + IQOADelegateResponseHandler::Marshal(aTuple, ret, str, *bufLen); +} + +template <> +bool IQOAResponseHandler::Unmarshal(const IpdlTuple& aTuple, BOOL& ret, + HINTERNET& h, DWORD& opt, LPVOID& buf, + LPDWORD& bufLen) { + nsDependentCSubstring str; + bool success = + IQOADelegateResponseHandler::Unmarshal(aTuple, ret, str, *bufLen); + if (!success) { + return false; + } + + if (buf && ret) { + MOZ_ASSERT(str.Length() == *bufLen); + memcpy(buf, str.Data(), str.Length()); + } + return true; +} + +/* InternetErrorDlg */ + +typedef SslFunctionBroker<ID_InternetErrorDlg, decltype(InternetErrorDlg)> + InternetErrorDlgFB; + +template <> +ShouldHookFunc* const InternetErrorDlgFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef RequestInfo<ID_InternetErrorDlg> IEDReqInfo; + +template <> +template <> +struct IEDReqInfo::FixedValue<4> { + static LPVOID* const value; +}; +LPVOID* const IEDReqInfo::FixedValue<4>::value = nullptr; + +typedef InternetErrorDlgFB::Request IEDReqHandler; + +template <> +bool IEDReqHandler::ShouldBroker(Endpoint endpoint, const HWND& hwnd, + const HINTERNET& h, const DWORD& err, + const DWORD& flags, LPVOID* const& data) { + const DWORD SUPPORTED_FLAGS = + FLAGS_ERROR_UI_FILTER_FOR_ERRORS | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS | + FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_NO_UI; + + // We broker if (1) the handle h is brokered (odd in client), + // (2) we support the requested action flags and (3) there is no user + // data, which wouldn't make sense for our supported flags anyway. + return ((endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h))) && + (!(flags & ~SUPPORTED_FLAGS)) && (data == nullptr); +} + +/* AcquireCredentialsHandleA */ + +typedef SslFunctionBroker<ID_AcquireCredentialsHandleA, + decltype(AcquireCredentialsHandleA)> + AcquireCredentialsHandleAFB; + +template <> +ShouldHookFunc* const AcquireCredentialsHandleAFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef RequestInfo<ID_AcquireCredentialsHandleA> ACHAReqInfo; + +template <> +template <> +struct ACHAReqInfo::FixedValue<0> { + static const LPSTR value; +}; +const LPSTR ACHAReqInfo::FixedValue<0>::value = nullptr; + +template <> +template <> +struct ACHAReqInfo::FixedValue<1> { + static const LPSTR value; +}; +const LPSTR ACHAReqInfo::FixedValue<1>::value = + const_cast<char*>(UNISP_NAME_A); // -Wwritable-strings + +template <> +template <> +struct ACHAReqInfo::FixedValue<2> { + static const unsigned long value; +}; +const unsigned long ACHAReqInfo::FixedValue<2>::value = SECPKG_CRED_OUTBOUND; + +template <> +template <> +struct ACHAReqInfo::FixedValue<3> { + static void* const value; +}; +void* const ACHAReqInfo::FixedValue<3>::value = nullptr; + +template <> +template <> +struct ACHAReqInfo::FixedValue<5> { + static const SEC_GET_KEY_FN value; +}; +const SEC_GET_KEY_FN ACHAReqInfo::FixedValue<5>::value = nullptr; + +template <> +template <> +struct ACHAReqInfo::FixedValue<6> { + static void* const value; +}; +void* const ACHAReqInfo::FixedValue<6>::value = nullptr; + +typedef AcquireCredentialsHandleAFB::Request ACHARequestHandler; +typedef AcquireCredentialsHandleAFB::RequestDelegate<SECURITY_STATUS HOOK_CALL( + LPSTR, LPSTR, unsigned long, void*, PSCHANNEL_CRED, SEC_GET_KEY_FN, void*)> + ACHADelegateRequestHandler; + +template <> +void ACHARequestHandler::Marshal(IpdlTuple& aTuple, const LPSTR& principal, + const LPSTR& pkg, const unsigned long& credUse, + const PVOID& logonId, const PVOID& auth, + const SEC_GET_KEY_FN& getKeyFn, + const PVOID& getKeyArg, + const PCredHandle& cred, + const PTimeStamp& expiry) { + const PSCHANNEL_CRED& scCred = reinterpret_cast<const PSCHANNEL_CRED&>(auth); + ACHADelegateRequestHandler::Marshal(aTuple, principal, pkg, credUse, logonId, + scCred, getKeyFn, getKeyArg); +} + +template <> +bool ACHARequestHandler::Unmarshal(ServerCallData& aScd, + const IpdlTuple& aTuple, LPSTR& principal, + LPSTR& pkg, unsigned long& credUse, + PVOID& logonId, PVOID& auth, + SEC_GET_KEY_FN& getKeyFn, PVOID& getKeyArg, + PCredHandle& cred, PTimeStamp& expiry) { + PSCHANNEL_CRED& scCred = reinterpret_cast<PSCHANNEL_CRED&>(auth); + if (!ACHADelegateRequestHandler::Unmarshal(aScd, aTuple, principal, pkg, + credUse, logonId, scCred, getKeyFn, + getKeyArg)) { + return false; + } + + cred = aScd.Allocate<CredHandle>(); + expiry = aScd.Allocate<::TimeStamp>(); + return true; +} + +typedef ResponseInfo<ID_AcquireCredentialsHandleA> ACHARspInfo; + +// Response phase must send output parameters +template <> +template <> +struct ACHARspInfo::ShouldMarshal<7> { + static const bool value = true; +}; +template <> +template <> +struct ACHARspInfo::ShouldMarshal<8> { + static const bool value = true; +}; + +/* QueryCredentialsAttributesA */ + +typedef SslFunctionBroker<ID_QueryCredentialsAttributesA, + decltype(QueryCredentialsAttributesA)> + QueryCredentialsAttributesAFB; + +template <> +ShouldHookFunc* const QueryCredentialsAttributesAFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +/* FreeCredentialsHandle */ + +typedef SslFunctionBroker<ID_FreeCredentialsHandle, + decltype(FreeCredentialsHandle)> + FreeCredentialsHandleFB; + +template <> +ShouldHookFunc* const FreeCredentialsHandleFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_SSL>; + +typedef FreeCredentialsHandleFB::Request FCHReq; + +template <> +bool FCHReq::ShouldBroker(Endpoint endpoint, const PCredHandle& h) { + // If we are server side then we were already validated since we had to be + // looked up in the "uint64_t <-> CredHandle" hashtable. + // In the client, we check that this is a dummy handle. + return (endpoint == SERVER) || ((h->dwLower == h->dwUpper) && + IsOdd(static_cast<uint64_t>(h->dwLower))); +} + +/* CreateMutexW */ + +// Get the user's SID as a string. Returns an empty string on failure. +static std::wstring GetUserSid() { + std::wstring ret; + // Get user SID from process token information + HANDLE token; + BOOL success = ::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token); + if (!success) { + return ret; + } + DWORD bufLen; + success = ::GetTokenInformation(token, TokenUser, nullptr, 0, &bufLen); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + return ret; + } + void* buf = malloc(bufLen); + success = ::GetTokenInformation(token, TokenUser, buf, bufLen, &bufLen); + MOZ_ASSERT(success); + if (success) { + TOKEN_USER* tokenUser = static_cast<TOKEN_USER*>(buf); + PSID sid = tokenUser->User.Sid; + LPWSTR sidStr; + success = ::ConvertSidToStringSid(sid, &sidStr); + if (success) { + ret = sidStr; + ::LocalFree(sidStr); + } + } + free(buf); + ::CloseHandle(token); + return ret; +} + +// Get the name Windows uses for the camera mutex. Returns an empty string +// on failure. +// The camera mutex is identified in Windows code using a hard-coded GUID +// string, "eed3bd3a-a1ad-4e99-987b-d7cb3fcfa7f0", and the user's SID. The GUID +// value was determined by investigating Windows code. It is referenced in +// CCreateSwEnum::CCreateSwEnum(void) in devenum.dll. +static std::wstring GetCameraMutexName() { + std::wstring userSid = GetUserSid(); + if (userSid.empty()) { + return userSid; + } + return std::wstring(L"eed3bd3a-a1ad-4e99-987b-d7cb3fcfa7f0 - ") + userSid; +} + +typedef FunctionBroker<ID_CreateMutexW, decltype(CreateMutexW)> CreateMutexWFB; + +template <> +ShouldHookFunc* const CreateMutexWFB::BaseType::mShouldHook = + &CheckQuirks<QUIRK_FLASH_HOOK_CREATEMUTEXW>; + +typedef CreateMutexWFB::Request CMWReqHandler; +typedef CMWReqHandler::Info CMWReqInfo; +typedef CreateMutexWFB::Response CMWRspHandler; + +template <> +bool CMWReqHandler::ShouldBroker(Endpoint endpoint, + const LPSECURITY_ATTRIBUTES& aAttribs, + const BOOL& aOwner, const LPCWSTR& aName) { + // Statically hold the camera mutex name so that we dont recompute it for + // every CreateMutexW call in the client process. + static std::wstring camMutexName = GetCameraMutexName(); + + // Only broker if we are requesting the camera mutex. Note that we only + // need to check that the client is actually requesting the camera. The + // command is always valid on the server as long as we can construct the + // mutex name. + if (endpoint == SERVER) { + return !camMutexName.empty(); + } + + return (!aOwner) && aName && (!camMutexName.empty()) && + (camMutexName == aName); +} + +// We dont need to marshal any parameters. We construct all of them +// server-side. +template <> +template <> +struct CMWReqInfo::ShouldMarshal<0> { + static const bool value = false; +}; +template <> +template <> +struct CMWReqInfo::ShouldMarshal<1> { + static const bool value = false; +}; +template <> +template <> +struct CMWReqInfo::ShouldMarshal<2> { + static const bool value = false; +}; + +template <> +template <> +BROKER_DISABLE_CFGUARD HANDLE CreateMutexWFB::RunFunction( + CreateMutexWFB::FunctionType* aOrigFunction, base::ProcessId aClientId, + LPSECURITY_ATTRIBUTES& aAttribs, BOOL& aOwner, LPCWSTR& aName) const { + // Use CreateMutexW to get the camera mutex and DuplicateHandle to open it + // for use in the child process. + // Recall that aAttribs, aOwner and aName are all unmarshaled so they are + // unassigned garbage. + SECURITY_ATTRIBUTES mutexAttrib = {sizeof(SECURITY_ATTRIBUTES), + nullptr /* ignored */, TRUE}; + std::wstring camMutexName = GetCameraMutexName(); + if (camMutexName.empty()) { + return 0; + } + HANDLE serverMutex = + ::CreateMutexW(&mutexAttrib, FALSE, camMutexName.c_str()); + if (serverMutex == 0) { + return 0; + } + ScopedProcessHandle clientProcHandle; + if (!base::OpenProcessHandle(aClientId, &clientProcHandle.rwget())) { + return 0; + } + HANDLE ret; + if (!::DuplicateHandle(::GetCurrentProcess(), serverMutex, clientProcHandle, + &ret, SYNCHRONIZE, FALSE, DUPLICATE_CLOSE_SOURCE)) { + return 0; + } + return ret; +} + +#endif // defined(XP_WIN) + +/*****************************************************************************/ + +#define FUN_HOOK(x) static_cast<FunctionHook*>(x) +void AddBrokeredFunctionHooks(FunctionHookArray& aHooks) { + // We transfer ownership of the FunctionHook objects to the array. +#if defined(XP_WIN) + aHooks[ID_GetKeyState] = + FUN_HOOK(new GetKeyStateFB("user32.dll", "GetKeyState", &GetKeyState)); + aHooks[ID_SetCursorPos] = + FUN_HOOK(new SetCursorPosFB("user32.dll", "SetCursorPos", &SetCursorPos)); + aHooks[ID_GetSaveFileNameW] = FUN_HOOK(new GetSaveFileNameWFB( + "comdlg32.dll", "GetSaveFileNameW", &GetSaveFileNameW)); + aHooks[ID_GetOpenFileNameW] = FUN_HOOK(new GetOpenFileNameWFB( + "comdlg32.dll", "GetOpenFileNameW", &GetOpenFileNameW)); + aHooks[ID_InternetOpenA] = FUN_HOOK( + new InternetOpenAFB("wininet.dll", "InternetOpenA", &InternetOpenA)); + aHooks[ID_InternetConnectA] = FUN_HOOK(new InternetConnectAFB( + "wininet.dll", "InternetConnectA", &InternetConnectA)); + aHooks[ID_InternetCloseHandle] = FUN_HOOK(new InternetCloseHandleFB( + "wininet.dll", "InternetCloseHandle", &InternetCloseHandle)); + aHooks[ID_InternetQueryDataAvailable] = + FUN_HOOK(new InternetQueryDataAvailableFB("wininet.dll", + "InternetQueryDataAvailable", + &InternetQueryDataAvailable)); + aHooks[ID_InternetReadFile] = FUN_HOOK(new InternetReadFileFB( + "wininet.dll", "InternetReadFile", &InternetReadFile)); + aHooks[ID_InternetWriteFile] = FUN_HOOK(new InternetWriteFileFB( + "wininet.dll", "InternetWriteFile", &InternetWriteFile)); + aHooks[ID_InternetSetOptionA] = FUN_HOOK(new InternetSetOptionAFB( + "wininet.dll", "InternetSetOptionA", &InternetSetOptionA)); + aHooks[ID_HttpAddRequestHeadersA] = FUN_HOOK(new HttpAddRequestHeadersAFB( + "wininet.dll", "HttpAddRequestHeadersA", &HttpAddRequestHeadersA)); + aHooks[ID_HttpOpenRequestA] = FUN_HOOK(new HttpOpenRequestAFB( + "wininet.dll", "HttpOpenRequestA", &HttpOpenRequestA)); + aHooks[ID_HttpQueryInfoA] = FUN_HOOK( + new HttpQueryInfoAFB("wininet.dll", "HttpQueryInfoA", &HttpQueryInfoA)); + aHooks[ID_HttpSendRequestA] = FUN_HOOK(new HttpSendRequestAFB( + "wininet.dll", "HttpSendRequestA", &HttpSendRequestA)); + aHooks[ID_HttpSendRequestExA] = FUN_HOOK(new HttpSendRequestExAFB( + "wininet.dll", "HttpSendRequestExA", &HttpSendRequestExA)); + aHooks[ID_HttpEndRequestA] = FUN_HOOK(new HttpEndRequestAFB( + "wininet.dll", "HttpEndRequestA", &HttpEndRequestA)); + aHooks[ID_InternetQueryOptionA] = FUN_HOOK(new InternetQueryOptionAFB( + "wininet.dll", "InternetQueryOptionA", &InternetQueryOptionA)); + aHooks[ID_InternetErrorDlg] = FUN_HOOK(new InternetErrorDlgFB( + "wininet.dll", "InternetErrorDlg", InternetErrorDlg)); + aHooks[ID_AcquireCredentialsHandleA] = + FUN_HOOK(new AcquireCredentialsHandleAFB("sspicli.dll", + "AcquireCredentialsHandleA", + &AcquireCredentialsHandleA)); + aHooks[ID_QueryCredentialsAttributesA] = + FUN_HOOK(new QueryCredentialsAttributesAFB("sspicli.dll", + "QueryCredentialsAttributesA", + &QueryCredentialsAttributesA)); + aHooks[ID_FreeCredentialsHandle] = FUN_HOOK(new FreeCredentialsHandleFB( + "sspicli.dll", "FreeCredentialsHandle", &FreeCredentialsHandle)); + aHooks[ID_CreateMutexW] = FUN_HOOK( + new CreateMutexWFB("kernel32.dll", "CreateMutexW", &CreateMutexW)); +#endif // defined(XP_WIN) +} + +#undef FUN_HOOK + +} // namespace mozilla::plugins |