[SSSD] [PATCH] allow to add more LDAP user mappings
Sumit Bose
sbose at redhat.com
Tue Oct 6 14:45:59 UTC 2009
Hi,
this patch makes it possible to add more user attribute mappings. I need
this (or a similar patch) to read password policy information from a
LDAP server to evaluate if the password is expired on the client if the
LDAP server does not support server side password policies. I have tired
to make the changes in a generic way so they can be use for other areas
as well.
bye,
Sumit
-------------- next part --------------
>From 118ba55475ce0e4c506336c24cff3d6ded72a942 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Tue, 6 Oct 2009 16:29:41 +0200
Subject: [PATCH] allow to add more LDAP user mappings
- as an example maps for shadow attributes and kerberos password
attributes are added
---
server/man/sssd-ldap.5.xml | 27 ++++++
server/providers/ldap/ldap_id.c | 10 +-
server/providers/ldap/sdap.c | 170 +++++++++++++++++++++++++++++++++--
server/providers/ldap/sdap.h | 42 +++++++++
server/providers/ldap/sdap_async.c | 34 +++++++
5 files changed, 268 insertions(+), 15 deletions(-)
diff --git a/server/man/sssd-ldap.5.xml b/server/man/sssd-ldap.5.xml
index 7a86c7a..b88005e 100644
--- a/server/man/sssd-ldap.5.xml
+++ b/server/man/sssd-ldap.5.xml
@@ -564,6 +564,33 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>ldap_user_extra_maps (comma separated list)</term>
+ <listitem>
+ <para>
+ Load and store additional users attributes from the
+ LDAP server.
+ </para>
+ <para>
+ Currently the following mappings are supported:
+ <variablelist><varlistentry>
+ <term>shadow</term>
+ <listitem><para>The attributes corresponding to
+ the entries of /etc/shadow</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>kerberos</term>
+ <listitem><para>The attributes corresponding to
+ the time the kerberos password was last set and
+ the time it will expire.</para></listitem>
+ </varlistentry></variablelist>
+ </para>
+ <para>
+ Default: no extra mappings
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</para>
</refsect1>
diff --git a/server/providers/ldap/ldap_id.c b/server/providers/ldap/ldap_id.c
index 271eaea..5e7d033 100644
--- a/server/providers/ldap/ldap_id.c
+++ b/server/providers/ldap/ldap_id.c
@@ -316,7 +316,7 @@ static 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, &state->attrs);
+ ctx->opts->user_map_size, &state->attrs);
if (ret != EOK) goto fail;
if (!connected(ctx)) {
@@ -479,7 +479,7 @@ static struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
/* TODO: handle attrs_type */
ret = build_attrs_from_map(state, ctx->opts->group_map,
- SDAP_OPTS_GROUP, &state->attrs);
+ ctx->opts->group_map_size, &state->attrs);
if (ret != EOK) goto fail;
if (!connected(ctx)) {
@@ -616,7 +616,7 @@ static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
state->name = name;
ret = build_attrs_from_map(state, ctx->opts->group_map,
- SDAP_OPTS_GROUP, &state->attrs);
+ ctx->opts->group_map_size, &state->attrs);
if (ret != EOK) goto fail;
if (!connected(ctx)) {
@@ -1070,7 +1070,7 @@ 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, &state->attrs);
+ ctx->opts->user_map_size, &state->attrs);
if (ret != EOK) goto fail;
if (!connected(ctx)) {
@@ -1217,7 +1217,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
/* TODO: handle attrs_type */
ret = build_attrs_from_map(state, ctx->opts->group_map,
- SDAP_OPTS_GROUP, &state->attrs);
+ ctx->opts->group_map_size, &state->attrs);
if (ret != EOK) goto fail;
if (!connected(ctx)) {
diff --git a/server/providers/ldap/sdap.c b/server/providers/ldap/sdap.c
index b2dc6f6..231a437 100644
--- a/server/providers/ldap/sdap.c
+++ b/server/providers/ldap/sdap.c
@@ -58,7 +58,8 @@ struct sdap_gen_opts default_basic_opts[] = {
{ "ldap_krb5_keytab", SDAP_STRING, NULL_STRING, NULL_STRING },
{ "ldap_krb5_init_creds", SDAP_BOOL, BOOL_TRUE, BOOL_TRUE },
/* use the same parm name as the krb5 module so we set it only once */
- { "krb5_realm", SDAP_STRING, NULL_STRING, NULL_STRING }
+ { "krb5_realm", SDAP_STRING, NULL_STRING, NULL_STRING },
+ { "ldap_user_extra_maps", SDAP_STRING, NULL_STRING, NULL_STRING }
};
struct sdap_id_map rfc2307_user_map[] = {
@@ -115,7 +116,63 @@ struct sdap_id_map rfc2307bis_group_map[] = {
{ "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }
};
+struct sdap_id_map kerberos_attributes_user_map[] = {
+ { "ldap_user_kerberos_last_change", "krbLastPwdChange", SYSDB_KRB_LSTCHG, NULL },
+ { "ldap_user_kerberos_expire", "krbPasswordExpiration", SYSDB_KRB_EXPIRE, NULL }
+};
+
+struct sdap_id_map shadow_attributes_user_map[] = {
+ { "ldap_user_shadow_last_change", "shadowLastChange", SYSDB_SP_LSTCHG, NULL },
+ { "ldap_user_shadow_min", "shadowMin", SYSDB_SP_MIN, NULL },
+ { "ldap_user_shadow_max", "shadowMax", SYSDB_SP_MAX, NULL },
+ { "ldap_user_shadow_warning", "shadowWarning", SYSDB_SP_WARN, NULL },
+ { "ldap_user_shadow_inactive", "shadowInactive", SYSDB_SP_INACT, NULL },
+ { "ldap_user_shadow_expire", "shadowExpire", SYSDB_SP_EXPIRE, NULL },
+ { "ldap_user_shadow_flag", "shadowFlag", SYSDB_SP_FLAG, NULL }
+};
+
+struct sdap_extra_map sdap_user_extra_map_list[] = {
+ { "kerberos", kerberos_attributes_user_map, SDAP_OPTS_KP },
+ { "shadow", shadow_attributes_user_map, SDAP_OPTS_SP },
+ { NULL, NULL, 0}
+};
+
/* =Retrieve-Options====================================================== */
+static int add_extra_map(struct confdb_ctx *cdb, struct sdap_options *opts,
+ const char *conf_path, struct sdap_id_map *map,
+ size_t *last, struct sdap_id_map *add_map,
+ int add_map_size)
+{
+ int i;
+ int current;
+ int ret;
+
+ for (i = 0; i < add_map_size; i++) {
+ current = i + *last;
+ map[current].opt_name = add_map[i].opt_name;
+ map[current].def_name = add_map[i].def_name;
+ map[current].sys_name = add_map[i].sys_name;
+
+ ret = confdb_get_string(cdb, opts, conf_path,
+ map[current].opt_name,
+ map[current].def_name,
+ &map[current].name);
+ if (ret != EOK ||
+ (map[current].def_name && !map[current].name)) {
+ DEBUG(0, ("Failed to retrieve a value (%s)\n",
+ map[current].opt_name));
+ if (ret == EOK) return EINVAL;
+ return ret;
+ }
+
+ DEBUG(5, ("Option %s has value %s\n",
+ map[current].opt_name, map[current].name));
+ }
+
+ *last += i;
+
+ return EOK;
+}
int sdap_get_options(TALLOC_CTX *memctx,
struct confdb_ctx *cdb,
@@ -127,6 +184,10 @@ int sdap_get_options(TALLOC_CTX *memctx,
struct sdap_options *opts;
char *schema;
int i, ret;
+ char **map_list;
+ int user_attributes;
+ int user_extra_map;
+ struct sdap_extra_map *extra_map;
opts = talloc_zero(memctx, struct sdap_options);
if (!opts) return ENOMEM;
@@ -134,12 +195,6 @@ int sdap_get_options(TALLOC_CTX *memctx,
opts->basic = talloc_array(opts, struct sdap_gen_opts, SDAP_OPTS_BASIC);
if (!opts) return ENOMEM;
- opts->user_map = talloc_array(opts, struct sdap_id_map, SDAP_OPTS_USER);
- if (!opts) return ENOMEM;
-
- opts->group_map = talloc_array(opts, struct sdap_id_map, SDAP_OPTS_GROUP);
- if (!opts) return ENOMEM;
-
for (i = 0; i < SDAP_OPTS_BASIC; i++) {
char *tmp;
@@ -237,6 +292,58 @@ int sdap_get_options(TALLOC_CTX *memctx,
goto done;
}
+ /* user map and extras */
+ user_attributes = SDAP_OPTS_USER;
+ user_extra_map = 0;
+
+ ret = confdb_get_string_as_list(cdb, opts, conf_path,
+ "ldap_user_extra_maps", &map_list);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(0, ("Failed to retrieve value for option (%s)\n",
+ SDAP_USER_EXTRA_MAP_LIST));
+ goto done;
+ }
+
+ if (ret == ENOENT) {
+ map_list = NULL;
+ } else {
+ for (i = 0; map_list[i] != NULL; i++) {
+ extra_map = sdap_user_extra_map_list;
+ while (extra_map->name != NULL) {
+ if (strncasecmp(map_list[i], extra_map->name,
+ strlen(extra_map->name)) == 0) {
+ DEBUG(9, ("Found extra map [%s].\n", extra_map->name));
+ user_extra_map++;
+ user_attributes += extra_map->size;
+ break;
+ }
+ extra_map++;
+ }
+ if (extra_map->name == NULL) {
+ DEBUG(1, ("No extra map found for [%s].\n", map_list[i]));
+ }
+ }
+ }
+
+ opts->user_map = talloc_array(opts, struct sdap_id_map, user_attributes);
+ if (!opts->user_map) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (user_extra_map > 0) {
+ opts->user_extra_map = talloc_array(opts, struct sdap_extra_map,
+ user_extra_map);
+ if (!opts->user_extra_map) {
+ ret = ENOMEM;
+ goto done;
+ }
+ opts->user_extra_map_size = user_extra_map;
+ } else {
+ opts->user_extra_map = NULL;
+ opts->user_extra_map_size = 0;
+ }
+
for (i = 0; i < SDAP_OPTS_USER; i++) {
opts->user_map[i].opt_name = default_user_map[i].opt_name;
@@ -251,13 +358,54 @@ int sdap_get_options(TALLOC_CTX *memctx,
(opts->user_map[i].def_name && !opts->user_map[i].name)) {
DEBUG(0, ("Failed to retrieve a value (%s)\n",
opts->user_map[i].opt_name));
- if (ret != EOK) ret = EINVAL;
+ if (ret == EOK) ret = EINVAL;
goto done;
}
DEBUG(5, ("Option %s has value %s\n",
opts->user_map[i].opt_name, opts->user_map[i].name));
}
+ opts->user_map_size = i;
+
+ if (map_list != NULL) {
+ for (i = 0; map_list[i] != NULL; i++) {
+ extra_map = sdap_user_extra_map_list;
+ while (extra_map->name != NULL) {
+ if (strncasecmp(map_list[i], extra_map->name,
+ strlen(extra_map->name)) == 0) {
+ DEBUG(9, ("Adding extra map [%s].\n", extra_map->name));
+ user_extra_map--;
+ if (user_extra_map < 0) {
+ DEBUG(1, ("More extra maps than expected.\n"));
+ ret = EINVAL;
+ goto done;
+ }
+ opts->user_extra_map[user_extra_map].map =
+ &opts->user_map[opts->user_map_size];
+ opts->user_extra_map[user_extra_map].size = extra_map->size;
+ opts->user_extra_map[user_extra_map].name = extra_map->name;
+ ret = add_extra_map(cdb, opts, conf_path, opts->user_map,
+ &opts->user_map_size, extra_map->map,
+ extra_map->size);
+ if (ret != EOK) {
+ DEBUG(1, ("add_extra_map failed.\n"));
+ goto done;
+ }
+ break;
+ }
+ extra_map++;
+ }
+ if (extra_map->name == NULL) {
+ DEBUG(1, ("No extra map found for [%s].\n", map_list[i]));
+ }
+ }
+ }
+
+ opts->group_map = talloc_array(opts, struct sdap_id_map, SDAP_OPTS_GROUP);
+ if (!opts->group_map) {
+ ret = ENOMEM;
+ goto done;
+ }
for (i = 0; i < SDAP_OPTS_GROUP; i++) {
@@ -281,6 +429,8 @@ int sdap_get_options(TALLOC_CTX *memctx,
opts->group_map[i].opt_name, opts->group_map[i].name));
}
+ opts->group_map_size = i;
+
ret = EOK;
*_opts = opts;
@@ -509,7 +659,7 @@ int sdap_parse_user(TALLOC_CTX *memctx, struct sdap_options *opts,
{
return sdap_parse_entry(memctx, sh, sm, opts->user_map,
- SDAP_OPTS_USER, _attrs, _dn);
+ opts->user_map_size, _attrs, _dn);
}
/* This function converts an ldap message into a sysdb_attrs structure.
@@ -523,7 +673,7 @@ int sdap_parse_group(TALLOC_CTX *memctx, struct sdap_options *opts,
{
return sdap_parse_entry(memctx, sh, sm, opts->group_map,
- SDAP_OPTS_GROUP, _attrs, _dn);
+ opts->group_map_size, _attrs, _dn);
}
/* =Get-DN-from-message=================================================== */
diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h
index cb98668..161a4f1 100644
--- a/server/providers/ldap/sdap.h
+++ b/server/providers/ldap/sdap.h
@@ -96,6 +96,7 @@ enum sdap_basic_opt {
SDAP_KRB5_KEYTAB,
SDAP_KRB5_KINIT,
SDAP_KRB5_REALM,
+ SDAP_USER_EXTRA_MAP_LIST,
SDAP_OPTS_BASIC /* opts counter */
};
@@ -134,6 +135,36 @@ enum sdap_group_opt {
SDAP_OPTS_GROUP /* attrs counter */
};
+#define SYSDB_KRB_LSTCHG "krbLastPwdChange"
+#define SYSDB_KRB_EXPIRE "krbPasswordExpiration"
+
+#define SYSDB_SP_LSTCHG "shadowLastChange"
+#define SYSDB_SP_MIN "shadowMin"
+#define SYSDB_SP_MAX "shadowMax"
+#define SYSDB_SP_WARN "shadowWarning"
+#define SYSDB_SP_INACT "shadowInactive"
+#define SYSDB_SP_EXPIRE "shadowExpire"
+#define SYSDB_SP_FLAG "shadowFlag"
+
+enum sdap_sp_opt {
+ SDAP_AT_SP_LSTCHG = 0,
+ SDAP_AT_SP_MIN,
+ SDAP_AT_SP_MAX,
+ SDAP_AT_SP_WARN,
+ SDAP_AT_SP_INACT,
+ SDAP_AT_SP_EXPIRE,
+ SDAP_AT_SP_FLAG,
+
+ SDAP_OPTS_SP /* attrs counter */
+};
+
+enum sdap_kp_opt {
+ SDAP_AT_KP_LSTCHG = 0,
+ SDAP_AT_KP_EXPIRE,
+
+ SDAP_OPTS_KP /* attrs counter */
+};
+
enum sdap_type {
SDAP_STRING,
SDAP_BLOB,
@@ -168,10 +199,21 @@ struct sdap_id_map {
char *name;
};
+struct sdap_extra_map {
+ const char *name;
+ struct sdap_id_map *map;
+ int size;
+};
+
struct sdap_options {
struct sdap_gen_opts *basic;
struct sdap_id_map *user_map;
struct sdap_id_map *group_map;
+ size_t user_map_size;
+ size_t group_map_size;
+
+ struct sdap_extra_map *user_extra_map;
+ size_t user_extra_map_size;
/* supported schema types */
enum schema_type {
diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c
index f68a31c..b723aca 100644
--- a/server/providers/ldap/sdap_async.c
+++ b/server/providers/ldap/sdap_async.c
@@ -1266,6 +1266,8 @@ static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx,
gid_t gid;
struct sysdb_attrs *user_attrs;
char *upn = NULL;
+ int i;
+ int m;
req = tevent_req_create(memctx, &state, struct sdap_save_user_state);
if (!req) return NULL;
@@ -1417,6 +1419,38 @@ static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx,
}
}
+ if (opts->user_extra_map != NULL) {
+ for (m = 0; m < opts->user_extra_map_size; m++) {
+ for (i = 0; i < opts->user_extra_map[m].size; i++) {
+ ret = sysdb_attrs_get_el(state->attrs,
+ opts->user_extra_map[m].map[i].sys_name,
+ &el);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_get_el failed.\n"));
+ goto fail;
+ }
+
+ if (el->num_values == 0) {
+ DEBUG(7, ("Attribute [%s] is not available for [%s].\n",
+ opts->user_extra_map[m].map[i].sys_name,
+ state->name));
+ } else {
+ DEBUG(9, ("Adding attribute [%s] with value [%s] to [%s].\n",
+ opts->user_extra_map[m].map[i].sys_name,
+ (const char*)el->values[0].data,
+ state->name));
+ ret = sysdb_attrs_add_string(user_attrs,
+ opts->user_extra_map[m].map[i].sys_name,
+ (const char*)el->values[0].data);
+ if (ret) {
+ DEBUG(1, ("sysdb_attrs_add_string failed.\n"));
+ goto fail;
+ }
+ }
+ }
+ }
+ }
+
DEBUG(6, ("Storing info for user %s\n", state->name));
subreq = sysdb_store_user_send(state, state->ev, state->handle,
--
1.6.2.5
More information about the sssd-devel
mailing list