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