diff options
author | Tomas Mraz <tm@t8m.info> | 2008-09-19 13:38:32 +0000 |
---|---|---|
committer | Tomas Mraz <tm@t8m.info> | 2008-09-19 13:38:32 +0000 |
commit | e15dee8abc38058cae9259a3aa3b625ea8febbfd (patch) | |
tree | 8377c78395629744b73b455364618444f0f1b88c /modules | |
parent | 742a6386465fb4290c3a5f86505f9a3e5e48fad3 (diff) | |
download | pam-e15dee8abc38058cae9259a3aa3b625ea8febbfd.tar.gz pam-e15dee8abc38058cae9259a3aa3b625ea8febbfd.tar.bz2 pam-e15dee8abc38058cae9259a3aa3b625ea8febbfd.zip |
Relevant BUGIDs:
Purpose of commit: new feature
Commit summary:
---------------
2008-09-19 Tomas Mraz <t8m@centrum.cz>
* modules/pam_cracklib/pam_cracklib.8.xml: Fix description
of the palindrome test. Document new options maxrepeat and
reject_username.
* modules/pam_cracklib/pam_cracklib.c(_pam_parse): Parse
the maxrepeat and reject_username options.
(password_check): Call the new tests usercheck() and
consecutive().
(_pam_unix_approve_pass): Pass user name to the password_check().
Diffstat (limited to 'modules')
-rw-r--r-- | modules/pam_cracklib/pam_cracklib.8.xml | 45 | ||||
-rw-r--r-- | modules/pam_cracklib/pam_cracklib.c | 90 |
2 files changed, 124 insertions, 11 deletions
diff --git a/modules/pam_cracklib/pam_cracklib.8.xml b/modules/pam_cracklib/pam_cracklib.8.xml index 19b74d27..3d061c43 100644 --- a/modules/pam_cracklib/pam_cracklib.8.xml +++ b/modules/pam_cracklib/pam_cracklib.8.xml @@ -59,7 +59,7 @@ <term>Palindrome</term> <listitem> <para> - Is the new password a palindrome of the old one? + Is the new password a palindrome? </para> </listitem> </varlistentry> @@ -120,6 +120,23 @@ </para> </listitem> </varlistentry> + <varlistentry> + <term>Same consecutive characters</term> + <listitem> + <para> + Optional check for same consecutive characters. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>Contains user name</term> + <listitem> + <para> + Optional check whether the password contains the user's name + in some form. + </para> + </listitem> + </varlistentry> </variablelist> <para> This module with no arguments will work well for standard unix @@ -349,6 +366,32 @@ <varlistentry> <term> + <option>maxrepeat=<replaceable>N</replaceable></option> + </term> + <listitem> + <para> + Reject passwords which contain more than N same consecutive + characters. The default is 0 which means that this check + is disabled. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <option>reject_username</option> + </term> + <listitem> + <para> + Check whether the name of the user in straight or reversed + form is contained in the new password. If it is found the + new password is rejected. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> <option>use_authtok</option> </term> <listitem> diff --git a/modules/pam_cracklib/pam_cracklib.c b/modules/pam_cracklib/pam_cracklib.c index 12cbcf3c..3dcc4729 100644 --- a/modules/pam_cracklib/pam_cracklib.c +++ b/modules/pam_cracklib/pam_cracklib.c @@ -99,6 +99,8 @@ struct cracklib_options { int min_class; int use_authtok; int try_first_pass; + int max_repeat; + int reject_user; char prompt_type[BUFSIZ]; const char *cracklib_dictpath; }; @@ -166,8 +168,14 @@ _pam_parse (pam_handle_t *pamh, struct cracklib_options *opt, opt->min_class = strtol(*argv+9,&ep,10); if (!ep) opt->min_class = 0; - if (opt->min_class > 4) - opt->min_class = 4 ; + if (opt->min_class > 4) + opt->min_class = 4; + } else if (!strncmp(*argv,"maxrepeat=",10)) { + opt->max_repeat = strtol(*argv+10,&ep,10); + if (!ep) + opt->max_repeat = 0; + } else if (!strncmp(*argv,"reject_username",15)) { + opt->reject_user = 1; } else if (!strncmp(*argv,"use_authtok",11)) { opt->use_authtok = 1; } else if (!strncmp(*argv,"use_first_pass",14)) { @@ -418,6 +426,58 @@ static int simple(struct cracklib_options *opt, const char *new) return 1; } +static int consecutive(struct cracklib_options *opt, const char *new) +{ + char c; + int i; + int same; + + if (opt->max_repeat == 0) + return 0; + + for (i = 0; new[i]; i++) { + if (i > 0 && new[i] == c) { + ++same; + if (same > opt->max_repeat) + return 1; + } else { + c = new[i]; + same = 1; + } + } + return 0; +} + +static int usercheck(struct cracklib_options *opt, const char *new, + char *user) +{ + char *f, *b; + + if (!opt->reject_user) + return 0; + + if (strstr(new, user) != NULL) + return 1; + + /* now reverse the username, we can do that in place + as it is strdup-ed */ + f = user; + b = user+strlen(user)-1; + while (f < b) { + char c; + + c = *f; + *f = *b; + *b = c; + --b; + ++f; + } + + if (strstr(new, user) != NULL) + return 1; + return 0; +} + static char * str_lower(char *string) { char *cp; @@ -428,10 +488,12 @@ static char * str_lower(char *string) } static const char *password_check(struct cracklib_options *opt, - const char *old, const char *new) + const char *old, const char *new, + const char *user) { const char *msg = NULL; char *oldmono = NULL, *newmono, *wrapped = NULL; + char *usermono = NULL; if (old && strcmp(new, old) == 0) { msg = _("is the same as the old one"); @@ -439,6 +501,7 @@ static const char *password_check(struct cracklib_options *opt, } newmono = str_lower(x_strdup(new)); + usermono = str_lower(x_strdup(user)); if (old) { oldmono = str_lower(x_strdup(old)); wrapped = malloc(strlen(oldmono) * 2 + 1); @@ -464,8 +527,15 @@ static const char *password_check(struct cracklib_options *opt, if (!msg && minclass (opt, new)) msg = _("not enough character classes"); + if (!msg && consecutive(opt, new)) + msg = _("contains too many same characters consecutively"); + + if (!msg && usercheck(opt, newmono, usermono)) + msg = _("contains the user name in some form"); + memset(newmono, 0, strlen(newmono)); free(newmono); + free(usermono); if (old) { memset(oldmono, 0, strlen(oldmono)); memset(wrapped, 0, strlen(wrapped)); @@ -532,18 +602,18 @@ static int _pam_unix_approve_pass(pam_handle_t *pamh, return PAM_AUTHTOK_ERR; } + retval = pam_get_item(pamh, PAM_USER, &user); + if (retval != PAM_SUCCESS || user == NULL) { + if (ctrl & PAM_DEBUG_ARG) + pam_syslog(pamh,LOG_ERR,"Can not get username"); + return PAM_AUTHTOK_ERR; + } /* * if one wanted to hardwire authentication token strength * checking this would be the place */ - msg = password_check(opt, pass_old, pass_new); + msg = password_check(opt, pass_old, pass_new, user); if (!msg) { - retval = pam_get_item(pamh, PAM_USER, &user); - if (retval != PAM_SUCCESS || user == NULL) { - if (ctrl & PAM_DEBUG_ARG) - pam_syslog(pamh,LOG_ERR,"Can not get username"); - return PAM_AUTHTOK_ERR; - } msg = check_old_password(user, pass_new); } |