Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/. */
6 #include "nsNPAPIPlugin.h"
7 #include "nsNPAPIPluginInstance.h"
8 #include "nsIMemory.h"
9 #include "nsPluginsDir.h"
10 #include "nsPluginsDirUtils.h"
11 #include "prmem.h"
12 #include "prenv.h"
13 #include "prerror.h"
14 #include "prio.h"
15 #include <sys/stat.h>
16 #include "nsString.h"
17 #include "nsIFile.h"
18 #include "nsIPrefBranch.h"
19 #include "nsIPrefService.h"
21 #define LOCAL_PLUGIN_DLL_SUFFIX ".so"
22 #if defined(__hpux)
23 #define DEFAULT_X11_PATH "/usr/lib/X11R6/"
24 #undef LOCAL_PLUGIN_DLL_SUFFIX
25 #define LOCAL_PLUGIN_DLL_SUFFIX ".sl"
26 #define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".so"
27 #elif defined(_AIX)
28 #define DEFAULT_X11_PATH "/usr/lib"
29 #define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".a"
30 #elif defined(SOLARIS)
31 #define DEFAULT_X11_PATH "/usr/openwin/lib/"
32 #elif defined(LINUX)
33 #define DEFAULT_X11_PATH "/usr/X11R6/lib/"
34 #elif defined(__APPLE__)
35 #define DEFAULT_X11_PATH "/usr/X11R6/lib"
36 #undef LOCAL_PLUGIN_DLL_SUFFIX
37 #define LOCAL_PLUGIN_DLL_SUFFIX ".dylib"
38 #define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".so"
39 #else
40 #define DEFAULT_X11_PATH ""
41 #endif
43 #if (MOZ_WIDGET_GTK == 2)
45 #define PLUGIN_MAX_LEN_OF_TMP_ARR 512
47 static void DisplayPR_LoadLibraryErrorMessage(const char *libName)
48 {
49 char errorMsg[PLUGIN_MAX_LEN_OF_TMP_ARR] = "Cannot get error from NSPR.";
50 if (PR_GetErrorTextLength() < (int) sizeof(errorMsg))
51 PR_GetErrorText(errorMsg);
53 fprintf(stderr, "LoadPlugin: failed to initialize shared library %s [%s]\n",
54 libName, errorMsg);
55 }
57 static void SearchForSoname(const char* name, char** soname)
58 {
59 if (!(name && soname))
60 return;
61 PRDir *fdDir = PR_OpenDir(DEFAULT_X11_PATH);
62 if (!fdDir)
63 return;
65 int n = strlen(name);
66 PRDirEntry *dirEntry;
67 while ((dirEntry = PR_ReadDir(fdDir, PR_SKIP_BOTH))) {
68 if (!PL_strncmp(dirEntry->name, name, n)) {
69 if (dirEntry->name[n] == '.' && dirEntry->name[n+1] && !dirEntry->name[n+2]) {
70 // name.N, wild guess this is what we need
71 char out[PLUGIN_MAX_LEN_OF_TMP_ARR] = DEFAULT_X11_PATH;
72 PL_strcat(out, dirEntry->name);
73 *soname = PL_strdup(out);
74 break;
75 }
76 }
77 }
79 PR_CloseDir(fdDir);
80 }
82 static bool LoadExtraSharedLib(const char *name, char **soname, bool tryToGetSoname)
83 {
84 bool ret = true;
85 PRLibSpec tempSpec;
86 PRLibrary *handle;
87 tempSpec.type = PR_LibSpec_Pathname;
88 tempSpec.value.pathname = name;
89 handle = PR_LoadLibraryWithFlags(tempSpec, PR_LD_NOW|PR_LD_GLOBAL);
90 if (!handle) {
91 ret = false;
92 DisplayPR_LoadLibraryErrorMessage(name);
93 if (tryToGetSoname) {
94 SearchForSoname(name, soname);
95 if (*soname) {
96 ret = LoadExtraSharedLib((const char *) *soname, nullptr, false);
97 }
98 }
99 }
100 return ret;
101 }
103 #define PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS 32
104 #define PREF_PLUGINS_SONAME "plugin.soname.list"
105 #if defined(SOLARIS) || defined(HPUX)
106 #define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX ":libXm" LOCAL_PLUGIN_DLL_SUFFIX
107 #else
108 #define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX
109 #endif
110 /*
111 this function looks for
112 user_pref("plugin.soname.list", "/usr/X11R6/lib/libXt.so.6:libXext.so");
113 in user's pref.js
114 and loads all libs in specified order
115 */
117 static void LoadExtraSharedLibs()
118 {
119 // check out if user's prefs.js has libs name
120 nsresult res;
121 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &res));
122 if (NS_SUCCEEDED(res) && (prefs != nullptr)) {
123 char *sonameList = nullptr;
124 bool prefSonameListIsSet = true;
125 res = prefs->GetCharPref(PREF_PLUGINS_SONAME, &sonameList);
126 if (!sonameList) {
127 // pref is not set, lets use hardcoded list
128 prefSonameListIsSet = false;
129 sonameList = PL_strdup(DEFAULT_EXTRA_LIBS_LIST);
130 }
131 if (sonameList) {
132 char *arrayOfLibs[PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS] = {0};
133 int numOfLibs = 0;
134 char *nextToken;
135 char *p = nsCRT::strtok(sonameList,":",&nextToken);
136 if (p) {
137 while (p && numOfLibs < PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS) {
138 arrayOfLibs[numOfLibs++] = p;
139 p = nsCRT::strtok(nextToken,":",&nextToken);
140 }
141 } else // there is just one lib
142 arrayOfLibs[numOfLibs++] = sonameList;
144 char sonameListToSave[PLUGIN_MAX_LEN_OF_TMP_ARR] = "";
145 for (int i=0; i<numOfLibs; i++) {
146 // trim out head/tail white spaces (just in case)
147 bool head = true;
148 p = arrayOfLibs[i];
149 while (*p) {
150 if (*p == ' ' || *p == '\t') {
151 if (head) {
152 arrayOfLibs[i] = ++p;
153 } else {
154 *p = 0;
155 }
156 } else {
157 head = false;
158 p++;
159 }
160 }
161 if (!arrayOfLibs[i][0]) {
162 continue; // null string
163 }
164 bool tryToGetSoname = true;
165 if (PL_strchr(arrayOfLibs[i], '/')) {
166 //assuming it's real name, try to stat it
167 struct stat st;
168 if (stat((const char*) arrayOfLibs[i], &st)) {
169 //get just a file name
170 arrayOfLibs[i] = PL_strrchr(arrayOfLibs[i], '/') + 1;
171 } else
172 tryToGetSoname = false;
173 }
174 char *soname = nullptr;
175 if (LoadExtraSharedLib(arrayOfLibs[i], &soname, tryToGetSoname)) {
176 //construct soname's list to save in prefs
177 p = soname ? soname : arrayOfLibs[i];
178 int n = PLUGIN_MAX_LEN_OF_TMP_ARR -
179 (strlen(sonameListToSave) + strlen(p));
180 if (n > 0) {
181 PL_strcat(sonameListToSave, p);
182 PL_strcat(sonameListToSave,":");
183 }
184 if (soname) {
185 PL_strfree(soname); // it's from strdup
186 }
187 if (numOfLibs > 1)
188 arrayOfLibs[i][strlen(arrayOfLibs[i])] = ':'; //restore ":" in sonameList
189 }
190 }
192 // Check whether sonameListToSave is a empty String, Bug: 329205
193 if (sonameListToSave[0])
194 for (p = &sonameListToSave[strlen(sonameListToSave) - 1]; *p == ':'; p--)
195 *p = 0; //delete tail ":" delimiters
197 if (!prefSonameListIsSet || PL_strcmp(sonameList, sonameListToSave)) {
198 // if user specified some bogus soname I overwrite it here,
199 // otherwise it'll decrease performance by calling popen() in SearchForSoname
200 // every time for each bogus name
201 prefs->SetCharPref(PREF_PLUGINS_SONAME, (const char *)sonameListToSave);
202 }
203 PL_strfree(sonameList);
204 }
205 }
206 }
207 #endif //MOZ_WIDGET_GTK2
209 /* nsPluginsDir implementation */
211 bool nsPluginsDir::IsPluginFile(nsIFile* file)
212 {
213 nsAutoCString filename;
214 if (NS_FAILED(file->GetNativeLeafName(filename)))
215 return false;
217 #ifdef ANDROID
218 // It appears that if you load
219 // 'libstagefright_honeycomb.so' on froyo, or
220 // 'libstagefright_froyo.so' on honeycomb, we will abort.
221 // Since these are just helper libs, we can ignore.
222 const char *cFile = filename.get();
223 if (strstr(cFile, "libstagefright") != nullptr)
224 return false;
225 #endif
227 NS_NAMED_LITERAL_CSTRING(dllSuffix, LOCAL_PLUGIN_DLL_SUFFIX);
228 if (filename.Length() > dllSuffix.Length() &&
229 StringEndsWith(filename, dllSuffix))
230 return true;
232 #ifdef LOCAL_PLUGIN_DLL_ALT_SUFFIX
233 NS_NAMED_LITERAL_CSTRING(dllAltSuffix, LOCAL_PLUGIN_DLL_ALT_SUFFIX);
234 if (filename.Length() > dllAltSuffix.Length() &&
235 StringEndsWith(filename, dllAltSuffix))
236 return true;
237 #endif
238 return false;
239 }
241 /* nsPluginFile implementation */
243 nsPluginFile::nsPluginFile(nsIFile* file)
244 : mPlugin(file)
245 {
246 }
248 nsPluginFile::~nsPluginFile()
249 {
250 }
252 nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
253 {
254 PRLibSpec libSpec;
255 libSpec.type = PR_LibSpec_Pathname;
256 bool exists = false;
257 mPlugin->Exists(&exists);
258 if (!exists)
259 return NS_ERROR_FILE_NOT_FOUND;
261 nsresult rv;
262 nsAutoCString path;
263 rv = mPlugin->GetNativePath(path);
264 if (NS_FAILED(rv))
265 return rv;
267 libSpec.value.pathname = path.get();
269 #if (MOZ_WIDGET_GTK == 2)
271 // Normally, Mozilla isn't linked against libXt and libXext
272 // since it's a Gtk/Gdk application. On the other hand,
273 // legacy plug-ins expect the libXt and libXext symbols
274 // to already exist in the global name space. This plug-in
275 // wrapper is linked against libXt and libXext, but since
276 // we never call on any of these libraries, plug-ins still
277 // fail to resolve Xt symbols when trying to do a dlopen
278 // at runtime. Explicitly opening Xt/Xext into the global
279 // namespace before attempting to load the plug-in seems to
280 // work fine.
283 #if defined(SOLARIS) || defined(HPUX)
284 // Acrobat/libXm: Lazy resolving might cause crash later (bug 211587)
285 *outLibrary = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW);
286 pLibrary = *outLibrary;
287 #else
288 // Some dlopen() doesn't recover from a failed PR_LD_NOW (bug 223744)
289 *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
290 pLibrary = *outLibrary;
291 #endif
292 if (!pLibrary) {
293 LoadExtraSharedLibs();
294 // try reload plugin once more
295 *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
296 pLibrary = *outLibrary;
297 if (!pLibrary) {
298 DisplayPR_LoadLibraryErrorMessage(libSpec.value.pathname);
299 return NS_ERROR_FAILURE;
300 }
301 }
302 #else
303 *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
304 pLibrary = *outLibrary;
305 #endif // MOZ_WIDGET_GTK2
307 #ifdef DEBUG
308 printf("LoadPlugin() %s returned %lx\n",
309 libSpec.value.pathname, (unsigned long)pLibrary);
310 #endif
312 if (!pLibrary) {
313 return NS_ERROR_FAILURE;
314 }
316 return NS_OK;
317 }
319 nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary)
320 {
321 *outLibrary = nullptr;
323 info.fVersion = nullptr;
325 // Sadly we have to load the library for this to work.
326 nsresult rv = LoadPlugin(outLibrary);
327 if (NS_FAILED(rv))
328 return rv;
330 const char* (*npGetPluginVersion)() =
331 (const char* (*)()) PR_FindFunctionSymbol(pLibrary, "NP_GetPluginVersion");
332 if (npGetPluginVersion) {
333 info.fVersion = PL_strdup(npGetPluginVersion());
334 }
336 const char* (*npGetMIMEDescription)() =
337 (const char* (*)()) PR_FindFunctionSymbol(pLibrary, "NP_GetMIMEDescription");
338 if (!npGetMIMEDescription) {
339 return NS_ERROR_FAILURE;
340 }
342 const char* mimedescr = npGetMIMEDescription();
343 if (!mimedescr) {
344 return NS_ERROR_FAILURE;
345 }
347 rv = ParsePluginMimeDescription(mimedescr, info);
348 if (NS_FAILED(rv)) {
349 return rv;
350 }
352 nsAutoCString path;
353 if (NS_FAILED(rv = mPlugin->GetNativePath(path)))
354 return rv;
355 info.fFullPath = PL_strdup(path.get());
357 nsAutoCString fileName;
358 if (NS_FAILED(rv = mPlugin->GetNativeLeafName(fileName)))
359 return rv;
360 info.fFileName = PL_strdup(fileName.get());
362 NP_GetValueFunc npGetValue = (NP_GetValueFunc)PR_FindFunctionSymbol(pLibrary, "NP_GetValue");
363 if (!npGetValue) {
364 return NS_ERROR_FAILURE;
365 }
367 const char *name = nullptr;
368 npGetValue(nullptr, NPPVpluginNameString, &name);
369 if (name) {
370 info.fName = PL_strdup(name);
371 }
372 else {
373 info.fName = PL_strdup(fileName.get());
374 }
376 const char *description = nullptr;
377 npGetValue(nullptr, NPPVpluginDescriptionString, &description);
378 if (description) {
379 info.fDescription = PL_strdup(description);
380 }
381 else {
382 info.fDescription = PL_strdup("");
383 }
385 return NS_OK;
386 }
388 nsresult nsPluginFile::FreePluginInfo(nsPluginInfo& info)
389 {
390 if (info.fName != nullptr)
391 PL_strfree(info.fName);
393 if (info.fDescription != nullptr)
394 PL_strfree(info.fDescription);
396 for (uint32_t i = 0; i < info.fVariantCount; i++) {
397 if (info.fMimeTypeArray[i] != nullptr)
398 PL_strfree(info.fMimeTypeArray[i]);
400 if (info.fMimeDescriptionArray[i] != nullptr)
401 PL_strfree(info.fMimeDescriptionArray[i]);
403 if (info.fExtensionArray[i] != nullptr)
404 PL_strfree(info.fExtensionArray[i]);
405 }
407 PR_FREEIF(info.fMimeTypeArray);
408 PR_FREEIF(info.fMimeDescriptionArray);
409 PR_FREEIF(info.fExtensionArray);
411 if (info.fFullPath != nullptr)
412 PL_strfree(info.fFullPath);
414 if (info.fFileName != nullptr)
415 PL_strfree(info.fFileName);
417 if (info.fVersion != nullptr)
418 PL_strfree(info.fVersion);
420 return NS_OK;
421 }