summaryrefslogtreecommitdiffstats
path: root/server/tools
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2010-01-12 18:00:49 +0100
committerStephen Gallagher <sgallagh@redhat.com>2010-01-20 08:55:59 -0500
commit30dcfad596af29830cd45adaebeb174a24151a34 (patch)
tree07d114c00bedbd9bc32995eaec108ac92143922e /server/tools
parenta2ad4811428a48830d040051c59eca6e13512710 (diff)
downloadsssd-30dcfad596af29830cd45adaebeb174a24151a34.tar.gz
sssd-30dcfad596af29830cd45adaebeb174a24151a34.tar.xz
sssd-30dcfad596af29830cd45adaebeb174a24151a34.zip
sss_groupshow - a utility to print properties of a local group
This patch adds a utility called sss_groupshow that allows user to print properties of a group in the local domain. Fixes: #306
Diffstat (limited to 'server/tools')
-rw-r--r--server/tools/sss_groupshow.c357
1 files changed, 357 insertions, 0 deletions
diff --git a/server/tools/sss_groupshow.c b/server/tools/sss_groupshow.c
new file mode 100644
index 0000000..b942c4e
--- /dev/null
+++ b/server/tools/sss_groupshow.c
@@ -0,0 +1,357 @@
+/*
+ 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"
+
+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);
+}