c4daf63ae5
- obsoletes pam-bsc1178727-initialize-daysleft.patch - Multiple minor bug fixes, portability fixes, and documentation improvements. - Extended libpam API with pam_modutil_check_user_in_passwd function. - pam_faillock: changed /run/faillock/$USER permissions from 0600 to 0660. - pam_motd: read motd files with target user credentials skipping unreadable ones. - pam_pwhistory: added a SELinux helper executable. - pam_unix, pam_usertype: implemented avoidance of certain timing attacks. - pam_wheel: implemented PAM_RUSER fallback for the case when getlogin fails. - pam_env: Reading of the user environment is deprecated and will be removed at some point in the future. - libpam: pam_modutil_drop_priv() now correctly sets the target user's supplementary groups, allowing pam_motd to filter messages accordingly - Refresh pam-xauth_ownership.patch - pam_tally2-removal.patch: Re-add pam_tally2 for deprecated sub-package - pam_cracklib-removal.patch: Re-add pam_cracklib for deprecated sub-package OBS-URL: https://build.opensuse.org/package/show/Linux-PAM/pam?expand=0&rev=228
1741 lines
54 KiB
Diff
1741 lines
54 KiB
Diff
From d702ff714c309069111899fd07c09e31c414c166 Mon Sep 17 00:00:00 2001
|
|
From: "Dmitry V. Levin" <ldv@altlinux.org>
|
|
Date: Thu, 29 Oct 2020 08:00:00 +0000
|
|
Subject: [PATCH] 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.
|
|
---
|
|
NEWS | 2 +
|
|
ci/install-dependencies.sh | 1 -
|
|
ci/run-build-and-tests.sh | 2 +-
|
|
conf/pam.conf | 5 -
|
|
configure.ac | 25 +-
|
|
doc/sag/Linux-PAM_SAG.xml | 2 -
|
|
doc/sag/pam_cracklib.xml | 34 -
|
|
modules/Makefile.am | 5 -
|
|
modules/pam_cracklib/Makefile.am | 33 -
|
|
modules/pam_cracklib/README.xml | 41 -
|
|
modules/pam_cracklib/pam_cracklib.8.xml | 592 --------------
|
|
modules/pam_cracklib/pam_cracklib.c | 899 ----------------------
|
|
modules/pam_cracklib/tst-pam_cracklib | 2 -
|
|
modules/pam_pwhistory/pam_pwhistory.8.xml | 6 +-
|
|
modules/pam_unix/pam_unix.8.xml | 6 +-
|
|
po/POTFILES.in | 1 -
|
|
xtests/.gitignore | 2 -
|
|
xtests/Makefile.am | 2 -
|
|
xtests/tst-pam_cracklib1.c | 135 ----
|
|
xtests/tst-pam_cracklib1.pamd | 2 -
|
|
xtests/tst-pam_cracklib2.c | 143 ----
|
|
xtests/tst-pam_cracklib2.pamd | 2 -
|
|
22 files changed, 10 insertions(+), 1932 deletions(-)
|
|
delete mode 100644 doc/sag/pam_cracklib.xml
|
|
delete mode 100644 modules/pam_cracklib/Makefile.am
|
|
delete mode 100644 modules/pam_cracklib/README.xml
|
|
delete mode 100644 modules/pam_cracklib/pam_cracklib.8.xml
|
|
delete mode 100644 modules/pam_cracklib/pam_cracklib.c
|
|
delete mode 100755 modules/pam_cracklib/tst-pam_cracklib
|
|
delete mode 100644 xtests/tst-pam_cracklib1.c
|
|
delete mode 100644 xtests/tst-pam_cracklib1.pamd
|
|
delete mode 100644 xtests/tst-pam_cracklib2.c
|
|
delete mode 100644 xtests/tst-pam_cracklib2.pamd
|
|
|
|
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/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
|