[packages/pam] up to 1.7.2

arekm arekm at pld-linux.org
Tue Aug 18 13:44:03 CEST 2026


commit d5c25bb063e52293654b592956f25ad91186e7f3
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date:   Tue Aug 18 13:22:52 2026 +0200

    up to 1.7.2
    
    Upstream switched to meson.
    Backport CVE-2026-54411 fix (pam_userdb timing leak).

 pam-memset_explicit-args.patch          |  11 --
 pam-mkhomedir-notfound.patch            |  43 +++---
 pam-pld-modules.patch                   | 263 +++++++++++++++++++++++++++++---
 pam.spec                                | 138 +++++++----------
 pam_access-rework-hostname-tokens.patch | 223 ---------------------------
 pam_pwgen-pam_i18n.patch                |  11 ++
 pam_userdb-consttime-compare.patch      | 157 +++++++++++++++++++
 7 files changed, 480 insertions(+), 366 deletions(-)
---
diff --git a/pam.spec b/pam.spec
index bfb2817..31d9b7f 100644
--- a/pam.spec
+++ b/pam.spec
@@ -6,10 +6,8 @@
 # Conditional build:
 %bcond_without	doc		# documentation
 %bcond_with	econf		# libeconf handled configuration
-%bcond_with	prelude		# Prelude IDS support (in libpam)
 %bcond_without	selinux		# SELinux support
 %bcond_without	audit		# Linux Auditing library support
-%bcond_without	static_libs	# static libraries
 %bcond_without	systemd		# logind support
 
 %define		pam_pld_version	1.1.2-1
@@ -23,8 +21,8 @@ Summary(ru.UTF-8):	Интструмент, обеспечивающий ауте
 Summary(tr.UTF-8):	Modüler, artımsal doğrulama birimleri
 Summary(uk.UTF-8):	Інструмент, що забезпечує аутентифікацію для програм
 Name:		pam
-Version:	1.6.0
-Release:	2
+Version:	1.7.2
+Release:	1
 Epoch:		1
 # The library is BSD licensed with option to relicense as GPLv2+
 # - this option is redundant as the BSD license allows that anyway.
@@ -32,7 +30,7 @@ Epoch:		1
 License:	BSD and GPL v2+
 Group:		Base
 Source0:	https://github.com/linux-pam/linux-pam/releases/download/v%{version}/Linux-PAM-%{version}.tar.xz
-# Source0-md5:	41a10af5fc35a7be472ae9864338e64a
+# Source0-md5:	934c26eca3fada956356a30489e86291
 Source2:	ftp://ftp.pld-linux.org/software/pam/%{name}-pld-%{pam_pld_version}.tar.gz
 # Source2-md5:	f9ec6fcafcf1801bf318e60040244f2e
 Source3:	other.pamd
@@ -48,13 +46,12 @@ Patch1:		%{name}_console-lex-static.patch
 Patch3:		%{name}-mkhomedir-notfound.patch
 Patch5:		%{name}-exec-failok.patch
 Patch6:		pam_console_pam_tty.patch
-Patch7:		pam_access-rework-hostname-tokens.patch
-Patch8:		pam-memset_explicit-args.patch
 Patch9:		pam_pwgen-const-argv.patch
+Patch10:	pam_pwgen-pam_i18n.patch
+# CVE-2026-54411, fixed upstream after 1.7.2
+Patch11:	pam_userdb-consttime-compare.patch
 URL:		http://www.linux-pam.org/
 %{?with_audit:BuildRequires:	audit-libs-devel >= 1.6.9}
-BuildRequires:	autoconf >= 2.61
-BuildRequires:	automake
 BuildRequires:	bison
 BuildRequires:	flex
 # gdbm due to db pulling libpthread
@@ -63,14 +60,14 @@ BuildRequires:	gettext-tools >= 0.18.3
 BuildRequires:	glibc-devel >= 6:2.10.1
 %{?with_econf:BuildRequires:	libeconf-devel >= 0.5.0}
 BuildRequires:	libnsl-devel
-%{?with_prelude:BuildRequires:	libprelude-devel >= 0.9.0}
 %{?with_selinux:BuildRequires:	libselinux-devel >= 2.1.9}
 BuildRequires:	libtirpc-devel
-BuildRequires:	libtool >= 2:2
 BuildRequires:	libxcrypt-devel
 %{?with_audit:BuildRequires:	linux-libc-headers >= 7:2.6.23.1}
+BuildRequires:	meson >= 0.62.0
+BuildRequires:	ninja >= 1.5
 BuildRequires:	pkgconfig
-BuildRequires:	rpmbuild(macros) >= 1.527
+BuildRequires:	rpmbuild(macros) >= 2.042
 %{?with_systemd:BuildRequires:	systemd-devel >= 1:254}
 BuildRequires:	tar >= 1:1.22
 BuildRequires:	xz
@@ -199,6 +196,7 @@ Group:		Development/Libraries
 Requires:	%{name}-libs = %{epoch}:%{version}-%{release}
 %{?with_audit:Requires:	audit-libs-devel >= 1.0.8}
 Requires:	filesystem >= 3.0-11
+Obsoletes:	%{name}-static < %{epoch}:1.7.2
 
 %description devel
 Header files for developing PAM based applications.
@@ -215,26 +213,6 @@ Bibliotecas e arquivos de inclusão para desenvolvimento com PAM
 %description devel -l uk.UTF-8
 Цей пакет містить хедери та бібліотеки програміста для PAM.
 
-%package static
-Summary:	PAM static libraries
-Summary(pl.UTF-8):	Biblioteki statyczne PAM
-Summary(ru.UTF-8):	Статические библиотеки разработчика для PAM
-Summary(uk.UTF-8):	Статичні бібліотеки програміста для PAM
-Group:		Development/Libraries
-Requires:	%{name}-devel = %{epoch}:%{version}-%{release}
-
-%description static
-PAM static libraries.
-
-%description static -l pl.UTF-8
-Biblioteki statyczne PAM.
-
-%description static -l ru.UTF-8
-Этот пакет содержит статические библиотеки разработчика для PAM.
-
-%description static -l uk.UTF-8
-Цей пакет містить статичні бібліотеки програміста для PAM.
-
 %package pam_selinux
 Summary:	PAM module - SELinux support
 Summary(pl.UTF-8):	Moduł PAM pozwalający na zmianę kontekstów SELinuksa
