diff --git a/SOURCES/pam-1.3.1-faillock-load-conf-from-file.patch b/SOURCES/pam-1.3.1-faillock-load-conf-from-file.patch new file mode 100644 index 0000000..81ea7cc --- /dev/null +++ b/SOURCES/pam-1.3.1-faillock-load-conf-from-file.patch @@ -0,0 +1,1212 @@ +diff -up Linux-PAM-1.3.1/modules/pam_faillock/faillock.8.xml.faillock-load-conf-from-file Linux-PAM-1.3.1/modules/pam_faillock/faillock.8.xml +--- Linux-PAM-1.3.1/modules/pam_faillock/faillock.8.xml.faillock-load-conf-from-file 2022-05-26 10:57:11.713067506 +0200 ++++ Linux-PAM-1.3.1/modules/pam_faillock/faillock.8.xml 2022-05-26 10:57:11.747067749 +0200 +@@ -57,12 +57,29 @@ + + + ++ ++ ++ ++ ++ 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 -up Linux-PAM-1.3.1/modules/pam_faillock/faillock_config.c.faillock-load-conf-from-file Linux-PAM-1.3.1/modules/pam_faillock/faillock_config.c +--- Linux-PAM-1.3.1/modules/pam_faillock/faillock_config.c.faillock-load-conf-from-file 2022-05-26 10:57:11.747067749 +0200 ++++ Linux-PAM-1.3.1/modules/pam_faillock/faillock_config.c 2022-05-26 10:57:11.747067749 +0200 +@@ -0,0 +1,266 @@ ++/* ++ * Copyright (c) 2022 Tomas Mraz ++ * Copyright (c) 2022 Iker Pedrosa ++ * ++ * 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 "faillock_config.h" ++#include "faillock.h" ++ ++#define FAILLOCK_DEFAULT_CONF "/etc/security/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) ++{ ++ char linebuf[FAILLOCK_CONF_MAX_LINELEN+1]; ++ const char *fname = (cfgfile != NULL) ? cfgfile : FAILLOCK_DEFAULT_CONF; ++ FILE *f = fopen(fname, "r"); ++ ++#ifdef VENDOR_FAILLOCK_DEFAULT_CONF ++ if (f == NULL && errno == ENOENT && cfgfile == NULL) { ++ /* ++ * If the default configuration file in /etc does not exist, ++ * try the vendor configuration file as fallback. ++ */ ++ f = fopen(VENDOR_FAILLOCK_DEFAULT_CONF, "r"); ++ } ++#endif /* VENDOR_FAILLOCK_DEFAULT_CONF */ ++ ++ if (f == NULL) { ++ /* ignore non-existent default config file */ ++ if (errno == ENOENT && cfgfile == NULL) ++ return PAM_SUCCESS; ++ return PAM_SERVICE_ERR; ++ } ++ ++ 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 PAM_SERVICE_ERR; ++ } ++ ++ 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] != '/') { ++ 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) { ++ config_log(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) { ++ config_log(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) { ++ config_log(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) { ++ config_log(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; ++ config_log(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 if (strcmp(name, "nodelay") == 0) { ++ opts->flags |= FAILLOCK_FLAG_NO_DELAY; ++ } ++ else { ++ 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 -up Linux-PAM-1.3.1/modules/pam_faillock/faillock_config.h.faillock-load-conf-from-file Linux-PAM-1.3.1/modules/pam_faillock/faillock_config.h +--- Linux-PAM-1.3.1/modules/pam_faillock/faillock_config.h.faillock-load-conf-from-file 2022-05-26 10:57:11.747067749 +0200 ++++ Linux-PAM-1.3.1/modules/pam_faillock/faillock_config.h 2022-05-26 10:57:11.747067749 +0200 +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (c) 2022 Tomas Mraz ++ * Copyright (c) 2022 Iker Pedrosa ++ * ++ * 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_config.h - load configuration options from file ++ * ++ */ ++ ++#ifndef _FAILLOCK_CONFIG_H ++#define _FAILLOCK_CONFIG_H ++ ++#include ++#include ++#include ++ ++#include ++ ++#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 FAILLOCK_FLAG_NO_DELAY 0x40 ++ ++#define FAILLOCK_CONF_MAX_LINELEN 1023 ++#define MAX_TIME_INTERVAL 604800 /* 7 days */ ++ ++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 *user; ++ char *admin_group; ++ int failures; ++ uint64_t latest_time; ++ uid_t uid; ++ 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 -up Linux-PAM-1.3.1/modules/pam_faillock/main.c.faillock-load-conf-from-file Linux-PAM-1.3.1/modules/pam_faillock/main.c +--- Linux-PAM-1.3.1/modules/pam_faillock/main.c.faillock-load-conf-from-file 2022-05-26 10:57:11.713067506 +0200 ++++ Linux-PAM-1.3.1/modules/pam_faillock/main.c 2022-05-26 10:57:11.747067749 +0200 +@@ -48,43 +48,50 @@ + #include + #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; + if (i >= argc || strlen(argv[i]) == 0) { +- fprintf(stderr, "%s: No user name supplied.\n", argv[0]); ++ 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) { ++ else if (strcmp(argv[i], "--reset") == 0) { + opts->reset = 1; + } + else { +@@ -92,6 +99,21 @@ args_parse(int argc, char **argv, struct + 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; + } + +@@ -109,10 +131,11 @@ do_user(struct options *opts, const char + 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) { +@@ -189,11 +212,11 @@ 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: ", opts->progname); +- perror(NULL); ++ fprintf(stderr, "%s: Error reading tally directory: %m\n", opts->progname); + return 2; + } + +diff -up Linux-PAM-1.3.1/modules/pam_faillock/Makefile.am.faillock-load-conf-from-file Linux-PAM-1.3.1/modules/pam_faillock/Makefile.am +--- Linux-PAM-1.3.1/modules/pam_faillock/Makefile.am.faillock-load-conf-from-file 2022-05-26 10:57:11.727067606 +0200 ++++ Linux-PAM-1.3.1/modules/pam_faillock/Makefile.am 2022-05-26 10:57:59.032406450 +0200 +@@ -17,7 +17,7 @@ TESTS = tst-pam_faillock + securelibdir = $(SECUREDIR) + secureconfdir = $(SCONFIGDIR) + +-noinst_HEADERS = faillock.h ++noinst_HEADERS = faillock.h faillock_config.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 +@@ -36,8 +36,8 @@ 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 ++pam_faillock_la_SOURCES = pam_faillock.c faillock.c faillock_config.c ++faillock_SOURCES = main.c faillock.c faillock_config.c + + if ENABLE_REGENERATE_MAN + noinst_DATA = README +diff -up Linux-PAM-1.3.1/modules/pam_faillock/pam_faillock.c.faillock-load-conf-from-file Linux-PAM-1.3.1/modules/pam_faillock/pam_faillock.c +--- Linux-PAM-1.3.1/modules/pam_faillock/pam_faillock.c.faillock-load-conf-from-file 2022-05-26 10:57:11.727067606 +0200 ++++ Linux-PAM-1.3.1/modules/pam_faillock/pam_faillock.c 2022-05-26 10:57:11.748067756 +0200 +@@ -38,7 +38,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -54,83 +53,50 @@ + #include + #include + ++#include "pam_inline.h" + #include "faillock.h" +- +-#define PAM_SM_AUTH +-#define PAM_SM_ACCOUNT ++#include "faillock_config.h" + + #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 ++static int + 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 = NULL; ++ + 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) { ++ const char *str = pam_str_skip_prefix(argv[i], "conf="); ++ ++ if (str != NULL) { ++ conf = str; ++ config_arg_index = i; ++ } ++ } ++ ++ if ((rv = read_config_file(pamh, opts, conf)) != PAM_SUCCESS) { ++ pam_syslog(pamh, LOG_ERR, ++ "Configuration file missing or broken"); ++ return rv; + } + + 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) { +@@ -163,226 +129,26 @@ args_parse(pam_handle_t *pamh, int argc, + 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); ++ if (opts->fatal_error) ++ return PAM_BUF_ERR; + 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) ++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; +- } ++ return pam_modutil_check_user_in_passwd(pamh, user, NULL) == PAM_SUCCESS; + } + +-static int get_pam_user(pam_handle_t *pamh, struct options *opts) ++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; ++ return rv == PAM_CONV_AGAIN ? PAM_INCOMPLETE : rv; + } + + if (*user == '\0') { +@@ -391,10 +157,10 @@ static int get_pam_user(pam_handle_t *pa + + if ((pwd=pam_modutil_getpwnam(pamh, user)) == NULL) { + if (opts->flags & FAILLOCK_FLAG_AUDIT) { +- pam_syslog(pamh, LOG_ERR, "User unknown: %s", user); ++ pam_syslog(pamh, LOG_NOTICE, "User unknown: %s", user); + } + else { +- pam_syslog(pamh, LOG_ERR, "User unknown"); ++ pam_syslog(pamh, LOG_NOTICE, "User unknown"); + } + return PAM_IGNORE; + } +@@ -421,10 +187,11 @@ check_tally(pam_handle_t *pamh, struct o + 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; + +@@ -446,7 +213,7 @@ check_tally(pam_handle_t *pamh, struct o + } + + latest_time = 0; +- for(i = 0; i < tallies->count; i++) { ++ 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; +@@ -455,7 +222,7 @@ check_tally(pam_handle_t *pamh, struct o + opts->latest_time = latest_time; + + failures = 0; +- for(i = 0; i < tallies->count; i++) { ++ 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; +@@ -498,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); +@@ -519,9 +287,10 @@ write_tally(pam_handle_t *pamh, struct o + 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) { +@@ -536,7 +305,7 @@ write_tally(pam_handle_t *pamh, struct o + failures = 0; + + for (i = 0; i < tallies->count; ++i) { +- if (tallies->records[i].time < oldtime) { ++ if (oldtime == 0 || tallies->records[i].time < oldtime) { + oldtime = tallies->records[i].time; + oldest = i; + } +@@ -630,16 +399,26 @@ faillock_message(pam_handle_t *pamh, str + left = opts->latest_time + opts->unlock_time - opts->now; + } + ++ pam_info(pamh, _("The account is locked due to %u failed logins."), ++ (unsigned int)opts->failures); + 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); ++#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 + } + } + } +@@ -663,7 +442,7 @@ opts_cleanup(struct options *opts) + + /*---------------------------------------------------------------------*/ + +-PAM_EXTERN int ++int + pam_sm_authenticate(pam_handle_t *pamh, int flags, + int argc, const char **argv) + { +@@ -673,13 +452,13 @@ 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; ++ rv = args_parse(pamh, argc, argv, flags, &opts); ++ if (rv != PAM_SUCCESS) + goto err; +- } + +- pam_fail_delay(pamh, 2000000); /* 2 sec delay for 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; +@@ -722,7 +501,7 @@ err: + + /*---------------------------------------------------------------------*/ + +-PAM_EXTERN int ++int + pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED, + int argc UNUSED, const char **argv UNUSED) + { +@@ -731,7 +510,7 @@ pam_sm_setcred(pam_handle_t *pamh UNUSED + + /*---------------------------------------------------------------------*/ + +-PAM_EXTERN int ++int + pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, + int argc, const char **argv) + { +@@ -741,12 +520,10 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int + + memset(&tallies, 0, sizeof(tallies)); + +- args_parse(pamh, argc, argv, flags, &opts); ++ rv = args_parse(pamh, argc, argv, flags, &opts); + +- if (opts.fatal_error) { +- rv = PAM_BUF_ERR; ++ if (rv != PAM_SUCCESS) + goto err; +- } + + opts.action = FAILLOCK_ACTION_AUTHSUCC; + +@@ -770,28 +547,3 @@ err: + + /*-----------------------------------------------------------------------*/ + +-#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/modules/pam_faillock/faillock.h b/modules/pam_faillock/faillock.h +index b22a9dfb..0ea0ffba 100644 +--- a/modules/pam_faillock/faillock.h ++++ b/modules/pam_faillock/faillock.h +diff -up Linux-PAM-1.5.1/modules/pam_faillock/faillock.h.faillock-load-conf-from-file Linux-PAM-1.5.1/modules/pam_faillock/faillock.h +--- Linux-PAM-1.5.1/modules/pam_faillock/faillock.h.faillock-load-conf-from-file 2020-11-25 17:57:02.000000000 +0100 ++++ Linux-PAM-1.5.1/modules/pam_faillock/faillock.h 2022-05-25 15:33:03.885551825 +0200 +@@ -67,7 +67,6 @@ 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 --git a/modules/pam_faillock/pam_faillock.c b/modules/pam_faillock/pam_faillock.c +index ddbb90e7..f46fca99 100644 +--- a/modules/pam_faillock/pam_faillock.c ++++ b/modules/pam_faillock/pam_faillock.c +@@ -134,10 +134,96 @@ args_parse(pam_handle_t *pamh, int argc, const char **argv, + return PAM_SUCCESS; + } + ++static int ++check_user_in_passwd(pam_handle_t *pamh, ++ const char *user_name, ++ const char *file_name) ++{ ++ int rc; ++ size_t user_len; ++ FILE *fp; ++ char line[BUFSIZ]; ++ ++ /* Validate the user name. */ ++ if ((user_len = strlen(user_name)) == 0) { ++ pam_syslog(pamh, LOG_NOTICE, "user name is not valid"); ++ return PAM_SERVICE_ERR; ++ } ++ ++ if (user_len > sizeof(line) - sizeof(":")) { ++ pam_syslog(pamh, LOG_NOTICE, "user name is too long"); ++ return PAM_SERVICE_ERR; ++ } ++ ++ if (strchr(user_name, ':') != NULL) { ++ /* ++ * "root:x" is not a local user name even if the passwd file ++ * contains a line starting with "root:x:". ++ */ ++ return PAM_PERM_DENIED; ++ } ++ ++ /* Open the passwd file. */ ++ if (file_name == NULL) { ++ file_name = "/etc/passwd"; ++ } ++ if ((fp = fopen(file_name, "r")) == NULL) { ++ pam_syslog(pamh, LOG_ERR, "error opening %s: %m", file_name); ++ return PAM_SERVICE_ERR; ++ } ++ ++ /* ++ * Scan the file using fgets() instead of fgetpwent_r() because ++ * the latter is not flexible enough in handling long lines ++ * in passwd files. ++ */ ++ rc = PAM_PERM_DENIED; ++ while (fgets(line, sizeof(line), fp) != NULL) { ++ size_t line_len; ++ const char *str; ++ ++ /* ++ * Does this line start with the user name ++ * followed by a colon? ++ */ ++ if (strncmp(user_name, line, user_len) == 0 && ++ line[user_len] == ':') { ++ rc = PAM_SUCCESS; ++ /* ++ * Continue reading the file to avoid timing attacks. ++ */ ++ } ++ /* Has a newline been read? */ ++ line_len = strlen(line); ++ if (line_len < sizeof(line) - 1 || ++ line[line_len - 1] == '\n') { ++ /* Yes, continue with the next line. */ ++ continue; ++ } ++ ++ /* No, read till the end of this line first. */ ++ while ((str = fgets(line, sizeof(line), fp)) != NULL) { ++ line_len = strlen(line); ++ if (line_len == 0 || ++ line[line_len - 1] == '\n') { ++ break; ++ } ++ } ++ if (str == NULL) { ++ /* fgets returned NULL, we are done. */ ++ break; ++ } ++ /* Continue with the next line. */ ++ } ++ ++ fclose(fp); ++ return rc; ++} ++ + static int + check_local_user (pam_handle_t *pamh, const char *user) + { +- return pam_modutil_check_user_in_passwd(pamh, user, NULL) == PAM_SUCCESS; ++ return check_user_in_passwd(pamh, user, NULL) == PAM_SUCCESS; + } + + static int diff --git a/SOURCES/pam-1.3.1-inline.patch b/SOURCES/pam-1.3.1-inline.patch new file mode 100644 index 0000000..65dfa26 --- /dev/null +++ b/SOURCES/pam-1.3.1-inline.patch @@ -0,0 +1,105 @@ +diff -up Linux-PAM-1.3.1/libpam/include/pam_cc_compat.h.inline Linux-PAM-1.3.1/libpam/include/pam_cc_compat.h +--- Linux-PAM-1.3.1/libpam/include/pam_cc_compat.h.inline 2022-05-26 10:44:31.702623614 +0200 ++++ Linux-PAM-1.3.1/libpam/include/pam_cc_compat.h 2022-05-26 10:44:31.703623621 +0200 +@@ -44,4 +44,17 @@ + # define DIAG_POP_IGNORE_CAST_ALIGN /* empty */ + #endif + ++/* ++ * Evaluates to ++ * 1, if the given two types are known to be the same ++ * 0, otherwise. ++ */ ++#if PAM_GNUC_PREREQ(3, 0) ++# define PAM_IS_SAME_TYPE(x_, y_) \ ++ __builtin_types_compatible_p(__typeof__(x_), __typeof__(y_)) ++#else ++/* Cannot tell whether these types are the same. */ ++# define PAM_IS_SAME_TYPE(x_, y_) 0 ++#endif ++ + #endif /* PAM_CC_COMPAT_H */ +diff -up Linux-PAM-1.3.1/libpam/include/pam_inline.h.inline Linux-PAM-1.3.1/libpam/include/pam_inline.h +--- Linux-PAM-1.3.1/libpam/include/pam_inline.h.inline 2022-05-26 10:44:31.703623621 +0200 ++++ Linux-PAM-1.3.1/libpam/include/pam_inline.h 2022-05-26 10:44:31.703623621 +0200 +@@ -0,0 +1,67 @@ ++/* ++ * Copyright (c) 2020 Dmitry V. Levin ++ * ++ * Handy inline functions and macros providing some convenient functionality ++ * to libpam and its modules. ++ */ ++ ++#ifndef PAM_INLINE_H ++#define PAM_INLINE_H ++ ++#include "pam_cc_compat.h" ++#include ++ ++/* ++ * Evaluates to ++ * - a syntax error if the argument is 0, ++ * 0, otherwise. ++ */ ++#define PAM_FAIL_BUILD_ON_ZERO(e_) (sizeof(int[-1 + 2 * !!(e_)]) * 0) ++ ++/* ++ * Evaluates to ++ * 1, if the given type is known to be a non-array type ++ * 0, otherwise. ++ */ ++#define PAM_IS_NOT_ARRAY(a_) PAM_IS_SAME_TYPE((a_), &(a_)[0]) ++ ++/* ++ * Evaluates to ++ * - a syntax error if the argument is not an array, ++ * 0, otherwise. ++ */ ++#define PAM_MUST_BE_ARRAY(a_) PAM_FAIL_BUILD_ON_ZERO(!PAM_IS_NOT_ARRAY(a_)) ++ ++/* Evaluates to the number of elements in the specified array. */ ++#define PAM_ARRAY_SIZE(a_) (sizeof(a_) / sizeof((a_)[0]) + PAM_MUST_BE_ARRAY(a_)) ++ ++/* ++ * Returns NULL if STR does not start with PREFIX, ++ * or a pointer to the first char in STR after PREFIX. ++ * The length of PREFIX is specified by PREFIX_LEN. ++ */ ++static inline const char * ++pam_str_skip_prefix_len(const char *str, const char *prefix, size_t prefix_len) ++{ ++ return strncmp(str, prefix, prefix_len) ? NULL : str + prefix_len; ++} ++ ++#define pam_str_skip_prefix(str_, prefix_) \ ++ pam_str_skip_prefix_len((str_), (prefix_), sizeof(prefix_) - 1 + PAM_MUST_BE_ARRAY(prefix_)) ++ ++/* ++ * Returns NULL if STR does not start with PREFIX ++ * (ignoring the case of the characters), ++ * or a pointer to the first char in STR after PREFIX. ++ * The length of PREFIX is specified by PREFIX_LEN. ++ */ ++static inline const char * ++pam_str_skip_icase_prefix_len(const char *str, const char *prefix, size_t prefix_len) ++{ ++ return strncasecmp(str, prefix, prefix_len) ? NULL : str + prefix_len; ++} ++ ++#define pam_str_skip_icase_prefix(str_, prefix_) \ ++ pam_str_skip_icase_prefix_len((str_), (prefix_), sizeof(prefix_) - 1 + PAM_MUST_BE_ARRAY(prefix_)) ++ ++#endif /* PAM_INLINE_H */ +diff -up Linux-PAM-1.3.1/libpam/Makefile.am.inline Linux-PAM-1.3.1/libpam/Makefile.am +--- Linux-PAM-1.3.1/libpam/Makefile.am.inline 2022-05-26 10:44:31.702623614 +0200 ++++ Linux-PAM-1.3.1/libpam/Makefile.am 2022-05-26 10:45:21.146977780 +0200 +@@ -18,7 +18,8 @@ include_HEADERS = include/security/_pam_ + include/security/pam_ext.h include/security/pam_modutil.h + + noinst_HEADERS = pam_prelude.h pam_private.h pam_tokens.h \ +- pam_modutil_private.h include/pam_cc_compat.h ++ pam_modutil_private.h include/pam_cc_compat.h \ ++ include/pam_inline.h + + libpam_la_LDFLAGS = -no-undefined -version-info 84:2:84 + libpam_la_LIBADD = @LIBAUDIT@ $(LIBPRELUDE_LIBS) @LIBDL@ diff --git a/SOURCES/pam-1.3.1-pam-cc-compat.patch b/SOURCES/pam-1.3.1-pam-cc-compat.patch new file mode 100644 index 0000000..fe9a95a --- /dev/null +++ b/SOURCES/pam-1.3.1-pam-cc-compat.patch @@ -0,0 +1,63 @@ +diff -up Linux-PAM-1.3.1/libpam/include/pam_cc_compat.h.pam-cc-compat Linux-PAM-1.3.1/libpam/include/pam_cc_compat.h +--- Linux-PAM-1.3.1/libpam/include/pam_cc_compat.h.pam-cc-compat 2022-05-26 10:43:50.436328027 +0200 ++++ Linux-PAM-1.3.1/libpam/include/pam_cc_compat.h 2022-05-26 10:43:50.436328027 +0200 +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2020 Dmitry V. Levin ++ */ ++ ++#ifndef PAM_CC_COMPAT_H ++#define PAM_CC_COMPAT_H ++ ++#include "config.h" ++#include ++ ++#if defined __clang__ && defined __clang_major__ && defined __clang_minor__ ++# define PAM_CLANG_PREREQ(maj, min) \ ++ ((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min)) ++#else ++# define PAM_CLANG_PREREQ(maj, min) 0 ++#endif ++ ++#if PAM_GNUC_PREREQ(4, 6) ++# define DIAG_PUSH_IGNORE_CAST_QUAL \ ++ _Pragma("GCC diagnostic push"); \ ++ _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") ++# define DIAG_POP_IGNORE_CAST_QUAL \ ++ _Pragma("GCC diagnostic pop") ++# define DIAG_PUSH_IGNORE_CAST_ALIGN \ ++ _Pragma("GCC diagnostic push"); \ ++ _Pragma("GCC diagnostic ignored \"-Wcast-align\"") ++# define DIAG_POP_IGNORE_CAST_ALIGN \ ++ _Pragma("GCC diagnostic pop") ++#elif PAM_CLANG_PREREQ(2, 6) ++# define DIAG_PUSH_IGNORE_CAST_QUAL \ ++ _Pragma("clang diagnostic push"); \ ++ _Pragma("clang diagnostic ignored \"-Wcast-qual\"") ++# define DIAG_POP_IGNORE_CAST_QUAL \ ++ _Pragma("clang diagnostic pop") ++# define DIAG_PUSH_IGNORE_CAST_ALIGN \ ++ _Pragma("clang diagnostic push"); \ ++ _Pragma("clang diagnostic ignored \"-Wcast-align\"") ++# define DIAG_POP_IGNORE_CAST_ALIGN \ ++ _Pragma("clang diagnostic pop") ++#else ++# define DIAG_PUSH_IGNORE_CAST_QUAL /* empty */ ++# define DIAG_POP_IGNORE_CAST_QUAL /* empty */ ++# define DIAG_PUSH_IGNORE_CAST_ALIGN /* empty */ ++# define DIAG_POP_IGNORE_CAST_ALIGN /* empty */ ++#endif ++ ++#endif /* PAM_CC_COMPAT_H */ +diff -up Linux-PAM-1.3.1/libpam/Makefile.am.pam-cc-compat Linux-PAM-1.3.1/libpam/Makefile.am +--- Linux-PAM-1.3.1/libpam/Makefile.am.pam-cc-compat 2022-05-26 10:43:50.436328027 +0200 ++++ Linux-PAM-1.3.1/libpam/Makefile.am 2022-05-26 10:44:00.865402730 +0200 +@@ -18,7 +18,7 @@ include_HEADERS = include/security/_pam_ + include/security/pam_ext.h include/security/pam_modutil.h + + noinst_HEADERS = pam_prelude.h pam_private.h pam_tokens.h \ +- pam_modutil_private.h ++ pam_modutil_private.h include/pam_cc_compat.h + + libpam_la_LDFLAGS = -no-undefined -version-info 84:2:84 + libpam_la_LIBADD = @LIBAUDIT@ $(LIBPRELUDE_LIBS) @LIBDL@ diff --git a/SPECS/pam.spec b/SPECS/pam.spec index 56d1104..58d1b87 100644 --- a/SPECS/pam.spec +++ b/SPECS/pam.spec @@ -3,7 +3,7 @@ Summary: An extensible library which provides authentication for applications Name: pam Version: 1.3.1 -Release: 16%{?dist} +Release: 16%{?dist}.1 # The library is BSD licensed with option to relicense as GPLv2+ # - this option is redundant as the BSD license allows that anyway. # pam_timestamp, pam_loginuid, and pam_console modules are GPLv2+. @@ -69,6 +69,12 @@ Patch49: pam-1.3.1-namespace-gdm-doc.patch Patch50: pam-1.3.1-pam-userdb-prevent-garbage-characters-from-db.patch # https://github.com/linux-pam/linux-pam/commit/3234488f2c52a021eec87df1990d256314c21bff Patch51: pam-1.3.1-pam-limits-unlimited-value.patch +# Needed by the next patch. Already upstreamed +Patch52: pam-1.3.1-pam-cc-compat.patch +Patch53: pam-1.3.1-inline.patch +# https://github.com/linux-pam/linux-pam/commit/9bcbe96d9e82a23d983c0618178a8dc25596ac2d +# https://github.com/linux-pam/linux-pam/commit/fc867a9e22eac2c9a0ed0577776bba4df21c9aad +Patch54: pam-1.3.1-faillock-load-conf-from-file.patch %define _pamlibdir %{_libdir} %define _moduledir %{_libdir}/security @@ -168,6 +174,9 @@ cp %{SOURCE18} . %patch49 -p1 -b .namespace-gdm-doc %patch50 -p1 -b .pam-userdb-prevent-garbage-characters-from-db %patch51 -p1 -b .pam-limits-unlimited-value +%patch52 -p1 -b .pam-cc-compat +%patch53 -p1 -b .inline +%patch54 -p1 -b .faillock-load-conf-from-file autoreconf -i @@ -414,6 +423,9 @@ done %doc doc/specs/rfc86.0.txt %changelog +* Tue Aug 2 2022 Iker Pedrosa - 1.3.1-16.1 +- faillock: load configuration from file. Resolves: #2112889 + * Fri Jan 28 2022 Iker Pedrosa - 1.3.1-16 - pam_limits: "Unlimited" is not a valid value for RLIMIT_NOFILE. Resolves: #2047655