diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c index f520be2b5..c5ea60dba 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c @@ -322,7 +322,9 @@ int ipapwd_getPolicy(const char *dn, Slapi_PBlock *pb = NULL; char *attrs[] = { "krbMaxPwdLife", "krbMinPwdLife", "krbPwdMinDiffChars", "krbPwdMinLength", - "krbPwdHistoryLength", NULL}; + "krbPwdHistoryLength", "ipaPwdMaxRepeat", + "ipaPwdMaxSequence", "ipaPwdDictCheck", + "ipaPwdUserCheck", NULL}; Slapi_Entry **es = NULL; Slapi_Entry *pe = NULL; int ret, res, scope, i; @@ -402,6 +404,10 @@ int ipapwd_getPolicy(const char *dn, policy->min_complexity = slapi_entry_attr_get_int(pe, "krbPwdMinDiffChars"); + policy->max_repeat = slapi_entry_attr_get_int(pe, "ipaPwdMaxRepeat"); + policy->max_sequence = slapi_entry_attr_get_int(pe, "ipaPwdMaxSequence"); + policy->dictcheck = slapi_entry_attr_get_bool(pe, "ipaPwdDictCheck"); + policy->usercheck = slapi_entry_attr_get_bool(pe, "ipaPwdUserCheck"); ret = 0; @@ -576,6 +582,7 @@ int ipapwd_CheckPolicy(struct ipapwd_data *data) time_t pwd_expiration; time_t last_pwd_change; char **pwd_history; + char *uid; char *tmpstr; int ret; @@ -641,9 +648,11 @@ int ipapwd_CheckPolicy(struct ipapwd_data *data) pwd_history = slapi_entry_attr_get_charray(data->target, "passwordHistory"); + uid = slapi_entry_attr_get_charptr(data->target, "uid"); /* check policy */ ret = ipapwd_check_policy(&pol, data->password, + uid, data->timeNow, acct_expiration, pwd_expiration, @@ -651,6 +660,7 @@ int ipapwd_CheckPolicy(struct ipapwd_data *data) pwd_history); slapi_ch_array_free(pwd_history); + slapi_ch_free_string(&uid); if (data->expireTime == 0) { if (pol.max_pwd_life > 0) { diff --git a/util/ipa_pwd.c b/util/ipa_pwd.c index 0d3c351c2..dbff5ef1c 100644 --- a/util/ipa_pwd.c +++ b/util/ipa_pwd.c @@ -28,8 +28,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -406,6 +408,7 @@ cleanup: */ int ipapwd_check_policy(struct ipapwd_policy *policy, char *password, + char *user, time_t cur_time, time_t acct_expiration, time_t pwd_expiration, @@ -414,6 +417,11 @@ int ipapwd_check_policy(struct ipapwd_policy *policy, { int pwdlen, blen; int ret; + pwquality_settings_t *pwq; + int check_pwquality = 0; + int entropy; + char buf[PWQ_MAX_ERROR_MESSAGE_LEN]; + void *auxerror; if (!policy || !password) { return IPAPWD_POLICY_ERROR; @@ -462,7 +470,7 @@ int ipapwd_check_policy(struct ipapwd_policy *policy, char *p, *n; int size, len; - /* we want the actual lenght in bytes here */ + /* we want the actual length in bytes here */ len = blen; p = password; @@ -526,6 +534,74 @@ int ipapwd_check_policy(struct ipapwd_policy *policy, } } + /* Only call into libpwquality if at least one setting is made + * because there are a number of checks that don't have knobs + * so preserve the previous behavior. + */ + check_pwquality = policy->max_repeat + policy->max_sequence + policy->dictcheck + policy->usercheck; + + if (check_pwquality > 0) { + /* Call libpwquality */ + openlog(NULL, LOG_CONS | LOG_NDELAY, LOG_DAEMON); + pwq = pwquality_default_settings(); + if (pwq == NULL) { + syslog(LOG_ERR, "Not able to set pwquality defaults\n"); + return IPAPWD_POLICY_ERROR; + } + if (policy->min_pwd_length < 6) + syslog(LOG_WARNING, "password policy min length is < 6. Will be enforced as 6\n"); + pwquality_set_int_value(pwq, PWQ_SETTING_MIN_LENGTH, policy->min_pwd_length); + pwquality_set_int_value(pwq, PWQ_SETTING_MAX_REPEAT, policy->max_repeat); + pwquality_set_int_value(pwq, PWQ_SETTING_MAX_SEQUENCE, policy->max_sequence); + pwquality_set_int_value(pwq, PWQ_SETTING_DICT_CHECK, policy->dictcheck); + pwquality_set_int_value(pwq, PWQ_SETTING_USER_CHECK, policy->usercheck); + + entropy = pwquality_check(pwq, password, NULL, user, &auxerror); + pwquality_free_settings(pwq); + +#ifdef TEST + if (user != NULL) { + fprintf(stderr, "Checking password for %s\n", user); + } else { + fprintf(stderr, "No user provided\n"); + } + + fprintf(stderr, "min length %d\n", policy->min_pwd_length); + fprintf(stderr, "max repeat %d\n", policy->max_repeat); + fprintf(stderr, "max sequence %d\n", policy->max_sequence); + fprintf(stderr, "dict check %d\n", policy->dictcheck); + fprintf(stderr, "user check %d\n", policy->usercheck); +#endif + + if (entropy < 0) { +#ifdef TEST + fprintf(stderr, "Bad password '%s': %s\n", password, pwquality_strerror(buf, sizeof(buf), entropy, auxerror)); +#endif + syslog(LOG_ERR, "Password is rejected with error %d: %s\n", entropy, pwquality_strerror(buf, sizeof(buf), entropy, auxerror)); + switch (entropy) { + case PWQ_ERROR_MIN_LENGTH: + return IPAPWD_POLICY_PWD_TOO_SHORT; + case PWQ_ERROR_PALINDROME: + return IPAPWD_POLICY_PWD_PALINDROME; + case PWQ_ERROR_MAX_CONSECUTIVE: + return IPAPWD_POLICY_PWD_CONSECUTIVE; + case PWQ_ERROR_MAX_SEQUENCE: + return IPAPWD_POLICY_PWD_SEQUENCE; + case PWQ_ERROR_CRACKLIB_CHECK: + return IPAPWD_POLICY_PWD_DICT_WORD; + case PWQ_ERROR_USER_CHECK: + return IPAPWD_POLICY_PWD_USER; + default: + return IPAPWD_POLICY_PWD_COMPLEXITY; + } + +#ifdef TEST + } else { + fprintf(stderr, "Password '%s' is ok, entropy is %d\n", password, entropy); +#endif + } + } + if (pwd_history) { char *hash; int i; @@ -549,13 +625,18 @@ char * IPAPWD_ERROR_STRINGS[] = { "Too soon to change password", "Password is too short", "Password reuse not permitted", - "Password is too simple" + "Password is too simple", + "Password has too many consecutive characters", + "Password contains a monotonic sequence", + "Password is based on a dictionary word", + "Password is a palindrone", + "Password contains username" }; char * IPAPWD_ERROR_STRING_GENERAL = "Password does not meet the policy requirements"; char * ipapwd_error2string(enum ipapwd_error err) { - if (err < 0 || err > IPAPWD_POLICY_PWD_COMPLEXITY) { + if (err < 0 || err > IPAPWD_POLICY_PWD_USER) { /* IPAPWD_POLICY_ERROR or out of boundary, return general error */ return IPAPWD_ERROR_STRING_GENERAL; } diff --git a/util/ipa_pwd.h b/util/ipa_pwd.h index afe4fdf3e..b3bb2be6e 100644 --- a/util/ipa_pwd.h +++ b/util/ipa_pwd.h @@ -44,7 +44,12 @@ enum ipapwd_error { IPAPWD_POLICY_PWD_TOO_YOUNG = 2, IPAPWD_POLICY_PWD_TOO_SHORT = 3, IPAPWD_POLICY_PWD_IN_HISTORY = 4, - IPAPWD_POLICY_PWD_COMPLEXITY = 5 + IPAPWD_POLICY_PWD_COMPLEXITY = 5, + IPAPWD_POLICY_PWD_CONSECUTIVE = 6, + IPAPWD_POLICY_PWD_SEQUENCE = 7, + IPAPWD_POLICY_PWD_DICT_WORD = 8, + IPAPWD_POLICY_PWD_PALINDROME = 9, + IPAPWD_POLICY_PWD_USER = 10 }; struct ipapwd_policy { @@ -56,6 +61,11 @@ struct ipapwd_policy { int max_fail; int failcnt_interval; int lockout_duration; + int max_repeat; + int max_sequence; + int max_classrepeat; + int dictcheck; + int usercheck; }; time_t ipapwd_gentime_to_time_t(char *timestr); @@ -68,6 +78,7 @@ int ipapwd_hash_password(char *password, int ipapwd_check_policy(struct ipapwd_policy *policy, char *password, + char *user, time_t cur_time, time_t acct_expiration, time_t pwd_expiration,