From 8babbeee01e67893af4828ddfc922ecac0be4197 Mon Sep 17 00:00:00 2001 From: Pavel Reichl Date: Fri, 27 Nov 2015 04:15:00 -0500 Subject: IDMAP: Add support for automatic adding of ranges Resolves: https://fedorahosted.org/sssd/ticket/2188 Reviewed-by: Sumit Bose --- Makefile.am | 2 +- 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 | 526 ++++++++++++++++++++++++++++--- src/lib/idmap/sss_idmap.exports | 10 + src/lib/idmap/sss_idmap.h | 65 ++++ 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 | 16 +- src/tests/cmocka/test_sss_idmap.c | 87 ++++- src/tests/sss_idmap-tests.c | 332 +++++++++++++++++++ 17 files changed, 1007 insertions(+), 63 deletions(-) diff --git a/Makefile.am b/Makefile.am index 6008b06dd..921b8c3df 100644 --- a/Makefile.am +++ b/Makefile.am @@ -956,7 +956,7 @@ libsss_idmap_la_SOURCES = \ src/util/murmurhash3.c libsss_idmap_la_LDFLAGS = \ -Wl,--version-script,$(srcdir)/src/lib/idmap/sss_idmap.exports \ - -version-info 4:0:4 + -version-info 5:0:5 dist_noinst_DATA += src/lib/idmap/sss_idmap.exports diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in index 647d08125..1fdb907c5 100644 --- a/src/config/SSSDConfig/__init__.py.in +++ b/src/config/SSSDConfig/__init__.py.in @@ -356,6 +356,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_helper_table_size' : _('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 0ea73d141..149590f4f 100644 --- a/src/config/etc/sssd.api.d/sssd-ad.conf +++ b/src/config/etc/sssd.api.d/sssd-ad.conf @@ -125,6 +125,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_helper_table_size = 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 13715ec34..822599db6 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_helper_table_size = 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 8fd45fd40..fc9fcefce 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_helper_table_size = 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 23ed46a58..269ef0132 100644 --- a/src/lib/idmap/sss_idmap.c +++ b/src/lib/idmap/sss_idmap.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "lib/idmap/sss_idmap.h" #include "lib/idmap/sss_idmap_private.h" @@ -41,6 +42,7 @@ struct idmap_range_params { char *range_id; uint32_t first_rid; + struct idmap_range_params *next; }; struct idmap_domain_info { @@ -49,6 +51,13 @@ struct idmap_domain_info { struct idmap_range_params range_params; struct idmap_domain_info *next; bool external_mapping; + + struct idmap_range_params *helpers; + bool auto_add_ranges; + bool helpers_owner; + + idmap_store_cb cb; + void *pvt; }; static void *default_alloc(size_t size, void *pvt) @@ -195,12 +204,34 @@ 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_helpers(struct sss_idmap_ctx *ctx, + struct idmap_range_params *helpers, + bool helpers_owner) +{ + struct idmap_range_params *it = helpers; + struct idmap_range_params *tmp; + + if (helpers_owner == false) { + return; + } + + 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 +240,9 @@ static void sss_idmap_free_domain(struct sss_idmap_ctx *ctx, } ctx->free_func(dom->range_params.range_id, ctx->alloc_pvt); + + free_helpers(ctx, dom->helpers, dom->helpers_owner); + 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 +303,22 @@ 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_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); +} + enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx, const char *dom_sid, id_t *slice_num, @@ -327,12 +377,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, + min, max)) { /* This range overlaps one already registered * We'll try the next available slot */ @@ -487,6 +534,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, uint32_t rid) +{ + const char *SEC_SLICE_NAME_FMT = "%s-%"PRIu32; + char *slice_name; + int len, len2; + + len = snprintf(NULL, 0, SEC_SLICE_NAME_FMT, domain_name, rid); + 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, + rid); + 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_helpers(struct sss_idmap_ctx *ctx, + const char *domain_sid, + 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_sid, first_rid); + 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 +713,67 @@ 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, + idmap_store_cb cb, + void *pvt) +{ + 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->auto_add_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->auto_add_ranges = false; + return IDMAP_SUCCESS; + } + + /* Add size of primary slice for first_rid of secondary slices. */ + rid += ctx->idmap_opts.rangesize; + err = get_helpers(ctx, domain_sid, rid, + &ctx->idmap_domain_info->helpers); + if (err == IDMAP_SUCCESS) { + ctx->idmap_domain_info->auto_add_ranges = true; + ctx->idmap_domain_info->helpers_owner = 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->auto_add_ranges = false; + } + + ctx->idmap_domain_info->cb = cb; + ctx->idmap_domain_info->pvt = pvt; + + 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 +792,198 @@ 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_range(struct sss_idmap_ctx *ctx, + const char *dom_sid, + long long rid, + struct idmap_range_params **_range) +{ + char *secondary_name; + enum idmap_error_code err; + int first_rid; + struct idmap_range_params *range; + + first_rid = (rid / ctx->idmap_opts.rangesize) * ctx->idmap_opts.rangesize; + + secondary_name = generate_sec_slice_name(ctx, dom_sid, first_rid); + if (secondary_name == NULL) { + return IDMAP_OUT_OF_MEMORY; + } + + err = generate_slice(ctx, secondary_name, first_rid, &range); + if (err == IDMAP_OUT_OF_SLICES) { + ctx->free_func(secondary_name, ctx->alloc_pvt); + return err; + } + + *_range = range; + return IDMAP_SUCCESS; +} + +static enum idmap_error_code +spawn_dom(struct sss_idmap_ctx *ctx, + struct idmap_domain_info *parent, + struct idmap_range_params *range) +{ + struct sss_idmap_range tmp; + static enum idmap_error_code err; + struct idmap_domain_info *it; + + tmp.min = range->min_id; + tmp.max = range->max_id; + + err = sss_idmap_add_domain_ex(ctx, + parent->name, + parent->sid, + &tmp, range->range_id, + range->first_rid, false); + if (err != IDMAP_SUCCESS) { + return err; + } + + it = ctx->idmap_domain_info; + while (it != NULL) { + /* Find the newly added domain. */ + if (it->range_params.first_rid == range->first_rid + && it->range_params.min_id == range->min_id + && it->range_params.max_id == range->max_id) { + + /* Share helpers. */ + it->helpers = parent->helpers; + it->auto_add_ranges = parent->auto_add_ranges; + + /* Share call back for storing domains */ + it->cb = parent->cb; + it->pvt = parent->pvt; + break; + } + + it = it->next; + } + + if (it == NULL) { + /* Failed to find just added domain. */ + return IDMAP_ERROR; + } + + /* Store mapping for newly created domain. */ + if (it->cb != NULL) { + err = it->cb(it->name, + it->sid, + it->range_params.range_id, + it->range_params.min_id, + it->range_params.max_id, + it->range_params.first_rid, + it->pvt); + if (err != IDMAP_SUCCESS) { + return err; + } + } + + return IDMAP_SUCCESS; +} + +static enum idmap_error_code +add_dom_for_sid(struct sss_idmap_ctx *ctx, + struct idmap_domain_info *matched_dom, + const char *sid, + uint32_t *_id) +{ + enum idmap_error_code err; + long long rid; + struct idmap_range_params *range = NULL; + + if (parse_rid(sid, strlen(matched_dom->sid), &rid) == false) { + err = IDMAP_SID_INVALID; + goto done; + } + + /* todo optimize */ + err = get_range(ctx, matched_dom->sid, rid, &range); + if (err != IDMAP_SUCCESS) { + goto done; + } + + err = spawn_dom(ctx, matched_dom, range); + if (err != IDMAP_SUCCESS) { + goto done; + } + + if (!comp_id(range, rid, _id)) { + err = IDMAP_ERROR; + goto done; + } + + err = IDMAP_SUCCESS; + +done: + if (range != NULL) { + ctx->free_func(range->range_id, ctx->alloc_pvt); + } + ctx->free_func(range, ctx->alloc_pvt); + return err; +} + 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 +997,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->auto_add_ranges) { + return add_dom_for_sid(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 +1072,42 @@ 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; + enum idmap_error_code err; CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID); @@ -710,24 +1121,34 @@ 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) { - *_sid = sid; - return IDMAP_SUCCESS; + for (struct idmap_range_params *it = idmap_domain_info->helpers; + it != NULL; + it = it->next) { + + if (id_is_in_range(id, it, &rid)) { + + if (idmap_domain_info->external_mapping == true + || idmap_domain_info->sid == NULL) { + return IDMAP_EXTERNAL; + } + + err = spawn_dom(ctx, idmap_domain_info, it); + if (err != IDMAP_SUCCESS) { + return err; + } + + return generate_sid(ctx, idmap_domain_info->sid, rid, _sid); + } } idmap_domain_info = idmap_domain_info->next; @@ -969,6 +1390,15 @@ sss_idmap_ctx_set_rangesize(struct sss_idmap_ctx *ctx, id_t rangesize) return IDMAP_SUCCESS; } +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) { diff --git a/src/lib/idmap/sss_idmap.exports b/src/lib/idmap/sss_idmap.exports index 52115636d..f10feea6f 100644 --- a/src/lib/idmap/sss_idmap.exports +++ b/src/lib/idmap/sss_idmap.exports @@ -54,3 +54,13 @@ SSS_IDMAP_0.4 { local: *; }; + +SSS_IDMAP_0.5 { + + # public functions + global: + + sss_idmap_ctx_set_extra_slice_init; + sss_idmap_add_auto_domain_ex; + +} SSS_IDMAP_0.4; \ No newline at end of file diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h index 079708329..483241eea 100644 --- a/src/lib/idmap/sss_idmap.h +++ b/src/lib/idmap/sss_idmap.h @@ -93,6 +93,17 @@ enum idmap_error_code { typedef void *(idmap_alloc_func)(size_t size, void *pvt); typedef void (idmap_free_func)(void *ptr, void *pvt); +/** + * Typedef for storing mappings of dynamically created domains + */ +typedef enum idmap_error_code (*idmap_store_cb)(const char *dom_name, + const char *dom_sid, + const char *range_id, + uint32_t min_id, + uint32_t max_id, + uint32_t first_rid, + void *pvt); + /** * Structure for id ranges * FIXME: this struct might change when it is clear how ranges are handled on @@ -174,6 +185,17 @@ sss_idmap_ctx_set_upper(struct sss_idmap_ctx *ctx, id_t upper); 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 * @@ -290,6 +312,49 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx, uint32_t rid, 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. + * @param[in] s_cv The callback for storing mapping of dynamically + * created domains. + * @param[in] pvt Private data for callback cb. + * + * @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, + idmap_store_cb cb, + void *pvt); + /** * @brief Check if a new range would collide with any existing one * diff --git a/src/lib/idmap/sss_idmap_private.h b/src/lib/idmap/sss_idmap_private.h index 1d3a36901..15300d11f 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 17ef80328..a088c4e81 100644 --- a/src/man/include/ldap_id_mapping.xml +++ b/src/man/include/ldap_id_mapping.xml @@ -243,6 +243,26 @@ ldap_schema = ad + + ldap_idmap_helper_table_size (integer) + + + Maximal number of secondary slices that is tried when + performing mapping from UNIX id to SID. + + + Note: Additional secondary slices might be generated + when SID is being mapped to UNIX id and RID part of + SID is out of range for secondary slices generated so + far. If value of ldap_idmap_helper_table_size is equal + to 0 then no additional secondary slices are + generated. + + + Default: 10 + + + diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c index 8b2841ead..28d4768b2 100644 --- a/src/providers/ad/ad_opts.c +++ b/src/providers/ad/ad_opts.c @@ -137,6 +137,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_helper_table_size", 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 cda10f89a..cd87852e5 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_helper_table_size", 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 54926c6c3..84ba2b542 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_helper_table_size", 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 d7a299220..e06f2b6ac 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 4d9de8a44..4e322124c 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, NULL, NULL); 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,9 @@ 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, + NULL, NULL); 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 1e52c8507..00e03ffd9 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,27 @@ 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, + NULL, NULL); + } 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, NULL, NULL); + } 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 +136,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 +160,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 +172,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 +298,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, 575600000); + + 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 +589,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 f5ec68383..900b7bff1 100644 --- a/src/tests/sss_idmap-tests.c +++ b/src/tests/sss_idmap-tests.c @@ -68,6 +68,20 @@ void idmap_ctx_setup(void) fail_unless(idmap_ctx != NULL, "sss_idmap_init returned NULL."); } +void idmap_ctx_setup_additional_seconary_slices(void) +{ + enum idmap_error_code err; + + err = sss_idmap_init(idmap_talloc, global_talloc_context, idmap_talloc_free, + &idmap_ctx); + + fail_unless(err == IDMAP_SUCCESS, "sss_idmap_init failed."); + fail_unless(idmap_ctx != NULL, "sss_idmap_init returned NULL."); + + idmap_ctx->idmap_opts.rangesize = 10; + idmap_ctx->idmap_opts.extra_slice_init = 5; +} + void idmap_ctx_teardown(void) { enum idmap_error_code err; @@ -85,6 +99,86 @@ 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, NULL, NULL); + + fail_unless(err == IDMAP_SUCCESS, "sss_idmap_add_auto_domain_ex failed."); +} + + +enum idmap_error_code cb(const char *dom_name, + const char *dom_sid, + const char *range_id, + uint32_t min_id, + uint32_t max_id, + uint32_t first_rid, + void *pvt) +{ + return IDMAP_ERROR; +} + +void idmap_add_domain_with_sec_slices_setup_cb_fail(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, cb, NULL); + + fail_unless(err == IDMAP_SUCCESS, "sss_idmap_add_auto_domain_ex failed."); +} + + +#define MAX 1000 +char data[MAX]; + +enum idmap_error_code cb2(const char *dom_name, + const char *dom_sid, + const char *range_id, + uint32_t min_id, + uint32_t max_id, + uint32_t first_rid, + void *pvt) +{ + char *p = (char*)pvt; + size_t len; + + len = snprintf(p, MAX, "%s, %s %s, %"PRIu32", %"PRIu32", %" PRIu32, + dom_name, dom_sid, range_id, min_id, max_id, first_rid); + + if (len >= MAX) { + return IDMAP_OUT_OF_MEMORY; + } + return IDMAP_SUCCESS; +} + +void idmap_add_domain_with_sec_slices_setup_cb_ok(void) +{ + enum idmap_error_code err; + struct sss_idmap_range range = { + IDMAP_RANGE_MIN, + IDMAP_RANGE_MIN + idmap_ctx->idmap_opts.rangesize - 1, + }; + + void *pvt = (void*) data; + + err = sss_idmap_add_auto_domain_ex(idmap_ctx, "test.dom", "S-1-5-21-1-2-3", + &range, NULL, 0, false, cb2, pvt); + + fail_unless(err == IDMAP_SUCCESS, "sss_idmap_add_auto_domain_ex failed."); +} + START_TEST(idmap_test_is_domain_sid) { size_t c; @@ -225,6 +319,145 @@ START_TEST(idmap_test_sid2uid) } END_TEST +START_TEST(idmap_test_sid2uid_ss) +{ + enum idmap_error_code err; + uint32_t id; + const uint32_t exp_id = 351800000; + const uint32_t exp_id2 = 832610000; + + 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 == exp_id, + "sss_idmap_sid_to_unix returned wrong id, " + "got [%d], expected [%d].", id, exp_id); + + 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 == exp_id2, + "sss_idmap_sid_to_unix returned wrong id, " + "got [%d], expected [%d].", id, exp_id2); +} +END_TEST + +START_TEST(idmap_test_sid2uid_ext_sec_slices) +{ + enum idmap_error_code err; + uint32_t id; + char *sid; + const uint32_t exp_id = 351800000; + + err = sss_idmap_unix_to_sid(idmap_ctx, exp_id, &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 == exp_id, + "sss_idmap_sid_to_unix returned wrong id, " + "got [%d], expected [%d].", id, exp_id); + + /* Secondary ranges were expanded by sid_to_unix call */ + err = sss_idmap_unix_to_sid(idmap_ctx, exp_id, &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_dyn_dom_store_cb_fail) +{ + enum idmap_error_code err; + uint32_t id; + char *sid; + const uint32_t exp_id = 351800000; + + err = sss_idmap_unix_to_sid(idmap_ctx, exp_id, &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_ERROR, "sss_idmap_sid_to_unix failed."); +} +END_TEST + +START_TEST(idmap_test_dyn_dom_store_cb_ok) +{ + enum idmap_error_code err; + uint32_t id; + char *sid; + const uint32_t exp_id = 351800000; + const char *exp_stored_data = "test.dom, S-1-5-21-1-2-3 S-1-5-21-1-2-3-4000000, 351800000, 351999999, 4000000"; + + err = sss_idmap_unix_to_sid(idmap_ctx, exp_id, &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(strcmp(data, + exp_stored_data) == 0, + "Storing dynamic domains idmapping failed: " + "expected [%s] but got [%s].", exp_stored_data, data); +} +END_TEST + + +START_TEST(idmap_test_sid2uid_additional_secondary_slices) +{ + enum idmap_error_code err; + struct TALLOC_CTX *tmp_ctx; + const char *dom_prefix = "S-1-5-21-1-2-3"; + const int max_rid = 80; + const char *sids[max_rid]; + unsigned int ids[max_rid]; + + tmp_ctx = talloc_new(NULL); + fail_unless(tmp_ctx != NULL, "Out of memory."); + + for (unsigned int i = 0; i < max_rid + 1; i++) { + sids[i] = talloc_asprintf(tmp_ctx, "%s-%u", dom_prefix, i); + + fail_unless(sids[i] != NULL, "Out of memory"); + + err = sss_idmap_sid_to_unix(idmap_ctx, sids[i], &ids[i]); + fail_unless(err == IDMAP_SUCCESS, "sss_idmap_sid_to_unix failed."); + } + + for (unsigned int i = 0; i < max_rid + 1; i++) { + char *sid; + + err = sss_idmap_unix_to_sid(idmap_ctx, ids[i], &sid); + fail_unless(err == IDMAP_SUCCESS, "sss_idmap_sid_to_unix failed."); + + fail_unless(strcmp(sid, sids[i]) == 0, + "sss_idmap_unix_to_sid returned wrong sid, " + "got [%s], expected [%s].", sid, sids[i]); + talloc_free(sid); + } + + talloc_free(tmp_ctx); +} +END_TEST + START_TEST(idmap_test_bin_sid2uid) { enum idmap_error_code err; @@ -284,6 +517,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, + 313800000, + &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 +883,73 @@ 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); + + /* Test secondary slices - callback to store failed. */ + TCase *tc_map_cb_fail = tcase_create("IDMAP mapping tests - store fail"); + tcase_add_checked_fixture(tc_map_cb_fail, + ck_leak_check_setup, + ck_leak_check_teardown); + tcase_add_checked_fixture(tc_map_cb_fail, + idmap_ctx_setup, + idmap_ctx_teardown); + tcase_add_checked_fixture(tc_map_cb_fail, + idmap_add_domain_with_sec_slices_setup_cb_fail, + NULL); + + tcase_add_test(tc_map_cb_fail, idmap_test_dyn_dom_store_cb_fail); + suite_add_tcase(s, tc_map_cb_fail); + + /* Test secondary slices - callback to store passed. */ + TCase *tc_map_cb_ok = tcase_create("IDMAP mapping tests"); + tcase_add_checked_fixture(tc_map_cb_ok, + ck_leak_check_setup, + ck_leak_check_teardown); + tcase_add_checked_fixture(tc_map_cb_ok, + idmap_ctx_setup, + idmap_ctx_teardown); + tcase_add_checked_fixture(tc_map_cb_ok, + idmap_add_domain_with_sec_slices_setup_cb_ok, + NULL); + + tcase_add_test(tc_map_cb_ok, idmap_test_dyn_dom_store_cb_ok); + suite_add_tcase(s, tc_map_cb_ok); + + /* Test additional secondary slices */ + TCase *tc_map_additional_secondary_slices = \ + tcase_create("IDMAP additional secondary slices"); + + tcase_add_checked_fixture(tc_map_additional_secondary_slices, + ck_leak_check_setup, + ck_leak_check_teardown); + tcase_add_checked_fixture(tc_map_additional_secondary_slices, + idmap_ctx_setup_additional_seconary_slices, + idmap_ctx_teardown); + tcase_add_checked_fixture(tc_map_additional_secondary_slices, + idmap_add_domain_with_sec_slices_setup, + NULL); + + tcase_add_test(tc_map_additional_secondary_slices, + idmap_test_sid2uid_additional_secondary_slices); + + suite_add_tcase(s, tc_map_additional_secondary_slices); + return s; } int main(int argc, const char *argv[]) -- cgit