[SSSD] [PATCHES] libsss_idmap enhancements

Sumit Bose sbose at redhat.com
Fri Jun 28 15:22:55 UTC 2013


On Fri, Jun 28, 2013 at 04:48:03PM +0200, Jakub Hrozek wrote:
> On Fri, Jun 28, 2013 at 12:38:50PM +0200, Sumit Bose wrote:
> > Hi,
> > 
> > the following 8 patches contain some enhancements for libsss_idmap which
> > will allow to handle external mapping as well and would make is possible
> > to use the calls from the library more generally in the LDAP based ID
> > providers.
> > 
> > See commit messages for more details.
> > 
> > bye,
> > Sumit
> 
> [PATCH 1/8] idmap: allow first RID to be set
> I think we should amend the header file to make it clear that some
> functions can return IDMAP_COLLISION. But it's OK to do it later via a
> ticket, no need to delay the release.

done

> 
> [PATCH 2/8] idmap: add optional unique range id
> Ack
> 
> [PATCH 3/8] idmap: add option to indicate external_mapping
> Ack
> 
> [PATCH 4/8] idmap: allow NULL domain sid for external mappings
> Ack
> 
> [PATCH 5/8] idmap: add calls to check if ID mapping conforms to ranges
> Ack, but I will add a newline after line 587 to separate two function
> calls before pushing.

done

> 
> [PATCH 6/8] idmap: add sss_idmap_domain_has_algorithmic_mapping
> 
> I think in that in sss_idmap_domain_has_algorithmic_mapping you should
> return IDMAP_NO_DOMAIN here instead:
> 
> +
> +    if (ctx->idmap_domain_info == NULL) {
> +        return IDMAP_SID_UNKNOWN;
> +    }

fixed

> +
> 
> [PATCH 7/8] Add sdap_idmap_domain_has_algorithmic_mapping()
> This is the patch that requires find_new_domain(). The code looks mostly
> good, but can you change the flow of the end of the function:
> 
> +    err = sss_idmap_domain_has_algorithmic_mapping(ctx->map, dom_sid, &has_algorithmic_mapping);
> +
> +    if (err == IDMAP_SUCCESS) {
> +        return has_algorithmic_mapping;
> +    } else  {
> +        return false;
> +    }
> +}
> 
> So that there is always a return outside if-else? Something like:
> -------------
> err = sss_idmap_domain_has_algorithmic_mapping(ctx->map, dom_sid, &has_algorithmic_mapping);
> if (err == IDMAP_SUCCESS) {
>     return has_algorithmic_mapping;
> }
> 
> return false;
> -------------
> 
> I find it much readable when there is an exit point and I think even our
> coding guidelines mandate that.

I will resend this patch later, I removed it from the updated versions
attached.

> 
> [PATCH 8/8] Add cmocka based tests for libsss_idmap
> Usable even without patch #7, so Ack. I'm glad we keep adding unit
> tests, that's really good.

Thank you for the review.

bye,
Sumit

> _______________________________________________
> sssd-devel mailing list
> sssd-devel at lists.fedorahosted.org
> https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
-------------- next part --------------
From 903e832df1cfbdffddf7a1d9140cdf282cec5e80 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 10 Jun 2013 11:55:16 +0200
Subject: [PATCH 1/7] idmap: allow first RID to be set

Currently libss_idmap implicitly assumes that the RID 0 is always mapped
to the first ID of the given range. This is not the case anymore when
multiple ranges are used e.g. for trusted domains in FreeIPA.

A new call sss_idmap_add_domain_ex() was added which can take the first
RID as an argument. This new call will get more options with other
patches hence I didn't change the library version with this patch.

Fixes https://fedorahosted.org/sssd/ticket/1938
---
 src/lib/idmap/sss_idmap.c |   99 ++++++++++++++++++++++++++++++++++++---------
 src/lib/idmap/sss_idmap.h |   30 +++++++++++++-
 2 files changed, 109 insertions(+), 20 deletions(-)

diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c
index 3a39aae..122f62f 100644
--- a/src/lib/idmap/sss_idmap.c
+++ b/src/lib/idmap/sss_idmap.c
@@ -38,6 +38,7 @@ struct idmap_domain_info {
     char *sid;
     struct sss_idmap_range *range;
     struct idmap_domain_info *next;
+    uint32_t first_rid;
 };
 
 static void *default_alloc(size_t size, void *pvt)
@@ -90,16 +91,16 @@ static struct sss_idmap_range *idmap_range_dup(struct sss_idmap_ctx *ctx,
     return new;
 }
 
