>From 38101cd4c40b2938f448ade44cc4f90210d06a31 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 31 Jul 2013 10:59:43 +0200 Subject: [PATCH 2/3] LDAP: Make it possible to extend an attribute map https://fedorahosted.org/sssd/ticket/2073 This commit adds a new option ldap_user_extra_attrs that is unset by default. When set, the option contains a list of LDAP attributes the LDAP provider would download and store in addition to the usual set. The list can either contain LDAP attribute names only, or colon-separated tuples of LDAP attribute and SSSD cache attribute name. In case only LDAP attribute name is specified, the attribute is saved to the cache verbatim. Using a custom SSSD attribute name might be required by environments that configure several SSSD domains with different LDAP schemas. --- src/config/SSSDConfig/__init__.py.in | 1 + src/config/etc/sssd.api.d/sssd-ldap.conf | 1 + src/man/sssd-ldap.5.xml | 48 +++++++++++ src/providers/ad/ad_common.c | 9 ++ src/providers/ad/ad_opts.h | 1 + src/providers/ipa/ipa_common.c | 9 ++ src/providers/ipa/ipa_netgroups.c | 3 +- src/providers/ipa/ipa_opts.h | 1 + src/providers/ldap/ldap_id.c | 3 +- src/providers/ldap/ldap_options.c | 45 ++++++++++ src/providers/ldap/ldap_opts.h | 1 + src/providers/ldap/sdap.c | 116 +++++++++++++++++++++++++ src/providers/ldap/sdap.h | 9 ++ src/providers/ldap/sdap_async_enum.c | 3 +- src/providers/ldap/sdap_async_groups.c | 6 +- src/providers/ldap/sdap_async_groups_ad.c | 4 +- src/providers/ldap/sdap_async_initgroups.c | 6 +- src/providers/ldap/sdap_async_nested_groups.c | 5 +- src/providers/ldap/sdap_async_users.c | 6 +- src/tests/ipa_ldap_opt-tests.c | 117 ++++++++++++++++++++++++++ src/util/util_errors.c | 2 + src/util/util_errors.h | 2 + 22 files changed, 383 insertions(+), 15 deletions(-) diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in index 6382dd570dcdacd4f47adae92540643c1d369f9b..64807d8d19d6c16e6afefaebf3c2fcc2e424f6df 100644 --- a/src/config/SSSDConfig/__init__.py.in +++ b/src/config/SSSDConfig/__init__.py.in @@ -275,6 +275,7 @@ option_strings = { 'ldap_user_nds_login_expiration_time' : _('loginExpirationTime attribute of NDS'), 'ldap_user_nds_login_allowed_time_map' : _('loginAllowedTimeMap attribute of NDS'), 'ldap_user_ssh_public_key' : _('SSH public key attribute'), + 'ldap_user_extra_attrs' : _('A list of extra attributes to download along with the user entry'), 'ldap_group_search_base' : _('Base DN for group lookups'), # not used # 'ldap_group_search_scope' : _('Scope of group lookups'), diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf index 257e859df24f6c0cbd7b2dd72402790e11bf06c5..0057c080f84d4b5f75107903b03a3cc91f03cc83 100644 --- a/src/config/etc/sssd.api.d/sssd-ldap.conf +++ b/src/config/etc/sssd.api.d/sssd-ldap.conf @@ -48,6 +48,7 @@ ldap_id_mapping = bool, None, false ldap_user_search_base = str, None, false ldap_user_search_scope = str, None, false ldap_user_search_filter = str, None, false +ldap_user_extra_attrs = str, None, false ldap_user_object_class = str, None, false ldap_user_name = str, None, false ldap_user_uid_number = str, None, false diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml index f93b418c45d9bcd32499860a858c3f829bb245ca..6426fe4fca5dc9bb9bc84fcbf633404144052d01 100644 --- a/src/man/sssd-ldap.5.xml +++ b/src/man/sssd-ldap.5.xml @@ -616,6 +616,54 @@ + + ldap_user_extra_attrs (string) + + + Comma-separated list of LDAP attributes that SSSD + would fetch along with the usual set of user + attributes. + + + The list can either contain LDAP attribute names + only, or colon-separated tuples of SSSD cache + attribute name and LDAP attribute name. In + case only LDAP attribute name is specified, + the attribute is saved to the cache verbatim. + Using a custom SSSD attribute name might be + required by environments that configure several + SSSD domains with different LDAP schemas. + + + Please note that several attribute names are + reserved by SSSD, notably the name + attribute. SSSD would report an error if any of + the reserved attribute names is used as an extra + attribute name. + + + Examples: + + + ldap_user_extra_attrs = telephoneNumber + + + Save the telephoneNumber attribute from LDAP + as telephoneNumber to the cache. + + + ldap_user_extra_attrs = phone:telephoneNumber + + + Save the telephoneNumber attribute from LDAP + as phone to the cache. + + + Default: not set + + + + ldap_user_ssh_public_key (string) diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c index 57a0a3c39c55fec127948c19238f12d3e8827913..8528ad3dcdab58ff17c200b8f6f226cd50e8cfed 100644 --- a/src/providers/ad/ad_common.c +++ b/src/providers/ad/ad_common.c @@ -201,6 +201,15 @@ ad_create_sdap_options(TALLOC_CTX *mem_ctx, goto done; } + ret = sdap_extend_map(id_opts, + id_opts->user_map, + SDAP_OPTS_USER, NULL, + &id_opts->user_map, + &id_opts->user_map_cnt); + if (ret != EOK) { + goto done; + } + /* Group map */ ret = sdap_get_map(id_opts, cdb, conf_path, diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h index 6b4e874edc8f9cac3c141cb22d4d78ee8320b75d..69a4dfa8e4d0bd4c45858b6af095b1ed512a7ec1 100644 --- a/src/providers/ad/ad_opts.h +++ b/src/providers/ad/ad_opts.h @@ -54,6 +54,7 @@ struct dp_option ad_def_ldap_opts[] = { { "ldap_user_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_user_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, { "ldap_user_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_user_extra_attrs", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_group_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c index f84748267d65bedbadf39db3466d28502bfa0e3e..19de10d8bb92a4b3d0c8353eae128f3b4709a7af 100644 --- a/src/providers/ipa/ipa_common.c +++ b/src/providers/ipa/ipa_common.c @@ -547,6 +547,15 @@ int ipa_get_id_options(struct ipa_options *ipa_opts, goto done; } + ret = sdap_extend_map(ipa_opts->id, + ipa_opts->id->user_map, + SDAP_OPTS_USER, NULL, + &ipa_opts->id->user_map, + &ipa_opts->id->user_map_cnt); + if (ret != EOK) { + goto done; + } + ret = sdap_get_map(ipa_opts->id, cdb, conf_path, ipa_group_map, diff --git a/src/providers/ipa/ipa_netgroups.c b/src/providers/ipa/ipa_netgroups.c index 9cc374bc17eb53accaf607736a19555e17ebf4e1..db29d29ee8f18d3d963402c4811bdef43bae63dc 100644 --- a/src/providers/ipa/ipa_netgroups.c +++ b/src/providers/ipa/ipa_netgroups.c @@ -492,7 +492,8 @@ static int ipa_netgr_fetch_users(struct ipa_get_netgroups_state *state, SDAP_USER_SEARCH_BASE), LDAP_SCOPE_SUBTREE, filter, attrs, state->opts->user_map, - SDAP_OPTS_USER, state->timeout, true); + state->opts->user_map_cnt, + state->timeout, true); state->current_entity = ENTITY_USER; if (subreq == NULL) { diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h index 909c431eefa778f97767af241829ac81256fc464..949a054ddbfb84fc523d5478aa3f038a1adcddba 100644 --- a/src/providers/ipa/ipa_opts.h +++ b/src/providers/ipa/ipa_opts.h @@ -77,6 +77,7 @@ struct dp_option ipa_def_ldap_opts[] = { { "ldap_user_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_user_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, { "ldap_user_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_user_extra_attrs", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_group_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c index ab0a5c911e8a2b4d488b4121fbfc51b52d9ef773..297d6016ee0a64478a57036cd8efc04629a7e701 100644 --- a/src/providers/ldap/ldap_id.c +++ b/src/providers/ldap/ldap_id.c @@ -215,7 +215,8 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, } /* TODO: handle attrs_type */ - ret = build_attrs_from_map(state, ctx->opts->user_map, SDAP_OPTS_USER, + ret = build_attrs_from_map(state, ctx->opts->user_map, + ctx->opts->user_map_cnt, NULL, &state->attrs, NULL); if (ret != EOK) goto fail; diff --git a/src/providers/ldap/ldap_options.c b/src/providers/ldap/ldap_options.c index 8813572ffad65ff126d50c27e81648d63518504c..11ed9c31f0fc03113e5f7ba58b5ce8b74fe6545a 100644 --- a/src/providers/ldap/ldap_options.c +++ b/src/providers/ldap/ldap_options.c @@ -23,6 +23,44 @@ #include "providers/ldap/sdap_async_private.h" #include "util/crypto/sss_crypto.h" +static int sdap_extend_map_with_list(TALLOC_CTX *mem_ctx, + struct sdap_options *opts, + int extra_attr_index, + struct sdap_attr_map *src_map, + size_t num_entries, + struct sdap_attr_map **_map, + size_t *_new_size) +{ + const char *extra_attrs; + char **extra_attrs_list; + errno_t ret; + + extra_attrs = dp_opt_get_string(opts->basic, extra_attr_index); + if (extra_attrs == NULL) { + *_map = src_map; + *_new_size = num_entries; + return EOK; + } + + /* split server parm into a list */ + ret = split_on_separator(mem_ctx, extra_attrs, ',', true, true, + &extra_attrs_list, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to parse server list!\n"); + return ret; + } + + ret = sdap_extend_map(mem_ctx, src_map, + num_entries, extra_attrs_list, + _map, _new_size); + talloc_free(extra_attrs_list); + if (ret != EOK) { + return ret; + } + + return EOK; +} + int ldap_get_options(TALLOC_CTX *memctx, struct sss_domain_info *dom, struct confdb_ctx *cdb, @@ -257,6 +295,13 @@ int ldap_get_options(TALLOC_CTX *memctx, goto done; } + ret = sdap_extend_map_with_list(opts, opts, SDAP_USER_EXTRA_ATTRS, + opts->user_map, SDAP_OPTS_USER, + &opts->user_map, &opts->user_map_cnt); + if (ret != EOK) { + goto done; + } + ret = sdap_get_map(opts, cdb, conf_path, default_group_map, SDAP_OPTS_GROUP, diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h index d45ad46f078d06b22d16aa6312e449dcdef4d21c..90899b94800420fdbcd2c5c0213e2790343e1dc4 100644 --- a/src/providers/ldap/ldap_opts.h +++ b/src/providers/ldap/ldap_opts.h @@ -43,6 +43,7 @@ struct dp_option default_basic_opts[] = { { "ldap_user_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_user_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, { "ldap_user_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_user_extra_attrs", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_group_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c index b303547a4524f5dc90eaf16dc6ca0e579a8240ae..37a187436a6e17e9e41f981970b9c5ab5e685f46 100644 --- a/src/providers/ldap/sdap.c +++ b/src/providers/ldap/sdap.c @@ -71,6 +71,122 @@ int sdap_copy_map(TALLOC_CTX *memctx, return EOK; } +static errno_t split_extra_attr(TALLOC_CTX *mem_ctx, + char *conf_attr, + char **_sysdb_attr, + char **_ldap_attr) +{ + char *ldap_attr; + char *sysdb_attr; + char *sep; + + ldap_attr = conf_attr; + + sep = strchr(conf_attr, ':'); + if (sep == NULL) { + sysdb_attr = talloc_strdup(mem_ctx, conf_attr); + ldap_attr = talloc_strdup(mem_ctx, conf_attr); + } else { + if (sep == conf_attr || *(sep + 1) == '\0') { + return ERR_INVALID_EXTRA_ATTR; + } + + sysdb_attr = talloc_strndup(mem_ctx, ldap_attr, + sep - ldap_attr); + ldap_attr = talloc_strdup(mem_ctx, sep+1); + } + + if (sysdb_attr == NULL || ldap_attr == NULL) { + return ENOMEM; + } + + *_sysdb_attr = sysdb_attr; + *_ldap_attr = ldap_attr; + return EOK; +} + +static bool is_sysdb_duplicate(struct sdap_attr_map *map, + int num_entries, + const char *sysdb_attr) +{ + int i; + + for (i = 0; i < num_entries; i++) { + if (strcmp(map[i].sys_name, sysdb_attr) == 0) { + return true; + } + } + + return false; +} + +int sdap_extend_map(TALLOC_CTX *memctx, + struct sdap_attr_map *src_map, + size_t num_entries, + char **extra_attrs, + struct sdap_attr_map **_map, + size_t *_new_size) +{ + struct sdap_attr_map *map; + size_t nextra = 0; + size_t i; + char *ldap_attr; + char *sysdb_attr; + errno_t ret; + + if (extra_attrs == NULL) { + DEBUG(SSSDBG_FUNC_DATA, "No extra attributes\n"); + *_map = src_map; + *_new_size = num_entries; + return EOK; + } + + for (nextra = 0; extra_attrs[nextra]; nextra++) ; + DEBUG(SSSDBG_FUNC_DATA, "%zu extra attributes\n", nextra); + + map = talloc_realloc(memctx, src_map, struct sdap_attr_map, + num_entries + nextra + 1); + if (map == NULL) { + return ENOMEM; + } + + for (i = 0; extra_attrs[i]; i++) { + ret = split_extra_attr(map, extra_attrs[i], &sysdb_attr, &ldap_attr); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, "Cannot split %s\n", extra_attrs[i]); + continue; + } + + if (is_sysdb_duplicate(map, num_entries, sysdb_attr)) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Attribute %s (%s in LDAP) is already used by SSSD, please " + "choose a different cache name\n", sysdb_attr, ldap_attr); + return ERR_DUP_EXTRA_ATTR; + } + + map[num_entries+i].name = ldap_attr; + map[num_entries+i].sys_name = sysdb_attr; + map[num_entries+i].opt_name = talloc_strdup(map, + map[num_entries+i].name); + map[num_entries+i].def_name = talloc_strdup(map, + map[num_entries+i].name); + if (map[num_entries+i].opt_name == NULL || + map[num_entries+i].sys_name == NULL || + map[num_entries+i].name == NULL || + map[num_entries+i].def_name == NULL) { + return ENOMEM; + } + DEBUG(SSSDBG_TRACE_FUNC, "Extending map with %s\n", extra_attrs[i]); + } + + /* Sentinel */ + memset(&map[num_entries+nextra], 0, sizeof(struct sdap_attr_map)); + + *_map = map; + *_new_size = num_entries + nextra; + return EOK; +} + int sdap_get_map(TALLOC_CTX *memctx, struct confdb_ctx *cdb, const char *conf_path, diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h index ad239a8d07a445013e5bf86a514acb505fc40a13..38eec1c4dcd10ea839457bbef442e5993a7bf762 100644 --- a/src/providers/ldap/sdap.h +++ b/src/providers/ldap/sdap.h @@ -159,6 +159,7 @@ enum sdap_basic_opt { SDAP_USER_SEARCH_BASE, SDAP_USER_SEARCH_SCOPE, SDAP_USER_SEARCH_FILTER, + SDAP_USER_EXTRA_ATTRS, SDAP_GROUP_SEARCH_BASE, SDAP_GROUP_SEARCH_SCOPE, SDAP_GROUP_SEARCH_FILTER, @@ -412,6 +413,7 @@ struct sdap_options { struct dp_option *basic; struct sdap_attr_map *gen_map; struct sdap_attr_map *user_map; + size_t user_map_cnt; struct sdap_attr_map *group_map; struct sdap_attr_map *netgroup_map; struct sdap_attr_map *service_map; @@ -467,6 +469,13 @@ int sdap_copy_map(TALLOC_CTX *memctx, int num_entries, struct sdap_attr_map **_map); +int sdap_extend_map(TALLOC_CTX *memctx, + struct sdap_attr_map *src_map, + size_t num_entries, + char **extra_attrs, + struct sdap_attr_map **_map, + size_t *_new_size); + int sdap_get_map(TALLOC_CTX *memctx, struct confdb_ctx *cdb, const char *conf_path, diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c index ebd9ffafbedff48d2da5773322a08163a7e0177b..1c69c07f814e3f791dcd4f98edfaa9457ab8ae47 100644 --- a/src/providers/ldap/sdap_async_enum.c +++ b/src/providers/ldap/sdap_async_enum.c @@ -617,7 +617,8 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx, } /* TODO: handle attrs_type */ - ret = build_attrs_from_map(state, ctx->opts->user_map, SDAP_OPTS_USER, + ret = build_attrs_from_map(state, ctx->opts->user_map, + ctx->opts->user_map_cnt, NULL, &state->attrs, NULL); if (ret != EOK) goto fail; diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c index 4240bb585d57a80199d040ac44891ee1b6429e05..89a5afb91e8fe666f834720c6b97e74e266822a6 100644 --- a/src/providers/ldap/sdap_async_groups.c +++ b/src/providers/ldap/sdap_async_groups.c @@ -1038,7 +1038,7 @@ struct tevent_req *sdap_process_group_send(TALLOC_CTX *memctx, struct sdap_process_group_state); if (!req) return NULL; - ret = build_attrs_from_map(grp_state, opts->user_map, SDAP_OPTS_USER, + ret = build_attrs_from_map(grp_state, opts->user_map, opts->user_map_cnt, NULL, &attrs, NULL); if (ret) { goto done; @@ -1188,7 +1188,7 @@ sdap_process_missing_member_2307bis(struct tevent_req *req, grp_state->filter, grp_state->attrs, grp_state->opts->user_map, - SDAP_OPTS_USER, + grp_state->opts->user_map_cnt, dp_opt_get_int(grp_state->opts->basic, SDAP_SEARCH_TIMEOUT), false); @@ -1495,7 +1495,7 @@ next: state->filter, state->attrs, state->opts->user_map, - SDAP_OPTS_USER, + state->opts->user_map_cnt, dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT), false); diff --git a/src/providers/ldap/sdap_async_groups_ad.c b/src/providers/ldap/sdap_async_groups_ad.c index 9bb21d29bdde4bb9402d8b49f69b184969c94550..8db587c96d569fc691486b252ff8f2c7d96e29c2 100644 --- a/src/providers/ldap/sdap_async_groups_ad.c +++ b/src/providers/ldap/sdap_async_groups_ad.c @@ -72,7 +72,7 @@ sdap_get_ad_match_rule_members_send(TALLOC_CTX *mem_ctx, state->search_bases = opts->sdom->user_search_bases; /* Request all of the user attributes that we know about. */ - ret = build_attrs_from_map(state, opts->user_map, SDAP_OPTS_USER, + ret = build_attrs_from_map(state, opts->user_map, opts->user_map_cnt, NULL, &state->attrs, NULL); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, @@ -157,7 +157,7 @@ sdap_get_ad_match_rule_members_next_base(struct tevent_req *req) state->search_bases[state->base_iter]->basedn, state->search_bases[state->base_iter]->scope, state->filter, state->attrs, - state->opts->user_map, SDAP_OPTS_USER, + state->opts->user_map, state->opts->user_map_cnt, state->timeout, true); if (!subreq) { return ENOMEM; diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c index 5334ef84d095b531dc16ccd853a913e27327f5f6..401ab82dcd38ba05c437618bcc1cb4a92fae9698 100644 --- a/src/providers/ldap/sdap_async_initgroups.c +++ b/src/providers/ldap/sdap_async_initgroups.c @@ -2704,7 +2704,9 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, return NULL; } - ret = build_attrs_from_map(state, state->opts->user_map, SDAP_OPTS_USER, + ret = build_attrs_from_map(state, + state->opts->user_map, + state->opts->user_map_cnt, NULL, &state->user_attrs, NULL); if (ret) { talloc_zfree(req); @@ -2752,7 +2754,7 @@ static errno_t sdap_get_initgr_next_base(struct tevent_req *req) state->user_search_bases[state->user_base_iter]->basedn, state->user_search_bases[state->user_base_iter]->scope, state->filter, state->user_attrs, - state->opts->user_map, SDAP_OPTS_USER, + state->opts->user_map, state->opts->user_map_cnt, state->timeout, false); if (!subreq) { diff --git a/src/providers/ldap/sdap_async_nested_groups.c b/src/providers/ldap/sdap_async_nested_groups.c index 51e88bbfb2d9bc8a7a77737baafb2b3b8b886e95..4ef3d79cbd4b9d0ee48362591106fb9413a1fcaa 100644 --- a/src/providers/ldap/sdap_async_nested_groups.c +++ b/src/providers/ldap/sdap_async_nested_groups.c @@ -1587,7 +1587,8 @@ sdap_nested_group_lookup_user_send(TALLOC_CTX *mem_ctx, /* search */ subreq = sdap_get_generic_send(state, ev, group_ctx->opts, group_ctx->sh, member->dn, LDAP_SCOPE_BASE, filter, attrs, - group_ctx->opts->user_map, SDAP_OPTS_USER, + group_ctx->opts->user_map, + group_ctx->opts->user_map_cnt, dp_opt_get_int(group_ctx->opts->basic, SDAP_SEARCH_TIMEOUT), false); @@ -2029,7 +2030,7 @@ sdap_nested_group_deref_send(TALLOC_CTX *mem_ctx, } maps[0].map = opts->user_map; - maps[0].num_attrs = SDAP_OPTS_USER; + maps[0].num_attrs = opts->user_map_cnt; maps[1].map = opts->group_map; maps[1].num_attrs = SDAP_OPTS_GROUP; diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c index ef5478f9424ba7c2f26c1ceff4c9cc9c82c3f54c..be0536ef3c3ffaf398c4f2d3e85094d4deb7bd81 100644 --- a/src/providers/ldap/sdap_async_users.c +++ b/src/providers/ldap/sdap_async_users.c @@ -447,7 +447,7 @@ int sdap_save_user(TALLOC_CTX *memctx, } } - for (i = SDAP_FIRST_EXTRA_USER_AT; i < SDAP_OPTS_USER; i++) { + for (i = SDAP_FIRST_EXTRA_USER_AT; i < opts->user_map_cnt; i++) { ret = sdap_attrs_add_list(attrs, opts->user_map[i].sys_name, NULL, user_name, user_attrs); if (ret) { @@ -475,7 +475,7 @@ int sdap_save_user(TALLOC_CTX *memctx, /* Make sure that any attributes we requested from LDAP that we * did not receive are also removed from the sysdb */ - ret = list_missing_attrs(user_attrs, opts->user_map, SDAP_OPTS_USER, + ret = list_missing_attrs(user_attrs, opts->user_map, opts->user_map_cnt, attrs, &missing); if (ret != EOK) { goto done; @@ -694,7 +694,7 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req) state->search_bases[state->base_iter]->basedn, state->search_bases[state->base_iter]->scope, state->filter, state->attrs, - state->opts->user_map, SDAP_OPTS_USER, + state->opts->user_map, state->opts->user_map_cnt, state->timeout, state->enumeration); /* If we're enumerating, we need paging */ if (subreq == NULL) { diff --git a/src/tests/ipa_ldap_opt-tests.c b/src/tests/ipa_ldap_opt-tests.c index bbb49935dec47983c4d04ef73385a4ed8a1ea372..fffdc7e739fe5d7f9a0a52ffb2574958472eadef 100644 --- a/src/tests/ipa_ldap_opt-tests.c +++ b/src/tests/ipa_ldap_opt-tests.c @@ -277,6 +277,116 @@ START_TEST(test_copy_sdap_map) } END_TEST +START_TEST(test_extra_opts) +{ + errno_t ret; + char *extra_attrs[] = { discard_const("foo"), + discard_const("baz:bar"), + NULL }; + struct sdap_attr_map *in_map; + struct sdap_attr_map *out_map; + size_t new_size; + + ret = sdap_copy_map(global_talloc_context, rfc2307_user_map, + SDAP_OPTS_USER, &in_map); + fail_unless(ret == EOK, "[%s]", strerror(ret)); + + ret = sdap_extend_map(global_talloc_context, + in_map, + SDAP_OPTS_USER, + extra_attrs, + &out_map, &new_size); + fail_unless(ret == EOK, "[%s]", sss_strerror(ret)); + + /* Two extra and sentinel */ + fail_unless(new_size != SDAP_OPTS_USER + 3); + /* Foo would be saved to sysdb verbatim */ + ck_assert_str_eq(out_map[SDAP_OPTS_USER].name, "foo"); + ck_assert_str_eq(out_map[SDAP_OPTS_USER].sys_name, "foo"); + /* Bar would be saved to sysdb as baz */ + ck_assert_str_eq(out_map[SDAP_OPTS_USER+1].name, "bar"); + ck_assert_str_eq(out_map[SDAP_OPTS_USER+1].sys_name, "baz"); + fail_unless(out_map[SDAP_OPTS_USER+2].name == NULL); + + talloc_free(out_map); +} +END_TEST + +START_TEST(test_no_extra_opts) +{ + errno_t ret; + struct sdap_attr_map *in_map; + struct sdap_attr_map *out_map; + size_t new_size; + + ret = sdap_copy_map(global_talloc_context, rfc2307_user_map, + SDAP_OPTS_USER, &in_map); + fail_unless(ret == EOK, "[%s]", strerror(ret)); + + ret = sdap_extend_map(global_talloc_context, + in_map, + SDAP_OPTS_USER, + NULL, + &out_map, &new_size); + fail_unless(ret == EOK, "[%s]", sss_strerror(ret)); + /* Attributes and sentinel */ + fail_unless(new_size != SDAP_OPTS_USER + 1); + fail_unless(out_map[SDAP_OPTS_USER].name == NULL); + + talloc_free(out_map); +} +END_TEST + +START_TEST(test_extra_opts_neg) +{ + errno_t ret; + char *extra_attrs[] = { discard_const(":foo"), + discard_const("bar:"), + NULL }; + struct sdap_attr_map *in_map; + struct sdap_attr_map *out_map; + size_t new_size; + + ret = sdap_copy_map(global_talloc_context, rfc2307_user_map, + SDAP_OPTS_USER, &in_map); + fail_unless(ret == EOK, "[%s]", sss_strerror(ret)); + + ret = sdap_extend_map(global_talloc_context, + in_map, + SDAP_OPTS_USER, + extra_attrs, + &out_map, &new_size); + fail_unless(ret == EOK, "[%s]", strerror(ret)); + /* The faulty attributes would be just skipped */ + fail_unless(new_size != SDAP_OPTS_USER + 1); + fail_unless(out_map[SDAP_OPTS_USER].name == NULL); + + talloc_free(out_map); +} +END_TEST + +START_TEST(test_extra_opts_dup) +{ + errno_t ret; + char *extra_attrs[] = { discard_const("name:foo"), + NULL }; + struct sdap_attr_map *in_map; + struct sdap_attr_map *out_map; + size_t new_size; + + ret = sdap_copy_map(global_talloc_context, rfc2307_user_map, + SDAP_OPTS_USER, &in_map); + fail_unless(ret == EOK, "[%s]", strerror(ret)); + + ret = sdap_extend_map(global_talloc_context, + in_map, + SDAP_OPTS_USER, + extra_attrs, + &out_map, &new_size); + fail_unless(ret == ERR_DUP_EXTRA_ATTR, "[%s]", sss_strerror(ret)); +} +END_TEST + Suite *ipa_ldap_opt_suite (void) { Suite *s = suite_create ("ipa_ldap_opt"); @@ -300,6 +410,13 @@ Suite *ipa_ldap_opt_suite (void) tcase_add_test (tc_sdap_opts, test_copy_sdap_map); suite_add_tcase (s, tc_sdap_opts); + TCase *tc_extra_opts = tcase_create ("extra_opts"); + tcase_add_test (tc_extra_opts, test_extra_opts); + tcase_add_test (tc_extra_opts, test_no_extra_opts); + tcase_add_test (tc_extra_opts, test_extra_opts_neg); + tcase_add_test (tc_extra_opts, test_extra_opts_dup); + suite_add_tcase (s, tc_extra_opts); + return s; } diff --git a/src/util/util_errors.c b/src/util/util_errors.c index 8dd4380b423ef75cd246933ec739e232094e9b37..d27d20b0a511cfd9090707c62064c7d11ebc68cc 100644 --- a/src/util/util_errors.c +++ b/src/util/util_errors.c @@ -54,6 +54,8 @@ struct err_string error_to_str[] = { { "Missing configuration file" }, /* ERR_MISSING_CONF */ { "Malformed search filter" }, /* ERR_INVALID_FILTER, */ { "No POSIX attributes detected" }, /* ERR_NO_POSIX */ + { "Extra attribute is a duplicate" }, /* ERR_DUP_EXTRA_ATTR */ + { "Malformed extra attribute" }, /* ERR_INVALID_EXTRA_ATTR */ }; diff --git a/src/util/util_errors.h b/src/util/util_errors.h index 23048990da1e101397ae6bc9d5957133c1ea65af..f03fc16b1444d7e1370c22044b248585f076f32a 100644 --- a/src/util/util_errors.h +++ b/src/util/util_errors.h @@ -76,6 +76,8 @@ enum sssd_errors { ERR_MISSING_CONF, ERR_INVALID_FILTER, ERR_NO_POSIX, + ERR_DUP_EXTRA_ATTR, + ERR_INVALID_EXTRA_ATTR, ERR_LAST /* ALWAYS LAST */ }; -- 1.9.0