diff options
author | Dmitry V. Levin <ldv@altlinux.org> | 2020-10-29 08:00:00 +0000 |
---|---|---|
committer | Dmitry V. Levin <ldv@altlinux.org> | 2020-10-29 08:00:00 +0000 |
commit | d702ff714c309069111899fd07c09e31c414c166 (patch) | |
tree | 0e4b5cf2449b8237ec9468faf2bba34c2e865076 | |
parent | a0d402a38d0f043861879b287ac6069cb8a7d4b9 (diff) | |
download | pam-d702ff714c309069111899fd07c09e31c414c166.tar.gz pam-d702ff714c309069111899fd07c09e31c414c166.tar.bz2 pam-d702ff714c309069111899fd07c09e31c414c166.zip |
Remove deprecated pam_cracklib module
* ci/install-dependencies.sh: Remove libcrack2-dev.
* ci/run-build-and-tests.sh (DISTCHECK_CONFIGURE_FLAGS): Remove
--enable-cracklib=check.
* conf/pam.conf: Remove references to pam_cracklib.so.
* configure.ac: Remove --enable-cracklib option.
(AC_SUBST): Remove LIBCRACK.
(AM_CONDITIONAL): Remove COND_BUILD_PAM_CRACKLIB.
(AC_CONFIG_FILES): Remove modules/pam_cracklib/Makefile.
* doc/sag/pam_cracklib.xml: Remove.
* doc/sag/Linux-PAM_SAG.xml: Do not include pam_cracklib.xml.
* modules/Makefile.am (MAYBE_PAM_CRACKLIB): Remove.
(SUBDIRS): Remove MAYBE_PAM_CRACKLIB.
* modules/pam_cracklib/Makefile.am: Remove.
* modules/pam_cracklib/README.xml: Likewise.
* modules/pam_cracklib/pam_cracklib.8.xml: Likewise.
* modules/pam_cracklib/pam_cracklib.c: Likewise.
* modules/pam_cracklib/tst-pam_cracklib: Likewise.
* xtests/tst-pam_cracklib1.c: Likewise.
* xtests/tst-pam_cracklib1.pamd: Likewise.
* xtests/tst-pam_cracklib2.c: Likewise.
* xtests/tst-pam_cracklib2.pamd: Likewise.
* modules/pam_pwhistory/pam_pwhistory.8.xml: Replace pam_cracklib
in examples with pam_passwdqc.
* modules/pam_unix/pam_unix.8.xml: Likewise.
* po/POTFILES.in: Remove ./modules/pam_cracklib/pam_cracklib.c.
* xtests/.gitignore: Remove tst-pam_cracklib1 and tst-pam_cracklib2.
* xtests/Makefile.am (EXTRA_DIST): Remove tst-pam_cracklib1.pamd
and tst-pam_cracklib2.pamd.
(XTESTS): Remove tst-pam_cracklib1 and tst-pam_cracklib2.
* NEWS: Document this change.
-rw-r--r-- | NEWS | 2 | ||||
-rwxr-xr-x | ci/install-dependencies.sh | 1 | ||||
-rwxr-xr-x | ci/run-build-and-tests.sh | 2 | ||||
-rw-r--r-- | conf/pam.conf | 5 | ||||
-rw-r--r-- | configure.ac | 25 | ||||
-rw-r--r-- | doc/sag/Linux-PAM_SAG.xml | 2 | ||||
-rw-r--r-- | doc/sag/pam_cracklib.xml | 34 | ||||
-rw-r--r-- | modules/Makefile.am | 5 | ||||
-rw-r--r-- | modules/pam_cracklib/Makefile.am | 33 | ||||
-rw-r--r-- | modules/pam_cracklib/README.xml | 41 | ||||
-rw-r--r-- | modules/pam_cracklib/pam_cracklib.8.xml | 592 | ||||
-rw-r--r-- | modules/pam_cracklib/pam_cracklib.c | 899 | ||||
-rwxr-xr-x | modules/pam_cracklib/tst-pam_cracklib | 2 | ||||
-rw-r--r-- | modules/pam_pwhistory/pam_pwhistory.8.xml | 6 | ||||
-rw-r--r-- | modules/pam_unix/pam_unix.8.xml | 6 | ||||
-rw-r--r-- | po/POTFILES.in | 1 | ||||
-rw-r--r-- | xtests/.gitignore | 2 | ||||
-rw-r--r-- | xtests/Makefile.am | 2 | ||||
-rw-r--r-- | xtests/tst-pam_cracklib1.c | 135 | ||||
-rw-r--r-- | xtests/tst-pam_cracklib1.pamd | 2 | ||||
-rw-r--r-- | xtests/tst-pam_cracklib2.c | 143 | ||||
-rw-r--r-- | xtests/tst-pam_cracklib2.pamd | 2 |
22 files changed, 10 insertions, 1932 deletions
@@ -2,6 +2,8 @@ Linux-PAM NEWS -- history of user-visible changes. Release 1.5.0 * pam_motd: read motd files with target user credentials skipping unreadable ones. +* Removed deprecated pam_cracklib module, use pam_passwdqc (from passwdqc project) + or pam_pwquality (from libpwquality project) instead. Release 1.4.0 * Multiple minor bug fixes and documentation improvements diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh index aaeaf389..aa85edb1 100755 --- a/ci/install-dependencies.sh +++ b/ci/install-dependencies.sh @@ -18,7 +18,6 @@ docbook-xsl flex gettext libaudit-dev -libcrack2-dev libdb-dev libfl-dev libselinux1-dev diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh index a16282ca..9a44019a 100755 --- a/ci/run-build-and-tests.sh +++ b/ci/run-build-and-tests.sh @@ -5,7 +5,7 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -DISTCHECK_CONFIGURE_FLAGS='--disable-dependency-tracking --enable-Werror --enable-tally --enable-tally2 --enable-cracklib=check' +DISTCHECK_CONFIGURE_FLAGS='--disable-dependency-tracking --enable-Werror --enable-tally --enable-tally2' export DISTCHECK_CONFIGURE_FLAGS case "${TARGET-}" in diff --git a/conf/pam.conf b/conf/pam.conf index 3a06bd66..4961a0aa 100644 --- a/conf/pam.conf +++ b/conf/pam.conf @@ -13,14 +13,12 @@ # chfn auth required pam_unix.so chfn account required pam_unix.so -chfn password required pam_cracklib.so retry=3 chfn password required pam_unix.so shadow md5 use_authtok # # The PAM configuration file for the `chsh' service # chsh auth required pam_unix.so chsh account required pam_unix.so -chsh password required pam_cracklib.so retry=3 chsh password required pam_unix.so shadow md5 use_authtok # # The PAM configuration file for the `ftp' service @@ -43,7 +41,6 @@ login auth required pam_unix.so login auth optional pam_group.so login account requisite pam_time.so login account required pam_unix.so -login password required pam_cracklib.so retry=3 login password required pam_unix.so shadow md5 use_authtok login session required pam_unix.so # @@ -63,7 +60,6 @@ other session required pam_deny.so # # The PAM configuration file for the `passwd' service # -passwd password requisite pam_cracklib.so retry=3 passwd password required pam_unix.so shadow md5 use_authtok # # The PAM configuration file for the `rexec' service @@ -83,7 +79,6 @@ rlogin auth requisite pam_securetty.so rlogin auth requisite pam_nologin.so rlogin auth required pam_rhosts_auth.so rlogin account required pam_unix.so -rlogin password required pam_cracklib.so retry=3 rlogin password required pam_unix.so shadow md5 use_authtok rlogin session required pam_unix.so rlogin session required pam_limits.so diff --git a/configure.ac b/configure.ac index 59327a75..4397124d 100644 --- a/configure.ac +++ b/configure.ac @@ -334,28 +334,6 @@ case "$ac_cv_search_dlopen" in esac AC_SUBST(LIBDL) -AC_ARG_ENABLE([cracklib], - [AS_HELP_STRING([--enable-cracklib], - [build deprecated pam_cracklib module])], - [], [enable_cracklib=no]) -LIBCRACK="" -case "$enable_cracklib" in - no) ;; - yes|check) - dnl Check for cracklib - AC_CHECK_HEADERS([crack.h], - [AC_CHECK_LIB([crack], [FascistCheck], - [LIBCRACK="-lcrack"])]) - if test -z "$LIBCRACK"; then - if test "$enable_cracklib" = yes; then - AC_MSG_FAILURE([failed to find cracklib]) - fi - fi - ;; - *) AC_MSG_ERROR([bad value $enable_cracklib for --enable-cracklib option]) ;; -esac -AC_SUBST(LIBCRACK) - dnl Look for Linux Auditing library - see documentation AC_ARG_ENABLE([audit], AS_HELP_STRING([--disable-audit],[do not enable audit support]), @@ -662,7 +640,6 @@ case "$enable_unix" in *) AC_MSG_ERROR([bad value $enable_unix for --enable-unix option]) ;; esac -AM_CONDITIONAL([COND_BUILD_PAM_CRACKLIB], [test -n "$LIBCRACK"]) AM_CONDITIONAL([COND_BUILD_PAM_KEYINIT], [test "$have_key_syscalls" = 1]) AM_CONDITIONAL([COND_BUILD_PAM_LASTLOG], [test "$ac_cv_func_logwtmp" = yes]) AM_CONDITIONAL([COND_BUILD_PAM_NAMESPACE], [test "$ac_cv_func_unshare" = yes]) @@ -682,7 +659,7 @@ AC_CONFIG_FILES([Makefile libpam/Makefile libpamc/Makefile libpamc/test/Makefile po/Makefile.in \ Make.xml.rules \ modules/Makefile \ - modules/pam_access/Makefile modules/pam_cracklib/Makefile \ + modules/pam_access/Makefile \ modules/pam_debug/Makefile modules/pam_deny/Makefile \ modules/pam_echo/Makefile modules/pam_env/Makefile \ modules/pam_faildelay/Makefile modules/pam_faillock/Makefile \ diff --git a/doc/sag/Linux-PAM_SAG.xml b/doc/sag/Linux-PAM_SAG.xml index 6a324aa5..03de0250 100644 --- a/doc/sag/Linux-PAM_SAG.xml +++ b/doc/sag/Linux-PAM_SAG.xml @@ -397,8 +397,6 @@ session required pam_warn.so <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_access.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="pam_cracklib.xml"/> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_debug.xml"/> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_deny.xml"/> diff --git a/doc/sag/pam_cracklib.xml b/doc/sag/pam_cracklib.xml deleted file mode 100644 index 898bbf9c..00000000 --- a/doc/sag/pam_cracklib.xml +++ /dev/null @@ -1,34 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" - "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> -<section id='sag-pam_cracklib'> - <title>pam_cracklib - checks the password against dictionary words</title> - <cmdsynopsis> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="../../modules/pam_cracklib/pam_cracklib.8.xml" xpointer='xpointer(//cmdsynopsis[@id = "pam_cracklib-cmdsynopsis"]/*)'/> - </cmdsynopsis> - <section id='sag-pam_cracklib-description'> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="../../modules/pam_cracklib/pam_cracklib.8.xml" xpointer='xpointer(//refsect1[@id = "pam_cracklib-description"]/*)'/> - </section> - <section id='sag-pam_cracklib-options'> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="../../modules/pam_cracklib/pam_cracklib.8.xml" xpointer='xpointer(//refsect1[@id = "pam_cracklib-options"]/*)'/> - </section> - <section id='sag-pam_cracklib-types'> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="../../modules/pam_cracklib/pam_cracklib.8.xml" xpointer='xpointer(//refsect1[@id = "pam_cracklib-types"]/*)'/> - </section> - <section id='sag-pam_cracklib-return_values'> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="../../modules/pam_cracklib/pam_cracklib.8.xml" xpointer='xpointer(//refsect1[@id = "pam_cracklib-return_values"]/*)'/> - </section> - <section id='sag-pam_cracklib-examples'> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="../../modules/pam_cracklib/pam_cracklib.8.xml" xpointer='xpointer(//refsect1[@id = "pam_cracklib-examples"]/*)'/> - </section> - <section id='sag-pam_cracklib-author'> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="../../modules/pam_cracklib/pam_cracklib.8.xml" xpointer='xpointer(//refsect1[@id = "pam_cracklib-author"]/*)'/> - </section> -</section> diff --git a/modules/Makefile.am b/modules/Makefile.am index 641108dd..aa03e319 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -2,10 +2,6 @@ # Copyright (c) 2005, 2006, 2008 Thorsten Kukuk <kukuk@thkukuk.de> # -if COND_BUILD_PAM_CRACKLIB - MAYBE_PAM_CRACKLIB = pam_cracklib -endif - if COND_BUILD_PAM_KEYINIT MAYBE_PAM_KEYINIT = pam_keyinit endif @@ -56,7 +52,6 @@ endif SUBDIRS := \ pam_access \ - $(MAYBE_PAM_CRACKLIB) \ pam_debug \ pam_deny \ pam_echo \ diff --git a/modules/pam_cracklib/Makefile.am b/modules/pam_cracklib/Makefile.am deleted file mode 100644 index e11c42d7..00000000 --- a/modules/pam_cracklib/Makefile.am +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2005, 2006, 2009 Thorsten Kukuk <kukuk@suse.de> -# - -CLEANFILES = *~ -MAINTAINERCLEANFILES = $(MANS) README - -EXTRA_DIST = $(XMLS) - -if HAVE_DOC -dist_man_MANS = pam_cracklib.8 -endif -XMLS = README.xml pam_cracklib.8.xml -dist_check_SCRIPTS = tst-pam_cracklib -TESTS = $(dist_check_SCRIPTS) - -securelibdir = $(SECUREDIR) -secureconfdir = $(SCONFIGDIR) - -AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ - $(WARN_CFLAGS) -AM_LDFLAGS = -no-undefined -avoid-version -module -if HAVE_VERSIONING - AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map -endif -pam_cracklib_la_LIBADD = $(top_builddir)/libpam/libpam.la \ - @LIBCRACK@ @LIBCRYPT@ -securelib_LTLIBRARIES = pam_cracklib.la - -if ENABLE_REGENERATE_MAN -dist_noinst_DATA = README --include $(top_srcdir)/Make.xml.rules -endif diff --git a/modules/pam_cracklib/README.xml b/modules/pam_cracklib/README.xml deleted file mode 100644 index c4a7b54c..00000000 --- a/modules/pam_cracklib/README.xml +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding='UTF-8'?> -<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" -"http://www.docbook.org/xml/4.3/docbookx.dtd" -[ -<!-- -<!ENTITY pamaccess SYSTEM "pam_cracklib.8.xml"> ---> -]> - -<article> - - <articleinfo> - - <title> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="pam_cracklib.8.xml" xpointer='xpointer(//refnamediv[@id = "pam_cracklib-name"]/*)'/> - </title> - - </articleinfo> - - <section> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="pam_cracklib.8.xml" xpointer='xpointer(//refsect1[@id = "pam_cracklib-description"]/*)'/> - </section> - - <section> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="pam_cracklib.8.xml" xpointer='xpointer(//refsect1[@id = "pam_cracklib-options"]/*)'/> - </section> - - <section> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="pam_cracklib.8.xml" xpointer='xpointer(//refsect1[@id = "pam_cracklib-examples"]/*)'/> - </section> - - <section> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="pam_cracklib.8.xml" xpointer='xpointer(//refsect1[@id = "pam_cracklib-author"]/*)'/> - </section> - -</article> diff --git a/modules/pam_cracklib/pam_cracklib.8.xml b/modules/pam_cracklib/pam_cracklib.8.xml deleted file mode 100644 index 75e44e2d..00000000 --- a/modules/pam_cracklib/pam_cracklib.8.xml +++ /dev/null @@ -1,592 +0,0 @@ -<?xml version="1.0" encoding='UTF-8'?> -<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" - "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"> - -<refentry id="pam_cracklib"> - - <refmeta> - <refentrytitle>pam_cracklib</refentrytitle> - <manvolnum>8</manvolnum> - <refmiscinfo class="sectdesc">Linux-PAM Manual</refmiscinfo> - </refmeta> - - <refnamediv id="pam_cracklib-name"> - <refname>pam_cracklib</refname> - <refpurpose>PAM module to check the password against dictionary words</refpurpose> - </refnamediv> - - <refsynopsisdiv> - <cmdsynopsis id="pam_cracklib-cmdsynopsis"> - <command>pam_cracklib.so</command> - <arg choice="opt"> - <replaceable>...</replaceable> - </arg> - </cmdsynopsis> - </refsynopsisdiv> - - <refsect1 id="pam_cracklib-description"> - - <title>DESCRIPTION</title> - - <para> - This module can be plugged into the <emphasis>password</emphasis> stack of - a given application to provide some plug-in strength-checking for passwords. - </para> - - <para> - The action of this module is to prompt the user for a password and - check its strength against a system dictionary and a set of rules for - identifying poor choices. - </para> - - <para> - The first action is to prompt for a single password, check its - strength and then, if it is considered strong, prompt for the password - a second time (to verify that it was typed correctly on the first - occasion). All being well, the password is passed on to subsequent - modules to be installed as the new authentication token. - </para> - - <para> - The strength checks works in the following manner: at first the - <function>Cracklib</function> routine is called to check if the password - is part of a dictionary; if this is not the case an additional set of - strength checks is done. These checks are: - </para> - - <variablelist> - <varlistentry> - <term>Palindrome</term> - <listitem> - <para> - Is the new password a palindrome? - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>Case Change Only</term> - <listitem> - <para> - Is the new password the old one with only a change of case? - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>Similar</term> - <listitem> - <para> - Is the new password too much like the old one? - This is primarily controlled by one argument, - <option>difok</option> which is a number of character changes - (inserts, removals, or replacements) between the old and new - password that are enough to accept the new password. - This defaults to 5 changes. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>Simple</term> - <listitem> - <para> - Is the new password too small? - This is controlled by 6 arguments <option>minlen</option>, - <option>maxclassrepeat</option>, - <option>dcredit</option>, <option>ucredit</option>, - <option>lcredit</option>, and <option>ocredit</option>. See the section - on the arguments for the details of how these work and there defaults. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>Rotated</term> - <listitem> - <para> - Is the new password a rotated version of the old password? - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>Same consecutive characters</term> - <listitem> - <para> - Optional check for same consecutive characters. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>Too long monotonic character sequence</term> - <listitem> - <para> - Optional check for too long monotonic character sequence. - </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 - password encryption. With md5 encryption, passwords can be longer - than 8 characters and the default settings for this module can make it - hard for the user to choose a satisfactory new password. Notably, the - requirement that the new password contain no more than 1/2 of the - characters in the old password becomes a non-trivial constraint. For - example, an old password of the form "the quick brown fox jumped over - the lazy dogs" would be difficult to change... In addition, the - default action is to allow passwords as small as 5 characters in - length. For a md5 systems it can be a good idea to increase the - required minimum size of a password. One can then allow more credit - for different kinds of characters but accept that the new password may - share most of these characters with the old password. - </para> - - </refsect1> - - <refsect1 id="pam_cracklib-options"> - - <title>OPTIONS</title> - <para> - <variablelist> - - <varlistentry> - <term> - <option>debug</option> - </term> - <listitem> - <para> - This option makes the module write information to - <citerefentry> - <refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum> - </citerefentry> - indicating the behavior of the module (this option does - not write password information to the log file). - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <option>authtok_type=<replaceable>XXX</replaceable></option> - </term> - <listitem> - <para> - The default action is for the module to use the - following prompts when requesting passwords: - "New UNIX password: " and "Retype UNIX password: ". - The example word <emphasis>UNIX</emphasis> can - be replaced with this option, by default it is empty. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <option>retry=<replaceable>N</replaceable></option> - </term> - <listitem> - <para> - Prompt user at most <replaceable>N</replaceable> times - before returning with error. The default is - <emphasis>1</emphasis>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <option>difok=<replaceable>N</replaceable></option> - </term> - <listitem> - <para> - This argument will change the default of - <emphasis>5</emphasis> for the number of character - changes in the new password that differentiate it - from the old password. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <option>minlen=<replaceable>N</replaceable></option> - </term> - <listitem> - <para> - The minimum acceptable size for the new password (plus - one if credits are not disabled which is the default). - In addition to the number of characters in the new password, - credit (of +1 in length) is given for each different kind - of character (<emphasis>other</emphasis>, - <emphasis>upper</emphasis>, <emphasis>lower</emphasis> and - <emphasis>digit</emphasis>). The default for this parameter - is <emphasis>9</emphasis> which is good for a old style UNIX - password all of the same type of character but may be too low - to exploit the added security of a md5 system. Note that - there is a pair of length limits in - <emphasis>Cracklib</emphasis> itself, a "way too short" limit - of 4 which is hard coded in and a defined limit (6) that will - be checked without reference to <option>minlen</option>. - If you want to allow passwords as short as 5 characters you - should not use this module. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <option>dcredit=<replaceable>N</replaceable></option> - </term> - <listitem> - <para> - (N >= 0) This is the maximum credit for having digits in - the new password. If you have less than or - <replaceable>N</replaceable> - digits, each digit will count +1 towards meeting the current - <option>minlen</option> value. The default for - <option>dcredit</option> is 1 which is the recommended - value for <option>minlen</option> less than 10. - </para> - <para> - (N < 0) This is the minimum number of digits that must - be met for a new password. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <option>ucredit=<replaceable>N</replaceable></option> - </term> - <listitem> - <para> - (N >= 0) This is the maximum credit for having upper - case letters in the new password. If you have less than - or <replaceable>N</replaceable> upper case letters each - letter will count +1 towards meeting the current - <option>minlen</option> value. The default for - <option>ucredit</option> is <emphasis>1</emphasis> which - is the recommended value for <option>minlen</option> less - than 10. - </para> - <para> - (N < 0) This is the minimum number of upper - case letters that must be met for a new password. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <option>lcredit=<replaceable>N</replaceable></option> - </term> - <listitem> - <para> - (N >= 0) This is the maximum credit for having - lower case letters in the new password. If you have - less than or <replaceable>N</replaceable> lower case - letters, each letter will count +1 towards meeting the - current <option>minlen</option> value. The default for - <option>lcredit</option> is 1 which is the recommended - value for <option>minlen</option> less than 10. - </para> - <para> - (N < 0) This is the minimum number of lower - case letters that must be met for a new password. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <option>ocredit=<replaceable>N</replaceable></option> - </term> - <listitem> - <para> - (N >= 0) This is the maximum credit for having other - characters in the new password. If you have less than or - <replaceable>N</replaceable> other characters, each - character will count +1 towards meeting the current - <option>minlen</option> value. The default for - <option>ocredit</option> is 1 which is the recommended - value for <option>minlen</option> less than 10. - </para> - <para> - (N < 0) This is the minimum number of other - characters that must be met for a new password. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <option>minclass=<replaceable>N</replaceable></option> - </term> - <listitem> - <para> - The minimum number of required classes of characters for - the new password. The default number is zero. The four - classes are digits, upper and lower letters and other - characters. - The difference to the <option>credit</option> check is - that a specific class if of characters is not required. - Instead <replaceable>N</replaceable> out of four of the - classes are required. - </para> - </listitem> - </varlistentry> - - <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>maxsequence=<replaceable>N</replaceable></option> - </term> - <listitem> - <para> - Reject passwords which contain monotonic character sequences - longer than N. The default is 0 which means that this check - is disabled. Examples of such sequence are '12345' or 'fedcb'. - Note that most such passwords will not pass the simplicity - check unless the sequence is only a minor part of the password. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <option>maxclassrepeat=<replaceable>N</replaceable></option> - </term> - <listitem> - <para> - Reject passwords which contain more than N consecutive - characters of the same class. 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>gecoscheck</option> - </term> - <listitem> - <para> - Check whether the words from the GECOS field (usually full name - of the user) longer than 3 characters in straight or reversed - form are contained in the new password. If any such word is - found the new password is rejected. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <option>enforce_for_root</option> - </term> - <listitem> - <para> - The module will return error on failed check also if the user - changing the password is root. This option is off by default - which means that just the message about the failed check is - printed but root can change the password anyway. - Note that root is not asked for an old password so the checks - that compare the old and new password are not performed. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <option>use_authtok</option> - </term> - <listitem> - <para> - This argument is used to <emphasis>force</emphasis> the - module to not prompt the user for a new password but use - the one provided by the previously stacked - <emphasis>password</emphasis> module. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <option>dictpath=<replaceable>/path/to/dict</replaceable></option> - </term> - <listitem> - <para> - Path to the cracklib dictionaries. - </para> - </listitem> - </varlistentry> - - </variablelist> - </para> - </refsect1> - - <refsect1 id="pam_cracklib-types"> - <title>MODULE TYPES PROVIDED</title> - <para> - Only the <option>password</option> module type is provided. - </para> - </refsect1> - - <refsect1 id='pam_cracklib-return_values'> - <title>RETURN VALUES</title> - <para> - <variablelist> - - <varlistentry> - <term>PAM_SUCCESS</term> - <listitem> - <para> - The new password passes all checks. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term>PAM_AUTHTOK_ERR</term> - <listitem> - <para> - No new password was entered, - the username could not be determined or the new - password fails the strength checks. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term>PAM_AUTHTOK_RECOVERY_ERR</term> - <listitem> - <para> - The old password was not supplied by a previous stacked - module or got not requested from the user. - The first error can happen if <option>use_authtok</option> - is specified. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term>PAM_SERVICE_ERR</term> - <listitem> - <para> - A internal error occurred. - </para> - </listitem> - </varlistentry> - - </variablelist> - </para> - </refsect1> - - <refsect1 id='pam_cracklib-examples'> - <title>EXAMPLES</title> - <para> - For an example of the use of this module, we show how it may be - stacked with the password component of - <citerefentry> - <refentrytitle>pam_unix</refentrytitle><manvolnum>8</manvolnum> - </citerefentry> - <programlisting> -# -# These lines stack two password type modules. In this example the -# user is given 3 opportunities to enter a strong password. The -# "use_authtok" argument ensures that the pam_unix module does not -# prompt for a password, but instead uses the one provided by -# pam_cracklib. -# -passwd password required pam_cracklib.so retry=3 -passwd password required pam_unix.so use_authtok - </programlisting> - </para> - - <para> - Another example (in the <filename>/etc/pam.d/passwd</filename> format) - is for the case that you want to use md5 password encryption: - <programlisting> -#%PAM-1.0 -# -# These lines allow a md5 systems to support passwords of at least 14 -# bytes with extra credit of 2 for digits and 2 for others the new -# password must have at least three bytes that are not present in the -# old password -# -password required pam_cracklib.so \ - difok=3 minlen=15 dcredit= 2 ocredit=2 -password required pam_unix.so use_authtok nullok md5 - </programlisting> - </para> - - <para> - And here is another example in case you don't want to use credits: - <programlisting> -#%PAM-1.0 -# -# These lines require the user to select a password with a minimum -# length of 8 and with at least 1 digit number, 1 upper case letter, -# and 1 other character -# -password required pam_cracklib.so \ - dcredit=-1 ucredit=-1 ocredit=-1 lcredit=0 minlen=8 -password required pam_unix.so use_authtok nullok md5 - </programlisting> - </para> - - </refsect1> - - <refsect1 id='pam_cracklib-see_also'> - <title>SEE ALSO</title> - <para> - <citerefentry> - <refentrytitle>pam.conf</refentrytitle><manvolnum>5</manvolnum> - </citerefentry>, - <citerefentry> - <refentrytitle>pam.d</refentrytitle><manvolnum>5</manvolnum> - </citerefentry>, - <citerefentry> - <refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum> - </citerefentry> - </para> - </refsect1> - - <refsect1 id='pam_cracklib-author'> - <title>AUTHOR</title> - <para> - pam_cracklib was written by Cristian Gafton <gafton@redhat.com> - </para> - </refsect1> - -</refentry> diff --git a/modules/pam_cracklib/pam_cracklib.c b/modules/pam_cracklib/pam_cracklib.c deleted file mode 100644 index 01291305..00000000 --- a/modules/pam_cracklib/pam_cracklib.c +++ /dev/null @@ -1,899 +0,0 @@ -/* - * pam_cracklib module - * - * 0.9. switch to using a distance algorithm in similar() - * 0.86. added support for setting minimum numbers of digits, uppers, - * lowers, and others - * 0.85. added six new options to use this with long passwords. - * 0.8. tidied output and improved D(()) usage for debugging. - * 0.7. added support for more obscure checks for new passwd. - * 0.6. root can reset user passwd to any values (it's only warned) - * 0.5. supports retries - 'retry=N' argument - * 0.4. added argument 'type=XXX' for 'New XXX password' prompt - * 0.3. Added argument 'debug' - * 0.2. new password is fed to cracklib for verify after typed once - * 0.1. First release - * - * Written by Cristian Gafton <gafton@redhat.com> 1996/09/10 - * Long password support by Philip W. Dalrymple <pwd@mdtsoft.com> 1997/07/18 - * See the end of the file for Copyright Information - * - * Modification for long password systems (>8 chars). The original - * module had problems when used in a md5 password system in that it - * allowed too short passwords but required that at least half of the - * bytes in the new password did not appear in the old one. this - * action is still the default and the changes should not break any - * current user. This modification adds 6 new options, one to set the - * number of bytes in the new password that are not in the old one, - * the other five to control the length checking, these are all - * documented (or will be before anyone else sees this code) in the PAM - * S.A.G. in the section on the cracklib module. - */ - -#include "config.h" - -#include <stdio.h> -#ifdef HAVE_LIBXCRYPT -# include <xcrypt.h> -#elif defined(HAVE_CRYPT_H) -# include <crypt.h> -#endif -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <stdarg.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <ctype.h> -#include <limits.h> -#include <pwd.h> -#include <security/pam_modutil.h> - -#ifdef HAVE_CRACK_H -#include <crack.h> -#else -extern char *FascistCheck(char *pw, const char *dictpath); -#endif - -#ifndef CRACKLIB_DICTS -#define CRACKLIB_DICTS NULL -#endif - -#ifdef MIN -#undef MIN -#endif -#define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> -#include <security/pam_ext.h> -#include "pam_inline.h" - -/* argument parsing */ -#define PAM_DEBUG_ARG 0x0001 - -struct cracklib_options { - int retry_times; - int diff_ok; - int min_length; - int dig_credit; - int up_credit; - int low_credit; - int oth_credit; - int min_class; - int max_repeat; - int max_sequence; - int max_class_repeat; - int reject_user; - int gecos_check; - int enforce_for_root; - const char *cracklib_dictpath; -}; - -#define CO_RETRY_TIMES 1 -#define CO_DIFF_OK 5 -#define CO_MIN_LENGTH 9 -# define CO_MIN_LENGTH_BASE 5 -#define CO_DIG_CREDIT 1 -#define CO_UP_CREDIT 1 -#define CO_LOW_CREDIT 1 -#define CO_OTH_CREDIT 1 -#define CO_MIN_WORD_LENGTH 4 - -static int -_pam_parse (pam_handle_t *pamh, struct cracklib_options *opt, - int argc, const char **argv) -{ - int ctrl=0; - - /* step through arguments */ - for (ctrl=0; argc-- > 0; ++argv) { - const char *str; - char *ep = NULL; - - /* generic options */ - - if (!strcmp(*argv,"debug")) - ctrl |= PAM_DEBUG_ARG; - else if ((str = pam_str_skip_prefix(*argv, "type=")) != NULL) - pam_set_item (pamh, PAM_AUTHTOK_TYPE, str); - else if ((str = pam_str_skip_prefix(*argv, "retry=")) != NULL) { - opt->retry_times = strtol(str, &ep, 10); - if (!ep || (opt->retry_times < 1)) - opt->retry_times = CO_RETRY_TIMES; - } else if ((str = pam_str_skip_prefix(*argv, "difok=")) != NULL) { - opt->diff_ok = strtol(str, &ep, 10); - if (!ep || (opt->diff_ok < 0)) - opt->diff_ok = CO_DIFF_OK; - } else if (pam_str_skip_prefix(*argv, "difignore=") != NULL) { - /* just ignore */ - } else if ((str = pam_str_skip_prefix(*argv, "minlen=")) != NULL) { - opt->min_length = strtol(str, &ep, 10); - if (!ep || (opt->min_length < CO_MIN_LENGTH_BASE)) - opt->min_length = CO_MIN_LENGTH_BASE; - } else if ((str = pam_str_skip_prefix(*argv, "dcredit=")) != NULL) { - opt->dig_credit = strtol(str, &ep, 10); - if (!ep) - opt->dig_credit = 0; - } else if ((str = pam_str_skip_prefix(*argv, "ucredit=")) != NULL) { - opt->up_credit = strtol(str, &ep, 10); - if (!ep) - opt->up_credit = 0; - } else if ((str = pam_str_skip_prefix(*argv, "lcredit=")) != NULL) { - opt->low_credit = strtol(str, &ep, 10); - if (!ep) - opt->low_credit = 0; - } else if ((str = pam_str_skip_prefix(*argv, "ocredit=")) != NULL) { - opt->oth_credit = strtol(str, &ep, 10); - if (!ep) - opt->oth_credit = 0; - } else if ((str = pam_str_skip_prefix(*argv, "minclass=")) != NULL) { - opt->min_class = strtol(str, &ep, 10); - if (!ep) - opt->min_class = 0; - if (opt->min_class > 4) - opt->min_class = 4; - } else if ((str = pam_str_skip_prefix(*argv, "maxrepeat=")) != NULL) { - opt->max_repeat = strtol(str, &ep, 10); - if (!ep) - opt->max_repeat = 0; - } else if ((str = pam_str_skip_prefix(*argv, "maxsequence=")) != NULL) { - opt->max_sequence = strtol(str, &ep, 10); - if (!ep) - opt->max_sequence = 0; - } else if ((str = pam_str_skip_prefix(*argv, "maxclassrepeat=")) != NULL) { - opt->max_class_repeat = strtol(str, &ep, 10); - if (!ep) - opt->max_class_repeat = 0; - } else if (!strcmp(*argv, "reject_username")) { - opt->reject_user = 1; - } else if (!strcmp(*argv, "gecoscheck")) { - opt->gecos_check = 1; - } else if (!strcmp(*argv, "enforce_for_root")) { - opt->enforce_for_root = 1; - } else if (pam_str_skip_prefix(*argv, "authtok_type=") != NULL) { - /* for pam_get_authtok, ignore */; - } else if (!strcmp(*argv, "use_authtok")) { - /* for pam_get_authtok, ignore */; - } else if (!strcmp(*argv, "use_first_pass")) { - /* for pam_get_authtok, ignore */; - } else if (!strcmp(*argv, "try_first_pass")) { - /* for pam_get_authtok, ignore */; - } else if ((str = pam_str_skip_prefix(*argv, "dictpath=")) != NULL) { - opt->cracklib_dictpath = str; - if (!*(opt->cracklib_dictpath)) { - opt->cracklib_dictpath = CRACKLIB_DICTS; - } - } else { - pam_syslog(pamh,LOG_ERR,"pam_parse: unknown option; %s",*argv); - } - } - - return ctrl; -} - -/* Helper functions */ - -/* - * can't be a palindrome - like `R A D A R' or `M A D A M' - */ -static int palindrome(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; -} - -/* - * Calculate how different two strings are in terms of the number of - * character removals, additions, and changes needed to go from one to - * the other - */ - -static int distdifferent(const char *old, const char *new, - size_t i, size_t j) -{ - char c, d; - - if ((i == 0) || (strlen(old) < i)) { - c = 0; - } else { - c = old[i - 1]; - } - if ((j == 0) || (strlen(new) < j)) { - d = 0; - } else { - d = new[j - 1]; - } - return (c != d); -} - -static int distcalculate(int **distances, const char *old, const char *new, - size_t i, size_t j) -{ - int tmp = 0; - - if (distances[i][j] != -1) { - return distances[i][j]; - } - - tmp = distcalculate(distances, old, new, i - 1, j - 1); - tmp = MIN(tmp, distcalculate(distances, old, new, i, j - 1)); - tmp = MIN(tmp, distcalculate(distances, old, new, i - 1, j)); - tmp += distdifferent(old, new, i, j); - - distances[i][j] = tmp; - - return tmp; -} - -static int distance(const char *old, const char *new) -{ - int **distances = NULL; - size_t m, n, i, j, r; - - m = strlen(old); - n = strlen(new); - distances = malloc(sizeof(int*) * (m + 1)); - - for (i = 0; i <= m; i++) { - distances[i] = malloc(sizeof(int) * (n + 1)); - for(j = 0; j <= n; j++) { - distances[i][j] = -1; - } - } - for (i = 0; i <= m; i++) { - distances[i][0] = i; - } - for (j = 0; j <= n; j++) { - distances[0][j] = j; - } - distances[0][0] = 0; - - r = distcalculate(distances, old, new, m, n); - - for (i = 0; i <= m; i++) { - memset(distances[i], 0, sizeof(int) * (n + 1)); - free(distances[i]); - } - free(distances); - - return r; -} - -static int similar(struct cracklib_options *opt, - const char *old, const char *new) -{ - if (distance(old, new) >= opt->diff_ok) { - return 0; - } - - if (strlen(new) >= (strlen(old) * 2)) { - return 0; - } - - /* passwords are too similar */ - return 1; -} - -/* - * enough classes of characters - */ - -static int minclass (struct cracklib_options *opt, - const char *new) -{ - int digits = 0; - int uppers = 0; - int lowers = 0; - int others = 0; - int total_class; - int i; - int retval; - - D(( "called" )); - for (i = 0; new[i]; i++) - { - if (isdigit (new[i])) - digits = 1; - else if (isupper (new[i])) - uppers = 1; - else if (islower (new[i])) - lowers = 1; - else - others = 1; - } - - total_class = digits + uppers + lowers + others; - - D (("total class: %d\tmin_class: %d", total_class, opt->min_class)); - - if (total_class >= opt->min_class) - retval = 0; - else - retval = 1; - - return retval; -} - - -/* - * a nice mix of characters. - */ -static int simple(struct cracklib_options *opt, const char *new) -{ - int digits = 0; - int uppers = 0; - int lowers = 0; - int others = 0; - int size; - int i; - enum { NONE, DIGIT, UCASE, LCASE, OTHER } prevclass = NONE; - int sameclass = 0; - - for (i = 0;new[i];i++) { - if (isdigit (new[i])) { - digits++; - if (prevclass != DIGIT) { - prevclass = DIGIT; - sameclass = 1; - } else - sameclass++; - } - else if (isupper (new[i])) { - uppers++; - if (prevclass != UCASE) { - prevclass = UCASE; - sameclass = 1; - } else - sameclass++; - } - else if (islower (new[i])) { - lowers++; - if (prevclass != LCASE) { - prevclass = LCASE; - sameclass = 1; - } else - sameclass++; - } - else { - others++; - if (prevclass != OTHER) { - prevclass = OTHER; - sameclass = 1; - } else - sameclass++; - } - if (opt->max_class_repeat > 0 && sameclass > opt->max_class_repeat) { - return 1; - } - } - - /* - * The scam was this - a password of only one character type - * must be 8 letters long. Two types, 7, and so on. - * This is now changed, the base size and the credits or defaults - * see the docs on the module for info on these parameters, the - * defaults cause the effect to be the same as before the change - */ - - if ((opt->dig_credit >= 0) && (digits > opt->dig_credit)) - digits = opt->dig_credit; - - if ((opt->up_credit >= 0) && (uppers > opt->up_credit)) - uppers = opt->up_credit; - - if ((opt->low_credit >= 0) && (lowers > opt->low_credit)) - lowers = opt->low_credit; - - if ((opt->oth_credit >= 0) && (others > opt->oth_credit)) - others = opt->oth_credit; - - size = opt->min_length; - - if (opt->dig_credit >= 0) - size -= digits; - else if (digits < opt->dig_credit * -1) - return 1; - - if (opt->up_credit >= 0) - size -= uppers; - else if (uppers < opt->up_credit * -1) - return 1; - - if (opt->low_credit >= 0) - size -= lowers; - else if (lowers < opt->low_credit * -1) - return 1; - - if (opt->oth_credit >= 0) - size -= others; - else if (others < opt->oth_credit * -1) - return 1; - - if (size <= i) - return 0; - - 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 sequence(struct cracklib_options *opt, const char *new) -{ - char c; - int i; - int sequp = 1; - int seqdown = 1; - - if (opt->max_sequence == 0) - return 0; - - if (new[0] == '\0') - return 0; - - for (i = 1; new[i]; i++) { - c = new[i-1]; - if (new[i] == c+1) { - ++sequp; - if (sequp > opt->max_sequence) - return 1; - seqdown = 1; - } else if (new[i] == c-1) { - ++seqdown; - if (seqdown > opt->max_sequence) - return 1; - sequp = 1; - } else { - sequp = 1; - seqdown = 1; - } - } - return 0; -} - -static int wordcheck(const char *new, char *word) -{ - char *f, *b; - - if (strstr(new, word) != NULL) - return 1; - - /* now reverse the word, we can do that in place - as it is strdup-ed */ - f = word; - b = word+strlen(word)-1; - while (f < b) { - char c; - - c = *f; - *f = *b; - *b = c; - --b; - ++f; - } - - if (strstr(new, word) != NULL) - return 1; - return 0; -} - -static int usercheck(struct cracklib_options *opt, const char *new, - char *user) -{ - if (!opt->reject_user) - return 0; - - return wordcheck(new, user); -} - -static char * str_lower(char *string) -{ - char *cp; - - if (!string) - return NULL; - - for (cp = string; *cp; cp++) - *cp = tolower(*cp); - return string; -} - -static int gecoscheck(pam_handle_t *pamh, struct cracklib_options *opt, const char *new, - const char *user) -{ - struct passwd *pwd; - char *list; - char *p; - char *next; - - if (!opt->gecos_check) - return 0; - - if ((pwd = pam_modutil_getpwnam(pamh, user)) == NULL) { - return 0; - } - - list = strdup(pwd->pw_gecos); - - if (list == NULL || *list == '\0') { - free(list); - return 0; - } - - for (p = list;;p = next + 1) { - next = strchr(p, ' '); - if (next) - *next = '\0'; - - if (strlen(p) >= CO_MIN_WORD_LENGTH) { - str_lower(p); - if (wordcheck(new, p)) { - free(list); - return 1; - } - } - - if (!next) - break; - } - - free(list); - return 0; -} - -static const char *password_check(pam_handle_t *pamh, struct cracklib_options *opt, - 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"); - return msg; - } - - newmono = str_lower(strdup(new)); - if (!newmono) - msg = _("memory allocation error"); - - usermono = str_lower(strdup(user)); - if (!usermono) - msg = _("memory allocation error"); - - if (!msg && old) { - oldmono = str_lower(strdup(old)); - if (oldmono) - wrapped = malloc(strlen(oldmono) * 2 + 1); - if (wrapped) { - strcpy (wrapped, oldmono); - strcat (wrapped, oldmono); - } else { - msg = _("memory allocation error"); - } - } - - if (!msg && palindrome(newmono)) - msg = _("is a palindrome"); - - if (!msg && oldmono && strcmp(oldmono, newmono) == 0) - msg = _("case changes only"); - - if (!msg && oldmono && similar(opt, oldmono, newmono)) - msg = _("is too similar to the old one"); - - if (!msg && simple(opt, new)) - msg = _("is too simple"); - - if (!msg && wrapped && strstr(wrapped, newmono)) - msg = _("is rotated"); - - if (!msg && minclass (opt, new)) - msg = _("not enough character classes"); - - if (!msg && consecutive(opt, new)) - msg = _("contains too many same characters consecutively"); - - if (!msg && sequence(opt, new)) - msg = _("contains too long of a monotonic character sequence"); - - if (!msg && (usercheck(opt, newmono, usermono) || gecoscheck(pamh, opt, newmono, user))) - msg = _("contains the user name in some form"); - - free(usermono); - if (newmono) { - memset(newmono, 0, strlen(newmono)); - free(newmono); - } - if (oldmono) { - memset(oldmono, 0, strlen(oldmono)); - free(oldmono); - } - if (wrapped) { - memset(wrapped, 0, strlen(wrapped)); - free(wrapped); - } - - return msg; -} - - -static int _pam_unix_approve_pass(pam_handle_t *pamh, - unsigned int ctrl, - struct cracklib_options *opt, - const char *pass_old, - const char *pass_new) -{ - const char *msg = NULL; - const char *user; - int retval; - - if (pass_new == NULL || (pass_old && !strcmp(pass_old,pass_new))) { - if (ctrl & PAM_DEBUG_ARG) - pam_syslog(pamh, LOG_DEBUG, "bad authentication token"); - pam_error(pamh, "%s", pass_new == NULL ? - _("No password has been supplied.") : - _("The password has not been changed.")); - return PAM_AUTHTOK_ERR; - } - - retval = pam_get_user(pamh, &user, NULL); - if (retval != PAM_SUCCESS) { - if (ctrl & PAM_DEBUG_ARG) - pam_syslog(pamh, LOG_NOTICE, "cannot determine user name: %s", - pam_strerror(pamh, retval)); - return PAM_AUTHTOK_ERR; - } - /* - * if one wanted to hardwire authentication token strength - * checking this would be the place - */ - msg = password_check(pamh, opt, pass_old, pass_new, user); - - if (msg) { - if (ctrl & PAM_DEBUG_ARG) - pam_syslog(pamh, LOG_NOTICE, - "new passwd fails strength check: %s", msg); - pam_error(pamh, _("BAD PASSWORD: %s"), msg); - return PAM_AUTHTOK_ERR; - }; - return PAM_SUCCESS; - -} - -/* The Main Thing (by Cristian Gafton, CEO at this module :-) - * (stolen from http://home.netscape.com) - */ -int -pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) -{ - unsigned int ctrl; - struct cracklib_options options; - - D(("called.")); - - memset(&options, 0, sizeof(options)); - options.retry_times = CO_RETRY_TIMES; - options.diff_ok = CO_DIFF_OK; - options.min_length = CO_MIN_LENGTH; - options.dig_credit = CO_DIG_CREDIT; - options.up_credit = CO_UP_CREDIT; - options.low_credit = CO_LOW_CREDIT; - options.oth_credit = CO_OTH_CREDIT; - options.cracklib_dictpath = CRACKLIB_DICTS; - - ctrl = _pam_parse(pamh, &options, argc, argv); - - if (flags & PAM_PRELIM_CHECK) { - /* Check for passwd dictionary */ - /* We cannot do that, since the original path is compiled - into the cracklib library and we don't know it. */ - return PAM_SUCCESS; - } else if (flags & PAM_UPDATE_AUTHTOK) { - int retval; - const void *oldtoken; - int tries; - - D(("do update")); - - - retval = pam_get_item (pamh, PAM_OLDAUTHTOK, &oldtoken); - if (retval != PAM_SUCCESS) { - if (ctrl & PAM_DEBUG_ARG) - pam_syslog(pamh,LOG_ERR,"Can not get old passwd"); - oldtoken = NULL; - } - - tries = 0; - while (tries < options.retry_times) { - const char *crack_msg; - const char *newtoken = NULL; - - - tries++; - - /* Planned modus operandi: - * Get a passwd. - * Verify it against cracklib. - * If okay get it a second time. - * Check to be the same with the first one. - * set PAM_AUTHTOK and return - */ - - retval = pam_get_authtok_noverify (pamh, &newtoken, NULL); - if (retval != PAM_SUCCESS) { - pam_syslog(pamh, LOG_ERR, "pam_get_authtok_noverify returned error: %s", - pam_strerror (pamh, retval)); - continue; - } else if (newtoken == NULL) { /* user aborted password change, quit */ - return PAM_AUTHTOK_ERR; - } - - D(("testing password")); - /* now test this passwd against cracklib */ - - D(("against cracklib")); - if ((crack_msg = FascistCheck (newtoken, options.cracklib_dictpath))) { - if (ctrl & PAM_DEBUG_ARG) - pam_syslog(pamh,LOG_DEBUG,"bad password: %s",crack_msg); - pam_error (pamh, _("BAD PASSWORD: %s"), crack_msg); - if (getuid() || options.enforce_for_root || (flags & PAM_CHANGE_EXPIRED_AUTHTOK)) - { - pam_set_item (pamh, PAM_AUTHTOK, NULL); - retval = PAM_AUTHTOK_ERR; - continue; - } - } - - /* check it for strength too... */ - D(("for strength")); - retval = _pam_unix_approve_pass (pamh, ctrl, &options, - oldtoken, newtoken); - if (retval != PAM_SUCCESS) { - if (getuid() || options.enforce_for_root || (flags & PAM_CHANGE_EXPIRED_AUTHTOK)) - { - pam_set_item(pamh, PAM_AUTHTOK, NULL); - retval = PAM_AUTHTOK_ERR; - continue; - } - } - - retval = pam_get_authtok_verify (pamh, &newtoken, NULL); - if (retval != PAM_SUCCESS) { - pam_syslog(pamh, LOG_ERR, "pam_get_authtok_verify returned error: %s", - pam_strerror (pamh, retval)); - pam_set_item(pamh, PAM_AUTHTOK, NULL); - continue; - } else if (newtoken == NULL) { /* user aborted password change, quit */ - return PAM_AUTHTOK_ERR; - } - - return PAM_SUCCESS; - } - - D(("returning because maxtries reached")); - - pam_set_item (pamh, PAM_AUTHTOK, NULL); - - /* if we have only one try, we can use the real reason, - else say that there were too many tries. */ - if (options.retry_times > 1) - return PAM_MAXTRIES; - else - return retval; - - } else { - if (ctrl & PAM_DEBUG_ARG) - pam_syslog(pamh, LOG_NOTICE, "UNKNOWN flags setting %02X",flags); - return PAM_SERVICE_ERR; - } - - /* Not reached */ - return PAM_SERVICE_ERR; -} - - - -/* - * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1996. - * 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, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 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. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED `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 THE AUTHOR 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. - * - * The following copyright was appended for the long password support - * added with the libpam 0.58 release: - * - * Modificaton Copyright (c) Philip W. Dalrymple III <pwd@mdtsoft.com> - * 1997. All rights reserved - * - * THE MODIFICATION THAT PROVIDES SUPPORT FOR LONG PASSWORD TYPE CHECKING TO - * THIS SOFTWARE IS PROVIDED `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 THE AUTHOR 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. - */ diff --git a/modules/pam_cracklib/tst-pam_cracklib b/modules/pam_cracklib/tst-pam_cracklib deleted file mode 100755 index 46a7060d..00000000 --- a/modules/pam_cracklib/tst-pam_cracklib +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -../../tests/tst-dlopen .libs/pam_cracklib.so diff --git a/modules/pam_pwhistory/pam_pwhistory.8.xml b/modules/pam_pwhistory/pam_pwhistory.8.xml index 9e1056b2..d88115c2 100644 --- a/modules/pam_pwhistory/pam_pwhistory.8.xml +++ b/modules/pam_pwhistory/pam_pwhistory.8.xml @@ -83,7 +83,7 @@ When password changing enforce the module to use the new password provided by a previously stacked <option>password</option> module (this is used in the example of the stacking of the - <command>pam_cracklib</command> module documented below). + <command>pam_passwdqc</command> module documented below). </para> </listitem> </varlistentry> @@ -197,10 +197,10 @@ password required pam_unix.so use_authtok </programlisting> </para> <para> - In combination with <command>pam_cracklib</command>: + In combination with <command>pam_passwdqc</command>: <programlisting> #%PAM-1.0 -password required pam_cracklib.so retry=3 +password required pam_passwdqc.so config=/etc/passwdqc.conf password required pam_pwhistory.so use_authtok password required pam_unix.so use_authtok </programlisting> diff --git a/modules/pam_unix/pam_unix.8.xml b/modules/pam_unix/pam_unix.8.xml index fa02c3a6..9f9c8185 100644 --- a/modules/pam_unix/pam_unix.8.xml +++ b/modules/pam_unix/pam_unix.8.xml @@ -223,7 +223,7 @@ When password changing enforce the module to set the new password to the one provided by a previously stacked <option>password</option> module (this is used in the - example of the stacking of the <command>pam_cracklib</command> + example of the stacking of the <command>pam_passwdqc</command> module documented below). </para> </listitem> @@ -465,8 +465,8 @@ auth required pam_unix.so # Ensure users account and password are still active account required pam_unix.so # Change the user's password, but at first check the strength -# with pam_cracklib(8) -password required pam_cracklib.so retry=3 minlen=6 difok=3 +# with pam_passwdqc(8) +password required pam_passwdqc.so config=/etc/passwdqc.conf password required pam_unix.so use_authtok nullok yescrypt session required pam_unix.so </programlisting> diff --git a/po/POTFILES.in b/po/POTFILES.in index f96264b9..cb4ad62f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -33,7 +33,6 @@ ./libpam/pam_syslog.c ./libpam/pam_vprompt.c ./modules/pam_access/pam_access.c -./modules/pam_cracklib/pam_cracklib.c ./modules/pam_debug/pam_debug.c ./modules/pam_deny/pam_deny.c ./modules/pam_echo/pam_echo.c diff --git a/xtests/.gitignore b/xtests/.gitignore index cd311127..41d2056b 100644 --- a/xtests/.gitignore +++ b/xtests/.gitignore @@ -7,8 +7,6 @@ tst-pam_dispatch2 tst-pam_dispatch3 tst-pam_dispatch4 tst-pam_dispatch5 -tst-pam_cracklib1 -tst-pam_cracklib2 tst-pam_limits1 tst-pam_unix1 tst-pam_unix2 diff --git a/xtests/Makefile.am b/xtests/Makefile.am index 2e942e8d..70f8441e 100644 --- a/xtests/Makefile.am +++ b/xtests/Makefile.am @@ -13,7 +13,6 @@ CLEANFILES = *~ $(XTESTS) EXTRA_DIST = run-xtests.sh tst-pam_dispatch1.pamd tst-pam_dispatch2.pamd \ tst-pam_dispatch3.pamd tst-pam_dispatch4.pamd \ tst-pam_dispatch5.pamd \ - tst-pam_cracklib1.pamd tst-pam_cracklib2.pamd \ tst-pam_unix1.pamd tst-pam_unix2.pamd tst-pam_unix3.pamd \ tst-pam_unix4.pamd \ tst-pam_unix1.sh tst-pam_unix2.sh tst-pam_unix3.sh \ @@ -40,7 +39,6 @@ EXTRA_DIST = run-xtests.sh tst-pam_dispatch1.pamd tst-pam_dispatch2.pamd \ XTESTS = tst-pam_dispatch1 tst-pam_dispatch2 tst-pam_dispatch3 \ tst-pam_dispatch4 tst-pam_dispatch5 \ - tst-pam_cracklib1 tst-pam_cracklib2 \ tst-pam_unix1 tst-pam_unix2 tst-pam_unix3 tst-pam_unix4 \ tst-pam_access1 tst-pam_access2 tst-pam_access3 \ tst-pam_access4 tst-pam_limits1 tst-pam_succeed_if1 \ diff --git a/xtests/tst-pam_cracklib1.c b/xtests/tst-pam_cracklib1.c deleted file mode 100644 index 1a219c83..00000000 --- a/xtests/tst-pam_cracklib1.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 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. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``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 THE AUTHOR 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. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <security/pam_appl.h> - -/* A conversation function which uses an internally-stored value for - the responses. */ -static int -fake_conv (int num_msg, const struct pam_message **msgm UNUSED, - struct pam_response **response, void *appdata_ptr UNUSED) -{ - static int calls = 0; - struct pam_response *reply; - int count; - - /* Sanity test. */ - if (num_msg <= 0) - return PAM_CONV_ERR; - - /* Allocate memory for the responses. */ - reply = calloc (num_msg, sizeof (struct pam_response)); - if (reply == NULL) - return PAM_CONV_ERR; - - /* Each prompt elicits the same response. */ - for (count = 0; count < num_msg; ++count) - { - reply[count].resp_retcode = 0; - /* first call get a password, second one NULL */ - if (calls) - reply[count].resp = NULL; - else - { - ++calls; - reply[count].resp = strdup ("Kindergarten"); - } - } - - /* Set the pointers in the response structure and return. */ - *response = reply; - return PAM_SUCCESS; -} - -static struct pam_conv conv = { - fake_conv, - NULL -}; - - -/* Check that pam_cracklib does not seg.fault on empty passwords. */ - -int -main(int argc, char *argv[]) -{ - pam_handle_t *pamh=NULL; - const char *user="root"; - int retval; - int debug = 0; - - if (argc > 1 && strcmp (argv[1], "-d") == 0) - debug = 1; - - retval = pam_start("tst-pam_cracklib1", user, &conv, &pamh); - if (retval != PAM_SUCCESS) - { - if (debug) - fprintf (stderr, "cracklib1: pam_start returned %d\n", retval); - return 1; - } - - /* Try one, first input is correct, second is NULL */ - retval = pam_chauthtok (pamh, 0); - if (retval != PAM_AUTHTOK_ERR) - { - if (debug) - fprintf (stderr, "cracklib1-1: pam_chauthtok returned %d\n", retval); - return 1; - } - - /* Try two, second input is NULL */ - retval = pam_chauthtok (pamh, 0); - if (retval != PAM_AUTHTOK_ERR) - { - if (debug) - fprintf (stderr, "cracklib1-2: pam_chauthtok returned %d\n", retval); - return 1; - } - - - retval = pam_end (pamh,retval); - if (retval != PAM_SUCCESS) - { - if (debug) - fprintf (stderr, "cracklib1: pam_end returned %d\n", retval); - return 1; - } - return 0; -} diff --git a/xtests/tst-pam_cracklib1.pamd b/xtests/tst-pam_cracklib1.pamd deleted file mode 100644 index 41a9188d..00000000 --- a/xtests/tst-pam_cracklib1.pamd +++ /dev/null @@ -1,2 +0,0 @@ -#%PAM-1.0 -password required pam_cracklib.so diff --git a/xtests/tst-pam_cracklib2.c b/xtests/tst-pam_cracklib2.c deleted file mode 100644 index 84b4ef64..00000000 --- a/xtests/tst-pam_cracklib2.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 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. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``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 THE AUTHOR 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. - */ - -/* This test case checks - Patch 1688777: pam_cracklib support for minimum character classes */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <security/pam_appl.h> - -int debug = 0; - -/* A conversation function which uses an internally-stored value for - the responses. */ -static int -fake_conv (int num_msg, const struct pam_message **msgm, - struct pam_response **response, void *appdata_ptr UNUSED) -{ - static int calls = 0; - struct pam_response *reply; - int count; - - /* Sanity test. */ - if (num_msg <= 0) - return PAM_CONV_ERR; - - /* Allocate memory for the responses. */ - reply = calloc (num_msg, sizeof (struct pam_response)); - if (reply == NULL) - return PAM_CONV_ERR; - - /* Each prompt elicits the same response. */ - for (count = 0; count < num_msg; ++count) - { - if (debug) - fprintf(stderr,"Query: %s\n", (*msgm)[count].msg); - reply[count].resp_retcode = 0; - /* first tow calls get a correct password, second a too - easy one. */ - if (calls > 1) - reply[count].resp = strdup ("too easy"); - else - { - ++calls; - reply[count].resp = strdup ("1a9C*8dK"); - } - if (debug) - fprintf(stderr,"Response: %s\n", reply[count].resp); - } - - /* Set the pointers in the response structure and return. */ - *response = reply; - return PAM_SUCCESS; -} - -static struct pam_conv conv = { - fake_conv, - NULL -}; - - -int -main(int argc, char *argv[]) -{ - pam_handle_t *pamh=NULL; - const char *user="root"; - int retval; - - if (argc > 1 && strcmp (argv[1], "-d") == 0) - debug = 1; - - retval = pam_start("tst-pam_cracklib2", user, &conv, &pamh); - if (retval != PAM_SUCCESS) - { - if (debug) - fprintf (stderr, "cracklib2: pam_start returned %d\n", retval); - return 1; - } - - /* Try one, first input is correct */ - retval = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK); - if (retval != PAM_SUCCESS) - { - if (debug) - fprintf (stderr, "cracklib2-1: pam_chauthtok returned %d\n", retval); - return 1; - } - - /* Try two, second input is wrong */ - retval = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK); - if (retval != PAM_AUTHTOK_ERR) - { - if (debug) - fprintf (stderr, "cracklib2-2: pam_chauthtok returned %d\n", retval); - return 1; - } - - - retval = pam_end (pamh,retval); - if (retval != PAM_SUCCESS) - { - if (debug) - fprintf (stderr, "cracklib2: pam_end returned %d\n", retval); - return 1; - } - return 0; -} diff --git a/xtests/tst-pam_cracklib2.pamd b/xtests/tst-pam_cracklib2.pamd deleted file mode 100644 index 5915aecd..00000000 --- a/xtests/tst-pam_cracklib2.pamd +++ /dev/null @@ -1,2 +0,0 @@ -#%PAM-1.0 -password required pam_cracklib.so minclass=4 |