@@ -269,60 +247,57 @@ danych GDBM.
 %patch -P3 -p1
 %patch -P5 -p1
 %patch -P6 -p1
-%patch -P7 -p1
-%patch -P8 -p1
 %patch -P9 -p1
+%patch -P10 -p1
+%patch -P11 -p1
 
 %build
-%{__libtoolize}
-%{__aclocal} -I m4
-%{__autoconf}
-%{__autoheader}
-%{__automake}
-%configure \
-	ac_cv_path_FO2PDF= \
-	%{__enable_disable static_libs static} \
-	--enable-shared \
+# -Dvendordir= : 1.7.2 turned vendordir on by default, which would move the
+# shipped configs out of /etc/security into /usr/share/pam/security
+%meson \
 	--libdir=/%{_lib} \
-	--includedir=%{_includedir}/security \
-	%{!?with_audit:--disable-audit} \
-	--enable-db=gdbm \
-	%{!?with_econf:--disable-econf} \
-	%{!?with_doc:--disable-regenerate-docu} \
-	--enable-isadir=../../%{_lib}/security \
-	--enable-lastlog \
-	%{__enable_disable systemd logind} \
-	%{!?with_prelude:--disable-prelude} \
-	%{!?with_selinux:--disable-selinux} \
-	--with-systemdunitdir="%{systemdunitdir}"
-
-# we must explicitely update-gmo as we patch a po file
-%{__make} -C po update-gmo
-%{__make} \
-	DEFS="-DHAVE_CONFIG_H -D_GNU_SOURCE"
+	-Daudit=%{__enabled_disabled audit} \
+	-Ddb=gdbm \
+	-Ddocs=%{__enabled_disabled doc} \
+	-Deconf=%{__enabled_disabled econf} \
+	-Delogind=disabled \
+	-Disadir=../../%{_lib}/security \
+	-Dlogind=%{__enabled_disabled systemd} \
+	-Dpam_lastlog=enabled \
+	-Dpwaccess=disabled \
+	-Dselinux=%{__enabled_disabled selinux} \
+	-Dsystemdunitdir=%{systemdunitdir} \
+	-Dvendordir=
+
+%meson_build
 
 %install
 rm -rf $RPM_BUILD_ROOT
 install -d $RPM_BUILD_ROOT{%{_libdir},/etc/pam.d,/usr/lib/pam.d,/var/{log,run/sepermit}} \
 	$RPM_BUILD_ROOT%{systemdtmpfilesdir}
 
-%{__make} install \
-	DESTDIR=$RPM_BUILD_ROOT \
-	pkgconfigdir=%{_pkgconfigdir}
+%meson_install
+
+# meson installs these next to the libraries
+install -d $RPM_BUILD_ROOT%{_pkgconfigdir}
+%{__mv} $RPM_BUILD_ROOT/%{_lib}/pkgconfig/*.pc $RPM_BUILD_ROOT%{_pkgconfigdir}
+rmdir $RPM_BUILD_ROOT/%{_lib}/pkgconfig
 
 %if %{with selinux}
-install -p modules/pam_selinux/.libs/pam_selinux_check $RPM_BUILD_ROOT%{_sbindir}
-cp -p modules/pam_selinux/pam_selinux_check.8 $RPM_BUILD_ROOT%{_mandir}/man8
+install -p %{_vpath_builddir}/modules/pam_selinux/pam_selinux_check $RPM_BUILD_ROOT%{_sbindir}
 cp -p %{SOURCE6} $RPM_BUILD_ROOT/etc/pam.d/pam_selinux_check
 %endif
 
 cp -p %{SOURCE9} $RPM_BUILD_ROOT%{systemdtmpfilesdir}/%{name}.conf
 
-install -d doc/txts
+%if %{with doc}
+install -d doc/txts doc/txts-userdb
+cp -p $RPM_BUILD_ROOT%{_docdir}/Linux-PAM/modules/*.txt doc/txts
 for r in modules/pam_*/README; do
-	cp -pf $r doc/txts/README.$(basename $(dirname $r))
+	cp -pf $r doc/txts/$(basename $(dirname $r)).txt
 done
-%{__rm} doc/txts/README.pam_userdb
+%{__mv} doc/txts/pam_userdb.txt doc/txts-userdb
+%endif
 install -d doc/html
 cp -pf doc/index.html doc/html/
 
@@ -332,9 +307,6 @@ echo ".so PAM.8" > $RPM_BUILD_ROOT%{_mandir}/man8/pam.8
 :> $RPM_BUILD_ROOT/etc/security/opasswd
 :> $RPM_BUILD_ROOT/etc/security/blacklist
 
-%{?with_static_libs:%{__mv} $RPM_BUILD_ROOT/%{_lib}/lib*.a $RPM_BUILD_ROOT%{_libdir}}
-%{__rm} $RPM_BUILD_ROOT/%{_lib}/lib*.la
-
 cd $RPM_BUILD_ROOT/%{_lib}
 ln -sf /%{_lib}/$(echo libpam.so.*.*.*) $RPM_BUILD_ROOT%{_libdir}/libpam.so
 ln -sf /%{_lib}/$(echo libpam_misc.so.*.*.*) $RPM_BUILD_ROOT%{_libdir}/libpam_misc.so
@@ -377,8 +349,6 @@ for module in $RPM_BUILD_ROOT/%{_lib}/security/pam*.so ; do
 done
 
 # useless - shut up check-files
