1 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8; -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "FunctionBrokerIPCUtils.h"
8 
9 #if defined(XP_WIN)
10 
11 #include <schannel.h>
12 
13 /* these defines are missing from mingw headers */
14 #ifndef SP_PROT_TLS1_1_CLIENT
15 #define SP_PROT_TLS1_1_CLIENT 0x00000200
16 #endif
17 
18 #ifndef SP_PROT_TLS1_2_CLIENT
19 #define SP_PROT_TLS1_2_CLIENT 0x00000800
20 #endif
21 
22 namespace mozilla {
23 namespace plugins {
24 
25 mozilla::LazyLogModule sPluginHooksLog("PluginHooks");
26 
27 static const DWORD SCHANNEL_SUPPORTED_PROTOCOLS =
28     SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT;
29 
30 static const DWORD SCHANNEL_SUPPORTED_FLAGS =
31     SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS |
32     SCH_CRED_REVOCATION_CHECK_END_CERT;
33 
CopyFromOfn(LPOPENFILENAMEW aLpofn)34 void OpenFileNameIPC::CopyFromOfn(LPOPENFILENAMEW aLpofn) {
35   mHwndOwner = nullptr;
36 
37   // Filter is double-NULL terminated.  mFilter should include the double-NULL.
38   mHasFilter = aLpofn->lpstrFilter != nullptr;
39   if (mHasFilter) {
40     uint32_t dNullIdx = 0;
41     while (aLpofn->lpstrFilter[dNullIdx] != L'\0' ||
42            aLpofn->lpstrFilter[dNullIdx + 1] != L'\0') {
43       dNullIdx++;
44     }
45     mFilter.assign(aLpofn->lpstrFilter, dNullIdx + 2);
46   }
47   mHasCustomFilter = aLpofn->lpstrCustomFilter != nullptr;
48   if (mHasCustomFilter) {
49     mCustomFilterIn = std::wstring(aLpofn->lpstrCustomFilter);
50     mNMaxCustFilterOut =
51         aLpofn->nMaxCustFilter - (wcslen(aLpofn->lpstrCustomFilter) + 1);
52   } else {
53     mNMaxCustFilterOut = 0;
54   }
55   mFilterIndex = aLpofn->nFilterIndex;
56   mFile = std::wstring(aLpofn->lpstrFile);
57   mNMaxFile = aLpofn->nMaxFile;
58   mNMaxFileTitle =
59       aLpofn->lpstrFileTitle != nullptr ? aLpofn->nMaxFileTitle : 0;
60   mHasInitialDir = aLpofn->lpstrInitialDir != nullptr;
61   if (mHasInitialDir) {
62     mInitialDir = std::wstring(aLpofn->lpstrInitialDir);
63   }
64   mHasTitle = aLpofn->lpstrTitle != nullptr;
65   if (mHasTitle) {
66     mTitle = std::wstring(aLpofn->lpstrTitle);
67   }
68   mHasDefExt = aLpofn->lpstrDefExt != nullptr;
69   if (mHasDefExt) {
70     mDefExt = std::wstring(aLpofn->lpstrDefExt);
71   }
72 
73   mFlags = aLpofn->Flags;
74   // If the user sets OFN_ALLOWMULTISELECT then we require OFN_EXPLORER
75   // as well.  Without OFN_EXPLORER, the method has ancient legacy
76   // behavior that we don't support.
77   MOZ_ASSERT((mFlags & OFN_EXPLORER) || !(mFlags & OFN_ALLOWMULTISELECT));
78 
79   // We ignore any visual customization and callbacks that the user set.
80   mFlags &= ~(OFN_ENABLEHOOK | OFN_ENABLETEMPLATEHANDLE | OFN_ENABLETEMPLATE);
81 
82   mFlagsEx = aLpofn->FlagsEx;
83 }
84 
AddToOfn(LPOPENFILENAMEW aLpofn) const85 void OpenFileNameIPC::AddToOfn(LPOPENFILENAMEW aLpofn) const {
86   aLpofn->lStructSize = sizeof(OPENFILENAMEW);
87   aLpofn->hwndOwner = mHwndOwner;
88   if (mHasFilter) {
89     memcpy(const_cast<LPWSTR>(aLpofn->lpstrFilter), mFilter.data(),
90            mFilter.size() * sizeof(wchar_t));
91   }
92   if (mHasCustomFilter) {
93     aLpofn->nMaxCustFilter = mCustomFilterIn.size() + 1 + mNMaxCustFilterOut;
94     wcscpy(aLpofn->lpstrCustomFilter, mCustomFilterIn.c_str());
95     memset(aLpofn->lpstrCustomFilter + mCustomFilterIn.size() + 1, 0,
96            mNMaxCustFilterOut * sizeof(wchar_t));
97   } else {
98     aLpofn->nMaxCustFilter = 0;
99   }
100   aLpofn->nFilterIndex = mFilterIndex;
101   if (mNMaxFile > 0) {
102     wcsncpy(aLpofn->lpstrFile, mFile.c_str(),
103             std::min(static_cast<uint32_t>(mFile.size() + 1), mNMaxFile));
104     aLpofn->lpstrFile[mNMaxFile - 1] = L'\0';
105   }
106   aLpofn->nMaxFile = mNMaxFile;
107   aLpofn->nMaxFileTitle = mNMaxFileTitle;
108   if (mHasInitialDir) {
109     wcscpy(const_cast<LPWSTR>(aLpofn->lpstrInitialDir), mInitialDir.c_str());
110   }
111   if (mHasTitle) {
112     wcscpy(const_cast<LPWSTR>(aLpofn->lpstrTitle), mTitle.c_str());
113   }
114   aLpofn->Flags = mFlags; /* TODO: Consider adding OFN_NOCHANGEDIR */
115   if (mHasDefExt) {
116     wcscpy(const_cast<LPWSTR>(aLpofn->lpstrDefExt), mDefExt.c_str());
117   }
118   aLpofn->FlagsEx = mFlagsEx;
119 }
120 
AllocateOfnStrings(LPOPENFILENAMEW aLpofn) const121 void OpenFileNameIPC::AllocateOfnStrings(LPOPENFILENAMEW aLpofn) const {
122   if (mHasFilter) {
123     // mFilter is double-NULL terminated and it includes the double-NULL in its
124     // length.
125     aLpofn->lpstrFilter =
126         static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mFilter.size())));
127   }
128   if (mHasCustomFilter) {
129     aLpofn->lpstrCustomFilter = static_cast<LPTSTR>(moz_xmalloc(
130         sizeof(wchar_t) * (mCustomFilterIn.size() + 1 + mNMaxCustFilterOut)));
131   }
132   aLpofn->lpstrFile =
133       static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * mNMaxFile));
134   if (mNMaxFileTitle > 0) {
135     aLpofn->lpstrFileTitle =
136         static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * mNMaxFileTitle));
137   }
138   if (mHasInitialDir) {
139     aLpofn->lpstrInitialDir = static_cast<LPCTSTR>(
140         moz_xmalloc(sizeof(wchar_t) * (mInitialDir.size() + 1)));
141   }
142   if (mHasTitle) {
143     aLpofn->lpstrTitle = static_cast<LPCTSTR>(
144         moz_xmalloc(sizeof(wchar_t) * (mTitle.size() + 1)));
145   }
146   if (mHasDefExt) {
147     aLpofn->lpstrDefExt = static_cast<LPCTSTR>(
148         moz_xmalloc(sizeof(wchar_t) * (mDefExt.size() + 1)));
149   }
150 }
151 
152 // static
FreeOfnStrings(LPOPENFILENAMEW aLpofn)153 void OpenFileNameIPC::FreeOfnStrings(LPOPENFILENAMEW aLpofn) {
154   if (aLpofn->lpstrFilter) {
155     free(const_cast<LPWSTR>(aLpofn->lpstrFilter));
156   }
157   if (aLpofn->lpstrCustomFilter) {
158     free(aLpofn->lpstrCustomFilter);
159   }
160   if (aLpofn->lpstrFile) {
161     free(aLpofn->lpstrFile);
162   }
163   if (aLpofn->lpstrFileTitle) {
164     free(aLpofn->lpstrFileTitle);
165   }
166   if (aLpofn->lpstrInitialDir) {
167     free(const_cast<LPWSTR>(aLpofn->lpstrInitialDir));
168   }
169   if (aLpofn->lpstrTitle) {
170     free(const_cast<LPWSTR>(aLpofn->lpstrTitle));
171   }
172   if (aLpofn->lpstrDefExt) {
173     free(const_cast<LPWSTR>(aLpofn->lpstrDefExt));
174   }
175 }
176 
CopyFromOfn(LPOPENFILENAMEW aLpofn)177 void OpenFileNameRetIPC::CopyFromOfn(LPOPENFILENAMEW aLpofn) {
178   if (aLpofn->lpstrCustomFilter != nullptr) {
179     mCustomFilterOut = std::wstring(aLpofn->lpstrCustomFilter +
180                                     wcslen(aLpofn->lpstrCustomFilter) + 1);
181   }
182   mFile.assign(aLpofn->lpstrFile, aLpofn->nMaxFile);
183   if (aLpofn->lpstrFileTitle != nullptr) {
184     mFileTitle.assign(aLpofn->lpstrFileTitle,
185                       wcslen(aLpofn->lpstrFileTitle) + 1);
186   }
187   mFileOffset = aLpofn->nFileOffset;
188   mFileExtension = aLpofn->nFileExtension;
189 }
190 
AddToOfn(LPOPENFILENAMEW aLpofn) const191 void OpenFileNameRetIPC::AddToOfn(LPOPENFILENAMEW aLpofn) const {
192   if (aLpofn->lpstrCustomFilter) {
193     LPWSTR secondString =
194         aLpofn->lpstrCustomFilter + wcslen(aLpofn->lpstrCustomFilter) + 1;
195     const wchar_t* customFilterOut = mCustomFilterOut.c_str();
196     MOZ_ASSERT(wcslen(aLpofn->lpstrCustomFilter) + 1 + wcslen(customFilterOut) +
197                    1 + 1 <=
198                aLpofn->nMaxCustFilter);
199     wcscpy(secondString, customFilterOut);
200     secondString[wcslen(customFilterOut) + 1] =
201         L'\0';  // terminated with two NULLs
202   }
203   MOZ_ASSERT(mFile.size() <= aLpofn->nMaxFile);
204   memcpy(aLpofn->lpstrFile, mFile.data(), mFile.size() * sizeof(wchar_t));
205   if (aLpofn->lpstrFileTitle != nullptr) {
206     MOZ_ASSERT(mFileTitle.size() + 1 < aLpofn->nMaxFileTitle);
207     wcscpy(aLpofn->lpstrFileTitle, mFileTitle.c_str());
208   }
209   aLpofn->nFileOffset = mFileOffset;
210   aLpofn->nFileExtension = mFileExtension;
211 }
212 
CopyFrom(const PSCHANNEL_CRED & aSCred)213 void IPCSchannelCred::CopyFrom(const PSCHANNEL_CRED& aSCred) {
214   // We assert that the aSCred fields take supported values.
215   // If they do not then we ignore the values we were given.
216   MOZ_ASSERT(aSCred->dwVersion == SCHANNEL_CRED_VERSION);
217   MOZ_ASSERT(aSCred->cCreds == 0);
218   MOZ_ASSERT(aSCred->paCred == nullptr);
219   MOZ_ASSERT(aSCred->hRootStore == nullptr);
220   MOZ_ASSERT(aSCred->cMappers == 0);
221   MOZ_ASSERT(aSCred->aphMappers == nullptr);
222   MOZ_ASSERT(aSCred->cSupportedAlgs == 0);
223   MOZ_ASSERT(aSCred->palgSupportedAlgs == nullptr);
224   MOZ_ASSERT((aSCred->grbitEnabledProtocols & SCHANNEL_SUPPORTED_PROTOCOLS) ==
225              aSCred->grbitEnabledProtocols);
226   mEnabledProtocols =
227       aSCred->grbitEnabledProtocols & SCHANNEL_SUPPORTED_PROTOCOLS;
228   mMinStrength = aSCred->dwMinimumCipherStrength;
229   mMaxStrength = aSCred->dwMaximumCipherStrength;
230   MOZ_ASSERT(aSCred->dwSessionLifespan == 0);
231   MOZ_ASSERT((aSCred->dwFlags & SCHANNEL_SUPPORTED_FLAGS) == aSCred->dwFlags);
232   mFlags = aSCred->dwFlags & SCHANNEL_SUPPORTED_FLAGS;
233   MOZ_ASSERT(aSCred->dwCredFormat == 0);
234 }
235 
CopyTo(PSCHANNEL_CRED & aSCred) const236 void IPCSchannelCred::CopyTo(PSCHANNEL_CRED& aSCred) const {
237   // Validate values as they come from an untrusted process.
238   memset(aSCred, 0, sizeof(SCHANNEL_CRED));
239   aSCred->dwVersion = SCHANNEL_CRED_VERSION;
240   aSCred->grbitEnabledProtocols =
241       mEnabledProtocols & SCHANNEL_SUPPORTED_PROTOCOLS;
242   aSCred->dwMinimumCipherStrength = mMinStrength;
243   aSCred->dwMaximumCipherStrength = mMaxStrength;
244   aSCred->dwFlags = mFlags & SCHANNEL_SUPPORTED_FLAGS;
245 }
246 
CopyFrom(const LPINTERNET_BUFFERSA & aBufs)247 void IPCInternetBuffers::CopyFrom(const LPINTERNET_BUFFERSA& aBufs) {
248   mBuffers.Clear();
249 
250   LPINTERNET_BUFFERSA inetBuf = aBufs;
251   while (inetBuf) {
252     MOZ_ASSERT(inetBuf->dwStructSize == sizeof(INTERNET_BUFFERSA));
253     Buffer* ipcBuf = mBuffers.AppendElement();
254 
255     ipcBuf->mHeader.SetIsVoid(inetBuf->lpcszHeader == nullptr);
256     if (inetBuf->lpcszHeader) {
257       ipcBuf->mHeader.Assign(inetBuf->lpcszHeader, inetBuf->dwHeadersLength);
258     }
259     ipcBuf->mHeaderTotal = inetBuf->dwHeadersTotal;
260 
261     ipcBuf->mBuffer.SetIsVoid(inetBuf->lpvBuffer == nullptr);
262     if (inetBuf->lpvBuffer) {
263       ipcBuf->mBuffer.Assign(static_cast<char*>(inetBuf->lpvBuffer),
264                              inetBuf->dwBufferLength);
265     }
266     ipcBuf->mBufferTotal = inetBuf->dwBufferTotal;
267     inetBuf = inetBuf->Next;
268   }
269 }
270 
CopyTo(LPINTERNET_BUFFERSA & aBufs) const271 void IPCInternetBuffers::CopyTo(LPINTERNET_BUFFERSA& aBufs) const {
272   MOZ_ASSERT(!aBufs);
273 
274   LPINTERNET_BUFFERSA lastBuf = nullptr;
275   for (size_t idx = 0; idx < mBuffers.Length(); ++idx) {
276     const Buffer& ipcBuf = mBuffers[idx];
277     LPINTERNET_BUFFERSA newBuf = static_cast<LPINTERNET_BUFFERSA>(
278         moz_xcalloc(1, sizeof(INTERNET_BUFFERSA)));
279     if (idx == 0) {
280       aBufs = newBuf;
281     } else {
282       MOZ_ASSERT(lastBuf);
283       lastBuf->Next = newBuf;
284       lastBuf = newBuf;
285     }
286 
287     newBuf->dwStructSize = sizeof(INTERNET_BUFFERSA);
288 
289     newBuf->dwHeadersTotal = ipcBuf.mHeaderTotal;
290     if (!ipcBuf.mHeader.IsVoid()) {
291       newBuf->lpcszHeader =
292           static_cast<LPCSTR>(moz_xmalloc(ipcBuf.mHeader.Length()));
293       memcpy(const_cast<char*>(newBuf->lpcszHeader), ipcBuf.mHeader.Data(),
294              ipcBuf.mHeader.Length());
295       newBuf->dwHeadersLength = ipcBuf.mHeader.Length();
296     }
297 
298     newBuf->dwBufferTotal = ipcBuf.mBufferTotal;
299     if (!ipcBuf.mBuffer.IsVoid()) {
300       newBuf->lpvBuffer = moz_xmalloc(ipcBuf.mBuffer.Length());
301       memcpy(newBuf->lpvBuffer, ipcBuf.mBuffer.Data(), ipcBuf.mBuffer.Length());
302       newBuf->dwBufferLength = ipcBuf.mBuffer.Length();
303     }
304   }
305 }
306 
FreeBuffers(LPINTERNET_BUFFERSA & aBufs)307 /* static */ void IPCInternetBuffers::FreeBuffers(LPINTERNET_BUFFERSA& aBufs) {
308   if (!aBufs) {
309     return;
310   }
311   while (aBufs) {
312     LPINTERNET_BUFFERSA temp = aBufs->Next;
313     free(const_cast<char*>(aBufs->lpcszHeader));
314     free(aBufs->lpvBuffer);
315     free(aBufs);
316     aBufs = temp;
317   }
318 }
319 
CopyFrom(const LPPRINTDLGW & aDlg)320 void IPCPrintDlg::CopyFrom(const LPPRINTDLGW& aDlg) {
321   // DLP: Trouble -- my prior impl "worked" but didn't return anything
322   // AFAIR.  So... ???  But it printed a page!!!  How?!
323   MOZ_ASSERT_UNREACHABLE("TODO: DLP:");
324 }
325 
CopyTo(LPPRINTDLGW & aDlg) const326 void IPCPrintDlg::CopyTo(LPPRINTDLGW& aDlg) const {
327   MOZ_ASSERT_UNREACHABLE("TODO: DLP:");
328 }
329 
330 }  // namespace plugins
331 }  // namespace mozilla
332 
333 #endif  // defined(XP_WIN)
334