1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/plugins/base/nsPluginsDirUnix.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,421 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsNPAPIPlugin.h" 1.10 +#include "nsNPAPIPluginInstance.h" 1.11 +#include "nsIMemory.h" 1.12 +#include "nsPluginsDir.h" 1.13 +#include "nsPluginsDirUtils.h" 1.14 +#include "prmem.h" 1.15 +#include "prenv.h" 1.16 +#include "prerror.h" 1.17 +#include "prio.h" 1.18 +#include <sys/stat.h> 1.19 +#include "nsString.h" 1.20 +#include "nsIFile.h" 1.21 +#include "nsIPrefBranch.h" 1.22 +#include "nsIPrefService.h" 1.23 + 1.24 +#define LOCAL_PLUGIN_DLL_SUFFIX ".so" 1.25 +#if defined(__hpux) 1.26 +#define DEFAULT_X11_PATH "/usr/lib/X11R6/" 1.27 +#undef LOCAL_PLUGIN_DLL_SUFFIX 1.28 +#define LOCAL_PLUGIN_DLL_SUFFIX ".sl" 1.29 +#define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".so" 1.30 +#elif defined(_AIX) 1.31 +#define DEFAULT_X11_PATH "/usr/lib" 1.32 +#define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".a" 1.33 +#elif defined(SOLARIS) 1.34 +#define DEFAULT_X11_PATH "/usr/openwin/lib/" 1.35 +#elif defined(LINUX) 1.36 +#define DEFAULT_X11_PATH "/usr/X11R6/lib/" 1.37 +#elif defined(__APPLE__) 1.38 +#define DEFAULT_X11_PATH "/usr/X11R6/lib" 1.39 +#undef LOCAL_PLUGIN_DLL_SUFFIX 1.40 +#define LOCAL_PLUGIN_DLL_SUFFIX ".dylib" 1.41 +#define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".so" 1.42 +#else 1.43 +#define DEFAULT_X11_PATH "" 1.44 +#endif 1.45 + 1.46 +#if (MOZ_WIDGET_GTK == 2) 1.47 + 1.48 +#define PLUGIN_MAX_LEN_OF_TMP_ARR 512 1.49 + 1.50 +static void DisplayPR_LoadLibraryErrorMessage(const char *libName) 1.51 +{ 1.52 + char errorMsg[PLUGIN_MAX_LEN_OF_TMP_ARR] = "Cannot get error from NSPR."; 1.53 + if (PR_GetErrorTextLength() < (int) sizeof(errorMsg)) 1.54 + PR_GetErrorText(errorMsg); 1.55 + 1.56 + fprintf(stderr, "LoadPlugin: failed to initialize shared library %s [%s]\n", 1.57 + libName, errorMsg); 1.58 +} 1.59 + 1.60 +static void SearchForSoname(const char* name, char** soname) 1.61 +{ 1.62 + if (!(name && soname)) 1.63 + return; 1.64 + PRDir *fdDir = PR_OpenDir(DEFAULT_X11_PATH); 1.65 + if (!fdDir) 1.66 + return; 1.67 + 1.68 + int n = strlen(name); 1.69 + PRDirEntry *dirEntry; 1.70 + while ((dirEntry = PR_ReadDir(fdDir, PR_SKIP_BOTH))) { 1.71 + if (!PL_strncmp(dirEntry->name, name, n)) { 1.72 + if (dirEntry->name[n] == '.' && dirEntry->name[n+1] && !dirEntry->name[n+2]) { 1.73 + // name.N, wild guess this is what we need 1.74 + char out[PLUGIN_MAX_LEN_OF_TMP_ARR] = DEFAULT_X11_PATH; 1.75 + PL_strcat(out, dirEntry->name); 1.76 + *soname = PL_strdup(out); 1.77 + break; 1.78 + } 1.79 + } 1.80 + } 1.81 + 1.82 + PR_CloseDir(fdDir); 1.83 +} 1.84 + 1.85 +static bool LoadExtraSharedLib(const char *name, char **soname, bool tryToGetSoname) 1.86 +{ 1.87 + bool ret = true; 1.88 + PRLibSpec tempSpec; 1.89 + PRLibrary *handle; 1.90 + tempSpec.type = PR_LibSpec_Pathname; 1.91 + tempSpec.value.pathname = name; 1.92 + handle = PR_LoadLibraryWithFlags(tempSpec, PR_LD_NOW|PR_LD_GLOBAL); 1.93 + if (!handle) { 1.94 + ret = false; 1.95 + DisplayPR_LoadLibraryErrorMessage(name); 1.96 + if (tryToGetSoname) { 1.97 + SearchForSoname(name, soname); 1.98 + if (*soname) { 1.99 + ret = LoadExtraSharedLib((const char *) *soname, nullptr, false); 1.100 + } 1.101 + } 1.102 + } 1.103 + return ret; 1.104 +} 1.105 + 1.106 +#define PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS 32 1.107 +#define PREF_PLUGINS_SONAME "plugin.soname.list" 1.108 +#if defined(SOLARIS) || defined(HPUX) 1.109 +#define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX ":libXm" LOCAL_PLUGIN_DLL_SUFFIX 1.110 +#else 1.111 +#define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX 1.112 +#endif 1.113 +/* 1.114 + this function looks for 1.115 + user_pref("plugin.soname.list", "/usr/X11R6/lib/libXt.so.6:libXext.so"); 1.116 + in user's pref.js 1.117 + and loads all libs in specified order 1.118 +*/ 1.119 + 1.120 +static void LoadExtraSharedLibs() 1.121 +{ 1.122 + // check out if user's prefs.js has libs name 1.123 + nsresult res; 1.124 + nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &res)); 1.125 + if (NS_SUCCEEDED(res) && (prefs != nullptr)) { 1.126 + char *sonameList = nullptr; 1.127 + bool prefSonameListIsSet = true; 1.128 + res = prefs->GetCharPref(PREF_PLUGINS_SONAME, &sonameList); 1.129 + if (!sonameList) { 1.130 + // pref is not set, lets use hardcoded list 1.131 + prefSonameListIsSet = false; 1.132 + sonameList = PL_strdup(DEFAULT_EXTRA_LIBS_LIST); 1.133 + } 1.134 + if (sonameList) { 1.135 + char *arrayOfLibs[PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS] = {0}; 1.136 + int numOfLibs = 0; 1.137 + char *nextToken; 1.138 + char *p = nsCRT::strtok(sonameList,":",&nextToken); 1.139 + if (p) { 1.140 + while (p && numOfLibs < PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS) { 1.141 + arrayOfLibs[numOfLibs++] = p; 1.142 + p = nsCRT::strtok(nextToken,":",&nextToken); 1.143 + } 1.144 + } else // there is just one lib 1.145 + arrayOfLibs[numOfLibs++] = sonameList; 1.146 + 1.147 + char sonameListToSave[PLUGIN_MAX_LEN_OF_TMP_ARR] = ""; 1.148 + for (int i=0; i<numOfLibs; i++) { 1.149 + // trim out head/tail white spaces (just in case) 1.150 + bool head = true; 1.151 + p = arrayOfLibs[i]; 1.152 + while (*p) { 1.153 + if (*p == ' ' || *p == '\t') { 1.154 + if (head) { 1.155 + arrayOfLibs[i] = ++p; 1.156 + } else { 1.157 + *p = 0; 1.158 + } 1.159 + } else { 1.160 + head = false; 1.161 + p++; 1.162 + } 1.163 + } 1.164 + if (!arrayOfLibs[i][0]) { 1.165 + continue; // null string 1.166 + } 1.167 + bool tryToGetSoname = true; 1.168 + if (PL_strchr(arrayOfLibs[i], '/')) { 1.169 + //assuming it's real name, try to stat it 1.170 + struct stat st; 1.171 + if (stat((const char*) arrayOfLibs[i], &st)) { 1.172 + //get just a file name 1.173 + arrayOfLibs[i] = PL_strrchr(arrayOfLibs[i], '/') + 1; 1.174 + } else 1.175 + tryToGetSoname = false; 1.176 + } 1.177 + char *soname = nullptr; 1.178 + if (LoadExtraSharedLib(arrayOfLibs[i], &soname, tryToGetSoname)) { 1.179 + //construct soname's list to save in prefs 1.180 + p = soname ? soname : arrayOfLibs[i]; 1.181 + int n = PLUGIN_MAX_LEN_OF_TMP_ARR - 1.182 + (strlen(sonameListToSave) + strlen(p)); 1.183 + if (n > 0) { 1.184 + PL_strcat(sonameListToSave, p); 1.185 + PL_strcat(sonameListToSave,":"); 1.186 + } 1.187 + if (soname) { 1.188 + PL_strfree(soname); // it's from strdup 1.189 + } 1.190 + if (numOfLibs > 1) 1.191 + arrayOfLibs[i][strlen(arrayOfLibs[i])] = ':'; //restore ":" in sonameList 1.192 + } 1.193 + } 1.194 + 1.195 + // Check whether sonameListToSave is a empty String, Bug: 329205 1.196 + if (sonameListToSave[0]) 1.197 + for (p = &sonameListToSave[strlen(sonameListToSave) - 1]; *p == ':'; p--) 1.198 + *p = 0; //delete tail ":" delimiters 1.199 + 1.200 + if (!prefSonameListIsSet || PL_strcmp(sonameList, sonameListToSave)) { 1.201 + // if user specified some bogus soname I overwrite it here, 1.202 + // otherwise it'll decrease performance by calling popen() in SearchForSoname 1.203 + // every time for each bogus name 1.204 + prefs->SetCharPref(PREF_PLUGINS_SONAME, (const char *)sonameListToSave); 1.205 + } 1.206 + PL_strfree(sonameList); 1.207 + } 1.208 + } 1.209 +} 1.210 +#endif //MOZ_WIDGET_GTK2 1.211 + 1.212 +/* nsPluginsDir implementation */ 1.213 + 1.214 +bool nsPluginsDir::IsPluginFile(nsIFile* file) 1.215 +{ 1.216 + nsAutoCString filename; 1.217 + if (NS_FAILED(file->GetNativeLeafName(filename))) 1.218 + return false; 1.219 + 1.220 +#ifdef ANDROID 1.221 + // It appears that if you load 1.222 + // 'libstagefright_honeycomb.so' on froyo, or 1.223 + // 'libstagefright_froyo.so' on honeycomb, we will abort. 1.224 + // Since these are just helper libs, we can ignore. 1.225 + const char *cFile = filename.get(); 1.226 + if (strstr(cFile, "libstagefright") != nullptr) 1.227 + return false; 1.228 +#endif 1.229 + 1.230 + NS_NAMED_LITERAL_CSTRING(dllSuffix, LOCAL_PLUGIN_DLL_SUFFIX); 1.231 + if (filename.Length() > dllSuffix.Length() && 1.232 + StringEndsWith(filename, dllSuffix)) 1.233 + return true; 1.234 + 1.235 +#ifdef LOCAL_PLUGIN_DLL_ALT_SUFFIX 1.236 + NS_NAMED_LITERAL_CSTRING(dllAltSuffix, LOCAL_PLUGIN_DLL_ALT_SUFFIX); 1.237 + if (filename.Length() > dllAltSuffix.Length() && 1.238 + StringEndsWith(filename, dllAltSuffix)) 1.239 + return true; 1.240 +#endif 1.241 + return false; 1.242 +} 1.243 + 1.244 +/* nsPluginFile implementation */ 1.245 + 1.246 +nsPluginFile::nsPluginFile(nsIFile* file) 1.247 +: mPlugin(file) 1.248 +{ 1.249 +} 1.250 + 1.251 +nsPluginFile::~nsPluginFile() 1.252 +{ 1.253 +} 1.254 + 1.255 +nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary) 1.256 +{ 1.257 + PRLibSpec libSpec; 1.258 + libSpec.type = PR_LibSpec_Pathname; 1.259 + bool exists = false; 1.260 + mPlugin->Exists(&exists); 1.261 + if (!exists) 1.262 + return NS_ERROR_FILE_NOT_FOUND; 1.263 + 1.264 + nsresult rv; 1.265 + nsAutoCString path; 1.266 + rv = mPlugin->GetNativePath(path); 1.267 + if (NS_FAILED(rv)) 1.268 + return rv; 1.269 + 1.270 + libSpec.value.pathname = path.get(); 1.271 + 1.272 +#if (MOZ_WIDGET_GTK == 2) 1.273 + 1.274 + // Normally, Mozilla isn't linked against libXt and libXext 1.275 + // since it's a Gtk/Gdk application. On the other hand, 1.276 + // legacy plug-ins expect the libXt and libXext symbols 1.277 + // to already exist in the global name space. This plug-in 1.278 + // wrapper is linked against libXt and libXext, but since 1.279 + // we never call on any of these libraries, plug-ins still 1.280 + // fail to resolve Xt symbols when trying to do a dlopen 1.281 + // at runtime. Explicitly opening Xt/Xext into the global 1.282 + // namespace before attempting to load the plug-in seems to 1.283 + // work fine. 1.284 + 1.285 + 1.286 +#if defined(SOLARIS) || defined(HPUX) 1.287 + // Acrobat/libXm: Lazy resolving might cause crash later (bug 211587) 1.288 + *outLibrary = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW); 1.289 + pLibrary = *outLibrary; 1.290 +#else 1.291 + // Some dlopen() doesn't recover from a failed PR_LD_NOW (bug 223744) 1.292 + *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0); 1.293 + pLibrary = *outLibrary; 1.294 +#endif 1.295 + if (!pLibrary) { 1.296 + LoadExtraSharedLibs(); 1.297 + // try reload plugin once more 1.298 + *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0); 1.299 + pLibrary = *outLibrary; 1.300 + if (!pLibrary) { 1.301 + DisplayPR_LoadLibraryErrorMessage(libSpec.value.pathname); 1.302 + return NS_ERROR_FAILURE; 1.303 + } 1.304 + } 1.305 +#else 1.306 + *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0); 1.307 + pLibrary = *outLibrary; 1.308 +#endif // MOZ_WIDGET_GTK2 1.309 + 1.310 +#ifdef DEBUG 1.311 + printf("LoadPlugin() %s returned %lx\n", 1.312 + libSpec.value.pathname, (unsigned long)pLibrary); 1.313 +#endif 1.314 + 1.315 + if (!pLibrary) { 1.316 + return NS_ERROR_FAILURE; 1.317 + } 1.318 + 1.319 + return NS_OK; 1.320 +} 1.321 + 1.322 +nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary) 1.323 +{ 1.324 + *outLibrary = nullptr; 1.325 + 1.326 + info.fVersion = nullptr; 1.327 + 1.328 + // Sadly we have to load the library for this to work. 1.329 + nsresult rv = LoadPlugin(outLibrary); 1.330 + if (NS_FAILED(rv)) 1.331 + return rv; 1.332 + 1.333 + const char* (*npGetPluginVersion)() = 1.334 + (const char* (*)()) PR_FindFunctionSymbol(pLibrary, "NP_GetPluginVersion"); 1.335 + if (npGetPluginVersion) { 1.336 + info.fVersion = PL_strdup(npGetPluginVersion()); 1.337 + } 1.338 + 1.339 + const char* (*npGetMIMEDescription)() = 1.340 + (const char* (*)()) PR_FindFunctionSymbol(pLibrary, "NP_GetMIMEDescription"); 1.341 + if (!npGetMIMEDescription) { 1.342 + return NS_ERROR_FAILURE; 1.343 + } 1.344 + 1.345 + const char* mimedescr = npGetMIMEDescription(); 1.346 + if (!mimedescr) { 1.347 + return NS_ERROR_FAILURE; 1.348 + } 1.349 + 1.350 + rv = ParsePluginMimeDescription(mimedescr, info); 1.351 + if (NS_FAILED(rv)) { 1.352 + return rv; 1.353 + } 1.354 + 1.355 + nsAutoCString path; 1.356 + if (NS_FAILED(rv = mPlugin->GetNativePath(path))) 1.357 + return rv; 1.358 + info.fFullPath = PL_strdup(path.get()); 1.359 + 1.360 + nsAutoCString fileName; 1.361 + if (NS_FAILED(rv = mPlugin->GetNativeLeafName(fileName))) 1.362 + return rv; 1.363 + info.fFileName = PL_strdup(fileName.get()); 1.364 + 1.365 + NP_GetValueFunc npGetValue = (NP_GetValueFunc)PR_FindFunctionSymbol(pLibrary, "NP_GetValue"); 1.366 + if (!npGetValue) { 1.367 + return NS_ERROR_FAILURE; 1.368 + } 1.369 + 1.370 + const char *name = nullptr; 1.371 + npGetValue(nullptr, NPPVpluginNameString, &name); 1.372 + if (name) { 1.373 + info.fName = PL_strdup(name); 1.374 + } 1.375 + else { 1.376 + info.fName = PL_strdup(fileName.get()); 1.377 + } 1.378 + 1.379 + const char *description = nullptr; 1.380 + npGetValue(nullptr, NPPVpluginDescriptionString, &description); 1.381 + if (description) { 1.382 + info.fDescription = PL_strdup(description); 1.383 + } 1.384 + else { 1.385 + info.fDescription = PL_strdup(""); 1.386 + } 1.387 + 1.388 + return NS_OK; 1.389 +} 1.390 + 1.391 +nsresult nsPluginFile::FreePluginInfo(nsPluginInfo& info) 1.392 +{ 1.393 + if (info.fName != nullptr) 1.394 + PL_strfree(info.fName); 1.395 + 1.396 + if (info.fDescription != nullptr) 1.397 + PL_strfree(info.fDescription); 1.398 + 1.399 + for (uint32_t i = 0; i < info.fVariantCount; i++) { 1.400 + if (info.fMimeTypeArray[i] != nullptr) 1.401 + PL_strfree(info.fMimeTypeArray[i]); 1.402 + 1.403 + if (info.fMimeDescriptionArray[i] != nullptr) 1.404 + PL_strfree(info.fMimeDescriptionArray[i]); 1.405 + 1.406 + if (info.fExtensionArray[i] != nullptr) 1.407 + PL_strfree(info.fExtensionArray[i]); 1.408 + } 1.409 + 1.410 + PR_FREEIF(info.fMimeTypeArray); 1.411 + PR_FREEIF(info.fMimeDescriptionArray); 1.412 + PR_FREEIF(info.fExtensionArray); 1.413 + 1.414 + if (info.fFullPath != nullptr) 1.415 + PL_strfree(info.fFullPath); 1.416 + 1.417 + if (info.fFileName != nullptr) 1.418 + PL_strfree(info.fFileName); 1.419 + 1.420 + if (info.fVersion != nullptr) 1.421 + PL_strfree(info.fVersion); 1.422 + 1.423 + return NS_OK; 1.424 +}