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.

     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 }

mercurial