/* SSSD sss_groupshow Copyright (C) Jakub Hrozek 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 . */ #include #include #include #include #include "db/sysdb.h" #include "util/util.h" #include "tools/tools_util.h" #include "tools/sss_sync_ops.h" struct group_show_state { const char **user_members; const char **group_members; const char **memberofs; gid_t gid; struct sysdb_ctx *sysdb; struct sss_domain_info *domain; bool done; int ret; }; 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);; } int parse_members(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct sss_domain_info *domain, struct ldb_message_element *el, const char ***user_members, const char ***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; } 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_free(dn); talloc_free(parent_dn); } um[um_index] = NULL; gm[gm_index] = NULL; um = talloc_realloc(mem_ctx, um, const char *, um_index+1); gm = talloc_realloc(mem_ctx, gm, const char *, gm_index+1); if (!um || !gm) { ret = ENOMEM; goto fail; } *user_members = um; *group_members = gm; talloc_free(tmp_ctx); return EOK; fail: talloc_free(um); talloc_free(gm); talloc_free(tmp_ctx); return ret; } static void group_show_done(struct tevent_req *req) { struct group_show_state *state = tevent_req_callback_data(req, struct group_show_state); int ret; int i; struct ldb_message *msg = NULL; struct ldb_context *ldb = sysdb_ctx_get_ldb(state->sysdb); struct ldb_message_element *el; struct ldb_dn *dn = NULL; ret = sysdb_search_group_recv(req, state, &msg); talloc_zfree(req); if (ret) { DEBUG(2, ("Search failed: %s (%d)\n", strerror(ret), ret)); ret = EIO; goto done; } DEBUG(6, ("Found entry %s\n", ldb_dn_get_linearized(msg->dn))); /* list members */ el = ldb_msg_find_element(msg, SYSDB_MEMBER); if (el) { ret = parse_members(state, ldb, state->domain, el, &state->user_members, &state->group_members); if (ret != EOK) { goto done; } } /* list memberofs */ el = ldb_msg_find_element(msg, SYSDB_MEMBEROF); if (el) { state->memberofs = talloc_array(state, const char *, el->num_values+1); if (state->memberofs == NULL) { ret = ENOMEM; goto done; } for (i = 0; i< el->num_values; ++i) { dn = ldb_dn_from_ldb_val(state, ldb, &(el->values[i])); state->memberofs[i] = rdn_as_string(state, dn); if (state->memberofs[i] == NULL) { ret = ENOMEM; goto done; } DEBUG(6, ("memberof value: %s\n", state->memberofs[i])); talloc_free(dn); } state->memberofs[el->num_values] = NULL; } state->gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0); if (state->gid == 0) { ret = EIO; goto done; } ret = EOK; done: state->ret = ret; state->done = true; } int main(int argc, const char **argv) { int ret = EXIT_SUCCESS; int pc_debug = 0; const char *pc_groupname = NULL; struct tools_ctx *tctx = NULL; struct tevent_req *req = NULL; const char *attrs[] = { SYSDB_MEMBEROF, SYSDB_GIDNUM, SYSDB_MEMBER, NULL }; struct group_show_state *search_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 }, 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"); if ((ret = poptGetNextOpt(pc)) < -1) { usage(pc, poptStrerror(ret)); ret = EXIT_FAILURE; goto fini; } debug_level = pc_debug; 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; } /* Do the search */ search_state = talloc_zero(tctx, struct group_show_state); if (search_state == NULL) { ret = EXIT_FAILURE; goto fini; } search_state->sysdb = tctx->sysdb; search_state->domain = tctx->local; req = sysdb_search_group_by_name_send(tctx, tctx->ev, tctx->sysdb, tctx->handle, tctx->local, tctx->octx->name, attrs); if (!req || !search_state) { ret = EXIT_FAILURE; goto fini; } tevent_req_set_callback(req, group_show_done, search_state); /* Busy wait */ while (!search_state->done) { tevent_loop_once(tctx->ev); } /* Process result */ ret = search_state->ret; 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 */ printf(_("Group: %s\nGID number: %d"), tctx->octx->name, search_state->gid); if (search_state->user_members) { printf(_("\nMember users: ")); for (i=0; search_state->user_members[i]; ++i) { printf("%s ", search_state->user_members[i]); } } if (search_state->group_members) { printf(_("\nMember groups: ")); for (i=0; search_state->group_members[i]; ++i) { printf("%s ", search_state->group_members[i]); } } if (search_state->memberofs) { printf(_("\nIs a member of: ")); for (i=0; search_state->memberofs[i]; ++i) { printf("%s ", search_state->memberofs[i]); } } printf("\n"); fini: talloc_free(tctx); poptFreeContext(pc); exit(ret); }