summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2013-07-31 10:59:43 +0200
committerJakub Hrozek <jhrozek@redhat.com>2014-05-02 13:34:50 +0200
commit4dd38025efda88f123eac672f87d3cda12f050c8 (patch)
tree438cb4577369e3fff8e7b5fe5895ad811c422f4b /src
parentfcb8e3f1f49bb34c409d8dbd75889eb72be05517 (diff)
downloadsssd-4dd38025efda88f123eac672f87d3cda12f050c8.tar.gz
sssd-4dd38025efda88f123eac672f87d3cda12f050c8.tar.xz
sssd-4dd38025efda88f123eac672f87d3cda12f050c8.zip
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. Reviewed-by: Simo Sorce <simo@redhat.com> Reviewed-by: Pavel Březina <pbrezina@redhat.com>
Diffstat (limited to 'src')
-rw-r--r--src/config/SSSDConfig/__init__.py.in1
-rw-r--r--src/config/etc/sssd.api.d/sssd-ldap.conf1
-rw-r--r--src/man/sssd-ldap.5.xml48
-rw-r--r--src/providers/ad/ad_common.c9
-rw-r--r--src/providers/ad/ad_opts.h1
-rw-r--r--src/providers/ipa/ipa_common.c9
-rw-r--r--src/providers/ipa/ipa_netgroups.c3
-rw-r--r--src/providers/ipa/ipa_opts.h1
-rw-r--r--src/providers/ldap/ldap_id.c3
-rw-r--r--src/providers/ldap/ldap_options.c45
-rw-r--r--src/providers/ldap/ldap_opts.h1
-rw-r--r--src/providers/ldap/sdap.c116
-rw-r--r--src/providers/ldap/sdap.h9
-rw-r--r--src/providers/ldap/sdap_async_enum.c3
-rw-r--r--src/providers/ldap/sdap_async_groups.c6
-rw-r--r--src/providers/ldap/sdap_async_groups_ad.c4
-rw-r--r--src/providers/ldap/sdap_async_initgroups.c6
-rw-r--r--src/providers/ldap/sdap_async_nested_groups.c5
-rw-r--r--src/providers/ldap/sdap_async_users.c6
-rw-r--r--src/tests/ipa_ldap_opt-tests.c117
-rw-r--r--src/util/util_errors.c2
-rw-r--r--src/util/util_errors.h2
22 files changed, 383 insertions, 15 deletions
diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 6382dd570..64807d8d1 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 257e859df..0057c080f 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 f93b418c4..6426fe4fc 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -616,6 +616,54 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>ldap_user_extra_attrs (string)</term>
+ <listitem>
+ <para>
+ Comma-separated list of LDAP attributes that SSSD
+ would fetch along with the usual set of user
+ attributes.
+ </para>
+ <para>
+ 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.
+ </para>
+ <para>
+ Please note that several attribute names are
+ reserved by SSSD, notably the <quote>name</quote>
+ attribute. SSSD would report an error if any of
+ the reserved attribute names is used as an extra
+ attribute name.
+ </para>
+ <para>
+ Examples:
+ </para>
+ <para>
+ ldap_user_extra_attrs = telephoneNumber
+ </para>
+ <para>
+ Save the <quote>telephoneNumber</quote> attribute from LDAP
+ as <quote>telephoneNumber</quote> to the cache.
+ </para>
+ <para>
+ ldap_user_extra_attrs = phone:telephoneNumber
+ </para>
+ <para>
+ Save the <quote>telephoneNumber</quote> attribute from LDAP
+ as <quote>phone</quote> to the cache.
+ </para>
+ <para>
+ Default: not set
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry condition="with_ssh">
<term>ldap_user_ssh_public_key (string)</term>
<listitem>
diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index 57a0a3c39..8528ad3dc 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 6b4e874ed..69a4dfa8e 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 f84748267..19de10d8b 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 9cc374bc1..db29d29ee 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 909c431ee..949a054dd 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 ab0a5c911..297d6016e 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 8813572ff..11ed9c31f 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 d45ad46f0..90899b948 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 b303547a4..37a187436 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 ad239a8d0..38eec1c4d 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 ebd9ffafb..1c69c07f8 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 4240bb585..89a5afb91 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 9bb21d29b..8db587c96 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 5334ef84d..401ab82dc 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 51e88bbfb..4ef3d79cb 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 ef5478f94..be0536ef3 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 bbb49935d..fffdc7e73 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 8dd4380b4..d27d20b0a 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 23048990d..f03fc16b1 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 */
};