1cdfb00
From d3f82e944dc5dab3812700a245deec4aa3245b21 Mon Sep 17 00:00:00 2001
1cdfb00
From: Pavel Reichl <preichl@redhat.com>
1cdfb00
Date: Wed, 18 Feb 2015 01:03:40 -0500
1cdfb00
Subject: [PATCH 08/99] SDAP: enable change phase of pw expire policy check
1cdfb00
1cdfb00
Implement new option which does checking password expiration policy
1cdfb00
in accounting phase.
1cdfb00
1cdfb00
This allows SSSD to issue shadow expiration warning even if alternate
1cdfb00
authentication method is used.
1cdfb00
1cdfb00
Resolves:
1cdfb00
https://fedorahosted.org/sssd/ticket/2167
1cdfb00
1cdfb00
Reviewed-by: Sumit Bose <sbose@redhat.com>
1cdfb00
(cherry picked from commit c9b0071bfcb8eb8c71e40248de46d23aceecc0f3)
1cdfb00
---
1cdfb00
 src/man/sssd-ldap.5.xml          | 27 +++++++++++++++++
1cdfb00
 src/providers/ldap/ldap_access.c | 12 ++++++++
1cdfb00
 src/providers/ldap/ldap_auth.c   |  1 +
1cdfb00
 src/providers/ldap/ldap_init.c   |  9 ++++++
1cdfb00
 src/providers/ldap/sdap_access.c | 62 +++++++++++++++++++++++++++++++++++++++-
1cdfb00
 src/providers/ldap/sdap_access.h |  6 ++++
1cdfb00
 src/util/util_errors.h           |  3 ++
1cdfb00
 7 files changed, 119 insertions(+), 1 deletion(-)
1cdfb00
1cdfb00
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
1cdfb00
index 5b36f69a679a1362290d8fea1f4c8fc29cc548d8..9fbc47487f3513a84e14b70ad85e32d08d1b9c6f 100644
1cdfb00
--- a/src/man/sssd-ldap.5.xml
1cdfb00
+++ b/src/man/sssd-ldap.5.xml
1cdfb00
@@ -1959,6 +1959,33 @@ ldap_access_filter = (employeeType=admin)
1cdfb00
                             ldap_account_expire_policy
1cdfb00
                         </para>
1cdfb00
                         <para>
1cdfb00
+                            <emphasis>pwd_expire_policy_reject,
1cdfb00
+                                      pwd_expire_policy_warn,
1cdfb00
+                                      pwd_expire_policy_renew:
1cdfb00
+                            </emphasis>
1cdfb00
+                            These options are useful if users are interested
1cdfb00
+                            in being warned that password is about to expire
1cdfb00
+                            and authentication is based on using a different
1cdfb00
+                            method than passwords - for example SSH keys.
1cdfb00
+                       </para>
1cdfb00
+                       <para>
1cdfb00
+                            The difference between these options is the action
1cdfb00
+                            taken if user password is expired:
1cdfb00
+                            pwd_expire_policy_reject - user is denied to log in,
1cdfb00
+                            pwd_expire_policy_warn - user is still able to log in,
1cdfb00
+                            pwd_expire_policy_renew - user is prompted to change
1cdfb00
+                            his password immediately.
1cdfb00
+                        </para>
1cdfb00
+                        <para>
1cdfb00
+                            Note If user password is expired no explicit message
1cdfb00
+                            is prompted by SSSD.
1cdfb00
+                        </para>
1cdfb00
+                        <para>
1cdfb00
+                            Please note that 'access_provider = ldap' must
1cdfb00
+                            be set for this feature to work. Also 'ldap_pwd_policy'
1cdfb00
+                            must be set to an appropriate password policy.
1cdfb00
+                        </para>
1cdfb00
+                        <para>
1cdfb00
                             <emphasis>authorized_service</emphasis>: use
1cdfb00
                             the authorizedService attribute to determine
1cdfb00
                             access
1cdfb00
diff --git a/src/providers/ldap/ldap_access.c b/src/providers/ldap/ldap_access.c
1cdfb00
index 1913cd9a92342cc985d5c098f224c4fe8c58d465..7ebdb20c06c5bb5f588071761c201ad566944d7e 100644
1cdfb00
--- a/src/providers/ldap/ldap_access.c
1cdfb00
+++ b/src/providers/ldap/ldap_access.c
1cdfb00
@@ -96,6 +96,18 @@ static void sdap_access_done(struct tevent_req *req)
1cdfb00
     case ERR_ACCOUNT_EXPIRED:
