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