/** * Obtains all of the information currently available for this plugin. */ nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info) { nsresult rv = NS_OK; // clear out the info, except for the first field. memset(&info, 0, sizeof(info)); // First open up resource we can use to get plugin info. #ifndef __LP64__ // Try to open a resource fork. nsAutoCloseResourceObject resourceObject(mPlugin); bool resourceOpened = resourceObject.ResourceOpened(); #endif // Try to get a bundle reference. nsCAutoString path; if (NS_FAILED(rv = mPlugin->GetNativePath(path))) return rv; CFBundleRef bundle = getPluginBundle(path.get()); // fill in full path info.fFullPath = PL_strdup(path.get()); // fill in file name nsCAutoString fileName; if (NS_FAILED(rv = mPlugin->GetNativeLeafName(fileName))) return rv; info.fFileName = PL_strdup(fileName.get()); // Get fBundle if (bundle) info.fBundle = PR_TRUE; // Get fName if (bundle) { CFTypeRef name = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginName")); if (name && ::CFGetTypeID(name) == ::CFStringGetTypeID()) info.fName = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(name)); } #ifndef __LP64__ if (!info.fName && resourceOpened) { // 'STR#', 126, 2 => plugin name. info.fName = GetPluginString(126, 2); } #endif // Get fDescription if (bundle) { CFTypeRef description = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginDescription")); if (description && ::CFGetTypeID(description) == ::CFStringGetTypeID()) info.fDescription = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(description)); } #ifndef __LP64__ if (!info.fDescription && resourceOpened) { // 'STR#', 126, 1 => plugin description. info.fDescription = GetPluginString(126, 1); } #endif // Get fVersion if (bundle) { // Look for the release version first CFTypeRef version = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("CFBundleShortVersionString")); if (!version) // try the build version version = ::CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleVersionKey); if (version && ::CFGetTypeID(version) == ::CFStringGetTypeID()) info.fVersion = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(version)); } // The last thing we need to do is get MIME data // fVariantCount, fMimeTypeArray, fExtensionArray, fMimeDescriptionArray // First look for data in a bundle plist if (bundle) { ParsePlistPluginInfo(info, bundle); ::CFRelease(bundle); if (info.fVariantCount > 0) return NS_OK; } // It's possible that our plugin has 2 entry points that'll give us mime type // info. Quicktime does this to get around the need of having admin rights to // change mime info in the resource fork. We need to use this info instead of // the resource. See bug 113464. // Try to get data from NP_GetMIMEDescription if (pLibrary) { NP_GETMIMEDESCRIPTION pfnGetMimeDesc = (NP_GETMIMEDESCRIPTION)PR_FindFunctionSymbol(pLibrary, NP_GETMIMEDESCRIPTION_NAME); if (pfnGetMimeDesc) ParsePluginMimeDescription(pfnGetMimeDesc(), info); if (info.fVariantCount) return NS_OK; } // We'll fill this in using BP_GetSupportedMIMETypes and/or resource fork data BPSupportedMIMETypes mi = {kBPSupportedMIMETypesStructVers_1, NULL, NULL}; // Try to get data from BP_GetSupportedMIMETypes if (pLibrary) { BP_GETSUPPORTEDMIMETYPES pfnMime = (BP_GETSUPPORTEDMIMETYPES)PR_FindFunctionSymbol(pLibrary, "BP_GetSupportedMIMETypes"); if (pfnMime && noErr == pfnMime(&mi, 0) && mi.typeStrings) { info.fVariantCount = (**(short**)mi.typeStrings) / 2; ::HLock(mi.typeStrings); if (mi.infoStrings) // it's possible some plugins have infoStrings missing ::HLock(mi.infoStrings); } } #ifndef __LP64__ // Try to get data from the resource fork if (!info.fVariantCount && resourceObject.ResourceOpened()) { mi.typeStrings = ::Get1Resource('STR#', 128); if (mi.typeStrings) { info.fVariantCount = (**(short**)mi.typeStrings) / 2; ::DetachResource(mi.typeStrings); ::HLock(mi.typeStrings); } else { // Don't add this plugin because no mime types could be found return NS_ERROR_FAILURE; } mi.infoStrings = ::Get1Resource('STR#', 127); if (mi.infoStrings) { ::DetachResource(mi.infoStrings); ::HLock(mi.infoStrings); } } #endif // Fill in the info struct based on the data in the BPSupportedMIMETypes struct int variantCount = info.fVariantCount; info.fMimeTypeArray = static_cast<char**>(NS_Alloc(variantCount * sizeof(char*))); if (!info.fMimeTypeArray) return NS_ERROR_OUT_OF_MEMORY; info.fExtensionArray = static_cast<char**>(NS_Alloc(variantCount * sizeof(char*))); if (!info.fExtensionArray) return NS_ERROR_OUT_OF_MEMORY; if (mi.infoStrings) { info.fMimeDescriptionArray = static_cast<char**>(NS_Alloc(variantCount * sizeof(char*))); if (!info.fMimeDescriptionArray) return NS_ERROR_OUT_OF_MEMORY; } short mimeIndex = 2; short descriptionIndex = 2; for (int i = 0; i < variantCount; i++) { info.fMimeTypeArray[i] = GetNextPluginStringFromHandle(mi.typeStrings, &mimeIndex); info.fExtensionArray[i] = GetNextPluginStringFromHandle(mi.typeStrings, &mimeIndex); if (mi.infoStrings) info.fMimeDescriptionArray[i] = GetNextPluginStringFromHandle(mi.infoStrings, &descriptionIndex); } ::HUnlock(mi.typeStrings); ::DisposeHandle(mi.typeStrings); if (mi.infoStrings) { ::HUnlock(mi.infoStrings); ::DisposeHandle(mi.infoStrings); } return NS_OK; }
/** * Obtains all of the information currently available for this plugin. */ nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary) { *outLibrary = nullptr; nsresult rv = NS_OK; if (!IsCompatibleArch(mPlugin)) { return NS_ERROR_FAILURE; } // clear out the info, except for the first field. memset(&info, 0, sizeof(info)); // Try to get a bundle reference. nsAutoCString path; if (NS_FAILED(rv = mPlugin->GetNativePath(path))) return rv; CFBundleRef bundle = getPluginBundle(path.get()); // fill in full path info.fFullPath = PL_strdup(path.get()); // fill in file name nsAutoCString fileName; if (NS_FAILED(rv = mPlugin->GetNativeLeafName(fileName))) return rv; info.fFileName = PL_strdup(fileName.get()); // Get fName if (bundle) { CFTypeRef name = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginName")); if (name && ::CFGetTypeID(name) == ::CFStringGetTypeID()) info.fName = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(name)); } // Get fDescription if (bundle) { CFTypeRef description = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginDescription")); if (description && ::CFGetTypeID(description) == ::CFStringGetTypeID()) info.fDescription = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(description)); } // Get fVersion if (bundle) { // Look for the release version first CFTypeRef version = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("CFBundleShortVersionString")); if (!version) // try the build version version = ::CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleVersionKey); if (version && ::CFGetTypeID(version) == ::CFStringGetTypeID()) info.fVersion = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(version)); } // The last thing we need to do is get MIME data // fVariantCount, fMimeTypeArray, fExtensionArray, fMimeDescriptionArray // First look for data in a bundle plist if (bundle) { ParsePlistPluginInfo(info, bundle); ::CFRelease(bundle); if (info.fVariantCount > 0) return NS_OK; } // Don't load "fbplugin" or any plugins whose name starts with "fbplugin_" // (Facebook plugins) if we're running on OS X 10.10 (Yosemite) or later. // A "fbplugin" file crashes on load, in the call to LoadPlugin() below. // See bug 1086977. if (nsCocoaFeatures::OnYosemiteOrLater()) { if (fileName.EqualsLiteral("fbplugin") || StringBeginsWith(fileName, NS_LITERAL_CSTRING("fbplugin_"))) { nsAutoCString msg; msg.AppendPrintf("Preventing load of %s (see bug 1086977)", fileName.get()); NS_WARNING(msg.get()); return NS_ERROR_FAILURE; } #if defined(MOZ_CRASHREPORTER) // The block above assumes that "fbplugin" is the filename of the plugin // to be blocked, or that the filename starts with "fbplugin_". But we // don't yet know for sure if this is always true. So for the time being // record extra information in our crash logs. CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Bug_1086977"), fileName); #endif } // It's possible that our plugin has 2 entry points that'll give us mime type // info. Quicktime does this to get around the need of having admin rights to // change mime info in the resource fork. We need to use this info instead of // the resource. See bug 113464. // Sadly we have to load the library for this to work. rv = LoadPlugin(outLibrary); #if defined(MOZ_CRASHREPORTER) if (nsCocoaFeatures::OnYosemiteOrLater()) { // If we didn't crash in LoadPlugin(), change the previous annotation so we // don't sow confusion. CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Bug_1086977"), NS_LITERAL_CSTRING("Didn't crash, please ignore")); } #endif if (NS_FAILED(rv)) return rv; // Try to get data from NP_GetMIMEDescription if (pLibrary) { NP_GETMIMEDESCRIPTION pfnGetMimeDesc = (NP_GETMIMEDESCRIPTION)PR_FindFunctionSymbol(pLibrary, NP_GETMIMEDESCRIPTION_NAME); if (pfnGetMimeDesc) ParsePluginMimeDescription(pfnGetMimeDesc(), info); if (info.fVariantCount) return NS_OK; } // We'll fill this in using BP_GetSupportedMIMETypes and/or resource fork data BPSupportedMIMETypes mi = {kBPSupportedMIMETypesStructVers_1, nullptr, nullptr}; // Try to get data from BP_GetSupportedMIMETypes if (pLibrary) { BP_GETSUPPORTEDMIMETYPES pfnMime = (BP_GETSUPPORTEDMIMETYPES)PR_FindFunctionSymbol(pLibrary, "BP_GetSupportedMIMETypes"); if (pfnMime && noErr == pfnMime(&mi, 0) && mi.typeStrings) { info.fVariantCount = (**(short**)mi.typeStrings) / 2; ::HLock(mi.typeStrings); if (mi.infoStrings) // it's possible some plugins have infoStrings missing ::HLock(mi.infoStrings); } } // Fill in the info struct based on the data in the BPSupportedMIMETypes struct int variantCount = info.fVariantCount; info.fMimeTypeArray = static_cast<char**>(moz_xmalloc(variantCount * sizeof(char*))); if (!info.fMimeTypeArray) return NS_ERROR_OUT_OF_MEMORY; info.fExtensionArray = static_cast<char**>(moz_xmalloc(variantCount * sizeof(char*))); if (!info.fExtensionArray) return NS_ERROR_OUT_OF_MEMORY; if (mi.infoStrings) { info.fMimeDescriptionArray = static_cast<char**>(moz_xmalloc(variantCount * sizeof(char*))); if (!info.fMimeDescriptionArray) return NS_ERROR_OUT_OF_MEMORY; } short mimeIndex = 2; short descriptionIndex = 2; for (int i = 0; i < variantCount; i++) { info.fMimeTypeArray[i] = GetNextPluginStringFromHandle(mi.typeStrings, &mimeIndex); info.fExtensionArray[i] = GetNextPluginStringFromHandle(mi.typeStrings, &mimeIndex); if (mi.infoStrings) info.fMimeDescriptionArray[i] = GetNextPluginStringFromHandle(mi.infoStrings, &descriptionIndex); } ::HUnlock(mi.typeStrings); ::DisposeHandle(mi.typeStrings); if (mi.infoStrings) { ::HUnlock(mi.infoStrings); ::DisposeHandle(mi.infoStrings); } return NS_OK; }