>From f88d0f449dcb13754faa6c267f0a15b5cee7bb39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= Date: Wed, 10 Aug 2011 10:56:10 +0200 Subject: [PATCH] sss_debuglevel - change the debug levels on the fly https://fedorahosted.org/sssd/ticket/950 --- .gitignore | 1 + Makefile.am | 10 +- contrib/sssd.spec.in | 2 + contrib/suse/sssd.spec.in | 2 + src/man/Makefile.am | 2 +- src/man/sss_debuglevel.8.xml | 66 +++++++ src/tools/sss_debuglevel.c | 404 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 485 insertions(+), 2 deletions(-) create mode 100644 src/man/sss_debuglevel.8.xml create mode 100644 src/tools/sss_debuglevel.c diff --git a/.gitignore b/.gitignore index 478cd7f..fa5495a 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ sss_useradd sss_userdel sss_usermod sss_groupshow +sss_debuglevel sssd sssd_be sssd_dp diff --git a/Makefile.am b/Makefile.am index 4e2e26b..1863564 100644 --- a/Makefile.am +++ b/Makefile.am @@ -58,7 +58,8 @@ sbin_PROGRAMS = \ sss_usermod \ sss_groupmod \ sss_groupshow \ - sss_cache + sss_cache \ + sss_debuglevel sssdlibexec_PROGRAMS = \ sssd_nss \ @@ -511,6 +512,13 @@ sss_cache_LDADD = \ libsss_util.la \ $(TOOLS_LIBS) +sss_debuglevel_SOURCES = \ + src/tools/sss_debuglevel.c \ + $(SSSD_TOOLS_OBJ) +sss_debuglevel_LDADD = \ + libsss_util.la \ + $(TOOLS_LIBS) + ################# # Feature Tests # ################# diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index 2639f3a..3c7e3c9 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -296,6 +296,7 @@ rm -rf $RPM_BUILD_ROOT %{_sbindir}/sss_groupshow %{_sbindir}/sss_obfuscate %{_sbindir}/sss_cache +%{_sbindir}/sss_debuglevel %{_mandir}/man8/sss_groupadd.8* %{_mandir}/man8/sss_groupdel.8* %{_mandir}/man8/sss_groupmod.8* @@ -305,6 +306,7 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man8/sss_usermod.8* %{_mandir}/man8/sss_obfuscate.8* %{_mandir}/man8/sss_cache.8* +%{_mandir}/man8/sss_debuglevel.8* %files -n libipa_hbac %defattr(-,root,root,-) diff --git a/contrib/suse/sssd.spec.in b/contrib/suse/sssd.spec.in index 5c3178f..e943427 100644 --- a/contrib/suse/sssd.spec.in +++ b/contrib/suse/sssd.spec.in @@ -176,6 +176,7 @@ rm -rf $RPM_BUILD_ROOT %{_sbindir}/sss_groupdel %{_sbindir}/sss_groupmod %{_sbindir}/sss_groupshow +%{_sbindir}/sss_debuglevel %{_libexecdir}/%{servicename}/ %{_libdir}/%{name}/ %{_libdir}/ldb/memberof.so @@ -202,6 +203,7 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man8/sss_useradd.8* %{_mandir}/man8/sss_userdel.8* %{_mandir}/man8/sss_usermod.8* +%{_mandir}/man8/sss_debuglevel.8* %{_mandir}/man8/sssd_krb5_locator_plugin.8* %{python_sitearch}/pysss.so %{python_sitelib}/*.py* diff --git a/src/man/Makefile.am b/src/man/Makefile.am index 24acb06..09af898 100644 --- a/src/man/Makefile.am +++ b/src/man/Makefile.am @@ -17,7 +17,7 @@ man_MANS = \ sssd.8 sssd.conf.5 sssd-ldap.5 \ sssd-krb5.5 sssd-ipa.5 sssd-simple.5 \ sssd_krb5_locator_plugin.8 sss_groupshow.8 \ - pam_sss.8 sss_obfuscate.8 sss_cache.8 + pam_sss.8 sss_obfuscate.8 sss_cache.8 sss_debuglevel.8 EXTRA_DIST = $(man_MANS:%=%.xml) $(wildcard $(srcdir)/include/*.xml) SUFFIXES = .1.xml .1 .3.xml .3 .5.xml .5 .8.xml .8 diff --git a/src/man/sss_debuglevel.8.xml b/src/man/sss_debuglevel.8.xml new file mode 100644 index 0000000..1c596bb --- /dev/null +++ b/src/man/sss_debuglevel.8.xml @@ -0,0 +1,66 @@ + + + +SSSD Manual pages + + + + + sss_debuglevel + 8 + + + + sss_debuglevel + change debug level while SSSD is running + + + + + sss_debuglevel + + options + + NEW_DEBUG_LEVEL + + + + + DESCRIPTION + + sss_debuglevel changes debug level of SSSD monitor + and providers to NEW_DEBUG_LEVEL while SSSD is running. + + + + + OPTIONS + + + + , + + + + Specify a non-default config file. The default is + /etc/sssd/sssd.conf. For reference + on the config file syntax and options, consult the + + sssd.conf + 5 + + manual page. + + + + + + NEW_DEBUG_LEVEL + + + + + + + diff --git a/src/tools/sss_debuglevel.c b/src/tools/sss_debuglevel.c new file mode 100644 index 0000000..4e40603 --- /dev/null +++ b/src/tools/sss_debuglevel.c @@ -0,0 +1,404 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2011 Red Hat + + 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 3 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, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "ldb.h" +#include "util/util.h" +#include "tools/tools_util.h" +#include "confdb/confdb.h" + +#define SSSD_PIDFILE ""PID_PATH"/sssd.pid" +#define MAX_PID_LENGTH 10 + +#define CHECK(expr, done, msg) do { \ + if (expr) { \ + ERROR(msg "\n"); \ + goto done; \ + } \ +} while(0); + +struct debuglevel_tool_ctx { + struct confdb_ctx *confdb; + char **sections; +}; + +static errno_t set_debug_level( + struct debuglevel_tool_ctx *tool_ctx, int debug_to_set, + const char *config_file +); +static errno_t send_sighup(void); +static errno_t connect_to_confdb( + TALLOC_CTX *ctx, struct confdb_ctx **cdb_ctx +); +static errno_t get_confdb_sections( + TALLOC_CTX *ctx, struct confdb_ctx *confdb, char ***output_sections +); + +static errno_t get_sssd_pid(pid_t *out_pid); +static pid_t parse_pid(const char *strpid); +static int parse_debug_level(const char *strlevel); + +int main(int argc, const char **argv) +{ + int ret; + int pc_debug = SSSDBG_DEFAULT; + int debug_to_set = SSSDBG_INVALID; + const char *debug_as_string = NULL; + const char *config_file = NULL; + const char *pc_config_file = NULL; + struct debuglevel_tool_ctx *ctx = NULL; + struct poptOption long_options[] = { + POPT_AUTOHELP + { "debug", '\0', POPT_ARG_INT, &pc_debug, + 0, _("The debug level to run with"), NULL }, + {"config", 'c', POPT_ARG_STRING, &pc_config_file, + 0, _("Specify a non-default config file"), NULL}, + POPT_TABLEEND + }; + poptContext pc = NULL; + + debug_prg_name = argv[0]; + + /* parse parameters */ + pc = poptGetContext(argv[0], argc, argv, long_options, 0); + poptSetOtherOptionHelp(pc, "DEBUG_LEVEL_TO_SET"); + while((ret = poptGetNextOpt(pc)) != -1) { + switch(ret) { + default: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(ret)); + poptPrintUsage(pc, stderr, 0); + ret = EXIT_FAILURE; + goto fini; + } + } + debug_level = debug_convert_old_level(pc_debug); + + /* get debug level */ + debug_as_string = poptGetArg(pc); + if (debug_as_string == NULL) { + BAD_POPT_PARAMS(pc, _("Specify debug level you want to set\n"), + ret, fini); + } + + /* get config file */ + config_file = pc_config_file == NULL + ? talloc_strdup(ctx, CONFDB_DEFAULT_CONFIG_FILE) + : talloc_strdup(ctx, pc_config_file); + if (config_file == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strdup() failed\n")); + ret = ENOMEM; + goto fini; + } + + CHECK_ROOT(ret, debug_prg_name); + + /* free pc_config_file? */ + /* free debug_as_string? */ + + debug_to_set = parse_debug_level(debug_as_string); + CHECK(debug_to_set == SSSDBG_INVALID, fini, "Invalid debug level."); + + /* allocate context */ + ctx = talloc_zero(NULL, struct debuglevel_tool_ctx); + if (ctx == NULL) { + DEBUG( + SSSDBG_CRIT_FAILURE, + ("Could not allocate memory for tools context\n") + ); + ret = ENOMEM; + goto fini; + } + + ret = connect_to_confdb(ctx, &ctx->confdb); + CHECK(ret != EOK, fini, "Could not connect to configuration database."); + + ret = get_confdb_sections(ctx, ctx->confdb, &ctx->sections); + CHECK(ret != EOK, fini, "Could not get all configuration sections."); + + ret = set_debug_level(ctx, debug_to_set, config_file); + CHECK(ret != EOK, fini, "Could not set debug level."); + + ret = send_sighup(); + CHECK(ret != EOK, fini, + "Could not force sssd processes to reload configuration. " + "Is sssd running?"); + +fini: + poptFreeContext(pc); + talloc_free(ctx); + return ret; +} + +errno_t set_debug_level( + struct debuglevel_tool_ctx *tool_ctx, int debug_to_set, + const char *config_file +) +{ + int ret; + int err; + const char *values[2]; + char **section = NULL; + TALLOC_CTX *ctx = talloc_new(NULL); + + /* convert debug_to_set to string */ + values[0] = talloc_asprintf(ctx, "0x%.4x", debug_to_set); + if (values[0] == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Could not allocate memory for " + "debug_to_set to string conversion\n")); + ret = ENOMEM; + goto done; + } + values[1] = NULL; + + /* write to confdb */ + for (section = tool_ctx->sections; *section != NULL; section++) { + ret = confdb_add_param( + tool_ctx->confdb, 1, *section, + CONFDB_SERVICE_DEBUG_LEVEL, values + ); + if (ret != EOK) + goto done; + } + + /* + * Change atime and mtime of sssd.conf, + * so the configuration can be restored on next start. + */ + errno = 0; + if (utime(config_file, NULL) == -1 ) { + err = errno; + DEBUG(SSSDBG_MINOR_FAILURE, ("Unable to change mtime of \"%s\": %s\n", + config_file, strerror(err))); + } + + ret = EOK; + +done: + talloc_free(ctx); + return ret; +} + +errno_t send_sighup() +{ + int ret; + pid_t pid; + + ret = get_sssd_pid(&pid); + if (ret != EOK) { + return ret; + } + + if (kill(pid, SIGHUP) != 0) { + ret = errno; + DEBUG( + SSSDBG_CRIT_FAILURE, + ("Could not send SIGHUP to process %d: %s\n", pid, strerror(errno)) + ); + return errno; + } + + return EOK; +} + +errno_t connect_to_confdb(TALLOC_CTX *ctx, struct confdb_ctx **cdb_ctx) +{ + int ret; + char* confdb_path = NULL; + + confdb_path = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE); + if (confdb_path == NULL) { + DEBUG( + SSSDBG_CRIT_FAILURE, + ("Could not allocate memory for confdb path\n") + ); + return ENOMEM; + } + + ret = confdb_init(ctx, cdb_ctx, confdb_path); + if (ret != EOK) { + DEBUG( + SSSDBG_CRIT_FAILURE, + ("Could not initialize connection to the confdb\n") + ); + } + + talloc_free(confdb_path); + return ret; +} + +errno_t get_confdb_sections( + TALLOC_CTX *ctx, struct confdb_ctx *confdb, char ***output_sections +) +{ + int ret; + int domain_count = 0; + int i = 0; + struct sss_domain_info *domain = NULL; + struct sss_domain_info *domain_list = NULL; + char **sections; + const char *known_services[] = { + CONFDB_MONITOR_CONF_ENTRY, + CONFDB_NSS_CONF_ENTRY, + CONFDB_PAM_CONF_ENTRY + }; + static const int known_services_count = 3; + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + return ENOMEM; + } + + /* get domains */ + ret = confdb_get_domains(confdb, &domain_list); + if (ret != EOK) + DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to get domain list\n")); + + for (domain = domain_list; domain != NULL; domain = domain->next) + domain_count++; + + /* allocate output space */ + sections = talloc_array(ctx, char*, + domain_count + known_services_count + 1); + if (sections == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Could not allocate memory for sections\n")); + ret = ENOMEM; + goto fail; + } + + for (i = 0; i < known_services_count; i++) { + sections[i] = talloc_strdup(tmp_ctx, known_services[i]); + if (sections[i] == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strdup() failed\n")); + ret = ENOMEM; + goto fail; + } + } + + for (domain = domain_list; domain != NULL; domain = domain->next, i++) { + sections[i] = talloc_asprintf( + tmp_ctx, CONFDB_DOMAIN_PATH_TMPL, domain->name + ); + if (sections[i] == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_asprintf() failed\n")); + ret = ENOMEM; + goto fail; + } + } + + /* add NULL to the end */ + sections[i] = NULL; + + *output_sections = talloc_steal(ctx, sections); + + return EOK; +fail: + talloc_free(tmp_ctx); + return ret; +} + +errno_t get_sssd_pid(pid_t *out_pid) +{ + int ret; + FILE *pid_file = NULL; + char pid_str[MAX_PID_LENGTH] = {'\0'}; + + *out_pid = 0; + + errno = 0; + pid_file = fopen(SSSD_PIDFILE, "r"); + if (pid_file == NULL) { + ret = errno; + DEBUG(SSSDBG_MINOR_FAILURE, ("Unable to open pid file \"%s\": %s\n", + SSSD_PIDFILE, strerror(ret))); + goto done; + } + + ret = fread(pid_str, sizeof(char), MAX_PID_LENGTH * sizeof(char), pid_file); + if (!feof(pid_file)) { + /* eof not reached */ + ret = ferror(pid_file); + if (ret != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to read from file \"%s\": %s\n", + SSSD_PIDFILE, strerror(ret))); + } else { + DEBUG(SSSDBG_CRIT_FAILURE, ("File \"%s\" contains invalid pid.\n", + SSSD_PIDFILE)); + } + goto done; + } + + *out_pid = parse_pid(pid_str); + if (*out_pid == 0) { + DEBUG( + SSSDBG_CRIT_FAILURE, + ("File \"%s\" contains invalid pid.\n", SSSD_PIDFILE) + ); + return EINVAL; + } + + ret = EOK; + +done: + if (pid_file != NULL) + fclose(pid_file); + return ret; +} + +pid_t parse_pid(const char *strpid) +{ + long value; + char *endptr; + + errno = 0; + value = strtol(strpid, &endptr, 0); + if ((errno != 0) || (endptr == strpid) + || ((*endptr != '\0') && (*endptr != '\n'))) { + return 0; + } + + return value; +} + +int parse_debug_level(const char *strlevel) +{ + long value; + char *endptr; + + errno = 0; + value = strtol(strlevel, &endptr, 0); + if ((errno != 0) || (endptr == strlevel) || (*endptr != '\0')) + return SSSDBG_INVALID; + + return debug_convert_old_level(value); +} -- 1.7.6