From 9361557ac54157d18070e6ff15a12a7bf28cf7e3 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 2 Mar 2010 12:19:07 +0100
Subject: [PATCH] groupshow: only show all parents in recursive mode

---
 src/man/sss_groupshow.8.xml |    2 +
 src/tools/sss_groupshow.c   |  244 +++++++++++++++++++++++++++++++++++++++----
 2 files changed, 225 insertions(+), 21 deletions(-)

diff --git a/src/man/sss_groupshow.8.xml b/src/man/sss_groupshow.8.xml
index 13e2dfc..cb1046b 100644
--- a/src/man/sss_groupshow.8.xml
+++ b/src/man/sss_groupshow.8.xml
@@ -45,6 +45,8 @@
                 <listitem>
                     <para>
                         Also print indirect group members in a tree-like hierarchy.
+                        Note that this also affects printing parent groups - without
+                        <option>R</option>, only the direct parent will be printed.
                     </para>
                 </listitem>
             </varlistentry>
diff --git a/src/tools/sss_groupshow.c b/src/tools/sss_groupshow.c
index 2f848b7..084da21 100644
--- a/src/tools/sss_groupshow.c
+++ b/src/tools/sss_groupshow.c
@@ -276,6 +276,7 @@ struct group_show_state {
 
 static void group_show_root_done(struct tevent_req *subreq);
 static void group_show_recurse_done(struct tevent_req *subreq);
+static void group_show_trim_done(struct tevent_req *subreq);
 
 struct tevent_req *group_show_recurse_send(TALLOC_CTX *,
                                            struct group_show_state *,
@@ -285,6 +286,17 @@ struct tevent_req *group_show_recurse_send(TALLOC_CTX *,
 static int group_show_recurse_recv(TALLOC_CTX *, struct tevent_req *,
                                    struct group_info ***);
 
+static struct tevent_req *group_show_trim_memberof_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,
+                                                const char **memberofs);
+static int group_show_trim_memberof_recv(TALLOC_CTX *mem_ctx,
+                                         struct tevent_req *req,
+                                         const char ***direct);
+
 struct tevent_req *group_show_send(TALLOC_CTX *mem_ctx,
                                    struct tevent_context *ev,
                                    struct sysdb_ctx *sysdb,
@@ -355,30 +367,47 @@ static void group_show_root_done(struct tevent_req *subreq)
         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);
+        if (group_members) {
+            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);
+                    return;
+                }
+                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);
+                    return;
+                }
             }
+            state->root->group_members[nmembers] = NULL;
         }
-        state->root->group_members[nmembers] = NULL;
 
+        if (state->root->memberofs == NULL) {
+            tevent_req_done(req);
+            return;
+        }
+
+        /* if not recursive, only show the direct parent */
+        subreq = group_show_trim_memberof_send(state, state->ev,
+                                               state->sysdb, state->handle,
+                                               state->domain, state->root->name,
+                                               state->root->memberofs);
+        if (!subreq) {
+            tevent_req_error(req, ENOMEM);
+            return;
+        }
+        tevent_req_set_callback(subreq, group_show_trim_done, req);
+        return;
+    }
+
+    if (group_members == NULL) {
         tevent_req_done(req);
         return;
     }
@@ -394,6 +423,26 @@ static void group_show_root_done(struct tevent_req *subreq)
     tevent_req_set_callback(subreq, group_show_recurse_done, req);
 }
 
+static void group_show_trim_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_trim_memberof_recv(state->root, subreq,
+                                        &state->root->memberofs);
+    talloc_zfree(subreq);
+    if (ret) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    tevent_req_done(req);
+    return;
+}
+
 static void group_show_recurse_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
@@ -428,6 +477,160 @@ static int group_show_recv(TALLOC_CTX *mem_ctx,
     return EOK;
 }
 
