Blame SOURCES/pam-1.3.1-faillock-update.patch

43d219
diff -up Linux-PAM-1.3.1/modules/pam_faillock/faillock.c.faillock-update Linux-PAM-1.3.1/modules/pam_faillock/faillock.c
43d219
--- Linux-PAM-1.3.1/modules/pam_faillock/faillock.c.faillock-update	2019-10-16 16:49:27.026893768 +0200
43d219
+++ Linux-PAM-1.3.1/modules/pam_faillock/faillock.c	2019-12-16 17:55:27.042001068 +0100
43d219
@@ -1,5 +1,6 @@
43d219
 /*
43d219
  * Copyright (c) 2010 Tomas Mraz <tmraz@redhat.com>
43d219
+ * Copyright (c) 2010, 2016, 2017 Red Hat, Inc.
43d219
  *
43d219
  * Redistribution and use in source and binary forms, with or without
43d219
  * modification, are permitted provided that the following conditions
43d219
@@ -47,6 +48,8 @@
43d219
 
43d219
 #include "faillock.h"
43d219
 
43d219
+#define ignore_return(x) if (1==((int)x)) {;}
43d219
+
43d219
 int
43d219
 open_tally (const char *dir, const char *user, uid_t uid, int create)
43d219
 {
43d219
@@ -54,7 +57,7 @@ open_tally (const char *dir, const char
43d219
 	int flags = O_RDWR;
43d219
 	int fd;
43d219
 
43d219
-	if (strstr(user, "../") != NULL)
43d219
+	if (dir == NULL || strstr(user, "../") != NULL)
43d219
 	/* just a defensive programming as the user must be a
43d219
 	 * valid user on the system anyway
43d219
 	 */
43d219
@@ -83,7 +86,7 @@ open_tally (const char *dir, const char
43d219
 		while (flock(fd, LOCK_EX) == -1 && errno == EINTR);
43d219
 		if (fstat(fd, &st) == 0) {
43d219
 			if (st.st_uid != uid) {
43d219
-				fchown(fd, uid, -1);
43d219
+				ignore_return(fchown(fd, uid, -1));
43d219
 			}
43d219
 		}
43d219
 	}
43d219
@@ -121,7 +124,7 @@ read_tally(int fd, struct tally_data *ta
43d219
 		if (count >= MAX_RECORDS)
43d219
 			break;
43d219
 	}
43d219
-	while (chunk == CHUNK_SIZE); 
43d219
+	while (chunk == CHUNK_SIZE);
43d219
 
43d219
 	tallies->records = data;
43d219
 	tallies->count = count;
