On 01/06/2016 04:34 PM, Sumit Bose wrote:
On Mon, Jan 04, 2016 at 03:40:05PM +0100, Pavel Reichl wrote:
Hello Sumit, thanks for comments. I attached rebased patch with fixes as you 
proposed.

On 12/10/2015 01:23 PM, Sumit Bose wrote:

Some unit-test where failing for me because of an issue in cleaning up
the secondary slices. 'it = it->next' does not work because it was just
freed in the body of the loop. I fixed it with the change below, but
maybe a do-while loop would be even nicer here?

Sorry to hear that. I fixed that in attached patch set.
Which test failed for you? make check is always passing in my environment.

This is what I see:

$ ./sss_idmap-tests
Running suite(s): IDMAP
88%: Checks: 25, Failures: 0, Errors: 3
(null):-1:S:IDMAP mapping tests:idmap_test_sid2uid_ss:0: (after this point) 
Received signal 11 (Segmentation fault)
(null):-1:S:IDMAP mapping tests:idmap_test_uid2sid_ss:0: (after this point) 
Received signal 11 (Segmentation fault)
(null):-1:S:IDMAP mapping tests:idmap_test_sid2uid_ext_sec_slices:0: (after 
this point) Received signal 11 (Segmentation fault)

and here is what valgrind has to say:

