summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/man/sss_groupshow.8.xml12
-rw-r--r--server/tools/sss_groupshow.c790
2 files changed, 698 insertions, 104 deletions
diff --git a/server/man/sss_groupshow.8.xml b/server/man/sss_groupshow.8.xml
index 816e2b76..13e2dfcb 100644
--- a/server/man/sss_groupshow.8.xml
+++ b/server/man/sss_groupshow.8.xml
@@ -31,13 +31,23 @@
<para>
<command>sss_groupshow</command> displays information about a group
identified by its name <replaceable>GROUP</replaceable>. The information
- include the group ID number, members of the group and the parent group.
+ includes the group ID number, members of the group and the parent group.
</para>
</refsect1>
<refsect1 id='options'>
<title>OPTIONS</title>
<variablelist remap='IP'>
+ <varlistentry>
+ <term>
+ <option>-R</option>,<option>--recursive</option>
+ </term>
+ <listitem>
+ <para>
+ Also print indirect group members in a tree-like hierarchy.
+ </para>
+ </listitem>
+ </varlistentry>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/param_help.xml" />
</variablelist>
</refsect1>
diff --git a/server/tools/sss_groupshow.c b/server/tools/sss_groupshow.c
index b942c4ea..4d1c7937 100644
--- a/server/tools/sss_groupshow.c
+++ b/server/tools/sss_groupshow.c
@@ -29,19 +29,25 @@
#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;
+#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;
- struct sysdb_ctx *sysdb;
- struct sss_domain_info *domain;
+ const char **user_members;
+ const char **memberofs;
- bool done;
- int ret;
+ struct group_info **group_members;
};
+/*==================Helper routines to process results================= */
const char *rdn_as_string(TALLOC_CTX *mem_ctx,
struct ldb_dn *dn)
{
@@ -55,12 +61,40 @@ const char *rdn_as_string(TALLOC_CTX *mem_ctx,
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)
+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;
@@ -114,6 +148,11 @@ int parse_members(TALLOC_CTX *mem_ctx,
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 {
@@ -123,58 +162,86 @@ int parse_members(TALLOC_CTX *mem_ctx,
goto fail;
}
- talloc_free(dn);
- talloc_free(parent_dn);
+ talloc_zfree(dn);
+ talloc_zfree(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;
+ 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;
- talloc_free(tmp_ctx);
+ *num_group_members = gm_index;
+ talloc_zfree(tmp_ctx);
return EOK;
fail:
- talloc_free(um);
- talloc_free(gm);
- talloc_free(tmp_ctx);
+ talloc_zfree(um);
+ talloc_zfree(gm);
+ talloc_zfree(tmp_ctx);
return ret;
}
-static void group_show_done(struct tevent_req *req)
+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 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;
+ int ret;
+ struct group_info *gi = 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;
+ 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;
}
- DEBUG(6, ("Found entry %s\n", ldb_dn_get_linearized(msg->dn)));
+ /* 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(state, ldb, state->domain, el,
- &state->user_members,
- &state->group_members);
+ ret = parse_members(gi, ldb, domain, el,
+ parent_name,
+ &gi->user_members,
+ group_members, num_group_members);
if (ret != EOK) {
goto done;
}
@@ -183,49 +250,551 @@ static void group_show_done(struct tevent_req *req)
/* 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;
+ ret = parse_memberofs(ldb, el, gi);
+ if (ret != EOK) {
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;
+ *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);
}
- DEBUG(6, ("memberof value: %s\n", state->memberofs[i]));
+ 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;
+ }
- talloc_free(dn);
+ 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;
}
- state->memberofs[el->num_values] = NULL;
+ /* 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;
}
- state->gid = ldb_msg_find_attr_as_uint64(msg,
- SYSDB_GIDNUM, 0);
- if (state->gid == 0) {
- ret = EIO;
- goto done;
+ /* 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;
}
- ret = EOK;
-done:
- state->ret = ret;
- state->done = true;
+ /* 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:", g->user_members[i]);
+ }
+ }
+ printf(_("\n%sIs a member of: "), padding);
+ if (g->memberofs) {
+ for (i=0; g->memberofs[i]; ++i) {
+ printf("%s:", 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;
- const char *attrs[] = { SYSDB_MEMBEROF, SYSDB_GIDNUM,
- SYSDB_MEMBER, NULL };
- struct group_show_state *search_state = NULL;
+ struct sss_groupshow_state *state = NULL;
int i;
poptContext pc = NULL;
@@ -233,6 +802,8 @@ int main(int argc, const char **argv)
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
};
@@ -249,14 +820,22 @@ int main(int argc, const char **argv)
/* parse ops_ctx */
pc = poptGetContext(NULL, argc, argv, long_options, 0);
poptSetOtherOptionHelp(pc, "GROUPNAME");
- if ((ret = poptGetNextOpt(pc)) < -1) {
+ 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;
}
- debug_level = pc_debug;
-
pc_groupname = poptGetArg(pc);
if (pc_groupname == NULL) {
usage(pc, _("Specify group to show\n"));
@@ -286,31 +865,45 @@ int main(int argc, const char **argv)
goto fini;
}
- /* Do the search */
- search_state = talloc_zero(tctx, struct group_show_state);
- if (search_state == NULL) {
- ret = EXIT_FAILURE;
+ /* The search itself */
+ state = talloc_zero(tctx, struct sss_groupshow_state);
+ if (!state) {
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) {
+ 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, group_show_done, search_state);
-
- /* Busy wait */
- while (!search_state->done) {
+ 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 */
- ret = search_state->ret;
if (ret) {
DEBUG(1, ("sysdb operation failed (%d)[%s]\n", ret, strerror(ret)));
switch (ret) {
@@ -328,27 +921,18 @@ int main(int argc, const char **argv)
}
/* 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]);
+ 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:", state->root->group_members[i]->name);
+ }
}
+ printf("\n");
}
- printf("\n");
fini:
talloc_free(tctx);