diff options
Diffstat (limited to 'src/tools/sss_groupshow.c')
-rw-r--r-- | src/tools/sss_groupshow.c | 944 |
1 files changed, 944 insertions, 0 deletions
diff --git a/src/tools/sss_groupshow.c b/src/tools/sss_groupshow.c new file mode 100644 index 000000000..2f848b7d8 --- /dev/null +++ b/src/tools/sss_groupshow.c @@ -0,0 +1,944 @@ +/* + SSSD + + sss_groupshow + + Copyright (C) Jakub Hrozek <jhrozek@redhat.com> 2010 + + 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 <stdio.h> +#include <stdlib.h> +#include <talloc.h> +#include <popt.h> + +#include "db/sysdb.h" +#include "util/util.h" +#include "tools/tools_util.h" +#include "tools/sss_sync_ops.h" + +#define PADDING_SPACES 4 +#define GROUP_SHOW_ATTRS { SYSDB_MEMBEROF, SYSDB_GIDNUM, \ + SYSDB_MEMBER, SYSDB_NAME, \ + NULL } +#define GROUP_SHOW_MPG_ATTRS { SYSDB_MEMBEROF, SYSDB_UIDNUM, \ + SYSDB_NAME, NULL } + +struct group_info { + const char *name; + gid_t gid; + bool mpg; + + const char **user_members; + const char **memberofs; + + struct group_info **group_members; +}; + +/*==================Helper routines to process results================= */ +const char *rdn_as_string(TALLOC_CTX *mem_ctx, + struct ldb_dn *dn) +{ + const struct ldb_val *val; + + val = ldb_dn_get_rdn_val(dn); + if (val == NULL) { + return NULL; + } + + return ldb_dn_escape_value(mem_ctx, *val);; +} + +static int parse_memberofs(struct ldb_context *ldb, + struct ldb_message_element *el, + struct group_info *gi) +{ + int i; + struct ldb_dn *dn = NULL; + + gi->memberofs = talloc_array(gi, const char *, el->num_values+1); + if (gi->memberofs == NULL) { + return ENOMEM; + } + + for (i = 0; i< el->num_values; ++i) { + dn = ldb_dn_from_ldb_val(gi, ldb, &(el->values[i])); + gi->memberofs[i] = talloc_strdup(gi, rdn_as_string(gi, dn)); + talloc_zfree(dn); + if (gi->memberofs[i] == NULL) { + return ENOMEM; + } + DEBUG(6, ("memberof value: %s\n", gi->memberofs[i])); + } + gi->memberofs[el->num_values] = NULL; + + return EOK; +} + +static int parse_members(TALLOC_CTX *mem_ctx, + struct ldb_context *ldb, + struct sss_domain_info *domain, + struct ldb_message_element *el, + const char *parent_name, + const char ***user_members, + const char ***group_members, + int *num_group_members) +{ + struct ldb_dn *user_basedn = NULL, *group_basedn = NULL; + struct ldb_dn *parent_dn = NULL; + struct ldb_dn *dn = NULL; + const char **um = NULL, **gm = NULL; + unsigned int um_index = 0, gm_index = 0; + TALLOC_CTX *tmp_ctx = NULL; + int ret; + int i; + + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) { + ret = ENOMEM; + goto fail; + } + + user_basedn = ldb_dn_new_fmt(tmp_ctx, ldb, + SYSDB_TMPL_USER_BASE, + domain->name); + group_basedn = ldb_dn_new_fmt(tmp_ctx, ldb, + SYSDB_TMPL_GROUP_BASE, + domain->name); + if (!user_basedn || !group_basedn) { + ret = ENOMEM; + goto fail; + } + + um = talloc_array(mem_ctx, const char *, el->num_values+1); + gm = talloc_array(mem_ctx, const char *, el->num_values+1); + if (!um || !gm) { + ret = ENOMEM; + goto fail; + } + + for (i = 0; i< el->num_values; ++i) { + dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &(el->values[i])); + + /* user member or group member? */ + parent_dn = ldb_dn_get_parent(tmp_ctx, dn); + if (ldb_dn_compare_base(parent_dn, user_basedn) == 0) { + um[um_index] = rdn_as_string(mem_ctx, dn); + if (um[um_index] == NULL) { + ret = ENOMEM; + goto fail; + } + DEBUG(6, ("User member %s\n", um[um_index])); + um_index++; + } else if (ldb_dn_compare_base(parent_dn, group_basedn) == 0) { + gm[gm_index] = rdn_as_string(mem_ctx, dn); + if (gm[gm_index] == NULL) { + ret = ENOMEM; + goto fail; + } + if (parent_name && strcmp(gm[gm_index], parent_name) == 0) { + DEBUG(6, ("Skipping circular nesting for group %s\n", + gm[gm_index])); + continue; + } + DEBUG(6, ("Group member %s\n", gm[gm_index])); + gm_index++; + } else { + DEBUG(2, ("Group member not a user nor group: %s\n", + ldb_dn_get_linearized(dn))); + ret = EIO; + goto fail; + } + + talloc_zfree(dn); + talloc_zfree(parent_dn); + } + um[um_index] = NULL; + gm[gm_index] = NULL; + + if (um_index > 0) { + um = talloc_realloc(mem_ctx, um, const char *, um_index+1); + if (!um) { + ret = ENOMEM; + goto fail; + } + } else { + talloc_zfree(um); + } + + if (gm_index > 0) { + gm = talloc_realloc(mem_ctx, gm, const char *, gm_index+1); + if (!gm) { + ret = ENOMEM; + goto fail; + } + } else { + talloc_zfree(gm); + } + + *user_members = um; + *group_members = gm; + *num_group_members = gm_index; + talloc_zfree(tmp_ctx); + return EOK; + +fail: + talloc_zfree(um); + talloc_zfree(gm); + talloc_zfree(tmp_ctx); + return ret; +} + +static int process_group(TALLOC_CTX *mem_ctx, + struct ldb_context *ldb, + struct ldb_message *msg, + struct sss_domain_info *domain, + const char *parent_name, + struct group_info **info, + const char ***group_members, + int *num_group_members) +{ + struct ldb_message_element *el; + int ret; + struct group_info *gi = NULL; + + DEBUG(6, ("Found entry %s\n", ldb_dn_get_linearized(msg->dn))); + + gi = talloc_zero(mem_ctx, struct group_info); + if (!gi) { + ret = ENOMEM; + goto done; + } + + /* mandatory data - name and gid */ + gi->name = talloc_strdup(gi, + ldb_msg_find_attr_as_string(msg, + SYSDB_NAME, + NULL)); + gi->gid = ldb_msg_find_attr_as_uint64(msg, + SYSDB_GIDNUM, 0); + if (gi->gid == 0 || gi->name == NULL) { + DEBUG(3, ("No name or no GID?\n")); + ret = EIO; + goto done; + } + + /* list members */ + el = ldb_msg_find_element(msg, SYSDB_MEMBER); + if (el) { + ret = parse_members(gi, ldb, domain, el, + parent_name, + &gi->user_members, + group_members, num_group_members); + if (ret != EOK) { + goto done; + } + } + + /* list memberofs */ + el = ldb_msg_find_element(msg, SYSDB_MEMBEROF); + if (el) { + ret = parse_memberofs(ldb, el, gi); + if (ret != EOK) { + goto done; + } + } + + *info = gi; + return EOK; +done: + talloc_zfree(gi); + return ret; +} + +/*========Find info about a group and recursively about subgroups====== */ +struct group_show_state { + struct tevent_context *ev; + struct sysdb_ctx *sysdb; + struct sysdb_handle *handle; + struct sss_domain_info *domain; + + struct group_info *root; + bool recursive; +}; + +static void group_show_root_done(struct tevent_req *subreq); +static void group_show_recurse_done(struct tevent_req *subreq); + +struct tevent_req *group_show_recurse_send(TALLOC_CTX *, + struct group_show_state *, + struct group_info *, + const char **, + const int ); +static int group_show_recurse_recv(TALLOC_CTX *, struct tevent_req *, + struct group_info ***); + +struct tevent_req *group_show_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_ctx *sysdb, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + bool recursive, + const char *name) +{ + struct group_show_state *search_state = NULL; + struct tevent_req *subreq = NULL; + struct tevent_req *req = NULL; + static const char *attrs[] = GROUP_SHOW_ATTRS; + + req = tevent_req_create(mem_ctx, &search_state, struct group_show_state); + if (req == NULL) { + return NULL; + } + search_state->ev = ev; + search_state->sysdb = sysdb; + search_state->handle = handle; + search_state->domain = domain; + search_state->recursive = recursive; + + /* First, search for the root group */ + subreq = sysdb_search_group_by_name_send(search_state, + search_state->ev, + search_state->sysdb, + search_state->handle, + search_state->domain, + name, attrs); + if (!subreq) { + talloc_zfree(req); + return NULL; + } + tevent_req_set_callback(subreq, group_show_root_done, req); + + return req; +} + +static void group_show_root_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct group_show_state *state = tevent_req_data(req, + struct group_show_state); + int ret; + int i; + struct ldb_message *msg = NULL; + const char **group_members = NULL; + int nmembers = 0; + + ret = sysdb_search_group_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret) { + DEBUG(2, ("Search failed: %s (%d)\n", strerror(ret), ret)); + tevent_req_error(req, ret); + return; + } + + ret = process_group(state, + sysdb_ctx_get_ldb(state->sysdb), + msg, state->domain, NULL, &state->root, + &group_members, &nmembers); + if (ret != EOK) { + DEBUG(2, ("Group processing failed: %s (%d)\n", + strerror(ret), ret)); + tevent_req_error(req, ret); + return; + } + + if (group_members == NULL) { + tevent_req_done(req); + return; + } + + if (state->recursive == false) { + /* if not recursive, just fill in names */ + state->root->group_members = talloc_array(state->root, + struct group_info *, + nmembers+1); + for (i=0; group_members[i]; i++) { + state->root->group_members[i] = talloc_zero(state->root, + struct group_info); + if (!state->root->group_members) { + tevent_req_error(req, ENOMEM); + } + state->root->group_members[i]->name = talloc_strdup(state->root, + group_members[i]); + if (!state->root->group_members[i]->name) { + tevent_req_error(req, ENOMEM); + } + } + state->root->group_members[nmembers] = NULL; + + tevent_req_done(req); + return; + } + + subreq = group_show_recurse_send(state->root, state, + state->root, + group_members, + nmembers); + if (!subreq) { + tevent_req_error(req, ret); + return; + } + tevent_req_set_callback(subreq, group_show_recurse_done, req); +} + +static void group_show_recurse_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct group_show_state *state = tevent_req_data(req, + struct group_show_state); + int ret; + + ret = group_show_recurse_recv(state->root, + subreq, + &state->root->group_members); + talloc_zfree(subreq); + if (ret) { + DEBUG(2, ("Recursive search failed: %s (%d)\n", strerror(ret), ret)); + tevent_req_error(req, EIO); + return; + } + + tevent_req_done(req); +} + +static int group_show_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct group_info **res) +{ + struct group_show_state *state = tevent_req_data(req, + struct group_show_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + *res = talloc_move(mem_ctx, &state->root); + + return EOK; +} + +/*==================Recursive search for nested groups================= */ +struct group_show_recurse { + const char **names; + int current; + + struct group_info *parent; + struct group_show_state *state; + + struct group_info **groups; +}; + +static int group_show_recurse_search(struct tevent_req *, + struct group_show_recurse *); +static void group_show_recurse_next(struct tevent_req *); +static void group_show_recurse_level_done(struct tevent_req *); +static void group_show_recurse_cont(struct tevent_req *); + +struct tevent_req *group_show_recurse_send(TALLOC_CTX *mem_ctx, + struct group_show_state *state, + struct group_info *parent, + const char **group_members, + const int nmembers) +{ + struct tevent_req *req = NULL; + struct group_show_recurse *recurse_state = NULL; + + req = tevent_req_create(mem_ctx, &recurse_state, struct group_show_recurse); + if (req == NULL) { + return NULL; + } + recurse_state->current = 0; + recurse_state->parent = parent; + recurse_state->names = group_members; + recurse_state->state = state; + recurse_state->groups = talloc_array(state->root, + struct group_info *, + nmembers+1); /* trailing NULL */ + + if (!recurse_state->names || + !recurse_state->names[recurse_state->current]) { + talloc_zfree(req); + return NULL; + } + + if (group_show_recurse_search(req, recurse_state) != EOK) { + talloc_zfree(req); + return NULL; + } + + return req; +} + +static int group_show_recurse_search(struct tevent_req *req, + struct group_show_recurse *recurse_state) +{ + static const char *attrs[] = GROUP_SHOW_ATTRS; + struct tevent_req *subreq = NULL; + + /* Skip circular groups */ + if (strcmp(recurse_state->names[recurse_state->current], + recurse_state->parent->name) == 0) { + DEBUG(0, ("CIRCULAR DEP DETECTED\n")); + group_show_recurse_cont(req); + return EOK; + } + + subreq = sysdb_search_group_by_name_send(recurse_state->state, + recurse_state->state->ev, + recurse_state->state->sysdb, + recurse_state->state->handle, + recurse_state->state->domain, + recurse_state->names[recurse_state->current], + attrs); + if (!subreq) { + return ENOMEM; + } + tevent_req_set_callback(subreq, group_show_recurse_next, req); + + return EOK; +} + +static void group_show_recurse_next(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct group_show_recurse *recurse_state = tevent_req_data(req, + struct group_show_recurse); + const char **group_members = NULL; + int nmembers = 0; + struct ldb_message *msg = NULL; + int ret; + struct tevent_req *recurse_req = NULL; + + ret = sysdb_search_group_recv(subreq, recurse_state, &msg); + talloc_zfree(subreq); + if (ret) { + DEBUG(2, ("Search failed: %s (%d)\n", strerror(ret), ret)); + tevent_req_error(req, EIO); + return; + } + + ret = process_group(recurse_state->state->root, + sysdb_ctx_get_ldb(recurse_state->state->sysdb), + msg, + recurse_state->state->domain, + recurse_state->parent->name, + &recurse_state->groups[recurse_state->current], + &group_members, + &nmembers); + if (ret != EOK) { + DEBUG(2, ("Group processing failed: %s (%d)\n", + strerror(ret), ret)); + tevent_req_error(req, ret); + return; + } + + /* descend to another level */ + if (nmembers > 0) { + recurse_req = group_show_recurse_send(recurse_state, + recurse_state->state, + recurse_state->groups[recurse_state->current], + group_members, nmembers); + if (!recurse_req) { + tevent_req_error(req, ENOMEM); + return; + } + /* to free group_members in the callback */ + group_members = talloc_move(recurse_req, &group_members); + tevent_req_set_callback(recurse_req, group_show_recurse_level_done, req); + return; + } + + /* Move to next group in the same level */ + group_show_recurse_cont(req); +} + +static void group_show_recurse_level_done(struct tevent_req *recurse_req) +{ + int ret; + struct tevent_req *req = tevent_req_callback_data(recurse_req, + struct tevent_req); + struct group_show_recurse *recurse_state = tevent_req_data(recurse_req, + struct group_show_recurse); + + ret = group_show_recurse_recv(recurse_state->state->root, recurse_req, + &recurse_state->parent->group_members); + talloc_zfree(recurse_req); + if (ret) { + DEBUG(2, ("Recursive search failed: %s (%d)\n", strerror(ret), ret)); + tevent_req_error(req, EIO); + return; + } + + /* Move to next group on the upper level */ + group_show_recurse_cont(req); +} + +static void group_show_recurse_cont(struct tevent_req *req) +{ + struct group_show_recurse *recurse_state = tevent_req_data(req, + struct group_show_recurse); + int ret; + + recurse_state->current++; + if (recurse_state->names[recurse_state->current] == NULL) { + recurse_state->groups[recurse_state->current] = NULL; /* Sentinel */ + tevent_req_done(req); + return; + } + + /* examine next group on the same level */ + ret = group_show_recurse_search(req, recurse_state); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } +} + +static int group_show_recurse_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct group_info ***out) +{ + struct group_show_recurse *recurse_state = tevent_req_data(req, + struct group_show_recurse); + + TEVENT_REQ_RETURN_ON_ERROR(req); + *out = talloc_move(mem_ctx, &recurse_state->groups); + + return EOK; +} + +/*==================Get info about MPG================================= */ +struct group_show_mpg_state { + struct ldb_context *ldb; + struct group_info *info; +}; + +static void group_show_mpg_done(struct tevent_req *); + +struct tevent_req *group_show_mpg_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_ctx *sysdb, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name) +{ + struct tevent_req *req = NULL; + struct tevent_req *subreq = NULL; + struct group_show_mpg_state *state; + static const char *mpg_attrs[] = GROUP_SHOW_MPG_ATTRS; + + req = tevent_req_create(mem_ctx, &state, struct group_show_mpg_state); + if (req == NULL) { + return NULL; + } + state->ldb = sysdb_ctx_get_ldb(sysdb); + + subreq = sysdb_search_user_by_name_send(mem_ctx, ev, sysdb, handle, + domain, name, mpg_attrs); + if (!subreq) { + talloc_zfree(req); + return NULL; + } + tevent_req_set_callback(subreq, group_show_mpg_done, req); + + return req; +} + +static void group_show_mpg_done(struct tevent_req *subreq) +{ + int ret; + struct ldb_message *msg = NULL; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct group_show_mpg_state *state = tevent_req_data(req, + struct group_show_mpg_state); + + ret = sysdb_search_user_recv(subreq, req, &msg); + talloc_zfree(subreq); + if (ret) { + DEBUG(2, ("Search failed: %s (%d)\n", strerror(ret), ret)); + tevent_req_error(req, ret); + return; + } + + state->info = talloc_zero(state, struct group_info); + if (!state->info) { + tevent_req_error(req, ENOMEM); + return; + } + + state->info->name = talloc_strdup(state->info, + ldb_msg_find_attr_as_string(msg, + SYSDB_NAME, + NULL)); + state->info->gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0); + if (state->info->gid == 0 || state->info->name == NULL) { + DEBUG(3, ("No name or no GID?\n")); + tevent_req_error(req, EIO); + return; + } + state->info->mpg = true; + + tevent_req_done(req); +} + +static int group_show_mpg_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct group_info **res) +{ + struct group_show_mpg_state *state = tevent_req_data(req, + struct group_show_mpg_state); + TEVENT_REQ_RETURN_ON_ERROR(req); + *res = talloc_move(mem_ctx, &state->info); + + return EOK; +} + +/*==================The main program=================================== */ +struct sss_groupshow_state { + struct group_info *root; + + int ret; + bool done; +}; + +static void sss_group_show_done(struct tevent_req *req) +{ + int ret; + struct sss_groupshow_state *sss_state = tevent_req_callback_data(req, + struct sss_groupshow_state); + + ret = group_show_recv(sss_state, req, &sss_state->root); + talloc_zfree(req); + + sss_state->ret = ret; + sss_state->done = true; +} + +static void sss_group_show_mpg_done(struct tevent_req *req) +{ + int ret; + struct sss_groupshow_state *sss_state = tevent_req_callback_data(req, + struct sss_groupshow_state); + + ret = group_show_mpg_recv(sss_state, req, &sss_state->root); + talloc_zfree(req); + + sss_state->ret = ret; + sss_state->done = true; +} + +static void print_group_info(struct group_info *g, int level) +{ + int i; + char padding[512]; + char fmt[8]; + + snprintf(fmt, 8, "%%%ds", level*PADDING_SPACES); + snprintf(padding, 512, fmt, ""); + + printf(_("%s%sGroup: %s\n"), padding, + g->mpg ? _("Magic Private ") : "", + g->name); + printf(_("%sGID number: %d\n"), padding, g->gid); + + printf(_("%sMember users: "), padding); + if (g->user_members) { + for (i=0; g->user_members[i]; ++i) { + printf("%s%s", i>0 ? "," : "", + g->user_members[i]); + } + } + printf(_("\n%sIs a member of: "), padding); + if (g->memberofs) { + for (i=0; g->memberofs[i]; ++i) { + printf("%s%s", i>0 ? "," : "", + g->memberofs[i]); + } + } + printf(_("\n%sMember groups: "), padding); +} + +static void print_recursive(struct group_info **group_members, int level) +{ + int i; + + if (group_members == NULL) { + return; + } + + level++; + for (i=0; group_members[i]; ++i) { + printf("\n"); + print_group_info(group_members[i], level); + printf("\n"); + print_recursive(group_members[i]->group_members, level); + } +} + +int main(int argc, const char **argv) +{ + int ret = EXIT_SUCCESS; + int pc_debug = 0; + bool pc_recursive = false; + const char *pc_groupname = NULL; + struct tools_ctx *tctx = NULL; + struct tevent_req *req = NULL; + struct sss_groupshow_state *state = NULL; + int i; + + poptContext pc = NULL; + struct poptOption long_options[] = { + POPT_AUTOHELP + { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug, + 0, _("The debug level to run with"), NULL }, + { "recursive", 'R', POPT_ARG_NONE, NULL, 'r', + _("Print indirect group members recursively"), NULL }, + POPT_TABLEEND + }; + + debug_prg_name = argv[0]; + + ret = set_locale(); + if (ret != EOK) { + DEBUG(1, ("set_locale failed (%d): %s\n", ret, strerror(ret))); + ERROR("Error setting the locale\n"); + ret = EXIT_FAILURE; + goto fini; + } + + /* parse ops_ctx */ + pc = poptGetContext(NULL, argc, argv, long_options, 0); + poptSetOtherOptionHelp(pc, "GROUPNAME"); + while ((ret = poptGetNextOpt(pc)) > 0) { + switch (ret) { + case 'r': + pc_recursive = true; + break; + } + } + + debug_level = pc_debug; + + if (ret != -1) { + usage(pc, poptStrerror(ret)); + ret = EXIT_FAILURE; + goto fini; + } + + pc_groupname = poptGetArg(pc); + if (pc_groupname == NULL) { + usage(pc, _("Specify group to show\n")); + ret = EXIT_FAILURE; + goto fini; + } + + CHECK_ROOT(ret, debug_prg_name); + + ret = init_sss_tools(&tctx); + if (ret != EOK) { + DEBUG(1, ("init_sss_tools failed (%d): %s\n", ret, strerror(ret))); + if (ret == ENOENT) { + ERROR("Error initializing the tools - no local domain\n"); + } else { + ERROR("Error initializing the tools\n"); + } + ret = EXIT_FAILURE; + goto fini; + } + + /* if the domain was not given as part of FQDN, default to local domain */ + ret = parse_name_domain(tctx, pc_groupname); + if (ret != EOK) { + ERROR("Invalid domain specified in FQDN\n"); + ret = EXIT_FAILURE; + goto fini; + } + + /* The search itself */ + state = talloc_zero(tctx, struct sss_groupshow_state); + if (!state) { + goto fini; + } + + req = group_show_send(tctx, tctx->ev, tctx->sysdb, tctx->handle, + tctx->local, pc_recursive, tctx->octx->name); + if (!req) { + ERROR("Cannot initiate search\n"); + ret = EXIT_FAILURE; + goto fini; + } + tevent_req_set_callback(req, sss_group_show_done, state); + while (!state->done) { + tevent_loop_once(tctx->ev); + } + ret = state->ret; + + /* Also show MPGs */ + if (ret == ENOENT) { + state->done = false; + state->ret = EOK; + + req = group_show_mpg_send(tctx, tctx->ev, tctx->sysdb, tctx->handle, + tctx->local, tctx->octx->name); + if (!req) { + ERROR("Cannot initiate search\n"); + ret = EXIT_FAILURE; + goto fini; + } + tevent_req_set_callback(req, sss_group_show_mpg_done, state); + while (!state->done) { + tevent_loop_once(tctx->ev); + } + ret = state->ret; + } + + /* Process result */ + if (ret) { + DEBUG(1, ("sysdb operation failed (%d)[%s]\n", ret, strerror(ret))); + switch (ret) { + case ENOENT: + ERROR("No such group in local domain. " + "Printing groups only allowed in local domain.\n"); + break; + + default: + ERROR("Internal error. Could not print group.\n"); + break; + } + ret = EXIT_FAILURE; + goto fini; + } + + /* print the results */ + print_group_info(state->root, 0); + if (pc_recursive) { + printf("\n"); + print_recursive(state->root->group_members, 0); + } else { + if (state->root->group_members) { + for (i=0; state->root->group_members[i]; ++i) { + printf("%s%s", i>0 ? "," : "", + state->root->group_members[i]->name); + } + } + printf("\n"); + } + +fini: + talloc_free(tctx); + poptFreeContext(pc); + exit(ret); +} |