This set of patches ends up fixing the initgroups call.
It still uses the slowest possible method, a future improvement is to
use the deref (IPA/DS/OpenLDAP) or the ASQ (AD) controls to reduce the
number of LDAP searches.

Patches 0001 though 0004 are dependencies for 0005

0001: add way to get a string w/o manually parsing the attributes

0002: make function public and move it to sdap.c

0003: this is also needed by the access modules, stores the original
memberof DNs

0004: remove redundant code and at the same time make it easier to use
the generic search function for users and groups retrieval. With this
change it will be possible to reduce further code duplication my
changing the code that searches for users and groups to use the generic
search function (I plan to do this once the patch is accepted)

0005: initgroups call fixups make it work and have specialized code
depending on the schema used (still doesn't fully support nested groups
in AD, but that is not a priority right now)

I have tested it with an IPA 1.2 server and seem to work properly.

Simo.

-- 
Simo Sorce * Red Hat, Inc * New York
>From d3e4d3e123950bb52c3424967f7b30d3148a586f Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Wed, 4 Nov 2009 15:33:45 -0500
Subject: [PATCH 1/5] Make available method to quickly retrive string

sysdb_attrs has a lot of methods to add them but very little to get information
out. Start adding a way to retrieve a single valued attribute as a string.
---
 server/db/sysdb.c |   35 ++++++++++++++++++++++++++++++++---
 server/db/sysdb.h |    3 +++
 2 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/server/db/sysdb.c b/server/db/sysdb.c
index ae32ef4..4e6e71e 100644
--- a/server/db/sysdb.c
+++ b/server/db/sysdb.c
@@ -65,8 +65,8 @@ struct sysdb_attrs *sysdb_new_attrs(TALLOC_CTX *memctx)
     return talloc_zero(memctx, struct sysdb_attrs);
 }
 
