summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomas Mraz <tm@t8m.info>2008-09-19 13:38:32 +0000
committerTomas Mraz <tm@t8m.info>2008-09-19 13:38:32 +0000
commite15dee8abc38058cae9259a3aa3b625ea8febbfd (patch)
tree8377c78395629744b73b455364618444f0f1b88c
parent742a6386465fb4290c3a5f86505f9a3e5e48fad3 (diff)
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().
-rw-r--r--ChangeLog11
-rw-r--r--NEWS5
-rw-r--r--modules/pam_cracklib/pam_cracklib.8.xml45
-rw-r--r--modules/pam_cracklib/pam_cracklib.c90
4 files changed, 138 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index 5da1343c..5a6c2bba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+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().
+
2008-09-16 Thorsten Kukuk <kukuk@thkukuk.de>
* modules/pam_cracklib/pam_cracklib.8.xml: Fix typo.
diff --git a/NEWS b/NEWS
index e4e2b743..5d9927b7 100644
--- a/NEWS
+++ b/NEWS
@@ -6,11 +6,12 @@ Release 1.0.90
* Supply hostname of the machine to netgroup match call in pam_access
* Make pam_namespace to work safe on child directories of parent directories
owned by users
-* Redifine LOCAL keyword of pam_access configuration file
+* Redefine LOCAL keyword of pam_access configuration file
* Add support fro try_first_pass and use_first_pass to pam_cracklib
* Print informative messages for rejected login and add silent and
no_log_info options to pam_tally
-
+* Add support for passing PAM_AUTHTOK to stdin of helpers from pam_exec
+* New password quality tests in pam_cracklib
Release 1.0.1
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);
}