diff options
Diffstat (limited to '')
-rw-r--r-- | src/tools/sssctl/sssctl.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c new file mode 100644 index 0000000..85d0d09 --- /dev/null +++ b/src/tools/sssctl/sssctl.c @@ -0,0 +1,354 @@ +/* + Authors: + Pavel Březina <pbrezina@redhat.com> + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <sys/wait.h> + +#include "util/util.h" +#include "tools/sssctl/sssctl.h" +#include "tools/common/sss_tools.h" +#include "tools/common/sss_process.h" + +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}; + int 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) { + ERROR("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; + } + + ERROR("Invalid input, please provide either " + "'%s' or '%s'.\n", yes, no); + + attempts++; + } while (attempts < 3); + + return SSSCTL_PROMPT_ERROR; +} + +errno_t sssctl_wrap_command(const char *command, + const char *subcommand, + struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + errno_t ret; + + if (subcommand != NULL) { + cmdline->argc++; + } + + const char **args = talloc_array_size(tool_ctx, + sizeof(char *), + cmdline->argc + 2); + if (!args) { + return ENOMEM; + } + + args[0] = command; + + if (subcommand != NULL) { + args[1] = subcommand; + memcpy(&args[2], cmdline->argv, sizeof(char *) * cmdline->argc); + } else { + memcpy(&args[1], cmdline->argv, sizeof(char *) * cmdline->argc); + } + + args[cmdline->argc + 1] = NULL; + + ret = sssctl_run_command(args); + + talloc_free(args); + + return ret; +} + +errno_t sssctl_run_command(const char *const argv[]) +{ + int ret; + int wstatus; + + DEBUG(SSSDBG_TRACE_FUNC, "Running '%s'\n", argv[0]); + + ret = fork(); + if (ret == -1) { + ERROR("Error while executing external command\n"); + return EFAULT; + } + + if (ret == 0) { + /* cast is safe - see + https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html + "The statement about argv[] and envp[] being constants ... " + */ + execvp(argv[0], discard_const_p(char * const, argv)); + ERROR("Error while executing external command\n"); + _exit(1); + } else { + if (waitpid(ret, &wstatus, 0) == -1) { + ERROR("Error while executing external command '%s'\n", argv[0]); + return EFAULT; + } else if (WEXITSTATUS(wstatus) != 0) { + ERROR("Command '%s' failed with [%d]\n", + argv[0], WEXITSTATUS(wstatus)); + return EIO; + } + } + + return EOK; +} + +static errno_t sssctl_manage_service(enum sssctl_svc_action action) +{ +#ifdef HAVE_SYSTEMD + switch (action) { + case SSSCTL_SVC_START: + return sssctl_systemd_start(); + case SSSCTL_SVC_STOP: + return sssctl_systemd_stop(); + case SSSCTL_SVC_RESTART: + return sssctl_systemd_restart(); + } +#elif defined(HAVE_SERVICE) + switch (action) { + case SSSCTL_SVC_START: + return sssctl_run_command( + (const char *[]){SERVICE_PATH, "sssd", "start", NULL}); + case SSSCTL_SVC_STOP: + return sssctl_run_command( + (const char *[]){SERVICE_PATH, "sssd", "stop", NULL}); + case SSSCTL_SVC_RESTART: + return sssctl_run_command( + (const char *[]){SERVICE_PATH, "sssd", "restart", NULL}); + } +#endif + + return ENOSYS; +} + +bool sssctl_start_sssd(bool force) +{ + enum sssctl_prompt_result prompt; + errno_t ret; + + if (sss_daemon_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_manage_service(SSSCTL_SVC_START); + switch(ret) { + case EOK: + return true; + case ENOSYS: + fprintf(stderr, "Starting SSSD automatically is not supported " + "on this platform, please start the service " + "manually\n"); + return false; + default: + 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_daemon_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_manage_service(SSSCTL_SVC_STOP); + switch(ret) { + case EOK: + return true; + case ENOSYS: + fprintf(stderr, "Stopping SSSD automatically is not supported " + "on this platform, please stop the service " + "manually\n"); + return false; + default: + 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_manage_service(SSSCTL_SVC_RESTART); + switch(ret) { + case EOK: + return true; + case ENOSYS: + fprintf(stderr, "Restarting SSSD automatically is not supported " + "on this platform, please restart the service " + "manually\n"); + return false; + default: + 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("domain-list", "List available domains", 0, sssctl_domain_list), + SSS_TOOL_COMMAND("domain-status", "Print information about domain", 0, sssctl_domain_status), + SSS_TOOL_COMMAND_FLAGS("user-checks", "Print information about a user and check authentication", 0, sssctl_user_checks, SSS_TOOL_FLAG_SKIP_CMD_INIT|SSS_TOOL_FLAG_SKIP_ROOT_CHECK), + SSS_TOOL_COMMAND("access-report", "Generate access report for a domain", 0, sssctl_access_report), + SSS_TOOL_DELIMITER("Information about cached content:"), + SSS_TOOL_COMMAND("user-show", "Information about cached user", 0, sssctl_user_show), + SSS_TOOL_COMMAND("group-show", "Information about cached group", 0, sssctl_group_show), + SSS_TOOL_COMMAND("netgroup-show", "Information about cached netgroup", 0, sssctl_netgroup_show), + SSS_TOOL_DELIMITER("Local data tools:"), + SSS_TOOL_COMMAND("client-data-backup", "Backup local data", 0, sssctl_client_data_backup), + SSS_TOOL_COMMAND("client-data-restore", "Restore local data from backup", 0, sssctl_client_data_restore), + SSS_TOOL_COMMAND("cache-remove", "Backup local data and remove cached content", 0, sssctl_cache_remove), + SSS_TOOL_COMMAND("cache-upgrade", "Perform cache upgrade", ERR_SYSDB_VERSION_TOO_OLD, sssctl_cache_upgrade), + SSS_TOOL_COMMAND("cache-expire", "Invalidate cached objects", 0, sssctl_cache_expire), + SSS_TOOL_COMMAND("cache-index", "Manage cache indexes", 0, sssctl_cache_index), + SSS_TOOL_DELIMITER("Log files tools:"), + SSS_TOOL_COMMAND("logs-remove", "Remove existing SSSD log files", 0, sssctl_logs_remove), + SSS_TOOL_COMMAND("logs-fetch", "Archive SSSD log files in tarball", 0, sssctl_logs_fetch), + SSS_TOOL_COMMAND("debug-level", "Change or print information about SSSD debug level", 0, sssctl_debug_level), + SSS_TOOL_COMMAND_FLAGS("analyze", "Analyze logged data", 0, sssctl_analyze, SSS_TOOL_FLAG_SKIP_CMD_INIT|SSS_TOOL_FLAG_SKIP_ROOT_CHECK), +#ifdef HAVE_LIBINI_CONFIG_V1_3 + SSS_TOOL_DELIMITER("Configuration files tools:"), + SSS_TOOL_COMMAND_FLAGS("config-check", "Perform static analysis of SSSD configuration", 0, sssctl_config_check, SSS_TOOL_FLAG_SKIP_CMD_INIT), +#endif + SSS_TOOL_DELIMITER("Certificate related tools:"), + SSS_TOOL_COMMAND_FLAGS("cert-show", "Print information about the certificate", 0, sssctl_cert_show, SSS_TOOL_FLAG_SKIP_CMD_INIT|SSS_TOOL_FLAG_SKIP_ROOT_CHECK), + SSS_TOOL_COMMAND("cert-map", "Show users mapped to the certificate", 0, sssctl_cert_map), + SSS_TOOL_COMMAND_FLAGS("cert-eval-rule", "Check mapping and matching rule with a certificate", 0, sssctl_cert_eval_rule, SSS_TOOL_FLAG_SKIP_CMD_INIT|SSS_TOOL_FLAG_SKIP_ROOT_CHECK), +#ifdef BUILD_PASSKEY + SSS_TOOL_DELIMITER("Passkey related tools:"), + SSS_TOOL_COMMAND_FLAGS("passkey-register", "Perform passkey registration", 0, sssctl_passkey_register, SSS_TOOL_FLAG_SKIP_CMD_INIT|SSS_TOOL_FLAG_SKIP_ROOT_CHECK), +#endif + SSS_TOOL_LAST + }; + + return sss_tool_main(argc, argv, commands, NULL); +} |