-%{__rm} $RPM_BUILD_ROOT/%{_lib}/security/*.la
-%{?with_static_libs:%{__rm} $RPM_BUILD_ROOT/%{_lib}/security/*.a}
 %{__rm} $RPM_BUILD_ROOT/%{_lib}/lib*.so
 %{__rm} -r $RPM_BUILD_ROOT%{_docdir}/Linux-PAM
 
@@ -386,9 +356,9 @@ done
 rm -rf rpm-doc
 install -d rpm-doc
 cp -a doc/html rpm-doc/html
-cp -a doc/sag/html rpm-doc/sag-html
-cp -a doc/adg/html rpm-doc/adg-html
-cp -a doc/mwg/html rpm-doc/mwg-html
+cp -a %{_vpath_builddir}/doc/sag/html rpm-doc/sag-html
+cp -a %{_vpath_builddir}/doc/adg/html rpm-doc/adg-html
+cp -a %{_vpath_builddir}/doc/mwg/html rpm-doc/mwg-html
 %endif
 
 %if %{without selinux}
@@ -457,9 +427,11 @@ fi
 
 %files -f Linux-PAM.lang
 %defattr(644,root,root,755)
-%doc AUTHORS CHANGELOG ChangeLog Copyright NEWS doc/txts/README*
+%doc AUTHORS Copyright NEWS
 %if %{with doc}
-%doc doc/specs/*.txt doc/sag/Linux-PAM_*.txt rpm-doc/{html,sag-html}
+%doc doc/txts/*.txt
+%doc doc/specs/*.txt %{_vpath_builddir}/doc/specs/*.txt
+%doc %{_vpath_builddir}/doc/sag/Linux-PAM_*.txt rpm-doc/{html,sag-html}
 %endif
 %dir /etc/pam.d
 %dir /etc/security/console.apps
@@ -600,7 +572,7 @@ fi
 %files devel
 %defattr(644,root,root,755)
 %if %{with doc}
-%doc doc/{adg,mwg}/Linux-PAM_*.txt rpm-doc/{adg,mwg}-html
+%doc %{_vpath_builddir}/doc/{adg,mwg}/Linux-PAM_*.txt rpm-doc/{adg,mwg}-html
 %endif
 %attr(755,root,root) %{_libdir}/libpam.so
 %attr(755,root,root) %{_libdir}/libpam_misc.so
@@ -613,14 +585,6 @@ fi
 %{_mandir}/man3/misc_conv.3*
 %{_mandir}/man3/pam*.3*
 
-%if %{with static_libs}
-%files static
-%defattr(644,root,root,755)
-%{_libdir}/libpam.a
-%{_libdir}/libpamc.a
-%{_libdir}/libpam_misc.a
-%endif
-
 %if %{with selinux}
 %files pam_selinux
 %defattr(644,root,root,755)
@@ -637,6 +601,6 @@ fi
 
 %files pam_userdb
 %defattr(644,root,root,755)
-%doc modules/pam_userdb/README
+%{?with_doc:%doc doc/txts-userdb/pam_userdb.txt}
 %attr(755,root,root) /%{_lib}/security/pam_userdb.so
 %{_mandir}/man8/pam_userdb.8*
diff --git a/pam-memset_explicit-args.patch b/pam-memset_explicit-args.patch
deleted file mode 100644
index a084339..0000000
--- a/pam-memset_explicit-args.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- Linux-PAM-1.6.0.orig/libpam/include/pam_inline.h
-+++ Linux-PAM-1.6.0/libpam/include/pam_inline.h
-@@ -82,7 +82,7 @@ pam_str_skip_icase_prefix_len(const char
- static inline void pam_overwrite_n(void *ptr, size_t len)
- {
- 	if (ptr)
--		memset_explicit(ptr, len);
-+		memset_explicit(ptr, 0, len);
- }
- #elif defined HAVE_EXPLICIT_BZERO
- static inline void pam_overwrite_n(void *ptr, size_t len)
diff --git a/pam-mkhomedir-notfound.patch b/pam-mkhomedir-notfound.patch
index c60fc49..0c97a80 100644
--- a/pam-mkhomedir-notfound.patch
+++ b/pam-mkhomedir-notfound.patch
@@ -1,6 +1,6 @@
-diff -urN Linux-PAM-0.99.7.1.orig/modules/pam_mkhomedir/pam_mkhomedir.8.xml Linux-PAM-0.99.7.1/modules/pam_mkhomedir/pam_mkhomedir.8.xml
---- Linux-PAM-0.99.7.1.orig/modules/pam_mkhomedir/pam_mkhomedir.8.xml	2006-05-30 15:03:09.000000000 +0200
-+++ Linux-PAM-0.99.7.1/modules/pam_mkhomedir/pam_mkhomedir.8.xml	2007-02-03 22:09:37.942620000 +0100
+diff -urN Linux-PAM-1.7.2.orig/modules/pam_mkhomedir/pam_mkhomedir.8.xml Linux-PAM-1.7.2/modules/pam_mkhomedir/pam_mkhomedir.8.xml
+--- Linux-PAM-1.7.2.orig/modules/pam_mkhomedir/pam_mkhomedir.8.xml	2026-01-22 09:00:00.000000000 +0100
++++ Linux-PAM-1.7.2/modules/pam_mkhomedir/pam_mkhomedir.8.xml	2026-08-18 12:12:05.673038517 +0200
 @@ -29,6 +29,9 @@
          umask=<replaceable>mode</replaceable>
        </arg>
@@ -11,10 +11,13 @@ diff -urN Linux-PAM-0.99.7.1.orig/modules/pam_mkhomedir/pam_mkhomedir.8.xml Linu
          skel=<replaceable>skeldir</replaceable>
        </arg>
      </cmdsynopsis>
-@@ -82,6 +94,20 @@
- 
-       <varlistentry>
-         <term>
+@@ -106,6 +109,20 @@
+           </para>
+         </listitem>
+       </varlistentry>
++
++      <varlistentry>
++        <term>
 +          <option>notfound=[<replaceable>create</replaceable>|<replaceable>deny</replaceable>|<replaceable>ignore</replaceable>]</option>
 +        </term>
 +        <listitem>
@@ -26,16 +29,14 @@ diff -urN Linux-PAM-0.99.7.1.orig/modules/pam_mkhomedir/pam_mkhomedir.8.xml Linu
 +          </para>
 +        </listitem>
 +      </varlistentry>
-+
-+      <varlistentry>
-+        <term>
-           skel=/path/to/skel/directory
-         </term>
-         <listitem>
---- Linux-PAM-1.4.0/modules/pam_mkhomedir/pam_mkhomedir.c.orig	2020-06-08 12:17:27.000000000 +0200
-+++ Linux-PAM-1.4.0/modules/pam_mkhomedir/pam_mkhomedir.c	2020-08-25 19:45:06.233402760 +0200
-@@ -53,8 +53,11 @@
- #include "pam_inline.h"
+ 
+       <varlistentry>
+         <term>
+diff -urN Linux-PAM-1.7.2.orig/modules/pam_mkhomedir/pam_mkhomedir.c Linux-PAM-1.7.2/modules/pam_mkhomedir/pam_mkhomedir.c
+--- Linux-PAM-1.7.2.orig/modules/pam_mkhomedir/pam_mkhomedir.c	2026-01-22 09:00:00.000000000 +0100
++++ Linux-PAM-1.7.2/modules/pam_mkhomedir/pam_mkhomedir.c	2026-08-18 12:12:05.673356863 +0200
+@@ -54,8 +54,11 @@
+ #include "pam_i18n.h"
  
  /* argument parsing */
 -#define MKHOMEDIR_DEBUG      020	/* be verbose about things */
