[SSSD] [PATCHES] libsss_idmap enhancements

Sumit Bose sbose at redhat.com
Fri Jun 28 10:40:23 UTC 2013


and now with patches ...

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
-------------- next part --------------
From cec2e622e221329d675b922f79542658a7c512ce 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/8] 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 |   28 ++++++++++++-
 2 files changed, 107 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..6f5a8dc 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
 };
 
 /**
@@ -244,6 +247,29 @@ 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
+ */
+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 f3aacef111e8067daaa99aa76d8de90656f97ed1 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/8] 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 6f5a8dc..74d55be 100644
--- a/src/lib/idmap/sss_idmap.h
+++ b/src/lib/idmap/sss_idmap.h
@@ -255,6 +255,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.
  *
@@ -268,6 +270,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 9560605bf5e90c84682144dbda7e458ed359aa84 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/8] 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 74d55be..b56e62a 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
 };
 
 /**
@@ -259,6 +262,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
@@ -271,7 +281,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
  *
@@ -284,6 +295,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,
@@ -301,6 +313,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,
@@ -319,6 +332,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,
@@ -337,6 +351,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,
@@ -354,6 +369,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,
@@ -370,6 +386,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,
@@ -388,6 +405,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 0a6a7ce40533bae53cc3a61e90726d6c619f6d4a 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/8] 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 26efe39404ddda88ae4a77d335773b19a1b46e5a 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/8] 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 |  110 +++++++++++++++++++++++++++++++++++++++++++++
 src/lib/idmap/sss_idmap.h |   75 ++++++++++++++++++++++++++++++
 2 files changed, 185 insertions(+), 0 deletions(-)

diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c
index ca7c5a0..86af3d3 100644
--- a/src/lib/idmap/sss_idmap.c
+++ b/src/lib/idmap/sss_idmap.c
@@ -541,6 +541,50 @@ 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 +700,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 b56e62a..3b3e6a4 100644
--- a/src/lib/idmap/sss_idmap.h
+++ b/src/lib/idmap/sss_idmap.h
@@ -358,6 +358,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 dd4063bc2e22dd7e24676cbb7f7381f8bc928fec 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/8] 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 86af3d3..50cc3ed 100644
--- a/src/lib/idmap/sss_idmap.c
+++ b/src/lib/idmap/sss_idmap.c
@@ -897,3 +897,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_SID_UNKNOWN;
+    }
+
+    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 3b3e6a4..1925f05 100644
--- a/src/lib/idmap/sss_idmap.h
+++ b/src/lib/idmap/sss_idmap.h
@@ -519,6 +519,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 0f338bf35627f4d51dc70374c066ec80cadcb67b Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Thu, 27 Jun 2013 12:48:49 +0200
Subject: [PATCH 7/8] Add sdap_idmap_domain_has_algorithmic_mapping()

This patch implements a wrapper for
sss_idmap_domain_has_algorithmic_mapping() for the sdap ID mapping.

Fixes https://fedorahosted.org/sssd/ticket/1960
---
 src/providers/ldap/sdap_idmap.c |   59 +++++++++++++++++++++++++++++++++++++++
 src/providers/ldap/sdap_idmap.h |    3 ++
 2 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/src/providers/ldap/sdap_idmap.c b/src/providers/ldap/sdap_idmap.c
index a81bc98..501ef52 100644
--- a/src/providers/ldap/sdap_idmap.c
+++ b/src/providers/ldap/sdap_idmap.c
@@ -390,3 +390,62 @@ done:
     talloc_free(dom_sid_str);
     return ret;
 }
+
+bool sdap_idmap_domain_has_algorithmic_mapping(struct sdap_idmap_ctx *ctx,
+                                               const char *dom_sid)
+{
+    enum idmap_error_code err;
+    bool has_algorithmic_mapping;
+    char *new_dom_sid;
+    int ret;
+    TALLOC_CTX *tmp_ctx = NULL;
+
+    err = sss_idmap_domain_has_algorithmic_mapping(ctx->map, dom_sid,
+                                                   &has_algorithmic_mapping);
+    if (err == IDMAP_SUCCESS) {
+        return has_algorithmic_mapping;
+    } else if (err != IDMAP_SID_UNKNOWN) {
+        return false;
+    }
+
+    /* This is the first time we've seen this domain
+     * Create a new domain for it. We'll use the dom-sid
+     * as the domain name for now, since we don't have
+     * any way to get the real name.
+     */
+
+    if (is_domain_sid(dom_sid)) {
+        new_dom_sid = discard_const(dom_sid);
+    } else {
+        tmp_ctx = talloc_new(NULL);
+        if (tmp_ctx == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, ("talloc_new failed.\n"));
+            return false;
+        }
+
+        ret = sdap_idmap_get_dom_sid_from_object(tmp_ctx, dom_sid,
+                                                 &new_dom_sid);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  ("Could not parse domain SID from [%s]\n", dom_sid));
+            talloc_free(tmp_ctx);
+            return false;
+        }
+    }
+
+    ret = ctx->find_new_domain(ctx, new_dom_sid, new_dom_sid);
+    talloc_free(tmp_ctx);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("Could not add new domain for sid [%s]\n", dom_sid));
+        return false;
+    }
+
+    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;
+    }
+}
diff --git a/src/providers/ldap/sdap_idmap.h b/src/providers/ldap/sdap_idmap.h
index 2e2123f..527fdc6 100644
--- a/src/providers/ldap/sdap_idmap.h
+++ b/src/providers/ldap/sdap_idmap.h
@@ -52,4 +52,7 @@ sdap_idmap_sid_to_unix(struct sdap_idmap_ctx *idmap_ctx,
                        const char *sid_str,
                        id_t *id);
 
+bool sdap_idmap_domain_has_algorithmic_mapping(struct sdap_idmap_ctx *ctx,
+                                               const char *dom_sid);
+
 #endif /* SDAP_IDMAP_H_ */
-- 
1.7.7.6

-------------- next part --------------
From 2c2848828ece94a20825520838476bf677f63b81 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 8/8] 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