diff --git a/Linux-PAM-1.5.1.tar.xz b/Linux-PAM-1.5.1.tar.xz new file mode 100644 index 0000000000000000000000000000000000000000..a2fd982694fe773460c85e75faee20eecea42de9 Binary files /dev/null and b/Linux-PAM-1.5.1.tar.xz differ diff --git a/Linux-PAM-1.5.1.tar.xz.asc b/Linux-PAM-1.5.1.tar.xz.asc new file mode 100644 index 0000000000000000000000000000000000000000..01d6a46fe5febd56880f5a2e6bfdffb7794ea850 --- /dev/null +++ b/Linux-PAM-1.5.1.tar.xz.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIcBAABCAAGBQJfvo0CAAoJEKgEH6g54W42L+0P/19bgVH4cRd7ONZLwYvWvWlQ +NXkjwn26MEXElWESlKnQQz08W5QASWCz3vgAn9NGDmS+lJ38i4Li4aGpn3COPE2g +BAN9LEaAErK60b3ZkWwDEARDs1JntA1vUuuHx0EoLEMtFEeU20h5PPMrsDwu7LGF +sD6KYdM6TWLMXcRybqGOeWmWxfp8S8MVNwVN3C3q0aVIOMxky0i4rzCL7zRTJztQ +q7FaX2xrTGfUiAI7smT/KGoK7pbQTzZtoR67uE/2WZ4bSyWMZcuDkt16WP/L6x9v +c5DnVaLazM9xYUAOn4tlPiG8LLmfXo1MjD+KOS9byAx+uTij3avxaC/vv0BDcATH +jywxH8iTPkvYXP0uJIa4Gbs1qi3vNZn+gaQt/T+rCVNo3dfFZZxBvLbTQ8AN1hKr +MnoQbIQh0buuSuwmAxF0EDIefX3bDCurKOTQrRajK7huFm0w2NgBqL8WR8f1Wmm9 +mGSdKuVpWSk5uEygCUFOfwviYbi1I1K2Dmo3TsLBgNPKvAF3LAGJC7KzD+Q+Nmos +XBOljilcAfdJ7t2P8W7xTSMEnXu7nI1TM+Er80ukfu0fipJEP0xyi+XWh+2n0Bx+ +3wwt8fSL7rmI4I4l6GRb3Jk/Gq1bKy956tgm3TE6gXTXVGZqNs0E28rNRURXDqZu +XrjVwhlpsH/Auk17hU65 +=E0ev +-----END PGP SIGNATURE----- diff --git a/pam-1.5.0-noflex.patch b/pam-1.5.0-noflex.patch new file mode 100644 index 0000000000000000000000000000000000000000..282b482f7ca4a0fb307059e87db3fa88e6706b38 --- /dev/null +++ b/pam-1.5.0-noflex.patch @@ -0,0 +1,24 @@ +diff -up Linux-PAM-1.5.0/doc/Makefile.am.noflex Linux-PAM-1.5.0/doc/Makefile.am +--- Linux-PAM-1.5.0/doc/Makefile.am.noflex 2020-11-10 16:46:13.000000000 +0100 ++++ Linux-PAM-1.5.0/doc/Makefile.am 2020-11-11 11:39:00.980421433 +0100 +@@ -2,7 +2,7 @@ + # Copyright (c) 2005, 2006 Thorsten Kukuk + # + +-SUBDIRS = man specs sag adg mwg ++SUBDIRS = man sag adg mwg + + CLEANFILES = *~ + +diff -up Linux-PAM-1.5.0/Makefile.am.noflex Linux-PAM-1.5.0/Makefile.am +--- Linux-PAM-1.5.0/Makefile.am.noflex 2020-11-11 11:39:00.980421433 +0100 ++++ Linux-PAM-1.5.0/Makefile.am 2020-11-11 11:39:15.887625418 +0100 +@@ -4,7 +4,7 @@ + + AUTOMAKE_OPTIONS = 1.9 gnu dist-xz no-dist-gzip check-news + +-SUBDIRS = libpam tests libpamc libpam_misc modules po conf examples xtests ++SUBDIRS = libpam tests libpamc libpam_misc modules po doc examples xtests + + if HAVE_DOC + SUBDIRS += doc diff --git a/pam-1.5.0-redhat-modules.patch b/pam-1.5.0-redhat-modules.patch new file mode 100644 index 0000000000000000000000000000000000000000..92d04da67b0d909f0115b804b2198db47e006f67 --- /dev/null +++ b/pam-1.5.0-redhat-modules.patch @@ -0,0 +1,25 @@ +diff -up Linux-PAM-1.5.0/configure.ac.redhat-modules Linux-PAM-1.5.0/configure.ac +--- Linux-PAM-1.5.0/configure.ac.redhat-modules 2020-11-11 11:21:21.947857371 +0100 ++++ Linux-PAM-1.5.0/configure.ac 2020-11-11 11:22:58.638193747 +0100 +@@ -639,6 +639,8 @@ AC_CONFIG_FILES([Makefile libpam/Makefil + po/Makefile.in \ + Make.xml.rules \ + modules/Makefile \ ++ modules/pam_chroot/Makefile modules/pam_console/Makefile \ ++ modules/pam_postgresok/Makefile \ + modules/pam_access/Makefile \ + modules/pam_debug/Makefile modules/pam_deny/Makefile \ + modules/pam_echo/Makefile modules/pam_env/Makefile \ +diff -up Linux-PAM-1.5.0/modules/Makefile.am.redhat-modules Linux-PAM-1.5.0/modules/Makefile.am +--- Linux-PAM-1.5.0/modules/Makefile.am.redhat-modules 2020-11-10 16:46:13.000000000 +0100 ++++ Linux-PAM-1.5.0/modules/Makefile.am 2020-11-11 11:21:21.947857371 +0100 +@@ -47,6 +47,9 @@ SUBDIRS := \ + pam_debug \ + pam_deny \ + pam_echo \ ++ pam_chroot \ ++ pam_console \ ++ pam_postgresok \ + pam_env \ + pam_exec \ + pam_faildelay \ diff --git a/pam-1.5.1-faillock-load-conf-from-file.patch b/pam-1.5.1-faillock-load-conf-from-file.patch new file mode 100644 index 0000000000000000000000000000000000000000..dbfa3d837a254e3d8c66069a3a03195a181b7fd7 --- /dev/null +++ b/pam-1.5.1-faillock-load-conf-from-file.patch @@ -0,0 +1,848 @@ +diff -up Linux-PAM-1.5.1/modules/pam_faillock/faillock.8.xml.faillock-load-conf-from-file Linux-PAM-1.5.1/modules/pam_faillock/faillock.8.xml +--- Linux-PAM-1.5.1/modules/pam_faillock/faillock.8.xml.faillock-load-conf-from-file 2020-11-25 17:57:02.000000000 +0100 ++++ Linux-PAM-1.5.1/modules/pam_faillock/faillock.8.xml 2022-05-25 15:30:33.700518571 +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.5.1/modules/pam_faillock/faillock_config.c.faillock-load-conf-from-file Linux-PAM-1.5.1/modules/pam_faillock/faillock_config.c +--- Linux-PAM-1.5.1/modules/pam_faillock/faillock_config.c.faillock-load-conf-from-file 2022-05-25 15:30:33.699518564 +0200 ++++ Linux-PAM-1.5.1/modules/pam_faillock/faillock_config.c 2022-05-25 15:30:33.700518571 +0200 +@@ -0,0 +1,263 @@ ++/* ++ * 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" ++ ++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.5.1/modules/pam_faillock/faillock_config.h.faillock-load-conf-from-file Linux-PAM-1.5.1/modules/pam_faillock/faillock_config.h +--- Linux-PAM-1.5.1/modules/pam_faillock/faillock_config.h.faillock-load-conf-from-file 2022-05-25 15:30:33.699518564 +0200 ++++ Linux-PAM-1.5.1/modules/pam_faillock/faillock_config.h 2022-05-25 15:30:33.700518571 +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.5.1/modules/pam_faillock/main.c.faillock-load-conf-from-file Linux-PAM-1.5.1/modules/pam_faillock/main.c +--- Linux-PAM-1.5.1/modules/pam_faillock/main.c.faillock-load-conf-from-file 2020-11-25 17:57:02.000000000 +0100 ++++ Linux-PAM-1.5.1/modules/pam_faillock/main.c 2022-05-25 15:37:05.801216176 +0200 +@@ -51,33 +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; +@@ -85,7 +92,7 @@ args_parse(int argc, char **argv, struct + 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; +@@ -95,6 +102,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; + } + +@@ -112,10 +134,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) { +@@ -191,8 +214,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 -up Linux-PAM-1.5.1/modules/pam_faillock/Makefile.am.faillock-load-conf-from-file Linux-PAM-1.5.1/modules/pam_faillock/Makefile.am +--- Linux-PAM-1.5.1/modules/pam_faillock/Makefile.am.faillock-load-conf-from-file 2020-11-25 17:57:02.000000000 +0100 ++++ Linux-PAM-1.5.1/modules/pam_faillock/Makefile.am 2022-05-25 15:30:33.700518571 +0200 +@@ -20,7 +20,7 @@ TESTS = $(dist_check_SCRIPTS) + securelibdir = $(SECUREDIR) + secureconfdir = $(SCONFIGDIR) + +-noinst_HEADERS = faillock.h ++noinst_HEADERS = faillock.h faillock_config.h + + AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ + $(WARN_CFLAGS) +@@ -41,8 +41,8 @@ dist_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 + dist_noinst_DATA = README +diff -up Linux-PAM-1.5.1/modules/pam_faillock/pam_faillock.c.faillock-load-conf-from-file Linux-PAM-1.5.1/modules/pam_faillock/pam_faillock.c +--- Linux-PAM-1.5.1/modules/pam_faillock/pam_faillock.c.faillock-load-conf-from-file 2020-11-25 17:57:02.000000000 +0100 ++++ Linux-PAM-1.5.1/modules/pam_faillock/pam_faillock.c 2022-05-25 15:33:03.885551825 +0200 +@@ -38,7 +38,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -56,55 +55,12 @@ + + #include "pam_inline.h" + #include "faillock.h" ++#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 FAILLOCK_FLAG_NO_DELAY 0x40 +- +-#define MAX_TIME_INTERVAL 604800 /* 7 days */ +-#define FAILLOCK_CONF_MAX_LINELEN 1023 +- +-static const char default_faillock_conf[] = FAILLOCK_DEFAULT_CONF; +- +-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; +-}; +- +-static int read_config_file( +- pam_handle_t *pamh, +- struct options *opts, +- const char *cfgfile +-); +- +-static void set_conf_opt( +- pam_handle_t *pamh, +- struct options *opts, +- const char *name, +- const char *value +-); +- + static int + args_parse(pam_handle_t *pamh, int argc, const char **argv, + int flags, struct options *opts) +@@ -112,11 +68,10 @@ args_parse(pam_handle_t *pamh, int argc, + int i; + int config_arg_index = -1; + int rv; +- const char *conf = default_faillock_conf; ++ const char *conf = NULL; + + memset(opts, 0, sizeof(*opts)); + +- opts->dir = strdup(FAILLOCK_DEFAULT_TALLYDIR); + opts->deny = 3; + opts->fail_interval = 900; + opts->unlock_time = 600; +@@ -174,185 +129,11 @@ 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; +- } +- + if (opts->fatal_error) + return PAM_BUF_ERR; + return PAM_SUCCESS; + } + +-/* parse a single configuration file */ +-static 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 && cfgfile == default_faillock_conf) +- 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; +-} +- +-static 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 if (strcmp(name, "nodelay") == 0) { +- opts->flags |= FAILLOCK_FLAG_NO_DELAY; +- } +- else { +- pam_syslog(pamh, LOG_ERR, "Unknown option: %s", name); +- } +-} +- + static int + check_local_user (pam_handle_t *pamh, const char *user) + { +@@ -406,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; + +@@ -483,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); +@@ -504,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) { +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/pam-1.5.1-pam-keyinit-thread-safe.patch b/pam-1.5.1-pam-keyinit-thread-safe.patch new file mode 100644 index 0000000000000000000000000000000000000000..f898b0b95ae051c91fd74b17f9e60f39cdbf19e1 --- /dev/null +++ b/pam-1.5.1-pam-keyinit-thread-safe.patch @@ -0,0 +1,150 @@ +From a35e092e24ee7632346a0e1b4a203c04d4cd2c62 Mon Sep 17 00:00:00 2001 +From: Iker Pedrosa +Date: Mon, 24 Jan 2022 15:43:23 +0100 +Subject: [PATCH] pam_keyinit: thread-safe implementation + +* modules/pam_keyinit/pam_keyinit.c: Bypass setre*id() C library calls +with kernel calls and change global variables definitions to be +thread-safe. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1997969 +Signed-off-by: Iker Pedrosa +Co-Authored-By: Andreas Schneider +--- + modules/pam_keyinit/pam_keyinit.c | 60 ++++++++++++++++++++++--------- + 1 file changed, 44 insertions(+), 16 deletions(-) + +diff --git a/modules/pam_keyinit/pam_keyinit.c b/modules/pam_keyinit/pam_keyinit.c +index 92e4953b..df9804b9 100644 +--- a/modules/pam_keyinit/pam_keyinit.c ++++ b/modules/pam_keyinit/pam_keyinit.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + #define KEY_SPEC_SESSION_KEYRING -3 /* ID for session keyring */ + #define KEY_SPEC_USER_KEYRING -4 /* ID for UID-specific keyring */ +@@ -31,12 +32,12 @@ + #define KEYCTL_REVOKE 3 /* revoke a key */ + #define KEYCTL_LINK 8 /* link a key into a keyring */ + +-static int my_session_keyring = 0; +-static int session_counter = 0; +-static int do_revoke = 0; +-static uid_t revoke_as_uid; +-static gid_t revoke_as_gid; +-static int xdebug = 0; ++static _Thread_local int my_session_keyring = 0; ++static _Atomic int session_counter = 0; ++static _Thread_local int do_revoke = 0; ++static _Thread_local uid_t revoke_as_uid; ++static _Thread_local gid_t revoke_as_gid; ++static _Thread_local int xdebug = 0; + + static void debug(pam_handle_t *pamh, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +@@ -64,6 +65,33 @@ static void error(pam_handle_t *pamh, const char *fmt, ...) + va_end(va); + } + ++static int pam_setreuid(uid_t ruid, uid_t euid) ++{ ++#if defined(SYS_setreuid32) ++ return syscall(SYS_setreuid32, ruid, euid); ++#else ++ return syscall(SYS_setreuid, ruid, euid); ++#endif ++} ++ ++static int pam_setregid(gid_t rgid, gid_t egid) ++{ ++#if defined(SYS_setregid32) ++ return syscall(SYS_setregid32, rgid, egid); ++#else ++ return syscall(SYS_setregid, rgid, egid); ++#endif ++} ++ ++static int pam_setresuid(uid_t ruid, uid_t euid, uid_t suid) ++{ ++#if defined(SYS_setresuid32) ++ return syscall(SYS_setresuid32, ruid, euid, suid); ++#else ++ return syscall(SYS_setresuid, ruid, euid, suid); ++#endif ++} ++ + /* + * initialise the session keyring for this process + */ +@@ -140,14 +168,14 @@ static int kill_keyrings(pam_handle_t *pamh, int error_ret) + + /* switch to the real UID and GID so that we have permission to + * revoke the key */ +- if (revoke_as_gid != old_gid && setregid(-1, revoke_as_gid) < 0) { ++ if (revoke_as_gid != old_gid && pam_setregid(-1, revoke_as_gid) < 0) { + error(pamh, "Unable to change GID to %d temporarily\n", revoke_as_gid); + return error_ret; + } + +- if (revoke_as_uid != old_uid && setresuid(-1, revoke_as_uid, old_uid) < 0) { ++ if (revoke_as_uid != old_uid && pam_setresuid(-1, revoke_as_uid, old_uid) < 0) { + error(pamh, "Unable to change UID to %d temporarily\n", revoke_as_uid); +- if (getegid() != old_gid && setregid(-1, old_gid) < 0) ++ if (getegid() != old_gid && pam_setregid(-1, old_gid) < 0) + error(pamh, "Unable to change GID back to %d\n", old_gid); + return error_ret; + } +@@ -157,12 +185,12 @@ static int kill_keyrings(pam_handle_t *pamh, int error_ret) + } + + /* return to the original UID and GID (probably root) */ +- if (revoke_as_uid != old_uid && setreuid(-1, old_uid) < 0) { ++ if (revoke_as_uid != old_uid && pam_setreuid(-1, old_uid) < 0) { + error(pamh, "Unable to change UID back to %d\n", old_uid); + ret = error_ret; + } + +- if (revoke_as_gid != old_gid && setregid(-1, old_gid) < 0) { ++ if (revoke_as_gid != old_gid && pam_setregid(-1, old_gid) < 0) { + error(pamh, "Unable to change GID back to %d\n", old_gid); + ret = error_ret; + } +@@ -215,14 +243,14 @@ static int do_keyinit(pam_handle_t *pamh, int argc, const char **argv, int error + + /* switch to the real UID and GID so that the keyring ends up owned by + * the right user */ +- if (gid != old_gid && setregid(gid, -1) < 0) { ++ if (gid != old_gid && pam_setregid(gid, -1) < 0) { + error(pamh, "Unable to change GID to %d temporarily\n", gid); + return error_ret; + } + +- if (uid != old_uid && setreuid(uid, -1) < 0) { ++ if (uid != old_uid && pam_setreuid(uid, -1) < 0) { + error(pamh, "Unable to change UID to %d temporarily\n", uid); +- if (setregid(old_gid, -1) < 0) ++ if (pam_setregid(old_gid, -1) < 0) + error(pamh, "Unable to change GID back to %d\n", old_gid); + return error_ret; + } +@@ -230,12 +258,12 @@ static int do_keyinit(pam_handle_t *pamh, int argc, const char **argv, int error + ret = init_keyrings(pamh, force, error_ret); + + /* return to the original UID and GID (probably root) */ +- if (uid != old_uid && setreuid(old_uid, -1) < 0) { ++ if (uid != old_uid && pam_setreuid(old_uid, -1) < 0) { + error(pamh, "Unable to change UID back to %d\n", old_uid); + ret = error_ret; + } + +- if (gid != old_gid && setregid(old_gid, -1) < 0) { ++ if (gid != old_gid && pam_setregid(old_gid, -1) < 0) { + error(pamh, "Unable to change GID back to %d\n", old_gid); + ret = error_ret; + } +-- +2.35.1 + diff --git a/pam-1.5.1-pam-limits-unlimited-value.patch b/pam-1.5.1-pam-limits-unlimited-value.patch new file mode 100644 index 0000000000000000000000000000000000000000..a025c45ddbb5cacb4a723331e466f517d1d8a6ac --- /dev/null +++ b/pam-1.5.1-pam-limits-unlimited-value.patch @@ -0,0 +1,99 @@ +From 3234488f2c52a021eec87df1990d256314c21bff Mon Sep 17 00:00:00 2001 +From: Josef Moellers +Date: Wed, 14 Apr 2021 16:39:28 +0200 +Subject: [PATCH] pam_limits: "Unlimited" is not a valid value for + RLIMIT_NOFILE. + +Replace it with a value obtained from /proc/sys/fs/nr_open + +* modules/pam_limits/limits.conf.5.xml: Document the replacement. +* modules/pam_limits/pam_limits.c: Replace unlimited RLIMIT_NOFILE + value with a value obtained from /proc/sys/fs/nr_open +--- + modules/pam_limits/limits.conf.5.xml | 2 ++ + modules/pam_limits/pam_limits.c | 49 ++++++++++++++++++++++++++++ + 2 files changed, 51 insertions(+) + +diff --git a/modules/pam_limits/limits.conf.5.xml b/modules/pam_limits/limits.conf.5.xml +index cd64ac90..c5bd6768 100644 +--- a/modules/pam_limits/limits.conf.5.xml ++++ b/modules/pam_limits/limits.conf.5.xml +@@ -283,6 +283,8 @@ + unlimited or infinity indicating no limit, + except for priority, nice, + and nonewprivs. ++ If nofile is to be set to one of these values, ++ it will be set to the contents of /proc/sys/fs/nr_open instead (see setrlimit(3)). + + + If a hard limit or soft limit of a resource is set to a valid value, +diff --git a/modules/pam_limits/pam_limits.c b/modules/pam_limits/pam_limits.c +index 10049973..7cc45d77 100644 +--- a/modules/pam_limits/pam_limits.c ++++ b/modules/pam_limits/pam_limits.c +@@ -487,6 +487,41 @@ static int init_limits(pam_handle_t *pamh, struct pam_limit_s *pl, int ctrl) + return retval; + } + ++/* ++ * Read the contents of and return it in *valuep ++ * return 1 if conversion succeeds, result is in *valuep ++ * return 0 if conversion fails, *valuep is untouched. ++ */ ++static int ++value_from_file(const char *pathname, rlim_t *valuep) ++{ ++ char buf[128]; ++ FILE *fp; ++ int retval; ++ ++ retval = 0; ++ ++ if ((fp = fopen(pathname, "r")) != NULL) { ++ if (fgets(buf, sizeof(buf), fp) != NULL) { ++ char *endptr; ++ unsigned long long value; ++ ++ errno = 0; ++ value = strtoull(buf, &endptr, 10); ++ if (endptr != buf && ++ (value != ULLONG_MAX || errno == 0) && ++ (unsigned long long) (rlim_t) value == value) { ++ *valuep = (rlim_t) value; ++ retval = 1; ++ } ++ } ++ ++ fclose(fp); ++ } ++ ++ return retval; ++} ++ + static void + process_limit (const pam_handle_t *pamh, int source, const char *lim_type, + const char *lim_item, const char *lim_value, +@@ -666,6 +701,20 @@ process_limit (const pam_handle_t *pamh, int source, const char *lim_type, + rlimit_value = 20 - int_value; + break; + #endif ++ case RLIMIT_NOFILE: ++ /* ++ * If nofile is to be set to "unlimited", try to set it to ++ * the value in /proc/sys/fs/nr_open instead. ++ */ ++ if (rlimit_value == RLIM_INFINITY) { ++ if (!value_from_file("/proc/sys/fs/nr_open", &rlimit_value)) ++ pam_syslog(pamh, LOG_WARNING, ++ "Cannot set \"nofile\" to a sensible value"); ++ else if (ctrl & PAM_DEBUG_ARG) ++ pam_syslog(pamh, LOG_DEBUG, "Setting \"nofile\" limit to %llu", ++ (unsigned long long) rlimit_value); ++ } ++ break; + } + + if ( (limit_item != LIMIT_LOGIN) +-- +2.33.1 + diff --git a/pam-1.5.1-pam-pwhistory-load-conf-from-file.patch b/pam-1.5.1-pam-pwhistory-load-conf-from-file.patch new file mode 100644 index 0000000000000000000000000000000000000000..4320292d68709ad1767b716bf117f40d80b0297b --- /dev/null +++ b/pam-1.5.1-pam-pwhistory-load-conf-from-file.patch @@ -0,0 +1,489 @@ +diff -up Linux-PAM-1.5.1/modules/pam_pwhistory/Makefile.am.pam-pwhistory-load-conf-from-file Linux-PAM-1.5.1/modules/pam_pwhistory/Makefile.am +--- Linux-PAM-1.5.1/modules/pam_pwhistory/Makefile.am.pam-pwhistory-load-conf-from-file 2020-11-25 17:57:02.000000000 +0100 ++++ Linux-PAM-1.5.1/modules/pam_pwhistory/Makefile.am 2022-08-22 09:08:48.916487811 +0200 +@@ -9,9 +9,10 @@ MAINTAINERCLEANFILES = $(MANS) README + EXTRA_DIST = $(XMLS) + + if HAVE_DOC +-dist_man_MANS = pam_pwhistory.8 pwhistory_helper.8 ++dist_man_MANS = pam_pwhistory.8 pwhistory_helper.8 pwhistory.conf.5 + endif +-XMLS = README.xml pam_pwhistory.8.xml pwhistory_helper.8.xml ++XMLS = README.xml pam_pwhistory.8.xml pwhistory_helper.8.xml \ ++ pwhistory.conf.5.xml + dist_check_SCRIPTS = tst-pam_pwhistory + TESTS = $(dist_check_SCRIPTS) + +@@ -26,12 +27,14 @@ if HAVE_VERSIONING + pam_pwhistory_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map + endif + +-noinst_HEADERS = opasswd.h ++noinst_HEADERS = opasswd.h pwhistory_config.h ++ ++dist_secureconf_DATA = pwhistory.conf + + securelib_LTLIBRARIES = pam_pwhistory.la + pam_pwhistory_la_CFLAGS = $(AM_CFLAGS) + pam_pwhistory_la_LIBADD = $(top_builddir)/libpam/libpam.la @LIBCRYPT@ @LIBSELINUX@ +-pam_pwhistory_la_SOURCES = pam_pwhistory.c opasswd.c ++pam_pwhistory_la_SOURCES = pam_pwhistory.c opasswd.c pwhistory_config.c + + sbin_PROGRAMS = pwhistory_helper + pwhistory_helper_CFLAGS = $(AM_CFLAGS) -DHELPER_COMPILE=\"pwhistory_helper\" @EXE_CFLAGS@ +diff -up Linux-PAM-1.5.1/modules/pam_pwhistory/pam_pwhistory.8.xml.pam-pwhistory-load-conf-from-file Linux-PAM-1.5.1/modules/pam_pwhistory/pam_pwhistory.8.xml +--- Linux-PAM-1.5.1/modules/pam_pwhistory/pam_pwhistory.8.xml.pam-pwhistory-load-conf-from-file 2020-11-25 17:57:02.000000000 +0100 ++++ Linux-PAM-1.5.1/modules/pam_pwhistory/pam_pwhistory.8.xml 2022-08-22 09:13:08.715628372 +0200 +@@ -36,6 +36,9 @@ + + authtok_type=STRING + ++ ++ conf=/path/to/config-file ++ + + + +@@ -104,7 +107,7 @@ + + + The last N passwords for each +- user are saved in /etc/security/opasswd. ++ user are saved. + The default is 10. Value of + 0 makes the module to keep the existing + contents of the opasswd file unchanged. +@@ -137,7 +140,26 @@ + + + ++ ++ ++ ++ ++ ++ ++ Use another configuration file instead of the default ++ /etc/security/pwhistory.conf. ++ ++ ++ ++ + ++ ++ The options for configuring the module behavior are described in the ++ pwhistory.conf ++ 5 manual page. The options ++ specified on the module command line override the values from the ++ configuration file. ++ + + + +@@ -223,6 +245,9 @@ password required pam_unix.so + SEE ALSO + + ++ pwhistory.conf5 ++ , ++ + pam.conf5 + , + +diff -up Linux-PAM-1.5.1/modules/pam_pwhistory/pam_pwhistory.c.pam-pwhistory-load-conf-from-file Linux-PAM-1.5.1/modules/pam_pwhistory/pam_pwhistory.c +--- Linux-PAM-1.5.1/modules/pam_pwhistory/pam_pwhistory.c.pam-pwhistory-load-conf-from-file 2020-11-25 17:57:02.000000000 +0100 ++++ Linux-PAM-1.5.1/modules/pam_pwhistory/pam_pwhistory.c 2022-08-22 09:11:34.949855242 +0200 +@@ -63,14 +63,8 @@ + + #include "opasswd.h" + #include "pam_inline.h" ++#include "pwhistory_config.h" + +-struct options_t { +- int debug; +- int enforce_for_root; +- int remember; +- int tries; +-}; +-typedef struct options_t options_t; + + + static void +@@ -299,6 +293,8 @@ pam_sm_chauthtok (pam_handle_t *pamh, in + options.remember = 10; + options.tries = 1; + ++ parse_config_file(pamh, argc, argv, &options); ++ + /* Parse parameters for module */ + for ( ; argc-- > 0; argv++) + parse_option (pamh, *argv, &options); +@@ -306,7 +302,6 @@ pam_sm_chauthtok (pam_handle_t *pamh, in + if (options.debug) + pam_syslog (pamh, LOG_DEBUG, "pam_sm_chauthtok entered"); + +- + if (options.remember == 0) + return PAM_IGNORE; + +diff -up Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory.conf.5.xml.pam-pwhistory-load-conf-from-file Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory.conf.5.xml +--- Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory.conf.5.xml.pam-pwhistory-load-conf-from-file 2022-08-22 09:08:48.916487811 +0200 ++++ Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory.conf.5.xml 2022-08-22 09:08:48.916487811 +0200 +@@ -0,0 +1,155 @@ ++ ++ ++ ++ ++ ++ ++ pwhistory.conf ++ 5 ++ Linux-PAM Manual ++ ++ ++ ++ pwhistory.conf ++ pam_pwhistory configuration file ++ ++ ++ ++ ++ DESCRIPTION ++ ++ pwhistory.conf provides a way to configure the ++ default settings for saving the last passwords for each user. ++ This file is read by the pam_pwhistory module and is the ++ preferred method over configuring pam_pwhistory 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 ++ ++ ++ ++ ++ ++ ++ ++ Turns on debugging via ++ ++ syslog3 ++ . ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ If this option is set, the check is enforced for root, too. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ The last N passwords for each ++ user are saved. ++ The default is 10. Value of ++ 0 makes the module to keep the existing ++ contents of the opasswd file unchanged. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Prompt user at most N times ++ before returning with error. The default is 1. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Store password history in file ++ /path/filename rather than the default ++ location. The default location is ++ /etc/security/opasswd. ++ ++ ++ ++ ++ ++ ++ ++ EXAMPLES ++ ++ /etc/security/pwhistory.conf file example: ++ ++ ++debug ++remember=5 ++file=/tmp/opasswd ++ ++ ++ ++ ++ FILES ++ ++ ++ /etc/security/pwhistory.conf ++ ++ the config file for custom options ++ ++ ++ ++ ++ ++ ++ SEE ALSO ++ ++ ++ pwhistory8 ++ , ++ ++ pam_pwhistory8 ++ , ++ ++ pam.conf5 ++ , ++ ++ pam.d5 ++ , ++ ++ pam8 ++ ++ ++ ++ ++ ++ AUTHOR ++ ++ pam_pwhistory was written by Thorsten Kukuk. The support for ++ pwhistory.conf was written by Iker Pedrosa. ++ ++ ++ ++ +diff -up Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory_config.c.pam-pwhistory-load-conf-from-file Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory_config.c +--- Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory_config.c.pam-pwhistory-load-conf-from-file 2022-08-22 09:08:48.916487811 +0200 ++++ Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory_config.c 2022-08-22 09:08:48.916487811 +0200 +@@ -0,0 +1,115 @@ ++/* ++ * 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 "pam_inline.h" ++#include "pwhistory_config.h" ++ ++#define PWHISTORY_DEFAULT_CONF "/etc/security/pwhistory.conf" ++ ++void ++parse_config_file(pam_handle_t *pamh, int argc, const char **argv, ++ struct options_t *options) ++{ ++ const char *fname = NULL; ++ int i; ++ char *val; ++ ++ for (i = 0; i < argc; ++i) { ++ const char *str = pam_str_skip_prefix(argv[i], "conf="); ++ ++ if (str != NULL) { ++ fname = str; ++ } ++ } ++ ++ if (fname == NULL) { ++ fname = PWHISTORY_DEFAULT_CONF; ++ } ++ ++ val = pam_modutil_search_key (pamh, fname, "debug"); ++ if (val != NULL) { ++ options->debug = 1; ++ free(val); ++ } ++ ++ val = pam_modutil_search_key (pamh, fname, "enforce_for_root"); ++ if (val != NULL) { ++ options->enforce_for_root = 1; ++ free(val); ++ } ++ ++ val = pam_modutil_search_key (pamh, fname, "remember"); ++ if (val != NULL) { ++ unsigned int temp; ++ if (sscanf(val, "%u", &temp) != 1) { ++ pam_syslog(pamh, LOG_ERR, ++ "Bad number supplied for remember argument"); ++ } else { ++ options->remember = temp; ++ } ++ free(val); ++ } ++ ++ val = pam_modutil_search_key (pamh, fname, "retry"); ++ if (val != NULL) { ++ unsigned int temp; ++ if (sscanf(val, "%u", &temp) != 1) { ++ pam_syslog(pamh, LOG_ERR, ++ "Bad number supplied for retry argument"); ++ } else { ++ options->tries = temp; ++ } ++ free(val); ++ } ++ ++ val = pam_modutil_search_key (pamh, fname, "file"); ++ if (val != NULL) { ++ if (*val != '/') { ++ pam_syslog (pamh, LOG_ERR, ++ "File path should be absolute: %s", val); ++ } else { ++ options->filename = val; ++ } ++ } ++} +diff -up Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory_config.h.pam-pwhistory-load-conf-from-file Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory_config.h +--- Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory_config.h.pam-pwhistory-load-conf-from-file 2022-08-22 09:08:48.916487811 +0200 ++++ Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory_config.h 2022-08-22 09:08:48.916487811 +0200 +@@ -0,0 +1,54 @@ ++/* ++ * 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. ++ */ ++ ++#ifndef _PWHISTORY_CONFIG_H ++#define _PWHISTORY_CONFIG_H ++ ++#include ++ ++struct options_t { ++ int debug; ++ int enforce_for_root; ++ int remember; ++ int tries; ++ const char *filename; ++}; ++typedef struct options_t options_t; ++ ++void ++parse_config_file(pam_handle_t *pamh, int argc, const char **argv, ++ struct options_t *options); ++ ++#endif /* _PWHISTORY_CONFIG_H */ +diff -up Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory.conf.pam-pwhistory-load-conf-from-file Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory.conf +--- Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory.conf.pam-pwhistory-load-conf-from-file 2022-08-22 09:08:48.916487811 +0200 ++++ Linux-PAM-1.5.1/modules/pam_pwhistory/pwhistory.conf 2022-08-22 09:08:48.916487811 +0200 +@@ -0,0 +1,21 @@ ++# Configuration for remembering the last passwords used by a user. ++# ++# Enable the debugging logs. ++# Enabled if option is present. ++# debug ++# ++# root account's passwords are also remembered. ++# Enabled if option is present. ++# enforce_for_root ++# ++# Number of passwords to remember. ++# The default is 10. ++# remember = 10 ++# ++# Number of times to prompt for the password. ++# The default is 1. ++# retry = 1 ++# ++# The directory where the last passwords are kept. ++# The default is /etc/security/opasswd. ++# file = /etc/security/opasswd diff --git a/pam-1.5.1-pam-usertype-SYS_UID_MAX.patch b/pam-1.5.1-pam-usertype-SYS_UID_MAX.patch new file mode 100644 index 0000000000000000000000000000000000000000..df0ac35a7762aac1cdf58b5413bac271c4838478 --- /dev/null +++ b/pam-1.5.1-pam-usertype-SYS_UID_MAX.patch @@ -0,0 +1,100 @@ +From 370064ef6f99581b08d473a42bb3417d5dda3e4e Mon Sep 17 00:00:00 2001 +From: Iker Pedrosa +Date: Thu, 17 Feb 2022 10:24:03 +0100 +Subject: [PATCH] pam_usertype: only use SYS_UID_MAX for system users + +* modules/pam_usertype/pam_usertype.c (pam_usertype_is_system): Stop +using SYS_UID_MIN to check if it is a system account, because all +accounts below the SYS_UID_MAX are system users. +* modules/pam_usertype/pam_usertype.8.xml: Remove reference to SYS_UID_MIN +as it is no longer used to calculate the system accounts. +* configure.ac: Remove PAM_USERTYPE_SYSUIDMIN. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1949137 +Signed-off-by: Iker Pedrosa +--- + configure.ac | 5 ----- + modules/pam_usertype/pam_usertype.8.xml | 2 +- + modules/pam_usertype/pam_usertype.c | 15 ++++++--------- + 3 files changed, 7 insertions(+), 15 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 639fc1ad..79113ad1 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -632,11 +632,6 @@ test -n "$opt_uidmin" || + opt_uidmin=1000 + AC_DEFINE_UNQUOTED(PAM_USERTYPE_UIDMIN, $opt_uidmin, [Minimum regular user uid.]) + +-AC_ARG_WITH([sysuidmin], AS_HELP_STRING([--with-sysuidmin=],[default value for system user min uid (101)]), opt_sysuidmin=$withval) +-test -n "$opt_sysuidmin" || +- opt_sysuidmin=101 +-AC_DEFINE_UNQUOTED(PAM_USERTYPE_SYSUIDMIN, $opt_sysuidmin, [Minimum system user uid.]) +- + AC_ARG_WITH([kernel-overflow-uid], AS_HELP_STRING([--with-kernel-overflow-uid=],[kernel overflow uid, default (uint16_t)-2=65534]), opt_kerneloverflowuid=$withval) + test -n "$opt_kerneloverflowuid" || + opt_kerneloverflowuid=65534 +diff --git a/modules/pam_usertype/pam_usertype.8.xml b/modules/pam_usertype/pam_usertype.8.xml +index 7651da6e..d9307ba3 100644 +--- a/modules/pam_usertype/pam_usertype.8.xml ++++ b/modules/pam_usertype/pam_usertype.8.xml +@@ -31,7 +31,7 @@ + pam_usertype.so is designed to succeed or fail authentication + based on type of the account of the authenticated user. + The type of the account is decided with help of +- SYS_UID_MIN and SYS_UID_MAX ++ SYS_UID_MAX + settings in /etc/login.defs. One use is to select + whether to load other modules based on this test. + +diff --git a/modules/pam_usertype/pam_usertype.c b/modules/pam_usertype/pam_usertype.c +index d03b73b5..cfd9c8bb 100644 +--- a/modules/pam_usertype/pam_usertype.c ++++ b/modules/pam_usertype/pam_usertype.c +@@ -194,7 +194,6 @@ static int + pam_usertype_is_system(pam_handle_t *pamh, uid_t uid) + { + uid_t uid_min; +- uid_t sys_min; + uid_t sys_max; + + if (uid == (uid_t)-1) { +@@ -202,21 +201,19 @@ pam_usertype_is_system(pam_handle_t *pamh, uid_t uid) + return PAM_USER_UNKNOWN; + } + +- if (uid <= 99) { +- /* Reserved. */ +- return PAM_SUCCESS; +- } +- + if (uid == PAM_USERTYPE_OVERFLOW_UID) { + /* nobody */ + return PAM_SUCCESS; + } + + uid_min = pam_usertype_get_id(pamh, "UID_MIN", PAM_USERTYPE_UIDMIN); +- sys_min = pam_usertype_get_id(pamh, "SYS_UID_MIN", PAM_USERTYPE_SYSUIDMIN); + sys_max = pam_usertype_get_id(pamh, "SYS_UID_MAX", uid_min - 1); + +- return uid >= sys_min && uid <= sys_max ? PAM_SUCCESS : PAM_AUTH_ERR; ++ if (uid <= sys_max && uid < uid_min) { ++ return PAM_SUCCESS; ++ } ++ ++ return PAM_AUTH_ERR; + } + + static int +@@ -253,7 +250,7 @@ pam_usertype_evaluate(struct pam_usertype_opts *opts, + + /** + * Arguments: +- * - issystem: uid in ++ * - issystem: uid less than SYS_UID_MAX + * - isregular: not issystem + * - use_uid: use user that runs application not that is being authenticate (same as in pam_succeed_if) + * - audit: log unknown users to syslog +-- +2.36.1 + diff --git a/pam-1.5.1-pam_filter_close_file_after_controlling_tty.patch b/pam-1.5.1-pam_filter_close_file_after_controlling_tty.patch new file mode 100644 index 0000000000000000000000000000000000000000..27af9c4daf86b12ef58f0430d90821aea527357b --- /dev/null +++ b/pam-1.5.1-pam_filter_close_file_after_controlling_tty.patch @@ -0,0 +1,42 @@ +From ec0e724fe53188c5c762c34ca9db6681c0de01b8 Mon Sep 17 00:00:00 2001 +From: Iker Pedrosa +Date: Thu, 1 Jul 2021 12:14:29 +0200 +Subject: [PATCH] pam_filter: Close file after controlling tty + +Failing to check the descriptor value meant that there was a bug in the +attempt to close the controlling tty. Moreover, this would lead to a +file descriptor leak as pointed out by the static analyzer tool: + +Error: RESOURCE_LEAK (CWE-772): [#def26] +Linux-PAM-1.5.1/modules/pam_filter/pam_filter.c:356: open_fn: Returning handle opened by "open". [Note: The source code implementation of the function has been overridden by a user model.] +Linux-PAM-1.5.1/modules/pam_filter/pam_filter.c:356: var_assign: Assigning: "t" = handle returned from "open("/dev/tty", 2)". +Linux-PAM-1.5.1/modules/pam_filter/pam_filter.c:357: off_by_one: Testing whether handle "t" is strictly greater than zero is suspicious. "t" leaks when it is zero. +Linux-PAM-1.5.1/modules/pam_filter/pam_filter.c:357: remediation: Did you intend to include equality with zero? +Linux-PAM-1.5.1/modules/pam_filter/pam_filter.c:367: leaked_handle: Handle variable "t" going out of scope leaks the handle. + 365| pam_syslog(pamh, LOG_ERR, + 366| "child cannot become new session: %m"); + 367|-> return PAM_ABORT; + 368| } + 369| + +Signed-off-by: Iker Pedrosa +--- + modules/pam_filter/pam_filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/modules/pam_filter/pam_filter.c b/modules/pam_filter/pam_filter.c +index 2f0af4fb..6e6def37 100644 +--- a/modules/pam_filter/pam_filter.c ++++ b/modules/pam_filter/pam_filter.c +@@ -354,7 +354,7 @@ set_filter (pam_handle_t *pamh, int flags UNUSED, int ctrl, + int t = open("/dev/tty", O_RDWR|O_NOCTTY); + #else + int t = open("/dev/tty",O_RDWR); +- if (t > 0) { ++ if (t >= 0) { + (void) ioctl(t, TIOCNOTTY, NULL); + close(t); + } +-- +2.31.1 + diff --git a/pam-1.5.1-timestamp-openssl-hmac-authentication.patch b/pam-1.5.1-timestamp-openssl-hmac-authentication.patch new file mode 100644 index 0000000000000000000000000000000000000000..abea7608fc117a9dedbb78a28837b784d23f7fd1 --- /dev/null +++ b/pam-1.5.1-timestamp-openssl-hmac-authentication.patch @@ -0,0 +1,738 @@ +From b3bb13e18a74e9ece825b7de1b81db97ebb107a0 Mon Sep 17 00:00:00 2001 +From: Iker Pedrosa +Date: Thu, 25 Mar 2021 09:43:30 +0100 +Subject: [PATCH] pam_timestamp: replace hmac implementation + +sha1 is no longer recommended as a cryptographic algorithm for +authentication. Thus, the idea of this change is to replace the +implementation provided by hmacsha1 included in pam_timestamp module by +the one in the openssl library. This way, there's no need to maintain +the cryptographic algorithm implementation and it can be easily changed +with a single configuration change. + +modules/pam_timestamp/hmac_openssl_wrapper.c: implement wrapper +functions around openssl's hmac implementation. Moreover, manage the key +generation and its read and write in a file. Include an option to +configure the cryptographic algorithm in login.defs file. +modules/pam_timestamp/hmac_openssl_wrapper.h: likewise. +modules/pam_timestamp/pam_timestamp.c: replace calls to functions +provided by hmacsha1 by functions provided by openssl's wrapper. +configure.ac: include openssl dependecy if it is enabled. +modules/pam_timestamp/Makefile.am: include new files and openssl library +to compilation. +ci/install-dependencies.sh: include openssl library to dependencies. +NEWS: add new item to next release. +Make.xml.rules.in: add stringparam profiling for hmac +doc/custom-man.xsl: change import docbook to one with profiling +modules/pam_timestamp/pam_timestamp.8.xml: add conditional paragraph to +indicate the value in /etc/login.defs that holds the value for the +encryption algorithm + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1947294 +--- + Make.xml.rules.in | 2 +- + NEWS | 5 + + configure.ac | 16 + + doc/custom-man.xsl | 2 +- + modules/pam_timestamp/Makefile.am | 15 +- + modules/pam_timestamp/hmac_openssl_wrapper.c | 381 +++++++++++++++++++ + modules/pam_timestamp/hmac_openssl_wrapper.h | 57 +++ + modules/pam_timestamp/pam_timestamp.8.xml | 5 + + modules/pam_timestamp/pam_timestamp.c | 53 ++- + 10 files changed, 524 insertions(+), 13 deletions(-) + create mode 100644 modules/pam_timestamp/hmac_openssl_wrapper.c + create mode 100644 modules/pam_timestamp/hmac_openssl_wrapper.h + +diff --git a/Make.xml.rules.in b/Make.xml.rules.in +index daa1b97b..27bb510e 100644 +--- a/Make.xml.rules.in ++++ b/Make.xml.rules.in +@@ -21,6 +21,6 @@ README: README.xml + + %.8: %.8.xml + $(XMLLINT) --nonet --xinclude --postvalid --noout $< +- $(XSLTPROC) -o $(srcdir)/$@ --path $(srcdir) --xinclude @STRINGPARAM_VENDORDIR@ --nonet $(top_srcdir)/doc/custom-man.xsl $< ++ $(XSLTPROC) -o $(srcdir)/$@ --path $(srcdir) --xinclude @STRINGPARAM_VENDORDIR@ @STRINGPARAM_HMAC@ --nonet $(top_srcdir)/doc/custom-man.xsl $< + + #CLEANFILES += $(man_MANS) README +diff --git a/NEWS b/NEWS +index 2d49ec39..f4d11303 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,5 +1,10 @@ + Linux-PAM NEWS -- history of user-visible changes. + ++Release next ++* pam_timestamp: change hmac algorithm to call openssl instead of the bundled ++ sha1 implementation if selected. Add option to select the hash ++ algorithm to use with HMAC. ++ + Release 1.5.1 + * pam_unix: fixed CVE-2020-27780 - authentication bypass when a user + doesn't exist and root password is blank +diff --git a/configure.ac b/configure.ac +index bd806473..9c92d0de 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -504,6 +504,22 @@ else + fi + AC_SUBST([STRINGPARAM_VENDORDIR]) + ++AC_ARG_ENABLE([openssl], ++ AS_HELP_STRING([--enable-openssl],[use OpenSSL crypto libraries]), ++ [OPENSSL_ENABLED=$enableval], OPENSSL_ENABLED=no) ++if test "$OPENSSL_ENABLED" = "yes" ; then ++ AC_CHECK_LIB([crypto], [EVP_MAC_CTX_new], ++ [CRYPTO_LIBS="-lcrypto" ++ use_openssl=yes ++ AC_DEFINE([WITH_OPENSSL], 1, [OpenSSL provides crypto algorithm for hmac]) ++ STRINGPARAM_HMAC="--stringparam profile.condition 'openssl_hmac'"], ++ [CRYPTO_LIBS="" ++ STRINGPARAM_HMAC="--stringparam profile.condition 'no_openssl_hmac'"]) ++fi ++AC_SUBST([CRYPTO_LIBS]) ++AC_SUBST([STRINGPARAM_HMAC]) ++AM_CONDITIONAL([COND_USE_OPENSSL], [test "x$use_openssl" = "xyes"]) ++ + dnl Checks for header files. + AC_HEADER_DIRENT + AC_HEADER_STDC +diff --git a/doc/custom-man.xsl b/doc/custom-man.xsl +index 4c35e839..a3408e6c 100644 +--- a/doc/custom-man.xsl ++++ b/doc/custom-man.xsl +@@ -1,6 +1,6 @@ + + +- ++ + + + +diff --git a/modules/pam_timestamp/Makefile.am b/modules/pam_timestamp/Makefile.am +index 1faa324a..d290b85f 100644 +--- a/modules/pam_timestamp/Makefile.am ++++ b/modules/pam_timestamp/Makefile.am +@@ -18,12 +18,12 @@ TESTS = $(dist_check_SCRIPTS) $(check_PROGRAMS) + securelibdir = $(SECUREDIR) + secureconfdir = $(SCONFIGDIR) + +-noinst_HEADERS = hmacsha1.h sha1.h ++noinst_HEADERS = hmacsha1.h sha1.h hmac_openssl_wrapper.h + + AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ + $(WARN_CFLAGS) + +-pam_timestamp_la_LDFLAGS = -no-undefined -avoid-version -module $(AM_LDFLAGS) ++pam_timestamp_la_LDFLAGS = -no-undefined -avoid-version -module $(AM_LDFLAGS) $(CRYPTO_LIBS) + pam_timestamp_la_LIBADD = $(top_builddir)/libpam/libpam.la + if HAVE_VERSIONING + pam_timestamp_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map +@@ -32,7 +32,12 @@ endif + securelib_LTLIBRARIES = pam_timestamp.la + sbin_PROGRAMS = pam_timestamp_check + +-pam_timestamp_la_SOURCES = pam_timestamp.c hmacsha1.c sha1.c ++pam_timestamp_la_SOURCES = pam_timestamp.c ++if COND_USE_OPENSSL ++pam_timestamp_la_SOURCES += hmac_openssl_wrapper.c ++else ++pam_timestamp_la_SOURCES += hmacsha1.c sha1.c ++endif + pam_timestamp_la_CFLAGS = $(AM_CFLAGS) + + pam_timestamp_check_SOURCES = pam_timestamp_check.c +@@ -40,7 +45,11 @@ pam_timestamp_check_CFLAGS = $(AM_CFLAGS) @EXE_CFLAGS@ + pam_timestamp_check_LDADD = $(top_builddir)/libpam/libpam.la + pam_timestamp_check_LDFLAGS = @EXE_LDFLAGS@ + ++if COND_USE_OPENSSL ++hmacfile_SOURCES = hmac_openssl_wrapper.c ++else + hmacfile_SOURCES = hmacfile.c hmacsha1.c sha1.c ++endif + hmacfile_LDADD = $(top_builddir)/libpam/libpam.la + + check_PROGRAMS = hmacfile +diff --git a/modules/pam_timestamp/hmac_openssl_wrapper.c b/modules/pam_timestamp/hmac_openssl_wrapper.c +new file mode 100644 +index 00000000..926c2fb9 +--- /dev/null ++++ b/modules/pam_timestamp/hmac_openssl_wrapper.c +@@ -0,0 +1,381 @@ ++/* Wrapper for hmac openssl implementation. ++ * ++ * Copyright (c) 2021 Red Hat, Inc. ++ * Written by 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" ++ ++#ifdef WITH_OPENSSL ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "hmac_openssl_wrapper.h" ++ ++#define LOGIN_DEFS "/etc/login.defs" ++#define CRYPTO_KEY "HMAC_CRYPTO_ALGO" ++#define DEFAULT_ALGORITHM "SHA512" ++#define MAX_HMAC_LENGTH 512 ++#define MAX_KEY_LENGTH EVP_MAX_KEY_LENGTH ++ ++static char * ++get_crypto_algorithm(pam_handle_t *pamh, int debug){ ++ char *config_value = NULL; ++ ++ config_value = pam_modutil_search_key(pamh, LOGIN_DEFS, CRYPTO_KEY); ++ ++ if (config_value == NULL) { ++ config_value = strdup(DEFAULT_ALGORITHM); ++ if (debug) { ++ pam_syslog(pamh, LOG_DEBUG, ++ "Key [%s] not found, falling back to default algorithm [%s]\n", ++ CRYPTO_KEY, DEFAULT_ALGORITHM); ++ } ++ } ++ ++ return config_value; ++} ++ ++static int ++generate_key(pam_handle_t *pamh, char **key, size_t key_size) ++{ ++ int fd = 0; ++ size_t bytes_read = 0; ++ char * tmp = NULL; ++ ++ fd = open("/dev/urandom", O_RDONLY); ++ if (fd == -1) { ++ pam_syslog(pamh, LOG_ERR, "Cannot open /dev/urandom: %m"); ++ return PAM_AUTH_ERR; ++ } ++ ++ tmp = malloc(key_size); ++ if (!tmp) { ++ pam_syslog(pamh, LOG_CRIT, "Not enough memory"); ++ close(fd); ++ return PAM_AUTH_ERR; ++ } ++ ++ bytes_read = pam_modutil_read(fd, tmp, key_size); ++ close(fd); ++ ++ if (bytes_read < key_size) { ++ pam_syslog(pamh, LOG_ERR, "Short read on random device"); ++ free(tmp); ++ return PAM_AUTH_ERR; ++ } ++ ++ *key = tmp; ++ ++ return PAM_SUCCESS; ++} ++ ++static int ++read_file(pam_handle_t *pamh, int fd, char **text, size_t *text_length) ++{ ++ struct stat st; ++ size_t bytes_read = 0; ++ char *tmp = NULL; ++ ++ if (fstat(fd, &st) == -1) { ++ pam_syslog(pamh, LOG_ERR, "Unable to stat file: %m"); ++ close(fd); ++ return PAM_AUTH_ERR; ++ } ++ ++ if (st.st_size == 0) { ++ pam_syslog(pamh, LOG_ERR, "Key file size cannot be 0"); ++ close(fd); ++ return PAM_AUTH_ERR; ++ } ++ ++ tmp = malloc(st.st_size); ++ if (!tmp) { ++ pam_syslog(pamh, LOG_CRIT, "Not enough memory"); ++ close(fd); ++ return PAM_AUTH_ERR; ++ } ++ ++ bytes_read = pam_modutil_read(fd, tmp, st.st_size); ++ close(fd); ++ ++ if (bytes_read < (size_t)st.st_size) { ++ pam_syslog(pamh, LOG_ERR, "Short read on key file"); ++ memset(tmp, 0, st.st_size); ++ free(tmp); ++ return PAM_AUTH_ERR; ++ } ++ ++ *text = tmp; ++ *text_length = st.st_size; ++ ++ return PAM_SUCCESS; ++} ++ ++static int ++write_file(pam_handle_t *pamh, const char *file_name, char *text, ++ size_t text_length, uid_t owner, gid_t group) ++{ ++ int fd = 0; ++ size_t bytes_written = 0; ++ ++ fd = open(file_name, ++ O_WRONLY | O_CREAT | O_TRUNC, ++ S_IRUSR | S_IWUSR); ++ if (fd == -1) { ++ pam_syslog(pamh, LOG_ERR, "Unable to open [%s]: %m", file_name); ++ memset(text, 0, text_length); ++ free(text); ++ return PAM_AUTH_ERR; ++ } ++ ++ if (fchown(fd, owner, group) == -1) { ++ pam_syslog(pamh, LOG_ERR, "Unable to change ownership [%s]: %m", file_name); ++ memset(text, 0, text_length); ++ free(text); ++ close(fd); ++ return PAM_AUTH_ERR; ++ } ++ ++ bytes_written = pam_modutil_write(fd, text, text_length); ++ close(fd); ++ ++ if (bytes_written < text_length) { ++ pam_syslog(pamh, LOG_ERR, "Short write on %s", file_name); ++ free(text); ++ return PAM_AUTH_ERR; ++ } ++ ++ return PAM_SUCCESS; ++} ++ ++static int ++key_management(pam_handle_t *pamh, const char *file_name, char **text, ++ size_t text_length, uid_t owner, gid_t group) ++{ ++ int fd = 0; ++ ++ fd = open(file_name, O_RDONLY | O_NOFOLLOW); ++ if (fd == -1) { ++ if (errno == ENOENT) { ++ if (generate_key(pamh, text, text_length)) { ++ pam_syslog(pamh, LOG_ERR, "Unable to generate key"); ++ return PAM_AUTH_ERR; ++ } ++ ++ if (write_file(pamh, file_name, *text, text_length, owner, group)) { ++ pam_syslog(pamh, LOG_ERR, "Unable to write key"); ++ return PAM_AUTH_ERR; ++ } ++ } else { ++ pam_syslog(pamh, LOG_ERR, "Unable to open %s: %m", file_name); ++ return PAM_AUTH_ERR; ++ } ++ } else { ++ if (read_file(pamh, fd, text, &text_length)) { ++ pam_syslog(pamh, LOG_ERR, "Error reading key file %s\n", file_name); ++ return PAM_AUTH_ERR; ++ } ++ } ++ ++ return PAM_SUCCESS; ++} ++ ++static int ++hmac_management(pam_handle_t *pamh, int debug, void **out, size_t *out_length, ++ char *key, size_t key_length, ++ const void *text, size_t text_length) ++{ ++ int ret = PAM_AUTH_ERR; ++ EVP_MAC *evp_mac = NULL; ++ EVP_MAC_CTX *ctx = NULL; ++ unsigned char *hmac_message = NULL; ++ size_t hmac_length; ++ char *algo = NULL; ++ OSSL_PARAM subalg_param[] = { OSSL_PARAM_END, OSSL_PARAM_END }; ++ ++ algo = get_crypto_algorithm(pamh, debug); ++ ++ subalg_param[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, ++ algo, ++ 0); ++ ++ evp_mac = EVP_MAC_fetch(NULL, "HMAC", NULL); ++ if (evp_mac == NULL) { ++ pam_syslog(pamh, LOG_ERR, "Unable to create hmac implementation"); ++ goto done; ++ } ++ ++ ctx = EVP_MAC_CTX_new(evp_mac); ++ if (ctx == NULL) { ++ pam_syslog(pamh, LOG_ERR, "Unable to create hmac context"); ++ goto done; ++ } ++ ++ ret = EVP_MAC_init(ctx, (const unsigned char *)key, key_length, subalg_param); ++ if (ret == 0) { ++ pam_syslog(pamh, LOG_ERR, "Unable to initialize hmac context"); ++ goto done; ++ } ++ ++ ret = EVP_MAC_update(ctx, (const unsigned char *)text, text_length); ++ if (ret == 0) { ++ pam_syslog(pamh, LOG_ERR, "Unable to update hmac context"); ++ goto done; ++ } ++ ++ hmac_message = (unsigned char*)malloc(sizeof(unsigned char) * MAX_HMAC_LENGTH); ++ if (!hmac_message) { ++ pam_syslog(pamh, LOG_CRIT, "Not enough memory"); ++ goto done; ++ } ++ ++ ret = EVP_MAC_final(ctx, hmac_message, &hmac_length, MAX_HMAC_LENGTH); ++ if (ret == 0) { ++ pam_syslog(pamh, LOG_ERR, "Unable to calculate hmac message"); ++ goto done; ++ } ++ ++ *out_length = hmac_length; ++ *out = malloc(*out_length); ++ if (*out == NULL) { ++ pam_syslog(pamh, LOG_CRIT, "Not enough memory"); ++ goto done; ++ } ++ ++ memcpy(*out, hmac_message, *out_length); ++ ret = PAM_SUCCESS; ++ ++done: ++ if (hmac_message != NULL) { ++ free(hmac_message); ++ } ++ if (key != NULL) { ++ memset(key, 0, key_length); ++ free(key); ++ } ++ if (ctx != NULL) { ++ EVP_MAC_CTX_free(ctx); ++ } ++ if (evp_mac != NULL) { ++ EVP_MAC_free(evp_mac); ++ } ++ free(algo); ++ ++ return ret; ++} ++ ++int ++hmac_size(pam_handle_t *pamh, int debug, size_t *hmac_length) ++{ ++ int ret = PAM_AUTH_ERR; ++ EVP_MAC *evp_mac = NULL; ++ EVP_MAC_CTX *ctx = NULL; ++ const unsigned char key[] = "ThisIsJustAKey"; ++ size_t key_length = MAX_KEY_LENGTH; ++ char *algo = NULL; ++ OSSL_PARAM subalg_param[] = { OSSL_PARAM_END, OSSL_PARAM_END }; ++ ++ algo = get_crypto_algorithm(pamh, debug); ++ ++ subalg_param[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, ++ algo, ++ 0); ++ ++ evp_mac = EVP_MAC_fetch(NULL, "HMAC", NULL); ++ if (evp_mac == NULL) { ++ pam_syslog(pamh, LOG_ERR, "Unable to create hmac implementation"); ++ goto done; ++ } ++ ++ ctx = EVP_MAC_CTX_new(evp_mac); ++ if (ctx == NULL) { ++ pam_syslog(pamh, LOG_ERR, "Unable to create hmac context"); ++ goto done; ++ } ++ ++ ret = EVP_MAC_init(ctx, key, key_length, subalg_param); ++ if (ret == 0) { ++ pam_syslog(pamh, LOG_ERR, "Unable to initialize hmac context"); ++ goto done; ++ } ++ ++ *hmac_length = EVP_MAC_CTX_get_mac_size(ctx); ++ ret = PAM_SUCCESS; ++ ++done: ++ if (ctx != NULL) { ++ EVP_MAC_CTX_free(ctx); ++ } ++ if (evp_mac != NULL) { ++ EVP_MAC_free(evp_mac); ++ } ++ free(algo); ++ ++ return ret; ++} ++ ++int ++hmac_generate(pam_handle_t *pamh, int debug, void **mac, size_t *mac_length, ++ const char *key_file, uid_t owner, gid_t group, ++ const void *text, size_t text_length) ++{ ++ char *key = NULL; ++ size_t key_length = MAX_KEY_LENGTH; ++ ++ if (key_management(pamh, key_file, &key, key_length, owner, group)) { ++ return PAM_AUTH_ERR; ++ } ++ ++ if (hmac_management(pamh, debug, mac, mac_length, key, key_length, ++ text, text_length)) { ++ return PAM_AUTH_ERR; ++ } ++ ++ return PAM_SUCCESS; ++} ++ ++#endif /* WITH_OPENSSL */ +diff --git a/modules/pam_timestamp/hmac_openssl_wrapper.h b/modules/pam_timestamp/hmac_openssl_wrapper.h +new file mode 100644 +index 00000000..cc27c811 +--- /dev/null ++++ b/modules/pam_timestamp/hmac_openssl_wrapper.h +@@ -0,0 +1,57 @@ ++/* Wrapper for hmac openssl implementation. ++ * ++ * Copyright (c) 2021 Red Hat, Inc. ++ * Written by 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. ++ * ++ */ ++#ifndef PAM_TIMESTAMP_HMAC_OPENSSL_WRAPPER_H ++#define PAM_TIMESTAMP_HMAC_OPENSSL_WRAPPER_H ++ ++#include "config.h" ++ ++#ifdef WITH_OPENSSL ++ ++#include ++#include ++ ++int ++hmac_size(pam_handle_t *pamh, int debug, size_t *hmac_length); ++ ++int ++hmac_generate(pam_handle_t *pamh, int debug, void **mac, size_t *mac_length, ++ const char *key_file, uid_t owner, gid_t group, ++ const void *text, size_t text_length); ++ ++#endif /* WITH_OPENSSL */ ++#endif /* PAM_TIMESTAMP_HMAC_OPENSSL_WRAPPER_H */ +diff --git a/modules/pam_timestamp/pam_timestamp.8.xml b/modules/pam_timestamp/pam_timestamp.8.xml +index e19a0bcf..83e5aea8 100644 +--- a/modules/pam_timestamp/pam_timestamp.8.xml ++++ b/modules/pam_timestamp/pam_timestamp.8.xml +@@ -50,6 +50,11 @@ for the user. When an application attempts to authenticate the user, a + pam_timestamp will treat a sufficiently recent timestamp + file as grounds for succeeding. + ++ ++ The default encryption hash is taken from the ++ HMAC_CRYPTO_ALGO variable from ++ /etc/login.defs. ++ + + + +diff --git a/modules/pam_timestamp/pam_timestamp.c b/modules/pam_timestamp/pam_timestamp.c +index 30be883c..01dd1385 100644 +--- a/modules/pam_timestamp/pam_timestamp.c ++++ b/modules/pam_timestamp/pam_timestamp.c +@@ -56,7 +56,11 @@ + #include + #include + #include ++#ifdef WITH_OPENSSL ++#include "hmac_openssl_wrapper.h" ++#else + #include "hmacsha1.h" ++#endif /* WITH_OPENSSL */ + + #include + #include +@@ -79,6 +83,9 @@ + #define BUFLEN PATH_MAX + #endif + ++#define ROOT_USER 0 ++#define ROOT_GROUP 0 ++ + /* Return PAM_SUCCESS if the given directory looks "safe". */ + static int + check_dir_perms(pam_handle_t *pamh, const char *tdir) +@@ -449,6 +456,13 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) + return PAM_AUTH_ERR; + } + ++#ifdef WITH_OPENSSL ++ if (hmac_size(pamh, debug, &maclen)) { ++ return PAM_AUTH_ERR; ++ } ++#else ++ maclen = hmac_sha1_size(); ++#endif /* WITH_OPENSSL */ + /* Check that the file is the expected size. */ + if (st.st_size == 0) { + /* Invalid, but may have been created by sudo. */ +@@ -456,7 +470,7 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) + return PAM_AUTH_ERR; + } + if (st.st_size != +- (off_t)(strlen(path) + 1 + sizeof(then) + hmac_sha1_size())) { ++ (off_t)(strlen(path) + 1 + sizeof(then) + maclen)) { + pam_syslog(pamh, LOG_NOTICE, "timestamp file `%s' " + "appears to be corrupted", path); + close(fd); +@@ -487,8 +501,17 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) + message_end = message + strlen(path) + 1 + sizeof(then); + + /* Regenerate the MAC. */ +- hmac_sha1_generate_file(pamh, &mac, &maclen, TIMESTAMPKEY, 0, 0, +- message, message_end - message); ++#ifdef WITH_OPENSSL ++ if (hmac_generate(pamh, debug, &mac, &maclen, TIMESTAMPKEY, ++ ROOT_USER, ROOT_GROUP, message, message_end - message)) { ++ close(fd); ++ free(message); ++ return PAM_AUTH_ERR; ++ } ++#else ++ hmac_sha1_generate_file(pamh, &mac, &maclen, TIMESTAMPKEY, ++ ROOT_USER, ROOT_GROUP, message, message_end - message); ++#endif /* WITH_OPENSSL */ + if ((mac == NULL) || + (memcmp(path, message, strlen(path)) != 0) || + (memcmp(mac, message_end, maclen) != 0)) { +@@ -605,8 +628,16 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, int argc, const char * + } + } + ++#ifdef WITH_OPENSSL ++ if (hmac_size(pamh, debug, &maclen)) { ++ return PAM_SESSION_ERR; ++ } ++#else ++ maclen = hmac_sha1_size(); ++#endif /* WITH_OPENSSL */ ++ + /* Generate the message. */ +- text = malloc(strlen(path) + 1 + sizeof(now) + hmac_sha1_size()); ++ text = malloc(strlen(path) + 1 + sizeof(now) + maclen); + if (text == NULL) { + pam_syslog(pamh, LOG_CRIT, "unable to allocate memory: %m"); + return PAM_SESSION_ERR; +@@ -621,15 +652,21 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, int argc, const char * + p += sizeof(now); + + /* Generate the MAC and append it to the plaintext. */ +- hmac_sha1_generate_file(pamh, &mac, &maclen, +- TIMESTAMPKEY, +- 0, 0, +- text, p - text); ++#ifdef WITH_OPENSSL ++ if (hmac_generate(pamh, debug, &mac, &maclen, TIMESTAMPKEY, ++ ROOT_USER, ROOT_GROUP, text, p - text)) { ++ free(text); ++ return PAM_SESSION_ERR; ++ } ++#else ++ hmac_sha1_generate_file(pamh, &mac, &maclen, TIMESTAMPKEY, ++ ROOT_USER, ROOT_GROUP, text, p - text); + if (mac == NULL) { + pam_syslog(pamh, LOG_ERR, "failure generating MAC: %m"); + free(text); + return PAM_SESSION_ERR; + } ++#endif /* WITH_OPENSSL */ + memmove(p, mac, maclen); + p += maclen; + free(mac); +-- +2.31.1 + diff --git a/pam-redhat-1.1.4.tar.bz2 b/pam-redhat-1.1.4.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..bdf1467539050a13e4bbb724bdaa87621a789c3e Binary files /dev/null and b/pam-redhat-1.1.4.tar.bz2 differ diff --git a/pam.spec b/pam.spec index ee87fa428758ccd20c72939d413d38c4cf60b259..db4be173935683910c4840d59c889281b93b7f1a 100644 --- a/pam.spec +++ b/pam.spec @@ -2,7 +2,7 @@ Summary: An extensible library which provides authentication for applications Name: pam -Version: 1.3.1 +Version: 1.5.1.1 Release: 36%{?dist} # The library is BSD licensed with option to relicense as GPLv2+ # - this option is redundant as the BSD license allows that anyway. @@ -123,6 +123,15 @@ Patch73: pam-1.3.1-pam-access-local.patch Patch74: pam-1.3.1-libpam-support-long-lines.patch # https://github.com/linux-pam/linux-pam/commit/940747f88c16e029b69a74e80a2e94f65cb3e628 Patch75: pam-1.3.1-pam-access-resolve-ip.patch +Patch76: pam-1.5.1-pam-pwhistory-load-conf-from-file.patch +Patch77: pam-1.5.0-noflex.patch +Patch78: pam-1.5.0-redhat-modules.patch +Patch79: pam-1.5.1-faillock-load-conf-from-file.patch +Patch80: pam-1.5.1-pam-usertype-SYS_UID_MAX.patch +Patch81: pam-1.5.1-pam_filter_close_file_after_controlling_tty.patch +Patch82: pam-1.5.1-timestamp-openssl-hmac-authentication.patch +Patch83: pam-1.5.1-pam-keyinit-thread-safe.patch +Patch84: pam-1.5.1-pam-limits-unlimited-value.patch %define _pamlibdir %{_libdir} %define _moduledir %{_libdir}/security @@ -499,6 +508,12 @@ done %doc doc/specs/rfc86.0.txt %changelog +* Wed May 28 2025 RELAI - 1.5.1-37 +- Apply patch to fix inconsistent system user UID handling and simplify logic for better accuracy. +- Apply patch to fix a file descriptor leak in pam_filter and ensure proper resource management. +- Apply patch to address thread-safety issues, ensuring reliable UID/GID switching and preventing race conditions in multi-threaded environments. +- Apply patch to correct invalid 'unlimited' value for RLIMIT_NOFILE, ensuring proper system limits and avoiding potential errors. + * Mon Nov 25 2024 Iker Pedrosa - 1.3.1-36 - pam_access: rework resolving of tokens as hostname. Resolves: CVE-2024-10963 and RHEL-66242 @@ -2350,4 +2365,4 @@ support) * Fri Dec 18 1998 Cristian Gafton - upgrade to ver 0.65 -- build the package out of internal CVS server +- build the package out of internal CVS server \ No newline at end of file diff --git a/pamtmp.conf b/pamtmp.conf index e4cfe2a10a599fc7a9f01efd2565ad4e56baf334..ab2237f19a76b5f26506fbfa88885681cd811433 100644 --- a/pamtmp.conf +++ b/pamtmp.conf @@ -2,3 +2,4 @@ d /run/console 0755 root root - d /run/faillock 0755 root root - d /run/sepermit 0755 root root - d /run/motd.d 0755 root root - +f /var/log/tallylog 0600 root root - diff --git a/smartcard-auth.pamd b/smartcard-auth.pamd index e8a67455059d3378a53031cfd6d30b1ad9d4df6c..95727701d445c3798243d2359de17b45656a2784 100644 --- a/smartcard-auth.pamd +++ b/smartcard-auth.pamd @@ -1,4 +1,19 @@ #%PAM-1.0 # This file is auto-generated. # User changes will be destroyed the next time authselect is run. -auth sufficient pam_sss.so allow_missing_name +auth required pam_env.so +auth [success=done ignore=ignore default=die] pam_pkcs11.so wait_for_card +auth required pam_deny.so + +account required pam_unix.so +account sufficient pam_localuser.so +account sufficient pam_succeed_if.so uid < 500 quiet +account required pam_permit.so + +password optional pam_pkcs11.so + +session optional pam_keyinit.so revoke +session required pam_limits.so +-session optional pam_systemd.so +session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid +session required pam_unix.so