@@ -48,16 +49,16 @@ diff -urN Linux-PAM-0.99.7.1.orig/modules/pam_mkhomedir/pam_mkhomedir.8.xml Linu
  
  #define LOGIN_DEFS           "/etc/login.defs"
  #define UMASK_DEFAULT        "0022"
-@@ -67,7 +70,7 @@
+@@ -76,7 +79,7 @@
  _pam_parse (const pam_handle_t *pamh, int flags, int argc, const char **argv,
  	    options_t *opt)
  {
 -   opt->ctrl = 0;
 +   opt->ctrl = HOMEDIR_CREATE;
     opt->umask = NULL;
-    opt->skeldir = "/etc/skel";
+    opt->skeldir = NULL;
  
-@@ -88,6 +91,15 @@
+@@ -97,6 +100,15 @@
  	 opt->umask = str;
        } else if ((str = pam_str_skip_prefix(*argv, "skel=")) != NULL) {
  	 opt->skeldir = str;
@@ -73,7 +74,7 @@ diff -urN Linux-PAM-0.99.7.1.orig/modules/pam_mkhomedir/pam_mkhomedir.8.xml Linu
        } else {
  	 pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
        }
-@@ -221,7 +233,12 @@
+@@ -261,7 +273,12 @@
        return PAM_SUCCESS;
     }
  
