From a31e80039a895de91f182eb8f0ee092b55edb9b0 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Mon, 23 Apr 2012 08:55:58 -0400
Subject: [PATCH 16/21] LDAP: Add helper routine to convert LDAP blob to SID
 string

---
 src/providers/ldap/ldap_common.c           |   37 ++++++
 src/providers/ldap/ldap_common.h           |    6 +
 src/providers/ldap/sdap_async_groups.c     |   24 +---
 src/providers/ldap/sdap_async_initgroups.c |  172 +++++++++++++++++++++++-----
 src/providers/ldap/sdap_async_users.c      |   24 +---
 5 files changed, 195 insertions(+), 68 deletions(-)

diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 6b03451adc844b5d05234f72fb29c63b0d6b82fa..8e117d26732f58482c0da528fae6844b4786c324 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -34,6 +34,7 @@
 #include "util/crypto/sss_crypto.h"
 
 #include "providers/ldap/ldap_opts.h"
+#include "providers/ldap/sdap_idmap.h"
 
 /* a fd the child process would log into */
 int ldap_child_debug_fd = -1;
@@ -1409,3 +1410,39 @@ char *sdap_get_id_specific_filter(TALLOC_CTX *mem_ctx,
     }
     return filter; /* NULL or not */
 }
+
+errno_t
+sdap_attrs_get_sid_str(TALLOC_CTX *mem_ctx,
+                       struct sdap_idmap_ctx *idmap_ctx,
+                       struct sysdb_attrs *sysdb_attrs,
+                       const char *sid_attr,
+                       char **_sid_str)
+{
+    errno_t ret;
+    enum idmap_error_code err;
+    struct ldb_message_element *el;
+    char *sid_str;
+
+    ret = sysdb_attrs_get_el(sysdb_attrs, sid_attr, &el);
+    if (ret != EOK || el->num_values != 1) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("No [%s] attribute while id-mapping. [%d][%s]\n",
+               sid_attr, el->num_values, strerror(ret)));
+        return ret;
+    }
+
+    err = sss_idmap_bin_sid_to_sid(idmap_ctx->map,
+                                   el->values[0].data,
+                                   el->values[0].length,
+                                   &sid_str);
+    if (err != IDMAP_SUCCESS) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("Could not convert SID: [%s]\n",
+               idmap_error_string(err)));
+        return EIO;
+    }
+
+    *_sid_str = talloc_steal(mem_ctx, sid_str);
+
+    return EOK;
+}
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index 44c53ed9445465419bd78c5261d40be61c947a00..8bd2584e1564cea5d3df9f2f47a345dd623efe4f 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -209,4 +209,10 @@ errno_t common_parse_search_base(TALLOC_CTX *mem_ctx,
                                  const char *old_filter,
                                  struct sdap_search_base ***_search_bases);
 
+errno_t
+sdap_attrs_get_sid_str(TALLOC_CTX *mem_ctx,
+                       struct sdap_idmap_ctx *idmap_ctx,
+                       struct sysdb_attrs *sysdb_attrs,
+                       const char *sid_attr,
+                       char **_sid_str);
 #endif /* _LDAP_COMMON_H_ */
diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
index 89882be04b826f9436f87409579b4ab73212d41c..67720025a8ed5c5b2c44b13b160d6ecb9833b2e3 100644
--- a/src/providers/ldap/sdap_async_groups.c
+++ b/src/providers/ldap/sdap_async_groups.c
@@ -198,7 +198,6 @@ static int sdap_save_group(TALLOC_CTX *memctx,
     TALLOC_CTX *tmpctx = NULL;
     bool posix_group;
     bool use_id_mapping = dp_opt_get_bool(opts->basic, SDAP_ID_MAPPING);
-    struct dom_sid *dom_sid;
     char *sid_str;
     char *dom_sid_str;
     enum idmap_error_code err;
@@ -229,25 +228,10 @@ static int sdap_save_group(TALLOC_CTX *memctx,
         DEBUG(SSSDBG_TRACE_LIBS,
               ("Mapping group [%s] objectSID to unix ID\n", name));
 
-        ret = sysdb_attrs_get_el(attrs,
-                                 opts->group_map[SDAP_AT_GROUP_OBJECTSID].sys_name,
-                                 &el);
-        if (ret != EOK || el->num_values != 1) {
-            DEBUG(SSSDBG_MINOR_FAILURE,
-                  ("No [%s] attribute for group [%s] while id-mapping\n",
-                   opts->group_map[SDAP_AT_GROUP_OBJECTSID].name,
-                   name));
-            goto fail;
-        }
-
-        ret = binary_to_dom_sid(tmpctx,
-                                el->values[0].data,
-                                el->values[0].length,
-                                &dom_sid);
-        if (ret != EOK) goto fail;
-
-        ret = dom_sid_to_string(tmpctx, dom_sid, &sid_str);
-        talloc_zfree(dom_sid);
+        ret = sdap_attrs_get_sid_str(
+                tmpctx, opts->idmap_ctx, attrs,
+                opts->group_map[SDAP_AT_GROUP_OBJECTSID].sys_name,
+                &sid_str);
         if (ret != EOK) goto fail;
 
         /* Add string representation to the cache for easier
diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
index b0b533242c83409d7ec1fd9ff721d7a59cb01556..ff9905f3141f231fa861f3087e76b7701cd0a0d8 100644
--- a/src/providers/ldap/sdap_async_initgroups.c
+++ b/src/providers/ldap/sdap_async_initgroups.c
@@ -25,6 +25,7 @@
 #include "db/sysdb.h"
 #include "providers/ldap/sdap_async_private.h"
 #include "providers/ldap/ldap_common.h"
+#include "providers/ldap/sdap_idmap.h"
 
 /* ==Save-fake-group-list=====================================*/
 static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
@@ -44,6 +45,9 @@ static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
     bool in_transaction = false;
     bool posix;
     time_t now;
+    char *sid_str;
+    enum idmap_error_code err;
+    bool use_id_mapping = dp_opt_get_bool(opts->basic, SDAP_ID_MAPPING);
 
     /* There are no groups in LDAP but we should add user to groups ?? */
     if (ldap_groups_count == 0) return EOK;
@@ -104,18 +108,50 @@ static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
 
             if (strcmp(name, missing[i]) == 0) {
                 posix = true;
-                ret = sysdb_attrs_get_uint32_t(ldap_groups[ai],
-                                               SYSDB_GIDNUM,
-                                               &gid);
-                if (ret == ENOENT || (ret == EOK && gid == 0)) {
-                    DEBUG(9, ("The group %s gid was %s\n",
-                              name, ret == ENOENT ? "missing" : "zero"));
-                    DEBUG(8, ("Marking group %s as non-posix and setting GID=0!\n", name));
-                    gid = 0;
-                    posix = false;
-                } else if (ret) {
-                    DEBUG(1, ("The GID attribute is malformed\n"));
-                    goto fail;
+
+                if (use_id_mapping) {
+                    DEBUG(SSSDBG_TRACE_LIBS,
+                          ("Mapping group [%s] objectSID to unix ID\n", name));
+
+                    ret = sdap_attrs_get_sid_str(
+                            tmp_ctx, opts->idmap_ctx, ldap_groups[ai],
+                            opts->group_map[SDAP_AT_GROUP_OBJECTSID].sys_name,
+                            &sid_str);
+                    if (ret != EOK) goto fail;
+
+                    DEBUG(SSSDBG_TRACE_INTERNAL,
+                          ("Group [%s] has objectSID [%s]\n",
+                           name, sid_str));
+
+                    /* Convert the SID into a UNIX group ID */
+                    err = sss_idmap_sid_to_unix(opts->idmap_ctx->map,
+                                                sid_str,
+                                                (uint32_t *)&gid);
+                    if (err != IDMAP_SUCCESS && err != IDMAP_NO_DOMAIN) {
+                        DEBUG(SSSDBG_MINOR_FAILURE,
+                              ("Could not convert objectSID [%s] to a UNIX ID\n",
+                               sid_str));
+                        ret = EIO;
+                        goto fail;
+                    }
+
+                    DEBUG(SSSDBG_TRACE_INTERNAL,
+                          ("Group [%s] has mapped gid [%lu]\n",
+                           name, (unsigned long)gid));
+                } else {
+                    ret = sysdb_attrs_get_uint32_t(ldap_groups[ai],
+                                                   SYSDB_GIDNUM,
+                                                   &gid);
+                    if (ret == ENOENT || (ret == EOK && gid == 0)) {
+                        DEBUG(9, ("The group %s gid was %s\n",
+                                  name, ret == ENOENT ? "missing" : "zero"));
+                        DEBUG(8, ("Marking group %s as non-posix and setting GID=0!\n", name));
+                        gid = 0;
+                        posix = false;
+                    } else if (ret) {
+                        DEBUG(1, ("The GID attribute is malformed\n"));
+                        goto fail;
+                    }
                 }
 
                 ret = sysdb_attrs_get_string(ldap_groups[ai],
@@ -2627,6 +2663,11 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
         break;
 
     case SDAP_SCHEMA_RFC2307BIS:
+    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 */
+
         ret = sysdb_attrs_get_string(state->orig_user,
                                      SYSDB_ORIG_DN,
                                      &orig_dn);
@@ -2647,11 +2688,6 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
         tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
         break;
     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 = sdap_initgr_nested_send(state, state->ev, state->opts,
                                          state->sysdb, state->dom, state->sh,
                                          state->orig_user, state->grp_attrs);
@@ -2677,11 +2713,24 @@ static void sdap_get_initgr_done(struct tevent_req *subreq)
     struct sdap_get_initgr_state *state = tevent_req_data(req,
                                                struct sdap_get_initgr_state);
     int ret;
+    TALLOC_CTX *tmp_ctx;
     gid_t primary_gid;
     char *gid;
+    char *sid_str;
+    char *dom_sid_str;
+    char *group_sid_str;
+    enum idmap_error_code err;
+    struct sdap_options *opts = state->opts;
+    bool use_id_mapping = dp_opt_get_bool(opts->basic, SDAP_ID_MAPPING);
 
     DEBUG(9, ("Initgroups done\n"));
 
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        tevent_req_error(req, ENOMEM);
+        return;
+    }
+
     switch (state->opts->schema_type) {
     case SDAP_SCHEMA_RFC2307:
         ret = sdap_initgr_rfc2307_recv(subreq);
@@ -2706,35 +2755,102 @@ static void sdap_get_initgr_done(struct tevent_req *subreq)
     if (ret) {
         DEBUG(9, ("Error in initgroups: [%d][%s]\n",
                   ret, strerror(ret)));
-        tevent_req_error(req, ret);
-        return;
+        goto fail;
     }
 
     /* We also need to update the user's primary group, since
      * the user may not be an explicit member of that group
      */
-    ret = sysdb_attrs_get_uint32_t(state->orig_user, SYSDB_GIDNUM, &primary_gid);
-    if (ret != EOK) {
-        DEBUG(6, ("Could not find user's primary GID\n"));
-        tevent_req_error(req, ret);
-        return;
+
+    if (use_id_mapping) {
+        DEBUG(SSSDBG_TRACE_LIBS,
+              ("Mapping primary group to unix ID\n"));
+
+        /* The primary group ID is just the RID part of the objectSID
+         * of the group. Generate the GID by adding this to the domain
+         * SID value.
+         */
+
+        /* Get the user SID so we can extract the domain SID
+         * from it.
+         */
+        ret = sdap_attrs_get_sid_str(
+                tmp_ctx, opts->idmap_ctx, state->orig_user,
+                opts->user_map[SDAP_AT_USER_OBJECTSID].sys_name,
+                &sid_str);
+        if (ret != EOK) goto fail;
+
+        /* Get the domain SID from the user SID */
+        ret = sdap_idmap_get_dom_sid_from_object(tmp_ctx, sid_str,
+                                                 &dom_sid_str);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  ("Could not parse domain SID from [%s]\n", sid_str));
+            goto fail;
+        }
+
+        ret = sysdb_attrs_get_uint32_t(
+                state->orig_user,
+                opts->user_map[SDAP_AT_USER_PRIMARY_GROUP].sys_name,
+                &primary_gid);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  ("no primary group ID provided\n"));
+            ret = EINVAL;
+            goto fail;
+        }
+
+        /* Add the RID to the end */
+        group_sid_str = talloc_asprintf(tmp_ctx, "%s-%lu",
+                                        dom_sid_str,
+                                        (unsigned long)primary_gid);
+        if (!group_sid_str) {
+            ret = ENOMEM;
+            goto fail;
+        }
+
+        /* Convert the SID into a UNIX group ID */
+        err = sss_idmap_sid_to_unix(opts->idmap_ctx->map,
+                                    sid_str,
+                                    (uint32_t *)&primary_gid);
+        if (err != IDMAP_SUCCESS) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  ("Could not convert objectSID [%s] to a UNIX ID\n",
+                   sid_str));
+            ret = EIO;
+            goto fail;
+        }
+    } else {
+        ret = sysdb_attrs_get_uint32_t(state->orig_user, SYSDB_GIDNUM,
+                                       &primary_gid);
+        if (ret != EOK) {
+            DEBUG(6, ("Could not find user's primary GID\n"));
+            goto fail;
+        }
     }
 
     gid = talloc_asprintf(state, "%lu", (unsigned long)primary_gid);
     if (gid == NULL) {
-        tevent_req_error(req, ENOMEM);
-        return;
+        ret = ENOMEM;
+        goto fail;
     }
 
     subreq = groups_get_send(req, state->ev, state->id_ctx, gid,
                              BE_FILTER_IDNUM, BE_ATTR_ALL);
     if (!subreq) {
-        tevent_req_error(req, ENOMEM);
-        return;
+        ret = ENOMEM;
+        goto fail;
     }
     tevent_req_set_callback(subreq, sdap_get_initgr_pgid, req);
 
