From 64d7121692e6b6ff171ea33acb808e4ff70a81ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= Date: Wed, 1 Jun 2016 13:38:22 +0200 Subject: [PATCH 25/27] sssctl: new tool --- Makefile.am | 21 ++ contrib/sssd.spec.in | 2 + src/external/systemd.m4 | 4 + src/tools/sssctl/sssctl.c | 236 +++++++++++++++ src/tools/sssctl/sssctl.h | 93 ++++++ src/tools/sssctl/sssctl_cache.c | 585 ++++++++++++++++++++++++++++++++++++++ src/tools/sssctl/sssctl_data.c | 239 ++++++++++++++++ src/tools/sssctl/sssctl_domains.c | 208 ++++++++++++++ src/tools/sssctl/sssctl_logs.c | 106 +++++++ src/tools/sssctl/sssctl_sifp.c | 118 ++++++++ 10 files changed, 1612 insertions(+) create mode 100644 src/tools/sssctl/sssctl.c create mode 100644 src/tools/sssctl/sssctl.h create mode 100644 src/tools/sssctl/sssctl_cache.c create mode 100644 src/tools/sssctl/sssctl_data.c create mode 100644 src/tools/sssctl/sssctl_domains.c create mode 100644 src/tools/sssctl/sssctl_logs.c create mode 100644 src/tools/sssctl/sssctl_sifp.c diff --git a/Makefile.am b/Makefile.am index b127a3c5696564d13fce14fb30bc497cbe30ea6b..6b8ea4d3f5b6132b0fef71747295afa9e56d6eaa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -130,6 +130,7 @@ sbin_PROGRAMS = \ sss_debuglevel \ sss_override \ sss_seed \ + sssctl \ $(NULL) sssdlibexec_PROGRAMS = \ @@ -727,6 +728,7 @@ dist_noinst_HEADERS = \ src/tools/common/sss_tools.h \ src/tools/common/sss_process.h \ src/tools/common/sss_colondb.h \ + src/tools/sssctl/sssctl.h \ src/util/probes.h \ $(NULL) @@ -1505,6 +1507,25 @@ sss_override_CFLAGS = \ $(AM_CFLAGS) \ $(NULL) +sssctl_SOURCES = \ + src/tools/sssctl/sssctl.c \ + src/tools/sssctl/sssctl_cache.c \ + src/tools/sssctl/sssctl_data.c \ + src/tools/sssctl/sssctl_logs.c \ + src/tools/sssctl/sssctl_domains.c \ + src/tools/sssctl/sssctl_sifp.c \ + $(SSSD_TOOLS_OBJ) \ + $(NULL) +sssctl_LDADD = \ + $(TOOLS_LIBS) \ + $(SSSD_INTERNAL_LTLIBS) \ + libsss_simpleifp.la \ + $(NULL) +sssctl_CFLAGS = \ + $(AM_CFLAGS) \ + -I$(top_srcdir)/src/lib/sifp + $(NULL) + if BUILD_SUDO sss_sudo_cli_SOURCES = \ src/sss_client/common.c \ diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index 68dc0afd95f6aadce9ad88ef54ea99a3c8ce7723..769a074848257e9e407d6e544496f6f14a6ea602 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -262,6 +262,7 @@ Also provides several other administrative tools: * sss_debuglevel to change the debug level on the fly * sss_seed which pre-creates a user entry for use in kickstarts * sss_obfuscate for generating an obfuscated LDAP password + * sssctl -- an sssd status and control utility %package -n python-sssdconfig Summary: SSSD and IPA configuration file manipulation classes and functions @@ -932,6 +933,7 @@ done %{_sbindir}/sss_override %{_sbindir}/sss_debuglevel %{_sbindir}/sss_seed +%{_sbindir}/sssctl %{_mandir}/man8/sss_groupadd.8* %{_mandir}/man8/sss_groupdel.8* %{_mandir}/man8/sss_groupmod.8* diff --git a/src/external/systemd.m4 b/src/external/systemd.m4 index 4c284459669a92838eaa9a8b5ff1ff1449915db8..87c93f50877d94f13f6007d1072cf08e2a2168e2 100644 --- a/src/external/systemd.m4 +++ b/src/external/systemd.m4 @@ -17,6 +17,10 @@ AS_IF([test x$HAVE_LIBSYSTEMD = xyes], [login_lib_name=libsystemd-login]) AM_COND_IF([HAVE_SYSTEMD], + [AC_DEFINE_UNQUOTED([HAVE_SYSTEMD], 1, [Build with libsystemd support])], + [AC_MSG_NOTICE([Build without libsystemd support])]) + +AM_COND_IF([HAVE_SYSTEMD], [PKG_CHECK_MODULES([SYSTEMD_LOGIN], [$login_lib_name], [AC_DEFINE_UNQUOTED([HAVE_SYSTEMD_LOGIN], 1, diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c new file mode 100644 index 0000000000000000000000000000000000000000..c10cc36191816e5323748b7e0039d88ca293b877 --- /dev/null +++ b/src/tools/sssctl/sssctl.c @@ -0,0 +1,236 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2016 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 "util/util.h" +#include "tools/sssctl/sssctl.h" +#include "tools/common/sss_tools.h" +#include "tools/common/sss_process.h" + +#ifdef HAVE_SYSTEMD_LOGIN + #define SSSD_SVC_CMD(cmd) "systemctl " cmd " sssd.service" +#else + #define SSSD_SVC_CMD(cmd) "service sssd " cmd +#endif + +static const char * +sssctl_prompt_str(enum sssctl_prompt_result result) +{ + switch (result) { + case SSSCTL_PROMPT_YES: + return _("yes"); + case SSSCTL_PROMPT_NO: + return _("no"); + case SSSCTL_PROMPT_ERROR: + return _("error"); + } + + return _("Invalid result."); +} + +enum sssctl_prompt_result +sssctl_prompt(const char *message, + enum sssctl_prompt_result defval) +{ + char answer[255] = {0}; + char c; + const char *yes = sssctl_prompt_str(SSSCTL_PROMPT_YES); + const char *no = sssctl_prompt_str(SSSCTL_PROMPT_NO); + int attempts = 0; + int ret; + + do { + if (defval != SSSCTL_PROMPT_ERROR) { + printf("%s (%s/%s) [%s] ", message, yes, no, + sssctl_prompt_str(defval)); + + /* Detect empty line. */ + c = getchar(); + if (c == '\n') { + return defval; + } else { + ungetc(c, stdin); + } + } else { + printf("%s (%s/%s)", message, yes, no); + } + + ret = scanf("%254s", answer); + + /* Clear stdin. */ + while ((c = getchar()) != '\n' && c != EOF); + + if (ret != 1) { + fprintf(stderr, _("Unable to read user input\n")); + return SSSCTL_PROMPT_ERROR; + } + + + if (strcasecmp(yes, answer) == 0) { + return SSSCTL_PROMPT_YES; + } + + if (strcasecmp(no, answer) == 0) { + return SSSCTL_PROMPT_NO; + } + + fprintf(stderr, _("Invalid input, please provide either " + "'%s' or '%s'.\n"), yes, no); + + attempts++; + } while (attempts < 3); + + return SSSCTL_PROMPT_ERROR; +} + +errno_t sssctl_run_command(const char *command) +{ + int ret; + + DEBUG(SSSDBG_TRACE_FUNC, "Running %s\n", command); + + ret = system(command); + if (ret == -1) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to execute %s\n", command); + fprintf(stderr, _("Error while executing external command\n")); + return EFAULT; + } else if (WEXITSTATUS(ret) != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Command %s failed with [%d]\n", + command, WEXITSTATUS(ret)); + fprintf(stderr, _("Error while executing external command\n")); + return EIO; + } + + return EOK; +} + +bool sssctl_start_sssd(bool force) +{ + enum sssctl_prompt_result prompt; + errno_t ret; + + if (sss_deamon_running()) { + return true; + } + + if (!force) { + prompt = sssctl_prompt(_("SSSD needs to be running. Start SSSD now?"), + SSSCTL_PROMPT_YES); + switch (prompt) { + case SSSCTL_PROMPT_YES: + /* continue */ + break; + case SSSCTL_PROMPT_NO: + case SSSCTL_PROMPT_ERROR: + return false; + } + } + + ret = sssctl_run_command(SSSD_SVC_CMD("start")); + if (ret != EOK) { + fprintf(stderr, "Unable to start SSSD!\n"); + return false; + } + + return true; +} + +bool sssctl_stop_sssd(bool force) +{ + enum sssctl_prompt_result prompt; + errno_t ret; + + if (!sss_deamon_running()) { + return true; + } + + if (!force) { + prompt = sssctl_prompt(_("SSSD must not be running. Stop SSSD now?"), + SSSCTL_PROMPT_YES); + switch (prompt) { + case SSSCTL_PROMPT_YES: + /* continue */ + break; + case SSSCTL_PROMPT_NO: + case SSSCTL_PROMPT_ERROR: + return false; + } + } + + ret = sssctl_run_command(SSSD_SVC_CMD("stop")); + if (ret != EOK) { + fprintf(stderr, "Unable to stop SSSD!\n"); + return false; + } + + return true; +} + +bool sssctl_restart_sssd(bool force) +{ + enum sssctl_prompt_result prompt; + errno_t ret; + + if (!force) { + prompt = sssctl_prompt(_("SSSD needs to be restarted. Restart SSSD now?"), + SSSCTL_PROMPT_YES); + switch (prompt) { + case SSSCTL_PROMPT_YES: + /* continue */ + break; + case SSSCTL_PROMPT_NO: + case SSSCTL_PROMPT_ERROR: + return false; + } + } + + ret = sssctl_run_command(SSSD_SVC_CMD("restart")); + if (ret != EOK) { + fprintf(stderr, "Unable to restart SSSD!\n"); + return false; + } + + return true; +} + +int main(int argc, const char **argv) +{ + struct sss_route_cmd commands[] = { + SSS_TOOL_DELIMITER("SSSD Status:"), + SSS_TOOL_COMMAND("list-domains", "List available domains", sssctl_list_domains), + SSS_TOOL_COMMAND("domain-status", "Print information about domain", sssctl_domain_status), + SSS_TOOL_DELIMITER("Information about cached content:"), + SSS_TOOL_COMMAND("user", "Information about cached user", sssctl_user), + SSS_TOOL_COMMAND("group", "Information about cached group", sssctl_group), + SSS_TOOL_COMMAND("netgroup", "Information about cached netgroup", sssctl_netgroup), + SSS_TOOL_DELIMITER("Local data tools:"), + SSS_TOOL_COMMAND("backup-local-data", "Backup local data", sssctl_backup_local_data), + SSS_TOOL_COMMAND("restore-local-data", "Restore local data from backup", sssctl_restore_local_data), + SSS_TOOL_COMMAND("remove-cache", "Backup local data and remove cached content", sssctl_remove_cache), + SSS_TOOL_DELIMITER("Log files tools:"), + SSS_TOOL_COMMAND("remove-logs", "Remove existing SSSD log files", sssctl_remove_logs), + SSS_TOOL_COMMAND("fetch-logs", "Archive SSSD log files in tarball", sssctl_fetch_logs), + {NULL, NULL, NULL} + }; + + return sss_tool_main(argc, argv, commands, NULL); +} diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h new file mode 100644 index 0000000000000000000000000000000000000000..5c7b8380a3986eb85895bbb80c1ba00504764381 --- /dev/null +++ b/src/tools/sssctl/sssctl.h @@ -0,0 +1,93 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2016 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 . +*/ + +#ifndef _SSSCTL_H_ +#define _SSSCTL_H_ + +#include "lib/sifp/sss_sifp.h" +#include "lib/sifp/sss_sifp_dbus.h" +#include "tools/common/sss_tools.h" + +enum sssctl_prompt_result { + SSSCTL_PROMPT_YES, + SSSCTL_PROMPT_NO, + SSSCTL_PROMPT_ERROR +}; + +enum sssctl_prompt_result +sssctl_prompt(const char *message, + enum sssctl_prompt_result defval); + +errno_t sssctl_run_command(const char *command); +bool sssctl_start_sssd(bool force); +bool sssctl_stop_sssd(bool force); +bool sssctl_restart_sssd(bool force); + +sss_sifp_error sssctl_sifp_init(struct sss_tool_ctx *tool_ctx, + sss_sifp_ctx **_sifp); + +void _sssctl_sifp_error(sss_sifp_ctx *sifp, + sss_sifp_error error, + const char *message); + +#define sssctl_sifp_error(sifp, error, message) \ + _sssctl_sifp_error(sifp, error, _(message)) + +errno_t sssctl_list_domains(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); + +errno_t sssctl_domain_status(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); + +errno_t sssctl_backup_local_data(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); + +errno_t sssctl_restore_local_data(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); + +errno_t sssctl_remove_cache(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); + +errno_t sssctl_remove_logs(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); + +errno_t sssctl_fetch_logs(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); + +errno_t sssctl_user(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); + +errno_t sssctl_group(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); + +errno_t sssctl_netgroup(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); + +#endif /* _SSSCTL_H_ */ diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c new file mode 100644 index 0000000000000000000000000000000000000000..02d91b1f11269cb1ac48d63c7d4dd390e2a3c466 --- /dev/null +++ b/src/tools/sssctl/sssctl_cache.c @@ -0,0 +1,585 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2016 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 "util/util.h" +#include "db/sysdb.h" +#include "tools/common/sss_tools.h" +#include "tools/sssctl/sssctl.h" + +#define NOT_FOUND_MSG(obj) _(obj " %s is not present in cache.\n") + +#define SSSCTL_CACHE_NAME {_("Name"), SYSDB_NAME, attr_string} +#define SSSCTL_CACHE_CREATE {_("Cache entry creation date"), SYSDB_CREATE_TIME, attr_time} +#define SSSCTL_CACHE_UPDATE {_("Cache entry last update time"), SYSDB_LAST_UPDATE, attr_time} +#define SSSCTL_CACHE_EXPIRE {_("Cache entry expiration time"), SYSDB_CACHE_EXPIRE, attr_expire} +#define SSSCTL_CACHE_IFP {_("Cached in InfoPipe"), SYSDB_IFP_CACHED, attr_yesno} +#define SSSCTL_CACHE_NULL {NULL, NULL, NULL} + +typedef errno_t (*sssctl_attr_fn)(TALLOC_CTX *mem_ctx, + struct sysdb_attrs *entry, + const char *attr, + const char **_value); + +typedef struct ldb_dn *(*sssctl_basedn_fn)(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain); + +struct sssctl_object_info { + const char *msg; + const char *attr; + sssctl_attr_fn attr_fn; +}; + +static errno_t time_to_string(TALLOC_CTX *mem_ctx, + time_t timestamp, + const char **_value) +{ + const char *value; + struct tm *tm; + char str[255]; + size_t ret; + + tm = gmtime(×tamp); + if (tm == NULL) { + return ENOMEM; + } + + ret = strftime(str, 255, "%x %X", tm); + if (ret == 0) { + return ERANGE; + } + + value = talloc_strdup(mem_ctx, str); + if (value == NULL) { + return ENOMEM; + } + + *_value = value; + + return EOK; +} + +static errno_t attr_string(TALLOC_CTX *mem_ctx, + struct sysdb_attrs *entry, + const char *attr, + const char **_value) +{ + return sysdb_attrs_get_string(entry, attr, _value); +} + +static errno_t attr_time(TALLOC_CTX *mem_ctx, + struct sysdb_attrs *entry, + const char *attr, + const char **_value) +{ + uint32_t value; + errno_t ret; + + ret = sysdb_attrs_get_uint32_t(entry, attr, &value); + if (ret != EOK) { + return ret; + } + + return time_to_string(mem_ctx, value, _value); +} + +static errno_t attr_expire(TALLOC_CTX *mem_ctx, + struct sysdb_attrs *entry, + const char *attr, + const char **_value) +{ + uint32_t value; + errno_t ret; + + ret = sysdb_attrs_get_uint32_t(entry, attr, &value); + if (ret != EOK) { + return ret; + } + + if (value < time(NULL)) { + *_value = "Expired"; + return EOK; + } + + return time_to_string(mem_ctx, value, _value); +} + +static errno_t attr_initgr(TALLOC_CTX *mem_ctx, + struct sysdb_attrs *entry, + const char *attr, + const char **_value) +{ + uint32_t value; + errno_t ret; + + ret = sysdb_attrs_get_uint32_t(entry, attr, &value); + if (ret == ENOENT) { + *_value = "Initgroups were not yet performed"; + return EOK; + } else if (ret != EOK) { + return ret; + } + + if (value < time(NULL)) { + *_value = "Expired"; + return EOK; + } + + return time_to_string(mem_ctx, value, _value); +} + +static errno_t attr_yesno(TALLOC_CTX *mem_ctx, + struct sysdb_attrs *entry, + const char *attr, + const char **_value) +{ + errno_t ret; + bool val; + + ret = sysdb_attrs_get_bool(entry, attr, &val); + if (ret == ENOENT) { + val = 0; + } else if (ret != EOK) { + return ret; + } + + *_value = val ? "Yes" : "No"; + + return EOK; +} + +static const char **sssctl_build_attrs(TALLOC_CTX *mem_ctx, + struct sssctl_object_info *info) +{ + const char **attrs; + size_t count; + int i; + + for (count = 0; info[count].attr != NULL; count++) { + /* no op */ + } + + attrs = talloc_zero_array(mem_ctx, const char *, count + 1); + if (attrs == NULL) { + return NULL; + } + + for (i = 0; i < count; i++) { + attrs[i] = talloc_strdup(attrs, info[i].attr); + if (attrs[i] == NULL) { + talloc_free(attrs); + return NULL; + } + } + + return attrs; +} + +static errno_t sssctl_query_cache(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *sysdb, + struct ldb_dn *base_dn, + const char *filter, + const char **attrs, + struct sysdb_attrs **_entry) +{ + TALLOC_CTX *tmp_ctx; + struct sysdb_attrs **sysdb_attrs; + struct ldb_message **msgs; + size_t count; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); + return ENOMEM; + } + + ret = sysdb_search_entry(tmp_ctx, sysdb, base_dn, LDB_SCOPE_SUBTREE, + filter, attrs, &count, &msgs); + if (ret == ENOENT) { + DEBUG(SSSDBG_TRACE_FUNC, "No result\n"); + goto done; + } else if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to search sysdb " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + + if (count != 1) { + DEBUG(SSSDBG_CRIT_FAILURE, "Search returned more than one result!\n"); + ret = ERR_INTERNAL; + goto done; + } + + ret = sysdb_msg2attrs(tmp_ctx, count, msgs, &sysdb_attrs); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to convert message to sysdb attrs " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + + *_entry = talloc_steal(mem_ctx, sysdb_attrs[0]); + +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t sssctl_find_object(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domains, + struct sss_domain_info *domain, + sssctl_basedn_fn basedn_fn, + const char *filter, + const char **attrs, + struct sysdb_attrs **_entry) +{ + TALLOC_CTX *tmp_ctx; + struct sss_domain_info *dom; + struct sysdb_attrs *entry; + struct ldb_dn *base_dn; + bool fqn_provided; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); + return ENOMEM; + } + + dom = domain == NULL ? domains : domain; + fqn_provided = domain == NULL ? false : true; + while (dom != NULL) { + if (!fqn_provided && dom->fqnames) { + dom = get_next_domain(dom, 0); + continue; + } + + base_dn = basedn_fn(tmp_ctx, dom); + if (base_dn == NULL) { + ret = ENOMEM; + goto done; + } + + ret = sssctl_query_cache(tmp_ctx, dom->sysdb, base_dn, filter, + attrs, &entry); + if (ret == EOK) { + /* Entry was found. */ + *_entry = talloc_steal(mem_ctx, entry); + goto done; + } else if (ret == ENOENT && fqn_provided) { + /* Not found but a domain was provided in input. We're done. */ + goto done; + } else if (ret != ENOENT) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to query cache [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + + dom = get_next_domain(dom, 0); + } + + ret = ENOENT; + +done: + talloc_free(tmp_ctx); + + return ret; +} + +static errno_t sssctl_fetch_object(TALLOC_CTX *mem_ctx, + struct sssctl_object_info *info, + struct sss_domain_info *domains, + struct sss_domain_info *domain, + sssctl_basedn_fn basedn_fn, + const char *class, + const char *attr_name, + const char *attr_value, + struct sysdb_attrs **_entry) +{ + TALLOC_CTX *tmp_ctx; + struct sysdb_attrs *entry; + const char *filter; + const char **attrs; + char *sanitized; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); + return ENOMEM; + } + + ret = sss_filter_sanitize(tmp_ctx, attr_value, &sanitized); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to sanitize input [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + + filter = talloc_asprintf(tmp_ctx, "(&(objectClass=%s)(%s=%s))", + class, attr_name, sanitized); + if (filter == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n"); + goto done; + } + + attrs = sssctl_build_attrs(tmp_ctx, info); + if (attrs == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get attribute list!\n"); + ret = ENOMEM; + goto done; + } + + ret = sssctl_find_object(tmp_ctx, domains, domain, basedn_fn, + filter, attrs, &entry); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to query cache [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + + *_entry = talloc_steal(mem_ctx, entry); + +done: + talloc_free(tmp_ctx); + + return ret; +} + +static errno_t sssctl_print_object(struct sssctl_object_info *info, + struct sss_domain_info *domains, + struct sss_domain_info *domain, + sssctl_basedn_fn basedn_fn, + const char *noent_fmt, + const char *class, + const char *attr_name, + const char *attr_value) +{ + TALLOC_CTX *tmp_ctx; + struct sysdb_attrs *entry; + const char *value; + errno_t ret; + int i; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); + return ENOMEM; + } + + ret = sssctl_fetch_object(tmp_ctx, info, domains, domain, basedn_fn, + class, attr_name, attr_value, &entry); + if (ret == ENOENT) { + printf(noent_fmt, attr_value); + ret = EOK; + goto done; + } else if (ret != EOK) { + fprintf(stderr, _("Error: Unable to get object [%d]: %s\n"), + ret, sss_strerror(ret)); + goto done; + } + + for (i = 0; info[i].attr != NULL; i++) { + ret = info[i].attr_fn(tmp_ctx, entry, info[i].attr, &value); + if (ret == ENOENT) { + continue; + } else if (ret != EOK) { + fprintf(stderr, _("%s: Unable to read value [%d]: %s\n"), + info[i].msg, ret, sss_strerror(ret)); + continue; + } + + printf("%s: %s\n", info[i].msg, value); + } + + ret = EOK; + +done: + talloc_free(tmp_ctx); + + return ret; +} + +static errno_t parse_cmdline(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + struct poptOption *options, + const char **_orig_name, + struct sss_domain_info **_domain) +{ + const char *input_name; + const char *orig_name; + struct sss_domain_info *domain; + int ret; + + ret = sss_tool_popt_ex(cmdline, options, SSS_TOOL_OPT_OPTIONAL, + NULL, NULL, "NAME", _("Specify name."), + &input_name, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); + return ret; + } + + ret = sss_tool_parse_name(tool_ctx, tool_ctx, input_name, + &orig_name, &domain); + if (ret != EOK) { + fprintf(stderr, _("Unable to parse name %s.\n"), input_name); + return ret; + } + + *_orig_name = orig_name; + *_domain = domain; + + return EOK; +} + +struct sssctl_cache_opts { + struct sss_domain_info *domain; + const char *value; + int sid; + int id; +}; + +errno_t sssctl_user(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + struct sssctl_cache_opts opts = {0}; + const char *attr; + errno_t ret; + + struct poptOption options[] = { + {"sid", 's', POPT_ARG_NONE , &opts.sid, 0, _("Search by SID"), NULL }, + {"uid", 'u', POPT_ARG_NONE, &opts.id, 0, _("Search by user ID"), NULL }, + POPT_TABLEEND + }; + + struct sssctl_object_info info[] = { + SSSCTL_CACHE_NAME, + SSSCTL_CACHE_CREATE, + SSSCTL_CACHE_UPDATE, + SSSCTL_CACHE_EXPIRE, + {_("Initgroups expiration time"), SYSDB_INITGR_EXPIRE, attr_initgr}, + SSSCTL_CACHE_IFP, + SSSCTL_CACHE_NULL + }; + + ret = parse_cmdline(cmdline, tool_ctx, options, &opts.value, &opts.domain); + if (ret != EOK) { + return ret; + } + + attr = SYSDB_NAME; + if (opts.sid) { + attr = SYSDB_SID; + } else if (opts.id) { + attr = SYSDB_UIDNUM; + } + + ret = sssctl_print_object(info, tool_ctx->domains, opts.domain, + sysdb_user_base_dn, NOT_FOUND_MSG("User"), + SYSDB_USER_CLASS, attr, opts.value); + if (ret != EOK) { + return ret; + } + + + return EOK; +} + +errno_t sssctl_group(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + struct sssctl_cache_opts opts = {0}; + const char *attr; + errno_t ret; + + struct poptOption options[] = { + {"sid", 's', POPT_ARG_NONE , &opts.sid, 0, _("Search by SID"), NULL }, + {"gid", 'g', POPT_ARG_NONE, &opts.id, 0, _("Search by group ID"), NULL }, + POPT_TABLEEND + }; + + struct sssctl_object_info info[] = { + SSSCTL_CACHE_NAME, + SSSCTL_CACHE_CREATE, + SSSCTL_CACHE_UPDATE, + SSSCTL_CACHE_EXPIRE, + SSSCTL_CACHE_IFP, + SSSCTL_CACHE_NULL + }; + + ret = parse_cmdline(cmdline, tool_ctx, options, &opts.value, &opts.domain); + if (ret != EOK) { + return ret; + } + + attr = SYSDB_NAME; + if (opts.sid) { + attr = SYSDB_SID; + } else if (opts.id) { + attr = SYSDB_GIDNUM; + } + + ret = sssctl_print_object(info, tool_ctx->domains, opts.domain, + sysdb_group_base_dn, NOT_FOUND_MSG("Group"), + SYSDB_GROUP_CLASS, attr, opts.value); + if (ret != EOK) { + return ret; + } + + + return EOK; +} + +errno_t sssctl_netgroup(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + struct sssctl_cache_opts opts = {0}; + errno_t ret; + + struct sssctl_object_info info[] = { + SSSCTL_CACHE_NAME, + SSSCTL_CACHE_CREATE, + SSSCTL_CACHE_UPDATE, + SSSCTL_CACHE_EXPIRE, + SSSCTL_CACHE_NULL + }; + + ret = parse_cmdline(cmdline, tool_ctx, NULL, &opts.value, &opts.domain); + if (ret != EOK) { + return ret; + } + + ret = sssctl_print_object(info, tool_ctx->domains, opts.domain, + sysdb_netgroup_base_dn, NOT_FOUND_MSG("Netgroup"), + SYSDB_NETGROUP_CLASS, SYSDB_NAME, opts.value); + if (ret != EOK) { + return ret; + } + + + return EOK; +} diff --git a/src/tools/sssctl/sssctl_data.c b/src/tools/sssctl/sssctl_data.c new file mode 100644 index 0000000000000000000000000000000000000000..31b7984a5cc664c7655bddb0d949b74a7a75e392 --- /dev/null +++ b/src/tools/sssctl/sssctl_data.c @@ -0,0 +1,239 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2016 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 "util/util.h" +#include "tools/common/sss_tools.h" +#include "tools/sssctl/sssctl.h" + +#define CACHE_FILE(db) " " DB_PATH "/" db +#define CACHE_FILES CACHE_FILE("*.ldb") + +#define SSS_BACKUP_DIR SSS_STATEDIR "/backup" +#define SSS_BACKUP_USER_OVERRIDES SSS_BACKUP_DIR "/sssd_user_overrides.bak" +#define SSS_BACKUP_GROUP_OVERRIDES SSS_BACKUP_DIR "/sssd_group_overrides.bak" + +struct sssctl_data_opts { + int override; + int start; + int stop; + int restart; +}; + +static errno_t sssctl_create_backup_dir(const char *path) +{ + mode_t old_umask; + errno_t ret; + + old_umask = umask(SSS_DFL_X_UMASK); + ret = mkdir(path, 0700); + umask(old_umask); + if (ret != EOK && errno != EEXIST) { + ret = errno; + DEBUG(SSSDBG_MINOR_FAILURE, "Unable to create backup directory " + "[%d]: %s\n", ret, sss_strerror(ret)); + return ret; + } + + return EOK; +} + +static bool sssctl_backup_file_exists(const char *file) +{ + return access(file, F_OK) == 0; +} + +static bool sssctl_backup_exist(const char **files) +{ + int i; + + for (i = 0; files[i] != NULL; i++) { + if (sssctl_backup_file_exists(files[i])) { + return true; + } + } + + return false; +} + +static errno_t sssctl_backup(bool force) +{ + const char *files[] = {SSS_BACKUP_USER_OVERRIDES, + SSS_BACKUP_GROUP_OVERRIDES, + NULL}; + enum sssctl_prompt_result prompt; + errno_t ret; + + ret = sssctl_create_backup_dir(SSS_BACKUP_DIR); + if (ret != EOK) { + fprintf(stderr, _("Unable to create backup directory [%d]: %s"), + ret, sss_strerror(ret)); + return ret; + } + + if (sssctl_backup_exist(files) && !force) { + prompt = sssctl_prompt(_("SSSD backup of local data already exist, " + "override?"), SSSCTL_PROMPT_NO); + switch (prompt) { + case SSSCTL_PROMPT_YES: + /* continue */ + break; + case SSSCTL_PROMPT_NO: + return EEXIST; + case SSSCTL_PROMPT_ERROR: + return EIO; + } + } + + ret = sssctl_run_command("sss_override user-export " + SSS_BACKUP_USER_OVERRIDES); + if (ret != EOK) { + fprintf(stderr, _("Unable to export user overrides\n")); + return ret; + } + + ret = sssctl_run_command("sss_override group-export " + SSS_BACKUP_GROUP_OVERRIDES); + if (ret != EOK) { + fprintf(stderr, _("Unable to export group overrides\n")); + return ret; + } + + return ret; +} + +errno_t sssctl_backup_local_data(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + struct sssctl_data_opts opts = {0}; + errno_t ret; + + /* Parse command line. */ + struct poptOption options[] = { + {"override", 'o', POPT_ARG_NONE, &opts.override, 0, _("Override existing backup"), NULL }, + POPT_TABLEEND + }; + + ret = sss_tool_popt(cmdline, options, SSS_TOOL_OPT_OPTIONAL, NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); + return ret; + } + + ret = sssctl_backup(opts.override); + if (ret == EEXIST) { + return EOK; + } + + return ret; +} + +errno_t sssctl_restore_local_data(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + struct sssctl_data_opts opts = {0}; + errno_t ret; + + /* Parse command line. */ + struct poptOption options[] = { + {"start", 's', POPT_ARG_NONE, &opts.start, 0, _("Start SSSD if it is not running"), NULL }, + {"restart", 'r', POPT_ARG_NONE, &opts.restart, 0, _("Restart SSSD after data import"), NULL }, + POPT_TABLEEND + }; + + ret = sss_tool_popt(cmdline, options, SSS_TOOL_OPT_OPTIONAL, NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); + return ret; + } + + if (!sssctl_start_sssd(opts.start)) { + return ERR_SSSD_NOT_RUNNING; + } + + + if (sssctl_backup_file_exists(SSS_BACKUP_USER_OVERRIDES)) { + ret = sssctl_run_command("sss_override user-import " + SSS_BACKUP_USER_OVERRIDES); + if (ret != EOK) { + fprintf(stderr, _("Unable to import user overrides\n")); + return ret; + } + } + + if (sssctl_backup_file_exists(SSS_BACKUP_USER_OVERRIDES)) { + ret = sssctl_run_command("sss_override group-import " + SSS_BACKUP_GROUP_OVERRIDES); + if (ret != EOK) { + fprintf(stderr, _("Unable to import group overrides\n")); + return ret; + } + } + + sssctl_restart_sssd(opts.restart); + + return ret; +} + +errno_t sssctl_remove_cache(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + struct sssctl_data_opts opts = {0}; + errno_t ret; + + /* Parse command line. */ + struct poptOption options[] = { + {"override", 'o', POPT_ARG_NONE, &opts.override, 0, _("Override existing backup"), NULL }, + {"stop", 's', POPT_ARG_NONE, &opts.stop, 0, _("Stop SSSD if it is running"), NULL }, + POPT_TABLEEND + }; + + ret = sss_tool_popt(cmdline, options, SSS_TOOL_OPT_OPTIONAL, NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); + return ret; + } + + if (!sssctl_stop_sssd(opts.stop)) { + return ERR_SSSD_RUNNING; + } + + printf(_("Creating backup of local data...\n")); + ret = sssctl_backup(opts.override); + if (ret != EOK) { + fprintf(stderr, _("Unable to create backup of local data," + " can not remove the cache.\n")); + return ret; + } + + printf(_("Removing cache files...\n")); + ret = sssctl_run_command("rm -f " CACHE_FILES); + if (ret != EOK) { + fprintf(stderr, _("Unable to remove cache files\n")); + return ret; + } + + return EOK; +} diff --git a/src/tools/sssctl/sssctl_domains.c b/src/tools/sssctl/sssctl_domains.c new file mode 100644 index 0000000000000000000000000000000000000000..51eeb48b444697b0a9447c1f1412ca24d767b29d --- /dev/null +++ b/src/tools/sssctl/sssctl_domains.c @@ -0,0 +1,208 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2016 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 "util/util.h" +#include "tools/common/sss_tools.h" +#include "tools/sssctl/sssctl.h" +#include "sbus/sssd_dbus.h" +#include "responder/ifp/ifp_iface.h" + +errno_t sssctl_list_domains(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + sss_sifp_ctx *sifp; + sss_sifp_error error; + char **domains; + int start = 0; + errno_t ret; + int i; + + /* Parse command line. */ + struct poptOption options[] = { + {"start", 's', POPT_ARG_NONE, &start, 0, _("Start SSSD if it is not running"), NULL }, + POPT_TABLEEND + }; + + ret = sss_tool_popt(cmdline, options, SSS_TOOL_OPT_OPTIONAL, NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); + return ret; + } + + if (!sssctl_start_sssd(start)) { + return ERR_SSSD_NOT_RUNNING; + } + + error = sssctl_sifp_init(tool_ctx, &sifp); + if (error != SSS_SIFP_OK) { + sssctl_sifp_error(sifp, error, "Unable to connect to the InfoPipe"); + return EFAULT; + } + + error = sss_sifp_list_domains(sifp, &domains); + if (error != SSS_SIFP_OK) { + sssctl_sifp_error(sifp, error, "Unable to get domains list"); + return EIO; + } + + for (i = 0; domains[i] != NULL; i++) { + puts(domains[i]); + } + + return EOK; +} + +static errno_t sssctl_domain_status_online(struct sss_tool_ctx *tool_ctx, + const char *domain_path, + bool force_start) +{ + sss_sifp_ctx *sifp; + sss_sifp_error sifp_error; + DBusError dbus_error; + DBusMessage *reply = NULL; + DBusMessage *msg = NULL; + bool is_online; + dbus_bool_t dbret; + errno_t ret; + + dbus_error_init(&dbus_error); + + if (!sssctl_start_sssd(force_start)) { + ret = ERR_SSSD_NOT_RUNNING; + goto done; + } + + sifp_error = sssctl_sifp_init(tool_ctx, &sifp); + if (sifp_error != SSS_SIFP_OK) { + sssctl_sifp_error(sifp, sifp_error, "Unable to connect to the InfoPipe"); + ret = EFAULT; + goto done; + } + + + msg = sss_sifp_create_message(domain_path, IFACE_IFP_DOMAINS_DOMAIN, + IFACE_IFP_DOMAINS_DOMAIN_ISONLINE); + if (msg == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create D-Bus message\n"); + goto done; + } + + + sifp_error = sss_sifp_send_message(sifp, msg, &reply); + if (sifp_error != SSS_SIFP_OK) { + sssctl_sifp_error(sifp, sifp_error, "Unable to get online status"); + ret = EIO; + goto done; + } + + dbret = dbus_message_get_args(reply, &dbus_error, + DBUS_TYPE_BOOLEAN, &is_online, + DBUS_TYPE_INVALID); + if (!dbret) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse D-Bus reply\n"); + if (dbus_error_is_set(&dbus_error)) { + DEBUG(SSSDBG_CRIT_FAILURE, "%s: %s\n", + dbus_error.name, dbus_error.message); + } + ret = EIO; + goto done; + } + + printf(_("Online status: %s\n"), is_online ? _("Online") : _("Offline")); + + ret = EOK; + +done: + if (msg != NULL) { + dbus_message_unref(msg); + } + + if (reply != NULL) { + dbus_message_unref(reply); + } + + dbus_error_free(&dbus_error); + + return ret; +} + +struct sssctl_domain_status_opts { + const char *domain; + int online; + int last; + int active; + int servers; + int force_start; +}; + +errno_t sssctl_domain_status(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + struct sssctl_domain_status_opts opts = {0}; + const char *path; + bool opt_set; + errno_t ret; + + /* Parse command line. */ + struct poptOption options[] = { + {"online", 'o', POPT_ARG_NONE , &opts.online, 0, _("Show online status"), NULL }, + /* + {"last-requests", 'l', POPT_ARG_NONE, &opts.last, 0, _("Show last requests that went to data provider"), NULL }, + {"active-server", 'a', POPT_ARG_NONE, &opts.active, 0, _("Show information about active server"), NULL }, + {"servers", 'r', POPT_ARG_NONE, &opts.servers, 0, _("Show list of discovered servers"), NULL }, + */ + {"start", 's', POPT_ARG_NONE, &opts.force_start, 0, _("Start SSSD if it is not running"), NULL }, + POPT_TABLEEND + }; + + ret = sss_tool_popt_ex(cmdline, options, SSS_TOOL_OPT_OPTIONAL, + NULL, NULL, "DOMAIN", _("Specify domain name."), + &opts.domain, &opt_set); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); + return ret; + } + + if (opt_set == false) { + opts.online = true; + opts.last = true; + opts.active = true; + opts.servers = true; + } + + path = sbus_opath_compose(tool_ctx, IFP_PATH_DOMAINS, opts.domain); + if (path == NULL) { + printf(_("Out of memory!\n")); + return ENOMEM; + } + + ret = sssctl_domain_status_online(tool_ctx, path, opts.force_start); + if (ret != EOK) { + fprintf(stderr, _("Unable to get online status\n")); + return ret; + } + + return EOK; +} diff --git a/src/tools/sssctl/sssctl_logs.c b/src/tools/sssctl/sssctl_logs.c new file mode 100644 index 0000000000000000000000000000000000000000..a203474648e3c1719e16146f8f7b484f9d62541c --- /dev/null +++ b/src/tools/sssctl/sssctl_logs.c @@ -0,0 +1,106 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2016 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 "util/util.h" +#include "tools/common/sss_tools.h" +#include "tools/common/sss_process.h" +#include "tools/sssctl/sssctl.h" + +#define LOG_FILE(file) " " LOG_PATH "/" file +#define LOG_FILES LOG_FILE("*.log") + +struct sssctl_logs_opts { + int delete; + int archived; +}; + +errno_t sssctl_remove_logs(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + struct sssctl_logs_opts opts = {0}; + errno_t ret; + + /* Parse command line. */ + struct poptOption options[] = { + {"delete", 'd', POPT_ARG_NONE, &opts.delete, 0, _("Delete log files instead of truncating"), NULL }, + POPT_TABLEEND + }; + + ret = sss_tool_popt(cmdline, options, SSS_TOOL_OPT_OPTIONAL, NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); + return ret; + } + + if (opts.delete) { + printf(_("Deleting log files...\n")); + ret = sssctl_run_command("rm -f " LOG_FILES); + if (ret != EOK) { + fprintf(stderr, _("Unable to remove log files\n")); + return ret; + } + + sss_signal(SIGHUP); + } else { + printf(_("Truncating log files...\n")); + ret = sssctl_run_command("truncate --size 0 " LOG_FILES); + if (ret != EOK) { + fprintf(stderr, _("Unable to truncate log files\n")); + return ret; + } + } + + return EOK; +} + +errno_t sssctl_fetch_logs(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + const char *file; + const char *cmd; + errno_t ret; + + /* Parse command line. */ + ret = sss_tool_popt_ex(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL, NULL, NULL, + "FILE", "Output file", &file, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); + return ret; + } + + cmd = talloc_asprintf(tool_ctx, "tar -czf %s %s", file, LOG_FILES); + if (cmd == NULL) { + fprintf(stderr, _("Out of memory!")); + } + + printf(_("Archiving log files into %s...\n"), file); + ret = sssctl_run_command(cmd); + if (ret != EOK) { + fprintf(stderr, _("Unable to archive log files\n")); + return ret; + } + + return EOK; +} diff --git a/src/tools/sssctl/sssctl_sifp.c b/src/tools/sssctl/sssctl_sifp.c new file mode 100644 index 0000000000000000000000000000000000000000..e541c4b27ba38e50b209b0957c8b38f03afc891a --- /dev/null +++ b/src/tools/sssctl/sssctl_sifp.c @@ -0,0 +1,118 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2016 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 "util/util.h" +#include "tools/sssctl/sssctl.h" + +#define ERR_SSSD _("Check that SSSD is running and " \ + "the InfoPipe responder is enabled.\n") + +struct sssctl_sifp_data { + sss_sifp_ctx *sifp; +}; + +static int sssctl_sifp_data_destructor(struct sssctl_sifp_data *ctx) +{ + if (ctx->sifp != NULL) { + sss_sifp_free(&ctx->sifp); + } + + return 0; +} + +static void *sssctl_sifp_talloc(size_t size, void *pvt) +{ + return talloc_size(pvt, size); +} + +static void sssctl_sifp_talloc_free(void *ptr, void *pvt) +{ + talloc_free(ptr); +} + +sss_sifp_error sssctl_sifp_init(struct sss_tool_ctx *tool_ctx, + sss_sifp_ctx **_sifp) +{ + struct sssctl_sifp_data *sifp_data; + sss_sifp_error error; + + sifp_data = talloc_zero(tool_ctx, struct sssctl_sifp_data); + if (sifp_data == NULL) { + return SSS_SIFP_OUT_OF_MEMORY; + } + + error = sss_sifp_init_ex(sifp_data, sssctl_sifp_talloc, + sssctl_sifp_talloc_free, &sifp_data->sifp); + if (error != SSS_SIFP_OK) { + *_sifp = sifp_data->sifp; + return error; + } + + talloc_set_destructor(sifp_data, sssctl_sifp_data_destructor); + *_sifp = sifp_data->sifp; + + return SSS_SIFP_OK; +} + +void _sssctl_sifp_error(sss_sifp_ctx *sifp, + sss_sifp_error error, + const char *message) +{ + const char *dbus_code; + const char *dbus_msg; + const char *sifp_msg; + + sifp_msg = sss_sifp_strerr(error); + + switch (error) { + case SSS_SIFP_OK: + break; + case SSS_SIFP_IO_ERROR: + dbus_code = sss_sifp_get_last_io_error_name(sifp); + dbus_msg = sss_sifp_get_last_io_error_message(sifp); + + fprintf(stderr, "%s [%d]: %s\n", message, error, sifp_msg); + fprintf(stderr, "%s: %s\n", dbus_code, dbus_msg); + + if (strcmp(dbus_code, DBUS_ERROR_SERVICE_UNKNOWN) == 0) { + fprintf(stderr, ERR_SSSD); + break; + } + + if (strcmp(dbus_code, DBUS_ERROR_SPAWN_CHILD_EXITED) == 0) { + fprintf(stderr, ERR_SSSD); + break; + } + + if (strcmp(dbus_code, DBUS_ERROR_NO_REPLY) == 0) { + fprintf(stderr, ERR_SSSD); + break; + } + + break; + default: + fprintf(stderr, "%s [%d]: %s\n", message, error, sifp_msg); + break; + } +} -- 2.4.11