$ valgrind .libs/lt-sss_idmap-tests
==17919== Memcheck, a memory error detector
==17919== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==17919== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==17919== Command: .libs/lt-sss_idmap-tests
==17919==
Running suite(s): IDMAP
==17919== Invalid read of size 4
==17919==    at 0x407C595: sss_idmap_free_domain.part.1 (sss_idmap.c:220)
==17919==    by 0x407C859: sss_idmap_free_domain (sss_idmap.c:240)
==17919==    by 0x407C859: sss_idmap_free (sss_idmap.c:241)
==17919==    by 0x804B60D: idmap_ctx_teardown (sss_idmap-tests.c:75)
==17919==    by 0x4050271: ??? (in /usr/lib/libcheck.so.0.0.0)
==17919==    by 0x405080D: ??? (in /usr/lib/libcheck.so.0.0.0)
==17919==    by 0x4050BED: srunner_run (in /usr/lib/libcheck.so.0.0.0)
==17919==    by 0x40511D3: srunner_run_all (in /usr/lib/libcheck.so.0.0.0)
==17919==    by 0x80492D1: main (sss_idmap-tests.c:747)
==17919==  Address 0x4437d68 is 64 bytes inside a block of size 68 free'd
==17919==    at 0x402C26D: free (in 
/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==17919==    by 0x4068C9E: _talloc_free_internal (talloc.c:1057)
==17919==    by 0x4068C9E: _talloc_free (talloc.c:1581)
==17919==    by 0x407C594: sss_idmap_free_domain.part.1 (sss_idmap.c:222)
==17919==    by 0x407C859: sss_idmap_free_domain (sss_idmap.c:240)
==17919==    by 0x407C859: sss_idmap_free (sss_idmap.c:241)
==17919==    by 0x804B60D: idmap_ctx_teardown (sss_idmap-tests.c:75)
==17919==    by 0x4050271: ??? (in /usr/lib/libcheck.so.0.0.0)
==17919==    by 0x405080D: ??? (in /usr/lib/libcheck.so.0.0.0)
==17919==    by 0x4050BED: srunner_run (in /usr/lib/libcheck.so.0.0.0)
==17919==    by 0x40511D3: srunner_run_all (in /usr/lib/libcheck.so.0.0.0)
==17919==    by 0x80492D1: main (sss_idmap-tests.c:747)
==17919==
100%: Checks: 25, Failures: 0, Errors: 0
==17919==
==17919== HEAP SUMMARY:
==17919==     in use at exit: 0 bytes in 0 blocks
==17919==   total heap usage: 1,918 allocs, 1,918 frees, 749,697 bytes allocated
==17919==
==17919== All heap blocks were freed -- no leaks are possible
==17919==
==17919== For counts of detected and suppressed errors, rerun with: -v
==17919== ERROR SUMMARY: 32 errors from 1 contexts (suppressed: 0 from 0)




diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c
index c4ae811..7ab5c66 100644
--- a/src/lib/idmap/sss_idmap.c
+++ b/src/lib/idmap/sss_idmap.c
@@ -210,6 +210,7 @@ static void sss_idmap_free_domain(struct
sss_idmap_ctx *ctx,
                                    struct idmap_domain_info *dom)
  {
      struct idmap_range_params *it;
+    struct idmap_range_params *next;

      if (ctx == NULL || dom == NULL) {
          return;
@@ -217,7 +218,8 @@ static void sss_idmap_free_domain(struct
sss_idmap_ctx *ctx,

      ctx->free_func(dom->range_params.range_id, ctx->alloc_pvt);
      /* Free list of secondary ranges */
-    for (it = dom->sec_ranges; it != NULL; it = it->next) {
+    for (it = dom->sec_ranges; it != NULL; it = next) {
+        next = it->next;
          ctx->free_func(it->range_id, ctx->alloc_pvt);
          ctx->free_func(it, ctx->alloc_pvt);
      }


While checking and playing with the test I came across

+    /* Todo - Add tests */
+    /* Add size of primary slice for first_rid of secondary slices. */
+    rid += ctx->idmap_opts.rangesize;

in sss_idmap_add_auto_domain_ex(). Does the 'Todo' only refer to 'Add
tests' or to 'Add size of primary slice for first_rid of secondary
slices.' as well? I'm asking because you really have to use the size of
the primary slice and not ctx->idmap_opts.rangesize here because the
primary range is given as a parameter to sss_idmap_add_auto_domain_ex()
and the size might be different then ctx->idmap_opts.rangesize. E.g. in
the unit-test the range is [1234,9876].

I removed the misleading comment about adding tests. I have no intention of 
changing how 'rid' is set currently.


About sss_idmap_add_auto_domain_ex(), I think having auto-generated
secondary ranges with external_mapping==true make no sense. I would
suggest to just create the primary range in this case.

OK, done.


I'll continue reviewing and testing ...

Thanks!

 From e0aa542e1f1329583eb89d166df87185cffd6362 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <prei...@redhat.com>
Date: Thu, 26 Nov 2015 10:46:34 -0500
Subject: [PATCH 1/2] IDMAP: New structure for domain range params

Create new internal structure idmap_range_params by merging ID mapping
range relevant fields from idmap_domain_info and remove corrsponding
fields.

Resolves:
https://fedorahosted.org/sssd/ticket/2188
---
  src/lib/idmap/sss_idmap.c | 110 +++++++++++++++++++++++-----------------------
  1 file changed, 56 insertions(+), 54 deletions(-)


...

@@ -447,8 +437,13 @@ enum idmap_error_code sss_idmap_check_collision(struct 
sss_idmap_ctx *ctx,
      enum idmap_error_code err;

      for (dom = ctx->idmap_domain_info; dom != NULL; dom = dom->next) {
-        err = sss_idmap_check_collision_ex(dom->name, dom->sid, dom->range,
-                                           dom->first_rid, dom->range_id,
+        struct sss_idmap_range range = { dom->range_params.min_id,
+                                         dom->range_params.max_id };

In general I agree with the refactoring in this patch, but I don't like
the declaration of variables in the code. Especially in the case here
and below where variables are declared inside a loop. Mainly because I
do not know if compilers are able handle this smart or if this might be
more expensive than declaring the variables outside of the loop.

As discussed in separate thread I moved all declaration to the beginning of the 
functions.


+
+        err = sss_idmap_check_collision_ex(dom->name, dom->sid,
+                                           &range,
+                                           dom->range_params.first_rid,
+                                           dom->range_params.range_id,
                                             dom->external_mapping,
                                             n_name, n_sid, n_range, 
n_first_rid,
                                             n_range_id, n_external_mapping);
@@ -467,12 +462,22 @@ static enum idmap_error_code dom_check_collision(
      enum idmap_error_code err;

      for (dom = dom_list; dom != NULL; dom = dom->next) {
-        err = sss_idmap_check_collision_ex(dom->name, dom->sid, dom->range,
-                                           dom->first_rid, dom->range_id,
+        struct sss_idmap_range range = { dom->range_params.min_id,
+                                         dom->range_params.max_id };
+        struct sss_idmap_range new_dom_range = {
+            new_dom->range_params.min_id,
+            new_dom->range_params.max_id };
+
+
+        err = sss_idmap_check_collision_ex(dom->name, dom->sid,
+                                           &range,
+                                           dom->range_params.first_rid,
+                                           dom->range_params.range_id,
                                             dom->external_mapping,
                                             new_dom->name, new_dom->sid,
-                                           new_dom->range, new_dom->first_rid,
-                                           new_dom->range_id,
+                                           &new_dom_range,
+                                           new_dom->range_params.first_rid,
+                                           new_dom->range_params.range_id,
                                             new_dom->external_mapping);
          if (err != IDMAP_SUCCESS) {
              return err;

...

 From ea48f8b5c252755168e9ae83d4b7ebb97152ea3c Mon Sep 17 00:00:00 2001
From: Pavel Reichl <prei...@redhat.com>
Date: Fri, 27 Nov 2015 04:15:00 -0500
Subject: [PATCH 2/2] IDMAP: introduce secondary slices

Resolves:
https://fedorahosted.org/sssd/ticket/2188
---
  src/config/SSSDConfig/__init__.py.in     |   1 +
  src/config/etc/sssd.api.d/sssd-ad.conf   |   1 +
  src/config/etc/sssd.api.d/sssd-ipa.conf  |   1 +
  src/config/etc/sssd.api.d/sssd-ldap.conf |   1 +
  src/lib/idmap/sss_idmap.c                | 430 +++++++++++++++++++++++++++----
  src/lib/idmap/sss_idmap.exports          |   3 +
  src/lib/idmap/sss_idmap.h                |  58 +++++
  src/lib/idmap/sss_idmap_private.h        |   4 +
  src/man/include/ldap_id_mapping.xml      |  11 +
  src/providers/ad/ad_opts.c               |   1 +
  src/providers/ipa/ipa_opts.c             |   1 +
  src/providers/ldap/ldap_opts.c           |   1 +
  src/providers/ldap/sdap.h                |   1 +
  src/providers/ldap/sdap_idmap.c          |  15 +-
  src/tests/cmocka/test_sss_idmap.c        |  86 ++++++-
  src/tests/sss_idmap-tests.c              | 114 ++++++++
  16 files changed, 667 insertions(+), 62 deletions(-)

diff --git a/src/config/SSSDConfig/__init__.py.in 
b/src/config/SSSDConfig/__init__.py.in
index 
fe2971d993ccf2975bbddbe6c74572ab9f5d4e51..7f9ced668b4b57c90ed4da4f49f56bf42b172304
 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -354,6 +354,7 @@ option_strings = {
      'ldap_idmap_autorid_compat' : _('Use autorid-compatible algorithm for 
ID-mapping'),
      'ldap_idmap_default_domain' : _('Name of the default domain for 
ID-mapping'),
      'ldap_idmap_default_domain_sid' : _('SID of the default domain for 
ID-mapping'),
+    'ldap_idmap_extra_slice_max' : _('Number of secondary slices'),

I think the _max might be a bit misleading here because it is possible
that more secondary slices can be used, this value just gives the number
of slices which are created at startup. So something like _initial,
_init or _start might fit better.

Btw, I'm not sure if it is useful, but currently there is no way to
switch of the usage of the secondary slices. Even setting
ldap_idmap_extra_slice_max to 0 will only skip the initial creation of
the slices but new slices will still be created when needed.

I changes the code so ldap_idmap_extra_slice_init == 0 should block adding new 
slices.


...

  enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx,
                                                  const char *dom_sid,
                                                  id_t *slice_num,
@@ -327,12 +366,9 @@ enum idmap_error_code sss_idmap_calculate_range(struct 
sss_idmap_ctx *ctx,
          /* Verify that this slice is not already in use */
          do {
              for (dom = ctx->idmap_domain_info; dom != NULL; dom = dom->next) {
-                uint32_t dmin = dom->range_params.min_id;
-                uint32_t dmax = dom->range_params.max_id;

-                if ((dmin <= min && dmax >= max) ||
-                    (dmin >= min && dmin <= max) ||
-                    (dmax >= min && dmax <= max)) {
+                if (check_overlap(&dom->range_params, min, max) ||
+                    check_collision_sec_slices(dom->sec_ranges, min, max)) {

I think it would be better to have a single call which checks for
overlaps/collisions.


OK done.

                      /* This range overlaps one already registered
                       * We'll try the next available slot
                       */

...

+static enum idmap_error_code
+get_sec_slices(struct sss_idmap_ctx *ctx,
+               const char *domain_name,
+               uint32_t first_rid,
+               struct idmap_range_params **_sec_slices)
+{
+    struct idmap_range_params *prev = NULL;
+    struct idmap_range_params *sec_slices = NULL;
+
+    for (int i = 0; i < ctx->idmap_opts.extra_slice_max; i++) {
+        static enum idmap_error_code err;
+        struct idmap_range_params *slice;
+        char *secondary_name;
+
+        secondary_name = generate_sec_slice_name(ctx, domain_name, i);

The number of the first secondary slice should be 1 otherwise there
would be a mismatch with get_new_sec_slide(), so please replace 'i' with
'i + 1'. Unfortunately you have to change some of the id values in the
tests because of this.

OK, done.


+        if (secondary_name == NULL) {
+            return IDMAP_OUT_OF_MEMORY;
+        }
+
+        err = generate_slice(ctx, secondary_name, first_rid, &slice);
+        if (err != IDMAP_SUCCESS) {
+            ctx->free_func(secondary_name, ctx->alloc_pvt);
+            return err;
+        }
+
+        first_rid += ctx->idmap_opts.rangesize;
+
+        if (prev != NULL) {
+            prev->next = slice;
+        }
+
+        if (sec_slices == NULL) {
+            sec_slices = slice;
+        }
+
+        prev = slice;
+    }
+
+    *_sec_slices = sec_slices;
+    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,
@@ -566,6 +702,48 @@ fail:
      return err;
  }

+enum idmap_error_code
+sss_idmap_add_auto_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,
+                             bool external_mapping)
+{
+    enum idmap_error_code err;
+

I think a check should be added if the size of the range given in the
sss_idmap_range struct is really idmap_opts.rangesize, otherwise we
would run into trouble.


OK done.

+    err = sss_idmap_add_domain_ex(ctx, domain_name, domain_sid, range,
+                                  range_id, rid, external_mapping);
+    if (err != IDMAP_SUCCESS) {
+        return err;
+    }
+
+    if (external_mapping) {
+        /* There's no point in generating secondary ranges if external_mapping
+           is enabled. */
+        ctx->idmap_domain_info->use_sec_ranges = false;
+        return IDMAP_SUCCESS;
+    }
+
+    /* Add size of primary slice for first_rid of secondary slices. */
+    rid += ctx->idmap_opts.rangesize;
+    err = get_sec_slices(ctx, domain_name, rid,
+                         &ctx->idmap_domain_info->sec_ranges);
+    if (err == IDMAP_SUCCESS) {
+        ctx->idmap_domain_info->use_sec_ranges = true;
+    } else {
+        /* Running out of slices for secondary mapping is a non-fatal
+         * problem. */
+        if (err == IDMAP_OUT_OF_SLICES) {
+            err = IDMAP_SUCCESS;
+        }
+        ctx->idmap_domain_info->use_sec_ranges = false;
+    }
+
+    return err;
+}
+
  enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
                                             const char *domain_name,
                                             const char *domain_sid,

...

+static bool comp_id(struct idmap_range_params *range_params, long long rid,
+                    uint32_t *_id)
+{
+    uint32_t id;
+
+    if (rid >= range_params->first_rid) {
+        id = range_params->min_id + (rid - range_params->first_rid);
+        if (id <= range_params->max_id) {

By default we restrict the POSIX IDs to 2^31 and since the maximum for
uint32_t is 2^32 there should be no overrun. But we allow to configure
ldap_idmap_range_max and hence there might be the chance for overruns.

There are nice built-ins
https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html which
are supported by clang
http://clang.llvm.org/docs/LanguageExtensions.html#checked-arithmetic-builtins
as well. But I'm not sure if we should start using them?

I would like to use them in future.


So I would suggest something like

        if (rid >= range_params->first_rid &&
               (UINT32_MAX - range_params->min_id) > (rid - 
range_params->first_rid)) {
            id = range_params->min_id + (rid - range_params->first_rid);
            if (id <= range_params->max_id) {

to return false on overflows (Please check the math, I carefully looked
at it for some time and think it is ok, but an addition pair of eyes and
the corresponding brain are very welcome :-)

I added this statement to the code. LGTM.


+            *_id = id;
+            return true;
+        }
+    }
+    return false;
+}
+

...

  enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
                                              const char *sid,
                                              uint32_t *_id)
  {
      struct idmap_domain_info *idmap_domain_info;
+    struct idmap_domain_info *matched_dom = NULL;
      size_t dom_len;
      long long rid;
-    char *endptr;
-    uint32_t id;
-    bool no_range = false;

      if (sid == NULL || _id == NULL) {
          return IDMAP_ERROR;
@@ -607,39 +862,68 @@ enum idmap_error_code sss_idmap_sid_to_unix(struct 
sss_idmap_ctx *ctx,
          return IDMAP_BUILTIN_SID;
      }

+    /* Try primary slices */
      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 (idmap_domain_info->external_mapping == true) {
-                    return IDMAP_EXTERNAL;
-                }
+        if (is_sid_from_dom(idmap_domain_info->sid, sid, &dom_len)) {

-                errno = 0;
-                rid = strtoull(sid + dom_len + 1, &endptr, 10);
-                if (errno != 0 || rid > UINT32_MAX || *endptr != '\0') {
-                    return IDMAP_SID_INVALID;
-                }
+            if (idmap_domain_info->external_mapping == true) {
+                return IDMAP_EXTERNAL;
+            }

-                if (rid >= idmap_domain_info->range_params.first_rid) {
-                    id = idmap_domain_info->range_params.min_id
-                            + (rid - 
idmap_domain_info->range_params.first_rid);
-                    if (id <= idmap_domain_info->range_params.max_id) {
-                        *_id = id;
-                        return IDMAP_SUCCESS;
-                    }
-                }
+            if (parse_rid(sid, dom_len, &rid) == false) {
+                return IDMAP_SID_INVALID;
+            }

-                no_range = true;
+            if (comp_id(&idmap_domain_info->range_params, rid, _id)) {
+                return IDMAP_SUCCESS;
              }
+
+            matched_dom = idmap_domain_info;
          }

          idmap_domain_info = idmap_domain_info->next;
      }

-    return no_range ? IDMAP_NO_RANGE : IDMAP_NO_DOMAIN;
+    /* Try secondary slices */
+    if (matched_dom != NULL && matched_dom->use_sec_ranges) {

maybe this part can be put into a separate function as well ?


OK done.

+        struct idmap_range_params *last_slide = NULL;
+        struct idmap_range_params *new_slice;
+        enum idmap_error_code err;
+
+        dom_len = strlen(matched_dom->sid);
+
+        if (parse_rid(sid, dom_len, &rid) == false) {
+            return IDMAP_SID_INVALID;
+        }
+
+        for (struct idmap_range_params *it = matched_dom->sec_ranges;
+             it != NULL; it = it->next) {
+            if (comp_id(it, rid, _id)) {
+                return IDMAP_SUCCESS;
+            }
+            last_slide = it;
+        }
+
+        /* If no secondary slide matched then new slide is added. */
+        err = get_new_sec_slide(ctx, matched_dom->name, rid, &new_slice);
+        if (err != IDMAP_SUCCESS) {
+            return err;
+        }
+
+        if (last_slide == NULL) {
+            matched_dom->sec_ranges = new_slice;
+        } else {
+            last_slide->next = new_slice;
+        }
+
+        if (comp_id(new_slice, rid, _id)) {
+            return IDMAP_SUCCESS;
+        }
+
+    }
+
+    return matched_dom ? IDMAP_NO_RANGE : IDMAP_NO_DOMAIN;
  }

  enum idmap_error_code sss_idmap_check_sid_unix(struct sss_idmap_ctx *ctx,

...

diff --git a/src/lib/idmap/sss_idmap.exports
b/src/lib/idmap/sss_idmap.exports
index
52115636d5a6b936f18b4392e9d12adc26c85f53..d4d3d0cb50146ba62b1bbd068420be2e6ea83976
100644
--- a/src/lib/idmap/sss_idmap.exports
+++ b/src/lib/idmap/sss_idmap.exports
@@ -8,13 +8,16 @@ SSS_IDMAP_0.4 {

I think you have to increase the version number.

          sss_idmap_ctx_set_lower;
          sss_idmap_ctx_set_upper;
          sss_idmap_ctx_set_rangesize;
+        sss_idmap_ctx_set_extra_slice_max;
          sss_idmap_ctx_get_autorid;
          sss_idmap_ctx_get_lower;
          sss_idmap_ctx_get_upper;
          sss_idmap_ctx_get_rangesize;
+        sss_idmap_ctx_get_extra_slice_max;
          sss_idmap_calculate_range;
          sss_idmap_add_domain;
          sss_idmap_add_domain_ex;
+        sss_idmap_add_auto_domain_ex;
          sss_idmap_check_collision;
          sss_idmap_check_collision_ex;
          sss_idmap_sid_to_unix;

...

I would add a test where you set the idmap parameters to some smaller
values than the default, e.g. range size to 10 and the number of initial
slices to 5. Then initialize the id-mapping for some domain and run a
loop with rid values from 0 to 80, call sss_idmap_sid_to_unix() and save
the POSIX IDs in an array. Then run sss_idmap_unix_to_sid() with the
values from the array and check if the expected SID is returned. This
will exercise adding more slices than initialized at startup and make
sure that there are no gaps between the slices or off-by-one errors at
the boundary of the slices.

OK, I will work on this now.

Additionally I think it would be more reliable if the secondary slices
can be saved to the cache and can be read at startup as well. I'm
thinking of the case when there is a collision in the secondary slices
of different domains. Currently we try to find a unused slice if a
collision is detected. But if after a restart the slices are initialized
in a different order the colliding slices might get swapped. Maybe
callbacks can be added to sss_idmap_add_auto_domain_ex() which can be
set to a function which can reads and writes the data from the cache?

OK, I will work on this after the test is done.


Thanks.


bye,
Sumit
_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://lists.fedorahosted.org/admin/lists/sssd-devel@lists.fedorahosted.org

>From ef2ff4c1ee7e1c76fc55eb223f15f396e1af885f Mon Sep 17 00:00:00 2001
From: Pavel Reichl <prei...@redhat.com>
Date: Thu, 26 Nov 2015 10:46:34 -0500
Subject: [PATCH 1/2] IDMAP: New structure for domain range params

Create new internal structure idmap_range_params by merging ID mapping
range relevant fields from idmap_domain_info and remove corrsponding
fields.

Resolves:
https://fedorahosted.org/sssd/ticket/2188
---
 src/lib/idmap/sss_idmap.c | 117 ++++++++++++++++++++++++----------------------
 1 file changed, 60 insertions(+), 57 deletions(-)

diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c
index 4c453120539a549807e9b6bb4db2dc396c1b3152..fce3010d8e840fa86bc8225ef000e6e789072108 100644
--- a/src/lib/idmap/sss_idmap.c
+++ b/src/lib/idmap/sss_idmap.c
@@ -33,13 +33,21 @@
 #define SID_FMT "%s-%d"
 #define SID_STR_MAX_LEN 1024
 
+/* Hold all parameters for unix<->sid mapping relevant for
+ * given slice. */
+struct idmap_range_params {
+    uint32_t min_id;
+    uint32_t max_id;
+    char *range_id;
+
+    uint32_t first_rid;
+};
+
 struct idmap_domain_info {
     char *name;
     char *sid;
-    struct sss_idmap_range *range;
+    struct idmap_range_params range_params;
     struct idmap_domain_info *next;
-    uint32_t first_rid;
-    char *range_id;
     bool external_mapping;
 };
 
@@ -72,37 +80,17 @@ static char *idmap_strdup(struct sss_idmap_ctx *ctx, const char *str)
     return new;
 }
 
-static struct sss_idmap_range *idmap_range_dup(struct sss_idmap_ctx *ctx,
-                                               struct sss_idmap_range *range)
-{
-    struct sss_idmap_range *new = NULL;
-
-    CHECK_IDMAP_CTX(ctx, NULL);
-
-
-    new = ctx->alloc_func(sizeof(struct sss_idmap_range), ctx->alloc_pvt);
-    if (new == NULL) {
-        return NULL;
-    }
-
-    memset(new, 0, sizeof(struct sss_idmap_range));
-
-    new->min = range->min;
-    new->max = range->max;
-
-    return new;
-}
-
-static bool id_is_in_range(uint32_t id, struct idmap_domain_info *dom,
+static bool id_is_in_range(uint32_t id,
+                           struct idmap_range_params *rp,
                            uint32_t *rid)
 {
-    if (id == 0 || dom == NULL || dom->range == NULL) {
+    if (id == 0 || rp == NULL) {
         return false;
     }
 
-    if (id >= dom->range->min && id <= dom->range->max) {
+    if (id >= rp->min_id && id <= rp->max_id) {
         if (rid != NULL) {
-            *rid = dom->first_rid + (id - dom->range->min);
+            *rid = rp->first_rid + (id - rp->min_id);
         }
 
         return true;
@@ -220,8 +208,7 @@ static void sss_idmap_free_domain(struct sss_idmap_ctx *ctx,
         return;
     }
 
-    ctx->free_func(dom->range_id, ctx->alloc_pvt);
-    ctx->free_func(dom->range, ctx->alloc_pvt);
+    ctx->free_func(dom->range_params.range_id, ctx->alloc_pvt);
     ctx->free_func(dom->name, ctx->alloc_pvt);
     ctx->free_func(dom->sid, ctx->alloc_pvt);
     ctx->free_func(dom, ctx->alloc_pvt);
@@ -340,9 +327,12 @@ enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx,
         /* Verify that this slice is not already in use */
         do {
             for (dom = ctx->idmap_domain_info; dom != NULL; dom = dom->next) {
-                if ((dom->range->min <= min && dom->range->max >= max) ||
-                    (dom->range->min >= min && dom->range->min <= max) ||
-                    (dom->range->max >= min && dom->range->max <= max)) {
+                uint32_t dmin = dom->range_params.min_id;
+                uint32_t dmax = dom->range_params.max_id;
+
+                if ((dmin <= min && dmax >= max) ||
+                    (dmin >= min && dmin <= max) ||
+                    (dmax >= min && dmax <= max)) {
                     /* This range overlaps one already registered
                      * We'll try the next available slot
                      */
@@ -445,10 +435,17 @@ enum idmap_error_code sss_idmap_check_collision(struct sss_idmap_ctx *ctx,
 {
     struct idmap_domain_info *dom;
     enum idmap_error_code err;
+    struct sss_idmap_range range;
 
     for (dom = ctx->idmap_domain_info; dom != NULL; dom = dom->next) {
-        err = sss_idmap_check_collision_ex(dom->name, dom->sid, dom->range,
-                                           dom->first_rid, dom->range_id,
+
+        range.min = dom->range_params.min_id;
+        range.max = dom->range_params.max_id;
+
+        err = sss_idmap_check_collision_ex(dom->name, dom->sid,
+                                           &range,
+                                           dom->range_params.first_rid,
+                                           dom->range_params.range_id,
                                            dom->external_mapping,
                                            n_name, n_sid, n_range, n_first_rid,
                                            n_range_id, n_external_mapping);
@@ -459,20 +456,29 @@ enum idmap_error_code sss_idmap_check_collision(struct sss_idmap_ctx *ctx,
     return IDMAP_SUCCESS;
 }
 
-static enum idmap_error_code dom_check_collision(
-                                             struct idmap_domain_info *dom_list,
-                                             struct idmap_domain_info *new_dom)
+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;
     enum idmap_error_code err;
+    struct sss_idmap_range range;
+    struct sss_idmap_range new_dom_range = { new_dom->range_params.min_id,
+                                             new_dom->range_params.max_id };
 
     for (dom = dom_list; dom != NULL; dom = dom->next) {
-        err = sss_idmap_check_collision_ex(dom->name, dom->sid, dom->range,
-                                           dom->first_rid, dom->range_id,
+        range.min = dom->range_params.min_id;
+        range.max = dom->range_params.max_id;
+
+        err = sss_idmap_check_collision_ex(dom->name, dom->sid,
+                                           &range,
+                                           dom->range_params.first_rid,
+                                           dom->range_params.range_id,
                                            dom->external_mapping,
                                            new_dom->name, new_dom->sid,
-                                           new_dom->range, new_dom->first_rid,
-                                           new_dom->range_id,
+                                           &new_dom_range,
+                                           new_dom->range_params.first_rid,
+                                           new_dom->range_params.range_id,
                                            new_dom->external_mapping);
         if (err != IDMAP_SUCCESS) {
             return err;
@@ -531,21 +537,18 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
         }
     }
 
-    dom->range = idmap_range_dup(ctx, range);
-    if (dom->range == NULL) {
-        err = IDMAP_OUT_OF_MEMORY;
-        goto fail;
-    }
+    dom->range_params.min_id = range->min;
+    dom->range_params.max_id = range->max;
 
     if (range_id != NULL) {
-        dom->range_id = idmap_strdup(ctx, range_id);
-        if (dom->range_id == NULL) {
+        dom->range_params.range_id = idmap_strdup(ctx, range_id);
+        if (dom->range_params.range_id == NULL) {
             err = IDMAP_OUT_OF_MEMORY;
             goto fail;
         }
     }
 
-    dom->first_rid = rid;
+    dom->range_params.first_rid = rid;
     dom->external_mapping = external_mapping;
 
     err = dom_check_collision(ctx->idmap_domain_info, dom);
@@ -621,10 +624,10 @@ enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
                     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) {
+                if (rid >= idmap_domain_info->range_params.first_rid) {
+                    id = idmap_domain_info->range_params.min_id
+                            + (rid - idmap_domain_info->range_params.first_rid);
+                    if (id <= idmap_domain_info->range_params.max_id) {
                         *_id = id;
                         return IDMAP_SUCCESS;
                     }
@@ -670,8 +673,8 @@ enum idmap_error_code sss_idmap_check_sid_unix(struct sss_idmap_ctx *ctx,
             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) {
+                if (id >= idmap_domain_info->range_params.min_id
+                    && id <= idmap_domain_info->range_params.max_id) {
                     return IDMAP_SUCCESS;
                 }
 
@@ -700,7 +703,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, &rid)) {
+        if (id_is_in_range(id, &idmap_domain_info->range_params, &rid)) {
 
             if (idmap_domain_info->external_mapping == true
                     || idmap_domain_info->sid == NULL) {
-- 
2.4.3

>From 936cae941983b278dd1fd3baffb04fbddd02f744 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <prei...@redhat.com>
Date: Fri, 27 Nov 2015 04:15:00 -0500
Subject: [PATCH 2/2] IDMAP: introduce secondary slices

Resolves:
https://fedorahosted.org/sssd/ticket/2188
---
 src/config/SSSDConfig/__init__.py.in     |   1 +
 src/config/etc/sssd.api.d/sssd-ad.conf   |   1 +
 src/config/etc/sssd.api.d/sssd-ipa.conf  |   1 +
 src/config/etc/sssd.api.d/sssd-ldap.conf |   1 +
 src/lib/idmap/sss_idmap.c                | 470 +++++++++++++++++++++++++++----
 src/lib/idmap/sss_idmap.exports          |   5 +-
 src/lib/idmap/sss_idmap.h                |  59 ++++
 src/lib/idmap/sss_idmap_private.h        |   4 +
 src/man/include/ldap_id_mapping.xml      |  20 ++
 src/providers/ad/ad_opts.c               |   1 +
 src/providers/ipa/ipa_opts.c             |   1 +
 src/providers/ldap/ldap_opts.c           |   1 +
 src/providers/ldap/sdap.h                |   1 +
 src/providers/ldap/sdap_idmap.c          |  15 +-
 src/tests/cmocka/test_sss_idmap.c        |  86 +++++-
 src/tests/sss_idmap-tests.c              | 121 ++++++++
 16 files changed, 725 insertions(+), 63 deletions(-)

diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index fe2971d993ccf2975bbddbe6c74572ab9f5d4e51..6506dbd3cab3acfbc18443686d87845389b71a43 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -354,6 +354,7 @@ option_strings = {
     'ldap_idmap_autorid_compat' : _('Use autorid-compatible algorithm for ID-mapping'),
     'ldap_idmap_default_domain' : _('Name of the default domain for ID-mapping'),
     'ldap_idmap_default_domain_sid' : _('SID of the default domain for ID-mapping'),
+    'ldap_idmap_extra_slice_init' : _('Number of secondary slices'),
 
     'ldap_groups_use_matching_rule_in_chain' : _('Use LDAP_MATCHING_RULE_IN_CHAIN for group lookups'),
     'ldap_initgroups_use_matching_rule_in_chain' : _('Use LDAP_MATCHING_RULE_IN_CHAIN for initgroup lookups'),
diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
index 5eb546caac913b839112a70bd81dbde2c7ff2d9f..8f828db819e9d33d001bedc13996f52fd89a188d 100644
--- a/src/config/etc/sssd.api.d/sssd-ad.conf
+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
@@ -123,6 +123,7 @@ ldap_idmap_range_size = int, None, false
 ldap_idmap_autorid_compat = bool, None, false
 ldap_idmap_default_domain = str, None, false
 ldap_idmap_default_domain_sid = str, None, false
+ldap_idmap_extra_slice_init = int, None, false
 ldap_groups_use_matching_rule_in_chain = bool, None, false
 ldap_initgroups_use_matching_rule_in_chain = bool, None, false
 ldap_use_tokengroups = bool, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
index ab712fe55cdac6d247a085aeca5cc82d65966623..35bf6facda7ae363087e64efc465959653a43f90 100644
--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
@@ -131,6 +131,7 @@ ldap_idmap_range_size = int, None, false
 ldap_idmap_autorid_compat = bool, None, false
 ldap_idmap_default_domain = str, None, false
 ldap_idmap_default_domain_sid = str, None, false
+ldap_idmap_extra_slice_init = int, None, false
 ldap_groups_use_matching_rule_in_chain = bool, None, false
 ldap_initgroups_use_matching_rule_in_chain = bool, None, false
 ldap_use_tokengroups = bool, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf
index 8fd45fd4093714f458161eb352157c845d926f06..54c50c7798498b20d3875c0bbd5db18be6ea2744 100644
--- a/src/config/etc/sssd.api.d/sssd-ldap.conf
+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
@@ -118,6 +118,7 @@ ldap_idmap_range_size = int, None, false
 ldap_idmap_autorid_compat = bool, None, false
 ldap_idmap_default_domain = str, None, false
 ldap_idmap_default_domain_sid = str, None, false
+ldap_idmap_extra_slice_init = int, None, false
 ldap_groups_use_matching_rule_in_chain = bool, None, false
 ldap_initgroups_use_matching_rule_in_chain = bool, None, false
 ldap_use_tokengroups = bool, None, false
diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c
index fce3010d8e840fa86bc8225ef000e6e789072108..fd4be746ba338891ae5686e1b9f49d7664d91694 100644
--- a/src/lib/idmap/sss_idmap.c
+++ b/src/lib/idmap/sss_idmap.c
@@ -41,6 +41,7 @@ struct idmap_range_params {
     char *range_id;
 
     uint32_t first_rid;
+    struct idmap_range_params *next;
 };
 
 struct idmap_domain_info {
@@ -49,6 +50,9 @@ struct idmap_domain_info {
     struct idmap_range_params range_params;
     struct idmap_domain_info *next;
     bool external_mapping;
+
+    struct idmap_range_params *sec_ranges;
+    bool use_sec_ranges;
 };
 
 static void *default_alloc(size_t size, void *pvt)
@@ -195,12 +199,29 @@ enum idmap_error_code sss_idmap_init(idmap_alloc_func *alloc_func,
     ctx->idmap_opts.idmap_lower = SSS_IDMAP_DEFAULT_LOWER;
     ctx->idmap_opts.idmap_upper = SSS_IDMAP_DEFAULT_UPPER;
     ctx->idmap_opts.rangesize = SSS_IDMAP_DEFAULT_RANGESIZE;
+    ctx->idmap_opts.extra_slice_init = SSS_IDMAP_DEFAULT_EXTRA_SLICE_INIT;
 
     *_ctx = ctx;
 
     return IDMAP_SUCCESS;
 }
 
+static void free_secondary_ranges(struct sss_idmap_ctx *ctx,
+                                  struct idmap_range_params *sec_ranges)
+{
+    struct idmap_range_params *it = sec_ranges;
+    struct idmap_range_params *tmp;
+
+    while (it != NULL) {
+        tmp = it->next;
+
+        ctx->free_func(it->range_id, ctx->alloc_pvt);
+        ctx->free_func(it, ctx->alloc_pvt);
+
+        it = tmp;
+    }
+}
+
 static void sss_idmap_free_domain(struct sss_idmap_ctx *ctx,
                                   struct idmap_domain_info *dom)
 {
@@ -209,6 +230,9 @@ static void sss_idmap_free_domain(struct sss_idmap_ctx *ctx,
     }
 
     ctx->free_func(dom->range_params.range_id, ctx->alloc_pvt);
+
+    free_secondary_ranges(ctx, dom->sec_ranges);
+
     ctx->free_func(dom->name, ctx->alloc_pvt);
     ctx->free_func(dom->sid, ctx->alloc_pvt);
     ctx->free_func(dom, ctx->alloc_pvt);
@@ -269,6 +293,36 @@ enum idmap_error_code sss_idmap_free_bin_sid(struct sss_idmap_ctx *ctx,
     return sss_idmap_free_ptr(ctx, bin_sid);
 }
 
+static bool check_overlap(struct idmap_range_params *range,
+                          id_t min, id_t max)
+{
+    return ((range->min_id <= min && range->max_id >= max)
+                || (range->min_id >= min && range->min_id <= max)
+                || (range->max_id >= min && range->max_id <= max));
+}
+
+static bool check_collision_sec_slices(struct idmap_range_params *sec_ranges,
+                                       id_t min, id_t max)
+{
+    struct idmap_range_params *it;
+
+    for (it = sec_ranges; it != NULL; it = it->next) {
+        if (check_overlap(it, min, max)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static bool check_dom_overlap(struct idmap_range_params *prim_range,
+                              struct idmap_range_params *sec_ranges,
+                              id_t min,
+                              id_t max)
+{
+    return check_overlap(prim_range, min, max)
+        || check_collision_sec_slices(sec_ranges, min, max);
+}
+
 enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx,
                                                 const char *dom_sid,
                                                 id_t *slice_num,
@@ -327,12 +381,9 @@ enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx,
         /* Verify that this slice is not already in use */
         do {
             for (dom = ctx->idmap_domain_info; dom != NULL; dom = dom->next) {
-                uint32_t dmin = dom->range_params.min_id;
-                uint32_t dmax = dom->range_params.max_id;
 
-                if ((dmin <= min && dmax >= max) ||
-                    (dmin >= min && dmin <= max) ||
-                    (dmax >= min && dmax <= max)) {
+                if (check_dom_overlap(&dom->range_params, dom->sec_ranges,
+                                      min, max)) {
                     /* This range overlaps one already registered
                      * We'll try the next available slot
                      */
@@ -487,6 +538,105 @@ idmap_error_code dom_check_collision(struct idmap_domain_info *dom_list,
     return IDMAP_SUCCESS;
 }
 
+static char*
+generate_sec_slice_name(struct sss_idmap_ctx *ctx,
+                        const char *domain_name, int slice_index)
+{
+    const char *SEC_SLICE_NAME_FMT = "%s#%d";
+    char *slice_name;
+    int len, len2;
+
+    len = snprintf(NULL, 0, SEC_SLICE_NAME_FMT, domain_name, slice_index + 1);
+    if (len <= 0) {
+        return NULL;
+    }
+
+    slice_name = ctx->alloc_func(len + 1, ctx->alloc_pvt);
+    if (slice_name == NULL) {
+        return NULL;
+    }
+
+    len2 = snprintf(slice_name, len + 1, SEC_SLICE_NAME_FMT, domain_name,
+                    slice_index + 1);
+    if (len != len2) {
+        ctx->free_func(slice_name, ctx->alloc_pvt);
+        return NULL;
+    }
+
+    return slice_name;
+}
+
+static enum idmap_error_code
+generate_slice(struct sss_idmap_ctx *ctx, char *slice_name, uint32_t first_rid,
+               struct idmap_range_params **_slice)
+{
+    struct idmap_range_params *slice;
+    struct sss_idmap_range tmp_range;
+    enum idmap_error_code err;
+
+    slice = ctx->alloc_func(sizeof(struct idmap_range_params), ctx->alloc_pvt);
+    if (slice == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+
+    slice->next = NULL;
+
+    err = sss_idmap_calculate_range(ctx, slice_name, NULL, &tmp_range);
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(slice, ctx->alloc_pvt);
+        return err;
+    }
+
+    slice->min_id = tmp_range.min;
+    slice->max_id = tmp_range.max;
+    slice->range_id = slice_name;
+    slice->first_rid = first_rid;
+
+    *_slice = slice;
+    return IDMAP_SUCCESS;
+}
+
+static enum idmap_error_code
+get_sec_slices(struct sss_idmap_ctx *ctx,
+               const char *domain_name,
+               uint32_t first_rid,
+               struct idmap_range_params **_sec_slices)
+{
+    struct idmap_range_params *prev = NULL;
+    struct idmap_range_params *sec_slices = NULL;
+    static enum idmap_error_code err;
+    struct idmap_range_params *slice;
+    char *secondary_name;
+
+    for (int i = 0; i < ctx->idmap_opts.extra_slice_init; i++) {
+        secondary_name = generate_sec_slice_name(ctx, domain_name, i + 1);
+        if (secondary_name == NULL) {
+            return IDMAP_OUT_OF_MEMORY;
+        }
+
+        err = generate_slice(ctx, secondary_name, first_rid, &slice);
+        if (err != IDMAP_SUCCESS) {
+            ctx->free_func(secondary_name, ctx->alloc_pvt);
+            return err;
+        }
+
+        first_rid += ctx->idmap_opts.rangesize;
+
+        if (prev != NULL) {
+            prev->next = slice;
+        }
+
+        if (sec_slices == NULL) {
+            sec_slices = slice;
+        }
+
+        prev = slice;
+    }
+
+    *_sec_slices = sec_slices;
+    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,
@@ -567,6 +717,61 @@ fail:
     return err;
 }
 
+enum idmap_error_code
+sss_idmap_add_auto_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,
+                             bool external_mapping)
+{
+    enum idmap_error_code err;
+
+    err = sss_idmap_add_domain_ex(ctx, domain_name, domain_sid, range,
+                                  range_id, rid, external_mapping);
+    if (err != IDMAP_SUCCESS) {
+        return err;
+    }
+
+    if (external_mapping) {
+        /* There's no point in generating secondary ranges if external_mapping
+           is enabled. */
+        ctx->idmap_domain_info->use_sec_ranges = false;
+        return IDMAP_SUCCESS;
+    }
+
+    if ((range->max - range->min + 1) != ctx->idmap_opts.rangesize) {
+        /* Range of primary slice is not equal to the value of
+           ldap_idmap_range_size option. */
+        return IDMAP_ERROR;
+    }
+
+    /* No additional secondary ranges should be added if no sec ranges are
+       predeclared. */
+    if (ctx->idmap_opts.extra_slice_init == 0) {
+        ctx->idmap_domain_info->use_sec_ranges = false;
+        return IDMAP_SUCCESS;
+    }
+
+    /* Add size of primary slice for first_rid of secondary slices. */
+    rid += ctx->idmap_opts.rangesize;
+    err = get_sec_slices(ctx, domain_name, rid,
+                         &ctx->idmap_domain_info->sec_ranges);
+    if (err == IDMAP_SUCCESS) {
+        ctx->idmap_domain_info->use_sec_ranges = true;
+    } else {
+        /* Running out of slices for secondary mapping is a non-fatal
+         * problem. */
+        if (err == IDMAP_OUT_OF_SLICES) {
+            err = IDMAP_SUCCESS;
+        }
+        ctx->idmap_domain_info->use_sec_ranges = false;
+    }
+
+    return err;
+}
+
 enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
                                            const char *domain_name,
                                            const char *domain_sid,
@@ -585,16 +790,140 @@ static bool sss_idmap_sid_is_builtin(const char *sid)
     return false;
 }
 
+static bool parse_rid(const char *sid, size_t dom_prefix_len, long long *_rid)
+{
+    long long rid;
+    char *endptr;
+
+    errno = 0;
+    /* Use suffix of sid - part after domain and following '-' */
+    rid = strtoull(sid + dom_prefix_len + 1, &endptr, 10);
+    if (errno != 0 || rid > UINT32_MAX || *endptr != '\0') {
+        return false;
+    }
+
+    *_rid = rid;
+    return true;
+}
+
+static bool is_sid_from_dom(const char *dom_sid, const char *sid,
+                            size_t *_dom_sid_len)
+{
+    size_t dom_sid_len;
+
+    if (dom_sid == NULL) {
+        return false;
+    }
+
+    dom_sid_len = strlen(dom_sid);
+    *_dom_sid_len = dom_sid_len;
+
+    if (strlen(sid) < dom_sid_len || sid[dom_sid_len] != '-') {
+        return false;
+    }
+
+    return strncmp(sid, dom_sid, dom_sid_len) == 0;
+}
+
+static bool comp_id(struct idmap_range_params *range_params, long long rid,
+                    uint32_t *_id)
+{
+    uint32_t id;
+
+    if (rid >= range_params->first_rid
+            && ((UINT32_MAX - range_params->min_id) >
+               (rid - range_params->first_rid))) {
+        id = range_params->min_id + (rid - range_params->first_rid);
+        if (id <= range_params->max_id) {
+            *_id = id;
+            return true;
+        }
+    }
+    return false;
+}
+
+static enum idmap_error_code
+get_new_sec_slide(struct sss_idmap_ctx *ctx,
+                  const char *dom_name,
+                  long long rid,
+                  struct idmap_range_params **_slice)
+{
+    char *secondary_name;
+    enum idmap_error_code err;
+    int index;
+    int first_rid;
+    struct idmap_range_params *slice;
+
+    index = rid / ctx->idmap_opts.rangesize;
+    first_rid = index * ctx->idmap_opts.rangesize;
+
+    secondary_name = generate_sec_slice_name(ctx, dom_name, index);
+    if (secondary_name == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+
+    err = generate_slice(ctx, secondary_name, first_rid, &slice);
+    if (err == IDMAP_OUT_OF_SLICES) {
+        ctx->free_func(secondary_name, ctx->alloc_pvt);
+        return err;
+    }
+
+    *_slice = slice;
+    return IDMAP_SUCCESS;
+}
+
+static enum idmap_error_code
+try_secondary_slices(struct sss_idmap_ctx *ctx,
+                     struct idmap_domain_info *matched_dom,
+                     const char *sid,
+                     uint32_t *_id)
+{
+    struct idmap_range_params *last_slide = NULL;
+    struct idmap_range_params *new_slice;
+    enum idmap_error_code err;
+    size_t dom_len;
+    long long rid;
+
+    dom_len = strlen(matched_dom->sid);
+
+    if (parse_rid(sid, dom_len, &rid) == false) {
+        return IDMAP_SID_INVALID;
+    }
+
+    for (struct idmap_range_params *it = matched_dom->sec_ranges; it != NULL;
+         it = it->next) {
+        if (comp_id(it, rid, _id)) {
+            return IDMAP_SUCCESS;
+        }
+        last_slide = it;
+    }
+
+    /* If no secondary slide matched then new slide is added. */
+    err = get_new_sec_slide(ctx, matched_dom->name, rid, &new_slice);
+    if (err != IDMAP_SUCCESS) {
+        return err;
+    }
+
+    if (last_slide == NULL) {
+        matched_dom->sec_ranges = new_slice;
+    } else {
+        last_slide->next = new_slice;
+    }
+
+    if (!comp_id(new_slice, rid, _id)) {
+        return IDMAP_ERROR;
+    }
+    return IDMAP_SUCCESS;
+}
+
 enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
                                             const char *sid,
                                             uint32_t *_id)
 {
     struct idmap_domain_info *idmap_domain_info;
+    struct idmap_domain_info *matched_dom = NULL;
     size_t dom_len;
     long long rid;
-    char *endptr;
-    uint32_t id;
-    bool no_range = false;
 
     if (sid == NULL || _id == NULL) {
         return IDMAP_ERROR;
@@ -608,39 +937,34 @@ enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
         return IDMAP_BUILTIN_SID;
     }
 
+    /* Try primary slices */
     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 (idmap_domain_info->external_mapping == true) {
-                    return IDMAP_EXTERNAL;
-                }
+        if (is_sid_from_dom(idmap_domain_info->sid, sid, &dom_len)) {
 
-                errno = 0;
-                rid = strtoull(sid + dom_len + 1, &endptr, 10);
-                if (errno != 0 || rid > UINT32_MAX || *endptr != '\0') {
-                    return IDMAP_SID_INVALID;
-                }
+            if (idmap_domain_info->external_mapping == true) {
+                return IDMAP_EXTERNAL;
+            }
 
-                if (rid >= idmap_domain_info->range_params.first_rid) {
-                    id = idmap_domain_info->range_params.min_id
-                            + (rid - idmap_domain_info->range_params.first_rid);
-                    if (id <= idmap_domain_info->range_params.max_id) {
-                        *_id = id;
-                        return IDMAP_SUCCESS;
-                    }
-                }
+            if (parse_rid(sid, dom_len, &rid) == false) {
+                return IDMAP_SID_INVALID;
+            }
 
-                no_range = true;
+            if (comp_id(&idmap_domain_info->range_params, rid, _id)) {
+                return IDMAP_SUCCESS;
             }
+
+            matched_dom = idmap_domain_info;
         }
 
         idmap_domain_info = idmap_domain_info->next;
     }
 
-    return no_range ? IDMAP_NO_RANGE : IDMAP_NO_DOMAIN;
+    if (matched_dom != NULL && matched_dom->use_sec_ranges) {
+        return try_secondary_slices(ctx, matched_dom, sid, _id);
+    }
+
+    return matched_dom ? IDMAP_NO_RANGE : IDMAP_NO_DOMAIN;
 }
 
 enum idmap_error_code sss_idmap_check_sid_unix(struct sss_idmap_ctx *ctx,
@@ -688,15 +1012,41 @@ enum idmap_error_code sss_idmap_check_sid_unix(struct sss_idmap_ctx *ctx,
     return no_range ? IDMAP_NO_RANGE : IDMAP_SID_UNKNOWN;
 }
 
+static enum idmap_error_code generate_sid(struct sss_idmap_ctx *ctx,
+                                          const char *dom_sid,
+                                          uint32_t rid,
+                                          char **_sid)
+{
+    char *sid;
+    int len;
+    int ret;
+
+    len = snprintf(NULL, 0, SID_FMT, dom_sid, rid);
+    if (len <= 0 || len > SID_STR_MAX_LEN) {
+        return IDMAP_ERROR;
+    }
+
+    sid = ctx->alloc_func(len + 1, ctx->alloc_pvt);
+    if (sid == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+
+    ret = snprintf(sid, len + 1, SID_FMT, dom_sid, rid);
+    if (ret != len) {
+        ctx->free_func(sid, ctx->alloc_pvt);
+        return IDMAP_ERROR;
+    }
+
+    *_sid = sid;
+    return IDMAP_SUCCESS;
+}
+
 enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx,
                                             uint32_t id,
                                             char **_sid)
 {
     struct idmap_domain_info *idmap_domain_info;
-    int len;
-    int ret;
     uint32_t rid;
-    char *sid = NULL;
 
     CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
 
@@ -710,24 +1060,30 @@ enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx,
                 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;
-            }
+            return generate_sid(ctx, idmap_domain_info->sid, rid, _sid);
+        }
 
-            sid = ctx->alloc_func(len + 1, ctx->alloc_pvt);
-            if (sid == NULL) {
-                return IDMAP_OUT_OF_MEMORY;
-            }
+        idmap_domain_info = idmap_domain_info->next;
+    }
 
-            ret = snprintf(sid, len + 1, SID_FMT, idmap_domain_info->sid, rid);
-            if (ret != len) {
-                ctx->free_func(sid, ctx->alloc_pvt);
-                return IDMAP_ERROR;
-            }
+    /* Check secondary ranges. */
+    idmap_domain_info = ctx->idmap_domain_info;
+    while (idmap_domain_info != NULL) {
+
+        for (struct idmap_range_params *it = idmap_domain_info->sec_ranges;
+             it != NULL;
+             it = it->next) {
 
-            *_sid = sid;
-            return IDMAP_SUCCESS;
+
+            if (id_is_in_range(id, it, &rid)) {
+
+                if (idmap_domain_info->external_mapping == true
+                    || idmap_domain_info->sid == NULL) {
+                    return IDMAP_EXTERNAL;
+                }
+
+                return generate_sid(ctx, idmap_domain_info->sid, rid, _sid);
+            }
         }
 
         idmap_domain_info = idmap_domain_info->next;
@@ -970,6 +1326,15 @@ sss_idmap_ctx_set_rangesize(struct sss_idmap_ctx *ctx, id_t rangesize)
 }
 
 enum idmap_error_code
+sss_idmap_ctx_set_extra_slice_init(struct sss_idmap_ctx *ctx,
+                                  int extra_slice_init)
+{
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+    ctx->idmap_opts.extra_slice_init = extra_slice_init;
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code
 sss_idmap_ctx_get_autorid(struct sss_idmap_ctx *ctx, bool *_autorid)
 {
     CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
@@ -1002,6 +1367,15 @@ sss_idmap_ctx_get_rangesize(struct sss_idmap_ctx *ctx, id_t *_rangesize)
 }
 
 enum idmap_error_code
+sss_idmap_ctx_get_extra_slide_max(struct sss_idmap_ctx *ctx,
+                                  int *_extra_slide_max)
+{
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+    *_extra_slide_max =  ctx->idmap_opts.extra_slice_init;
+    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)
diff --git a/src/lib/idmap/sss_idmap.exports b/src/lib/idmap/sss_idmap.exports
index 52115636d5a6b936f18b4392e9d12adc26c85f53..ad1818e10506857b15927d95523b104fcf18f890 100644
--- a/src/lib/idmap/sss_idmap.exports
+++ b/src/lib/idmap/sss_idmap.exports
@@ -1,4 +1,4 @@
-SSS_IDMAP_0.4 {
+SSS_IDMAP_0.5 {
 
     # public functions
     global:
@@ -8,13 +8,16 @@ SSS_IDMAP_0.4 {
         sss_idmap_ctx_set_lower;
         sss_idmap_ctx_set_upper;
         sss_idmap_ctx_set_rangesize;
+        sss_idmap_ctx_set_extra_slice_init;
         sss_idmap_ctx_get_autorid;
         sss_idmap_ctx_get_lower;
         sss_idmap_ctx_get_upper;
         sss_idmap_ctx_get_rangesize;
+        sss_idmap_ctx_get_extra_slice_init;
         sss_idmap_calculate_range;
         sss_idmap_add_domain;
         sss_idmap_add_domain_ex;
+        sss_idmap_add_auto_domain_ex;
         sss_idmap_check_collision;
         sss_idmap_check_collision_ex;
         sss_idmap_sid_to_unix;
diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h
index 0797083293f7e010962828ddcd72709b290859b9..c19f6ad7bd4c4628d08bf5d90888d89bf1c79d5d 100644
--- a/src/lib/idmap/sss_idmap.h
+++ b/src/lib/idmap/sss_idmap.h
@@ -175,6 +175,17 @@ enum idmap_error_code
 sss_idmap_ctx_set_rangesize(struct sss_idmap_ctx *ctx, id_t rangesize);
 
 /**
+ * @brief Set the number of secondary slices available for domain
+ *
+ * @param[in] ctx                  idmap context
+ * @param[in] extra_slice_init     number of secondary slices to be generated
+ *                                 at startup
+ */
+enum idmap_error_code
+sss_idmap_ctx_set_extra_slice_init(struct sss_idmap_ctx *ctx,
+                                  int extra_slice_init);
+
+/**
  * @brief Check if autorid compatibility mode is set
  *
  * @param[in] ctx           idmap context
@@ -211,6 +222,16 @@ enum idmap_error_code
 sss_idmap_ctx_get_rangesize(struct sss_idmap_ctx *ctx, id_t *rangesize);
 
 /**
+ * @brief Get the maximal number of secondary slices available for domain
+ *
+ * @param[in] ctx                  idmap context
+ * @param[out] _extra_slice_init    maximal number of secondary slices
+ */
+enum idmap_error_code
+sss_idmap_ctx_get_extra_slide_max(struct sss_idmap_ctx *ctx,
+                                  int *_extra_slide_max);
+
+/**
  * @brief Calculate new range of available POSIX IDs
  *
  * @param[in] ctx           Idmap context
@@ -291,6 +312,44 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
                                               bool external_mapping);
 
 /**
+ * @brief Add a domain with the first mappable RID to the idmap context and
+ * generate automatically secondary slices
+ *
+ * @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] 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.
+ * @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
+ *                          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_auto_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,
+                             bool external_mapping);
+
+/**
  * @brief Check if a new range would collide with any existing one
  *
  * @param[in] ctx         Idmap context
diff --git a/src/lib/idmap/sss_idmap_private.h b/src/lib/idmap/sss_idmap_private.h
index 1d3a36901781ae51ab79015d0b789559325c8de5..15300d11fc50a47c6d37149fdb79477069d931f4 100644
--- a/src/lib/idmap/sss_idmap_private.h
+++ b/src/lib/idmap/sss_idmap_private.h
@@ -29,6 +29,7 @@
 #define SSS_IDMAP_DEFAULT_UPPER 2000200000
 #define SSS_IDMAP_DEFAULT_RANGESIZE 200000
 #define SSS_IDMAP_DEFAULT_AUTORID false
+#define SSS_IDMAP_DEFAULT_EXTRA_SLICE_INIT 10
 
 #define CHECK_IDMAP_CTX(ctx, ret) do { \
     if (ctx == NULL || ctx->alloc_func == NULL || ctx->free_func == NULL) { \
@@ -48,6 +49,9 @@ struct sss_idmap_opts {
 
     /* number of available UIDs (for single domain) */
     id_t rangesize;
+
+    /* maximal number of secondary slices */
+    int extra_slice_init;
 };
 
 struct sss_idmap_ctx {
diff --git a/src/man/include/ldap_id_mapping.xml b/src/man/include/ldap_id_mapping.xml
index 17ef803289d14fa52b725c90062ee4ba0379acd0..301a7cc9ef62e85f5553d90c0323cc614ec6938c 100644
--- a/src/man/include/ldap_id_mapping.xml
+++ b/src/man/include/ldap_id_mapping.xml
@@ -243,6 +243,26 @@ ldap_schema = ad
                         </para>
                     </listitem>
                 </varlistentry>
+                <varlistentry>
+                    <term>ldap_idmap_extra_slice_init (integer)</term>
+                    <listitem>
+                        <para>
+                          Number of secondary slices to use for ID mapping
+                          that are generated at the startup.
+                        </para>
+                        <para>
+                          Note: Additional secondary slices might be generated
+                          when SID is being mapped to UNIX uid and RID part of
+                          SID is out of range for secondary slices generated so
+                          far. If value of ldap_idmap_extra_slice_init is equal
+                          to 0 then no additional secondary slices are
+                          generated.
+                        </para>
+                        <para>
+                            Default: 10
+                        </para>
+                    </listitem>
+                </varlistentry>
             </variablelist>
         </refsect3>
     </refsect2>
diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
index 4ea96637ca7264c76109ed8c2f7b5e8a94f73bfe..18a21e205cebd0ac14672ebf97b0ede54c63d8f8 100644
--- a/src/providers/ad/ad_opts.c
+++ b/src/providers/ad/ad_opts.c
@@ -135,6 +135,7 @@ struct dp_option ad_def_ldap_opts[] = {
     { "ldap_idmap_autorid_compat", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_idmap_default_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_idmap_default_domain_sid", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_idmap_extra_slice_init", DP_OPT_NUMBER, { .number = 10 }, NULL_NUMBER },
     { "ldap_groups_use_matching_rule_in_chain", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_initgroups_use_matching_rule_in_chain", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_use_tokengroups", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE},
diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c
index bc983ec32d63c37b6fdf06d6009df9084f82d4bf..7ff6589f8cd5342d3f0ef5a8f4210013bbe06bc7 100644
--- a/src/providers/ipa/ipa_opts.c
+++ b/src/providers/ipa/ipa_opts.c
@@ -147,6 +147,7 @@ struct dp_option ipa_def_ldap_opts[] = {
     { "ldap_idmap_autorid_compat", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_idmap_default_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_idmap_default_domain_sid", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_idmap_extra_slice_init", DP_OPT_NUMBER, { .number = 10 }, NULL_NUMBER },
     { "ldap_groups_use_matching_rule_in_chain", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_initgroups_use_matching_rule_in_chain", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_use_tokengroups", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE},
diff --git a/src/providers/ldap/ldap_opts.c b/src/providers/ldap/ldap_opts.c
index 54926c6c31b1b6edfc1f07b22e79225c5fdddf5b..85bc42fdf8cd198e29fcadaa161f92d76092d5bd 100644
--- a/src/providers/ldap/ldap_opts.c
+++ b/src/providers/ldap/ldap_opts.c
@@ -111,6 +111,7 @@ struct dp_option default_basic_opts[] = {
     { "ldap_idmap_autorid_compat", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_idmap_default_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_idmap_default_domain_sid", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_idmap_extra_slice_init", DP_OPT_NUMBER, { .number = 10 }, NULL_NUMBER },
     { "ldap_groups_use_matching_rule_in_chain", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_initgroups_use_matching_rule_in_chain", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_use_tokengroups", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE},
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index edfbf229b4c4396592020de931eba5f83a8f06ed..b82c5475bcb12188fb400c62be6f682e1e2ca541 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -223,6 +223,7 @@ enum sdap_basic_opt {
     SDAP_IDMAP_AUTORID_COMPAT,
     SDAP_IDMAP_DEFAULT_DOMAIN,
     SDAP_IDMAP_DEFAULT_DOMAIN_SID,
+    SDAP_IDMAP_EXTRA_SLICE_INIT,
     SDAP_AD_MATCHING_RULE_GROUPS,
     SDAP_AD_MATCHING_RULE_INITGROUPS,
     SDAP_AD_USE_TOKENGROUPS,
diff --git a/src/providers/ldap/sdap_idmap.c b/src/providers/ldap/sdap_idmap.c
index 4d9de8a447d46dedc8df49dc5663037248eb6996..2bdb4c290d6d2c2a70ec72e2d5e8bd72f44d0130 100644
--- a/src/providers/ldap/sdap_idmap.c
+++ b/src/providers/ldap/sdap_idmap.c
@@ -94,9 +94,10 @@ sdap_idmap_add_configured_external_range(struct sdap_idmap_ctx *idmap_ctx)
 
     id_ctx = idmap_ctx->id_ctx;
 
-    err = sss_idmap_add_domain_ex(idmap_ctx->map, id_ctx->be->domain->name,
-                                  id_ctx->be->domain->domain_id, &range,
-                                  NULL, 0, true);
+    err = sss_idmap_add_auto_domain_ex(idmap_ctx->map,
+                                       id_ctx->be->domain->name,
+                                       id_ctx->be->domain->domain_id, &range,
+                                       NULL, 0, true);
     if (err != IDMAP_SUCCESS) {
         DEBUG(SSSDBG_CRIT_FAILURE,
               "Could not add domain [%s] to the map: [%d]\n",
@@ -142,6 +143,7 @@ sdap_idmap_init(TALLOC_CTX *mem_ctx,
     id_t idmap_upper;
     id_t rangesize;
     bool autorid_mode;
+    int extra_slice_init;
     struct sdap_idmap_ctx *idmap_ctx = NULL;
 
     tmp_ctx = talloc_new(NULL);
@@ -163,6 +165,8 @@ sdap_idmap_init(TALLOC_CTX *mem_ctx,
                                SDAP_IDMAP_RANGESIZE);
     autorid_mode = dp_opt_get_bool(idmap_ctx->id_ctx->opts->basic,
                                    SDAP_IDMAP_AUTORID_COMPAT);
+    extra_slice_init = dp_opt_get_int(idmap_ctx->id_ctx->opts->basic,
+                                     SDAP_IDMAP_EXTRA_SLICE_INIT);
 
     /* Validate that the values make sense */
     if (rangesize <= 0
@@ -203,6 +207,7 @@ sdap_idmap_init(TALLOC_CTX *mem_ctx,
     err |= sss_idmap_ctx_set_lower(idmap_ctx->map, idmap_lower);
     err |= sss_idmap_ctx_set_upper(idmap_ctx->map, idmap_upper);
     err |= sss_idmap_ctx_set_rangesize(idmap_ctx->map, rangesize);
+    err |= sss_idmap_ctx_set_extra_slice_init(idmap_ctx->map, extra_slice_init);
     if (err != IDMAP_SUCCESS) {
         /* This should never happen */
         DEBUG(SSSDBG_CRIT_FAILURE, "sss_idmap_ctx corrupted\n");
@@ -377,8 +382,8 @@ sdap_idmap_add_domain(struct sdap_idmap_ctx *idmap_ctx,
     }
 
     /* Add this domain to the map */
-    err = sss_idmap_add_domain_ex(idmap_ctx->map, dom_name, dom_sid, &range,
-                                  NULL, 0, external_mapping);
+    err = sss_idmap_add_auto_domain_ex(idmap_ctx->map, dom_name, dom_sid,
+                                       &range, NULL, 0, external_mapping);
     if (err != IDMAP_SUCCESS) {
         DEBUG(SSSDBG_CRIT_FAILURE,
               "Could not add domain [%s] to the map: [%d]\n",
diff --git a/src/tests/cmocka/test_sss_idmap.c b/src/tests/cmocka/test_sss_idmap.c
index 1e52c8507461ab3caa04eb2c0e63410c363ba723..91e38546436bb3c248e63dcba0bbc3ba425c3483 100644
--- a/src/tests/cmocka/test_sss_idmap.c
+++ b/src/tests/cmocka/test_sss_idmap.c
@@ -82,7 +82,7 @@ static int test_sss_idmap_setup(void **state)
 }
 
 static int setup_ranges(struct test_ctx *test_ctx, bool external_mapping,
-                        bool second_domain)
+                        bool second_domain, bool sec_slices)
 {
     struct sss_idmap_range range;
     enum idmap_error_code err;
@@ -103,15 +103,26 @@ static int setup_ranges(struct test_ctx *test_ctx, bool external_mapping,
         sid = TEST_DOM_SID;
     }
 
-    err = sss_idmap_add_domain_ex(test_ctx->idmap_ctx, name, sid, &range, NULL,
-                                  0, external_mapping);
+    if (sec_slices) {
+        err = sss_idmap_add_auto_domain_ex(test_ctx->idmap_ctx, name, sid,
+                                           &range, NULL, 0, external_mapping);
+    } else {
+        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);
+    if (sec_slices) {
+        err = sss_idmap_add_auto_domain_ex(test_ctx->idmap_ctx, name, sid,
+                                           &range, NULL, TEST_OFFSET,
+                                           external_mapping);
+    } else {
+        err = sss_idmap_add_domain_ex(test_ctx->idmap_ctx, name, sid, &range,
+                                      NULL, TEST_OFFSET, external_mapping);
+    }
     assert_int_equal(err, IDMAP_SUCCESS);
     return 0;
 }
@@ -124,7 +135,19 @@ static int test_sss_idmap_setup_with_domains(void **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, false, false, false);
+    return 0;
+}
+
+static int test_sss_idmap_setup_with_domains_sec_slices(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, true);
     return 0;
 }
 
@@ -136,7 +159,7 @@ static int test_sss_idmap_setup_with_external_mappings(void **state) {
     test_ctx = talloc_get_type(*state, struct test_ctx);
     assert_non_null(test_ctx);
 
-    setup_ranges(test_ctx, true, false);
+    setup_ranges(test_ctx, true, false, false);
     return 0;
 }
 
@@ -148,8 +171,8 @@ static int test_sss_idmap_setup_with_both(void **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);
+    setup_ranges(test_ctx, false, false, false);
+    setup_ranges(test_ctx, true, true, false);
     return 0;
 }
 
@@ -274,6 +297,48 @@ void test_map_id(void **state)
     sss_idmap_free_sid(test_ctx->idmap_ctx, sid);
 }
 
+void test_map_id_sec_slices(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"-4000000",
+                                &id);
+    assert_int_equal(err, IDMAP_SUCCESS);
+    assert_int_equal(id, 351800000);
+
+    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");
+    sss_idmap_free_sid(test_ctx->idmap_ctx, sid);
+
+    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);
+    sss_idmap_free_sid(test_ctx->idmap_ctx, sid);
+}
+
 void test_map_id_external(void **state)
 {
     struct test_ctx *test_ctx;
@@ -523,6 +588,9 @@ int main(int argc, const char *argv[])
         cmocka_unit_test_setup_teardown(test_map_id,
                                         test_sss_idmap_setup_with_domains,
                                         test_sss_idmap_teardown),
+        cmocka_unit_test_setup_teardown(test_map_id_sec_slices,
+                                        test_sss_idmap_setup_with_domains_sec_slices,
+                                        test_sss_idmap_teardown),
         cmocka_unit_test_setup_teardown(test_map_id_external,
                                         test_sss_idmap_setup_with_external_mappings,
                                         test_sss_idmap_teardown),
diff --git a/src/tests/sss_idmap-tests.c b/src/tests/sss_idmap-tests.c
index f5ec68383679bfc685467bd625c86b8d6f474d48..1e130778f4ae092d21103155852fa6ee15e263bf 100644
--- a/src/tests/sss_idmap-tests.c
+++ b/src/tests/sss_idmap-tests.c
@@ -85,6 +85,20 @@ void idmap_add_domain_setup(void)
     fail_unless(err == IDMAP_SUCCESS, "sss_idmap_add_domain failed.");
 }
 
+void idmap_add_domain_with_sec_slices_setup(void)
+{
+    enum idmap_error_code err;
+    struct sss_idmap_range range = {
+        IDMAP_RANGE_MIN,
+        IDMAP_RANGE_MIN + idmap_ctx->idmap_opts.rangesize - 1,
+    };
+
+    err = sss_idmap_add_auto_domain_ex(idmap_ctx, "test.dom", "S-1-5-21-1-2-3",
+                                       &range, NULL, 0, false);
+
+    fail_unless(err == IDMAP_SUCCESS, "sss_idmap_add_auto_domain_ex failed.");
+}
+
 START_TEST(idmap_test_is_domain_sid)
 {
     size_t c;
@@ -225,6 +239,63 @@ START_TEST(idmap_test_sid2uid)
 }
 END_TEST
 
+START_TEST(idmap_test_sid2uid_ss)
+{
+    enum idmap_error_code err;
+    uint32_t id;
+
+    err = sss_idmap_sid_to_unix(idmap_ctx, "S-1-5-21-1-2-3333-1000", &id);
+    fail_unless(err == IDMAP_NO_DOMAIN, "sss_idmap_sid_to_unix did not detect "
+                                        "unknown domain");
+
+    /* RID out of primary and secondary range */
+    err = sss_idmap_sid_to_unix(idmap_ctx, "S-1-5-21-1-2-3-4000000", &id);
+    fail_unless(err == IDMAP_SUCCESS, "sss_idmap_sid_to_unix failed.");
+    fail_unless(id == 351800000,
+                "sss_idmap_sid_to_unix returned wrong id, "
+                "got [%d], expected [%d].", id, 351800000);
+
+    err = sss_idmap_sid_to_unix(idmap_ctx, "S-1-5-21-1-2-3-1000", &id);
+    fail_unless(err == IDMAP_SUCCESS, "sss_idmap_sid_to_unix failed.");
+    fail_unless(id == (1000 + IDMAP_RANGE_MIN),
+                "sss_idmap_sid_to_unix returned wrong id, "
+                "got [%d], expected [%d].", id, 1000 + IDMAP_RANGE_MIN);
+
+    err = sss_idmap_sid_to_unix(idmap_ctx, "S-1-5-21-1-2-3-210000", &id);
+    fail_unless(err == IDMAP_SUCCESS, "sss_idmap_sid_to_unix failed.");
+    fail_unless(id == 1638210000,
+                "sss_idmap_sid_to_unix returned wrong id, "
+                "got [%d], expected [%d].", id, 1638210000);
+}
+END_TEST
+
+START_TEST(idmap_test_sid2uid_ext_sec_slices)
+{
+    enum idmap_error_code err;
+    uint32_t id;
+    char *sid;
+
+    err = sss_idmap_unix_to_sid(idmap_ctx, 351800000, &sid);
+    fail_unless(err == IDMAP_NO_DOMAIN, "sss_idmap_unix_to_sid did not detect "
+                                        "id out of range");
+
+    /* RID out of primary and secondary range */
+    err = sss_idmap_sid_to_unix(idmap_ctx, "S-1-5-21-1-2-3-4000000", &id);
+    fail_unless(err == IDMAP_SUCCESS, "sss_idmap_sid_to_unix failed.");
+    fail_unless(id == 351800000,
+                "sss_idmap_sid_to_unix returned wrong id, "
+                "got [%d], expected [%d].", id, 351800000);
+
+    /* Secondary ranges were expanded by sid_to_unix call */
+    err = sss_idmap_unix_to_sid(idmap_ctx, 351800000, &sid);
+    fail_unless(err == IDMAP_SUCCESS, "sss_idmap_unix_to_sid failed.");
+    fail_unless(strcmp(sid, "S-1-5-21-1-2-3-4000000") == 0,
+                "sss_idmap_unix_to_sid returned wrong SID, "
+                "expected [%s], got [%s].", "S-1-5-21-1-2-3-4000000", sid);
+    sss_idmap_free_sid(idmap_ctx, sid);
+}
+END_TEST
+
 START_TEST(idmap_test_bin_sid2uid)
 {
     enum idmap_error_code err;
@@ -284,6 +355,38 @@ START_TEST(idmap_test_uid2sid)
 }
 END_TEST
 
+START_TEST(idmap_test_uid2sid_ss)
+{
+    enum idmap_error_code err;
+    char *sid;
+
+    err = sss_idmap_unix_to_sid(idmap_ctx,
+                                IDMAP_RANGE_MIN + idmap_ctx->idmap_opts.rangesize + 1,
+                                &sid);
+    fail_unless(err == IDMAP_NO_DOMAIN, "sss_idmap_unix_to_sid did not detect "
+                                        "id out of range");
+
+    err = sss_idmap_unix_to_sid(idmap_ctx, 2234, &sid);
+    fail_unless(err == IDMAP_SUCCESS, "sss_idmap_unix_to_sid failed.");
+    fail_unless(strcmp(sid, "S-1-5-21-1-2-3-1000") == 0,
+                "sss_idmap_unix_to_sid returned wrong SID, "
+                "expected [%s], got [%s].", "S-1-5-21-1-2-3-1000", sid);
+
+    sss_idmap_free_sid(idmap_ctx, sid);
+
+    /* Secondary ranges */
+    err = sss_idmap_unix_to_sid(idmap_ctx,
+                                111400000,
+                                &sid);
+    fail_unless(err == IDMAP_SUCCESS, "sss_idmap_unix_to_sid failed.");
+    fail_unless(strcmp(sid, "S-1-5-21-1-2-3-400000") == 0,
+                "sss_idmap_unix_to_sid returned wrong SID, "
+                "expected [%s], got [%s].", "S-1-5-21-1-2-3-400000", sid);
+
+    sss_idmap_free_sid(idmap_ctx, sid);
+}
+END_TEST
+
 START_TEST(idmap_test_uid2dom_sid)
 {
     enum idmap_error_code err;
@@ -618,6 +721,24 @@ Suite *idmap_test_suite (void)
 
     suite_add_tcase(s, tc_map);
 
+    /* Test secondary slices */
+    TCase *tc_map_ss = tcase_create("IDMAP mapping tests");
+    tcase_add_checked_fixture(tc_map_ss,
+                              ck_leak_check_setup,
+                              ck_leak_check_teardown);
+    tcase_add_checked_fixture(tc_map_ss,
+                              idmap_ctx_setup,
+                              idmap_ctx_teardown);
+    tcase_add_checked_fixture(tc_map_ss,
+                              idmap_add_domain_with_sec_slices_setup,
+                              NULL);
+
+    tcase_add_test(tc_map_ss, idmap_test_sid2uid_ss);
+    tcase_add_test(tc_map_ss, idmap_test_uid2sid_ss);
+    tcase_add_test(tc_map_ss, idmap_test_sid2uid_ext_sec_slices);
+
+    suite_add_tcase(s, tc_map_ss);
+
     return s;
 }
 int main(int argc, const char *argv[])
-- 
2.4.3

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

Reply via email to