[SSSD] [PATCH] Check for expired passwords in LDAP provider

Sumit Bose sbose at redhat.com
Fri Oct 9 19:38:37 UTC 2009


Hi,

with this patch the LDAP provider check typical attributes which
determines the lifetime of a password. If there is more than one scheme
available the following order is user:
 - server side password policies
 - Kerberos password attributes
 - shadow attributes
Currently only in the case of server side password policies the password
can actually be changed. Kerberos password should be changed with the
Kerberos backend.

bye,
Sumit
-------------- next part --------------
>From aeb81745ed107b21575094d829e6b1eb8f3ac514 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Fri, 9 Oct 2009 13:34:35 +0200
Subject: [PATCH] Check for expired passwords in LDAP provider

- based on the existance of some attributes in the user's LDAP/sysdb
  object the lifetime of the password is evaluated
- if 'pwdAttribute' exists it is assumed that server side password
  policies are in place and not additional evaluation is done
- if 'kerberosLastChange' exists the attribute 'kerberosExpiration'
  is evaluated; to change the password the kerberos backend should
  be used
- if 'shadowLstChg' exists the shadow attributes are evaluated;
  changing the password will be implemented later together with an
  asynchronous ldap modify request
---
 server/providers/ldap/ldap_auth.c  |  364 ++++++++++++++++++++++++++++++++++--
 server/providers/ldap/sdap.c       |   24 +++-
 server/providers/ldap/sdap.h       |   28 +++-
 server/providers/ldap/sdap_async.c |   25 +++
 4 files changed, 418 insertions(+), 23 deletions(-)

diff --git a/server/providers/ldap/ldap_auth.c b/server/providers/ldap/ldap_auth.c
index 487fb07..b1f44a9 100644
--- a/server/providers/ldap/ldap_auth.c
+++ b/server/providers/ldap/ldap_auth.c
@@ -29,9 +29,13 @@
 #define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW ((ber_tag_t) 0x82U)
 #endif
 
+#define _XOPEN_SOURCE 500 /* for strptime() */
+#include <time.h>
+#undef _XOPEN_SOURCE
 #include <errno.h>
 #include <sys/time.h>
 
+#include <shadow.h>
 #include <security/pam_modules.h>
 
 #include "util/util.h"
@@ -39,11 +43,213 @@
 #include "providers/dp_backend.h"
 #include "providers/ldap/sdap_async.h"
 
+enum pwexpire {
+    PWEXPIRE_NONE = 0,
+    PWEXPIRE_LDAP_PASSWORD_POLICY,
+    PWEXPIRE_KERBEROS,
+    PWEXPIRE_SHADOW
+};
+
 struct sdap_auth_ctx {
     struct be_ctx *be;
     struct sdap_options *opts;
 };
 