diff --git a/pam-pld-modules.patch b/pam-pld-modules.patch
index 0049144..e6fc381 100644
--- a/pam-pld-modules.patch
+++ b/pam-pld-modules.patch
@@ -1,24 +1,239 @@
---- Linux-PAM-1.6.0/configure.ac.orig	2024-03-22 18:58:45.064426280 +0100
-+++ Linux-PAM-1.6.0/configure.ac	2024-03-22 18:59:27.857527783 +0100
-@@ -774,6 +774,8 @@ AC_CONFIG_FILES([Makefile libpam/Makefil
- 	po/Makefile.in \
- 	Make.xml.rules \
- 	modules/Makefile \
-+	modules/pam_console/Makefile modules/pam_pwexport/Makefile \
-+	modules/pam_pwgen/Makefile modules/pam_rps/Makefile \
- 	modules/pam_access/Makefile \
- 	modules/pam_canonicalize_user/Makefile \
- 	modules/pam_debug/Makefile modules/pam_deny/Makefile \
---- Linux-PAM-1.4.0.org/modules/Makefile.am	2020-06-08 12:17:27.000000000 +0200
-+++ Linux-PAM-1.4.0/modules/Makefile.am	2021-03-21 13:19:44.089594925 +0100
-@@ -98,6 +98,10 @@ SUBDIRS := \
- 	pam_warn \
- 	pam_wheel \
- 	pam_xauth \
-+	pam_console \
-+	pam_pwexport \
-+	pam_pwgen \
-+	pam_rps \
- 	#
- 
- CLEANFILES = *~
+--- Linux-PAM-1.7.2.orig/modules/meson.build	2026-01-22 09:00:00.000000000 +0100
++++ Linux-PAM-1.7.2/modules/meson.build	2026-08-18 12:15:36.703326906 +0200
+@@ -43,3 +43,9 @@
+ subdir('pam_warn')
+ subdir('pam_wheel')
+ subdir('pam_xauth')
++
++# PLD-specific modules, shipped in pam-pld-*.tar.gz
++subdir('pam_console')
++subdir('pam_pwexport')
++subdir('pam_pwgen')
++subdir('pam_rps')
+--- Linux-PAM-1.7.2.orig/modules/maps/modules-auth-password.map	1970-01-01 01:00:00.000000000 +0100
++++ Linux-PAM-1.7.2/modules/maps/modules-auth-password.map	1970-01-01 01:00:00.000000000 +0100
+@@ -0,0 +1,7 @@
++{
++  global:
++    pam_sm_authenticate;
++    pam_sm_chauthtok;
++    pam_sm_setcred;
++  local: *;
++};
+--- Linux-PAM-1.7.2.orig/modules/pam_console/meson.build	1970-01-01 01:00:00.000000000 +0100
++++ Linux-PAM-1.7.2/modules/pam_console/meson.build	1970-01-01 01:00:00.000000000 +0100
+@@ -0,0 +1,87 @@
++# -*- mode: meson -*-
++# PLD-specific module, not part of upstream Linux-PAM.
++
++pam_console_lockdir = localstatedir / 'run' / 'console'
++pam_console_c_args = ['-DLOCKDIR="@0@"'.format(pam_console_lockdir)]
++
++pam_module_map_path = meson.current_source_dir() / '..' / 'maps' / 'modules-auth-session.map'
++
++shared_module(
++  'pam_console',
++  name_prefix: '',
++  sources: ['pam_console.c', 'regerr.c', 'handlers.c'],
++  c_args: pam_console_c_args,
++  dependencies: [libpam_internal_dep, libpam_dep],
++  link_depends: [pam_module_map_path],
++  link_args: ['-Wl,--version-script=' + pam_module_map_path],
++  install: true,
++  install_dir: securedir,
++)
++
++configfile_gen = custom_target(
++  'configfile-gen',
++  output: ['configfile.tab.c', 'configfile.tab.h', 'configfile.lex.c'],
++  command: [
++    find_program('sh'),
++    files('gen-configfile.sh'),
++    meson.current_source_dir(),
++    prog_yacc,
++    prog_flex,
++    '@OUTPUT0@',
++    '@OUTPUT2@',
++  ],
++)
++
++executable(
++  'pam_console_apply',
++  sources: [
++    'pam_console_apply.c',
++    'chmod.c',
++    'modechange.c',
++    'regerr.c',
++    'configfile.c',
++    'hashtable.c',
++    # configfile.c #includes the generated sources; naming the header here is
++    # what orders the generator before this target is compiled
++    configfile_gen[1],
++  ],
++  c_args: pam_console_c_args,
++  link_args: exe_link_args,
++  dependencies: [libpam_internal_dep, libpam_dep],
++  install: true,
++  install_dir: sbindir,
++)
++
++install_data(
++  ['console.apps.5', 'console.handlers.5', 'console.perms.5'],
++  install_dir: mandir / 'man5',
++  install_tag: 'man',
++)
++
++install_data(
++  ['pam_console.8', 'pam_console_apply.8'],
++  install_dir: mandir / 'man8',
++  install_tag: 'man',
++)
++
++install_data(
++  ['console.handlers', 'console.perms'],
++  install_dir: sconfigdir,
++  install_tag: 'config',
++)
++
++install_data(
++  '50-default.perms',
++  install_dir: sconfigdir / 'console.perms.d',
++  install_tag: 'config',
++)
++
++install_emptydir(
++  sconfigdir / 'console.apps',
++  install_tag: 'config',
++)
++
++install_emptydir(
++  pam_console_lockdir,
++  install_tag: 'config',
++)
+--- Linux-PAM-1.7.2.orig/modules/pam_pwexport/meson.build	1970-01-01 01:00:00.000000000 +0100
++++ Linux-PAM-1.7.2/modules/pam_pwexport/meson.build	1970-01-01 01:00:00.000000000 +0100
+@@ -0,0 +1,21 @@
++# -*- mode: meson -*-
++# PLD-specific module, not part of upstream Linux-PAM.
++
++pam_module_map_path = meson.current_source_dir() / '..' / 'maps' / 'modules-auth-password.map'
++
++shared_module(
++  'pam_pwexport',
++  name_prefix: '',
++  sources: ['pam_pwexport.c'],
++  dependencies: [libpam_internal_dep, libpam_dep],
++  link_depends: [pam_module_map_path],
++  link_args: ['-Wl,--version-script=' + pam_module_map_path],
++  install: true,
++  install_dir: securedir,
++)
++
++install_data(
++  'pam_pwexport.8',
++  install_dir: mandir / 'man8',
++  install_tag: 'man',
++)
+--- Linux-PAM-1.7.2.orig/modules/pam_pwgen/meson.build	1970-01-01 01:00:00.000000000 +0100
++++ Linux-PAM-1.7.2/modules/pam_pwgen/meson.build	1970-01-01 01:00:00.000000000 +0100
+@@ -0,0 +1,56 @@
++# -*- mode: meson -*-
++# PLD-specific module, not part of upstream Linux-PAM.
++
++pam_module_map_path = meson.current_source_dir() / '..' / 'maps' / 'modules-password.map'
++
++shared_module(
++  'pam_pwgen',
++  name_prefix: '',
++  sources: ['pam_pwgen.c'],
++  dependencies: [libpam_internal_dep, libpam_dep, libcrypt, libaudit],
++  link_depends: [pam_module_map_path],
++  link_args: ['-Wl,--version-script=' + pam_module_map_path],
++  install: true,
++  install_dir: securedir,
++)
++
++executable(
++  'pam_pwgen',
++  sources: ['pam_pwgen_app.c'],
++  link_args: exe_link_args,
++  dependencies: [libpam_internal_dep, libpam_dep, libaudit],
++  install: true,
++  install_dir: prefixdir / get_option('bindir'),
++)
++
++executable(
++  'pwgen_trigram',
++  sources: ['pwgen_trigram.c'],
++  link_args: exe_link_args,
++  dependencies: [libpam_internal_dep, libpam_dep, libaudit],
++  install: true,
++  install_dir: sbindir,
++)
++
++install_data(
++  [
++    'trigram.de',
++    'trigram.dk',
++    'trigram.en',
++    'trigram.es',
++    'trigram.fi',
++    'trigram.it',
++    'trigram.ja',
++    'trigram.no',
++    'trigram.pl',
++  ],
++  install_dir: sconfigdir,
++  install_tag: 'config',
++)
++
++install_symlink(
++  'trigram',
++  pointing_to: 'trigram.en',
++  install_dir: sconfigdir,
++  install_tag: 'config',
++)
+--- Linux-PAM-1.7.2.orig/modules/pam_rps/meson.build	1970-01-01 01:00:00.000000000 +0100
++++ Linux-PAM-1.7.2/modules/pam_rps/meson.build	1970-01-01 01:00:00.000000000 +0100
+@@ -0,0 +1,21 @@
++# -*- mode: meson -*-
++# PLD-specific module, not part of upstream Linux-PAM.
++
++pam_module_map_path = meson.current_source_dir() / '..' / 'maps' / 'modules-auth.map'
++
++shared_module(
++  'pam_rps',
++  name_prefix: '',
++  sources: ['pam_rps.c'],
++  dependencies: [libpam_internal_dep, libpam_dep],
++  link_depends: [pam_module_map_path],
++  link_args: ['-Wl,--version-script=' + pam_module_map_path],
++  install: true,
++  install_dir: securedir,
++)
++
++install_data(
++  'pam_rps.8',
++  install_dir: mandir / 'man8',
++  install_tag: 'man',
++)
+--- Linux-PAM-1.7.2.orig/modules/pam_console/gen-configfile.sh	1970-01-01 01:00:00.000000000 +0100
++++ Linux-PAM-1.7.2/modules/pam_console/gen-configfile.sh	1970-01-01 01:00:00.000000000 +0100
+@@ -0,0 +1,17 @@
++#!/bin/sh
++# configfile.c #includes the generated parser and lexer, so their internals
++# have to become static; sed-static does that rewriting.
++set -e
++
++srcdir=$1
++yacc=$2
++lex=$3
++tab_c=$4
++lex_c=$5
++
++# -d makes bison derive the header name from the -o argument
++"$yacc" -d -o "$tab_c" -p _pc_yy "$srcdir/configfile.y"
++sh "$srcdir/sed-static" "$tab_c"
++
++"$lex" -Cr -o"$lex_c" -P_pc_yy "$srcdir/configfile.l"
++sh "$srcdir/sed-static" "$lex_c"
diff --git a/pam_access-rework-hostname-tokens.patch b/pam_access-rework-hostname-tokens.patch
deleted file mode 100644
index f08cf0a..0000000
--- a/pam_access-rework-hostname-tokens.patch
+++ /dev/null
@@ -1,223 +0,0 @@
-From: Thorsten Kukuk <kukuk at suse.com>
-Date: Thu, 14 Nov 2024 10:27:28 +0100
-Subject: pam_access: rework resolving of tokens as hostname
-
-* modules/pam_access/pam_access.c: separate resolving of IP addresses
-  from hostnames. Don't resolve TTYs or display variables as hostname
-  (#834).
-  Add "nodns" option to disallow resolving of tokens as hostname.
-* modules/pam_access/pam_access.8.xml: document nodns option
-* modules/pam_access/access.conf.5.xml: document that hostnames should
-  be written as FQHN.
-
-(cherry picked from commit 940747f88c16e029b69a74e80a2e94f65cb3e628)
----
- modules/pam_access/access.conf.5.xml |  4 ++
- modules/pam_access/pam_access.8.xml  | 46 +++++++++++++++--------
- modules/pam_access/pam_access.c      | 72 +++++++++++++++++++++++++++++++++++-
- 3 files changed, 105 insertions(+), 17 deletions(-)
-
-diff --git a/modules/pam_access/access.conf.5.xml b/modules/pam_access/access.conf.5.xml
-index 65c6b69..67e5354 100644
---- a/modules/pam_access/access.conf.5.xml
-+++ b/modules/pam_access/access.conf.5.xml
-@@ -233,6 +233,10 @@
-       An IPv6 link local host address must contain the interface
-       identifier. IPv6 link local network/netmask is not supported.
-     </para>
-+    <para>
-+      Hostnames should be written as Fully-Qualified Host Name (FQHN) to avoid
-+      confusion with device names or PAM service names.
-+    </para>
-   </refsect1>
- 
-   <refsect1 xml:id="access.conf-see_also">
-diff --git a/modules/pam_access/pam_access.8.xml b/modules/pam_access/pam_access.8.xml
-index dcc5039..d907b80 100644
---- a/modules/pam_access/pam_access.8.xml
-+++ b/modules/pam_access/pam_access.8.xml
-@@ -22,11 +22,14 @@
-       <arg choice="opt" rep="norepeat">
-         debug
-       </arg>
-+      <arg choice="opt" rep="norepeat">
-+        noaudit
-+      </arg>
-       <arg choice="opt" rep="norepeat">
-         nodefgroup
-       </arg>
-       <arg choice="opt" rep="norepeat">
--        noaudit
-+        nodns
-       </arg>
-       <arg choice="opt" rep="norepeat">
-         quiet_log
-@@ -132,6 +135,33 @@
-         </listitem>
-       </varlistentry>
- 
-+      <varlistentry>
-+        <term>
-+          nodefgroup
-+        </term>
-+        <listitem>
-+          <para>
-+            User tokens which are not enclosed in parentheses will not be
-+	    matched against the group database. The backwards compatible default is
-+            to try the group database match even for tokens not enclosed
-+            in parentheses.
-+          </para>
-+        </listitem>
-+      </varlistentry>
-+
-+      <varlistentry>
-+        <term>
-+          nodns
-+        </term>
-+        <listitem>
-+          <para>
-+	    Do not try to resolve tokens as hostnames, only IPv4 and IPv6
-+	    addresses will be resolved. Which means to allow login from a
-+	    remote host, the IP addresses need to be specified in <filename>access.conf</filename>.
-+          </para>
-+        </listitem>
-+      </varlistentry>
-+
-       <varlistentry>
-         <term>
-           quiet_log
-@@ -185,20 +215,6 @@
-         </listitem>
-       </varlistentry>
- 
--      <varlistentry>
--        <term>
--          nodefgroup
--        </term>
--        <listitem>
--          <para>
--            User tokens which are not enclosed in parentheses will not be
--	    matched against the group database. The backwards compatible default is
--            to try the group database match even for tokens not enclosed
--            in parentheses.
--          </para>
--        </listitem>
--      </varlistentry>
--
-     </variablelist>
-   </refsect1>
- 
-diff --git a/modules/pam_access/pam_access.c b/modules/pam_access/pam_access.c
-index 11f6b92..15acbf9 100644
---- a/modules/pam_access/pam_access.c
-+++ b/modules/pam_access/pam_access.c
-@@ -100,6 +100,7 @@ struct login_info {
-     int only_new_group_syntax;		/* Only allow group entries of the form "(xyz)" */
-     int noaudit;			/* Do not audit denials */
-     int quiet_log;			/* Do not log denials */
-+    int nodns;                          /* Do not try to resolve tokens as hostnames */
-     const char *fs;			/* field separator */
-     const char *sep;			/* list-element separator */
-     int from_remote_host;               /* If PAM_RHOST was used for from */
-@@ -154,6 +155,8 @@ parse_args(pam_handle_t *pamh, struct login_info *loginfo,
- 	    loginfo->noaudit = YES;
- 	} else if (strcmp (argv[i], "quiet_log") == 0) {
- 	    loginfo->quiet_log = YES;
-+	} else if (strcmp (argv[i], "nodns") == 0) {
-+	    loginfo->nodns = YES;
- 	} else {
- 	    pam_syslog(pamh, LOG_ERR, "unrecognized option [%s]", argv[i]);
- 	}
-@@ -820,7 +823,7 @@ remote_match (pam_handle_t *pamh, char *tok, struct login_info *item)
-       if ((str_len = strlen(string)) > tok_len
- 	  && strcasecmp(tok, string + str_len - tok_len) == 0)
- 	return YES;
--    } else if (tok[tok_len - 1] == '.') {       /* internet network numbers (end with ".") */
-+    } else if (tok[tok_len - 1] == '.') {       /* internet network numbers/subnet (end with ".") */
-       struct addrinfo hint;
- 
-       memset (&hint, '\0', sizeof (hint));
-@@ -895,6 +898,39 @@ string_match (pam_handle_t *pamh, const char *tok, const char *string,
- }
- 
- 
-+static int
-+is_device (pam_handle_t *pamh, const char *tok)
-+{
-+  struct stat st;
-+  const char *dev = "/dev/";
-+  char *devname;
-+
-+  devname = malloc (strlen(dev) + strlen (tok) + 1);
-+  if (devname == NULL) {
-+      pam_syslog(pamh, LOG_ERR, "Cannot allocate memory for device name: %m");
-+      /*
-+       * We should return an error and abort, but pam_access has no good
-+       * error handling.
-+       */
-+      return NO;
-+  }
-+
-+  char *cp = stpcpy (devname, dev);
-+  strcpy (cp, tok);
-+
-+  if (lstat(devname, &st) != 0)
-+    {
-+      free (devname);
-+      return NO;
-+    }
-+  free (devname);
-+
-+  if (S_ISCHR(st.st_mode))
-+    return YES;
-+
-+  return NO;
-+}
-+
- /* network_netmask_match - match a string against one token
-  * where string is a hostname or ip (v4,v6) address and tok
-  * represents either a hostname, a single ip (v4,v6) address
-@@ -956,10 +992,42 @@ network_netmask_match (pam_handle_t *pamh,
- 	    return NO;
- 	  }
-       }
-+    else if (isipaddr(tok, NULL, NULL) == YES)
-+      {
-+	if (getaddrinfo (tok, NULL, NULL, &ai) != 0)
-+	  {
-+	    if (item->debug)
-+	      pam_syslog(pamh, LOG_DEBUG, "cannot resolve IP address \"%s\"", tok);
-+
-+	    return NO;
-+	  }
-+	netmask_ptr = NULL;
-+      }
-+    else if (item->nodns)
-+      {
-+	/* Only hostnames are left, which we would need to resolve via DNS */
-+	return NO;
-+      }
-     else
-       {
-+	/* Bail out on X11 Display entries and ttys. */
-+	if (tok[0] == ':')
-+	  {
-+	    if (item->debug)
-+	      pam_syslog (pamh, LOG_DEBUG,
-+			  "network_netmask_match: tok=%s is X11 display", tok);
-+	    return NO;
-+	  }
-+	if (is_device (pamh, tok))
-+	  {
-+	    if (item->debug)
-+	      pam_syslog (pamh, LOG_DEBUG,
-+			  "network_netmask_match: tok=%s is a TTY", tok);
-+	    return NO;
-+	  }
-+
-         /*
--	 * It is either an IP address or a hostname.
-+	 * It is most likely a hostname.
- 	 * Let getaddrinfo sort everything out
- 	 */
- 	if (getaddrinfo (tok, NULL, NULL, &ai) != 0)
diff --git a/pam_pwgen-pam_i18n.patch b/pam_pwgen-pam_i18n.patch
new file mode 100644
index 0000000..d8237dc
--- /dev/null
+++ b/pam_pwgen-pam_i18n.patch
@@ -0,0 +1,11 @@
+--- Linux-PAM-1.7.2.orig/modules/pam_pwgen/pam_pwgen.c	2007-02-05 15:50:40.000000000 +0100
++++ Linux-PAM-1.7.2/modules/pam_pwgen/pam_pwgen.c	2026-08-18 12:17:51.700819525 +0200
+@@ -63,6 +63,8 @@
+ #include <security/_pam_macros.h>
+ #include <security/pam_ext.h>
+ 
++#include "pam_i18n.h"
++
+ #ifndef LINUX_PAM
+ #include <security/pam_appl.h>
+ #endif				/* LINUX_PAM */
diff --git a/pam_userdb-consttime-compare.patch b/pam_userdb-consttime-compare.patch
new file mode 100644
index 0000000..5be97d9
--- /dev/null
+++ b/pam_userdb-consttime-compare.patch
@@ -0,0 +1,157 @@
+From 30708d973b63891bf700299ce3ae0f1086398284 Mon Sep 17 00:00:00 2001
+From: vlefebvre <valentin.lefebvre at suse.com>
+Date: Tue, 16 Jun 2026 16:31:29 +0200
+Subject: [PATCH] pam_userdb: fix password comparison timing leak
+
+* libpam/include/pam_inline.h: Include <ctype.h>.
+(pam_consttime_strcaseeq): New function that implements a constant-time,
+case-insensitive string equality check.
+* modules/pam_userdb/pam_userdb.c (user_lookup): Use it along with
+pam_consttime_streq instead of strncmp and strncasecmp to fix
+timing side-channel that leaks password prefix bytes and length
+(CWE-208).
+
+Resolves: https://github.com/linux-pam/linux-pam/issues/992
+Co-authored-by: Dmitry V. Levin <ldv at strace.io>
+---
+ libpam/include/pam_inline.h     | 20 +++++++++
+ modules/pam_userdb/pam_userdb.c | 75 +++++++++++++++++++--------------
+ 2 files changed, 64 insertions(+), 31 deletions(-)
+
+diff --git a/libpam/include/pam_inline.h b/libpam/include/pam_inline.h
+index d79d6fdf2..86d131cf4 100644
+--- a/libpam/include/pam_inline.h
++++ b/libpam/include/pam_inline.h
+@@ -9,6 +9,7 @@
+ #define PAM_INLINE_H
+ 
+ #include "pam_cc_compat.h"
++#include <ctype.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -244,4 +245,23 @@ pam_consttime_streq(const char *userinput, const char *secret) {
+ 	return ret == 0;
+ }
+ 
++/*
++ * Constant-time, case-insensitive string equality check.
++ * Same contract as pam_consttime_streq but uses tolower() on each byte.
++ * Runs for exactly strlen(userinput)+1 iterations regardless of secret.
++ */
++static inline int
++pam_consttime_strcaseeq(const char *userinput, const char *secret) {
++	volatile const char *u = userinput, *s = secret;
++	volatile int ret = 0;
++
++	do {
++		ret |= tolower((unsigned char)*u) ^ tolower((unsigned char)*s);
++
++		s += !!*s;
++	} while (*u++ != '\0');
++
++	return ret == 0;
++}
++
+ #endif /* PAM_INLINE_H */
+diff --git a/modules/pam_userdb/pam_userdb.c b/modules/pam_userdb/pam_userdb.c
+index bdb8553cc..b37f096cd 100644
+--- a/modules/pam_userdb/pam_userdb.c
++++ b/modules/pam_userdb/pam_userdb.c
+@@ -321,15 +321,24 @@ user_lookup (pam_handle_t *pamh, const char *database, const char *cryptmode,
+ 	} else {
+ 
+ 	  /* Unknown password encryption method -
+-	   * default to plaintext password storage
++	   * default to plaintext password storage.
++	   * Use constant-time comparison: strncmp/strncasecmp leak prefix bytes
++	   * and the length pre-check leaks the password length (CWE-208).
+ 	   */
+ 
+-	  if (strlen(pass) != (size_t)data.dsize) {
+-	    compare = 1; /* wrong password len -> wrong password */
+-	  } else if (ctrl & PAM_ICASE_ARG) {
+-	    compare = strncasecmp(data.dptr, pass, data.dsize);
++	  /* libdb is not guaranteed to produce null-terminated strings */
++	  char *stored = strndup(data.dptr, data.dsize);
++	  if (stored == NULL) {
++	    pam_syslog(pamh, LOG_CRIT, "strndup failed: data.dptr");
++	    compare = -2;
+ 	  } else {
+-	    compare = strncmp(data.dptr, pass, data.dsize);
++	    if (ctrl & PAM_ICASE_ARG) {
++	      compare = pam_consttime_strcaseeq(pass, stored) ? 0 : 1;
++	    } else {
++	      compare = pam_consttime_streq(pass, stored) ? 0 : 1;
++	    }
++	    pam_overwrite_string(stored);
++	    free(stored);
+ 	  }
+ 
+ 	  if (cryptmode && pam_str_skip_icase_prefix(cryptmode, "none") == NULL
+@@ -361,36 +370,40 @@ user_lookup (pam_handle_t *pamh, const char *database, const char *cryptmode,
+         }
+ 
+         /* now handle the key_only case */
++        size_t ulen = strlen(user);
+         for (key = db_firstkey(dbm);
+              key.dptr != NULL;
+              key = db_nextkey(dbm, key)) {
+-            int compare;
+-            /* first compare the user portion (case sensitive) */
+-            compare = strncmp(key.dptr, user, strlen(user));
+-            if (compare == 0) {
+-                /* assume failure */
+-                compare = -1;
+-                /* if we have the divider where we expect it to be... */
+-                if (key.dptr[strlen(user)] == '-') {
+-		    saw_user = 1;
+-		    if ((size_t)key.dsize == strlen(user) + 1 + strlen(pass)) {
+-		        if (ctrl & PAM_ICASE_ARG) {
+-			    /* compare the password portion (case insensitive)*/
+-                            compare = strncasecmp(key.dptr + strlen(user) + 1,
+-                                                  pass,
+-                                                  strlen(pass));
+-		        } else {
+-                            /* compare the password portion (case sensitive) */
+-                            compare = strncmp(key.dptr + strlen(user) + 1,
+-                                              pass,
+-                                              strlen(pass));
+-		        }
+-		    }
+-                }
+-                if (compare == 0) {
++            /* assume failure */
++            int compare = -1;
++
++            /*
++             * First compare the user portion (case sensitive);
++             * user is caller-supplied, so this memcmp leaks nothing secret.
++             */
++            if ((size_t)key.dsize > ulen &&
++                key.dptr[ulen] == '-' &&
++                memcmp(key.dptr, user, ulen) == 0) {
++                saw_user = 1;
++                char *stored_pass = strndup(key.dptr + ulen + 1,
++                                            key.dsize - ulen - 1);
++                if (stored_pass == NULL) {
+                     db_close(dbm);
+-                    return 0; /* match */
++                    return -2;
+                 }
++                /* compare the password portion (case (in)sensitive) */
++                if (ctrl & PAM_ICASE_ARG) {
++                    compare = pam_consttime_strcaseeq(pass, stored_pass) ? 0 : 1;
++                } else {
++                    compare = pam_consttime_streq(pass, stored_pass) ? 0 : 1;
++                }
++                pam_overwrite_string(stored_pass);
++                free(stored_pass);
++            }
++
++            if (compare == 0) {
++                db_close(dbm);
++                return 0; /* match */
+             }
+         }
+         db_close(dbm);
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/pam.git/commitdiff/d5c25bb063e52293654b592956f25ad91186e7f3



More information about the pld-cvs-commit mailing list