[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