diff options
Diffstat (limited to 'dom/plugins/ipc/FunctionBrokerIPCUtils.cpp')
-rw-r--r-- | dom/plugins/ipc/FunctionBrokerIPCUtils.cpp | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/dom/plugins/ipc/FunctionBrokerIPCUtils.cpp b/dom/plugins/ipc/FunctionBrokerIPCUtils.cpp new file mode 100644 index 0000000000..e0ee31e635 --- /dev/null +++ b/dom/plugins/ipc/FunctionBrokerIPCUtils.cpp @@ -0,0 +1,334 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8; -*- */ +/* vim: set sw=2 ts=8 et 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 "FunctionBrokerIPCUtils.h" + +#if defined(XP_WIN) + +# include <schannel.h> + +/* these defines are missing from mingw headers */ +# ifndef SP_PROT_TLS1_1_CLIENT +# define SP_PROT_TLS1_1_CLIENT 0x00000200 +# endif + +# ifndef SP_PROT_TLS1_2_CLIENT +# define SP_PROT_TLS1_2_CLIENT 0x00000800 +# endif + +namespace mozilla { +namespace plugins { + +mozilla::LazyLogModule sPluginHooksLog("PluginHooks"); + +static const DWORD SCHANNEL_SUPPORTED_PROTOCOLS = + SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT; + +static const DWORD SCHANNEL_SUPPORTED_FLAGS = + SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS | + SCH_CRED_REVOCATION_CHECK_END_CERT; + +void OpenFileNameIPC::CopyFromOfn(LPOPENFILENAMEW aLpofn) { + mHwndOwner = nullptr; + + // Filter is double-NULL terminated. mFilter should include the double-NULL. + mHasFilter = aLpofn->lpstrFilter != nullptr; + if (mHasFilter) { + uint32_t dNullIdx = 0; + while (aLpofn->lpstrFilter[dNullIdx] != L'\0' || + aLpofn->lpstrFilter[dNullIdx + 1] != L'\0') { + dNullIdx++; + } + mFilter.assign(aLpofn->lpstrFilter, dNullIdx + 2); + } + mHasCustomFilter = aLpofn->lpstrCustomFilter != nullptr; + if (mHasCustomFilter) { + mCustomFilterIn = std::wstring(aLpofn->lpstrCustomFilter); + mNMaxCustFilterOut = + aLpofn->nMaxCustFilter - (wcslen(aLpofn->lpstrCustomFilter) + 1); + } else { + mNMaxCustFilterOut = 0; + } + mFilterIndex = aLpofn->nFilterIndex; + mFile = std::wstring(aLpofn->lpstrFile); + mNMaxFile = aLpofn->nMaxFile; + mNMaxFileTitle = + aLpofn->lpstrFileTitle != nullptr ? aLpofn->nMaxFileTitle : 0; + mHasInitialDir = aLpofn->lpstrInitialDir != nullptr; + if (mHasInitialDir) { + mInitialDir = std::wstring(aLpofn->lpstrInitialDir); + } + mHasTitle = aLpofn->lpstrTitle != nullptr; + if (mHasTitle) { + mTitle = std::wstring(aLpofn->lpstrTitle); + } + mHasDefExt = aLpofn->lpstrDefExt != nullptr; + if (mHasDefExt) { + mDefExt = std::wstring(aLpofn->lpstrDefExt); + } + + mFlags = aLpofn->Flags; + // If the user sets OFN_ALLOWMULTISELECT then we require OFN_EXPLORER + // as well. Without OFN_EXPLORER, the method has ancient legacy + // behavior that we don't support. + MOZ_ASSERT((mFlags & OFN_EXPLORER) || !(mFlags & OFN_ALLOWMULTISELECT)); + + // We ignore any visual customization and callbacks that the user set. + mFlags &= ~(OFN_ENABLEHOOK | OFN_ENABLETEMPLATEHANDLE | OFN_ENABLETEMPLATE); + + mFlagsEx = aLpofn->FlagsEx; +} + +void OpenFileNameIPC::AddToOfn(LPOPENFILENAMEW aLpofn) const { + aLpofn->lStructSize = sizeof(OPENFILENAMEW); + aLpofn->hwndOwner = mHwndOwner; + if (mHasFilter) { + memcpy(const_cast<LPWSTR>(aLpofn->lpstrFilter), mFilter.data(), + mFilter.size() * sizeof(wchar_t)); + } + if (mHasCustomFilter) { + aLpofn->nMaxCustFilter = mCustomFilterIn.size() + 1 + mNMaxCustFilterOut; + wcscpy(aLpofn->lpstrCustomFilter, mCustomFilterIn.c_str()); + memset(aLpofn->lpstrCustomFilter + mCustomFilterIn.size() + 1, 0, + mNMaxCustFilterOut * sizeof(wchar_t)); + } else { + aLpofn->nMaxCustFilter = 0; + } + aLpofn->nFilterIndex = mFilterIndex; + if (mNMaxFile > 0) { + wcsncpy(aLpofn->lpstrFile, mFile.c_str(), + std::min(static_cast<uint32_t>(mFile.size() + 1), mNMaxFile)); + aLpofn->lpstrFile[mNMaxFile - 1] = L'\0'; + } + aLpofn->nMaxFile = mNMaxFile; + aLpofn->nMaxFileTitle = mNMaxFileTitle; + if (mHasInitialDir) { + wcscpy(const_cast<LPWSTR>(aLpofn->lpstrInitialDir), mInitialDir.c_str()); + } + if (mHasTitle) { + wcscpy(const_cast<LPWSTR>(aLpofn->lpstrTitle), mTitle.c_str()); + } + aLpofn->Flags = mFlags; /* TODO: Consider adding OFN_NOCHANGEDIR */ + if (mHasDefExt) { + wcscpy(const_cast<LPWSTR>(aLpofn->lpstrDefExt), mDefExt.c_str()); + } + aLpofn->FlagsEx = mFlagsEx; +} + +void OpenFileNameIPC::AllocateOfnStrings(LPOPENFILENAMEW aLpofn) const { + if (mHasFilter) { + // mFilter is double-NULL terminated and it includes the double-NULL in its + // length. + aLpofn->lpstrFilter = + static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mFilter.size()))); + } + if (mHasCustomFilter) { + aLpofn->lpstrCustomFilter = static_cast<LPTSTR>(moz_xmalloc( + sizeof(wchar_t) * (mCustomFilterIn.size() + 1 + mNMaxCustFilterOut))); + } + aLpofn->lpstrFile = + static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * mNMaxFile)); + if (mNMaxFileTitle > 0) { + aLpofn->lpstrFileTitle = + static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * mNMaxFileTitle)); + } + if (mHasInitialDir) { + aLpofn->lpstrInitialDir = static_cast<LPCTSTR>( + moz_xmalloc(sizeof(wchar_t) * (mInitialDir.size() + 1))); + } + if (mHasTitle) { + aLpofn->lpstrTitle = static_cast<LPCTSTR>( + moz_xmalloc(sizeof(wchar_t) * (mTitle.size() + 1))); + } + if (mHasDefExt) { + aLpofn->lpstrDefExt = static_cast<LPCTSTR>( + moz_xmalloc(sizeof(wchar_t) * (mDefExt.size() + 1))); + } +} + +// static +void OpenFileNameIPC::FreeOfnStrings(LPOPENFILENAMEW aLpofn) { + if (aLpofn->lpstrFilter) { + free(const_cast<LPWSTR>(aLpofn->lpstrFilter)); + } + if (aLpofn->lpstrCustomFilter) { + free(aLpofn->lpstrCustomFilter); + } + if (aLpofn->lpstrFile) { + free(aLpofn->lpstrFile); + } + if (aLpofn->lpstrFileTitle) { + free(aLpofn->lpstrFileTitle); + } + if (aLpofn->lpstrInitialDir) { + free(const_cast<LPWSTR>(aLpofn->lpstrInitialDir)); + } + if (aLpofn->lpstrTitle) { + free(const_cast<LPWSTR>(aLpofn->lpstrTitle)); + } + if (aLpofn->lpstrDefExt) { + free(const_cast<LPWSTR>(aLpofn->lpstrDefExt)); + } +} + +void OpenFileNameRetIPC::CopyFromOfn(LPOPENFILENAMEW aLpofn) { + if (aLpofn->lpstrCustomFilter != nullptr) { + mCustomFilterOut = std::wstring(aLpofn->lpstrCustomFilter + + wcslen(aLpofn->lpstrCustomFilter) + 1); + } + mFile.assign(aLpofn->lpstrFile, aLpofn->nMaxFile); + if (aLpofn->lpstrFileTitle != nullptr) { + mFileTitle.assign(aLpofn->lpstrFileTitle, + wcslen(aLpofn->lpstrFileTitle) + 1); + } + mFileOffset = aLpofn->nFileOffset; + mFileExtension = aLpofn->nFileExtension; +} + +void OpenFileNameRetIPC::AddToOfn(LPOPENFILENAMEW aLpofn) const { + if (aLpofn->lpstrCustomFilter) { + LPWSTR secondString = + aLpofn->lpstrCustomFilter + wcslen(aLpofn->lpstrCustomFilter) + 1; + const wchar_t* customFilterOut = mCustomFilterOut.c_str(); + MOZ_ASSERT(wcslen(aLpofn->lpstrCustomFilter) + 1 + wcslen(customFilterOut) + + 1 + 1 <= + aLpofn->nMaxCustFilter); + wcscpy(secondString, customFilterOut); + secondString[wcslen(customFilterOut) + 1] = + L'\0'; // terminated with two NULLs + } + MOZ_ASSERT(mFile.size() <= aLpofn->nMaxFile); + memcpy(aLpofn->lpstrFile, mFile.data(), mFile.size() * sizeof(wchar_t)); + if (aLpofn->lpstrFileTitle != nullptr) { + MOZ_ASSERT(mFileTitle.size() + 1 < aLpofn->nMaxFileTitle); + wcscpy(aLpofn->lpstrFileTitle, mFileTitle.c_str()); + } + aLpofn->nFileOffset = mFileOffset; + aLpofn->nFileExtension = mFileExtension; +} + +void IPCSchannelCred::CopyFrom(const PSCHANNEL_CRED& aSCred) { + // We assert that the aSCred fields take supported values. + // If they do not then we ignore the values we were given. + MOZ_ASSERT(aSCred->dwVersion == SCHANNEL_CRED_VERSION); + MOZ_ASSERT(aSCred->cCreds == 0); + MOZ_ASSERT(aSCred->paCred == nullptr); + MOZ_ASSERT(aSCred->hRootStore == nullptr); + MOZ_ASSERT(aSCred->cMappers == 0); + MOZ_ASSERT(aSCred->aphMappers == nullptr); + MOZ_ASSERT(aSCred->cSupportedAlgs == 0); + MOZ_ASSERT(aSCred->palgSupportedAlgs == nullptr); + MOZ_ASSERT((aSCred->grbitEnabledProtocols & SCHANNEL_SUPPORTED_PROTOCOLS) == + aSCred->grbitEnabledProtocols); + mEnabledProtocols = + aSCred->grbitEnabledProtocols & SCHANNEL_SUPPORTED_PROTOCOLS; + mMinStrength = aSCred->dwMinimumCipherStrength; + mMaxStrength = aSCred->dwMaximumCipherStrength; + MOZ_ASSERT(aSCred->dwSessionLifespan == 0); + MOZ_ASSERT((aSCred->dwFlags & SCHANNEL_SUPPORTED_FLAGS) == aSCred->dwFlags); + mFlags = aSCred->dwFlags & SCHANNEL_SUPPORTED_FLAGS; + MOZ_ASSERT(aSCred->dwCredFormat == 0); +} + +void IPCSchannelCred::CopyTo(PSCHANNEL_CRED& aSCred) const { + // Validate values as they come from an untrusted process. + memset(aSCred, 0, sizeof(SCHANNEL_CRED)); + aSCred->dwVersion = SCHANNEL_CRED_VERSION; + aSCred->grbitEnabledProtocols = + mEnabledProtocols & SCHANNEL_SUPPORTED_PROTOCOLS; + aSCred->dwMinimumCipherStrength = mMinStrength; + aSCred->dwMaximumCipherStrength = mMaxStrength; + aSCred->dwFlags = mFlags & SCHANNEL_SUPPORTED_FLAGS; +} + +void IPCInternetBuffers::CopyFrom(const LPINTERNET_BUFFERSA& aBufs) { + mBuffers.Clear(); + + LPINTERNET_BUFFERSA inetBuf = aBufs; + while (inetBuf) { + MOZ_ASSERT(inetBuf->dwStructSize == sizeof(INTERNET_BUFFERSA)); + Buffer* ipcBuf = mBuffers.AppendElement(); + + ipcBuf->mHeader.SetIsVoid(inetBuf->lpcszHeader == nullptr); + if (inetBuf->lpcszHeader) { + ipcBuf->mHeader.Assign(inetBuf->lpcszHeader, inetBuf->dwHeadersLength); + } + ipcBuf->mHeaderTotal = inetBuf->dwHeadersTotal; + + ipcBuf->mBuffer.SetIsVoid(inetBuf->lpvBuffer == nullptr); + if (inetBuf->lpvBuffer) { + ipcBuf->mBuffer.Assign(static_cast<char*>(inetBuf->lpvBuffer), + inetBuf->dwBufferLength); + } + ipcBuf->mBufferTotal = inetBuf->dwBufferTotal; + inetBuf = inetBuf->Next; + } +} + +void IPCInternetBuffers::CopyTo(LPINTERNET_BUFFERSA& aBufs) const { + MOZ_ASSERT(!aBufs); + + LPINTERNET_BUFFERSA lastBuf = nullptr; + for (size_t idx = 0; idx < mBuffers.Length(); ++idx) { + const Buffer& ipcBuf = mBuffers[idx]; + LPINTERNET_BUFFERSA newBuf = static_cast<LPINTERNET_BUFFERSA>( + moz_xcalloc(1, sizeof(INTERNET_BUFFERSA))); + if (idx == 0) { + aBufs = newBuf; + } else { + MOZ_ASSERT(lastBuf); + lastBuf->Next = newBuf; + lastBuf = newBuf; + } + + newBuf->dwStructSize = sizeof(INTERNET_BUFFERSA); + + newBuf->dwHeadersTotal = ipcBuf.mHeaderTotal; + if (!ipcBuf.mHeader.IsVoid()) { + newBuf->lpcszHeader = + static_cast<LPCSTR>(moz_xmalloc(ipcBuf.mHeader.Length())); + memcpy(const_cast<char*>(newBuf->lpcszHeader), ipcBuf.mHeader.Data(), + ipcBuf.mHeader.Length()); + newBuf->dwHeadersLength = ipcBuf.mHeader.Length(); + } + + newBuf->dwBufferTotal = ipcBuf.mBufferTotal; + if (!ipcBuf.mBuffer.IsVoid()) { + newBuf->lpvBuffer = moz_xmalloc(ipcBuf.mBuffer.Length()); + memcpy(newBuf->lpvBuffer, ipcBuf.mBuffer.Data(), ipcBuf.mBuffer.Length()); + newBuf->dwBufferLength = ipcBuf.mBuffer.Length(); + } + } +} + +/* static */ +void IPCInternetBuffers::FreeBuffers(LPINTERNET_BUFFERSA& aBufs) { + if (!aBufs) { + return; + } + while (aBufs) { + LPINTERNET_BUFFERSA temp = aBufs->Next; + free(const_cast<char*>(aBufs->lpcszHeader)); + free(aBufs->lpvBuffer); + free(aBufs); + aBufs = temp; + } +} + +void IPCPrintDlg::CopyFrom(const LPPRINTDLGW& aDlg) { + // DLP: Trouble -- my prior impl "worked" but didn't return anything + // AFAIR. So... ??? But it printed a page!!! How?! + MOZ_ASSERT_UNREACHABLE("TODO: DLP:"); +} + +void IPCPrintDlg::CopyTo(LPPRINTDLGW& aDlg) const { + MOZ_ASSERT_UNREACHABLE("TODO: DLP:"); +} + +} // namespace plugins +} // namespace mozilla + +#endif // defined(XP_WIN) |