+static errno_t check_pwexpire_kerberos(const char *expire_date, time_t now,
+                                       enum sdap_result *result)
+{
+    char *end;
+    struct tm tm = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+    time_t expire_time;
+
+    *result = SDAP_AUTH_FAILED;
+
+    end = strptime(expire_date, "%Y%m%d%H%M%SZ", &tm);
+    if (end == NULL) {
+        DEBUG(1, ("Kerberos expire date [%s] invalid.\n", expire_date));
+        return EINVAL;
+    }
+    if (*end != '\0') {
+        DEBUG(1, ("Kerberos expire date [%s] contains extra characters.\n",
+                  expire_date));
+        return EINVAL;
+    }
+
+    expire_time = mktime(&tm);
+    if (expire_time == -1) {
+        DEBUG(1, ("mktime failed to convert [%s].\n", expire_date));
+        return EINVAL;
+    }
+
+    if (difftime(now, expire_time) > 0.0) {
+        DEBUG(4, ("Kerberos password expired.\n"));
+        *result = SDAP_AUTH_PW_EXPIRED;
+    } else {
+        *result = SDAP_AUTH_SUCCESS;
+    }
+
+    return EOK;
+}
+
+static errno_t check_pwexpire_shadow(struct spwd *spwd, time_t now,
+                                     enum sdap_result *result)
+{
+    long today;
+    long password_age;
+
+    if (spwd->sp_lstchg <= 0) {
+        DEBUG(4, ("Last change day is not set, new password needed.\n"));
+        *result = SDAP_AUTH_PW_EXPIRED;
+        return EOK;
+    }
+
+    today = (long) (now / (60 * 60 *24));
+    password_age = today - spwd->sp_lstchg;
+    if (password_age < 0) {
+        DEBUG(2, ("The last password change time is in the future!.\n"));
+        *result = SDAP_AUTH_SUCCESS;
+        return EOK;
+    }
+
+    if ((spwd->sp_expire != -1 && today > spwd->sp_expire) ||
+        (spwd->sp_max != -1 && spwd->sp_inact != -1 &&
+         password_age > spwd->sp_max + spwd->sp_inact))
+    {
+        DEBUG(4, ("Account expired.\n"));
+        *result = SDAP_ACCT_EXPIRED;
+        return EOK;
+    }
+
+    if (spwd->sp_max != -1 && password_age > spwd->sp_max) {
+        DEBUG(4, ("Password expired.\n"));
+        *result = SDAP_AUTH_PW_EXPIRED;
+        return EOK;
+    }
+
+/* TODO: evaluate spwd->min and spwd->warn */
+
+    *result = SDAP_AUTH_SUCCESS;
+    return EOK;
+}
+
+static errno_t string_to_shadowpw_days(const char *s, long *d)
+{
+    long l;
+    char *endptr;
+
+    if (s == NULL || *s == '\0') {
+        *d = -1;
+        return EOK;
+    }
+
+    errno = 0;
+    l = strtol(s, &endptr, 10);
+    if (errno != 0) {
+        DEBUG(1, ("strtol failed [%d][%s].\n", errno, strerror(errno)));
+        return errno;
+    }
+
+    if (*endptr != '\0') {
+        DEBUG(1, ("Input string [%s] is invalid.\n", s));
+        return EINVAL;
+    }
+
+    if (*d < -1) {
+        DEBUG(1, ("Input string contains not allowed negative value [%d].\n",
+                  *d));
+        return EINVAL;
+    }
+
+    *d = l;
+
+    return EOK;
+}
+
+static errno_t find_password_expiration_attributes(TALLOC_CTX *mem_ctx,
+                                               const struct ldb_message *msg,
+                                               enum pwexpire *type, void **data)
+{
+    const char *mark;
+    const char *val;
+    struct spwd *spwd;
+    int ret;
+
+    *type = PWEXPIRE_NONE;
+    *data = NULL;
+
+    mark = ldb_msg_find_attr_as_string(msg, SYSDB_PWD_ATTRIBUTE, NULL);
+    if (mark != NULL) {
+        DEBUG(9, ("Found pwdAttribute, "
+                  "assuming LDAP password policies are active.\n"));
+
+        *type = PWEXPIRE_LDAP_PASSWORD_POLICY;
+        return EOK;
+    }
+
+    mark = ldb_msg_find_attr_as_string(msg, SYSDB_KRBPW_LASTCHANGE, NULL);
+    if (mark != NULL) {
+        DEBUG(9, ("Found Kerberos password expiration attributes.\n"))
+        val = ldb_msg_find_attr_as_string(msg, SYSDB_KRBPW_EXPIRATION,
+                                          NULL);
+        if (val != NULL) {
+            *data = talloc_strdup(mem_ctx, val);
+            if (*data == NULL) {
+                DEBUG(1, ("talloc_strdup failed.\n"));
+                return ENOMEM;
+            }
+            *type = PWEXPIRE_KERBEROS;
+
+            return EOK;
+        }
+    }
+
+    mark = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_LASTCHANGE, NULL);
+    if (mark != NULL) {
+        DEBUG(9, ("Found shadow password expiration attributes.\n"))
+        spwd = talloc_zero(mem_ctx, struct spwd);
+        if (spwd == NULL) {
+            DEBUG(1, ("talloc failed.\n"));
+            return ENOMEM;
+        }
+
+        val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_LASTCHANGE, NULL);
+        ret = string_to_shadowpw_days(val, &spwd->sp_lstchg);
+        if (ret != EOK) goto shadow_fail;
+
+        val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_MIN, NULL);
+        ret = string_to_shadowpw_days(val, &spwd->sp_min);
+        if (ret != EOK) goto shadow_fail;
+
+        val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_MAX, NULL);
+        ret = string_to_shadowpw_days(val, &spwd->sp_max);
+        if (ret != EOK) goto shadow_fail;
+
+        val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_WARNING, NULL);
+        ret = string_to_shadowpw_days(val, &spwd->sp_warn);
+        if (ret != EOK) goto shadow_fail;
+
+        val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_INACTIVE, NULL);
+        ret = string_to_shadowpw_days(val, &spwd->sp_inact);
+        if (ret != EOK) goto shadow_fail;
+
+        val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_EXPIRE, NULL);
+        ret = string_to_shadowpw_days(val, &spwd->sp_expire);
+        if (ret != EOK) goto shadow_fail;
+
+        *data = spwd;
+        *type = PWEXPIRE_SHADOW;
+
+        return EOK;
+    }
+
+    DEBUG(9, ("No password expiration attributes found.\n"));
+    return EOK;
+
+shadow_fail:
+        talloc_free(spwd);
+        return ret;
+}
+
 /* ==Get-User-DN========================================================== */
 
 struct get_user_dn_state {
@@ -55,6 +261,8 @@ struct get_user_dn_state {
     const char *name;
 
     char *dn;
+    enum pwexpire pw_expire_type;
+    void *pw_expire_data;
 };
 
 static void get_user_dn_done(void *pvt, int err, struct ldb_result *res);
@@ -77,13 +285,22 @@ struct tevent_req *get_user_dn_send(TALLOC_CTX *memctx,
     state->sh = sh;
     state->name = username;
 
-    state->attrs = talloc_array(state, const char *, 2);
+    state->attrs = talloc_array(state, const char *, 11);
     if (!state->attrs) {
         talloc_zfree(req);
         return NULL;
     }
     state->attrs[0] = SYSDB_ORIG_DN;
-    state->attrs[1] = NULL;
+    state->attrs[1] = SYSDB_SHADOWPW_LASTCHANGE;
+    state->attrs[2] = SYSDB_SHADOWPW_MIN;
+    state->attrs[3] = SYSDB_SHADOWPW_MAX;
+    state->attrs[4] = SYSDB_SHADOWPW_WARNING;
+    state->attrs[5] = SYSDB_SHADOWPW_INACTIVE;
+    state->attrs[6] = SYSDB_SHADOWPW_EXPIRE;
+    state->attrs[7] = SYSDB_KRBPW_LASTCHANGE;
+    state->attrs[8] = SYSDB_KRBPW_EXPIRATION;
+    state->attrs[9] = SYSDB_PWD_ATTRIBUTE;
+    state->attrs[10] = NULL;
 
     /* this sysdb call uses a sysdn operation, which means it will be
      * schedule only after we return, no timer hack needed */
@@ -104,6 +321,7 @@ static void get_user_dn_done(void *pvt, int err, struct ldb_result *res)
     struct get_user_dn_state *state = tevent_req_data(req,
                                            struct get_user_dn_state);
     const char *dn;
+    int ret;
 
     if (err != LDB_SUCCESS) {
         tevent_req_error(req, EIO);
@@ -133,12 +351,22 @@ static void get_user_dn_done(void *pvt, int err, struct ldb_result *res)
                 break;
             }
         }
+
         state->dn = talloc_strdup(state, dn);
         if (!state->dn) {
             tevent_req_error(req, ENOMEM);
             break;
         }
 
+        ret = find_password_expiration_attributes(state, res->msgs[0],
+                                                  &state->pw_expire_type,
+                                                  &state->pw_expire_data);
+        if (ret != EOK) {
+            DEBUG(1, ("find_password_expiration_attributes failed.\n"));
+            tevent_req_error(req, ENOMEM);
+            break;
+        }
+
         tevent_req_done(req);
         break;
 
@@ -151,7 +379,9 @@ static void get_user_dn_done(void *pvt, int err, struct ldb_result *res)
 }
 
 static int get_user_dn_recv(struct tevent_req *req,
-                            TALLOC_CTX *memctx, char **dn)
+                            TALLOC_CTX *memctx, char **dn,
+                            enum pwexpire *pw_expire_type,
+                            void **pw_expire_data)
 {
     struct get_user_dn_state *state = tevent_req_data(req,
                                            struct get_user_dn_state);
@@ -165,6 +395,11 @@ static int get_user_dn_recv(struct tevent_req *req,
     *dn = talloc_steal(memctx, state->dn);
     if (!*dn) return ENOMEM;
 
+    /* state->pw_expire_data may be NULL */
+    *pw_expire_data = talloc_steal(memctx, state->pw_expire_data);
+
+    *pw_expire_type = state->pw_expire_type;
+
     return EOK;
 }
 
@@ -180,6 +415,8 @@ struct auth_state {
 
     enum sdap_result result;
     char *dn;
+    enum pwexpire pw_expire_type;
+    void *pw_expire_data;
 };
 
 static void auth_connect_done(struct tevent_req *subreq);
@@ -249,7 +486,8 @@ static void auth_get_user_dn_done(struct tevent_req *subreq)
                                                     struct auth_state);
     int ret;
 
