From b94e437131d1f396e1a700e2a5664199af008cfd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 10 Jan 2010 18:05:54 +0100 Subject: replace plugin enabling via EnabledPlugins by par-plugin Enabled = yes/no Signed-off-by: Denys Vlasenko --- src/Daemon/Daemon.cpp | 7 -- src/Daemon/MiddleWare.cpp | 39 +++++++--- src/Daemon/PluginManager.cpp | 179 +++++++++++++++++++++---------------------- src/Daemon/PluginManager.h | 16 +--- src/Daemon/Settings.cpp | 7 -- src/Daemon/Settings.h | 1 - src/Daemon/abrt.conf | 6 +- src/Daemon/abrt.conf.5 | 4 - 8 files changed, 121 insertions(+), 138 deletions(-) (limited to 'src') diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp index 1a6cadf..7577611 100644 --- a/src/Daemon/Daemon.cpp +++ b/src/Daemon/Daemon.cpp @@ -173,13 +173,6 @@ static int SetUpMW() { g_setBlackList.insert(*it_b); } - VERB1 log("Registering plugins"); - set_string_t::iterator it_p = g_settings_setEnabledPlugins.begin(); - for (; it_p != g_settings_setEnabledPlugins.end(); it_p++) - { - if (g_pPluginManager->RegisterPlugin(it_p->c_str()) != 0) - return -1; - } VERB1 log("Adding actions or reporters"); vector_pair_string_string_t::iterator it_ar = g_settings_vectorActionsAndReporters.begin(); for (; it_ar != g_settings_vectorActionsAndReporters.end(); it_ar++) diff --git a/src/Daemon/MiddleWare.cpp b/src/Daemon/MiddleWare.cpp index 25fe253..3656060 100644 --- a/src/Daemon/MiddleWare.cpp +++ b/src/Daemon/MiddleWare.cpp @@ -204,7 +204,11 @@ static void DebugDumpToCrashReport(const char *pDebugDumpDir, map_crash_report_t static std::string GetLocalUUID(const char *pAnalyzer, const char *pDebugDumpDir) { CAnalyzer* analyzer = g_pPluginManager->GetAnalyzer(pAnalyzer); - return analyzer->GetLocalUUID(pDebugDumpDir); + if (analyzer) + { + return analyzer->GetLocalUUID(pDebugDumpDir); + } + throw CABRTException(EXCEP_PLUGIN, "Error running '%s'", pAnalyzer); } /** @@ -217,7 +221,11 @@ static std::string GetGlobalUUID(const char *pAnalyzer, const char *pDebugDumpDir) { CAnalyzer* analyzer = g_pPluginManager->GetAnalyzer(pAnalyzer); - return analyzer->GetGlobalUUID(pDebugDumpDir); + if (analyzer) + { + return analyzer->GetGlobalUUID(pDebugDumpDir); + } + throw CABRTException(EXCEP_PLUGIN, "Error running '%s'", pAnalyzer); } /** @@ -232,7 +240,11 @@ static void CreateReport(const char *pAnalyzer, int force) { CAnalyzer* analyzer = g_pPluginManager->GetAnalyzer(pAnalyzer); - analyzer->CreateReport(pDebugDumpDir, force); + if (analyzer) + { + analyzer->CreateReport(pDebugDumpDir, force); + } + /* else: GetAnalyzer() already complained, no need to handle it here */ } mw_result_t CreateCrashReport(const char *pUUID, @@ -320,9 +332,14 @@ void RunAction(const char *pActionDir, const char *pPluginName, const char *pPluginArgs) { + CAction* action = g_pPluginManager->GetAction(pPluginName); + if (!action) + { + /* GetAction() already complained */ + return; + } try { - CAction* action = g_pPluginManager->GetAction(pPluginName); action->Run(pActionDir, pPluginArgs); } catch (CABRTException& e) @@ -770,13 +787,17 @@ static void RunAnalyzerActions(const char *pAnalyzer, const char *pDebugDumpDir) 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 { - if (g_pPluginManager->GetPluginType(plugin_name) == ACTION) - { - CAction* action = g_pPluginManager->GetAction(plugin_name); - action->Run(pDebugDumpDir, it_a->second.c_str()); - } + action->Run(pDebugDumpDir, it_a->second.c_str()); } catch (CABRTException& e) { diff --git a/src/Daemon/PluginManager.cpp b/src/Daemon/PluginManager.cpp index 663228b..4aef630 100644 --- a/src/Daemon/PluginManager.cpp +++ b/src/Daemon/PluginManager.cpp @@ -138,7 +138,7 @@ void CPluginManager::LoadPlugins() if (!ext || strcmp(ext + 1, PLUGINS_LIB_EXTENSION) != 0) continue; *ext = '\0'; - LoadPlugin(dent->d_name + sizeof(PLUGINS_LIB_PREFIX)-1); + LoadPlugin(dent->d_name + sizeof(PLUGINS_LIB_PREFIX)-1, /*enabled_only:*/ true); } closedir(dir); } @@ -153,16 +153,37 @@ void CPluginManager::UnLoadPlugins() } } -void CPluginManager::LoadPlugin(const char *pName) +CPlugin* CPluginManager::LoadPlugin(const char *pName, bool enabled_only) { - if (m_mapLoadedModules.find(pName) != m_mapLoadedModules.end()) + map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName); + if (it_plugin != m_mapPlugins.end()) { - return; + return it_plugin->second; /* ok */ + } + + const char *conf_name = pName; + if (strncmp(pName, "Kerneloops", sizeof("Kerneloops")-1) == 0) + { + /* Kerneloops{,Scanner,Reporter} share the same .conf file */ + conf_name = "Kerneloops"; + } + map_plugin_settings_t pluginSettings; + std::string conf_fullname = ssprintf(PLUGINS_CONF_DIR"/%s."PLUGINS_CONF_EXTENSION, conf_name); + LoadPluginSettings(conf_fullname.c_str(), pluginSettings); + VERB3 log("Loaded %s.conf", conf_name); + + if (enabled_only) + { + map_plugin_settings_t::iterator it = pluginSettings.find("Enabled"); + if (it == pluginSettings.end() || !string_to_bool(it->second.c_str())) + { + VERB3 log("Plugin %s: 'Enabled' is not set, not loading it (yet)", pName); + return NULL; /* error */ + } } std::string libPath = ssprintf(PLUGINS_LIB_DIR"/"PLUGINS_LIB_PREFIX"%s."PLUGINS_LIB_EXTENSION, pName); CLoadedModule* module = new CLoadedModule(libPath.c_str()); - if (module->GetMagicNumber() != PLUGINS_MAGIC_NUMBER || module->GetType() < 0 || module->GetType() > MAX_PLUGIN_TYPE @@ -172,95 +193,63 @@ void CPluginManager::LoadPlugin(const char *pName) module->GetMagicNumber(), PLUGINS_MAGIC_NUMBER, module->GetType(), MAX_PLUGIN_TYPE); delete module; - return; - } - - log("Plugin %s (%s) succesfully loaded", pName, module->GetVersion()); - m_mapLoadedModules[pName] = module; -} - -void CPluginManager::UnLoadPlugin(const char *pName) -{ - map_loaded_module_t::iterator it_module = m_mapLoadedModules.find(pName); - if (it_module != m_mapLoadedModules.end()) - { - UnRegisterPlugin(pName); - delete it_module->second; - m_mapLoadedModules.erase(it_module); - log("Plugin %s successfully unloaded", pName); + return NULL; /* error */ } -} + VERB3 log("Loaded plugin %s v.%s", pName, module->GetVersion()); -int CPluginManager::RegisterPlugin(const char *pName) -{ - map_loaded_module_t::iterator it_module = m_mapLoadedModules.find(pName); - if (it_module == m_mapLoadedModules.end()) - { - error_msg("Can't initialize plugin %s: no such plugin installed", pName); - return -1; /* failure */ - } - if (m_mapPlugins.find(pName) != m_mapPlugins.end()) - { - return 0; /* already registered, success */ - } - - /* Loaded, but not registered yet */ - CPlugin* plugin = it_module->second->PluginNew(); - map_plugin_settings_t pluginSettings; - - const char *conf_name = pName; - if (strncmp(pName, "Kerneloops", sizeof("Kerneloops")-1) == 0) { - /* Kerneloops{,Scanner,Reporter} share the same .conf file */ - conf_name = "Kerneloops"; - } - LoadPluginSettings(ssprintf(PLUGINS_CONF_DIR"/%s."PLUGINS_CONF_EXTENSION, conf_name).c_str(), pluginSettings); - VERB3 log("Loaded %s.conf", conf_name); + CPlugin* plugin = NULL; try { + plugin = module->PluginNew(); plugin->Init(); plugin->SetSettings(pluginSettings); } catch (CABRTException& e) { - error_msg("Can't initialize plugin %s(%s): %s", + error_msg("Can't initialize plugin %s: %s", pName, - plugin_type_str[it_module->second->GetType()], e.what() ); - UnLoadPlugin(pName); - return -1; /* failure */ + delete plugin; + delete module; + return NULL; /* error */ } - m_mapPlugins[pName] = plugin; - log("Registered plugin %s(%s)", pName, plugin_type_str[it_module->second->GetType()]); - return 0; /* success */ -} -void CPluginManager::RegisterPluginDBUS(const char *pName, const char *pDBUSSender) -{ - int polkit_result = polkit_check_authorization(pDBUSSender, - "org.fedoraproject.abrt.change-daemon-settings"); - if (polkit_result == PolkitYes) - { - RegisterPlugin(pName); - } else - { - log("User %s not authorized, returned %d", pDBUSSender, polkit_result); - } + m_mapLoadedModules[pName] = module; + m_mapPlugins[pName] = plugin; + log("Registered %s plugin '%s'", plugin_type_str[module->GetType()], pName); + return plugin; /* ok */ } -void CPluginManager::UnRegisterPlugin(const char *pName) +void CPluginManager::UnLoadPlugin(const char *pName) { map_loaded_module_t::iterator it_module = m_mapLoadedModules.find(pName); if (it_module != m_mapLoadedModules.end()) { map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName); - if (it_plugin != m_mapPlugins.end()) + if (it_plugin != m_mapPlugins.end()) /* always true */ { it_plugin->second->DeInit(); delete it_plugin->second; m_mapPlugins.erase(it_plugin); - log("UnRegistered plugin %s(%s)", pName, plugin_type_str[it_module->second->GetType()]); } + delete it_module->second; + m_mapLoadedModules.erase(it_module); + log("UnRegistered %s plugin %s", plugin_type_str[it_module->second->GetType()], pName); + } +} + +void CPluginManager::RegisterPluginDBUS(const char *pName, const char *pDBUSSender) +{ + int polkit_result = polkit_check_authorization(pDBUSSender, + "org.fedoraproject.abrt.change-daemon-settings"); + if (polkit_result == PolkitYes) + { +//TODO: report success/failure + LoadPlugin(pName); + } else + { + log("User %s not authorized, returned %d", pDBUSSender, polkit_result); } } @@ -270,7 +259,7 @@ void CPluginManager::UnRegisterPluginDBUS(const char *pName, const char *pDBUSSe "org.fedoraproject.abrt.change-daemon-settings"); if (polkit_result == PolkitYes) { - UnRegisterPlugin(pName); + UnLoadPlugin(pName); } else { log("user %s not authorized, returned %d", pDBUSSender, polkit_result); @@ -280,50 +269,57 @@ void CPluginManager::UnRegisterPluginDBUS(const char *pName, const char *pDBUSSe CAnalyzer* CPluginManager::GetAnalyzer(const char *pName) { - map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName); - if (it_plugin == m_mapPlugins.end()) + CPlugin* plugin = LoadPlugin(pName); + if (!plugin) { - throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not registered", pName); + error_msg("Plugin '%s' is not registered", pName); + return NULL; } if (m_mapLoadedModules[pName]->GetType() != ANALYZER) { - throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not an analyzer plugin", pName); + error_msg("Plugin '%s' is not an analyzer plugin", pName); + return NULL; } - return (CAnalyzer*)(it_plugin->second); + return (CAnalyzer*)plugin; } CReporter* CPluginManager::GetReporter(const char *pName) { - map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName); - if (it_plugin == m_mapPlugins.end()) + CPlugin* plugin = LoadPlugin(pName); + if (!plugin) { - throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not registered", pName); + error_msg("Plugin '%s' is not registered", pName); + return NULL; } if (m_mapLoadedModules[pName]->GetType() != REPORTER) { - throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not a reporter plugin", pName); + error_msg("Plugin '%s' is not a reporter plugin", pName); + return NULL; } - return (CReporter*)(it_plugin->second); + return (CReporter*)plugin; } -CAction* CPluginManager::GetAction(const char *pName) +CAction* CPluginManager::GetAction(const char *pName, bool silent) { - map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName); - if (it_plugin == m_mapPlugins.end()) + CPlugin* plugin = LoadPlugin(pName); + if (!plugin) { - throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not registered", pName); + error_msg("Plugin '%s' is not registered", pName); + return NULL; } if (m_mapLoadedModules[pName]->GetType() != ACTION) { - throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not an action plugin", pName); + if (!silent) + error_msg("Plugin '%s' is not an action plugin", pName); + return NULL; } - return (CAction*)(it_plugin->second); + return (CAction*)plugin; } CDatabase* CPluginManager::GetDatabase(const char *pName) { - map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName); - if (it_plugin == m_mapPlugins.end()) + CPlugin* plugin = LoadPlugin(pName); + if (!plugin) { throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not registered", pName); } @@ -331,17 +327,18 @@ CDatabase* CPluginManager::GetDatabase(const char *pName) { throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not a database plugin", pName); } - return (CDatabase*)(it_plugin->second); + return (CDatabase*)plugin; } plugin_type_t CPluginManager::GetPluginType(const char *pName) { - map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName); - if (it_plugin == m_mapPlugins.end()) + CPlugin* plugin = LoadPlugin(pName); + if (!plugin) { throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not registered", pName); } - return m_mapLoadedModules[pName]->GetType(); + map_loaded_module_t::iterator it_module = m_mapLoadedModules.find(pName); + return it_module->second->GetType(); } vector_map_string_t CPluginManager::GetPluginsInfo() diff --git a/src/Daemon/PluginManager.h b/src/Daemon/PluginManager.h index 2d649c5..65058a5 100644 --- a/src/Daemon/PluginManager.h +++ b/src/Daemon/PluginManager.h @@ -74,7 +74,7 @@ class CPluginManager * A method, which loads particular plugin. * @param pName A plugin name. */ - void LoadPlugin(const char *pName); + CPlugin* LoadPlugin(const char *pName, bool enabled_only = false); /** * A method, which unloads particular plugin. * @param pName A plugin name. @@ -84,18 +84,6 @@ class CPluginManager * A method, which registers particular plugin. * @param pName A plugin name. */ - int RegisterPlugin(const char *pName); - /** - * A method, which unregister particular plugin. - * @param pName A plugin name. - */ - void UnRegisterPlugin(const char *pName); - /** - * A method, which registers particular plugin, - * called via DBUS - * @param pName A plugin name. - * @param pDBUSSender DBUS user identification - */ void RegisterPluginDBUS(const char *pName, const char *pDBUSSender); /** * A method, which unregister particular plugin, @@ -121,7 +109,7 @@ class CPluginManager * @param pName A plugin name. * @return An action plugin. */ - CAction* GetAction(const char *pName); + CAction* GetAction(const char *pName, bool silent = false); /** * A method, which returns instance of particular database plugin. * @param pName A plugin name. diff --git a/src/Daemon/Settings.cpp b/src/Daemon/Settings.cpp index d89bebf..48658e2 100644 --- a/src/Daemon/Settings.cpp +++ b/src/Daemon/Settings.cpp @@ -37,7 +37,6 @@ bool g_settings_bOpenGPGCheck = false; /* one line: "OpenGPGPublicKeys = value1,value2" */ set_string_t g_settings_setOpenGPGPublicKeys; set_string_t g_settings_mapBlackList; -set_string_t g_settings_setEnabledPlugins; std::string g_settings_sDatabase; unsigned int g_settings_nMaxCrashReportsSize = 1000; /* one line: "ActionsAndReporters = aa_first,bb_first(bb_second),cc_first" */ @@ -168,11 +167,6 @@ static void ParseCommon() { g_settings_sDatabase = it->second; } - it = s_mapSectionCommon.find("EnabledPlugins"); - if (it != end) - { - g_settings_setEnabledPlugins = ParseList(it->second.c_str()); - } it = s_mapSectionCommon.find("MaxCrashReportsSize"); if (it != end) { @@ -434,7 +428,6 @@ void SaveSettings() SaveBool("OpenGPGCheck", g_settings_bOpenGPGCheck, fOut); SaveSetString("OpenGPGPublicKeys", g_settings_setOpenGPGPublicKeys, fOut); SaveSetString("BlackList", g_settings_mapBlackList, fOut); - SaveSetString("EnabledPlugins", g_settings_setEnabledPlugins, fOut); fprintf(fOut, "Database = %s\n", g_settings_sDatabase.c_str()); fprintf(fOut, "MaxCrashReportsSize = %u\n", g_settings_nMaxCrashReportsSize); SaveVectorPairStrings("ActionsAndReporters", g_settings_vectorActionsAndReporters, fOut); diff --git a/src/Daemon/Settings.h b/src/Daemon/Settings.h index 9ee9370..3fdb8b9 100644 --- a/src/Daemon/Settings.h +++ b/src/Daemon/Settings.h @@ -9,7 +9,6 @@ typedef map_map_string_t map_abrt_settings_t; extern set_string_t g_settings_setOpenGPGPublicKeys; extern set_string_t g_settings_mapBlackList; -extern set_string_t g_settings_setEnabledPlugins; extern unsigned int g_settings_nMaxCrashReportsSize; extern bool g_settings_bOpenGPGCheck; extern std::string g_settings_sDatabase; diff --git a/src/Daemon/abrt.conf b/src/Daemon/abrt.conf index 276bf25..acf8566 100644 --- a/src/Daemon/abrt.conf +++ b/src/Daemon/abrt.conf @@ -9,11 +9,7 @@ OpenGPGCheck = no OpenGPGPublicKeys = /etc/pki/rpm-gpg/RPM-GPG-KEY-fedora # Blacklisted packages BlackList = nspluginwrapper -# Enabled plugins. -# You can disable handling e.g. Python crashes by not listing Python here. -# There has to be exactly one database plugin enabled. -EnabledPlugins = SQLite3, CCpp, Logger, Kerneloops, KerneloopsScanner, KerneloopsReporter, Bugzilla, Python, RunApp -# Database +# Which database plugin to use Database = SQLite3 # Max size for crash storage [MiB] MaxCrashReportsSize = 1000 diff --git a/src/Daemon/abrt.conf.5 b/src/Daemon/abrt.conf.5 index 3b172bc..7114f5c 100644 --- a/src/Daemon/abrt.conf.5 +++ b/src/Daemon/abrt.conf.5 @@ -30,10 +30,6 @@ to report them if "EnableOpenGPG = yes". .I abrt will ignore packages in this list and will not handle their crashes. .TP -.B EnabledPlugins = \fIplugin\fP, \fIplugin\fP ... -.I abrt -will only load plugins in this list. -.TP .B Database = \fIdatabasePlugin\fP This specifies which database plugin .I abrt -- cgit From 1d038a9cf5e154406710800c372631f5c7c3fd81 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 11 Jan 2010 07:20:12 +0100 Subject: abrt-hook-python: add input sanitization and directory size guard Signed-off-by: Denys Vlasenko --- src/Hooks/CCpp.cpp | 85 ++++-------------------------- src/Hooks/Makefile.am | 8 +-- src/Hooks/abrt-hook-python.cpp | 39 ++++++++------ src/Hooks/hooklib.cpp | 116 +++++++++++++++++++++++++++++++++++++++++ src/Hooks/hooklib.h | 21 ++++++++ 5 files changed, 174 insertions(+), 95 deletions(-) create mode 100644 src/Hooks/hooklib.cpp create mode 100644 src/Hooks/hooklib.h (limited to 'src') diff --git a/src/Hooks/CCpp.cpp b/src/Hooks/CCpp.cpp index 3a13358..4935b34 100644 --- a/src/Hooks/CCpp.cpp +++ b/src/Hooks/CCpp.cpp @@ -19,9 +19,11 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "abrtlib.h" +#include "hooklib.h" #include "DebugDump.h" #include "ABRTException.h" #include +#include #define FILENAME_EXECUTABLE "executable" #define FILENAME_COREDUMP "coredump" @@ -63,9 +65,9 @@ int main(int argc, char** argv) int fd; struct stat sb; - const char* program_name = argv[0]; if (argc < 5) { + const char* program_name = argv[0]; error_msg_and_die("Usage: %s: DUMPDIR PID SIGNO UID CORE_SIZE_LIMIT", program_name); } openlog("abrt", 0, LOG_DAEMON); @@ -124,62 +126,13 @@ int main(int argc, char** argv) /* Parse abrt.conf and plugins/CCpp.conf */ unsigned setting_MaxCrashReportsSize = 0; bool setting_MakeCompatCore = false; - bool abrt_conf = true; - FILE *fp = fopen(CONF_DIR"/abrt.conf", "r"); - if (fp) - { - char line[256]; - while (1) - { - if (fgets(line, sizeof(line), fp) == NULL) - { - /* Next .conf file plz */ - if (abrt_conf) - { - abrt_conf = false; - fp = fopen(CONF_DIR"/plugins/CCpp.conf", "r"); - if (fp) - continue; - } - break; - } + parse_conf(CONF_DIR"/plugins/CCpp.conf", &setting_MaxCrashReportsSize, &setting_MakeCompatCore); - unsigned len = strlen(line); - if (len > 0 && line[len-1] == '\n') - line[--len] = '\0'; - const char *p = skip_whitespace(line); -#undef DIRECTIVE -#define DIRECTIVE "MaxCrashReportsSize" - if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0) - { - p = skip_whitespace(p + sizeof(DIRECTIVE)-1); - if (*p != '=') - continue; - p = skip_whitespace(p + 1); - if (isdigit(*p)) - /* x1.25: go a bit up, so that usual in-daemon trimming - * kicks in first, and we don't "fight" with it. */ - setting_MaxCrashReportsSize = (unsigned long)xatou(p) * 5 / 4; - continue; - } -#undef DIRECTIVE -#define DIRECTIVE "MakeCompatCore" - if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0) - { - p = skip_whitespace(p + sizeof(DIRECTIVE)-1); - if (*p != '=') - continue; - p = skip_whitespace(p + 1); - setting_MakeCompatCore = string_to_bool(p); - continue; - } -#undef DIRECTIVE - /* add more 'if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)' here... */ - } - fclose(fp); + if (setting_MaxCrashReportsSize > 0) + { + check_free_space(setting_MaxCrashReportsSize); } - char path[PATH_MAX]; /* Check /var/cache/abrt/last-ccpp marker, do not dump repeated crashes @@ -288,30 +241,10 @@ int main(int argc, char** argv) */ dd.Close(); - /* rhbz#539551: "abrt going crazy when crashing process is respawned". - * Do we want to protect against or ameliorate this? How? Ideas: - * (1) nice ourself? - * (2) check total size of dump dir, if it overflows, either abort dump - * or delete oldest/biggest dumps? [abort would be simpler, - * abrtd already does "delete on overflow" thing] - * (3) detect parallel dumps in progress and back off - * (pause/renice further/??) - */ - + /* rhbz#539551: "abrt going crazy when crashing process is respawned" */ if (setting_MaxCrashReportsSize > 0) { - string worst_dir; - while (1) - { - const char *base_dirname = strrchr(path, '/') + 1; /* never NULL */ - /* We exclude our own dump from candidates for deletion (3rd param): */ - double dirsize = get_dirsize_find_largest_dir(DEBUG_DUMPS_DIR, &worst_dir, base_dirname); - if (dirsize / (1024*1024) < setting_MaxCrashReportsSize || worst_dir == "") - break; - log("size of '%s' >= %u MB, deleting '%s'", DEBUG_DUMPS_DIR, setting_MaxCrashReportsSize, worst_dir.c_str()); - delete_debug_dump_dir(concat_path_file(DEBUG_DUMPS_DIR, worst_dir.c_str()).c_str()); - worst_dir = ""; - } + trim_debug_dumps(setting_MaxCrashReportsSize, path); } if (!setting_MakeCompatCore) diff --git a/src/Hooks/Makefile.am b/src/Hooks/Makefile.am index 7581971..ebabd87 100644 --- a/src/Hooks/Makefile.am +++ b/src/Hooks/Makefile.am @@ -1,9 +1,10 @@ libexec_PROGRAMS = abrt-hook-ccpp abrt-hook-python bin_PROGRAMS = dumpoops -# CCpp +# abrt-hook-ccpp abrt_hook_ccpp_SOURCES = \ - CCpp.cpp + CCpp.cpp \ + hooklib.h hooklib.cpp abrt_hook_ccpp_CPPFLAGS = \ -I$(srcdir)/../../inc \ -I$(srcdir)/../../lib/Utils \ @@ -34,7 +35,8 @@ dumpoops_LDADD = \ # abrt-hook-python abrt_hook_python_SOURCES = \ - abrt-hook-python.cpp + abrt-hook-python.cpp \ + hooklib.h hooklib.cpp abrt_hook_python_CPPFLAGS = \ -I$(srcdir)/../../inc \ -I$(srcdir)/../../lib/Utils \ diff --git a/src/Hooks/abrt-hook-python.cpp b/src/Hooks/abrt-hook-python.cpp index 3f79d28..406cd82 100644 --- a/src/Hooks/abrt-hook-python.cpp +++ b/src/Hooks/abrt-hook-python.cpp @@ -24,12 +24,14 @@ /* We can easily get rid of abrtlib (libABRTUtils.so) usage in this file, * but DebugDump will pull it in anyway */ #include "abrtlib.h" +#include "hooklib.h" #include "DebugDump.h" #if HAVE_CONFIG_H # include #endif #define MAX_BT_SIZE (1024*1024) +#define MAX_BT_SIZE_STR "1 MB" static char *pid; static char *executable; @@ -74,9 +76,15 @@ int main(int argc, char** argv) ); } } - if (!pid) + if (!pid || !executable || !uuid) goto usage; -// is it really ok if other params aren't specified? abrtd might get confused... + + unsigned setting_MaxCrashReportsSize = 0; + parse_conf(NULL, &setting_MaxCrashReportsSize, NULL); + if (setting_MaxCrashReportsSize > 0) + { + check_free_space(setting_MaxCrashReportsSize); + } // Read the backtrace from stdin char *bt = (char*)xmalloc(MAX_BT_SIZE); @@ -88,35 +96,34 @@ int main(int argc, char** argv) bt[len] = '\0'; if (len == MAX_BT_SIZE-1) { - error_msg("Backtrace size limit exceeded, trimming to 1 MB"); + error_msg("Backtrace size limit exceeded, trimming to " MAX_BT_SIZE_STR); } + char *cmdline = get_cmdline(xatou(pid)); /* never NULL */ + // Create directory with the debug dump char path[PATH_MAX]; snprintf(path, sizeof(path), DEBUG_DUMPS_DIR"/pyhook-%ld-%s", (long)time(NULL), pid); - CDebugDump dd; dd.Create(path, geteuid()); - dd.SaveText(FILENAME_ANALYZER, "Python"); - if (executable) - dd.SaveText(FILENAME_EXECUTABLE, executable); - pid_t pidt = xatoi(pid); - char *cmdline = get_cmdline(pidt); + dd.SaveText(FILENAME_ANALYZER, "Python"); + dd.SaveText(FILENAME_EXECUTABLE, executable); + dd.SaveText("backtrace", bt); + free(bt); dd.SaveText("cmdline", cmdline); free(cmdline); - - if (uuid) - dd.SaveText("uuid", uuid); - + dd.SaveText("uuid", uuid); char uid[sizeof(int) * 3 + 2]; - sprintf(uid, "%d", (int)getuid()); + sprintf(uid, "%u", (unsigned)getuid()); dd.SaveText("uid", uid); - dd.SaveText("backtrace", bt); - free(bt); dd.Close(); + if (setting_MaxCrashReportsSize > 0) + { + trim_debug_dumps(setting_MaxCrashReportsSize, path); + } return 0; } diff --git a/src/Hooks/hooklib.cpp b/src/Hooks/hooklib.cpp new file mode 100644 index 0000000..41b9627 --- /dev/null +++ b/src/Hooks/hooklib.cpp @@ -0,0 +1,116 @@ +/* + 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 "abrtlib.h" +#include "hooklib.h" +#include "DebugDump.h" +#include + +using namespace std; + +void parse_conf(const char *additional_conf, unsigned *setting_MaxCrashReportsSize, bool *setting_MakeCompatCore) +{ + FILE *fp = fopen(CONF_DIR"/abrt.conf", "r"); + if (!fp) + return; + + char line[256]; + while (1) + { + if (fgets(line, sizeof(line), fp) == NULL) + { + fclose(fp); + if (additional_conf) + { + /* Next .conf file plz */ + fp = fopen(additional_conf, "r"); + if (fp) + { + additional_conf = NULL; + continue; + } + } + break; + } + + unsigned len = strlen(line); + if (len > 0 && line[len-1] == '\n') + line[--len] = '\0'; + const char *p = skip_whitespace(line); +#undef DIRECTIVE +#define DIRECTIVE "MaxCrashReportsSize" + if (setting_MaxCrashReportsSize && strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0) + { + p = skip_whitespace(p + sizeof(DIRECTIVE)-1); + if (*p != '=') + continue; + p = skip_whitespace(p + 1); + if (isdigit(*p)) + { + /* x1.25: go a bit up, so that usual in-daemon trimming + * kicks in first, and we don't "fight" with it. */ + *setting_MaxCrashReportsSize = (unsigned long)xatou(p) * 5 / 4; + } + continue; + } +#undef DIRECTIVE +#define DIRECTIVE "MakeCompatCore" + if (setting_MakeCompatCore && strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0) + { + p = skip_whitespace(p + sizeof(DIRECTIVE)-1); + if (*p != '=') + continue; + p = skip_whitespace(p + 1); + *setting_MakeCompatCore = string_to_bool(p); + continue; + } +#undef DIRECTIVE + /* add more 'if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)' here... */ + } +} + +void check_free_space(unsigned setting_MaxCrashReportsSize) +{ + /* Check that at least MaxCrashReportsSize/4 MBs are free. */ + struct statvfs vfs; + if (statvfs(DEBUG_DUMPS_DIR, &vfs) != 0 + || (vfs.f_bfree / (1024*1024 / 4)) * vfs.f_bsize < setting_MaxCrashReportsSize + ) { + error_msg_and_die("Low free disk space detected, aborting dump"); + } +} + +/* rhbz#539551: "abrt going crazy when crashing process is respawned". + * Check total size of dump dir, if it overflows, + * delete oldest/biggest dumps. + */ +void trim_debug_dumps(unsigned setting_MaxCrashReportsSize, const char *exclude_path) +{ + int count = 10; + string worst_dir; + while (--count >= 0) + { + const char *base_dirname = strrchr(exclude_path, '/') + 1; /* never NULL */ + /* We exclude our own dump from candidates for deletion (3rd param): */ + double dirsize = get_dirsize_find_largest_dir(DEBUG_DUMPS_DIR, &worst_dir, base_dirname); + if (dirsize / (1024*1024) < setting_MaxCrashReportsSize || worst_dir == "") + break; + log("size of '%s' >= %u MB, deleting '%s'", DEBUG_DUMPS_DIR, setting_MaxCrashReportsSize, worst_dir.c_str()); + delete_debug_dump_dir(concat_path_file(DEBUG_DUMPS_DIR, worst_dir.c_str()).c_str()); + worst_dir = ""; + } +} diff --git a/src/Hooks/hooklib.h b/src/Hooks/hooklib.h new file mode 100644 index 0000000..0794ff6 --- /dev/null +++ b/src/Hooks/hooklib.h @@ -0,0 +1,21 @@ +/* + 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. +*/ + +void parse_conf(const char *additional_conf, unsigned *setting_MaxCrashReportsSize, bool *setting_MakeCompatCore); +void check_free_space(unsigned setting_MaxCrashReportsSize); +void trim_debug_dumps(unsigned setting_MaxCrashReportsSize, const char *exclude_path); -- cgit From b1c4304104910c4bc066cd43f9784fe2f3ddf1ad Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 11 Jan 2010 07:21:31 +0100 Subject: *: cast pids and uigs to long, not int Signed-off-by: Denys Vlasenko --- src/Daemon/Daemon.cpp | 4 ++-- src/Daemon/PluginManager.cpp | 4 ++-- src/Hooks/CCpp.cpp | 26 +++++++++++++------------- src/Hooks/abrt-hook-python.cpp | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp index 7577611..9e1aa0d 100644 --- a/src/Daemon/Daemon.cpp +++ b/src/Daemon/Daemon.cpp @@ -361,8 +361,8 @@ static int CreatePidFile() if (fd >= 0) { /* write our pid to it */ - char buf[sizeof(int)*3 + 2]; - int len = sprintf(buf, "%u\n", (unsigned)getpid()); + char buf[sizeof(long)*3 + 2]; + int len = sprintf(buf, "%lu\n", (long)getpid()); write(fd, buf, len); close(fd); return 0; diff --git a/src/Daemon/PluginManager.cpp b/src/Daemon/PluginManager.cpp index 4aef630..697b964 100644 --- a/src/Daemon/PluginManager.cpp +++ b/src/Daemon/PluginManager.cpp @@ -412,7 +412,7 @@ void CPluginManager::SetPluginSettings(const char *pName, } if (chown(confDir.c_str(), uid, gid) == -1) { - perror_msg("Can't change '%s' ownership to %u:%u", confPath.c_str(), (int)uid, (int)gid); + perror_msg("Can't change '%s' ownership to %lu:%lu", confPath.c_str(), (long)uid, (long)gid); return; } } @@ -430,7 +430,7 @@ void CPluginManager::SetPluginSettings(const char *pName, SavePluginSettings(confPath, pSettings); if (chown(confPath.c_str(), uid, gid) == -1) { - perror_msg("Can't change '%s' ownership to %u:%u", confPath.c_str(), (int)uid, (int)gid); + perror_msg("Can't change '%s' ownership to %lu:%lu", confPath.c_str(), (long)uid, (long)gid); return; } */ diff --git a/src/Hooks/CCpp.cpp b/src/Hooks/CCpp.cpp index 4935b34..b09a132 100644 --- a/src/Hooks/CCpp.cpp +++ b/src/Hooks/CCpp.cpp @@ -46,17 +46,17 @@ static char* malloc_readlink(const char *linkname) static char* get_executable(pid_t pid) { - char buf[sizeof("/proc/%u/exe") + sizeof(int)*3]; + char buf[sizeof("/proc/%lu/exe") + sizeof(long)*3]; - sprintf(buf, "/proc/%u/exe", (int)pid); + sprintf(buf, "/proc/%lu/exe", (long)pid); return malloc_readlink(buf); } static char* get_cwd(pid_t pid) { - char buf[sizeof("/proc/%u/cwd") + sizeof(int)*3]; + char buf[sizeof("/proc/%lu/cwd") + sizeof(long)*3]; - sprintf(buf, "/proc/%u/cwd", (int)pid); + sprintf(buf, "/proc/%lu/cwd", (long)pid); return malloc_readlink(buf); } @@ -115,12 +115,12 @@ int main(int argc, char** argv) char* executable = get_executable(pid); if (executable == NULL) { - error_msg_and_die("can't read /proc/%u/exe link", (int)pid); + error_msg_and_die("can't read /proc/%lu/exe link", (long)pid); } if (strstr(executable, "/abrt-hook-ccpp")) { - error_msg_and_die("pid %u is '%s', not dumping it to avoid recursion", - (int)pid, executable); + error_msg_and_die("pid %lu is '%s', not dumping it to avoid recursion", + (long)pid, executable); } /* Parse abrt.conf and plugins/CCpp.conf */ @@ -185,7 +185,7 @@ int main(int argc, char** argv) * but it does not log file name */ error_msg_and_die("error saving coredump to %s", path); } - log("saved core dump of pid %u (%s) to %s (%llu bytes)", (int)pid, executable, path, (long long)core_size); + log("saved core dump of pid %lu (%s) to %s (%llu bytes)", (long)pid, executable, path, (long long)core_size); return 0; } @@ -193,7 +193,7 @@ int main(int argc, char** argv) const char *signame = strsignal(signal_no); char *reason = xasprintf("Process was terminated by signal %s (%s)", signal_str, signame ? signame : signal_str); - snprintf(path, sizeof(path), "%s/ccpp-%ld-%u", dddir, (long)time(NULL), (int)pid); + snprintf(path, sizeof(path), "%s/ccpp-%ld-%lu", dddir, (long)time(NULL), (long)pid); CDebugDump dd; dd.Create(path, uid); dd.SaveText(FILENAME_ANALYZER, "CCpp"); @@ -228,7 +228,7 @@ int main(int argc, char** argv) } lseek(core_fd, 0, SEEK_SET); /* note: core_fd is still open, we may use it later to copy core to user's dir */ - log("saved core dump of pid %u (%s) to %s (%llu bytes)", (int)pid, executable, path, (long long)core_size); + log("saved core dump of pid %lu (%s) to %s (%llu bytes)", (long)pid, executable, path, (long long)core_size); free(executable); free(cmdline); path[len] = '\0'; /* path now contains directory name */ @@ -282,7 +282,7 @@ int main(int argc, char** argv) } /* Mimic "core.PID" if requested */ - char core_basename[sizeof("core.%u") + sizeof(int)*3] = "core"; + char core_basename[sizeof("core.%lu") + sizeof(long)*3] = "core"; char buf[] = "0\n"; fd = open("/proc/sys/kernel/core_uses_pid", O_RDONLY); if (fd >= 0) @@ -292,7 +292,7 @@ int main(int argc, char** argv) } if (strcmp(buf, "1\n") == 0) { - sprintf(core_basename, "core.%u", (int)pid); + sprintf(core_basename, "core.%lu", (long)pid); } /* man core: @@ -358,7 +358,7 @@ int main(int argc, char** argv) unlink(core_basename); return 1; } - log("saved core dump of pid %u to %s/%s (%llu bytes)", (int)pid, user_pwd, core_basename, (long long)size); + log("saved core dump of pid %lu to %s/%s (%llu bytes)", (long)pid, user_pwd, core_basename, (long long)size); return 0; } diff --git a/src/Hooks/abrt-hook-python.cpp b/src/Hooks/abrt-hook-python.cpp index 406cd82..468c7ec 100644 --- a/src/Hooks/abrt-hook-python.cpp +++ b/src/Hooks/abrt-hook-python.cpp @@ -115,8 +115,8 @@ int main(int argc, char** argv) dd.SaveText("cmdline", cmdline); free(cmdline); dd.SaveText("uuid", uuid); - char uid[sizeof(int) * 3 + 2]; - sprintf(uid, "%u", (unsigned)getuid()); + char uid[sizeof(long) * 3 + 2]; + sprintf(uid, "%lu", (long)getuid()); dd.SaveText("uid", uid); dd.Close(); -- cgit From 14ef0cfe72faf6696df3ef8f42927e9458ccbeeb Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 11 Jan 2010 07:22:13 +0100 Subject: *: misc fixes Signed-off-by: Denys Vlasenko --- src/Applet/CCApplet.cpp | 2 +- src/Daemon/CrashWatcher.cpp | 12 +++++------- src/Daemon/abrt-debuginfo-install | 6 ++++-- src/Hooks/CCpp.cpp | 2 +- src/Hooks/abrt-hook-python.cpp | 2 ++ 5 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/Applet/CCApplet.cpp b/src/Applet/CCApplet.cpp index 07e44d8..770915a 100644 --- a/src/Applet/CCApplet.cpp +++ b/src/Applet/CCApplet.cpp @@ -205,7 +205,7 @@ void CApplet::CrashNotify(const char *format, ...) if (gtk_status_icon_is_embedded(m_pStatusIcon)) notify_notification_show(m_pNotification, &err); if (err != NULL) - error_msg(err->message); + error_msg("%s", err->message); } void CApplet::OnAppletActivate_CB(GtkStatusIcon *status_icon, gpointer user_data) diff --git a/src/Daemon/CrashWatcher.cpp b/src/Daemon/CrashWatcher.cpp index 88c058b..59f9e65 100644 --- a/src/Daemon/CrashWatcher.cpp +++ b/src/Daemon/CrashWatcher.cpp @@ -168,12 +168,11 @@ int CreateReportThread(const char* pUUID, const char* pUID, int force, const cha thread_data->force = force; thread_data->peer = xstrdup(pSender); -//TODO: do we need this? -//pthread_attr_t attr; -//pthread_attr_init(&attr); -//pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - int r = pthread_create(&thread_data->thread_id, NULL, create_report, thread_data); + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int r = pthread_create(&thread_data->thread_id, &attr, create_report, thread_data); + pthread_attr_destroy(&attr); if (r != 0) { free(thread_data->UUID); @@ -187,7 +186,6 @@ int CreateReportThread(const char* pUUID, const char* pUID, int force, const cha return r; } VERB3 log("Thread %llx created", (unsigned long long)thread_data->thread_id); -//pthread_attr_destroy(&attr); return r; } diff --git a/src/Daemon/abrt-debuginfo-install b/src/Daemon/abrt-debuginfo-install index cfae49a..35f4d6a 100755 --- a/src/Daemon/abrt-debuginfo-install +++ b/src/Daemon/abrt-debuginfo-install @@ -145,9 +145,11 @@ print_package_names() { fi # when we look for debuginfo we need only -debuginfo* repos, so we can disable the rest and thus make it faster # also we want only fedora repositories, because abrt won't work for other packages anyway - local cmd="yum $yumopts --disablerepo=* --enablerepo=fedora-debuginfo* --enablerepo=updates-debuginfo* --quiet provides $missing_debuginfo_files" + local cmd="yum $yumopts '--disablerepo=*' '--enablerepo=fedora-debuginfo*' '--enablerepo=updates-debuginfo*' --quiet provides $missing_debuginfo_files" echo "$cmd" >"yum_provides.$1.OUT" - local yum_provides_OUT="`$cmd 2>&1`" + # eval is needed to strip away ''s; cant remove them above and just use + # $cmd, that would perform globbing on '*' + local yum_provides_OUT="`eval $cmd 2>&1`" local err=$? printf "%s\nyum exitcode:%s\n" "$yum_provides_OUT" $err >>"yum_provides.$1.OUT" test $err = 0 || error_msg_and_die "yum provides... exited with $err: diff --git a/src/Hooks/CCpp.cpp b/src/Hooks/CCpp.cpp index b09a132..b5bfff7 100644 --- a/src/Hooks/CCpp.cpp +++ b/src/Hooks/CCpp.cpp @@ -70,7 +70,7 @@ int main(int argc, char** argv) const char* program_name = argv[0]; error_msg_and_die("Usage: %s: DUMPDIR PID SIGNO UID CORE_SIZE_LIMIT", program_name); } - openlog("abrt", 0, LOG_DAEMON); + openlog("abrt", 0, LOG_PID | LOG_DAEMON); logmode = LOGMODE_SYSLOG; errno = 0; diff --git a/src/Hooks/abrt-hook-python.cpp b/src/Hooks/abrt-hook-python.cpp index 468c7ec..1a7eace 100644 --- a/src/Hooks/abrt-hook-python.cpp +++ b/src/Hooks/abrt-hook-python.cpp @@ -79,6 +79,8 @@ int main(int argc, char** argv) if (!pid || !executable || !uuid) goto usage; +//TODO: sanitize uuid and executable (size, valid chars etc) + unsigned setting_MaxCrashReportsSize = 0; parse_conf(NULL, &setting_MaxCrashReportsSize, NULL); if (setting_MaxCrashReportsSize > 0) -- cgit From edf6beb585dc38c365ccbdaae85756b2814e1329 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 11 Jan 2010 12:09:57 +0100 Subject: *: assorted fixes prompted by security analysis; more to come Signed-off-by: Denys Vlasenko --- src/Applet/CCApplet.cpp | 11 ++++++----- src/Daemon/Daemon.cpp | 8 +++++--- src/Daemon/MiddleWare.cpp | 2 ++ src/Daemon/PluginManager.cpp | 2 ++ src/Daemon/RPM.cpp | 4 ++-- src/Hooks/CCpp.cpp | 2 +- src/Hooks/dumpoops.cpp | 1 + 7 files changed, 19 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/Applet/CCApplet.cpp b/src/Applet/CCApplet.cpp index 770915a..302fe0b 100644 --- a/src/Applet/CCApplet.cpp +++ b/src/Applet/CCApplet.cpp @@ -192,20 +192,21 @@ void CApplet::SetIconTooltip(const char *format, ...) void CApplet::CrashNotify(const char *format, ...) { va_list args; - char *buf; - int n; - GError *err = NULL; va_start(args, format); - buf = NULL; - n = vasprintf(&buf, format, args); + char *buf = xvasprintf(format, args); va_end(args); notify_notification_update(m_pNotification, _("Warning"), buf, NULL); + + GError *err = NULL; if (gtk_status_icon_is_embedded(m_pStatusIcon)) notify_notification_show(m_pNotification, &err); if (err != NULL) + { error_msg("%s", err->message); + g_error_free(err); + } } void CApplet::OnAppletActivate_CB(GtkStatusIcon *status_icon, gpointer user_data) diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp index 9e1aa0d..0f9c622 100644 --- a/src/Daemon/Daemon.cpp +++ b/src/Daemon/Daemon.cpp @@ -203,10 +203,12 @@ static int SetUpCron() int nM = -1; int nS = -1; +//TODO: rewrite using good old sscanf? + if (pos != std::string::npos) { - std::string sH = ""; - std::string sM = ""; + std::string sH; + std::string sM; sH = it_c->first.substr(0, pos); nH = xatou(sH.c_str()); @@ -221,7 +223,7 @@ static int SetUpCron() } else { - std::string sS = ""; + std::string sS; sS = it_c->first; nS = xatou(sS.c_str()); diff --git a/src/Daemon/MiddleWare.cpp b/src/Daemon/MiddleWare.cpp index 3656060..a348a92 100644 --- a/src/Daemon/MiddleWare.cpp +++ b/src/Daemon/MiddleWare.cpp @@ -548,6 +548,8 @@ report_status_t Report(const map_crash_report_t& pCrashReport, static bool IsDebugDumpSaved(const char *pUID, const char *pDebugDumpDir) { + /* TODO: use database query instead of dumping all rows and searching in them */ + CDatabase* database = g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str()); database->Connect(); vector_database_rows_t rows = database->GetUIDData(pUID); diff --git a/src/Daemon/PluginManager.cpp b/src/Daemon/PluginManager.cpp index 697b964..a6550e7 100644 --- a/src/Daemon/PluginManager.cpp +++ b/src/Daemon/PluginManager.cpp @@ -138,6 +138,8 @@ void CPluginManager::LoadPlugins() if (!ext || strcmp(ext + 1, PLUGINS_LIB_EXTENSION) != 0) continue; *ext = '\0'; + if (strncmp(dent->d_name, PLUGINS_LIB_PREFIX, sizeof(PLUGINS_LIB_PREFIX)-1) != 0) + continue; LoadPlugin(dent->d_name + sizeof(PLUGINS_LIB_PREFIX)-1, /*enabled_only:*/ true); } closedir(dir); diff --git a/src/Daemon/RPM.cpp b/src/Daemon/RPM.cpp index 6f05c0b..6cc0ba6 100644 --- a/src/Daemon/RPM.cpp +++ b/src/Daemon/RPM.cpp @@ -4,8 +4,8 @@ CRPM::CRPM() { - char *argv[] = { (char*)"" }; - m_poptContext = rpmcliInit(0, argv, NULL); + static const char *const argv[] = { "", NULL }; + m_poptContext = rpmcliInit(1, (char**)argv, NULL); } CRPM::~CRPM() diff --git a/src/Hooks/CCpp.cpp b/src/Hooks/CCpp.cpp index b5bfff7..ea08bae 100644 --- a/src/Hooks/CCpp.cpp +++ b/src/Hooks/CCpp.cpp @@ -139,7 +139,7 @@ int main(int argc, char** argv) * if they happen too often. Else, write new marker value. */ snprintf(path, sizeof(path), "%s/last-ccpp", dddir); - fd = open(path, O_RDWR | O_CREAT, 0666); + fd = open(path, O_RDWR | O_CREAT, 0600); if (fd >= 0) { int sz; diff --git a/src/Hooks/dumpoops.cpp b/src/Hooks/dumpoops.cpp index 4b6778d..01e65c4 100644 --- a/src/Hooks/dumpoops.cpp +++ b/src/Hooks/dumpoops.cpp @@ -83,6 +83,7 @@ int main(int argc, char **argv) void *handle; errno = 0; +//TODO: use it directly, not via dlopen? handle = dlopen(PLUGINS_LIB_DIR"/libKerneloopsScanner.so", RTLD_NOW); if (!handle) perror_msg_and_die("can't load %s", PLUGINS_LIB_DIR"/libKerneloopsScanner.so"); -- cgit From 20645ae11a8a9a89cc712896b2f72a25bc62c8db Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 11 Jan 2010 12:12:53 +0100 Subject: DebugDump: more consistent logic in setting mode and uid:gid on dump dir With comments! yay. Before it, too restrictive mode was preventing python craches to be handled. Signed-off-by: Karel Klic Signed-off-by: Denys Vlasenko --- src/Hooks/CCpp.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/Hooks/CCpp.cpp b/src/Hooks/CCpp.cpp index ea08bae..21fe0be 100644 --- a/src/Hooks/CCpp.cpp +++ b/src/Hooks/CCpp.cpp @@ -216,6 +216,10 @@ int main(int argc, char** argv) dd.Close(); perror_msg_and_die("can't open '%s'", path); } +//TODO: chown to uid:abrt? +//Currently it is owned by 0:0 but is readable by anyone, so the owner +//of the crashed binary still can access it, as he has +//r-x access to the dump dir. core_size = copyfd_eof(STDIN_FILENO, core_fd); if (core_size < 0 || fsync(core_fd) != 0) { -- cgit From d037916adc56d384717ebd6b7a5963543febc170 Mon Sep 17 00:00:00 2001 From: Karel Klic Date: Mon, 11 Jan 2010 12:27:18 +0100 Subject: Catch and display ABRTException thrown by CDebugDump::Create --- src/Hooks/abrt-hook-python.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/Hooks/abrt-hook-python.cpp b/src/Hooks/abrt-hook-python.cpp index 1a7eace..d7fca67 100644 --- a/src/Hooks/abrt-hook-python.cpp +++ b/src/Hooks/abrt-hook-python.cpp @@ -26,6 +26,7 @@ #include "abrtlib.h" #include "hooklib.h" #include "DebugDump.h" +#include "ABRTException.h" #if HAVE_CONFIG_H # include #endif @@ -108,7 +109,12 @@ int main(int argc, char** argv) snprintf(path, sizeof(path), DEBUG_DUMPS_DIR"/pyhook-%ld-%s", (long)time(NULL), pid); CDebugDump dd; - dd.Create(path, geteuid()); + + try { + dd.Create(path, geteuid()); + } catch (CABRTException &e) { + error_msg_and_die("Error while creating debug dump: %s", e.what()); + } dd.SaveText(FILENAME_ANALYZER, "Python"); dd.SaveText(FILENAME_EXECUTABLE, executable); -- cgit From 71fb2d7e690640b391b76b5432f07b4a81351c8b Mon Sep 17 00:00:00 2001 From: Karel Klic Date: Tue, 12 Jan 2010 14:26:08 +0100 Subject: Fixing /var/cache/abrt/ permissions by allowing users to read, but not to change their crash data. Adds abrt user, changes abrt-hook-python to use suid instead of sgid bit (uid=abrt), sets /var/cache/abrt and every dump subdirectory to be owned by abrt user. Read access for users and their own crashes is provided by group (/var/cache/abrt/ccpp-xxxx-xx has user's group). --- src/Daemon/Daemon.cpp | 14 +++++++------- src/Hooks/abrt-hook-python.cpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp index 0f9c622..09d8ab8 100644 --- a/src/Daemon/Daemon.cpp +++ b/src/Daemon/Daemon.cpp @@ -632,7 +632,7 @@ static void start_syslog_logging() logmode = LOGMODE_SYSLOG; } -static void ensure_writable_dir(const char *dir, mode_t mode, const char *group) +static void ensure_writable_dir(const char *dir, mode_t mode, const char *user) { struct stat sb; @@ -641,12 +641,12 @@ static void ensure_writable_dir(const char *dir, mode_t mode, const char *group) if (stat(dir, &sb) != 0 || !S_ISDIR(sb.st_mode)) error_msg_and_die("'%s' is not a directory", dir); - struct group *gr = getgrnam(group); - if (!gr) - perror_msg_and_die("Can't find group '%s'", group); + struct passwd *pw = getpwnam(user); + if (!pw) + perror_msg_and_die("Can't find user '%s'", user); - if ((sb.st_uid != 0 || sb.st_gid != gr->gr_gid) && chown(dir, 0, gr->gr_gid) != 0) - perror_msg_and_die("Can't set owner 0:%u on '%s'", (unsigned int)gr->gr_gid, dir); + if ((sb.st_uid != pw->pw_uid || sb.st_gid != pw->pw_gid) && chown(dir, pw->pw_uid, pw->pw_gid) != 0) + perror_msg_and_die("Can't set owner %u:%u on '%s'", (unsigned int)pw->pw_uid, (unsigned int)pw->pw_gid, dir); if ((sb.st_mode & 07777) != mode && chmod(dir, mode) != 0) perror_msg_and_die("Can't set mode %o on '%s'", mode, dir); } @@ -657,7 +657,7 @@ static void sanitize_dump_dir_rights() * us with thousands of bogus or malicious dumps */ /* 07000 bits are setuid, setgit, and sticky, and they must be unset */ /* 00777 bits are usual "rwxrwxrwx" access rights */ - ensure_writable_dir(DEBUG_DUMPS_DIR, 0775, "abrt"); + ensure_writable_dir(DEBUG_DUMPS_DIR, 0755, "abrt"); /* debuginfo cache */ ensure_writable_dir(DEBUG_DUMPS_DIR"-di", 0755, "root"); /* temp dir */ diff --git a/src/Hooks/abrt-hook-python.cpp b/src/Hooks/abrt-hook-python.cpp index d7fca67..b921fba 100644 --- a/src/Hooks/abrt-hook-python.cpp +++ b/src/Hooks/abrt-hook-python.cpp @@ -111,7 +111,7 @@ int main(int argc, char** argv) CDebugDump dd; try { - dd.Create(path, geteuid()); + dd.Create(path, getuid()); } catch (CABRTException &e) { error_msg_and_die("Error while creating debug dump: %s", e.what()); } -- cgit From 223a6051757ac531d89c2a576da89b6b6f46ecf2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 12 Jan 2010 16:30:40 +0100 Subject: src/Hooks/CCpp.cpp -> src/Hooks/abrt_hook_ccpp.cpp Signed-off-by: Denys Vlasenko --- src/Hooks/CCpp.cpp | 368 ------------------------------------------- src/Hooks/Makefile.am | 2 +- src/Hooks/abrt_hook_ccpp.cpp | 368 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 369 insertions(+), 369 deletions(-) delete mode 100644 src/Hooks/CCpp.cpp create mode 100644 src/Hooks/abrt_hook_ccpp.cpp (limited to 'src') diff --git a/src/Hooks/CCpp.cpp b/src/Hooks/CCpp.cpp deleted file mode 100644 index 21fe0be..0000000 --- a/src/Hooks/CCpp.cpp +++ /dev/null @@ -1,368 +0,0 @@ -/* - CCpp.cpp - the hook for C/C++ crashing program - - 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 "abrtlib.h" -#include "hooklib.h" -#include "DebugDump.h" -#include "ABRTException.h" -#include -#include - -#define FILENAME_EXECUTABLE "executable" -#define FILENAME_COREDUMP "coredump" - -using namespace std; - -static char* malloc_readlink(const char *linkname) -{ - char buf[PATH_MAX + 1]; - int len; - - len = readlink(linkname, buf, sizeof(buf)-1); - if (len >= 0) - { - buf[len] = '\0'; - return xstrdup(buf); - } - return NULL; -} - -static char* get_executable(pid_t pid) -{ - char buf[sizeof("/proc/%lu/exe") + sizeof(long)*3]; - - sprintf(buf, "/proc/%lu/exe", (long)pid); - return malloc_readlink(buf); -} - -static char* get_cwd(pid_t pid) -{ - char buf[sizeof("/proc/%lu/cwd") + sizeof(long)*3]; - - sprintf(buf, "/proc/%lu/cwd", (long)pid); - return malloc_readlink(buf); -} - -int main(int argc, char** argv) -{ - int fd; - struct stat sb; - - if (argc < 5) - { - const char* program_name = argv[0]; - error_msg_and_die("Usage: %s: DUMPDIR PID SIGNO UID CORE_SIZE_LIMIT", program_name); - } - openlog("abrt", 0, LOG_PID | LOG_DAEMON); - logmode = LOGMODE_SYSLOG; - - errno = 0; - const char* dddir = argv[1]; - pid_t pid = xatoi_u(argv[2]); - const char* signal_str = argv[3]; - int signal_no = xatoi_u(argv[3]); - uid_t uid = xatoi_u(argv[4]); - off_t ulimit_c = strtoull(argv[5], NULL, 10); - off_t core_size = 0; - - if (errno || pid <= 0 || ulimit_c < 0) - { - error_msg_and_die("pid '%s' or limit '%s' is bogus", argv[2], argv[5]); - } - if (signal_no != SIGQUIT - && signal_no != SIGILL - && signal_no != SIGABRT - && signal_no != SIGFPE - && signal_no != SIGSEGV - ) { - /* not an error, exit silently */ - return 0; - } - - - char *user_pwd = get_cwd(pid); /* may be NULL on error */ - int core_fd = STDIN_FILENO; - - if (!daemon_is_ok()) - { - /* not an error, exit with exitcode 0 */ - log("abrt daemon is not running. If it crashed, " - "/proc/sys/kernel/core_pattern contains a stale value, " - "consider resetting it to 'core'" - ); - goto create_user_core; - } - - try - { - char* executable = get_executable(pid); - if (executable == NULL) - { - error_msg_and_die("can't read /proc/%lu/exe link", (long)pid); - } - if (strstr(executable, "/abrt-hook-ccpp")) - { - error_msg_and_die("pid %lu is '%s', not dumping it to avoid recursion", - (long)pid, executable); - } - - /* Parse abrt.conf and plugins/CCpp.conf */ - unsigned setting_MaxCrashReportsSize = 0; - bool setting_MakeCompatCore = false; - parse_conf(CONF_DIR"/plugins/CCpp.conf", &setting_MaxCrashReportsSize, &setting_MakeCompatCore); - - if (setting_MaxCrashReportsSize > 0) - { - check_free_space(setting_MaxCrashReportsSize); - } - - char path[PATH_MAX]; - - /* Check /var/cache/abrt/last-ccpp marker, do not dump repeated crashes - * if they happen too often. Else, write new marker value. - */ - snprintf(path, sizeof(path), "%s/last-ccpp", dddir); - fd = open(path, O_RDWR | O_CREAT, 0600); - if (fd >= 0) - { - int sz; - fstat(fd, &sb); /* !paranoia. this can't fail. */ - - if (sb.st_size != 0 /* if it wasn't created by us just now... */ - && (unsigned)(time(NULL) - sb.st_mtime) < 20 /* and is relatively new [is 20 sec ok?] */ - ) { - sz = read(fd, path, sizeof(path)-1); /* (ab)using path as scratch buf */ - if (sz > 0) - { - path[sz] = '\0'; - if (strcmp(executable, path) == 0) - { - error_msg("not dumping repeating crash in '%s'", executable); - if (setting_MakeCompatCore) - goto create_user_core; - return 1; - } - } - lseek(fd, 0, SEEK_SET); - } - sz = write(fd, executable, strlen(executable)); - if (sz >= 0) - ftruncate(fd, sz); - close(fd); - } - - if (strstr(executable, "/abrtd")) - { - /* If abrtd crashes, we don't want to create a _directory_, - * since that can make new copy of abrtd to process it, - * and maybe crash again... - * Unlike dirs, mere files are ignored by abrtd. - */ - snprintf(path, sizeof(path), "%s/abrtd-coredump", dddir); - core_fd = xopen3(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - core_size = copyfd_eof(STDIN_FILENO, core_fd); - if (core_size < 0 || close(core_fd) != 0) - { - unlink(path); - /* copyfd_eof logs the error including errno string, - * but it does not log file name */ - error_msg_and_die("error saving coredump to %s", path); - } - log("saved core dump of pid %lu (%s) to %s (%llu bytes)", (long)pid, executable, path, (long long)core_size); - return 0; - } - - char* cmdline = get_cmdline(pid); /* never NULL */ - const char *signame = strsignal(signal_no); - char *reason = xasprintf("Process was terminated by signal %s (%s)", signal_str, signame ? signame : signal_str); - - snprintf(path, sizeof(path), "%s/ccpp-%ld-%lu", dddir, (long)time(NULL), (long)pid); - CDebugDump dd; - dd.Create(path, uid); - dd.SaveText(FILENAME_ANALYZER, "CCpp"); - dd.SaveText(FILENAME_EXECUTABLE, executable); - dd.SaveText(FILENAME_CMDLINE, cmdline); - dd.SaveText(FILENAME_REASON, reason); - - int len = strlen(path); - snprintf(path + len, sizeof(path) - len, "/"FILENAME_COREDUMP); - - /* We need coredumps to be readable by all, because - * when abrt daemon processes coredump, - * process producing backtrace is run under the same UID - * as the crashed process. - * Thus 644, not 600 */ - core_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644); - if (core_fd < 0) - { - dd.Delete(); - dd.Close(); - perror_msg_and_die("can't open '%s'", path); - } -//TODO: chown to uid:abrt? -//Currently it is owned by 0:0 but is readable by anyone, so the owner -//of the crashed binary still can access it, as he has -//r-x access to the dump dir. - core_size = copyfd_eof(STDIN_FILENO, core_fd); - if (core_size < 0 || fsync(core_fd) != 0) - { - unlink(path); - dd.Delete(); - dd.Close(); - /* copyfd_eof logs the error including errno string, - * but it does not log file name */ - error_msg_and_die("error saving coredump to %s", path); - } - lseek(core_fd, 0, SEEK_SET); - /* note: core_fd is still open, we may use it later to copy core to user's dir */ - log("saved core dump of pid %lu (%s) to %s (%llu bytes)", (long)pid, executable, path, (long long)core_size); - free(executable); - free(cmdline); - path[len] = '\0'; /* path now contains directory name */ - - /* We close dumpdir before we start catering for crash storm case. - * Otherwise, delete_debug_dump_dir's from other concurrent - * CCpp's won't be able to delete our dump (their delete_debug_dump_dir - * will wait for us), and we won't be able to delete their dumps. - * Classic deadlock. - */ - dd.Close(); - - /* rhbz#539551: "abrt going crazy when crashing process is respawned" */ - if (setting_MaxCrashReportsSize > 0) - { - trim_debug_dumps(setting_MaxCrashReportsSize, path); - } - - if (!setting_MakeCompatCore) - return 0; - /* fall through to creating user core */ - } - catch (CABRTException& e) - { - error_msg_and_die("%s", e.what()); - } - catch (std::exception& e) - { - error_msg_and_die("%s", e.what()); - } - - - create_user_core: - /* note: core_size may be == 0 ("unknown") */ - if (core_size > ulimit_c || ulimit_c == 0) - return 0; - - /* Write a core file for user */ - - struct passwd* pw = getpwuid(uid); - gid_t gid = pw ? pw->pw_gid : uid; - setgroups(1, &gid); - xsetregid(gid, gid); - xsetreuid(uid, uid); - - errno = 0; - if (user_pwd == NULL - || chdir(user_pwd) != 0 - ) { - perror_msg_and_die("can't cd to %s", user_pwd); - } - - /* Mimic "core.PID" if requested */ - char core_basename[sizeof("core.%lu") + sizeof(long)*3] = "core"; - char buf[] = "0\n"; - fd = open("/proc/sys/kernel/core_uses_pid", O_RDONLY); - if (fd >= 0) - { - read(fd, buf, sizeof(buf)); - close(fd); - } - if (strcmp(buf, "1\n") == 0) - { - sprintf(core_basename, "core.%lu", (long)pid); - } - - /* man core: - * There are various circumstances in which a core dump file - * is not produced: - * - * [skipped obvious ones] - * The process does not have permission to write the core file. - * ...if a file with the same name exists and is not writable - * or is not a regular file (e.g., it is a directory or a symbolic link). - * - * A file with the same name already exists, but there is more - * than one hard link to that file. - * - * The file system where the core dump file would be created is full; - * or has run out of inodes; or is mounted read-only; - * or the user has reached their quota for the file system. - * - * The RLIMIT_CORE or RLIMIT_FSIZE resource limits for the process - * are set to zero. - * [shouldn't it be checked by kernel? 2.6.30.9-96 doesn't, still - * calls us even if "ulimit -c 0"] - * - * The binary being executed by the process does not have - * read permission enabled. [how we can check it here?] - * - * The process is executing a set-user-ID (set-group-ID) program - * that is owned by a user (group) other than the real - * user (group) ID of the process. [TODO?] - * (However, see the description of the prctl(2) PR_SET_DUMPABLE operation, - * and the description of the /proc/sys/fs/suid_dumpable file in proc(5).) - */ - - /* Do not O_TRUNC: if later checks fail, we do not want to have file already modified here */ - errno = 0; - int usercore_fd = open(core_basename, O_WRONLY | O_CREAT | O_NOFOLLOW, 0600); /* kernel makes 0600 too */ - if (usercore_fd < 0 - || fstat(usercore_fd, &sb) != 0 - || !S_ISREG(sb.st_mode) - || sb.st_nlink != 1 - /* kernel internal dumper checks this too: if (inode->i_uid != current->fsuid) , need to mimic? */ - ) { - perror_msg_and_die("%s/%s is not a regular file with link count 1", user_pwd, core_basename); - } - - /* Note: we do not copy more than ulimit_c */ - off_t size; - if (ftruncate(usercore_fd, 0) != 0 - || (size = copyfd_size(core_fd, usercore_fd, ulimit_c)) < 0 - || close(usercore_fd) != 0 - ) { - /* perror first, otherwise unlink may trash errno */ - perror_msg("write error writing %s/%s", user_pwd, core_basename); - unlink(core_basename); - return 1; - } - if (size == ulimit_c && size != core_size) - { - /* We copied exactly ulimit_c bytes (and it doesn't accidentally match - * core_size (imagine exactly 1MB coredump with "ulimit -c 1M" - that'd be ok)), - * it means that core is larger than ulimit_c. Abort and delete the dump. - */ - unlink(core_basename); - return 1; - } - log("saved core dump of pid %lu to %s/%s (%llu bytes)", (long)pid, user_pwd, core_basename, (long long)size); - - return 0; -} diff --git a/src/Hooks/Makefile.am b/src/Hooks/Makefile.am index ebabd87..d9c0fba 100644 --- a/src/Hooks/Makefile.am +++ b/src/Hooks/Makefile.am @@ -3,7 +3,7 @@ bin_PROGRAMS = dumpoops # abrt-hook-ccpp abrt_hook_ccpp_SOURCES = \ - CCpp.cpp \ + abrt_hook_ccpp.cpp \ hooklib.h hooklib.cpp abrt_hook_ccpp_CPPFLAGS = \ -I$(srcdir)/../../inc \ diff --git a/src/Hooks/abrt_hook_ccpp.cpp b/src/Hooks/abrt_hook_ccpp.cpp new file mode 100644 index 0000000..e417743 --- /dev/null +++ b/src/Hooks/abrt_hook_ccpp.cpp @@ -0,0 +1,368 @@ +/* + abrt_hook_ccpp.cpp - the hook for C/C++ crashing program + + 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 "abrtlib.h" +#include "hooklib.h" +#include "DebugDump.h" +#include "ABRTException.h" +#include +#include + +#define FILENAME_EXECUTABLE "executable" +#define FILENAME_COREDUMP "coredump" + +using namespace std; + +static char* malloc_readlink(const char *linkname) +{ + char buf[PATH_MAX + 1]; + int len; + + len = readlink(linkname, buf, sizeof(buf)-1); + if (len >= 0) + { + buf[len] = '\0'; + return xstrdup(buf); + } + return NULL; +} + +static char* get_executable(pid_t pid) +{ + char buf[sizeof("/proc/%lu/exe") + sizeof(long)*3]; + + sprintf(buf, "/proc/%lu/exe", (long)pid); + return malloc_readlink(buf); +} + +static char* get_cwd(pid_t pid) +{ + char buf[sizeof("/proc/%lu/cwd") + sizeof(long)*3]; + + sprintf(buf, "/proc/%lu/cwd", (long)pid); + return malloc_readlink(buf); +} + +int main(int argc, char** argv) +{ + int fd; + struct stat sb; + + if (argc < 5) + { + const char* program_name = argv[0]; + error_msg_and_die("Usage: %s: DUMPDIR PID SIGNO UID CORE_SIZE_LIMIT", program_name); + } + openlog("abrt", 0, LOG_PID | LOG_DAEMON); + logmode = LOGMODE_SYSLOG; + + errno = 0; + const char* dddir = argv[1]; + pid_t pid = xatoi_u(argv[2]); + const char* signal_str = argv[3]; + int signal_no = xatoi_u(argv[3]); + uid_t uid = xatoi_u(argv[4]); + off_t ulimit_c = strtoull(argv[5], NULL, 10); + off_t core_size = 0; + + if (errno || pid <= 0 || ulimit_c < 0) + { + error_msg_and_die("pid '%s' or limit '%s' is bogus", argv[2], argv[5]); + } + if (signal_no != SIGQUIT + && signal_no != SIGILL + && signal_no != SIGABRT + && signal_no != SIGFPE + && signal_no != SIGSEGV + ) { + /* not an error, exit silently */ + return 0; + } + + + char *user_pwd = get_cwd(pid); /* may be NULL on error */ + int core_fd = STDIN_FILENO; + + if (!daemon_is_ok()) + { + /* not an error, exit with exitcode 0 */ + log("abrt daemon is not running. If it crashed, " + "/proc/sys/kernel/core_pattern contains a stale value, " + "consider resetting it to 'core'" + ); + goto create_user_core; + } + + try + { + char* executable = get_executable(pid); + if (executable == NULL) + { + error_msg_and_die("can't read /proc/%lu/exe link", (long)pid); + } + if (strstr(executable, "/abrt-hook-ccpp")) + { + error_msg_and_die("pid %lu is '%s', not dumping it to avoid recursion", + (long)pid, executable); + } + + /* Parse abrt.conf and plugins/CCpp.conf */ + unsigned setting_MaxCrashReportsSize = 0; + bool setting_MakeCompatCore = false; + parse_conf(CONF_DIR"/plugins/CCpp.conf", &setting_MaxCrashReportsSize, &setting_MakeCompatCore); + + if (setting_MaxCrashReportsSize > 0) + { + check_free_space(setting_MaxCrashReportsSize); + } + + char path[PATH_MAX]; + + /* Check /var/cache/abrt/last-ccpp marker, do not dump repeated crashes + * if they happen too often. Else, write new marker value. + */ + snprintf(path, sizeof(path), "%s/last-ccpp", dddir); + fd = open(path, O_RDWR | O_CREAT, 0600); + if (fd >= 0) + { + int sz; + fstat(fd, &sb); /* !paranoia. this can't fail. */ + + if (sb.st_size != 0 /* if it wasn't created by us just now... */ + && (unsigned)(time(NULL) - sb.st_mtime) < 20 /* and is relatively new [is 20 sec ok?] */ + ) { + sz = read(fd, path, sizeof(path)-1); /* (ab)using path as scratch buf */ + if (sz > 0) + { + path[sz] = '\0'; + if (strcmp(executable, path) == 0) + { + error_msg("not dumping repeating crash in '%s'", executable); + if (setting_MakeCompatCore) + goto create_user_core; + return 1; + } + } + lseek(fd, 0, SEEK_SET); + } + sz = write(fd, executable, strlen(executable)); + if (sz >= 0) + ftruncate(fd, sz); + close(fd); + } + + if (strstr(executable, "/abrtd")) + { + /* If abrtd crashes, we don't want to create a _directory_, + * since that can make new copy of abrtd to process it, + * and maybe crash again... + * Unlike dirs, mere files are ignored by abrtd. + */ + snprintf(path, sizeof(path), "%s/abrtd-coredump", dddir); + core_fd = xopen3(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + core_size = copyfd_eof(STDIN_FILENO, core_fd); + if (core_size < 0 || close(core_fd) != 0) + { + unlink(path); + /* copyfd_eof logs the error including errno string, + * but it does not log file name */ + error_msg_and_die("error saving coredump to %s", path); + } + log("saved core dump of pid %lu (%s) to %s (%llu bytes)", (long)pid, executable, path, (long long)core_size); + return 0; + } + + char* cmdline = get_cmdline(pid); /* never NULL */ + const char *signame = strsignal(signal_no); + char *reason = xasprintf("Process was terminated by signal %s (%s)", signal_str, signame ? signame : signal_str); + + snprintf(path, sizeof(path), "%s/ccpp-%ld-%lu", dddir, (long)time(NULL), (long)pid); + CDebugDump dd; + dd.Create(path, uid); + dd.SaveText(FILENAME_ANALYZER, "CCpp"); + dd.SaveText(FILENAME_EXECUTABLE, executable); + dd.SaveText(FILENAME_CMDLINE, cmdline); + dd.SaveText(FILENAME_REASON, reason); + + int len = strlen(path); + snprintf(path + len, sizeof(path) - len, "/"FILENAME_COREDUMP); + + /* We need coredumps to be readable by all, because + * when abrt daemon processes coredump, + * process producing backtrace is run under the same UID + * as the crashed process. + * Thus 644, not 600 */ + core_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644); + if (core_fd < 0) + { + dd.Delete(); + dd.Close(); + perror_msg_and_die("can't open '%s'", path); + } +//TODO: chown to uid:abrt? +//Currently it is owned by 0:0 but is readable by anyone, so the owner +//of the crashed binary still can access it, as he has +//r-x access to the dump dir. + core_size = copyfd_eof(STDIN_FILENO, core_fd); + if (core_size < 0 || fsync(core_fd) != 0) + { + unlink(path); + dd.Delete(); + dd.Close(); + /* copyfd_eof logs the error including errno string, + * but it does not log file name */ + error_msg_and_die("error saving coredump to %s", path); + } + lseek(core_fd, 0, SEEK_SET); + /* note: core_fd is still open, we may use it later to copy core to user's dir */ + log("saved core dump of pid %lu (%s) to %s (%llu bytes)", (long)pid, executable, path, (long long)core_size); + free(executable); + free(cmdline); + path[len] = '\0'; /* path now contains directory name */ + + /* We close dumpdir before we start catering for crash storm case. + * Otherwise, delete_debug_dump_dir's from other concurrent + * CCpp's won't be able to delete our dump (their delete_debug_dump_dir + * will wait for us), and we won't be able to delete their dumps. + * Classic deadlock. + */ + dd.Close(); + + /* rhbz#539551: "abrt going crazy when crashing process is respawned" */ + if (setting_MaxCrashReportsSize > 0) + { + trim_debug_dumps(setting_MaxCrashReportsSize, path); + } + + if (!setting_MakeCompatCore) + return 0; + /* fall through to creating user core */ + } + catch (CABRTException& e) + { + error_msg_and_die("%s", e.what()); + } + catch (std::exception& e) + { + error_msg_and_die("%s", e.what()); + } + + + create_user_core: + /* note: core_size may be == 0 ("unknown") */ + if (core_size > ulimit_c || ulimit_c == 0) + return 0; + + /* Write a core file for user */ + + struct passwd* pw = getpwuid(uid); + gid_t gid = pw ? pw->pw_gid : uid; + setgroups(1, &gid); + xsetregid(gid, gid); + xsetreuid(uid, uid); + + errno = 0; + if (user_pwd == NULL + || chdir(user_pwd) != 0 + ) { + perror_msg_and_die("can't cd to %s", user_pwd); + } + + /* Mimic "core.PID" if requested */ + char core_basename[sizeof("core.%lu") + sizeof(long)*3] = "core"; + char buf[] = "0\n"; + fd = open("/proc/sys/kernel/core_uses_pid", O_RDONLY); + if (fd >= 0) + { + read(fd, buf, sizeof(buf)); + close(fd); + } + if (strcmp(buf, "1\n") == 0) + { + sprintf(core_basename, "core.%lu", (long)pid); + } + + /* man core: + * There are various circumstances in which a core dump file + * is not produced: + * + * [skipped obvious ones] + * The process does not have permission to write the core file. + * ...if a file with the same name exists and is not writable + * or is not a regular file (e.g., it is a directory or a symbolic link). + * + * A file with the same name already exists, but there is more + * than one hard link to that file. + * + * The file system where the core dump file would be created is full; + * or has run out of inodes; or is mounted read-only; + * or the user has reached their quota for the file system. + * + * The RLIMIT_CORE or RLIMIT_FSIZE resource limits for the process + * are set to zero. + * [shouldn't it be checked by kernel? 2.6.30.9-96 doesn't, still + * calls us even if "ulimit -c 0"] + * + * The binary being executed by the process does not have + * read permission enabled. [how we can check it here?] + * + * The process is executing a set-user-ID (set-group-ID) program + * that is owned by a user (group) other than the real + * user (group) ID of the process. [TODO?] + * (However, see the description of the prctl(2) PR_SET_DUMPABLE operation, + * and the description of the /proc/sys/fs/suid_dumpable file in proc(5).) + */ + + /* Do not O_TRUNC: if later checks fail, we do not want to have file already modified here */ + errno = 0; + int usercore_fd = open(core_basename, O_WRONLY | O_CREAT | O_NOFOLLOW, 0600); /* kernel makes 0600 too */ + if (usercore_fd < 0 + || fstat(usercore_fd, &sb) != 0 + || !S_ISREG(sb.st_mode) + || sb.st_nlink != 1 + /* kernel internal dumper checks this too: if (inode->i_uid != current->fsuid) , need to mimic? */ + ) { + perror_msg_and_die("%s/%s is not a regular file with link count 1", user_pwd, core_basename); + } + + /* Note: we do not copy more than ulimit_c */ + off_t size; + if (ftruncate(usercore_fd, 0) != 0 + || (size = copyfd_size(core_fd, usercore_fd, ulimit_c)) < 0 + || close(usercore_fd) != 0 + ) { + /* perror first, otherwise unlink may trash errno */ + perror_msg("write error writing %s/%s", user_pwd, core_basename); + unlink(core_basename); + return 1; + } + if (size == ulimit_c && size != core_size) + { + /* We copied exactly ulimit_c bytes (and it doesn't accidentally match + * core_size (imagine exactly 1MB coredump with "ulimit -c 1M" - that'd be ok)), + * it means that core is larger than ulimit_c. Abort and delete the dump. + */ + unlink(core_basename); + return 1; + } + log("saved core dump of pid %lu to %s/%s (%llu bytes)", (long)pid, user_pwd, core_basename, (long long)size); + + return 0; +} -- cgit From bb4ce908e5dcec73b4a0f1bce0d2e6d499228c3c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 12 Jan 2010 16:34:48 +0100 Subject: grr... src/Hooks/abrt_hook_ccpp.cpp -> abrt-hook-ccpp.cpp Signed-off-by: Denys Vlasenko --- src/Hooks/Makefile.am | 2 +- src/Hooks/abrt-hook-ccpp.cpp | 368 +++++++++++++++++++++++++++++++++++++++++++ src/Hooks/abrt_hook_ccpp.cpp | 368 ------------------------------------------- 3 files changed, 369 insertions(+), 369 deletions(-) create mode 100644 src/Hooks/abrt-hook-ccpp.cpp delete mode 100644 src/Hooks/abrt_hook_ccpp.cpp (limited to 'src') diff --git a/src/Hooks/Makefile.am b/src/Hooks/Makefile.am index d9c0fba..2b04990 100644 --- a/src/Hooks/Makefile.am +++ b/src/Hooks/Makefile.am @@ -3,7 +3,7 @@ bin_PROGRAMS = dumpoops # abrt-hook-ccpp abrt_hook_ccpp_SOURCES = \ - abrt_hook_ccpp.cpp \ + abrt-hook-ccpp.cpp \ hooklib.h hooklib.cpp abrt_hook_ccpp_CPPFLAGS = \ -I$(srcdir)/../../inc \ diff --git a/src/Hooks/abrt-hook-ccpp.cpp b/src/Hooks/abrt-hook-ccpp.cpp new file mode 100644 index 0000000..237ea6f --- /dev/null +++ b/src/Hooks/abrt-hook-ccpp.cpp @@ -0,0 +1,368 @@ +/* + abrt-hook-ccpp.cpp - the hook for C/C++ crashing program + + 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 "abrtlib.h" +#include "hooklib.h" +#include "DebugDump.h" +#include "ABRTException.h" +#include +#include + +#define FILENAME_EXECUTABLE "executable" +#define FILENAME_COREDUMP "coredump" + +using namespace std; + +static char* malloc_readlink(const char *linkname) +{ + char buf[PATH_MAX + 1]; + int len; + + len = readlink(linkname, buf, sizeof(buf)-1); + if (len >= 0) + { + buf[len] = '\0'; + return xstrdup(buf); + } + return NULL; +} + +static char* get_executable(pid_t pid) +{ + char buf[sizeof("/proc/%lu/exe") + sizeof(long)*3]; + + sprintf(buf, "/proc/%lu/exe", (long)pid); + return malloc_readlink(buf); +} + +static char* get_cwd(pid_t pid) +{ + char buf[sizeof("/proc/%lu/cwd") + sizeof(long)*3]; + + sprintf(buf, "/proc/%lu/cwd", (long)pid); + return malloc_readlink(buf); +} + +int main(int argc, char** argv) +{ + int fd; + struct stat sb; + + if (argc < 5) + { + const char* program_name = argv[0]; + error_msg_and_die("Usage: %s: DUMPDIR PID SIGNO UID CORE_SIZE_LIMIT", program_name); + } + openlog("abrt", 0, LOG_PID | LOG_DAEMON); + logmode = LOGMODE_SYSLOG; + + errno = 0; + const char* dddir = argv[1]; + pid_t pid = xatoi_u(argv[2]); + const char* signal_str = argv[3]; + int signal_no = xatoi_u(argv[3]); + uid_t uid = xatoi_u(argv[4]); + off_t ulimit_c = strtoull(argv[5], NULL, 10); + off_t core_size = 0; + + if (errno || pid <= 0 || ulimit_c < 0) + { + error_msg_and_die("pid '%s' or limit '%s' is bogus", argv[2], argv[5]); + } + if (signal_no != SIGQUIT + && signal_no != SIGILL + && signal_no != SIGABRT + && signal_no != SIGFPE + && signal_no != SIGSEGV + ) { + /* not an error, exit silently */ + return 0; + } + + + char *user_pwd = get_cwd(pid); /* may be NULL on error */ + int core_fd = STDIN_FILENO; + + if (!daemon_is_ok()) + { + /* not an error, exit with exitcode 0 */ + log("abrt daemon is not running. If it crashed, " + "/proc/sys/kernel/core_pattern contains a stale value, " + "consider resetting it to 'core'" + ); + goto create_user_core; + } + + try + { + char* executable = get_executable(pid); + if (executable == NULL) + { + error_msg_and_die("can't read /proc/%lu/exe link", (long)pid); + } + if (strstr(executable, "/abrt-hook-ccpp")) + { + error_msg_and_die("pid %lu is '%s', not dumping it to avoid recursion", + (long)pid, executable); + } + + /* Parse abrt.conf and plugins/CCpp.conf */ + unsigned setting_MaxCrashReportsSize = 0; + bool setting_MakeCompatCore = false; + parse_conf(CONF_DIR"/plugins/CCpp.conf", &setting_MaxCrashReportsSize, &setting_MakeCompatCore); + + if (setting_MaxCrashReportsSize > 0) + { + check_free_space(setting_MaxCrashReportsSize); + } + + char path[PATH_MAX]; + + /* Check /var/cache/abrt/last-ccpp marker, do not dump repeated crashes + * if they happen too often. Else, write new marker value. + */ + snprintf(path, sizeof(path), "%s/last-ccpp", dddir); + fd = open(path, O_RDWR | O_CREAT, 0600); + if (fd >= 0) + { + int sz; + fstat(fd, &sb); /* !paranoia. this can't fail. */ + + if (sb.st_size != 0 /* if it wasn't created by us just now... */ + && (unsigned)(time(NULL) - sb.st_mtime) < 20 /* and is relatively new [is 20 sec ok?] */ + ) { + sz = read(fd, path, sizeof(path)-1); /* (ab)using path as scratch buf */ + if (sz > 0) + { + path[sz] = '\0'; + if (strcmp(executable, path) == 0) + { + error_msg("not dumping repeating crash in '%s'", executable); + if (setting_MakeCompatCore) + goto create_user_core; + return 1; + } + } + lseek(fd, 0, SEEK_SET); + } + sz = write(fd, executable, strlen(executable)); + if (sz >= 0) + ftruncate(fd, sz); + close(fd); + } + + if (strstr(executable, "/abrtd")) + { + /* If abrtd crashes, we don't want to create a _directory_, + * since that can make new copy of abrtd to process it, + * and maybe crash again... + * Unlike dirs, mere files are ignored by abrtd. + */ + snprintf(path, sizeof(path), "%s/abrtd-coredump", dddir); + core_fd = xopen3(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + core_size = copyfd_eof(STDIN_FILENO, core_fd); + if (core_size < 0 || close(core_fd) != 0) + { + unlink(path); + /* copyfd_eof logs the error including errno string, + * but it does not log file name */ + error_msg_and_die("error saving coredump to %s", path); + } + log("saved core dump of pid %lu (%s) to %s (%llu bytes)", (long)pid, executable, path, (long long)core_size); + return 0; + } + + char* cmdline = get_cmdline(pid); /* never NULL */ + const char *signame = strsignal(signal_no); + char *reason = xasprintf("Process was terminated by signal %s (%s)", signal_str, signame ? signame : signal_str); + + snprintf(path, sizeof(path), "%s/ccpp-%ld-%lu", dddir, (long)time(NULL), (long)pid); + CDebugDump dd; + dd.Create(path, uid); + dd.SaveText(FILENAME_ANALYZER, "CCpp"); + dd.SaveText(FILENAME_EXECUTABLE, executable); + dd.SaveText(FILENAME_CMDLINE, cmdline); + dd.SaveText(FILENAME_REASON, reason); + + int len = strlen(path); + snprintf(path + len, sizeof(path) - len, "/"FILENAME_COREDUMP); + + /* We need coredumps to be readable by all, because + * when abrt daemon processes coredump, + * process producing backtrace is run under the same UID + * as the crashed process. + * Thus 644, not 600 */ + core_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644); + if (core_fd < 0) + { + dd.Delete(); + dd.Close(); + perror_msg_and_die("can't open '%s'", path); + } +//TODO: chown to uid:abrt? +//Currently it is owned by 0:0 but is readable by anyone, so the owner +//of the crashed binary still can access it, as he has +//r-x access to the dump dir. + core_size = copyfd_eof(STDIN_FILENO, core_fd); + if (core_size < 0 || fsync(core_fd) != 0) + { + unlink(path); + dd.Delete(); + dd.Close(); + /* copyfd_eof logs the error including errno string, + * but it does not log file name */ + error_msg_and_die("error saving coredump to %s", path); + } + lseek(core_fd, 0, SEEK_SET); + /* note: core_fd is still open, we may use it later to copy core to user's dir */ + log("saved core dump of pid %lu (%s) to %s (%llu bytes)", (long)pid, executable, path, (long long)core_size); + free(executable); + free(cmdline); + path[len] = '\0'; /* path now contains directory name */ + + /* We close dumpdir before we start catering for crash storm case. + * Otherwise, delete_debug_dump_dir's from other concurrent + * CCpp's won't be able to delete our dump (their delete_debug_dump_dir + * will wait for us), and we won't be able to delete their dumps. + * Classic deadlock. + */ + dd.Close(); + + /* rhbz#539551: "abrt going crazy when crashing process is respawned" */ + if (setting_MaxCrashReportsSize > 0) + { + trim_debug_dumps(setting_MaxCrashReportsSize, path); + } + + if (!setting_MakeCompatCore) + return 0; + /* fall through to creating user core */ + } + catch (CABRTException& e) + { + error_msg_and_die("%s", e.what()); + } + catch (std::exception& e) + { + error_msg_and_die("%s", e.what()); + } + + + create_user_core: + /* note: core_size may be == 0 ("unknown") */ + if (core_size > ulimit_c || ulimit_c == 0) + return 0; + + /* Write a core file for user */ + + struct passwd* pw = getpwuid(uid); + gid_t gid = pw ? pw->pw_gid : uid; + setgroups(1, &gid); + xsetregid(gid, gid); + xsetreuid(uid, uid); + + errno = 0; + if (user_pwd == NULL + || chdir(user_pwd) != 0 + ) { + perror_msg_and_die("can't cd to %s", user_pwd); + } + + /* Mimic "core.PID" if requested */ + char core_basename[sizeof("core.%lu") + sizeof(long)*3] = "core"; + char buf[] = "0\n"; + fd = open("/proc/sys/kernel/core_uses_pid", O_RDONLY); + if (fd >= 0) + { + read(fd, buf, sizeof(buf)); + close(fd); + } + if (strcmp(buf, "1\n") == 0) + { + sprintf(core_basename, "core.%lu", (long)pid); + } + + /* man core: + * There are various circumstances in which a core dump file + * is not produced: + * + * [skipped obvious ones] + * The process does not have permission to write the core file. + * ...if a file with the same name exists and is not writable + * or is not a regular file (e.g., it is a directory or a symbolic link). + * + * A file with the same name already exists, but there is more + * than one hard link to that file. + * + * The file system where the core dump file would be created is full; + * or has run out of inodes; or is mounted read-only; + * or the user has reached their quota for the file system. + * + * The RLIMIT_CORE or RLIMIT_FSIZE resource limits for the process + * are set to zero. + * [shouldn't it be checked by kernel? 2.6.30.9-96 doesn't, still + * calls us even if "ulimit -c 0"] + * + * The binary being executed by the process does not have + * read permission enabled. [how we can check it here?] + * + * The process is executing a set-user-ID (set-group-ID) program + * that is owned by a user (group) other than the real + * user (group) ID of the process. [TODO?] + * (However, see the description of the prctl(2) PR_SET_DUMPABLE operation, + * and the description of the /proc/sys/fs/suid_dumpable file in proc(5).) + */ + + /* Do not O_TRUNC: if later checks fail, we do not want to have file already modified here */ + errno = 0; + int usercore_fd = open(core_basename, O_WRONLY | O_CREAT | O_NOFOLLOW, 0600); /* kernel makes 0600 too */ + if (usercore_fd < 0 + || fstat(usercore_fd, &sb) != 0 + || !S_ISREG(sb.st_mode) + || sb.st_nlink != 1 + /* kernel internal dumper checks this too: if (inode->i_uid != current->fsuid) , need to mimic? */ + ) { + perror_msg_and_die("%s/%s is not a regular file with link count 1", user_pwd, core_basename); + } + + /* Note: we do not copy more than ulimit_c */ + off_t size; + if (ftruncate(usercore_fd, 0) != 0 + || (size = copyfd_size(core_fd, usercore_fd, ulimit_c)) < 0 + || close(usercore_fd) != 0 + ) { + /* perror first, otherwise unlink may trash errno */ + perror_msg("write error writing %s/%s", user_pwd, core_basename); + unlink(core_basename); + return 1; + } + if (size == ulimit_c && size != core_size) + { + /* We copied exactly ulimit_c bytes (and it doesn't accidentally match + * core_size (imagine exactly 1MB coredump with "ulimit -c 1M" - that'd be ok)), + * it means that core is larger than ulimit_c. Abort and delete the dump. + */ + unlink(core_basename); + return 1; + } + log("saved core dump of pid %lu to %s/%s (%llu bytes)", (long)pid, user_pwd, core_basename, (long long)size); + + return 0; +} diff --git a/src/Hooks/abrt_hook_ccpp.cpp b/src/Hooks/abrt_hook_ccpp.cpp deleted file mode 100644 index e417743..0000000 --- a/src/Hooks/abrt_hook_ccpp.cpp +++ /dev/null @@ -1,368 +0,0 @@ -/* - abrt_hook_ccpp.cpp - the hook for C/C++ crashing program - - 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 "abrtlib.h" -#include "hooklib.h" -#include "DebugDump.h" -#include "ABRTException.h" -#include -#include - -#define FILENAME_EXECUTABLE "executable" -#define FILENAME_COREDUMP "coredump" - -using namespace std; - -static char* malloc_readlink(const char *linkname) -{ - char buf[PATH_MAX + 1]; - int len; - - len = readlink(linkname, buf, sizeof(buf)-1); - if (len >= 0) - { - buf[len] = '\0'; - return xstrdup(buf); - } - return NULL; -} - -static char* get_executable(pid_t pid) -{ - char buf[sizeof("/proc/%lu/exe") + sizeof(long)*3]; - - sprintf(buf, "/proc/%lu/exe", (long)pid); - return malloc_readlink(buf); -} - -static char* get_cwd(pid_t pid) -{ - char buf[sizeof("/proc/%lu/cwd") + sizeof(long)*3]; - - sprintf(buf, "/proc/%lu/cwd", (long)pid); - return malloc_readlink(buf); -} - -int main(int argc, char** argv) -{ - int fd; - struct stat sb; - - if (argc < 5) - { - const char* program_name = argv[0]; - error_msg_and_die("Usage: %s: DUMPDIR PID SIGNO UID CORE_SIZE_LIMIT", program_name); - } - openlog("abrt", 0, LOG_PID | LOG_DAEMON); - logmode = LOGMODE_SYSLOG; - - errno = 0; - const char* dddir = argv[1]; - pid_t pid = xatoi_u(argv[2]); - const char* signal_str = argv[3]; - int signal_no = xatoi_u(argv[3]); - uid_t uid = xatoi_u(argv[4]); - off_t ulimit_c = strtoull(argv[5], NULL, 10); - off_t core_size = 0; - - if (errno || pid <= 0 || ulimit_c < 0) - { - error_msg_and_die("pid '%s' or limit '%s' is bogus", argv[2], argv[5]); - } - if (signal_no != SIGQUIT - && signal_no != SIGILL - && signal_no != SIGABRT - && signal_no != SIGFPE - && signal_no != SIGSEGV - ) { - /* not an error, exit silently */ - return 0; - } - - - char *user_pwd = get_cwd(pid); /* may be NULL on error */ - int core_fd = STDIN_FILENO; - - if (!daemon_is_ok()) - { - /* not an error, exit with exitcode 0 */ - log("abrt daemon is not running. If it crashed, " - "/proc/sys/kernel/core_pattern contains a stale value, " - "consider resetting it to 'core'" - ); - goto create_user_core; - } - - try - { - char* executable = get_executable(pid); - if (executable == NULL) - { - error_msg_and_die("can't read /proc/%lu/exe link", (long)pid); - } - if (strstr(executable, "/abrt-hook-ccpp")) - { - error_msg_and_die("pid %lu is '%s', not dumping it to avoid recursion", - (long)pid, executable); - } - - /* Parse abrt.conf and plugins/CCpp.conf */ - unsigned setting_MaxCrashReportsSize = 0; - bool setting_MakeCompatCore = false; - parse_conf(CONF_DIR"/plugins/CCpp.conf", &setting_MaxCrashReportsSize, &setting_MakeCompatCore); - - if (setting_MaxCrashReportsSize > 0) - { - check_free_space(setting_MaxCrashReportsSize); - } - - char path[PATH_MAX]; - - /* Check /var/cache/abrt/last-ccpp marker, do not dump repeated crashes - * if they happen too often. Else, write new marker value. - */ - snprintf(path, sizeof(path), "%s/last-ccpp", dddir); - fd = open(path, O_RDWR | O_CREAT, 0600); - if (fd >= 0) - { - int sz; - fstat(fd, &sb); /* !paranoia. this can't fail. */ - - if (sb.st_size != 0 /* if it wasn't created by us just now... */ - && (unsigned)(time(NULL) - sb.st_mtime) < 20 /* and is relatively new [is 20 sec ok?] */ - ) { - sz = read(fd, path, sizeof(path)-1); /* (ab)using path as scratch buf */ - if (sz > 0) - { - path[sz] = '\0'; - if (strcmp(executable, path) == 0) - { - error_msg("not dumping repeating crash in '%s'", executable); - if (setting_MakeCompatCore) - goto create_user_core; - return 1; - } - } - lseek(fd, 0, SEEK_SET); - } - sz = write(fd, executable, strlen(executable)); - if (sz >= 0) - ftruncate(fd, sz); - close(fd); - } - - if (strstr(executable, "/abrtd")) - { - /* If abrtd crashes, we don't want to create a _directory_, - * since that can make new copy of abrtd to process it, - * and maybe crash again... - * Unlike dirs, mere files are ignored by abrtd. - */ - snprintf(path, sizeof(path), "%s/abrtd-coredump", dddir); - core_fd = xopen3(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - core_size = copyfd_eof(STDIN_FILENO, core_fd); - if (core_size < 0 || close(core_fd) != 0) - { - unlink(path); - /* copyfd_eof logs the error including errno string, - * but it does not log file name */ - error_msg_and_die("error saving coredump to %s", path); - } - log("saved core dump of pid %lu (%s) to %s (%llu bytes)", (long)pid, executable, path, (long long)core_size); - return 0; - } - - char* cmdline = get_cmdline(pid); /* never NULL */ - const char *signame = strsignal(signal_no); - char *reason = xasprintf("Process was terminated by signal %s (%s)", signal_str, signame ? signame : signal_str); - - snprintf(path, sizeof(path), "%s/ccpp-%ld-%lu", dddir, (long)time(NULL), (long)pid); - CDebugDump dd; - dd.Create(path, uid); - dd.SaveText(FILENAME_ANALYZER, "CCpp"); - dd.SaveText(FILENAME_EXECUTABLE, executable); - dd.SaveText(FILENAME_CMDLINE, cmdline); - dd.SaveText(FILENAME_REASON, reason); - - int len = strlen(path); - snprintf(path + len, sizeof(path) - len, "/"FILENAME_COREDUMP); - - /* We need coredumps to be readable by all, because - * when abrt daemon processes coredump, - * process producing backtrace is run under the same UID - * as the crashed process. - * Thus 644, not 600 */ - core_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644); - if (core_fd < 0) - { - dd.Delete(); - dd.Close(); - perror_msg_and_die("can't open '%s'", path); - } -//TODO: chown to uid:abrt? -//Currently it is owned by 0:0 but is readable by anyone, so the owner -//of the crashed binary still can access it, as he has -//r-x access to the dump dir. - core_size = copyfd_eof(STDIN_FILENO, core_fd); - if (core_size < 0 || fsync(core_fd) != 0) - { - unlink(path); - dd.Delete(); - dd.Close(); - /* copyfd_eof logs the error including errno string, - * but it does not log file name */ - error_msg_and_die("error saving coredump to %s", path); - } - lseek(core_fd, 0, SEEK_SET); - /* note: core_fd is still open, we may use it later to copy core to user's dir */ - log("saved core dump of pid %lu (%s) to %s (%llu bytes)", (long)pid, executable, path, (long long)core_size); - free(executable); - free(cmdline); - path[len] = '\0'; /* path now contains directory name */ - - /* We close dumpdir before we start catering for crash storm case. - * Otherwise, delete_debug_dump_dir's from other concurrent - * CCpp's won't be able to delete our dump (their delete_debug_dump_dir - * will wait for us), and we won't be able to delete their dumps. - * Classic deadlock. - */ - dd.Close(); - - /* rhbz#539551: "abrt going crazy when crashing process is respawned" */ - if (setting_MaxCrashReportsSize > 0) - { - trim_debug_dumps(setting_MaxCrashReportsSize, path); - } - - if (!setting_MakeCompatCore) - return 0; - /* fall through to creating user core */ - } - catch (CABRTException& e) - { - error_msg_and_die("%s", e.what()); - } - catch (std::exception& e) - { - error_msg_and_die("%s", e.what()); - } - - - create_user_core: - /* note: core_size may be == 0 ("unknown") */ - if (core_size > ulimit_c || ulimit_c == 0) - return 0; - - /* Write a core file for user */ - - struct passwd* pw = getpwuid(uid); - gid_t gid = pw ? pw->pw_gid : uid; - setgroups(1, &gid); - xsetregid(gid, gid); - xsetreuid(uid, uid); - - errno = 0; - if (user_pwd == NULL - || chdir(user_pwd) != 0 - ) { - perror_msg_and_die("can't cd to %s", user_pwd); - } - - /* Mimic "core.PID" if requested */ - char core_basename[sizeof("core.%lu") + sizeof(long)*3] = "core"; - char buf[] = "0\n"; - fd = open("/proc/sys/kernel/core_uses_pid", O_RDONLY); - if (fd >= 0) - { - read(fd, buf, sizeof(buf)); - close(fd); - } - if (strcmp(buf, "1\n") == 0) - { - sprintf(core_basename, "core.%lu", (long)pid); - } - - /* man core: - * There are various circumstances in which a core dump file - * is not produced: - * - * [skipped obvious ones] - * The process does not have permission to write the core file. - * ...if a file with the same name exists and is not writable - * or is not a regular file (e.g., it is a directory or a symbolic link). - * - * A file with the same name already exists, but there is more - * than one hard link to that file. - * - * The file system where the core dump file would be created is full; - * or has run out of inodes; or is mounted read-only; - * or the user has reached their quota for the file system. - * - * The RLIMIT_CORE or RLIMIT_FSIZE resource limits for the process - * are set to zero. - * [shouldn't it be checked by kernel? 2.6.30.9-96 doesn't, still - * calls us even if "ulimit -c 0"] - * - * The binary being executed by the process does not have - * read permission enabled. [how we can check it here?] - * - * The process is executing a set-user-ID (set-group-ID) program - * that is owned by a user (group) other than the real - * user (group) ID of the process. [TODO?] - * (However, see the description of the prctl(2) PR_SET_DUMPABLE operation, - * and the description of the /proc/sys/fs/suid_dumpable file in proc(5).) - */ - - /* Do not O_TRUNC: if later checks fail, we do not want to have file already modified here */ - errno = 0; - int usercore_fd = open(core_basename, O_WRONLY | O_CREAT | O_NOFOLLOW, 0600); /* kernel makes 0600 too */ - if (usercore_fd < 0 - || fstat(usercore_fd, &sb) != 0 - || !S_ISREG(sb.st_mode) - || sb.st_nlink != 1 - /* kernel internal dumper checks this too: if (inode->i_uid != current->fsuid) , need to mimic? */ - ) { - perror_msg_and_die("%s/%s is not a regular file with link count 1", user_pwd, core_basename); - } - - /* Note: we do not copy more than ulimit_c */ - off_t size; - if (ftruncate(usercore_fd, 0) != 0 - || (size = copyfd_size(core_fd, usercore_fd, ulimit_c)) < 0 - || close(usercore_fd) != 0 - ) { - /* perror first, otherwise unlink may trash errno */ - perror_msg("write error writing %s/%s", user_pwd, core_basename); - unlink(core_basename); - return 1; - } - if (size == ulimit_c && size != core_size) - { - /* We copied exactly ulimit_c bytes (and it doesn't accidentally match - * core_size (imagine exactly 1MB coredump with "ulimit -c 1M" - that'd be ok)), - * it means that core is larger than ulimit_c. Abort and delete the dump. - */ - unlink(core_basename); - return 1; - } - log("saved core dump of pid %lu to %s/%s (%llu bytes)", (long)pid, user_pwd, core_basename, (long long)size); - - return 0; -} -- cgit From b85dabbbf338c8e5f4813f3a04e298ce3a8b319f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 12 Jan 2010 17:07:01 +0100 Subject: abrt-hook-python: sanitize input more; log to syslog Signed-off-by: Denys Vlasenko --- src/Hooks/abrt-hook-ccpp.cpp | 3 +-- src/Hooks/abrt-hook-python.cpp | 53 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/Hooks/abrt-hook-ccpp.cpp b/src/Hooks/abrt-hook-ccpp.cpp index 237ea6f..1c91dc8 100644 --- a/src/Hooks/abrt-hook-ccpp.cpp +++ b/src/Hooks/abrt-hook-ccpp.cpp @@ -23,7 +23,6 @@ #include "DebugDump.h" #include "ABRTException.h" #include -#include #define FILENAME_EXECUTABLE "executable" #define FILENAME_COREDUMP "coredump" @@ -70,7 +69,7 @@ int main(int argc, char** argv) const char* program_name = argv[0]; error_msg_and_die("Usage: %s: DUMPDIR PID SIGNO UID CORE_SIZE_LIMIT", program_name); } - openlog("abrt", 0, LOG_PID | LOG_DAEMON); + openlog("abrt", LOG_PID, LOG_DAEMON); logmode = LOGMODE_SYSLOG; errno = 0; diff --git a/src/Hooks/abrt-hook-python.cpp b/src/Hooks/abrt-hook-python.cpp index b921fba..c8a25e3 100644 --- a/src/Hooks/abrt-hook-python.cpp +++ b/src/Hooks/abrt-hook-python.cpp @@ -20,7 +20,7 @@ */ #include -#include +#include /* We can easily get rid of abrtlib (libABRTUtils.so) usage in this file, * but DebugDump will pull it in anyway */ #include "abrtlib.h" @@ -38,12 +38,33 @@ static char *pid; static char *executable; static char *uuid; -int main(int argc, char** argv) +/* Note: "" will return false */ +static bool isxdigit_str(const char *str) { - // Error if daemon is not running. - if (!daemon_is_ok()) - error_msg_and_die("Daemon is not running."); + do { + if ((*str < '0' || *str > '9') /* not a digit */ + && ((*str | 0x20) < 'a' || (*str | 0x20) > 'f') /* not A-F or a-f */ + ) + { + return false; + } + str++; + } while (*str); + return true; +} + +static bool printable_str(const char *str) +{ + do { + if ((unsigned char)(*str) < ' ' || *str == 0x7f) + return false; + str++; + } while (*str); + return true; +} +int main(int argc, char** argv) +{ // Parse options static const struct option longopts[] = { // name , has_arg , flag, val @@ -79,8 +100,18 @@ int main(int argc, char** argv) } if (!pid || !executable || !uuid) goto usage; + if (strlen(uuid) > 128 || !isxdigit_str(uuid)) + goto usage; + if (strlen(executable) > PATH_MAX || !printable_str(executable)) + goto usage; + // pid string is sanitized later by xatou() -//TODO: sanitize uuid and executable (size, valid chars etc) + openlog("abrt", LOG_PID, LOG_DAEMON); + logmode = LOGMODE_SYSLOG; + + // Error if daemon is not running + if (!daemon_is_ok()) + error_msg_and_die("daemon is not running, python crash dump aborted"); unsigned setting_MaxCrashReportsSize = 0; parse_conf(NULL, &setting_MaxCrashReportsSize, NULL); @@ -94,14 +125,15 @@ int main(int argc, char** argv) ssize_t len = full_read(STDIN_FILENO, bt, MAX_BT_SIZE-1); if (len < 0) { - perror_msg_and_die("Read error"); + perror_msg_and_die("read error"); } bt[len] = '\0'; if (len == MAX_BT_SIZE-1) { - error_msg("Backtrace size limit exceeded, trimming to " MAX_BT_SIZE_STR); + error_msg("backtrace size limit exceeded, trimming to " MAX_BT_SIZE_STR); } + // This also checks that pid is a valid numeric string char *cmdline = get_cmdline(xatou(pid)); /* never NULL */ // Create directory with the debug dump @@ -109,11 +141,10 @@ int main(int argc, char** argv) snprintf(path, sizeof(path), DEBUG_DUMPS_DIR"/pyhook-%ld-%s", (long)time(NULL), pid); CDebugDump dd; - try { dd.Create(path, getuid()); } catch (CABRTException &e) { - error_msg_and_die("Error while creating debug dump: %s", e.what()); + error_msg_and_die("error while creating crash dump %s: %s", path, e.what()); } dd.SaveText(FILENAME_ANALYZER, "Python"); @@ -128,6 +159,8 @@ int main(int argc, char** argv) dd.SaveText("uid", uid); dd.Close(); + log("saved python crash dump of pid %s to %s", pid, path); + if (setting_MaxCrashReportsSize > 0) { trim_debug_dumps(setting_MaxCrashReportsSize, path); -- cgit From 82c1b530de565ec0dab054289c398fc1f5e73507 Mon Sep 17 00:00:00 2001 From: Jiri Moskovcak Date: Wed, 13 Jan 2010 12:06:32 +0100 Subject: don't use deleted variable --- src/Daemon/PluginManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Daemon/PluginManager.cpp b/src/Daemon/PluginManager.cpp index a6550e7..1c7237d 100644 --- a/src/Daemon/PluginManager.cpp +++ b/src/Daemon/PluginManager.cpp @@ -235,9 +235,9 @@ void CPluginManager::UnLoadPlugin(const char *pName) delete it_plugin->second; m_mapPlugins.erase(it_plugin); } - delete it_module->second; m_mapLoadedModules.erase(it_module); log("UnRegistered %s plugin %s", plugin_type_str[it_module->second->GetType()], pName); + delete it_module->second; } } -- cgit From f5925030be2963ddf257e6768dcd5712b0e6df08 Mon Sep 17 00:00:00 2001 From: Jiri Moskovcak Date: Wed, 13 Jan 2010 12:44:04 +0100 Subject: fixed the switched lines 2nd try --- src/Daemon/PluginManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Daemon/PluginManager.cpp b/src/Daemon/PluginManager.cpp index 1c7237d..e14f852 100644 --- a/src/Daemon/PluginManager.cpp +++ b/src/Daemon/PluginManager.cpp @@ -235,8 +235,8 @@ void CPluginManager::UnLoadPlugin(const char *pName) delete it_plugin->second; m_mapPlugins.erase(it_plugin); } - m_mapLoadedModules.erase(it_module); log("UnRegistered %s plugin %s", plugin_type_str[it_module->second->GetType()], pName); + m_mapLoadedModules.erase(it_module); delete it_module->second; } } -- cgit From df1d7cd05d8f6abba8c713e773828deee19baf22 Mon Sep 17 00:00:00 2001 From: Karel Klic Date: Wed, 13 Jan 2010 14:21:20 +0100 Subject: Better error messages for abrt-backtrace execution --- src/Backtrace/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/Backtrace/main.c b/src/Backtrace/main.c index 7dfba43..5e69338 100644 --- a/src/Backtrace/main.c +++ b/src/Backtrace/main.c @@ -28,8 +28,8 @@ /* Too large files are trimmed. */ #define FILE_SIZE_LIMIT 20000000 /* ~ 20 MB */ -#define EX_PARSINGFAILED EX__MAX + 1 -#define EX_THREADDETECTIONFAILED EX__MAX + 2 +#define EX_PARSINGFAILED EX__MAX + 1 /* = 79 */ +#define EX_THREADDETECTIONFAILED EX__MAX + 2 /* = 80 */ const char *argp_program_version = "abrt-backtrace " VERSION; const char *argp_program_bug_address = ""; -- cgit From 9e3970c52f800739b4f554a2ec4ef236b566fb00 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 13 Jan 2010 16:47:39 +0100 Subject: *: disable plugin loading/unloading through GUI. Document keyring a bit Signed-off-by: Denys Vlasenko --- src/Daemon/CommLayerServerDBus.cpp | 4 +++ src/Daemon/MiddleWare.cpp | 4 ++- src/Daemon/PluginManager.cpp | 3 +- src/Daemon/PluginManager.h | 2 ++ src/Gui/ABRTPlugin.py | 39 +++++++++++----------- src/Gui/CCDBusBackend.py | 16 +++++---- src/Gui/CCReporterDialog.py | 2 +- src/Gui/ConfBackend.py | 22 ++++++++++-- src/Gui/PluginList.py | 4 +-- src/Gui/PluginsSettingsDialog.py | 68 ++++++++++++++++++++------------------ 10 files changed, 98 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/Daemon/CommLayerServerDBus.cpp b/src/Daemon/CommLayerServerDBus.cpp index 9222c59..8589941 100644 --- a/src/Daemon/CommLayerServerDBus.cpp +++ b/src/Daemon/CommLayerServerDBus.cpp @@ -393,6 +393,7 @@ static int handle_SetPluginSettings(DBusMessage* call, DBusMessage* reply) return 0; } +#ifdef PLUGIN_DYNAMIC_LOAD_UNLOAD static int handle_RegisterPlugin(DBusMessage* call, DBusMessage* reply) { int r; @@ -432,6 +433,7 @@ static int handle_UnRegisterPlugin(DBusMessage* call, DBusMessage* reply) send_flush_and_unref(reply); return 0; } +#endif static int handle_GetSettings(DBusMessage* call, DBusMessage* reply) { @@ -496,10 +498,12 @@ static DBusHandlerResult message_received(DBusConnection* conn, DBusMessage* msg r = handle_GetPluginSettings(msg, reply); else if (strcmp(member, "SetPluginSettings") == 0) r = handle_SetPluginSettings(msg, reply); +#ifdef PLUGIN_DYNAMIC_LOAD_UNLOAD else if (strcmp(member, "RegisterPlugin") == 0) r = handle_RegisterPlugin(msg, reply); else if (strcmp(member, "UnRegisterPlugin") == 0) r = handle_UnRegisterPlugin(msg, reply); +#endif else if (strcmp(member, "GetSettings") == 0) r = handle_GetSettings(msg, reply); else if (strcmp(member, "SetSettings") == 0) diff --git a/src/Daemon/MiddleWare.cpp b/src/Daemon/MiddleWare.cpp index a348a92..70527eb 100644 --- a/src/Daemon/MiddleWare.cpp +++ b/src/Daemon/MiddleWare.cpp @@ -517,7 +517,9 @@ report_status_t Report(const map_crash_report_t& pCrashReport, #endif ret[plugin_name].push_back("1"); // REPORT_STATUS_IDX_FLAG ret[plugin_name].push_back(res); // REPORT_STATUS_IDX_MSG - message += res + "\n"; + if (message != "") + message += "; "; + message += res; } } catch (CABRTException& e) diff --git a/src/Daemon/PluginManager.cpp b/src/Daemon/PluginManager.cpp index e14f852..136277c 100644 --- a/src/Daemon/PluginManager.cpp +++ b/src/Daemon/PluginManager.cpp @@ -241,6 +241,7 @@ void CPluginManager::UnLoadPlugin(const char *pName) } } +#ifdef PLUGIN_DYNAMIC_LOAD_UNLOAD void CPluginManager::RegisterPluginDBUS(const char *pName, const char *pDBUSSender) { int polkit_result = polkit_check_authorization(pDBUSSender, @@ -267,7 +268,7 @@ void CPluginManager::UnRegisterPluginDBUS(const char *pName, const char *pDBUSSe log("user %s not authorized, returned %d", pDBUSSender, polkit_result); } } - +#endif CAnalyzer* CPluginManager::GetAnalyzer(const char *pName) { diff --git a/src/Daemon/PluginManager.h b/src/Daemon/PluginManager.h index 65058a5..d3e686c 100644 --- a/src/Daemon/PluginManager.h +++ b/src/Daemon/PluginManager.h @@ -80,6 +80,7 @@ class CPluginManager * @param pName A plugin name. */ void UnLoadPlugin(const char *pName); +#ifdef PLUGIN_DYNAMIC_LOAD_UNLOAD /** * A method, which registers particular plugin. * @param pName A plugin name. @@ -92,6 +93,7 @@ class CPluginManager * @param pDBUSSender DBUS user identification */ void UnRegisterPluginDBUS(const char *pName, const char *pDBUSSender); +#endif /** * A method, which returns instance of particular analyzer plugin. * @param pName A plugin name. diff --git a/src/Gui/ABRTPlugin.py b/src/Gui/ABRTPlugin.py index ea90b87..03b61fb 100644 --- a/src/Gui/ABRTPlugin.py +++ b/src/Gui/ABRTPlugin.py @@ -16,39 +16,40 @@ from ConfBackend import ConfBackendGnomeKeyring, ConfBackendInitError class PluginSettings(dict): def __init__(self): dict.__init__(self) - self.conf = None + self.client_side_conf = None try: - self.conf = ConfBackendGnomeKeyring() + self.client_side_conf = ConfBackendGnomeKeyring() except ConfBackendInitError, e: print e pass def check(self): + # if present, these should be non-empty for key in ["Password", "Login"]: if key in self.keys(): - # some of the required keys is missing if not self[key]: + # some of the required keys are missing return False # settings are OK return True - def load(self, name, default_settings): + def load_daemon_settings(self, name, daemon_settings): # load settings from daemon - for key in default_settings.keys(): - self[str(key)] = str(default_settings[key]) + for key in daemon_settings.keys(): + self[str(key)] = str(daemon_settings[key]) - if self.conf: - settings = self.conf.load(name) - # overwrite defaluts with user setting + if self.client_side_conf: + settings = self.client_side_conf.load(name) + # overwrite daemon data with user setting for key in settings.keys(): - # only rewrite keys needed by the plugin - # e.g we don't want a pass field for logger - if key in default_settings.keys(): + # only rewrite keys which exist in plugin's keys. + # e.g. we don't want a password field for logger plugin + if key in daemon_settings.keys(): self[str(key)] = str(settings[key]) - def save(self, name): - if self.conf: - self.conf.save(name, self) + def save_on_client_side(self, name): + if self.client_side_conf: + self.client_side_conf.save(name, self) class PluginInfo(): """Class to represent common plugin info""" @@ -90,11 +91,11 @@ class PluginInfo(): def __getitem__(self, item): return self.__dict__[item] - def load_settings(self, default_settings): + def load_daemon_settings(self, daemon_settings): if self.Name: - self.Settings.load(self.Name, default_settings) + self.Settings.load_daemon_settings(self.Name, daemon_settings) else: print _("Plugin name is not set, can't load its settings") - def save_settings(self): - self.Settings.save(str(self.Name)) + def save_settings_on_client_side(self): + self.Settings.save_on_client_side(str(self.Name)) diff --git a/src/Gui/CCDBusBackend.py b/src/Gui/CCDBusBackend.py index 85987e8..ac378f4 100644 --- a/src/Gui/CCDBusBackend.py +++ b/src/Gui/CCDBusBackend.py @@ -167,7 +167,10 @@ class DBusManager(gobject.GObject): def Report(self, report, reporters_settings = None): # map < Plguin_name vec > - self.daemon().Report(report, reporters_settings, reply_handler=self.report_done, error_handler=self.error_handler_cb, timeout=60) + if reporters_settings: + self.daemon().Report(report, reporters_settings, reply_handler=self.report_done, error_handler=self.error_handler_cb, timeout=60) + else: + self.daemon().Report(report, reply_handler=self.report_done, error_handler=self.error_handler_cb, timeout=60) def DeleteDebugDump(self,UUID): return self.daemon().DeleteDebugDump(UUID) @@ -192,11 +195,12 @@ class DBusManager(gobject.GObject): # print i return settings - def registerPlugin(self, plugin_name): - return self.daemon().RegisterPlugin(plugin_name) - - def unRegisterPlugin(self, plugin_name): - return self.daemon().UnRegisterPlugin(plugin_name) +# "Enable" toggling in GUI is disabled for now. Grep for PLUGIN_DYNAMIC_LOAD_UNLOAD +# def registerPlugin(self, plugin_name): +# return self.daemon().RegisterPlugin(plugin_name) +# +# def unRegisterPlugin(self, plugin_name): +# return self.daemon().UnRegisterPlugin(plugin_name) def setPluginSettings(self, plugin_name, plugin_settings): return self.daemon().SetPluginSettings(plugin_name, plugin_settings) diff --git a/src/Gui/CCReporterDialog.py b/src/Gui/CCReporterDialog.py index 09a9c91..bba8942 100644 --- a/src/Gui/CCReporterDialog.py +++ b/src/Gui/CCReporterDialog.py @@ -131,7 +131,7 @@ class ReporterDialog(): ui.dehydrate() if plugin.Settings.check(): try: - plugin.save_settings() + plugin.save_settings_on_client_side() except Exception, e: gui_error_message(_("Can't save plugin settings:\n %s" % e)) box = image.get_parent() diff --git a/src/Gui/ConfBackend.py b/src/Gui/ConfBackend.py index 5e26f3e..024a103 100644 --- a/src/Gui/ConfBackend.py +++ b/src/Gui/ConfBackend.py @@ -38,6 +38,22 @@ class ConfBackend(object): raise NotImplementedError +# We use Gnome keyring in the following way: +# we store passwords for each plugin in a key named "abrt:". +# The value of the key becomes the value of "Password" setting. +# Other settings (if plugin has them) are stored as attributes of this key. +# +# Example: Key "abrt:Bugzilla" with bugzilla password as value, and with attributes: +# +# AbrtPluginInfo: Bugzilla +# NoSSLVerify: yes +# Login: user@host.com +# BugzillaURL: https://host.with.bz.com/ +# +# The attribute "AbrtPluginInfo" is special, it is used for retrieving +# the key via keyring API find_items_sync() function. + + class ConfBackendGnomeKeyring(ConfBackend): def __init__(self): ConfBackend.__init__(self) @@ -47,7 +63,7 @@ class ConfBackendGnomeKeyring(ConfBackend): self.default_key_ring = gkey.get_default_keyring_sync() except: # could happen if keyring daemon is running, but we run gui under - # user who is not owner is the running session - using su + # user who is not the owner of the running session - using su raise ConfBackendInitError(_("Can't get default keyring")) def save(self, name, settings): @@ -62,7 +78,7 @@ class ConfBackendGnomeKeyring(ConfBackend): # nothing found pass except gkey.DeniedError: - raise ConfBackendSaveError(_("Acces to gnome-keyring has been denied, plugins settings won't be saved.")) + raise ConfBackendSaveError(_("Access to gnome-keyring has been denied, plugins settings won't be saved.")) # delete all items containg "AbrtPluginInfo":, so we always have only 1 item per plugin for item in item_list: @@ -79,7 +95,7 @@ class ConfBackendGnomeKeyring(ConfBackend): password, True) except gkey.DeniedError, e: - raise ConfBackendSaveError(_("Acces to gnome-keyring has been denied, plugins settings won't be saved.")) + raise ConfBackendSaveError(_("Access to gnome-keyring has been denied, plugins settings won't be saved.")) def load(self, name): item_list = None diff --git a/src/Gui/PluginList.py b/src/Gui/PluginList.py index e57040d..79df126 100644 --- a/src/Gui/PluginList.py +++ b/src/Gui/PluginList.py @@ -20,8 +20,8 @@ class PluginInfoList(list): entry.__dict__[column] = row[column] if entry.Enabled == "yes": #entry.Settings = PluginSettings(self.dm.getPluginSettings(str(entry))) - default_settings = self.dm.getPluginSettings(str(entry)) - entry.load_settings(default_settings) + daemon_settings = self.dm.getPluginSettings(str(entry)) + entry.load_daemon_settings(daemon_settings) self.append(entry) self.ddict[entry.getName()] = entry else: diff --git a/src/Gui/PluginsSettingsDialog.py b/src/Gui/PluginsSettingsDialog.py index 8453385..5feda4a 100644 --- a/src/Gui/PluginsSettingsDialog.py +++ b/src/Gui/PluginsSettingsDialog.py @@ -44,20 +44,21 @@ class PluginsSettingsDialog: column.set_attributes(column.gray_background, visible=3, cell_background=4) column.set_resizable(True) - # toggle - group_name_renderer = gtk.CellRendererText() - toggle_renderer = gtk.CellRendererToggle() - toggle_renderer.set_property('activatable', True) - toggle_renderer.connect( 'toggled', self.on_enabled_toggled, self.pluginsListStore ) - column = gtk.TreeViewColumn(_('Enabled')) - column.pack_start(toggle_renderer, True) - column.pack_start(group_name_renderer, True) - column.add_attribute( toggle_renderer, "active", 1) - column.add_attribute( toggle_renderer, "visible", 2) - column.add_attribute( group_name_renderer, "visible", 3) - column.add_attribute( group_name_renderer, "markup", 0) - column.add_attribute( group_name_renderer, "cell_background", 4) - self.pluginlist.insert_column(column, 0) +# "Enable" toggle column is disabled for now. Grep for PLUGIN_DYNAMIC_LOAD_UNLOAD +# # toggle +# group_name_renderer = gtk.CellRendererText() +# toggle_renderer = gtk.CellRendererToggle() +# toggle_renderer.set_property('activatable', True) +# toggle_renderer.connect( 'toggled', self.on_enabled_toggled, self.pluginsListStore ) +# column = gtk.TreeViewColumn(_('Enabled')) +# column.pack_start(toggle_renderer, True) +# column.pack_start(group_name_renderer, True) +# column.add_attribute( toggle_renderer, "active", 1) +# column.add_attribute( toggle_renderer, "visible", 2) +# column.add_attribute( group_name_renderer, "visible", 3) +# column.add_attribute( group_name_renderer, "markup", 0) +# column.add_attribute( group_name_renderer, "cell_background", 4) +# self.pluginlist.insert_column(column, 0) #connect signals self.pluginlist.connect("cursor-changed", self.on_tvDumps_cursor_changed) @@ -65,24 +66,25 @@ class PluginsSettingsDialog: self.builder.get_object("bClose").connect("clicked", self.on_bClose_clicked) self.builder.get_object("bConfigurePlugin").set_sensitive(False) - def on_enabled_toggled(self,cell, path, model): - plugin = model[path][model.get_n_columns()-1] - if plugin: - if model[path][1]: - #print "self.ccdaemon.UnRegisterPlugin(%s)" % (plugin.getName()) - self.ccdaemon.unRegisterPlugin(plugin.getName()) - # FIXME: create class plugin and move this into method Plugin.Enable() - plugin.Enabled = "no" - plugin.Settings = None - else: - #print "self.ccdaemon.RegisterPlugin(%s)" % (model[path][model.get_n_columns()-1]) - self.ccdaemon.registerPlugin(plugin.getName()) - # FIXME: create class plugin and move this into method Plugin.Enable() - plugin.Enabled = "yes" - default_settings = self.ccdaemon.getPluginSettings(plugin.getName()) - plugin.Settings = PluginSettings() - plugin.Settings.load(plugin.getName(), default_settings) - model[path][1] = not model[path][1] +# "Enable" toggle column is disabled for now. Grep for PLUGIN_DYNAMIC_LOAD_UNLOAD +# def on_enabled_toggled(self,cell, path, model): +# plugin = model[path][model.get_n_columns()-1] +# if plugin: +# if model[path][1]: +# #print "self.ccdaemon.UnRegisterPlugin(%s)" % (plugin.getName()) +# self.ccdaemon.unRegisterPlugin(plugin.getName()) +# # FIXME: create class plugin and move this into method Plugin.Enable() +# plugin.Enabled = "no" +# plugin.Settings = None +# else: +# #print "self.ccdaemon.RegisterPlugin(%s)" % (model[path][model.get_n_columns()-1]) +# self.ccdaemon.registerPlugin(plugin.getName()) +# # FIXME: create class plugin and move this into method Plugin.Enable() +# plugin.Enabled = "yes" +# default_settings = self.ccdaemon.getPluginSettings(plugin.getName()) +# plugin.Settings = PluginSettings() +# plugin.Settings.load(plugin.getName(), default_settings) +# model[path][1] = not model[path][1] def filter_plugins(self, model, miter, data): return True @@ -135,7 +137,7 @@ class PluginsSettingsDialog: ui.dehydrate() if pluginfo.Settings: try: - pluginfo.save_settings() + pluginfo.save_settings_on_client_side() # FIXME: do we need to call this? all reporters set their settings # when Report() is called self.ccdaemon.setPluginSettings(pluginfo.getName(), pluginfo.Settings) -- cgit From 7f1a96006b50365f54ff94d110ee4011c1b9a32a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 13 Jan 2010 18:02:22 +0100 Subject: fix plugin type display in GUI Signed-off-by: Denys Vlasenko --- src/Gui/CCMainWindow.py | 6 ++-- src/Gui/PluginsSettingsDialog.py | 69 ++++++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/Gui/CCMainWindow.py b/src/Gui/CCMainWindow.py index 77ce3d3..f4e3a73 100644 --- a/src/Gui/CCMainWindow.py +++ b/src/Gui/CCMainWindow.py @@ -69,9 +69,9 @@ class MainWindow(): #icon, package_name, application, date, crash_rate, user, is_reported, ?object? self.dumpsListStore = gtk.ListStore(gtk.gdk.Pixbuf, str,str,str,str,str,bool, object) # set filter - self.modelfilter = self.dumpsListStore.filter_new() - self.modelfilter.set_visible_func(self.filter_dumps, None) - self.dlist.set_model(self.modelfilter) + modelfilter = self.dumpsListStore.filter_new() + modelfilter.set_visible_func(self.filter_dumps, None) + self.dlist.set_model(modelfilter) # add pixbuff separatelly icon_column = gtk.TreeViewColumn(_("Icon")) icon_column.cell = gtk.CellRendererPixbuf() diff --git a/src/Gui/PluginsSettingsDialog.py b/src/Gui/PluginsSettingsDialog.py index 5feda4a..0d41962 100644 --- a/src/Gui/PluginsSettingsDialog.py +++ b/src/Gui/PluginsSettingsDialog.py @@ -6,10 +6,12 @@ from PluginSettingsUI import PluginSettingsUI from ABRTPlugin import PluginSettings, PluginInfo from abrt_utils import _ + class PluginsSettingsDialog: def __init__(self, parent, daemon): #print "Settings dialog init" self.ccdaemon = daemon + self.builder = gtk.Builder() builderfile = "%s%ssettings.glade" % (sys.path[0],"/") #print builderfile @@ -22,43 +24,41 @@ class PluginsSettingsDialog: raise Exception(_("Can't load gui description for SettingsDialog!")) #self.window.set_parent(parent) - self.pluginlist = self.builder.get_object("tvSettings") + self.pluginlist = self.builder.get_object("tvSettings") # a TreeView # cell_text, toggle_active, toggle_visible, group_name_visible, color, plugin self.pluginsListStore = gtk.TreeStore(str, bool, bool, bool, str, object) # set filter - self.modelfilter = self.pluginsListStore.filter_new() - self.modelfilter.set_visible_func(self.filter_plugins, None) - self.pluginlist.set_model(self.modelfilter) - # =============================================== - columns = [None]*1 - columns[0] = gtk.TreeViewColumn(_("Name")) + modelfilter = self.pluginsListStore.filter_new() + modelfilter.set_visible_func(self.filter_plugins, None) + self.pluginlist.set_model(modelfilter) - # create list - for column in columns: - n = self.pluginlist.append_column(column) - column.cell = gtk.CellRendererText() - column.gray_background = gtk.CellRendererText() - column.pack_start(column.cell, True) - column.pack_start(column.gray_background, True) - column.set_attributes(column.cell, markup=(n-1), visible=2) - column.set_attributes(column.gray_background, visible=3, cell_background=4) - column.set_resizable(True) + # Create/configure columns and add them to pluginlist + # column "name" has two kind of cells: + column = gtk.TreeViewColumn(_("Name")) + # cells for individual plugins (white) + cell_name = gtk.CellRendererText() + column.pack_start(cell_name, True) + column.set_attributes(cell_name, markup=0, visible=2) # show 0th field (plugin name) from data items if 2th field is true + # cells for plugin types (gray) + cell_plugin_type = gtk.CellRendererText() + column.pack_start(cell_plugin_type, True) + column.add_attribute(cell_plugin_type, "visible", 3) + column.add_attribute(cell_plugin_type, "markup", 0) + column.add_attribute(cell_plugin_type, "cell_background", 4) + # column "name" is ready, insert + column.set_resizable(True) + self.pluginlist.append_column(column) # "Enable" toggle column is disabled for now. Grep for PLUGIN_DYNAMIC_LOAD_UNLOAD -# # toggle -# group_name_renderer = gtk.CellRendererText() -# toggle_renderer = gtk.CellRendererToggle() -# toggle_renderer.set_property('activatable', True) -# toggle_renderer.connect( 'toggled', self.on_enabled_toggled, self.pluginsListStore ) -# column = gtk.TreeViewColumn(_('Enabled')) -# column.pack_start(toggle_renderer, True) -# column.pack_start(group_name_renderer, True) -# column.add_attribute( toggle_renderer, "active", 1) -# column.add_attribute( toggle_renderer, "visible", 2) -# column.add_attribute( group_name_renderer, "visible", 3) -# column.add_attribute( group_name_renderer, "markup", 0) -# column.add_attribute( group_name_renderer, "cell_background", 4) -# self.pluginlist.insert_column(column, 0) +# column = gtk.TreeViewColumn(_("Enabled")) +# # column "enabled" has one kind of cells: +# cell_toggle_enable = gtk.CellRendererToggle() +# cell_toggle_enable.set_property("activatable", True) +# cell_toggle_enable.connect("toggled", self.on_enabled_toggled, self.pluginsListStore) +# column.pack_start(cell_toggle_enable, True) +# column.add_attribute(cell_toggle_enable, "active", 1) +# column.add_attribute(cell_toggle_enable, "visible", 2) +# self.pluginlist.append_column(column) #connect signals self.pluginlist.connect("cursor-changed", self.on_tvDumps_cursor_changed) @@ -88,6 +88,7 @@ class PluginsSettingsDialog: def filter_plugins(self, model, miter, data): return True + def hydrate(self): #print "settings hydrate" self.pluginsListStore.clear() @@ -100,13 +101,13 @@ class PluginsSettingsDialog: #gui_error_message("Error while loading plugins info, please check if abrt daemon is running\n %s" % e) plugin_rows = {} for plugin_type in PluginInfo.types.keys(): - it = self.pluginsListStore.append(None, ["%s" % (PluginInfo.types[plugin_type]),0 , 0, 1,"gray", None]) + it = self.pluginsListStore.append(None, ["%s" % PluginInfo.types[plugin_type], 0, 0, 1, "gray", None]) plugin_rows[plugin_type] = it for entry in pluginlist: - n = self.pluginsListStore.append(plugin_rows[entry.getType()],["%s\n%s" % (entry.getName(), entry.Description), entry.Enabled == "yes", 1, 0, "white", entry]) + self.pluginsListStore.append(plugin_rows[entry.getType()], + ["%s\n%s" % (entry.getName(), entry.Description), entry.Enabled == "yes", 1, 0, "white", entry]) self.pluginlist.expand_all() - def dehydrate(self): # we have nothing to save, plugin's does the work pass -- cgit From b3938fc6d23373e8331385e52ca36d3eb0ef7337 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 13 Jan 2010 18:34:33 +0100 Subject: add an URL to Gnome keyring API (it wasn't trivial to google for) Signed-off-by: Denys Vlasenko --- src/Gui/ConfBackend.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/Gui/ConfBackend.py b/src/Gui/ConfBackend.py index 024a103..1d6ac9e 100644 --- a/src/Gui/ConfBackend.py +++ b/src/Gui/ConfBackend.py @@ -1,5 +1,8 @@ from abrt_utils import _ +# Doc on Gnome keyring API: +# http://library.gnome.org/devel/gnome-keyring/stable/ + #FIXME: add some backend factory try: -- cgit From 8d51d37a4a330a0574ebe11d37bce3abadea3162 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 14 Jan 2010 16:11:13 +0100 Subject: GUI: make it so that even non-loaded plugins show up in "Plugins" dialog Signed-off-by: Denys Vlasenko --- src/CLI/dbus.cpp | 6 ++- src/CLI/dbus.h | 6 ++- src/Daemon/CommLayerServerDBus.cpp | 10 ++-- src/Daemon/Daemon.cpp | 3 +- src/Daemon/PluginManager.cpp | 96 +++++++++++++++++++------------------- src/Daemon/PluginManager.h | 13 ++++-- src/Gui/ABRTPlugin.py | 3 +- src/Gui/CCDBusBackend.py | 2 - src/Gui/CCDumpList.py | 2 - src/Gui/PluginList.py | 17 +++---- 10 files changed, 80 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/CLI/dbus.cpp b/src/CLI/dbus.cpp index b218679..0d03c4d 100644 --- a/src/CLI/dbus.cpp +++ b/src/CLI/dbus.cpp @@ -184,7 +184,8 @@ int32_t call_DeleteDebugDump(const char* uuid) return result; } -vector_map_string_t call_GetPluginsInfo() +#ifdef UNUSED +map_map_string_t call_GetPluginsInfo() { DBusMessage *msg = new_call_msg(__func__ + 5); DBusMessage *reply = send_get_reply_and_unref(msg); @@ -192,7 +193,7 @@ vector_map_string_t call_GetPluginsInfo() DBusMessageIter in_iter; dbus_message_iter_init(reply, &in_iter); - vector_map_string_t argout; + map_map_string_t argout; int r = load_val(&in_iter, argout); if (r != ABRT_DBUS_LAST_FIELD) /* more values present, or bad type */ error_msg_and_die("dbus call %s: return type mismatch", __func__ + 5); @@ -200,6 +201,7 @@ vector_map_string_t call_GetPluginsInfo() dbus_message_unref(reply); return argout; } +#endif void handle_dbus_err(bool error_flag, DBusError *err) { diff --git a/src/CLI/dbus.h b/src/CLI/dbus.h index 3c157c0..c692e19 100644 --- a/src/CLI/dbus.h +++ b/src/CLI/dbus.h @@ -28,15 +28,17 @@ map_crash_report_t call_CreateReport(const char *uuid); report_status_t call_Report(const map_crash_report_t& report); int32_t call_DeleteDebugDump(const char* uuid); +#ifdef UNUSED /* Gets basic data about all installed plugins. */ -vector_map_string_t call_GetPluginsInfo(); +map_map_string_t call_GetPluginsInfo(); /** Gets default plugin settings. * @param name - * Corresponds to name obtained from call_GetPluginsInfo. + * Corresponds to name obtained from call_GetPluginsInfo. */ map_plugin_settings_t call_GetPluginSettings(const char *name); +#endif void handle_dbus_err(bool error_flag, DBusError *err); diff --git a/src/Daemon/CommLayerServerDBus.cpp b/src/Daemon/CommLayerServerDBus.cpp index 8589941..db0d2f5 100644 --- a/src/Daemon/CommLayerServerDBus.cpp +++ b/src/Daemon/CommLayerServerDBus.cpp @@ -325,11 +325,9 @@ static int handle_DeleteDebugDump(DBusMessage* call, DBusMessage* reply) static int handle_GetPluginsInfo(DBusMessage* call, DBusMessage* reply) { - vector_map_string_t plugins_info = g_pPluginManager->GetPluginsInfo(); - DBusMessageIter out_iter; dbus_message_iter_init_append(reply, &out_iter); - store_val(&out_iter, plugins_info); + store_val(&out_iter, g_pPluginManager->GetPluginsInfo()); send_flush_and_unref(reply); return 0; @@ -348,9 +346,9 @@ static int handle_GetPluginSettings(DBusMessage* call, DBusMessage* reply) return -1; } - long unix_uid = get_remote_uid(call); - VERB1 log("got %s('%s') call from uid %ld", "GetPluginSettings", PluginName, unix_uid); - map_plugin_settings_t plugin_settings = g_pPluginManager->GetPluginSettings(PluginName, to_string(unix_uid).c_str()); + //long unix_uid = get_remote_uid(call); + //VERB1 log("got %s('%s') call from uid %ld", "GetPluginSettings", PluginName, unix_uid); + map_plugin_settings_t plugin_settings = g_pPluginManager->GetPluginSettings(PluginName); //, to_string(unix_uid).c_str()); DBusMessageIter out_iter; dbus_message_iter_init_append(reply, &out_iter); diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp index 09d8ab8..a2970af 100644 --- a/src/Daemon/Daemon.cpp +++ b/src/Daemon/Daemon.cpp @@ -65,7 +65,8 @@ * Returns report_status_t (map_vector_string_t) - the status of each call. * 2nd parameter is the contents of user's abrt.conf. * - DeleteDebugDump(UUID): delete it from DB and delete corresponding /var/cache/abrt/DIR - * - GetPluginsInfo(): returns vector_map_string_t + * - GetPluginsInfo(): returns map_map_string_t + * map["plugin"] = { "Name": "plugin", "Enabled": "yes" ... } * - GetPluginSettings(PluginName): returns map_plugin_settings_t (map_string_t) * - SetPluginSettings(PluginName, map_plugin_settings_t): returns void * - RegisterPlugin(PluginName): returns void diff --git a/src/Daemon/PluginManager.cpp b/src/Daemon/PluginManager.cpp index 136277c..c552880 100644 --- a/src/Daemon/PluginManager.cpp +++ b/src/Daemon/PluginManager.cpp @@ -27,6 +27,8 @@ #include "Polkit.h" #include "PluginManager.h" +using namespace std; + /** * Text representation of plugin types. */ @@ -40,12 +42,12 @@ static const char *const plugin_type_str[] = { bool LoadPluginSettings(const char *pPath, map_plugin_settings_t& pSettings) { - std::ifstream fIn; + ifstream fIn; fIn.open(pPath); if (!fIn.is_open()) return false; - std::string line; + string line; while (!fIn.eof()) { getline(fIn, line); @@ -54,8 +56,8 @@ bool LoadPluginSettings(const char *pPath, map_plugin_settings_t& pSettings) bool is_value = false; bool valid = false; bool in_quote = false; - std::string key; - std::string value; + string key; + string value; for (ii = 0; ii < line.length(); ii++) { if (line[ii] == '"') @@ -157,6 +159,10 @@ void CPluginManager::UnLoadPlugins() CPlugin* CPluginManager::LoadPlugin(const char *pName, bool enabled_only) { + map_string_t plugin_info; + + plugin_info["Name"] = pName; + map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName); if (it_plugin != m_mapPlugins.end()) { @@ -170,8 +176,9 @@ CPlugin* CPluginManager::LoadPlugin(const char *pName, bool enabled_only) conf_name = "Kerneloops"; } map_plugin_settings_t pluginSettings; - std::string conf_fullname = ssprintf(PLUGINS_CONF_DIR"/%s."PLUGINS_CONF_EXTENSION, conf_name); + string conf_fullname = ssprintf(PLUGINS_CONF_DIR"/%s."PLUGINS_CONF_EXTENSION, conf_name); LoadPluginSettings(conf_fullname.c_str(), pluginSettings); + m_map_plugin_settings[pName] = pluginSettings; VERB3 log("Loaded %s.conf", conf_name); if (enabled_only) @@ -179,12 +186,21 @@ CPlugin* CPluginManager::LoadPlugin(const char *pName, bool enabled_only) map_plugin_settings_t::iterator it = pluginSettings.find("Enabled"); if (it == pluginSettings.end() || !string_to_bool(it->second.c_str())) { + plugin_info["Enabled"] = "no"; + string empty; + plugin_info["Type"] = empty; + plugin_info["Version"] = empty; + plugin_info["Description"] = empty; + plugin_info["Email"] = empty; + plugin_info["WWW"] = empty; + plugin_info["GTKBuilder"] = empty; + m_map_plugin_info[pName] = plugin_info; VERB3 log("Plugin %s: 'Enabled' is not set, not loading it (yet)", pName); return NULL; /* error */ } } - std::string libPath = ssprintf(PLUGINS_LIB_DIR"/"PLUGINS_LIB_PREFIX"%s."PLUGINS_LIB_EXTENSION, pName); + string libPath = ssprintf(PLUGINS_LIB_DIR"/"PLUGINS_LIB_PREFIX"%s."PLUGINS_LIB_EXTENSION, pName); CLoadedModule* module = new CLoadedModule(libPath.c_str()); if (module->GetMagicNumber() != PLUGINS_MAGIC_NUMBER || module->GetType() < 0 @@ -217,6 +233,16 @@ CPlugin* CPluginManager::LoadPlugin(const char *pName, bool enabled_only) return NULL; /* error */ } + plugin_info["Enabled"] = "yes"; + plugin_info["Type"] = plugin_type_str[module->GetType()]; + //plugin_info["Name"] = module->GetName(); + plugin_info["Version"] = module->GetVersion(); + plugin_info["Description"] = module->GetDescription(); + plugin_info["Email"] = module->GetEmail(); + plugin_info["WWW"] = module->GetWWW(); + plugin_info["GTKBuilder"] = module->GetGTKBuilder(); + + m_map_plugin_info[pName] = plugin_info; m_mapLoadedModules[pName] = module; m_mapPlugins[pName] = plugin; log("Registered %s plugin '%s'", plugin_type_str[module->GetType()], pName); @@ -344,28 +370,6 @@ plugin_type_t CPluginManager::GetPluginType(const char *pName) return it_module->second->GetType(); } -vector_map_string_t CPluginManager::GetPluginsInfo() -{ - vector_map_string_t ret; - map_loaded_module_t::iterator it_module = m_mapLoadedModules.begin(); - for (; it_module != m_mapLoadedModules.end(); it_module++) - { - map_string_t plugin_info; - - plugin_info["Enabled"] = (m_mapPlugins.find(it_module->second->GetName()) != m_mapPlugins.end()) ? - "yes" : "no"; - plugin_info["Type"] = plugin_type_str[it_module->second->GetType()]; - plugin_info["Name"] = it_module->second->GetName(); - plugin_info["Version"] = it_module->second->GetVersion(); - plugin_info["Description"] = it_module->second->GetDescription(); - plugin_info["Email"] = it_module->second->GetEmail(); - plugin_info["WWW"] = it_module->second->GetWWW(); - plugin_info["GTKBuilder"] = it_module->second->GetGTKBuilder(); - ret.push_back(plugin_info); - } - return ret; -} - void CPluginManager::SetPluginSettings(const char *pName, const char *pUID, const map_plugin_settings_t& pSettings) @@ -388,14 +392,14 @@ void CPluginManager::SetPluginSettings(const char *pName, return; } - std::string home = get_home_dir(xatoi_u(pUID.c_str())); + string home = get_home_dir(xatoi_u(pUID.c_str())); if (home == "") { return; } - std::string confDir = home + "/.abrt"; - std::string confPath = confDir + "/" + pName + "."PLUGINS_CONF_EXTENSION; + string confDir = home + "/.abrt"; + string confPath = confDir + "/" + pName + "."PLUGINS_CONF_EXTENSION; uid_t uid = xatoi_u(pUID.c_str()); struct passwd* pw = getpwuid(uid); gid_t gid = pw ? pw->pw_gid : uid; @@ -440,33 +444,31 @@ void CPluginManager::SetPluginSettings(const char *pName, #endif } -map_plugin_settings_t CPluginManager::GetPluginSettings(const char *pName, - const char *pUID) +map_plugin_settings_t CPluginManager::GetPluginSettings(const char *pName) { map_plugin_settings_t ret; + map_loaded_module_t::iterator it_module = m_mapLoadedModules.find(pName); if (it_module != m_mapLoadedModules.end()) { map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName); if (it_plugin != m_mapPlugins.end()) { + VERB3 log("Returning settings for loaded plugin %s", pName); ret = it_plugin->second->GetSettings(); - /** we don't want to load it from daemon if it's running under root - but wi might get back to this once we make the daemon to not run - with root privileges - */ - /* - if (it_module->second->GetType() == REPORTER) - { - std::string home = get_home_dir(xatoi_u(pUID.c_str())); - if (home != "") - { - LoadPluginSettings(home + "/.abrt/" + pName + "."PLUGINS_CONF_EXTENSION, ret); - } - } - */ return ret; } } + /* else: module is not loaded */ + map_map_string_t::iterator it_settings = m_map_plugin_settings.find(pName); + if (it_settings != m_map_plugin_settings.end()) + { + /* but it exists, its settings are available nevertheless */ + VERB3 log("Returning settings for non-loaded plugin %s", pName); + ret = it_settings->second; + return ret; + } + + VERB3 log("Request for settings of unknown plugin %s, returning null result", pName); return ret; } diff --git a/src/Daemon/PluginManager.h b/src/Daemon/PluginManager.h index d3e686c..22cc387 100644 --- a/src/Daemon/PluginManager.h +++ b/src/Daemon/PluginManager.h @@ -50,6 +50,11 @@ class CPluginManager * Registered plugins. A key is a plugin name. */ map_plugin_t m_mapPlugins; + /** + * List of all possible plugins (loaded or not), with some attributes. + */ + map_map_string_t m_map_plugin_info; + map_map_string_t m_map_plugin_settings; public: /** @@ -130,7 +135,7 @@ class CPluginManager * Then user can fill all needed informations like URLs etc. * @return A vector of maps */ - vector_map_string_t GetPluginsInfo(); + const map_map_string_t& GetPluginsInfo() { return m_map_plugin_info; } /** * A method, which sets up a plugin. The settings are also saved in home * directory of an user. @@ -144,11 +149,9 @@ class CPluginManager /** * A method, which returns plugin's settings according to user. * @param pName A plugin name. - * @param pUID An uid of user. - * @return Plugin's settings accorting to user. + * @return Plugin's settings. */ - map_plugin_settings_t GetPluginSettings(const char *pName, - const char *pUID); + map_plugin_settings_t GetPluginSettings(const char *pName); }; /** diff --git a/src/Gui/ABRTPlugin.py b/src/Gui/ABRTPlugin.py index 03b61fb..9f66a83 100644 --- a/src/Gui/ABRTPlugin.py +++ b/src/Gui/ABRTPlugin.py @@ -53,7 +53,8 @@ class PluginSettings(dict): class PluginInfo(): """Class to represent common plugin info""" - types = {"Analyzer":_("Analyzer plugins"), + types = {"":_("Not loaded plugins"), + "Analyzer":_("Analyzer plugins"), "Action":_("Action plugins"), "Reporter":_("Reporter plugins"), "Database":_("Database plugins")} diff --git a/src/Gui/CCDBusBackend.py b/src/Gui/CCDBusBackend.py index ac378f4..64deb39 100644 --- a/src/Gui/CCDBusBackend.py +++ b/src/Gui/CCDBusBackend.py @@ -191,8 +191,6 @@ class DBusManager(gobject.GObject): def getPluginSettings(self, plugin_name): settings = self.daemon().GetPluginSettings(plugin_name) - #for i in settings.keys(): - # print i return settings # "Enable" toggling in GUI is disabled for now. Grep for PLUGIN_DYNAMIC_LOAD_UNLOAD diff --git a/src/Gui/CCDumpList.py b/src/Gui/CCDumpList.py index 09191f5..a8657e0 100644 --- a/src/Gui/CCDumpList.py +++ b/src/Gui/CCDumpList.py @@ -6,7 +6,6 @@ class DumpList(list): """Class to store list of debug dumps""" def __init__(self,dbus_manager=None): self.dm = dbus_manager - self.ddict = {} def load(self): if self.dm: @@ -21,7 +20,6 @@ class DumpList(list): # print "DumpList adding %s:%s" % (column,row[column]) entry.__dict__[column] = row[column] self.append(entry) - self.ddict[entry.getUUID()] = entry except Exception, e: # FIXME handle exception better # this is just temporary workaround for rhbz#543725 diff --git a/src/Gui/PluginList.py b/src/Gui/PluginList.py index 79df126..6db603e 100644 --- a/src/Gui/PluginList.py +++ b/src/Gui/PluginList.py @@ -6,24 +6,21 @@ class PluginInfoList(list): """Class to store list of PluginInfos""" def __init__(self,dbus_manager=None): self.dm = dbus_manager - self.ddict = {} def load(self): if self.dm: #print "loading PluginList" rows = self.dm.getPluginsInfo() #print rows - for row in rows: + for plugin_name in rows: + row = rows[plugin_name] entry = PluginInfo() - for column in row: - #print "PluginInfoList adding %s:%s" % (column,row[column]) - entry.__dict__[column] = row[column] - if entry.Enabled == "yes": - #entry.Settings = PluginSettings(self.dm.getPluginSettings(str(entry))) - daemon_settings = self.dm.getPluginSettings(str(entry)) - entry.load_daemon_settings(daemon_settings) + for attr_name in row: + print "PluginInfoList adding %s[%s]:%s" % (plugin_name, attr_name, row[attr_name]) + entry.__dict__[attr_name] = row[attr_name] + daemon_settings = self.dm.getPluginSettings(plugin_name) + entry.load_daemon_settings(daemon_settings) self.append(entry) - self.ddict[entry.getName()] = entry else: print "db == None!" -- cgit From ab4aa70e27cd66c7b2f3f530cfb6f026322eb91c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 14 Jan 2010 16:13:04 +0100 Subject: comment out forgotten debugging Signed-off-by: Denys Vlasenko --- src/Gui/PluginList.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Gui/PluginList.py b/src/Gui/PluginList.py index 6db603e..50a4067 100644 --- a/src/Gui/PluginList.py +++ b/src/Gui/PluginList.py @@ -16,7 +16,7 @@ class PluginInfoList(list): row = rows[plugin_name] entry = PluginInfo() for attr_name in row: - print "PluginInfoList adding %s[%s]:%s" % (plugin_name, attr_name, row[attr_name]) + #print "PluginInfoList adding %s[%s]:%s" % (plugin_name, attr_name, row[attr_name]) entry.__dict__[attr_name] = row[attr_name] daemon_settings = self.dm.getPluginSettings(plugin_name) entry.load_daemon_settings(daemon_settings) -- cgit From 2a8dfdad5a5e4ccb0c7a2e9147c38336ba76d733 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 14 Jan 2010 17:47:01 +0100 Subject: gui: add logging infrastructure Signed-off-by: Denys Vlasenko --- src/Gui/ABRTExceptions.py | 2 +- src/Gui/ABRTPlugin.py | 5 ++--- src/Gui/CCDBusBackend.py | 20 +++++++++---------- src/Gui/CCMainWindow.py | 26 +++++++++++++++++------- src/Gui/CCReporterDialog.py | 2 +- src/Gui/CC_gui_functions.py | 20 ++++++++++--------- src/Gui/ConfBackend.py | 2 +- src/Gui/PluginList.py | 7 +++---- src/Gui/PluginSettingsUI.py | 2 +- src/Gui/PluginsSettingsDialog.py | 17 +++++++++++----- src/Gui/SettingsDialog.py | 2 +- src/Gui/abrt_utils.py | 43 ++++++++++++++++++++++++++++++---------- 12 files changed, 94 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/Gui/ABRTExceptions.py b/src/Gui/ABRTExceptions.py index c4d6b59..c857f71 100644 --- a/src/Gui/ABRTExceptions.py +++ b/src/Gui/ABRTExceptions.py @@ -1,4 +1,4 @@ -from abrt_utils import _ +from abrt_utils import _, log, log1, log2 class IsRunning(Exception): def __init__(self): diff --git a/src/Gui/ABRTPlugin.py b/src/Gui/ABRTPlugin.py index 9f66a83..5fb551d 100644 --- a/src/Gui/ABRTPlugin.py +++ b/src/Gui/ABRTPlugin.py @@ -10,7 +10,7 @@ Type Email Description """ -from abrt_utils import _ +from abrt_utils import _, log, log1, log2 from ConfBackend import ConfBackendGnomeKeyring, ConfBackendInitError class PluginSettings(dict): @@ -63,7 +63,6 @@ class PluginInfo(): "Type", "Email", "Description"] def __init__(self): - #print "Init PluginInfo" self.WWW = None self.Name = None self.Enabled = None @@ -96,7 +95,7 @@ class PluginInfo(): if self.Name: self.Settings.load_daemon_settings(self.Name, daemon_settings) else: - print _("Plugin name is not set, can't load its settings") + log("Plugin name is not set, can't load its settings") def save_settings_on_client_side(self): self.Settings.save_on_client_side(str(self.Name)) diff --git a/src/Gui/CCDBusBackend.py b/src/Gui/CCDBusBackend.py index 64deb39..1ec2d8a 100644 --- a/src/Gui/CCDBusBackend.py +++ b/src/Gui/CCDBusBackend.py @@ -6,7 +6,7 @@ from dbus.mainloop.glib import DBusGMainLoop import gtk from dbus.exceptions import * import ABRTExceptions -from abrt_utils import _ +from abrt_utils import _, log, log1, log2 CC_NAME = 'com.redhat.abrt' CC_IFACE = 'com.redhat.abrt' @@ -111,13 +111,13 @@ class DBusManager(gobject.GObject): # def disconnected(self, *args): # print "disconnect" - def error_handler_cb(self,error): - self.emit("abrt-error",error) + def error_handler_cb(self, error): + self.emit("abrt-error", error) - def warning_handler_cb(self,arg): - self.emit("warning",arg) + def warning_handler_cb(self, arg): + self.emit("warning", arg) - def error_handler(self,arg): + def error_handler(self, arg): # used to silently ingore dbus timeouts pass @@ -134,11 +134,11 @@ class DBusManager(gobject.GObject): self.emit("crash") def update_cb(self, message, job_id=0): - print "Update >>%s<<" % message + log1("Update:%s", message) self.emit("update", message) def warning_cb(self, message, job_id=0): - print "Warning >>%s<<" % message + log1("Warning:%s", message) self.emit("warning", message) def owner_changed_cb(self,name, old_owner, new_owner): @@ -151,7 +151,7 @@ class DBusManager(gobject.GObject): def jobdone_cb(self, dest, uuid): # TODO: check that it is indeed OUR job: # remember uuid in getReport and compare here - print "Our job for UUID %s is done." % uuid + log1("Our job for UUID %s is done", uuid) dump = self.daemon().CreateReport(uuid) if dump: self.emit("analyze-complete", dump) @@ -208,6 +208,6 @@ class DBusManager(gobject.GObject): def setSettings(self, settings): # FIXME: STUB!!!! - print "setSettings stub" + log1("setSettings stub") retval = self.daemon().SetSettings(self.daemon().GetSettings()) print ">>>", retval diff --git a/src/Gui/CCMainWindow.py b/src/Gui/CCMainWindow.py index f4e3a73..432fd43 100644 --- a/src/Gui/CCMainWindow.py +++ b/src/Gui/CCMainWindow.py @@ -2,6 +2,7 @@ import sys import os import pwd +import getopt import pygtk pygtk.require("2.0") import gobject @@ -12,6 +13,11 @@ except RuntimeError,e: print e os.exit() import gtk.glade +try: + import rpm +except Exception, ex: + rpm = None + import CCDBusBackend from CC_gui_functions import * from CCDumpList import getDumpList, DumpList @@ -21,12 +27,7 @@ from SettingsDialog import SettingsDialog from CCReport import Report from PluginList import getPluginInfoList import ABRTExceptions -from abrt_utils import _ - -try: - import rpm -except Exception, ex: - rpm = None +from abrt_utils import _, init_logging, log, log1, log2 class MainWindow(): @@ -381,8 +382,19 @@ class MainWindow(): self.window.present() if __name__ == "__main__": + try: + opts, args = getopt.getopt(sys.argv[1:], "v") + except getopt.GetoptError, err: + print str(err) # prints something like "option -a not recognized" + sys.exit(2) + verbose = 0 + for opt, arg in opts: + if opt == "-v": + verbose += 1 + init_logging("abrt-gui", verbose) + log1("log level:%d", verbose) + cc = MainWindow() cc.hydrate() cc.show() gtk.main() - diff --git a/src/Gui/CCReporterDialog.py b/src/Gui/CCReporterDialog.py index bba8942..ab6ad0f 100644 --- a/src/Gui/CCReporterDialog.py +++ b/src/Gui/CCReporterDialog.py @@ -12,7 +12,7 @@ from ABRTPlugin import PluginInfo from PluginSettingsUI import PluginSettingsUI from PluginList import getPluginInfoList #from CCDumpList import getDumpList, DumpList -from abrt_utils import _ +from abrt_utils import _, log, log1, log2 # FIXME - create method or smth that returns type|editable|content CD_TYPE = 0 diff --git a/src/Gui/CC_gui_functions.py b/src/Gui/CC_gui_functions.py index 0532ab7..0379f20 100644 --- a/src/Gui/CC_gui_functions.py +++ b/src/Gui/CC_gui_functions.py @@ -15,13 +15,15 @@ try: import rpm except: rpm = None +from abrt_utils import _, log, log1, log2 + def on_url_clicked(label, url): import gnomevfs file_mimetype = gnomevfs.get_mime_type(url) default_app = gnomevfs.mime_get_default_application(file_mimetype) if default_app: - #print "Default Application:", default_app[2] + log2("default application:%s", default_app[2]) subprocess.Popen([default_app[2], url]) def gui_report_dialog ( report_status_dict, parent_dialog, @@ -160,8 +162,8 @@ def gui_question_dialog ( message, parent_dialog=None, dialog.destroy() return ret -def get_icon_for_package(theme,package): - #print package +def get_icon_for_package(theme, package): + log2("get_icon_for_package('%s')", package) try: return theme.load_icon(package, 22, gtk.ICON_LOOKUP_USE_BUILTIN) except: @@ -169,7 +171,7 @@ def get_icon_for_package(theme,package): if not rpm: return None ts = rpm.TransactionSet() - mi = ts.dbMatch( 'name', package ) + mi = ts.dbMatch('name', package) possible_icons = [] icon_filename = "" filenames = "" @@ -180,19 +182,19 @@ def get_icon_for_package(theme,package): if filename.rfind(".png") != -1: possible_icons.append(filename) if filename.rfind(".desktop") != -1: - #print filename + log2("desktop file:'%s'", filename) desktop_file = open(filename, 'r') lines = desktop_file.readlines() for line in lines: if line.find("Icon=") != -1: - #print line[5:-1] + log2("Icon='%s'", line[5:-1]) icon_filename = line[5:-1] break desktop_file.close() # .dektop file found for filename in h['filenames']: if filename.rfind("%s.png" % icon_filename) != -1: - #print filename + log2("png file:'%s'", filename) icon_filename = filename break #we didn't find the .desktop file @@ -205,8 +207,8 @@ def get_icon_for_package(theme,package): if icon_filename: break if icon_filename: - #print "icon created form %s" % icon_filename - return gtk.gdk.pixbuf_new_from_file_at_size(icon_filename,22,22) + log1("icon created from %s", icon_filename) + return gtk.gdk.pixbuf_new_from_file_at_size(icon_filename, 22, 22) else: return None diff --git a/src/Gui/ConfBackend.py b/src/Gui/ConfBackend.py index 1d6ac9e..08ceed5 100644 --- a/src/Gui/ConfBackend.py +++ b/src/Gui/ConfBackend.py @@ -1,4 +1,4 @@ -from abrt_utils import _ +from abrt_utils import _, log, log1, log2 # Doc on Gnome keyring API: # http://library.gnome.org/devel/gnome-keyring/stable/ diff --git a/src/Gui/PluginList.py b/src/Gui/PluginList.py index 50a4067..d2232bb 100644 --- a/src/Gui/PluginList.py +++ b/src/Gui/PluginList.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import CCDBusBackend from ABRTPlugin import PluginInfo, PluginSettings +from abrt_utils import _, log, log1, log2 class PluginInfoList(list): """Class to store list of PluginInfos""" @@ -9,20 +10,18 @@ class PluginInfoList(list): def load(self): if self.dm: - #print "loading PluginList" rows = self.dm.getPluginsInfo() - #print rows for plugin_name in rows: row = rows[plugin_name] entry = PluginInfo() for attr_name in row: - #print "PluginInfoList adding %s[%s]:%s" % (plugin_name, attr_name, row[attr_name]) + log2("PluginInfoList: adding %s[%s]:%s", plugin_name, attr_name, row[attr_name]) entry.__dict__[attr_name] = row[attr_name] daemon_settings = self.dm.getPluginSettings(plugin_name) entry.load_daemon_settings(daemon_settings) self.append(entry) else: - print "db == None!" + log("PluginInfoList: db == None") def getEnabledPlugins(self): return [x for x in self if x["Enabled"] == 'yes'] diff --git a/src/Gui/PluginSettingsUI.py b/src/Gui/PluginSettingsUI.py index a26f87f..c324b31 100644 --- a/src/Gui/PluginSettingsUI.py +++ b/src/Gui/PluginSettingsUI.py @@ -1,5 +1,5 @@ import gtk -from abrt_utils import _ +from abrt_utils import _, log, log1, log2 class PluginSettingsUI(gtk.Dialog): def __init__(self, pluginfo, parent=None): diff --git a/src/Gui/PluginsSettingsDialog.py b/src/Gui/PluginsSettingsDialog.py index 0d41962..611a8c5 100644 --- a/src/Gui/PluginsSettingsDialog.py +++ b/src/Gui/PluginsSettingsDialog.py @@ -4,7 +4,7 @@ from PluginList import getPluginInfoList, PluginInfoList from CC_gui_functions import * from PluginSettingsUI import PluginSettingsUI from ABRTPlugin import PluginSettings, PluginInfo -from abrt_utils import _ +from abrt_utils import _, log, log1, log2 class PluginsSettingsDialog: @@ -13,7 +13,7 @@ class PluginsSettingsDialog: self.ccdaemon = daemon self.builder = gtk.Builder() - builderfile = "%s%ssettings.glade" % (sys.path[0],"/") + builderfile = "%s%ssettings.glade" % (sys.path[0], "/") #print builderfile try: self.builder.add_from_file(builderfile) @@ -99,13 +99,20 @@ class PluginsSettingsDialog: except Exception, e: print e #gui_error_message("Error while loading plugins info, please check if abrt daemon is running\n %s" % e) + return plugin_rows = {} for plugin_type in PluginInfo.types.keys(): - it = self.pluginsListStore.append(None, ["%s" % PluginInfo.types[plugin_type], 0, 0, 1, "gray", None]) + it = self.pluginsListStore.append(None, + ["%s" % PluginInfo.types[plugin_type], 0, 0, 1, "gray", None]) plugin_rows[plugin_type] = it for entry in pluginlist: + if entry.Description: + text = "%s\n%s" % (entry.getName(), entry.Description) + else: + # non-loaded plugins have empty description + text = "%s" % entry.getName() self.pluginsListStore.append(plugin_rows[entry.getType()], - ["%s\n%s" % (entry.getName(), entry.Description), entry.Enabled == "yes", 1, 0, "white", entry]) + [text, entry.Enabled == "yes", 1, 0, "white", entry]) self.pluginlist.expand_all() def dehydrate(self): @@ -149,7 +156,7 @@ class PluginsSettingsDialog: elif response == gtk.RESPONSE_CANCEL: pass else: - print _("unknown response from settings dialog") + log("unknown response from settings dialog:%d", response) ui.destroy() def on_bClose_clicked(self, button): diff --git a/src/Gui/SettingsDialog.py b/src/Gui/SettingsDialog.py index c2b292f..893c23f 100644 --- a/src/Gui/SettingsDialog.py +++ b/src/Gui/SettingsDialog.py @@ -3,7 +3,7 @@ import gtk from PluginList import getPluginInfoList from CC_gui_functions import * #from PluginSettingsUI import PluginSettingsUI -from abrt_utils import _ +from abrt_utils import _, log, log1, log2 #FIXME: create a better struct, to automatize hydrate/dehydrate process diff --git a/src/Gui/abrt_utils.py b/src/Gui/abrt_utils.py index 6122b9c..2fabb54 100644 --- a/src/Gui/abrt_utils.py +++ b/src/Gui/abrt_utils.py @@ -1,16 +1,37 @@ +import sys import gtk.glade + PROGNAME = "abrt" +g_verbose = 0 + import locale -try: - locale.setlocale (locale.LC_ALL, "") -except locale.Error, e: - import os - os.environ['LC_ALL'] = 'C' - locale.setlocale (locale.LC_ALL, "") import gettext -gettext.bind_textdomain_codeset(PROGNAME,locale.nl_langinfo(locale.CODESET)) -gettext.bindtextdomain(PROGNAME, '/usr/share/locale') -gtk.glade.bindtextdomain(PROGNAME, '/usr/share/locale') -gtk.glade.textdomain(PROGNAME) -gettext.textdomain(PROGNAME) + _ = lambda x: gettext.lgettext(x) + +def init_logging(progname, v): + global PROGNAME, g_verbose + PROGNAME = progname + g_verbose = v + try: + locale.setlocale(locale.LC_ALL, "") + except locale.Error, e: + import os + os.environ['LC_ALL'] = 'C' + locale.setlocale(locale.LC_ALL, "") + gettext.bind_textdomain_codeset(PROGNAME, locale.nl_langinfo(locale.CODESET)) + gettext.bindtextdomain(PROGNAME, '/usr/share/locale') + gtk.glade.bindtextdomain(PROGNAME, '/usr/share/locale') + gtk.glade.textdomain(PROGNAME) + gettext.textdomain(PROGNAME) + +def log(fmt, *args): + sys.stderr.write("%s: %s\n" % (PROGNAME, fmt % args)) + +def log1(fmt, *args): + if g_verbose >= 1: + sys.stderr.write("%s: %s\n" % (PROGNAME, fmt % args)) + +def log2(fmt, *args): + if g_verbose >= 2: + sys.stderr.write("%s: %s\n" % (PROGNAME, fmt % args)) -- cgit From 1ff447ffaaa02cd0c46607f817c13328114145bc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 14 Jan 2010 23:06:00 +0100 Subject: add code to make GUI -> daemon settings passing less weird. not enabled yet Signed-off-by: Denys Vlasenko --- src/Gui/CCDBusBackend.py | 2 +- src/Gui/CCMainWindow.py | 8 +++- src/Gui/ConfBackend.py | 100 +++++++++++++++++++++++++++++++++++++---------- 3 files changed, 87 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/Gui/CCDBusBackend.py b/src/Gui/CCDBusBackend.py index 1ec2d8a..f4ef104 100644 --- a/src/Gui/CCDBusBackend.py +++ b/src/Gui/CCDBusBackend.py @@ -40,7 +40,7 @@ class DBusManager(gobject.GObject): if session: try: - app_proxy = session.get_object(APP_NAME,APP_PATH) + app_proxy = session.get_object(APP_NAME, APP_PATH) app_iface = dbus.Interface(app_proxy, dbus_interface=APP_IFACE) # app is running, so make it show it self app_iface.show() diff --git a/src/Gui/CCMainWindow.py b/src/Gui/CCMainWindow.py index 432fd43..0bc00e5 100644 --- a/src/Gui/CCMainWindow.py +++ b/src/Gui/CCMainWindow.py @@ -18,6 +18,7 @@ try: except Exception, ex: rpm = None +from ConfBackend import ConfBackendGnomeKeyring, ConfBackendInitError import CCDBusBackend from CC_gui_functions import * from CCDumpList import getDumpList, DumpList @@ -42,11 +43,10 @@ class MainWindow(): sys.exit() except Exception, e: # show error message if connection fails - # FIXME add an option to start the daemon gui_error_message("%s" % e) sys.exit() #Set the Glade file - self.gladefile = "%s%sccgui.glade" % (sys.path[0],"/") + self.gladefile = "%s/ccgui.glade" % sys.path[0] self.wTree = gtk.glade.XML(self.gladefile) #Get the Main Window, and connect the "destroy" event @@ -304,6 +304,10 @@ class MainWindow(): self.pluginlist = getPluginInfoList(self.ccdaemon) for plugin in self.pluginlist.getReporterPlugins(): reporters_settings[str(plugin)] = plugin.Settings + # TODO: this way, we don't need to talk to daemon in order to get + # all plugin settings: + #reporters_settings2 = ConfBackendGnomeKeyring().load_all() + #log1("reporters_settings2:%s", str(reporters_settings2)) self.ccdaemon.Report(result, reporters_settings) #self.hydrate() except Exception, e: diff --git a/src/Gui/ConfBackend.py b/src/Gui/ConfBackend.py index 08ceed5..fa1d663 100644 --- a/src/Gui/ConfBackend.py +++ b/src/Gui/ConfBackend.py @@ -2,6 +2,7 @@ from abrt_utils import _, log, log1, log2 # Doc on Gnome keyring API: # http://library.gnome.org/devel/gnome-keyring/stable/ +# Python bindings are in gnome-python2-desktop package #FIXME: add some backend factory @@ -56,14 +57,19 @@ class ConfBackend(object): # The attribute "AbrtPluginInfo" is special, it is used for retrieving # the key via keyring API find_items_sync() function. +g_default_key_ring = None class ConfBackendGnomeKeyring(ConfBackend): def __init__(self): + global g_default_key_ring + ConfBackend.__init__(self) + if g_default_key_ring: + return if not gkey.is_available(): raise ConfBackendInitError(_("Can't connect to Gnome Keyring daemon")) try: - self.default_key_ring = gkey.get_default_keyring_sync() + g_default_key_ring = gkey.get_default_keyring_sync() except: # could happen if keyring daemon is running, but we run gui under # user who is not the owner of the running session - using su @@ -71,31 +77,36 @@ class ConfBackendGnomeKeyring(ConfBackend): def save(self, name, settings): settings_tmp = settings.copy() - settings_tmp["AbrtPluginInfo"] = name - password = "" + settings_tmp["AbrtPluginInfo"] = name # old way + settings_tmp["Application"] = "abrt" + settings_tmp["AbrtPluginName"] = name - item_list = [] + # delete all keyring items containg "AbrtPluginInfo":"", + # so we always have only 1 item per plugin try: - item_list = gkey.find_items_sync(gkey.ITEM_GENERIC_SECRET, {"AbrtPluginInfo":str(name)}) + item_list = gkey.find_items_sync(gkey.ITEM_GENERIC_SECRET, { "AbrtPluginInfo": str(name) }) + for item in item_list: + log2("found old keyring item: ring:'%s' item_id:%s attrs:%s", item.keyring, item.item_id, str(item.attributes)) + log2("deleting it from keyring '%s'", g_default_key_ring) + gkey.item_delete_sync(g_default_key_ring, item.item_id) except gkey.NoMatchError: # nothing found pass except gkey.DeniedError: raise ConfBackendSaveError(_("Access to gnome-keyring has been denied, plugins settings won't be saved.")) - - # delete all items containg "AbrtPluginInfo":, so we always have only 1 item per plugin - for item in item_list: - gkey.item_delete_sync(self.default_key_ring, item.item_id) - + # if plugin has a "Password" setting, we handle it specially: in keyring, + # it is stored as item.secret, not as one of attributes + password = "" if "Password" in settings_tmp: password = settings_tmp["Password"] del settings_tmp["Password"] + # store new settings for this plugin as one keyring item try: - gkey.item_create_sync(self.default_key_ring, + gkey.item_create_sync(g_default_key_ring, gkey.ITEM_GENERIC_SECRET, - "abrt:%s" % name, - settings_tmp, - password, + "abrt:%s" % name, # display_name + settings_tmp, # attrs + password, # secret True) except gkey.DeniedError, e: raise ConfBackendSaveError(_("Access to gnome-keyring has been denied, plugins settings won't be saved.")) @@ -103,17 +114,66 @@ class ConfBackendGnomeKeyring(ConfBackend): def load(self, name): item_list = None try: + log2("looking for keyring items with 'AbrtPluginInfo:%s' attr", str(name)) item_list = gkey.find_items_sync(gkey.ITEM_GENERIC_SECRET, {"AbrtPluginInfo":str(name)}) + for item in item_list: + # gnome keyring is weeeeird. why display_name, type, mtime, ctime + # aren't available in find_items_sync() results? why we need to + # get them via additional call, item_get_info_sync()? + # internally, item has GNOME_KEYRING_TYPE_FOUND type, + # and info has GNOME_KEYRING_TYPE_ITEM_INFO type. + # why not use the same type for both? + # + # and worst of all, this information took four hours of googling... + # + #info = gkey.item_get_info_sync(item.keyring, item.item_id) + log2("found keyring item: ring:'%s' item_id:%s attrs:%s", # "secret:'%s' display_name:'%s'" + item.keyring, item.item_id, str(item.attributes) #, item.secret, info.get_display_name() + ) except gkey.NoMatchError: # nothing found pass - if item_list: retval = item_list[0].attributes.copy() retval["Password"] = item_list[0].secret return retval - else: - return {} - #for i in item_list: - # for attr in i.attributes: - # print attr, i.attributes[attr] + return {} + + # This routine loads setting for all plugins. It doesn't need plugin name. + # Thus we can avoid talking to abrtd just in order to get plugin names. + def load_all(self): + retval = {} + item_list = {} + try: + log2("looking for keyring items with 'Application:abrt' attr") + item_list = gkey.find_items_sync(gkey.ITEM_GENERIC_SECRET, { "Application": "abrt" }) + except gkey.NoMatchError: + # nothing found + pass + for item in item_list: + # gnome keyring is weeeeird. why display_name, type, mtime, ctime + # aren't available in find_items_sync() results? why we need to + # get them via additional call, item_get_info_sync()? + # internally, item has GNOME_KEYRING_TYPE_FOUND type, + # and info has GNOME_KEYRING_TYPE_ITEM_INFO type. + # why not use the same type for both? + # + # and worst of all, this information took four hours of googling... + # + #info = gkey.item_get_info_sync(item.keyring, item.item_id) + log2("found keyring item: ring:%s item_id:%s attrs:%s", # "secret:%s display_name:'%s'" + item.keyring, item.item_id, str(item.attributes) #, item.secret, info.get_display_name() + ) + attrs = item.attributes.copy() + if "AbrtPluginName" in attrs: + plugin_name = attrs["AbrtPluginName"] + # If plugin has a "Password" setting, we handle it specially: in keyring, + # it is stored as item.secret, not as one of attributes + if item.secret: + attrs["Password"] = item.secret + # avoiding sending useless duplicate info over dbus... + del attrs["Application"] + del attrs["AbrtPluginInfo"] + del attrs["AbrtPluginName"] + retval[plugin_name] = attrs; + return retval -- cgit From f0e636a2bac1d6a76fed613bee9505b4abfdf8b1 Mon Sep 17 00:00:00 2001 From: Jiri Moskovcak Date: Fri, 15 Jan 2010 15:18:22 +0100 Subject: use repr() to print variable values in python hook --- src/Hooks/abrt_exception_handler.py.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Hooks/abrt_exception_handler.py.in b/src/Hooks/abrt_exception_handler.py.in index a0b0519..e0e1954 100644 --- a/src/Hooks/abrt_exception_handler.py.in +++ b/src/Hooks/abrt_exception_handler.py.in @@ -213,7 +213,7 @@ def handleMyException((etype, value, tb)): text += ("\nLocal variables in innermost frame:\n") try: for (key, val) in frame.f_locals.items(): - text += "%s: %s\n" % (key, val) + text += "%s: %s\n" % (key, repr(val)) except: pass -- cgit From 494ed25390a3c1fa831ca594b77135eb5f18fba8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 15 Jan 2010 16:04:27 +0100 Subject: GUI: better code for plugin settings overriding; better logging; fixed "not reported" display bug Signed-off-by: Denys Vlasenko --- src/Gui/ABRTPlugin.py | 4 ++-- src/Gui/CCMainWindow.py | 31 ++++++++++++++---------- src/Gui/ConfBackend.py | 64 ++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 73 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/Gui/ABRTPlugin.py b/src/Gui/ABRTPlugin.py index 5fb551d..320c81c 100644 --- a/src/Gui/ABRTPlugin.py +++ b/src/Gui/ABRTPlugin.py @@ -11,14 +11,14 @@ Email Description """ from abrt_utils import _, log, log1, log2 -from ConfBackend import ConfBackendGnomeKeyring, ConfBackendInitError +from ConfBackend import getCurrentConfBackend, ConfBackendInitError class PluginSettings(dict): def __init__(self): dict.__init__(self) self.client_side_conf = None try: - self.client_side_conf = ConfBackendGnomeKeyring() + self.client_side_conf = getCurrentConfBackend() except ConfBackendInitError, e: print e pass diff --git a/src/Gui/CCMainWindow.py b/src/Gui/CCMainWindow.py index 0bc00e5..5ffc027 100644 --- a/src/Gui/CCMainWindow.py +++ b/src/Gui/CCMainWindow.py @@ -18,7 +18,7 @@ try: except Exception, ex: rpm = None -from ConfBackend import ConfBackendGnomeKeyring, ConfBackendInitError +from ConfBackend import getCurrentConfBackend, ConfBackendInitError import CCDBusBackend from CC_gui_functions import * from CCDumpList import getDumpList, DumpList @@ -234,9 +234,11 @@ class MainWindow(): # it is not informative (no URL to the report) for message in dump.getMessage().split('\n'): if message: - if "http" in message[0:5] or "file:///"[0:8] in message: - message = "%s" % (message, message) + #Doesn't work (far too easy to make it worse, not better): + #if "http" in message[0:5] or "file:///"[0:8] in message: + # message = "%s" % (message, message) report_label += "%s\n" % message + log2("setting markup '%s'", report_label) self.wTree.get_widget("lReported").set_markup(report_label) else: self.wTree.get_widget("lReported").set_markup(_("Not reported!")) @@ -298,17 +300,20 @@ class MainWindow(): try: self.pBarWindow.show_all() self.timer = gobject.timeout_add(100, self.progress_update_cb) - reporters_settings = {} - # self.pluginlist = getPluginInfoList(self.ccdaemon, refresh=True) - # don't force refresh! - self.pluginlist = getPluginInfoList(self.ccdaemon) - for plugin in self.pluginlist.getReporterPlugins(): - reporters_settings[str(plugin)] = plugin.Settings - # TODO: this way, we don't need to talk to daemon in order to get - # all plugin settings: - #reporters_settings2 = ConfBackendGnomeKeyring().load_all() - #log1("reporters_settings2:%s", str(reporters_settings2)) + # Old way: it needs to talk to daemon + #reporters_settings = {} + ## self.pluginlist = getPluginInfoList(self.ccdaemon, refresh=True) + ## don't force refresh! + #self.pluginlist = getPluginInfoList(self.ccdaemon) + #for plugin in self.pluginlist.getReporterPlugins(): + # reporters_settings[str(plugin)] = plugin.Settings + reporters_settings = getCurrentConfBackend().load_all() + log2("Report(result,settings):") + log2(" result:%s", str(result)) + # Careful, this will print reporters_settings["Password"] too + log2(" settings:%s", str(reporters_settings)) self.ccdaemon.Report(result, reporters_settings) + log2("Report() returned") #self.hydrate() except Exception, e: gui_error_message(_("Reporting failed!\n%s" % e)) diff --git a/src/Gui/ConfBackend.py b/src/Gui/ConfBackend.py index fa1d663..0d47760 100644 --- a/src/Gui/ConfBackend.py +++ b/src/Gui/ConfBackend.py @@ -4,8 +4,6 @@ from abrt_utils import _, log, log1, log2 # http://library.gnome.org/devel/gnome-keyring/stable/ # Python bindings are in gnome-python2-desktop package -#FIXME: add some backend factory - try: import gnomekeyring as gkey except ImportError, e: @@ -49,13 +47,14 @@ class ConfBackend(object): # # Example: Key "abrt:Bugzilla" with bugzilla password as value, and with attributes: # +# Application: abrt # AbrtPluginInfo: Bugzilla # NoSSLVerify: yes # Login: user@host.com # BugzillaURL: https://host.with.bz.com/ # -# The attribute "AbrtPluginInfo" is special, it is used for retrieving -# the key via keyring API find_items_sync() function. +# Attributes "Application" and "AbrtPluginInfo" are special, they are used +# for efficient key retrieval via keyring API find_items_sync() function. g_default_key_ring = None @@ -66,7 +65,7 @@ class ConfBackendGnomeKeyring(ConfBackend): ConfBackend.__init__(self) if g_default_key_ring: return - if not gkey.is_available(): + if not gkey or not gkey.is_available(): raise ConfBackendInitError(_("Can't connect to Gnome Keyring daemon")) try: g_default_key_ring = gkey.get_default_keyring_sync() @@ -77,9 +76,8 @@ class ConfBackendGnomeKeyring(ConfBackend): def save(self, name, settings): settings_tmp = settings.copy() - settings_tmp["AbrtPluginInfo"] = name # old way settings_tmp["Application"] = "abrt" - settings_tmp["AbrtPluginName"] = name + settings_tmp["AbrtPluginInfo"] = name # delete all keyring items containg "AbrtPluginInfo":"", # so we always have only 1 item per plugin @@ -144,6 +142,37 @@ class ConfBackendGnomeKeyring(ConfBackend): def load_all(self): retval = {} item_list = {} + + # UGLY compat cludge for users who has saved items without "Application" attr + # (abrt <= 1.0.3 was saving those) + item_ids = gkey.list_item_ids_sync(g_default_key_ring) + log2("all keyring item ids:%s", item_ids) + for item_id in item_ids: + info = gkey.item_get_info_sync(g_default_key_ring, item_id) + attrs = gkey.item_get_attributes_sync(g_default_key_ring, item_id) + log2("keyring item %s: attrs:%s", item_id, str(attrs)) + if "AbrtPluginInfo" in attrs: + if not "Application" in attrs: + log2("updating old-style keyring item") + attrs["Application"] = "abrt" + try: + gkey.item_set_attributes_sync(g_default_key_ring, item_id, attrs) + except: + log2("error updating old-style keyring item") + plugin_name = attrs["AbrtPluginInfo"] + # If plugin has a "Password" setting, we handle it specially: in keyring, + # it is stored as item.secret, not as one of attributes + if info.get_secret(): + attrs["Password"] = info.get_secret() + # avoiding sending useless duplicate info over dbus... + del attrs["AbrtPluginInfo"] + try: + del attrs["Application"] + except: + pass + retval[plugin_name] = attrs; + # end of UGLY compat cludge + try: log2("looking for keyring items with 'Application:abrt' attr") item_list = gkey.find_items_sync(gkey.ITEM_GENERIC_SECRET, { "Application": "abrt" }) @@ -165,15 +194,28 @@ class ConfBackendGnomeKeyring(ConfBackend): item.keyring, item.item_id, str(item.attributes) #, item.secret, info.get_display_name() ) attrs = item.attributes.copy() - if "AbrtPluginName" in attrs: - plugin_name = attrs["AbrtPluginName"] + if "AbrtPluginInfo" in attrs: + plugin_name = attrs["AbrtPluginInfo"] # If plugin has a "Password" setting, we handle it specially: in keyring, # it is stored as item.secret, not as one of attributes if item.secret: attrs["Password"] = item.secret # avoiding sending useless duplicate info over dbus... - del attrs["Application"] del attrs["AbrtPluginInfo"] - del attrs["AbrtPluginName"] + try: + del attrs["Application"] + except: + pass retval[plugin_name] = attrs; return retval + + +# Rudimentary backend factory + +currentConfBackend = None + +def getCurrentConfBackend(): + global currentConfBackend + if not currentConfBackend: + currentConfBackend = ConfBackendGnomeKeyring() + return currentConfBackend -- cgit