+    talloc_free(tmp_ctx);
     tevent_req_done(req);
+    return;
+
+fail:
+    talloc_free(tmp_ctx);
+    tevent_req_error(req, ret);
+    return;
 }
 
 static void sdap_get_initgr_pgid(struct tevent_req *subreq)
diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
index c6534993a43391aee8136292e2a9f1c1686390bd..c894e874b11b57de150829e13125d481fcd20a3e 100644
--- a/src/providers/ldap/sdap_async_users.c
+++ b/src/providers/ldap/sdap_async_users.c
@@ -56,7 +56,6 @@ int sdap_save_user(TALLOC_CTX *memctx,
     char **missing = NULL;
     TALLOC_CTX *tmpctx = NULL;
     bool use_id_mapping = dp_opt_get_bool(opts->basic, SDAP_ID_MAPPING);
-    struct dom_sid *dom_sid;
     char *sid_str;
     char *dom_sid_str = NULL;
     char *group_sid_str;
@@ -122,25 +121,10 @@ int sdap_save_user(TALLOC_CTX *memctx,
         DEBUG(SSSDBG_TRACE_LIBS,
               ("Mapping user [%s] objectSID to unix ID\n", name));
 
-        ret = sysdb_attrs_get_el(attrs,
-                                 opts->user_map[SDAP_AT_USER_OBJECTSID].sys_name,
-                                 &el);
-        if (ret != EOK || el->num_values != 1) {
-            DEBUG(SSSDBG_MINOR_FAILURE,
-                  ("No [%s] attribute for user [%s] while id-mapping. [%d][%s]\n",
-                   opts->user_map[SDAP_AT_USER_OBJECTSID].name,
-                   name, el->num_values, strerror(ret)));
-            goto fail;
-        }
-
-        ret = binary_to_dom_sid(tmpctx,
-                                el->values[0].data,
-                                el->values[0].length,
-                                &dom_sid);
-        if (ret != EOK) goto fail;
-
-        ret = dom_sid_to_string(tmpctx, dom_sid, &sid_str);
-        talloc_zfree(dom_sid);
+        ret = sdap_attrs_get_sid_str(
+                tmpctx, opts->idmap_ctx, attrs,
+                opts->user_map[SDAP_AT_USER_OBJECTSID].sys_name,
+                &sid_str);
         if (ret != EOK) goto fail;
 
         /* Add string representation to the cache for easier
-- 
1.7.10