-    ret = get_user_dn_recv(subreq, state, &state->dn);
+    ret = get_user_dn_recv(subreq, state, &state->dn, &state->pw_expire_type,
+                           &state->pw_expire_data);
     talloc_zfree(subreq);
     if (ret) {
         tevent_req_error(req, ret);
@@ -286,7 +524,8 @@ static void auth_bind_user_done(struct tevent_req *subreq)
 }
 
 int auth_recv(struct tevent_req *req, enum sdap_result *result,
-                     TALLOC_CTX *memctx, struct sdap_handle **sh, char **dn)
+                     TALLOC_CTX *memctx, struct sdap_handle **sh, char **dn,
+                     enum pwexpire *pw_expire_type, void **pw_expire_data)
 {
     struct auth_state *state = tevent_req_data(req,
                                                     struct auth_state);
@@ -309,6 +548,12 @@ int auth_recv(struct tevent_req *req, enum sdap_result *result,
         if (*dn == NULL) return ENOMEM;
     }
 
+    if (pw_expire_data != NULL) {
+        *pw_expire_data = talloc_steal(memctx, state->pw_expire_data);
+    }
+
+    *pw_expire_type = state->pw_expire_type;
+
     *result = state->result;
     return EOK;
 }
@@ -393,33 +638,79 @@ static void sdap_auth4chpass_done(struct tevent_req *req)
     struct tevent_req *subreq;
     enum sdap_result result;
     int ret;