+/*=========Nonrecursive search should only show direct parent========== */
+struct group_show_trim_state {
+    const char *name;
+    struct ldb_dn *dn;
+
+    const char **all;
+    int  current;
+
+    const char **direct;
+    int ndirect;
+
+    struct tevent_context *ev;
+    struct sysdb_ctx *sysdb;
+    struct sysdb_handle *handle;
+    struct sss_domain_info *domain;
+};
+
+static int group_show_trim_memberof_next(struct tevent_req *req);
+static void group_show_trim_memberof_done(struct tevent_req *subreq);
+
+static struct tevent_req *group_show_trim_memberof_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,
+                                                const char **memberofs)
+{
+    struct tevent_req *req = NULL;
+    struct group_show_trim_state *state;
+    int ret;
+
+    req = tevent_req_create(mem_ctx, &state, struct group_show_trim_state);
+    if (req == NULL) {
+        return NULL;
+    }
+    state->ev = ev;
+    state->sysdb = sysdb;
+    state->handle = handle;
+    state->domain = domain;
+    state->name = name;
+    state->all = memberofs;
+
+    state->dn = sysdb_group_dn(state->sysdb, state,
+                               state->domain->name,
+                               state->name);
+    if (!state->dn) {
+        talloc_zfree(req);
+        return NULL;
+    }
+
+    ret = group_show_trim_memberof_next(req);
+    if (ret) {
+        talloc_zfree(req);
+        return NULL;
+    }
+
+    return req;
+}
+
+static int group_show_trim_memberof_next(struct tevent_req *req)
+{
+    const char *filter;
+    struct tevent_req *subreq = NULL;
+    struct group_show_trim_state *state = tevent_req_data(req,
+                                                 struct group_show_trim_state);
+
+    filter = talloc_asprintf(req, "(&(%s=%s)(%s=%s))",
+                             SYSDB_NAME, state->all[state->current],
+                             SYSDB_MEMBER, ldb_dn_get_linearized(state->dn));
+    if (!filter) {
+        return ENOMEM;
+    }
+
+    subreq = sysdb_search_groups_send(state, state->ev, state->sysdb,
+                                      state->handle, state->domain,
+                                      filter, NULL);
+    if (!subreq) {
+        return ENOMEM;
+    }
+    tevent_req_set_callback(subreq, group_show_trim_memberof_done, req);
+
+    return EOK;
+}
+
+static void group_show_trim_memberof_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                 struct tevent_req);
+    struct group_show_trim_state *state = tevent_req_data(req,
+                                                 struct group_show_trim_state);
+    int ret;
+    struct ldb_message **msgs;
+    size_t count = 0;
+    const char *name;
+
+    ret = sysdb_search_groups_recv(subreq, state, &count, &msgs);
+    talloc_zfree(subreq);
+    /* ENOENT is OK, the group is just not a direct parent */
+    if (ret != EOK && ret != ENOENT) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    if (count > 0) {
+        name = ldb_msg_find_attr_as_string(msgs[0],
+                                           SYSDB_NAME, NULL);
+        if (!name) {
+            DEBUG(2, ("Entry %s has no Name Attribute ?!?\n",
+                  ldb_dn_get_linearized(msgs[0]->dn)));
+            tevent_req_error(req, EFAULT);
+            return;
+        }
+
+        state->direct = talloc_realloc(state, state->direct,
+                                       const char *, state->ndirect+2);
+        if (!state->direct) {
+            tevent_req_error(req, ENOMEM);
+        }
+
+        state->direct[state->ndirect] = talloc_strdup(state->direct, name);
+        if (!state->direct[state->ndirect]) {
+            tevent_req_error(req, ENOMEM);
+        }
+
+        state->direct[state->ndirect+1] = NULL;
+        state->ndirect++;
+    }
+
+    state->current++;
+    if (state->all[state->current] != NULL) {
+        ret = group_show_trim_memberof_next(req);
+        if (ret != EOK) {
+            tevent_req_error(req, ret);
+        }
+        return;
+    }
+
+    tevent_req_done(req);
+}
+
+static int group_show_trim_memberof_recv(TALLOC_CTX *mem_ctx,
+                                         struct tevent_req *req,
+                                         const char ***direct)
+{
+    struct group_show_trim_state *state = tevent_req_data(req,
+                                                 struct group_show_trim_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+    *direct = talloc_move(mem_ctx, &state->direct);
+
+    return EOK;
+}
+
 /*==================Recursive search for nested groups================= */
 struct group_show_recurse {
     const char **names;
@@ -489,7 +692,6 @@ static int group_show_recurse_search(struct tevent_req *req,
     /* 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;
     }
-- 
1.6.6

