Documented on
http://msdn.microsoft.com/en-us/library/cc220785(v=prot.10).aspx
Introduced in nss_ldap 208:
* add support for native Active Directory password
policy attributes (enabled if shadowLastChange is
mapped to pwdLastSet)
---
Sorry, I managed to break the previous E-mail.
This patch is provided as a quick hack, as I just thought this feature could be
interesting in sssd.
Probably not really useful as we currently require all shadow attributes to be present in
ldap_auth.c
anyway, but if we're fine allowing partial shadow entries, I'm happy to write the
associated patch.
A few technical details are available on
https://bugzilla.redhat.com/show_bug.cgi?id=694311
(related to nss_ldap).
src/config/SSSDConfig.py | 1 +
src/config/etc/sssd.api.d/sssd-ldap.conf | 1 +
src/man/sssd-ldap.5.xml | 15 ++++++++++
src/providers/ldap/ldap_auth.c | 9 +++++-
src/providers/ldap/ldap_common.c | 43 ++++++++++++++++++++++++++++++
src/providers/ldap/ldap_common.h | 1 +
src/providers/ldap/sdap.h | 1 +
7 files changed, 70 insertions(+), 1 deletions(-)
diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py
index 5135174..992e1f4 100644
--- a/src/config/SSSDConfig.py
+++ b/src/config/SSSDConfig.py
@@ -167,6 +167,7 @@ option_strings = {
'ldap_user_modify_timestamp' : _('Modification time attribute'),
#replaced by ldap_entry_usn# 'ldap_user_entry_usn' : _('entryUSN
attribute'),
'ldap_user_shadow_last_change' : _('shadowLastChange attribute'),
+ 'ldap_user_ads_last_change' : _('pwdLastSet attribute'),
'ldap_user_shadow_min' : _('shadowMin attribute'),
'ldap_user_shadow_max' : _('shadowMax attribute'),
'ldap_user_shadow_warning' : _('shadowWarning attribute'),
diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf
b/src/config/etc/sssd.api.d/sssd-ldap.conf
index 5fd0cfb..6700df9 100644
--- a/src/config/etc/sssd.api.d/sssd-ldap.conf
+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
@@ -51,6 +51,7 @@ ldap_user_member_of = str, None, false
ldap_user_modify_timestamp = str, None, false
ldap_user_entry_usn = str, None, false
ldap_user_shadow_last_change = str, None, false
+ldap_user_ads_last_change = str, None, false
ldap_user_shadow_min = str, None, false
ldap_user_shadow_max = str, None, false
ldap_user_shadow_warning = str, None, false
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index 2a39732..0db3ce7 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -313,6 +313,21 @@
</varlistentry>
<varlistentry>
+ <term>ldap_user_ads_last_change (string)</term>
+ <listitem>
+ <para>
+ When using ldap_pwd_policy=shadow, this parameter
+ contains the name of an LDAP attribute corresponding
+ to pwdLastSet in Active Directory server, fell back to
+ when ldap_user_shadow_last_change was not available.
+ </para>
+ <para>
+ Default: pwdLastSet
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>ldap_user_shadow_min (string)</term>
<listitem>
<para>
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
index e45d5b3..4aad59b 100644
--- a/src/providers/ldap/ldap_auth.c
+++ b/src/providers/ldap/ldap_auth.c
@@ -286,7 +286,8 @@ static errno_t find_password_expiration_attributes(TALLOC_CTX
*mem_ctx,
return EINVAL;
}
} else if (strcasecmp(pwd_policy, PWD_POL_OPT_SHADOW) == 0) {
- mark = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_LASTCHANGE, NULL);
+ mark = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_LASTCHANGE, NULL) ||
+ ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_ADS_LASTCHANGE, NULL);
if (mark != NULL) {
DEBUG(9, ("Found shadow password expiration attributes.\n"))
spwd = talloc_zero(mem_ctx, struct spwd);
@@ -297,6 +298,12 @@ static errno_t find_password_expiration_attributes(TALLOC_CTX
*mem_ctx,
val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_LASTCHANGE, NULL);
ret = string_to_shadowpw_days(val, &spwd->sp_lstchg);
+
+ /* Fallback to pwdLastSet for ADS */
+ if (ret != EOK) {
+ val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_ADS_LASTCHANGE,
NULL);
+ ret = ads_pwdlastset_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);
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 9eb9cc3..22c9bb7 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -163,6 +163,7 @@ struct sdap_attr_map rfc2307bis_user_map[] = {
{ "ldap_user_modify_timestamp", "modifyTimestamp",
SYSDB_ORIG_MODSTAMP, NULL },
{ "ldap_user_entry_usn", NULL, SYSDB_USN, NULL },
{ "ldap_user_shadow_last_change", "shadowLastChange",
SYSDB_SHADOWPW_LASTCHANGE, NULL },
+ { "ldap_user_ads_last_change", "pwdLastSet",
SYSDB_SHADOWPW_ADS_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 },
@@ -878,6 +879,48 @@ errno_t string_to_shadowpw_days(const char *s, long *d)
return EOK;
}
+errno_t ads_pwdlastset_to_shadowpw_days(const char *s, long *d)
+{
+ long long ll;
+ long days;
+ char *endptr;
+
+ if (s == NULL || *s == '\0') {
+ *d = -1;
+ return EOK;
+ }
+
+ errno = 0;
+ ll = strtoll(s, &endptr, 10);
+ if (errno != 0) {
+ DEBUG(1, ("strtoll failed [%d][%s].\n", errno, strerror(errno)));
+ return errno;
+ }
+
+ if (*endptr != '\0') {
+ DEBUG(1, ("Input string [%s] is invalid.\n", s));
+ return EINVAL;
+ }
+
+ /* Magic value for password reset */
+ if (ll = 0LL) {
+ DEBUG(9, ("Magic pwdLastSet date 0, password change forced.\n"));
+ *d = 0L;
+ return EOK;
+ }
+
+ days = ll / 864000000000LL - 134774LL;
+
+ if (days < 0L) {
+ DEBUG(1, ("Date is before Jan 1, 1970 [%d].\n", ll));
+ return EINVAL;
+ }
+
+ *d = days;
+
+ return EOK;
+}
+
errno_t get_sysdb_attr_name(TALLOC_CTX *mem_ctx,
struct sdap_attr_map *map,
size_t map_size,
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index 9146da5..cf301de 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -146,6 +146,7 @@ int setup_child(struct sdap_id_ctx *ctx);
errno_t string_to_shadowpw_days(const char *s, long *d);
+errno_t ads_pwdlastset_to_shadowpw_days(const char *s, long *d);
errno_t get_sysdb_attr_name(TALLOC_CTX *mem_ctx,
struct sdap_attr_map *map,
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 32dc344..fdd5b7a 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -115,6 +115,7 @@ struct sdap_ppolicy_data {
};
#define SYSDB_SHADOWPW_LASTCHANGE "shadowLastChange"
+#define SYSDB_SHADOWPW_ADS_LASTCHANGE "pwdLastSet"
#define SYSDB_SHADOWPW_MIN "shadowMin"
#define SYSDB_SHADOWPW_MAX "shadowMax"
#define SYSDB_SHADOWPW_WARNING "shadowWarning"
--
1.7.4.4