mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Extend password policy to evaluate passwords using libpwpolicy
Enable checking: maxrepeat - reject passwrods which contain more than N consecutive characters. maxsequence - rejected passwords which contain character sequences (abcde). dictcheck - check passwords using cracklib usercheck - check whether the password contains the user name. The class checking provided by libpwpolicy is not used because this overlaps with the existing IPA checking. This includes the options dcredit, ucredit, lcredit, ocredit, minclass and maxclassrepeat. The pwquality min length is fixed at 6 so if there is a conflict between the system policy and pwquality log that length is enforced at 6. https://pagure.io/freeipa/issue/6964 https://pagure.io/freeipa/issue/5948 https://pagure.io/freeipa/issue/2445 https://pagure.io/freeipa/issue/298 Signed-off-by: Rob Crittenden <rcritten@redhat.com> Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> Reviewed-By: Christian Heimes <cheimes@redhat.com>
This commit is contained in:
parent
3fc2eda4e1
commit
c4cca53e88
@ -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) {
|
||||
|
@ -28,8 +28,10 @@
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <pwquality.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user