+    enum pwexpire pw_expire_type;
+    void* pw_expire_data;
 
-    ret = auth_recv(req, &result, state, &state->sh, &state->dn);
+    ret = auth_recv(req, &result, state, &state->sh, &state->dn,
+                    &pw_expire_type, &pw_expire_data);
     talloc_zfree(req);
     if (ret) {
         state->pd->pam_status = PAM_SYSTEM_ERR;
         goto done;
     }
 
+    if (result == SDAP_AUTH_SUCCESS) {
+        switch (pw_expire_type) {
+            case PWEXPIRE_SHADOW:
+                ret = check_pwexpire_shadow(pw_expire_data, time(NULL),
+                                            &result);
+                if (ret != EOK) {
+                    DEBUG(1, ("check_pwexpire_shadow failed.\n"));
+                    state->pd->pam_status = PAM_SYSTEM_ERR;
+                    goto done;
+                }
+                break;
+            case PWEXPIRE_KERBEROS:
+                ret = check_pwexpire_kerberos(pw_expire_data, time(NULL),
+                                              &result);
+                if (ret != EOK) {
+                    DEBUG(1, ("check_pwexpire_kerberos failed.\n"));
+                    state->pd->pam_status = PAM_SYSTEM_ERR;
+                    goto done;
+                }
+
+                if (result == SDAP_AUTH_PW_EXPIRED) {
+                    DEBUG(1, ("LDAP provider cannot change kerberos "
+                              "passwords.\n"));
+                    state->pd->pam_status = PAM_SYSTEM_ERR;
+                    goto done;
+                }
+                break;
+            case PWEXPIRE_LDAP_PASSWORD_POLICY:
+            case PWEXPIRE_NONE:
+                break;
+            default:
+                DEBUG(1, ("Unknow pasword expiration type.\n"));
+                    state->pd->pam_status = PAM_SYSTEM_ERR;
+                    goto done;
+        }
+    }
 
     switch (result) {
     case SDAP_AUTH_SUCCESS:
     case SDAP_AUTH_PW_EXPIRED:
         DEBUG(7, ("user [%s] successfully authenticated.\n", state->dn));
-        subreq = sdap_exop_modify_passwd_send(state,
-                                              state->breq->be_ctx->ev,
-                                              state->sh,
-                                              state->dn,
-                                              state->password,
-                                              state->new_password);
-
-        if (!subreq) {
-            DEBUG(2, ("Failed to change password for %s\n", state->username));
+        if (pw_expire_type == PWEXPIRE_SHADOW) {
+/* TODO: implement async ldap modify request */
+            DEBUG(1, ("Changing shadow password attributes not implemented.\n"));
+            state->pd->pam_status = PAM_SYSTEM_ERR;
             goto done;
-        }
+        } else {
+            subreq = sdap_exop_modify_passwd_send(state,
+                                                  state->breq->be_ctx->ev,
+                                                  state->sh,
+                                                  state->dn,
+                                                  state->password,
+                                                  state->new_password);
+
+            if (!subreq) {
+                DEBUG(2, ("Failed to change password for %s\n", state->username));
+                goto done;
+            }
 
-        tevent_req_set_callback(subreq, sdap_pam_chpass_done, state);
-        return;
+            tevent_req_set_callback(subreq, sdap_pam_chpass_done, state);
+            return;
+        }
         break;
     default:
         state->pd->pam_status = PAM_SYSTEM_ERR;
@@ -524,20 +815,53 @@ static void sdap_pam_auth_done(struct tevent_req *req)
     struct tevent_req *subreq;
     enum sdap_result result;
     int ret;
+    enum pwexpire pw_expire_type;
+    void* pw_expire_data;
 
-    ret = auth_recv(req, &result, NULL, NULL, NULL);
+    ret = auth_recv(req, &result, state, NULL, NULL, &pw_expire_type,
+                    &pw_expire_data);
     talloc_zfree(req);
     if (ret) {
         state->pd->pam_status = PAM_SYSTEM_ERR;
         goto done;
     }
 
+    if (result == SDAP_AUTH_SUCCESS) {
+        switch (pw_expire_type) {
+            case PWEXPIRE_SHADOW:
+                ret = check_pwexpire_shadow(pw_expire_data, time(NULL),
+                                            &result);
+                if (ret != EOK) {
+                    DEBUG(1, ("check_pwexpire_shadow failed.\n"));
+                    state->pd->pam_status = PAM_SYSTEM_ERR;
+                    goto done;
+                }
+                break;
+            case PWEXPIRE_KERBEROS:
+                ret = check_pwexpire_kerberos(pw_expire_data, time(NULL),
+                                              &result);
+                if (ret != EOK) {
+                    DEBUG(1, ("check_pwexpire_kerberos failed.\n"));
+                    state->pd->pam_status = PAM_SYSTEM_ERR;
+                    goto done;
+                }
+                break;
+            case PWEXPIRE_LDAP_PASSWORD_POLICY:
+            case PWEXPIRE_NONE:
+                break;
+            default:
+                DEBUG(1, ("Unknow pasword expiration type.\n"));
+                    state->pd->pam_status = PAM_SYSTEM_ERR;
+                    goto done;
+        }
+    }
+
     switch (result) {
     case SDAP_AUTH_SUCCESS:
         state->pd->pam_status = PAM_SUCCESS;
         break;
     case SDAP_AUTH_FAILED:
-        state->pd->pam_status = PAM_CRED_INSUFFICIENT;
+        state->pd->pam_status = PAM_PERM_DENIED;
         break;
     case SDAP_UNAVAIL:
         state->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
diff --git a/server/providers/ldap/sdap.c b/server/providers/ldap/sdap.c
index b2dc6f6..3e717f6 100644
--- a/server/providers/ldap/sdap.c
+++ b/server/providers/ldap/sdap.c
@@ -74,7 +74,17 @@ struct sdap_id_map rfc2307_user_map[] = {
     { "ldap_user_fullname", "cn", SYSDB_FULLNAME, NULL },
     { "ldap_user_member_of", NULL, SYSDB_MEMBEROF, NULL },
     { "ldap_user_uuid", NULL, SYSDB_UUID, NULL },
-    { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }
+    { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+    { "ldap_user_shadow_last_change", "shadowLastChange", SYSDB_SHADOWPW_LASTCHANGE, NULL },
+    { "ldap_user_shadow_min", "shadowMin", SYSDB_SHADOWPW_MIN, NULL },
+    { "ldap_user_shadow_max", "shadowMax", SYSDB_SHADOWPW_MAX, NULL },
+    { "ldap_user_shadow_warning", "shadowWarning", SYSDB_SHADOWPW_WARNING, NULL },
+    { "ldap_user_shadow_inactive", "shadowInactive", SYSDB_SHADOWPW_INACTIVE, NULL },
+    { "ldap_user_shadow_expire", "shadowExpire", SYSDB_SHADOWPW_EXPIRE, NULL },
+    { "ldap_user_shadow_flag", "shadowFlag", SYSDB_SHADOWPW_FLAG, NULL },
+    { "ldap_user_krb_last_pwd_change", "krbLastPwdChange", SYSDB_KRBPW_LASTCHANGE, NULL },
+    { "ldap_user_krb_password_expiration", "krbPasswordExpiration", SYSDB_KRBPW_EXPIRATION, NULL },
+    { "ldap_pwd_attribute", "pwdAttribute", SYSDB_PWD_ATTRIBUTE, NULL }
 };
 
 struct sdap_id_map rfc2307_group_map[] = {
@@ -101,7 +111,17 @@ struct sdap_id_map rfc2307bis_user_map[] = {
     { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL },
     /* FIXME: this is 389ds specific */
     { "ldap_user_uuid", "nsUniqueId", SYSDB_UUID, NULL },
-    { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }
+    { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+    { "ldap_user_shadow_last_change", "shadowLastChange", SYSDB_SHADOWPW_LASTCHANGE, NULL },
+    { "ldap_user_shadow_min", "shadowMin", SYSDB_SHADOWPW_MIN, NULL },
+    { "ldap_user_shadow_max", "shadowMax", SYSDB_SHADOWPW_MAX, NULL },
+    { "ldap_user_shadow_warning", "shadowWarning", SYSDB_SHADOWPW_WARNING, NULL },
+    { "ldap_user_shadow_inactive", "shadowInactive", SYSDB_SHADOWPW_INACTIVE, NULL },
+    { "ldap_user_shadow_expire", "shadowExpire", SYSDB_SHADOWPW_EXPIRE, NULL },
+    { "ldap_user_shadow_flag", "shadowFlag", SYSDB_SHADOWPW_FLAG, NULL },
+    { "ldap_user_krb_last_pwd_change", "krbLastPwdChange", SYSDB_KRBPW_LASTCHANGE, NULL },
+    { "ldap_user_krb_password_expiration", "krbPasswordExpiration", SYSDB_KRBPW_EXPIRATION, NULL },
+    { "ldap_pwd_attribute", "pwdAttribute", SYSDB_PWD_ATTRIBUTE, NULL }
 };
 
 struct sdap_id_map rfc2307bis_group_map[] = {
diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h
index 92771de..7021854 100644
--- a/server/providers/ldap/sdap.h
+++ b/server/providers/ldap/sdap.h
@@ -59,6 +59,19 @@ struct sdap_handle {
     struct sdap_op *ops;
 };
 
+#define SYSDB_SHADOWPW_LASTCHANGE "shadowLastChange"
+#define SYSDB_SHADOWPW_MIN "shadowMin"
+#define SYSDB_SHADOWPW_MAX "shadowMax"
+#define SYSDB_SHADOWPW_WARNING "shadowWarning"
+#define SYSDB_SHADOWPW_INACTIVE "shadowInactive"
+#define SYSDB_SHADOWPW_EXPIRE "shadowExpire"
+#define SYSDB_SHADOWPW_FLAG "shadowFlag"
+
+#define SYSDB_KRBPW_LASTCHANGE "krbLastPwdChange"
+#define SYSDB_KRBPW_EXPIRATION "krbPasswordExpiration"
+
+#define SYSDB_PWD_ATTRIBUTE "pwdAttribute"
+
 enum sdap_result {
     SDAP_SUCCESS,
     SDAP_NOT_FOUND,
@@ -67,7 +80,8 @@ enum sdap_result {
     SDAP_ERROR,
     SDAP_AUTH_SUCCESS,
     SDAP_AUTH_FAILED,
-    SDAP_AUTH_PW_EXPIRED
+    SDAP_AUTH_PW_EXPIRED,
+    SDAP_ACCT_EXPIRED
 };
 
 enum sdap_basic_opt {
@@ -117,10 +131,22 @@ enum sdap_user_opt {
     SDAP_AT_USER_MEMBEROF,
     SDAP_AT_USER_UUID,
     SDAP_AT_USER_MODSTAMP,
+    SDAP_AT_SP_LSTCHG,
+    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_AT_KP_LASTCHANGE,
+    SDAP_AT_KP_EXPIRATION,
+    SDAP_AT_PWD_ATTRIBUTE,
 
     SDAP_OPTS_USER /* attrs counter */
 };
 
+#define SDAP_FIRST_EXTRA_USER_AT SDAP_AT_SP_LSTCHG
+
 /* the objectclass must be the first attribute.
  * Functions depend on this */
 enum sdap_group_opt {
diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c
index 6fd2837..470b82d 100644
--- a/server/providers/ldap/sdap_async.c
+++ b/server/providers/ldap/sdap_async.c
@@ -1281,6 +1281,7 @@ int sdap_auth_recv(struct tevent_req *req, enum sdap_result *result)
         default:
             *result = SDAP_ERROR;
     }
+
     return EOK;
 }
 
@@ -1326,6 +1327,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;
+    char *val = NULL;
 
     req = tevent_req_create(memctx, &state, struct sdap_save_user_state);
     if (!req) return NULL;
@@ -1477,6 +1480,28 @@ static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx,
         }
     }
 
+    for (i = SDAP_FIRST_EXTRA_USER_AT; i < SDAP_OPTS_USER; i++) {
+        ret = sysdb_attrs_get_el(state->attrs, opts->user_map[i].sys_name, &el);
+        if (ret) {
+            goto fail;
+        }
+        if (el->num_values > 0) {
+            DEBUG(9, ("Adding [%s]=[%s] to user attributes.\n",
+                      opts->user_map[i].sys_name,
+                      (const char*) el->values[0].data));
+            val = talloc_strdup(user_attrs, (const char*) el->values[0].data);
+            if (val == NULL) {
+                ret = ENOMEM;
+                goto fail;
+            }
+            ret = sysdb_attrs_add_string(user_attrs,
+                                         opts->user_map[i].sys_name, val);
+            if (ret) {
+                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