From e4501544296fe5c31be8c9397f426e6a2077c6ed Mon Sep 17 00:00:00 2001 From: ipedrosa Date: Jun 23 2020 13:26:18 +0000 Subject: [PATCH 1/2] pam_faillock: removed as the module has already been upstreamed --- diff --git a/pam_faillock/Makefile.am b/pam_faillock/Makefile.am deleted file mode 100644 index f69416e..0000000 --- a/pam_faillock/Makefile.am +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright (c) 2005, 2006, 2007, 2009 Thorsten Kukuk -# Copyright (c) 2008, 2018 Red Hat, Inc. -# Copyright (c) 2010 Tomas Mraz -# - -CLEANFILES = *~ -MAINTAINERCLEANFILES = $(MANS) README - -EXTRA_DIST = README $(MANS) $(XMLS) tst-pam_faillock - -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 - -securelibdir = $(SECUREDIR) -secureconfdir = $(SCONFIGDIR) - -noinst_HEADERS = faillock.h - -faillock_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include @PIE_CFLAGS@ -pam_faillock_la_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include - -pam_faillock_la_LDFLAGS = -no-undefined -avoid-version -module -pam_faillock_la_LIBADD = -L$(top_builddir)/libpam -lpam $(LIBAUDIT) -if HAVE_VERSIONING - pam_faillock_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map -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 - -pam_faillock_la_SOURCES = pam_faillock.c faillock.c -faillock_SOURCES = main.c faillock.c - -if ENABLE_REGENERATE_MAN -noinst_DATA = README -README: pam_faillock.8.xml --include $(top_srcdir)/Make.xml.rules -endif diff --git a/pam_faillock/README.xml b/pam_faillock/README.xml deleted file mode 100644 index f0654db..0000000 --- a/pam_faillock/README.xml +++ /dev/null @@ -1,46 +0,0 @@ - - ---> -]> - -
- - - - - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="pam_faillock.8.xml" xpointer='xpointer(//refnamediv[@id = "pam_faillock-name"]/*)'/> - - - - -
- -
- -
- -
- -
- -
- -
- -
- -
- -
- -
diff --git a/pam_faillock/faillock.8.xml b/pam_faillock/faillock.8.xml deleted file mode 100644 index 10942d5..0000000 --- a/pam_faillock/faillock.8.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - faillock - 8 - Linux-PAM Manual - - - - faillock - Tool for displaying and modifying the authentication failure record files - - - - - faillock - - --dir /path/to/tally-directory - - - --user username - - - --reset - - - - - - - DESCRIPTION - - - The pam_faillock.so module maintains a list of - failed authentication attempts per user during a specified interval - and locks the account in case there were more than - deny consecutive failed authentications. - It stores the failure records into per-user files in the tally - directory. - - - The faillock command is an application which - can be used to examine and modify the contents of the - the tally files. It can display the recent failed authentication - attempts of the username or clear the tally - files of all or individual usernames. - - - - - - OPTIONS - - - - - - - - The directory where the user files with the failure records are kept. The - default is /var/run/faillock. - - - - - - - - - - The user whose failure records should be displayed or cleared. - - - - - - - - - - Instead of displaying the user's failure records, clear them. - - - - - - - - FILES - - - /var/run/faillock/* - - the files logging the authentication failures for users - - - - - - - SEE ALSO - - - pam_faillock8 - , - - pam8 - - - - - - AUTHOR - - faillock was written by Tomas Mraz. - - - - diff --git a/pam_faillock/faillock.c b/pam_faillock/faillock.c deleted file mode 100644 index e492f5f..0000000 --- a/pam_faillock/faillock.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2010 Tomas Mraz - * 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 - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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) -{ - char *path; - int flags = O_RDWR; - int fd; - - if (dir == NULL || strstr(user, "../") != NULL) - /* just a defensive programming as the user must be a - * valid user on the system anyway - */ - return -1; - path = malloc(strlen(dir) + strlen(user) + 2); - if (path == NULL) - return -1; - - strcpy(path, dir); - if (*dir && dir[strlen(dir) - 1] != '/') { - strcat(path, "/"); - } - strcat(path, user); - - if (create) { - flags |= O_CREAT; - } - - fd = open(path, flags, 0600); - - free(path); - - if (fd != -1) { - struct stat st; - - while (flock(fd, LOCK_EX) == -1 && errno == EINTR); - if (fstat(fd, &st) == 0) { - if (st.st_uid != uid) { - ignore_return(fchown(fd, uid, -1)); - } - } - } - - return fd; -} - -#define CHUNK_SIZE (64 * sizeof(struct tally)) -#define MAX_RECORDS 1024 - -int -read_tally(int fd, struct tally_data *tallies) -{ - void *data = NULL, *newdata; - unsigned int count = 0; - ssize_t chunk = 0; - - do { - newdata = realloc(data, count * sizeof(struct tally) + CHUNK_SIZE); - if (newdata == NULL) { - free(data); - return -1; - } - - data = newdata; - - chunk = pam_modutil_read(fd, (char *)data + count * sizeof(struct tally), CHUNK_SIZE); - if (chunk < 0) { - free(data); - return -1; - } - - count += chunk/sizeof(struct tally); - - if (count >= MAX_RECORDS) - break; - } - while (chunk == CHUNK_SIZE); - - tallies->records = data; - tallies->count = count; - - return 0; -} - -int -update_tally(int fd, struct tally_data *tallies) -{ - void *data = tallies->records; - unsigned int count = tallies->count; - ssize_t chunk; - - if (tallies->count > MAX_RECORDS) { - data = tallies->records + (count - MAX_RECORDS); - count = MAX_RECORDS; - } - - if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { - return -1; - } - - chunk = pam_modutil_write(fd, data, count * sizeof(struct tally)); - - if (chunk != (ssize_t)(count * sizeof(struct tally))) { - return -1; - } - - if (ftruncate(fd, count * sizeof(struct tally)) == -1) - return -1; - - return 0; -} diff --git a/pam_faillock/faillock.conf b/pam_faillock/faillock.conf deleted file mode 100644 index f5288dc..0000000 --- a/pam_faillock/faillock.conf +++ /dev/null @@ -1,62 +0,0 @@ -# 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 n 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 = diff --git a/pam_faillock/faillock.conf.5.xml b/pam_faillock/faillock.conf.5.xml deleted file mode 100644 index 9e2bfaf..0000000 --- a/pam_faillock/faillock.conf.5.xml +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - - faillock.conf - 5 - Linux-PAM Manual - - - - faillock.conf - pam_faillock configuration file - - - - - DESCRIPTION - - faillock.conf provides a way to configure the - default settings for locking the user after multiple failed authentication attempts. - This file is read by the pam_faillock module and is the - preferred method over configuring pam_faillock directly. - - - The file has a very simple name = value format with possible comments - starting with # character. The whitespace at the beginning of line, end - of line, and around the = sign is ignored. - - - - - - OPTIONS - - - - - - - - The directory where the user files with the failure records are kept. The - default is /var/run/faillock. - - - - - - - - - - Will log the user name into the system log if the user is not found. - - - - - - - - - - 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. - - - - - - - - - - Don't log informative messages via syslog3. - - - - - - - - - - Only track failed user authentications attempts for local users - in /etc/passwd and ignore centralized (AD, IdM, LDAP, etc.) users. - The faillock8 - 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. - - - - - - - - - - Deny access if the number of consecutive authentication failures - for this user during the recent interval exceeds - n. The default is 3. - - - - - - - - - - The length of the interval during which the consecutive - authentication failures must happen for the user account - lock out is n seconds. - The default is 900 (15 minutes). - - - - - - - - - - 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 faillock8 command. - The default is 600 (10 minutes). - - - Note that the default directory that pam_faillock - 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. - - - 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. - - - - - - - - - - Root account can become locked as well as regular accounts. - - - - - - - - - - This option implies 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 - option. - - - - - - - - - - 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 - and will apply to them. - By default the option is not set. - - - - - - - - EXAMPLES - - /etc/security/faillock.conf file example: - - -deny=4 -unlock_time=1200 -silent - - - - - FILES - - - /etc/security/faillock.conf - - the config file for custom options - - - - - - - SEE ALSO - - - faillock8 - , - - pam_faillock8 - , - - pam.conf5 - , - - pam.d5 - , - - pam8 - - - - - - AUTHOR - - pam_faillock was written by Tomas Mraz. The support for faillock.conf was written by Brian Ward. - - - - diff --git a/pam_faillock/faillock.h b/pam_faillock/faillock.h deleted file mode 100644 index 5f38657..0000000 --- a/pam_faillock/faillock.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2010 Tomas Mraz - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * faillock.h - authentication failure data file record structure - * - * Each record in the file represents an instance of login failure of - * the user at the recorded time - */ - - -#ifndef _FAILLOCK_H -#define _FAILLOCK_H - -#include -#include - -#define TALLY_STATUS_VALID 0x1 /* the tally file entry is valid */ -#define TALLY_STATUS_RHOST 0x2 /* the source is rhost */ -#define TALLY_STATUS_TTY 0x4 /* the source is tty - if both TALLY_FLAG_RHOST and TALLY_FLAG_TTY are not set the source is service */ - -struct tally { - char source[52]; /* rhost or tty of the login failure (not necessarily NULL terminated) */ - uint16_t reserved; /* reserved for future use */ - uint16_t status; /* record status */ - uint64_t time; /* time of the login failure */ -}; -/* 64 bytes per entry */ - -struct tally_data { - struct tally *records; /* array of tallies */ - unsigned int count; /* number of records */ -}; - -#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); -int update_tally(int fd, struct tally_data *tallies); -#endif - diff --git a/pam_faillock/main.c b/pam_faillock/main.c deleted file mode 100644 index 501f73f..0000000 --- a/pam_faillock/main.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 2010 Tomas Mraz - * Copyright (c) 2010 Red Hat, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_LIBAUDIT -#include -#endif - -#include "faillock.h" - -struct options { - unsigned int reset; - const char *dir; - const char *user; - const char *progname; -}; - -static int -args_parse(int argc, char **argv, struct options *opts) -{ - int i; - memset(opts, 0, sizeof(*opts)); - - opts->dir = FAILLOCK_DEFAULT_TALLYDIR; - opts->progname = argv[0]; - - for (i = 1; i < argc; ++i) { - - if (strcmp(argv[i], "--dir") == 0) { - ++i; - if (i >= argc || strlen(argv[i]) == 0) { - fprintf(stderr, "%s: No directory supplied.\n", argv[0]); - return -1; - } - opts->dir = argv[i]; - } - else if (strcmp(argv[i], "--user") == 0) { - ++i; - if (i >= argc || strlen(argv[i]) == 0) { - fprintf(stderr, "%s: No user name supplied.\n", argv[0]); - return -1; - } - opts->user = argv[i]; - } - else if (strcmp(argv[i], "--reset") == 0) { - opts->reset = 1; - } - else { - fprintf(stderr, "%s: Unknown option: %s\n", argv[0], argv[i]); - return -1; - } - } - return 0; -} - -static void -usage(const char *progname) -{ - fprintf(stderr, _("Usage: %s [--dir /path/to/tally-directory] [--user username] [--reset]\n"), - progname); -} - -static int -do_user(struct options *opts, const char *user) -{ - int fd; - int rv; - struct tally_data tallies; - struct passwd *pwd; - - pwd = getpwnam(user); - - fd = open_tally(opts->dir, user, pwd != NULL ? pwd->pw_uid : 0, 0); - - if (fd == -1) { - if (errno == ENOENT) { - return 0; - } - else { - fprintf(stderr, "%s: Error opening the tally file for %s:", - opts->progname, user); - perror(NULL); - return 3; - } - } - if (opts->reset) { -#ifdef HAVE_LIBAUDIT - int audit_fd; -#endif - - while ((rv=ftruncate(fd, 0)) == -1 && errno == EINTR); - if (rv == -1) { - fprintf(stderr, "%s: Error clearing the tally file for %s:", - opts->progname, user); - perror(NULL); -#ifdef HAVE_LIBAUDIT - } - if ((audit_fd=audit_open()) >= 0) { - - if (pwd != NULL) { - audit_log_acct_message(audit_fd, AUDIT_USER_MGMT, NULL, - "faillock-reset", NULL, pwd->pw_uid, NULL, NULL, NULL, rv == 0); - } - close(audit_fd); - } - if (rv == -1) { -#endif - close(fd); - return 4; - } - } - else { - unsigned int i; - - memset(&tallies, 0, sizeof(tallies)); - if ((rv=read_tally(fd, &tallies)) == -1) { - fprintf(stderr, "%s: Error reading the tally file for %s:", - opts->progname, user); - perror(NULL); - close(fd); - return 5; - } - - printf("%s:\n", user); - printf("%-19s %-5s %-48s %-5s\n", "When", "Type", "Source", "Valid"); - - for (i = 0; i < tallies.count; i++) { - struct tm *tm; - char timebuf[80]; - uint16_t status = tallies.records[i].status; - time_t when = tallies.records[i].time; - - tm = localtime(&when); - strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm); - printf("%-19s %-5s %-52.52s %s\n", timebuf, - status & TALLY_STATUS_RHOST ? "RHOST" : (status & TALLY_STATUS_TTY ? "TTY" : "SVC"), - tallies.records[i].source, status & TALLY_STATUS_VALID ? "V":"I"); - } - free(tallies.records); - } - close(fd); - return 0; -} - -static int -do_allusers(struct options *opts) -{ - struct dirent **userlist; - int rv, i; - - rv = scandir(opts->dir, &userlist, NULL, alphasort); - if (rv < 0) { - fprintf(stderr, "%s: Error reading tally directory: ", opts->progname); - perror(NULL); - return 2; - } - - for (i = 0; i < rv; i++) { - if (userlist[i]->d_name[0] == '.') { - if ((userlist[i]->d_name[1] == '.' && userlist[i]->d_name[2] == '\0') || - userlist[i]->d_name[1] == '\0') - continue; - } - do_user(opts, userlist[i]->d_name); - free(userlist[i]); - } - free(userlist); - - return 0; -} - - -/*-----------------------------------------------------------------------*/ -int -main (int argc, char *argv[]) -{ - struct options opts; - - if (args_parse(argc, argv, &opts)) { - usage(argv[0]); - return 1; - } - - if (opts.user == NULL) { - return do_allusers(&opts); - } - - return do_user(&opts, opts.user); -} - diff --git a/pam_faillock/pam_faillock.8.xml b/pam_faillock/pam_faillock.8.xml deleted file mode 100644 index ec4c0db..0000000 --- a/pam_faillock/pam_faillock.8.xml +++ /dev/null @@ -1,322 +0,0 @@ - - - - - - - pam_faillock - 8 - Linux-PAM Manual - - - - pam_faillock - Module counting authentication failures during a specified interval - - - - - auth ... pam_faillock.so - - preauth|authfail|authsucc - - - dir=/path/to/tally-directory - - - even_deny_root - - - deny=n - - - fail_interval=n - - - unlock_time=n - - - root_unlock_time=n - - - admin_group=name - - - audit - - - silent - - - no_log_info - - - - account ... pam_faillock.so - - dir=/path/to/tally-directory - - - no_log_info - - - - - - - DESCRIPTION - - - This module maintains a list of failed authentication attempts per - user during a specified interval and locks the account in case - there were more than deny consecutive - failed authentications. - - - Normally, failed attempts to authenticate root will - not cause the root account to become - blocked, to prevent denial-of-service: if your users aren't given - shell accounts and root may only login via su or - at the machine console (not telnet/rsh, etc), this is safe. - - - - - - OPTIONS - - - - - - - - This argument must be set accordingly to the position of this module - instance in the PAM stack. - - - The preauth argument must be used when the module - is called before the modules which ask for the user credentials such - as the password. The module just examines whether the user should - be blocked from accessing the service in case there were anomalous - number of failed consecutive authentication attempts recently. This - call is optional if authsucc is used. - - - The authfail argument must be used when the module - is called after the modules which determine the authentication outcome, - failed. Unless the user is already blocked due to previous authentication - failures, the module will record the failure into the appropriate user - tally file. - - - The authsucc argument must be used when the module - is called after the modules which determine the authentication outcome, - succeded. Unless the user is already blocked due to previous authentication - failures, the module will then clear the record of the failures in the - respective user tally file. Otherwise it will return authentication error. - If this call is not done, the pam_faillock will not distinguish between - consecutive and non-consecutive failed authentication attempts. The - preauth call must be used in such case. Due to - complications in the way the PAM stack can be configured it is also - possible to call pam_faillock as an account module. - In such configuration the module must be also called in the - preauth stage. - - - - - - The options for configuring the module behavior are described in the - faillock.conf5 - manual page. The options specified on the module command - line override the values from the configuration file. - - - - - MODULE TYPES PROVIDED - - The and module types are - provided. - - - - - RETURN VALUES - - - PAM_AUTH_ERR - - - A invalid option was given, the module was not able - to retrieve the user name, no valid counter file - was found, or too many failed logins. - - - - - PAM_SUCCESS - - - Everything was successful. - - - - - PAM_IGNORE - - - User not present in passwd database. - - - - - - - - NOTES - - Configuring options on the module command line is not recommend. The - /etc/security/faillock.conf should be used instead. - - - The setup of pam_faillock in the PAM stack is different - from the pam_tally2 module setup. - - - Individual files with the failure records are created as owned by - the user. This allows pam_faillock.so module - to work correctly when it is called from a screensaver. - - - Note that using the module in without the - option specified in /etc/security/faillock.conf - or with requisite control field leaks an information about - existence or non-existence of an user account in the system because - the 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 - is not existing on a system. - - - - - EXAMPLES - - Here are two possible configuration examples for /etc/pam.d/login. - They make pam_faillock to lock the account after 4 consecutive - failed logins during the default interval of 15 minutes. Root account will be locked - as well. The accounts will be automatically unlocked after 20 minutes. - - - In the first example the module is called only in the auth - phase and the module does not print any information about the account blocking - by pam_faillock. The preauth call can - 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. - - - /etc/security/faillock.conf file example: - - -deny=4 -unlock_time=1200 -silent - - - /etc/pam.d/config file example: - - -auth required pam_securetty.so -auth required pam_env.so -auth required pam_nologin.so -# 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 -auth sufficient pam_faillock.so authsucc -auth required pam_deny.so -account required pam_unix.so -password required pam_unix.so shadow -session required pam_selinux.so close -session required pam_loginuid.so -session required pam_unix.so -session required pam_selinux.so open - - - In the second example the module is called both in the auth - and account phases and the module gives the authenticating - user message when the account is locked if option is not - specified in the faillock.conf. - - -auth required pam_securetty.so -auth required pam_env.so -auth required pam_nologin.so -auth required pam_faillock.so preauth -# optionally use requisite above if you do not want to prompt for the password -# on locked accounts -auth sufficient pam_unix.so -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 -# on non-consecutive authentication failures -account required pam_unix.so -password required pam_unix.so shadow -session required pam_selinux.so close -session required pam_loginuid.so -session required pam_unix.so -session required pam_selinux.so open - - - - - FILES - - - /var/run/faillock/* - - the files logging the authentication failures for users - - - - /etc/security/faillock.conf - - the config file for pam_faillock options - - - - - - - SEE ALSO - - - faillock8 - , - - faillock.conf5 - , - - pam.conf5 - , - - pam.d5 - , - - pam8 - - - - - - AUTHOR - - pam_faillock was written by Tomas Mraz. - - - - diff --git a/pam_faillock/pam_faillock.c b/pam_faillock/pam_faillock.c deleted file mode 100644 index 8f24fe9..0000000 --- a/pam_faillock/pam_faillock.c +++ /dev/null @@ -1,797 +0,0 @@ -/* - * Copyright (c) 2010, 2017, 2019 Tomas Mraz - * 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 - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_LIBAUDIT -#include -#endif - -#include -#include -#include - -#include "faillock.h" - -#define PAM_SM_AUTH -#define PAM_SM_ACCOUNT - -#define FAILLOCK_ACTION_PREAUTH 0 -#define FAILLOCK_ACTION_AUTHSUCC 1 -#define FAILLOCK_ACTION_AUTHFAIL 2 - -#define FAILLOCK_FLAG_DENY_ROOT 0x1 -#define FAILLOCK_FLAG_AUDIT 0x2 -#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; - unsigned int flags; - unsigned short deny; - unsigned int fail_interval; - unsigned int unlock_time; - unsigned int root_unlock_time; - char *dir; - const char *conf; - const char *user; - 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 = 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; - - if ((rv=read_config_file(pamh, opts, opts->conf)) != PAM_SUCCESS) { - pam_syslog(pamh, LOG_DEBUG, - "Configuration file missing"); - } - - 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 { - char buf[FAILLOCK_CONF_MAX_LINELEN + 1]; - char *val; - - strncpy(buf, argv[i], sizeof(buf) - 1); - buf[sizeof(buf) - 1] = '\0'; - - val = strchr(buf, '='); - if (val != NULL) { - *val = '\0'; - ++val; - } - else { - val = buf + sizeof(buf) - 1; - } - set_conf_opt(pamh, opts, buf, val); - } - } - - 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 { - eq = 1; - } - ++ptr; - } - - /* 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(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(name, "unlock_time") == 0) { - unsigned int temp; - - if (strcmp(value, "never") == 0) { - opts->unlock_time = 0; - } - else if (sscanf(value, "%u", &temp) != 1 || - temp > MAX_TIME_INTERVAL) { - pam_syslog(pamh, LOG_ERR, - "Bad number supplied for unlock_time argument"); - } - else { - opts->unlock_time = temp; - } - } - else if (strcmp(name, "root_unlock_time") == 0) { - unsigned int temp; - - if (strcmp(value, "never") == 0) { - opts->root_unlock_time = 0; - } - 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(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 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; - } - } - - 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) -{ - const char *user; - int rv; - struct passwd *pwd; - - if ((rv=pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) { - return rv; - } - - if (*user == '\0') { - return PAM_IGNORE; - } - - if ((pwd=pam_modutil_getpwnam(pamh, user)) == NULL) { - if (opts->flags & FAILLOCK_FLAG_AUDIT) { - pam_syslog(pamh, LOG_ERR, "User unknown: %s", user); - } - else { - pam_syslog(pamh, LOG_ERR, "User unknown"); - } - return PAM_IGNORE; - } - opts->user = user; - opts->uid = pwd->pw_uid; - - if (pwd->pw_uid == 0) { - opts->is_admin = 1; - return PAM_SUCCESS; - } - - if (opts->admin_group && *opts->admin_group) { - opts->is_admin = pam_modutil_user_in_group_uid_nam(pamh, - pwd->pw_uid, opts->admin_group); - } - - return PAM_SUCCESS; -} - -static int -check_tally(pam_handle_t *pamh, struct options *opts, struct tally_data *tallies, int *fd) -{ - int tfd; - unsigned int i; - uint64_t latest_time; - int failures; - - opts->now = time(NULL); - - tfd = open_tally(opts->dir, opts->user, opts->uid, 0); - - *fd = tfd; - - if (tfd == -1) { - if (errno == EACCES || errno == ENOENT) { - return PAM_SUCCESS; - } - pam_syslog(pamh, LOG_ERR, "Error opening the tally file for %s: %m", opts->user); - return PAM_SYSTEM_ERR; - } - - if (read_tally(tfd, tallies) != 0) { - pam_syslog(pamh, LOG_ERR, "Error reading the tally file for %s: %m", opts->user); - return PAM_SYSTEM_ERR; - } - - if (opts->is_admin && !(opts->flags & FAILLOCK_FLAG_DENY_ROOT)) { - return PAM_SUCCESS; - } - - latest_time = 0; - for(i = 0; i < tallies->count; i++) { - if ((tallies->records[i].status & TALLY_STATUS_VALID) && - tallies->records[i].time > latest_time) - latest_time = tallies->records[i].time; - } - - opts->latest_time = latest_time; - - failures = 0; - for(i = 0; i < tallies->count; i++) { - if ((tallies->records[i].status & TALLY_STATUS_VALID) && - latest_time - tallies->records[i].time < opts->fail_interval) { - ++failures; - } - } - - opts->failures = failures; - - if (opts->deny && failures >= opts->deny) { - if ((!opts->is_admin && opts->unlock_time && latest_time + opts->unlock_time < opts->now) || - (opts->is_admin && opts->root_unlock_time && latest_time + opts->root_unlock_time < opts->now)) { -#ifdef HAVE_LIBAUDIT - if (opts->action != FAILLOCK_ACTION_PREAUTH) { /* do not audit in preauth */ - char buf[64]; - int audit_fd; - const void *rhost = NULL, *tty = NULL; - - audit_fd = audit_open(); - /* If there is an error & audit support is in the kernel report error */ - if ((audit_fd < 0) && !(errno == EINVAL || errno == EPROTONOSUPPORT || - errno == EAFNOSUPPORT)) - return PAM_SYSTEM_ERR; - - (void)pam_get_item(pamh, PAM_TTY, &tty); - (void)pam_get_item(pamh, PAM_RHOST, &rhost); - snprintf(buf, sizeof(buf), "pam_faillock uid=%u ", opts->uid); - audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_UNLOCK_TIMED, buf, - rhost, NULL, tty, 1); - } -#endif - opts->flags |= FAILLOCK_FLAG_UNLOCKED; - return PAM_SUCCESS; - } - return PAM_AUTH_ERR; - } - return PAM_SUCCESS; -} - -static void -reset_tally(pam_handle_t *pamh, struct options *opts, int *fd) -{ - int rv; - - if (*fd == -1) { - *fd = open_tally(opts->dir, opts->user, opts->uid, 1); - } - else { - while ((rv=ftruncate(*fd, 0)) == -1 && errno == EINTR); - if (rv == -1) { - pam_syslog(pamh, LOG_ERR, "Error clearing the tally file for %s: %m", opts->user); - } - } -} - -static int -write_tally(pam_handle_t *pamh, struct options *opts, struct tally_data *tallies, int *fd) -{ - struct tally *records; - unsigned int i; - int failures; - unsigned int oldest; - uint64_t oldtime; - const void *source = NULL; - - if (*fd == -1) { - *fd = open_tally(opts->dir, opts->user, opts->uid, 1); - } - if (*fd == -1) { - if (errno == EACCES) { - return PAM_SUCCESS; - } - pam_syslog(pamh, LOG_ERR, "Error opening the tally file for %s: %m", opts->user); - return PAM_SYSTEM_ERR; - } - - oldtime = 0; - oldest = 0; - failures = 0; - - for (i = 0; i < tallies->count; ++i) { - if (tallies->records[i].time < oldtime) { - oldtime = tallies->records[i].time; - oldest = i; - } - if (opts->flags & FAILLOCK_FLAG_UNLOCKED || - opts->now - tallies->records[i].time >= opts->fail_interval ) { - tallies->records[i].status &= ~TALLY_STATUS_VALID; - } else { - ++failures; - } - } - - if (oldest >= tallies->count || (tallies->records[oldest].status & TALLY_STATUS_VALID)) { - oldest = tallies->count; - - if ((records=realloc(tallies->records, (oldest+1) * sizeof (*tallies->records))) == NULL) { - pam_syslog(pamh, LOG_CRIT, "Error allocating memory for tally records: %m"); - return PAM_BUF_ERR; - } - - ++tallies->count; - tallies->records = records; - } - - memset(&tallies->records[oldest], 0, sizeof (*tallies->records)); - - tallies->records[oldest].status = TALLY_STATUS_VALID; - if (pam_get_item(pamh, PAM_RHOST, &source) != PAM_SUCCESS || source == NULL) { - if (pam_get_item(pamh, PAM_TTY, &source) != PAM_SUCCESS || source == NULL) { - if (pam_get_item(pamh, PAM_SERVICE, &source) != PAM_SUCCESS || source == NULL) { - source = ""; - } - } - else { - tallies->records[oldest].status |= TALLY_STATUS_TTY; - } - } - else { - tallies->records[oldest].status |= TALLY_STATUS_RHOST; - } - - 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; - - if (opts->deny && failures == opts->deny) { -#ifdef HAVE_LIBAUDIT - char buf[64]; - int audit_fd; - - audit_fd = audit_open(); - /* If there is an error & audit support is in the kernel report error */ - if ((audit_fd < 0) && !(errno == EINVAL || errno == EPROTONOSUPPORT || - errno == EAFNOSUPPORT)) - return PAM_SYSTEM_ERR; - - snprintf(buf, sizeof(buf), "pam_faillock uid=%u ", opts->uid); - audit_log_user_message(audit_fd, AUDIT_ANOM_LOGIN_FAILURES, buf, - NULL, NULL, NULL, 1); - - if (!opts->is_admin || (opts->flags & FAILLOCK_FLAG_DENY_ROOT)) { - audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_LOCK, buf, - NULL, NULL, NULL, 1); - } - close(audit_fd); -#endif - if (!(opts->flags & FAILLOCK_FLAG_NO_LOG_INFO)) { - pam_syslog(pamh, LOG_INFO, "Consecutive login failures for user %s account temporarily locked", - opts->user); - } - } - - if (update_tally(*fd, tallies) == 0) - return PAM_SUCCESS; - - return PAM_SYSTEM_ERR; -} - -static void -faillock_message(pam_handle_t *pamh, struct options *opts) -{ - int64_t left; - - if (!(opts->flags & FAILLOCK_FLAG_SILENT)) { - if (opts->is_admin) { - left = opts->latest_time + opts->root_unlock_time - opts->now; - } - else { - left = opts->latest_time + opts->unlock_time - opts->now; - } - - if (left > 0) { - left = (left + 59)/60; /* minutes */ - - pam_info(pamh, _("Account temporarily locked due to %d failed logins"), - opts->failures); - pam_info(pamh, _("(%d minutes left to unlock)"), (int)left); - } - else { - pam_info(pamh, _("Account locked due to %d failed logins"), - opts->failures); - } - } -} - -static void -tally_cleanup(struct tally_data *tallies, int fd) -{ - if (fd != -1) { - close(fd); - } - - free(tallies->records); -} - -static void -opts_cleanup(struct options *opts) -{ - free(opts->dir); - free(opts->admin_group); -} - -/*---------------------------------------------------------------------*/ - -PAM_EXTERN int -pam_sm_authenticate(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - struct options opts; - int rv, fd = -1; - struct tally_data tallies; - - 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) { - goto err; - } - - 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; -} - -/*---------------------------------------------------------------------*/ - -PAM_EXTERN int -pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED, - int argc UNUSED, const char **argv UNUSED) -{ - return PAM_SUCCESS; -} - -/*---------------------------------------------------------------------*/ - -PAM_EXTERN int -pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - struct options opts; - int rv, fd = -1; - struct tally_data tallies; - - memset(&tallies, 0, sizeof(tallies)); - - 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) { - goto err; - } - - 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); - -err: - opts_cleanup(&opts); - - return rv; -} - -/*-----------------------------------------------------------------------*/ - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_faillock_modstruct = { - MODULE_NAME, -#ifdef PAM_SM_AUTH - pam_sm_authenticate, - pam_sm_setcred, -#else - NULL, - NULL, -#endif -#ifdef PAM_SM_ACCOUNT - pam_sm_acct_mgmt, -#else - NULL, -#endif - NULL, - NULL, - NULL, -}; - -#endif /* #ifdef PAM_STATIC */ - diff --git a/pam_faillock/tst-pam_faillock b/pam_faillock/tst-pam_faillock deleted file mode 100755 index ec454c2..0000000 --- a/pam_faillock/tst-pam_faillock +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -../../tests/tst-dlopen .libs/pam_faillock.so From 497e01dfd477f126e1d12d0aed84bf79a338653d Mon Sep 17 00:00:00 2001 From: ipedrosa Date: Jun 23 2020 13:30:18 +0000 Subject: [PATCH 2/2] New release 1.1.3 --- diff --git a/CHANGELOG.pam-redhat b/CHANGELOG.pam-redhat index 6c3ce20..334ef17 100644 --- a/CHANGELOG.pam-redhat +++ b/CHANGELOG.pam-redhat @@ -4,6 +4,9 @@ Changelog of pam-redhat modules This changelog describes only changes after branching of pam-redhat modules without autoconf support. +1.1.3: Tue Jun 23 2020 +* pam_faillock: removed as the module has already been upstreamed + 1.1.2: Wed Dec 18 2019 * pam_faillock: fix regression in handling of admin_group and dir options diff --git a/Makefile b/Makefile index cb11b1e..acd2567 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION=1.1.2 +VERSION=1.1.3 TAG=pam-redhat-$(VERSION) nothing: