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 #ifndef nsPluginHost_h_
7 #define nsPluginHost_h_
8 
9 #include "mozilla/LinkedList.h"
10 #include "mozilla/StaticPtr.h"
11 
12 #include "nsIPluginHost.h"
13 #include "nsIObserver.h"
14 #include "nsCOMPtr.h"
15 #include "prlink.h"
16 #include "nsIPluginTag.h"
17 #include "nsPluginsDir.h"
18 #include "nsWeakReference.h"
19 #include "MainThreadUtils.h"
20 #include "nsTArray.h"
21 #include "nsINamed.h"
22 #include "nsTObserverArray.h"
23 #include "nsITimer.h"
24 #include "nsPluginTags.h"
25 #include "nsIEffectiveTLDService.h"
26 #include "nsIIDNService.h"
27 #include "nsCRT.h"
28 #include "mozilla/dom/PromiseNativeHandler.h"
29 #include "mozilla/plugins/PluginTypes.h"
30 
31 #ifdef XP_WIN
32 #  include <minwindef.h>
33 #  include "nsIWindowsRegKey.h"
34 #endif
35 
36 namespace mozilla {
37 namespace plugins {
38 class BlocklistPromiseHandler;
39 }  // namespace plugins
40 namespace dom {
41 class ContentParent;
42 }  // namespace dom
43 }  // namespace mozilla
44 
45 class nsNPAPIPlugin;
46 class nsIFile;
47 class nsIChannel;
48 class nsPluginNativeWindow;
49 class nsObjectLoadingContent;
50 class nsPluginInstanceOwner;
51 class nsPluginUnloadRunnable;
52 class nsNPAPIPluginInstance;
53 class nsNPAPIPluginStreamListener;
54 class nsIPluginInstanceOwner;
55 class nsIInputStream;
56 class nsIStreamListener;
57 #ifndef npapi_h_
58 struct _NPP;
59 typedef _NPP* NPP;
60 #endif
61 
62 class PluginFinder;
63 
64 class nsPluginHost final : public nsIPluginHost,
65                            public nsIObserver,
66                            public nsITimerCallback,
67                            public nsSupportsWeakReference,
68                            public nsINamed {
69   friend class nsPluginTag;
70   friend class nsFakePluginTag;
71   friend class PluginFinder;
72   virtual ~nsPluginHost();
73 
74  public:
75   nsPluginHost();
76 
77   static already_AddRefed<nsPluginHost> GetInst();
78 
79   NS_DECL_ISUPPORTS
80   NS_DECL_NSIPLUGINHOST
81   NS_DECL_NSIOBSERVER
82   NS_DECL_NSITIMERCALLBACK
83   NS_DECL_NSINAMED
84 
85   // Acts like a bitfield
86   enum PluginFilter {
87     eExcludeNone = nsIPluginHost::EXCLUDE_NONE,
88     eExcludeDisabled = nsIPluginHost::EXCLUDE_DISABLED,
89     eExcludeFake = nsIPluginHost::EXCLUDE_FAKE
90   };
91   // FIXME-jsplugins comment about fake
92   bool HavePluginForType(const nsACString& aMimeType,
93                          PluginFilter aFilter = eExcludeDisabled);
94 
95   // FIXME-jsplugins what if fake has different extensions
96   bool HavePluginForExtension(const nsACString& aExtension,
97                               /* out */ nsACString& aMimeType,
98                               PluginFilter aFilter = eExcludeDisabled);
99 
100   void GetPlugins(nsTArray<nsCOMPtr<nsIInternalPluginTag>>& aPluginArray,
101                   bool aIncludeDisabled = false);
102 
103   nsresult GetURL(nsISupports* pluginInst, const char* url, const char* target,
104                   nsNPAPIPluginStreamListener* streamListener,
105                   const char* altHost, const char* referrer,
106                   bool forceJSEnabled);
107   nsresult PostURL(nsISupports* pluginInst, const char* url,
108                    uint32_t postDataLen, const char* postData,
109                    const char* target,
110                    nsNPAPIPluginStreamListener* streamListener,
111                    const char* altHost, const char* referrer,
112                    bool forceJSEnabled, uint32_t postHeadersLength,
113                    const char* postHeaders);
114 
115   nsresult UserAgent(const char** retstring);
116   nsresult ParsePostBufferToFixHeaders(const char* inPostData,
117                                        uint32_t inPostDataLen,
118                                        char** outPostData,
119                                        uint32_t* outPostDataLen);
120   nsresult NewPluginNativeWindow(nsPluginNativeWindow** aPluginNativeWindow);
121 
122   void AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, bool isVisible);
123   void RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame);
124 
125   nsresult GetPluginName(nsNPAPIPluginInstance* aPluginInstance,
126                          const char** aPluginName);
127   nsresult StopPluginInstance(nsNPAPIPluginInstance* aInstance);
128   nsresult GetPluginTagForInstance(nsNPAPIPluginInstance* aPluginInstance,
129                                    nsIPluginTag** aPluginTag);
130 
131   nsresult NewPluginURLStream(const nsString& aURL,
132                               nsNPAPIPluginInstance* aInstance,
133                               nsNPAPIPluginStreamListener* aListener,
134                               nsIInputStream* aPostStream = nullptr,
135                               const char* aHeadersData = nullptr,
136                               uint32_t aHeadersDataLen = 0);
137 
138   nsresult GetURLWithHeaders(
139       nsNPAPIPluginInstance* pluginInst, const char* url,
140       const char* target = nullptr,
141       nsNPAPIPluginStreamListener* streamListener = nullptr,
142       const char* altHost = nullptr, const char* referrer = nullptr,
143       bool forceJSEnabled = false, uint32_t getHeadersLength = 0,
144       const char* getHeaders = nullptr);
145 
146   nsresult AddHeadersToChannel(const char* aHeadersData,
147                                uint32_t aHeadersDataLen,
148                                nsIChannel* aGenericChannel);
149 
150   // Helper that checks if a type is whitelisted in plugin.allowed_types.
151   // Always returns true if plugin.allowed_types is not set
152   static bool IsTypeWhitelisted(const char* aType);
153 
154   /**
155    * Returns true if a plugin can be used to load the requested MIME type. Used
156    * for short circuiting before sending things to plugin code.
157    */
158   static bool CanUsePluginForMIMEType(const nsACString& aMIMEType);
159 
160   // checks whether aType is a type we recognize for potential special handling
161   enum SpecialType {
162     eSpecialType_None,
163     // Needed to whitelist for async init support
164     eSpecialType_Test,
165     // Informs some decisions about OOP and quirks
166     eSpecialType_Flash
167   };
168   static SpecialType GetSpecialType(const nsACString& aMIMEType);
169 
170   static nsresult PostPluginUnloadEvent(PRLibrary* aLibrary);
171 
172   void PluginCrashed(nsNPAPIPlugin* aPlugin, const nsAString& aPluginDumpID,
173                      const nsACString& aAdditionalMinidumps);
174 
175   nsNPAPIPluginInstance* FindInstance(const char* mimetype);
176   nsNPAPIPluginInstance* FindOldestStoppedInstance();
177   uint32_t StoppedInstanceCount();
178 
179   nsTArray<RefPtr<nsNPAPIPluginInstance>>* InstanceArray();
180 
181   // Return the tag for |aLibrary| if found, nullptr if not.
182   nsPluginTag* FindTagForLibrary(PRLibrary* aLibrary);
183 
184   // The last argument should be false if we already have an in-flight stream
185   // and don't need to set up a new stream.
186   nsresult InstantiatePluginInstance(const nsACString& aMimeType, nsIURI* aURL,
187                                      nsObjectLoadingContent* aContent,
188                                      nsPluginInstanceOwner** aOwner);
189 
190   // Does not accept nullptr and should never fail.
191   nsPluginTag* TagForPlugin(nsNPAPIPlugin* aPlugin);
192 
193   nsPluginTag* PluginWithId(uint32_t aId);
194 
195   nsresult GetPlugin(const nsACString& aMimeType, nsNPAPIPlugin** aPlugin);
196   nsresult GetPluginForContentProcess(uint32_t aPluginId,
197                                       nsNPAPIPlugin** aPlugin);
198   void NotifyContentModuleDestroyed(uint32_t aPluginId);
199 
200   nsresult NewPluginStreamListener(nsIURI* aURL,
201                                    nsNPAPIPluginInstance* aInstance,
202                                    nsIStreamListener** aStreamListener);
203 
204   void CreateWidget(nsPluginInstanceOwner* aOwner);
205 
206   nsresult EnumerateSiteData(const nsACString& domain,
207                              const nsTArray<nsCString>& sites,
208                              nsTArray<nsCString>& result, bool firstMatchOnly);
209 
210   nsresult UpdateCachedSerializablePluginList();
211   nsresult SendPluginsToContent(mozilla::dom::ContentParent* parent);
212   nsresult SetPluginsInContent(
213       uint32_t aPluginEpoch, nsTArray<mozilla::plugins::PluginTag>& aPlugins,
214       nsTArray<mozilla::plugins::FakePluginTag>& aFakePlugins);
215 
216   void UpdatePluginBlocklistState(nsPluginTag* aPluginTag,
217                                   bool aShouldSoftblock = false);
218 
219  private:
220   nsresult LoadPlugins();
221   nsresult UnloadPlugins();
222 
223   nsresult SetUpPluginInstance(const nsACString& aMimeType, nsIURI* aURL,
224                                nsPluginInstanceOwner* aOwner);
225 
226   friend class nsPluginUnloadRunnable;
227   friend class mozilla::plugins::BlocklistPromiseHandler;
228 
229   void DestroyRunningInstances(nsPluginTag* aPluginTag);
230 
231   // Writes updated plugins settings to disk and unloads the plugin
232   // if it is now disabled. Should only be called by the plugin tag in question
233   void UpdatePluginInfo(nsPluginTag* aPluginTag);
234 
235   nsresult TrySetUpPluginInstance(const nsACString& aMimeType, nsIURI* aURL,
236                                   nsPluginInstanceOwner* aOwner);
237 
238   // FIXME-jsplugins comment here about when things may be fake
239   nsPluginTag* FindPreferredPlugin(const nsTArray<nsPluginTag*>& matches);
240 
241   // Find a plugin for the given type.  If aIncludeFake is true a fake plugin
242   // will be preferred if one exists; otherwise a fake plugin will never be
243   // returned.  If aCheckEnabled is false, disabled plugins can be returned.
244   nsIInternalPluginTag* FindPluginForType(const nsACString& aMimeType,
245                                           bool aIncludeFake,
246                                           bool aCheckEnabled);
247 
248   // Find specifically a fake plugin for the given type.  If aCheckEnabled is
249   // false, disabled plugins can be returned.
250   nsFakePluginTag* FindFakePluginForType(const nsACString& aMimeType,
251                                          bool aCheckEnabled);
252 
253   // Find specifically a fake plugin for the given extension.  If aCheckEnabled
254   // is false, disabled plugins can be returned.  aMimeType will be filled in
255   // with the MIME type the plugin is registered for.
256   nsFakePluginTag* FindFakePluginForExtension(const nsACString& aExtension,
257                                               /* out */ nsACString& aMimeType,
258                                               bool aCheckEnabled);
259 
260   // Find specifically a native (NPAPI) plugin for the given type.  If
261   // aCheckEnabled is false, disabled plugins can be returned.
262   nsPluginTag* FindNativePluginForType(const nsACString& aMimeType,
263                                        bool aCheckEnabled);
264 
265   // Find specifically a native (NPAPI) plugin for the given extension.  If
266   // aCheckEnabled is false, disabled plugins can be returned.  aMimeType will
267   // be filled in with the MIME type the plugin is registered for.
268   nsPluginTag* FindNativePluginForExtension(const nsACString& aExtension,
269                                             /* out */ nsACString& aMimeType,
270                                             bool aCheckEnabled);
271 
272   nsresult FindStoppedPluginForURL(nsIURI* aURL,
273                                    nsIPluginInstanceOwner* aOwner);
274 
275   nsresult BroadcastPluginsToContent();
276 
277   // FIXME revisit, no ns prefix
278   // Registers or unregisters the given mime type with the category manager
279   enum nsRegisterType {
280     ePluginRegister,
281     ePluginUnregister,
282     // Checks if this type should still be registered first
283     ePluginMaybeUnregister
284   };
285   void RegisterWithCategoryManager(const nsCString& aMimeType,
286                                    nsRegisterType aType);
287 
288   void AddPluginTag(nsPluginTag* aPluginTag);
289 
290   nsresult EnsurePluginLoaded(nsPluginTag* aPluginTag);
291 
292   bool IsRunningPlugin(nsPluginTag* aPluginTag);
293 
294   // Checks to see if a tag object is in our list of live tags.
295   bool IsLiveTag(nsIPluginTag* tag);
296 
297   // Checks our list of live tags for an equivalent tag.
298   nsPluginTag* HaveSamePlugin(const nsPluginTag* aPluginTag);
299 
300   void OnPluginInstanceDestroyed(nsPluginTag* aPluginTag);
301 
302   // To be used by the chrome process whenever the set of plugins changes.
303   void IncrementChromeEpoch();
304 
305   // To be used by the chrome process; returns the current epoch.
306   uint32_t ChromeEpoch();
307 
308   // To be used by the content process to get/set the last observed epoch value
309   // from the chrome process.
310   uint32_t ChromeEpochForContent();
311   void SetChromeEpochForContent(uint32_t aEpoch);
312 
313   void UpdateInMemoryPluginInfo(nsPluginTag* aPluginTag);
314 
315   void ClearNonRunningPlugins();
316   nsresult ActuallyReloadPlugins();
317 
318   // Callback into the host from PluginFinder once it's done.
319   void FindingFinished();
320 
321   RefPtr<nsPluginTag> mPlugins;
322 
323   nsTArray<RefPtr<nsFakePluginTag>> mFakePlugins;
324 
325   AutoTArray<mozilla::plugins::PluginTag, 1> mSerializablePlugins;
326   nsTArray<mozilla::plugins::FakePluginTag> mSerializableFakePlugins;
327 
328   bool mPluginsLoaded;
329 
330   // set by pref plugin.override_internal_types
331   bool mOverrideInternalTypes;
332 
333   // set by pref plugin.disable
334   bool mPluginsDisabled;
335 
336   // set by pref plugin.load_flash_only
337   bool mFlashOnly;
338 
339   // Only one plugin finding operation should be run at a time.
340   RefPtr<PluginFinder> mPendingFinder;
341   bool mDoReloadOnceFindingFinished;
342   bool mAddedFinderShutdownBlocker;
343 
344   // Any instances in this array will have valid plugin objects via GetPlugin().
345   // When removing an instance it might not die - be sure to null out it's
346   // plugin.
347   nsTArray<RefPtr<nsNPAPIPluginInstance>> mInstances;
348 
349   // An nsIFile for the pluginreg.dat file in the profile.
350 #ifdef XP_WIN
351   // In order to reload plugins when they change, we watch the registry via
352   // this object.
353   nsCOMPtr<nsIWindowsRegKey> mRegKeyHKLM;
354   nsCOMPtr<nsIWindowsRegKey> mRegKeyHKCU;
355 #endif
356 
357   nsCOMPtr<nsIEffectiveTLDService> mTLDService;
358   nsCOMPtr<nsIIDNService> mIDNService;
359 
360   // Helpers for ClearSiteData and SiteHasData.
361   nsresult NormalizeHostname(nsCString& host);
362 
363   nsWeakPtr mCurrentDocument;  // weak reference, we use it to id document only
364 
365   // This epoch increases each time we load the list of plugins from disk.
366   // In the chrome process, this stores the actual epoch.
367   // In the content process, this stores the last epoch value observed
368   // when reading plugins from chrome.
369   uint32_t mPluginEpoch;
370 
371   static nsIFile* sPluginTempDir;
372 
373   // We need to hold a global ptr to ourselves because we register for
374   // two different CIDs for some reason...
375   static mozilla::StaticRefPtr<nsPluginHost> sInst;
376 };
377 
378 class PluginDestructionGuard
379     : public mozilla::LinkedListElement<PluginDestructionGuard> {
380  public:
381   explicit PluginDestructionGuard(nsNPAPIPluginInstance* aInstance);
382   explicit PluginDestructionGuard(NPP npp);
383 
384   ~PluginDestructionGuard();
385 
386   static bool DelayDestroy(nsNPAPIPluginInstance* aInstance);
387 
388  protected:
Init()389   void Init() {
390     NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
391 
392     mDelayedDestroy = false;
393 
394     sList.insertBack(this);
395   }
396 
397   RefPtr<nsNPAPIPluginInstance> mInstance;
398   bool mDelayedDestroy;
399 
400   static mozilla::LinkedList<PluginDestructionGuard> sList;
401 };
402 
403 #endif  // nsPluginHost_h_
404