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