dom/plugins/base/nsPluginsDirUnix.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial