From d702ff714c309069111899fd07c09e31c414c166 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" 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 # -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 -# - -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 @@ - - ---> -]> - -
- - - - - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="pam_cracklib.8.xml" xpointer='xpointer(//refnamediv[@id = "pam_cracklib-name"]/*)'/> - - - - -
- -
- -
- -
- -
- -
- -
- -
- -
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 @@ - - - - - - - pam_cracklib - 8 - Linux-PAM Manual - - - - pam_cracklib - PAM module to check the password against dictionary words - - - - - pam_cracklib.so - - ... - - - - - - - DESCRIPTION - - - This module can be plugged into the password stack of - a given application to provide some plug-in strength-checking for passwords. - - - - 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. - - - - 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. - - - - The strength checks works in the following manner: at first the - Cracklib 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: - - - - - Palindrome - - - Is the new password a palindrome? - - - - - Case Change Only - - - Is the new password the old one with only a change of case? - - - - - Similar - - - Is the new password too much like the old one? - This is primarily controlled by one argument, - 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. - - - - - Simple - - - Is the new password too small? - This is controlled by 6 arguments , - , - , , - , and . See the section - on the arguments for the details of how these work and there defaults. - - - - - Rotated - - - Is the new password a rotated version of the old password? - - - - - Same consecutive characters - - - Optional check for same consecutive characters. - - - - - Too long monotonic character sequence - - - Optional check for too long monotonic character sequence. - - - - - Contains user name - - - Optional check whether the password contains the user's name - in some form. - - - - - - 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. - - - - - - - OPTIONS - - - - - - - - - - This option makes the module write information to - - syslog3 - - indicating the behavior of the module (this option does - not write password information to the log file). - - - - - - - - - - - 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 UNIX can - be replaced with this option, by default it is empty. - - - - - - - - - - - Prompt user at most N times - before returning with error. The default is - 1. - - - - - - - - - - - This argument will change the default of - 5 for the number of character - changes in the new password that differentiate it - from the old password. - - - - - - - - - - - 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 (other, - upper, lower and - digit). The default for this parameter - is 9 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 - Cracklib 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 . - If you want to allow passwords as short as 5 characters you - should not use this module. - - - - - - - - - - - (N >= 0) This is the maximum credit for having digits in - the new password. If you have less than or - N - digits, each digit will count +1 towards meeting the current - value. The default for - is 1 which is the recommended - value for less than 10. - - - (N < 0) This is the minimum number of digits that must - be met for a new password. - - - - - - - - - - - (N >= 0) This is the maximum credit for having upper - case letters in the new password. If you have less than - or N upper case letters each - letter will count +1 towards meeting the current - value. The default for - is 1 which - is the recommended value for less - than 10. - - - (N < 0) This is the minimum number of upper - case letters that must be met for a new password. - - - - - - - - - - - (N >= 0) This is the maximum credit for having - lower case letters in the new password. If you have - less than or N lower case - letters, each letter will count +1 towards meeting the - current value. The default for - is 1 which is the recommended - value for less than 10. - - - (N < 0) This is the minimum number of lower - case letters that must be met for a new password. - - - - - - - - - - - (N >= 0) This is the maximum credit for having other - characters in the new password. If you have less than or - N other characters, each - character will count +1 towards meeting the current - value. The default for - is 1 which is the recommended - value for less than 10. - - - (N < 0) This is the minimum number of other - characters that must be met for a new password. - - - - - - - - - - - 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 check is - that a specific class if of characters is not required. - Instead N out of four of the - classes are required. - - - - - - - - - - - Reject passwords which contain more than N same consecutive - characters. The default is 0 which means that this check - is disabled. - - - - - - - - - - - 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. - - - - - - - - - - - Reject passwords which contain more than N consecutive - characters of the same class. The default is 0 which means - that this check is disabled. - - - - - - - - - - - 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. - - - - - - - - - - - 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. - - - - - - - - - - - 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. - - - - - - - - - - - This argument is used to force the - module to not prompt the user for a new password but use - the one provided by the previously stacked - password module. - - - - - - - - - - - Path to the cracklib dictionaries. - - - - - - - - - - MODULE TYPES PROVIDED - - Only the module type is provided. - - - - - RETURN VALUES - - - - - PAM_SUCCESS - - - The new password passes all checks. - - - - - - PAM_AUTHTOK_ERR - - - No new password was entered, - the username could not be determined or the new - password fails the strength checks. - - - - - - PAM_AUTHTOK_RECOVERY_ERR - - - The old password was not supplied by a previous stacked - module or got not requested from the user. - The first error can happen if - is specified. - - - - - - PAM_SERVICE_ERR - - - A internal error occurred. - - - - - - - - - - EXAMPLES - - For an example of the use of this module, we show how it may be - stacked with the password component of - - pam_unix8 - - -# -# 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 - - - - - Another example (in the /etc/pam.d/passwd format) - is for the case that you want to use md5 password encryption: - -#%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 - - - - - And here is another example in case you don't want to use credits: - -#%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 - - - - - - - SEE ALSO - - - pam.conf5 - , - - pam.d5 - , - - pam8 - - - - - - AUTHOR - - pam_cracklib was written by Cristian Gafton <gafton@redhat.com> - - - - 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 1996/09/10 - * Long password support by Philip W. Dalrymple 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 -#ifdef HAVE_LIBXCRYPT -# include -#elif defined(HAVE_CRYPT_H) -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_CRACK_H -#include -#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 -#include -#include -#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 , 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 - * 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