-int sysdb_attrs_get_el(struct sysdb_attrs *attrs, const char *name,
-                       struct ldb_message_element **el)
+static int sysdb_attrs_get_el_int(struct sysdb_attrs *attrs, const char *name,
+                                  bool alloc, struct ldb_message_element **el)
 {
     struct ldb_message_element *e = NULL;
     int i;
@@ -76,7 +76,7 @@ int sysdb_attrs_get_el(struct sysdb_attrs *attrs, const char *name,
             e = &(attrs->a[i]);
     }
 
-    if (!e) {
+    if (!e && alloc) {
         e = talloc_realloc(attrs, attrs->a,
                            struct ldb_message_element, attrs->num+1);
         if (!e) return ENOMEM;
@@ -93,11 +93,40 @@ int sysdb_attrs_get_el(struct sysdb_attrs *attrs, const char *name,
         attrs->num++;
     }
 
+    if (!e) {
+        return ENOENT;
+    }
+
     *el = e;
 
     return EOK;
 }
 
+int sysdb_attrs_get_el(struct sysdb_attrs *attrs, const char *name,
+                       struct ldb_message_element **el)
+{
+    return sysdb_attrs_get_el_int(attrs, name, true, el);
+}
+
+int sysdb_attrs_get_string(struct sysdb_attrs *attrs, const char *name,
+                           const char **string)
+{
+    struct ldb_message_element *el;
+    int ret;
+
+    ret = sysdb_attrs_get_el_int(attrs, name, false, &el);
+    if (ret) {
+        return ret;
+    }
+
+    if (el->num_values != 1) {
+        return ERANGE;
+    }
+
+    *string = (const char *)el->values[0].data;
+    return EOK;
+}
+
 int sysdb_attrs_add_val(struct sysdb_attrs *attrs,
                         const char *name, const struct ldb_val *val)
 {
diff --git a/server/db/sysdb.h b/server/db/sysdb.h
index 0b47422..394b524 100644
--- a/server/db/sysdb.h
+++ b/server/db/sysdb.h
@@ -74,6 +74,7 @@
 
 #define SYSDB_ORIG_DN "originalDN"
 #define SYSDB_ORIG_MODSTAMP "originalModifyTimestamp"
+#define SYSDB_ORIG_MEMBEROF "originalMemberOf"
 
 #define SYSDB_USN "entryUSN"
 #define SYSDB_HIGH_USN "highestUSN"
@@ -173,6 +174,8 @@ int sysdb_attrs_get_el(struct sysdb_attrs *attrs, const char *name,
                        struct ldb_message_element **el);
 int sysdb_attrs_steal_string(struct sysdb_attrs *attrs,
                              const char *name, char *str);
+int sysdb_attrs_get_string(struct sysdb_attrs *attrs, const char *name,
+                           const char **string);
 
 int sysdb_attrs_replace_name(struct sysdb_attrs *attrs, const char *oldname,
                                  const char *newname);
-- 
1.6.2.5

>From 41651419ad48a71256b1720e4a321666fc9816cb Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Wed, 4 Nov 2009 15:35:00 -0500
Subject: [PATCH 2/5] Make useful function more broadly available.

---
 server/providers/ldap/ldap_id.c |   30 ------------------------------
 server/providers/ldap/sdap.c    |   27 +++++++++++++++++++++++++++
 server/providers/ldap/sdap.h    |    3 +++
 3 files changed, 30 insertions(+), 30 deletions(-)

diff --git a/server/providers/ldap/ldap_id.c b/server/providers/ldap/ldap_id.c
index b7e29e6..ba7cdab 100644
--- a/server/providers/ldap/ldap_id.c
+++ b/server/providers/ldap/ldap_id.c
@@ -32,36 +32,6 @@
 #include "providers/ldap/ldap_common.h"
 #include "providers/ldap/sdap_async.h"
 
-static int build_attrs_from_map(TALLOC_CTX *memctx,
-                                struct sdap_attr_map *map,
-                                size_t size,
-                                const char ***_attrs)
-{
-    char **attrs;
-    int i, j;
-
-    attrs = talloc_array(memctx, char *, size + 1);
-    if (!attrs) return ENOMEM;
-
-    /* first attribute is "objectclass" not the specifc one */
-    attrs[0] = talloc_strdup(memctx, "objectClass");
-    if (!attrs[0]) return ENOMEM;
-
-    /* add the others */
-    for (i = j = 1; i < size; i++) {
-        if (map[i].name) {
-            attrs[j] = map[i].name;
-            j++;
-        }
-    }
-    attrs[j] = NULL;
-
-    *_attrs = (const char **)attrs;
-
-    return EOK;
-}
-
-
 /* =Connection-handling-functions========================================= */
 
 static bool connected(struct sdap_id_ctx *ctx)
diff --git a/server/providers/ldap/sdap.c b/server/providers/ldap/sdap.c
index 5da698a..d9bb323 100644
--- a/server/providers/ldap/sdap.c
+++ b/server/providers/ldap/sdap.c
@@ -421,4 +421,31 @@ bool sdap_rootdse_sasl_mech_is_supported(struct sysdb_attrs *rootdse,
     return false;
 }
 
+int build_attrs_from_map(TALLOC_CTX *memctx,
+                         struct sdap_attr_map *map,
+                         size_t size, const char ***_attrs)
+{
+    char **attrs;
+    int i, j;
+
+    attrs = talloc_array(memctx, char *, size + 1);
+    if (!attrs) return ENOMEM;
+
+    /* first attribute is "objectclass" not the specifc one */
+    attrs[0] = talloc_strdup(memctx, "objectClass");
+    if (!attrs[0]) return ENOMEM;
+
+    /* add the others */
+    for (i = j = 1; i < size; i++) {
+        if (map[i].name) {
+            attrs[j] = map[i].name;
+            j++;
+        }
+    }
+    attrs[j] = NULL;
+
+    *_attrs = (const char **)attrs;
+
+    return EOK;
+}
 
diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h
index 03dab30..7e5c4b7 100644
--- a/server/providers/ldap/sdap.h
+++ b/server/providers/ldap/sdap.h
@@ -226,4 +226,7 @@ errno_t setup_tls_config(struct dp_option *basic_opts);
 bool sdap_rootdse_sasl_mech_is_supported(struct sysdb_attrs *rootdse,
                                          const char *sasl_mech);
 
+int build_attrs_from_map(TALLOC_CTX *memctx,
+                         struct sdap_attr_map *map,
+                         size_t size, const char ***_attrs);
 #endif /* _SDAP_H_ */
-- 
1.6.2.5

>From 1ae6ddbc2758b469773e8467676dd85dff25c1dd Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Wed, 4 Nov 2009 15:38:04 -0500
Subject: [PATCH 3/5] Store the original memberof attributes if any

Also change the interface of sdap_save_user_send() so that it can be more
easily reused like it was done for sdap_save_group_send().
---
 server/providers/ldap/sdap_async.c |   37 +++++++++++++++++++++++++++++------
 1 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c
index dfdd267..e255d15 100644
--- a/server/providers/ldap/sdap_async.c
+++ b/server/providers/ldap/sdap_async.c
@@ -1305,7 +1305,6 @@ struct sdap_save_user_state {
 
 static void sdap_save_user_done(struct tevent_req *subreq);
 
-    /* FIXME: support non legacy */
     /* FIXME: support storing additional attributes */
 
 static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx,
@@ -1314,7 +1313,7 @@ static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx,
                                               struct sdap_options *opts,
                                               struct sss_domain_info *dom,
                                               struct sdap_handle *sh,
-                                              struct sdap_msg *entry)
+                                              struct sysdb_attrs *attrs)
 {
     struct tevent_req *req, *subreq;
     struct sdap_save_user_state *state;
@@ -1340,12 +1339,9 @@ static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx,
     state->sh = sh;
     state->dom = dom;
     state->opts = opts;
+    state->attrs = attrs;
     state->timestamp = NULL;
 
-    ret = sdap_parse_user(state, state->opts, state->sh,
-                          entry, &state->attrs, NULL);
-    if (ret) goto fail;
-
     ret = sysdb_attrs_get_el(state->attrs,
                              opts->user_map[SDAP_AT_USER_NAME].sys_name, &el);
     if (ret) goto fail;
@@ -1435,6 +1431,25 @@ static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx,
         }
     }
 
+    ret = sysdb_attrs_get_el(state->attrs, SYSDB_MEMBEROF, &el);
+    if (ret) {
+        goto fail;
+    }
+    if (el->num_values == 0) {
+        DEBUG(7, ("Original memberOf is not available for [%s].\n",
+                  state->name));
+    } else {
+        DEBUG(7, ("Adding original memberOf attributes to [%s].\n",
+                  state->name));
+        for (i = 0; i < el->num_values; i++) {
+            ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF,
+                                         (const char *) el->values[i].data);
+            if (ret) {
+                goto fail;
+            }
+        }
+    }
+
     ret = sysdb_attrs_get_el(state->attrs,
                       opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name, &el);
     if (ret) {
@@ -2295,6 +2310,7 @@ static void sdap_get_users_done(struct sdap_op *op,
     struct sdap_get_users_state *state = tevent_req_data(req,
                                             struct sdap_get_users_state);
     struct tevent_req *subreq;
+    struct sysdb_attrs *usr_attrs;
     char *errmsg;
     int result;
     int ret;
@@ -2315,9 +2331,16 @@ static void sdap_get_users_done(struct sdap_op *op,
 
     case LDAP_RES_SEARCH_ENTRY:
 
+        ret = sdap_parse_user(state, state->opts, state->sh,
+                              reply, &usr_attrs, NULL);
+        if (ret != EOK) {
+            tevent_req_error(req, ret);
+            return;
+        }
+
         subreq = sdap_save_user_send(state, state->ev, state->handle,
                                      state->opts, state->dom,
-                                     state->sh, reply);
+                                     state->sh, usr_attrs);
         if (!subreq) {
             tevent_req_error(req, ENOMEM);
             return;
-- 
1.6.2.5

>From 3864c725c5d34842ae12615e8b7c00b79a10cc0c Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Wed, 4 Nov 2009 17:04:49 -0500
Subject: [PATCH 4/5] Unify parse routines, use maps in generic searches

This remove redundant code and also allows the generic search to be used to use
maps to convert attributes.
---
 server/providers/ldap/sdap.c       |  179 ++++++++++++------------------------
 server/providers/ldap/sdap.h       |   10 +-
 server/providers/ldap/sdap_async.c |   14 ++-
 server/providers/ldap/sdap_async.h |    4 +-
 4 files changed, 77 insertions(+), 130 deletions(-)

diff --git a/server/providers/ldap/sdap.c b/server/providers/ldap/sdap.c
index d9bb323..39c67cc 100644
--- a/server/providers/ldap/sdap.c
+++ b/server/providers/ldap/sdap.c
@@ -68,17 +68,20 @@ int sdap_get_map(TALLOC_CTX *memctx,
 
 /* =Parse-msg============================================================= */
 
-static int sdap_parse_entry(TALLOC_CTX *memctx,
-                            struct sdap_handle *sh, struct sdap_msg *sm,
-                            struct sdap_attr_map *map, int attrs_num,
-                            struct sysdb_attrs **_attrs, char **_dn)
+int sdap_parse_entry(TALLOC_CTX *memctx,
+                     struct sdap_handle *sh, struct sdap_msg *sm,
+                     struct sdap_attr_map *map, int attrs_num,
+                     struct sysdb_attrs **_attrs, char **_dn)
 {
     struct sysdb_attrs *attrs;
     BerElement *ber = NULL;
-    char **vals;
+    struct berval **vals;
+    struct ldb_val v;
     char *str;
     int lerrno;
     int a, i, ret;
+    const char *name;
+    bool store;
 
     lerrno = 0;
     ldap_set_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
@@ -108,48 +111,64 @@ static int sdap_parse_entry(TALLOC_CTX *memctx,
     }
     ldap_memfree(str);
 
-    vals = ldap_get_values(sh->ldap, sm->msg, "objectClass");
-    if (!vals) {
-        DEBUG(1, ("Unknown entry type, no objectClasses found!\n"));
-        ret = EINVAL;
-        goto fail;
-    }
+    if (map) {
+        vals = ldap_get_values_len(sh->ldap, sm->msg, "objectClass");
+        if (!vals) {
+            DEBUG(1, ("Unknown entry type, no objectClasses found!\n"));
+            ret = EINVAL;
+            goto fail;
+        }
 
-    for (i = 0; vals[i]; i++) {
-        /* the objectclass is always the first name in the map */
-        if (strcasecmp(vals[i], map[0].name) == 0) {
-            /* ok it's a user */
-            break;
+        for (i = 0; vals[i]; i++) {
+            /* the objectclass is always the first name in the map */
+            if (strncasecmp(map[0].name,
+                            vals[i]->bv_val, vals[i]->bv_len) == 0) {
+                /* ok it's an entry of the right type */
+                break;
+            }
         }
+        if (!vals[i]) {
+            DEBUG(1, ("objectClass not matching: %s\n",
+                      map[0].name));
+            ldap_value_free_len(vals);
+            ret = EINVAL;
+            goto fail;
+        }
+        ldap_value_free_len(vals);
     }
-    if (!vals[i]) {
-        DEBUG(1, ("Not a user entry, objectClass not matching: %s\n",
-                  map[0].name));
-        ldap_value_free(vals);
-        ret = EINVAL;
-        goto fail;
-    }
-    ldap_value_free(vals);
 
     str = ldap_first_attribute(sh->ldap, sm->msg, &ber);
     if (!str) {
         ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
         DEBUG(1, ("Entry has no attributes [%d(%s)]!?\n",
                   lerrno, ldap_err2string(lerrno)));
-        ret = EINVAL;
-        goto fail;
+        if (map) {
+            ret = EINVAL;
+            goto fail;
+        }
     }
     while (str) {
-        for (a = 1; a < attrs_num; a++) {
-            /* check if this attr is valid with the chosen schema */
-            if (!map[a].name) continue;
-            /* check if it is an attr we are interested in */
-            if (strcasecmp(str, map[a].name) == 0) break;
-        }
-        if (a < attrs_num) {
+        if (map) {
+            for (a = 1; a < attrs_num; a++) {
+                /* check if this attr is valid with the chosen schema */
+                if (!map[a].name) continue;
+                /* check if it is an attr we are interested in */
+                if (strcasecmp(str, map[a].name) == 0) break;
+            }
             /* interesting attr */
+            if (a < attrs_num) {
+                store = true;
+                name = map[a].sys_name;
+            } else {
+                store = false;
+            }
+        } else {
+            name = str;
+            store = true;
+        }
 
-            vals = ldap_get_values(sh->ldap, sm->msg, str);
+        if (store) {
+            vals = ldap_get_values_len(sh->ldap, sm->msg, str);
             if (!vals) {
                 ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
                 DEBUG(1, ("LDAP Library error: %d(%s)",
@@ -163,96 +182,14 @@ static int sdap_parse_entry(TALLOC_CTX *memctx,
                 goto fail;
             }
             for (i = 0; vals[i]; i++) {
-                ret = sysdb_attrs_add_string(attrs, map[a].sys_name, vals[i]);
+                v.data = (uint8_t *)vals[i]->bv_val;
+                v.length = vals[i]->bv_len;
+
+                ret = sysdb_attrs_add_val(attrs, name, &v);
                 if (ret) goto fail;
             }
-            ldap_value_free(vals);
-        }
-
-        ldap_memfree(str);
-        str = ldap_next_attribute(sh->ldap, sm->msg, ber);
-    }
-    ber_free(ber, 0);
-
-    ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
-    if (lerrno) {
-        DEBUG(1, ("LDAP Library error: %d(%s)",
-                  lerrno, ldap_err2string(lerrno)));
-        ret = EIO;
-        goto fail;
-    }
-
-    *_attrs = attrs;
-    return EOK;
-
-fail:
-    if (ber) ber_free(ber, 0);
-    talloc_free(attrs);
-    return ret;
-}
-
-int sdap_parse_generic_entry(TALLOC_CTX *memctx,
-                             struct sdap_handle *sh,
-                             struct sdap_msg *sm,
-                             struct sysdb_attrs **_attrs)
-{
-    struct sysdb_attrs *attrs;
-    BerElement *ber = NULL;
-    struct berval **vals;
-    struct ldb_val v;
-    char *str;
-    int lerrno;
-    int i;
-    int ret;
-
-    lerrno = 0;
-    ldap_set_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
-
-    attrs = sysdb_new_attrs(memctx);
-    if (!attrs) return ENOMEM;
-
-    str = ldap_get_dn(sh->ldap, sm->msg);
-    if (!str) {
-        ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
-        DEBUG(1, ("ldap_get_dn failed: %d(%s)\n",
-                  lerrno, ldap_err2string(lerrno)));
-        ret = EIO;
-        goto fail;
-    }
-
-    DEBUG(9, ("OriginalDN: [%s].\n", str));
-    ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_DN, str);
-    if (ret) goto fail;
-    ldap_memfree(str);
-
-    str = ldap_first_attribute(sh->ldap, sm->msg, &ber);
-    if (!str) {
-        ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
-        DEBUG(9, ("Entry has no attributes [%d(%s)]!?\n",
-                  lerrno, ldap_err2string(lerrno)));
-    }
-    while (str) {
-        vals = ldap_get_values_len(sh->ldap, sm->msg, str);
-        if (!vals) {
-            ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
-            DEBUG(1, ("LDAP Library error: %d(%s)",
-                      lerrno, ldap_err2string(lerrno)));
-            ret = EIO;
-            goto fail;
-        }
-        if (!vals[0]) {
-            DEBUG(1, ("Missing value after ldap_get_values() ??\n"));
-            ret = EINVAL;
-            goto fail;
-        }
-        for (i = 0; vals[i]; i++) {
-            v.data = (uint8_t *) vals[i]->bv_val;
-            v.length = vals[i]->bv_len;
-
-            ret = sysdb_attrs_add_val(attrs, str, &v);
-            if (ret) goto fail;
+            ldap_value_free_len(vals);
         }
-        ldap_value_free_len(vals);
 
         ldap_memfree(str);
         str = ldap_next_attribute(sh->ldap, sm->msg, ber);
diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h
index 7e5c4b7..fec9eef 100644
--- a/server/providers/ldap/sdap.h
+++ b/server/providers/ldap/sdap.h
@@ -205,6 +205,11 @@ int sdap_get_map(TALLOC_CTX *memctx,
                  int num_entries,
                  struct sdap_attr_map **_map);
 
+int sdap_parse_entry(TALLOC_CTX *memctx,
+                     struct sdap_handle *sh, struct sdap_msg *sm,
+                     struct sdap_attr_map *map, int attrs_num,
+                     struct sysdb_attrs **_attrs, char **_dn);
+
 int sdap_parse_user(TALLOC_CTX *memctx, struct sdap_options *opts,
                     struct sdap_handle *sh, struct sdap_msg *sm,
                     struct sysdb_attrs **_attrs, char **_dn);
@@ -213,11 +218,6 @@ int sdap_parse_group(TALLOC_CTX *memctx, struct sdap_options *opts,
                      struct sdap_handle *sh, struct sdap_msg *sm,
                      struct sysdb_attrs **_attrs, char **_dn);
 
-int sdap_parse_generic_entry(TALLOC_CTX *memctx,
-                                    struct sdap_handle *sh,
-                                    struct sdap_msg *sm,
-                                    struct sysdb_attrs **_attrs);
-
 int sdap_get_msg_dn(TALLOC_CTX *memctx, struct sdap_handle *sh,
                     struct sdap_msg *sm, char **_dn);
 
diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c
index e255d15..c7b81ea 100644
--- a/server/providers/ldap/sdap_async.c
+++ b/server/providers/ldap/sdap_async.c
@@ -3287,7 +3287,7 @@ struct tevent_req *sdap_get_rootdse_send(TALLOC_CTX *memctx,
 
     subreq = sdap_get_generic_send(state, ev, opts, sh,
                                    "", LDAP_SCOPE_BASE,
-                                   "(objectclass=*)", NULL);
+                                   "(objectclass=*)", NULL, NULL, 0);
     if (!subreq) {
         talloc_zfree(req);
         return NULL;
@@ -3648,6 +3648,8 @@ struct sdap_get_generic_state {
     int scope;
     const char *filter;
     const char **attrs;
+    struct sdap_attr_map *map;
+    int map_num_attrs;
 
     struct sdap_op *op;
 
@@ -3670,7 +3672,9 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
                                          const char *search_base,
                                          int scope,
                                          const char *filter,
-                                         const char **attrs)
+                                         const char **attrs,
+                                         struct sdap_attr_map *map,
+                                         int map_num_attrs)
 {
     struct tevent_req *req = NULL;
     struct sdap_get_generic_state *state = NULL;
@@ -3688,6 +3692,8 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
     state->scope = scope;
     state->filter = filter;
     state->attrs = attrs;
+    state->map = map;
+    state->map_num_attrs = map_num_attrs;
     state->op = NULL;
     state->reply_max = 0;
     state->reply_count = 0;
@@ -3762,7 +3768,9 @@ static void sdap_get_generic_done(struct sdap_op *op,
         break;
 
     case LDAP_RES_SEARCH_ENTRY:
-        ret = sdap_parse_generic_entry(state, state->sh, reply, &attrs);
+        ret = sdap_parse_entry(state, state->sh, reply,
+                               state->map, state->map_num_attrs,
+                               &attrs, NULL);
         if (ret != EOK) {
             DEBUG(1, ("sdap_parse_generic_entry failed.\n"));
             tevent_req_error(req, ENOMEM);
diff --git a/server/providers/ldap/sdap_async.h b/server/providers/ldap/sdap_async.h
index 911933a..955dce4 100644
--- a/server/providers/ldap/sdap_async.h
+++ b/server/providers/ldap/sdap_async.h
@@ -106,7 +106,9 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
                                          const char *search_base,
                                          int scope,
                                          const char *filter,
-                                         const char **attrs);
+                                         const char **attrs,
+                                         struct sdap_attr_map *map,
+                                         int map_num_attrs);
 int sdap_get_generic_recv(struct tevent_req *req,
                          TALLOC_CTX *mem_ctx, size_t *reply_count,
                          struct sysdb_attrs ***reply_list);
-- 
1.6.2.5

>From e5360e0bad8d052942b796b1ab94241e0a08e1a1 Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Wed, 4 Nov 2009 15:40:04 -0500
Subject: [PATCH 5/5] Fix and enhance initgroups call

This call was failing and was defective because it didn't properly handle the
various different schemas we support.
Now the function does 2 things:
- Updates the user entry to make sure it is still valid
- Retrieves every group the user is member of
---
 server/providers/ldap/sdap_async.c |  807 ++++++++++++++++++++++++++++--------
 1 files changed, 637 insertions(+), 170 deletions(-)

diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c
index c7b81ea..1698359 100644
--- a/server/providers/ldap/sdap_async.c
+++ b/server/providers/ldap/sdap_async.c
@@ -1331,6 +1331,8 @@ static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx,
     int i;
     char *val = NULL;
 
+    DEBUG(9, ("Save user\n"));
+
     req = tevent_req_create(memctx, &state, struct sdap_save_user_state);
     if (!req) return NULL;
 
@@ -1573,7 +1575,9 @@ static int sdap_save_user_recv(struct tevent_req *req,
         return err;
     }
 
-    *timestamp = talloc_steal(mem_ctx, state->timestamp);
+    if (timestamp) {
+        *timestamp = talloc_steal(mem_ctx, state->timestamp);
+    }
 
     return EOK;
 }
@@ -2753,6 +2757,486 @@ int sdap_get_groups_recv(struct tevent_req *req,
     return EOK;
 }
 
+/* ==Initgr-call-(groups-a-user-is-member-of)-Save-Groups================= */
+
+struct sdap_save_groups_state {
+    struct tevent_context *ev;
+    struct sysdb_ctx *sysdb;
+    struct sdap_options *opts;
+    struct sss_domain_info *dom;
+
+    struct sysdb_attrs **groups;
+    int count;
+    int cur;
+    bool savemembers;
+
+    struct sysdb_handle *handle;
+};
+
+static void sdap_save_groups_trans(struct tevent_req *subreq);
+static void sdap_save_groups_store(struct tevent_req *req);
+static void sdap_save_groups_process(struct tevent_req *subreq);
+struct tevent_req *sdap_save_groups_send(TALLOC_CTX *memctx,
+                                         struct tevent_context *ev,
+                                         struct sss_domain_info *dom,
+                                         struct sysdb_ctx *sysdb,
+                                         struct sdap_options *opts,
+                                         struct sysdb_attrs **groups,
+                                         int num_groups)
+{
+    struct tevent_req *req, *subreq;
+    struct sdap_save_groups_state *state;
+
+    req = tevent_req_create(memctx, &state, struct sdap_save_groups_state);
+    if (!req) return NULL;
+
+    state->ev = ev;
+    state->opts = opts;
+    state->sysdb = sysdb;
+    state->dom = dom;
+    state->groups = groups;
+    state->count = 0;
+    state->cur = 0;
+    state->handle = NULL;
+
+    switch (opts->schema_type) {
+    case SDAP_SCHEMA_RFC2307:
+    case SDAP_SCHEMA_RFC2307BIS:
+        state->savemembers = true;
+        break;
+
+    case SDAP_SCHEMA_IPA_V1:
+    case SDAP_SCHEMA_AD:
+        state->savemembers = false;
+        break;
+
+    default:
+        tevent_req_error(req, EINVAL);
+        tevent_req_post(req, ev);
+        return req;
+    }
+
+    subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
+    if (!subreq) {
+        tevent_req_error(req, ENOMEM);
+        tevent_req_post(req, ev);
+        return req;
+    }
+    tevent_req_set_callback(subreq, sdap_save_groups_trans, req);
+
+    return req;
+}
+
+static void sdap_save_groups_trans(struct tevent_req *subreq)
+{
+    struct tevent_req *req;
+    struct sdap_save_groups_state *state;
+    int ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct sdap_save_groups_state);
+
+    ret = sysdb_transaction_recv(subreq, state, &state->handle);
+    talloc_zfree(subreq);
+    if (ret) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    sdap_save_groups_store(req);
+}
+
+static void sdap_save_groups_store(struct tevent_req *req)
+{
+    struct tevent_req *subreq;
+    struct sdap_save_groups_state *state;
+
+    state = tevent_req_data(req, struct sdap_save_groups_state);
+
+    /* 1st pass savemembers = false */
+    /* 2nd pass savemembers = true */
+    subreq = sdap_save_group_send(state, state->ev, state->handle,
+                                  state->opts, state->dom,
+                                  state->groups[state->cur],
+                                  state->savemembers);
+    if (!subreq) {
+        tevent_req_error(req, ENOMEM);
+        return;
+    }
+    tevent_req_set_callback(subreq, sdap_save_groups_process, req);
+}
+
+static void sdap_save_groups_process(struct tevent_req *subreq)
+{
+    struct tevent_req *req;
+    struct sdap_save_groups_state *state;
+    int ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct sdap_save_groups_state);
+
+    ret = sdap_save_group_recv(subreq, NULL, NULL);
+    talloc_zfree(subreq);
+
+    /* Do not fail completely on errors.
+     * Just report the failure to save and go on */
+    if (ret) {
+        DEBUG(2, ("Failed to store group %d. Ignoring.\n", state->cur));
+    }
+
+    state->cur++;
+    if (state->cur < state->count) {
+        sdap_save_groups_store(req);
+    } else if (state->savemembers == false) {
+        state->savemembers = true;
+        state->cur = 0;
+        sdap_save_groups_store(req);
+    } else {
+        subreq = sysdb_transaction_commit_send(state, state->ev,
+                                               state->handle);
+        if (!subreq) {
+            tevent_req_error(req, ENOMEM);
+            return;
+        }
+        /* sysdb_transaction_complete will call tevent_req_done(req) */
+        tevent_req_set_callback(subreq, sysdb_transaction_complete, req);
+    }
+}
+
+static int sdap_save_groups_recv(struct tevent_req *req)
+{
+    enum tevent_req_state tstate;
+    uint64_t err;
+
+    if (tevent_req_is_error(req, &tstate, &err)) {
+        if (err) return err;
+        return EIO;
+    }
+    return EOK;
+}
+
+
+/* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307-Classic/BIS========= */
+
+struct sdap_initgr_rfc2307_state {
+    struct tevent_context *ev;
+    struct sysdb_ctx *sysdb;
+    struct sdap_options *opts;
+    struct sss_domain_info *dom;
+    struct sdap_handle *sh;
+
+    struct sdap_op *op;
+};
+
+static void sdap_initgr_rfc2307_process(struct tevent_req *subreq);
+static void sdap_initgr_rfc2307_done(struct tevent_req *subreq);
+struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx,
+                                            struct tevent_context *ev,
+                                            struct sdap_options *opts,
+                                            struct sysdb_ctx *sysdb,
+                                            struct sss_domain_info *dom,
+                                            struct sdap_handle *sh,
+                                            const char *base_dn,
+                                            const char *name,
+                                            const char **grp_attrs)
+{
+    struct tevent_req *req, *subreq;
+    struct sdap_initgr_rfc2307_state *state;
+    const char *filter;
+
+    req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);
+    if (!req) return NULL;
+
+    state->ev = ev;
+    state->opts = opts;
+    state->sysdb = sysdb;
+    state->dom = dom;
+    state->sh = sh;
+    state->op = NULL;
+
+    filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
+                             opts->group_map[SDAP_AT_GROUP_MEMBER].name,
+                             name, opts->group_map[SDAP_OC_GROUP].name);
+    if (!filter) {
+        talloc_zfree(req);
+        return NULL;
+    }
+
+    subreq = sdap_get_generic_send(state, state->ev, state->opts,
+                                   state->sh, base_dn, LDAP_SCOPE_SUBTREE,
+                                   filter, grp_attrs,
+                                   state->opts->group_map, SDAP_OPTS_GROUP);
+    if (!subreq) {
+        talloc_zfree(req);
+        return NULL;
+    }
+    tevent_req_set_callback(subreq, sdap_initgr_rfc2307_process, req);
+
+    return req;
+}
+
+static void sdap_initgr_rfc2307_process(struct tevent_req *subreq)
+{
+    struct tevent_req *req;
+    struct sdap_initgr_rfc2307_state *state;
+    struct sysdb_attrs **groups;
+    size_t count;
+    int ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
+
+    ret = sdap_get_generic_recv(subreq, state, &count, &groups);
+    talloc_zfree(subreq);
+    if (ret) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    if (count == 0) {
+        tevent_req_done(req);
+        return;
+    }
+
+    subreq = sdap_save_groups_send(state, state->ev, state->dom,
+                                   state->sysdb, state->opts,
+                                   groups, count);
+    if (!subreq) {
+        tevent_req_error(req, ENOMEM);
+        return;
+    }
+    tevent_req_set_callback(subreq, sdap_initgr_rfc2307_done, req);
+}
+
+static void sdap_initgr_rfc2307_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req;
+    int ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+
+    ret = sdap_save_groups_recv(subreq);
+    talloc_zfree(subreq);
+    if (ret) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    tevent_req_done(req);
+}
+
+static int sdap_initgr_rfc2307_recv(struct tevent_req *req)
+{
+    enum tevent_req_state tstate;
+    uint64_t err;
+
+    if (tevent_req_is_error(req, &tstate, &err)) {
+        if (err) return err;
+        return EIO;
+    }
+    return EOK;
+}
+
+
+/* ==Initgr-call-(groups-a-user-is-member-of)-nested-groups=============== */
+
+struct sdap_initgr_nested_state {
+    struct tevent_context *ev;
+    struct sysdb_ctx *sysdb;
+    struct sdap_options *opts;
+    struct sss_domain_info *dom;
+    struct sdap_handle *sh;
+
+    const char **grp_attrs;
+
+    char *filter;
+    char **group_dns;
+    int count;
+    int cur;
+
+    struct sdap_op *op;
+
+    struct sysdb_attrs **groups;
+    int groups_cur;
+};
+
+static void sdap_initgr_nested_search(struct tevent_req *subreq);
+static void sdap_initgr_nested_store(struct tevent_req *req);
+static void sdap_initgr_nested_done(struct tevent_req *subreq);
+static struct tevent_req *sdap_initgr_nested_send(TALLOC_CTX *memctx,
+                                                  struct tevent_context *ev,
+                                                  struct sdap_options *opts,
+                                                  struct sysdb_ctx *sysdb,
+                                                  struct sss_domain_info *dom,
+                                                  struct sdap_handle *sh,
+                                                  struct sysdb_attrs *user,
+                                                  const char **grp_attrs)
+{
+    struct tevent_req *req, *subreq;
+    struct sdap_initgr_nested_state *state;
+    struct ldb_message_element *el;
+    int i, ret;
+
+    req = tevent_req_create(memctx, &state, struct sdap_initgr_nested_state);
+    if (!req) return NULL;
+
+    state->ev = ev;
+    state->opts = opts;
+    state->sysdb = sysdb;
+    state->dom = dom;
+    state->sh = sh;
+    state->grp_attrs = grp_attrs;
+    state->op = NULL;
+
+    state->filter = talloc_asprintf(state, "(objectclass=%s)",
+                                    opts->group_map[SDAP_OC_GROUP].name);
+    if (!state->filter) {
+        talloc_zfree(req);
+        return NULL;
+    }
+
+    /* TODO: test rootDSE for deref support and use it if available */
+    /* TODO: or test rootDSE for ASQ support and use it if available */
+
+    ret = sysdb_attrs_get_el(user, SYSDB_MEMBEROF, &el);
+    if (ret || !el || el->num_values == 0) {
+        DEBUG(4, ("User entry lacks original memberof ?\n"));
+        /* user with no groups ? */
+        tevent_req_error(req, ENOENT);
+        tevent_req_post(req, ev);
+    }
+    state->count = el->num_values;
+
+    state->groups = talloc_zero_array(state, struct sysdb_attrs *,
+                                      state->count + 1);;
+    if (!state->groups) {
+        talloc_zfree(req);
+        return NULL;
+    }
+    state->groups_cur = 0;
+
+    state->group_dns = talloc_array(state, char *, state->count + 1);
+    if (!state->group_dns) {
+        talloc_zfree(req);
+        return NULL;
+    }
+    for (i = 0; i < state->count; i++) {
+        state->group_dns[i] = talloc_strdup(state->group_dns,
+                                            (char *)el->values[i].data);
+        if (!state->group_dns[i]) {
+            talloc_zfree(req);
+            return NULL;
+        }
+    }
+    state->group_dns[i] = NULL; /* terminate */
+    state->cur = 0;
+
+    subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
+                                   state->group_dns[state->cur],
+                                   LDAP_SCOPE_BASE,
+                                   state->filter, state->grp_attrs,
+                                   state->opts->group_map, SDAP_OPTS_GROUP);
+    if (!subreq) {
+        talloc_zfree(req);
+        return NULL;
+    }
+    tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);
+
+    return req;
+}
+
+static void sdap_initgr_nested_search(struct tevent_req *subreq)
+{
+    struct tevent_req *req;
+    struct sdap_initgr_nested_state *state;
+    struct sysdb_attrs **groups;
+    size_t count;
+    int ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct sdap_initgr_nested_state);
+
+    ret = sdap_get_generic_recv(subreq, state, &count, &groups);
+    talloc_zfree(subreq);
+    if (ret) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    if (count == 1) {
+        state->groups[state->groups_cur] = groups[0];
+        state->groups_cur++;
+    } else {
+        DEBUG(2, ("Search for group %s, returned %d results. Skipping\n",
+                  state->group_dns[state->cur], count));
+    }
+
+    state->cur++;
+    if (state->cur < state->count) {
+        subreq = sdap_get_generic_send(state, state->ev,
+                                       state->opts, state->sh,
+                                       state->group_dns[state->cur],
+                                       LDAP_SCOPE_BASE,
+                                       state->filter, state->grp_attrs,
+                                       state->opts->group_map,
+                                       SDAP_OPTS_GROUP);
+        if (!subreq) {
+            tevent_req_error(req, ENOMEM);
+            return;
+        }
+        tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);
+    } else {
+        sdap_initgr_nested_store(req);
+    }
+}
+
+static void sdap_initgr_nested_store(struct tevent_req *req)
+{
+    struct tevent_req *subreq;
+    struct sdap_initgr_nested_state *state;
+
+    state = tevent_req_data(req, struct sdap_initgr_nested_state);
+
+    subreq = sdap_save_groups_send(state, state->ev, state->dom,
+                                   state->sysdb, state->opts,
+                                   state->groups, state->groups_cur);
+    if (!subreq) {
+        tevent_req_error(req, ENOMEM);
+        return;
+    }
+    tevent_req_set_callback(subreq, sdap_initgr_nested_done, req);
+}
+
+static void sdap_initgr_nested_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req;
+    int ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+
+    ret = sdap_save_groups_recv(subreq);
+    talloc_zfree(subreq);
+    if (ret) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    tevent_req_done(req);
+}
+
+static int sdap_initgr_nested_recv(struct tevent_req *req)
+{
+    enum tevent_req_state tstate;
+    uint64_t err;
+
+    if (tevent_req_is_error(req, &tstate, &err)) {
+        if (err) return err;
+        return EIO;
+    }
+    return EOK;
+}
+
+
 /* ==Initgr-call-(groups-a-user-is-member-of)============================= */
 
 struct sdap_get_initgr_state {
@@ -2764,18 +3248,16 @@ struct sdap_get_initgr_state {
     const char *name;
     const char **grp_attrs;
 
-    const char *filter;
+    struct sysdb_attrs *orig_user;
 
     struct sysdb_handle *handle;
-    struct sdap_op *op;
 };
 
+static void sdap_get_initgr_user(struct tevent_req *subreq);
+static void sdap_get_initgr_store(struct tevent_req *subreq);
+static void sdap_get_initgr_commit(struct tevent_req *subreq);
 static void sdap_get_initgr_process(struct tevent_req *subreq);
-static void sdap_get_initgr_transaction(struct tevent_req *subreq);
-static void sdap_get_initgr_done(struct sdap_op *op,
-                                 struct sdap_msg *reply,
-                                 int error, void *pvt);
-static void sdap_get_initgr_save_done(struct tevent_req *subreq);
+static void sdap_get_initgr_done(struct tevent_req *subreq);
 
 struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
                                         struct tevent_context *ev,
@@ -2788,10 +3270,13 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
 {
     struct tevent_req *req, *subreq;
     struct sdap_get_initgr_state *state;
-    struct timeval tv = {0, 0};
+    const char *base_dn;
+    char *filter;
     const char **attrs;
     int ret;
 
+    DEBUG(9, ("Retrieving info for initgroups call\n"));
+
     req = tevent_req_create(memctx, &state, struct sdap_get_initgr_state);
     if (!req) return NULL;
 
@@ -2802,124 +3287,89 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
     state->sh = sh;
     state->name = name;
     state->grp_attrs = grp_attrs;
+    state->orig_user = NULL;
 
-    switch (opts->schema_type) {
-    case SDAP_SCHEMA_RFC2307:
-
-        subreq = tevent_wakeup_send(state, ev, tv);
-        if (!subreq) {
-            ret = ENOMEM;
-            goto fail;
-        }
-        tevent_req_set_callback(subreq, sdap_get_initgr_process, req);
-        break;
-
-    case SDAP_SCHEMA_RFC2307BIS:
-
-        attrs = talloc_array(state, const char *, 2);
-        if (!attrs) {
-            ret = ENOMEM;
-            goto fail;
-        }
-        attrs[0] = SYSDB_ORIG_DN;
-        attrs[1] = NULL;
+    filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
+                        state->opts->user_map[SDAP_AT_USER_NAME].name,
+                        state->name,
+                        state->opts->user_map[SDAP_OC_USER].name);
+    if (!filter) {
+        talloc_zfree(req);
+        return NULL;
+    }
 
-        subreq = sysdb_search_user_by_name_send(state, ev, sysdb, NULL,
-                                                dom, name, attrs);
-        if (!subreq) {
-            ret = ENOMEM;
-            goto fail;
-        }
-        tevent_req_set_callback(subreq, sdap_get_initgr_process, req);
-        break;
+    base_dn = dp_opt_get_string(state->opts->basic,
+                                SDAP_USER_SEARCH_BASE);
+    if (!base_dn) {
+        talloc_zfree(req);
+        return NULL;
+    }
 
-    default:
-        ret = EINVAL;
-        goto fail;
+    ret = build_attrs_from_map(state, state->opts->user_map,
+                               SDAP_OPTS_USER, &attrs);
+    if (ret) {
+        talloc_zfree(req);
+        return NULL;
     }
 
-    return req;
+    subreq = sdap_get_generic_send(state, state->ev,
+                                   state->opts, state->sh,
+                                   base_dn, LDAP_SCOPE_SUBTREE,
+                                   filter, attrs,
+                                   state->opts->user_map, SDAP_OPTS_USER);
+    if (!subreq) {
+        talloc_zfree(req);
+        return NULL;
+    }
+    tevent_req_set_callback(subreq, sdap_get_initgr_user, req);
 
-fail:
-    tevent_req_error(req, EIO);
-    tevent_req_post(req, ev);
     return req;
 }
 
-static void sdap_get_initgr_process(struct tevent_req *subreq)
+static void sdap_get_initgr_user(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
     struct sdap_get_initgr_state *state = tevent_req_data(req,
                                                struct sdap_get_initgr_state);
-    struct ldb_message *msg;
-    const char *user_dn;
+    struct sysdb_attrs **usr_attrs;
+    size_t count;
     int ret;
 
-    switch (state->opts->schema_type) {
-    case SDAP_SCHEMA_RFC2307:
-
-        if (!tevent_wakeup_recv(subreq)) {
-            tevent_req_error(req, EFAULT);
-            return;
-        }
-        talloc_zfree(subreq);
-
-        state->filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
-                           state->opts->group_map[SDAP_AT_GROUP_MEMBER].name,
-                           state->name,
-                           state->opts->group_map[SDAP_OC_GROUP].name);
-        break;
-
-    case SDAP_SCHEMA_RFC2307BIS:
-
-        ret = sysdb_search_user_recv(subreq, state, &msg);
-        talloc_zfree(subreq);
-        if (ret) {
-            tevent_req_error(req, ret);
-            return;
-        }
-
-        user_dn = ldb_msg_find_attr_as_string(msg, SYSDB_ORIG_DN, NULL);
-        if (!user_dn) {
-            tevent_req_error(req, ENOENT);
-            return;
-        }
-
-        state->filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
-                            state->opts->group_map[SDAP_AT_GROUP_MEMBER].name,
-                            user_dn,
-                            state->opts->group_map[SDAP_OC_GROUP].name);
+    DEBUG(9, ("Receiving info for the user\n"));
 
-        talloc_free(msg);
-        break;
-
-    default:
-        tevent_req_error(req, EINVAL);
+    ret = sdap_get_generic_recv(subreq, state, &count, &usr_attrs);
+    talloc_zfree(subreq);
+    if (ret) {
+        tevent_req_error(req, ret);
         return;
     }
 
-    if (!state->filter) {
-        tevent_req_error(req, ENOMEM);
+    if (count != 1) {
+        DEBUG(2, ("Expected one user entry and got %d\n", count));
+        tevent_req_error(req, ENOENT);
         return;
     }
 
+    state->orig_user = usr_attrs[0];
+
     subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
     if (!subreq) {
         tevent_req_error(req, ENOMEM);
         return;
     }
-    tevent_req_set_callback(subreq, sdap_get_initgr_transaction, req);
+    tevent_req_set_callback(subreq, sdap_get_initgr_store, req);
 }
 
-static void sdap_get_initgr_transaction(struct tevent_req *subreq)
+static void sdap_get_initgr_store(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
     struct sdap_get_initgr_state *state = tevent_req_data(req,
                                                struct sdap_get_initgr_state);
-    int ret, lret;
-    int msgid;
+    int ret;
+
+    DEBUG(9, ("Storing the user\n"));
 
     ret = sysdb_transaction_recv(subreq, state, &state->handle);
     talloc_zfree(subreq);
@@ -2928,116 +3378,116 @@ static void sdap_get_initgr_transaction(struct tevent_req *subreq)
         return;
     }
 
-    DEBUG(5, ("calling ldap_search_ext with filter:[%s].\n", state->filter));
-
-    lret = ldap_search_ext(state->sh->ldap,
-                           dp_opt_get_string(state->opts->basic,
-                                              SDAP_GROUP_SEARCH_BASE),
-                           LDAP_SCOPE_SUBTREE, state->filter,
-                           discard_const(state->grp_attrs),
-                           false, NULL, NULL, NULL, 0, &msgid);
-    if (lret != LDAP_SUCCESS) {
-        DEBUG(3, ("ldap_search_ext failed: %s\n", ldap_err2string(lret)));
-        tevent_req_error(req, EIO);
+    subreq = sdap_save_user_send(state, state->ev, state->handle,
+                                 state->opts, state->dom,
+                                 state->sh, state->orig_user);
+    if (!subreq) {
+        tevent_req_error(req, ENOMEM);
         return;
     }
+    tevent_req_set_callback(subreq, sdap_get_initgr_commit, req);
+}
 
-    DEBUG(8, ("ldap_search_ext called, msgid = %d\n", msgid));
+static void sdap_get_initgr_commit(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct sdap_get_initgr_state *state = tevent_req_data(req,
+                                               struct sdap_get_initgr_state);
+    int ret;
 
-    /* FIXME: get timeouts from configuration, for now 10 minutes */
-    ret = sdap_op_add(state, state->ev, state->sh, msgid,
-                      sdap_get_initgr_done, req,
-                      dp_opt_get_int(state->opts->basic,
-                                      SDAP_SEARCH_TIMEOUT),
-                      &state->op);
+    DEBUG(9, ("Commit change\n"));
+
+    ret = sdap_save_user_recv(subreq, NULL, NULL);
+    talloc_zfree(subreq);
     if (ret) {
-        DEBUG(1, ("Failed to set up operation!\n"));
         tevent_req_error(req, ret);
+        return;
+    }
+
+    subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
+    if (!subreq) {
+        tevent_req_error(req, ENOMEM);
+        return;
     }
+    tevent_req_set_callback(subreq, sdap_get_initgr_process, req);
 }
 
-static void sdap_get_initgr_done(struct sdap_op *op,
-                                 struct sdap_msg *reply,
-                                 int error, void *pvt)
+static void sdap_get_initgr_process(struct tevent_req *subreq)
 {
-    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
     struct sdap_get_initgr_state *state = tevent_req_data(req,
                                                struct sdap_get_initgr_state);
-    struct tevent_req *subreq;
-    struct sysdb_attrs *grp_attrs;
-    char *errmsg;
-    int result;
+    const char *user_dn;
     int ret;
 
-    if (error) {
-        tevent_req_error(req, error);
+    DEBUG(9, ("Process user's groups\n"));
+
+    ret = sysdb_transaction_commit_recv(subreq);
+    talloc_zfree(subreq);
+    if (ret) {
+        tevent_req_error(req, ret);
         return;
     }
 
-    switch (ldap_msgtype(reply->msg)) {
-    case LDAP_RES_SEARCH_REFERENCE:
-        /* ignore references for now */
-        talloc_free(reply);
-
-        /* unlock the operation so that we can proceed with the next result */
-        sdap_unlock_next_reply(state->op);
+    switch (state->opts->schema_type) {
+    case SDAP_SCHEMA_RFC2307:
+        subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts,
+                                    state->sysdb, state->dom, state->sh,
+                                    dp_opt_get_string(state->opts->basic,
+                                                  SDAP_GROUP_SEARCH_BASE),
+                                    state->name, state->grp_attrs);
+        if (!subreq) {
+            tevent_req_error(req, ENOMEM);
+            return;
+        }
+        tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
         break;
 
-    case LDAP_RES_SEARCH_ENTRY:
+    case SDAP_SCHEMA_RFC2307BIS:
 
-        /* allocate on reply so that it will be freed once the
-         * reply is processed. Remember to steal if you need something
-         * to stick longer */
-        ret = sdap_parse_group(reply, state->opts, state->sh,
-                               reply, &grp_attrs, NULL);
-        if (ret != EOK) {
-            tevent_req_error(req, ret);
+        ret = sysdb_attrs_get_string(state->orig_user,
+                                     SYSDB_ORIG_DN, &user_dn);
+        if (ret) {
+            tevent_req_error(req, EINVAL);
             return;
         }
 
-        subreq = sdap_save_group_send(state, state->ev, state->handle,
-                                     state->opts, state->dom,
-                                     grp_attrs, true);
+        subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts,
+                                          state->sysdb, state->dom,
+                                          state->sh, user_dn,
+                                          state->name, state->grp_attrs);
         if (!subreq) {
             tevent_req_error(req, ENOMEM);
             return;
         }
-        tevent_req_set_callback(subreq, sdap_get_initgr_save_done, req);
-
-        break;
-
-    case LDAP_RES_SEARCH_RESULT:
-        /* End of the story */
-
-        ret = ldap_parse_result(state->sh->ldap, reply->msg,
-                                &result, NULL, &errmsg, NULL, NULL, 0);
-        if (ret != LDAP_SUCCESS) {
-            DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid));
-            tevent_req_error(req, EIO);
-            return;
-        }
+        tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
+        return;
 
-        DEBUG(3, ("Search result: %s(%d), %s\n",
-                  ldap_err2string(result), result, errmsg));
+    case SDAP_SCHEMA_IPA_V1:
+    case SDAP_SCHEMA_AD:
+        /* TODO: AD uses a different member/memberof schema
+         *       We need an AD specific call that is able to unroll
+         *       nested groups by doing extensive recursive searches */
 
-        subreq = sysdb_transaction_commit_send(state, state->ev,
-                                               state->handle);
+        subreq = sdap_initgr_nested_send(state, state->ev, state->opts,
+                                         state->sysdb, state->dom, state->sh,
+                                         state->orig_user, state->grp_attrs);
         if (!subreq) {
             tevent_req_error(req, ENOMEM);
             return;
         }
-        /* sysdb_transaction_complete will call tevent_req_done(req) */
-        tevent_req_set_callback(subreq, sysdb_transaction_complete, req);
-        break;
+        tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
+        return;
 
     default:
-        /* what is going on here !? */
-        tevent_req_error(req, EIO);
+        tevent_req_error(req, EINVAL);
         return;
     }
 }
 
