1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "nsPluginTags.h"
7
8 #include "prlink.h"
9 #include "plstr.h"
10 #include "nsIPluginInstanceOwner.h"
11 #include "nsPluginsDir.h"
12 #include "nsPluginHost.h"
13 #include "nsIBlocklistService.h"
14 #include "nsIUnicodeDecoder.h"
15 #include "nsIPlatformCharset.h"
16 #include "nsPluginLogging.h"
17 #include "nsNPAPIPlugin.h"
18 #include "nsCharSeparatedTokenizer.h"
19 #include "mozilla/Preferences.h"
20 #include "mozilla/Unused.h"
21 #include "nsNetUtil.h"
22 #include <cctype>
23 #include "mozilla/dom/EncodingUtils.h"
24 #include "mozilla/dom/ContentChild.h"
25 #include "mozilla/dom/FakePluginTagInitBinding.h"
26
27 using mozilla::dom::EncodingUtils;
28 using mozilla::dom::FakePluginTagInit;
29 using namespace mozilla;
30
31 // These legacy flags are used in the plugin registry. The states are now
32 // stored in prefs, but we still need to be able to import them.
33 #define NS_PLUGIN_FLAG_ENABLED 0x0001 // is this plugin enabled?
34 // no longer used 0x0002 // reuse only if regenerating pluginreg.dat
35 #define NS_PLUGIN_FLAG_FROMCACHE 0x0004 // this plugintag info was loaded from cache
36 // no longer used 0x0008 // reuse only if regenerating pluginreg.dat
37 #define NS_PLUGIN_FLAG_CLICKTOPLAY 0x0020 // this is a click-to-play plugin
38
39 static const char kPrefDefaultEnabledState[] = "plugin.default.state";
40 static const char kPrefDefaultEnabledStateXpi[] = "plugin.defaultXpi.state";
41
42 // check comma delimited extensions
ExtensionInList(const nsCString & aExtensionList,const nsACString & aExtension)43 static bool ExtensionInList(const nsCString& aExtensionList,
44 const nsACString& aExtension)
45 {
46 nsCCharSeparatedTokenizer extensions(aExtensionList, ',');
47 while (extensions.hasMoreTokens()) {
48 const nsCSubstring& extension = extensions.nextToken();
49 if (extension.Equals(aExtension, nsCaseInsensitiveCStringComparator())) {
50 return true;
51 }
52 }
53 return false;
54 }
55
56 // Search for an extension in an extensions array, and return its
57 // matching mime type
SearchExtensions(const nsTArray<nsCString> & aExtensions,const nsTArray<nsCString> & aMimeTypes,const nsACString & aFindExtension,nsACString & aMatchingType)58 static bool SearchExtensions(const nsTArray<nsCString> & aExtensions,
59 const nsTArray<nsCString> & aMimeTypes,
60 const nsACString & aFindExtension,
61 nsACString & aMatchingType)
62 {
63 uint32_t mimes = aMimeTypes.Length();
64 MOZ_ASSERT(mimes == aExtensions.Length(),
65 "These arrays should have matching elements");
66
67 aMatchingType.Truncate();
68
69 for (uint32_t i = 0; i < mimes; i++) {
70 if (ExtensionInList(aExtensions[i], aFindExtension)) {
71 aMatchingType = aMimeTypes[i];
72 return true;
73 }
74 }
75
76 return false;
77 }
78
79 static nsCString
MakeNiceFileName(const nsCString & aFileName)80 MakeNiceFileName(const nsCString & aFileName)
81 {
82 nsCString niceName = aFileName;
83 int32_t niceNameLength = aFileName.RFind(".");
84 NS_ASSERTION(niceNameLength != kNotFound, "aFileName doesn't have a '.'?");
85 while (niceNameLength > 0) {
86 char chr = aFileName[niceNameLength - 1];
87 if (!std::isalpha(chr))
88 niceNameLength--;
89 else
90 break;
91 }
92
93 // If it turns out that niceNameLength <= 0, we'll fall back and use the
94 // entire aFileName (which we've already taken care of, a few lines back).
95 if (niceNameLength > 0) {
96 niceName.Truncate(niceNameLength);
97 }
98
99 ToLowerCase(niceName);
100 return niceName;
101 }
102
103 static nsCString
MakePrefNameForPlugin(const char * const subname,nsIInternalPluginTag * aTag)104 MakePrefNameForPlugin(const char* const subname, nsIInternalPluginTag* aTag)
105 {
106 nsCString pref;
107 nsAutoCString pluginName(aTag->GetNiceFileName());
108
109 if (pluginName.IsEmpty()) {
110 // Use filename if nice name fails
111 pluginName = aTag->FileName();
112 if (pluginName.IsEmpty()) {
113 MOZ_ASSERT_UNREACHABLE("Plugin with no filename or nice name in list");
114 pluginName.AssignLiteral("unknown-plugin-name");
115 }
116 }
117
118 pref.AssignLiteral("plugin.");
119 pref.Append(subname);
120 pref.Append('.');
121 pref.Append(pluginName);
122
123 return pref;
124 }
125
126 static nsresult
CStringArrayToXPCArray(nsTArray<nsCString> & aArray,uint32_t * aCount,char16_t *** aResults)127 CStringArrayToXPCArray(nsTArray<nsCString> & aArray,
128 uint32_t* aCount,
129 char16_t*** aResults)
130 {
131 uint32_t count = aArray.Length();
132 if (!count) {
133 *aResults = nullptr;
134 *aCount = 0;
135 return NS_OK;
136 }
137
138 *aResults =
139 static_cast<char16_t**>(moz_xmalloc(count * sizeof(**aResults)));
140 *aCount = count;
141
142 for (uint32_t i = 0; i < count; i++) {
143 (*aResults)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(aArray[i]));
144 }
145
146 return NS_OK;
147 }
148
149 static nsCString
GetStatePrefNameForPlugin(nsIInternalPluginTag * aTag)150 GetStatePrefNameForPlugin(nsIInternalPluginTag* aTag)
151 {
152 return MakePrefNameForPlugin("state", aTag);
153 }
154
155 static nsresult
IsEnabledStateLockedForPlugin(nsIInternalPluginTag * aTag,bool * aIsEnabledStateLocked)156 IsEnabledStateLockedForPlugin(nsIInternalPluginTag* aTag,
157 bool* aIsEnabledStateLocked)
158 {
159 *aIsEnabledStateLocked = false;
160 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
161
162 if (NS_WARN_IF(!prefs)) {
163 return NS_ERROR_FAILURE;
164 }
165
166 Unused << prefs->PrefIsLocked(GetStatePrefNameForPlugin(aTag).get(),
167 aIsEnabledStateLocked);
168
169 return NS_OK;
170 }
171
172 /* nsIInternalPluginTag */
nsIInternalPluginTag()173 nsIInternalPluginTag::nsIInternalPluginTag()
174 {
175 }
176
nsIInternalPluginTag(const char * aName,const char * aDescription,const char * aFileName,const char * aVersion)177 nsIInternalPluginTag::nsIInternalPluginTag(const char* aName,
178 const char* aDescription,
179 const char* aFileName,
180 const char* aVersion)
181 : mName(aName)
182 , mDescription(aDescription)
183 , mFileName(aFileName)
184 , mVersion(aVersion)
185 {
186 }
187
nsIInternalPluginTag(const char * aName,const char * aDescription,const char * aFileName,const char * aVersion,const nsTArray<nsCString> & aMimeTypes,const nsTArray<nsCString> & aMimeDescriptions,const nsTArray<nsCString> & aExtensions)188 nsIInternalPluginTag::nsIInternalPluginTag(const char* aName,
189 const char* aDescription,
190 const char* aFileName,
191 const char* aVersion,
192 const nsTArray<nsCString>& aMimeTypes,
193 const nsTArray<nsCString>& aMimeDescriptions,
194 const nsTArray<nsCString>& aExtensions)
195 : mName(aName)
196 , mDescription(aDescription)
197 , mFileName(aFileName)
198 , mVersion(aVersion)
199 , mMimeTypes(aMimeTypes)
200 , mMimeDescriptions(aMimeDescriptions)
201 , mExtensions(aExtensions)
202 {
203 }
204
~nsIInternalPluginTag()205 nsIInternalPluginTag::~nsIInternalPluginTag()
206 {
207 }
208
209 bool
HasExtension(const nsACString & aExtension,nsACString & aMatchingType) const210 nsIInternalPluginTag::HasExtension(const nsACString& aExtension,
211 nsACString& aMatchingType) const
212 {
213 return SearchExtensions(mExtensions, mMimeTypes, aExtension, aMatchingType);
214 }
215
216 bool
HasMimeType(const nsACString & aMimeType) const217 nsIInternalPluginTag::HasMimeType(const nsACString& aMimeType) const
218 {
219 return mMimeTypes.Contains(aMimeType,
220 nsCaseInsensitiveCStringArrayComparator());
221 }
222
223 /* nsPluginTag */
224
225 uint32_t nsPluginTag::sNextId;
226
nsPluginTag(nsPluginInfo * aPluginInfo,int64_t aLastModifiedTime,bool fromExtension)227 nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo,
228 int64_t aLastModifiedTime,
229 bool fromExtension)
230 : nsIInternalPluginTag(aPluginInfo->fName, aPluginInfo->fDescription,
231 aPluginInfo->fFileName, aPluginInfo->fVersion),
232 mId(sNextId++),
233 mContentProcessRunningCount(0),
234 mHadLocalInstance(false),
235 mLibrary(nullptr),
236 mIsJavaPlugin(false),
237 mIsFlashPlugin(false),
238 mSupportsAsyncInit(false),
239 mSupportsAsyncRender(false),
240 mFullPath(aPluginInfo->fFullPath),
241 mLastModifiedTime(aLastModifiedTime),
242 mSandboxLevel(0),
243 mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
244 mCachedBlocklistStateValid(false),
245 mIsFromExtension(fromExtension)
246 {
247 InitMime(aPluginInfo->fMimeTypeArray,
248 aPluginInfo->fMimeDescriptionArray,
249 aPluginInfo->fExtensionArray,
250 aPluginInfo->fVariantCount);
251 InitSandboxLevel();
252 EnsureMembersAreUTF8();
253 FixupVersion();
254 }
255
nsPluginTag(const char * aName,const char * aDescription,const char * aFileName,const char * aFullPath,const char * aVersion,const char * const * aMimeTypes,const char * const * aMimeDescriptions,const char * const * aExtensions,int32_t aVariants,int64_t aLastModifiedTime,bool fromExtension,bool aArgsAreUTF8)256 nsPluginTag::nsPluginTag(const char* aName,
257 const char* aDescription,
258 const char* aFileName,
259 const char* aFullPath,
260 const char* aVersion,
261 const char* const* aMimeTypes,
262 const char* const* aMimeDescriptions,
263 const char* const* aExtensions,
264 int32_t aVariants,
265 int64_t aLastModifiedTime,
266 bool fromExtension,
267 bool aArgsAreUTF8)
268 : nsIInternalPluginTag(aName, aDescription, aFileName, aVersion),
269 mId(sNextId++),
270 mContentProcessRunningCount(0),
271 mHadLocalInstance(false),
272 mLibrary(nullptr),
273 mIsJavaPlugin(false),
274 mIsFlashPlugin(false),
275 mSupportsAsyncInit(false),
276 mSupportsAsyncRender(false),
277 mFullPath(aFullPath),
278 mLastModifiedTime(aLastModifiedTime),
279 mSandboxLevel(0),
280 mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
281 mCachedBlocklistStateValid(false),
282 mIsFromExtension(fromExtension)
283 {
284 InitMime(aMimeTypes, aMimeDescriptions, aExtensions,
285 static_cast<uint32_t>(aVariants));
286 InitSandboxLevel();
287 if (!aArgsAreUTF8)
288 EnsureMembersAreUTF8();
289 FixupVersion();
290 }
291
nsPluginTag(uint32_t aId,const char * aName,const char * aDescription,const char * aFileName,const char * aFullPath,const char * aVersion,nsTArray<nsCString> aMimeTypes,nsTArray<nsCString> aMimeDescriptions,nsTArray<nsCString> aExtensions,bool aIsJavaPlugin,bool aIsFlashPlugin,bool aSupportsAsyncInit,bool aSupportsAsyncRender,int64_t aLastModifiedTime,bool aFromExtension,int32_t aSandboxLevel)292 nsPluginTag::nsPluginTag(uint32_t aId,
293 const char* aName,
294 const char* aDescription,
295 const char* aFileName,
296 const char* aFullPath,
297 const char* aVersion,
298 nsTArray<nsCString> aMimeTypes,
299 nsTArray<nsCString> aMimeDescriptions,
300 nsTArray<nsCString> aExtensions,
301 bool aIsJavaPlugin,
302 bool aIsFlashPlugin,
303 bool aSupportsAsyncInit,
304 bool aSupportsAsyncRender,
305 int64_t aLastModifiedTime,
306 bool aFromExtension,
307 int32_t aSandboxLevel)
308 : nsIInternalPluginTag(aName, aDescription, aFileName, aVersion, aMimeTypes,
309 aMimeDescriptions, aExtensions),
310 mId(aId),
311 mContentProcessRunningCount(0),
312 mLibrary(nullptr),
313 mIsJavaPlugin(aIsJavaPlugin),
314 mIsFlashPlugin(aIsFlashPlugin),
315 mSupportsAsyncInit(aSupportsAsyncInit),
316 mSupportsAsyncRender(aSupportsAsyncRender),
317 mLastModifiedTime(aLastModifiedTime),
318 mSandboxLevel(aSandboxLevel),
319 mNiceFileName(),
320 mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
321 mCachedBlocklistStateValid(false),
322 mIsFromExtension(aFromExtension)
323 {
324 }
325
~nsPluginTag()326 nsPluginTag::~nsPluginTag()
327 {
328 NS_ASSERTION(!mNext, "Risk of exhausting the stack space, bug 486349");
329 }
330
NS_IMPL_ISUPPORTS(nsPluginTag,nsPluginTag,nsIInternalPluginTag,nsIPluginTag)331 NS_IMPL_ISUPPORTS(nsPluginTag, nsPluginTag, nsIInternalPluginTag, nsIPluginTag)
332
333 void nsPluginTag::InitMime(const char* const* aMimeTypes,
334 const char* const* aMimeDescriptions,
335 const char* const* aExtensions,
336 uint32_t aVariantCount)
337 {
338 if (!aMimeTypes) {
339 return;
340 }
341
342 for (uint32_t i = 0; i < aVariantCount; i++) {
343 if (!aMimeTypes[i]) {
344 continue;
345 }
346
347 nsAutoCString mimeType(aMimeTypes[i]);
348
349 // Convert the MIME type, which is case insensitive, to lowercase in order
350 // to properly handle a mixed-case type.
351 ToLowerCase(mimeType);
352
353 if (!nsPluginHost::IsTypeWhitelisted(mimeType.get())) {
354 continue;
355 }
356
357 // Look for certain special plugins.
358 switch (nsPluginHost::GetSpecialType(mimeType)) {
359 case nsPluginHost::eSpecialType_Java:
360 mIsJavaPlugin = true;
361 mSupportsAsyncInit = true;
362 break;
363 case nsPluginHost::eSpecialType_Flash:
364 // VLC sometimes claims to implement the Flash MIME type, and we want
365 // to allow users to control that separately from Adobe Flash.
366 if (Name().EqualsLiteral("Shockwave Flash")) {
367 mIsFlashPlugin = true;
368 mSupportsAsyncInit = true;
369 }
370 break;
371 case nsPluginHost::eSpecialType_Silverlight:
372 case nsPluginHost::eSpecialType_Unity:
373 case nsPluginHost::eSpecialType_Test:
374 mSupportsAsyncInit = true;
375 break;
376 case nsPluginHost::eSpecialType_None:
377 default:
378 #ifndef RELEASE_OR_BETA
379 // Allow async init for all plugins on Nightly and Aurora
380 mSupportsAsyncInit = true;
381 #endif
382 break;
383 }
384
385 // Fill in our MIME type array.
386 mMimeTypes.AppendElement(mimeType);
387
388 // Now fill in the MIME descriptions.
389 if (aMimeDescriptions && aMimeDescriptions[i]) {
390 // we should cut off the list of suffixes which the mime
391 // description string may have, see bug 53895
392 // it is usually in form "some description (*.sf1, *.sf2)"
393 // so we can search for the opening round bracket
394 char cur = '\0';
395 char pre = '\0';
396 char * p = PL_strrchr(aMimeDescriptions[i], '(');
397 if (p && (p != aMimeDescriptions[i])) {
398 if ((p - 1) && *(p - 1) == ' ') {
399 pre = *(p - 1);
400 *(p - 1) = '\0';
401 } else {
402 cur = *p;
403 *p = '\0';
404 }
405 }
406 mMimeDescriptions.AppendElement(nsCString(aMimeDescriptions[i]));
407 // restore the original string
408 if (cur != '\0') {
409 *p = cur;
410 }
411 if (pre != '\0') {
412 *(p - 1) = pre;
413 }
414 } else {
415 mMimeDescriptions.AppendElement(nsCString());
416 }
417
418 // Now fill in the extensions.
419 if (aExtensions && aExtensions[i]) {
420 mExtensions.AppendElement(nsCString(aExtensions[i]));
421 } else {
422 mExtensions.AppendElement(nsCString());
423 }
424 }
425 }
426
427 void
InitSandboxLevel()428 nsPluginTag::InitSandboxLevel()
429 {
430 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
431 nsAutoCString sandboxPref("dom.ipc.plugins.sandbox-level.");
432 sandboxPref.Append(GetNiceFileName());
433 if (NS_FAILED(Preferences::GetInt(sandboxPref.get(), &mSandboxLevel))) {
434 mSandboxLevel = Preferences::GetInt("dom.ipc.plugins.sandbox-level.default"
435 );
436 }
437
438 #if defined(_AMD64_)
439 // As level 2 is now the default NPAPI sandbox level for 64-bit flash, we
440 // don't want to allow a lower setting unless this environment variable is
441 // set. This should be changed if the firefox.js pref file is changed.
442 if (mIsFlashPlugin &&
443 !PR_GetEnv("MOZ_ALLOW_WEAKER_SANDBOX") && mSandboxLevel < 2) {
444 mSandboxLevel = 2;
445 }
446 #endif
447 #endif
448 }
449
450 #if !defined(XP_WIN) && !defined(XP_MACOSX)
ConvertToUTF8(nsIUnicodeDecoder * aUnicodeDecoder,nsAFlatCString & aString)451 static nsresult ConvertToUTF8(nsIUnicodeDecoder *aUnicodeDecoder,
452 nsAFlatCString& aString)
453 {
454 int32_t numberOfBytes = aString.Length();
455 int32_t outUnicodeLen;
456 nsAutoString buffer;
457 nsresult rv = aUnicodeDecoder->GetMaxLength(aString.get(), numberOfBytes,
458 &outUnicodeLen);
459 NS_ENSURE_SUCCESS(rv, rv);
460 if (!buffer.SetLength(outUnicodeLen, fallible))
461 return NS_ERROR_OUT_OF_MEMORY;
462 rv = aUnicodeDecoder->Convert(aString.get(), &numberOfBytes,
463 buffer.BeginWriting(), &outUnicodeLen);
464 NS_ENSURE_SUCCESS(rv, rv);
465 buffer.SetLength(outUnicodeLen);
466 CopyUTF16toUTF8(buffer, aString);
467
468 return NS_OK;
469 }
470 #endif
471
EnsureMembersAreUTF8()472 nsresult nsPluginTag::EnsureMembersAreUTF8()
473 {
474 #if defined(XP_WIN) || defined(XP_MACOSX)
475 return NS_OK;
476 #else
477 nsresult rv;
478
479 nsCOMPtr<nsIPlatformCharset> pcs =
480 do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
481 NS_ENSURE_SUCCESS(rv, rv);
482 nsCOMPtr<nsIUnicodeDecoder> decoder;
483
484 nsAutoCString charset;
485 rv = pcs->GetCharset(kPlatformCharsetSel_FileName, charset);
486 NS_ENSURE_SUCCESS(rv, rv);
487 if (!charset.LowerCaseEqualsLiteral("utf-8")) {
488 decoder = EncodingUtils::DecoderForEncoding(charset);
489 ConvertToUTF8(decoder, mFileName);
490 ConvertToUTF8(decoder, mFullPath);
491 }
492
493 // The description of the plug-in and the various MIME type descriptions
494 // should be encoded in the standard plain text file encoding for this system.
495 // XXX should we add kPlatformCharsetSel_PluginResource?
496 rv = pcs->GetCharset(kPlatformCharsetSel_PlainTextInFile, charset);
497 NS_ENSURE_SUCCESS(rv, rv);
498 if (!charset.LowerCaseEqualsLiteral("utf-8")) {
499 decoder = EncodingUtils::DecoderForEncoding(charset);
500 ConvertToUTF8(decoder, mName);
501 ConvertToUTF8(decoder, mDescription);
502 for (uint32_t i = 0; i < mMimeDescriptions.Length(); ++i) {
503 ConvertToUTF8(decoder, mMimeDescriptions[i]);
504 }
505 }
506 return NS_OK;
507 #endif
508 }
509
FixupVersion()510 void nsPluginTag::FixupVersion()
511 {
512 #if defined(XP_LINUX)
513 if (mIsFlashPlugin) {
514 mVersion.ReplaceChar(',', '.');
515 }
516 #endif
517 }
518
519 NS_IMETHODIMP
GetDescription(nsACString & aDescription)520 nsPluginTag::GetDescription(nsACString& aDescription)
521 {
522 aDescription = mDescription;
523 return NS_OK;
524 }
525
526 NS_IMETHODIMP
GetFilename(nsACString & aFileName)527 nsPluginTag::GetFilename(nsACString& aFileName)
528 {
529 aFileName = mFileName;
530 return NS_OK;
531 }
532
533 NS_IMETHODIMP
GetFullpath(nsACString & aFullPath)534 nsPluginTag::GetFullpath(nsACString& aFullPath)
535 {
536 aFullPath = mFullPath;
537 return NS_OK;
538 }
539
540 NS_IMETHODIMP
GetVersion(nsACString & aVersion)541 nsPluginTag::GetVersion(nsACString& aVersion)
542 {
543 aVersion = mVersion;
544 return NS_OK;
545 }
546
547 NS_IMETHODIMP
GetName(nsACString & aName)548 nsPluginTag::GetName(nsACString& aName)
549 {
550 aName = mName;
551 return NS_OK;
552 }
553
554 bool
IsActive()555 nsPluginTag::IsActive()
556 {
557 return IsEnabled() && !IsBlocklisted();
558 }
559
560 NS_IMETHODIMP
GetActive(bool * aResult)561 nsPluginTag::GetActive(bool *aResult)
562 {
563 *aResult = IsActive();
564 return NS_OK;
565 }
566
567 bool
IsEnabled()568 nsPluginTag::IsEnabled()
569 {
570 const PluginState state = GetPluginState();
571 return (state == ePluginState_Enabled) || (state == ePluginState_Clicktoplay);
572 }
573
574 NS_IMETHODIMP
GetDisabled(bool * aDisabled)575 nsPluginTag::GetDisabled(bool* aDisabled)
576 {
577 *aDisabled = !IsEnabled();
578 return NS_OK;
579 }
580
581 bool
IsBlocklisted()582 nsPluginTag::IsBlocklisted()
583 {
584 uint32_t blocklistState;
585 nsresult rv = GetBlocklistState(&blocklistState);
586 return NS_FAILED(rv) || blocklistState == nsIBlocklistService::STATE_BLOCKED;
587 }
588
589 NS_IMETHODIMP
GetBlocklisted(bool * aBlocklisted)590 nsPluginTag::GetBlocklisted(bool* aBlocklisted)
591 {
592 *aBlocklisted = IsBlocklisted();
593 return NS_OK;
594 }
595
596 NS_IMETHODIMP
GetIsEnabledStateLocked(bool * aIsEnabledStateLocked)597 nsPluginTag::GetIsEnabledStateLocked(bool* aIsEnabledStateLocked)
598 {
599 return IsEnabledStateLockedForPlugin(this, aIsEnabledStateLocked);
600 }
601
602 bool
IsClicktoplay()603 nsPluginTag::IsClicktoplay()
604 {
605 const PluginState state = GetPluginState();
606 return (state == ePluginState_Clicktoplay);
607 }
608
609 NS_IMETHODIMP
GetClicktoplay(bool * aClicktoplay)610 nsPluginTag::GetClicktoplay(bool *aClicktoplay)
611 {
612 *aClicktoplay = IsClicktoplay();
613 return NS_OK;
614 }
615
616 NS_IMETHODIMP
GetEnabledState(uint32_t * aEnabledState)617 nsPluginTag::GetEnabledState(uint32_t *aEnabledState)
618 {
619 int32_t enabledState;
620 nsresult rv = Preferences::GetInt(GetStatePrefNameForPlugin(this).get(),
621 &enabledState);
622 if (NS_SUCCEEDED(rv) &&
623 enabledState >= nsIPluginTag::STATE_DISABLED &&
624 enabledState <= nsIPluginTag::STATE_ENABLED) {
625 *aEnabledState = (uint32_t)enabledState;
626 return rv;
627 }
628
629 const char* const pref = mIsFromExtension ? kPrefDefaultEnabledStateXpi
630 : kPrefDefaultEnabledState;
631
632 enabledState = Preferences::GetInt(pref, nsIPluginTag::STATE_ENABLED);
633 if (enabledState >= nsIPluginTag::STATE_DISABLED &&
634 enabledState <= nsIPluginTag::STATE_ENABLED) {
635 *aEnabledState = (uint32_t)enabledState;
636 return NS_OK;
637 }
638
639 return NS_ERROR_UNEXPECTED;
640 }
641
642 NS_IMETHODIMP
SetEnabledState(uint32_t aEnabledState)643 nsPluginTag::SetEnabledState(uint32_t aEnabledState)
644 {
645 if (aEnabledState >= ePluginState_MaxValue)
646 return NS_ERROR_ILLEGAL_VALUE;
647 uint32_t oldState = nsIPluginTag::STATE_DISABLED;
648 GetEnabledState(&oldState);
649 if (oldState != aEnabledState) {
650 Preferences::SetInt(GetStatePrefNameForPlugin(this).get(), aEnabledState);
651 if (RefPtr<nsPluginHost> host = nsPluginHost::GetInst()) {
652 host->UpdatePluginInfo(this);
653 }
654 }
655 return NS_OK;
656 }
657
658 nsPluginTag::PluginState
GetPluginState()659 nsPluginTag::GetPluginState()
660 {
661 uint32_t enabledState = nsIPluginTag::STATE_DISABLED;
662 GetEnabledState(&enabledState);
663 return (PluginState)enabledState;
664 }
665
666 void
SetPluginState(PluginState state)667 nsPluginTag::SetPluginState(PluginState state)
668 {
669 static_assert((uint32_t)nsPluginTag::ePluginState_Disabled == nsIPluginTag::STATE_DISABLED, "nsPluginTag::ePluginState_Disabled must match nsIPluginTag::STATE_DISABLED");
670 static_assert((uint32_t)nsPluginTag::ePluginState_Clicktoplay == nsIPluginTag::STATE_CLICKTOPLAY, "nsPluginTag::ePluginState_Clicktoplay must match nsIPluginTag::STATE_CLICKTOPLAY");
671 static_assert((uint32_t)nsPluginTag::ePluginState_Enabled == nsIPluginTag::STATE_ENABLED, "nsPluginTag::ePluginState_Enabled must match nsIPluginTag::STATE_ENABLED");
672 SetEnabledState((uint32_t)state);
673 }
674
675 NS_IMETHODIMP
GetMimeTypes(uint32_t * aCount,char16_t *** aResults)676 nsPluginTag::GetMimeTypes(uint32_t* aCount, char16_t*** aResults)
677 {
678 return CStringArrayToXPCArray(mMimeTypes, aCount, aResults);
679 }
680
681 NS_IMETHODIMP
GetMimeDescriptions(uint32_t * aCount,char16_t *** aResults)682 nsPluginTag::GetMimeDescriptions(uint32_t* aCount, char16_t*** aResults)
683 {
684 return CStringArrayToXPCArray(mMimeDescriptions, aCount, aResults);
685 }
686
687 NS_IMETHODIMP
GetExtensions(uint32_t * aCount,char16_t *** aResults)688 nsPluginTag::GetExtensions(uint32_t* aCount, char16_t*** aResults)
689 {
690 return CStringArrayToXPCArray(mExtensions, aCount, aResults);
691 }
692
693 bool
HasSameNameAndMimes(const nsPluginTag * aPluginTag) const694 nsPluginTag::HasSameNameAndMimes(const nsPluginTag *aPluginTag) const
695 {
696 NS_ENSURE_TRUE(aPluginTag, false);
697
698 if ((!mName.Equals(aPluginTag->mName)) ||
699 (mMimeTypes.Length() != aPluginTag->mMimeTypes.Length())) {
700 return false;
701 }
702
703 for (uint32_t i = 0; i < mMimeTypes.Length(); i++) {
704 if (!mMimeTypes[i].Equals(aPluginTag->mMimeTypes[i])) {
705 return false;
706 }
707 }
708
709 return true;
710 }
711
712 NS_IMETHODIMP
GetLoaded(bool * aIsLoaded)713 nsPluginTag::GetLoaded(bool* aIsLoaded)
714 {
715 *aIsLoaded = !!mPlugin;
716 return NS_OK;
717 }
718
TryUnloadPlugin(bool inShutdown)719 void nsPluginTag::TryUnloadPlugin(bool inShutdown)
720 {
721 // We never want to send NPP_Shutdown to an in-process plugin unless
722 // this process is shutting down.
723 if (!mPlugin) {
724 return;
725 }
726 if (inShutdown || mPlugin->GetLibrary()->IsOOP()) {
727 mPlugin->Shutdown();
728 mPlugin = nullptr;
729 }
730 }
731
732 const nsCString&
GetNiceFileName()733 nsPluginTag::GetNiceFileName()
734 {
735 if (!mNiceFileName.IsEmpty()) {
736 return mNiceFileName;
737 }
738
739 if (mIsFlashPlugin) {
740 mNiceFileName.AssignLiteral("flash");
741 return mNiceFileName;
742 }
743
744 if (mIsJavaPlugin) {
745 mNiceFileName.AssignLiteral("java");
746 return mNiceFileName;
747 }
748
749 mNiceFileName = MakeNiceFileName(mFileName);
750 return mNiceFileName;
751 }
752
753 NS_IMETHODIMP
GetNiceName(nsACString & aResult)754 nsPluginTag::GetNiceName(nsACString & aResult)
755 {
756 aResult = GetNiceFileName();
757 return NS_OK;
758 }
759
760 NS_IMETHODIMP
GetBlocklistState(uint32_t * aResult)761 nsPluginTag::GetBlocklistState(uint32_t *aResult)
762 {
763 #if defined(MOZ_WIDGET_ANDROID)
764 *aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
765 return NS_OK;
766 #else
767 if (mCachedBlocklistStateValid) {
768 *aResult = mCachedBlocklistState;
769 return NS_OK;
770 }
771
772 if (!XRE_IsParentProcess()) {
773 *aResult = nsIBlocklistService::STATE_BLOCKED;
774 dom::ContentChild* cp = dom::ContentChild::GetSingleton();
775 if (!cp->SendGetBlocklistState(mId, aResult)) {
776 return NS_OK;
777 }
778 } else {
779 nsCOMPtr<nsIBlocklistService> blocklist =
780 do_GetService("@mozilla.org/extensions/blocklist;1");
781
782 if (!blocklist) {
783 *aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
784 return NS_OK;
785 }
786
787 // The EmptyString()s are so we use the currently running application
788 // and toolkit versions
789 if (NS_FAILED(blocklist->GetPluginBlocklistState(this, EmptyString(),
790 EmptyString(), aResult))) {
791 *aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
792 return NS_OK;
793 }
794 }
795
796 MOZ_ASSERT(*aResult <= UINT16_MAX);
797 mCachedBlocklistState = (uint16_t) *aResult;
798 mCachedBlocklistStateValid = true;
799 return NS_OK;
800 #endif // defined(MOZ_WIDGET_ANDROID)
801 }
802
803 void
InvalidateBlocklistState()804 nsPluginTag::InvalidateBlocklistState()
805 {
806 mCachedBlocklistStateValid = false;
807 }
808
809 NS_IMETHODIMP
GetLastModifiedTime(PRTime * aLastModifiedTime)810 nsPluginTag::GetLastModifiedTime(PRTime* aLastModifiedTime)
811 {
812 MOZ_ASSERT(aLastModifiedTime);
813 *aLastModifiedTime = mLastModifiedTime;
814 return NS_OK;
815 }
816
IsFromExtension() const817 bool nsPluginTag::IsFromExtension() const
818 {
819 return mIsFromExtension;
820 }
821
822 /* nsFakePluginTag */
823
nsFakePluginTag()824 nsFakePluginTag::nsFakePluginTag()
825 : mState(nsPluginTag::ePluginState_Disabled)
826 {
827 }
828
~nsFakePluginTag()829 nsFakePluginTag::~nsFakePluginTag()
830 {
831 }
832
833 NS_IMPL_ADDREF(nsFakePluginTag)
NS_IMPL_RELEASE(nsFakePluginTag)834 NS_IMPL_RELEASE(nsFakePluginTag)
835 NS_INTERFACE_TABLE_HEAD(nsFakePluginTag)
836 NS_INTERFACE_TABLE_BEGIN
837 NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsFakePluginTag, nsIPluginTag,
838 nsIInternalPluginTag)
839 NS_INTERFACE_TABLE_ENTRY(nsFakePluginTag, nsIInternalPluginTag)
840 NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsFakePluginTag, nsISupports,
841 nsIInternalPluginTag)
842 NS_INTERFACE_TABLE_ENTRY(nsFakePluginTag, nsIFakePluginTag)
843 NS_INTERFACE_TABLE_END
844 NS_INTERFACE_TABLE_TAIL
845
846 /* static */
847 nsresult
848 nsFakePluginTag::Create(const FakePluginTagInit& aInitDictionary,
849 nsFakePluginTag** aPluginTag)
850 {
851 NS_ENSURE_TRUE(!aInitDictionary.mMimeEntries.IsEmpty(), NS_ERROR_INVALID_ARG);
852
853 RefPtr<nsFakePluginTag> tag = new nsFakePluginTag();
854 nsresult rv = NS_NewURI(getter_AddRefs(tag->mHandlerURI),
855 aInitDictionary.mHandlerURI);
856 NS_ENSURE_SUCCESS(rv, rv);
857
858 CopyUTF16toUTF8(aInitDictionary.mNiceName, tag->mNiceName);
859 CopyUTF16toUTF8(aInitDictionary.mFullPath, tag->mFullPath);
860 CopyUTF16toUTF8(aInitDictionary.mName, tag->mName);
861 CopyUTF16toUTF8(aInitDictionary.mDescription, tag->mDescription);
862 CopyUTF16toUTF8(aInitDictionary.mFileName, tag->mFileName);
863 CopyUTF16toUTF8(aInitDictionary.mVersion, tag->mVersion);
864
865 for (const FakePluginMimeEntry& mimeEntry : aInitDictionary.mMimeEntries) {
866 CopyUTF16toUTF8(mimeEntry.mType, *tag->mMimeTypes.AppendElement());
867 CopyUTF16toUTF8(mimeEntry.mDescription,
868 *tag->mMimeDescriptions.AppendElement());
869 CopyUTF16toUTF8(mimeEntry.mExtension, *tag->mExtensions.AppendElement());
870 }
871
872 tag.forget(aPluginTag);
873 return NS_OK;
874 }
875
876 bool
HandlerURIMatches(nsIURI * aURI)877 nsFakePluginTag::HandlerURIMatches(nsIURI* aURI)
878 {
879 bool equals = false;
880 return NS_SUCCEEDED(mHandlerURI->Equals(aURI, &equals)) && equals;
881 }
882
883 NS_IMETHODIMP
GetHandlerURI(nsIURI ** aResult)884 nsFakePluginTag::GetHandlerURI(nsIURI **aResult)
885 {
886 NS_IF_ADDREF(*aResult = mHandlerURI);
887 return NS_OK;
888 }
889
890 NS_IMETHODIMP
GetDescription(nsACString & aResult)891 nsFakePluginTag::GetDescription(/* utf-8 */ nsACString& aResult)
892 {
893 aResult = mDescription;
894 return NS_OK;
895 }
896
897 NS_IMETHODIMP
GetFilename(nsACString & aResult)898 nsFakePluginTag::GetFilename(/* utf-8 */ nsACString& aResult)
899 {
900 aResult = mFileName;
901 return NS_OK;
902 }
903
904 NS_IMETHODIMP
GetFullpath(nsACString & aResult)905 nsFakePluginTag::GetFullpath(/* utf-8 */ nsACString& aResult)
906 {
907 aResult = mFullPath;
908 return NS_OK;
909 }
910
911 NS_IMETHODIMP
GetVersion(nsACString & aResult)912 nsFakePluginTag::GetVersion(/* utf-8 */ nsACString& aResult)
913 {
914 aResult = mVersion;
915 return NS_OK;
916 }
917
918 NS_IMETHODIMP
GetName(nsACString & aResult)919 nsFakePluginTag::GetName(/* utf-8 */ nsACString& aResult)
920 {
921 aResult = mName;
922 return NS_OK;
923 }
924
925 const nsCString&
GetNiceFileName()926 nsFakePluginTag::GetNiceFileName()
927 {
928 // We don't try to mimic the special-cased flash/java names if the fake plugin
929 // claims one of their MIME types, but do allow directly setting niceName if
930 // emulating those is desired.
931 if (mNiceName.IsEmpty() && !mFileName.IsEmpty()) {
932 mNiceName = MakeNiceFileName(mFileName);
933 }
934
935 return mNiceName;
936 }
937
938 NS_IMETHODIMP
GetNiceName(nsACString & aResult)939 nsFakePluginTag::GetNiceName(/* utf-8 */ nsACString& aResult)
940 {
941 aResult = GetNiceFileName();
942 return NS_OK;
943 }
944
945 NS_IMETHODIMP
GetBlocklistState(uint32_t * aResult)946 nsFakePluginTag::GetBlocklistState(uint32_t* aResult)
947 {
948 // Fake tags don't currently support blocklisting
949 *aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
950 return NS_OK;
951 }
952
953 NS_IMETHODIMP
GetBlocklisted(bool * aBlocklisted)954 nsFakePluginTag::GetBlocklisted(bool* aBlocklisted)
955 {
956 // Fake tags can't be blocklisted
957 *aBlocklisted = false;
958 return NS_OK;
959 }
960
961 NS_IMETHODIMP
GetIsEnabledStateLocked(bool * aIsEnabledStateLocked)962 nsFakePluginTag::GetIsEnabledStateLocked(bool* aIsEnabledStateLocked)
963 {
964 return IsEnabledStateLockedForPlugin(this, aIsEnabledStateLocked);
965 }
966
967 bool
IsEnabled()968 nsFakePluginTag::IsEnabled()
969 {
970 return mState == nsPluginTag::ePluginState_Enabled ||
971 mState == nsPluginTag::ePluginState_Clicktoplay;
972 }
973
974 NS_IMETHODIMP
GetDisabled(bool * aDisabled)975 nsFakePluginTag::GetDisabled(bool* aDisabled)
976 {
977 *aDisabled = !IsEnabled();
978 return NS_OK;
979 }
980
981 NS_IMETHODIMP
GetClicktoplay(bool * aClicktoplay)982 nsFakePluginTag::GetClicktoplay(bool* aClicktoplay)
983 {
984 *aClicktoplay = (mState == nsPluginTag::ePluginState_Clicktoplay);
985 return NS_OK;
986 }
987
988 NS_IMETHODIMP
GetEnabledState(uint32_t * aEnabledState)989 nsFakePluginTag::GetEnabledState(uint32_t* aEnabledState)
990 {
991 *aEnabledState = (uint32_t)mState;
992 return NS_OK;
993 }
994
995 NS_IMETHODIMP
SetEnabledState(uint32_t aEnabledState)996 nsFakePluginTag::SetEnabledState(uint32_t aEnabledState)
997 {
998 // There are static asserts above enforcing that this enum matches
999 mState = (nsPluginTag::PluginState)aEnabledState;
1000 // FIXME-jsplugins update
1001 return NS_OK;
1002 }
1003
1004 NS_IMETHODIMP
GetMimeTypes(uint32_t * aCount,char16_t *** aResults)1005 nsFakePluginTag::GetMimeTypes(uint32_t* aCount, char16_t*** aResults)
1006 {
1007 return CStringArrayToXPCArray(mMimeTypes, aCount, aResults);
1008 }
1009
1010 NS_IMETHODIMP
GetMimeDescriptions(uint32_t * aCount,char16_t *** aResults)1011 nsFakePluginTag::GetMimeDescriptions(uint32_t* aCount, char16_t*** aResults)
1012 {
1013 return CStringArrayToXPCArray(mMimeDescriptions, aCount, aResults);
1014 }
1015
1016 NS_IMETHODIMP
GetExtensions(uint32_t * aCount,char16_t *** aResults)1017 nsFakePluginTag::GetExtensions(uint32_t* aCount, char16_t*** aResults)
1018 {
1019 return CStringArrayToXPCArray(mExtensions, aCount, aResults);
1020 }
1021
1022 NS_IMETHODIMP
GetActive(bool * aResult)1023 nsFakePluginTag::GetActive(bool *aResult)
1024 {
1025 // Fake plugins can't be blocklisted, so this is just !Disabled
1026 *aResult = IsEnabled();
1027 return NS_OK;
1028 }
1029
1030 NS_IMETHODIMP
GetLastModifiedTime(PRTime * aLastModifiedTime)1031 nsFakePluginTag::GetLastModifiedTime(PRTime* aLastModifiedTime)
1032 {
1033 // FIXME-jsplugins What should this return, if anything?
1034 MOZ_ASSERT(aLastModifiedTime);
1035 *aLastModifiedTime = 0;
1036 return NS_OK;
1037 }
1038
1039 // We don't load fake plugins out of a library, so they should always be there.
1040 NS_IMETHODIMP
GetLoaded(bool * ret)1041 nsFakePluginTag::GetLoaded(bool* ret)
1042 {
1043 *ret = true;
1044 return NS_OK;
1045 }
1046