-static bool id_is_in_range(uint32_t id, struct sss_idmap_range *range,
+static bool id_is_in_range(uint32_t id, struct idmap_domain_info *dom,
                            uint32_t *rid)
 {
-    if (id == 0 || range == NULL) {
+    if (id == 0 || dom == NULL || dom->range == NULL) {
         return false;
     }
 
-    if (id >= range->min && id <= range->max) {
+    if (id >= dom->range->min && id <= dom->range->max) {
         if (rid != NULL) {
-            *rid = id - range->min;
+            *rid = dom->first_rid + (id - dom->range->min);
         }
 
         return true;
@@ -330,12 +331,51 @@ enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx,
     return IDMAP_SUCCESS;
 }
 
-enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
-                                           const char *domain_name,
-                                           const char *domain_sid,
-                                           struct sss_idmap_range *range)
+static enum idmap_error_code dom_check_collision(
+                                             struct idmap_domain_info *dom_list,
+                                             struct idmap_domain_info *new_dom)
+{
+    struct idmap_domain_info *dom;
+
+    for (dom = dom_list; dom != NULL; dom = dom->next) {
+
+        /* check if ID ranges overlap */
+        if ((new_dom->range->min >= dom->range->min
+                && new_dom->range->min <= dom->range->max)
+            || (new_dom->range->max >= dom->range->min
+                && new_dom->range->max <= dom->range->max)) {
+            return IDMAP_COLLISION;
+        }
+
+        /* check if domain name and SID are consistent */
+        if ((strcasecmp(new_dom->name, dom->name) == 0
+                && strcasecmp(new_dom->sid, dom->sid) != 0)
+            || (strcasecmp(new_dom->name, dom->name) != 0
+                && strcasecmp(new_dom->sid, dom->sid) == 0)) {
+            return IDMAP_COLLISION;
+        }
+
+        /* check if RID ranges overlap */
+        if (strcasecmp(new_dom->name, dom->name) == 0
+                && strcasecmp(new_dom->sid, dom->sid) == 0
+                && new_dom->first_rid >= dom->first_rid
+                && new_dom->first_rid <=
+                    dom->first_rid + (dom->range->max - dom->range->min)) {
+            return IDMAP_COLLISION;
+        }
+    }
+
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
+                                              const char *domain_name,
+                                              const char *domain_sid,
+                                              struct sss_idmap_range *range,
+                                              uint32_t rid)
 {
     struct idmap_domain_info *dom = NULL;
+    enum idmap_error_code err;
 
     CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
 
@@ -372,6 +412,14 @@ enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
         goto fail;
     }
 
+    dom->first_rid = rid;
+
+    err = dom_check_collision(ctx->idmap_domain_info, dom);
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(dom, ctx->alloc_pvt);
+        return err;
+    }
+
     dom->next = ctx->idmap_domain_info;
     ctx->idmap_domain_info = dom;
 
@@ -385,6 +433,14 @@ fail:
     return IDMAP_OUT_OF_MEMORY;
 }
 
+enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
+                                           const char *domain_name,
+                                           const char *domain_sid,
+                                           struct sss_idmap_range *range)
+{
+    return sss_idmap_add_domain_ex(ctx, domain_name, domain_sid, range, 0);
+}
+
 static bool sss_idmap_sid_is_builtin(const char *sid)
 {
     if (strncmp(sid, "S-1-5-32-", 9) == 0) {
@@ -396,14 +452,16 @@ static bool sss_idmap_sid_is_builtin(const char *sid)
 
 enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
                                             const char *sid,
-                                            uint32_t *id)
+                                            uint32_t *_id)
 {
     struct idmap_domain_info *idmap_domain_info;
     size_t dom_len;
     long long rid;
     char *endptr;
+    uint32_t id;
+    bool no_range = false;
 
-    if (sid == NULL || id == NULL) {
+    if (sid == NULL || _id == NULL) {
         return IDMAP_ERROR;
     }
 
@@ -417,27 +475,30 @@ enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
 
     while (idmap_domain_info != NULL) {
         dom_len = strlen(idmap_domain_info->sid);
-        if (strlen(sid) > dom_len && sid[dom_len] == '-' &&
-            strncmp(sid, idmap_domain_info->sid, dom_len) == 0) {
+        if (strlen(sid) > dom_len && sid[dom_len] == '-'
+                && strncmp(sid, idmap_domain_info->sid, dom_len) == 0) {
             errno = 0;
             rid = strtoull(sid + dom_len + 1, &endptr, 10);
             if (errno != 0 || rid > UINT32_MAX || *endptr != '\0') {
                 return IDMAP_SID_INVALID;
             }
 
-            if (rid + idmap_domain_info->range->min >
-                                                idmap_domain_info->range->max) {
-                return IDMAP_NO_RANGE;
+            if (rid >= idmap_domain_info->first_rid) {
+                id = idmap_domain_info->range->min
+                        + (rid - idmap_domain_info->first_rid);
+                if (id <= idmap_domain_info->range->max) {
+                    *_id = id;
+                    return IDMAP_SUCCESS;
+                }
             }
 
-            *id = rid + idmap_domain_info->range->min;
-            return IDMAP_SUCCESS;
+            no_range = true;
         }
 
         idmap_domain_info = idmap_domain_info->next;
     }
 
-    return IDMAP_NO_DOMAIN;
+    return no_range ? IDMAP_NO_RANGE : IDMAP_NO_DOMAIN;
 }
 
 enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx,
@@ -455,7 +516,7 @@ enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx,
     idmap_domain_info = ctx->idmap_domain_info;
 
     while (idmap_domain_info != NULL) {
-        if (id_is_in_range(id, idmap_domain_info->range, &rid)) {
+        if (id_is_in_range(id, idmap_domain_info, &rid)) {
             len = snprintf(NULL, 0, SID_FMT, idmap_domain_info->sid, rid);
             if (len <= 0 || len > SID_STR_MAX_LEN) {
                 return IDMAP_ERROR;
diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h
index 9710501..3beeca1 100644
--- a/src/lib/idmap/sss_idmap.h
+++ b/src/lib/idmap/sss_idmap.h
@@ -74,7 +74,10 @@ enum idmap_error_code {
     IDMAP_BUILTIN_SID,
 
     /** No more free slices */
-    IDMAP_OUT_OF_SLICES
+    IDMAP_OUT_OF_SLICES,
+
+    /** New domain collides with existing one */
+    IDMAP_COLLISION
 };
 
 /**
@@ -237,6 +240,7 @@ enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx,
  *                          context
  *  - #IDMAP_SID_INVALID:   Invalid SID provided
  *  - #IDMAP_NO_DOMAIN:     No domain domain name given
+ *  - #IDMAP_COLLISION:     New domain collides with existing one
  */
 enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
                                            const char *domain_name,
@@ -244,6 +248,30 @@ enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
                                            struct sss_idmap_range *range);
 
 /**
+ * @brief Add a domain with the first mappable RID to the idmap context
+ *
+ * @param[in] ctx         Idmap context
+ * @param[in] domain_name Zero-terminated string with the domain name
+ * @param[in] domain_sid  Zero-terminated string representation of the domain
+ *                        SID (S-1-15-.....)
+ * @param[in] range       TBD Some information about the id ranges of this
+ *                        domain
+ * @param[in] rid         The RID that should be mapped to the first ID of the
+ *                        given range.
+ *
+ * @return
+ *  - #IDMAP_OUT_OF_MEMORY: Insufficient memory to store the data in the idmap
+ *                          context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_NO_DOMAIN:     No domain domain name given
+ *  - #IDMAP_COLLISION:     New domain collides with existing one
+ */
+enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
+                                              const char *domain_name,
+                                              const char *domain_sid,
+                                              struct sss_idmap_range *range,
+                                              uint32_t rid);
+/**
  * @brief Translate SID to a unix UID or GID
  *
  * @param[in] ctx Idmap context
-- 
1.7.7.6

-------------- next part --------------
From 42d0c406f120ea0c12492e0a83fbebbddf2d2f9f Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 10 Jun 2013 12:06:27 +0200
Subject: [PATCH 2/7] idmap: add optional unique range id

To be able to detect configuration changes in idranges managed by
FreeIPA an identifier should be stored on the client together with the
other idrange related data.

Fixes https://fedorahosted.org/sssd/ticket/1979
---
 src/lib/idmap/sss_idmap.c |   15 ++++++++++++++-
 src/lib/idmap/sss_idmap.h |    3 +++
 2 files changed, 17 insertions(+), 1 deletions(-)

diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c
index 122f62f..b04d849 100644
--- a/src/lib/idmap/sss_idmap.c
+++ b/src/lib/idmap/sss_idmap.c
@@ -39,6 +39,7 @@ struct idmap_domain_info {
     struct sss_idmap_range *range;
     struct idmap_domain_info *next;
     uint32_t first_rid;
+    char *range_id;
 };
 
 static void *default_alloc(size_t size, void *pvt)
@@ -339,6 +340,9 @@ static enum idmap_error_code dom_check_collision(
 
     for (dom = dom_list; dom != NULL; dom = dom->next) {
 
+        /* TODO: if both ranges have the same ID check if an update is
+         * needed. */
+
         /* check if ID ranges overlap */
         if ((new_dom->range->min >= dom->range->min
                 && new_dom->range->min <= dom->range->max)
@@ -372,6 +376,7 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
                                               const char *domain_name,
                                               const char *domain_sid,
                                               struct sss_idmap_range *range,
+                                              const char *range_id,
                                               uint32_t rid)
 {
     struct idmap_domain_info *dom = NULL;
@@ -412,6 +417,13 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
         goto fail;
     }
 
+    if (range_id != NULL) {
+        dom->range_id = idmap_strdup(ctx, range_id);
+        if (dom->range_id == NULL) {
+            goto fail;
+        }
+    }
+
     dom->first_rid = rid;
 
     err = dom_check_collision(ctx->idmap_domain_info, dom);
@@ -438,7 +450,8 @@ enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
                                            const char *domain_sid,
                                            struct sss_idmap_range *range)
 {
-    return sss_idmap_add_domain_ex(ctx, domain_name, domain_sid, range, 0);
+    return sss_idmap_add_domain_ex(ctx, domain_name, domain_sid, range, NULL,
+                                   0);
 }
 
 static bool sss_idmap_sid_is_builtin(const char *sid)
diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h
index 3beeca1..5536aeb 100644
--- a/src/lib/idmap/sss_idmap.h
+++ b/src/lib/idmap/sss_idmap.h
@@ -256,6 +256,8 @@ enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
  *                        SID (S-1-15-.....)
  * @param[in] range       TBD Some information about the id ranges of this
  *                        domain
+ * @param[in] range_id    optional unique identifier of a range, it is needed
+ *                        to allow updates at runtime
  * @param[in] rid         The RID that should be mapped to the first ID of the
  *                        given range.
  *
@@ -270,6 +272,7 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
                                               const char *domain_name,
                                               const char *domain_sid,
                                               struct sss_idmap_range *range,
+                                              const char *range_id,
                                               uint32_t rid);
 /**
  * @brief Translate SID to a unix UID or GID
-- 
1.7.7.6

-------------- next part --------------
From d69f6024dcb067be86be0d4d83f7fc82bef09271 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 10 Jun 2013 13:24:46 +0200
Subject: [PATCH 3/7] idmap: add option to indicate external_mapping

The idea is that ranges for IDs from AD can be used in libsss_idmap as
well, but whenever a mapping is requested for this range a specific
error code IDMAP_EXTERNAL is returned to tell SSSD to do
an AD lookup. This way SSSD does not need to inspect the ranges itself
but all is done inside if libsss_idmap.

Fixes https://fedorahosted.org/sssd/ticket/1960
---
 src/lib/idmap/sss_idmap.c |   25 +++++++++++++++++++++++--
 src/lib/idmap/sss_idmap.h |   22 ++++++++++++++++++++--
 2 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c
index b04d849..0a145c4 100644
--- a/src/lib/idmap/sss_idmap.c
+++ b/src/lib/idmap/sss_idmap.c
@@ -40,6 +40,7 @@ struct idmap_domain_info {
     struct idmap_domain_info *next;
     uint32_t first_rid;
     char *range_id;
+    bool external_mapping;
 };
 
 static void *default_alloc(size_t size, void *pvt)
@@ -359,9 +360,17 @@ static enum idmap_error_code dom_check_collision(
             return IDMAP_COLLISION;
         }
 
+        /* check if external_mapping is consistent */
+        if (strcasecmp(new_dom->name, dom->name) == 0
+                && strcasecmp(new_dom->sid, dom->sid) == 0
+                && new_dom->external_mapping != dom->external_mapping) {
+            return IDMAP_COLLISION;
+        }
+
         /* check if RID ranges overlap */
         if (strcasecmp(new_dom->name, dom->name) == 0
                 && strcasecmp(new_dom->sid, dom->sid) == 0
+                && new_dom->external_mapping == false
                 && new_dom->first_rid >= dom->first_rid
                 && new_dom->first_rid <=
                     dom->first_rid + (dom->range->max - dom->range->min)) {
@@ -377,7 +386,8 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
                                               const char *domain_sid,
                                               struct sss_idmap_range *range,
                                               const char *range_id,
-                                              uint32_t rid)
+                                              uint32_t rid,
+                                              bool external_mapping)
 {
     struct idmap_domain_info *dom = NULL;
     enum idmap_error_code err;
@@ -425,6 +435,7 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
     }
 
     dom->first_rid = rid;
+    dom->external_mapping = external_mapping;
 
     err = dom_check_collision(ctx->idmap_domain_info, dom);
     if (err != IDMAP_SUCCESS) {
@@ -451,7 +462,7 @@ enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
                                            struct sss_idmap_range *range)
 {
     return sss_idmap_add_domain_ex(ctx, domain_name, domain_sid, range, NULL,
-                                   0);
+                                   0, false);
 }
 
 static bool sss_idmap_sid_is_builtin(const char *sid)
@@ -490,6 +501,11 @@ enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
         dom_len = strlen(idmap_domain_info->sid);
         if (strlen(sid) > dom_len && sid[dom_len] == '-'
                 && strncmp(sid, idmap_domain_info->sid, dom_len) == 0) {
+
+            if (idmap_domain_info->external_mapping == true) {
+                return IDMAP_EXTERNAL;
+            }
+
             errno = 0;
             rid = strtoull(sid + dom_len + 1, &endptr, 10);
             if (errno != 0 || rid > UINT32_MAX || *endptr != '\0') {
@@ -530,6 +546,11 @@ enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx,
 
     while (idmap_domain_info != NULL) {
         if (id_is_in_range(id, idmap_domain_info, &rid)) {
+
+            if (idmap_domain_info->external_mapping == true) {
+                return IDMAP_EXTERNAL;
+            }
+
             len = snprintf(NULL, 0, SID_FMT, idmap_domain_info->sid, rid);
             if (len <= 0 || len > SID_STR_MAX_LEN) {
                 return IDMAP_ERROR;
diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h
index 5536aeb..824a7c6 100644
--- a/src/lib/idmap/sss_idmap.h
+++ b/src/lib/idmap/sss_idmap.h
@@ -77,7 +77,10 @@ enum idmap_error_code {
     IDMAP_OUT_OF_SLICES,
 
     /** New domain collides with existing one */
-    IDMAP_COLLISION
+    IDMAP_COLLISION,
+
+    /** External source should be consulted for idmapping */
+    IDMAP_EXTERNAL
 };
 
 /**
@@ -260,6 +263,13 @@ enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
  *                        to allow updates at runtime
  * @param[in] rid         The RID that should be mapped to the first ID of the
  *                        given range.
+ * @param[in] external_mapping  If set to true the ID will not be mapped
+ *                        algorithmically, but the *_to_unix and *_unix_to_*
+ *                        calls will return IDMAP_EXTERNAL to instruct the
+ *                        caller to check external sources. For a single
+ *                        domain all ranges must be of the same type. It is
+ *                        not possible to mix algorithmic and external
+ *                        mapping.
  *
  * @return
  *  - #IDMAP_OUT_OF_MEMORY: Insufficient memory to store the data in the idmap
@@ -273,7 +283,8 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
                                               const char *domain_sid,
                                               struct sss_idmap_range *range,
                                               const char *range_id,
-                                              uint32_t rid);
+                                              uint32_t rid,
+                                              bool external_mapping);
 /**
  * @brief Translate SID to a unix UID or GID
  *
@@ -286,6 +297,7 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
  *  - #IDMAP_SID_INVALID:   Invalid SID provided
  *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
  *                          idmap context
+ *  - #IDMAP_EXTERNAL:      external source is authoritative for mapping
  */
 enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
                                             const char *sid,
@@ -303,6 +315,7 @@ enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
  *  - #IDMAP_SID_INVALID:   Invalid SID provided
  *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
  *                          idmap context
+ *  - #IDMAP_EXTERNAL:      external source is authoritative for mapping
  */
 enum idmap_error_code sss_idmap_dom_sid_to_unix(struct sss_idmap_ctx *ctx,
                                                 struct sss_dom_sid *dom_sid,
@@ -321,6 +334,7 @@ enum idmap_error_code sss_idmap_dom_sid_to_unix(struct sss_idmap_ctx *ctx,
  *  - #IDMAP_SID_INVALID:   Invalid SID provided
  *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
  *                          idmap context
+ *  - #IDMAP_EXTERNAL:      external source is authoritative for mapping
  */
 enum idmap_error_code sss_idmap_bin_sid_to_unix(struct sss_idmap_ctx *ctx,
                                                 uint8_t *bin_sid,
@@ -339,6 +353,7 @@ enum idmap_error_code sss_idmap_bin_sid_to_unix(struct sss_idmap_ctx *ctx,
  *  - #IDMAP_SID_INVALID:   Invalid SID provided
  *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
  *                          idmap context
+ *  - #IDMAP_EXTERNAL:      external source is authoritative for mapping
  */
 enum idmap_error_code sss_idmap_smb_sid_to_unix(struct sss_idmap_ctx *ctx,
                                                 struct dom_sid *smb_sid,
@@ -356,6 +371,7 @@ enum idmap_error_code sss_idmap_smb_sid_to_unix(struct sss_idmap_ctx *ctx,
  *  - #IDMAP_NO_DOMAIN: No domains are added to the idmap context
  *  - #IDMAP_NO_RANGE:  The provided ID cannot be found in the domains added
  *                      to the idmap context
+ *  - #IDMAP_EXTERNAL:  external source is authoritative for mapping
  */
 enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx,
                                             uint32_t id,
@@ -372,6 +388,7 @@ enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx,
  *  - #IDMAP_NO_DOMAIN: No domains are added to the idmap context
  *  - #IDMAP_NO_RANGE:  The provided ID cannot be found in the domains added
  *                      to the idmap context
+ *  - #IDMAP_EXTERNAL:  external source is authoritative for mapping
  */
 enum idmap_error_code sss_idmap_unix_to_dom_sid(struct sss_idmap_ctx *ctx,
                                                 uint32_t id,
@@ -390,6 +407,7 @@ enum idmap_error_code sss_idmap_unix_to_dom_sid(struct sss_idmap_ctx *ctx,
  *  - #IDMAP_NO_DOMAIN: No domains are added to the idmap context
  *  - #IDMAP_NO_RANGE:  The provided ID cannot be found in the domains added
  *                      to the idmap context
+ *  - #IDMAP_EXTERNAL:  external source is authoritative for mapping
  */
 enum idmap_error_code sss_idmap_unix_to_bin_sid(struct sss_idmap_ctx *ctx,
                                                 uint32_t id,
-- 
1.7.7.6

-------------- next part --------------
From c885277766728ee81ffde891b04eb2f04f0914bf Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 17 Jun 2013 16:25:18 +0200
Subject: [PATCH 4/7] idmap: allow NULL domain sid for external mappings

Since it is planned that the LDAP based ID providers (LDAP, AD, IPA)
will always use libsss_idmap to map ID or get information about how to
map it, it must be possible to add domains to libsss_idmap which do not
have a SID or where is SID is not known when external mapping is used.
Algorithmic mapping always requires a domain SID.

Fixes https://fedorahosted.org/sssd/ticket/1960
---
 src/lib/idmap/sss_idmap.c |   76 ++++++++++++++++++++++++++-------------------
 1 files changed, 44 insertions(+), 32 deletions(-)

diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c
index 0a145c4..ca7c5a0 100644
--- a/src/lib/idmap/sss_idmap.c
+++ b/src/lib/idmap/sss_idmap.c
@@ -338,6 +338,8 @@ static enum idmap_error_code dom_check_collision(
                                              struct idmap_domain_info *new_dom)
 {
     struct idmap_domain_info *dom;
+    bool names_equal;
+    bool sids_equal;
 
     for (dom = dom_list; dom != NULL; dom = dom->next) {
 
@@ -352,24 +354,24 @@ static enum idmap_error_code dom_check_collision(
             return IDMAP_COLLISION;
         }
 
+        names_equal = (strcasecmp(new_dom->name, dom->name) == 0);
+        sids_equal = ((new_dom->sid == NULL && dom->sid == NULL)
+                        || (new_dom->sid != NULL && dom->sid != NULL
+                            && strcasecmp(new_dom->sid, dom->sid) == 0));
+
         /* check if domain name and SID are consistent */
-        if ((strcasecmp(new_dom->name, dom->name) == 0
-                && strcasecmp(new_dom->sid, dom->sid) != 0)
-            || (strcasecmp(new_dom->name, dom->name) != 0
-                && strcasecmp(new_dom->sid, dom->sid) == 0)) {
+        if ((names_equal && !sids_equal) || (!names_equal && sids_equal)) {
             return IDMAP_COLLISION;
         }
 
         /* check if external_mapping is consistent */
-        if (strcasecmp(new_dom->name, dom->name) == 0
-                && strcasecmp(new_dom->sid, dom->sid) == 0
+        if (names_equal && sids_equal
                 && new_dom->external_mapping != dom->external_mapping) {
             return IDMAP_COLLISION;
         }
 
         /* check if RID ranges overlap */
-        if (strcasecmp(new_dom->name, dom->name) == 0
-                && strcasecmp(new_dom->sid, dom->sid) == 0
+        if (names_equal && sids_equal
                 && new_dom->external_mapping == false
                 && new_dom->first_rid >= dom->first_rid
                 && new_dom->first_rid <=
@@ -402,7 +404,12 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
         return IDMAP_NO_RANGE;
     }
 
-    if (!is_domain_sid(domain_sid)) {
+    /* For algorithmic mapping a valid domain SID is required, for external
+     * mapping it may be NULL, but if set it should be valid. */
+    if ((!external_mapping && !is_domain_sid(domain_sid))
+            || (external_mapping
+                && domain_sid != NULL
+                && !is_domain_sid(domain_sid))) {
         return IDMAP_SID_INVALID;
     }
 
@@ -417,9 +424,11 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
         goto fail;
     }
 
-    dom->sid = idmap_strdup(ctx, domain_sid);
-    if (dom->sid == NULL) {
-        goto fail;
+    if (domain_sid != NULL) {
+        dom->sid = idmap_strdup(ctx, domain_sid);
+        if (dom->sid == NULL) {
+            goto fail;
+        }
     }
 
     dom->range = idmap_range_dup(ctx, range);
@@ -498,30 +507,32 @@ enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
     }
 
     while (idmap_domain_info != NULL) {
-        dom_len = strlen(idmap_domain_info->sid);
-        if (strlen(sid) > dom_len && sid[dom_len] == '-'
-                && strncmp(sid, idmap_domain_info->sid, dom_len) == 0) {
+        if (idmap_domain_info->sid != NULL) {
+            dom_len = strlen(idmap_domain_info->sid);
+            if (strlen(sid) > dom_len && sid[dom_len] == '-'
+                    && strncmp(sid, idmap_domain_info->sid, dom_len) == 0) {
 
-            if (idmap_domain_info->external_mapping == true) {
-                return IDMAP_EXTERNAL;
-            }
+                if (idmap_domain_info->external_mapping == true) {
+                    return IDMAP_EXTERNAL;
+                }
 
-            errno = 0;
-            rid = strtoull(sid + dom_len + 1, &endptr, 10);
-            if (errno != 0 || rid > UINT32_MAX || *endptr != '\0') {
-                return IDMAP_SID_INVALID;
-            }
+                errno = 0;
+                rid = strtoull(sid + dom_len + 1, &endptr, 10);
+                if (errno != 0 || rid > UINT32_MAX || *endptr != '\0') {
+                    return IDMAP_SID_INVALID;
+                }
 
-            if (rid >= idmap_domain_info->first_rid) {
-                id = idmap_domain_info->range->min
-                        + (rid - idmap_domain_info->first_rid);
-                if (id <= idmap_domain_info->range->max) {
-                    *_id = id;
-                    return IDMAP_SUCCESS;
+                if (rid >= idmap_domain_info->first_rid) {
+                    id = idmap_domain_info->range->min
+                            + (rid - idmap_domain_info->first_rid);
+                    if (id <= idmap_domain_info->range->max) {
+                        *_id = id;
+                        return IDMAP_SUCCESS;
+                    }
                 }
-            }
 
-            no_range = true;
+                no_range = true;
+            }
         }
 
         idmap_domain_info = idmap_domain_info->next;
@@ -547,7 +558,8 @@ enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx,
     while (idmap_domain_info != NULL) {
         if (id_is_in_range(id, idmap_domain_info, &rid)) {
 
-            if (idmap_domain_info->external_mapping == true) {
+            if (idmap_domain_info->external_mapping == true
+                    || idmap_domain_info->sid == NULL) {
                 return IDMAP_EXTERNAL;
             }
 
-- 
1.7.7.6

-------------- next part --------------
From a4fbfcfad3e49f7a14433253b144f6ccd33593a1 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 10 Jun 2013 16:47:14 +0200
Subject: [PATCH 5/7] idmap: add calls to check if ID mapping conforms to
 ranges

When ID are mapped externally it must be checked if the extern ID falls
into the right configured range to avoid ID conflicts.

Fixes https://fedorahosted.org/sssd/ticket/1960
---
 src/lib/idmap/sss_idmap.c |  111 +++++++++++++++++++++++++++++++++++++++++++++
 src/lib/idmap/sss_idmap.h |   75 ++++++++++++++++++++++++++++++
 2 files changed, 186 insertions(+), 0 deletions(-)

diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c
index ca7c5a0..34539ce 100644
--- a/src/lib/idmap/sss_idmap.c
+++ b/src/lib/idmap/sss_idmap.c
@@ -541,6 +541,51 @@ enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
     return no_range ? IDMAP_NO_RANGE : IDMAP_NO_DOMAIN;
 }
 
+enum idmap_error_code sss_idmap_check_sid_unix(struct sss_idmap_ctx *ctx,
+                                               const char *sid,
+                                               uint32_t id)
+{
+    struct idmap_domain_info *idmap_domain_info;
+    size_t dom_len;
+    bool no_range = false;
+
+    if (sid == NULL) {
+        return IDMAP_ERROR;
+    }
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    if (ctx->idmap_domain_info == NULL) {
+        return IDMAP_NO_DOMAIN;
+    }
+
+    idmap_domain_info = ctx->idmap_domain_info;
+
+    if (sss_idmap_sid_is_builtin(sid)) {
+        return IDMAP_BUILTIN_SID;
+    }
+
+    while (idmap_domain_info != NULL) {
+        if (idmap_domain_info->sid != NULL) {
+            dom_len = strlen(idmap_domain_info->sid);
+            if (strlen(sid) > dom_len && sid[dom_len] == '-'
+                    && strncmp(sid, idmap_domain_info->sid, dom_len) == 0) {
+
+                if (id >= idmap_domain_info->range->min
+                    && id <= idmap_domain_info->range->max) {
+                    return IDMAP_SUCCESS;
+                }
+
+                no_range = true;
+            }
+        }
+
+        idmap_domain_info = idmap_domain_info->next;
+    }
+
+    return no_range ? IDMAP_NO_RANGE : IDMAP_SID_UNKNOWN;
+}
+
 enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx,
                                             uint32_t id,
                                             char **_sid)
@@ -656,6 +701,72 @@ done:
     return err;
 }
 
+enum idmap_error_code sss_idmap_check_dom_sid_to_unix(struct sss_idmap_ctx *ctx,
+                                                    struct sss_dom_sid *dom_sid,
+                                                    uint32_t id)
+{
+    enum idmap_error_code err;
+    char *sid;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    err = sss_idmap_dom_sid_to_sid(ctx, dom_sid, &sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_check_sid_unix(ctx, sid, id);
+
+done:
+    ctx->free_func(sid, ctx->alloc_pvt);
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_check_bin_sid_unix(struct sss_idmap_ctx *ctx,
+                                                   uint8_t *bin_sid,
+                                                   size_t length,
+                                                   uint32_t id)
+{
+    enum idmap_error_code err;
+    char *sid;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    err = sss_idmap_bin_sid_to_sid(ctx, bin_sid, length, &sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_check_sid_unix(ctx, sid, id);
+
+done:
+    ctx->free_func(sid, ctx->alloc_pvt);
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_check_smb_sid_unix(struct sss_idmap_ctx *ctx,
+                                                   struct dom_sid *smb_sid,
+                                                   uint32_t id)
+{
+    enum idmap_error_code err;
+    char *sid;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    err = sss_idmap_smb_sid_to_sid(ctx, smb_sid, &sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_check_sid_unix(ctx, sid, id);
+
+done:
+    ctx->free_func(sid, ctx->alloc_pvt);
+
+    return err;
+}
 enum idmap_error_code sss_idmap_unix_to_dom_sid(struct sss_idmap_ctx *ctx,
                                                 uint32_t id,
                                                 struct sss_dom_sid **_dom_sid)
diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h
index 824a7c6..c9e996d 100644
--- a/src/lib/idmap/sss_idmap.h
+++ b/src/lib/idmap/sss_idmap.h
@@ -360,6 +360,81 @@ enum idmap_error_code sss_idmap_smb_sid_to_unix(struct sss_idmap_ctx *ctx,
                                                 uint32_t *id);
 
 /**
+ * @brief Check if a SID and a unix UID or GID belong to the same range
+ *
+ * @param[in] ctx Idmap context
+ * @param[in] sid Zero-terminated string representation of the SID
+ * @param[in] id  Unix UID or GID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domains are added to the idmap context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
+ *                          idmap context
+ *  - #IDMAP_NO_RANGE       No matching ID range found
+ */
+enum idmap_error_code sss_idmap_check_sid_unix(struct sss_idmap_ctx *ctx,
+                                               const char *sid,
+                                               uint32_t id);
+
+/**
+ * @brief Check if a SID structure and a unix UID or GID belong to the same range
+ *
+ * @param[in] ctx     Idmap context
+ * @param[in] dom_sid SID structure
+ * @param[in] id      Unix UID or GID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domains are added to the idmap context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
+ *                          idmap context
+ *  - #IDMAP_NO_RANGE       No matching ID range found
+ */
+enum idmap_error_code sss_idmap_check_dom_sid_unix(struct sss_idmap_ctx *ctx,
+                                                   struct sss_dom_sid *dom_sid,
+                                                   uint32_t id);
+
+/**
+ * @brief Check if a binary SID and a unix UID or GID belong to the same range
+ *
+ * @param[in] ctx     Idmap context
+ * @param[in] bin_sid Array with the binary SID
+ * @param[in] length  Size of the array containing the binary SID
+ * @param[in] id      Unix UID or GID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domains are added to the idmap context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
+ *                          idmap context
+ *  - #IDMAP_NO_RANGE       No matching ID range found
+ */
+enum idmap_error_code sss_idmap_check_bin_sid_unix(struct sss_idmap_ctx *ctx,
+                                                   uint8_t *bin_sid,
+                                                   size_t length,
+                                                   uint32_t id);
+
+/**
+ * @brief Check if a Samba dom_sid structure and a unix UID or GID belong to
+ * the same range
+ *
+ * @param[in] ctx     Idmap context
+ * @param[in] smb_sid Samba dom_sid structure
+ * @param[in] id      Unix UID or GID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domains are added to the idmap context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
+ *                          idmap context
+ *  - #IDMAP_NO_RANGE       No matching ID range found
+ */
+enum idmap_error_code sss_idmap_check_smb_sid_unix(struct sss_idmap_ctx *ctx,
+                                                   struct dom_sid *smb_sid,
+                                                   uint32_t id);
+
+/**
  * @brief Translate unix UID or GID to a SID
  *
  * @param[in] ctx  Idmap context
-- 
1.7.7.6

-------------- next part --------------
From 13ef98903da08c6ddef83596030347c4cdff6288 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Tue, 11 Jun 2013 10:54:05 +0200
Subject: [PATCH 6/7] idmap: add sss_idmap_domain_has_algorithmic_mapping

With this call it can be checked if for a given domain algorithmic
mapping is available or if the ID must be read from an external source.
The default if an error occurs or no matching range was found is false,
i.e external mapping, to meet the requirements for simple LDAP based
domains where only external mapping is available.

Fixes https://fedorahosted.org/sssd/ticket/1960
---
 src/lib/idmap/sss_idmap.c |   41 +++++++++++++++++++++++++++++++++++++++++
 src/lib/idmap/sss_idmap.h |   14 ++++++++++++++
 2 files changed, 55 insertions(+), 0 deletions(-)

diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c
index 34539ce..c7ac0c7 100644
--- a/src/lib/idmap/sss_idmap.c
+++ b/src/lib/idmap/sss_idmap.c
@@ -898,3 +898,44 @@ sss_idmap_ctx_get_rangesize(struct sss_idmap_ctx *ctx, id_t *_rangesize)
     *_rangesize =  ctx->idmap_opts.rangesize;
     return IDMAP_SUCCESS;
 }
+
+enum idmap_error_code
+sss_idmap_domain_has_algorithmic_mapping(struct sss_idmap_ctx *ctx,
+                                         const char *dom_sid,
+                                         bool *has_algorithmic_mapping)
+{
+    struct idmap_domain_info *idmap_domain_info;
+    size_t len;
+    size_t dom_sid_len;
+
+    if (dom_sid == NULL) {
+        return IDMAP_SID_INVALID;
+    }
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    if (ctx->idmap_domain_info == NULL) {
+        return IDMAP_NO_DOMAIN;
+    }
+
+    idmap_domain_info = ctx->idmap_domain_info;
+
+    while (idmap_domain_info != NULL) {
+        if (idmap_domain_info->sid != NULL) {
+            len = strlen(idmap_domain_info->sid);
+            dom_sid_len = strlen(dom_sid);
+            if (((dom_sid_len > len && dom_sid[len] == '-')
+                        || dom_sid_len == len)
+                    && strncmp(dom_sid, idmap_domain_info->sid, len) == 0) {
+
+                *has_algorithmic_mapping = !idmap_domain_info->external_mapping;
+                return IDMAP_SUCCESS;
+
+            }
+        }
+
+        idmap_domain_info = idmap_domain_info->next;
+    }
+
+    return IDMAP_SID_UNKNOWN;
+}
diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h
index c9e996d..d326469 100644
--- a/src/lib/idmap/sss_idmap.h
+++ b/src/lib/idmap/sss_idmap.h
@@ -521,6 +521,20 @@ const char *idmap_error_string(enum idmap_error_code err);
 bool is_domain_sid(const char *str);
 
 /**
+ * @brief Check if a domain is configured with algorithmic mapping
+ *
+ * @param[in] ctx      Idmap context
+ * @param[in] dom_sid  SID string, can be either a domain SID or an object SID
+ *
+ * @return
+ * TODO ....
+ */
+enum idmap_error_code
+sss_idmap_domain_has_algorithmic_mapping(struct sss_idmap_ctx *ctx,
+                                         const char *dom_sid,
+                                         bool *has_algorithmic_mapping);
+
+/**
  * @brief Convert binary SID to SID structure
  *
  * @param[in] ctx      Idmap context
-- 
1.7.7.6

-------------- next part --------------
From c0a86346c2a23ead5e41ff8eb986243947dd2a3d Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 10 Jun 2013 12:06:45 +0200
Subject: [PATCH 7/7] Add cmocka based tests for libsss_idmap

This patch implements some unit tests for the recent enhancements to
libsss_idmap.
---
 Makefile.am                       |   14 ++-
 src/tests/cmocka/test_sss_idmap.c |  421 +++++++++++++++++++++++++++++++++++++
 2 files changed, 434 insertions(+), 1 deletions(-)
 create mode 100644 src/tests/cmocka/test_sss_idmap.c

diff --git a/Makefile.am b/Makefile.am
index bd0e928..0cf6d92 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -148,7 +148,8 @@ if HAVE_CMOCKA
         test-io \
         sss_nss_idmap-tests \
         dyndns-tests \
-        fqnames-tests
+        fqnames-tests \
+        test_sss_idmap
 endif
 
 check_PROGRAMS = \
@@ -1316,6 +1317,17 @@ fqnames_tests_LDADD = \
     $(SSSD_INTERNAL_LTLIBS) \
     libsss_test_common.la
 
+test_sss_idmap_SOURCES = \
+    $(TEST_MOCK_OBJ) \
+    src/tests/cmocka/test_sss_idmap.c
+test_sss_idmap_CFLAGS = \
+    $(AM_CFLAGS)
+test_sss_idmap_LDADD = \
+    $(CMOCKA_LIBS) \
+    libsss_idmap.la \
+    $(SSSD_INTERNAL_LTLIBS) \
+    libsss_test_common.la
+
 endif
 
 noinst_PROGRAMS = pam_test_client
diff --git a/src/tests/cmocka/test_sss_idmap.c b/src/tests/cmocka/test_sss_idmap.c
new file mode 100644
index 0000000..2f6a67d
--- /dev/null
+++ b/src/tests/cmocka/test_sss_idmap.c
@@ -0,0 +1,421 @@
+/*
+    Authors:
+        Sumit Bose <sbose at redhat.com>
+
+    Copyright (C) 2013 Red Hat
+
+    SSSD tests: Unit tests for libsss_idmap
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <popt.h>
+
+#include "tests/cmocka/common_mock.h"
+
+#include "lib/idmap/sss_idmap.h"
+
+#define TEST_RANGE_MIN 200000
+#define TEST_RANGE_MAX 399999
+#define TEST_DOM_NAME "test.dom"
+#define TEST_DOM_SID "S-1-5-21-123-456-789"
+
+#define TEST_2_RANGE_MIN 600000
+#define TEST_2_RANGE_MAX 799999
+#define TEST_2_DOM_NAME "test2.dom"
+#define TEST_2_DOM_SID "S-1-5-21-987-654-321"
+
+#define TEST_OFFSET 1000000
+#define TEST_OFFSET_STR "1000000"
+
+struct test_ctx {
+    TALLOC_CTX *mem_idmap;
+    struct sss_idmap_ctx *idmap_ctx;
+};
+
+static void *idmap_talloc(size_t size, void *pvt)
+{
+    return talloc_size(pvt, size);
+}
+
+static void idmap_free(void *ptr, void *pvt)
+{
+    talloc_free(ptr);
+}
+
+void test_sss_idmap_setup(void **state)
+{
+    struct test_ctx *test_ctx;
+    enum idmap_error_code err;
+
+    assert_true(leak_check_setup());
+
+    test_ctx = talloc_zero(global_talloc_context, struct test_ctx);
+    assert_non_null(test_ctx);
+
+    check_leaks_push(test_ctx);
+
+    test_ctx->mem_idmap = talloc_new(test_ctx);
+    assert_non_null(test_ctx->mem_idmap);
+
+    err = sss_idmap_init(idmap_talloc, test_ctx->mem_idmap, idmap_free,
+                         &test_ctx->idmap_ctx);
+    assert_int_equal(err, IDMAP_SUCCESS);
+
+    *state = test_ctx;
+}
+
+void setup_ranges(struct test_ctx *test_ctx, bool external_mapping,
+                  bool second_domain)
+{
+    struct sss_idmap_range range;
+    enum idmap_error_code err;
+    const char *name;
+    const char *sid;
+
+    assert_non_null(test_ctx);
+
+    if (second_domain) {
+        range.min = TEST_2_RANGE_MIN;
+        range.max = TEST_2_RANGE_MAX;
+        name = TEST_2_DOM_NAME;
+        sid = TEST_2_DOM_SID;
+    } else {
+        range.min = TEST_RANGE_MIN;
+        range.max = TEST_RANGE_MAX;
+        name = TEST_DOM_NAME;
+        sid = TEST_DOM_SID;
+    }
+
+    err = sss_idmap_add_domain_ex(test_ctx->idmap_ctx, name, sid, &range, NULL,
+                                  0, external_mapping);
+    assert_int_equal(err, IDMAP_SUCCESS);
+
+    range.min += TEST_OFFSET;
+    range.max += TEST_OFFSET;
+
+    err = sss_idmap_add_domain_ex(test_ctx->idmap_ctx, name, sid, &range, NULL,
+                                  TEST_OFFSET, external_mapping);
+    assert_int_equal(err, IDMAP_SUCCESS);
+}
+
+void test_sss_idmap_setup_with_domains(void **state) {
+    struct test_ctx *test_ctx;
+
+    test_sss_idmap_setup(state);
+
+    test_ctx = talloc_get_type(*state, struct test_ctx);
+    assert_non_null(test_ctx);
+
+    setup_ranges(test_ctx, false, false);
+}
+
+void test_sss_idmap_setup_with_external_mappings(void **state) {
+    struct test_ctx *test_ctx;
+
+    test_sss_idmap_setup(state);
+
+    test_ctx = talloc_get_type(*state, struct test_ctx);
+    assert_non_null(test_ctx);
+
+    setup_ranges(test_ctx, true, false);
+}
+
+void test_sss_idmap_setup_with_both(void **state) {
+    struct test_ctx *test_ctx;
+
+    test_sss_idmap_setup(state);
+
+    test_ctx = talloc_get_type(*state, struct test_ctx);
+    assert_non_null(test_ctx);
+
+    setup_ranges(test_ctx, false, false);
+    setup_ranges(test_ctx, true, true);
+}
+
+void test_sss_idmap_teardown(void **state)
+{
+    struct test_ctx *test_ctx;
+
+    test_ctx = talloc_get_type(*state, struct test_ctx);
+
+    assert_non_null(test_ctx);
+
+    talloc_free(test_ctx->idmap_ctx);
+    talloc_free(test_ctx->mem_idmap);
+    assert_true(check_leaks_pop(test_ctx) == true);
+    talloc_free(test_ctx);
+    assert_true(leak_check_teardown());
+}
+
+void test_add_domain(void **state)
+{
+    struct test_ctx *test_ctx;
+    enum idmap_error_code err;
+    struct sss_idmap_range range;
+
+    test_ctx = talloc_get_type(*state, struct test_ctx);
+
+    assert_non_null(test_ctx);
+
+    range.min = TEST_RANGE_MIN;
+    range.max = TEST_RANGE_MAX;
+
+    err = sss_idmap_add_domain(test_ctx->idmap_ctx, TEST_DOM_NAME, TEST_DOM_SID,
+                               &range);
+    assert_int_equal(err, IDMAP_SUCCESS);
+
+    err = sss_idmap_add_domain(test_ctx->idmap_ctx, TEST_DOM_NAME, TEST_DOM_SID,
+                               &range);
+    assert_int_equal(err, IDMAP_COLLISION);
+
+    err = sss_idmap_add_domain_ex(test_ctx->idmap_ctx, TEST_DOM_NAME,
+                                  TEST_DOM_SID, &range, NULL, 0, false);
+    assert_int_equal(err, IDMAP_COLLISION);
+
+    range.min = TEST_RANGE_MIN + TEST_OFFSET;
+    range.max = TEST_RANGE_MAX + TEST_OFFSET;
+    err = sss_idmap_add_domain_ex(test_ctx->idmap_ctx, TEST_DOM_NAME,
+                                  TEST_DOM_SID, &range, NULL, 0, false);
+    assert_int_equal(err, IDMAP_COLLISION);
+
+    err = sss_idmap_add_domain_ex(test_ctx->idmap_ctx, TEST_DOM_NAME"X",
+                                  TEST_DOM_SID, &range, NULL, TEST_OFFSET,
+                                  false);
+    assert_int_equal(err, IDMAP_COLLISION);
+
+    err = sss_idmap_add_domain_ex(test_ctx->idmap_ctx, TEST_DOM_NAME,
+                                  TEST_DOM_SID"1", &range, NULL, TEST_OFFSET,
+                                  false);
+    assert_int_equal(err, IDMAP_COLLISION);
+
+    err = sss_idmap_add_domain_ex(test_ctx->idmap_ctx, TEST_DOM_NAME,
+                                  TEST_DOM_SID, &range, NULL, TEST_OFFSET,
+                                  true);
+    assert_int_equal(err, IDMAP_COLLISION);
+
+    err = sss_idmap_add_domain_ex(test_ctx->idmap_ctx, TEST_DOM_NAME,
+                                  TEST_DOM_SID, &range, NULL, TEST_OFFSET,
+                                  false);
+    assert_int_equal(err, IDMAP_SUCCESS);
+
+    range.min = TEST_RANGE_MIN + 2 * TEST_OFFSET;
+    range.max = TEST_RANGE_MAX + 2 * TEST_OFFSET;
+    err = sss_idmap_add_domain_ex(test_ctx->idmap_ctx, TEST_DOM_NAME"-nosid",
+                                  NULL, &range, NULL, TEST_OFFSET,
+                                  false);
+    assert_int_equal(err, IDMAP_SID_INVALID);
+
+    err = sss_idmap_add_domain_ex(test_ctx->idmap_ctx, TEST_DOM_NAME"-nosid",
+                                  NULL, &range, NULL, TEST_OFFSET,
+                                  true);
+    assert_int_equal(err, IDMAP_SUCCESS);
+}
+
+void test_map_id(void **state)
+{
+    struct test_ctx *test_ctx;
+    enum idmap_error_code err;
+    uint32_t id;
+    char *sid = NULL;
+
+    test_ctx = talloc_get_type(*state, struct test_ctx);
+
+    assert_non_null(test_ctx);
+
+    err = sss_idmap_sid_to_unix(test_ctx->idmap_ctx, TEST_DOM_SID"1-1", &id);
+    assert_int_equal(err, IDMAP_NO_DOMAIN);
+
+    err = sss_idmap_sid_to_unix(test_ctx->idmap_ctx, TEST_DOM_SID"-400000",
+                                &id);
+    assert_int_equal(err, IDMAP_NO_RANGE);
+
+    err = sss_idmap_unix_to_sid(test_ctx->idmap_ctx, TEST_OFFSET - 1, &sid);
+    assert_int_equal(err, IDMAP_NO_DOMAIN);
+
+    err = sss_idmap_sid_to_unix(test_ctx->idmap_ctx, TEST_DOM_SID"-0", &id);
+    assert_int_equal(err, IDMAP_SUCCESS);
+    assert_int_equal(id, TEST_RANGE_MIN);
+
+    err = sss_idmap_unix_to_sid(test_ctx->idmap_ctx, id, &sid);
+    assert_int_equal(err, IDMAP_SUCCESS);
+    assert_string_equal(sid, TEST_DOM_SID"-0");
+
+    err = sss_idmap_sid_to_unix(test_ctx->idmap_ctx,
+                                TEST_DOM_SID"-"TEST_OFFSET_STR, &id);
+    assert_int_equal(err, IDMAP_SUCCESS);
+    assert_int_equal(id, TEST_RANGE_MIN+TEST_OFFSET);
+
+    err = sss_idmap_unix_to_sid(test_ctx->idmap_ctx, id, &sid);
+    assert_int_equal(err, IDMAP_SUCCESS);
+    assert_string_equal(sid, TEST_DOM_SID"-"TEST_OFFSET_STR);
+}
+
+void test_map_id_external(void **state)
+{
+    struct test_ctx *test_ctx;
+    enum idmap_error_code err;
+    uint32_t id;
+    char *sid = NULL;
+
+    test_ctx = talloc_get_type(*state, struct test_ctx);
+
+    assert_non_null(test_ctx);
+
+    err = sss_idmap_sid_to_unix(test_ctx->idmap_ctx, TEST_DOM_SID"1-1", &id);
+    assert_int_equal(err, IDMAP_NO_DOMAIN);
+
+    err = sss_idmap_sid_to_unix(test_ctx->idmap_ctx, TEST_DOM_SID"-400000",
+                                &id);
+    assert_int_equal(err, IDMAP_EXTERNAL);
+
+    err = sss_idmap_unix_to_sid(test_ctx->idmap_ctx, TEST_OFFSET - 1, &sid);
+    assert_int_equal(err, IDMAP_NO_DOMAIN);
+
+    err = sss_idmap_sid_to_unix(test_ctx->idmap_ctx, TEST_DOM_SID"-0", &id);
+    assert_int_equal(err, IDMAP_EXTERNAL);
+
+    err = sss_idmap_unix_to_sid(test_ctx->idmap_ctx, TEST_RANGE_MIN, &sid);
+    assert_int_equal(err, IDMAP_EXTERNAL);
+
+    err = sss_idmap_sid_to_unix(test_ctx->idmap_ctx,
+                                TEST_DOM_SID"-"TEST_OFFSET_STR, &id);
+    assert_int_equal(err, IDMAP_EXTERNAL);
+
+    err = sss_idmap_unix_to_sid(test_ctx->idmap_ctx,
+                                TEST_RANGE_MIN + TEST_OFFSET, &sid);
+    assert_int_equal(err, IDMAP_EXTERNAL);
+}
+
+void test_check_sid_id(void **state)
+{
+    struct test_ctx *test_ctx;
+    enum idmap_error_code err;
+
+    test_ctx = talloc_get_type(*state, struct test_ctx);
+
+    assert_non_null(test_ctx);
+
+    err = sss_idmap_check_sid_unix(test_ctx->idmap_ctx, TEST_DOM_SID"-400000",
+                                   TEST_RANGE_MIN-1);
+    assert_int_equal(err, IDMAP_NO_RANGE);
+
+    err = sss_idmap_check_sid_unix(test_ctx->idmap_ctx, TEST_DOM_SID"-400000",
+                                   TEST_RANGE_MIN);
+    assert_int_equal(err, IDMAP_SUCCESS);
+
+    err = sss_idmap_check_sid_unix(test_ctx->idmap_ctx, TEST_DOM_SID"1-400000",
+                                   TEST_RANGE_MIN);
+    assert_int_equal(err, IDMAP_SID_UNKNOWN);
+
+    err = sss_idmap_check_sid_unix(test_ctx->idmap_ctx, TEST_DOM_SID"-400000",
+                                   TEST_RANGE_MAX + TEST_OFFSET);
+    assert_int_equal(err, IDMAP_SUCCESS);
+
+    err = sss_idmap_check_sid_unix(test_ctx->idmap_ctx, TEST_DOM_SID"-400000",
+                                   TEST_RANGE_MAX + TEST_OFFSET + 1);
+    assert_int_equal(err, IDMAP_NO_RANGE);
+}
+
+void test_has_algorithmic(void **state)
+{
+    struct test_ctx *test_ctx;
+    bool use_id_mapping;
+    enum idmap_error_code err;
+
+    test_ctx = talloc_get_type(*state, struct test_ctx);
+
+    assert_non_null(test_ctx);
+
+    err = sss_idmap_domain_has_algorithmic_mapping(NULL, NULL, &use_id_mapping);
+    assert_int_equal(err, IDMAP_SID_INVALID);
+
+    err = sss_idmap_domain_has_algorithmic_mapping(NULL, TEST_DOM_SID,
+                                                   &use_id_mapping);
+    assert_int_equal(err, IDMAP_CONTEXT_INVALID);
+
+    err = sss_idmap_domain_has_algorithmic_mapping(test_ctx->idmap_ctx, NULL,
+                                                   &use_id_mapping);
+    assert_int_equal(err, IDMAP_SID_INVALID);
+
+    err = sss_idmap_domain_has_algorithmic_mapping(test_ctx->idmap_ctx,
+                                                   TEST_DOM_SID"1",
+                                                   &use_id_mapping);
+    assert_int_equal(err, IDMAP_SID_UNKNOWN);
+
+    err = sss_idmap_domain_has_algorithmic_mapping(test_ctx->idmap_ctx,
+                                                   TEST_DOM_SID,
+                                                   &use_id_mapping);
+    assert_int_equal(err, IDMAP_SUCCESS);
+    assert_true(use_id_mapping);
+
+    err = sss_idmap_domain_has_algorithmic_mapping(test_ctx->idmap_ctx,
+                                                   TEST_2_DOM_SID,
+                                                   &use_id_mapping);
+    assert_int_equal(err, IDMAP_SUCCESS);
+    assert_false(use_id_mapping);
+}
+
+
+int main(int argc, const char *argv[])
+{
+    poptContext pc;
+    int opt;
+    struct poptOption long_options[] = {
+        POPT_AUTOHELP
+        SSSD_DEBUG_OPTS
+        POPT_TABLEEND
+    };
+
+    const UnitTest tests[] = {
+        unit_test_setup_teardown(test_add_domain,
+                                 test_sss_idmap_setup, test_sss_idmap_teardown),
+        unit_test_setup_teardown(test_map_id,
+                                 test_sss_idmap_setup_with_domains,
+                                 test_sss_idmap_teardown),
+        unit_test_setup_teardown(test_map_id_external,
+                                 test_sss_idmap_setup_with_external_mappings,
+                                 test_sss_idmap_teardown),
+        unit_test_setup_teardown(test_check_sid_id,
+                                 test_sss_idmap_setup_with_domains,
+                                 test_sss_idmap_teardown),
+        unit_test_setup_teardown(test_check_sid_id,
+                                 test_sss_idmap_setup_with_external_mappings,
+                                 test_sss_idmap_teardown),
+        unit_test_setup_teardown(test_has_algorithmic,
+                                 test_sss_idmap_setup_with_both,
+                                 test_sss_idmap_teardown),
+    };
+
+    /* Set debug level to invalid value so we can deside if -d 0 was used. */
+    debug_level = SSSDBG_INVALID;
+
+    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+    while((opt = poptGetNextOpt(pc)) != -1) {
+        switch(opt) {
+        default:
+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
+                    poptBadOption(pc, 0), poptStrerror(opt));
+            poptPrintUsage(pc, stderr, 0);
+            return 1;
+        }
+    }
+    poptFreeContext(pc);
+
+    DEBUG_INIT(debug_level);
+
+    tests_set_cwd();
+
+    return run_tests(tests);
+}
-- 
1.7.7.6



More information about the sssd-devel mailing list