-static void sdap_get_initgr_save_done(struct tevent_req *subreq)
+static void sdap_get_initgr_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
@@ -3045,17 +3495,34 @@ static void sdap_get_initgr_save_done(struct tevent_req *subreq)
                                                struct sdap_get_initgr_state);
     int ret;
 
-    ret = sdap_save_group_recv(subreq, NULL, NULL);
-    talloc_zfree(subreq);
+    DEBUG(9, ("Initgroups done\n"));
 
-    /* Do not fail completely on errors.
-     * Just report the failure to save and go on */
+    switch (state->opts->schema_type) {
+    case SDAP_SCHEMA_RFC2307:
+    case SDAP_SCHEMA_RFC2307BIS:
+
+        ret = sdap_initgr_rfc2307_recv(subreq);
+        break;
+
+    case SDAP_SCHEMA_IPA_V1:
+    case SDAP_SCHEMA_AD:
+
+        ret = sdap_initgr_nested_recv(subreq);
+        break;
+
+    default:
+
+        ret = EINVAL;
+        break;
+    }
+
+    talloc_zfree(subreq);
     if (ret) {
-        DEBUG(2, ("Failed to store group. Ignoring.\n"));
+        tevent_req_error(req, ret);
+        return;
     }
 
-    /* unlock the operation so that we can proceed with the next result */
-    sdap_unlock_next_reply(state->op);
+    tevent_req_done(req);
 }
 
 int sdap_get_initgr_recv(struct tevent_req *req)
-- 
1.6.2.5

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to