summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/providers/ldap/ldap_auth.c71
1 files changed, 66 insertions, 5 deletions
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
index 231ae2e9..533db8e2 100644
--- a/src/providers/ldap/ldap_auth.c
+++ b/src/providers/ldap/ldap_auth.c
@@ -46,6 +46,12 @@
#include "providers/ldap/ldap_common.h"
#include "providers/ldap/sdap_async.h"
+/* MIT Kerberos has the same hardcoded warning interval of 7 days. Due to the
+ * fact that using the expiration time of a Kerberos password with LDAP
+ * authentication is presumably a rare case a separate config option is not
+ * necessary. */
+#define KERBEROS_PWEXPIRE_WARNING_TIME (7 * 24 * 60 * 60)
+
enum pwexpire {
PWEXPIRE_NONE = 0,
PWEXPIRE_LDAP_PASSWORD_POLICY,
@@ -53,12 +59,42 @@ enum pwexpire {
PWEXPIRE_SHADOW
};
+static errno_t add_expired_warning(struct pam_data *pd, long exp_time)
+{
+ int ret;
+ uint32_t *data;
+
+ if (exp_time < 0 || exp_time > UINT32_MAX) {
+ DEBUG(1, ("Time to expire out of range.\n"));
+ return EINVAL;
+ }
+
+ data = talloc_array(pd, uint32_t, 2);
+ if (data == NULL) {
+ DEBUG(1, ("talloc_size failed.\n"));
+ return ENOMEM;
+ }
+
+ data[0] = SSS_PAM_USER_INFO_EXPIRE_WARN;
+ data[1] = (uint32_t) exp_time;
+
+ ret = pam_add_response(pd, SSS_PAM_USER_INFO, 2 * sizeof(uint32_t),
+ (uint8_t *) data);
+ if (ret != EOK) {
+ DEBUG(1, ("pam_add_response failed.\n"));
+ }
+
+ return EOK;
+}
+
static errno_t check_pwexpire_kerberos(const char *expire_date, time_t now,
+ struct pam_data *pd,
enum sdap_result *result)
{
char *end;
struct tm tm;
time_t expire_time;
+ int ret;
memset(&tm, 0, sizeof(tm));
@@ -92,16 +128,27 @@ static errno_t check_pwexpire_kerberos(const char *expire_date, time_t now,
*result = SDAP_AUTH_PW_EXPIRED;
} else {
*result = SDAP_AUTH_SUCCESS;
+
+ if (pd != NULL &&
+ difftime(now + KERBEROS_PWEXPIRE_WARNING_TIME, expire_time) > 0.0) {
+ ret = add_expired_warning(pd, (long) difftime(expire_time, now));
+ if (ret != EOK) {
+ DEBUG(1, ("add_expired_warning failed.\n"));
+ }
+ }
}
return EOK;
}
static errno_t check_pwexpire_shadow(struct spwd *spwd, time_t now,
+ struct pam_data *pd,
enum sdap_result *result)
{
long today;
long password_age;
+ long exp;
+ int ret;
if (spwd->sp_lstchg <= 0) {
DEBUG(4, ("Last change day is not set, new password needed.\n"));
@@ -132,7 +179,21 @@ static errno_t check_pwexpire_shadow(struct spwd *spwd, time_t now,
return EOK;
}
-/* TODO: evaluate spwd->min and spwd->warn */
+ if (pd != NULL && spwd->sp_max != -1 && spwd->sp_warn != -1 &&
+ password_age > spwd->sp_max - spwd->sp_warn ) {
+
+ /* add_expired_warning() expects time in seconds */
+ exp = (spwd->sp_max - password_age) * (60 * 60 * 24);
+ if (exp == 0) {
+ /* Seconds until next midnight */
+ exp = ((today + 1) * (60 * 60 * 24)) - now;
+ }
+
+ ret = add_expired_warning(pd, exp);
+ if (ret != EOK) {
+ DEBUG(1, ("add_expired_warning failed.\n"));
+ }
+ }
*result = SDAP_AUTH_SUCCESS;
return EOK;
@@ -745,7 +806,7 @@ static void sdap_auth4chpass_done(struct tevent_req *req)
if (result == SDAP_AUTH_SUCCESS) {
switch (pw_expire_type) {
case PWEXPIRE_SHADOW:
- ret = check_pwexpire_shadow(pw_expire_data, time(NULL),
+ ret = check_pwexpire_shadow(pw_expire_data, time(NULL), NULL,
&result);
if (ret != EOK) {
DEBUG(1, ("check_pwexpire_shadow failed.\n"));
@@ -754,7 +815,7 @@ static void sdap_auth4chpass_done(struct tevent_req *req)
}
break;
case PWEXPIRE_KERBEROS:
- ret = check_pwexpire_kerberos(pw_expire_data, time(NULL),
+ ret = check_pwexpire_kerberos(pw_expire_data, time(NULL), NULL,
&result);
if (ret != EOK) {
DEBUG(1, ("check_pwexpire_kerberos failed.\n"));
@@ -954,7 +1015,7 @@ static void sdap_pam_auth_done(struct tevent_req *req)
switch (pw_expire_type) {
case PWEXPIRE_SHADOW:
ret = check_pwexpire_shadow(pw_expire_data, time(NULL),
- &result);
+ state->pd, &result);
if (ret != EOK) {
DEBUG(1, ("check_pwexpire_shadow failed.\n"));
state->pd->pam_status = PAM_SYSTEM_ERR;
@@ -963,7 +1024,7 @@ static void sdap_pam_auth_done(struct tevent_req *req)
break;
case PWEXPIRE_KERBEROS:
ret = check_pwexpire_kerberos(pw_expire_data, time(NULL),
- &result);
+ state->pd, &result);
if (ret != EOK) {
DEBUG(1, ("check_pwexpire_kerberos failed.\n"));
state->pd->pam_status = PAM_SYSTEM_ERR;