diff options
Diffstat (limited to 'src/Daemon/MiddleWare.cpp')
| -rw-r--r-- | src/Daemon/MiddleWare.cpp | 1132 |
1 files changed, 0 insertions, 1132 deletions
diff --git a/src/Daemon/MiddleWare.cpp b/src/Daemon/MiddleWare.cpp deleted file mode 100644 index c7ed4df5..00000000 --- a/src/Daemon/MiddleWare.cpp +++ /dev/null @@ -1,1132 +0,0 @@ -/* - MiddleWare.cpp - - Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com) - Copyright (C) 2009 RedHat inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#include <fnmatch.h> -#include <algorithm> -#include "abrtlib.h" -#include "abrt_types.h" -#include "Daemon.h" -#include "Settings.h" -#include "rpm.h" -#include "debug_dump.h" -#include "abrt_exception.h" -#include "abrt_packages.h" -#include "comm_layer_inner.h" -#include "MiddleWare.h" - -using namespace std; - -/** - * An instance of CPluginManager. When MiddleWare wants to do something - * with plugins, it calls the plugin manager. - * @see PluginManager.h - */ -CPluginManager* g_pPluginManager; - -/** - * A map, which associates particular analyzer to one or more - * action or reporter plugins. These are activated when a crash, which - * is maintained by particular analyzer, occurs. - */ -typedef std::map<std::string, vector_pair_string_string_t> map_analyzer_actions_and_reporters_t; -static map_analyzer_actions_and_reporters_t s_mapAnalyzerActionsAndReporters; -/** - * A vector of one or more action or reporter plugins. These are - * activated when any crash occurs. - */ -static vector_pair_string_string_t s_vectorActionsAndReporters; - - -static void RunAnalyzerActions(const char *pAnalyzer, const char* pPackageName, const char *pDebugDumpDir, int force); - - -static char* is_text_file(const char *name, ssize_t *sz) -{ - /* We were using magic.h API to check for file being text, but it thinks - * that file containing just "0" is not text (!!) - * So, we do it ourself. - */ - - int fd = open(name, O_RDONLY); - if (fd < 0) - return NULL; /* it's not text (because it does not exist! :) */ - - char *buf = (char*)xmalloc(*sz); - ssize_t r = *sz = full_read(fd, buf, *sz); - close(fd); - if (r < 0) - { - free(buf); - return NULL; /* it's not text (because we can't read it) */ - } - - /* Some files in our dump directories are known to always be textual */ - const char *base = strrchr(name, '/'); - if (base) - { - base++; - if (strcmp(base, FILENAME_BACKTRACE) == 0 - || strcmp(base, FILENAME_CMDLINE) == 0 - ) { - return buf; - } - } - - /* Every once in a while, even a text file contains a few garbled - * or unexpected non-ASCII chars. We should not declare it "binary". - */ - const unsigned RATIO = 50; - unsigned total_chars = r + RATIO; - unsigned bad_chars = 1; /* 1 prevents division by 0 later */ - while (--r >= 0) - { - if (buf[r] >= 0x7f - /* among control chars, only '\t','\n' etc are allowed */ - || (buf[r] < ' ' && !isspace(buf[r])) - ) { - if (buf[r] == '\0') - { - /* We don't like NULs very much. Not text for sure! */ - free(buf); - return NULL; - } - bad_chars++; - } - } - - if ((total_chars / bad_chars) >= RATIO) - return buf; /* looks like text to me */ - - free(buf); - return NULL; /* it's binary */ -} - -static void load_crash_data_from_debug_dump(CDebugDump& dd, map_crash_data_t& data) -{ - std::string short_name; - std::string full_name; - - dd.InitGetNextFile(); - while (dd.GetNextFile(&short_name, &full_name)) - { - ssize_t sz = 4*1024; - char *text = NULL; - bool editable = is_editable_file(short_name.c_str()); - - if (!editable) - { - text = is_text_file(full_name.c_str(), &sz); - if (!text) - { - add_to_crash_data_ext(data, - short_name.c_str(), - CD_BIN, - CD_ISNOTEDITABLE, - full_name.c_str() - ); - continue; - } - } - - std::string content; - if (sz < 4*1024) /* is_text_file did read entire file */ - content.assign(text, sz); - else /* no, need to read it all */ - dd.LoadText(short_name.c_str(), content); - free(text); - - add_to_crash_data_ext(data, - short_name.c_str(), - CD_TXT, - editable ? CD_ISEDITABLE : CD_ISNOTEDITABLE, - content.c_str() - ); - } -} - -/** - * Transforms a debugdump directory to inner crash - * report form. This form is used for later reporting. - * @param pDebugDumpDir A debugdump dir containing all necessary data. - * @param pCrashData A created crash report. - */ -static void DebugDumpToCrashReport(const char *pDebugDumpDir, map_crash_data_t& pCrashData) -{ - VERB3 log(" DebugDumpToCrashReport('%s')", pDebugDumpDir); - - CDebugDump dd; - dd.Open(pDebugDumpDir); - - const char *const *v = must_have_files; - while (*v) - { - if (!dd.Exist(*v)) - { - throw CABRTException(EXCEP_ERROR, "DebugDumpToCrashReport(): important file '%s' is missing", *v); - } - v++; - } - - load_crash_data_from_debug_dump(dd, pCrashData); -} - -/** - * Get a local UUID from particular analyzer plugin. - * @param pAnalyzer A name of an analyzer plugin. - * @param pDebugDumpDir A debugdump dir containing all necessary data. - * @return A local UUID. - */ -static std::string GetLocalUUID(const char *pAnalyzer, const char *pDebugDumpDir) -{ - CAnalyzer* analyzer = g_pPluginManager->GetAnalyzer(pAnalyzer); - if (analyzer) - { - return analyzer->GetLocalUUID(pDebugDumpDir); - } - throw CABRTException(EXCEP_PLUGIN, "Error running '%s'", pAnalyzer); -} - -/** - * Get a global UUID from particular analyzer plugin. - * @param pAnalyzer A name of an analyzer plugin. - * @param pDebugDumpDir A debugdump dir containing all necessary data. - * @return A global UUID. - */ -static std::string GetGlobalUUID(const char *pAnalyzer, - const char *pDebugDumpDir) -{ - CAnalyzer* analyzer = g_pPluginManager->GetAnalyzer(pAnalyzer); - if (analyzer) - { - return analyzer->GetGlobalUUID(pDebugDumpDir); - } - throw CABRTException(EXCEP_PLUGIN, "Error running '%s'", pAnalyzer); -} - -/** - * Take care of getting all additional data needed - * for computing UUIDs and creating a report for particular analyzer - * plugin. This report could be send somewhere afterwards. - * @param pAnalyzer A name of an analyzer plugin. - * @param pDebugDumpPath A debugdump dir containing all necessary data. - */ -static void run_analyser_CreateReport(const char *pAnalyzer, - const char *pDebugDumpDir, - int force) -{ - CAnalyzer* analyzer = g_pPluginManager->GetAnalyzer(pAnalyzer); - if (analyzer) - { - analyzer->CreateReport(pDebugDumpDir, force); - } - /* else: GetAnalyzer() already complained, no need to handle it here */ -} - -/* - * Called in three cases: - * (1) by StartJob dbus call -> CreateReportThread(), in the thread - * (2) by CreateReport dbus call - * (3) by daemon if AutoReportUID is set for this user's crashes - */ -mw_result_t CreateCrashReport(const char *crash_id, - long caller_uid, - int force, - map_crash_data_t& pCrashData) -{ - VERB2 log("CreateCrashReport('%s',%ld,result)", crash_id, caller_uid); - - database_row_t row; - CDatabase* database = g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str()); - database->Connect(); - row = database->GetRow(crash_id); - database->DisConnect(); - if (row.m_sUUID == "") - { - error_msg("crash '%s' is not in database", crash_id); - return MW_IN_DB_ERROR; - } - if (caller_uid != 0 /* not called by root */ - && row.m_sInformAll != "1" - && to_string(caller_uid) != row.m_sUID - ) { - error_msg("crash '%s' can't be accessed by user with uid %ld", crash_id, caller_uid); - return MW_IN_DB_ERROR; - } - - mw_result_t r = MW_OK; - try - { - { - CDebugDump dd; - dd.Open(row.m_sDebugDumpDir.c_str()); - load_crash_data_from_debug_dump(dd, pCrashData); - } - - std::string analyzer = get_crash_data_item_content(pCrashData, FILENAME_ANALYZER); - const char* package = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_PACKAGE); - char* package_name = get_package_name_from_NVR_or_NULL(package); - - // TODO: explain what run_analyser_CreateReport and RunAnalyzerActions are expected to do. - // Do they potentially add more files to dump dir? - // Why we calculate dup_hash after run_analyser_CreateReport but before RunAnalyzerActions? - // Why do we reload dump dir's data via DebugDumpToCrashReport? - - VERB3 log(" run_analyser_CreateReport('%s')", analyzer.c_str()); - run_analyser_CreateReport(analyzer.c_str(), row.m_sDebugDumpDir.c_str(), force); - - std::string dup_hash = GetGlobalUUID(analyzer.c_str(), row.m_sDebugDumpDir.c_str()); - VERB3 log(" DUPHASH:'%s'", dup_hash.c_str()); - - VERB3 log(" RunAnalyzerActions('%s','%s','%s',force=%d)", analyzer.c_str(), package_name, row.m_sDebugDumpDir.c_str(), force); - RunAnalyzerActions(analyzer.c_str(), package_name, row.m_sDebugDumpDir.c_str(), force); - free(package_name); - DebugDumpToCrashReport(row.m_sDebugDumpDir.c_str(), pCrashData); - add_to_crash_data_ext(pCrashData, CD_UUID , CD_SYS, CD_ISNOTEDITABLE, row.m_sUUID.c_str()); - add_to_crash_data_ext(pCrashData, CD_DUPHASH, CD_TXT, CD_ISNOTEDITABLE, dup_hash.c_str()); - } - catch (CABRTException& e) - { - r = MW_CORRUPTED; - error_msg("%s", e.what()); - if (e.type() == EXCEP_DD_OPEN) - { - r = MW_ERROR; - } - else if (e.type() == EXCEP_DD_LOAD) - { - r = MW_FILE_ERROR; - } - else if (e.type() == EXCEP_PLUGIN) - { - r = MW_PLUGIN_ERROR; - } - } - - VERB3 log("CreateCrashReport() returns %d", r); - return r; -} - -void RunAction(const char *pActionDir, - const char *pPluginName, - const char *pPluginArgs) -{ - CAction* action = g_pPluginManager->GetAction(pPluginName); - if (!action) - { - /* GetAction() already complained */ - return; - } - try - { - action->Run(pActionDir, pPluginArgs, /*force:*/ 0); - } - catch (CABRTException& e) - { - error_msg("Execution of '%s' was not successful: %s", pPluginName, e.what()); - } -} - -void RunActionsAndReporters(const char *pDebugDumpDir) -{ - vector_pair_string_string_t::iterator it_ar = s_vectorActionsAndReporters.begin(); - map_plugin_settings_t plugin_settings; - for (; it_ar != s_vectorActionsAndReporters.end(); it_ar++) - { - const char *plugin_name = it_ar->first.c_str(); - try - { - VERB3 log("RunActionsAndReporters: checking %s", plugin_name); - plugin_type_t tp = g_pPluginManager->GetPluginType(plugin_name); - if (tp == REPORTER) - { - CReporter* reporter = g_pPluginManager->GetReporter(plugin_name); /* can't be NULL */ - map_crash_data_t crashReport; - DebugDumpToCrashReport(pDebugDumpDir, crashReport); - VERB2 log("%s.Report(...)", plugin_name); - reporter->Report(crashReport, plugin_settings, it_ar->second.c_str()); - } - else if (tp == ACTION) - { - CAction* action = g_pPluginManager->GetAction(plugin_name); /* can't be NULL */ - VERB2 log("%s.Run('%s','%s')", plugin_name, pDebugDumpDir, it_ar->second.c_str()); - action->Run(pDebugDumpDir, it_ar->second.c_str(), /*force:*/ 0); - } - } - catch (CABRTException& e) - { - error_msg("Activation of plugin '%s' was not successful: %s", plugin_name, e.what()); - } - } -} - - -// Do not trust client_report here! -// dbus handler passes it from user without checking -report_status_t Report(const map_crash_data_t& client_report, - const vector_string_t &reporters, - map_map_string_t& settings, - long caller_uid) -{ - // Get ID fields - const char *UID = get_crash_data_item_content_or_NULL(client_report, CD_UID); - const char *UUID = get_crash_data_item_content_or_NULL(client_report, CD_UUID); - if (!UID || !UUID) - { - throw CABRTException(EXCEP_ERROR, "Report(): UID or UUID is missing in client's report data"); - } - string crash_id = ssprintf("%s:%s", UID, UUID); - - // Retrieve corresponding stored record - map_crash_data_t stored_report; - mw_result_t r = FillCrashInfo(crash_id.c_str(), stored_report); - if (r != MW_OK) - { - return report_status_t(); - } - - // Is it allowed for this user to report? - if (caller_uid != 0 // not called by root - && get_crash_data_item_content(stored_report, CD_INFORMALL) != "1" - && strcmp(to_string(caller_uid).c_str(), UID) != 0 - ) { - throw CABRTException(EXCEP_ERROR, "Report(): user with uid %ld can't report crash %s", - caller_uid, crash_id.c_str()); - } - - const std::string& pDumpDir = get_crash_data_item_content(stored_report, CD_DUMPDIR); - - // Save comment, "how to reproduce", backtrace -//TODO: we should iterate through stored_report and modify all -//modifiable fields which have new data in client_report - const char *comment = get_crash_data_item_content_or_NULL(client_report, FILENAME_COMMENT); - const char *reproduce = get_crash_data_item_content_or_NULL(client_report, FILENAME_REPRODUCE); - const char *backtrace = get_crash_data_item_content_or_NULL(client_report, FILENAME_BACKTRACE); - if (comment || reproduce || backtrace) - { - CDebugDump dd; - dd.Open(pDumpDir.c_str()); - if (comment) - { - dd.SaveText(FILENAME_COMMENT, comment); - add_to_crash_data_ext(stored_report, FILENAME_COMMENT, CD_TXT, CD_ISEDITABLE, comment); - } - if (reproduce) - { - dd.SaveText(FILENAME_REPRODUCE, reproduce); - add_to_crash_data_ext(stored_report, FILENAME_REPRODUCE, CD_TXT, CD_ISEDITABLE, reproduce); - } - if (backtrace) - { - dd.SaveText(FILENAME_BACKTRACE, backtrace); - add_to_crash_data_ext(stored_report, FILENAME_BACKTRACE, CD_TXT, CD_ISEDITABLE, backtrace); - } - } - - /* Remove BIN filenames from stored_report if they are not present in client's data */ - map_crash_data_t::const_iterator its = stored_report.begin(); - while (its != stored_report.end()) - { - if (its->second[CD_TYPE] == CD_BIN) - { - std::string key = its->first; - if (get_crash_data_item_content_or_NULL(client_report, key.c_str()) == NULL) - { - /* client does not have it -> does not want it passed to reporters */ - VERB3 log("Won't report BIN file %s:'%s'", key.c_str(), its->second[CD_CONTENT].c_str()); - its++; /* move off the element we will erase */ - stored_report.erase(key); - continue; - } - } - its++; - } - - const std::string& analyzer = get_crash_data_item_content(stored_report, FILENAME_ANALYZER); - - std::string dup_hash = GetGlobalUUID(analyzer.c_str(), pDumpDir.c_str()); - VERB3 log(" DUPHASH:'%s'", dup_hash.c_str()); - add_to_crash_data_ext(stored_report, CD_DUPHASH, CD_TXT, CD_ISNOTEDITABLE, dup_hash.c_str()); - - // Run reporters - - VERB3 { - log("Run reporters"); - log_map_crash_data(client_report, " client_report"); - log_map_crash_data(stored_report, " stored_report"); - } -#define client_report client_report_must_not_be_used_below - - map_crash_data_t::const_iterator its_PACKAGE = stored_report.find(FILENAME_PACKAGE); - std::string packageNVR = its_PACKAGE->second[CD_CONTENT]; - char * packageName = get_package_name_from_NVR_or_NULL(packageNVR.c_str()); - - // analyzer with package name (CCpp:xorg-x11-app) has higher priority - char* key = xasprintf("%s:%s",analyzer.c_str(),packageName); - free(packageName); - map_analyzer_actions_and_reporters_t::iterator end = s_mapAnalyzerActionsAndReporters.end(); - map_analyzer_actions_and_reporters_t::iterator keyPtr = s_mapAnalyzerActionsAndReporters.find(key); - if (keyPtr == end) - { - VERB3 log("'%s' not found, looking for '%s'", key, analyzer.c_str()); - // if there is no such settings, then try default analyzer - keyPtr = s_mapAnalyzerActionsAndReporters.find(analyzer); - } - free(key); - - bool at_least_one_reporter_succeeded = false; - report_status_t ret; - std::string message; - if (keyPtr != end) - { - VERB2 log("Found AnalyzerActionsAndReporters for '%s'", analyzer.c_str()); - - vector_pair_string_string_t::iterator it_r = keyPtr->second.begin(); - for (; it_r != keyPtr->second.end(); it_r++) - { - const char *plugin_name = it_r->first.c_str(); - - /* Check if the reporter is in the input list of allowed reporters. */ - if (reporters.end() == std::find(reporters.begin(), reporters.end(), plugin_name)) - { - continue; - } - - try - { - if (g_pPluginManager->GetPluginType(plugin_name) == REPORTER) - { - CReporter* reporter = g_pPluginManager->GetReporter(plugin_name); /* can't be NULL */ - map_plugin_settings_t plugin_settings = settings[plugin_name]; - std::string res = reporter->Report(stored_report, plugin_settings, it_r->second.c_str()); - ret[plugin_name].push_back("1"); // REPORT_STATUS_IDX_FLAG - ret[plugin_name].push_back(res); // REPORT_STATUS_IDX_MSG - if (message != "") - message += ";"; - message += res; - at_least_one_reporter_succeeded = true; - } - } - catch (CABRTException& e) - { - ret[plugin_name].push_back("0"); // REPORT_STATUS_IDX_FLAG - ret[plugin_name].push_back(e.what()); // REPORT_STATUS_IDX_MSG - update_client("Reporting via '%s' was not successful: %s", plugin_name, e.what()); - } - } // for - } // if - - if (at_least_one_reporter_succeeded) - { - CDatabase* database = g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str()); - database->Connect(); - report_status_t::iterator ret_it = ret.begin(); - while (ret_it != ret.end()) - { - const string &plugin_name = ret_it->first; - const vector_string_t &v = ret_it->second; - if (v[REPORT_STATUS_IDX_FLAG] == "1") - { - database->SetReportedPerReporter(crash_id.c_str(), plugin_name.c_str(), v[REPORT_STATUS_IDX_MSG].c_str()); - } - ret_it++; - } - database->SetReported(crash_id.c_str(), message.c_str()); - database->DisConnect(); - } - - return ret; -#undef client_report -} - -/** - * Check whether particular debugdump directory is saved - * in database. This check is done together with an UID of an user. - * @param uid - * An UID of an user. - * @param debug_dump_dir - * A debugdump dir containing all necessary data. - * @return - * It returns true if debugdump dir is already saved, otherwise - * it returns false. - * @todo - * Use database query instead of dumping all rows and searching in them. - */ -static bool is_debug_dump_saved(long uid, const char *debug_dump_dir) -{ - if (g_settings_sDatabase.empty()) - error_msg_and_die(_("Database plugin not specified. Please check abrtd settings.")); - - CDatabase* database = g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str()); - database->Connect(); - vector_database_rows_t rows = database->GetUIDData(uid); - database->DisConnect(); - - size_t ii; - bool found = false; - for (ii = 0; ii < rows.size(); ii++) - { - if (0 == strcmp(rows[ii].m_sDebugDumpDir.c_str(), debug_dump_dir)) - { - found = true; - break; - } - } - - return found; -} - -void LoadOpenGPGPublicKey(const char* key) -{ - VERB1 log("Loading GPG key '%s'", key); - rpm_load_gpgkey(key); -} - -/** - * Returns the first full path argument in the command line or NULL. - * Skips options are in form "-XXX". - * Caller must delete the returned string using free(). - */ -static char *get_argv1_if_full_path(const char* cmdline) -{ - const char *argv1 = strpbrk(cmdline, " \t"); - while (argv1 != NULL) - { - /* we found space in cmdline, so it might contain - * path to some script like: - * /usr/bin/python [-XXX] /usr/bin/system-control-network - */ - argv1++; /* skip the space */ - if (*argv1 == '-') /* skip arguments */ - { - /* looks like -XXX in "perl -XXX /usr/bin/script.pl", skip */ - argv1 = strpbrk(argv1, " \t"); - continue; - } - else if (*argv1 == ' ' || *argv1 == '\t') /* skip multiple spaces */ - continue; - else if (*argv1 != '/') - { - /* if the string following the space doesn't start - * with '/' it's probably not a full path to script - * and we can't use it to determine the package name - */ - break; - } - - /* cut the rest of cmdline arguments */ - int len = strchrnul(argv1, ' ') - argv1; - return xstrndup(argv1, len); - } - return NULL; -} - -static bool is_path_blacklisted(const char *path) -{ - set_string_t::iterator it = g_settings_setBlackListedPaths.begin(); - while (it != g_settings_setBlackListedPaths.end()) - { - if (fnmatch(it->c_str(), path, /*flags:*/ 0) == 0) - { - return true; - } - it++; - } - return false; -} - - -/** - * Get a package name from executable name and save - * package description to particular debugdump directory of a crash. - * @param pExecutable A name of crashed application. - * @param pDebugDumpDir A debugdump dir containing all necessary data. - * @return It return results of operation. See mw_result_t. - */ -static mw_result_t SavePackageDescriptionToDebugDump( - const char *pExecutable, - const char *cmdline, - bool remote, - const char *pDebugDumpDir) -{ - char* rpm_pkg = NULL; - char* packageName = NULL; - char* component = NULL; - std::string scriptName; /* only if "interpreter /path/to/script" */ - - if (strcmp(pExecutable, "kernel") == 0) - { - component = xstrdup("kenel"); - rpm_pkg = xstrdup("kernel"); - packageName = xstrdup("kernel"); - } - else - { - if (is_path_blacklisted(pExecutable)) - { - log("Blacklisted executable '%s'", pExecutable); - return MW_BLACKLISTED; - } - - rpm_pkg = rpm_get_package_nvr(pExecutable); - if (rpm_pkg == NULL) - { - if (g_settings_bProcessUnpackaged || remote) - { - VERB2 log("Crash in unpackaged executable '%s', proceeding without packaging information", pExecutable); - try - { - CDebugDump dd; - dd.Open(pDebugDumpDir); - dd.SaveText(FILENAME_PACKAGE, ""); - dd.SaveText(FILENAME_COMPONENT, ""); - dd.SaveText(FILENAME_DESCRIPTION, "Crashed executable does not belong to any installed package"); - return MW_OK; - } - catch (CABRTException& e) - { - error_msg("%s", e.what()); - return MW_ERROR; - } - } - else - { - log("Executable '%s' doesn't belong to any package", pExecutable); - return MW_PACKAGE_ERROR; - } - } - - /* Check well-known interpreter names */ - - const char *basename = strrchr(pExecutable, '/'); - if (basename) basename++; else basename = pExecutable; - - /* Add more interpreters as needed */ - if (strcmp(basename, "python") == 0 - || strcmp(basename, "perl") == 0 - ) { -// TODO: we don't verify that python executable is not modified -// or that python package is properly signed -// (see CheckFingerprint/CheckHash below) - - /* Try to find package for the script by looking at argv[1]. - * This will work only if the cmdline contains the whole path. - * Example: python /usr/bin/system-control-network - */ - bool knownOrigin = false; - char *script_name = get_argv1_if_full_path(cmdline); - if (script_name) - { - char *script_pkg = rpm_get_package_nvr(script_name); - if (script_pkg) - { - /* There is a well-formed script name in argv[1], - * and it does belong to some package. - * Replace interpreter's rpm_pkg and pExecutable - * with data pertaining to the script. - */ - free(rpm_pkg); - rpm_pkg = script_pkg; - scriptName = script_name; - pExecutable = scriptName.c_str(); - knownOrigin = true; - /* pExecutable has changed, check it again */ - if (is_path_blacklisted(pExecutable)) - { - log("Blacklisted executable '%s'", pExecutable); - return MW_BLACKLISTED; - } - } - free(script_name); - } - - if (!knownOrigin && !g_settings_bProcessUnpackaged && !remote) - { - log("Interpreter crashed, but no packaged script detected: '%s'", cmdline); - return MW_PACKAGE_ERROR; - } - } - - packageName = get_package_name_from_NVR_or_NULL(rpm_pkg); - VERB2 log("Package:'%s' short:'%s'", rpm_pkg, packageName); - - if (g_settings_setBlackListedPkgs.find(packageName) != g_settings_setBlackListedPkgs.end()) - { - log("Blacklisted package '%s'", packageName); - free(packageName); - return MW_BLACKLISTED; - } - if (g_settings_bOpenGPGCheck && !remote) - { - if (rpm_chk_fingerprint(packageName)) - { - log("Package '%s' isn't signed with proper key", packageName); - free(packageName); - return MW_GPG_ERROR; - } - /* - Checking the MD5 sum requires to run prelink to "un-prelink" the - binaries - this is considered potential security risk so we don't - use it, until we find some non-intrusive way - - Delete? - */ - /* - if (!CheckHash(packageName.c_str(), pExecutable)) - { - error_msg("Executable '%s' seems to be modified, " - "doesn't match one from package '%s'", - pExecutable, packageName.c_str()); - return MW_GPG_ERROR; - } - */ - } - component = rpm_get_component(pExecutable); - } - - char *dsc = rpm_get_description(packageName); - free(packageName); - - char host[HOST_NAME_MAX + 1]; - if (!remote) - { - // HOST_NAME_MAX is defined in limits.h - int ret = gethostname(host, HOST_NAME_MAX); - host[HOST_NAME_MAX] = '\0'; - if (ret < 0) - { - perror_msg("gethostname"); - host[0] = '\0'; - } - } - - try - { - CDebugDump dd; - dd.Open(pDebugDumpDir); - if (rpm_pkg) - { - dd.SaveText(FILENAME_PACKAGE, rpm_pkg); - free(rpm_pkg); - } - - if (dsc) - { - dd.SaveText(FILENAME_DESCRIPTION, dsc); - free(dsc); - } - - if (component) - { - dd.SaveText(FILENAME_COMPONENT, component); - free(component); - } - - if (!remote) - dd.SaveText(FILENAME_HOSTNAME, host); - } - catch (CABRTException& e) - { - error_msg("%s", e.what()); - return MW_ERROR; - } - - return MW_OK; -} - -bool analyzer_has_InformAllUsers(const char *analyzer_name) -{ - CAnalyzer* analyzer = g_pPluginManager->GetAnalyzer(analyzer_name); - if (!analyzer) - { - return false; - } - map_plugin_settings_t settings = analyzer->GetSettings(); - map_plugin_settings_t::const_iterator it = settings.find("InformAllUsers"); - if (it == settings.end()) - return false; - return string_to_bool(it->second.c_str()); -} - -bool analyzer_has_AutoReportUIDs(const char *analyzer_name, const char *uid_str) -{ - CAnalyzer* analyzer = g_pPluginManager->GetAnalyzer(analyzer_name); - if (!analyzer) - { - return false; - } - map_plugin_settings_t settings = analyzer->GetSettings(); - map_plugin_settings_t::const_iterator it = settings.find("AutoReportUIDs"); - if (it == settings.end()) - return false; - - vector_string_t logins; - parse_args(it->second.c_str(), logins); - - uid_t uid = xatoi_u(uid_str); - unsigned size = logins.size(); - for (unsigned ii = 0; ii < size; ii++) - { - struct passwd* pw = getpwnam(logins[ii].c_str()); - if (!pw) - continue; - if (pw->pw_uid == uid) - return true; - } - - return false; -} - -void autoreport(const pair_string_string_t& reporter_options, const map_crash_data_t& crash_report) -{ - CReporter* reporter = g_pPluginManager->GetReporter(reporter_options.first.c_str()); - if (!reporter) - { - return; - } - map_plugin_settings_t plugin_settings; - /*std::string res =*/ reporter->Report(crash_report, plugin_settings, reporter_options.second.c_str()); -} - -/** - * Execute all action plugins, which are associated to - * particular analyzer plugin. - * @param pAnalyzer A name of an analyzer plugin. - * @param pDebugDumpPath A debugdump dir containing all necessary data. - */ -static void RunAnalyzerActions(const char *pAnalyzer, const char *pPackageName, const char *pDebugDumpDir, int force) -{ - map_analyzer_actions_and_reporters_t::iterator analyzer; - if (pPackageName != NULL) - { - /*try to find analyzer:component first*/ - char *analyzer_component = xasprintf("%s:%s", pAnalyzer, pPackageName); - analyzer = s_mapAnalyzerActionsAndReporters.find(analyzer_component); - /* if we didn't find an action for specific package, use the generic one */ - if (analyzer == s_mapAnalyzerActionsAndReporters.end()) - { - VERB2 log("didn't find action for %s, trying just %s", analyzer_component, pAnalyzer); - map_analyzer_actions_and_reporters_t::iterator analyzer = s_mapAnalyzerActionsAndReporters.find(pAnalyzer); - } - free(analyzer_component); - } - else - { - VERB2 log("no package name specified, trying to find action for: %s", pAnalyzer); - analyzer = s_mapAnalyzerActionsAndReporters.find(pAnalyzer); - } - if (analyzer != s_mapAnalyzerActionsAndReporters.end()) - { - vector_pair_string_string_t::iterator it_a = analyzer->second.begin(); - for (; it_a != analyzer->second.end(); it_a++) - { - const char *plugin_name = it_a->first.c_str(); - CAction* action = g_pPluginManager->GetAction(plugin_name, /*silent:*/ true); - if (!action) - { - /* GetAction() already complained if no such plugin. - * If plugin exists but isn't an Action, it's not an error. - */ - continue; - } - try - { - action->Run(pDebugDumpDir, it_a->second.c_str(), force); - } - catch (CABRTException& e) - { - update_client("Action performed by '%s' was not successful: %s", plugin_name, e.what()); - } - } - } -} - -/** - * Save a debugdump into database. If saving is - * successful, then crash info is filled. Otherwise the crash info is - * not changed. - * @param pUUID A local UUID of a crash. - * @param pUID An UID of an user. - * @param pTime Time when a crash occurs. - * @param pDebugDumpPath A debugdump path. - * @param pCrashData A filled crash info. - * @return It return results of operation. See mw_result_t. - */ -static mw_result_t SaveDebugDumpToDatabase(const char *crash_id, - bool inform_all_users, - const char *pTime, - const char *pDebugDumpDir, - map_crash_data_t& pCrashData) -{ - CDatabase* database = g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str()); - database->Connect(); - /* note: if [UUID,UID] record exists, pDebugDumpDir is not updated in the record */ - database->Insert_or_Update(crash_id, inform_all_users, pDebugDumpDir, pTime); - database_row_t row = database->GetRow(crash_id); - database->DisConnect(); - - mw_result_t res = FillCrashInfo(crash_id, pCrashData); - if (res == MW_OK) - { - const char *first = get_crash_data_item_content(pCrashData, CD_DUMPDIR).c_str(); - if (row.m_sReported == "1") - { - log("Crash is in database already (dup of %s) and is reported", first); - return MW_REPORTED; - } - if (row.m_sCount != "1") - { - log("Crash is in database already (dup of %s)", first); - return MW_OCCURRED; - } - } - return res; -} - -mw_result_t SaveDebugDump(const char *pDebugDumpDir, - map_crash_data_t& pCrashData) -{ - std::string UID; - std::string time; - std::string analyzer; - std::string executable; - std::string cmdline; - bool remote = false; - try - { - CDebugDump dd; - dd.Open(pDebugDumpDir); - dd.LoadText(FILENAME_TIME, time); - dd.LoadText(CD_UID, UID); - dd.LoadText(FILENAME_ANALYZER, analyzer); - dd.LoadText(FILENAME_EXECUTABLE, executable); - dd.LoadText(FILENAME_CMDLINE, cmdline); - if (dd.Exist(FILENAME_REMOTE)) - { - std::string remote_str; - dd.LoadText(FILENAME_REMOTE, remote_str); - remote = (remote_str.find('1') != std::string::npos); - } - } - catch (CABRTException& e) - { - error_msg("%s", e.what()); - return MW_ERROR; - } - - /* Convert UID string to number uid_num. The UID string can be modified by user or - wrongly saved (empty or non-numeric), so xatou() cannot be used here, - because it would kill the daemon. */ - char *endptr; - errno = 0; - unsigned long uid_num = strtoul(UID.c_str(), &endptr, 10); - if (errno || UID.c_str() == endptr || *endptr != '\0' || uid_num > UINT_MAX) - { - error_msg("Invalid UID '%s' loaded from %s", UID.c_str(), pDebugDumpDir); - return MW_ERROR; - } - - if (is_debug_dump_saved(uid_num, pDebugDumpDir)) - return MW_IN_DB; - - mw_result_t res = SavePackageDescriptionToDebugDump(executable.c_str(), cmdline.c_str(), remote, pDebugDumpDir); - if (res != MW_OK) - return res; - - std::string UUID = GetLocalUUID(analyzer.c_str(), pDebugDumpDir); - std::string crash_id = ssprintf("%s:%s", UID.c_str(), UUID.c_str()); - /* Loads pCrashData (from the *first debugdump dir* if this one is a dup) - * Returns: - * MW_REPORTED: "the crash is flagged as reported in DB" (which also means it's a dup) - * MW_OCCURRED: "crash count is != 1" (iow: it is > 1 - dup) - * MW_OK: "crash count is 1" (iow: this is a new crash, not a dup) - * else: an error code - */ - return SaveDebugDumpToDatabase(crash_id.c_str(), - analyzer_has_InformAllUsers(analyzer.c_str()), - time.c_str(), - pDebugDumpDir, - pCrashData); -} - -mw_result_t FillCrashInfo(const char *crash_id, - map_crash_data_t& pCrashData) -{ - CDatabase* database = g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str()); - database->Connect(); - database_row_t row = database->GetRow(crash_id); - database->DisConnect(); - - std::string package; - std::string executable; - std::string description; - std::string analyzer; - try - { - CDebugDump dd; - dd.Open(row.m_sDebugDumpDir.c_str()); - load_crash_data_from_debug_dump(dd, pCrashData); - } - catch (CABRTException& e) - { - error_msg("%s", e.what()); - return MW_ERROR; - } - - add_to_crash_data(pCrashData, CD_UID , row.m_sUID.c_str() ); - add_to_crash_data(pCrashData, CD_UUID , row.m_sUUID.c_str() ); - add_to_crash_data(pCrashData, CD_INFORMALL , row.m_sInformAll.c_str() ); - add_to_crash_data(pCrashData, CD_COUNT , row.m_sCount.c_str() ); - add_to_crash_data(pCrashData, CD_REPORTED , row.m_sReported.c_str() ); - add_to_crash_data(pCrashData, CD_MESSAGE , row.m_sMessage.c_str() ); - add_to_crash_data(pCrashData, CD_DUMPDIR , row.m_sDebugDumpDir.c_str()); - add_to_crash_data(pCrashData, FILENAME_TIME , row.m_sTime.c_str() ); - - return MW_OK; -} - -void GetUUIDsOfCrash(long caller_uid, vector_string_t &result) -{ - CDatabase* database = g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str()); - vector_database_rows_t rows; - database->Connect(); - rows = database->GetUIDData(caller_uid); - database->DisConnect(); - - unsigned ii; - for (ii = 0; ii < rows.size(); ii++) - { - string crash_id = ssprintf("%s:%s", rows[ii].m_sUID.c_str(), rows[ii].m_sUUID.c_str()); - result.push_back(crash_id); - } -} - -void AddAnalyzerActionOrReporter(const char *pAnalyzer, - const char *pAnalyzerOrReporter, - const char *pArgs) -{ - s_mapAnalyzerActionsAndReporters[pAnalyzer].push_back(make_pair(std::string(pAnalyzerOrReporter), std::string(pArgs))); -} - -void AddActionOrReporter(const char *pActionOrReporter, - const char *pArgs) -{ - VERB3 log("AddActionOrReporter('%s','%s')", pActionOrReporter, pArgs); - s_vectorActionsAndReporters.push_back(make_pair(std::string(pActionOrReporter), std::string(pArgs))); -} |
