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