Index: pam-debian/modules/pam_unix/pam_unix_passwd.c
===================================================================
--- pam-debian.orig/modules/pam_unix/pam_unix_passwd.c	2011-10-10 16:22:05.790699739 -0700
+++ pam-debian/modules/pam_unix/pam_unix_passwd.c	2011-10-10 16:24:49.656776455 -0700
@@ -87,6 +87,9 @@
 		      unsigned long versnum, unsigned int proto);
 #endif				/* GNU libc 2.1 */
 
+extern const char *obscure_msg(const char *, const char *, const struct passwd *,
+			       unsigned int);
+
 /*
    How it works:
    Gets in username (has to be done) from the calling program
@@ -501,6 +504,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);
@@ -517,7 +525,7 @@
 	int retval;
 	int remember = -1;
 	int rounds = -1;
-	int pass_min_len = 0;
+	int pass_min_len = 6;
 
 	/* <DO NOT free() THESE> */
 	const char *user;
Index: pam-debian/modules/pam_unix/support.h
===================================================================
--- pam-debian.orig/modules/pam_unix/support.h	2011-10-10 16:22:05.742699130 -0700
+++ pam-debian/modules/pam_unix/support.h	2011-10-10 16:24:49.656776455 -0700
@@ -90,8 +90,9 @@
 					   password hash algorithms */
 #define UNIX_BLOWFISH_PASS       26	/* new password hashes will use blowfish */
 #define UNIX_MIN_PASS_LEN        27	/* min length for password */
+#define UNIX_OBSCURE_CHECKS      28	/* enable obscure checks on passwords */
 /* -------------- */
-#define UNIX_CTRLS_              28	/* number of ctrl arguments defined */
+#define UNIX_CTRLS_              29	/* number of ctrl arguments defined */
 
 #define UNIX_DES_CRYPT(ctrl)	(off(UNIX_MD5_PASS,ctrl)&&off(UNIX_BIGCRYPT,ctrl)&&off(UNIX_SHA256_PASS,ctrl)&&off(UNIX_SHA512_PASS,ctrl)&&off(UNIX_BLOWFISH_PASS,ctrl))
 
@@ -100,34 +101,35 @@
 /* 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_^(0260420000),  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_^(0260420000), 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_SHA256_PASS */     {"sha256",       _ALL_ON_^(0260420000), 020000000},
-/* UNIX_SHA512_PASS */     {"sha512",       _ALL_ON_^(0260420000), 040000000},
-/* UNIX_ALGO_ROUNDS */     {"rounds=",         _ALL_ON_,          0100000000},
-/* UNIX_BLOWFISH_PASS */   {"blowfish",    _ALL_ON_^(0260420000), 0200000000},
-/* UNIX_MIN_PASS_LEN */    {"minlen=",		_ALL_ON_,          0400000000},
+/* 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_^(0x2C22000),   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_^(0x2C22000),  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_SHA256_PASS */     {"sha256",          _ALL_ON_^(0x2C22000), 0x400000},
+/* UNIX_SHA512_PASS */     {"sha512",          _ALL_ON_^(0x2C22000), 0x800000},
+/* UNIX_ALGO_ROUNDS */     {"rounds=",         _ALL_ON_,            0x1000000},
+/* UNIX_BLOWFISH_PASS */   {"blowfish",        _ALL_ON_^(0x2C22000),0x2000000},
+/* UNIX_MIN_PASS_LEN */    {"minlen=",         _ALL_ON_,            0x4000000},
+/* UNIX_OBSCURE_CHECKS */  {"obscure",         _ALL_ON_,            0x8000000},
 };
 
 #define UNIX_DEFAULTS  (unix_args[UNIX__NONULL].flag)
Index: pam-debian/modules/pam_unix/pam_unix.8.xml
===================================================================
--- pam-debian.orig/modules/pam_unix/pam_unix.8.xml	2011-10-10 16:22:05.822700144 -0700
+++ pam-debian/modules/pam_unix/pam_unix.8.xml	2011-10-10 16:24:49.656776455 -0700
@@ -333,8 +333,81 @@
         <listitem>
           <para>
             Set a minimum password length of <replaceable>n</replaceable>
