Index: Linux-PAM/modules/pam_unix/pam_unix_passwd.c
===================================================================
--- Linux-PAM/modules/pam_unix/pam_unix_passwd.c.orig
+++ Linux-PAM/modules/pam_unix/pam_unix_passwd.c
@@ -127,6 +127,9 @@
#define OPW_TMPFILE "/etc/security/nopasswd"
#define OLD_PASSWORDS_FILE "/etc/security/opasswd"
+extern const char *obscure_msg(const char *, const char *, const struct passwd *,
+ unsigned int);
+
/*
* i64c - convert an integer to a radix 64 character
*/
@@ -991,12 +994,8 @@
#ifdef USE_CRACKLIB
remark = FascistCheck (pass_new, CRACKLIB_DICTS);
D(("called cracklib [%s]", remark));
-#else
- if (strlen(pass_new) < 6)
- remark = _("You must choose a longer password");
- D(("length check [%s]", remark));
#endif
- if (on(UNIX_REMEMBER_PASSWD, ctrl)) {
+ if (!remark && on(UNIX_REMEMBER_PASSWD, ctrl)) {
if ((retval = check_old_password(user, pass_new)) == PAM_AUTHTOK_ERR)
remark = _("Password has been already used. Choose another.");
if (retval == PAM_ABORT) {
@@ -1005,6 +1004,11 @@
return retval;
}
}
+ if (!remark && pass_old != NULL) { /* only check if we don't already have a failure */
+ struct passwd *pwd;
+ pwd = pam_modutil_getpwnam(pamh, user);
+ remark = (char *)obscure_msg(pass_old,pass_new,pwd,ctrl); /* do obscure checks */
+ }
}
if (remark) {
_make_remark(pamh, ctrl, PAM_ERROR_MSG, remark);
Index: Linux-PAM/modules/pam_unix/pam_unix_acct.c
===================================================================
--- Linux-PAM/modules/pam_unix/pam_unix_acct.c.orig
+++ Linux-PAM/modules/pam_unix/pam_unix_acct.c
@@ -266,7 +266,9 @@
curdays = time(NULL) / (60 * 60 * 24);
D(("today is %d, last change %d", curdays, spent->sp_lstchg));
- if ((curdays > spent->sp_expire) && (spent->sp_expire != -1)) {
+ if ((curdays > spent->sp_expire) && (spent->sp_expire != -1)
+ && (spent->sp_expire != 0))
+ {
pam_syslog(pamh, LOG_NOTICE,
"account %s has expired (account expired)",
uname);
@@ -293,7 +295,9 @@
if ((curdays - spent->sp_lstchg > spent->sp_max)
&& (curdays - spent->sp_lstchg > spent->sp_inact)
&& (curdays - spent->sp_lstchg > spent->sp_max + spent->sp_inact)
- && (spent->sp_max != -1) && (spent->sp_inact != -1)) {
+ && (spent->sp_max != -1) && (spent->sp_max != 0)
+ && (spent->sp_inact != -1) && (spent->sp_inact != 0))
+ {
pam_syslog(pamh, LOG_NOTICE,
"account %s has expired (failed to change password)",
uname);
@@ -302,7 +306,9 @@
D(("account expired 2"));
return PAM_ACCT_EXPIRED;
}
- if ((curdays - spent->sp_lstchg > spent->sp_max) && (spent->sp_max != -1)) {
+ if ((curdays - spent->sp_lstchg > spent->sp_max)
+ && (spent->sp_max != -1) && (spent->sp_max != 0))
+ {
pam_syslog(pamh, LOG_DEBUG,
"expired password for user %s (password aged)",
uname);
@@ -312,7 +318,9 @@
return PAM_NEW_AUTHTOK_REQD;
}
if ((curdays - spent->sp_lstchg > spent->sp_max - spent->sp_warn)
- && (spent->sp_max != -1) && (spent->sp_warn != -1)) {
+ && (spent->sp_max != -1) && (spent->sp_warn != -1)
+ && (spent->sp_max != 0) && (spent->sp_warn != 0))
+ {
daysleft = (spent->sp_lstchg + spent->sp_max) - curdays;
pam_syslog(pamh, LOG_DEBUG,
"password for user %s will expire in %d days",
Index: Linux-PAM/modules/pam_unix/support.c
===================================================================
--- Linux-PAM/modules/pam_unix/support.c.orig
+++ Linux-PAM/modules/pam_unix/support.c
@@ -36,6 +36,9 @@
#define SELINUX_ENABLED 0
#endif
+unsigned int pass_min_len = 1;
+unsigned int pass_max_len = 8;
+
/* this is a front-end for module-application conversations */
int _make_remark(pam_handle_t * pamh, unsigned int ctrl,
@@ -80,6 +83,7 @@
D(("SILENT"));
set(UNIX__QUIET, ctrl);
}
+
/* now parse the arguments to this module */
while (argc-- > 0) {
@@ -89,7 +93,8 @@
for (j = 0; j < UNIX_CTRLS_; ++j) {
if (unix_args[j].token
- && !strncmp(*argv, unix_args[j].token, strlen(unix_args[j].token))) {
+ && !strncmp(*argv, unix_args[j].token, strlen(unix_args[j].token)))
+ {
break;
}
}
@@ -101,16 +106,21 @@
ctrl &= unix_args[j].mask; /* for turning things off */
ctrl |= unix_args[j].flag; /* for turning things on */
- if (remember != NULL) {
- if (j == UNIX_REMEMBER_PASSWD) {
- *remember = strtol(*argv + 9, NULL, 10);
- if ((*remember == INT_MIN) || (*remember == INT_MAX))
- *remember = -1;
- if (*remember > 400)
- *remember = 400;
- }
+ /* special cases */
+ if (remember != NULL && j == UNIX_REMEMBER_PASSWD) {
+ *remember = strtol(*argv + 9, NULL, 10);
+ if ((*remember == INT_MIN) || (*remember == INT_MAX))
+ *remember = -1;
+ if (*remember > 400)
+ *remember = 400;
+ } else if (j == UNIX_MAX_PASS_LEN) {
+ pass_max_len = atoi(*argv + 4);
+ } else if (j == UNIX_MIN_PASS_LEN) {
+ pass_min_len = atoi(*argv + 4);
}
}
+ if (pass_min_len > pass_max_len)
+ pass_min_len = pass_max_len;
++argv; /* step to next argument */
}
@@ -692,6 +702,8 @@
} else if (!p || (*salt == '*')) {
retval = PAM_AUTH_ERR;
} else {
+ /* Hack off sysv pw aging foo */
+ if (strrchr(salt, ',')) *(strrchr(salt, ',')) = '\0';
if (!strncmp(salt, "$1$", 3)) {
pp = Goodcrypt_md5(p, salt);
if (strcmp(pp, salt) != 0) {
Index: Linux-PAM/modules/pam_unix/support.h
===================================================================
--- Linux-PAM/modules/pam_unix/support.h.orig
+++ Linux-PAM/modules/pam_unix/support.h
@@ -84,8 +84,11 @@
#define UNIX_NOREAP 21 /* don't reap child process */
#define UNIX_BROKEN_SHADOW 22 /* ignore errors reading password aging
* information during acct management */
+#define UNIX_MAX_PASS_LEN 23 /* Max length for password */
+#define UNIX_MIN_PASS_LEN 24 /* Min length for password */
+#define UNIX_OBSCURE_CHECKS 25 /* enable obscure checks on passwords */
/* -------------- */
-#define UNIX_CTRLS_ 23 /* number of ctrl arguments defined */
+#define UNIX_CTRLS_ 26 /* number of ctrl arguments defined */
static const UNIX_Ctrls unix_args[UNIX_CTRLS_] =
@@ -93,29 +96,32 @@
/* symbol token name ctrl mask ctrl *
* ----------------------- ------------------- --------------------- -------- */
-/* UNIX__OLD_PASSWD */ {NULL, _ALL_ON_, 01},
-/* UNIX__VERIFY_PASSWD */ {NULL, _ALL_ON_, 02},
-/* UNIX__IAMROOT */ {NULL, _ALL_ON_, 04},
-/* UNIX_AUDIT */ {"audit", _ALL_ON_, 010},
-/* UNIX_USE_FIRST_PASS */ {"use_first_pass", _ALL_ON_^(060), 020},
-/* UNIX_TRY_FIRST_PASS */ {"try_first_pass", _ALL_ON_^(060), 040},
-/* UNIX_NOT_SET_PASS */ {"not_set_pass", _ALL_ON_, 0100},
-/* UNIX__PRELIM */ {NULL, _ALL_ON_^(0600), 0200},
-/* UNIX__UPDATE */ {NULL, _ALL_ON_^(0600), 0400},
-/* UNIX__NONULL */ {NULL, _ALL_ON_, 01000},
-/* UNIX__QUIET */ {NULL, _ALL_ON_, 02000},
-/* UNIX_USE_AUTHTOK */ {"use_authtok", _ALL_ON_, 04000},
-/* UNIX_SHADOW */ {"shadow", _ALL_ON_, 010000},
-/* UNIX_MD5_PASS */ {"md5", _ALL_ON_^(0400000), 020000},
-/* UNIX__NULLOK */ {"nullok", _ALL_ON_^(01000), 0},
-/* UNIX_DEBUG */ {"debug", _ALL_ON_, 040000},
-/* UNIX_NODELAY */ {"nodelay", _ALL_ON_, 0100000},
-/* UNIX_NIS */ {"nis", _ALL_ON_, 0200000},
-/* UNIX_BIGCRYPT */ {"bigcrypt", _ALL_ON_^(020000), 0400000},
-/* UNIX_LIKE_AUTH */ {"likeauth", _ALL_ON_, 01000000},
-/* UNIX_REMEMBER_PASSWD */ {"remember=", _ALL_ON_, 02000000},
-/* UNIX_NOREAP */ {"noreap", _ALL_ON_, 04000000},
-/* UNIX_BROKEN_SHADOW */ {"broken_shadow", _ALL_ON_, 010000000},
+/* UNIX__OLD_PASSWD */ {NULL, _ALL_ON_, 0x1},
+/* UNIX__VERIFY_PASSWD */ {NULL, _ALL_ON_, 0x2},
+/* UNIX__IAMROOT */ {NULL, _ALL_ON_, 0x4},
+/* UNIX_AUDIT */ {"audit", _ALL_ON_, 0x8},
+/* UNIX_USE_FIRST_PASS */ {"use_first_pass", _ALL_ON_^(0x30), 0x10},
+/* UNIX_TRY_FIRST_PASS */ {"try_first_pass", _ALL_ON_^(0x30), 0x20},
+/* UNIX_NOT_SET_PASS */ {"not_set_pass", _ALL_ON_, 0x40},
+/* UNIX__PRELIM */ {NULL, _ALL_ON_^(0x180), 0x80},
+/* UNIX__UPDATE */ {NULL, _ALL_ON_^(0x180), 0x100},
+/* UNIX__NONULL */ {NULL, _ALL_ON_, 0x200},
+/* UNIX__QUIET */ {NULL, _ALL_ON_, 0x400},
+/* UNIX_USE_AUTHTOK */ {"use_authtok", _ALL_ON_, 0x800},
+/* UNIX_SHADOW */ {"shadow", _ALL_ON_, 0x1000},
+/* UNIX_MD5_PASS */ {"md5", _ALL_ON_^(0x20000), 0x2000},
+/* UNIX__NULLOK */ {"nullok", _ALL_ON_^(0x200), 0},
+/* UNIX_DEBUG */ {"debug", _ALL_ON_, 0x4000},
+/* UNIX_NODELAY */ {"nodelay", _ALL_ON_, 0x8000},
+/* UNIX_NIS */ {"nis", _ALL_ON_, 0x10000},
+/* UNIX_BIGCRYPT */ {"bigcrypt", _ALL_ON_^(0x2000), 0x20000},
+/* UNIX_LIKE_AUTH */ {"likeauth", _ALL_ON_, 0x40000},
+/* UNIX_REMEMBER_PASSWD */ {"remember=", _ALL_ON_, 0x80000},
+/* UNIX_NOREAP */ {"noreap", _ALL_ON_, 0x100000},
+/* UNIX_BROKEN_SHADOW */ {"broken_shadow", _ALL_ON_, 0x200000},
+/* UNIX_MAX_PASS_LEN */ {"max=", _ALL_ON_, 0x400000},
+/* UNIX_MIN_PASS_LEN */ {"min=", _ALL_ON_, 0x800000},
+/* UNIX_OBSCURE_CHECKS */ {"obscure", _ALL_ON_, 0x1000000},
};
#define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag)
@@ -152,4 +158,8 @@
extern int _unix_shadowed(const struct passwd *pwd);
extern struct spwd *_unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user);
+
+extern unsigned int pass_min_len;
+extern unsigned int pass_max_len;
+
#endif /* _PAM_UNIX_SUPPORT_H */
Index: Linux-PAM/modules/pam_unix/unix_chkpwd.c
===================================================================
--- Linux-PAM/modules/pam_unix/unix_chkpwd.c.orig
+++ Linux-PAM/modules/pam_unix/unix_chkpwd.c
@@ -192,6 +192,13 @@
return PAM_AUTHTOK_ERR;
}
+ /* Hack off SysVR4 password aging */
+ {
+ char *tmp;
+
+ if ((tmp = strrchr(salt, ',')) != NULL) *tmp = '\0';
+ }
+
/* the moment of truth -- do we agree with the password? */
retval = PAM_AUTH_ERR;
if (!strncmp(salt, "$1$", 3)) {
Index: Linux-PAM/modules/pam_unix/pam_unix.8.xml
===================================================================
--- Linux-PAM/modules/pam_unix/pam_unix.8.xml.orig
+++ Linux-PAM/modules/pam_unix/pam_unix.8.xml
@@ -269,6 +269,101 @@
+
+
+
+
+
+
+ Set a minimum password length of n
+ characters. The default value is 1.
+
+
+
+
+
+
+
+
+
+ Set a maximum password length of n
+ characters. The default value is 8.
+
+
+
+
+
+
+
+
+
+ Enable some extra checks on password strength. These checks
+ are based on the "obscure" checks in the original shadow
+ package. The behavior is similar to the pam_cracklib
+ module, but for non-dictionary-based checks. The following
+ checks are implemented:
+
+
+
+
+
+
+
+ Verifies that the new password is not a palindrome
+ of (i.e., the reverse of) the previous one.
+
+
+
+
+
+
+
+
+
+ Verifies that the new password isn't the same as the
+ old one with a change of case.
+
+
+
+
+
+
+
+
+
+ Verifies that the new password isn't too much like
+ the previous one.
+
+
+
+
+
+
+
+
+
+ Is the new password too simple? This is based on
+ the length of the password and the number of
+ different types of characters (alpha, numeric, etc.)
+ used.
+
+
+
+
+
+
+
+
+
+ Is the new password a rotated version of the old
+ password? (E.g., "billy" and "illyb")
+
+
+
+
+
+
+
Invalid arguments are logged with
Index: Linux-PAM/modules/pam_unix/obscure.c
===================================================================
--- /dev/null
+++ Linux-PAM/modules/pam_unix/obscure.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#include "support.h"
+
+/* can't be a palindrome - like `R A D A R' or `M A D A M' */
+static int palindrome(const char *old, const char *new) {
+ int i, j;
+
+ i = strlen (new);
+
+ for (j = 0;j < i;j++)
+ if (new[i - j - 1] != new[j])
+ return 0;
+
+ return 1;
+}
+
+/* more than half of the characters are different ones. */
+static int similar(const char *old, const char *new) {
+ int i, j;
+
+ /*
+ * XXX - sometimes this fails when changing from a simple password
+ * to a really long one (MD5). For now, I just return success if
+ * the new password is long enough. Please feel free to suggest
+ * something better... --marekm
+ */
+ if (strlen(new) >= 8)
+ return 0;
+
+ for (i = j = 0; new[i] && old[i]; i++)
+ if (strchr(new, old[i]))
+ j++;
+
+ if (i >= j * 2)
+ return 0;
+
+ return 1;
+}
+
+/* a nice mix of characters. */
+static int simple(const char *old, const char *new) {
+ int digits = 0;
+ int uppers = 0;
+ int lowers = 0;
+ int others = 0;
+ int size;
+ int i;
+
+ for (i = 0;new[i];i++) {
+ if (isdigit (new[i]))
+ digits++;
+ else if (isupper (new[i]))
+ uppers++;
+ else if (islower (new[i]))
+ lowers++;
+ else
+ others++;
+ }
+
+ /*
+ * The scam is this - a password of only one character type
+ * must be 8 letters long. Two types, 7, and so on.
+ */
+
+ size = 9;
+ if (digits) size--;
+ if (uppers) size--;
+ if (lowers) size--;
+ if (others) size--;
+
+ if (size <= i)
+ return 0;
+
+ return 1;
+}
+
+static char *str_lower(char *string) {
+ char *cp;
+
+ for (cp = string; *cp; cp++)
+ *cp = tolower(*cp);
+ return string;
+}
+
+static const char * password_check(const char *old, const char *new,
+ const struct passwd *pwdp) {
+ const char *msg = NULL;
+ char *oldmono, *newmono, *wrapped;
+
+ if (strcmp(new, old) == 0)
+ return "Bad: new password must be different than the old one";
+
+ newmono = str_lower(strdup(new));
+ oldmono = str_lower(strdup(old));
+ wrapped = (char *)malloc(strlen(oldmono) * 2 + 1);
+ strcpy (wrapped, oldmono);
+ strcat (wrapped, oldmono);
+
+ if (palindrome(oldmono, newmono)) {
+ msg = "Bad: new password cannot be a panlindrome";
+ } else if (strcmp(oldmono, newmono) == 0) {
+ msg = "Bad: new and old password must differ by more than just case";
+ } else if (similar(oldmono, newmono)) {
+ msg = "Bad: new and old password are too similar";
+ } else if (simple(old, new)) {
+ msg = "Bad: new password is too simple";
+ } else if (strstr(wrapped, newmono)) {
+ msg = "Bad: new password is just a wrapped version of the old one";
+ }
+
+ _pam_delete(newmono);
+ _pam_delete(oldmono);
+ _pam_delete(wrapped);
+
+ return msg;
+}
+
+const char *obscure_msg(const char *old, const char *new,
+ const struct passwd *pwdp, unsigned int ctrl) {
+ int oldlen, newlen;
+ char *new1, *old1;
+ const char *msg;
+
+ if (old == NULL)
+ return NULL; /* no check if old is NULL */
+
+ oldlen = strlen(old);
+ newlen = strlen(new);
+
+ if ( newlen < pass_min_len )
+ return "Bad: new password is too short";
+
+ /* Remaining checks are optional. */
+ if (off(UNIX_OBSCURE_CHECKS,ctrl))
+ return NULL;
+
+ if ((msg = password_check(old, new, pwdp)) != NULL)
+ return msg;
+
+ /* The traditional crypt() truncates passwords to 8 chars. It is
+ possible to circumvent the above checks by choosing an easy
+ 8-char password and adding some random characters to it...
+ Example: "password$%^&*123". So check it again, this time
+ truncated to the maximum length. Idea from npasswd. --marekm */
+
+ if (on(UNIX_MD5_PASS,ctrl))
+ return NULL; /* unlimited password length */
+
+ if (oldlen <= pass_max_len && newlen <= pass_max_len)
+ return NULL;
+
+ new1 = strdup(new);
+ old1 = strdup(old);
+ if (newlen > pass_max_len)
+ new1[pass_max_len] = '\0';
+ if (oldlen > pass_max_len)
+ old1[pass_max_len] = '\0';
+
+ msg = password_check(old1, new1, pwdp);
+
+ _pam_delete(new1);
+ _pam_delete(old1);
+
+ return msg;
+}
Index: Linux-PAM/modules/pam_unix/pam_unix.8
===================================================================
--- Linux-PAM/modules/pam_unix/pam_unix.8.orig
+++ Linux-PAM/modules/pam_unix/pam_unix.8
@@ -1,11 +1,11 @@
.\" Title: pam_unix
.\" Author:
-.\" Generator: DocBook XSL Stylesheets v1.70.1
-.\" Date: 09/20/2006
-.\" Manual: Linux\-PAM Manual
-.\" Source: Linux\-PAM Manual
+.\" Generator: DocBook XSL Stylesheets v1.72.0
+.\" Date: 08/19/2007
+.\" Manual: Linux-PAM Manual
+.\" Source: Linux-PAM Manual
.\"
-.TH "PAM_UNIX" "8" "09/20/2006" "Linux\-PAM Manual" "Linux\-PAM Manual"
+.TH "PAM_UNIX" "8" "08/19/2007" "Linux\-PAM Manual" "Linux\-PAM Manual"
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
@@ -46,61 +46,134 @@
Remaining arguments, supported by others functions of this module, are silently ignored. Other arguments are logged as errors through
\fBsyslog\fR(3).
.SH "OPTIONS"
-.TP 3n
+.PP
\fBdebug\fR
+.RS 4
Turns on debugging via
\fBsyslog\fR(3).
-.TP 3n
+.RE
+.PP
\fBaudit\fR
+.RS 4
A little more extreme than debug.
-.TP 3n
+.RE
+.PP
\fBnullok\fR
+.RS 4
The default action of this module is to not permit the user access to a service if their official password is blank. The
\fBnullok\fR
argument overrides this default.
-.TP 3n
+.RE
+.PP
\fBtry_first_pass\fR
+.RS 4
Before prompting the user for their password, the module first tries the previous stacked module's password in case that satisfies this module as well.
-.TP 3n
+.RE
+.PP
\fBuse_first_pass\fR
+.RS 4
The argument
\fBuse_first_pass\fR
forces the module to use a previous stacked modules password and will never prompt the user \- if no password is available or the password is not appropriate, the user will be denied access.
-.TP 3n
+.RE
+.PP
\fBnodelay\fR
+.RS 4
This argument can be used to discourage the authentication component from requesting a delay should the authentication as a whole fail. The default action is for the module to request a delay\-on\-failure of the order of two second.
-.TP 3n
+.RE
+.PP
\fBuse_authtok\fR
+.RS 4
When password changing enforce the module to set the new password to the one provided by a previously stacked
\fBpassword\fR
module (this is used in the example of the stacking of the
\fBpam_cracklib\fR
module documented above).
-.TP 3n
+.RE
+.PP
\fBnot_set_pass\fR
+.RS 4
This argument is used to inform the module that it is not to pay attention to/make available the old or new passwords from/to other (stacked) password modules.
-.TP 3n
+.RE
+.PP
\fBnis\fR
+.RS 4
NIS RPC is used for setting new passwords.
-.TP 3n
+.RE
+.PP
\fBremember=\fR\fB\fIn\fR\fR
+.RS 4
The last
\fIn\fR
passwords for each user are saved in
\fI/etc/security/opasswd\fR
in order to force password change history and keep the user from alternating between the same password too frequently.
-.TP 3n
+.RE
+.PP
\fBshadow\fR
+.RS 4
Try to maintain a shadow based system.
-.TP 3n
+.RE
+.PP
\fBmd5\fR
+.RS 4
When a user changes their password next, encrypt it with the MD5 algorithm.
-.TP 3n
+.RE
+.PP
\fBbigcrypt\fR
+.RS 4
When a user changes their password next, encrypt it with the DEC C2 algorithm.
-.TP 3n
+.RE
+.PP
\fBbroken_shadow\fR
+.RS 4
Ignore errors reading shadow inforation for users in the account management module.
+.RE
+.PP
+\fBmin=\fR\fB\fIn\fR\fR
+.RS 4
+Set a minimum password length of
+\fIn\fR
+characters. The default value is 1.
+.RE
+.PP
+\fBmax=\fR\fB\fIn\fR\fR
+.RS 4
+Set a maximum password length of
+\fIn\fR
+characters. The default value is 8.
+.RE
+.PP
+\fBobscure\fR
+.RS 4
+Enable some extra checks on password strength. These checks are based on the "obscure" checks in the original shadow package. The behavior is similar to the pam_cracklib module, but for non\-dictionary\-based checks. The following checks are implemented:
+.PP
+\fBPalindrome\fR
+.RS 4
+Verifies that the new password is not a palindrome of (i.e., the reverse of) the previous one.
+.RE
+.PP
+\fBCase Change Only\fR
+.RS 4
+Verifies that the new password isn't the same as the old one with a change of case.
+.RE
+.PP
+\fBSimilar\fR
+.RS 4
+Verifies that the new password isn't too much like the previous one.
+.RE
+.PP
+\fBSimple\fR
+.RS 4
+Is the new password too simple? This is based on the length of the password and the number of different types of characters (alpha, numeric, etc.) used.
+.RE
+.PP
+\fBRotated\fR
+.RS 4
+Is the new password a rotated version of the old password? (E.g., "billy" and "illyb")
+.RE
+.sp
+.RE
.PP
Invalid arguments are logged with
\fBsyslog\fR(3).
@@ -108,16 +181,18 @@
.PP
All service are supported.
.SH "RETURN VALUES"
-.TP 3n
+.PP
PAM_IGNORE
+.RS 4
Ignore this module.
+.RE
.SH "EXAMPLES"
.PP
An example usage for
\fI/etc/pam.d/login\fR
would be:
.sp
-.RS 3n
+.RS 4
.nf
# Authenticate the user
auth required pam_unix.so
Index: Linux-PAM/modules/pam_unix/Makefile.am
===================================================================
--- Linux-PAM/modules/pam_unix/Makefile.am.orig
+++ Linux-PAM/modules/pam_unix/Makefile.am
@@ -42,7 +42,7 @@
pam_unix_la_SOURCES = bigcrypt.c pam_unix_acct.c \
pam_unix_auth.c pam_unix_passwd.c pam_unix_sess.c support.c \
- yppasswd_xdr.c md5_good.c md5_broken.c
+ yppasswd_xdr.c md5_good.c md5_broken.c obscure.c
bigcrypt_SOURCES = bigcrypt.c bigcrypt_main.c
bigcrypt_CFLAGS = $(AM_CFLAGS)
Index: Linux-PAM/modules/pam_unix/README
===================================================================
--- Linux-PAM/modules/pam_unix/README.orig
+++ Linux-PAM/modules/pam_unix/README
@@ -119,6 +119,46 @@
Ignore errors reading shadow inforation for users in the account management
module.
+min=n
+
+ Set a minimum password length of n characters. The default value is 1.
+
+max=n
+
+ Set a maximum password length of n characters. The default value is 8.
+
+obscure
+
+ Enable some extra checks on password strength. These checks are based on
+ the "obscure" checks in the original shadow package. The behavior is
+ similar to the pam_cracklib module, but for non-dictionary-based checks.
+ The following checks are implemented:
+
+ Palindrome
+
+ Verifies that the new password is not a palindrome of (i.e., the
+ reverse of) the previous one.
+
+ Case Change Only
+
+ Verifies that the new password isn't the same as the old one with a
+ change of case.
+
+ Similar
+
+ Verifies that the new password isn't too much like the previous one.
+
+ Simple
+
+ Is the new password too simple? This is based on the length of the
+ password and the number of different types of characters (alpha,
+ numeric, etc.) used.
+
+ Rotated
+
+ Is the new password a rotated version of the old password? (E.g.,
+ "billy" and "illyb")
+
Invalid arguments are logged with syslog(3).
EXAMPLES