From 95a08a0c02281b28bd1914e0727b40ae25b4e16a Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Mon, 10 Jun 2013 11:55:16 +0200 Subject: idmap: allow first RID to be set Currently libss_idmap implicitly assumes that the RID 0 is always mapped to the first ID of the given range. This is not the case anymore when multiple ranges are used e.g. for trusted domains in FreeIPA. A new call sss_idmap_add_domain_ex() was added which can take the first RID as an argument. This new call will get more options with other patches hence I didn't change the library version with this patch. Fixes https://fedorahosted.org/sssd/ticket/1938 --- src/lib/idmap/sss_idmap.c | 99 ++++++++++++++++++++++++++++++++++++++--------- src/lib/idmap/sss_idmap.h | 30 +++++++++++++- 2 files changed, 109 insertions(+), 20 deletions(-) diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c index 3a39aaef..122f62f5 100644 --- a/src/lib/idmap/sss_idmap.c +++ b/src/lib/idmap/sss_idmap.c @@ -38,6 +38,7 @@ struct idmap_domain_info { char *sid; struct sss_idmap_range *range; struct idmap_domain_info *next; + uint32_t first_rid; }; static void *default_alloc(size_t size, void *pvt) @@ -90,16 +91,16 @@ static struct sss_idmap_range *idmap_range_dup(struct sss_idmap_ctx *ctx, return new; } -static bool id_is_in_range(uint32_t id, struct sss_idmap_range *range, +static bool id_is_in_range(uint32_t id, struct idmap_domain_info *dom, uint32_t *rid) { - if (id == 0 || range == NULL) { + if (id == 0 || dom == NULL || dom->range == NULL) { return false; } - if (id >= range->min && id <= range->max) { + if (id >= dom->range->min && id <= dom->range->max) { if (rid != NULL) { - *rid = id - range->min; + *rid = dom->first_rid + (id - dom->range->min); } return true; @@ -330,12 +331,51 @@ enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx, return IDMAP_SUCCESS; } -enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx, - const char *domain_name, - const char *domain_sid, - struct sss_idmap_range *range) +static enum idmap_error_code dom_check_collision( + struct idmap_domain_info *dom_list, + struct idmap_domain_info *new_dom) +{ + struct idmap_domain_info *dom; + + for (dom = dom_list; dom != NULL; dom = dom->next) { + + /* check if ID ranges overlap */ + if ((new_dom->range->min >= dom->range->min + && new_dom->range->min <= dom->range->max) + || (new_dom->range->max >= dom->range->min + && new_dom->range->max <= dom->range->max)) { + return IDMAP_COLLISION; + } + + /* check if domain name and SID are consistent */ + if ((strcasecmp(new_dom->name, dom->name) == 0 + && strcasecmp(new_dom->sid, dom->sid) != 0) + || (strcasecmp(new_dom->name, dom->name) != 0 + && strcasecmp(new_dom->sid, dom->sid) == 0)) { + return IDMAP_COLLISION; + } + + /* check if RID ranges overlap */ + if (strcasecmp(new_dom->name, dom->name) == 0 + && strcasecmp(new_dom->sid, dom->sid) == 0 + && new_dom->first_rid >= dom->first_rid + && new_dom->first_rid <= + dom->first_rid + (dom->range->max - dom->range->min)) { + return IDMAP_COLLISION; + } + } + + return IDMAP_SUCCESS; +} + +enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx, + const char *domain_name, + const char *domain_sid, + struct sss_idmap_range *range, + uint32_t rid) { struct idmap_domain_info *dom = NULL; + enum idmap_error_code err; CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID); @@ -372,6 +412,14 @@ enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx, goto fail; } + dom->first_rid = rid; + + err = dom_check_collision(ctx->idmap_domain_info, dom); + if (err != IDMAP_SUCCESS) { + ctx->free_func(dom, ctx->alloc_pvt); + return err; + } + dom->next = ctx->idmap_domain_info; ctx->idmap_domain_info = dom; @@ -385,6 +433,14 @@ fail: return IDMAP_OUT_OF_MEMORY; } +enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx, + const char *domain_name, + const char *domain_sid, + struct sss_idmap_range *range) +{ + return sss_idmap_add_domain_ex(ctx, domain_name, domain_sid, range, 0); +} + static bool sss_idmap_sid_is_builtin(const char *sid) { if (strncmp(sid, "S-1-5-32-", 9) == 0) { @@ -396,14 +452,16 @@ static bool sss_idmap_sid_is_builtin(const char *sid) enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx, const char *sid, - uint32_t *id) + uint32_t *_id) { struct idmap_domain_info *idmap_domain_info; size_t dom_len; long long rid; char *endptr; + uint32_t id; + bool no_range = false; - if (sid == NULL || id == NULL) { + if (sid == NULL || _id == NULL) { return IDMAP_ERROR; } @@ -417,27 +475,30 @@ enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx, while (idmap_domain_info != NULL) { dom_len = strlen(idmap_domain_info->sid); - if (strlen(sid) > dom_len && sid[dom_len] == '-' && - strncmp(sid, idmap_domain_info->sid, dom_len) == 0) { + if (strlen(sid) > dom_len && sid[dom_len] == '-' + && strncmp(sid, idmap_domain_info->sid, dom_len) == 0) { errno = 0; rid = strtoull(sid + dom_len + 1, &endptr, 10); if (errno != 0 || rid > UINT32_MAX || *endptr != '\0') { return IDMAP_SID_INVALID; } - if (rid + idmap_domain_info->range->min > - idmap_domain_info->range->max) { - return IDMAP_NO_RANGE; + if (rid >= idmap_domain_info->first_rid) { + id = idmap_domain_info->range->min + + (rid - idmap_domain_info->first_rid); + if (id <= idmap_domain_info->range->max) { + *_id = id; + return IDMAP_SUCCESS; + } } - *id = rid + idmap_domain_info->range->min; - return IDMAP_SUCCESS; + no_range = true; } idmap_domain_info = idmap_domain_info->next; } - return IDMAP_NO_DOMAIN; + return no_range ? IDMAP_NO_RANGE : IDMAP_NO_DOMAIN; } enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx, @@ -455,7 +516,7 @@ enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx, idmap_domain_info = ctx->idmap_domain_info; while (idmap_domain_info != NULL) { - if (id_is_in_range(id, idmap_domain_info->range, &rid)) { + if (id_is_in_range(id, idmap_domain_info, &rid)) { len = snprintf(NULL, 0, SID_FMT, idmap_domain_info->sid, rid); if (len <= 0 || len > SID_STR_MAX_LEN) { return IDMAP_ERROR; diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h index 9710501b..3beeca11 100644 --- a/src/lib/idmap/sss_idmap.h +++ b/src/lib/idmap/sss_idmap.h @@ -74,7 +74,10 @@ enum idmap_error_code { IDMAP_BUILTIN_SID, /** No more free slices */ - IDMAP_OUT_OF_SLICES + IDMAP_OUT_OF_SLICES, + + /** New domain collides with existing one */ + IDMAP_COLLISION }; /** @@ -237,12 +240,37 @@ enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx, * context * - #IDMAP_SID_INVALID: Invalid SID provided * - #IDMAP_NO_DOMAIN: No domain domain name given + * - #IDMAP_COLLISION: New domain collides with existing one */ enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx, const char *domain_name, const char *domain_sid, struct sss_idmap_range *range); +/** + * @brief Add a domain with the first mappable RID to the idmap context + * + * @param[in] ctx Idmap context + * @param[in] domain_name Zero-terminated string with the domain name + * @param[in] domain_sid Zero-terminated string representation of the domain + * SID (S-1-15-.....) + * @param[in] range TBD Some information about the id ranges of this + * domain + * @param[in] rid The RID that should be mapped to the first ID of the + * given range. + * + * @return + * - #IDMAP_OUT_OF_MEMORY: Insufficient memory to store the data in the idmap + * context + * - #IDMAP_SID_INVALID: Invalid SID provided + * - #IDMAP_NO_DOMAIN: No domain domain name given + * - #IDMAP_COLLISION: New domain collides with existing one + */ +enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx, + const char *domain_name, + const char *domain_sid, + struct sss_idmap_range *range, + uint32_t rid); /** * @brief Translate SID to a unix UID or GID * -- cgit