-            characters. The max. for DES crypt based passwords are 8
-            characters.
+            characters.  The default value is 6.  The maximum for DES
+            crypt-based passwords is 8 characters.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>
+          <option>obscure</option>
+        </term>
+        <listitem>
+          <para>
+            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:
+            <variablelist>
+              <varlistentry>
+                <term>
+                  <option>Palindrome</option>
+                </term>
+                <listitem>
+                  <para>
+                    Verifies that the new password is not a palindrome
+                    of (i.e., the reverse of) the previous one.
+                  </para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
+                <term>
+                  <option>Case Change Only</option>
+                </term>
+                <listitem>
+                  <para>
+                    Verifies that the new password isn't the same as the
+                    old one with a change of case.
+                  </para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
+                <term>
+                  <option>Similar</option>
+                </term>
+                <listitem>
+                  <para>
+                    Verifies that the new password isn't too much like
+                    the previous one.
+                  </para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
+                <term>
+                  <option>Simple</option>
+                </term>
+                <listitem>
+                  <para>
+                    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.
+                  </para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
+                <term>
+                  <option>Rotated</option>
+                </term>
+                <listitem>
+                  <para>
+                    Is the new password a rotated version of the old
+                    password?  (E.g., "billy" and "illyb")
+                  </para>
+                </listitem>
+              </varlistentry>
+            </variablelist>
           </para>
         </listitem>
       </varlistentry>
Index: pam-debian/modules/pam_unix/obscure.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ pam-debian/modules/pam_unix/obscure.c	2011-10-10 16:24:49.656776455 -0700
@@ -0,0 +1,198 @@
+/*
+ * 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 "config.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+
+
+#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 palindrome");
+	} 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);
+
+	/* 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 (!UNIX_DES_CRYPT(ctrl))
+		return NULL;  /* unlimited password length */
+
+	if (oldlen <= 8 && newlen <= 8)
+		return NULL;
+
+	new1 = strndup(new,8);
+	old1 = strndup(old,8);
+
+	msg = password_check(old1, new1, pwdp);
+
+	_pam_delete(new1);
+	_pam_delete(old1);
+
+	return msg;
+}
Index: pam-debian/modules/pam_unix/Makefile.am
===================================================================
--- pam-debian.orig/modules/pam_unix/Makefile.am	2011-10-10 16:22:05.754699282 -0700
+++ pam-debian/modules/pam_unix/Makefile.am	2011-10-10 16:24:49.656776455 -0700
@@ -41,7 +41,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 \
-	passverify.c yppasswd_xdr.c md5_good.c md5_broken.c
+	passverify.c yppasswd_xdr.c md5_good.c md5_broken.c obscure.c
 
 bigcrypt_SOURCES = bigcrypt.c bigcrypt_main.c
 bigcrypt_CFLAGS = $(AM_CFLAGS)
Index: pam-debian/modules/pam_unix/pam_unix.8
===================================================================
--- pam-debian.orig/modules/pam_unix/pam_unix.8	2011-10-10 16:22:05.802699891 -0700
+++ pam-debian/modules/pam_unix/pam_unix.8	2011-10-10 16:24:49.656776455 -0700
@@ -1,161 +1,22 @@
+'\" t
 .\"     Title: pam_unix
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.74.0 <http://docbook.sf.net/>
-.\"      Date: 10/27/2010
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\"      Date: 05/31/2011
 .\"    Manual: Linux-PAM Manual
 .\"    Source: Linux-PAM Manual
 .\"  Language: English
 .\"
-.TH "PAM_UNIX" "8" "10/27/2010" "Linux-PAM Manual" "Linux\-PAM Manual"
+.TH "PAM_UNIX" "8" "05/31/2011" "Linux-PAM Manual" "Linux\-PAM Manual"
 .\" -----------------------------------------------------------------
-.\" * (re)Define some macros
+.\" * Define some portability stuff
 .\" -----------------------------------------------------------------
 .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" toupper - uppercase a string (locale-aware)
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
 .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.de toupper