43d219
diff -up Linux-PAM-1.3.1/modules/pam_faillock/faillock.conf.5.xml.faillock-update Linux-PAM-1.3.1/modules/pam_faillock/faillock.conf.5.xml
43d219
--- Linux-PAM-1.3.1/modules/pam_faillock/faillock.conf.5.xml.faillock-update	2019-10-16 17:34:58.073276020 +0200
43d219
+++ Linux-PAM-1.3.1/modules/pam_faillock/faillock.conf.5.xml	2019-10-16 16:26:05.000000000 +0200
43d219
@@ -0,0 +1,243 @@
43d219
+
43d219
+
43d219
+	"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
43d219
+
43d219
+<refentry id="faillock.conf">
43d219
+
43d219
+  <refmeta>
43d219
+    <refentrytitle>faillock.conf</refentrytitle>
43d219
+    <manvolnum>5</manvolnum>
43d219
+    <refmiscinfo class="sectdesc">Linux-PAM Manual</refmiscinfo>
43d219
+  </refmeta>
43d219
+
43d219
+  <refnamediv id="faillock.conf-name">
43d219
+    <refname>faillock.conf</refname>
43d219
+    <refpurpose>pam_faillock configuration file</refpurpose>
43d219
+  </refnamediv>
43d219
+
43d219
+  <refsect1 id="faillock.conf-description">
43d219
+
43d219
+    <title>DESCRIPTION</title>
43d219
+    <para>
43d219
+       <emphasis remap='B'>faillock.conf</emphasis> provides a way to configure the
43d219
+       default settings for locking the user after multiple failed authentication attempts.
43d219
+       This file is read by the <emphasis>pam_faillock</emphasis> module and is the
43d219
+       preferred method over configuring <emphasis>pam_faillock</emphasis> directly.
43d219
+    </para>
43d219
+    <para>
43d219
+       The file has a very simple <emphasis>name = value</emphasis> format with possible comments
43d219
+       starting with <emphasis>#</emphasis> character. The whitespace at the beginning of line, end
43d219
+       of line, and around the <emphasis>=</emphasis> sign is ignored.
43d219
+    </para>
43d219
+  </refsect1>
43d219
+
43d219
+  <refsect1 id="faillock.conf-options">
43d219
+
43d219
+    <title>OPTIONS</title>
43d219
+         <variablelist>
43d219
+            <varlistentry>
43d219
+              <term>
43d219
+                <option>dir=<replaceable>/path/to/tally-directory</replaceable></option>
43d219
+              </term>
43d219
+              <listitem>
43d219
+                <para>
43d219
+                  The directory where the user files with the failure records are kept. The
43d219
+                  default is <filename>/var/run/faillock</filename>.
43d219
+                </para>
43d219
+              </listitem>
43d219
+            </varlistentry>
43d219
+            <varlistentry>
43d219
+              <term>
43d219
+                <option>audit</option>
43d219
+              </term>
43d219
+              <listitem>
43d219
+                <para>
43d219
+                  Will log the user name into the system log if the user is not found.
43d219
+                </para>
43d219
+              </listitem>
43d219
+            </varlistentry>
43d219
+            <varlistentry>
43d219
+              <term>
43d219
+                <option>silent</option>
43d219
+              </term>
43d219
+              <listitem>
43d219
+                <para>
43d219
+                  Don't print informative messages to the user. Please note that when
43d219
+                  this option is not used there will be difference in the authentication
43d219
+                  behavior for users which exist on the system and non-existing users.
43d219
+                </para>
43d219
+              </listitem>
43d219
+            </varlistentry>
43d219
+            <varlistentry>
43d219
+              <term>
43d219
+                <option>no_log_info</option>
43d219
+              </term>
43d219
+              <listitem>
43d219
+                <para>
43d219
+                  Don't log informative messages via <citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
43d219
+                </para>
43d219
+              </listitem>
43d219
+            </varlistentry>
43d219
+            <varlistentry>
43d219
+              <term>
43d219
+                <option>local_users_only</option>
43d219
+              </term>
43d219
+              <listitem>
43d219
+                <para>
43d219
+                  Only track failed user authentications attempts for local users
43d219
+                  in /etc/passwd and ignore centralized (AD, IdM, LDAP, etc.) users.
43d219
+                  The <citerefentry><refentrytitle>faillock</refentrytitle><manvolnum>8</manvolnum></citerefentry>
43d219
+                  command will also no longer track user failed
43d219
+                  authentication attempts. Enabling this option will prevent a
43d219
+                  double-lockout scenario where a user is locked out locally and
43d219
+                  in the centralized mechanism.
43d219
+                </para>
43d219
+              </listitem>
43d219
+            </varlistentry>
43d219
+            <varlistentry>
43d219
+              <term>
43d219
+                <option>deny=<replaceable>n</replaceable></option>
43d219
+              </term>
43d219
+              <listitem>
43d219
+                <para>
43d219
+                  Deny access if the number of consecutive authentication failures
43d219
+                  for this user during the recent interval exceeds
43d219
+                  <replaceable>n</replaceable>. The default is 3.
43d219
+                </para>
43d219
+              </listitem>
43d219
+            </varlistentry>
43d219
+            <varlistentry>
43d219
+              <term>
43d219
+                <option>fail_interval=<replaceable>n</replaceable></option>
43d219
+              </term>
43d219
+              <listitem>
43d219
+                <para>
43d219
+                  The length of the interval during which the consecutive
43d219
+                  authentication failures must happen for the user account
43d219
+                  lock out is <replaceable>n</replaceable> seconds.
43d219
+                  The default is 900 (15 minutes).
43d219
+                </para>
43d219
+              </listitem>
43d219
+            </varlistentry>
43d219
+            <varlistentry>
43d219
+              <term>
43d219
+                <option>unlock_time=<replaceable>n</replaceable></option>
43d219
+              </term>
43d219
+              <listitem>
43d219
+                <para>
43d219
+                  The access will be reenabled after
43d219
+                  <replaceable>n</replaceable> seconds after the lock out.
43d219
+                  The value 0 has the same meaning as value
43d219
+                  <emphasis>never</emphasis> - the access
43d219
+                  will not be reenabled without resetting the faillock
43d219
+                  entries by the <citerefentry><refentrytitle>faillock</refentrytitle><manvolnum>8</manvolnum></citerefentry> command.
43d219
+                  The default is 600 (10 minutes).
43d219
+                </para>
43d219
+                <para>
43d219
+                  Note that the default directory that <emphasis>pam_faillock</emphasis>
43d219
+                  uses is usually cleared on system boot so the access will be also reenabled
43d219
+                  after system reboot. If that is undesirable a different tally directory
43d219
+                  must be set with the <option>dir</option> option.
43d219
+                </para>
43d219
+                <para>
43d219
+                  Also note that it is usually undesirable to permanently lock
43d219
+                  out the users as they can become easily a target of denial of service
43d219
+                  attack unless the usernames are random and kept secret to potential
43d219
+                  attackers.
43d219
+                </para>
43d219
+              </listitem>
43d219
+            </varlistentry>
43d219
+            <varlistentry>
43d219
+              <term>
43d219
+                <option>even_deny_root</option>
43d219
+              </term>
43d219
+              <listitem>
43d219
+                <para>
43d219
+                  Root account can become locked as well as regular accounts.
43d219
+                </para>
43d219
+              </listitem>
43d219
+            </varlistentry>
43d219
+            <varlistentry>
43d219
+              <term>
43d219
+                <option>root_unlock_time=<replaceable>n</replaceable></option>
43d219
+              </term>
43d219
+              <listitem>
43d219
+                <para>
43d219
+                  This option implies <option>even_deny_root</option> option.
43d219
+                  Allow access after <replaceable>n</replaceable> seconds
43d219
+                  to root account after the account is locked. In case the
43d219
+                  option is not specified the value is the same as of the
43d219
+                  <option>unlock_time</option> option.
43d219
+                </para>
43d219
+              </listitem>
43d219
+            </varlistentry>
43d219
+            <varlistentry>
43d219
+              <term>
43d219
+                <option>admin_group=<replaceable>name</replaceable></option>
43d219
+              </term>
43d219
+              <listitem>
43d219
+                <para>
43d219
+                  If a group name is specified with this option, members
43d219
+                  of the group will be handled by this module the same as
43d219
+                  the root account (the options <option>even_deny_root</option>
43d219
+                  and <option>root_unlock_time</option> will apply to them.
43d219
+                  By default the option is not set.
43d219
+                </para>
43d219
+              </listitem>
43d219
+            </varlistentry>
43d219
+        </variablelist>
43d219
+  </refsect1>
43d219
+
43d219
+  <refsect1 id='faillock.conf-examples'>
43d219
+    <title>EXAMPLES</title>
43d219
+    <para>
43d219
+      /etc/security/faillock.conf file example:
43d219
+    </para>
43d219
+    <programlisting>
43d219
+deny=4
43d219
+unlock_time=1200
43d219
+silent
43d219
+    </programlisting>
43d219
+  </refsect1>
43d219
+
43d219
+  <refsect1 id="faillock.conf-files">
43d219
+    <title>FILES</title>
43d219
+    <variablelist>
43d219
+      <varlistentry>
43d219
+        <term><filename>/etc/security/faillock.conf</filename></term>
43d219
+        <listitem>
43d219
+          <para>the config file for custom options</para>
43d219
+        </listitem>
43d219
+      </varlistentry>
43d219
+    </variablelist>
43d219
+  </refsect1>
43d219
+
43d219
+  <refsect1 id='faillock.conf-see_also'>
43d219
+    <title>SEE ALSO</title>
43d219
+    <para>
43d219
+      <citerefentry>
43d219
+        <refentrytitle>faillock</refentrytitle><manvolnum>8</manvolnum>
43d219
+      </citerefentry>,
43d219
+      <citerefentry>
43d219
+        <refentrytitle>pam_faillock</refentrytitle><manvolnum>8</manvolnum>
43d219
+      </citerefentry>,
43d219
+      <citerefentry>
43d219
+        <refentrytitle>pam.conf</refentrytitle><manvolnum>5</manvolnum>
43d219
+      </citerefentry>,
43d219
+      <citerefentry>
43d219
+        <refentrytitle>pam.d</refentrytitle><manvolnum>5</manvolnum>
43d219
+      </citerefentry>,
43d219
+      <citerefentry>
43d219
+        <refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum>
43d219
+      </citerefentry>
43d219
+    </para>
43d219
+  </refsect1>
43d219
+
43d219
+  <refsect1 id='faillock.conf-author'>
43d219
+    <title>AUTHOR</title>
43d219
+      <para>
43d219
+        pam_faillock was written by Tomas Mraz. The support for faillock.conf was written by Brian Ward.
43d219
+      </para>
43d219
+  </refsect1>
43d219
+
43d219
+</refentry>
43d219
diff -up Linux-PAM-1.3.1/modules/pam_faillock/faillock.conf.faillock-update Linux-PAM-1.3.1/modules/pam_faillock/faillock.conf
43d219
--- Linux-PAM-1.3.1/modules/pam_faillock/faillock.conf.faillock-update	2019-10-16 17:34:50.607405060 +0200
43d219
+++ Linux-PAM-1.3.1/modules/pam_faillock/faillock.conf	2019-10-16 16:26:05.000000000 +0200
43d219
@@ -0,0 +1,62 @@
43d219
+# Configuration for locking the user after multiple failed
43d219
+# authentication attempts.
43d219
+#
43d219
+# The directory where the user files with the failure records are kept.
43d219
+# The default is /var/run/faillock.
43d219
+# dir = /var/run/faillock
43d219
+#
43d219
+# Will log the user name into the system log if the user is not found.
43d219
+# Enabled if option is present.
43d219
+# audit
43d219
+#
43d219
+# Don't print informative messages.
43d219
+# Enabled if option is present.
43d219
+# silent
43d219
+#
43d219
+# Don't log informative messages via syslog.
43d219
+# Enabled if option is present.
43d219
+# no_log_info
43d219
+#
43d219
+# Only track failed user authentications attempts for local users
43d219
+# in /etc/passwd and ignore centralized (AD, IdM, LDAP, etc.) users.
43d219
+# The `faillock` command will also no longer track user failed
43d219
+# authentication attempts. Enabling this option will prevent a
43d219
+# double-lockout scenario where a user is locked out locally and
43d219
+# in the centralized mechanism.
43d219
+# Enabled if option is present.
43d219
+# local_users_only
43d219
+#
43d219
+# Deny access if the number of consecutive authentication failures
43d219
+# for this user during the recent interval exceeds n tries.
43d219
+# The default is 3.
43d219
+# deny = 3
43d219
+#
43d219
+# The length of the interval during which the consecutive
43d219
+# authentication failures must happen for the user account
43d219
+# lock out is <replaceable>n</replaceable> seconds.
43d219
+# The default is 900 (15 minutes).
43d219
+# fail_interval = 900
43d219
+#
43d219
+# The access will be reenabled after n seconds after the lock out.
43d219
+# The value 0 has the same meaning as value `never` - the access
43d219
+# will not be reenabled without resetting the faillock
43d219
+# entries by the `faillock` command.
43d219
+# The default is 600 (10 minutes).
43d219
+# unlock_time = 600
43d219
+#
43d219
+# Root account can become locked as well as regular accounts.
43d219
+# Enabled if option is present.
43d219
+# even_deny_root
43d219
+#
43d219
+# This option implies the `even_deny_root` option.
43d219
+# Allow access after n seconds to root account after the
43d219
+# account is locked. In case the option is not specified
43d219
+# the value is the same as of the `unlock_time` option.
43d219
+# root_unlock_time = 900
43d219
+#
43d219
+# If a group name is specified with this option, members
43d219
+# of the group will be handled by this module the same as
43d219
+# the root account (the options `even_deny_root>` and
43d219
+# `root_unlock_time` will apply to them.
43d219
+# By default, the option is not set.
43d219
+# admin_group = <admin_group_name>
43d219
diff -up Linux-PAM-1.3.1/modules/pam_faillock/faillock.h.faillock-update Linux-PAM-1.3.1/modules/pam_faillock/faillock.h
43d219
--- Linux-PAM-1.3.1/modules/pam_faillock/faillock.h.faillock-update	2019-10-16 16:49:27.026893768 +0200
43d219
+++ Linux-PAM-1.3.1/modules/pam_faillock/faillock.h	2019-10-16 16:51:40.431628566 +0200
43d219
@@ -65,6 +65,7 @@ struct tally_data {
43d219
 };
43d219
 
43d219
 #define FAILLOCK_DEFAULT_TALLYDIR "/var/run/faillock"
43d219
+#define FAILLOCK_DEFAULT_CONF "/etc/security/faillock.conf"
43d219
 
43d219
 int open_tally(const char *dir, const char *user, uid_t uid, int create);
43d219
 int read_tally(int fd, struct tally_data *tallies);
43d219
diff -up Linux-PAM-1.3.1/modules/pam_faillock/Makefile.am.faillock-update Linux-PAM-1.3.1/modules/pam_faillock/Makefile.am
43d219
--- Linux-PAM-1.3.1/modules/pam_faillock/Makefile.am.faillock-update	2019-10-16 16:49:27.026893768 +0200
43d219
+++ Linux-PAM-1.3.1/modules/pam_faillock/Makefile.am	2019-10-16 16:50:15.065078080 +0200
43d219
@@ -1,6 +1,6 @@
43d219
 #
43d219
 # Copyright (c) 2005, 2006, 2007, 2009 Thorsten Kukuk <kukuk@thkukuk.de>
43d219
-# Copyright (c) 2008 Red Hat, Inc.
43d219
+# Copyright (c) 2008, 2018 Red Hat, Inc.
43d219
 # Copyright (c) 2010 Tomas Mraz <tmraz@redhat.com>
43d219
 #
43d219
 
43d219
@@ -9,8 +9,8 @@ MAINTAINERCLEANFILES = $(MANS) README
43d219
 
43d219
 EXTRA_DIST = README $(MANS) $(XMLS) tst-pam_faillock
43d219
 
43d219
-man_MANS = pam_faillock.8 faillock.8
43d219
-XMLS = README.xml pam_faillock.8.xml faillock.8.xml
43d219
+man_MANS = pam_faillock.8 faillock.8 faillock.conf.5
43d219
+XMLS = README.xml pam_faillock.8.xml faillock.8.xml faillock.conf.5.xml
43d219
 
43d219
 TESTS = tst-pam_faillock
43d219
 
43d219
@@ -31,6 +31,8 @@ endif
43d219
 faillock_LDFLAGS = -Wl,-z,now @PIE_LDFLAGS@
43d219
 faillock_LDADD = -L$(top_builddir)/libpam -lpam $(LIBAUDIT)
43d219
 
43d219
+secureconf_DATA = faillock.conf
43d219
+
43d219
 securelib_LTLIBRARIES = pam_faillock.la
43d219
 sbin_PROGRAMS = faillock
43d219
 
43d219
diff -up Linux-PAM-1.3.1/modules/pam_faillock/pam_faillock.8.xml.faillock-update Linux-PAM-1.3.1/modules/pam_faillock/pam_faillock.8.xml
43d219
--- Linux-PAM-1.3.1/modules/pam_faillock/pam_faillock.8.xml.faillock-update	2019-10-16 16:49:27.030893701 +0200
43d219
+++ Linux-PAM-1.3.1/modules/pam_faillock/pam_faillock.8.xml	2019-10-16 16:53:39.544606052 +0200
43d219
@@ -126,141 +126,13 @@
43d219
                 </para>
43d219
               </listitem>
43d219
             </varlistentry>
43d219
-            <varlistentry>
43d219
-              <term>
43d219
-                <option>dir=<replaceable>/path/to/tally-directory</replaceable></option>
43d219
-              </term>
43d219
-              <listitem>
43d219
-                <para>
43d219
-                  The directory where the user files with the failure records are kept. The
43d219
-                  default is <filename>/var/run/faillock</filename>.
43d219
-                </para>
43d219
-              </listitem>
43d219
-            </varlistentry>
43d219
-            <varlistentry>
43d219
-              <term>
43d219
-                <option>audit</option>
43d219
-              </term>
43d219
-              <listitem>
43d219
-                <para>
43d219
-                  Will log the user name into the system log if the user is not found.
43d219
-                </para>
43d219
-              </listitem>
43d219
-            </varlistentry>
43d219
-            <varlistentry>
43d219
-              <term>
43d219
-                <option>silent</option>
43d219
-              </term>
43d219
-              <listitem>
43d219
-                <para>
43d219
-                  Don't print informative messages. This option is implicite
43d219
-                  in the <emphasis>authfail</emphasis> and <emphasis>authsucc</emphasis>
43d219
-                  functions.
43d219
-                </para>
43d219
-              </listitem>
43d219
-            </varlistentry>
43d219
-            <varlistentry>
43d219
-              <term>
43d219
-                <option>no_log_info</option>
43d219
-              </term>
43d219
-              <listitem>
43d219
-                <para>
43d219
-                  Don't log informative messages via <citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
43d219
-                </para>
43d219
-              </listitem>
43d219
-            </varlistentry>
43d219
-            <varlistentry>
43d219
-              <term>
43d219
-                <option>deny=<replaceable>n</replaceable></option>
43d219
-              </term>
43d219
-              <listitem>
43d219
-                <para>
43d219
-                  Deny access if the number of consecutive authentication failures
43d219
-                  for this user during the recent interval exceeds
43d219
-                  <replaceable>n</replaceable>. The default is 3.
43d219
-                </para>
43d219
-              </listitem>
43d219
-            </varlistentry>
43d219
-            <varlistentry>
43d219
-              <term>
43d219
-                <option>fail_interval=<replaceable>n</replaceable></option>
43d219
-              </term>
43d219
-              <listitem>
43d219
-                <para>
43d219
-                  The length of the interval during which the consecutive
43d219
-                  authentication failures must happen for the user account
43d219
-                  lock out is <replaceable>n</replaceable> seconds.
43d219
-                  The default is 900 (15 minutes).
43d219
-                </para>
43d219
-              </listitem>
43d219
-            </varlistentry>
43d219
-            <varlistentry>
43d219
-              <term>
43d219
-                <option>unlock_time=<replaceable>n</replaceable></option>
43d219
-              </term>
43d219
-              <listitem>
43d219
-                <para>
43d219
-                  The access will be reenabled after
43d219
-                  <replaceable>n</replaceable> seconds after the lock out.
43d219
-                  The value 0 has the same meaning as value
43d219
-                  <emphasis>never</emphasis> - the access
43d219
-                  will not be reenabled without resetting the faillock
43d219
-                  entries by the <citerefentry><refentrytitle>faillock</refentrytitle><manvolnum>8</manvolnum></citerefentry> command.
43d219
-                  The default is 600 (10 minutes).
43d219
-                </para>
43d219
-                <para>
43d219
-                  Note that the default directory that <emphasis>pam_faillock</emphasis>
43d219
-                  uses is usually cleared on system boot so the access will be also reenabled
43d219
-                  after system reboot. If that is undesirable a different tally directory
43d219
-                  must be set with the <option>dir</option> option.
43d219
-                </para>
43d219
-                <para>
43d219
-                  Also note that it is usually undesirable to permanently lock
43d219
-                  out the users as they can become easily a target of denial of service
43d219
-                  attack unless the usernames are random and kept secret to potential
43d219
-                  attackers.
43d219
-                </para>
43d219
-              </listitem>
43d219
-            </varlistentry>
43d219
-            <varlistentry>
43d219
-              <term>
43d219
-                <option>even_deny_root</option>
43d219
-              </term>
43d219
-              <listitem>
43d219
-                <para>
43d219
-                  Root account can become locked as well as regular accounts.
43d219
-                </para>
43d219
-              </listitem>
43d219
-            </varlistentry>
43d219
-            <varlistentry>
43d219
-              <term>
43d219
-                <option>root_unlock_time=<replaceable>n</replaceable></option>
43d219
-              </term>
43d219
-              <listitem>
43d219
-                <para>
43d219
-                  This option implies <option>even_deny_root</option> option.
43d219
-                  Allow access after <replaceable>n</replaceable> seconds
43d219
-                  to root account after the account is locked. In case the
43d219
-                  option is not specified the value is the same as of the
43d219
-                  <option>unlock_time</option> option.
43d219
-                </para>
43d219
-              </listitem>
43d219
-            </varlistentry>
43d219
-            <varlistentry>
43d219
-              <term>
43d219
-                <option>admin_group=<replaceable>name</replaceable></option>
43d219
-              </term>
43d219
-              <listitem>
43d219
-                <para>
43d219
-                  If a group name is specified with this option, members
43d219
-                  of the group will be handled by this module the same as
43d219
-                  the root account (the options <option>even_deny_root></option>
43d219
-                  and <option>root_unlock_time</option> will apply to them.
43d219
-                  By default the option is not set.
43d219
-                </para>
43d219
-              </listitem>
43d219
-            </varlistentry>
43d219
         </variablelist>
43d219
+        <para>
43d219
+          The options for configuring the module behavior are described in the 
43d219
+          <citerefentry><refentrytitle>faillock.conf</refentrytitle><manvolnum>5</manvolnum>
43d219
+          </citerefentry> manual page. The options specified on the module command
43d219
+          line override the values from the configuration file.
43d219
+        </para>
43d219
   </refsect1>
43d219
 
43d219
   <refsect1 id="pam_faillock-types">
43d219
@@ -306,19 +178,23 @@
43d219
   <refsect1 id='pam_faillock-notes'>
43d219
     <title>NOTES</title>
43d219
     <para>
43d219
-      <emphasis>pam_faillock</emphasis> setup in the PAM stack is different
43d219
+      Configuring options on the module command line is not recommend. The
43d219
+      <emphasis>/etc/security/faillock.conf</emphasis> should be used instead.
43d219
+    </para>
43d219
+    <para>
43d219
+      The setup of <emphasis>pam_faillock</emphasis> in the PAM stack is different
43d219
       from the <emphasis>pam_tally2</emphasis> module setup.
43d219
     </para>
43d219
     <para>
43d219
-      The individual files with the failure records are created as owned by
43d219
+      Individual files with the failure records are created as owned by
43d219
       the user. This allows <emphasis remap='B'>pam_faillock.so</emphasis> module
43d219
       to work correctly when it is called from a screensaver.
43d219
     </para>
43d219
     <para>
43d219
       Note that using the module in <option>preauth</option> without the
43d219
-      <option>silent</option> option or with <emphasis>requisite</emphasis>
43d219
-      control field leaks an information about existence or
43d219
-      non-existence of an user account in the system because
43d219
+      <option>silent</option> option specified in <filename>/etc/security/faillock.conf</filename>
43d219
+      or with <emphasis>requisite</emphasis> control field leaks an information about
43d219
+      existence or non-existence of an user account in the system because
43d219
       the failures are not recorded for the unknown users. The message
43d219
       about the user account being locked is never displayed for nonexisting
43d219
       user accounts allowing the adversary to infer that a particular account
43d219
@@ -341,15 +217,26 @@
43d219
       be added to tell the user that his login is blocked by the module and also to abort
43d219
       the authentication without even asking for password in such case.
43d219
     </para>
43d219
+    <para>
43d219
+      /etc/security/faillock.conf file example:
43d219
+    </para>
43d219
+    <programlisting>
43d219
+deny=4
43d219
+unlock_time=1200
43d219
+silent
43d219
+    </programlisting>
43d219
+    <para>
43d219
+      /etc/pam.d/config file example:
43d219
+    </para>
43d219
     <programlisting>
43d219
 auth     required       pam_securetty.so
43d219
 auth     required       pam_env.so
43d219
 auth     required       pam_nologin.so
43d219
-# optionally call: auth requisite pam_faillock.so preauth deny=4 even_deny_root unlock_time=1200
43d219
+# optionally call: auth requisite pam_faillock.so preauth
43d219
 # to display the message about account being locked
43d219
 auth     [success=1 default=bad] pam_unix.so
43d219
-auth     [default=die]  pam_faillock.so authfail deny=4 even_deny_root unlock_time=1200
43d219
-auth     sufficient     pam_faillock.so authsucc deny=4 even_deny_root unlock_time=1200
43d219
+auth     [default=die]  pam_faillock.so authfail
43d219
+auth     sufficient     pam_faillock.so authsucc
43d219
 auth     required       pam_deny.so
43d219
 account  required       pam_unix.so
43d219
 password required       pam_unix.so shadow
43d219
@@ -361,17 +248,18 @@ session  required       pam_selinux.so o
43d219
     <para>
43d219
       In the second example the module is called both in the <emphasis>auth</emphasis>
43d219
       and <emphasis>account</emphasis> phases and the module gives the authenticating
43d219
-      user message when the account is locked 
43d219
+      user message when the account is locked if <option>silent</option> option is not
43d219
+      specified in the <filename>faillock.conf</filename>.
43d219
     </para>
43d219
     <programlisting>
43d219
 auth     required       pam_securetty.so
43d219
 auth     required       pam_env.so
43d219
 auth     required       pam_nologin.so
43d219
-auth     required       pam_faillock.so preauth silent deny=4 even_deny_root unlock_time=1200
43d219
+auth     required       pam_faillock.so preauth
43d219
 # optionally use requisite above if you do not want to prompt for the password
43d219
-# on locked accounts, possibly with removing the silent option as well
43d219
+# on locked accounts
43d219
 auth     sufficient     pam_unix.so
43d219
-auth     [default=die]  pam_faillock.so authfail deny=4 even_deny_root unlock_time=1200
43d219
+auth     [default=die]  pam_faillock.so authfail
43d219
 auth     required       pam_deny.so
43d219
 account  required       pam_faillock.so
43d219
 # if you drop the above call to pam_faillock.so the lock will be done also
43d219
@@ -394,6 +282,12 @@ session  required       pam_selinux.so o
43d219
           <para>the files logging the authentication failures for users</para>
43d219
         </listitem>
43d219
       </varlistentry>
43d219
+      <varlistentry>
43d219
+        <term><filename>/etc/security/faillock.conf</filename></term>
43d219
+        <listitem>
43d219
+          <para>the config file for pam_faillock options</para>
43d219
+        </listitem>
43d219
+      </varlistentry>
43d219
     </variablelist>
43d219
   </refsect1>
43d219
 
43d219
@@ -404,6 +298,9 @@ session  required       pam_selinux.so o
43d219
         <refentrytitle>faillock</refentrytitle><manvolnum>8</manvolnum>
43d219
       </citerefentry>,
43d219
       <citerefentry>
43d219
+        <refentrytitle>faillock.conf</refentrytitle><manvolnum>5</manvolnum>
43d219
+      </citerefentry>,
43d219
+      <citerefentry>
43d219
         <refentrytitle>pam.conf</refentrytitle><manvolnum>5</manvolnum>
43d219
       </citerefentry>,
43d219
       <citerefentry>
43d219
diff -up Linux-PAM-1.3.1/modules/pam_faillock/pam_faillock.c.faillock-update Linux-PAM-1.3.1/modules/pam_faillock/pam_faillock.c
43d219
--- Linux-PAM-1.3.1/modules/pam_faillock/pam_faillock.c.faillock-update	2019-10-16 16:49:27.030893701 +0200
43d219
+++ Linux-PAM-1.3.1/modules/pam_faillock/pam_faillock.c	2019-12-16 17:55:11.403270018 +0100
43d219
@@ -1,5 +1,6 @@
43d219
 /*
43d219
- * Copyright (c) 2010, 2017 Tomas Mraz <tmraz@redhat.com>
43d219
+ * Copyright (c) 2010, 2017, 2019 Tomas Mraz <tmraz@redhat.com>
43d219
+ * Copyright (c) 2010, 2017, 2019 Red Hat, Inc.
43d219
  *
43d219
  * Redistribution and use in source and binary forms, with or without
43d219
  * modification, are permitted provided that the following conditions
43d219
@@ -43,6 +44,7 @@
43d219
 #include <time.h>
43d219
 #include <pwd.h>
43d219
 #include <syslog.h>
43d219
+#include <ctype.h>
43d219
 
43d219
 #ifdef HAVE_LIBAUDIT
43d219
 #include <libaudit.h>
43d219
@@ -66,8 +68,14 @@
43d219
 #define FAILLOCK_FLAG_SILENT		0x4
43d219
 #define FAILLOCK_FLAG_NO_LOG_INFO	0x8
43d219
 #define FAILLOCK_FLAG_UNLOCKED		0x10
43d219
+#define FAILLOCK_FLAG_LOCAL_ONLY	0x20
43d219
 
43d219
 #define MAX_TIME_INTERVAL 604800 /* 7 days */
43d219
+#define FAILLOCK_CONF_MAX_LINELEN 1023
43d219
+#define FAILLOCK_ERROR_CONF_OPEN -3
43d219
+#define FAILLOCK_ERROR_CONF_MALFORMED -4
43d219
+
43d219
+#define PATH_PASSWD "/etc/passwd"
43d219
 
43d219
 struct options {
43d219
 	unsigned int action;
43d219
@@ -76,117 +84,295 @@ struct options {
43d219
 	unsigned int fail_interval;
43d219
 	unsigned int unlock_time;
43d219
 	unsigned int root_unlock_time;
43d219
-	const char *dir;
43d219
+	char *dir;
43d219
+	const char *conf;
43d219
 	const char *user;
43d219
-	const char *admin_group;
43d219
+	char *admin_group;
43d219
 	int failures;
43d219
 	uint64_t latest_time;
43d219
 	uid_t uid;
43d219
 	int is_admin;
43d219
 	uint64_t now;
43d219
+	int fatal_error;
43d219
 };
43d219
 
43d219
+int read_config_file(
43d219
+	pam_handle_t *pamh,
43d219
+	struct options *opts,
43d219
+	const char *cfgfile
43d219
+);
43d219
+
43d219
+void set_conf_opt(
43d219
+	pam_handle_t *pamh,
43d219
+	struct options *opts,
43d219
+	const char *name,
43d219
+	const char *value
43d219
+);
43d219
+
43d219
 static void
43d219
 args_parse(pam_handle_t *pamh, int argc, const char **argv,
43d219
 		int flags, struct options *opts)
43d219
 {
43d219
 	int i;
43d219
+	int rv;
43d219
 	memset(opts, 0, sizeof(*opts));
43d219
 
43d219
-	opts->dir = FAILLOCK_DEFAULT_TALLYDIR;
43d219
+	opts->dir = strdup(FAILLOCK_DEFAULT_TALLYDIR);
43d219
+	opts->conf = FAILLOCK_DEFAULT_CONF;
43d219
 	opts->deny = 3;
43d219
 	opts->fail_interval = 900;
43d219
 	opts->unlock_time = 600;
43d219
 	opts->root_unlock_time = MAX_TIME_INTERVAL+1;
43d219
 
43d219
-	for (i = 0; i < argc; ++i) {
43d219
+	if ((rv=read_config_file(pamh, opts, opts->conf)) != PAM_SUCCESS) {
43d219
+		pam_syslog(pamh, LOG_DEBUG,
43d219
+					"Configuration file missing");
43d219
+	}
43d219
 
43d219
-		if (strncmp(argv[i], "dir=", 4) == 0) {
43d219
-			if (argv[i][4] != '/') {
43d219
-				pam_syslog(pamh, LOG_ERR,
43d219
-					"Tally directory is not absolute path (%s); keeping default", argv[i]);
43d219
-	        	} else {
43d219
-			        opts->dir = argv[i]+4;
43d219
-			}
43d219
-		} 
43d219
-		else if (strncmp(argv[i], "deny=", 5) == 0) {
43d219
-			if (sscanf(argv[i]+5, "%hu", &opts->deny) != 1) {
43d219
-				pam_syslog(pamh, LOG_ERR,
43d219
-					"Bad number supplied for deny argument");
43d219
-        		}
43d219
-		}
43d219
-		else if (strncmp(argv[i], "fail_interval=", 14) == 0) {
43d219
-			unsigned int temp;
43d219
-			if (sscanf(argv[i]+14, "%u", &temp) != 1 ||
43d219
-				temp > MAX_TIME_INTERVAL) {
43d219
-				pam_syslog(pamh, LOG_ERR,
43d219
-					"Bad number supplied for fail_interval argument");
43d219
-	        	} else {
43d219
-				opts->fail_interval = temp;
43d219
-			}
43d219
+	for (i = 0; i < argc; ++i) {
43d219
+		if (strcmp(argv[i], "preauth") == 0) {
43d219
+			opts->action = FAILLOCK_ACTION_PREAUTH;
43d219
+		}
43d219
+		else if (strcmp(argv[i], "authfail") == 0) {
43d219
+			opts->action = FAILLOCK_ACTION_AUTHFAIL;
43d219
+		}
43d219
+		else if (strcmp(argv[i], "authsucc") == 0) {
43d219
+			opts->action = FAILLOCK_ACTION_AUTHSUCC;
43d219
 		}
43d219
-		else if (strncmp(argv[i], "unlock_time=", 12) == 0) {
43d219
-			unsigned int temp;
43d219
+		else {
43d219
+			char buf[FAILLOCK_CONF_MAX_LINELEN + 1];
43d219
+			char *val;
43d219
 
43d219
-			if (strcmp(argv[i]+12, "never") == 0) {
43d219
-				opts->unlock_time = 0;
43d219
-			}
43d219
-			else if (sscanf(argv[i]+12, "%u", &temp) != 1 ||
43d219
-				temp > MAX_TIME_INTERVAL) {
43d219
-				pam_syslog(pamh, LOG_ERR,
43d219
-					"Bad number supplied for unlock_time argument");
43d219
+			strncpy(buf, argv[i], sizeof(buf) - 1);
43d219
+			buf[sizeof(buf) - 1] = '\0';
43d219
+
43d219
+			val = strchr(buf, '=');
43d219
+			if (val != NULL) {
43d219
+				*val = '\0';
43d219
+				++val;
43d219
 			}
43d219
 			else {
43d219
-				opts->unlock_time = temp;
43d219
+				val = buf + sizeof(buf) - 1;
43d219
 			}
43d219
+			set_conf_opt(pamh, opts, buf, val);
43d219
 		}
43d219
-		else if (strncmp(argv[i], "root_unlock_time=", 17) == 0) {
43d219
-			unsigned int temp;
43d219
+	}
43d219
 
43d219
-			if (strcmp(argv[i]+17, "never") == 0) {
43d219
-				opts->root_unlock_time = 0;
43d219
-			}
43d219
-			else if (sscanf(argv[i]+17, "%u", &temp) != 1 ||
43d219
-				temp > MAX_TIME_INTERVAL) {
43d219
-				pam_syslog(pamh, LOG_ERR,
43d219
-					"Bad number supplied for root_unlock_time argument");
43d219
+	if (opts->root_unlock_time == MAX_TIME_INTERVAL+1)
43d219
+		opts->root_unlock_time = opts->unlock_time;
43d219
+	if (flags & PAM_SILENT)
43d219
+		opts->flags |= FAILLOCK_FLAG_SILENT;
43d219
+
43d219
+	if (opts->dir == NULL) {
43d219
+		pam_syslog(pamh, LOG_CRIT, "Error allocating memory: %m");
43d219
+		opts->fatal_error = 1;
43d219
+	}
43d219
+}
43d219
+
43d219
+/* parse a single configuration file */
43d219
+int
43d219
+read_config_file(pam_handle_t *pamh, struct options *opts, const char *cfgfile)
43d219
+{
43d219
+	FILE *f;
43d219
+	char linebuf[FAILLOCK_CONF_MAX_LINELEN+1];
43d219
+
43d219
+	f = fopen(cfgfile, "r");
43d219
+	if (f == NULL) {
43d219
+		/* ignore non-existent default config file */
43d219
+		if (errno == ENOENT && strcmp(cfgfile, FAILLOCK_DEFAULT_CONF) == 0)
43d219
+			return 0;
43d219
+		return FAILLOCK_ERROR_CONF_OPEN;
43d219
+	}
43d219
+
43d219
+	while (fgets(linebuf, sizeof(linebuf), f) != NULL) {
43d219
+		size_t len;
43d219
+		char *ptr;
43d219
+		char *name;
43d219
+		int eq;
43d219
+
43d219
+		len = strlen(linebuf);
43d219
+		/* len cannot be 0 unless there is a bug in fgets */
43d219
+		if (len && linebuf[len - 1] != '\n' && !feof(f)) {
43d219
+			(void) fclose(f);
43d219
+			return FAILLOCK_ERROR_CONF_MALFORMED;
43d219
+		}
43d219
+
43d219
+		if ((ptr=strchr(linebuf, '#')) != NULL) {
43d219
+			*ptr = '\0';
43d219
+		} else {
43d219
+			ptr = linebuf + len;
43d219
+		}
43d219
+
43d219
+		/* drop terminating whitespace including the \n */
43d219
+		while (ptr > linebuf) {
43d219
+			if (!isspace(*(ptr-1))) {
43d219
+				*ptr = '\0';
43d219
+				break;
43d219
+			}
43d219
+			--ptr;
43d219
+		}
43d219
+
43d219
+		/* skip initial whitespace */
43d219
+		for (ptr = linebuf; isspace(*ptr); ptr++);
43d219
+		if (*ptr == '\0')
43d219
+			continue;
43d219
+
43d219
+		/* grab the key name */
43d219
+		eq = 0;
43d219
+		name = ptr;
43d219
+		while (*ptr != '\0') {
43d219
+			if (isspace(*ptr) || *ptr == '=') {
43d219
+				eq = *ptr == '=';
43d219
+				*ptr = '\0';
43d219
+				++ptr;
43d219
+				break;
43d219
+			}
43d219
+			++ptr;
43d219
+		}
43d219
+
43d219
+		/* grab the key value */
43d219
+		while (*ptr != '\0') {
43d219
+			if (*ptr != '=' || eq) {
43d219
+				if (!isspace(*ptr)) {
43d219
+					break;
43d219
+				}
43d219
 			} else {
43d219
-				opts->root_unlock_time = temp;
43d219
+				eq = 1;
43d219
 			}
43d219
+			++ptr;
43d219
 		}
43d219
-		else if (strncmp(argv[i], "admin_group=", 12) == 0) {
43d219
-			opts->admin_group = argv[i] + 12;
43d219
+
43d219
+		/* set the key:value pair on opts */
43d219
+		set_conf_opt(pamh, opts, name, ptr);
43d219
+	}
43d219
+
43d219
+	(void)fclose(f);
43d219
+	return PAM_SUCCESS;
43d219
+}
43d219
+
43d219
+void set_conf_opt(pam_handle_t *pamh, struct options *opts, const char *name, const char *value)
43d219
+{
43d219
+	if (strcmp(name, "dir") == 0) {
43d219
+		if (value[0] != '/') {
43d219
+			pam_syslog(pamh, LOG_ERR,
43d219
+				"Tally directory is not absolute path (%s); keeping default", value);
43d219
+		} else {
43d219
+			free(opts->dir);
43d219
+			opts->dir = strdup(value);
43d219
 		}
43d219
- 		else if (strcmp(argv[i], "preauth") == 0) {
43d219
-			opts->action = FAILLOCK_ACTION_PREAUTH;
43d219
+	}
43d219
+	else if (strcmp(name, "deny") == 0) {
43d219
+		if (sscanf(value, "%hu", &opts->deny) != 1) {
43d219
+			pam_syslog(pamh, LOG_ERR,
43d219
+				"Bad number supplied for deny argument");
43d219
+		}
43d219
+	}
43d219
+	else if (strcmp(name, "fail_interval") == 0) {
43d219
+		unsigned int temp;
43d219
+		if (sscanf(value, "%u", &temp) != 1 ||
43d219
+			temp > MAX_TIME_INTERVAL) {
43d219
+			pam_syslog(pamh, LOG_ERR,
43d219
+				"Bad number supplied for fail_interval argument");
43d219
+		} else {
43d219
+			opts->fail_interval = temp;
43d219
 		}
43d219
- 		else if (strcmp(argv[i], "authfail") == 0) {
43d219
-			opts->action = FAILLOCK_ACTION_AUTHFAIL;
43d219
+	}
43d219
+	else if (strcmp(name, "unlock_time") == 0) {
43d219
+		unsigned int temp;
43d219
+
43d219
+		if (strcmp(value, "never") == 0) {
43d219
+			opts->unlock_time = 0;
43d219
 		}
43d219
-	 	else if (strcmp(argv[i], "authsucc") == 0) {
43d219
-			opts->action = FAILLOCK_ACTION_AUTHSUCC;
43d219
+		else if (sscanf(value, "%u", &temp) != 1 ||
43d219
+			temp > MAX_TIME_INTERVAL) {
43d219
+			pam_syslog(pamh, LOG_ERR,
43d219
+				"Bad number supplied for unlock_time argument");
43d219
 		}
43d219
-	 	else if (strcmp(argv[i], "even_deny_root") == 0) {
43d219
-			opts->flags |= FAILLOCK_FLAG_DENY_ROOT;
43d219
+		else {
43d219
+			opts->unlock_time = temp;
43d219
 		}
43d219
-	 	else if (strcmp(argv[i], "audit") == 0) {
43d219
-			opts->flags |= FAILLOCK_FLAG_AUDIT;
43d219
+	}
43d219
+	else if (strcmp(name, "root_unlock_time") == 0) {
43d219
+		unsigned int temp;
43d219
+
43d219
+		if (strcmp(value, "never") == 0) {
43d219
+			opts->root_unlock_time = 0;
43d219
 		}
43d219
-	 	else if (strcmp(argv[i], "silent") == 0) {
43d219
-			opts->flags |= FAILLOCK_FLAG_SILENT;
43d219
+		else if (sscanf(value, "%u", &temp) != 1 ||
43d219
+			temp > MAX_TIME_INTERVAL) {
43d219
+			pam_syslog(pamh, LOG_ERR,
43d219
+				"Bad number supplied for root_unlock_time argument");
43d219
+		} else {
43d219
+			opts->root_unlock_time = temp;
43d219
 		}
43d219
-	 	else if (strcmp(argv[i], "no_log_info") == 0) {
43d219
-			opts->flags |= FAILLOCK_FLAG_NO_LOG_INFO;
43d219
+	}
43d219
+	else if (strcmp(name, "admin_group") == 0) {
43d219
+		free(opts->admin_group);
43d219
+		opts->admin_group = strdup(value);
43d219
+		if (opts->admin_group == NULL) {
43d219
+			opts->fatal_error = 1;
43d219
+			pam_syslog(pamh, LOG_CRIT, "Error allocating memory: %m");
43d219
 		}
43d219
-		else {
43d219
-			pam_syslog(pamh, LOG_ERR, "Unknown option: %s", argv[i]);
43d219
+	}
43d219
+	else if (strcmp(name, "even_deny_root") == 0) {
43d219
+		opts->flags |= FAILLOCK_FLAG_DENY_ROOT;
43d219
+	}
43d219
+	else if (strcmp(name, "audit") == 0) {
43d219
+		opts->flags |= FAILLOCK_FLAG_AUDIT;
43d219
+	}
43d219
+	else if (strcmp(name, "silent") == 0) {
43d219
+		opts->flags |= FAILLOCK_FLAG_SILENT;
43d219
+	}
43d219
+	else if (strcmp(name, "no_log_info") == 0) {
43d219
+		opts->flags |= FAILLOCK_FLAG_NO_LOG_INFO;
43d219
+	}
43d219
+	else if (strcmp(name, "local_users_only") == 0) {
43d219
+		opts->flags |= FAILLOCK_FLAG_LOCAL_ONLY;
43d219
+	}
43d219
+	else {
43d219
+		pam_syslog(pamh, LOG_ERR, "Unknown option: %s", name);
43d219
+	}
43d219
+}
43d219
+
43d219
+static int check_local_user (pam_handle_t *pamh, const char *user)
43d219
+{
43d219
+	struct passwd pw, *pwp;
43d219
+	char buf[4096];
43d219
+	int found = 0;
43d219
+	FILE *fp;
43d219
+	int errn;
43d219
+
43d219
+	fp = fopen(PATH_PASSWD, "r");
43d219
+	if (fp == NULL) {
43d219
+		pam_syslog(pamh, LOG_ERR, "unable to open %s: %m",
43d219
+			   PATH_PASSWD);
43d219
+		return -1;
43d219
+	}
43d219
+
43d219
+	for (;;) {
43d219
+		errn = fgetpwent_r(fp, &pw, buf, sizeof (buf), &pwp);
43d219
+		if (errn == ERANGE) {
43d219
+			pam_syslog(pamh, LOG_WARNING, "%s contains very long lines; corrupted?",
43d219
+				   PATH_PASSWD);
43d219
+			/* we can continue here as next call will read further */
43d219
+			continue;
43d219
+		}
43d219
+		if (errn != 0)
43d219
+			break;
43d219
+		if (strcmp(pwp->pw_name, user) == 0) {
43d219
+			found = 1;
43d219
+			break;
43d219
 		}
43d219
 	}
43d219
 
43d219
-	if (opts->root_unlock_time == MAX_TIME_INTERVAL+1)
43d219
-		opts->root_unlock_time = opts->unlock_time;
43d219
-	if (flags & PAM_SILENT)
43d219
-		opts->flags |= FAILLOCK_FLAG_SILENT;
43d219
+	fclose (fp);
43d219
+
43d219
+	if (errn != 0 && errn != ENOENT) {
43d219
+		pam_syslog(pamh, LOG_ERR, "unable to enumerate local accounts: %m");
43d219
+		return -1;
43d219
+	} else {
43d219
+		return found;
43d219
+	}
43d219
 }
43d219
 
43d219
 static int get_pam_user(pam_handle_t *pamh, struct options *opts)
43d219
@@ -393,7 +579,7 @@ write_tally(pam_handle_t *pamh, struct o
43d219
 
43d219
 	strncpy(tallies->records[oldest].source, source, sizeof(tallies->records[oldest].source));
43d219
 	/* source does not have to be null terminated */
43d219
-	
43d219
+
43d219
 	tallies->records[oldest].time = opts->now;
43d219
 
43d219
 	++failures;
43d219
@@ -468,6 +654,13 @@ tally_cleanup(struct tally_data *tallies
43d219
 	free(tallies->records);
43d219
 }
43d219
 
43d219
+static void
43d219
+opts_cleanup(struct options *opts)
43d219
+{
43d219
+	free(opts->dir);
43d219
+	free(opts->admin_group);
43d219
+}
43d219
+
43d219
 /*---------------------------------------------------------------------*/
43d219
 
43d219
 PAM_EXTERN int
43d219
@@ -481,39 +674,49 @@ pam_sm_authenticate(pam_handle_t *pamh,
43d219
 	memset(&tallies, 0, sizeof(tallies));
43d219
 
43d219
 	args_parse(pamh, argc, argv, flags, &opts);
43d219
+	if (opts.fatal_error) {
43d219
+		rv = PAM_BUF_ERR;
43d219
+		goto err;
43d219
+	}
43d219
 
43d219
 	pam_fail_delay(pamh, 2000000);	/* 2 sec delay for on failure */
43d219
 
43d219
 	if ((rv=get_pam_user(pamh, &opts)) != PAM_SUCCESS) {
43d219
-		return rv;
43d219
+		goto err;
43d219
 	}
43d219
 
43d219
-	switch (opts.action) {
43d219
-		case FAILLOCK_ACTION_PREAUTH:
43d219
-			rv = check_tally(pamh, &opts, &tallies, &fd;;
43d219
-			if (rv == PAM_AUTH_ERR && !(opts.flags & FAILLOCK_FLAG_SILENT)) {
43d219
-				faillock_message(pamh, &opts);
43d219
-			}
43d219
-                        break;
43d219
-
43d219
-		case FAILLOCK_ACTION_AUTHSUCC:
43d219
-			rv = check_tally(pamh, &opts, &tallies, &fd;;
43d219
-			if (rv == PAM_SUCCESS) {
43d219
-				reset_tally(pamh, &opts, &fd;;
43d219
-			}
43d219
-                        break;
43d219
-
43d219
-		case FAILLOCK_ACTION_AUTHFAIL:
43d219
-			rv = check_tally(pamh, &opts, &tallies, &fd;;
43d219
-			if (rv == PAM_SUCCESS) {
43d219
-				rv = PAM_IGNORE; /* this return value should be ignored */
43d219
-				write_tally(pamh, &opts, &tallies, &fd;;
43d219
-			}
43d219
-			break;
43d219
+	if (!(opts.flags & FAILLOCK_FLAG_LOCAL_ONLY) ||
43d219
+		check_local_user (pamh, opts.user) != 0) {
43d219
+		switch (opts.action) {
43d219
+			case FAILLOCK_ACTION_PREAUTH:
43d219
+				rv = check_tally(pamh, &opts, &tallies, &fd;;
43d219
+				if (rv == PAM_AUTH_ERR && !(opts.flags & FAILLOCK_FLAG_SILENT)) {
43d219
+					faillock_message(pamh, &opts);
43d219
+				}
43d219
+				break;
43d219
+
43d219
+			case FAILLOCK_ACTION_AUTHSUCC:
43d219
+				rv = check_tally(pamh, &opts, &tallies, &fd;;
43d219
+				if (rv == PAM_SUCCESS) {
43d219
+					reset_tally(pamh, &opts, &fd;;
43d219
+				}
43d219
+				break;
43d219
+
43d219
+			case FAILLOCK_ACTION_AUTHFAIL:
43d219
+				rv = check_tally(pamh, &opts, &tallies, &fd;;
43d219
+				if (rv == PAM_SUCCESS) {
43d219
+					rv = PAM_IGNORE; /* this return value should be ignored */
43d219
+					write_tally(pamh, &opts, &tallies, &fd;;
43d219
+				}
43d219
+				break;
43d219
+		}
43d219
 	}
43d219
 
43d219
 	tally_cleanup(&tallies, fd);
43d219
 
43d219
+err:
43d219
+	opts_cleanup(&opts);
43d219
+
43d219
 	return rv;
43d219
 }
43d219
 
43d219
@@ -540,18 +743,29 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int
43d219
 
43d219
 	args_parse(pamh, argc, argv, flags, &opts);
43d219
 
43d219
+	if (opts.fatal_error) {
43d219
+		rv = PAM_BUF_ERR;
43d219
+		goto err;
43d219
+	}
43d219
+
43d219
 	opts.action = FAILLOCK_ACTION_AUTHSUCC;
43d219
 
43d219
 	if ((rv=get_pam_user(pamh, &opts)) != PAM_SUCCESS) {
43d219
-		return rv;
43d219
+		goto err;
43d219
 	}
43d219
 
43d219
-	check_tally(pamh, &opts, &tallies, &fd;; /* for auditing */
43d219
-	reset_tally(pamh, &opts, &fd;;
43d219
+	if (!(opts.flags & FAILLOCK_FLAG_LOCAL_ONLY) ||
43d219
+		check_local_user (pamh, opts.user) != 0) {
43d219
+		check_tally(pamh, &opts, &tallies, &fd;; /* for auditing */
43d219
+		reset_tally(pamh, &opts, &fd;;
43d219
+	}
43d219
 
43d219
 	tally_cleanup(&tallies, fd);
43d219
 
43d219
-	return PAM_SUCCESS;
43d219
+err:
43d219
+	opts_cleanup(&opts);
43d219
+
43d219
+	return rv;
43d219
 }
43d219
 
43d219
 /*-----------------------------------------------------------------------*/