1cdfb00
         pam_status = PAM_ACCT_EXPIRED;
1cdfb00
         break;
1cdfb00
+    case ERR_PASSWORD_EXPIRED:
1cdfb00
+        pam_status = PAM_PERM_DENIED;
1cdfb00
+        break;
1cdfb00
+    case ERR_PASSWORD_EXPIRED_REJECT:
1cdfb00
+        pam_status = PAM_PERM_DENIED;
1cdfb00
+        break;
1cdfb00
+    case ERR_PASSWORD_EXPIRED_WARN:
1cdfb00
+        pam_status = PAM_SUCCESS;
1cdfb00
+        break;
1cdfb00
+    case ERR_PASSWORD_EXPIRED_RENEW:
1cdfb00
+        pam_status = PAM_NEW_AUTHTOK_REQD;
1cdfb00
+        break;
1cdfb00
     default:
1cdfb00
         DEBUG(SSSDBG_CRIT_FAILURE, "Error retrieving access check result.\n");
1cdfb00
         pam_status = PAM_SYSTEM_ERR;
1cdfb00
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
1cdfb00
index 4035aaf58c23291eb8115ef320758ba7666ed4e2..bdcc4505dc82cf3ca4bec9ce71ec6a9c28dd54e8 100644
1cdfb00
--- a/src/providers/ldap/ldap_auth.c
1cdfb00
+++ b/src/providers/ldap/ldap_auth.c
1cdfb00
@@ -47,6 +47,7 @@
1cdfb00
 #include "providers/ldap/sdap_async.h"
1cdfb00
 #include "providers/ldap/sdap_async_private.h"
1cdfb00
 #include "providers/ldap/ldap_auth.h"
1cdfb00
+#include "providers/ldap/sdap_access.h"
1cdfb00
 
1cdfb00
 #define LDAP_PWEXPIRE_WARNING_TIME 0
1cdfb00
 
