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