From ed42a853c838cd4cb66516d5d280c8b603e4198d Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Tue, 21 Dec 2010 13:30:33 +0100 Subject: [PATCH 1/2] Add LDAP expire policy based on AD attributes The second bit of userAccountControl is used to determine if the account is enabled or disabled. accountExpires is checked to see if the account is expired. --- src/config/SSSDConfig.py | 2 + src/config/etc/sssd.api.d/sssd-ldap.conf | 2 + src/man/sssd-ldap.5.xml | 35 ++++++++++++ src/providers/ipa/ipa_common.c | 4 +- src/providers/ldap/ldap_common.c | 8 ++- src/providers/ldap/ldap_init.c | 3 +- src/providers/ldap/sdap.h | 5 ++ src/providers/ldap/sdap_access.c | 85 ++++++++++++++++++++++++++++++ src/providers/ldap/sdap_access.h | 1 + 9 files changed, 141 insertions(+), 4 deletions(-) diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py index b3861a5..d84509c 100644 --- a/src/config/SSSDConfig.py +++ b/src/config/SSSDConfig.py @@ -172,6 +172,8 @@ option_strings = { 'ldap_user_krb_last_pwd_change' : _('krbLastPwdChange attribute'), 'ldap_user_krb_password_expiration' : _('krbPasswordExpiration attribute'), 'ldap_pwd_attribute' : _('Attribute indicating that server side password policies are active'), + 'ldap_user_ad_account_expires' : _('accountExpires attribute of AD'), + 'ldap_user_ad_user_account_control' : _('userAccountControl attribute of AD'), 'ldap_group_search_base' : _('Base DN for group lookups'), # not used # 'ldap_group_search_scope' : _('Scope of group lookups'), diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf index 8aaecd5..0644383 100644 --- a/src/config/etc/sssd.api.d/sssd-ldap.conf +++ b/src/config/etc/sssd.api.d/sssd-ldap.conf @@ -58,6 +58,8 @@ ldap_user_krb_last_pwd_change = str, None, false ldap_user_krb_password_expiration = str, None, false ldap_user_authorized_service = str, None, false ldap_pwd_attribute = str, None, false +ldap_user_ad_account_expires = str, None, false +ldap_user_ad_user_account_control = str, None, false ldap_group_search_base = str, None, false ldap_group_search_scope = str, None, false ldap_group_search_filter = str, None, false diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml index 175ec35..65c679d 100644 --- a/src/man/sssd-ldap.5.xml +++ b/src/man/sssd-ldap.5.xml @@ -436,6 +436,34 @@ + ldap_user_ad_account_expires (string) + + + When using ldap_account_expire_policy=ad, this + parameter contains the name of an LDAP attribute + storing the expiration time of the account. + + + Default: accountExpires + + + + + + ldap_user_ad_user_account_control (string) + + + When using ldap_account_expire_policy=ad, this + parameter contains the name of an LDAP attribute + storing the user account control bit field. + + + Default: userAccountControl + + + + + ldap_user_principal (string) @@ -1128,6 +1156,13 @@ ldap_access_filter = memberOf=cn=allowedusers,ou=Groups,dc=example,dc=com is expired. + ad: use the value of the 32bit + field ldap_user_ad_user_account_control and allow + access if the second bit is not set. If the + attribute is missing access is granted. Also the + expiration time of the account is checked. + + Default: Empty diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c index 4c96bab..fe12577 100644 --- a/src/providers/ipa/ipa_common.c +++ b/src/providers/ipa/ipa_common.c @@ -115,7 +115,9 @@ struct sdap_attr_map ipa_user_map[] = { { "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 }, - { "ldap_user_authorized_service", "authorizedService", SYSDB_AUTHORIZED_SERVICE, NULL } + { "ldap_user_authorized_service", "authorizedService", SYSDB_AUTHORIZED_SERVICE, NULL }, + { "ldap_user_ad_account_expires", "accountExpires", SYSDB_AD_ACCOUNT_EXPIRES, NULL}, + { "ldap_user_ad_user_account_control", "userAccountControl", SYSDB_AD_USER_ACCOUNT_CONTROL, NULL} }; struct sdap_attr_map ipa_group_map[] = { diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c index 6daf2c9..e98e718 100644 --- a/src/providers/ldap/ldap_common.c +++ b/src/providers/ldap/ldap_common.c @@ -121,7 +121,9 @@ struct sdap_attr_map rfc2307_user_map[] = { { "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 }, - { "ldap_user_authorized_service", "authorizedService", SYSDB_AUTHORIZED_SERVICE, NULL } + { "ldap_user_authorized_service", "authorizedService", SYSDB_AUTHORIZED_SERVICE, NULL }, + { "ldap_user_ad_account_expires", "accountExpires", SYSDB_AD_ACCOUNT_EXPIRES, NULL}, + { "ldap_user_ad_user_account_control", "userAccountControl", SYSDB_AD_USER_ACCOUNT_CONTROL, NULL} }; struct sdap_attr_map rfc2307_group_map[] = { @@ -161,7 +163,9 @@ struct sdap_attr_map rfc2307bis_user_map[] = { { "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 }, - { "ldap_user_authorized_service", "authorizedService", SYSDB_AUTHORIZED_SERVICE, NULL } + { "ldap_user_authorized_service", "authorizedService", SYSDB_AUTHORIZED_SERVICE, NULL }, + { "ldap_user_ad_account_expires", "accountExpires", SYSDB_AD_ACCOUNT_EXPIRES, NULL}, + { "ldap_user_ad_user_account_control", "userAccountControl", SYSDB_AD_USER_ACCOUNT_CONTROL, NULL} }; struct sdap_attr_map rfc2307bis_group_map[] = { diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c index d5dad36..61f9233 100644 --- a/src/providers/ldap/ldap_init.c +++ b/src/providers/ldap/ldap_init.c @@ -345,7 +345,8 @@ int sssm_ldap_access_init(struct be_ctx *bectx, "but no ldap_account_expire_policy configured. " "All domain users will be denied access.\n")); } else { - if (strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_SHADOW) != 0) { + if (strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_SHADOW) != 0 && + strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_AD) != 0) { DEBUG(1, ("Unsupported LDAP account expire policy [%s].\n", dummy)); ret = EINVAL; diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h index 9ef9b70..57f849a 100644 --- a/src/providers/ldap/sdap.h +++ b/src/providers/ldap/sdap.h @@ -127,6 +127,9 @@ struct sdap_ppolicy_data { #define SYSDB_PWD_ATTRIBUTE "pwdAttribute" +#define SYSDB_AD_ACCOUNT_EXPIRES "adAccountExpires" +#define SYSDB_AD_USER_ACCOUNT_CONTROL "adUserAccountControl" + #define SDAP_ROOTDSE_ATTR_NAMING_CONTEXTS "namingContexts" #define SDAP_ROOTDSE_ATTR_DEFAULT_NAMING_CONTEXT "defaultNamingContext" @@ -231,6 +234,8 @@ enum sdap_user_attrs { SDAP_AT_KP_EXPIRATION, SDAP_AT_PWD_ATTRIBUTE, SDAP_AT_AUTH_SVC, + SDAP_AT_AD_ACCOUNT_EXPIRES, + SDAP_AT_AD_USER_ACCOUNT_CONTROL, SDAP_OPTS_USER /* attrs counter */ }; diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c index df433b6..a3c560d 100644 --- a/src/providers/ldap/sdap_access.c +++ b/src/providers/ldap/sdap_access.c @@ -340,6 +340,84 @@ static errno_t sdap_account_expired_shadow(struct pam_data *pd, return EOK; } +#define UAC_ACCOUNTDISABLE 0x00000002 +#define AD_NEVER_EXP 0x7fffffffffffffffLL +#define AD_TO_UNIX_TIME_CONST 11644473600LL +#define AD_DISABLE_MESSAGE "The user account is disabled on the AD server" +#define AD_EXPIRED_MESSAGE "The user account is expired on the AD server" + +static bool ad_account_expired(uint64_t expiration_time) +{ + time_t now; + int err; + uint64_t nt_now; + + if (expiration_time == 0 || expiration_time == AD_NEVER_EXP) { + return false; + } + + now = time(NULL); + if (now == ((time_t) -1)) { + err = errno; + DEBUG(1, ("time failed [%d][%s].\n", err, strerror(err))); + return true; + } + + /* NT timestamps start at 1601-01-01 and use a 100ns base */ + nt_now = (now + AD_TO_UNIX_TIME_CONST) * 1000 * 1000 * 10; + + if (nt_now > expiration_time) { + return true; + } + + return false; +} + +static errno_t sdap_account_expired_ad(struct pam_data *pd, + struct ldb_message *user_entry, + int *pam_status) +{ + uint32_t uac; + uint64_t expiration_time; + int ret; + + DEBUG(6, ("Performing AD access check for user [%s]\n", pd->user)); + + uac = ldb_msg_find_attr_as_uint(user_entry, SYSDB_AD_USER_ACCOUNT_CONTROL, + 0); + DEBUG(9, ("User account control for user [%s] is [%X].\n", + pd->user, uac)); + + expiration_time = ldb_msg_find_attr_as_uint64(user_entry, + SYSDB_AD_ACCOUNT_EXPIRES, 0); + DEBUG(9, ("Expiration time for user [%s] is [%lld].\n", + pd->user, expiration_time)); + + if (uac & UAC_ACCOUNTDISABLE) { + *pam_status = PAM_PERM_DENIED; + + ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO, + sizeof(AD_DISABLE_MESSAGE), + (const uint8_t *) AD_DISABLE_MESSAGE); + if (ret != EOK) { + DEBUG(1, ("pam_add_response failed.\n")); + } + } else if (ad_account_expired(expiration_time)) { + *pam_status = PAM_ACCT_EXPIRED; + + ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO, + sizeof(AD_EXPIRED_MESSAGE), + (const uint8_t *) AD_EXPIRED_MESSAGE); + if (ret != EOK) { + DEBUG(1, ("pam_add_response failed.\n")); + } + } else { + *pam_status = PAM_SUCCESS; + } + + return EOK; +} + struct sdap_account_expired_req_ctx { int pam_status; }; @@ -379,6 +457,13 @@ static struct tevent_req *sdap_account_expired_send(TALLOC_CTX *mem_ctx, DEBUG(1, ("sdap_account_expired_shadow failed.\n")); goto done; } + } else if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_AD) == 0) { + ret = sdap_account_expired_ad(pd, user_entry, + &state->pam_status); + if (ret != EOK) { + DEBUG(1, ("sdap_account_expired_ad failed.\n")); + goto done; + } } else { DEBUG(1, ("Unsupported LDAP account expire policy [%s]. " "Access denied.\n", expire)); diff --git a/src/providers/ldap/sdap_access.h b/src/providers/ldap/sdap_access.h index 66193a6..28c857f 100644 --- a/src/providers/ldap/sdap_access.h +++ b/src/providers/ldap/sdap_access.h @@ -34,6 +34,7 @@ #define LDAP_ACCESS_SERVICE_NAME "authorized_service" #define LDAP_ACCOUNT_EXPIRE_SHADOW "shadow" +#define LDAP_ACCOUNT_EXPIRE_AD "ad" enum ldap_access_rule { LDAP_ACCESS_EMPTY = -1, -- 1.7.3.3