1cdfb00
diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
1cdfb00
index 44333a9a3a45de16aaaf83fecaea4817cebc90d4..8d5619779d38c0df5ec4761b4409c71e8976686c 100644
1cdfb00
--- a/src/providers/ldap/ldap_init.c
1cdfb00
+++ b/src/providers/ldap/ldap_init.c
1cdfb00
@@ -423,6 +423,15 @@ int sssm_ldap_access_init(struct be_ctx *bectx,
1cdfb00
             access_ctx->access_rule[c] = LDAP_ACCESS_HOST;
1cdfb00
         } else if (strcasecmp(order_list[c], LDAP_ACCESS_LOCK_NAME) == 0) {
1cdfb00
             access_ctx->access_rule[c] = LDAP_ACCESS_LOCKOUT;
1cdfb00
+        } else if (strcasecmp(order_list[c],
1cdfb00
+                              LDAP_ACCESS_EXPIRE_POLICY_REJECT_NAME) == 0) {
1cdfb00
+            access_ctx->access_rule[c] = LDAP_ACCESS_EXPIRE_POLICY_REJECT;
1cdfb00
+        } else if (strcasecmp(order_list[c],
1cdfb00
+                              LDAP_ACCESS_EXPIRE_POLICY_WARN_NAME) == 0) {
1cdfb00
+            access_ctx->access_rule[c] = LDAP_ACCESS_EXPIRE_POLICY_WARN;
1cdfb00
+        } else if (strcasecmp(order_list[c],
1cdfb00
+                              LDAP_ACCESS_EXPIRE_POLICY_RENEW_NAME) == 0) {
1cdfb00
+            access_ctx->access_rule[c] = LDAP_ACCESS_EXPIRE_POLICY_RENEW;
1cdfb00
         } else {
1cdfb00
             DEBUG(SSSDBG_CRIT_FAILURE,
1cdfb00
                   "Unexpected access rule name [%s].\n", order_list[c]);
1cdfb00
diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
1cdfb00
index a6c882cae634f080b200fe75f51867e39192bcd9..dd2fb6b92bc83ee36fc396d26e3d0d7e78021d71 100644
1cdfb00
--- a/src/providers/ldap/sdap_access.c
1cdfb00
+++ b/src/providers/ldap/sdap_access.c
1cdfb00
@@ -39,10 +39,16 @@
1cdfb00
 #include "providers/ldap/sdap_async.h"
1cdfb00
 #include "providers/data_provider.h"
1cdfb00
 #include "providers/dp_backend.h"
1cdfb00
+#include "providers/ldap/ldap_auth.h"
1cdfb00
 
1cdfb00
 #define PERMANENTLY_LOCKED_ACCOUNT "000001010000Z"
1cdfb00
 #define MALFORMED_FILTER "Malformed access control filter [%s]\n"
1cdfb00
 
1cdfb00
+static errno_t perform_pwexpire_policy(TALLOC_CTX *mem_ctx,
1cdfb00
+                                       struct sss_domain_info *domain,
1cdfb00
+                                       struct pam_data *pd,
1cdfb00
+                                       struct sdap_options *opts);
1cdfb00
+
1cdfb00
 static errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain,
1cdfb00
                                          const char *username,
1cdfb00
                                          const char *attr_name,
1cdfb00
@@ -237,6 +243,30 @@ static errno_t sdap_access_check_next_rule(struct sdap_access_req_ctx *state,
1cdfb00
                                        state->pd, state->user_entry);
1cdfb00
             break;
1cdfb00
 
1cdfb00
+        case LDAP_ACCESS_EXPIRE_POLICY_REJECT:
1cdfb00
+            ret = perform_pwexpire_policy(state, state->domain, state->pd,
1cdfb00
+                                          state->access_ctx->id_ctx->opts);
1cdfb00
+            if (ret == ERR_PASSWORD_EXPIRED) {
1cdfb00
+                ret = ERR_PASSWORD_EXPIRED_REJECT;
1cdfb00
+            }
1cdfb00
+            break;
1cdfb00
+
1cdfb00
+        case LDAP_ACCESS_EXPIRE_POLICY_WARN:
1cdfb00
+            ret = perform_pwexpire_policy(state, state->domain, state->pd,
1cdfb00
+                                          state->access_ctx->id_ctx->opts);
1cdfb00
+            if (ret == ERR_PASSWORD_EXPIRED) {
1cdfb00
+                ret = ERR_PASSWORD_EXPIRED_WARN;
1cdfb00
+            }
1cdfb00
+            break;
1cdfb00
+
1cdfb00
+        case LDAP_ACCESS_EXPIRE_POLICY_RENEW:
1cdfb00
+            ret = perform_pwexpire_policy(state, state->domain, state->pd,
1cdfb00
+                                          state->access_ctx->id_ctx->opts);
1cdfb00
+            if (ret == ERR_PASSWORD_EXPIRED) {
1cdfb00
+                ret = ERR_PASSWORD_EXPIRED_RENEW;
1cdfb00
+            }
1cdfb00
+            break;
1cdfb00
+
1cdfb00
         case LDAP_ACCESS_SERVICE:
1cdfb00
             ret = sdap_access_service( state->pd, state->user_entry);
1cdfb00
             break;
1cdfb00
@@ -651,7 +681,6 @@ static errno_t sdap_account_expired_nds(struct pam_data *pd,
1cdfb00
     return EOK;
1cdfb00
 }
1cdfb00
 
1cdfb00
-
1cdfb00
 static errno_t sdap_account_expired(struct sdap_access_ctx *access_ctx,
1cdfb00
                                     struct pam_data *pd,
1cdfb00
                                     struct ldb_message *user_entry)
1cdfb00
@@ -702,6 +731,37 @@ static errno_t sdap_account_expired(struct sdap_access_ctx *access_ctx,
1cdfb00
     return ret;
1cdfb00
 }
1cdfb00
 
1cdfb00
+static errno_t perform_pwexpire_policy(TALLOC_CTX *mem_ctx,
1cdfb00
+                                       struct sss_domain_info *domain,
1cdfb00
+                                       struct pam_data *pd,
1cdfb00
+                                       struct sdap_options *opts)
1cdfb00
+{
1cdfb00
+    enum pwexpire pw_expire_type;
1cdfb00
+    void *pw_expire_data;
1cdfb00
+    errno_t ret;
1cdfb00
+    char *dn;
1cdfb00
+
1cdfb00
+    ret = get_user_dn(mem_ctx, domain, opts, pd->user, &dn, &pw_expire_type,
1cdfb00
+                      &pw_expire_data);
1cdfb00
+    if (ret != EOK) {
1cdfb00
+        DEBUG(SSSDBG_MINOR_FAILURE, "get_user_dn returned %d:[%s].\n",
1cdfb00
+              ret, sss_strerror(ret));
1cdfb00
+        goto done;
1cdfb00
+    }
1cdfb00
+
1cdfb00
+    ret = check_pwexpire_policy(pw_expire_type, pw_expire_data, pd,
1cdfb00
+                                domain->pwd_expiration_warning);
1cdfb00
+    if (ret != EOK) {
1cdfb00
+        DEBUG(SSSDBG_MINOR_FAILURE,
1cdfb00
+              "check_pwexpire_policy returned %d:[%s].\n",
1cdfb00
+              ret, sss_strerror(ret));
1cdfb00
+        goto done;
1cdfb00
+    }
1cdfb00
+
1cdfb00
+done:
1cdfb00
+    return ret;
1cdfb00
+}
1cdfb00
+
1cdfb00
 struct sdap_access_filter_req_ctx {
1cdfb00
     const char *username;
1cdfb00
     const char *filter;
1cdfb00
diff --git a/src/providers/ldap/sdap_access.h b/src/providers/ldap/sdap_access.h
1cdfb00
index f085e619961198b887d65ed5ee0bc5cdd90d1b20..a8c6639109bd7e6dcb325a5e8d080f743ec56d97 100644
1cdfb00
--- a/src/providers/ldap/sdap_access.h
1cdfb00
+++ b/src/providers/ldap/sdap_access.h
1cdfb00
@@ -39,6 +39,9 @@
1cdfb00
 
1cdfb00
 #define LDAP_ACCESS_FILTER_NAME "filter"
1cdfb00
 #define LDAP_ACCESS_EXPIRE_NAME "expire"
1cdfb00
+#define LDAP_ACCESS_EXPIRE_POLICY_REJECT_NAME "pwd_expire_policy_reject"
1cdfb00
+#define LDAP_ACCESS_EXPIRE_POLICY_WARN_NAME "pwd_expire_policy_warn"
1cdfb00
+#define LDAP_ACCESS_EXPIRE_POLICY_RENEW_NAME "pwd_expire_policy_renew"
1cdfb00
 #define LDAP_ACCESS_SERVICE_NAME "authorized_service"
1cdfb00
 #define LDAP_ACCESS_HOST_NAME "host"
1cdfb00
 #define LDAP_ACCESS_LOCK_NAME "lockout"
1cdfb00
@@ -57,6 +60,9 @@ enum ldap_access_rule {
1cdfb00
     LDAP_ACCESS_SERVICE,
1cdfb00
     LDAP_ACCESS_HOST,
1cdfb00
     LDAP_ACCESS_LOCKOUT,
1cdfb00
+    LDAP_ACCESS_EXPIRE_POLICY_REJECT,
1cdfb00
+    LDAP_ACCESS_EXPIRE_POLICY_WARN,
1cdfb00
+    LDAP_ACCESS_EXPIRE_POLICY_RENEW,
1cdfb00
     LDAP_ACCESS_LAST
1cdfb00
 };
1cdfb00
 
1cdfb00
diff --git a/src/util/util_errors.h b/src/util/util_errors.h
1cdfb00
index 39455dc8adfe8784bd3f06382d701b7f9e97f004..97e210e31dc6501860d1490966369a0d3ebe2cc2 100644
1cdfb00
--- a/src/util/util_errors.h
1cdfb00
+++ b/src/util/util_errors.h
1cdfb00
@@ -64,6 +64,9 @@ enum sssd_errors {
1cdfb00
     ERR_NETWORK_IO,
1cdfb00
     ERR_ACCOUNT_EXPIRED,
1cdfb00
     ERR_PASSWORD_EXPIRED,
1cdfb00
+    ERR_PASSWORD_EXPIRED_REJECT,
1cdfb00
+    ERR_PASSWORD_EXPIRED_WARN,
1cdfb00
+    ERR_PASSWORD_EXPIRED_RENEW,
1cdfb00
     ERR_ACCESS_DENIED,
1cdfb00
     ERR_SRV_NOT_FOUND,
1cdfb00
     ERR_SRV_LOOKUP_ERROR,
1cdfb00
-- 
1cdfb00
2.4.0
1cdfb00