/* 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/common/sss_tools.h" #include "tools/sssctl/sssctl.h" #include "sbus/sbus_opath.h" #include "responder/ifp/ifp_iface/ifp_iface_sync.h" static errno_t sssctl_domain_list_get_properties(TALLOC_CTX *mem_ctx, struct sbus_sync_connection *conn, const char *path, const char **_name, bool *_is_subdom) { errno_t ret; if (_name != NULL) { ret = sbus_get_ifp_domains_name(mem_ctx, conn, IFP_BUS, path, _name); if (ret != EOK) { goto done; } } if (_is_subdom != NULL) { ret = sbus_get_ifp_domains_subdomain(conn, IFP_BUS, path, _is_subdom); if (ret != EOK) { goto done; } } ret = EOK; done: if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get domain property [%d]: %s\n", ret, sss_strerror(ret)); PRINT_IFP_WARNING(ret); } return ret; } errno_t sssctl_domain_list(struct sss_cmdline *cmdline, struct sss_tool_ctx *tool_ctx, void *pvt) { TALLOC_CTX *tmp_ctx; struct sbus_sync_connection *conn; const char **paths; const char *name; bool is_subdom; int start = 0; int verbose = 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 }, {"verbose", 'v', POPT_ARG_NONE, &verbose, 0, _("Show domain list including primary or trusted domain type"), 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; } tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n"); return ENOMEM; } conn = sbus_sync_connect_system(tmp_ctx, NULL); if (conn == NULL) { ERROR("Unable to connect to system bus!\n"); ret = EIO; goto done; } ret = sbus_call_ifp_ListDomains(tmp_ctx, conn, IFP_BUS, IFP_PATH, &paths); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to list domains [%d]: %s\n", ret, sss_strerror(ret)); PRINT_IFP_WARNING(ret); goto done; } if (verbose) { for (i = 0; paths[i] != NULL; i++) { ret = sssctl_domain_list_get_properties(tmp_ctx, conn, paths[i], &name, &is_subdom); if (ret != EOK) { goto done; } if (is_subdom) { printf("Trusted domain: %s\n", name); } else { printf("Primary domain: %s\n", name); } } return EOK; } for (i = 0; paths[i] != NULL; i++) { ret = sssctl_domain_list_get_properties(tmp_ctx, conn, paths[i], &name, NULL); if (ret != EOK) { goto done; } puts(name); } done: talloc_free(tmp_ctx); return ret; } static errno_t sssctl_domain_status_online(struct sbus_sync_connection *conn, const char *domain_path) { bool is_online; errno_t ret; ret = sbus_call_ifp_domain_IsOnline(conn, IFP_BUS, domain_path, &is_online); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get domain status [%d]: %s\n", ret, sss_strerror(ret)); PRINT_IFP_WARNING(ret); return ret; } PRINT("Online status: %s\n", is_online ? _("Online") : _("Offline")); return EOK; } static const char *proper_service_name(const char *service) { if (strcasecmp(service, "AD_GC") == 0) { return "AD Global Catalog"; } else if (strcasecmp(service, "AD") == 0) { return "AD Domain Controller"; } else if (strncasecmp(service, "sd_gc_", strlen("sd_gc_")) == 0) { return "AD Global Catalog"; } else if (strncasecmp(service, "sd_", strlen("sd_")) == 0) { return "AD Domain Controller"; } return service; } static errno_t sssctl_domain_status_active_server(struct sbus_sync_connection *conn, const char *domain_path) { TALLOC_CTX *tmp_ctx; const char *server; const char **services; 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 = sbus_call_ifp_domain_ListServices(tmp_ctx, conn, IFP_BUS, domain_path, &services); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get domain services [%d]: %s\n", ret, sss_strerror(ret)); PRINT_IFP_WARNING(ret); goto done; } if (services == NULL) { PRINT("This domain has no active servers.\n"); ret = EOK; goto done; } PRINT("Active servers:\n"); for (i = 0; services[i] != NULL; i++) { ret = sbus_call_ifp_domain_ActiveServer(tmp_ctx, conn, IFP_BUS, domain_path, services[i], &server); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get active server [%d]: %s\n", ret, sss_strerror(ret)); PRINT_IFP_WARNING(ret); goto done; } /* SBUS_REQ_STRING_DEFAULT handles (server == NULL) case gracefully */ server = SBUS_REQ_STRING_DEFAULT(server, _("not connected")); printf("%s: %s\n", proper_service_name(services[i]), server); } ret = EOK; done: talloc_free(tmp_ctx); return ret; } static errno_t sssctl_domain_status_server_list(struct sbus_sync_connection *conn, const char *domain_path) { TALLOC_CTX *tmp_ctx; const char **servers; const char **services; errno_t ret; int i, j; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); return ENOMEM; } ret = sbus_call_ifp_domain_ListServices(tmp_ctx, conn, IFP_BUS, domain_path, &services); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get domain services [%d]: %s\n", ret, sss_strerror(ret)); PRINT_IFP_WARNING(ret); goto done; } if (services == NULL) { PRINT("No servers discovered.\n"); ret = EOK; goto done; } for (i = 0; services[i] != NULL; i++) { PRINT("Discovered %s servers:\n", proper_service_name(services[i])); ret = sbus_call_ifp_domain_ListServers(tmp_ctx, conn, IFP_BUS, domain_path, services[i], &servers); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get domain servers [%d]: %s\n", ret, sss_strerror(ret)); PRINT_IFP_WARNING(ret); goto done; } if (servers == NULL || servers[0] == NULL) { PRINT("None so far.\n"); continue; } for (j = 0; servers[j] != NULL; j++) { printf("- %s\n", servers[j]); } printf("\n"); } ret = EOK; done: talloc_free(tmp_ctx); 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) { TALLOC_CTX *tmp_ctx = NULL; struct sssctl_domain_status_opts opts = {0}; struct sbus_sync_connection *conn; 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 }, {"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."), SSS_TOOL_OPT_REQUIRED, &opts.domain, &opt_set); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); goto done; } if (opt_set == false) { opts.online = true; opts.last = true; opts.active = true; opts.servers = true; } tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n"); ret = ENOMEM; goto done; } path = sbus_opath_compose(tmp_ctx, IFP_PATH_DOMAINS, opts.domain); if (path == NULL) { PRINT("Out of memory!\n"); ret = ENOMEM; goto done; } if (!sssctl_start_sssd(opts.force_start)) { ret = ERR_SSSD_NOT_RUNNING; goto done; } conn = sbus_sync_connect_system(tmp_ctx, NULL); if (conn == NULL) { ERROR("Unable to connect to system bus!\n"); ret = EIO; goto done; } if (opts.online) { ret = sssctl_domain_status_online(conn, path); if (ret != EOK) { ERROR("Unable to get online status\n"); goto done; } printf("\n"); } if (opts.active) { ret = sssctl_domain_status_active_server(conn, path); if (ret != EOK) { ERROR("Unable to get online status\n"); goto done; } printf("\n"); } if (opts.servers) { ret = sssctl_domain_status_server_list(conn, path); if (ret != EOK) { ERROR("Unable to get server list\n"); goto done; } } ret = EOK; done: talloc_free(tmp_ctx); free(discard_const(opts.domain)); return ret; }