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