From fc867a9e22eac2c9a0ed0577776bba4df21c9aad Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Wed, 20 Apr 2022 10:08:40 +0200 Subject: faillock: load configuration from file * modules/pam_faillock/main.c: Load configuration from file * modules/pam_faillock/pam_faillock: Improve tally directory management * modules/pam_faillock/faillock_config.c: Print errors * modules/pam_faillock/faillock_config.h: Extend options structure and define get_tally_dir(). * modules/pam_faillock/Makefile.am: Compile faillock_config.c for faillock binary. * modules/pam_faillock/faillock.8.xml: Update with the new configuration option. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1978029 Signed-off-by: Iker Pedrosa --- modules/pam_faillock/Makefile.am | 2 +- modules/pam_faillock/faillock.8.xml | 21 ++++++++++++-- modules/pam_faillock/faillock_config.c | 49 ++++++++++++++++++++++++++------ modules/pam_faillock/faillock_config.h | 4 +++ modules/pam_faillock/main.c | 51 +++++++++++++++++++++++++--------- modules/pam_faillock/pam_faillock.c | 15 ++++------ 6 files changed, 109 insertions(+), 33 deletions(-) (limited to 'modules/pam_faillock') diff --git a/modules/pam_faillock/Makefile.am b/modules/pam_faillock/Makefile.am index a0f0efa8..ca73bd05 100644 --- a/modules/pam_faillock/Makefile.am +++ b/modules/pam_faillock/Makefile.am @@ -45,7 +45,7 @@ securelib_LTLIBRARIES = pam_faillock.la sbin_PROGRAMS = faillock pam_faillock_la_SOURCES = pam_faillock.c faillock.c faillock_config.c -faillock_SOURCES = main.c faillock.c +faillock_SOURCES = main.c faillock.c faillock_config.c if ENABLE_REGENERATE_MAN dist_noinst_DATA = README diff --git a/modules/pam_faillock/faillock.8.xml b/modules/pam_faillock/faillock.8.xml index 6c20593c..81d2107c 100644 --- a/modules/pam_faillock/faillock.8.xml +++ b/modules/pam_faillock/faillock.8.xml @@ -55,14 +55,31 @@ OPTIONS + + + + + + + The file where the configuration is located. The default is + /etc/security/faillock.conf. + + + - The directory where the user files with the failure records are kept. The - default is /var/run/faillock. + The directory where the user files with the failure records are kept. + + + The priority to set this option is to use the value provided + from the command line. If this isn't provided, then the value + from the configuration file is used. Finally, if neither of + them has been provided, then + /var/run/faillock is used. diff --git a/modules/pam_faillock/faillock_config.c b/modules/pam_faillock/faillock_config.c index 8740b826..0d14aad1 100644 --- a/modules/pam_faillock/faillock_config.c +++ b/modules/pam_faillock/faillock_config.c @@ -46,12 +46,35 @@ #include #include "faillock_config.h" +#include "faillock.h" #define FAILLOCK_DEFAULT_CONF SCONFIGDIR "/faillock.conf" #ifdef VENDOR_SCONFIGDIR #define VENDOR_FAILLOCK_DEFAULT_CONF VENDOR_SCONFIGDIR "/faillock.conf" #endif +static void PAM_FORMAT((printf, 3, 4)) PAM_NONNULL((3)) +config_log(const pam_handle_t *pamh, int priority, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + if (pamh) { + pam_vsyslog(pamh, priority, fmt, args); + } else { + char *buf = NULL; + + if (vasprintf(&buf, fmt, args) < 0) { + fprintf(stderr, "vasprintf: %m"); + va_end(args); + return; + } + fprintf(stderr, "%s\n", buf); + free(buf); + } + va_end(args); +} + /* parse a single configuration file */ int read_config_file(pam_handle_t *pamh, struct options *opts, const char *cfgfile) @@ -149,16 +172,21 @@ set_conf_opt(pam_handle_t *pamh, struct options *opts, const char *name, { if (strcmp(name, "dir") == 0) { if (value[0] != '/') { - pam_syslog(pamh, LOG_ERR, - "Tally directory is not absolute path (%s); keeping default", value); + config_log(pamh, LOG_ERR, + "Tally directory is not absolute path (%s); keeping value", + value); } else { free(opts->dir); opts->dir = strdup(value); + if (opts->dir == NULL) { + opts->fatal_error = 1; + config_log(pamh, LOG_CRIT, "Error allocating memory: %m"); + } } } else if (strcmp(name, "deny") == 0) { if (sscanf(value, "%hu", &opts->deny) != 1) { - pam_syslog(pamh, LOG_ERR, + config_log(pamh, LOG_ERR, "Bad number supplied for deny argument"); } } @@ -166,7 +194,7 @@ set_conf_opt(pam_handle_t *pamh, struct options *opts, const char *name, unsigned int temp; if (sscanf(value, "%u", &temp) != 1 || temp > MAX_TIME_INTERVAL) { - pam_syslog(pamh, LOG_ERR, + config_log(pamh, LOG_ERR, "Bad number supplied for fail_interval argument"); } else { opts->fail_interval = temp; @@ -180,7 +208,7 @@ set_conf_opt(pam_handle_t *pamh, struct options *opts, const char *name, } else if (sscanf(value, "%u", &temp) != 1 || temp > MAX_TIME_INTERVAL) { - pam_syslog(pamh, LOG_ERR, + config_log(pamh, LOG_ERR, "Bad number supplied for unlock_time argument"); } else { @@ -195,7 +223,7 @@ set_conf_opt(pam_handle_t *pamh, struct options *opts, const char *name, } else if (sscanf(value, "%u", &temp) != 1 || temp > MAX_TIME_INTERVAL) { - pam_syslog(pamh, LOG_ERR, + config_log(pamh, LOG_ERR, "Bad number supplied for root_unlock_time argument"); } else { opts->root_unlock_time = temp; @@ -206,7 +234,7 @@ set_conf_opt(pam_handle_t *pamh, struct options *opts, const char *name, opts->admin_group = strdup(value); if (opts->admin_group == NULL) { opts->fatal_error = 1; - pam_syslog(pamh, LOG_CRIT, "Error allocating memory: %m"); + config_log(pamh, LOG_CRIT, "Error allocating memory: %m"); } } else if (strcmp(name, "even_deny_root") == 0) { @@ -228,6 +256,11 @@ set_conf_opt(pam_handle_t *pamh, struct options *opts, const char *name, opts->flags |= FAILLOCK_FLAG_NO_DELAY; } else { - pam_syslog(pamh, LOG_ERR, "Unknown option: %s", name); + config_log(pamh, LOG_ERR, "Unknown option: %s", name); } } + +const char *get_tally_dir(const struct options *opts) +{ + return (opts->dir != NULL) ? opts->dir : FAILLOCK_DEFAULT_TALLYDIR; +} diff --git a/modules/pam_faillock/faillock_config.h b/modules/pam_faillock/faillock_config.h index 81aa6654..db2851f5 100644 --- a/modules/pam_faillock/faillock_config.h +++ b/modules/pam_faillock/faillock_config.h @@ -75,11 +75,15 @@ struct options { int is_admin; uint64_t now; int fatal_error; + + unsigned int reset; + const char *progname; }; 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); +const char *get_tally_dir(const struct options *opts); #endif /* _FAILLOCK_CONFIG_H */ diff --git a/modules/pam_faillock/main.c b/modules/pam_faillock/main.c index ea6329ca..35208870 100644 --- a/modules/pam_faillock/main.c +++ b/modules/pam_faillock/main.c @@ -51,32 +51,40 @@ #define AUDIT_NO_ID ((unsigned int) -1) #endif +#include "pam_inline.h" #include "faillock.h" - -struct options { - unsigned int reset; - const char *dir; - const char *user; - const char *progname; -}; +#include "faillock_config.h" static int args_parse(int argc, char **argv, struct options *opts) { int i; + int rv; + const char *dir = NULL; + const char *conf = NULL; + 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) { + if (strcmp(argv[i], "--conf") == 0) { + ++i; + if (i >= argc || strlen(argv[i]) == 0) { + fprintf(stderr, "%s: No configuration file supplied.\n", + argv[0]); + return -1; + } + conf = argv[i]; + } + else if (strcmp(argv[i], "--dir") == 0) { ++i; if (i >= argc || strlen(argv[i]) == 0) { - fprintf(stderr, "%s: No directory supplied.\n", argv[0]); + fprintf(stderr, "%s: No records directory supplied.\n", + argv[0]); return -1; } - opts->dir = argv[i]; + dir = argv[i]; } else if (strcmp(argv[i], "--user") == 0) { ++i; @@ -94,6 +102,21 @@ args_parse(int argc, char **argv, struct options *opts) return -1; } } + + if ((rv = read_config_file(NULL, opts, conf)) != PAM_SUCCESS) { + fprintf(stderr, "Configuration file missing or broken"); + return rv; + } + + if (dir != NULL) { + free(opts->dir); + opts->dir = strdup(dir); + if (opts->dir == NULL) { + fprintf(stderr, "Error allocating memory: %m"); + return -1; + } + } + return 0; } @@ -111,10 +134,11 @@ do_user(struct options *opts, const char *user) int rv; struct tally_data tallies; struct passwd *pwd; + const char *dir = get_tally_dir(opts); pwd = getpwnam(user); - fd = open_tally(opts->dir, user, pwd != NULL ? pwd->pw_uid : 0, 0); + fd = open_tally(dir, user, pwd != NULL ? pwd->pw_uid : 0, 0); if (fd == -1) { if (errno == ENOENT) { @@ -195,8 +219,9 @@ do_allusers(struct options *opts) { struct dirent **userlist; int rv, i; + const char *dir = get_tally_dir(opts); - rv = scandir(opts->dir, &userlist, NULL, alphasort); + rv = scandir(dir, &userlist, NULL, alphasort); if (rv < 0) { fprintf(stderr, "%s: Error reading tally directory: %m\n", opts->progname); return 2; diff --git a/modules/pam_faillock/pam_faillock.c b/modules/pam_faillock/pam_faillock.c index 0a5b6b62..ddbb90e7 100644 --- a/modules/pam_faillock/pam_faillock.c +++ b/modules/pam_faillock/pam_faillock.c @@ -72,7 +72,6 @@ args_parse(pam_handle_t *pamh, int argc, const char **argv, memset(opts, 0, sizeof(*opts)); - opts->dir = strdup(FAILLOCK_DEFAULT_TALLYDIR); opts->deny = 3; opts->fail_interval = 900; opts->unlock_time = 600; @@ -130,11 +129,6 @@ args_parse(pam_handle_t *pamh, int argc, const char **argv, 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; - } - if (opts->fatal_error) return PAM_BUF_ERR; return PAM_SUCCESS; @@ -193,10 +187,11 @@ check_tally(pam_handle_t *pamh, struct options *opts, struct tally_data *tallies unsigned int i; uint64_t latest_time; int failures; + const char *dir = get_tally_dir(opts); opts->now = time(NULL); - tfd = open_tally(opts->dir, opts->user, opts->uid, 0); + tfd = open_tally(dir, opts->user, opts->uid, 0); *fd = tfd; @@ -270,9 +265,10 @@ static void reset_tally(pam_handle_t *pamh, struct options *opts, int *fd) { int rv; + const char *dir = get_tally_dir(opts); if (*fd == -1) { - *fd = open_tally(opts->dir, opts->user, opts->uid, 1); + *fd = open_tally(dir, opts->user, opts->uid, 1); } else { while ((rv=ftruncate(*fd, 0)) == -1 && errno == EINTR); @@ -291,9 +287,10 @@ write_tally(pam_handle_t *pamh, struct options *opts, struct tally_data *tallies unsigned int oldest; uint64_t oldtime; const void *source = NULL; + const char *dir = get_tally_dir(opts); if (*fd == -1) { - *fd = open_tally(opts->dir, opts->user, opts->uid, 1); + *fd = open_tally(dir, opts->user, opts->uid, 1); } if (*fd == -1) { if (errno == EACCES) { -- cgit v1.2.3