-.tr aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ
-\\$*
-.tr aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz
-..
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" SH-xref - format a cross-reference to an SH section
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.de SH-xref
-.ie n \{\
-.\}
-.toupper \\$*
-.el \{\
-\\$*
-.\}
-..
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" SH - level-one heading that works better for non-TTY output
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.de1 SH
-.\" put an extra blank line of space above the head in non-TTY output
-.if t \{\
-.sp 1
-.\}
-.sp \\n[PD]u
-.nr an-level 1
-.set-an-margin
-.nr an-prevailing-indent \\n[IN]
-.fi
-.in \\n[an-margin]u
-.ti 0
-.HTML-TAG ".NH \\n[an-level]"
-.it 1 an-trap
-.nr an-no-space-flag 1
-.nr an-break-flag 1
-\." make the size of the head bigger
-.ps +3
-.ft B
-.ne (2v + 1u)
-.ie n \{\
-.\" if n (TTY output), use uppercase
-.toupper \\$*
-.\}
-.el \{\
-.nr an-break-flag 0
-.\" if not n (not TTY), use normal case (not uppercase)
-\\$1
-.in \\n[an-margin]u
-.ti 0
-.\" if not n (not TTY), put a border/line under subheading
-.sp -.6
-\l'\n(.lu'
-.\}
-..
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" SS - level-two heading that works better for non-TTY output
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.de1 SS
-.sp \\n[PD]u
-.nr an-level 1
-.set-an-margin
-.nr an-prevailing-indent \\n[IN]
-.fi
-.in \\n[IN]u
-.ti \\n[SN]u
-.it 1 an-trap
-.nr an-no-space-flag 1
-.nr an-break-flag 1
-.ps \\n[PS-SS]u
-\." make the size of the head bigger
-.ps +2
-.ft B
-.ne (2v + 1u)
-.if \\n[.$] \&\\$*
-..
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" BB/BE - put background/screen (filled box) around block of text
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.de BB
-.if t \{\
-.sp -.5
-.br
-.in +2n
-.ll -2n
-.gcolor red
-.di BX
-.\}
-..
-.de EB
-.if t \{\
-.if "\\$2"adjust-for-leading-newline" \{\
-.sp -1
-.\}
-.br
-.di
-.in
-.ll
-.gcolor
-.nr BW \\n(.lu-\\n(.i
-.nr BH \\n(dn+.5v
-.ne \\n(BHu+.5v
-.ie "\\$2"adjust-for-leading-newline" \{\
-\M[\\$1]\h'1n'\v'+.5v'\D'P \\n(BWu 0 0 \\n(BHu -\\n(BWu 0 0 -\\n(BHu'\M[]
-.\}
-.el \{\
-\M[\\$1]\h'1n'\v'-.5v'\D'P \\n(BWu 0 0 \\n(BHu -\\n(BWu 0 0 -\\n(BHu'\M[]
-.\}
-.in 0
-.sp -.5v
-.nf
-.BX
-.in
-.sp .5v
-.fi
-.\}
-..
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" BM/EM - put colored marker in margin next to block of text
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.de BM
-.if t \{\
-.br
-.ll -2n
-.gcolor red
-.di BX
-.\}
-..
-.de EM
-.if t \{\
-.br
-.di
-.ll
-.gcolor
-.nr BH \\n(dn
-.ne \\n(BHu
-\M[\\$1]\D'P -.75n 0 0 \\n(BHu -(\\n[.i]u - \\n(INu - .75n) 0 0 -\\n(BHu'\M[]
-.in 0
-.nf
-.BX
-.in
-.fi
-.\}
-..
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -166,38 +27,36 @@
 .\" -----------------------------------------------------------------
 .\" * MAIN CONTENT STARTS HERE *
 .\" -----------------------------------------------------------------
-.SH "Name"
+.SH "NAME"
 pam_unix \- Module for traditional password authentication
-.SH "Synopsis"
-.fam C
+.SH "SYNOPSIS"
 .HP \w'\fBpam_unix\&.so\fR\ 'u
 \fBpam_unix\&.so\fR [\&.\&.\&.]
-.fam
 .SH "DESCRIPTION"
 .PP
-This is the standard Unix authentication module\&. It uses standard calls from the system\'s libraries to retrieve and set account information as well as authentication\&. Usually this is obtained from the /etc/passwd and the /etc/shadow file as well if shadow is enabled\&.
+This is the standard Unix authentication module\&. It uses standard calls from the system\*(Aqs libraries to retrieve and set account information as well as authentication\&. Usually this is obtained from the /etc/passwd and the /etc/shadow file as well if shadow is enabled\&.
 .PP
-The account component performs the task of establishing the status of the user\'s account and password based on the following
+The account component performs the task of establishing the status of the user\*(Aqs account and password based on the following
 \fIshadow\fR
 elements: expire, last_change, max_change, min_change, warn_change\&. In the case of the latter, it may offer advice to the user on changing their password or, through the
 \fBPAM_AUTHTOKEN_REQD\fR
 return, delay giving service to the user until they have established a new password\&. The entries listed above are documented in the
 \fBshadow\fR(5)
-manual page\&. Should the user\'s record not contain one or more of these entries, the corresponding
+manual page\&. Should the user\*(Aqs record not contain one or more of these entries, the corresponding
 \fIshadow\fR
 check is not performed\&.
 .PP
 The authentication component performs the task of checking the users credentials (password)\&. The default action of this module is to not permit the user access to a service if their official password is blank\&.
 .PP
 A helper binary,
-\fBunix_chkpwd\fR(8), is provided to check the user\'s password when it is stored in a read protected database\&. This binary is very simple and will only check the password of the user invoking it\&. It is called transparently on behalf of the user by the authenticating component of this module\&. In this way it is possible for applications like
+\fBunix_chkpwd\fR(8), is provided to check the user\*(Aqs password when it is stored in a read protected database\&. This binary is very simple and will only check the password of the user invoking it\&. It is called transparently on behalf of the user by the authenticating component of this module\&. In this way it is possible for applications like
 \fBxlock\fR(1)
-to work without being setuid\-root\&. The module, by default, will temporarily turn off SIGCHLD handling for the duration of execution of the helper binary\&. This is generally the right thing to do, as many applications are not prepared to handle this signal from a child they didn\'t know was
+to work without being setuid\-root\&. The module, by default, will temporarily turn off SIGCHLD handling for the duration of execution of the helper binary\&. This is generally the right thing to do, as many applications are not prepared to handle this signal from a child they didn\*(Aqt know was
 \fBfork()\fRd\&. The
 \fBnoreap\fR
 module argument can be used to suppress this temporary shielding and may be needed for use with certain applications\&.
 .PP
-The password component of this module performs the task of updating the user\'s password\&.
+The password component of this module performs the task of updating the user\*(Aqs password\&.
 .PP
 The session component of this module logs when a user logins or leave the system\&.
 .PP
@@ -225,7 +84,7 @@
 .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\&.
+Before prompting the user for their password, the module first tries the previous stacked module\*(Aqs password in case that satisfies this module as well\&.
 .RE
 .PP
 \fBuse_first_pass\fR
@@ -264,7 +123,7 @@
 The last
 \fIn\fR
 passwords for each user are saved in
-\FC/etc/security/opasswd\F[]
+/etc/security/opasswd
 in order to force password change history and keep the user from alternating between the same password too frequently\&.
 .RE
 .PP
@@ -319,7 +178,38 @@
 .RS 4
 Set a minimum password length of
 \fIn\fR
-characters\&. The max\&. for DES crypt based passwords are 8 characters\&.
+characters\&. The default value is 6\&. The maximum for DES crypt\-based passwords is 8 characters\&.
+.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\*(Aqt the same as the old one with a change of case\&.
+.RE
+.PP
+\fBSimilar\fR
+.RS 4
+Verifies that the new password isn\*(Aqt 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
@@ -340,21 +230,13 @@
 .SH "EXAMPLES"
 .PP
 An example usage for
-\FC/etc/pam\&.d/login\F[]
+/etc/pam\&.d/login
 would be:
 .sp
 .if n \{\
 .RS 4
 .\}
-.fam C
-.ps -1
 .nf
-.if t \{\
-.sp -1
-.\}
-.BB lightgray adjust-for-leading-newline
-.sp -1
-
 # Authenticate the user
 auth       required   pam_unix\&.so
 # Ensure users account and password are still active
@@ -365,13 +247,7 @@
 password   required   pam_unix\&.so use_authtok nullok md5
 session    required   pam_unix\&.so
       
-.EB lightgray adjust-for-leading-newline
-.if t \{\
-.sp 1
-.\}
 .fi
-.fam
-.ps +1
 .if n \{\
 .RE
 .\}
