summaryrefslogtreecommitdiff
path: root/modules/pam_faillock
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pam_faillock')
-rw-r--r--modules/pam_faillock/Makefile.am4
-rw-r--r--modules/pam_faillock/Makefile.in38
-rw-r--r--modules/pam_faillock/README2
-rw-r--r--modules/pam_faillock/faillock.84
-rw-r--r--modules/pam_faillock/faillock.c17
-rw-r--r--modules/pam_faillock/faillock.conf.59
-rw-r--r--modules/pam_faillock/faillock.conf.5.xml10
-rw-r--r--modules/pam_faillock/main.c7
-rw-r--r--modules/pam_faillock/pam_faillock.86
-rw-r--r--modules/pam_faillock/pam_faillock.8.xml2
-rw-r--r--modules/pam_faillock/pam_faillock.c75
11 files changed, 98 insertions, 76 deletions
diff --git a/modules/pam_faillock/Makefile.am b/modules/pam_faillock/Makefile.am
index b1f2b3e5..44a49660 100644
--- a/modules/pam_faillock/Makefile.am
+++ b/modules/pam_faillock/Makefile.am
@@ -25,7 +25,7 @@ noinst_HEADERS = faillock.h
AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \
$(WARN_CFLAGS)
-faillock_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@
+faillock_CFLAGS = $(AM_CFLAGS) @EXE_CFLAGS@
pam_faillock_la_LDFLAGS = -no-undefined -avoid-version -module
pam_faillock_la_LIBADD = $(top_builddir)/libpam/libpam.la $(LIBAUDIT)
@@ -33,7 +33,7 @@ if HAVE_VERSIONING
pam_faillock_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map
endif
-faillock_LDFLAGS = @PIE_LDFLAGS@
+faillock_LDFLAGS = @EXE_LDFLAGS@
faillock_LDADD = $(top_builddir)/libpam/libpam.la $(LIBAUDIT)
dist_secureconf_DATA = faillock.conf
diff --git a/modules/pam_faillock/Makefile.in b/modules/pam_faillock/Makefile.in
index b2a80262..9070f173 100644
--- a/modules/pam_faillock/Makefile.in
+++ b/modules/pam_faillock/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -101,18 +101,21 @@ host_triplet = @host@
sbin_PROGRAMS = faillock$(EXEEXT)
subdir = modules/pam_faillock
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \
- $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
- $(top_srcdir)/m4/japhar_grep_cflags.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 \
$(top_srcdir)/m4/jh_path_xml_catalog.m4 \
$(top_srcdir)/m4/ld-O1.m4 $(top_srcdir)/m4/ld-as-needed.m4 \
- $(top_srcdir)/m4/ld-no-undefined.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/ld-no-undefined.m4 \
+ $(top_srcdir)/m4/ld-z-now.m4 $(top_srcdir)/m4/lib-ld.m4 \
$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
$(top_srcdir)/m4/libprelude.m4 $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
- $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/m4/warn_lang_flags.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(dist_check_SCRIPTS) \
@@ -400,6 +403,7 @@ am__set_TESTS_bases = \
bases='$(TEST_LOGS)'; \
bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
RECHECK_LOGS = $(TEST_LOGS)
AM_RECURSIVE_TARGETS = check recheck
TEST_SUITE_LOG = test-suite.log
@@ -444,6 +448,9 @@ CC_FOR_BUILD = @CC_FOR_BUILD@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
+CRYPTO_LIBS = @CRYPTO_LIBS@
+CRYPT_CFLAGS = @CRYPT_CFLAGS@
+CRYPT_LIBS = @CRYPT_LIBS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
@@ -457,6 +464,8 @@ ECONF_CFLAGS = @ECONF_CFLAGS@
ECONF_LIBS = @ECONF_LIBS@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
+EXE_CFLAGS = @EXE_CFLAGS@
+EXE_LDFLAGS = @EXE_LDFLAGS@
FGREP = @FGREP@
FO2PDF = @FO2PDF@
GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
@@ -476,7 +485,6 @@ LEX = @LEX@
LEXLIB = @LEXLIB@
LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
LIBAUDIT = @LIBAUDIT@
-LIBCRACK = @LIBCRACK@
LIBCRYPT = @LIBCRYPT@
LIBDB = @LIBDB@
LIBDL = @LIBDL@
@@ -523,8 +531,6 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
-PIE_CFLAGS = @PIE_CFLAGS@
-PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
@@ -535,6 +541,7 @@ SECUREDIR = @SECUREDIR@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
+STRINGPARAM_HMAC = @STRINGPARAM_HMAC@
STRINGPARAM_VENDORDIR = @STRINGPARAM_VENDORDIR@
STRIP = @STRIP@
TIRPC_CFLAGS = @TIRPC_CFLAGS@
@@ -584,7 +591,6 @@ htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
-libc_cv_fpie = @libc_cv_fpie@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
@@ -592,9 +598,6 @@ localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
-pam_cv_ld_O1 = @pam_cv_ld_O1@
-pam_cv_ld_as_needed = @pam_cv_ld_as_needed@
-pam_cv_ld_no_undefined = @pam_cv_ld_no_undefined@
pam_xauth_path = @pam_xauth_path@
pdfdir = @pdfdir@
prefix = @prefix@
@@ -604,6 +607,7 @@ sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
+systemdunitdir = @systemdunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
@@ -621,11 +625,11 @@ noinst_HEADERS = faillock.h
AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \
$(WARN_CFLAGS)
-faillock_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@
+faillock_CFLAGS = $(AM_CFLAGS) @EXE_CFLAGS@
pam_faillock_la_LDFLAGS = -no-undefined -avoid-version -module \
$(am__append_1)
pam_faillock_la_LIBADD = $(top_builddir)/libpam/libpam.la $(LIBAUDIT)
-faillock_LDFLAGS = @PIE_LDFLAGS@
+faillock_LDFLAGS = @EXE_LDFLAGS@
faillock_LDADD = $(top_builddir)/libpam/libpam.la $(LIBAUDIT)
dist_secureconf_DATA = faillock.conf
securelib_LTLIBRARIES = pam_faillock.la
@@ -1095,7 +1099,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS)
test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
fi; \
echo "$${col}$$br$${std}"; \
- echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
echo "$${col}$$br$${std}"; \
create_testsuite_report --maybe-color; \
echo "$$col$$br$$std"; \
diff --git a/modules/pam_faillock/README b/modules/pam_faillock/README
index c88705ad..3b63c6bb 100644
--- a/modules/pam_faillock/README
+++ b/modules/pam_faillock/README
@@ -66,7 +66,7 @@ screensaver.
Note that using the module in preauth without the silent option specified in /
etc/security/faillock.conf or with requisite control field leaks an information
-about existence or non-existence of an user account in the system because the
+about existence or non-existence of a user account in the system because the
failures are not recorded for the unknown users. The message about the user
account being locked is never displayed for non-existing user accounts allowing
the adversary to infer that a particular account is not existing on a system.
diff --git a/modules/pam_faillock/faillock.8 b/modules/pam_faillock/faillock.8
index 3ba58aa0..55443532 100644
--- a/modules/pam_faillock/faillock.8
+++ b/modules/pam_faillock/faillock.8
@@ -2,12 +2,12 @@
.\" Title: faillock
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\" Date: 06/08/2020
+.\" Date: 09/03/2021
.\" Manual: Linux-PAM Manual
.\" Source: Linux-PAM Manual
.\" Language: English
.\"
-.TH "FAILLOCK" "8" "06/08/2020" "Linux-PAM Manual" "Linux\-PAM Manual"
+.TH "FAILLOCK" "8" "09/03/2021" "Linux-PAM Manual" "Linux\-PAM Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/modules/pam_faillock/faillock.c b/modules/pam_faillock/faillock.c
index e492f5f9..091f253a 100644
--- a/modules/pam_faillock/faillock.c
+++ b/modules/pam_faillock/faillock.c
@@ -74,9 +74,12 @@ open_tally (const char *dir, const char *user, uid_t uid, int create)
if (create) {
flags |= O_CREAT;
+ if (access(dir, F_OK) != 0) {
+ mkdir(dir, 0755);
+ }
}
- fd = open(path, flags, 0600);
+ fd = open(path, flags, 0660);
free(path);
@@ -88,6 +91,18 @@ open_tally (const char *dir, const char *user, uid_t uid, int create)
if (st.st_uid != uid) {
ignore_return(fchown(fd, uid, -1));
}
+
+ /*
+ * If umask is set to 022, as will probably in most systems, then the
+ * group will not be able to write to the file. So, change the file
+ * permissions just in case.
+ * Note: owners of this file are user:root, so if the permissions are
+ * not changed the root process writing to this file will require
+ * CAP_DAC_OVERRIDE.
+ */
+ if (!(st.st_mode & S_IWGRP)) {
+ ignore_return(fchmod(fd, 0660));
+ }
}
}
diff --git a/modules/pam_faillock/faillock.conf.5 b/modules/pam_faillock/faillock.conf.5
index 7870153d..7b4ddb55 100644
--- a/modules/pam_faillock/faillock.conf.5
+++ b/modules/pam_faillock/faillock.conf.5
@@ -2,12 +2,12 @@
.\" Title: faillock.conf
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\" Date: 06/08/2020
+.\" Date: 09/03/2021
.\" Manual: Linux-PAM Manual
.\" Source: Linux-PAM Manual
.\" Language: English
.\"
-.TH "FAILLOCK\&.CONF" "5" "06/08/2020" "Linux-PAM Manual" "Linux\-PAM Manual"
+.TH "FAILLOCK\&.CONF" "5" "09/03/2021" "Linux-PAM Manual" "Linux\-PAM Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -76,6 +76,11 @@ Only track failed user authentications attempts for local users in /etc/passwd a
command will also no longer track user failed authentication attempts\&. Enabling this option will prevent a double\-lockout scenario where a user is locked out locally and in the centralized mechanism\&.
.RE
.PP
+\fBnodelay\fR
+.RS 4
+Don\*(Aqt enforce a delay after authentication failures\&.
+.RE
+.PP
\fBdeny=\fR\fB\fIn\fR\fR
.RS 4
Deny access if the number of consecutive authentication failures for this user during the recent interval exceeds
diff --git a/modules/pam_faillock/faillock.conf.5.xml b/modules/pam_faillock/faillock.conf.5.xml
index aa8500b9..04a84107 100644
--- a/modules/pam_faillock/faillock.conf.5.xml
+++ b/modules/pam_faillock/faillock.conf.5.xml
@@ -96,6 +96,16 @@
</varlistentry>
<varlistentry>
<term>
+ <option>nodelay</option>
+ </term>
+ <listitem>
+ <para>
+ Don't enforce a delay after authentication failures.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
<option>deny=<replaceable>n</replaceable></option>
</term>
<listitem>
diff --git a/modules/pam_faillock/main.c b/modules/pam_faillock/main.c
index c5780166..f62e1bb2 100644
--- a/modules/pam_faillock/main.c
+++ b/modules/pam_faillock/main.c
@@ -70,14 +70,13 @@ args_parse(int argc, char **argv, struct options *opts)
opts->progname = argv[0];
for (i = 1; i < argc; ++i) {
-
if (strcmp(argv[i], "--dir") == 0) {
++i;
if (i >= argc || strlen(argv[i]) == 0) {
fprintf(stderr, "%s: No directory supplied.\n", argv[0]);
return -1;
}
- opts->dir = argv[i];
+ opts->dir = argv[i];
}
else if (strcmp(argv[i], "--user") == 0) {
++i;
@@ -85,7 +84,7 @@ args_parse(int argc, char **argv, struct options *opts)
fprintf(stderr, "%s: No user name supplied.\n", argv[0]);
return -1;
}
- opts->user = argv[i];
+ opts->user = argv[i];
}
else if (strcmp(argv[i], "--reset") == 0) {
opts->reset = 1;
@@ -157,7 +156,7 @@ do_user(struct options *opts, const char *user)
unsigned int i;
memset(&tallies, 0, sizeof(tallies));
- if ((rv=read_tally(fd, &tallies)) == -1) {
+ if (read_tally(fd, &tallies) == -1) {
fprintf(stderr, "%s: Error reading the tally file for %s:",
opts->progname, user);
perror(NULL);
diff --git a/modules/pam_faillock/pam_faillock.8 b/modules/pam_faillock/pam_faillock.8
index 593b1fec..cec02ea2 100644
--- a/modules/pam_faillock/pam_faillock.8
+++ b/modules/pam_faillock/pam_faillock.8
@@ -2,12 +2,12 @@
.\" Title: pam_faillock
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\" Date: 06/08/2020
+.\" Date: 09/03/2021
.\" Manual: Linux-PAM Manual
.\" Source: Linux-PAM Manual
.\" Language: English
.\"
-.TH "PAM_FAILLOCK" "8" "06/08/2020" "Linux-PAM Manual" "Linux\-PAM Manual"
+.TH "PAM_FAILLOCK" "8" "09/03/2021" "Linux-PAM Manual" "Linux\-PAM Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -145,7 +145,7 @@ option specified in
/etc/security/faillock\&.conf
or with
\fIrequisite\fR
-control field leaks an information about existence or non\-existence of an user account in the system because the failures are not recorded for the unknown users\&. The message about the user account being locked is never displayed for non\-existing user accounts allowing the adversary to infer that a particular account is not existing on a system\&.
+control field leaks an information about existence or non\-existence of a user account in the system because the failures are not recorded for the unknown users\&. The message about the user account being locked is never displayed for non\-existing user accounts allowing the adversary to infer that a particular account is not existing on a system\&.
.SH "EXAMPLES"
.PP
Here are two possible configuration examples for
diff --git a/modules/pam_faillock/pam_faillock.8.xml b/modules/pam_faillock/pam_faillock.8.xml
index f43b4015..58c16442 100644
--- a/modules/pam_faillock/pam_faillock.8.xml
+++ b/modules/pam_faillock/pam_faillock.8.xml
@@ -234,7 +234,7 @@
Note that using the module in <option>preauth</option> without the
<option>silent</option> option specified in <filename>/etc/security/faillock.conf</filename>
or with <emphasis>requisite</emphasis> control field leaks an information about
- existence or non-existence of an user account in the system because
+ existence or non-existence of a user account in the system because
the failures are not recorded for the unknown users. The message
about the user account being locked is never displayed for non-existing
user accounts allowing the adversary to infer that a particular account
diff --git a/modules/pam_faillock/pam_faillock.c b/modules/pam_faillock/pam_faillock.c
index f592d0a2..8328fbae 100644
--- a/modules/pam_faillock/pam_faillock.c
+++ b/modules/pam_faillock/pam_faillock.c
@@ -67,12 +67,11 @@
#define FAILLOCK_FLAG_NO_LOG_INFO 0x8
#define FAILLOCK_FLAG_UNLOCKED 0x10
#define FAILLOCK_FLAG_LOCAL_ONLY 0x20
+#define FAILLOCK_FLAG_NO_DELAY 0x40
#define MAX_TIME_INTERVAL 604800 /* 7 days */
#define FAILLOCK_CONF_MAX_LINELEN 1023
-#define PATH_PASSWD "/etc/passwd"
-
static const char default_faillock_conf[] = FAILLOCK_DEFAULT_CONF;
struct options {
@@ -111,6 +110,7 @@ args_parse(pam_handle_t *pamh, int argc, const char **argv,
int flags, struct options *opts)
{
int i;
+ int config_arg_index = -1;
int rv;
const char *conf = default_faillock_conf;
@@ -123,10 +123,12 @@ args_parse(pam_handle_t *pamh, int argc, const char **argv,
opts->root_unlock_time = MAX_TIME_INTERVAL+1;
for (i = 0; i < argc; ++i) {
- const char *str;
+ const char *str = pam_str_skip_prefix(argv[i], "conf=");
- if ((str = pam_str_skip_prefix(argv[i], "conf=")) != NULL)
+ if (str != NULL) {
conf = str;
+ config_arg_index = i;
+ }
}
if ((rv = read_config_file(pamh, opts, conf)) != PAM_SUCCESS) {
@@ -136,7 +138,10 @@ args_parse(pam_handle_t *pamh, int argc, const char **argv,
}
for (i = 0; i < argc; ++i) {
- if (strcmp(argv[i], "preauth") == 0) {
+ if (i == config_arg_index) {
+ continue;
+ }
+ else if (strcmp(argv[i], "preauth") == 0) {
opts->action = FAILLOCK_ACTION_PREAUTH;
}
else if (strcmp(argv[i], "authfail") == 0) {
@@ -340,6 +345,9 @@ set_conf_opt(pam_handle_t *pamh, struct options *opts, const char *name, const c
else if (strcmp(name, "local_users_only") == 0) {
opts->flags |= FAILLOCK_FLAG_LOCAL_ONLY;
}
+ else if (strcmp(name, "nodelay") == 0) {
+ opts->flags |= FAILLOCK_FLAG_NO_DELAY;
+ }
else {
pam_syslog(pamh, LOG_ERR, "Unknown option: %s", name);
}
@@ -348,42 +356,7 @@ set_conf_opt(pam_handle_t *pamh, struct options *opts, const char *name, const c
static int
check_local_user (pam_handle_t *pamh, const char *user)
{
- struct passwd pw, *pwp;
- char buf[16384];
- int found = 0;
- FILE *fp;
- int errn;
-
- fp = fopen(PATH_PASSWD, "r");
- if (fp == NULL) {
- pam_syslog(pamh, LOG_ERR, "unable to open %s: %m",
- PATH_PASSWD);
- return -1;
- }
-
- for (;;) {
- errn = fgetpwent_r(fp, &pw, buf, sizeof (buf), &pwp);
- if (errn == ERANGE) {
- pam_syslog(pamh, LOG_WARNING, "%s contains very long lines; corrupted?",
- PATH_PASSWD);
- break;
- }
- if (errn != 0)
- break;
- if (strcmp(pwp->pw_name, user) == 0) {
- found = 1;
- break;
- }
- }
-
- fclose (fp);
-
- if (errn != 0 && errn != ENOENT) {
- pam_syslog(pamh, LOG_ERR, "unable to enumerate local accounts: %m");
- return -1;
- } else {
- return found;
- }
+ return pam_modutil_check_user_in_passwd(pamh, user, NULL) == PAM_SUCCESS;
}
static int
@@ -647,7 +620,21 @@ faillock_message(pam_handle_t *pamh, struct options *opts)
if (left > 0) {
left = (left + 59)/60; /* minutes */
- pam_info(pamh, _("(%d minutes left to unlock)"), (int)left);
+#if defined HAVE_DNGETTEXT && defined ENABLE_NLS
+ pam_info(
+ pamh,
+ dngettext(PACKAGE,
+ "(%d minute left to unlock)",
+ "(%d minutes left to unlock)",
+ (int)left),
+ (int)left);
+#else
+ if (left == 1)
+ pam_info(pamh, _("(%d minute left to unlock)"), (int)left);
+ else
+ /* TRANSLATORS: only used if dngettext is not supported. */
+ pam_info(pamh, _("(%d minutes left to unlock)"), (int)left);
+#endif
}
}
}
@@ -685,7 +672,9 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags,
if (rv != PAM_SUCCESS)
goto err;
- pam_fail_delay(pamh, 2000000); /* 2 sec delay on failure */
+ if (!(opts.flags & FAILLOCK_FLAG_NO_DELAY)) {
+ pam_fail_delay(pamh, 2000000); /* 2 sec delay on failure */
+ }
if ((rv=get_pam_user(pamh, &opts)) != PAM_SUCCESS) {
goto err;