diff -pruN 1.7.0-5/debian/changelog 1.7.0-5ubuntu2/debian/changelog
--- 1.7.0-5/debian/changelog	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/changelog	2025-09-06 15:08:48.000000000 +0000
@@ -1,3 +1,70 @@
+pam (1.7.0-5ubuntu2) questing; urgency=medium
+
+  * Rebuild to include updated RISC-V base ISA RVA23
+
+ -- Heinrich Schuchardt <heinrich.schuchardt@canonical.com>  Sat, 06 Sep 2025 15:08:48 +0000
+
+pam (1.7.0-5ubuntu1) questing; urgency=medium
+
+  * Merge with Debian unstable (LP: #2112053). Remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager
+      when there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/patches/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/patches/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/update-motd.5, debian/libpam-runtime.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - Add lintian override for pam_extrausers_chkpwd
+    - Disable custom daemon restart detection code if needrestart is available
+    - d/p/pam_env-remove-deprecation-notice-for-user_readenv.patch: drop
+      deprecation warning about user_readenv from pam_env (LP 2059859)
+    - debian/patches/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - d/po/eu.po, d/po/fi.po, d/po/vi.po: Clean-up translation files
+    - debian/patches/fix-pam_motd_ftbfs.patch: fix FTBFS in display_legal()
+    - d/p/031_pam_include: fix loading from /usr/lib/pam.d (LP #2087827)
+  * Drop Changes:
+    - debian/pam-configs/mkhomedir: honor default private home directory
+      permissions for pam_mkdir.so by specifying a umask of 0027
+      (LP #1957024)
+      [Dropped the above change and its revert below]
+    - debian/pam-configs/mkhomedir: remove umask override added previously
+      for LP #1957024 as this is not actually needed since pam_mkhomedir
+      already respects HOME_MODE from login.defs and it complicates umask
+      management in general
+    - SECURITY UPDATE: privilege escalation via pam_namespace
+      [Fixed in 1.7.0-4]
+  * Changed Delta:
+    - d/p/extrausers.patch,
+      d/p/pam_umask_usergroups_from_login.defs.patch,
+      d/p/update-motd-manpage-ref: Update patches to work with meson. Drop
+      text-based man-pages in favor of XML ones. Add required code to build
+      scripts.
+    - debian/tests/usr-lib-config: Fix typo in "mv /usr/lib/pam.d/passwd
+      /etc/pam.d/*"
+
+ -- Ankush Pathak <ankush.pathak@canonical.com>  Thu, 03 Jul 2025 22:03:16 +0530
+
 pam (1.7.0-5) unstable; urgency=high
 
   * pam_access: backport upstream commit to implement nodns option to allow people to work around #1087019
@@ -57,6 +124,96 @@ pam (1.7.0-1) experimental; urgency=medi
 
  -- Sam Hartman <hartmans@debian.org>  Thu, 16 Jan 2025 15:59:23 -0700
 
+pam (1.5.3-7ubuntu6) questing; urgency=medium
+
+  * SECURITY UPDATE: privilege escalation via pam_namespace
+    - debian/patches/pam_namespace_170.patch: sync pam_namespace module to
+      version 1.7.0.
+    - debian/patches/pam_namespace_post170-*.patch: add post-1.7.0 changes
+      from upstream git tree.
+    - debian/patches/pam_namespace_revert_abi.patch: revert ABI change to
+      prevent unintended issues in running daemons.
+    - debian/patches/CVE-2025-6020-1.patch: fix potential privilege
+      escalation.
+    - debian/patches/CVE-2025-6020-2.patch: add flags to indicate path
+      safety.
+    - debian/patches/CVE-2025-6020-3.patch: secure_opendir: do not look at
+      the group ownership.
+    - debian/patches/pam_namespace_o_directory.patch: removed, included in
+      patch cluster above.
+    - CVE-2025-6020
+
+ -- Marc Deslauriers <marc.deslauriers@ubuntu.com>  Wed, 18 Jun 2025 12:58:44 -0400
+
+pam (1.5.3-7ubuntu5) questing; urgency=medium
+
+  * d/p/031_pam_include: fix loading from /usr/lib/pam.d (LP: #2087827)
+
+ -- Simon Chopin <schopin@ubuntu.com>  Wed, 21 May 2025 16:03:01 +0200
+
+pam (1.5.3-7ubuntu4) plucky; urgency=medium
+
+  * debian/pam-configs/mkhomedir: remove umask override added previously
+    for LP#1957024 as this is not actually needed since pam_mkhomedir
+    already respects HOME_MODE from login.defs and it complicates umask
+    management in general
+
+ -- Alex Murray <alex.murray@canonical.com>  Wed, 20 Nov 2024 06:43:46 +1030
+
+pam (1.5.3-7ubuntu3) plucky; urgency=medium
+
+  [ Ponnuvel Palaniyappan ]
+  * debian/pam-configs/mkhomedir: honor default private home directory
+    permissions for pam_mkdir.so by specifying a umask of 0027
+    (LP: #1957024)
+
+ -- Alex Murray <alex.murray@canonical.com>  Thu, 07 Nov 2024 13:29:20 +1030
+
+pam (1.5.3-7ubuntu2) oracular; urgency=medium
+
+  * debian/patches/fix-pam_motd_ftbfs.patch: fix FTBFS in display_legal()
+
+ -- Nishit Majithia <nishit.majithia@canonical.com>  Fri, 16 Aug 2024 14:53:00 +0530
+
+pam (1.5.3-7ubuntu1) oracular; urgency=medium
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager
+      when there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/patches/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - Add lintian override for pam_extrausers_chkpwd
+    - Disable custom daemon restart detection code if needrestart is available
+    - d/p/pam_env-remove-deprecation-notice-for-user_readenv.patch: drop
+      deprecation warning about user_readenv from pam_env (LP 2059859)
+
+ -- Dan Bungert <daniel.bungert@canonical.com>  Tue, 30 Apr 2024 16:17:36 -0600
+
 pam (1.5.3-7) unstable; urgency=medium
 
   * Correct Build depends for docbook5, Closes: #1065064
@@ -73,6 +230,69 @@ pam (1.5.3-6) unstable; urgency=medium
 
  -- Steve Langasek <steve.langasek@ubuntu.com>  Thu, 29 Feb 2024 12:56:32 -0800
 
+pam (1.5.3-5ubuntu5) noble; urgency=medium
+
+  * d/p/pam_env-remove-deprecation-notice-for-user_readenv.patch: drop
+    deprecation warning about user_readenv from pam_env (LP: #2059859)
+
+ -- Andreas Hasenack <andreas@canonical.com>  Wed, 10 Apr 2024 16:19:22 -0300
+
+pam (1.5.3-5ubuntu4) noble; urgency=medium
+
+  * No-change rebuild for CVE-2024-3094
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Sun, 31 Mar 2024 00:03:23 +0000
+
+pam (1.5.3-5ubuntu3) noble; urgency=medium
+
+  * No-change rebuild against libdb5.3t64
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Sat, 02 Mar 2024 20:36:06 +0000
+
+pam (1.5.3-5ubuntu2) noble; urgency=medium
+
+  * Fix FTBFS when built with -Werror=implicit-function-declaration
+    (LP: #2055453)
+
+ -- Dan Bungert <daniel.bungert@canonical.com>  Thu, 29 Feb 2024 11:53:08 -0700
+
+pam (1.5.3-5ubuntu1) noble; urgency=medium
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager
+      when there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/patches/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - Add lintian override for pam_extrausers_chkpwd
+    - Disable custom daemon restart detection code if needrestart is available
+
+ -- Dan Bungert <daniel.bungert@canonical.com>  Thu, 29 Feb 2024 10:25:41 -0700
+
 pam (1.5.3-5) unstable; urgency=medium
 
   * Revert renaming libpam0g to libpam0t64 for time_t transition: apt
@@ -90,6 +310,54 @@ pam (1.5.3-5) unstable; urgency=medium
 
  -- Sam Hartman <hartmans@debian.org>  Thu, 29 Feb 2024 09:46:54 -0700
 
+pam (1.5.3-4ubuntu1) noble; urgency=medium
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0t64.postinst: only ask questions during update-manager
+      when there are non-default services running.
+    - debian/libpam0t64.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/patches/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - Add lintian override for pam_extrausers_chkpwd
+    - Disable custom daemon restart detection code if needrestart is available
+  * Dropped changes, included in Debian:
+    - SECURITY UPDATE: pam_namespace local denial of service
+      - debian/patches/CVE-2024-22365.patch: use O_DIRECTORY to
+        prevent local DoS situations in modules/pam_namespace/pam_namespace.c.
+      - CVE-2024-22365
+    - Install into /usr/{lib,sbin} instead of /{lib,sbin}. Assumes
+      usrmerge aliasing symlinks are in place since bookworm to keep
+      compatibility with PAM modules still installing into /lib.
+      (DEP17 M2) (Closes: #1060160).
+    - Mitigate /usr-move file loss. (Closes: #1062802)
+    - Update lintian override for setgid binary.
+
+ -- Dan Bungert <daniel.bungert@canonical.com>  Wed, 28 Feb 2024 21:07:18 -0700
+
 pam (1.5.3-4) unstable; urgency=medium
 
   * Upload to unstable
@@ -161,6 +429,68 @@ pam (1.5.3-1) experimental; urgency=medi
 
  -- Sam Hartman <hartmans@debian.org>  Mon, 15 Jan 2024 15:45:50 -0700
 
+pam (1.5.2-9.1ubuntu3) noble; urgency=medium
+
+  [ Chris Hofstaedtler ]
+  * Install into /usr/{lib,sbin} instead of /{lib,sbin}. Assumes
+    usrmerge aliasing symlinks are in place since bookworm to keep
+    compatibility with PAM modules still installing into /lib.
+    (DEP17 M2) (Closes: #1060160).
+  * Update lintian override for setgid binary.
+
+  [ Helmut Grohne ]
+  * Mitigate /usr-move file loss. (Closes: #1062802)
+
+ -- Julian Andres Klode <juliank@ubuntu.com>  Thu, 22 Feb 2024 13:24:31 +0100
+
+pam (1.5.2-9.1ubuntu2) noble; urgency=medium
+
+  * SECURITY UPDATE: pam_namespace local denial of service
+    - debian/patches-applied/CVE-2024-22365.patch: use O_DIRECTORY to
+      prevent local DoS situations in modules/pam_namespace/pam_namespace.c.
+    - CVE-2024-22365
+
+ -- Marc Deslauriers <marc.deslauriers@ubuntu.com>  Wed, 17 Jan 2024 12:28:44 -0500
+
+pam (1.5.2-9.1ubuntu1) noble; urgency=medium
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - Add lintian override for pam_extrausers_chkpwd
+    - Disable custom daemon restart detection code if needrestart is available
+  * debian/update-motd.5: fix a typo; thanks to David
+    Collantes <david@collantes.us>.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Mon, 20 Nov 2023 06:39:20 -0800
+
 pam (1.5.2-9.1) unstable; urgency=medium
 
   * Non-maintainer upload acked by Sam Hartman.
@@ -197,6 +527,43 @@ pam (1.5.2-7) unstable; urgency=medium
 
  -- Sam Hartman <hartmans@debian.org>  Wed, 16 Aug 2023 17:22:53 -0600
 
+pam (1.5.2-6ubuntu1) mantic; urgency=medium
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - Add lintian override for pam_extrausers_chkpwd
+    - Disable custom daemon restart detection code if needrestart is available
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Mon, 15 May 2023 15:17:53 -0700
+
 pam (1.5.2-6) unstable; urgency=medium
 
   * Update debian/copyright, Thanks Bastian Germann, Closes: #460232
@@ -209,6 +576,43 @@ pam (1.5.2-6) unstable; urgency=medium
 
  -- Sam Hartman <hartmans@debian.org>  Tue, 03 Jan 2023 13:15:23 -0700
 
+pam (1.5.2-5ubuntu1) lunar; urgency=medium
+
+  * Merge from Debian unstable; remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - Add lintian override for pam_extrausers_chkpwd
+    - Disable custom daemon restart detection code if needrestart is available
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Mon, 07 Nov 2022 12:53:39 -0800
+
 pam (1.5.2-5) unstable; urgency=medium
 
   * pam_namespace_helper manpage *wasn't* missing, it was just being
@@ -242,6 +646,47 @@ pam (1.5.2-3) unstable; urgency=medium
 
  -- Steve Langasek <vorlon@debian.org>  Thu, 06 Oct 2022 04:05:02 +0000
 
+pam (1.5.2-2ubuntu1) kinetic; urgency=medium
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - Add lintian override for pam_extrausers_chkpwd
+    - Disable custom daemon restart detection code if needrestart is available
+  * Dropped changes, no longer needed:
+    - d/libpam-modules.postinst: Add /snap/bin to $PATH in /etc/environment
+  * Refresh patches.
+  * debian/patches-applied/extrausers.patch: update for upstream changes.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Thu, 18 Aug 2022 18:16:30 +0000
+
 pam (1.5.2-2) unstable; urgency=medium
 
   * Pass --with-systemdunitdir=/usr/lib/systemd/system for consistent
@@ -287,6 +732,44 @@ pam (1.5.2-1) unstable; urgency=medium
 
  -- Steve Langasek <vorlon@debian.org>  Thu, 18 Aug 2022 07:27:16 +0000
 
+pam (1.4.0-13ubuntu1) kinetic; urgency=medium
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - Add lintian override for pam_extrausers_chkpwd
+    - Disable custom daemon restart detection code if needrestart is available
+    - d/libpam-modules.postinst: Add /snap/bin to $PATH in /etc/environment
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Tue, 26 Apr 2022 11:10:38 -0700
+
 pam (1.4.0-13) unstable; urgency=medium
 
   * Don't build with NIS support.  This is only used for password changes on
@@ -295,6 +778,55 @@ pam (1.4.0-13) unstable; urgency=medium
 
  -- Steve Langasek <vorlon@debian.org>  Mon, 25 Apr 2022 16:12:04 -0700
 
+pam (1.4.0-11ubuntu2) jammy; urgency=medium
+
+  * Drop Recommends on update-motd which is no longer used and is not being
+    maintained.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 23 Mar 2022 18:43:24 -0700
+
+pam (1.4.0-11ubuntu1) jammy; urgency=medium
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/control: have libpam-modules recommend update-motd package
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - Add lintian override for pam_extrausers_chkpwd
+    - Disable custom daemon restart detection code if needrestart is available
+    - d/libpam-modules.postinst: Add /snap/bin to $PATH in /etc/environment
+  * Dropped changes, included in Debian:
+    - d/p/pam_env-allow-environment-files-without-EOL-at-EOF.patch:
+      Allow /etc/environment files without EOL at EOF.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Mon, 07 Feb 2022 08:51:50 -0800
+
 pam (1.4.0-11) unstable; urgency=medium
 
   * Whitespace fixes in debconf templates.
@@ -306,6 +838,69 @@ pam (1.4.0-11) unstable; urgency=medium
 
  -- Steve Langasek <vorlon@debian.org>  Mon, 06 Dec 2021 11:11:31 -0800
 
+pam (1.4.0-10ubuntu2) jammy; urgency=medium
+
+  [ Sergio Durigan Junior ]
+  * d/p/pam_env-allow-environment-files-without-EOL-at-EOF.patch:
+    Allow /etc/environment files without EOL at EOF.  In other words,
+    allow files without a newline at the end. (LP: #1953201)
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Mon, 06 Dec 2021 11:05:28 -0800
+
+pam (1.4.0-10ubuntu1) jammy; urgency=medium
+
+  * Merge from Debian unstable (LP: #1916509). Remaining changes:
+    - debian/control: have libpam-modules recommend update-motd package
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - Add lintian override for pam_extrausers_chkpwd
+    - Disable custom daemon restart detection code if needrestart is available
+    - d/libpam-modules.postinst: Add /snap/bin to $PATH in /etc/environment
+  * Dropped changes, obsoleted:
+    - pam_motd: Export MOTD_SHOWN=pam after showing MOTD
+    - Return only PAM_IGNORE or error from pam_motd
+    - Fix patches to fix FTBFS
+    - Backport pam_faillock module from pam 1.4.0
+    - debian/patches-applied/nullok_secure-compat.patch: Support
+      nullok_secure as a deprecated alias for nullok.
+    -  debian/pam-configs/unix: use nullok, not nullok_secure.
+  * Patches:
+    - d/p/pam_motd-legal-notice: refreshed
+    - Refreshed d/p/pam_umask_usergroups_from_login.defs.patch to use
+      pam_modutil_search_key instead of our own hand-rolled version
+    - d/p/extrausers.patch: Refreshed the patch and fixed the
+      HAVE_LIBSELINUX conditional removed upstream.
+  * d/local/pam-auth-update: refreshed the md5sum for debian/local/common-session
+
+ -- Simon Chopin <simon.chopin@canonical.com>  Tue, 26 Oct 2021 10:49:14 +0200
+
 pam (1.4.0-10) unstable; urgency=medium
 
   * Fix syntax error in libpam0g.postinst when a systemd unit fails,
@@ -461,6 +1056,122 @@ pam (1.4.0-1) unstable; urgency=medium
 
  -- Steve Langasek <vorlon@debian.org>  Mon, 28 Dec 2020 06:05:13 +0000
 
+pam (1.3.1-5ubuntu11) impish; urgency=medium
+
+  * extrausers.patch: update for compatibility with the removal of
+    nullok_secure.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 15 Sep 2021 22:39:58 -0700
+
+pam (1.3.1-5ubuntu10) impish; urgency=medium
+
+  * Fix up the nullok_secure-compat.patch to apply properly on 1.3.1.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 15 Sep 2021 18:28:12 -0700
+
+pam (1.3.1-5ubuntu9) impish; urgency=medium
+
+  * Correctly document current VCS in debian/control.
+  * Drop patches to implement "nullok_secure" option for pam_unix.
+    Closes: #674857, #936071, LP: #1860826.
+  * debian/patches-applied/nullok_secure-compat.patch: Support
+    nullok_secure as a deprecated alias for nullok.
+  * debian/pam-configs/unix: use nullok, not nullok_secure.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 15 Sep 2021 18:18:19 -0700
+
+pam (1.3.1-5ubuntu8) impish; urgency=medium
+
+  * Disable custom daemon restart detection code if needrestart is available
+    (LP: #1935972)
+
+ -- Simon Chopin <simon.chopin@canonical.com>  Tue, 13 Jul 2021 10:28:04 +0200
+
+pam (1.3.1-5ubuntu7) impish; urgency=medium
+
+  * Backport pam_faillock module from pam 1.4.0 (LP: #1927796)
+    - debian/patches-applied/add_pam_faillock.patch: add module.
+    - debian/patches-applied/pam_faillock_create_directory: create dir
+      before creating file in modules/pam_faillock/faillock.c.
+    - debian/rules: set execute permissions on pam_faillock test.
+    - debian/libpam-modules-bin.install: install faillock binary and man
+      page.
+
+ -- Richard Maciel Costa <richard.maciel.costa@canonical.com>  Thu, 08 Apr 2021 07:06:27 -0400
+
+pam (1.3.1-5ubuntu6) groovy; urgency=medium
+
+  * Fix FTBFS with selinux/flask.h
+    - debian/patches-applied/selinux_flask_ftbfs.patch: Fix FTBFS due to
+      deprecated selinux/flask.h
+
+ -- Mike Salvatore <mike.salvatore@canonical.com>  Wed, 05 Aug 2020 21:10:51 -0400
+
+pam (1.3.1-5ubuntu5) groovy; urgency=medium
+
+  * debian/libpam-modules.postinst: Add /snap/bin to $PATH in
+    /etc/environment. (LP: #1659719)
+
+ -- Michael Hudson-Doyle <michael.hudson@ubuntu.com>  Fri, 10 Jul 2020 08:35:49 +1200
+
+pam (1.3.1-5ubuntu4) focal; urgency=medium
+
+  * Return only PAM_IGNORE or error from pam_motd (LP: #1856703)
+
+ -- Balint Reczey <rbalint@ubuntu.com>  Tue, 17 Dec 2019 17:41:40 +0100
+
+pam (1.3.1-5ubuntu3) focal; urgency=medium
+
+  * Fix patches to fix FTBFS
+
+ -- Balint Reczey <rbalint@ubuntu.com>  Thu, 05 Dec 2019 13:18:35 +0100
+
+pam (1.3.1-5ubuntu2) focal; urgency=medium
+
+  * pam_motd: Export MOTD_SHOWN=pam after showing MOTD (LP: #1855092)
+
+ -- Balint Reczey <rbalint@ubuntu.com>  Wed, 04 Dec 2019 12:23:57 +0100
+
+pam (1.3.1-5ubuntu1) disco; urgency=medium
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/control: have libpam-modules recommend update-motd package
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/libpam0g.postinst: the init script for 'samba' is now named
+      'smbd' in Ubuntu, so fix the restart handling.
+    - don't notify about xdm restarts during a release-upgrade
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - Add lintian override for pam_extrausers_chkpwd
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 13 Feb 2019 23:16:59 -0800
+
 pam (1.3.1-5) unstable; urgency=medium
 
   * xdm restart check was inverted in the prior upload; turn it the right
@@ -469,6 +1180,50 @@ pam (1.3.1-5) unstable; urgency=medium
 
  -- Steve Langasek <vorlon@debian.org>  Thu, 14 Feb 2019 07:08:47 +0000
 
+pam (1.3.1-4ubuntu1) disco; urgency=medium
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/control: have libpam-modules recommend update-motd package
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/libpam0g.postinst: the init script for 'samba' is now named
+      'smbd' in Ubuntu, so fix the restart handling.
+    - don't notify about xdm restarts during a release-upgrade
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - Add lintian override for pam_extrausers_chkpwd
+  * Dropped changes, included in Debian:
+    - Fix the name of the samba service being restarted
+    - Fix debian/patches-applied/update-motd to apply the correct changes
+      to the README
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 13 Feb 2019 15:43:33 -0800
+
 pam (1.3.1-4) unstable; urgency=medium
 
   * Fix the name of the samba services to be restarted on upgrade.
@@ -491,6 +1246,60 @@ pam (1.3.1-3) unstable; urgency=medium
 
  -- Steve Langasek <vorlon@debian.org>  Wed, 13 Feb 2019 20:41:46 +0000
 
+pam (1.3.1-2ubuntu1) disco; urgency=medium
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/control: have libpam-modules recommend update-motd package
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/libpam0g.postinst: the init script for 'samba' is now named
+      'smbd' in Ubuntu, so fix the restart handling.
+    - don't notify about xdm restarts during a release-upgrade
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+  * Dropped changes, included in Debian:
+    - pam-configs/mkhomedir: Added a config for pam_mkhomedir, disabled
+      by default.
+  * Dropped changes, obsoleted:
+    - debian/patches-applied/cve-2015-3238.patch: removed manpage changes
+      so they don't get regenerated during build and cause a multiarch
+      installation issue.
+  * Fix the name of the samba service being restarted, which was now
+    differently wrong in each of Debian and Ubuntu.
+  * Update extrausers.patch for changes in the upstream build system.
+  * Fix debian/patches-applied/update-motd to apply the correct changes
+    to the README (should be forwarded to Debian)
+  * debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+    include changes to the README.
+  * Add lintian override for pam_extrausers_chkpwd
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 13 Feb 2019 06:07:03 +0000
+
 pam (1.3.1-2) unstable; urgency=medium
 
   * Bump the version check for service restarts to 1.3.1-2.
@@ -582,6 +1391,68 @@ pam (1.1.8-3.7) unstable; urgency=medium
 
  -- Timo Aaltonen <tjaalton@debian.org>  Fri, 02 Feb 2018 16:57:43 +0200
 
+pam (1.1.8-3.6ubuntu2) bionic; urgency=medium
+
+  * pam-auth-update: Add support for --enable option which is useful for
+    enabling non-default configs without asking the admin. (LP:
+    #1192719)
+
+ -- Timo Aaltonen <tjaalton@debian.org>  Thu, 05 Apr 2018 15:27:42 +0300
+
+pam (1.1.8-3.6ubuntu1) bionic; urgency=medium
+
+  * Merge with Debian unstable.
+    - Fixes unescaped brace in pam_getenv regex.  LP: #1538284.
+    - Fixes pam_namespace defaults for compatibility with dash.  LP: #1081323.
+  * Remaining changes:
+    - debian/control: have libpam-modules recommend update-motd package
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/libpam0g.postinst: the init script for 'samba' is now named
+      'smbd' in Ubuntu, so fix the restart handling.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - pam-configs/mkhomedir: Added a config for pam_mkhomedir, disabled
+      by default.
+    - don't notify about xdm restarts during a release-upgrade
+    - debian/patches-applied/cve-2015-3238.patch: removed manpage changes
+      so they don't get regenerated during build and cause a multiarch
+      installation issue.
+  * Dropped changes, included in Debian:
+    - Build-depend on libfl-dev.
+    - debian/patches-applied/pam-limits-nofile-fd-setsize-cap: cap the default
+      soft nofile limit read from pid 1 to FD_SETSIZE.
+  * Fix references to /var/run in update-motd.5.  LP: #1571864
+  * Fix service restart handling to integrate with systemd instead of
+    upstart.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Thu, 26 Oct 2017 23:23:18 -0700
+
 pam (1.1.8-3.6) unstable; urgency=medium
 
   * Non-maintainer upload.
@@ -649,6 +1520,74 @@ pam (1.1.8-3.3) unstable; urgency=low
 
  -- Laurent Bigonville <bigon@debian.org>  Wed, 18 May 2016 02:04:29 +0200
 
+pam (1.1.8-3.2ubuntu3) artful; urgency=medium
+
+  * No-change rebuild to pick up -fPIE compiler default in static
+    libraries
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Fri, 21 Apr 2017 20:53:23 +0000
+
+pam (1.1.8-3.2ubuntu2) xenial; urgency=medium
+
+  * debian/patches-applied/cve-2015-3238.patch: removed manpage changes
+    so they don't get regenerated during build and cause a multiarch
+    installation issue. (LP: #1558114)
+
+ -- Marc Deslauriers <marc.deslauriers@ubuntu.com>  Wed, 16 Mar 2016 13:34:02 -0400
+
+pam (1.1.8-3.2ubuntu1) xenial; urgency=medium
+
+  * Merge from Debian unstable. Remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/libpam0g.postinst: the init script for 'samba' is now named
+      'smbd' in Ubuntu, so fix the restart handling.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - Build-depend on libfl-dev in addition to flex, for cross-building
+      support.
+    - Add /usr/local/games to PATH.
+    - Adjust debian/patches-applied/update-motd to write to
+      /run/motd.dynamic, as sysvinit/ssh/login in Debian have been changed
+      to use this file and no longer links /etc/motd to /var/run/motd.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      include patch to autogenerated manpage file
+    - debian/patches-applied/pam-loginuid-in-containers: pam_loginuid:
+      Update patch with follow-up changes to loginuid.c
+    - debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - debian/patches-applied/extrausers.patch: Ship pre-generated man page
+    - debian/patches-applied/pam-limits-nofile-fd-setsize-cap: cap the default
+      soft nofile limit read from pid 1 to FD_SETSIZE.
+    - debian/control: have libpam-modules recommend update-motd package
+
+ -- Marc Deslauriers <marc.deslauriers@ubuntu.com>  Wed, 16 Mar 2016 09:50:51 -0400
+
 pam (1.1.8-3.2) unstable; urgency=medium
 
   * Non-maintainer upload.
@@ -657,6 +1596,76 @@ pam (1.1.8-3.2) unstable; urgency=medium
 
  -- Tianon Gravi <tianon@debian.org>  Wed, 06 Jan 2016 15:53:31 -0800
 
+pam (1.1.8-3.1ubuntu3) vivid; urgency=medium
+
+  * d/applied-patches/pam-limits-nofile-fd-setsize-cap: cap the default
+    soft nofile limit read from pid 1 to FD_SETSIZE.
+
+ -- Robie Basak <robie.basak@ubuntu.com>  Wed, 22 Apr 2015 08:55:24 +0000
+
+pam (1.1.8-3.1ubuntu2) vivid; urgency=medium
+
+  * debian/control:
+    - have libpam-modules recommend update-motd package
+      + while libpam-modules provides pam_motd, which does dynamically
+        generate the motd from /etc/update-motd.d on login, hundreds of
+        users have asked in the past few years how they might "force"
+        a MOTD update;  this is provided by /usr/sbin/update-motd
+        in the tiny update-motd package (already in main); recommend
+        this package
+
+ -- Dustin Kirkland <kirkland@ubuntu.com>  Tue, 11 Nov 2014 12:49:14 -0600
+
+pam (1.1.8-3.1ubuntu1) vivid; urgency=low
+
+  * Merge from Debian unstable.  Remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/libpam0g.postinst: the init script for 'samba' is now named
+      'smbd' in Ubuntu, so fix the restart handling.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - Build-depend on libfl-dev in addition to flex, for cross-building
+      support.
+    - Add /usr/local/games to PATH.
+    - Adjust debian/patches-applied/update-motd to write to
+      /run/motd.dynamic, as sysvinit/ssh/login in Debian have been changed
+      to use this file and no longer links /etc/motd to /var/run/motd.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      include patch to autogenerated manpage file
+    - debian/patches-applied/pam-loginuid-in-containers: pam_loginuid:
+      Update patch with follow-up changes to loginuid.c
+    - debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+      that is basically just a copy of pam_unix but looks at
+      /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+    - debian/libpam-modules-bin.install: install the helper binaries for
+      pam_extrausers to /sbin
+    - debian/rules: Make pam_extrausers_chkpwd sguid shadow
+    - debian/patches-applied/extrausers.patch: Ship pre-generated man page
+
+ -- Michael Vogt <michael.vogt@ubuntu.com>  Mon, 27 Oct 2014 09:57:52 +0100
+
 pam (1.1.8-3.1) unstable; urgency=high
 
   * Non-maintainer upload by the Security Team.
@@ -667,6 +1676,78 @@ pam (1.1.8-3.1) unstable; urgency=high
 
  -- Michael Gilbert <mgilbert@debian.org>  Sat, 09 Aug 2014 09:50:42 +0000
 
+pam (1.1.8-3ubuntu4) utopic; urgency=medium
+
+  * No-change rebuild to get debug symbols on all architectures.
+
+ -- Brian Murray <brian@ubuntu.com>  Tue, 21 Oct 2014 12:32:23 -0700
+
+pam (1.1.8-3ubuntu3) utopic; urgency=medium
+
+  * debian/patches-applied/extrausers.patch:
+    - Ship pre-generated man page
+
+ -- Michael Terry <mterry@ubuntu.com>  Tue, 22 Jul 2014 14:13:31 -0400
+
+pam (1.1.8-3ubuntu2) utopic; urgency=medium
+
+  * debian/patches-applied/extrausers.patch: Add a pam_extrausers module
+    that is basically just a copy of pam_unix but looks at
+    /var/lib/extrausers/{group,passwd,shadow} instead of /etc/
+  * debian/libpam-modules-bin.install: install the helper binaries for
+    pam_extrausers to /sbin
+  * debian/rules: Make pam_extrausers_chkpwd sguid shadow
+
+ -- Michael Terry <mterry@ubuntu.com>  Fri, 18 Jul 2014 14:52:08 -0400
+
+pam (1.1.8-3ubuntu1) utopic; urgency=medium
+
+  [ StÃ©phane Graber ]
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/libpam0g.postinst: the init script for 'samba' is now named
+      'smbd' in Ubuntu, so fix the restart handling.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - Build-depend on libfl-dev in addition to flex, for cross-building
+      support.
+    - Add /usr/local/games to PATH.
+    - Adjust debian/patches-applied/update-motd to write to
+      /run/motd.dynamic, as sysvinit/ssh/login in Debian have been changed
+      to use this file and no longer links /etc/motd to /var/run/motd.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      include patch to autogenerated manpage file
+    - debian/patches-applied/pam-loginuid-in-containers: pam_loginuid:
+      Update patch with follow-up changes to loginuid.c
+
+  [ Timo Aaltonen ]
+  * pam-configs/mkhomedir: Added a config for pam_mkhomedir, disabled
+    by default. (LP: #557013)
+
+ -- StÃ©phane Graber <stgraber@ubuntu.com>  Fri, 02 May 2014 14:59:10 -0400
+
 pam (1.1.8-3) unstable; urgency=low
 
   * debian/rules: On hurd, link libpam explicitly with -lpthread since glibc
@@ -683,6 +1764,54 @@ pam (1.1.8-2) unstable; urgency=medium
 
  -- Steve Langasek <vorlon@debian.org>  Thu, 13 Feb 2014 15:02:00 -0800
 
+pam (1.1.8-1ubuntu2) trusty; urgency=medium
+
+  * debian/patches-applied/pam-loginuid-in-containers: pam_loginuid:
+    Update patch with follow-up changes to loginuid.c
+
+ -- StÃ©phane Graber <stgraber@ubuntu.com>  Fri, 31 Jan 2014 22:11:02 +0000
+
+pam (1.1.8-1ubuntu1) trusty; urgency=medium
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/libpam0g.postinst: the init script for 'samba' is now named
+      'smbd' in Ubuntu, so fix the restart handling.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - Build-depend on libfl-dev in addition to flex, for cross-building
+      support.
+    - Add /usr/local/games to PATH.
+    - Adjust debian/patches-applied/update-motd to write to
+      /run/motd.dynamic, as sysvinit/ssh/login in Debian have been changed
+      to use this file and no longer links /etc/motd to /var/run/motd.
+  * debian/patches-applied/pam_umask_usergroups_from_login.defs.patch: include
+    patch to autogenerated manpage file
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Thu, 16 Jan 2014 02:40:41 +0000
+
 pam (1.1.8-1) unstable; urgency=medium
 
   * New upstream release.
@@ -716,6 +1845,47 @@ pam (1.1.8-1) unstable; urgency=medium
 
  -- Steve Langasek <vorlon@debian.org>  Thu, 16 Jan 2014 00:38:42 +0000
 
+pam (1.1.3-11ubuntu1) trusty; urgency=medium
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/libpam0g.postinst: the init script for 'samba' is now named
+      'smbd' in Ubuntu, so fix the restart handling.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - Build-depend on libfl-dev in addition to flex, for cross-building
+      support.
+    - Add /usr/local/games to PATH.
+    - Adjust debian/patches-applied/update-motd to write to
+      /run/motd.dynamic, as sysvinit/ssh/login in Debian have been changed
+      to use this file and no longer links /etc/motd to /var/run/motd.
+  * Dropped changes, merged in Debian:
+    - Disable libaudit for stage1 bootstrap.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Mon, 13 Jan 2014 21:41:05 -0800
+
 pam (1.1.3-11) unstable; urgency=low
 
   [ Wookey ]
@@ -729,6 +1899,46 @@ pam (1.1.3-11) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Tue, 14 Jan 2014 03:33:31 +0000
 
+pam (1.1.3-10ubuntu1) trusty; urgency=low
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/libpam0g.postinst: the init script for 'samba' is now named
+      'smbd' in Ubuntu, so fix the restart handling.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix's explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - Build-depend on libfl-dev in addition to flex, for cross-building
+      support.
+    - Add /usr/local/games to PATH.
+    - Disable libaudit for stage1 bootstrap.
+    - Adjust debian/patches-applied/update-motd to write to
+      /run/motd.dynamic, as sysvinit/ssh/login in Debian have been changed
+      to use this file and no longer links /etc/motd to /var/run/motd.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Sun, 20 Oct 2013 18:21:34 -0700
+
 pam (1.1.3-10) unstable; urgency=low
 
   * Fix pam-auth-update handling of trailing blank lines in the fields of
@@ -750,6 +1960,56 @@ pam (1.1.3-9) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Tue, 12 Feb 2013 23:06:30 +0000
 
+pam (1.1.3-8ubuntu3) saucy; urgency=low
+
+  * Adjust debian/patches-applied/update-motd to write to /run/motd.dynamic,
+    as sysvinit/ssh/login in Debian have been changed to use this file and
+    no longer links /etc/motd to /var/run/motd.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Sat, 18 May 2013 00:07:43 -0500
+
+pam (1.1.3-8ubuntu2) raring; urgency=low
+
+  * Disable libaudit for stage1 bootstrap (LP: #1126404)
+
+ -- Wookey <wookey@wookware.org>  Fri, 15 Feb 2013 12:45:27 +0000
+
+pam (1.1.3-8ubuntu1) raring; urgency=low
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/libpam0g.postinst: the init script for 'samba' is now named
+      'smbd' in Ubuntu, so fix the restart handling.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix' explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - Build-depend on libfl-dev in addition to flex, for cross-building
+      support.
+    - Add /usr/local/games to PATH.  LP: #110287.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Mon, 11 Feb 2013 22:08:44 -0800
+
 pam (1.1.3-8) unstable; urgency=low
 
   * Confirm NMU for bug #611136; thanks to Michael Gilbert.
@@ -786,6 +2046,55 @@ pam (1.1.3-7.1) unstable; urgency=low
 
  -- Michael Gilbert <mgilbert@debian.org>  Sun, 29 Apr 2012 02:23:26 -0400
 
+pam (1.1.3-7ubuntu3) quantal; urgency=low
+
+  [ Nathan Williams ]
+  * Add /usr/local/games to PATH.  LP: #110287.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Tue, 03 Jul 2012 06:55:25 +0000
+
+pam (1.1.3-7ubuntu2) precise; urgency=low
+
+  * No-change rebuild with gzip 1.4-1ubuntu2 to get multiarch-clean
+    compression of manpages.  LP: #871083.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 08 Feb 2012 17:15:39 -0800
+
+pam (1.1.3-7ubuntu1) precise; urgency=low
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/libpam0g.postinst: the init script for 'samba' is now named
+      'smbd' in Ubuntu, so fix the restart handling.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix' explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - Build-depend on libfl-dev in addition to flex, for cross-building
+      support.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Sat, 28 Jan 2012 11:36:07 -0800
+
 pam (1.1.3-7) unstable; urgency=low
 
   * Updated debconf translations:
@@ -813,6 +2122,49 @@ pam (1.1.3-7) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Sat, 28 Jan 2012 10:57:49 -0800
 
+pam (1.1.3-6ubuntu1) precise; urgency=low
+
+  * Merge from Debian unstable.  Remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/libpam0g.postinst: the init script for 'samba' is now named
+      'smbd' in Ubuntu, so fix the restart handling.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix' explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+  * Dropped changes, included in Debian:
+    - debian/patches-applied/update-motd: set a sane umask before calling
+      run-parts, and restore the old mask afterwards, so /run/motd gets
+      consistent permissions.
+    - debian/patches-applied/update-motd: new module option for pam_motd,
+      'noupdate', which suppresses the call to run-parts /etc/update-motd.d.
+    - debian/libpam0g.postinst: drop kdm from the list of services to
+      restart.
+  * Build-depend on libfl-dev in addition to flex, for cross-building
+    support.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Mon, 07 Nov 2011 21:15:00 -0800
+
 pam (1.1.3-6) unstable; urgency=low
 
   * debian/patches-applied/hurd_no_setfsuid: we don't want to check all
@@ -840,6 +2192,59 @@ pam (1.1.3-6) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Sun, 06 Nov 2011 19:43:14 -0800
 
+pam (1.1.3-5ubuntu2) precise; urgency=low
+
+  * Rebuild with dpkg 1.16.1.1ubuntu2 to restore large file support.
+
+ -- Colin Watson <cjwatson@ubuntu.com>  Tue, 01 Nov 2011 16:59:55 -0400
+
+pam (1.1.3-5ubuntu1) precise; urgency=low
+
+  * Merge from Debian unstable.  Remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/libpam0g.postinst: drop kdm from the list of services to
+      restart.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - add debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix' explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+      (Closes: #583958)
+  * Dropped changes, included in Debian:
+    - debian/patches-applied/CVE-2011-3148.patch
+    - debian/patches-applied/CVE-2011-3149.patch
+    - debian/patches-applied/update-motd: updated to use clean environment
+      and absolute paths in modules/pam_motd/pam_motd.c.
+  * debian/libpam0g.postinst: the init script for 'samba' is now named 'smbd'
+    in Ubuntu, so fix the restart handling.
+  * debian/patches-applied/update-motd: set a sane umask before calling
+    run-parts, and restore the old mask afterwards, so /run/motd gets
+    consistent permissions.  LP: #871943.
+  * debian/patches-applied/update-motd: new module option for pam_motd,
+    'noupdate', which suppresses the call to run-parts /etc/update-motd.d.
+    LP: #805423.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Sun, 30 Oct 2011 09:45:00 -0600
+
 pam (1.1.3-5) unstable; urgency=low
 
   [ Kees Cook ]
@@ -894,6 +2299,64 @@ pam (1.1.3-3) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Sat, 24 Sep 2011 20:08:56 +0000
 
+pam (1.1.3-2ubuntu2.1) oneiric-security; urgency=low
+
+  * SECURITY UPDATE: possible code execution via incorrect environment file
+    parsing (LP: #874469)
+    - debian/patches-applied/CVE-2011-3148.patch: correctly count leading
+      whitespace when parsing environment file in modules/pam_env/pam_env.c.
+    - CVE-2011-3148
+  * SECURITY UPDATE: denial of service via overflowed environment variable
+    expansion (LP: #874565)
+    - debian/patches-applied/CVE-2011-3149.patch: when overflowing, exit
+      with PAM_BUF_ERR in modules/pam_env/pam_env.c.
+    - CVE-2011-3149
+  * SECURITY UPDATE: code execution via incorrect environment cleaning
+    - debian/patches-applied/update-motd: updated to use clean environment
+      and absolute paths in modules/pam_motd/pam_motd.c.
+    - CVE-2011-XXXX
+
+ -- Marc Deslauriers <marc.deslauriers@ubuntu.com>  Tue, 18 Oct 2011 09:33:47 -0400
+
+pam (1.1.3-2ubuntu1) oneiric; urgency=low
+
+  * Merge with Debian to get bug fix for unknown kernel rlimits. Remaining
+    changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/libpam0g.postinst: drop kdm from the list of services to
+      restart.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - debian/local/common-session{,-noninteractive}: Enable pam_umask by
+      default, now that the umask setting is gone from /etc/profile.
+    - debian/local/pam-auth-update: Add the new md5sums for pam_umask addition.
+    - add debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+      Deprecate pam_unix' explicit "usergroups" option and instead read it
+      from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined
+      there. This restores compatibility with the pre-PAM behaviour of login.
+      (Closes: #583958)
+  * Dropped changes:
+    - debian/patches-applied/027_pam_limits_better_init_allow_explicit_root:
+      no need to bump the hard limit for number of file descriptors any more
+      since we read kernel limits directly now.
+
+ -- Kees Cook <kees@ubuntu.com>  Thu, 18 Aug 2011 16:41:18 -0500
+
 pam (1.1.3-2) unstable; urgency=low
 
   [ Kees Cook ]
@@ -910,6 +2373,73 @@ pam (1.1.3-2) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Tue, 21 Jun 2011 11:41:12 -0700
 
+pam (1.1.3-1ubuntu3) oneiric; urgency=low
+
+  [ Steve Langasek ]
+  * debian/patches/pam_motd-legal-notice: use pam_modutil_gain/drop_priv
+    common helper functions, instead of hand-rolled uid-setting code.
+
+  [ Martin Pitt ]
+  * debian/local/common-session{,-noninteractive}: Enable pam_umask by
+    default, now that the umask setting is gone from /etc/profile.
+    (LP: #253096, UbuntuSpec:umask-to-0002)
+  * debian/local/pam-auth-update: Add the new md5sum of above files.
+  * Add debian/patches-applied/pam_umask_usergroups_from_login.defs.patch:
+    Deprecate pam_unix' explicit "usergroups" option and instead read it from
+    /etc/login.def's "USERGROUP_ENAB" option if umask is only defined there.
+    This restores compatibility with the pre-PAM behaviour of login.
+    (Closes: #583958)
+
+ -- Martin Pitt <martin.pitt@ubuntu.com>  Fri, 24 Jun 2011 11:07:57 +0200
+
+pam (1.1.3-1ubuntu2) oneiric; urgency=low
+
+  * debian/patches-applied/update-motd-manpage-ref: refresh patch to apply
+    cleanly against new upstream.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Sat, 04 Jun 2011 14:20:17 -0700
+
+pam (1.1.3-1ubuntu1) oneiric; urgency=low
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/027_pam_limits_better_init_allow_explicit_root:
+      bump the hard limit for number of file descriptors, to keep pace with
+      the changes in the kernel.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/libpam0g.postinst: drop kdm from the list of services to
+      restart.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - New patch, lib_security_multiarch_compat, which lets us reuse the
+      upstream --enable-isadir functionality to support a true path for
+      module lookups; this way we don't have to force a hard transition to
+      multiarch, but can support resolving modules in both the multiarch and
+      non-multiarch directories.
+    - build for multiarch, splitting our executables out of libpam-modules
+      into a new package, libpam-modules-bin, so that modules can be
+      co-installable between architectures.
+  * Dropped changes:
+    - bumping the service restart version in libpam0g.postinst to ensure
+      servers don't fail to find the pam modules in the new paths; the min
+      version requirement upstream is higher than this now.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Sat, 04 Jun 2011 14:04:19 -0700
+
 pam (1.1.3-1) unstable; urgency=low
 
   * New upstream release.
@@ -927,6 +2457,46 @@ pam (1.1.3-1) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Sat, 04 Jun 2011 03:10:50 -0700
 
+pam (1.1.2-3ubuntu1) oneiric; urgency=low
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/027_pam_limits_better_init_allow_explicit_root:
+      bump the hard limit for number of file descriptors, to keep pace with
+      the changes in the kernel.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+    - debian/libpam0g.postinst: drop kdm from the list of services to
+      restart.
+    - debian/libpam0g.postinst: check if gdm is actually running before
+      trying to reload it.
+    - New patch, lib_security_multiarch_compat, which lets us reuse the
+      upstream --enable-isadir functionality to support a true path for
+      module lookups; this way we don't have to force a hard transition to
+      multiarch, but can support resolving modules in both the multiarch and
+      non-multiarch directories.
+    - build for multiarch, splitting our executables out of libpam-modules
+      into a new package, libpam-modules-bin, so that modules can be
+      co-installable between architectures.
+    - bumping the service restart version in libpam0g.postinst to ensure
+      servers don't fail to find the pam modules in the new paths.
+  * bump debhelper build-dep for final multiarch support.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Fri, 20 May 2011 12:53:24 -0700
+
 pam (1.1.2-3) unstable; urgency=low
 
   [ Kees Cook ]
@@ -945,6 +2515,92 @@ pam (1.1.2-3) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Sun, 01 May 2011 01:49:11 -0700
 
+pam (1.1.2-2ubuntu8) natty; urgency=low
+
+  * Check if gdm is actually running before trying to reload it. (LP: #745532)
+
+ -- StÃ©phane Graber <stgraber@ubuntu.com>  Mon, 11 Apr 2011 21:57:36 -0400
+
+pam (1.1.2-2ubuntu7) natty; urgency=low
+
+  * debian/patches-applied/027_pam_limits_better_init_allow_explicit_root:
+    bump the hard limit for number of file descriptors, to keep pace with
+    the changes in the kernel.  Fortunately this shadowing should all go
+    away next cycle when we can start to grab defaults directly from /proc.
+    LP: #663090
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Tue, 05 Apr 2011 13:02:02 -0700
+
+pam (1.1.2-2ubuntu6) natty; urgency=low
+
+  * debian/libpam0g.postinst: according to Kubuntu developers, kdm no longer
+    keeps libpam loaded persistently at runtime, so it's not necessary to
+    force a kdm restart on ABI bump.  Which is good, since restarting kdm
+    now seems to also log users out of running sessions, which we rather
+    want to avoid.  LP: #744944.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Tue, 29 Mar 2011 13:16:26 -0700
+
+pam (1.1.2-2ubuntu5) natty; urgency=low
+
+  * Force a service restart on upgrade to the new libpam0g, to ensure
+    servers don't fail to find the pam modules in the new paths.
+  * libpam-modules should also Pre-Depend: on the multiarch-aware libpam0g,
+    for the same reason.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Tue, 22 Mar 2011 02:19:51 -0700
+
+pam (1.1.2-2ubuntu4) natty; urgency=low
+
+  * Build for multiarch; FFe LP: #733501.
+  * Split our executables out of libpam-modules into a new package,
+    libpam-modules-bin, so that modules can be co-installable between
+    architectures.
+  * New patch, lib_security_multiarch_compat, which lets us reuse the
+    upstream --enable-isadir functionality to support a true path for module
+    lookups; this way we don't have to force a hard transition to multiarch,
+    but can support resolving modules in both the multiarch and
+    non-multiarch directories.
+  * Build-Depend on the multiarchified debhelper.
+  * Add Pre-Depends: ${misc:Pre-Depends} for multiarch-support.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Fri, 18 Mar 2011 00:12:26 -0700
+
+pam (1.1.2-2ubuntu3) natty; urgency=low
+
+  * Er, but let's get this patch applying cleanly.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Mon, 21 Feb 2011 16:10:11 -0800
+
+pam (1.1.2-2ubuntu2) natty; urgency=low
+
+  * debian/patches/update-motd-manpage-ref: patch the manpage too, not just
+    the xml source.
+
+ -- Steve Langasek <vorlon@debian.org>  Mon, 21 Feb 2011 15:47:27 -0800
+
+pam (1.1.2-2ubuntu1) natty; urgency=low
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Thu, 17 Feb 2011 16:15:47 -0800
+
 pam (1.1.2-2) unstable; urgency=low
 
   * debian/patches-applied/hurd_no_setfsuid: handle some new calls to
@@ -1003,6 +2659,32 @@ pam (1.1.1-7) UNRELEASED; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Wed, 17 Nov 2010 16:53:46 -0800
 
+pam (1.1.1-6.1ubuntu1) natty; urgency=low
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+  * Dropped changes:
+    - libpam-modules depend on base-files (>= 5.0.0ubuntu6): 5.0.0ubuntu20
+      is in 10.04 LTS and this is an essential package, so no more need for
+      the versioned dependency.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Tue, 15 Feb 2011 23:36:47 -0800
+
 pam (1.1.1-6.1) unstable; urgency=low
 
   * Non-maintainer upload.
@@ -1040,6 +2722,38 @@ pam (1.1.1-5) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Sun, 05 Sep 2010 12:42:34 -0700
 
+pam (1.1.1-4ubuntu2) maverick-security; urgency=low
+
+  * SECURITY UPDATE: root privilege escalation via symlink following.
+    - debian/patches-applied/pam_motd-legal-notice: drop privs for work.
+    - CVE-2010-0832
+
+ -- Kees Cook <kees@ubuntu.com>  Mon, 25 Oct 2010 06:40:32 -0700
+
+pam (1.1.1-4ubuntu1) maverick; urgency=low
+
+  * Merge from Debian unstable, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's
+      not present there or in /etc/security/pam_env.conf. (should send to
+      Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - Make libpam-modules depend on base-files (>= 5.0.0ubuntu6), to ensure
+      run-parts does the right thing in /etc/update-motd.d.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent
+      showing it again.
+    - debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+      for update-motd, with some best practices and notes of explanation.
+    - debian/patches/update-motd-manpage-ref: add a reference in pam_motd(8)
+      to update-motd(5)
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Mon, 16 Aug 2010 19:12:35 -0700
+
 pam (1.1.1-4) unstable; urgency=low
 
   * debian/patches/conditional_module,_conditional_man: if we don't have the
@@ -1058,6 +2772,40 @@ pam (1.1.1-4) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Sun, 15 Aug 2010 21:53:46 -0700
 
+pam (1.1.1-3ubuntu2) maverick; urgency=low
+
+  * Trigger a rebuild, applying changes from 1.1.1-2ubuntu2 which
+    were previously not committed to bzr
+
+ -- Dustin Kirkland <kirkland@ubuntu.com>  Thu, 13 May 2010 10:04:23 +0200
+
+pam (1.1.1-3ubuntu1) maverick; urgency=low
+
+  * Merge from Debian, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - Make libpam-modules depend on base-files (>= 5.0.0ubuntu6), to ensure
+      run-parts does the right thing in /etc/update-motd.d.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent showing
+      it again.
+  * Dropped changes:
+    - debian/local/common-{auth,account,password}.md5sums: include the
+      Ubuntu-specific intrepid,jaunty md5sums for use during the
+      common-session-noninteractive upgrade - upgrades to maverick are
+      only supported from lucid, so this delta can be dropped.
+    - debian/patches-applied/ubuntu-no-error-if-missingok: 'missingok' option
+      is obsoleted by 10.04 LTS and no longer needs to be supported for
+      upgrades.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Thu, 13 May 2010 00:39:44 +0200
+
 pam (1.1.1-3) unstable; urgency=low
 
   * pam-auth-update: fix a bug in our handling of module options when the
@@ -1068,6 +2816,41 @@ pam (1.1.1-3) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Sun, 25 Apr 2010 05:53:44 -0700
 
+pam (1.1.1-2ubuntu2) lucid; urgency=low
+
+  * debian/update-motd.5, debian/libpam-modules.manpages: add a manpage
+    for update-motd, with some best practices and notes of explanation,
+    LP: #562566
+  * debian/patches/update-motd-manpage-ref: add a reference in pam_mod(8)
+    to update-motd(5), LP: #552175
+
+ -- Dustin Kirkland <kirkland@ubuntu.com>  Tue, 13 Apr 2010 16:58:12 -0500
+
+pam (1.1.1-2ubuntu1) lucid; urgency=low
+
+  * Merge from Debian, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - Make libpam-modules depend on base-files (>= 5.0.0ubuntu6), to ensure
+      run-parts does the right thing in /etc/update-motd.d.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent showing
+      it again.
+    - debian/local/common-{auth,account,password}.md5sums: include the
+      Ubuntu-specific intrepid,jaunty md5sums for use during the
+      common-session-noninteractive upgrade.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Thu, 18 Feb 2010 12:04:18 +0000
+
 pam (1.1.1-2) unstable; urgency=low
 
   * Document the new symbols added in 1.1.1 in debian/libpam0g.symbols, and
@@ -1076,6 +2859,31 @@ pam (1.1.1-2) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Wed, 17 Feb 2010 23:21:23 -0800
 
+pam (1.1.1-1ubuntu1) lucid; urgency=low
+
+  * Merge from Debian, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - Make libpam-modules depend on base-files (>= 5.0.0ubuntu6), to ensure
+      run-parts does the right thing in /etc/update-motd.d.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent showing
+      it again.
+    - debian/local/common-{auth,account,password}.md5sums: include the
+      Ubuntu-specific intrepid,jaunty md5sums for use during the
+      common-session-noninteractive upgrade.
+
+ -- Steve Langasek <vorlon@debian.org>  Mon, 01 Feb 2010 09:55:02 -0800
+
 pam (1.1.1-1) unstable; urgency=low
 
   * New upstream version.
@@ -1103,6 +2911,47 @@ pam (1.1.1-1) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Mon, 01 Feb 2010 02:04:33 -0800
 
+pam (1.1.0-4ubuntu3) lucid; urgency=low
+
+  * Brown paper bag: remove the right patch from the series file.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Thu, 10 Dec 2009 23:09:03 -0800
+
+pam (1.1.0-4ubuntu2) lucid; urgency=low
+
+  * "Rebase" Ubuntu patches to apply them last in the series.
+  * Drop patch ubuntu-regression_fix_securetty, superseded by the more
+    precise fix in pam_securetty_tty_check_before_user_check.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Thu, 10 Dec 2009 22:52:20 -0800
+
+pam (1.1.0-4ubuntu1) lucid; urgency=low
+
+  * Merge from Debian, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-regression_fix_securetty: prompt for
+      password on bad username.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - Make libpam-modules depend on base-files (>= 5.0.0ubuntu6), to ensure
+      run-parts does the right thing in /etc/update-motd.d.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent showing
+      it again.
+    - debian/local/common-{auth,account,password}.md5sums: include the
+      Ubuntu-specific intrepid,jaunty md5sums for use during the
+      common-session-noninteractive upgrade.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Thu, 05 Nov 2009 21:33:15 -0800
+
 pam (1.1.0-4) unstable; urgency=low
 
   * debian/patches/pam_securetty_tty_check_before_user_check: new patch,
@@ -1152,6 +3001,36 @@ pam (1.1.0-3) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Mon, 07 Sep 2009 18:47:45 -0700
 
+pam (1.1.0-2ubuntu1) karmic; urgency=low
+
+  * Merge from Debian, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-regression_fix_securetty: prompt for
+      password on bad username.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - Make libpam-modules depend on base-files (>= 5.0.0ubuntu6), to ensure
+      run-parts does the right thing in /etc/update-motd.d.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent showing
+      it again.
+    - debian/local/common-{auth,account,password}.md5sums: include the
+      Ubuntu-specific intrepid,jaunty md5sums for use during the
+      common-session-noninteractive upgrade.
+  * Changes merged in Debian:
+    - debian/local/common-password, debian/pam-configs/unix: switch from
+      "md5" to "sha512" as password crypt default.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Fri, 04 Sep 2009 01:11:48 -0700
+
 pam (1.1.0-2) unstable; urgency=low
 
   [ Steve Langasek ]
@@ -1180,6 +3059,41 @@ pam (1.1.0-2) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Mon, 31 Aug 2009 14:21:27 -0700
 
+pam (1.1.0-1ubuntu1) karmic; urgency=low
+
+  * Merge from Debian, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-regression_fix_securetty: prompt for
+      password on bad username.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/local/common-password, debian/pam-configs/unix: switch from
+      "md5" to "sha512" as password crypt default.
+    - Make libpam-modules depend on base-files (>= 5.0.0ubuntu6), to ensure
+      run-parts does the right thing in /etc/update-motd.d.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent showing
+      it again.
+    - debian/local/common-{auth,account,password}.md5sums: include the
+      Ubuntu-specific intrepid,jaunty md5sums for use during the
+      common-session-noninteractive upgrade.
+  * Dropped changes, superseded upstream:
+    - debian/patches-applied/ubuntu-fix_standard_types: Use standard u_int8_t
+      type rather than __u8.
+    - debian/patches-applied/ubuntu-user_defined_environment: Look at
+      ~/.pam_environment too, with the same format as
+      /etc/security/pam_env.conf.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 26 Aug 2009 00:40:14 -0700
+
 pam (1.1.0-1) unstable; urgency=low
 
   * New upstream version.
@@ -1223,6 +3137,42 @@ pam (1.1.0-1) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Tue, 25 Aug 2009 20:35:26 -0700
 
+pam (1.0.1-11ubuntu1) karmic; urgency=low
+
+  * Merge from Debian, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-fix_standard_types: Use standard u_int8_t
+      type rather than __u8.
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-regression_fix_securetty: prompt for
+      password on bad username.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/ubuntu-user_defined_environment: Look at
+      ~/.pam_environment too, with the same format as
+      /etc/security/pam_env.conf.  (Originally patch 100; converted to quilt.)
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/local/common-password, debian/pam-configs/unix: switch from
+      "md5" to "sha512" as password crypt default.
+    - Make libpam-modules depend on base-files (>= 5.0.0ubuntu6), to ensure
+      run-parts does the right thing in /etc/update-motd.d.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent showing
+      it again.
+  * debian/local/pam-auth-update: prune some more md5sums from intrepid
+    pre-release versions, reducing the Ubuntu delta some
+  * debian/local/common-{auth,account,password}.md5sums: include the
+    Ubuntu-specific intrepid,jaunty md5sums for use during the
+    common-session-noninteractive upgrade.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Sun, 23 Aug 2009 20:14:58 -0700
+
 pam (1.0.1-11) unstable; urgency=low
 
   * debian/libpam-runtime.postinst: bump the --force version check to
@@ -1250,6 +3200,37 @@ pam (1.0.1-11) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Sun, 23 Aug 2009 18:07:11 -0700
 
+pam (1.0.1-10ubuntu1) karmic; urgency=low
+
+  * Merge from Debian, remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-fix_standard_types: Use standard u_int8_t
+      type rather than __u8.
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-regression_fix_securetty: prompt for
+      password on bad username.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/ubuntu-user_defined_environment: Look at
+      ~/.pam_environment too, with the same format as
+      /etc/security/pam_env.conf.  (Originally patch 100; converted to quilt.)
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/local/common-password, debian/pam-configs/unix: switch from
+      "md5" to "sha512" as password crypt default.
+    - Make libpam-modules depend on base-files (>= 5.0.0ubuntu6), to ensure
+      run-parts does the right thing in /etc/update-motd.d.
+    - debian/patches-applied/pam_motd-legal-notice: display the contents of
+      /etc/legal once, then set a flag in the user's homedir to prevent showing
+      it again.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Fri, 07 Aug 2009 09:50:02 +0100
+
 pam (1.0.1-10) unstable; urgency=high
 
   [ Steve Langasek ]
@@ -1286,6 +3267,51 @@ pam (1.0.1-10) unstable; urgency=high
 
  -- Steve Langasek <vorlon@debian.org>  Thu, 06 Aug 2009 17:54:32 +0100
 
+pam (1.0.1-9ubuntu3) karmic; urgency=low
+
+  * Make libpam-modules depend on base-files (>= 5.0.0ubuntu6), to ensure
+    run-parts does the right thing in /etc/update-motd.d.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 15 Jul 2009 23:55:50 -0700
+
+pam (1.0.1-9ubuntu2) karmic; urgency=low
+
+  [ Dustin Kirkland ]
+  * debian/patches/update-motd: run the update-motd scripts in pam_motd;
+    render update-motd obsolete, LP: #399071
+  * debian/patches-applied/pam_motd-legal-notice: display the contents of
+    /etc/legal once, then set a flag in the user's homedir to prevent showing
+    it again.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 15 Jul 2009 20:41:52 -0700
+
+pam (1.0.1-9ubuntu1) jaunty; urgency=low
+
+  * Merge from Debian unstable
+  * Remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-fix_standard_types: Use standard u_int8_t
+      type rather than __u8.
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-regression_fix_securetty: prompt for
+      password on bad username.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/ubuntu-user_defined_environment: Look at
+      ~/.pam_environment too, with the same format as
+      /etc/security/pam_env.conf.  (Originally patch 100; converted to quilt.)
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/local/common-password, debian/pam-configs/unix: switch from
+      "md5" to "sha512" as password crypt default.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Fri, 20 Mar 2009 19:12:10 -0700
+
 pam (1.0.1-9) unstable; urgency=low
 
   * Move the pam module packages to section 'admin'.
@@ -1319,6 +3345,56 @@ pam (1.0.1-8) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Fri, 20 Mar 2009 18:15:07 -0700
 
+pam (1.0.1-7ubuntu1) jaunty; urgency=low
+
+  * Merge from Debian unstable
+  * Remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-fix_standard_types: Use standard u_int8_t
+      type rather than __u8.
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-regression_fix_securetty: prompt for
+      password on bad username.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/ubuntu-user_defined_environment: Look at
+      ~/.pam_environment too, with the same format as
+      /etc/security/pam_env.conf.  (Originally patch 100; converted to quilt.)
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/local/common-password, debian/pam-configs/unix: switch from
+      "md5" to "sha512" as password crypt default.
+  * Dropped changes, merged in Debian:
+    - debian/local/pam-auth-update (et al): new interface for managing
+      /etc/pam.d/common-*, using drop-in config snippets provided by module
+      packages.
+    - New patch dont_freeze_password_chain, cherry-picked from upstream:
+      don't always follow the same path through the password stack on
+      the PAM_UPDATE_AUTHTOK pass as was used in the PAM_PRELIM_CHECK
+      pass; this Linux-PAM deviation from the original PAM spec causes a
+      number of problems, in particular causing wrong return values when
+      using the refactored pam-auth-update stack.  LP: #303515, #305882.
+    - debian/patches/027_pam_limits_better_init_allow_explicit_root:
+      Add documentation to the patch showing how to set limits for root.
+  * Bump the libpam-cracklib dependency on libpam-runtime to 1.0.1-6,
+    reducing the delta with Debian.
+  * Drop upgrade handling code from libpam-runtime.postinst that's only
+    needed when upgrading from 1.0.1-2ubuntu1, a superseded intrepid
+    pre-release version of the package.
+  * pam-auth-update: swap out known md5sums from intrepid pre-release versions
+    with the md5sums from the released intrepid version
+  * pam-auth-update: drop some md5sums that will only be seen on upgrade from
+    pre-intrepid versions; skipping over the 8.10 final release is not
+    supported, and upgrading via 8.10 means those config files will be
+    replaced so the old md5sums will never be seen again.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Tue, 03 Mar 2009 17:34:19 -0800
+
 pam (1.0.1-7) unstable; urgency=low
 
   * 027_pam_limits_better_init_allow_explicit_root:
@@ -1353,6 +3429,67 @@ pam (1.0.1-6) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Sat, 28 Feb 2009 13:36:57 -0800
 
+pam (1.0.1-5ubuntu2) jaunty; urgency=low
+
+  * New patch dont_freeze_password_chain, cherry-picked from upstream:
+    don't always follow the same path through the password stack on
+    the PAM_UPDATE_AUTHTOK pass as was used in the PAM_PRELIM_CHECK
+    pass; this Linux-PAM deviation from the original PAM spec causes a
+    number of problems, in particular causing wrong return values when
+    using the refactored pam-auth-update stack.  LP: #303515, #305882.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Fri, 27 Feb 2009 16:20:24 -0800
+
+pam (1.0.1-5ubuntu1) jaunty; urgency=low
+
+  * Merge from Debian unstable
+  * Remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-fix_standard_types: Use standard u_int8_t
+      type rather than __u8.
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-regression_fix_securetty: prompt for
+      password on bad username.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/ubuntu-user_defined_environment: Look at
+      ~/.pam_environment too, with the same format as
+      /etc/security/pam_env.conf.  (Originally patch 100; converted to quilt.)
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/local/pam-auth-update (et al): new interface for managing
+      /etc/pam.d/common-*, using drop-in config snippets provided by module
+      packages.
+    - debian/local/common-password, debian/pam-configs/unix: switch from
+      "md5" to "sha512" as password crypt default.
+  * Bump the version numbers referenced in the config files, again, as pam
+    has revved in Debian and moved the bar.
+  * pam-auth-update: If /var/lib/pam/seen is absent, treat this the same
+    as a present but empty file; thanks to Greg Price for the patch.
+    LP: #294513.
+  * pam-auth-update: Ignore removed profiles when detecting an empty set
+    of currently-enabled modules.  Thanks to Greg Price for this as well.
+  * debian/control: libpam-runtime needs a versioned dependency on
+    debconf, because it uses the x_loadtemplatefile extension that's 
+    not supported by debconf versions before hardy.  LP: #295135.
+  * pam-auth-update: trim leading whitespace from multiline fields when
+    parsing PAM profiles.  LP: #295441.
+  * pam-auth-update: factor out the duplicate code used for returning
+    the lines for a given module
+
+  [ Jonathan Marsden ]
+  * debian/patches/027_pam_limits_better_init_allow_explicit_root:
+    Add to patch, documenting how to set limits for root user.
+    Include an example.  Alters limits.conf, limits.conf.5.xml,
+    and limits.conf.5 .  (LP: #65244)
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Thu, 08 Jan 2009 20:26:25 +0000
+
 pam (1.0.1-5) unstable; urgency=low
 
   * Build-conflict with libxcrypt-dev, which otherwise pulls libxcrypt in as
@@ -1388,6 +3525,111 @@ pam (1.0.1-5) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Tue, 06 Jan 2009 00:05:13 -0800
 
+pam (1.0.1-4ubuntu5.4) jaunty; urgency=low
+
+  * No-change upload to jaunty to fix publication on armel.
+
+ -- Colin Watson <cjwatson@ubuntu.com>  Tue, 18 Nov 2008 14:09:00 +0000
+
+pam (1.0.1-4ubuntu5.3) intrepid-updates; urgency=low
+
+  * No-change upload of 1.0.1-4ubuntu5.1 to -updates. -proposed package was
+    copied while some ports were not built yet.
+
+ -- Martin Pitt <martin.pitt@ubuntu.com>  Tue, 11 Nov 2008 14:50:12 +0100
+
+pam (1.0.1-4ubuntu5.2) intrepid-proposed; urgency=low
+
+  * No-change rebuild because the archive admin (me) copied the package
+    to jaunty too soon.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 05 Nov 2008 20:28:11 +0000
+
+pam (1.0.1-4ubuntu5.1) intrepid-proposed; urgency=low
+
+  * Allow passwords to change on expired accounts, by passing
+    new_authtok_reqd return codes immediately (LP: #291091).
+
+ -- Kees Cook <kees@ubuntu.com>  Wed, 05 Nov 2008 09:31:45 -0800
+
+pam (1.0.1-4ubuntu5) intrepid; urgency=low
+
+  * debian/libpam0g.postinst: change 'cupsys' to 'cups' in the list of
+    default desktop services that are ignored in deciding whether to prompt
+    for service restarts on upgrade.  Partially addresses LP #278117.
+  * debian/libpam0g.postinst: also filter out samba, which may be installed
+    on the desktop to enable filesharing.
+  * debian/libpam-cracklib.prerm, debian/libpam-runtime.prerm: add the
+    ubiquitous debhelper tokens (currently a no-op)
+  * pam-auth-update: Use -Initial only for the first profile, even when
+    there's no explicit -Initial config for that first profile
+  * fix common-session/common-password to use the same overall stack
+    structure as auth/account, so that we get the correct behavior when
+    all password modules fail.  LP: #272232.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 15 Oct 2008 18:11:13 -0700
+
+pam (1.0.1-4ubuntu4) intrepid; urgency=low
+
+  * Fix a bug in the parser that caused spewing of errors when there
+    were more lines in the config file following the managed block.
+    LP: #270328.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Tue, 23 Sep 2008 06:34:56 +0000
+
+pam (1.0.1-4ubuntu3) intrepid; urgency=low
+
+  * Fix up the code that saves state to /var/lib/pam, so that it matches
+    what's expected by the code which later compares the saved and active
+    profiles in the case that there are both primary and additional
+    modules present.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Tue, 16 Sep 2008 06:49:56 +0000
+
+pam (1.0.1-4ubuntu2) intrepid; urgency=low
+
+  * Brown paper bag bug: fix a missing comma in pam-auth-update.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Sat, 13 Sep 2008 08:55:32 +0000
+
+pam (1.0.1-4ubuntu1) intrepid; urgency=low
+
+  * Merge from Debian unstable
+  * Remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-fix_standard_types: Use standard u_int8_t
+      type rather than __u8.
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-regression_fix_securetty: prompt for
+      password on bad username.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/ubuntu-user_defined_environment: Look at
+      ~/.pam_environment too, with the same format as
+      /etc/security/pam_env.conf.  (Originally patch 100; converted to quilt.)
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/local/pam-auth-update (et al): new interface for managing
+      /etc/pam.d/common-*, using drop-in config snippets provided by module
+      packages.
+    - debian/local/common-password, debian/pam-configs/unix: switch from
+      "md5" to "sha512" as password crypt default.
+  * Bump the version numbers referenced in the config files, again, as pam
+    has revved in Debian and moved the bar.
+  * debian/pam-config/*: refine the password profiles to use a 'primary'
+    block, to better parallel the auth structure.
+  * Drop '-Final' from the field names in /usr/share/pam-configs, supporting
+    these field names for backwards compatibility only
+  * Bump the dependency version requirement to 1.0.1-4ubuntu1 for the above
+    change
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Sat, 13 Sep 2008 08:55:19 +0000
+
 pam (1.0.1-4) unstable; urgency=high
 
   * High-urgency upload for RC bugfix.
@@ -1410,6 +3652,88 @@ pam (1.0.1-4) unstable; urgency=high
 
  -- Steve Langasek <vorlon@debian.org>  Thu, 28 Aug 2008 22:59:23 -0700
 
+pam (1.0.1-3ubuntu5) intrepid; urgency=low
+
+  [ Steve Langasek ]
+  * Never remove the .pam-old files; just avoid creating them if --force isn't
+    set.
+  * Add a manpage for pam-auth-update.
+  * Automatically upgrade the boilerplate for /etc/pam.d/common-* if we
+    detect that they have not been locally modified.
+
+  [ Kees Cook ]
+  * debian/local/common-password, debian/pam-configs/unix: switch from "md5"
+    to "sha512" as password crypt default.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Tue, 26 Aug 2008 06:33:07 +0000
+
+pam (1.0.1-3ubuntu4) intrepid; urgency=low
+
+  * If two profiles have the same Priority, sort by the profile name to
+    ensure a complete sort so we can filter out all the duplicates from the
+    list and not write out broken configs.  LP: #260371.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Fri, 22 Aug 2008 17:33:14 +0000
+
+pam (1.0.1-3ubuntu3) intrepid; urgency=low
+
+  * s/pam-auth-config/pam-auth-update/ in the source, I can't seem to get
+    this name consistent to save my life - I'm starting to think I named it
+    wrong...
+  * Fix the regex used when suppressing jump counts when reading the saved
+    config, so that we don't clobber module options with numbers in them.
+  * If the target doesn't already exist, don't try to copy it.
+  * Filter the config list to exclude configs that no longer exist.
+    LP: #260122.
+  * Avoid unnecessary sort/grep in the case where we already have a sorted
+    list.
+  * Implement pam-auth-update --remove, for use in package prerms when called
+    with "remove".
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Thu, 21 Aug 2008 15:38:37 -0700
+
+pam (1.0.1-3ubuntu2) intrepid; urgency=high
+
+  * debian/local/common-session: the session stack needs to be handled the
+    same way as the password stack, with the possibility of zero primary
+    modules; required to fix build failures on the Ubuntu buildds due to
+    su not being able to open sessions by default.  LP: #259867.
+  * debian/libpam-runtime.postinst: when upgrading from the broken
+    1.0.1-2ubuntu1 version, manually edit /etc/pam.d/common-session to
+    recover.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 20 Aug 2008 13:27:10 -0700
+
+pam (1.0.1-3ubuntu1) intrepid; urgency=low
+
+  * Merge from Debian unstable
+  * Remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-fix_standard_types: Use standard u_int8_t
+      type rather than __u8.
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-regression_fix_securetty: prompt for
+      password on bad username.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/ubuntu-user_defined_environment: Look at
+      ~/.pam_environment too, with the same format as
+      /etc/security/pam_env.conf.  (Originally patch 100; converted to quilt.)
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+    - debian/local/pam-auth-update (et al): new interface for managing
+      /etc/pam.d/common-*, using drop-in config snippets provided by module
+      packages.
+  * Remove spurious 'conflict' with a non-existent module, which was added
+    just as an example
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 20 Aug 2008 11:58:35 -0700
+
 pam (1.0.1-3) unstable; urgency=high
 
   * 055_pam_unix_nullok_secure: don't call _pammodutil_tty_secure with a NULL
@@ -1419,6 +3743,40 @@ pam (1.0.1-3) unstable; urgency=high
 
  -- Steve Langasek <vorlon@debian.org>  Wed, 20 Aug 2008 11:55:47 -0700
 
+pam (1.0.1-2ubuntu1) intrepid; urgency=low
+
+  * Merge from Debian unstable
+  * Remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam-runtime.postinst,
+      debian/local/common-{auth,password}{,.md5sums}:
+      Use the new 'missingok' option by default for pam_smbpass in case
+      libpam-smbpass is not installed (LP: #216990); must use "requisite"
+      rather than "required" to prevent "pam_smbpass migrate" from firing in
+      the event of an auth failure; md5sums updated accordingly.
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-fix_standard_types: Use standard u_int8_t
+      type rather than __u8.
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-regression_fix_securetty: prompt for
+      password on bad username.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/ubuntu-user_defined_environment: Look at
+      ~/.pam_environment too, with the same format as
+      /etc/security/pam_env.conf.  (Originally patch 100; converted to quilt.)
+    - Change Vcs-Bzr to point at the Ubuntu branch.
+  * debian/local/pam-auth-update (et al): new interface for managing
+    /etc/pam.d/common-*, using drop-in config snippets provided by module
+    packages.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 20 Aug 2008 09:17:28 +0000
+
 pam (1.0.1-2) unstable; urgency=low
 
   * 007_modules_pam_unix: update the documentation to correctly document
@@ -1443,6 +3801,49 @@ pam (1.0.1-2) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Fri, 08 Aug 2008 10:47:26 -0700
 
+pam (1.0.1-1ubuntu1) intrepid; urgency=low
+
+  * Merge from Debian unstable
+  * Dropped changes:
+    - Linux-PAM/modules/pam_selinux/pam_selinux.8: Ubuntu pam_selinux manpage
+      is 2 years newer than Debian's, contains a number of character escaping
+      fixes plus content updates
+    - debian/patches-applied/ubuntu-pam_selinux_seusers: patch pam_selinux to
+      correctly support seusers (backported from changes in PAM 0.99.8).  
+    - debian/rules: install unix_chkpwd setgid shadow instead of setuid root.
+      The nis package handles overriding this as necessary.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Bound RLIMIT_NICE
+      from below as well as from above. Fix off-by-one error when converting
+      RLIMIT_NICE to the range of values used by the kernel.
+  * Remaining changes:
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf. (should send to Debian).
+    - debian/libpam-runtime.postinst,
+      debian/local/common-{auth,password}{,.md5sums}:
+      Use the new 'missingok' option by default for pam_smbpass in case
+      libpam-smbpass is not installed (LP: #216990); must use "requisite"
+      rather than "required" to prevent "pam_smbpass migrate" from firing in
+      the event of an auth failure; md5sums updated accordingly.
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running.
+    - debian/patches-applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-fix_standard_types: Use standard u_int8_t
+      type rather than __u8.
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-regression_fix_securetty: prompt for
+      password on bad username.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits.
+    - debian/patches-applied/ubuntu-user_defined_environment: Look at
+      ~/.pam_environment too, with the same format as
+      /etc/security/pam_env.conf.  (Originally patch 100; converted to quilt.)
+  * Refresh patch ubuntu-no-error-if-missingok for the new upstream version.
+  * Change Vcs-Bzr to point at the new Ubuntu branch.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Mon, 28 Jul 2008 20:58:26 +0000
+
 pam (1.0.1-1) unstable; urgency=low
 
   * New upstream version.
@@ -1558,6 +3959,69 @@ pam (0.99.7.1-7) unstable; urgency=mediu
 
  -- Steve Langasek <vorlon@debian.org>  Mon, 21 Jul 2008 11:49:59 -0700
 
+pam (0.99.7.1-6ubuntu2) intrepid; urgency=low
+
+  * debian/libpam-modules.postinst: revert addition of ~/bin to the end of the
+    default PATH set in /etc/environment as it was pointed out by Colin
+    Watson that getenv() does not properly expand '~'
+
+ -- Jamie Strandboge <jamie@ubuntu.com>  Tue, 24 Jun 2008 06:29:40 -0400
+
+pam (0.99.7.1-6ubuntu1) intrepid; urgency=low
+
+  * Merge from debian unstable
+  * Dropped changes:
+    - Linux-PAM/modules/pam_limits/README,
+      Linux-PAM/modules/pam_selinux/README: Ubuntu versions had some
+      insignificant character differences, dropping in favor of Debian
+      versions; pam_selinux documentation has dropped "multiple", and added
+      "select_context", and "use_current_range" as options.
+    - debian/control, debian/local/common-session{,md5sums}: use
+      libpam-foreground for session management.
+    - Build using db4.5 instead of db4.6.
+  * Remaining changes:
+    - Linux-PAM/modules/pam_selinux/pam_selinux.8: Ubuntu pam_selinux manpage
+      is 2 years newer than Debian's, contains a number of character escaping
+      fixes plus content updates; (should send to Debian).
+    - debian/control: Maintainer updated.
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf; add ~/bin to PATH
+      (LP: #64064); (should send to Debian).
+    - debian/libpam-runtime.postinst,
+      debian/local/common-{auth,password}{,.md5sums}:
+      Use the new 'missingok' option by default for pam_smbpass in case
+      libpam-smbpass is not installed (LP: #216990); must use "requisite"
+      rather than "required" to prevent "pam_smbpass migrate" from firing in
+      the event of an auth failure; md5sums updated accordingly.
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running (LP: #141309).
+    - debian/applied/series: Ubuntu patches are as below ...
+    - debian/patches-applied/ubuntu-fix_standard_types: Use standard u_int8_t
+      type rather than __u8.
+    - debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+      module option 'missingok' which will suppress logging of errors by
+      libpam if the module is not found.
+    - debian/patches-applied/ubuntu-pam_selinux_seusers: patch pam_selinux to
+      correctly support seusers (backported from changes in PAM 0.99.8).  
+      Without this patch login will not get correct security context when 
+      using libselinux >= 1.27.2 (LP: #187822).
+    - debian/patches-applied/ubuntu-regression_fix_securetty: securetty's
+      earlier behavior would correctly prompt for password on bad usernames
+      (LP: #139075).
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits. Bound
+      RLIMIT_NICE from below as well as from above. Fix off-by-one error when
+      converting RLIMIT_NICE to the range of values used by the kernel.
+    - debian/patches-applied/ubuntu-user_defined_environment: Look at
+      ~/.pam_environment too, with the same format as
+      /etc/security/pam_env.conf.  (Originally patch 100; converted to quilt.)
+    - debian/rules: install unix_chkpwd setgid shadow instead of setuid root.
+      The nis package handles overriding this as necessary.
+  * Alphabetized this merge changelog entry by filename (easier reading
+    against Ubuntu patch).
+
+ -- Dustin Kirkland <kirkland@ubuntu.com>  Fri, 20 Jun 2008 10:32:00 -0500
+
 pam (0.99.7.1-6) unstable; urgency=low
 
   * Debconf translations:
@@ -1584,6 +4048,98 @@ pam (0.99.7.1-6) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Sun, 16 Mar 2008 02:06:28 -0700
 
+pam (0.99.7.1-5ubuntu8) intrepid; urgency=low
+
+  * debian/libpam-modules.postinst: Add ~/bin to the end of the default PATH
+    set in /etc/environment (LP: #64064).
+
+ -- Dustin Kirkland <kirkland@ubuntu.com>  Thu, 19 Jun 2008 12:52:48 -0500
+
+pam (0.99.7.1-5ubuntu7) intrepid; urgency=low
+
+  * debian/patches-applied/ubuntu-no-error-if-missingok: add a new, magic
+    module option 'missingok' which will suppress logging of errors by
+    libpam if the module is not found.
+  * debian/local/common-{auth,password}, debian/libpam-runtime.postinst:
+    Use the new 'missingok' option by default for pam_smbpass, to
+    correct the problem of very loud logging introduced in the previous
+    upload when libpam-smbpass is not installed.  LP: #216990.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Tue, 22 Apr 2008 18:53:37 +0000
+
+pam (0.99.7.1-5ubuntu6) hardy; urgency=low
+
+  * debian/local/common-{auth,password}, debian/libpam-runtime.postinst:
+    Add pam_smbpass as an optional module in the stack, to keep NTLM
+    passwords (for filesharing) in sync with the main system passwords on a
+    best-effort basis.  LP: #208419.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Tue, 08 Apr 2008 18:21:40 +0000
+
+pam (0.99.7.1-5ubuntu5) hardy; urgency=low
+
+  * debian/local/common-session: Drop libpam-foreground. It's gone for good,
+    and we do not want this in the PAM config for new installations, since it
+    just spams syslog with error messages. (LP: #198714)
+
+ -- Martin Pitt <martin.pitt@ubuntu.com>  Tue, 11 Mar 2008 11:22:11 +0100
+
+pam (0.99.7.1-5ubuntu4) hardy; urgency=low
+
+  * ubuntu-pam_selinux_seusers: patch pam_selinux to correctly support
+    seusers (backported from changes in PAM 0.99.8).  Without this patch
+    login will not get correct security context when using libselinux
+    >= 1.27.2 (LP: #187822).
+
+ -- Caleb Case <ccase@tresys.com>  Wed, 30 Jan 2008 06:39:48 -0500
+
+pam (0.99.7.1-5ubuntu3) hardy; urgency=low
+
+  * Temporarily reenable libpam-foreground in common-session again, until
+    dbus' at_console policy works with ConsoleKit.
+
+ -- Martin Pitt <martin.pitt@ubuntu.com>  Thu, 29 Nov 2007 15:17:54 +0100
+
+pam (0.99.7.1-5ubuntu2) hardy; urgency=low
+
+  * debian/local/common-session{,.md5sums}, debian/control: Drop
+    libpam-foreground, superseded by ConsoleKit integration into hal.
+  * debian/control: Build against libdb4.6 again. This drops this Debian delta
+    and 4.6 is our target version in Hardy.
+
+ -- Martin Pitt <martin.pitt@ubuntu.com>  Thu, 22 Nov 2007 18:56:47 +0100
+
+pam (0.99.7.1-5ubuntu1) gutsy; urgency=low
+
+  * Resynchronise with Debian. Remaining changes:
+    - debian/control, debian/local/common-session{,md5sums}: use
+      libpam-foreground for session management.
+    - debian/rules: install unix_chkpwd setgid shadow instead of setuid root.
+      The nis package handles overriding this as necessary.
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf.
+    - debian/patches-applied/ubuntu-fix_standard_types: Use standard u_int8_t
+      type rather than __u8.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits. Bound
+      RLIMIT_NICE from below as well as from above. Fix off-by-one error when
+      converting RLIMIT_NICE to the range of values used by the kernel.
+      (Originally patch 101; converted to quilt.)
+    - debian/patches-applied/ubuntu-user_defined_environment: Look at
+      ~/.pam_environment too, with the same format as
+      /etc/security/pam_env.conf.  (Originally patch 100; converted to quilt.)
+    - debian/patches-applied/ubuntu-regression_fix_securetty: securetty's
+      earlier behavior would correctly prompt for password on bad usernames
+      (LP: #139075).
+    - Build using db4.5 instead of db4.6.
+    - debian/libpam0g.postinst: only ask questions during update-manager when
+      there are non-default services running (LP: #141309).
+  * debian/libpam0g.postinst: don't display a debconf warning about display
+    managers that need restarting when update-manager is running, instead
+    signal to update-notifier if a reboot is required.
+
+ -- Steve Langasek <vorlon@debian.org>  Fri, 28 Sep 2007 23:45:24 -0700
+
 pam (0.99.7.1-5) unstable; urgency=low
 
   * More lintian overrides, related to debconf prompting in the postinst
@@ -1628,6 +4184,55 @@ pam (0.99.7.1-5) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Fri, 28 Sep 2007 00:17:00 -0700
 
+pam (0.99.7.1-4ubuntu4) gutsy; urgency=low
+
+  * debian/libpam0g.postinst: call "reload" for all display managers
+    (LP: #139065).
+  * debian/libpam0g.postinst: only ask questions during update-manager when
+    there are non-default services running (LP: #141309).
+
+ -- Kees Cook <kees@ubuntu.com>  Mon, 24 Sep 2007 15:01:29 -0700
+
+pam (0.99.7.1-4ubuntu3) gutsy; urgency=low
+
+  * ubuntu-regression_fix_securetty: securetty's earlier behavior would
+    correctly prompt for password on bad usernames (LP: #139075).
+
+ -- Kees Cook <kees@ubuntu.com>  Wed, 12 Sep 2007 15:20:09 -0700
+
+pam (0.99.7.1-4ubuntu2) gutsy; urgency=low
+
+  * Build using db4.5 (instead of db4.6).  One db4.x version less on the CD.
+
+ -- Matthias Klose <doko@ubuntu.com>  Wed, 12 Sep 2007 17:44:25 +0200
+
+pam (0.99.7.1-4ubuntu1) gutsy; urgency=low
+
+  * Resynchronise with Debian (LP: #43169, #14505, #80431). Remaining changes:
+    - debian/control, debian/local/common-session{,md5sums}: use
+      libpam-foreground for session management.
+    - debian/rules: install unix_chkpwd setgid shadow instead of setuid root.
+      The nis package handles overriding this as necessary.
+    - debian/libpam-modules.postinst: Add PATH to /etc/environment if it's not
+      present there or in /etc/security/pam_env.conf.
+    - debian/patches-applied/ubuntu-fix_standard_types: Use standard u_int8_t
+      type rather than __u8.
+    - debian/patches-applied/ubuntu-rlimit_nice_correction: Explicitly
+      initialise RLIMIT_NICE rather than relying on the kernel limits. Bound
+      RLIMIT_NICE from below as well as from above. Fix off-by-one error when
+      converting RLIMIT_NICE to the range of values used by the kernel.
+      (Originally patch 101; converted to quilt.)
+    - debian/patches-applied/ubuntu-user_defined_environment: Look at
+      ~/.pam_environment too, with the same format as
+      /etc/security/pam_env.conf.  (Originally patch 100; converted to quilt.)
+  * Dropped:
+    - debian/rules: bashism fixes (merged upstream).
+    - debian/control: Conflict on ancient nis (expired with Breezy).
+    - debian/libpam-runtime.postinst: check for ancient pam (expired with
+      Breezy).
+
+ -- Kees Cook <kees@ubuntu.com>  Wed, 05 Sep 2007 15:18:36 -0700
+
 pam (0.99.7.1-4) unstable; urgency=low
 
   * libpam0g.postinst, libpam0g.templates: gdm doesn't need to be restarted
@@ -1874,6 +4479,32 @@ pam (0.99.7.1-2) unstable; urgency=low
 
  -- Steve Langasek <vorlon@debian.org>  Sun, 26 Aug 2007 19:15:09 -0700
 
+pam (0.79-4ubuntu2) feisty; urgency=low
+
+  * Remove /usr/bin/X11 from default PATH (new installs only).
+
+ -- Colin Watson <cjwatson@ubuntu.com>  Wed, 20 Dec 2006 16:14:37 +0000
+
+pam (0.79-4ubuntu1) feisty; urgency=low
+
+  * Resynchronise with Debian. Remaining changes:
+    - Patch 100 (renumbered from 060): Look at ~/.pam_environment too, with
+      the same format as /etc/security/pam_env.conf.
+    - Patch 101 (renumbered from 061): Explicitly initialise RLIMIT_NICE
+      rather than relying on the kernel limits. Bound RLIMIT_NICE from below
+      as well as from above. Fix off-by-one error when converting
+      RLIMIT_NICE to the range of values used by the kernel.
+    - Add PATH to /etc/environment if it's not present there or in
+      /etc/security/pam_env.conf.
+    - debian/rules: Fix a bashism.
+    - Install unix_chkpwd setgid shadow instead of setuid root. The nis
+      package handles overriding this as necessary.
+    - Use pam_foreground in the default session.
+    - Linux-PAM/libpamc/test/regress/test.libpamc.c: Use standard u_int8_t
+      type rather than __u8.
+
+ -- Colin Watson <cjwatson@ubuntu.com>  Tue, 19 Dec 2006 10:32:47 +0000
+
 pam (0.79-4) unstable; urgency=medium
 
   * Medium-urgency upload; at least one RC bugfix, but also a
@@ -1926,6 +4557,12 @@ pam (0.79-3.2) unstable; urgency=low
 
  -- Margarita Manterola <marga@debian.org>  Sat,  5 Aug 2006 02:11:22 -0300
 
+pam (0.79-3.1ubuntu1) edgy; urgency=low
+
+  * Resynchronise with Debian.
+
+ -- Colin Watson <cjwatson@ubuntu.com>  Thu, 29 Jun 2006 17:27:34 +0100
+
 pam (0.79-3.1) unstable; urgency=low
 
   * Non-maintainer upload.
@@ -1936,6 +4573,114 @@ pam (0.79-3.1) unstable; urgency=low
 
  -- Roger Leigh <rleigh@debian.org>  Sun,  5 Feb 2006 21:46:59 +0000
 
+pam (0.79-3ubuntu14) dapper; urgency=low
+
+  * debian/patches-applied/061_pam_rlimits_nice_rtprio: Protect use of
+    RLIMIT_NICE in init_limits() with an #ifdef.
+
+ -- Colin Watson <cjwatson@ubuntu.com>  Fri, 12 May 2006 17:42:40 +0100
+
+pam (0.79-3ubuntu13) dapper; urgency=low
+
+  * debian/patches-applied/061_pam_rlimits_nice_rtprio: Set soft and hard
+    nice limits to 20 (= userland nice value 0) rather than unlimited by
+    default. Correct off-by-one error (the same error as in Linux 2.6.12,
+    but fixed in 2.6.13) in user<->kernel translation of nice limit.
+
+ -- Colin Watson <cjwatson@ubuntu.com>  Thu, 11 May 2006 11:29:58 +0100
+
+pam (0.79-3ubuntu12) dapper; urgency=low
+
+  * debian/control: Add libpam-foreground dependency to libpam-runtime, since
+    the default /etc/pam.d/common-session refers to it. Closes: LP#35142
+
+ -- Martin Pitt <martin.pitt@ubuntu.com>  Mon, 10 Apr 2006 14:42:40 +0200
+
+pam (0.79-3ubuntu11) dapper; urgency=low
+
+  [ Dana Olson ]
+  * debian/patches-applied/061_pam_rlimits_nice_rtprio: removed glibc
+    workaround now that glibc is aware of rlimits.
+
+  [ Martin Pitt ]
+  * debian/rules: Fix bashisms.
+
+ -- Martin Pitt <martin.pitt@ubuntu.com>  Thu,  6 Apr 2006 15:03:37 +0200
+
+pam (0.79-3ubuntu10) dapper; urgency=low
+
+  * debian/patches-applied/061_pam_rlimits_nice_rtprio: Support "nice" and
+    "rtprio" rlimits, new in Linux 2.6.12. Backported from upstream thanks
+    to Dana Olson and others (closes: Malone #17348).
+
+ -- Colin Watson <cjwatson@ubuntu.com>  Thu, 23 Feb 2006 16:22:12 +0000
+
+pam (0.79-3ubuntu9) dapper; urgency=low
+
+  * Fix operator precedence in libpam-modules.postinst.
+
+ -- Colin Watson <cjwatson@ubuntu.com>  Thu, 16 Feb 2006 15:23:04 +0000
+
+pam (0.79-3ubuntu8) dapper; urgency=low
+
+  * Make pam_env be quiet if it can't find the user's configuration file,
+    since it's optional.
+
+ -- Tollef Fog Heen <tfheen@ubuntu.com>  Sat,  4 Feb 2006 16:44:12 +0100
+
+pam (0.79-3ubuntu7) dapper; urgency=low
+
+  * Add the PATH on initial install for real this time.
+
+ -- Tollef Fog Heen <tfheen@ubuntu.com>  Thu,  2 Feb 2006 20:33:42 +0100
+
+pam (0.79-3ubuntu6) dapper; urgency=low
+
+  * Changes from Roger Leigh:
+
+  * Linux-PAM/libpamc/include/security/pam_client.h,
+    Linux-PAM/libpamc/pamc_converse.c: Apply patch from
+    latest upstream version to remove redefinition of internal
+    glibc/libstdc++ types.  Closes: #344447.
+  * Linux-PAM/libpamc/test/regress/test.libpamc.c: Also switch to standard
+    types; not taken from upstream.
+ 
+ -- Reinhard Tartler <siretart@ubuntu.com>  Wed,  1 Feb 2006 13:14:24 +0000
+
+pam (0.79-3ubuntu5) dapper; urgency=low
+
+  * Add pam_foreground to /etc/pam.d/common-session
+
+ -- Matthew Garrett <mjg59@srcf.ucam.org>  Tue, 24 Jan 2006 02:26:19 +0000
+
+pam (0.79-3ubuntu4) dapper; urgency=low
+
+  * Add PATH on initial install, too.
+
+ -- Tollef Fog Heen <tfheen@ubuntu.com>  Mon, 23 Jan 2006 15:55:40 +0100
+
+pam (0.79-3ubuntu3) dapper; urgency=low
+
+  * Add PATH to /etc/environment if it's not present there or in
+    /etc/security/pam_env.conf and we are upgrading from a version which
+    didn't add it.
+
+ -- Tollef Fog Heen <tfheen@ubuntu.com>  Tue, 17 Jan 2006 15:54:01 +0100
+
+pam (0.79-3ubuntu2) dapper; urgency=low
+
+  * Look at ~/.pam_environment too.  Same format as
+    /etc/security/pam_env.conf.  The patch is recorded as
+    patches-applied/060_pam_env_per_user
+
+ -- Tollef Fog Heen <tfheen@ubuntu.com>  Tue, 17 Jan 2006 15:32:55 +0100
+
+pam (0.79-3ubuntu1) dapper; urgency=low
+
+  * Resynchronise with Debian.
+
+ -- Colin Watson <cjwatson@ubuntu.com>  Mon, 21 Nov 2005 12:15:44 +0000
+
 pam (0.79-3) unstable; urgency=low
 
   * Patch 059
@@ -2016,6 +4761,34 @@ pam (0.76-23) unstable; urgency=low
 
  -- Sam Hartman <hartmans@debian.org>  Sun, 10 Jul 2005 16:42:25 -0400
 
+pam (0.76-22ubuntu3) breezy; urgency=low
+
+  * Fix pam_getenv, which never worked:
+    - Parse /etc/security/pam_env.conf using its own syntax, and then
+      /etc/environment using its own syntax rather than the syntax of
+      /etc/security/pam_env.conf.
+    - 'my $val' was used in an incorrect scope; fixed.
+    - Exit non-zero if the requested environment variable is not found.
+
+ -- Colin Watson <cjwatson@ubuntu.com>  Mon, 12 Sep 2005 18:32:54 +0100
+
+pam (0.76-22ubuntu2) breezy; urgency=low
+
+  * debian/rules: Install unix_chkpwd setgid shadow instead of setuid root.
+    This only breaks when using NIS lookups, therefore the new nis package
+    dpkg-statoverrides it back to setuid root while being installed.
+    (Debian #155583, http://udu.wiki.ubuntu.com/ProactiveSecurityRoadmap)
+  * debian/control: Added conflict to nis (<< 3.13-3ubuntu1): This is the
+    version that corrects the permissions for usage with NIS.
+
+ -- Martin Pitt <martin.pitt@ubuntu.com>  Fri, 17 Jun 2005 12:34:23 +0200
+
+pam (0.76-22ubuntu1) breezy; urgency=low
+
+  * Fix FTBFS with gcc-3.4 (closes: #259634). Ubuntu 9037.
+
+ -- Matthias Klose <doko@ubuntu.com>  Wed,  4 May 2005 18:14:51 +0200
+
 pam (0.76-22) unstable; urgency=medium
 
   * Add uploaders
@@ -2435,8 +5208,6 @@ pam (0.72-20) unstable; urgency=low
 
  -- Sam Hartman <hartmans@debian.org>  Fri,  6 Apr 2001 06:38:15 -0400
 
-
-
 pam (0.72-19) unstable; urgency=low
 
   * New maintainer, closes: #92353
@@ -3242,3 +6013,4 @@ pam (0.56-1) unstable; urgency=low
   * Reorganization of package structure (-dev, -dbg, etc).
 
  -- Klee Dienes <klee@debian.org>  Sat, 8 Mar 1997 01:21:17 -0500
+
diff -pruN 1.7.0-5/debian/control 1.7.0-5ubuntu2/debian/control
--- 1.7.0-5/debian/control	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/control	2025-07-03 16:33:16.000000000 +0000
@@ -1,13 +1,15 @@
 Source: pam
 Section: libs
 Priority: optional
-Maintainer: Sam Hartman <hartmans@debian.org>
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
+XSBC-Original-Maintainer: Sam Hartman <hartmans@debian.org>
 Standards-Version: 4.7.0
 Build-Depends: debhelper-compat (= 13), dh-exec,  flex,  libcrypt-dev, libdb-dev, libselinux1-dev [linux-any], libsystemd-dev [linux-any] <!stage1>, po-debconf, meson, libaudit-dev [linux-any] <!stage1>, pkgconf, libfl-dev, libfl-dev:native
 Build-Depends-Indep: docbook-xsl-ns, docbook5-xml, xsltproc, libxml2-utils, w3m, fop
 Build-Conflicts: libdb4.2-dev, libxcrypt-dev
-Vcs-Browser: https://salsa.debian.org/vorlon/pam
-Vcs-Git: https://salsa.debian.org/vorlon/pam.git
+Vcs-Git: https://code.launchpad.net/~ubuntu-core-dev/ubuntu/+source/pam/+git/pam
+XS-Debian-Vcs-Browser: https://salsa.debian.org/vorlon/pam
+XS-Debian-Vcs-Git: https://salsa.debian.org/vorlon/pam.git
 Homepage: http://www.linux-pam.org/
 Rules-Requires-Root: binary-targets
 
diff -pruN 1.7.0-5/debian/libpam-modules-bin.install 1.7.0-5ubuntu2/debian/libpam-modules-bin.install
--- 1.7.0-5/debian/libpam-modules-bin.install	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/libpam-modules-bin.install	2025-07-03 16:33:16.000000000 +0000
@@ -4,5 +4,7 @@ usr/sbin/mkhomedir_helper
 usr/sbin/pam_namespace_helper
 usr/sbin/pwhistory_helper
 usr/sbin/pam_timestamp_check
+usr/sbin/pam_extrausers_chkpwd
+usr/sbin/pam_extrausers_update
 usr/sbin/faillock
 usr/lib/systemd/system/pam_namespace.service
diff -pruN 1.7.0-5/debian/libpam-modules-bin.lintian-overrides 1.7.0-5ubuntu2/debian/libpam-modules-bin.lintian-overrides
--- 1.7.0-5/debian/libpam-modules-bin.lintian-overrides	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/libpam-modules-bin.lintian-overrides	2025-07-03 16:33:16.000000000 +0000
@@ -1,2 +1,4 @@
 # yes, we know it's sgid, that's the whole point...
+libpam-modules-bin: setgid-binary *usr/sbin/unix_chkpwd* 2755 root/shadow
+libpam-modules-bin: setgid-binary *usr/sbin/pam_extrausers_chkpwd* 2755 root/shadow
 libpam-modules-bin: elevated-privileges 2755 root/shadow [usr/sbin/unix_chkpwd]
diff -pruN 1.7.0-5/debian/libpam-modules.postinst 1.7.0-5ubuntu2/debian/libpam-modules.postinst
--- 1.7.0-5/debian/libpam-modules.postinst	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/libpam-modules.postinst	2025-07-03 16:33:16.000000000 +0000
@@ -16,4 +16,22 @@ then
 	touch "$DPKG_ROOT"/etc/environment
 fi
 
+# Add PATH to /etc/environment if it's not present there or in
+# /etc/security/pam_env.conf
+if [ "$1" = "configure" ] && dpkg --compare-versions "$2" lt 1.3.1-5ubuntu5; then
+	if ! grep -qs ^PATH "$DPKG_ROOT"/etc/security/pam_env.conf; then
+		if ! grep -qs ^PATH= "$DPKG_ROOT"/etc/environment; then
+			echo 'PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"' >> "$DPKG_ROOT"/etc/environment
+		fi
+	fi
+fi
+
+if dpkg --compare-versions "$2" lt-nl 1.1.2-1 \
+   && grep -q 'pam_unix.*\bmin=[0-9]\+' /etc/pam.d/common-password
+then
+	echo "'min=' option to pam_unix is obsolete."
+	echo "replacing with 'minlen=' in /etc/pam.d/common-password."
+	sed -i -e'/pam_unix/ s/\bmin=/minlen=/' /etc/pam.d/common-password
+fi
+
 #DEBHELPER#
diff -pruN 1.7.0-5/debian/libpam-runtime.manpages 1.7.0-5ubuntu2/debian/libpam-runtime.manpages
--- 1.7.0-5/debian/libpam-runtime.manpages	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/libpam-runtime.manpages	2025-07-03 16:33:16.000000000 +0000
@@ -12,3 +12,4 @@ debian/tmp/usr/share/man/man8/pam_timest
 debian/tmp/usr/share/man/man8/faillock.8
 debian/tmp/usr/share/man/man8/pwhistory_helper.8
 debian/tmp/usr/share/man/man8/pam_namespace_helper.8
+debian/update-motd.5
diff -pruN 1.7.0-5/debian/libpam0g.postinst 1.7.0-5ubuntu2/debian/libpam0g.postinst
--- 1.7.0-5/debian/libpam0g.postinst	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/libpam0g.postinst	2025-07-03 16:33:16.000000000 +0000
@@ -123,7 +123,7 @@ fi
 
 if [ "$1" = "configure" ]
 then
-    if [ ! -z "$2" ]; then
+    if [ ! -z "$2" ] && [ ! -x /usr/lib/needrestart/apt-pinvoke ]; then
 	if dpkg --compare-versions "$2" lt 1.4.0-2; then
 	    db_version 2.0
 
@@ -152,13 +152,28 @@ then
 	    echo "Checking init scripts..."
 	    services=$(installed_services "$check")
 	    if [ -n "$services" ]; then
-		db_input critical libraries/restart-without-asking || true
+		db_reset libpam0g/restart-services
+		db_set libpam0g/restart-services "$services"
+		question_priority="critical"
+		# Do not prompt when we're running in the upgrade-manager
+		# and only default services need restarting.
+		nondefault_services=$(echo "$services" | sed \
+			-e's/\batd\b//g' \
+			-e's/\bcron\b//g' \
+			-e's/\bcups\b//g' \
+			-e's/\bgdm\b//g' \
+			-e's/\bsmbd\b//g' \
+			-e's/^ *//g')
+		if [ -n "$RELEASE_UPGRADE_IN_PROGRESS" ] && [ -z "$nondefault_services" ]; then
+			question_priority="medium"
+		fi
+		db_input "$question_priority" libraries/restart-without-asking || true
 		db_go || true
 		db_get libraries/restart-without-asking
 		if [ "$RET" != true ]; then
 		    db_reset libpam0g/restart-services
 		    db_set libpam0g/restart-services "$services"
-		    db_input critical libpam0g/restart-services || true
+		    db_input "$question_priority" libpam0g/restart-services || true
 		    db_go || true
 		    db_get libpam0g/restart-services
 
@@ -179,6 +194,13 @@ then
 
 			case "$service" in
 			    gdm)
+				# If gdm isn't running, there's no need to reload it (LP: #745532)
+				if ! $idl status | grep -q 'Active: active (running)'
+				then
+					echo "  $service: not running, no reload needed."
+					continue
+				fi
+
 				echo -n "  $service: reloading..."
 				if $idl reload > /dev/null 2>&1; then
 				    echo "done."
@@ -217,8 +239,14 @@ then
 		done
 		services=$(installed_services "$dms")
 		if [ -n "$services" ]; then
-		    db_input critical libpam0g/xdm-needs-restart || true
-		    db_go || true
+		    if [ -n "$RELEASE_UPGRADE_IN_PROGRESS" ] \
+		       && [ -x /usr/share/update-notifier/notify-reboot-required ]
+		    then
+			/usr/share/update-notifier/notify-reboot-required
+		    else
+			db_input critical libpam0g/xdm-needs-restart || true
+			db_go || true
+		    fi
 		fi
 	    fi
 
diff -pruN 1.7.0-5/debian/local/common-session 1.7.0-5ubuntu2/debian/local/common-session
--- 1.7.0-5/debian/local/common-session	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/local/common-session	2025-07-03 16:33:16.000000000 +0000
@@ -19,7 +19,10 @@ session	requisite			pam_deny.so
 # this avoids us returning an error just because nothing sets a success code
 # since the modules above will each just jump around
 session	required			pam_permit.so
-# reset the umask for new sessions
+# The pam_umask module will set the umask according to the system default in
+# /etc/login.defs and user settings, solving the problem of different
+# umask settings with different shells, display managers, remote sessions etc.
+# See "man pam_umask".
 session optional			pam_umask.so
 # and here are more per-package modules (the "Additional" block)
 $session_additional
diff -pruN 1.7.0-5/debian/local/common-session-noninteractive 1.7.0-5ubuntu2/debian/local/common-session-noninteractive
--- 1.7.0-5/debian/local/common-session-noninteractive	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/local/common-session-noninteractive	2025-07-03 16:33:16.000000000 +0000
@@ -20,7 +20,10 @@ session	requisite			pam_deny.so
 # this avoids us returning an error just because nothing sets a success code
 # since the modules above will each just jump around
 session	required			pam_permit.so
-# reset the umask for new sessions
+# The pam_umask module will set the umask according to the system default in
+# /etc/login.defs and user settings, solving the problem of different
+# umask settings with different shells, display managers, remote sessions etc.
+# See "man pam_umask".
 session optional			pam_umask.so
 # and here are more per-package modules (the "Additional" block)
 $session_nonint_additional
diff -pruN 1.7.0-5/debian/local/pam-auth-update 1.7.0-5ubuntu2/debian/local/pam-auth-update
--- 1.7.0-5/debian/local/pam-auth-update	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/local/pam-auth-update	2025-07-03 16:33:16.000000000 +0000
@@ -56,11 +56,12 @@ my %md5sums = (
         	'f297c731a467822cbd86e1283263e8a3',
 		'240fb92986c885b327cdb21dd641da8c',
 		'4a25673e8b36f1805219027d3be02cd2',
-                '9e633425b1878897695217ecaf75e204',
+		'd38511a6ce8324742c151eed9fb57ba1',
 	],
 	'session-noninteractive' => [
 		'ad2b78ce1498dd637ef36469430b6ac6',
                 '53c1ede0bf4c07879d3582d875917545',
+		'a20e8df3469bfe25c13a3b39161b30f0',
 	],
 );
 my @invalid_modules = ('pam_tally');
diff -pruN 1.7.0-5/debian/patches/031_pam_include 1.7.0-5ubuntu2/debian/patches/031_pam_include
--- 1.7.0-5/debian/patches/031_pam_include	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/patches/031_pam_include	2025-07-03 16:33:16.000000000 +0000
@@ -10,8 +10,8 @@ Updated for pam 1.7.0 by Sam Hartman <ha
 
 Upstream status: not yet submitted
 ---
- libpam/pam_handlers.c | 36 ++++++++++++++++++++++++++++++++----
- 1 file changed, 32 insertions(+), 4 deletions(-)
+ libpam/pam_handlers.c | 5 +++++
+ 1 file changed, 5 insertions(+)
 
 diff --git a/libpam/pam_handlers.c b/libpam/pam_handlers.c
 index 7fd6ce8..1df5e40 100644
@@ -28,54 +28,11 @@ index 7fd6ce8..1df5e40 100644
  		} else {
  		    /* Illegal module type */
  		    D(("bad module type: %s", tok));
-@@ -197,8 +201,10 @@ static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
+@@ -197,6 +201,7 @@ static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
  		_pam_set_default_control(actions, _PAM_ACTION_BAD);
  	    }
  
 +parsing_done:
  	    tok = _pam_tokenize(NULL, &nexttok);
  	    if (pam_include) {
-+		struct stat include_dir;
  		if (substack) {
- 		    res = _pam_add_handler(pamh, PAM_HT_SUBSTACK, other,
- 				stack_level, module_type, actions, tok,
-@@ -209,13 +215,35 @@ static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
- 			return PAM_ABORT;
- 		    }
- 		}
--		if (_pam_load_conf_file(pamh, tok, this_service, module_type,
--		    include_level + 1, stack_level + substack
-+		if (tok[0] == '/') {
-+		    if (_pam_load_conf_file(pamh, tok, this_service,
-+		                            module_type, include_level+1, stack_level + substack
-+#ifdef PAM_READ_BOTH_CONFS
-+		                            , !other
-+#endif /* PAM_READ_BOTH_CONFS */
-+		       ) == PAM_SUCCESS)
-+			continue;
-+		}
-+		else if (!stat(PAM_CONFIG_D, &include_dir)
-+		         && S_ISDIR(include_dir.st_mode))
-+		{
-+		    char *include_file;
-+		    if (asprintf (&include_file, PAM_CONFIG_DF, tok) < 0) {
-+			pam_syslog(pamh, LOG_CRIT, "asprintf failed");
-+			return PAM_ABORT;
-+		    }
-+		    if (_pam_load_conf_file(pamh, include_file, this_service,
-+		                            module_type, include_level+1, stack_level + substack
- #ifdef PAM_READ_BOTH_CONFS
- 					      , !other
- #endif /* PAM_READ_BOTH_CONFS */
--		    ) == PAM_SUCCESS)
--		    continue;
-+		       ) == PAM_SUCCESS)
-+		    {
-+			free(include_file);
-+			continue;
-+		    }
-+		    free(include_file);
-+		}
- 		_pam_set_default_control(actions, _PAM_ACTION_BAD);
- 		mod_path = NULL;
- 		handler_type = PAM_HT_MUST_FAIL;
diff -pruN 1.7.0-5/debian/patches/extrausers.patch 1.7.0-5ubuntu2/debian/patches/extrausers.patch
--- 1.7.0-5/debian/patches/extrausers.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/patches/extrausers.patch	2025-07-03 16:33:16.000000000 +0000
@@ -0,0 +1,6855 @@
+Description: Add a pam_extrausers module
+ This is basically a copy of pam_unix but looks at
+ /var/lib/extrausers/{group,passwd,shadow} instead of /etc
+ modules/pam_extrausers/meson.build is a modified version of
+ modules/module-meson.build
+ Ideally, modules/module-meson.build should've have been patched and symlinked as
+ modules/pam_extrausers/meson.build
+Author: Michael Terry <mterry@ubuntu.com>
+Last-Updated: 2025-07-10
+Forwarded: no
+
+--- /dev/null
++++ b/modules/pam_extrausers/bigcrypt.c
+@@ -0,0 +1,159 @@
++/*
++ * This function implements the "bigcrypt" algorithm specifically for
++ * Linux-PAM.
++ *
++ * This algorithm is algorithm 0 (default) shipped with the C2 secure
++ * implementation of Digital UNIX.
++ *
++ * Disclaimer: This work is not based on the source code to Digital
++ * UNIX, nor am I connected to Digital Equipment Corp, in any way
++ * other than as a customer. This code is based on published
++ * interfaces and reasonable guesswork.
++ *
++ * Description: The cleartext is divided into blocks of SEGMENT_SIZE=8
++ * characters or less. Each block is encrypted using the standard UNIX
++ * libc crypt function. The result of the encryption for one block
++ * provides the salt for the suceeding block.
++ *
++ * Restrictions: The buffer used to hold the encrypted result is
++ * statically allocated. (see MAX_PASS_LEN below).  This is necessary,
++ * as the returned pointer points to "static data that are overwritten
++ * by each call", (XPG3: XSI System Interface + Headers pg 109), and
++ * this is a drop in replacement for crypt();
++ *
++ * Andy Phillips <atp@mssl.ucl.ac.uk>
++ */
++
++#include "config.h"
++
++#include <string.h>
++#include <stdlib.h>
++#include <security/_pam_macros.h>
++#ifdef HAVE_LIBXCRYPT
++#include <xcrypt.h>
++#elif defined(HAVE_CRYPT_H)
++#include <crypt.h>
++#endif
++
++#include "bigcrypt.h"
++
++/*
++ * Max cleartext password length in segments of 8 characters this
++ * function can deal with (16 segments of 8 chars= max 128 character
++ * password).
++ */
++
++#define MAX_PASS_LEN       16
++#define SEGMENT_SIZE       8
++#define SALT_SIZE          2
++#define KEYBUF_SIZE        ((MAX_PASS_LEN*SEGMENT_SIZE)+SALT_SIZE)
++#define ESEGMENT_SIZE      11
++#define CBUF_SIZE          ((MAX_PASS_LEN*ESEGMENT_SIZE)+SALT_SIZE+1)
++
++char *bigcrypt(const char *key, const char *salt)
++{
++	char *dec_c2_cryptbuf;
++#ifdef HAVE_CRYPT_R
++	struct crypt_data *cdata;
++#endif
++	unsigned long int keylen, n_seg, j;
++	char *cipher_ptr, *plaintext_ptr, *tmp_ptr, *salt_ptr;
++	char keybuf[KEYBUF_SIZE + 1];
++
++	D(("called with key='%s', salt='%s'.", key, salt));
++
++	/* reset arrays */
++	dec_c2_cryptbuf = malloc(CBUF_SIZE);
++	if (!dec_c2_cryptbuf) {
++		return NULL;
++	}
++#ifdef HAVE_CRYPT_R
++	cdata = malloc(sizeof(*cdata));
++	if(!cdata) {
++		free(dec_c2_cryptbuf);
++		return NULL;
++	}
++	cdata->initialized = 0;
++#endif
++	memset(keybuf, 0, KEYBUF_SIZE + 1);
++	memset(dec_c2_cryptbuf, 0, CBUF_SIZE);
++
++	/* fill KEYBUF_SIZE with key */
++	strncpy(keybuf, key, KEYBUF_SIZE);
++
++	/* deal with case that we are doing a password check for a
++	   conventially encrypted password: the salt will be
++	   SALT_SIZE+ESEGMENT_SIZE long. */
++	if (strlen(salt) == (SALT_SIZE + ESEGMENT_SIZE))
++		keybuf[SEGMENT_SIZE] = '\0';	/* terminate password early(?) */
++
++	keylen = strlen(keybuf);
++
++	if (!keylen) {
++		n_seg = 1;
++	} else {
++		/* work out how many segments */
++		n_seg = 1 + ((keylen - 1) / SEGMENT_SIZE);
++	}
++
++	if (n_seg > MAX_PASS_LEN)
++		n_seg = MAX_PASS_LEN;	/* truncate at max length */
++
++	/* set up some pointers */
++	cipher_ptr = dec_c2_cryptbuf;
++	plaintext_ptr = keybuf;
++
++	/* do the first block with supplied salt */
++#ifdef HAVE_CRYPT_R
++	tmp_ptr = crypt_r(plaintext_ptr, salt, cdata);	/* libc crypt_r() */
++#else
++	tmp_ptr = crypt(plaintext_ptr, salt);	/* libc crypt() */
++#endif
++	if (tmp_ptr == NULL) {
++		free(dec_c2_cryptbuf);
++		return NULL;
++	}
++	/* and place in the static area */
++	strncpy(cipher_ptr, tmp_ptr, 13);
++	cipher_ptr += ESEGMENT_SIZE + SALT_SIZE;
++	plaintext_ptr += SEGMENT_SIZE;	/* first block of SEGMENT_SIZE */
++
++	/* change the salt (1st 2 chars of previous block) - this was found
++	   by dowsing */
++
++	salt_ptr = cipher_ptr - ESEGMENT_SIZE;
++
++	/* so far this is identical to "return crypt(key, salt);", if
++	   there is more than one block encrypt them... */
++
++	if (n_seg > 1) {
++		for (j = 2; j <= n_seg; j++) {
++
++#ifdef HAVE_CRYPT_R
++			tmp_ptr = crypt_r(plaintext_ptr, salt_ptr, cdata);
++#else
++			tmp_ptr = crypt(plaintext_ptr, salt_ptr);
++#endif
++			if (tmp_ptr == NULL) {
++				_pam_overwrite(dec_c2_cryptbuf);
++				free(dec_c2_cryptbuf);
++				return NULL;
++			}
++
++			/* skip the salt for seg!=0 */
++			strncpy(cipher_ptr, (tmp_ptr + SALT_SIZE), ESEGMENT_SIZE);
++
++			cipher_ptr += ESEGMENT_SIZE;
++			plaintext_ptr += SEGMENT_SIZE;
++			salt_ptr = cipher_ptr - ESEGMENT_SIZE;
++		}
++	}
++	D(("key=|%s|, salt=|%s|\nbuf=|%s|\n", key, salt, dec_c2_cryptbuf));
++
++#ifdef HAVE_CRYPT_R
++	free(cdata);
++#endif
++
++	/* this is the <NUL> terminated encrypted password */
++	return dec_c2_cryptbuf;
++}
+--- /dev/null
++++ b/modules/pam_extrausers/bigcrypt.h
+@@ -0,0 +1 @@
++extern char *bigcrypt(const char *key, const char *salt);
+--- /dev/null
++++ b/modules/pam_extrausers/bigcrypt_main.c
+@@ -0,0 +1,18 @@
++#include <stdio.h>
++#include <string.h>
++
++#include "bigcrypt.h"
++
++int
++main(int argc, char **argv)
++{
++	if (argc < 3) {
++		fprintf(stderr, "Usage: %s password salt\n",
++			strchr(argv[0], '/') ?
++			(strchr(argv[0], '/') + 1) :
++			argv[0]);
++		return 0;
++	}
++	fprintf(stdout, "%s\n", bigcrypt(argv[1], argv[2]));
++	return 0;
++}
+--- /dev/null
++++ b/modules/pam_extrausers/lckpwdf.-c
+@@ -0,0 +1,142 @@
++/*
++ * This is a hack, but until libc and glibc both include this function
++ * by default (libc only includes it if nys is not being used, at the
++ * moment, and glibc doesn't appear to have it at all) we need to have
++ * it here, too.  :-(
++ *
++ * This should not become an official part of PAM.
++ *
++ * BEGIN_HACK
++ */
++
++/*
++ * lckpwdf.c -- prevent simultaneous updates of password files
++ *
++ * Before modifying any of the password files, call lckpwdf().  It may block
++ * for up to 15 seconds trying to get the lock.  Return value is 0 on success
++ * or -1 on failure.  When you are done, call ulckpwdf() to release the lock.
++ * The lock is also released automatically when the process exits.  Only one
++ * process at a time may hold the lock.
++ *
++ * These functions are supposed to be conformant with AT&T SVID Issue 3.
++ *
++ * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
++ * public domain.
++ */
++
++#include <fcntl.h>
++#include <signal.h>
++#ifdef WITH_SELINUX
++#include <selinux/selinux.h>
++#endif
++
++#define LOCKFILE "/var/lib/extrausers/.pwd.lock"
++#define TIMEOUT 15
++
++static int lockfd = -1;
++
++static int set_close_on_exec(int fd)
++{
++	int flags = fcntl(fd, F_GETFD, 0);
++	if (flags == -1)
++		return -1;
++	flags |= FD_CLOEXEC;
++	return fcntl(fd, F_SETFD, flags);
++}
++
++static int do_lock(int fd)
++{
++	struct flock fl;
++
++	memset(&fl, 0, sizeof fl);
++	fl.l_type = F_WRLCK;
++	fl.l_whence = SEEK_SET;
++	return fcntl(fd, F_SETLKW, &fl);
++}
++
++static void alarm_catch(int sig)
++{
++/* does nothing, but fcntl F_SETLKW will fail with EINTR */
++}
++
++static int extrausers_lckpwdf(void)
++{
++	struct sigaction act, oldact;
++	sigset_t set, oldset;
++
++	if (lockfd != -1)
++		return -1;
++
++#ifdef WITH_SELINUX
++	if(is_selinux_enabled()>0)
++	{
++		lockfd = open(LOCKFILE, O_WRONLY);
++		if(lockfd == -1 && errno == ENOENT)
++		{
++			security_context_t create_context;
++			int rc;
++
++			if(getfilecon("/var/lib/extrausers/passwd", &create_context))
++				return -1;
++			rc = setfscreatecon(create_context);
++			freecon(create_context);
++			if(rc)
++				return -1;
++			lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
++			if(setfscreatecon(NULL))
++				return -1;
++		}
++	}
++	else
++#endif
++	lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
++	if (lockfd == -1)
++		return -1;
++	if (set_close_on_exec(lockfd) == -1)
++		goto cleanup_fd;
++
++	memset(&act, 0, sizeof act);
++	act.sa_handler = alarm_catch;
++	act.sa_flags = 0;
++	sigfillset(&act.sa_mask);
++	if (sigaction(SIGALRM, &act, &oldact) == -1)
++		goto cleanup_fd;
++
++	sigemptyset(&set);
++	sigaddset(&set, SIGALRM);
++	if (sigprocmask(SIG_UNBLOCK, &set, &oldset) == -1)
++		goto cleanup_sig;
++
++	alarm(TIMEOUT);
++	if (do_lock(lockfd) == -1)
++		goto cleanup_alarm;
++	alarm(0);
++	sigprocmask(SIG_SETMASK, &oldset, NULL);
++	sigaction(SIGALRM, &oldact, NULL);
++	return 0;
++
++      cleanup_alarm:
++	alarm(0);
++	sigprocmask(SIG_SETMASK, &oldset, NULL);
++      cleanup_sig:
++	sigaction(SIGALRM, &oldact, NULL);
++      cleanup_fd:
++	close(lockfd);
++	lockfd = -1;
++	return -1;
++}
++
++static int extrausers_ulckpwdf(void)
++{
++	unlink(LOCKFILE);
++	if (lockfd == -1)
++		return -1;
++
++	if (close(lockfd) == -1) {
++		lockfd = -1;
++		return -1;
++	}
++	lockfd = -1;
++	return 0;
++}
++/* END_HACK */
+--- /dev/null
++++ b/modules/pam_extrausers/md5.c
+@@ -0,0 +1,255 @@
++/*
++ * $Id$
++ *
++ * This code implements the MD5 message-digest algorithm.
++ * The algorithm is due to Ron Rivest.  This code was
++ * written by Colin Plumb in 1993, no copyright is claimed.
++ * This code is in the public domain; do with it what you wish.
++ *
++ * Equivalent code is available from RSA Data Security, Inc.
++ * This code has been tested against that, and is equivalent,
++ * except that you don't need to include two pages of legalese
++ * with every copy.
++ *
++ * To compute the message digest of a chunk of bytes, declare an
++ * MD5Context structure, pass it to MD5Init, call MD5Update as
++ * needed on buffers full of bytes, and then call MD5Final, which
++ * will fill a supplied 16-byte array with the digest.
++ *
++ */
++
++#include <string.h>
++#include "md5.h"
++
++#ifndef HIGHFIRST
++#define byteReverse(buf, len)	/* Nothing */
++#else
++static void byteReverse(unsigned char *buf, unsigned longs);
++
++#ifndef ASM_MD5
++/*
++ * Note: this code is harmless on little-endian machines.
++ */
++static void byteReverse(unsigned char *buf, unsigned longs)
++{
++	uint32 t;
++	do {
++		t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
++		    ((unsigned) buf[1] << 8 | buf[0]);
++		*(uint32 *) buf = t;
++		buf += 4;
++	} while (--longs);
++}
++#endif
++#endif
++
++/*
++ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
++ * initialization constants.
++ */
++void MD5Name(MD5Init)(struct MD5Context *ctx)
++{
++	ctx->buf[0] = 0x67452301U;
++	ctx->buf[1] = 0xefcdab89U;
++	ctx->buf[2] = 0x98badcfeU;
++	ctx->buf[3] = 0x10325476U;
++
++	ctx->bits[0] = 0;
++	ctx->bits[1] = 0;
++}
++
++/*
++ * Update context to reflect the concatenation of another buffer full
++ * of bytes.
++ */
++void MD5Name(MD5Update)(struct MD5Context *ctx, unsigned const char *buf, unsigned len)
++{
++	uint32 t;
++
++	/* Update bitcount */
++
++	t = ctx->bits[0];
++	if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
++		ctx->bits[1]++;	/* Carry from low to high */
++	ctx->bits[1] += len >> 29;
++
++	t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
++
++	/* Handle any leading odd-sized chunks */
++
++	if (t) {
++		unsigned char *p = (unsigned char *) ctx->in + t;
++
++		t = 64 - t;
++		if (len < t) {
++			memcpy(p, buf, len);
++			return;
++		}
++		memcpy(p, buf, t);
++		byteReverse(ctx->in, 16);
++		MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in);
++		buf += t;
++		len -= t;
++	}
++	/* Process data in 64-byte chunks */
++
++	while (len >= 64) {
++		memcpy(ctx->in, buf, 64);
++		byteReverse(ctx->in, 16);
++		MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in);
++		buf += 64;
++		len -= 64;
++	}
++
++	/* Handle any remaining bytes of data. */
++
++	memcpy(ctx->in, buf, len);
++}
++
++/*
++ * Final wrapup - pad to 64-byte boundary with the bit pattern
++ * 1 0* (64-bit count of bits processed, MSB-first)
++ */
++void MD5Name(MD5Final)(unsigned char digest[16], struct MD5Context *ctx)
++{
++	unsigned count;
++	unsigned char *p;
++
++	/* Compute number of bytes mod 64 */
++	count = (ctx->bits[0] >> 3) & 0x3F;
++
++	/* Set the first char of padding to 0x80.  This is safe since there is
++	   always at least one byte free */
++	p = ctx->in + count;
++	*p++ = 0x80;
++
++	/* Bytes of padding needed to make 64 bytes */
++	count = 64 - 1 - count;
++
++	/* Pad out to 56 mod 64 */
++	if (count < 8) {
++		/* Two lots of padding:  Pad the first block to 64 bytes */
++		memset(p, 0, count);
++		byteReverse(ctx->in, 16);
++		MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in);
++
++		/* Now fill the next block with 56 bytes */
++		memset(ctx->in, 0, 56);
++	} else {
++		/* Pad block to 56 bytes */
++		memset(p, 0, count - 8);
++	}
++	byteReverse(ctx->in, 14);
++
++	/* Append length in bits and transform */
++	memcpy((uint32 *)ctx->in + 14, ctx->bits, 2*sizeof(uint32));
++
++	MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in);
++	byteReverse((unsigned char *) ctx->buf, 4);
++	memcpy(digest, ctx->buf, 16);
++	memset(ctx, 0, sizeof(*ctx));	/* In case it's sensitive */
++}
++
++#ifndef ASM_MD5
++
++/* The four core functions - F1 is optimized somewhat */
++
++/* #define F1(x, y, z) (x & y | ~x & z) */
++#define F1(x, y, z) (z ^ (x & (y ^ z)))
++#define F2(x, y, z) F1(z, x, y)
++#define F3(x, y, z) (x ^ y ^ z)
++#define F4(x, y, z) (y ^ (x | ~z))
++
++/* This is the central step in the MD5 algorithm. */
++#define MD5STEP(f, w, x, y, z, data, s) \
++	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
++
++/*
++ * The core of the MD5 algorithm, this alters an existing MD5 hash to
++ * reflect the addition of 16 longwords of new data.  MD5Update blocks
++ * the data and converts bytes into longwords for this routine.
++ */
++void MD5Name(MD5Transform)(uint32 buf[4], uint32 const in[16])
++{
++	register uint32 a, b, c, d;
++
++	a = buf[0];
++	b = buf[1];
++	c = buf[2];
++	d = buf[3];
++
++	MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478U, 7);
++	MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756U, 12);
++	MD5STEP(F1, c, d, a, b, in[2] + 0x242070dbU, 17);
++	MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceeeU, 22);
++	MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0fafU, 7);
++	MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62aU, 12);
++	MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613U, 17);
++	MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501U, 22);
++	MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8U, 7);
++	MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7afU, 12);
++	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1U, 17);
++	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7beU, 22);
++	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122U, 7);
++	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193U, 12);
++	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438eU, 17);
++	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821U, 22);
++
++	MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562U, 5);
++	MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340U, 9);
++	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51U, 14);
++	MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aaU, 20);
++	MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105dU, 5);
++	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453U, 9);
++	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681U, 14);
++	MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8U, 20);
++	MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6U, 5);
++	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6U, 9);
++	MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87U, 14);
++	MD5STEP(F2, b, c, d, a, in[8] + 0x455a14edU, 20);
++	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905U, 5);
++	MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8U, 9);
++	MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9U, 14);
++	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8aU, 20);
++
++	MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942U, 4);
++	MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681U, 11);
++	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122U, 16);
++	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380cU, 23);
++	MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44U, 4);
++	MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9U, 11);
++	MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60U, 16);
++	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70U, 23);
++	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6U, 4);
++	MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127faU, 11);
++	MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085U, 16);
++	MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05U, 23);
++	MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039U, 4);
++	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5U, 11);
++	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8U, 16);
++	MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665U, 23);
++
++	MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244U, 6);
++	MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97U, 10);
++	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7U, 15);
++	MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039U, 21);
++	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3U, 6);
++	MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92U, 10);
++	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47dU, 15);
++	MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1U, 21);
++	MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4fU, 6);
++	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0U, 10);
++	MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314U, 15);
++	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1U, 21);
++	MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82U, 6);
++	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235U, 10);
++	MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bbU, 15);
++	MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391U, 21);
++
++	buf[0] += a;
++	buf[1] += b;
++	buf[2] += c;
++	buf[3] += d;
++}
++
++#endif
+--- /dev/null
++++ b/modules/pam_extrausers/md5.h
+@@ -0,0 +1,31 @@
++
++#ifndef MD5_H
++#define MD5_H
++
++typedef unsigned int uint32;
++
++struct MD5Context {
++	uint32 buf[4];
++	uint32 bits[2];
++	unsigned char in[64];
++};
++
++void GoodMD5Init(struct MD5Context *);
++void GoodMD5Update(struct MD5Context *, unsigned const char *, unsigned);
++void GoodMD5Final(unsigned char digest[16], struct MD5Context *);
++void GoodMD5Transform(uint32 buf[4], uint32 const in[16]);
++void BrokenMD5Init(struct MD5Context *);
++void BrokenMD5Update(struct MD5Context *, unsigned const char *, unsigned);
++void BrokenMD5Final(unsigned char digest[16], struct MD5Context *);
++void BrokenMD5Transform(uint32 buf[4], uint32 const in[16]);
++
++char *Goodcrypt_md5(const char *pw, const char *salt);
++char *Brokencrypt_md5(const char *pw, const char *salt);
++
++/*
++ * This is needed to make RSAREF happy on some MS-DOS compilers.
++ */
++
++typedef struct MD5Context MD5_CTX;
++
++#endif				/* MD5_H */
+--- /dev/null
++++ b/modules/pam_extrausers/md5_broken.c
+@@ -0,0 +1,4 @@
++#define MD5Name(x) Broken##x
++
++#include "md5.c"
++#include "md5_crypt.c"
+--- /dev/null
++++ b/modules/pam_extrausers/md5_crypt.c
+@@ -0,0 +1,154 @@
++/*
++ * $Id$
++ *
++ * ----------------------------------------------------------------------------
++ * "THE BEER-WARE LICENSE" (Revision 42):
++ * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
++ * can do whatever you want with this stuff. If we meet some day, and you think
++ * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
++ * ----------------------------------------------------------------------------
++ *
++ * Origin: Id: crypt.c,v 1.3 1995/05/30 05:42:22 rgrimes Exp
++ *
++ */
++
++#include <string.h>
++#include <stdlib.h>
++#include "md5.h"
++
++static unsigned char itoa64[] =	/* 0 ... 63 => ascii - 64 */
++"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
++
++static void to64(char *s, unsigned long v, int n)
++{
++	while (--n >= 0) {
++		*s++ = itoa64[v & 0x3f];
++		v >>= 6;
++	}
++}
++
++/*
++ * UNIX password
++ *
++ * Use MD5 for what it is best at...
++ */
++
++char *MD5Name(crypt_md5)(const char *pw, const char *salt)
++{
++	const char *magic = "$1$";
++	/* This string is magic for this algorithm.  Having
++	 * it this way, we can get get better later on */
++	char *passwd, *p;
++	const char *sp, *ep;
++	unsigned char final[16];
++	int sl, pl, i, j;
++	MD5_CTX ctx, ctx1;
++	unsigned long l;
++
++	/* Refine the Salt first */
++	sp = salt;
++
++	/* TODO: now that we're using malloc'ed memory, get rid of the
++	   strange constant buffer size. */
++	passwd = malloc(120);
++
++	/* If it starts with the magic string, then skip that */
++	if (!strncmp(sp, magic, strlen(magic)))
++		sp += strlen(magic);
++
++	/* It stops at the first '$', max 8 chars */
++	for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
++		continue;
++
++	/* get the length of the true salt */
++	sl = ep - sp;
++
++	MD5Name(MD5Init)(&ctx);
++
++	/* The password first, since that is what is most unknown */
++	MD5Name(MD5Update)(&ctx,(unsigned const char *)pw,strlen(pw));
++
++	/* Then our magic string */
++	MD5Name(MD5Update)(&ctx,(unsigned const char *)magic,strlen(magic));
++
++	/* Then the raw salt */
++	MD5Name(MD5Update)(&ctx,(unsigned const char *)sp,sl);
++
++	/* Then just as many characters of the MD5(pw,salt,pw) */
++	MD5Name(MD5Init)(&ctx1);
++	MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw));
++	MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl);
++	MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw));
++	MD5Name(MD5Final)(final,&ctx1);
++	for (pl = strlen(pw); pl > 0; pl -= 16)
++		MD5Name(MD5Update)(&ctx,(unsigned const char *)final,pl>16 ? 16 : pl);
++
++	/* Don't leave anything around in vm they could use. */
++	memset(final, 0, sizeof final);
++
++	/* Then something really weird... */
++	for (j = 0, i = strlen(pw); i; i >>= 1)
++		if (i & 1)
++			MD5Name(MD5Update)(&ctx, (unsigned const char *)final+j, 1);
++		else
++			MD5Name(MD5Update)(&ctx, (unsigned const char *)pw+j, 1);
++
++	/* Now make the output string */
++	strcpy(passwd, magic);
++	strncat(passwd, sp, sl);
++	strcat(passwd, "$");
++
++	MD5Name(MD5Final)(final,&ctx);
++
++	/*
++	 * and now, just to make sure things don't run too fast
++	 * On a 60 Mhz Pentium this takes 34 msec, so you would
++	 * need 30 seconds to build a 1000 entry dictionary...
++	 */
++	for (i = 0; i < 1000; i++) {
++		MD5Name(MD5Init)(&ctx1);
++		if (i & 1)
++			MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw));
++		else
++			MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16);
++
++		if (i % 3)
++			MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl);
++
++		if (i % 7)
++			MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw));
++
++		if (i & 1)
++			MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16);
++		else
++			MD5Name(MD5Update)(&ctx1,(unsigned const char *)pw,strlen(pw));
++		MD5Name(MD5Final)(final,&ctx1);
++	}
++
++	p = passwd + strlen(passwd);
++
++	l = (final[0] << 16) | (final[6] << 8) | final[12];
++	to64(p, l, 4);
++	p += 4;
++	l = (final[1] << 16) | (final[7] << 8) | final[13];
++	to64(p, l, 4);
++	p += 4;
++	l = (final[2] << 16) | (final[8] << 8) | final[14];
++	to64(p, l, 4);
++	p += 4;
++	l = (final[3] << 16) | (final[9] << 8) | final[15];
++	to64(p, l, 4);
++	p += 4;
++	l = (final[4] << 16) | (final[10] << 8) | final[5];
++	to64(p, l, 4);
++	p += 4;
++	l = final[11];
++	to64(p, l, 2);
++	p += 2;
++	*p = '\0';
++
++	/* Don't leave anything around in vm they could use. */
++	memset(final, 0, sizeof final);
++
++	return passwd;
++}
+--- /dev/null
++++ b/modules/pam_extrausers/md5_good.c
+@@ -0,0 +1,5 @@
++#define HIGHFIRST
++#define MD5Name(x) Good##x
++
++#include "md5.c"
++#include "md5_crypt.c"
+--- /dev/null
++++ b/modules/pam_extrausers/obscure.c
+@@ -0,0 +1,199 @@
++/*
++ * Copyright 1989 - 1994, Julianne Frances Haugh
++ * All rights reserved.
++ *
++ * 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, this list of conditions and the following disclaimer.
++ * 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. Neither the name of Julianne F. Haugh nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``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 JULIE HAUGH OR CONTRIBUTORS 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 <ctype.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdlib.h>
++#include <pwd.h>
++#include <security/pam_modules.h>
++#include <security/_pam_macros.h>
++
++
++#include "pam_i18n.h"
++#include "support.h"
++
++/* can't be a palindrome - like `R A D A R' or `M A D A M' */
++static int palindrome(const char *old, const char *new) {
++	int	i, j;
++
++	i = strlen (new);
++
++	for (j = 0;j < i;j++)
++		if (new[i - j - 1] != new[j])
++			return 0;
++
++	return 1;
++}
++
++/* more than half of the characters are different ones. */
++static int similar(const char *old, const char *new) {
++	int i, j;
++
++	/*
++	 * XXX - sometimes this fails when changing from a simple password
++	 * to a really long one (MD5).  For now, I just return success if
++	 * the new password is long enough.  Please feel free to suggest
++	 * something better...  --marekm
++	 */
++	if (strlen(new) >= 8)
++		return 0;
++
++	for (i = j = 0; new[i] && old[i]; i++)
++		if (strchr(new, old[i]))
++			j++;
++
++	if (i >= j * 2)
++		return 0;
++
++	return 1;
++}
++
++/* a nice mix of characters. */
++static int simple(const char *old, const char *new) {
++	int	digits = 0;
++	int	uppers = 0;
++	int	lowers = 0;
++	int	others = 0;
++	int	size;
++	int	i;
++
++	for (i = 0;new[i];i++) {
++		if (isdigit (new[i]))
++			digits++;
++		else if (isupper (new[i]))
++			uppers++;
++		else if (islower (new[i]))
++			lowers++;
++		else
++			others++;
++	}
++
++	/*
++	 * The scam is this - a password of only one character type
++	 * must be 8 letters long.  Two types, 7, and so on.
++	 */
++
++	size = 9;
++	if (digits) size--;
++	if (uppers) size--;
++	if (lowers) size--;
++	if (others) size--;
++
++	if (size <= i)
++		return 0;
++
++	return 1;
++}
++
++static char *str_lower(char *string) {
++	char *cp;
++
++	for (cp = string; *cp; cp++)
++		*cp = tolower(*cp);
++	return string;
++}
++
++static const char * password_check(const char *old, const char *new,
++				   const struct passwd *pwdp) {
++	const char *msg = NULL;
++	char *oldmono, *newmono, *wrapped;
++
++	if (strcmp(new, old) == 0)
++		return _("Bad: new password must be different than the old one");
++
++	newmono = str_lower(strdup(new));
++	oldmono = str_lower(strdup(old));
++	wrapped = (char *)malloc(strlen(oldmono) * 2 + 1);
++	strcpy (wrapped, oldmono);
++	strcat (wrapped, oldmono);
++
++	if (palindrome(oldmono, newmono)) {
++		msg = _("Bad: new password cannot be a palindrome");
++	} else if (strcmp(oldmono, newmono) == 0) {
++		msg = _("Bad: new and old password must differ by more than just case");
++	} else if (similar(oldmono, newmono)) {
++		msg = _("Bad: new and old password are too similar");
++	} else if (simple(old, new)) {
++		msg = _("Bad: new password is too simple");
++	} else if (strstr(wrapped, newmono)) {
++		msg = _("Bad: new password is just a wrapped version of the old one");
++	}
++
++	_pam_delete(newmono);
++	_pam_delete(oldmono);
++	_pam_delete(wrapped);
++
++	return msg;
++}
++
++const char *obscure_msg(const char *old, const char *new,
++			       const struct passwd *pwdp, unsigned int ctrl) {
++	int oldlen, newlen;
++	char *new1, *old1;
++	const char *msg;
++
++	if (old == NULL)
++		return NULL; /* no check if old is NULL */
++
++	oldlen = strlen(old);
++	newlen = strlen(new);
++
++	/* Remaining checks are optional. */
++	if (off(UNIX_OBSCURE_CHECKS,ctrl))
++		return NULL;
++
++	if ((msg = password_check(old, new, pwdp)) != NULL)
++		return msg;
++
++	/* The traditional crypt() truncates passwords to 8 chars.  It is
++	   possible to circumvent the above checks by choosing an easy
++	   8-char password and adding some random characters to it...
++	   Example: "password$%^&*123".  So check it again, this time
++	   truncated to the maximum length.  Idea from npasswd.  --marekm */
++
++	if (!UNIX_DES_CRYPT(ctrl))
++		return NULL;  /* unlimited password length */
++
++	if (oldlen <= 8 && newlen <= 8)
++		return NULL;
++
++	new1 = strndup(new,8);
++	old1 = strndup(old,8);
++
++	msg = password_check(old1, new1, pwdp);
++
++	_pam_delete(new1);
++	_pam_delete(old1);
++
++	return msg;
++}
+--- /dev/null
++++ b/modules/pam_extrausers/pam_unix_acct.c
+@@ -0,0 +1,305 @@
++/*
++ * Copyright Elliot Lee, 1996.  All rights reserved.
++ * Copyright Jan R\EAkorajski, 1999.  All rights reserved.
++ *
++ * 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 <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++#include <sys/types.h>
++#include <sys/resource.h>
++#include <syslog.h>
++#include <pwd.h>
++#include <shadow.h>
++#include <time.h>		/* for time() */
++#include <errno.h>
++#include <sys/wait.h>
++
++#include <security/_pam_macros.h>
++
++/* indicate that the following groups are defined */
++
++#ifdef PAM_STATIC
++# include "pam_unix_static.h"
++#else
++# define PAM_SM_ACCOUNT
++#endif
++
++#include <security/pam_modules.h>
++#include <security/pam_ext.h>
++#include <security/pam_modutil.h>
++
++#include "pam_i18n.h"
++#include "support.h"
++#include "passverify.h"
++
++int _unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl,
++	const char *user, int *daysleft)
++{
++  int retval=0, child, fds[2];
++  struct sigaction newsa, oldsa;
++  D(("running verify_binary"));
++
++  /* create a pipe for the messages */
++  if (pipe(fds) != 0) {
++    D(("could not make pipe"));
++    pam_syslog(pamh, LOG_ERR, "Could not make pipe: %m");
++    return PAM_AUTH_ERR;
++  }
++  D(("called."));
++
++  if (off(UNIX_NOREAP, ctrl)) {
++    /*
++     * This code arranges that the demise of the child does not cause
++     * the application to receive a signal it is not expecting - which
++     * may kill the application or worse.
++     *
++     * The "noreap" module argument is provided so that the admin can
++     * override this behavior.
++     */
++     memset(&newsa, '\0', sizeof(newsa));
++     newsa.sa_handler = SIG_DFL;
++     sigaction(SIGCHLD, &newsa, &oldsa);
++  }
++
++  /* fork */
++  child = fork();
++  if (child == 0) {
++    int i=0;
++    struct rlimit rlim;
++    static char *envp[] = { NULL };
++    char *args[] = { NULL, NULL, NULL, NULL };
++
++    /* reopen stdout as pipe */
++    dup2(fds[1], STDOUT_FILENO);
++
++    /* XXX - should really tidy up PAM here too */
++
++    if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
++      if (rlim.rlim_max >= MAX_FD_NO)
++        rlim.rlim_max = MAX_FD_NO;
++      for (i=0; i < (int)rlim.rlim_max; i++) {
++	if (i != STDOUT_FILENO) {
++	  close(i);
++	}
++      }
++    }
++
++    if (geteuid() == 0) {
++      /* must set the real uid to 0 so the helper will not error
++         out if pam is called from setuid binary (su, sudo...) */
++      if (setuid(0) == -1) {
++          pam_syslog(pamh, LOG_ERR, "setuid failed: %m");
++          printf("-1\n");
++          fflush(stdout);
++          _exit(PAM_AUTHINFO_UNAVAIL);
++      }
++    }
++
++    /* exec binary helper */
++    args[0] = x_strdup(CHKPWD_HELPER);
++    args[1] = x_strdup(user);
++    args[2] = x_strdup("chkexpiry");
++
++    execve(CHKPWD_HELPER, args, envp);
++
++    pam_syslog(pamh, LOG_ERR, "helper binary execve failed: %m");
++    /* should not get here: exit with error */
++    D(("helper binary is not available"));
++    printf("-1\n");
++    fflush(stdout);
++    _exit(PAM_AUTHINFO_UNAVAIL);
++  } else {
++    close(fds[1]);
++    if (child > 0) {
++      char buf[32];
++      int rc=0;
++      /* wait for helper to complete: */
++      while ((rc=waitpid(child, &retval, 0)) < 0 && errno == EINTR);
++      if (rc<0) {
++	pam_syslog(pamh, LOG_ERR, "pam_extrausers_chkpwd waitpid returned %d: %m", rc);
++	retval = PAM_AUTH_ERR;
++      } else if (!WIFEXITED(retval)) {
++        pam_syslog(pamh, LOG_ERR, "pam_extrausers_chkpwd abnormal exit: %d", retval);
++        retval = PAM_AUTH_ERR;
++      } else {
++	retval = WEXITSTATUS(retval);
++        rc = pam_modutil_read(fds[0], buf, sizeof(buf) - 1);
++	if(rc > 0) {
++	      buf[rc] = '\0';
++	      if (sscanf(buf,"%d", daysleft) != 1 )
++	        retval = PAM_AUTH_ERR;
++	    }
++	else {
++	    pam_syslog(pamh, LOG_ERR, "read pam_extrausers_chkpwd output error %d: %m", rc);
++	    retval = PAM_AUTH_ERR;
++	  }
++      }
++    } else {
++      pam_syslog(pamh, LOG_ERR, "Fork failed: %m");
++      D(("fork failed"));
++      retval = PAM_AUTH_ERR;
++    }
++    close(fds[0]);
++  }
++
++  if (off(UNIX_NOREAP, ctrl)) {
++        sigaction(SIGCHLD, &oldsa, NULL);   /* restore old signal handler */
++  }
++
++  D(("Returning %d",retval));
++  return retval;
++}
++
++/*
++ * PAM framework looks for this entry-point to pass control to the
++ * account management module.
++ */
++
++int
++pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
++{
++	unsigned int ctrl;
++	const void *void_uname;
++	const char *uname;
++	int retval, daysleft;
++	struct spwd *spent;
++	struct passwd *pwent;
++	char buf[256];
++
++	D(("called."));
++
++	ctrl = _set_ctrl(pamh, flags, NULL, NULL, NULL, argc, argv);
++
++	retval = pam_get_item(pamh, PAM_USER, &void_uname);
++	uname = void_uname;
++	D(("user = `%s'", uname));
++	if (retval != PAM_SUCCESS || uname == NULL) {
++		pam_syslog(pamh, LOG_ALERT,
++			 "could not identify user (from uid=%lu)",
++			 (unsigned long int)getuid());
++		return PAM_USER_UNKNOWN;
++	}
++
++	retval = get_account_info(pamh, uname, &pwent, &spent);
++	if (retval == PAM_USER_UNKNOWN) {
++		pam_syslog(pamh, LOG_ALERT,
++			 "could not identify user (from getpwnam(%s))",
++			 uname);
++		return retval;
++	}
++
++	if (retval == PAM_SUCCESS && spent == NULL)
++		return PAM_SUCCESS;
++
++	if (retval == PAM_UNIX_RUN_HELPER) {
++		retval = _unix_run_verify_binary(pamh, ctrl, uname, &daysleft);
++		if (retval == PAM_AUTHINFO_UNAVAIL &&
++			on(UNIX_BROKEN_SHADOW, ctrl))
++			return PAM_SUCCESS;
++	} else if (retval != PAM_SUCCESS) {
++		if (on(UNIX_BROKEN_SHADOW,ctrl))
++			return PAM_SUCCESS;
++		else
++			return retval;
++	} else
++		retval = check_shadow_expiry(pamh, spent, &daysleft);
++
++	switch (retval) {
++	case PAM_ACCT_EXPIRED:
++		pam_syslog(pamh, LOG_NOTICE,
++			"account %s has expired (account expired)",
++			uname);
++		_make_remark(pamh, ctrl, PAM_ERROR_MSG,
++			_("Your account has expired; please contact your system administrator"));
++		break;
++	case PAM_NEW_AUTHTOK_REQD:
++		if (daysleft == 0) {
++			pam_syslog(pamh, LOG_NOTICE,
++				"expired password for user %s (root enforced)",
++				uname);
++			_make_remark(pamh, ctrl, PAM_ERROR_MSG,
++				_("You are required to change your password immediately (root enforced)"));
++		} else {
++			pam_syslog(pamh, LOG_DEBUG,
++				"expired password for user %s (password aged)",
++				uname);
++			_make_remark(pamh, ctrl, PAM_ERROR_MSG,
++				_("You are required to change your password immediately (password aged)"));
++		}
++		break;
++	case PAM_AUTHTOK_EXPIRED:
++		pam_syslog(pamh, LOG_NOTICE,
++			"account %s has expired (failed to change password)",
++			uname);
++		_make_remark(pamh, ctrl, PAM_ERROR_MSG,
++			_("Your account has expired; please contact your system administrator"));
++		break;
++	case PAM_AUTHTOK_ERR:
++		retval = PAM_SUCCESS;
++		/* fallthrough */
++	case PAM_SUCCESS:
++		if (daysleft >= 0) {
++			pam_syslog(pamh, LOG_DEBUG,
++				"password for user %s will expire in %d days",
++				uname, daysleft);
++#if defined HAVE_DNGETTEXT && defined ENABLE_NLS
++			snprintf (buf, sizeof (buf),
++				dngettext(PACKAGE,
++				  "Warning: your password will expire in %d day",
++				  "Warning: your password will expire in %d days",
++				  daysleft),
++				daysleft);
++#else
++			if (daysleft == 1)
++			    snprintf(buf, sizeof (buf),
++				_("Warning: your password will expire in %d day"),
++				daysleft);
++			else
++			    snprintf(buf, sizeof (buf),
++			    /* TRANSLATORS: only used if dngettext is not supported */
++				_("Warning: your password will expire in %d days"),
++				daysleft);
++#endif
++			_make_remark(pamh, ctrl, PAM_TEXT_INFO, buf);
++		}
++	}
++
++	D(("all done"));
++
++	return retval;
++}
+--- /dev/null
++++ b/modules/pam_extrausers/pam_unix_auth.c
+@@ -0,0 +1,219 @@
++/*
++ * Copyright Alexander O. Yuriev, 1996.  All rights reserved.
++ * NIS+ support by Thorsten Kukuk <kukuk@weber.uni-paderborn.de>
++ * Copyright Jan R\EAkorajski, 1999.  All rights reserved.
++ *
++ * 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 <stdio.h>
++#include <stdlib.h>
++#include <stdarg.h>
++#include <string.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <ctype.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <syslog.h>
++
++/* indicate the following groups are defined */
++
++#ifdef PAM_STATIC
++# include "pam_unix_static.h"
++#else
++# define PAM_SM_AUTH
++#endif
++
++#define _PAM_EXTERN_FUNCTIONS
++#include <security/_pam_macros.h>
++#include <security/pam_modules.h>
++#include <security/pam_ext.h>
++
++#include "pam_i18n.h"
++#include "support.h"
++
++/*
++ * PAM framework looks for these entry-points to pass control to the
++ * authentication module.
++ */
++
++/* Fun starts here :)
++
++ * pam_sm_authenticate() performs UNIX/shadow authentication
++ *
++ *      First, if shadow support is available, attempt to perform
++ *      authentication using shadow passwords. If shadow is not
++ *      available, or user does not have a shadow password, fallback
++ *      onto a normal UNIX authentication
++ */
++
++#define _UNIX_AUTHTOK  "-UN*X-PASS"
++
++#define AUTH_RETURN						\
++do {								\
++	if (on(UNIX_LIKE_AUTH, ctrl) && ret_data) {		\
++		D(("recording return code for next time [%d]",	\
++					retval));		\
++		*ret_data = retval;				\
++		pam_set_data(pamh, "unix_setcred_return",	\
++		             (void *) ret_data, setcred_free);	\
++	} else if (ret_data)					\
++	  free (ret_data);                                      \
++	D(("done. [%s]", pam_strerror(pamh, retval)));		\
++	return retval;						\
++} while (0)
++
++
++static void
++setcred_free (pam_handle_t *pamh UNUSED, void *ptr, int err UNUSED)
++{
++	if (ptr)
++		free (ptr);
++}
++
++int
++pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
++{
++	unsigned int ctrl;
++	int retval, *ret_data = NULL;
++	const char *name;
++	const void *p;
++
++	D(("called."));
++
++	ctrl = _set_ctrl(pamh, flags, NULL, NULL, NULL, argc, argv);
++
++	/* Get a few bytes so we can pass our return value to
++	   pam_sm_setcred(). */
++	if (on(UNIX_LIKE_AUTH, ctrl))
++		ret_data = malloc(sizeof(int));
++
++	/* get the user'name' */
++
++	retval = pam_get_user(pamh, &name, NULL);
++	if (retval == PAM_SUCCESS) {
++		/*
++		 * Various libraries at various times have had bugs related to
++		 * '+' or '-' as the first character of a user name. Don't
++		 * allow this characters here.
++		 */
++		if (name == NULL || name[0] == '-' || name[0] == '+') {
++			pam_syslog(pamh, LOG_ERR, "bad username [%s]", name);
++			retval = PAM_USER_UNKNOWN;
++			AUTH_RETURN;
++		}
++		if (on(UNIX_DEBUG, ctrl))
++			D(("username [%s] obtained", name));
++	} else {
++		D(("trouble reading username"));
++		if (retval == PAM_CONV_AGAIN) {
++			D(("pam_get_user/conv() function is not ready yet"));
++			/* it is safe to resume this function so we translate this
++			 * retval to the value that indicates we're happy to resume.
++			 */
++			retval = PAM_INCOMPLETE;
++		}
++		AUTH_RETURN;
++	}
++
++	/* if this user does not have a password... */
++
++	if (_unix_blankpasswd(pamh, ctrl, name)) {
++		D(("user '%s' has blank passwd", name));
++		name = NULL;
++		retval = PAM_SUCCESS;
++		AUTH_RETURN;
++	}
++	/* get this user's authentication token */
++
++	retval = _unix_read_password(pamh, ctrl, NULL, _("Password: "), NULL
++				     ,_UNIX_AUTHTOK, &p);
++	if (retval != PAM_SUCCESS) {
++		if (retval != PAM_CONV_AGAIN) {
++			pam_syslog(pamh, LOG_CRIT,
++			    "auth could not identify password for [%s]", name);
++		} else {
++			D(("conversation function is not ready yet"));
++			/*
++			 * it is safe to resume this function so we translate this
++			 * retval to the value that indicates we're happy to resume.
++			 */
++			retval = PAM_INCOMPLETE;
++		}
++		name = NULL;
++		AUTH_RETURN;
++	}
++	D(("user=%s, password=[%s]", name, p));
++
++	/* verify the password of this user */
++	retval = _unix_verify_password(pamh, name, p, ctrl);
++	name = p = NULL;
++
++	AUTH_RETURN;
++}
++
++
++/*
++ * The only thing _pam_set_credentials_unix() does is initialization of
++ * UNIX group IDs.
++ *
++ * Well, everybody but me on linux-pam is convinced that it should not
++ * initialize group IDs, so I am not doing it but don't say that I haven't
++ * warned you. -- AOY
++ */
++
++int
++pam_sm_setcred (pam_handle_t *pamh, int flags UNUSED,
++		int argc UNUSED, const char **argv UNUSED)
++{
++	int retval;
++	const void *pretval = NULL;
++
++	D(("called."));
++
++	retval = PAM_SUCCESS;
++
++	D(("recovering return code from auth call"));
++	/* We will only find something here if UNIX_LIKE_AUTH is set --
++	   don't worry about an explicit check of argv. */
++	if (pam_get_data(pamh, "unix_setcred_return", &pretval) == PAM_SUCCESS
++	    && pretval) {
++	        retval = *(const int *)pretval;
++		pam_set_data(pamh, "unix_setcred_return", NULL, NULL);
++		D(("recovered data indicates that old retval was %d", retval));
++	}
++
++	return retval;
++}
+--- /dev/null
++++ b/modules/pam_extrausers/pam_unix_passwd.c
+@@ -0,0 +1,844 @@
++/*
++ * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software.
++ * Copyright (C) 1996.
++ * Copyright (c) Jan RÃªkorajski, 1999.
++ * Copyright (c) Red Hat, Inc., 2007, 2008.
++ *
++ * 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 <stdio.h>
++#include <stdlib.h>
++#include <stdarg.h>
++#include <string.h>
++#include <malloc.h>
++#include <unistd.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <pwd.h>
++#include <syslog.h>
++#include <shadow.h>
++#include <time.h>		/* for time() */
++#include <fcntl.h>
++#include <ctype.h>
++#include <sys/time.h>
++#include <sys/stat.h>
++
++#include <signal.h>
++#include <errno.h>
++#include <sys/wait.h>
++#include <sys/resource.h>
++
++#include <security/_pam_macros.h>
++
++/* indicate the following groups are defined */
++
++#ifdef PAM_STATIC
++# include "pam_unix_static.h"
++#else
++# define PAM_SM_PASSWORD
++#endif
++
++#include <security/pam_modules.h>
++#include <security/pam_ext.h>
++#include <security/pam_modutil.h>
++
++#include "pam_i18n.h"
++#include "md5.h"
++#include "support.h"
++#include "passverify.h"
++#include "bigcrypt.h"
++
++#if (HAVE_YP_GET_DEFAULT_DOMAIN || HAVE_GETDOMAINNAME) && HAVE_YP_MASTER
++# define HAVE_NIS
++#endif
++
++#ifdef HAVE_NIS
++# include <rpc/rpc.h>
++
++# if HAVE_RPCSVC_YP_PROT_H
++#  include <rpcsvc/yp_prot.h>
++# endif
++
++# if HAVE_RPCSVC_YPCLNT_H
++#  include <rpcsvc/ypclnt.h>
++# endif
++
++# include "yppasswd.h"
++
++# if !HAVE_DECL_GETRPCPORT
++extern int getrpcport(const char *host, unsigned long prognum,
++		      unsigned long versnum, unsigned int proto);
++# endif				/* GNU libc 2.1 */
++#endif
++
++extern const char *obscure_msg(const char *, const char *, const struct passwd *,
++			       unsigned int);
++
++/*
++   How it works:
++   Gets in username (has to be done) from the calling program
++   Does authentication of user (only if we are not running as root)
++   Gets new password/checks for sanity
++   Sets it.
++ */
++
++/* data tokens */
++
++#define _UNIX_OLD_AUTHTOK	"-UN*X-OLD-PASS"
++#define _UNIX_NEW_AUTHTOK	"-UN*X-NEW-PASS"
++
++#define MAX_PASSWD_TRIES	3
++
++#ifdef HAVE_NIS
++static char *getNISserver(pam_handle_t *pamh, unsigned int ctrl)
++{
++	char *master;
++	char *domainname;
++	int port, err;
++
++#ifdef HAVE_YP_GET_DEFAULT_DOMAIN
++	if ((err = yp_get_default_domain(&domainname)) != 0) {
++		pam_syslog(pamh, LOG_WARNING, "can't get local yp domain: %s",
++			 yperr_string(err));
++		return NULL;
++	}
++#elif defined(HAVE_GETDOMAINNAME)
++	char domainname_res[256];
++
++	if (getdomainname (domainname_res, sizeof (domainname_res)) == 0)
++	  {
++	    if (strcmp (domainname_res, "(none)") == 0)
++	      {
++		/* If domainname is not set, some systems will return "(none)" */
++		domainname_res[0] = '\0';
++	      }
++	    domainname = domainname_res;
++	  }
++	else domainname = NULL;
++#endif
++
++	if ((err = yp_master(domainname, "passwd.byname", &master)) != 0) {
++		pam_syslog(pamh, LOG_WARNING, "can't find the master ypserver: %s",
++			 yperr_string(err));
++		return NULL;
++	}
++	port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP);
++	if (port == 0) {
++		pam_syslog(pamh, LOG_WARNING,
++		         "yppasswdd not running on NIS master host");
++		return NULL;
++	}
++	if (port >= IPPORT_RESERVED) {
++		pam_syslog(pamh, LOG_WARNING,
++		         "yppasswd daemon running on illegal port");
++		return NULL;
++	}
++	if (on(UNIX_DEBUG, ctrl)) {
++	  pam_syslog(pamh, LOG_DEBUG, "Use NIS server on %s with port %d",
++		     master, port);
++	}
++	return master;
++}
++#endif
++
++#ifdef WITH_SELINUX
++
++static int _unix_run_update_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user,
++    const char *fromwhat, const char *towhat, int remember)
++{
++    int retval, child, fds[2];
++    struct sigaction newsa, oldsa;
++
++    D(("called."));
++    /* create a pipe for the password */
++    if (pipe(fds) != 0) {
++	D(("could not make pipe"));
++	return PAM_AUTH_ERR;
++    }
++
++    if (off(UNIX_NOREAP, ctrl)) {
++	/*
++	 * This code arranges that the demise of the child does not cause
++	 * the application to receive a signal it is not expecting - which
++	 * may kill the application or worse.
++	 *
++	 * The "noreap" module argument is provided so that the admin can
++	 * override this behavior.
++	 */
++        memset(&newsa, '\0', sizeof(newsa));
++        newsa.sa_handler = SIG_DFL;
++        sigaction(SIGCHLD, &newsa, &oldsa);
++    }
++
++    /* fork */
++    child = fork();
++    if (child == 0) {
++        int i=0;
++        struct rlimit rlim;
++	static char *envp[] = { NULL };
++	char *args[] = { NULL, NULL, NULL, NULL, NULL, NULL };
++        char buffer[16];
++
++	/* XXX - should really tidy up PAM here too */
++
++	/* reopen stdin as pipe */
++	dup2(fds[0], STDIN_FILENO);
++
++	if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
++	  if (rlim.rlim_max >= MAX_FD_NO)
++	    rlim.rlim_max = MAX_FD_NO;
++	  for (i=0; i < (int)rlim.rlim_max; i++) {
++	    if (i != STDIN_FILENO)
++		close(i);
++	  }
++	}
++
++	/* exec binary helper */
++	args[0] = x_strdup(UPDATE_HELPER);
++	args[1] = x_strdup(user);
++	args[2] = x_strdup("update");
++	if (on(UNIX_SHADOW, ctrl))
++		args[3] = x_strdup("1");
++	else
++		args[3] = x_strdup("0");
++
++        snprintf(buffer, sizeof(buffer), "%d", remember);
++        args[4] = x_strdup(buffer);
++
++	execve(UPDATE_HELPER, args, envp);
++
++	/* should not get here: exit with error */
++	D(("helper binary is not available"));
++	_exit(PAM_AUTHINFO_UNAVAIL);
++    } else if (child > 0) {
++	/* wait for child */
++	/* if the stored password is NULL */
++        int rc=0;
++	if (fromwhat)
++	  pam_modutil_write(fds[1], fromwhat, strlen(fromwhat)+1);
++	else
++	  pam_modutil_write(fds[1], "", 1);
++	if (towhat) {
++	  pam_modutil_write(fds[1], towhat, strlen(towhat)+1);
++	}
++	else
++	  pam_modutil_write(fds[1], "", 1);
++
++	close(fds[0]);       /* close here to avoid possible SIGPIPE above */
++	close(fds[1]);
++	/* wait for helper to complete: */
++	while ((rc=waitpid(child, &retval, 0)) < 0 && errno == EINTR);
++	if (rc<0) {
++	  pam_syslog(pamh, LOG_ERR, "pam_extrausers_update waitpid failed: %m");
++	  retval = PAM_AUTHTOK_ERR;
++	} else if (!WIFEXITED(retval)) {
++          pam_syslog(pamh, LOG_ERR, "pam_extrausers_update abnormal exit: %d", retval);
++          retval = PAM_AUTHTOK_ERR;
++        } else {
++	  retval = WEXITSTATUS(retval);
++	}
++    } else {
++	D(("fork failed"));
++	close(fds[0]);
++	close(fds[1]);
++	retval = PAM_AUTH_ERR;
++    }
++
++    if (off(UNIX_NOREAP, ctrl)) {
++        sigaction(SIGCHLD, &oldsa, NULL);   /* restore old signal handler */
++    }
++
++    return retval;
++}
++#endif
++
++static int check_old_password(const char *forwho, const char *newpass)
++{
++	static char buf[16384];
++	char *s_luser, *s_uid, *s_npas, *s_pas;
++	int retval = PAM_SUCCESS;
++	FILE *opwfile;
++	size_t len = strlen(forwho);
++
++	opwfile = fopen(OLD_PASSWORDS_FILE, "r");
++	if (opwfile == NULL)
++		return PAM_ABORT;
++
++	while (fgets(buf, 16380, opwfile)) {
++		if (!strncmp(buf, forwho, len) && (buf[len] == ':' ||
++			buf[len] == ',')) {
++			char *sptr;
++			buf[strlen(buf) - 1] = '\0';
++			s_luser = strtok_r(buf, ":,", &sptr);
++			s_uid = strtok_r(NULL, ":,", &sptr);
++			s_npas = strtok_r(NULL, ":,", &sptr);
++			s_pas = strtok_r(NULL, ":,", &sptr);
++			while (s_pas != NULL) {
++				char *md5pass = Goodcrypt_md5(newpass, s_pas);
++				if (!strcmp(md5pass, s_pas)) {
++					_pam_delete(md5pass);
++					retval = PAM_AUTHTOK_ERR;
++					break;
++				}
++				s_pas = strtok_r(NULL, ":,", &sptr);
++				_pam_delete(md5pass);
++			}
++			break;
++		}
++	}
++	fclose(opwfile);
++
++	return retval;
++}
++
++static int _do_setpass(pam_handle_t* pamh, const char *forwho,
++		       const char *fromwhat,
++		       char *towhat, unsigned int ctrl, int remember)
++{
++	struct passwd *pwd = NULL;
++	int retval = 0;
++	int unlocked = 0;
++	char *master = NULL;
++
++	D(("called"));
++
++	pwd = getpwnam(forwho);
++
++	if (pwd == NULL) {
++		retval = PAM_AUTHTOK_ERR;
++		goto done;
++	}
++
++	if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) {
++#ifdef HAVE_NIS
++	  if ((master=getNISserver(pamh, ctrl)) != NULL) {
++		struct timeval timeout;
++		struct yppasswd yppwd;
++		CLIENT *clnt;
++		int status;
++		enum clnt_stat err;
++
++		/* Unlock passwd file to avoid deadlock */
++		unlock_pwdf();
++		unlocked = 1;
++
++		/* Initialize password information */
++		yppwd.newpw.pw_passwd = pwd->pw_passwd;
++		yppwd.newpw.pw_name = pwd->pw_name;
++		yppwd.newpw.pw_uid = pwd->pw_uid;
++		yppwd.newpw.pw_gid = pwd->pw_gid;
++		yppwd.newpw.pw_gecos = pwd->pw_gecos;
++		yppwd.newpw.pw_dir = pwd->pw_dir;
++		yppwd.newpw.pw_shell = pwd->pw_shell;
++		yppwd.oldpass = fromwhat ? strdup (fromwhat) : strdup ("");
++		yppwd.newpw.pw_passwd = towhat;
++
++		D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho));
++
++		/* The yppasswd.x file said `unix authentication required',
++		 * so I added it. This is the only reason it is in here.
++		 * My yppasswdd doesn't use it, but maybe some others out there
++		 * do.                                        --okir
++		 */
++		clnt = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp");
++		clnt->cl_auth = authunix_create_default();
++		memset((char *) &status, '\0', sizeof(status));
++		timeout.tv_sec = 25;
++		timeout.tv_usec = 0;
++		err = clnt_call(clnt, YPPASSWDPROC_UPDATE,
++				(xdrproc_t) xdr_yppasswd, (char *) &yppwd,
++				(xdrproc_t) xdr_int, (char *) &status,
++				timeout);
++
++		free (yppwd.oldpass);
++
++		if (err) {
++			_make_remark(pamh, ctrl, PAM_TEXT_INFO,
++				clnt_sperrno(err));
++		} else if (status) {
++			D(("Error while changing NIS password.\n"));
++		}
++		D(("The password has%s been changed on %s.",
++		   (err || status) ? " not" : "", master));
++		pam_syslog(pamh, LOG_NOTICE, "password%s changed for %s on %s",
++			 (err || status) ? " not" : "", pwd->pw_name, master);
++
++		auth_destroy(clnt->cl_auth);
++		clnt_destroy(clnt);
++		if (err || status) {
++			_make_remark(pamh, ctrl, PAM_TEXT_INFO,
++				_("NIS password could not be changed."));
++			retval = PAM_TRY_AGAIN;
++		}
++#ifdef PAM_DEBUG
++		sleep(5);
++#endif
++	    } else {
++		    retval = PAM_TRY_AGAIN;
++	    }
++#else
++          if (on(UNIX_DEBUG, ctrl)) {
++            pam_syslog(pamh, LOG_DEBUG, "No NIS support available");
++          }
++
++          retval = PAM_TRY_AGAIN;
++#endif
++	}
++
++	if (_unix_comesfromsource(pamh, forwho, 1, 0)) {
++		if(unlocked) {
++			if (lock_pwdf() != PAM_SUCCESS) {
++				return PAM_AUTHTOK_LOCK_BUSY;
++			}
++		}
++#ifdef WITH_SELINUX
++	        if (unix_selinux_confined())
++			  return _unix_run_update_binary(pamh, ctrl, forwho, fromwhat, towhat, remember);
++#endif
++		/* first, save old password */
++		if (save_old_password(pamh, forwho, fromwhat, remember)) {
++			retval = PAM_AUTHTOK_ERR;
++			goto done;
++		}
++		if (on(UNIX_SHADOW, ctrl) || is_pwd_shadowed(pwd)) {
++			retval = unix_update_shadow(pamh, forwho, towhat);
++			if (retval == PAM_SUCCESS)
++				if (!is_pwd_shadowed(pwd))
++					retval = unix_update_passwd(pamh, forwho, "x");
++		} else {
++			retval = unix_update_passwd(pamh, forwho, towhat);
++		}
++	}
++
++
++done:
++	unlock_pwdf();
++
++	return retval;
++}
++
++static int _unix_verify_shadow(pam_handle_t *pamh, const char *user, unsigned int ctrl)
++{
++	struct passwd *pwent = NULL;	/* Password and shadow password */
++	struct spwd *spent = NULL;	/* file entries for the user */
++	int daysleft;
++	int retval;
++
++	retval = get_account_info(pamh, user, &pwent, &spent);
++	if (retval == PAM_USER_UNKNOWN) {
++		return retval;
++	}
++
++	if (retval == PAM_SUCCESS && spent == NULL)
++		return PAM_SUCCESS;
++
++	if (retval == PAM_UNIX_RUN_HELPER) {
++		retval = _unix_run_verify_binary(pamh, ctrl, user, &daysleft);
++		if (retval == PAM_AUTH_ERR || retval == PAM_USER_UNKNOWN)
++			return retval;
++	}
++	else if (retval == PAM_SUCCESS)
++		retval = check_shadow_expiry(pamh, spent, &daysleft);
++
++	if (on(UNIX__IAMROOT, ctrl) || retval == PAM_NEW_AUTHTOK_REQD)
++		return PAM_SUCCESS;
++
++	return retval;
++}
++
++static int _pam_unix_approve_pass(pam_handle_t * pamh
++				  ,unsigned int ctrl
++				  ,const char *pass_old
++				  ,const char *pass_new,
++                                  int pass_min_len)
++{
++	const void *user;
++	const char *remark = NULL;
++	int retval = PAM_SUCCESS;
++
++	D(("&new=%p, &old=%p", pass_old, pass_new));
++	D(("new=[%s]", pass_new));
++	D(("old=[%s]", pass_old));
++
++	if (pass_new == NULL || (pass_old && !strcmp(pass_old, pass_new))) {
++		if (on(UNIX_DEBUG, ctrl)) {
++			pam_syslog(pamh, LOG_DEBUG, "bad authentication token");
++		}
++		_make_remark(pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ?
++			_("No password supplied") : _("Password unchanged"));
++		return PAM_AUTHTOK_ERR;
++	}
++	/*
++	 * if one wanted to hardwire authentication token strength
++	 * checking this would be the place - AGM
++	 */
++
++	retval = pam_get_item(pamh, PAM_USER, &user);
++	if (retval != PAM_SUCCESS) {
++		if (on(UNIX_DEBUG, ctrl)) {
++			pam_syslog(pamh, LOG_ERR, "Can not get username");
++			return PAM_AUTHTOK_ERR;
++		}
++	}
++	if (off(UNIX__IAMROOT, ctrl)) {
++		if (strlen(pass_new) < pass_min_len)
++		  remark = _("You must choose a longer password");
++		D(("length check [%s]", remark));
++		if (on(UNIX_REMEMBER_PASSWD, ctrl)) {
++			if ((retval = check_old_password(user, pass_new)) == PAM_AUTHTOK_ERR)
++			  remark = _("Password has been already used. Choose another.");
++			if (retval == PAM_ABORT) {
++				pam_syslog(pamh, LOG_ERR, "can't open %s file to check old passwords",
++					OLD_PASSWORDS_FILE);
++				return retval;
++			}
++		}
++		if (!remark && pass_old != NULL) { /* only check if we don't already have a failure */
++			struct passwd *pwd;
++			pwd = pam_modutil_getpwnam(pamh, user);
++			remark = (char *)obscure_msg(pass_old,pass_new,pwd,ctrl); /* do obscure checks */
++		}
++	}
++	if (remark) {
++		_make_remark(pamh, ctrl, PAM_ERROR_MSG, remark);
++		retval = PAM_AUTHTOK_ERR;
++	}
++	return retval;
++}
++
++int
++pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
++{
++	unsigned int ctrl, lctrl;
++	int retval;
++	int remember = -1;
++	int rounds = -1;
++	int pass_min_len = 6;
++
++	/* <DO NOT free() THESE> */
++	const char *user;
++	const void *pass_old, *pass_new;
++	/* </DO NOT free() THESE> */
++
++	D(("called."));
++
++	ctrl = _set_ctrl(pamh, flags, &remember, &rounds, &pass_min_len,
++	                 argc, argv);
++
++	/*
++	 * First get the name of a user
++	 */
++	retval = pam_get_user(pamh, &user, NULL);
++	if (retval == PAM_SUCCESS) {
++		/*
++		 * Various libraries at various times have had bugs related to
++		 * '+' or '-' as the first character of a user name. Don't
++		 * allow them.
++		 */
++		if (user == NULL || user[0] == '-' || user[0] == '+') {
++			pam_syslog(pamh, LOG_ERR, "bad username [%s]", user);
++			return PAM_USER_UNKNOWN;
++		}
++		if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl))
++			pam_syslog(pamh, LOG_DEBUG, "username [%s] obtained",
++			         user);
++	} else {
++		if (on(UNIX_DEBUG, ctrl))
++			pam_syslog(pamh, LOG_DEBUG,
++			         "password - could not identify user");
++		return retval;
++	}
++
++	D(("Got username of %s", user));
++
++	/*
++	 * Before we do anything else, check to make sure that the user's
++	 * info is in one of the databases we can modify from this module,
++	 * which currently is 'files' and 'nis'.  We have to do this because
++	 * getpwnam() doesn't tell you *where* the information it gives you
++	 * came from, nor should it.  That's our job.
++	 */
++	if (_unix_comesfromsource(pamh, user, 1, on(UNIX_NIS, ctrl)) == 0) {
++		pam_syslog(pamh, LOG_DEBUG,
++			 "user \"%s\" does not exist in /var/lib/extrausers/passwd%s",
++			 user, on(UNIX_NIS, ctrl) ? " or NIS" : "");
++		return PAM_USER_UNKNOWN;
++	} else {
++		struct passwd *pwd;
++		_unix_getpwnam(pamh, user, 1, on(UNIX_NIS, ctrl), &pwd);
++		if (pwd == NULL) {
++			pam_syslog(pamh, LOG_DEBUG,
++				"user \"%s\" has corrupted passwd entry",
++				user);
++			return PAM_USER_UNKNOWN;
++		}
++	}
++
++	/*
++	 * This is not an AUTH module!
++	 */
++	if (on(UNIX__NONULL, ctrl))
++		set(UNIX__NULLOK, ctrl);
++
++	if (on(UNIX__PRELIM, ctrl)) {
++		/*
++		 * obtain and verify the current password (OLDAUTHTOK) for
++		 * the user.
++		 */
++		char *Announce;
++
++		D(("prelim check"));
++
++		if (_unix_blankpasswd(pamh, ctrl, user)) {
++			return PAM_SUCCESS;
++		} else if (off(UNIX__IAMROOT, ctrl) || on(UNIX_NIS, ctrl)) {
++			/* instruct user what is happening */
++			if (asprintf(&Announce, _("Changing password for %s."),
++				user) < 0) {
++				pam_syslog(pamh, LOG_CRIT,
++				         "password - out of memory");
++				return PAM_BUF_ERR;
++			}
++
++			lctrl = ctrl;
++			set(UNIX__OLD_PASSWD, lctrl);
++			retval = _unix_read_password(pamh, lctrl
++						     ,Announce
++					     ,(on(UNIX__IAMROOT, ctrl)
++			                       ? _("NIS server root password: ")
++			                       : _("(current) UNIX password: "))
++						     ,NULL
++						     ,_UNIX_OLD_AUTHTOK
++					     ,&pass_old);
++			free(Announce);
++
++			if (retval != PAM_SUCCESS) {
++				pam_syslog(pamh, LOG_NOTICE,
++				    "password - (old) token not obtained");
++				return retval;
++			}
++			/* verify that this is the password for this user
++			 * if we're not using NIS */
++
++			if (off(UNIX_NIS, ctrl)) {
++				retval = _unix_verify_password(pamh, user, pass_old, ctrl);
++			}
++		} else {
++			D(("process run by root so do nothing this time around"));
++			pass_old = NULL;
++			retval = PAM_SUCCESS;	/* root doesn't have too */
++		}
++
++		if (retval != PAM_SUCCESS) {
++			D(("Authentication failed"));
++			pass_old = NULL;
++			return retval;
++		}
++		retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old);
++		pass_old = NULL;
++		if (retval != PAM_SUCCESS) {
++			pam_syslog(pamh, LOG_CRIT,
++			         "failed to set PAM_OLDAUTHTOK");
++		}
++		retval = _unix_verify_shadow(pamh,user, ctrl);
++		if (retval == PAM_AUTHTOK_ERR) {
++			if (off(UNIX__IAMROOT, ctrl))
++				_make_remark(pamh, ctrl, PAM_ERROR_MSG,
++					     _("You must wait longer to change your password"));
++			else
++				retval = PAM_SUCCESS;
++		}
++	} else if (on(UNIX__UPDATE, ctrl)) {
++		/*
++		 * tpass is used below to store the _pam_md() return; it
++		 * should be _pam_delete()'d.
++		 */
++
++		char *tpass = NULL;
++		int retry = 0;
++
++		/*
++		 * obtain the proposed password
++		 */
++
++		D(("do update"));
++
++		/*
++		 * get the old token back. NULL was ok only if root [at this
++		 * point we assume that this has already been enforced on a
++		 * previous call to this function].
++		 */
++
++		if (off(UNIX_NOT_SET_PASS, ctrl)) {
++			retval = pam_get_item(pamh, PAM_OLDAUTHTOK
++					      ,&pass_old);
++		} else {
++			retval = pam_get_data(pamh, _UNIX_OLD_AUTHTOK
++					      ,&pass_old);
++			if (retval == PAM_NO_MODULE_DATA) {
++				retval = PAM_SUCCESS;
++				pass_old = NULL;
++			}
++		}
++		D(("pass_old [%s]", pass_old));
++
++		if (retval != PAM_SUCCESS) {
++			pam_syslog(pamh, LOG_NOTICE, "user not authenticated");
++			return retval;
++		}
++
++		D(("get new password now"));
++
++		lctrl = ctrl;
++
++		if (on(UNIX_USE_AUTHTOK, lctrl)) {
++			set(UNIX_USE_FIRST_PASS, lctrl);
++		}
++		retry = 0;
++		retval = PAM_AUTHTOK_ERR;
++		while ((retval != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) {
++			/*
++			 * use_authtok is to force the use of a previously entered
++			 * password -- needed for pluggable password strength checking
++			 */
++
++			retval = _unix_read_password(pamh, lctrl
++						     ,NULL
++					     ,_("Enter new UNIX password: ")
++					    ,_("Retype new UNIX password: ")
++						     ,_UNIX_NEW_AUTHTOK
++					     ,&pass_new);
++
++			if (retval != PAM_SUCCESS) {
++				if (on(UNIX_DEBUG, ctrl)) {
++					pam_syslog(pamh, LOG_ALERT,
++						 "password - new password not obtained");
++				}
++				pass_old = NULL;	/* tidy up */
++				return retval;
++			}
++			D(("returned to _unix_chauthtok"));
++
++			/*
++			 * At this point we know who the user is and what they
++			 * propose as their new password. Verify that the new
++			 * password is acceptable.
++			 */
++
++			if (*(const char *)pass_new == '\0') {	/* "\0" password = NULL */
++				pass_new = NULL;
++			}
++			retval = _pam_unix_approve_pass(pamh, ctrl, pass_old,
++			                                pass_new, pass_min_len);
++
++			if (retval != PAM_SUCCESS && off(UNIX_NOT_SET_PASS, ctrl)) {
++				pam_set_item(pamh, PAM_AUTHTOK, NULL);
++			}
++		}
++
++		if (retval != PAM_SUCCESS) {
++			pam_syslog(pamh, LOG_NOTICE,
++			         "new password not acceptable");
++			pass_new = pass_old = NULL;	/* tidy up */
++			return retval;
++		}
++		if (lock_pwdf() != PAM_SUCCESS) {
++			return PAM_AUTHTOK_LOCK_BUSY;
++		}
++
++		if (pass_old) {
++			retval = _unix_verify_password(pamh, user, pass_old, ctrl);
++			if (retval != PAM_SUCCESS) {
++				pam_syslog(pamh, LOG_NOTICE, "user password changed by another process");
++				unlock_pwdf();
++				return retval;
++			}
++		}
++
++		retval = _unix_verify_shadow(pamh, user, ctrl);
++		if (retval != PAM_SUCCESS) {
++			pam_syslog(pamh, LOG_NOTICE, "user shadow entry expired");
++			unlock_pwdf();
++			return retval;
++		}
++
++		retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new,
++		                                pass_min_len);
++		if (retval != PAM_SUCCESS) {
++			pam_syslog(pamh, LOG_NOTICE,
++			         "new password not acceptable 2");
++			pass_new = pass_old = NULL;	/* tidy up */
++			unlock_pwdf();
++			return retval;
++		}
++
++		/*
++		 * By reaching here we have approved the passwords and must now
++		 * rebuild the password database file.
++		 */
++
++		/*
++		 * First we encrypt the new password.
++		 */
++
++		tpass = create_password_hash(pamh, pass_new, ctrl, rounds);
++		if (tpass == NULL) {
++			pam_syslog(pamh, LOG_CRIT,
++				"crypt() failure or out of memory for password");
++			pass_new = pass_old = NULL;	/* tidy up */
++			unlock_pwdf();
++			return PAM_BUF_ERR;
++		}
++
++		D(("password processed"));
++
++		/* update the password database(s) -- race conditions..? */
++
++		retval = _do_setpass(pamh, user, pass_old, tpass, ctrl,
++		                     remember);
++	        /* _do_setpass has called unlock_pwdf for us */
++
++		_pam_delete(tpass);
++		pass_old = pass_new = NULL;
++	} else {		/* something has broken with the module */
++		pam_syslog(pamh, LOG_ALERT,
++		         "password received unknown request");
++		retval = PAM_ABORT;
++	}
++
++	D(("retval was %d", retval));
++
++	return retval;
++}
+--- /dev/null
++++ b/modules/pam_extrausers/pam_unix_sess.c
+@@ -0,0 +1,133 @@
++/*
++ * $Id$
++ *
++ * Copyright Alexander O. Yuriev, 1996.  All rights reserved.
++ * Copyright Jan R\EAkorajski, 1999.  All rights reserved.
++ *
++ * 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 <stdio.h>
++#include <stdlib.h>
++#include <stdarg.h>
++#include <unistd.h>
++#include <syslog.h>
++#include <fcntl.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++
++/* indicate the following groups are defined */
++
++#ifdef PAM_STATIC
++# include "pam_unix_static.h"
++#else
++# define PAM_SM_SESSION
++#endif
++
++#include <security/_pam_macros.h>
++#include <security/pam_modules.h>
++#include <security/pam_ext.h>
++#include <security/pam_modutil.h>
++
++#include "support.h"
++
++/*
++ * PAM framework looks for these entry-points to pass control to the
++ * session module.
++ */
++
++int
++pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
++{
++	char *user_name, *service;
++	unsigned int ctrl;
++	int retval;
++    const char *login_name;
++
++	D(("called."));
++
++	ctrl = _set_ctrl(pamh, flags, NULL, NULL, NULL, argc, argv);
++
++	retval = pam_get_item(pamh, PAM_USER, (void *) &user_name);
++	if (user_name == NULL || *user_name == '\0' || retval != PAM_SUCCESS) {
++		pam_syslog(pamh, LOG_CRIT,
++		         "open_session - error recovering username");
++		return PAM_SESSION_ERR;		/* How did we get authenticated with
++						   no username?! */
++	}
++	retval = pam_get_item(pamh, PAM_SERVICE, (void *) &service);
++	if (service == NULL || *service == '\0' || retval != PAM_SUCCESS) {
++		pam_syslog(pamh, LOG_CRIT,
++		         "open_session - error recovering service");
++		return PAM_SESSION_ERR;
++	}
++	login_name = pam_modutil_getlogin(pamh);
++	if (login_name == NULL) {
++	    login_name = "";
++	}
++	pam_syslog(pamh, LOG_INFO, "session opened for user %s by %s(uid=%lu)",
++		 user_name, login_name, (unsigned long)getuid());
++
++	return PAM_SUCCESS;
++}
++
++int
++pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
++{
++	char *user_name, *service;
++	unsigned int ctrl;
++	int retval;
++
++	D(("called."));
++
++	ctrl = _set_ctrl(pamh, flags, NULL, NULL, NULL, argc, argv);
++
++	retval = pam_get_item(pamh, PAM_USER, (void *) &user_name);
++	if (user_name == NULL || *user_name == '\0' || retval != PAM_SUCCESS) {
++		pam_syslog(pamh, LOG_CRIT,
++		         "close_session - error recovering username");
++		return PAM_SESSION_ERR;		/* How did we get authenticated with
++						   no username?! */
++	}
++	retval = pam_get_item(pamh, PAM_SERVICE, (void *) &service);
++	if (service == NULL || *service == '\0' || retval != PAM_SUCCESS) {
++		pam_syslog(pamh, LOG_CRIT,
++		         "close_session - error recovering service");
++		return PAM_SESSION_ERR;
++	}
++	pam_syslog(pamh, LOG_INFO, "session closed for user %s",
++		user_name);
++
++	return PAM_SUCCESS;
++}
+--- /dev/null
++++ b/modules/pam_extrausers/pam_unix_static.c
+@@ -0,0 +1,23 @@
++#include "config.h"
++
++#ifdef PAM_STATIC
++
++#define static extern
++#define PAM_SM_ACCOUNT
++#define PAM_SM_AUTH
++#define PAM_SM_PASSWORD
++#define PAM_SM_SESSION
++#include "pam_unix_static.h"
++#include <security/pam_modules.h>
++
++struct pam_module _pam_extrausers_modstruct = {
++	"pam_extrausers",
++	pam_sm_authenticate,
++	pam_sm_setcred,
++	pam_sm_acct_mgmt,
++	pam_sm_open_session,
++	pam_sm_close_session,
++	pam_sm_chauthtok,
++};
++
++#endif
+--- /dev/null
++++ b/modules/pam_extrausers/pam_unix_static.h
+@@ -0,0 +1,6 @@
++#define pam_sm_acct_mgmt _pam_unix_sm_acct_mgmt
++#define pam_sm_authenticate _pam_unix_sm_authenticate
++#define pam_sm_setcred _pam_unix_sm_setcred
++#define pam_sm_chauthtok _pam_unix_sm_chauthtok
++#define pam_sm_open_session _pam_unix_sm_open_session
++#define pam_sm_close_session _pam_unix_sm_close_session
+--- /dev/null
++++ b/modules/pam_extrausers/passverify.c
+@@ -0,0 +1,1164 @@
++/*
++ * Copyright information at end of file.
++ */
++#include "config.h"
++#include <security/_pam_macros.h>
++#include <security/pam_modules.h>
++#include "support.h"
++#include <stdio.h>
++#include <string.h>
++#include <sys/types.h>
++#include <unistd.h>
++#include <pwd.h>
++#include <shadow.h>
++#include <syslog.h>
++#include <stdarg.h>
++#include <signal.h>
++#include <errno.h>
++#include <time.h>
++#include <sys/time.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#ifdef HAVE_LIBXCRYPT
++#include <xcrypt.h>
++#elif defined(HAVE_CRYPT_H)
++#include <crypt.h>
++#endif
++
++#include "md5.h"
++#include "bigcrypt.h"
++#include "passverify.h"
++
++#ifdef WITH_SELINUX
++#include <selinux/selinux.h>
++#define SELINUX_ENABLED is_selinux_enabled()>0
++#else
++#define SELINUX_ENABLED 0
++#endif
++
++#ifdef HELPER_COMPILE
++#define pam_modutil_getpwnam(h,n) getpwnam(n)
++#define pam_modutil_getspnam(h,n) getspnam(n)
++#define pam_syslog(h,a,b,c) helper_log_err(a,b,c)
++#else
++#include <security/pam_modutil.h>
++#include <security/pam_ext.h>
++#endif
++
++#if defined(USE_LCKPWDF)
++# include "./lckpwdf.-c"
++#endif
++
++static void
++strip_hpux_aging(char *hash)
++{
++	static const char valid[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++		"abcdefghijklmnopqrstuvwxyz"
++		"0123456789./";
++	if ((*hash != '$') && (strlen(hash) > 13)) {
++		for (hash += 13; *hash != '\0'; hash++) {
++			if (strchr(valid, *hash) == NULL) {
++				*hash = '\0';
++				break;
++			}
++		}
++	}
++}
++
++int
++verify_pwd_hash(const char *p, char *hash, unsigned int nullok)
++{
++	size_t hash_len;
++	char *pp = NULL;
++	int retval;
++	D(("called"));
++
++	strip_hpux_aging(hash);
++	hash_len = strlen(hash);
++	if (!hash_len) {
++		/* the stored password is NULL */
++		if (nullok) { /* this means we've succeeded */
++			D(("user has empty password - access granted"));
++			retval = PAM_SUCCESS;
++		} else {
++			D(("user has empty password - access denied"));
++			retval = PAM_AUTH_ERR;
++		}
++	} else if (!p || *hash == '*' || *hash == '!') {
++		retval = PAM_AUTH_ERR;
++	} else {
++		if (!strncmp(hash, "$1$", 3)) {
++			pp = Goodcrypt_md5(p, hash);
++			if (pp && strcmp(pp, hash) != 0) {
++				_pam_delete(pp);
++				pp = Brokencrypt_md5(p, hash);
++			}
++		} else if (*hash != '$' && hash_len >= 13) {
++			pp = bigcrypt(p, hash);
++			if (pp && hash_len == 13 && strlen(pp) > hash_len) {
++				_pam_overwrite(pp + hash_len);
++			}
++		} else {
++			/*
++			 * Ok, we don't know the crypt algorithm, but maybe
++			 * libcrypt knows about it? We should try it.
++			 */
++#ifdef HAVE_CRYPT_R
++			struct crypt_data *cdata;
++			cdata = malloc(sizeof(*cdata));
++			if (cdata != NULL) {
++				cdata->initialized = 0;
++				pp = x_strdup(crypt_r(p, hash, cdata));
++				memset(cdata, '\0', sizeof(*cdata));
++				free(cdata);
++			}
++#else
++			pp = x_strdup(crypt(p, hash));
++#endif
++		}
++		p = NULL;		/* no longer needed here */
++
++		/* the moment of truth -- do we agree with the password? */
++		D(("comparing state of pp[%s] and hash[%s]", pp, hash));
++
++		if (pp && strcmp(pp, hash) == 0) {
++			retval = PAM_SUCCESS;
++		} else {
++			retval = PAM_AUTH_ERR;
++		}
++	}
++
++	if (pp)
++		_pam_delete(pp);
++	D(("done [%d].", retval));
++
++	return retval;
++}
++
++int
++is_pwd_shadowed(const struct passwd *pwd)
++{
++	if (pwd != NULL) {
++		if (strcmp(pwd->pw_passwd, "x") == 0) {
++			return 1;
++		}
++		if ((pwd->pw_passwd[0] == '#') &&
++		    (pwd->pw_passwd[1] == '#') &&
++		    (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0)) {
++			return 1;
++		}
++	}
++	return 0;
++}
++
++PAMH_ARG_DECL(int get_account_info,
++	const char *name, struct passwd **pwd, struct spwd **spwdent)
++{
++	/* UNIX passwords area */
++	*pwd = pam_modutil_getpwnam(pamh, name);	/* Get password file entry... */
++	*spwdent = NULL;
++
++	if (*pwd != NULL) {
++		if (strcmp((*pwd)->pw_passwd, "*NP*") == 0)
++		{ /* NIS+ */
++#ifdef HELPER_COMPILE
++			uid_t save_euid, save_uid;
++
++			save_euid = geteuid();
++			save_uid = getuid();
++			if (save_uid == (*pwd)->pw_uid)
++				setreuid(save_euid, save_uid);
++			else  {
++				setreuid(0, -1);
++				if (setreuid(-1, (*pwd)->pw_uid) == -1) {
++					setreuid(-1, 0);
++					setreuid(0, -1);
++					if(setreuid(-1, (*pwd)->pw_uid) == -1)
++						return PAM_CRED_INSUFFICIENT;
++				}
++			}
++
++			*spwdent = pam_modutil_getspnam(pamh, name);
++			if (save_uid == (*pwd)->pw_uid)
++				setreuid(save_uid, save_euid);
++			else {
++				setreuid(-1, 0);
++				setreuid(save_uid, -1);
++				setreuid(-1, save_euid);
++			}
++
++			if (*spwdent == NULL || (*spwdent)->sp_pwdp == NULL)
++				return PAM_AUTHINFO_UNAVAIL;
++#else
++			/* we must run helper for NIS+ passwords */
++			return PAM_UNIX_RUN_HELPER;
++#endif
++		} else if (is_pwd_shadowed(*pwd)) {
++			/*
++			 * ...and shadow password file entry for this user,
++			 * if shadowing is enabled
++			 */
++			*spwdent = pam_modutil_getspnam(pamh, name);
++#ifndef HELPER_COMPILE
++			if (*spwdent == NULL && (geteuid() || SELINUX_ENABLED))
++				return PAM_UNIX_RUN_HELPER;
++#endif
++			if (*spwdent == NULL || (*spwdent)->sp_pwdp == NULL)
++				return PAM_AUTHINFO_UNAVAIL;
++		}
++	} else {
++		return PAM_USER_UNKNOWN;
++	}
++	return PAM_SUCCESS;
++}
++
++PAMH_ARG_DECL(int get_pwd_hash,
++	const char *name, struct passwd **pwd, char **hash)
++{
++	int retval;
++	struct spwd *spwdent = NULL;
++
++	retval = get_account_info(PAMH_ARG(name, pwd, &spwdent));
++	if (retval != PAM_SUCCESS) {
++		return retval;
++	}
++
++	if (spwdent)
++		*hash = x_strdup(spwdent->sp_pwdp);
++	else
++		*hash = x_strdup((*pwd)->pw_passwd);
++	if (*hash == NULL)
++		return PAM_BUF_ERR;
++
++	return PAM_SUCCESS;
++}
++
++PAMH_ARG_DECL(int check_shadow_expiry,
++	struct spwd *spent, int *daysleft)
++{
++	long int curdays;
++	*daysleft = -1;
++	curdays = (long int)(time(NULL) / (60 * 60 * 24));
++	D(("today is %d, last change %d", curdays, spent->sp_lstchg));
++	if ((curdays >= spent->sp_expire) && (spent->sp_expire != -1)) {
++		D(("account expired"));
++		return PAM_ACCT_EXPIRED;
++	}
++	if (spent->sp_lstchg == 0) {
++		D(("need a new password"));
++		*daysleft = 0;
++		return PAM_NEW_AUTHTOK_REQD;
++	}
++	if (curdays < spent->sp_lstchg) {
++		pam_syslog(pamh, LOG_DEBUG,
++			 "account %s has password changed in future",
++			 spent->sp_namp);
++		return PAM_SUCCESS;
++	}
++	if ((curdays - spent->sp_lstchg > spent->sp_max)
++	    && (curdays - spent->sp_lstchg > spent->sp_inact)
++	    && (curdays - spent->sp_lstchg > spent->sp_max + spent->sp_inact)
++	    && (spent->sp_max != -1) && (spent->sp_inact != -1)) {
++		*daysleft = (int)((spent->sp_lstchg + spent->sp_max) - curdays);
++		D(("authtok expired"));
++		return PAM_AUTHTOK_EXPIRED;
++	}
++	if ((curdays - spent->sp_lstchg > spent->sp_max) && (spent->sp_max != -1)) {
++		D(("need a new password 2"));
++		return PAM_NEW_AUTHTOK_REQD;
++	}
++	if ((curdays - spent->sp_lstchg > spent->sp_max - spent->sp_warn)
++	    && (spent->sp_max != -1) && (spent->sp_warn != -1)) {
++		*daysleft = (int)((spent->sp_lstchg + spent->sp_max) - curdays);
++		D(("warn before expiry"));
++	}
++	if ((curdays - spent->sp_lstchg < spent->sp_min)
++	    && (spent->sp_min != -1)) {
++		/*
++		 * The last password change was too recent. This error will be ignored
++		 * if no password change is attempted.
++		 */
++		D(("password change too recent"));
++		return PAM_AUTHTOK_ERR;
++	}
++	return PAM_SUCCESS;
++}
++
++/* passwd/salt conversion macros */
++
++#define PW_TMPFILE              "/var/lib/extrausers/npasswd"
++#define SH_TMPFILE              "/var/lib/extrausers/nshadow"
++#define OPW_TMPFILE             "/var/lib/extrausers/nopasswd"
++
++/*
++ * i64c - convert an integer to a radix 64 character
++ */
++static int
++i64c(int i)
++{
++        if (i < 0)
++                return ('.');
++        else if (i > 63)
++                return ('z');
++        if (i == 0)
++                return ('.');
++        if (i == 1)
++                return ('/');
++        if (i >= 2 && i <= 11)
++                return ('0' - 2 + i);
++        if (i >= 12 && i <= 37)
++                return ('A' - 12 + i);
++        if (i >= 38 && i <= 63)
++                return ('a' - 38 + i);
++        return ('\0');
++}
++
++/* <where> must point to a buffer of at least <length>+1 length */
++static void
++crypt_make_salt(char *where, int length)
++{
++        struct timeval tv;
++        MD5_CTX ctx;
++        unsigned char tmp[16];
++        unsigned char *src = (unsigned char *)where;
++        int i;
++#ifdef PAM_PATH_RANDOMDEV
++	int fd;
++	int rv;
++
++	if ((rv = fd = open(PAM_PATH_RANDOMDEV, O_RDONLY)) != -1) {
++		while ((rv = read(fd, where, length)) != length && errno == EINTR);
++		close (fd);
++	}
++	if (rv != length) {
++#endif
++        /*
++         * Code lifted from Marek Michalkiewicz's shadow suite. (CG)
++         * removed use of static variables (AGM)
++         *
++	 * will work correctly only for length <= 16 */
++	src = tmp;
++        GoodMD5Init(&ctx);
++        gettimeofday(&tv, (struct timezone *) 0);
++        GoodMD5Update(&ctx, (void *) &tv, sizeof tv);
++        i = getpid();
++        GoodMD5Update(&ctx, (void *) &i, sizeof i);
++        i = clock();
++        GoodMD5Update(&ctx, (void *) &i, sizeof i);
++        GoodMD5Update(&ctx, src, length);
++        GoodMD5Final(tmp, &ctx);
++#ifdef PAM_PATH_RANDOMDEV
++	}
++#endif
++        for (i = 0; i < length; i++)
++                *where++ = i64c(src[i] & 077);
++        *where = '\0';
++}
++
++char *
++crypt_md5_wrapper(const char *pass_new)
++{
++        unsigned char result[16];
++        char *cp = (char *) result;
++
++        cp = stpcpy(cp, "$1$");      /* magic for the MD5 */
++	crypt_make_salt(cp, 8);
++
++        /* no longer need cleartext */
++        cp = Goodcrypt_md5(pass_new, (const char *) result);
++	pass_new = NULL;
++
++        return cp;
++}
++
++PAMH_ARG_DECL(char * create_password_hash,
++	const char *password, unsigned int ctrl, int rounds)
++{
++	const char *algoid;
++	char salt[64]; /* contains rounds number + max 16 bytes of salt + algo id */
++	char *sp;
++
++	if (on(UNIX_MD5_PASS, ctrl)) {
++		/* algoid = "$1" */
++		return crypt_md5_wrapper(password);
++	} else if (on(UNIX_BLOWFISH_PASS, ctrl)) {
++		algoid = "$2a$";
++	} else if (on(UNIX_SHA256_PASS, ctrl)) {
++		algoid = "$5$";
++	} else if (on(UNIX_SHA512_PASS, ctrl)) {
++		algoid = "$6$";
++	} else { /* must be crypt/bigcrypt */
++		char tmppass[9];
++		char *crypted;
++
++		crypt_make_salt(salt, 2);
++		if (off(UNIX_BIGCRYPT, ctrl) && strlen(password) > 8) {
++			strncpy(tmppass, password, sizeof(tmppass)-1);
++			tmppass[sizeof(tmppass)-1] = '\0';
++			password = tmppass;
++		}
++		crypted = bigcrypt(password, salt);
++		memset(tmppass, '\0', sizeof(tmppass));
++		password = NULL;
++		return crypted;
++	}
++
++#ifdef HAVE_CRYPT_GENSALT_R
++	if (on(UNIX_BLOWFISH_PASS, ctrl)) {
++		char entropy[17];
++		crypt_make_salt(entropy, sizeof(entropy) - 1);
++		sp = crypt_gensalt_r (algoid, rounds,
++				      entropy, sizeof(entropy),
++				      salt, sizeof(salt));
++	} else {
++#endif
++		sp = stpcpy(salt, algoid);
++		if (on(UNIX_ALGO_ROUNDS, ctrl)) {
++			sp += snprintf(sp, sizeof(salt) - 3, "rounds=%u$", rounds);
++		}
++		crypt_make_salt(sp, 8);
++		/* For now be conservative so the resulting hashes
++		 * are not too long. 8 bytes of salt prevents dictionary
++		 * attacks well enough. */
++#ifdef HAVE_CRYPT_GENSALT_R
++	}
++#endif
++	sp = crypt(password, salt);
++	if (!sp || strncmp(algoid, sp, strlen(algoid)) != 0) {
++		/* libxcrypt/libc doesn't know the algorithm, use MD5 */
++		pam_syslog(pamh, LOG_ERR,
++			   "Algo %s not supported by the crypto backend, "
++			   "falling back to MD5\n",
++			   on(UNIX_BLOWFISH_PASS, ctrl) ? "blowfish" :
++			   on(UNIX_SHA256_PASS, ctrl) ? "sha256" :
++			   on(UNIX_SHA512_PASS, ctrl) ? "sha512" : algoid);
++		if(sp) {
++		   memset(sp, '\0', strlen(sp));
++		}
++		return crypt_md5_wrapper(password);
++	}
++
++	return x_strdup(sp);
++}
++
++#ifdef WITH_SELINUX
++int
++unix_selinux_confined(void)
++{
++    static int confined = -1;
++    int fd;
++    char tempfile[]="/var/lib/extrausers/.pwdXXXXXX";
++
++    if (confined != -1)
++	return confined;
++
++    /* cannot be confined without SELinux enabled */
++    if (!SELINUX_ENABLED){
++	confined = 0;
++	return confined;
++    }
++
++    /* let's try opening shadow read only */
++    if ((fd=open("/var/lib/extrausers/shadow", O_RDONLY)) != -1) {
++        close(fd);
++        confined = 0;
++        return confined;
++    }
++
++    if (errno == EACCES) {
++	confined = 1;
++	return confined;
++    }
++
++    /* shadow opening failed because of other reasons let's try
++       creating a file in /var/lib/extrausers */
++    if ((fd=mkstemp(tempfile)) != -1) {
++        unlink(tempfile);
++        close(fd);
++        confined = 0;
++        return confined;
++    }
++
++    confined = 1;
++    return confined;
++}
++
++#else
++int
++unix_selinux_confined(void)
++{
++    return 0;
++}
++#endif
++
++#ifdef USE_LCKPWDF
++int
++lock_pwdf(void)
++{
++        int i;
++        int retval;
++
++#ifndef HELPER_COMPILE
++        if (unix_selinux_confined()) {
++                return PAM_SUCCESS;
++        }
++#endif
++        /* These values for the number of attempts and the sleep time
++           are, of course, completely arbitrary.
++           My reading of the PAM docs is that, once pam_chauthtok() has been
++           called with PAM_UPDATE_AUTHTOK, we are obliged to take any
++           reasonable steps to make sure the token is updated; so retrying
++           for 1/10 sec. isn't overdoing it. */
++        i=0;
++        while((retval = extrausers_lckpwdf()) != 0 && i < 100) {
++                usleep(1000);
++                i++;
++        }
++        if(retval != 0) {
++                return PAM_AUTHTOK_LOCK_BUSY;
++        }
++        return PAM_SUCCESS;
++}
++
++void
++unlock_pwdf(void)
++{
++#ifndef HELPER_COMPILE
++        if (unix_selinux_confined()) {
++                return;
++        }
++#endif
++        extrausers_ulckpwdf();
++}
++#else
++int
++lock_pwdf(void)
++{
++	return PAM_SUCCESS;
++}
++
++void
++unlock_pwdf(void)
++{
++	return;
++}
++#endif
++
++#ifdef HELPER_COMPILE
++int
++save_old_password(const char *forwho, const char *oldpass,
++		  int howmany)
++#else
++int
++save_old_password(pam_handle_t *pamh, const char *forwho, const char *oldpass,
++		  int howmany)
++#endif
++{
++    static char buf[16384];
++    static char nbuf[16384];
++    char *s_luser, *s_uid, *s_npas, *s_pas, *pass;
++    int npas;
++    FILE *pwfile, *opwfile;
++    int err = 0;
++    int oldmask;
++    int found = 0;
++    struct passwd *pwd = NULL;
++    struct stat st;
++    size_t len = strlen(forwho);
++#ifdef WITH_SELINUX
++    security_context_t prev_context=NULL;
++#endif
++
++    if (howmany < 0) {
++	return PAM_SUCCESS;
++    }
++
++    if (oldpass == NULL) {
++	return PAM_SUCCESS;
++    }
++
++    oldmask = umask(077);
++
++#ifdef WITH_SELINUX
++    if (SELINUX_ENABLED) {
++      security_context_t passwd_context=NULL;
++      if (getfilecon("/var/lib/extrausers/passwd",&passwd_context)<0) {
++        return PAM_AUTHTOK_ERR;
++      };
++      if (getfscreatecon(&prev_context)<0) {
++        freecon(passwd_context);
++        return PAM_AUTHTOK_ERR;
++      }
++      if (setfscreatecon(passwd_context)) {
++        freecon(passwd_context);
++        freecon(prev_context);
++        return PAM_AUTHTOK_ERR;
++      }
++      freecon(passwd_context);
++    }
++#endif
++    pwfile = fopen(OPW_TMPFILE, "w");
++    umask(oldmask);
++    if (pwfile == NULL) {
++      err = 1;
++      goto done;
++    }
++
++    opwfile = fopen(OLD_PASSWORDS_FILE, "r");
++    if (opwfile == NULL) {
++	fclose(pwfile);
++      err = 1;
++      goto done;
++    }
++
++    if (fstat(fileno(opwfile), &st) == -1) {
++	fclose(opwfile);
++	fclose(pwfile);
++	err = 1;
++	goto done;
++    }
++
++    if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
++	fclose(opwfile);
++	fclose(pwfile);
++	err = 1;
++	goto done;
++    }
++    if (fchmod(fileno(pwfile), st.st_mode) == -1) {
++	fclose(opwfile);
++	fclose(pwfile);
++	err = 1;
++	goto done;
++    }
++
++    while (fgets(buf, 16380, opwfile)) {
++	if (!strncmp(buf, forwho, len) && strchr(":,\n", buf[len]) != NULL) {
++	    char *sptr = NULL;
++	    found = 1;
++	    if (howmany == 0)
++		continue;
++	    buf[strlen(buf) - 1] = '\0';
++	    s_luser = strtok_r(buf, ":", &sptr);
++	    s_uid = strtok_r(NULL, ":", &sptr);
++	    s_npas = strtok_r(NULL, ":", &sptr);
++	    s_pas = strtok_r(NULL, ":", &sptr);
++	    npas = strtol(s_npas, NULL, 10) + 1;
++	    while (npas > howmany) {
++		s_pas = strpbrk(s_pas, ",");
++		if (s_pas != NULL)
++		    s_pas++;
++		npas--;
++	    }
++	    pass = crypt_md5_wrapper(oldpass);
++	    if (s_pas == NULL)
++		snprintf(nbuf, sizeof(nbuf), "%s:%s:%d:%s\n",
++			 s_luser, s_uid, npas, pass);
++	    else
++		snprintf(nbuf, sizeof(nbuf),"%s:%s:%d:%s,%s\n",
++			 s_luser, s_uid, npas, s_pas, pass);
++	    _pam_delete(pass);
++	    if (fputs(nbuf, pwfile) < 0) {
++		err = 1;
++		break;
++	    }
++	} else if (fputs(buf, pwfile) < 0) {
++	    err = 1;
++	    break;
++	}
++    }
++    fclose(opwfile);
++
++    if (!found) {
++	pwd = pam_modutil_getpwnam(pamh, forwho);
++	if (pwd == NULL) {
++	    err = 1;
++	} else {
++	    pass = crypt_md5_wrapper(oldpass);
++	    snprintf(nbuf, sizeof(nbuf), "%s:%lu:1:%s\n",
++		     forwho, (unsigned long)pwd->pw_uid, pass);
++	    _pam_delete(pass);
++	    if (fputs(nbuf, pwfile) < 0) {
++		err = 1;
++	    }
++	}
++    }
++
++    if (fflush(pwfile) || fsync(fileno(pwfile))) {
++	D(("fflush or fsync error writing entries to old passwords file: %m"));
++	err = 1;
++    }
++
++    if (fclose(pwfile)) {
++	D(("fclose error writing entries to old passwords file: %m"));
++	err = 1;
++    }
++
++done:
++    if (!err) {
++	if (rename(OPW_TMPFILE, OLD_PASSWORDS_FILE))
++	    err = 1;
++    }
++#ifdef WITH_SELINUX
++    if (SELINUX_ENABLED) {
++      if (setfscreatecon(prev_context)) {
++        err = 1;
++      }
++      if (prev_context)
++        freecon(prev_context);
++      prev_context=NULL;
++    }
++#endif
++    if (!err) {
++	return PAM_SUCCESS;
++    } else {
++	unlink(OPW_TMPFILE);
++	return PAM_AUTHTOK_ERR;
++    }
++}
++
++PAMH_ARG_DECL(int unix_update_passwd,
++	const char *forwho, const char *towhat)
++{
++    struct passwd *tmpent = NULL;
++    struct stat st;
++    FILE *pwfile, *opwfile;
++    int err = 1, found = 0;
++    int oldmask;
++#ifdef WITH_SELINUX
++    security_context_t prev_context=NULL;
++#endif
++
++    oldmask = umask(077);
++#ifdef WITH_SELINUX
++    if (SELINUX_ENABLED) {
++      security_context_t passwd_context=NULL;
++      if (getfilecon("/var/lib/extrausers/passwd",&passwd_context)<0) {
++	return PAM_AUTHTOK_ERR;
++      };
++      if (getfscreatecon(&prev_context)<0) {
++	freecon(passwd_context);
++	return PAM_AUTHTOK_ERR;
++      }
++      if (setfscreatecon(passwd_context)) {
++	freecon(passwd_context);
++	freecon(prev_context);
++	return PAM_AUTHTOK_ERR;
++      }
++      freecon(passwd_context);
++    }
++#endif
++    pwfile = fopen(PW_TMPFILE, "w");
++    umask(oldmask);
++    if (pwfile == NULL) {
++      err = 1;
++      goto done;
++    }
++
++    opwfile = fopen("/var/lib/extrausers/passwd", "r");
++    if (opwfile == NULL) {
++	fclose(pwfile);
++	err = 1;
++	goto done;
++    }
++
++    if (fstat(fileno(opwfile), &st) == -1) {
++	fclose(opwfile);
++	fclose(pwfile);
++	err = 1;
++	goto done;
++    }
++
++    if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
++	fclose(opwfile);
++	fclose(pwfile);
++	err = 1;
++	goto done;
++    }
++    if (fchmod(fileno(pwfile), st.st_mode) == -1) {
++	fclose(opwfile);
++	fclose(pwfile);
++	err = 1;
++	goto done;
++    }
++
++    tmpent = fgetpwent(opwfile);
++    while (tmpent) {
++	if (!strcmp(tmpent->pw_name, forwho)) {
++	    /* To shut gcc up */
++	    union {
++		const char *const_charp;
++		char *charp;
++	    } assigned_passwd;
++	    assigned_passwd.const_charp = towhat;
++
++	    tmpent->pw_passwd = assigned_passwd.charp;
++	    err = 0;
++	    found = 1;
++	}
++	if (putpwent(tmpent, pwfile)) {
++	    D(("error writing entry to password file: %m"));
++	    err = 1;
++	    break;
++	}
++	tmpent = fgetpwent(opwfile);
++    }
++    fclose(opwfile);
++
++    if (fflush(pwfile) || fsync(fileno(pwfile))) {
++	D(("fflush or fsync error writing entries to password file: %m"));
++	err = 1;
++    }
++
++    if (fclose(pwfile)) {
++	D(("fclose error writing entries to password file: %m"));
++	err = 1;
++    }
++
++done:
++    if (!err) {
++	if (!rename(PW_TMPFILE, "/var/lib/extrausers/passwd"))
++	    pam_syslog(pamh,
++		LOG_NOTICE, "password changed for %s", forwho);
++	else
++	    err = 1;
++    }
++#ifdef WITH_SELINUX
++    if (SELINUX_ENABLED) {
++      if (setfscreatecon(prev_context)) {
++	err = 1;
++      }
++      if (prev_context)
++	freecon(prev_context);
++      prev_context=NULL;
++    }
++#endif
++    if (!err) {
++	return PAM_SUCCESS;
++    } else {
++	unlink(PW_TMPFILE);
++	return found ? PAM_AUTHTOK_ERR : PAM_USER_UNKNOWN;
++    }
++}
++
++PAMH_ARG_DECL(int unix_update_shadow,
++	const char *forwho, char *towhat)
++{
++    struct spwd spwdent, *stmpent = NULL;
++    struct stat st;
++    FILE *pwfile, *opwfile;
++    int err = 0;
++    int oldmask;
++    int wroteentry = 0;
++#ifdef WITH_SELINUX
++    security_context_t prev_context=NULL;
++#endif
++
++    oldmask = umask(077);
++
++#ifdef WITH_SELINUX
++    if (SELINUX_ENABLED) {
++      security_context_t shadow_context=NULL;
++      if (getfilecon("/var/lib/extrausers/shadow",&shadow_context)<0) {
++	return PAM_AUTHTOK_ERR;
++      };
++      if (getfscreatecon(&prev_context)<0) {
++	freecon(shadow_context);
++	return PAM_AUTHTOK_ERR;
++      }
++      if (setfscreatecon(shadow_context)) {
++	freecon(shadow_context);
++	freecon(prev_context);
++	return PAM_AUTHTOK_ERR;
++      }
++      freecon(shadow_context);
++    }
++#endif
++    pwfile = fopen(SH_TMPFILE, "w");
++    umask(oldmask);
++    if (pwfile == NULL) {
++	err = 1;
++	goto done;
++    }
++
++    opwfile = fopen("/var/lib/extrausers/shadow", "r");
++    if (opwfile == NULL) {
++	fclose(pwfile);
++	err = 1;
++	goto done;
++    }
++
++    if (fstat(fileno(opwfile), &st) == -1) {
++	fclose(opwfile);
++	fclose(pwfile);
++	err = 1;
++	goto done;
++    }
++
++    if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
++	fclose(opwfile);
++	fclose(pwfile);
++	err = 1;
++	goto done;
++    }
++    if (fchmod(fileno(pwfile), st.st_mode) == -1) {
++	fclose(opwfile);
++	fclose(pwfile);
++	err = 1;
++	goto done;
++    }
++
++    stmpent = fgetspent(opwfile);
++    while (stmpent) {
++
++	if (!strcmp(stmpent->sp_namp, forwho)) {
++	    stmpent->sp_pwdp = towhat;
++	    stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24);
++	    if (stmpent->sp_lstchg == 0)
++	        stmpent->sp_lstchg = -1; /* Don't request passwort change
++					    only because time isn't set yet. */
++	    wroteentry = 1;
++	    D(("Set password %s for %s", stmpent->sp_pwdp, forwho));
++	}
++
++	if (putspent(stmpent, pwfile)) {
++	    D(("error writing entry to shadow file: %m"));
++	    err = 1;
++	    break;
++	}
++
++	stmpent = fgetspent(opwfile);
++    }
++
++    fclose(opwfile);
++
++    if (!wroteentry && !err) {
++	spwdent.sp_namp = forwho;
++	spwdent.sp_pwdp = towhat;
++	spwdent.sp_lstchg = time(NULL) / (60 * 60 * 24);
++	if (spwdent.sp_lstchg == 0)
++	    spwdent.sp_lstchg = -1; /* Don't request passwort change
++				       only because time isn't set yet. */
++	spwdent.sp_min = spwdent.sp_max = spwdent.sp_warn = spwdent.sp_inact =
++	    spwdent.sp_expire = -1;
++	spwdent.sp_flag = (unsigned long)-1l;
++	if (putspent(&spwdent, pwfile)) {
++	    D(("error writing entry to shadow file: %m"));
++	    err = 1;
++	}
++    }
++
++    if (fflush(pwfile) || fsync(fileno(pwfile))) {
++	D(("fflush or fsync error writing entries to shadow file: %m"));
++	err = 1;
++    }
++
++    if (fclose(pwfile)) {
++	D(("fclose error writing entries to shadow file: %m"));
++	err = 1;
++    }
++
++ done:
++    if (!err) {
++	if (!rename(SH_TMPFILE, "/var/lib/extrausers/shadow"))
++	    pam_syslog(pamh,
++		LOG_NOTICE, "password changed for %s", forwho);
++	else
++	    err = 1;
++    }
++
++#ifdef WITH_SELINUX
++    if (SELINUX_ENABLED) {
++      if (setfscreatecon(prev_context)) {
++	err = 1;
++      }
++      if (prev_context)
++	freecon(prev_context);
++      prev_context=NULL;
++    }
++#endif
++
++    if (!err) {
++	return PAM_SUCCESS;
++    } else {
++	unlink(SH_TMPFILE);
++	return PAM_AUTHTOK_ERR;
++    }
++}
++
++#ifdef HELPER_COMPILE
++
++int
++helper_verify_password(const char *name, const char *p, int nullok)
++{
++	struct passwd *pwd = NULL;
++	char *salt = NULL;
++	int retval;
++
++	retval = get_pwd_hash(name, &pwd, &salt);
++
++	if (pwd == NULL || salt == NULL) {
++		helper_log_err(LOG_WARNING, "check pass; user unknown");
++		retval = PAM_USER_UNKNOWN;
++	} else {
++		retval = verify_pwd_hash(p, salt, nullok);
++	}
++
++	if (salt) {
++		_pam_overwrite(salt);
++		_pam_drop(salt);
++	}
++
++	p = NULL;		/* no longer needed here */
++
++	return retval;
++}
++
++void
++helper_log_err(int err, const char *format, ...)
++{
++	va_list args;
++
++	va_start(args, format);
++	openlog(HELPER_COMPILE, LOG_CONS | LOG_PID, LOG_AUTHPRIV);
++	vsyslog(err, format, args);
++	va_end(args);
++	closelog();
++}
++
++static void
++su_sighandler(int sig)
++{
++#ifndef SA_RESETHAND
++        /* emulate the behaviour of the SA_RESETHAND flag */
++        if ( sig == SIGILL || sig == SIGTRAP || sig == SIGBUS || sig = SIGSERV ) {
++		struct sigaction sa;
++		memset(&sa, '\0', sizeof(sa));
++		sa.sa_handler = SIG_DFL;
++                sigaction(sig, &sa, NULL);
++	}
++#endif
++        if (sig > 0) {
++                _exit(sig);
++        }
++}
++
++void
++setup_signals(void)
++{
++        struct sigaction action;        /* posix signal structure */
++
++        /*
++         * Setup signal handlers
++         */
++        (void) memset((void *) &action, 0, sizeof(action));
++        action.sa_handler = su_sighandler;
++#ifdef SA_RESETHAND
++        action.sa_flags = SA_RESETHAND;
++#endif
++        (void) sigaction(SIGILL, &action, NULL);
++        (void) sigaction(SIGTRAP, &action, NULL);
++        (void) sigaction(SIGBUS, &action, NULL);
++        (void) sigaction(SIGSEGV, &action, NULL);
++        action.sa_handler = SIG_IGN;
++        action.sa_flags = 0;
++        (void) sigaction(SIGTERM, &action, NULL);
++        (void) sigaction(SIGHUP, &action, NULL);
++        (void) sigaction(SIGINT, &action, NULL);
++        (void) sigaction(SIGQUIT, &action, NULL);
++}
++
++char *
++getuidname(uid_t uid)
++{
++        struct passwd *pw;
++        static char username[256];
++
++        pw = getpwuid(uid);
++        if (pw == NULL)
++                return NULL;
++
++        strncpy(username, pw->pw_name, sizeof(username));
++        username[sizeof(username) - 1] = '\0';
++
++        return username;
++}
++
++int
++read_passwords(int fd, int npass, char **passwords)
++{
++        int rbytes = 0;
++        int offset = 0;
++        int i = 0;
++        char *pptr;
++        while (npass > 0) {
++                rbytes = read(fd, passwords[i]+offset, MAXPASS-offset);
++
++                if (rbytes < 0) {
++                        if (errno == EINTR) continue;
++                        break;
++                }
++                if (rbytes == 0)
++                        break;
++
++                while (npass > 0 && (pptr=memchr(passwords[i]+offset, '\0', rbytes))
++                        != NULL) {
++                        rbytes -= pptr - (passwords[i]+offset) + 1;
++                        i++;
++                        offset = 0;
++                        npass--;
++                        if (rbytes > 0) {
++                                if (npass > 0)
++                                        memcpy(passwords[i], pptr+1, rbytes);
++                                memset(pptr+1, '\0', rbytes);
++                        }
++                }
++                offset += rbytes;
++        }
++
++        /* clear up */
++        if (offset > 0 && npass > 0) {
++                memset(passwords[i], '\0', offset);
++        }
++
++        return i;
++}
++
++#endif
++/* ****************************************************************** *
++ * Copyright (c) Jan RÃªkorajski 1999.
++ * Copyright (c) Andrew G. Morgan 1996-8.
++ * Copyright (c) Alex O. Yuriev, 1996.
++ * Copyright (c) Cristian Gafton 1996.
++ * Copyright (c) Red Hat, Inc. 1996, 2007, 2008.
++ *
++ * 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.
++ */
+--- /dev/null
++++ b/modules/pam_extrausers/passverify.h
+@@ -0,0 +1,119 @@
++/*
++ * Copyright information at end of file.
++ */
++
++#include <sys/types.h>
++#include <pwd.h>
++#include <security/pam_modules.h>
++
++#define PAM_UNIX_RUN_HELPER PAM_CRED_INSUFFICIENT
++
++#define MAXPASS		200	/* the maximum length of a password */
++
++#define OLD_PASSWORDS_FILE      "/var/lib/extrausers/opasswd"
++
++int
++verify_pwd_hash(const char *p, char *hash, unsigned int nullok);
++
++int
++is_pwd_shadowed(const struct passwd *pwd);
++
++char *
++crypt_md5_wrapper(const char *pass_new);
++
++int
++unix_selinux_confined(void);
++
++int
++lock_pwdf(void);
++
++void
++unlock_pwdf(void);
++
++#ifdef HELPER_COMPILE
++int
++save_old_password(const char *forwho, const char *oldpass,
++		  int howmany);
++#else
++int
++save_old_password(pam_handle_t *pamh, const char *forwho, const char *oldpass,
++		  int howmany);
++#endif
++
++#ifdef HELPER_COMPILE
++void
++helper_log_err(int err, const char *format,...);
++
++int
++helper_verify_password(const char *name, const char *p, int nullok);
++
++void
++setup_signals(void);
++
++char *
++getuidname(uid_t uid);
++
++int
++read_passwords(int fd, int npass, char **passwords);
++#endif
++
++#ifdef HELPER_COMPILE
++#define PAMH_ARG_DECL(fname, ...)	fname(__VA_ARGS__)
++#define PAMH_ARG(...)			__VA_ARGS__
++#else
++#define PAMH_ARG_DECL(fname, ...)	fname(pam_handle_t *pamh, __VA_ARGS__)
++#define PAMH_ARG(...)			pamh, __VA_ARGS__
++#endif
++
++PAMH_ARG_DECL(char * create_password_hash,
++	const char *password, unsigned int ctrl, int rounds);
++
++PAMH_ARG_DECL(int get_account_info,
++	const char *name, struct passwd **pwd, struct spwd **spwdent);
++
++PAMH_ARG_DECL(int get_pwd_hash,
++	const char *name, struct passwd **pwd, char **hash);
++
++PAMH_ARG_DECL(int check_shadow_expiry,
++	struct spwd *spent, int *daysleft);
++
++PAMH_ARG_DECL(int unix_update_passwd,
++	const char *forwho, const char *towhat);
++
++PAMH_ARG_DECL(int unix_update_shadow,
++	const char *forwho, char *towhat);
++
++/* ****************************************************************** *
++ * Copyright (c) Red Hat, Inc. 2007.
++ *
++ * 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.
++ */
+--- /dev/null
++++ b/modules/pam_extrausers/support.c
+@@ -0,0 +1,1084 @@
++/*
++ * Copyright information at end of file.
++ */
++
++#include "config.h"
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <stdarg.h>
++#include <stdio.h>
++#include <string.h>
++#include <malloc.h>
++#include <pwd.h>
++#include <shadow.h>
++#include <limits.h>
++#include <utmp.h>
++#include <errno.h>
++#include <signal.h>
++#include <ctype.h>
++#include <syslog.h>
++#include <sys/resource.h>
++#ifdef HAVE_RPCSVC_YPCLNT_H
++#include <rpcsvc/ypclnt.h>
++#endif
++
++#include <security/_pam_macros.h>
++#include <security/pam_modules.h>
++#include <security/pam_ext.h>
++#include <security/pam_modutil.h>
++
++#include "support.h"
++#include "passverify.h"
++#ifdef WITH_SELINUX
++#include <selinux/selinux.h>
++#define SELINUX_ENABLED is_selinux_enabled()>0
++#else
++#define SELINUX_ENABLED 0
++#endif
++
++// This was originally defined in libpam/pam_modutil_searchkey.c
++// Upstream dropped this with commit:
++// https://github.com/linux-pam/linux-pam/commit/539816e4a0a277dbb632412be91e482fff9d9d09
++#define BUF_SIZE 8192
++
++static char *
++search_key (const char *key, const char *filename)
++{
++  FILE *fp;
++  char *buf = NULL;
++  size_t buflen = 0;
++  char *retval = NULL;
++
++  fp = fopen (filename, "r");
++  if (NULL == fp)
++    return NULL;
++
++  while (!feof (fp))
++    {
++      char *tmp, *cp;
++#if defined(HAVE_GETLINE)
++      ssize_t n = getline (&buf, &buflen, fp);
++#elif defined (HAVE_GETDELIM)
++      ssize_t n = getdelim (&buf, &buflen, '\n', fp);
++#else
++      ssize_t n;
++
++      if (buf == NULL)
++        {
++          buflen = BUF_SIZE;
++          buf = malloc (buflen);
++	  if (buf == NULL) {
++	    fclose (fp);
++	    return NULL;
++	  }
++        }
++      buf[0] = '\0';
++      if (fgets (buf, buflen - 1, fp) == NULL)
++        break;
++      else if (buf != NULL)
++        n = strlen (buf);
++      else
++        n = 0;
++#endif /* HAVE_GETLINE / HAVE_GETDELIM */
++      cp = buf;
++
++      if (n < 1)
++        break;
++
++      tmp = strchr (cp, '#');  /* remove comments */
++      if (tmp)
++        *tmp = '\0';
++      while (isspace ((int)*cp))    /* remove spaces and tabs */
++        ++cp;
++      if (*cp == '\0')        /* ignore empty lines */
++        continue;
++
++      if (cp[strlen (cp) - 1] == '\n')
++        cp[strlen (cp) - 1] = '\0';
++
++      tmp = strsep (&cp, " \t=");
++      if (cp != NULL)
++        while (isspace ((int)*cp) || *cp == '=')
++          ++cp;
++
++      if (strcasecmp (tmp, key) == 0)
++        {
++          retval = strdup (cp);
++          break;
++        }
++    }
++  fclose (fp);
++
++  free (buf);
++
++  return retval;
++}
++
++
++/* this is a front-end for module-application conversations */
++
++int _make_remark(pam_handle_t * pamh, unsigned int ctrl,
++		    int type, const char *text)
++{
++	int retval = PAM_SUCCESS;
++
++	if (off(UNIX__QUIET, ctrl)) {
++		retval = pam_prompt(pamh, type, NULL, "%s", text);
++	}
++	return retval;
++}
++
++/*
++ * set the control flags for the UNIX module.
++ */
++
++int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int *rounds,
++	      int *pass_min_len, int argc, const char **argv)
++{
++	unsigned int ctrl;
++	char *val;
++	int j;
++
++	D(("called."));
++
++	ctrl = UNIX_DEFAULTS;	/* the default selection of options */
++
++	/* set some flags manually */
++
++	if (getuid() == 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) {
++		D(("IAMROOT"));
++		set(UNIX__IAMROOT, ctrl);
++	}
++	if (flags & PAM_UPDATE_AUTHTOK) {
++		D(("UPDATE_AUTHTOK"));
++		set(UNIX__UPDATE, ctrl);
++	}
++	if (flags & PAM_PRELIM_CHECK) {
++		D(("PRELIM_CHECK"));
++		set(UNIX__PRELIM, ctrl);
++	}
++	if (flags & PAM_SILENT) {
++		D(("SILENT"));
++		set(UNIX__QUIET, ctrl);
++	}
++
++	/* preset encryption method with value from /etc/login.defs */
++	val = search_key ("ENCRYPT_METHOD", LOGIN_DEFS);
++	if (val) {
++	  for (j = 0; j < UNIX_CTRLS_; ++j) {
++	    if (unix_args[j].token && unix_args[j].is_hash_algo
++		&& !strncasecmp(val, unix_args[j].token, strlen(unix_args[j].token))) {
++	      break;
++	    }
++	  }
++	  if (j >= UNIX_CTRLS_) {
++	    pam_syslog(pamh, LOG_WARNING, "unrecognized ENCRYPT_METHOD value [%s]", val);
++	  } else {
++	    ctrl &= unix_args[j].mask;	/* for turning things off */
++	    ctrl |= unix_args[j].flag;	/* for turning things on  */
++	  }
++	  free (val);
++
++	  /* read number of rounds for crypt algo */
++	  if (rounds && (on(UNIX_SHA256_PASS, ctrl) || on(UNIX_SHA512_PASS, ctrl))) {
++	    val=search_key ("SHA_CRYPT_MAX_ROUNDS", LOGIN_DEFS);
++
++	    if (val) {
++	      *rounds = strtol(val, NULL, 10);
++	      free (val);
++	    }
++	  }
++	}
++
++	/* now parse the arguments to this module */
++
++	for (; argc-- > 0; ++argv) {
++		int sl;
++
++		D(("pam_extrausers arg: %s", *argv));
++
++		for (j = 0; j < UNIX_CTRLS_; ++j) {
++			if (unix_args[j].token) {
++			    sl = strlen(unix_args[j].token);
++			    if (unix_args[j].token[sl-1] == '=') {
++				/* exclude argument from comparison */
++				if (!strncmp(*argv, unix_args[j].token, sl))
++				    break;
++			    } else {
++				/* compare full strings */
++				if (!strcmp(*argv, unix_args[j].token))
++				    break;
++			    }
++			}
++		}
++
++		if (j >= UNIX_CTRLS_) {
++			pam_syslog(pamh, LOG_ERR,
++			         "unrecognized option [%s]", *argv);
++		} else {
++			/* special cases */
++			if (j == UNIX_REMEMBER_PASSWD) {
++				if (remember == NULL) {
++					pam_syslog(pamh, LOG_ERR,
++					    "option remember not allowed for this module type");
++					continue;
++				}
++				*remember = strtol(*argv + 9, NULL, 10);
++				if ((*remember == INT_MIN) || (*remember == INT_MAX))
++					*remember = -1;
++				if (*remember > 400)
++					*remember = 400;
++			} else if (j == UNIX_MIN_PASS_LEN) {
++				if (pass_min_len == NULL) {
++					pam_syslog(pamh, LOG_ERR,
++					    "option minlen not allowed for this module type");
++					continue;
++				}
++				*pass_min_len = atoi(*argv + 7);
++			} else if (j == UNIX_ALGO_ROUNDS) {
++				if (rounds == NULL) {
++					pam_syslog(pamh, LOG_ERR,
++					    "option rounds not allowed for this module type");
++					continue;
++				}
++				*rounds = strtol(*argv + 7, NULL, 10);
++			}
++
++			ctrl &= unix_args[j].mask;	/* for turning things off */
++			ctrl |= unix_args[j].flag;	/* for turning things on  */
++		}
++	}
++
++	if (UNIX_DES_CRYPT(ctrl)
++	    && pass_min_len && *pass_min_len > 8)
++	  {
++	    pam_syslog (pamh, LOG_NOTICE, "Password minlen reset to 8 characters");
++	    *pass_min_len = 8;
++	  }
++
++	if (flags & PAM_DISALLOW_NULL_AUTHTOK) {
++		D(("DISALLOW_NULL_AUTHTOK"));
++		set(UNIX__NONULL, ctrl);
++	}
++
++	/* Set default rounds for blowfish */
++	if (on(UNIX_BLOWFISH_PASS, ctrl) && off(UNIX_ALGO_ROUNDS, ctrl) && rounds != NULL) {
++		*rounds = 5;
++		set(UNIX_ALGO_ROUNDS, ctrl);
++	}
++
++	/* Enforce sane "rounds" values */
++	if (on(UNIX_ALGO_ROUNDS, ctrl)) {
++		if (on(UNIX_BLOWFISH_PASS, ctrl)) {
++			if (*rounds < 4 || *rounds > 31)
++				*rounds = 5;
++		} else if (on(UNIX_SHA256_PASS, ctrl) || on(UNIX_SHA512_PASS, ctrl)) {
++			if ((*rounds < 1000) || (*rounds == INT_MAX))
++				/* don't care about bogus values */
++				unset(UNIX_ALGO_ROUNDS, ctrl);
++			if (*rounds >= 10000000)
++				*rounds = 9999999;
++		}
++	}
++
++	/* auditing is a more sensitive version of debug */
++
++	if (on(UNIX_AUDIT, ctrl)) {
++		set(UNIX_DEBUG, ctrl);
++	}
++	/* return the set of flags */
++
++	D(("done."));
++	return ctrl;
++}
++
++static void _cleanup(pam_handle_t * pamh UNUSED, void *x, int error_status UNUSED)
++{
++	_pam_delete(x);
++}
++
++/* ************************************************************** *
++ * Useful non-trivial functions                                   *
++ * ************************************************************** */
++
++  /*
++   * the following is used to keep track of the number of times a user fails
++   * to authenticate themself.
++   */
++
++#define FAIL_PREFIX                   "-UN*X-FAIL-"
++#define UNIX_MAX_RETRIES              3
++
++struct _pam_failed_auth {
++	char *user;		/* user that's failed to be authenticated */
++	char *name;		/* attempt from user with name */
++	int uid;		/* uid of calling user */
++	int euid;		/* euid of calling process */
++	int count;		/* number of failures so far */
++};
++
++#ifndef PAM_DATA_REPLACE
++#error "Need to get an updated libpam 0.52 or better"
++#endif
++
++static void _cleanup_failures(pam_handle_t * pamh, void *fl, int err)
++{
++	int quiet;
++	const void *service = NULL;
++	const void *ruser = NULL;
++	const void *rhost = NULL;
++	const void *tty = NULL;
++	struct _pam_failed_auth *failure;
++
++	D(("called"));
++
++	quiet = err & PAM_DATA_SILENT;	/* should we log something? */
++	err &= PAM_DATA_REPLACE;	/* are we just replacing data? */
++	failure = (struct _pam_failed_auth *) fl;
++
++	if (failure != NULL) {
++
++		if (!quiet && !err) {	/* under advisement from Sun,may go away */
++
++			/* log the number of authentication failures */
++			if (failure->count > 1) {
++				(void) pam_get_item(pamh, PAM_SERVICE,
++						    &service);
++				(void) pam_get_item(pamh, PAM_RUSER,
++						    &ruser);
++				(void) pam_get_item(pamh, PAM_RHOST,
++						    &rhost);
++				(void) pam_get_item(pamh, PAM_TTY,
++						    &tty);
++				pam_syslog(pamh, LOG_NOTICE,
++				         "%d more authentication failure%s; "
++				         "logname=%s uid=%d euid=%d "
++				         "tty=%s ruser=%s rhost=%s "
++				         "%s%s",
++				         failure->count - 1, failure->count == 2 ? "" : "s",
++				         failure->name, failure->uid, failure->euid,
++				         tty ? (const char *)tty : "", ruser ? (const char *)ruser : "",
++				         rhost ? (const char *)rhost : "",
++				         (failure->user && failure->user[0] != '\0')
++				          ? " user=" : "", failure->user
++				);
++
++				if (failure->count > UNIX_MAX_RETRIES) {
++					pam_syslog(pamh, LOG_ALERT,
++						 "service(%s) ignoring max retries; %d > %d",
++						 service == NULL ? "**unknown**" : (const char *)service,
++						 failure->count,
++						 UNIX_MAX_RETRIES);
++				}
++			}
++		}
++		_pam_delete(failure->user);	/* tidy up */
++		_pam_delete(failure->name);	/* tidy up */
++		free(failure);
++	}
++}
++
++/*
++ * _unix_getpwnam() searches only /var/lib/extrausers/passwd and NIS to find user information
++ */
++static void _unix_cleanup(pam_handle_t *pamh UNUSED, void *data, int error_status UNUSED)
++{
++	free(data);
++}
++
++int _unix_getpwnam(pam_handle_t *pamh, const char *name,
++		   int files, int nis, struct passwd **ret)
++{
++	FILE *passwd;
++	char buf[16384];
++	int matched = 0, buflen;
++	char *slogin, *spasswd, *suid, *sgid, *sgecos, *shome, *sshell, *p;
++
++	memset(buf, 0, sizeof(buf));
++
++	if (!matched && files) {
++		int userlen = strlen(name);
++		passwd = fopen("/var/lib/extrausers/passwd", "r");
++		if (passwd != NULL) {
++			while (fgets(buf, sizeof(buf), passwd) != NULL) {
++				if ((buf[userlen] == ':') &&
++				    (strncmp(name, buf, userlen) == 0)) {
++					p = buf + strlen(buf) - 1;
++					while (isspace(*p) && (p >= buf)) {
++						*p-- = '\0';
++					}
++					matched = 1;
++					break;
++				}
++			}
++			fclose(passwd);
++		}
++	}
++
++#if defined(HAVE_YP_GET_DEFAULT_DOMAIN) && defined (HAVE_YP_BIND) && defined (HAVE_YP_MATCH) && defined (HAVE_YP_UNBIND)
++	if (!matched && nis) {
++		char *userinfo = NULL, *domain = NULL;
++		int len = 0, i;
++		len = yp_get_default_domain(&domain);
++		if (len == YPERR_SUCCESS) {
++			len = yp_bind(domain);
++		}
++		if (len == YPERR_SUCCESS) {
++			i = yp_match(domain, "passwd.byname", name,
++				     strlen(name), &userinfo, &len);
++			yp_unbind(domain);
++			if ((i == YPERR_SUCCESS) && ((size_t)len < sizeof(buf))) {
++				strncpy(buf, userinfo, sizeof(buf) - 1);
++				buf[sizeof(buf) - 1] = '\0';
++				matched = 1;
++			}
++		}
++	}
++#else
++	/* we don't have NIS support, make compiler happy. */
++	nis = 0;
++#endif
++
++	if (matched && (ret != NULL)) {
++		*ret = NULL;
++
++		slogin = buf;
++
++		spasswd = strchr(slogin, ':');
++		if (spasswd == NULL) {
++			return matched;
++		}
++		*spasswd++ = '\0';
++
++		suid = strchr(spasswd, ':');
++		if (suid == NULL) {
++			return matched;
++		}
++		*suid++ = '\0';
++
++		sgid = strchr(suid, ':');
++		if (sgid == NULL) {
++			return matched;
++		}
++		*sgid++ = '\0';
++
++		sgecos = strchr(sgid, ':');
++		if (sgecos == NULL) {
++			return matched;
++		}
++		*sgecos++ = '\0';
++
++		shome = strchr(sgecos, ':');
++		if (shome == NULL) {
++			return matched;
++		}
++		*shome++ = '\0';
++
++		sshell = strchr(shome, ':');
++		if (sshell == NULL) {
++			return matched;
++		}
++		*sshell++ = '\0';
++
++		buflen = sizeof(struct passwd) +
++			 strlen(slogin) + 1 +
++			 strlen(spasswd) + 1 +
++			 strlen(sgecos) + 1 +
++			 strlen(shome) + 1 +
++			 strlen(sshell) + 1;
++		*ret = malloc(buflen);
++		if (*ret == NULL) {
++			return matched;
++		}
++		memset(*ret, '\0', buflen);
++
++		(*ret)->pw_uid = strtol(suid, &p, 10);
++		if ((strlen(suid) == 0) || (*p != '\0')) {
++			free(*ret);
++			*ret = NULL;
++			return matched;
++		}
++
++		(*ret)->pw_gid = strtol(sgid, &p, 10);
++		if ((strlen(sgid) == 0) || (*p != '\0')) {
++			free(*ret);
++			*ret = NULL;
++			return matched;
++		}
++
++		p = ((char*)(*ret)) + sizeof(struct passwd);
++		(*ret)->pw_name = strcpy(p, slogin);
++		p += strlen(p) + 1;
++		(*ret)->pw_passwd = strcpy(p, spasswd);
++		p += strlen(p) + 1;
++		(*ret)->pw_gecos = strcpy(p, sgecos);
++		p += strlen(p) + 1;
++		(*ret)->pw_dir = strcpy(p, shome);
++		p += strlen(p) + 1;
++		(*ret)->pw_shell = strcpy(p, sshell);
++
++		snprintf(buf, sizeof(buf), "_pam_unix_getpwnam_%s", name);
++
++		if (pam_set_data(pamh, buf,
++				 *ret, _unix_cleanup) != PAM_SUCCESS) {
++			free(*ret);
++			*ret = NULL;
++		}
++	}
++
++	return matched;
++}
++
++/*
++ * _unix_comsefromsource() is a quick check to see if information about a given
++ * user comes from a particular source (just files and nis for now)
++ *
++ */
++int _unix_comesfromsource(pam_handle_t *pamh,
++			  const char *name, int files, int nis)
++{
++	return _unix_getpwnam(pamh, name, files, nis, NULL);
++}
++
++/*
++ * verify the password of a user
++ */
++
++#include <sys/types.h>
++#include <sys/wait.h>
++
++static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd,
++				   unsigned int ctrl, const char *user)
++{
++    int retval, child, fds[2];
++    struct sigaction newsa, oldsa;
++
++    D(("called."));
++    /* create a pipe for the password */
++    if (pipe(fds) != 0) {
++	D(("could not make pipe"));
++	return PAM_AUTH_ERR;
++    }
++
++    if (off(UNIX_NOREAP, ctrl)) {
++	/*
++	 * This code arranges that the demise of the child does not cause
++	 * the application to receive a signal it is not expecting - which
++	 * may kill the application or worse.
++	 *
++	 * The "noreap" module argument is provided so that the admin can
++	 * override this behavior.
++	 */
++        memset(&newsa, '\0', sizeof(newsa));
++	newsa.sa_handler = SIG_DFL;
++	sigaction(SIGCHLD, &newsa, &oldsa);
++    }
++
++    /* fork */
++    child = fork();
++    if (child == 0) {
++        int i=0;
++        int nullok = off(UNIX__NONULL, ctrl);
++        struct rlimit rlim;
++	static char *envp[] = { NULL };
++	char *args[] = { NULL, NULL, NULL, NULL };
++
++	/* XXX - should really tidy up PAM here too */
++
++	/* reopen stdin as pipe */
++	dup2(fds[0], STDIN_FILENO);
++
++	if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
++          if (rlim.rlim_max >= MAX_FD_NO)
++                rlim.rlim_max = MAX_FD_NO;
++	  for (i=0; i < (int)rlim.rlim_max; i++) {
++		if (i != STDIN_FILENO)
++		  close(i);
++	  }
++	}
++
++	if (geteuid() == 0) {
++          /* must set the real uid to 0 so the helper will not error
++	     out if pam is called from setuid binary (su, sudo...) */
++	  if (setuid(0) == -1) {
++             D(("setuid failed"));
++	     _exit(PAM_AUTHINFO_UNAVAIL);
++          }
++	}
++
++	/* exec binary helper */
++	args[0] = strdup(CHKPWD_HELPER);
++	args[1] = x_strdup(user);
++
++	if (on(UNIX_NULLOK_SECURE, ctrl)) {
++	    const void *uttyname;
++	    retval = pam_get_item(pamh, PAM_TTY, &uttyname);
++	    if (retval != PAM_SUCCESS || uttyname == NULL)
++	    {
++	        nullok = 0;
++	    }
++	}
++
++	if (nullok) {
++	  args[2]=strdup("nullok");
++	} else {
++	  args[2]=strdup("nonull");
++	}
++
++	execve(CHKPWD_HELPER, args, envp);
++
++	/* should not get here: exit with error */
++	D(("helper binary is not available"));
++	_exit(PAM_AUTHINFO_UNAVAIL);
++    } else if (child > 0) {
++	/* wait for child */
++	/* if the stored password is NULL */
++        int rc=0;
++	if (passwd != NULL) {            /* send the password to the child */
++	    if (write(fds[1], passwd, strlen(passwd)+1) == -1) {
++	      pam_syslog (pamh, LOG_ERR, "Cannot send password to helper: %m");
++	      retval = PAM_AUTH_ERR;
++	    }
++	    passwd = NULL;
++	} else {                         /* blank password */
++	    if (write(fds[1], "", 1) == -1) {
++	      pam_syslog (pamh, LOG_ERR, "Cannot send password to helper: %m");
++	      retval = PAM_AUTH_ERR;
++	    }
++	}
++	close(fds[0]);       /* close here to avoid possible SIGPIPE above */
++	close(fds[1]);
++	/* wait for helper to complete: */
++	while ((rc=waitpid(child, &retval, 0)) < 0 && errno == EINTR);
++	if (rc<0) {
++	  pam_syslog(pamh, LOG_ERR, "pam_extrausers_chkpwd waitpid returned %d: %m", rc);
++	  retval = PAM_AUTH_ERR;
++	} else if (!WIFEXITED(retval)) {
++	  pam_syslog(pamh, LOG_ERR, "pam_extrausers_chkpwd abnormal exit: %d", retval);
++	  retval = PAM_AUTH_ERR;
++	} else {
++	  retval = WEXITSTATUS(retval);
++	}
++    } else {
++	D(("fork failed"));
++	close(fds[0]);
++	close(fds[1]);
++	retval = PAM_AUTH_ERR;
++    }
++
++    if (off(UNIX_NOREAP, ctrl)) {
++        sigaction(SIGCHLD, &oldsa, NULL);   /* restore old signal handler */
++    }
++
++    D(("returning %d", retval));
++    return retval;
++}
++
++/*
++ * _unix_blankpasswd() is a quick check for a blank password
++ *
++ * returns TRUE if user does not have a password
++ * - to avoid prompting for one in such cases (CG)
++ */
++
++int
++_unix_blankpasswd (pam_handle_t *pamh, unsigned int ctrl, const char *name)
++{
++	struct passwd *pwd = NULL;
++	char *salt = NULL;
++	int retval;
++
++	D(("called"));
++
++	/*
++	 * This function does not have to be too smart if something goes
++	 * wrong, return FALSE and let this case to be treated somewhere
++	 * else (CG)
++	 */
++
++	if (on(UNIX__NONULL, ctrl))
++		return 0;	/* will fail but don't let on yet */
++
++	if (on(UNIX_NULLOK_SECURE, ctrl)) {
++		int retval2;
++		const void *uttyname;
++		retval2 = pam_get_item(pamh, PAM_TTY, &uttyname);
++		if (retval2 != PAM_SUCCESS || uttyname == NULL)
++			return 0;
++	}
++
++	/* UNIX passwords area */
++
++	retval = get_pwd_hash(pamh, name, &pwd, &salt);
++
++	if (retval == PAM_UNIX_RUN_HELPER) {
++		/* salt will not be set here so we can return immediately */
++		if (_unix_run_helper_binary(pamh, NULL, ctrl, name) == PAM_SUCCESS)
++			return 1;
++		else
++			return 0;
++	}
++
++	/* Does this user have a password? */
++	if (salt == NULL) {
++		retval = 0;
++	} else {
++		if (strlen(salt) == 0)
++			retval = 1;
++		else
++			retval = 0;
++	}
++
++	/* tidy up */
++
++	if (salt)
++		_pam_delete(salt);
++
++	return retval;
++}
++
++int _unix_verify_password(pam_handle_t * pamh, const char *name
++			  ,const char *p, unsigned int ctrl)
++{
++	struct passwd *pwd = NULL;
++	char *salt = NULL;
++	char *data_name;
++	int retval;
++
++
++	D(("called"));
++
++#ifdef HAVE_PAM_FAIL_DELAY
++	if (off(UNIX_NODELAY, ctrl)) {
++		D(("setting delay"));
++		(void) pam_fail_delay(pamh, 2000000);	/* 2 sec delay for on failure */
++	}
++#endif
++
++	/* locate the entry for this user */
++
++	D(("locating user's record"));
++
++	retval = get_pwd_hash(pamh, name, &pwd, &salt);
++
++	data_name = (char *) malloc(sizeof(FAIL_PREFIX) + strlen(name));
++	if (data_name == NULL) {
++		pam_syslog(pamh, LOG_CRIT, "no memory for data-name");
++	} else {
++		strcpy(data_name, FAIL_PREFIX);
++		strcpy(data_name + sizeof(FAIL_PREFIX) - 1, name);
++	}
++
++	if (retval != PAM_SUCCESS) {
++		if (retval == PAM_UNIX_RUN_HELPER) {
++			D(("running helper binary"));
++			retval = _unix_run_helper_binary(pamh, p, ctrl, name);
++		} else {
++			D(("user's record unavailable"));
++			p = NULL;
++			if (on(UNIX_AUDIT, ctrl)) {
++				/* this might be a typo and the user has given a password
++				   instead of a username. Careful with this. */
++				pam_syslog(pamh, LOG_WARNING,
++				         "check pass; user (%s) unknown", name);
++			} else {
++				name = NULL;
++				if (on(UNIX_DEBUG, ctrl) || pwd == NULL) {
++				    pam_syslog(pamh, LOG_WARNING,
++				            "check pass; user unknown");
++				} else {
++				    /* don't log failure as another pam module can succeed */
++				    goto cleanup;
++				}
++			}
++		}
++	} else {
++		retval = verify_pwd_hash(p, salt,
++		                         _unix_blankpasswd(pamh, ctrl, name));
++	}
++
++	if (retval == PAM_SUCCESS) {
++		if (data_name)	/* reset failures */
++			pam_set_data(pamh, data_name, NULL, _cleanup_failures);
++	} else {
++		if (data_name != NULL) {
++			struct _pam_failed_auth *new = NULL;
++			const struct _pam_failed_auth *old = NULL;
++
++			/* get a failure recorder */
++
++			new = (struct _pam_failed_auth *)
++			    malloc(sizeof(struct _pam_failed_auth));
++
++			if (new != NULL) {
++
++			    const char *login_name;
++			    const void *void_old;
++
++
++			    login_name = pam_modutil_getlogin(pamh);
++			    if (login_name == NULL) {
++				login_name = "";
++			    }
++
++			        new->user = x_strdup(name ? name : "");
++				new->uid = getuid();
++				new->euid = geteuid();
++				new->name = x_strdup(login_name);
++
++				/* any previous failures for this user ? */
++				if (pam_get_data(pamh, data_name, &void_old)
++				    == PAM_SUCCESS)
++				        old = void_old;
++				else
++				        old = NULL;
++
++				if (old != NULL) {
++					new->count = old->count + 1;
++					if (new->count >= UNIX_MAX_RETRIES) {
++						retval = PAM_MAXTRIES;
++					}
++				} else {
++					const void *service=NULL;
++					const void *ruser=NULL;
++					const void *rhost=NULL;
++					const void *tty=NULL;
++
++					(void) pam_get_item(pamh, PAM_SERVICE,
++							    &service);
++					(void) pam_get_item(pamh, PAM_RUSER,
++							    &ruser);
++					(void) pam_get_item(pamh, PAM_RHOST,
++							    &rhost);
++					(void) pam_get_item(pamh, PAM_TTY,
++							    &tty);
++
++					pam_syslog(pamh, LOG_NOTICE,
++					         "authentication failure; "
++					         "logname=%s uid=%d euid=%d "
++					         "tty=%s ruser=%s rhost=%s "
++					         "%s%s",
++					         new->name, new->uid, new->euid,
++					         tty ? (const char *)tty : "",
++					         ruser ? (const char *)ruser : "",
++					         rhost ? (const char *)rhost : "",
++					         (new->user && new->user[0] != '\0')
++					          ? " user=" : "",
++					         new->user
++					);
++					new->count = 1;
++				}
++
++				pam_set_data(pamh, data_name, new, _cleanup_failures);
++
++			} else {
++				pam_syslog(pamh, LOG_CRIT,
++				         "no memory for failure recorder");
++			}
++		}
++	}
++
++cleanup:
++	if (data_name)
++		_pam_delete(data_name);
++	if (salt)
++		_pam_delete(salt);
++
++	D(("done [%d].", retval));
++
++	return retval;
++}
++
++/*
++ * obtain a password from the user
++ */
++
++int _unix_read_password(pam_handle_t * pamh
++			,unsigned int ctrl
++			,const char *comment
++			,const char *prompt1
++			,const char *prompt2
++			,const char *data_name
++			,const void **pass)
++{
++	int authtok_flag;
++	int retval = PAM_SUCCESS;
++	char *token;
++
++	D(("called"));
++
++	/*
++	 * make sure nothing inappropriate gets returned
++	 */
++
++	*pass = token = NULL;
++
++	/*
++	 * which authentication token are we getting?
++	 */
++
++	authtok_flag = on(UNIX__OLD_PASSWD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK;
++
++	/*
++	 * should we obtain the password from a PAM item ?
++	 */
++
++	if (on(UNIX_TRY_FIRST_PASS, ctrl) || on(UNIX_USE_FIRST_PASS, ctrl)) {
++		retval = pam_get_item(pamh, authtok_flag, pass);
++		if (retval != PAM_SUCCESS) {
++			/* very strange. */
++			pam_syslog(pamh, LOG_ALERT,
++				 "pam_get_item returned error to unix-read-password"
++			    );
++			return retval;
++		} else if (*pass != NULL) {	/* we have a password! */
++			return PAM_SUCCESS;
++		} else if (on(UNIX_USE_AUTHTOK, ctrl)
++			   && off(UNIX__OLD_PASSWD, ctrl)) {
++			return PAM_AUTHTOK_ERR;
++		} else if (on(UNIX_USE_FIRST_PASS, ctrl)) {
++			return PAM_AUTHTOK_RECOVERY_ERR;	  /* didn't work */
++		}
++	}
++	/*
++	 * getting here implies we will have to get the password from the
++	 * user directly.
++	 */
++
++	{
++		int replies=1;
++		char *resp[2] = { NULL, NULL };
++
++		if (comment != NULL && off(UNIX__QUIET, ctrl)) {
++			retval = pam_info(pamh, "%s", comment);
++		}
++
++		if (retval == PAM_SUCCESS) {
++			retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF,
++			    &resp[0], "%s", prompt1);
++
++			if (retval == PAM_SUCCESS && prompt2 != NULL) {
++				retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF,
++				    &resp[1], "%s", prompt2);
++				++replies;
++			}
++		}
++
++		if (resp[0] != NULL && resp[replies-1] != NULL) {
++			/* interpret the response */
++
++			if (retval == PAM_SUCCESS) {	/* a good conversation */
++
++				token = resp[0];
++				if (token != NULL) {
++					if (replies == 2) {
++						/* verify that password entered correctly */
++						if (strcmp(token, resp[replies - 1])) {
++							/* mistyped */
++							retval = PAM_AUTHTOK_RECOVERY_ERR;
++							_make_remark(pamh, ctrl,
++							    PAM_ERROR_MSG, MISTYPED_PASS);
++						}
++					}
++				} else {
++					pam_syslog(pamh, LOG_NOTICE,
++						    "could not recover authentication token");
++				}
++
++			}
++
++		} else {
++			retval = (retval == PAM_SUCCESS)
++			    ? PAM_AUTHTOK_RECOVERY_ERR : retval;
++		}
++
++		resp[0] = NULL;
++		if (replies > 1)
++			_pam_delete(resp[1]);
++	}
++
++	if (retval != PAM_SUCCESS) {
++		_pam_delete(token);
++
++		if (on(UNIX_DEBUG, ctrl))
++			pam_syslog(pamh, LOG_DEBUG,
++			         "unable to obtain a password");
++		return retval;
++	}
++	/* 'token' is the entered password */
++
++	if (off(UNIX_NOT_SET_PASS, ctrl)) {
++
++		/* we store this password as an item */
++
++		retval = pam_set_item(pamh, authtok_flag, token);
++		_pam_delete(token);	/* clean it up */
++		if (retval != PAM_SUCCESS
++		    || (retval = pam_get_item(pamh, authtok_flag, pass))
++		    != PAM_SUCCESS) {
++
++			*pass = NULL;
++			pam_syslog(pamh, LOG_CRIT, "error manipulating password");
++			return retval;
++
++		}
++	} else {
++		/*
++		 * then store it as data specific to this module. pam_end()
++		 * will arrange to clean it up.
++		 */
++
++		retval = pam_set_data(pamh, data_name, (void *) token, _cleanup);
++		if (retval != PAM_SUCCESS) {
++			pam_syslog(pamh, LOG_CRIT,
++			         "error manipulating password data [%s]",
++				 pam_strerror(pamh, retval));
++			_pam_delete(token);
++			return retval;
++		}
++		*pass = token;
++		token = NULL;	/* break link to password */
++	}
++
++	return PAM_SUCCESS;
++}
++
++/* ****************************************************************** *
++ * Copyright (c) Jan RÃªkorajski 1999.
++ * Copyright (c) Andrew G. Morgan 1996-8.
++ * Copyright (c) Alex O. Yuriev, 1996.
++ * Copyright (c) Cristian Gafton 1996.
++ * Copyright (c) Red Hat, Inc. 2007.
++ *
++ * 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.
++ */
+--- /dev/null
++++ b/modules/pam_extrausers/support.h
+@@ -0,0 +1,179 @@
++/*
++ * $Id$
++ */
++
++#ifndef _PAM_UNIX_SUPPORT_H
++#define _PAM_UNIX_SUPPORT_H
++
++#include <pwd.h>
++
++/*
++ * File to read value of ENCRYPT_METHOD from.
++ */
++#define LOGIN_DEFS "/etc/login.defs"
++
++
++/*
++ * here is the string to inform the user that the new passwords they
++ * typed were not the same.
++ */
++
++#define MISTYPED_PASS "Sorry, passwords do not match"
++
++/* type definition for the control options */
++
++typedef struct {
++	const char *token;
++	unsigned int mask;	/* shall assume 32 bits of flags */
++	unsigned int flag;
++        unsigned int is_hash_algo;
++} UNIX_Ctrls;
++
++/*
++ * macro to determine if a given flag is on
++ */
++
++#define on(x,ctrl)  (unix_args[x].flag & ctrl)
++
++/*
++ * macro to determine that a given flag is NOT on
++ */
++
++#define off(x,ctrl) (!on(x,ctrl))
++
++/*
++ * macro to turn on/off a ctrl flag manually
++ */
++
++#define set(x,ctrl)   (ctrl = ((ctrl)&unix_args[x].mask)|unix_args[x].flag)
++#define unset(x,ctrl) (ctrl &= ~(unix_args[x].flag))
++
++/* the generic mask */
++
++#define _ALL_ON_  (~0U)
++
++/* end of macro definitions definitions for the control flags */
++
++/* ****************************************************************** *
++ * ctrl flags proper..
++ */
++
++/*
++ * here are the various options recognized by the unix module. They
++ * are enumerated here and then defined below. Internal arguments are
++ * given NULL tokens.
++ */
++
++#define UNIX__OLD_PASSWD          0	/* internal */
++#define UNIX__VERIFY_PASSWD       1	/* internal */
++#define UNIX__IAMROOT             2	/* internal */
++
++#define UNIX_AUDIT                3	/* print more things than debug..
++					   some information may be sensitive */
++#define UNIX_USE_FIRST_PASS       4
++#define UNIX_TRY_FIRST_PASS       5
++#define UNIX_NOT_SET_PASS         6	/* don't set the AUTHTOK items */
++
++#define UNIX__PRELIM              7	/* internal */
++#define UNIX__UPDATE              8	/* internal */
++#define UNIX__NONULL              9	/* internal */
++#define UNIX__QUIET              10	/* internal */
++#define UNIX_USE_AUTHTOK         11	/* insist on reading PAM_AUTHTOK */
++#define UNIX_SHADOW              12	/* signal shadow on */
++#define UNIX_MD5_PASS            13	/* force the use of MD5 passwords */
++#define UNIX__NULLOK             14	/* Null token ok */
++#define UNIX_DEBUG               15	/* send more info to syslog(3) */
++#define UNIX_NODELAY             16	/* admin does not want a fail-delay */
++#define UNIX_NIS                 17	/* wish to use NIS for pwd */
++#define UNIX_BIGCRYPT            18	/* use DEC-C2 crypt()^x function */
++#define UNIX_LIKE_AUTH           19	/* need to auth for setcred to work */
++#define UNIX_REMEMBER_PASSWD     20	/* Remember N previous passwords */
++#define UNIX_NOREAP              21     /* don't reap child process */
++#define UNIX_BROKEN_SHADOW       22     /* ignore errors reading password aging
++					 * information during acct management */
++#define UNIX_SHA256_PASS         23	/* new password hashes will use SHA256 */
++#define UNIX_SHA512_PASS         24	/* new password hashes will use SHA512 */
++#define UNIX_ALGO_ROUNDS         25	/* optional number of rounds for new
++					   password hash algorithms */
++#define UNIX_BLOWFISH_PASS       26	/* new password hashes will use blowfish */
++#define UNIX_MIN_PASS_LEN        27	/* min length for password */
++#define UNIX_OBSCURE_CHECKS      28	/* enable obscure checks on passwords */
++#define UNIX_NULLOK_SECURE       29	/* NULL passwords allowed only on secure ttys */
++/* -------------- */
++#define UNIX_CTRLS_              30	/* number of ctrl arguments defined */
++
++#define UNIX_DES_CRYPT(ctrl)	(off(UNIX_MD5_PASS,ctrl)&&off(UNIX_BIGCRYPT,ctrl)&&off(UNIX_SHA256_PASS,ctrl)&&off(UNIX_SHA512_PASS,ctrl)&&off(UNIX_BLOWFISH_PASS,ctrl))
++
++static const UNIX_Ctrls unix_args[UNIX_CTRLS_] =
++{
++/* symbol                  token name          ctrl mask             ctrl     *
++ * ----------------------- ------------------- --------------------- -------- */
++
++/* UNIX__OLD_PASSWD */     {NULL,              _ALL_ON_,                  0x1, 0},
++/* UNIX__VERIFY_PASSWD */  {NULL,              _ALL_ON_,                  0x2, 0},
++/* UNIX__IAMROOT */        {NULL,              _ALL_ON_,                  0x4, 0},
++/* UNIX_AUDIT */           {"audit",           _ALL_ON_,                  0x8, 0},
++/* UNIX_USE_FIRST_PASS */  {"use_first_pass",  _ALL_ON_^(0x30),          0x10, 0},
++/* UNIX_TRY_FIRST_PASS */  {"try_first_pass",  _ALL_ON_^(0x30),          0x20, 0},
++/* UNIX_NOT_SET_PASS */    {"not_set_pass",    _ALL_ON_,                 0x40, 0},
++/* UNIX__PRELIM */         {NULL,              _ALL_ON_^(0x180),         0x80, 0},
++/* UNIX__UPDATE */         {NULL,              _ALL_ON_^(0x180),        0x100, 0},
++/* UNIX__NONULL */         {NULL,              _ALL_ON_^(0x10000000),   0x200, 0},
++/* UNIX__QUIET */          {NULL,              _ALL_ON_,                0x400, 0},
++/* UNIX_USE_AUTHTOK */     {"use_authtok",     _ALL_ON_,                0x800, 0},
++/* UNIX_SHADOW */          {"shadow",          _ALL_ON_,               0x1000, 0},
++/* UNIX_MD5_PASS */        {"md5",             _ALL_ON_^(0x2C22000),   0x2000, 1},
++/* UNIX__NULLOK */         {"nullok",          _ALL_ON_^(0x200),            0, 0},
++/* UNIX_DEBUG */           {"debug",           _ALL_ON_,               0x4000, 0},
++/* UNIX_NODELAY */         {"nodelay",         _ALL_ON_,               0x8000, 0},
++/* UNIX_NIS */             {"nis",             _ALL_ON_,              0x10000, 0},
++/* UNIX_BIGCRYPT */        {"bigcrypt",        _ALL_ON_^(0x2C22000),  0x20000, 1},
++/* UNIX_LIKE_AUTH */       {"likeauth",        _ALL_ON_,              0x40000, 0},
++/* UNIX_REMEMBER_PASSWD */ {"remember=",       _ALL_ON_,              0x80000, 0},
++/* UNIX_NOREAP */          {"noreap",          _ALL_ON_,             0x100000, 0},
++/* UNIX_BROKEN_SHADOW */   {"broken_shadow",   _ALL_ON_,             0x200000, 0},
++/* UNIX_SHA256_PASS */     {"sha256",          _ALL_ON_^(0x2C22000), 0x400000, 1},
++/* UNIX_SHA512_PASS */     {"sha512",          _ALL_ON_^(0x2C22000), 0x800000, 1},
++/* UNIX_ALGO_ROUNDS */     {"rounds=",         _ALL_ON_,            0x1000000, 0},
++/* UNIX_BLOWFISH_PASS */   {"blowfish",        _ALL_ON_^(0x2C22000),0x2000000, 1},
++/* UNIX_MIN_PASS_LEN */    {"minlen=",         _ALL_ON_,            0x4000000, 0},
++/* UNIX_OBSCURE_CHECKS */  {"obscure",         _ALL_ON_,            0x8000000, 0},
++/* UNIX_NULLOK_SECURE */   {"nullok_secure",   _ALL_ON_^(0x200),   0x10000000, 0},
++};
++
++#define UNIX_DEFAULTS  (unix_args[UNIX__NONULL].flag)
++
++#define MAX_FD_NO 2000000
++
++/* use this to free strings. ESPECIALLY password strings */
++
++#define _pam_delete(xx)		\
++{				\
++	_pam_overwrite(xx);	\
++	_pam_drop(xx);		\
++}
++
++extern int _make_remark(pam_handle_t * pamh, unsigned int ctrl
++		       ,int type, const char *text);
++extern int _set_ctrl(pam_handle_t * pamh, int flags, int *remember, int *rounds,
++		     int *pass_min_len, int argc, const char **argv);
++extern int _unix_getpwnam (pam_handle_t *pamh,
++			   const char *name, int files, int nis,
++			   struct passwd **ret);
++extern int _unix_comesfromsource (pam_handle_t *pamh,
++				  const char *name, int files, int nis);
++extern int _unix_blankpasswd(pam_handle_t *pamh,unsigned int ctrl,
++			     const char *name);
++extern int _unix_verify_password(pam_handle_t * pamh, const char *name
++			  ,const char *p, unsigned int ctrl);
++extern int _unix_read_password(pam_handle_t * pamh
++			,unsigned int ctrl
++			,const char *comment
++			,const char *prompt1
++			,const char *prompt2
++			,const char *data_name
++			,const void **pass);
++
++extern int _unix_run_verify_binary(pam_handle_t *pamh,
++			unsigned int ctrl, const char *user, int *daysleft);
++#endif /* _PAM_UNIX_SUPPORT_H */
+--- /dev/null
++++ b/modules/pam_extrausers/unix_chkpwd.c
+@@ -0,0 +1,239 @@
++/*
++ * This program is designed to run setuid(root) or with sufficient
++ * privilege to read all of the unix password databases. It is designed
++ * to provide a mechanism for the current user (defined by this
++ * process' uid) to verify their own password.
++ *
++ * The password is read from the standard input. The exit status of
++ * this program indicates whether the user is authenticated or not.
++ *
++ * Copyright information is located at the end of the file.
++ *
++ */
++
++#include "config.h"
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <syslog.h>
++#include <unistd.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <pwd.h>
++#include <shadow.h>
++#include <signal.h>
++#include <time.h>
++#include <errno.h>
++#ifdef HAVE_LIBAUDIT
++#include <libaudit.h>
++#endif
++
++#include <security/_pam_types.h>
++#include <security/_pam_macros.h>
++
++#include "passverify.h"
++
++static int _check_expiry(const char *uname)
++{
++	struct spwd *spent;
++	struct passwd *pwent;
++	int retval;
++	int daysleft;
++
++	retval = get_account_info(uname, &pwent, &spent);
++	if (retval != PAM_SUCCESS) {
++		helper_log_err(LOG_ALERT, "could not obtain user info (%s)", uname);
++		printf("-1\n");
++		return retval;
++	}
++
++	if (spent == NULL) {
++		printf("-1\n");
++		return retval;
++	}
++
++	retval = check_shadow_expiry(spent, &daysleft);
++	printf("%d\n", daysleft);
++	return retval;
++}
++
++#ifdef HAVE_LIBAUDIT
++static int _audit_log(int type, const char *uname, int rc)
++{
++	int audit_fd;
++
++	audit_fd = audit_open();
++	if (audit_fd < 0) {
++		/* You get these error codes only when the kernel doesn't have
++		 * audit compiled in. */
++		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
++			errno == EAFNOSUPPORT)
++			return PAM_SUCCESS;
++
++		helper_log_err(LOG_CRIT, "audit_open() failed: %m");
++		return PAM_AUTH_ERR;
++	}
++
++	rc = audit_log_acct_message(audit_fd, type, NULL, "PAM:pam_extrausers_chkpwd",
++		uname, -1, NULL, NULL, NULL, rc == PAM_SUCCESS);
++	if (rc == -EPERM && geteuid() != 0) {
++		rc = 0;
++	}
++
++	audit_close(audit_fd);
++
++	return rc < 0 ? PAM_AUTH_ERR : PAM_SUCCESS;
++}
++#endif
++
++int main(int argc, char *argv[])
++{
++	char pass[MAXPASS + 1];
++	char *option;
++	int npass, nullok;
++	int blankpass = 0;
++	int retval = PAM_AUTH_ERR;
++	char *user;
++	char *passwords[] = { pass };
++
++	/*
++	 * Catch or ignore as many signal as possible.
++	 */
++	setup_signals();
++
++	/*
++	 * we establish that this program is running with non-tty stdin.
++	 * this is to discourage casual use. It does *NOT* prevent an
++	 * intruder from repeatadly running this program to determine the
++	 * password of the current user (brute force attack, but one for
++	 * which the attacker must already have gained access to the user's
++	 * account).
++	 */
++
++	if (isatty(STDIN_FILENO) || argc != 3 ) {
++		helper_log_err(LOG_NOTICE
++		      ,"inappropriate use of Unix helper binary [UID=%d]"
++			 ,getuid());
++#ifdef HAVE_LIBAUDIT
++		_audit_log(AUDIT_ANOM_EXEC, getuidname(getuid()), PAM_SYSTEM_ERR);
++#endif
++		fprintf(stderr
++		 ,"This binary is not designed for running in this way\n"
++		      "-- the system administrator has been informed\n");
++		sleep(10);	/* this should discourage/annoy the user */
++		return PAM_SYSTEM_ERR;
++	}
++
++	/*
++	 * Determine what the current user's name is.
++	 * We must thus skip the check if the real uid is 0.
++	 */
++	if (getuid() == 0) {
++	  user=argv[1];
++	}
++	else {
++	  user = getuidname(getuid());
++	  /* if the caller specifies the username, verify that user
++	     matches it */
++	  if (strcmp(user, argv[1])) {
++	    gid_t gid = getgid();
++	    user = argv[1];
++	    /* no match -> permanently change to the real user and proceed */
++	    if (setresgid(gid, gid, gid) != 0 || setuid(getuid()) != 0)
++		return PAM_AUTH_ERR;
++	  }
++	}
++
++	option=argv[2];
++
++	if (strcmp(option, "chkexpiry") == 0)
++	  /* Check account information from the shadow file */
++	  return _check_expiry(argv[1]);
++	/* read the nullok/nonull option */
++	else if (strcmp(option, "nullok") == 0)
++	  nullok = 1;
++	else if (strcmp(option, "nonull") == 0)
++	  nullok = 0;
++	else {
++#ifdef HAVE_LIBAUDIT
++	  _audit_log(AUDIT_ANOM_EXEC, getuidname(getuid()), PAM_SYSTEM_ERR);
++#endif
++	  return PAM_SYSTEM_ERR;
++	}
++	/* read the password from stdin (a pipe from the pam_unix module) */
++
++	npass = read_passwords(STDIN_FILENO, 1, passwords);
++
++	if (npass != 1) {	/* is it a valid password? */
++		helper_log_err(LOG_DEBUG, "no password supplied");
++		*pass = '\0';
++	}
++
++	if (*pass == '\0') {
++		blankpass = 1;
++	}
++
++	retval = helper_verify_password(user, pass, nullok);
++
++	memset(pass, '\0', MAXPASS);	/* clear memory of the password */
++
++	/* return pass or fail */
++
++	if (retval != PAM_SUCCESS) {
++		if (!nullok || !blankpass) {
++			/* no need to log blank pass test */
++#ifdef HAVE_LIBAUDIT
++			if (getuid() != 0)
++				_audit_log(AUDIT_USER_AUTH, user, PAM_AUTH_ERR);
++#endif
++			helper_log_err(LOG_NOTICE, "password check failed for user (%s)", user);
++		}
++		return PAM_AUTH_ERR;
++	} else {
++	        if (getuid() != 0) {
++#ifdef HAVE_LIBAUDIT
++			return _audit_log(AUDIT_USER_AUTH, user, PAM_SUCCESS);
++#else
++		        return PAM_SUCCESS;
++#endif
++	        }
++		return PAM_SUCCESS;
++	}
++}
++
++/*
++ * Copyright (c) Andrew G. Morgan, 1996. All rights reserved
++ * Copyright (c) Red Hat, Inc., 2007,2008. All rights reserved
++ *
++ * 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.
++ */
+--- /dev/null
++++ b/modules/pam_extrausers/unix_update.c
+@@ -0,0 +1,191 @@
++/*
++ * This program is designed to run with sufficient privilege
++ * to read and write all of the unix password databases.
++ * Its purpose is to allow updating the databases when
++ * SELinux confinement of the caller domain prevents them to
++ * do that themselves.
++ *
++ * The password is read from the standard input. The exit status of
++ * this program indicates whether the password was updated or not.
++ *
++ * Copyright information is located at the end of the file.
++ *
++ */
++
++#include "config.h"
++
++#include <stdarg.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <syslog.h>
++#include <unistd.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <pwd.h>
++#include <shadow.h>
++#include <signal.h>
++#include <time.h>
++#include <sys/time.h>
++
++#include <security/_pam_types.h>
++#include <security/_pam_macros.h>
++
++#include "passverify.h"
++
++static int
++set_password(const char *forwho, const char *shadow, const char *remember)
++{
++    struct passwd *pwd = NULL;
++    int retval;
++    char pass[MAXPASS + 1];
++    char towhat[MAXPASS + 1];
++    int npass = 0;
++    /* we don't care about number format errors because the helper
++       should be called internally only */
++    int doshadow = atoi(shadow);
++    int nremember = atoi(remember);
++    char *passwords[] = { pass, towhat };
++
++    /* read the password from stdin (a pipe from the pam_unix module) */
++
++    npass = read_passwords(STDIN_FILENO, 2, passwords);
++
++    if (npass != 2) {	/* is it a valid password? */
++      if (npass == 1) {
++        helper_log_err(LOG_DEBUG, "no new password supplied");
++	memset(pass, '\0', MAXPASS);
++      } else {
++        helper_log_err(LOG_DEBUG, "no valid passwords supplied");
++      }
++      return PAM_AUTHTOK_ERR;
++    }
++
++    if (lock_pwdf() != PAM_SUCCESS)
++	return PAM_AUTHTOK_LOCK_BUSY;
++
++    pwd = getpwnam(forwho);
++
++    if (pwd == NULL) {
++        retval = PAM_USER_UNKNOWN;
++        goto done;
++    }
++
++    /* If real caller uid is not root we must verify that
++       received old pass agrees with the current one.
++       We always allow change from null pass. */
++    if (getuid()) {
++	retval = helper_verify_password(forwho, pass, 1);
++	if (retval != PAM_SUCCESS) {
++	    goto done;
++	}
++    }
++
++    /* first, save old password */
++    if (save_old_password(forwho, pass, nremember)) {
++	retval = PAM_AUTHTOK_ERR;
++	goto done;
++    }
++
++    if (doshadow || is_pwd_shadowed(pwd)) {
++	retval = unix_update_shadow(forwho, towhat);
++	if (retval == PAM_SUCCESS)
++	    if (!is_pwd_shadowed(pwd))
++		retval = unix_update_passwd(forwho, "x");
++    } else {
++	retval = unix_update_passwd(forwho, towhat);
++    }
++
++done:
++    memset(pass, '\0', MAXPASS);
++    memset(towhat, '\0', MAXPASS);
++
++    unlock_pwdf();
++
++    if (retval == PAM_SUCCESS) {
++	return PAM_SUCCESS;
++    } else {
++	return PAM_AUTHTOK_ERR;
++    }
++}
++
++int main(int argc, char *argv[])
++{
++	char *option;
++
++	/*
++	 * Catch or ignore as many signal as possible.
++	 */
++	setup_signals();
++
++	/*
++	 * we establish that this program is running with non-tty stdin.
++	 * this is to discourage casual use. It does *NOT* prevent an
++	 * intruder from repeatadly running this program to determine the
++	 * password of the current user (brute force attack, but one for
++	 * which the attacker must already have gained access to the user's
++	 * account).
++	 */
++
++	if (isatty(STDIN_FILENO) || argc != 5 ) {
++		helper_log_err(LOG_NOTICE
++		      ,"inappropriate use of Unix helper binary [UID=%d]"
++			 ,getuid());
++		fprintf(stderr
++		 ,"This binary is not designed for running in this way\n"
++		      "-- the system administrator has been informed\n");
++		sleep(10);	/* this should discourage/annoy the user */
++		return PAM_SYSTEM_ERR;
++	}
++
++	/* We must be root to read/update shadow.
++	 */
++	if (geteuid() != 0) {
++	    return PAM_CRED_INSUFFICIENT;
++	}
++
++	option = argv[2];
++
++	if (strcmp(option, "update") == 0) {
++	    /* Attempting to change the password */
++	    return set_password(argv[1], argv[3], argv[4]);
++	}
++
++	return PAM_SYSTEM_ERR;
++}
++
++/*
++ * Copyright (c) Andrew G. Morgan, 1996. All rights reserved
++ * Copyright (c) Red Hat, Inc., 2007, 2008. All rights reserved
++ *
++ * 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.
++ */
+--- /dev/null
++++ b/modules/pam_extrausers/yppasswd.h
+@@ -0,0 +1,51 @@
++/*
++ * yppasswdd
++ * Copyright 1994, 1995, 1996 Olaf Kirch, <okir@lst.de>
++ *
++ * This program is covered by the GNU General Public License, version 2
++ * or later. It is provided in the hope that it is useful. However, the author
++ * disclaims ALL WARRANTIES, expressed or implied. See the GPL for details.
++ *
++ * This file was generated automatically by rpcgen from yppasswd.x, and
++ * editied manually.
++ */
++
++#ifndef _YPPASSWD_H_
++#define _YPPASSWD_H_
++
++#define YPPASSWDPROG ((u_long)100009)
++#define YPPASSWDVERS ((u_long)1)
++#define YPPASSWDPROC_UPDATE ((u_long)1)
++
++/*
++ * The password struct passed by the update call. I renamed it to
++ * xpasswd to avoid a type clash with the one defined in <pwd.h>.
++ */
++#ifndef __sgi
++typedef struct xpasswd {
++	char *pw_name;
++	char *pw_passwd;
++	int pw_uid;
++	int pw_gid;
++	char *pw_gecos;
++	char *pw_dir;
++	char *pw_shell;
++} xpasswd;
++
++#else
++#include <pwd.h>
++typedef struct xpasswd xpasswd;
++#endif
++
++/* The updated password information, plus the old password.
++ */
++typedef struct yppasswd {
++	char *oldpass;
++	xpasswd newpw;
++} yppasswd;
++
++/* XDR encoding/decoding routines */
++bool_t xdr_xpasswd(XDR * xdrs, xpasswd * objp);
++bool_t xdr_yppasswd(XDR * xdrs, yppasswd * objp);
++
++#endif	/* _YPPASSWD_H_ */
+--- /dev/null
++++ b/modules/pam_extrausers/yppasswd_xdr.c
+@@ -0,0 +1,40 @@
++/*
++ * yppasswdd
++ * Copyright 1994, 1995, 1996 Olaf Kirch, <okir@lst.de>
++ *
++ * This program is covered by the GNU General Public License, version 2
++ * or later. It is provided in the hope that it is useful. However, the author
++ * disclaims ALL WARRANTIES, expressed or implied. See the GPL for details.
++ *
++ * This file was generated automatically by rpcgen from yppasswd.x, and
++ * editied manually.
++ */
++
++#include "config.h"
++
++#ifdef HAVE_RPC_RPC_H
++
++#include <rpc/rpc.h>
++#include "yppasswd.h"
++
++bool_t
++xdr_xpasswd(XDR * xdrs, xpasswd * objp)
++{
++	return xdr_string(xdrs, &objp->pw_name, ~0)
++	    && xdr_string(xdrs, &objp->pw_passwd, ~0)
++	    && xdr_int(xdrs, &objp->pw_uid)
++	    && xdr_int(xdrs, &objp->pw_gid)
++	    && xdr_string(xdrs, &objp->pw_gecos, ~0)
++	    && xdr_string(xdrs, &objp->pw_dir, ~0)
++	    && xdr_string(xdrs, &objp->pw_shell, ~0);
++}
++
++
++bool_t
++xdr_yppasswd(XDR * xdrs, yppasswd * objp)
++{
++	return xdr_string(xdrs, &objp->oldpass, ~0)
++	    && xdr_xpasswd(xdrs, &objp->newpw);
++}
++
++#endif
+--- /dev/null
++++ b/modules/pam_extrausers/tst-pam_extrausers
+@@ -0,0 +1,2 @@
++#!/bin/sh
++../../tests/tst-dlopen .libs/pam_extrausers.so
+--- /dev/null
++++ b/modules/pam_extrausers/pam_extrausers.8.xml
+@@ -0,0 +1,484 @@
++<refentry xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="pam_extrausers">
++
++  <refmeta>
++    <refentrytitle>pam_extrausers</refentrytitle>
++    <manvolnum>8</manvolnum>
++    <refmiscinfo class="sectdesc">Linux-PAM Manual</refmiscinfo>
++  </refmeta>
++
++  <refnamediv xml:id="pam_extrausers-name">
++    <refname>pam_extrausers</refname>
++    <refpurpose>Module for libnss-extrausers authentication</refpurpose>
++  </refnamediv>
++
++  <refsynopsisdiv>
++    <cmdsynopsis xml:id="pam_extrausers-cmdsynopsis">
++      <command>pam_extrausers.so</command>
++      <arg choice="opt">
++        ...
++      </arg>
++    </cmdsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1 xml:id="pam_extrausers-description">
++
++    <title>DESCRIPTION</title>
++
++    <para>
++      This is similar to the standard Unix authentication module pam_unix.
++      But instead of using /etc/passwd and /etc/shadow, it uses
++      /var/lib/extrausers/passwd and /var/lib/extrausers/shadow.
++    </para>
++
++    <para>
++      The account component performs the task of establishing the status
++      of the user's account and password based on the following
++      <emphasis>shadow</emphasis> elements: expire, last_change, max_change,
++      min_change, warn_change. In the case of the latter, it may offer advice
++      to the user on changing their password or, through the
++      <emphasis remap='B'>PAM_AUTHTOKEN_REQD</emphasis> return, delay
++      giving service to the user until they have established a new password.
++      The entries listed above are documented in the <citerefentry>
++      <refentrytitle>shadow</refentrytitle><manvolnum>5</manvolnum>
++      </citerefentry> manual page. Should the user's record not contain
++      one or more of these entries, the corresponding
++      <emphasis>shadow</emphasis> check is not performed.
++    </para>
++
++    <para>
++      The authentication component performs the task of checking the
++      users credentials (password). The default action of this module
++      is to not permit the user access to a service if their official
++      password is blank.
++    </para>
++
++    <para>
++      The password component of this module performs the task of updating
++      the user's password. The default encryption hash is taken from the
++      <emphasis remap='B'>ENCRYPT_METHOD</emphasis> variable from
++      <emphasis>/etc/login.defs</emphasis>
++    </para>
++
++    <para>
++      The session component of this module logs when a user logins
++      or leave the system.
++    </para>
++
++    <para>
++      Remaining arguments, supported by others functions of this
++      module, are silently ignored. Other arguments are logged as
++      errors through <citerefentry>
++      <refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum>
++      </citerefentry>.
++    </para>
++  </refsect1>
++
++  <refsect1 xml:id="pam_extrausers-options">
++
++    <title>OPTIONS</title>
++    <variablelist>
++      <varlistentry>
++        <term>
++          <option>debug</option>
++        </term>
++        <listitem>
++          <para>
++	    Turns on debugging via
++            <citerefentry>
++              <refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum>
++            </citerefentry>.
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term>
++          <option>audit</option>
++        </term>
++        <listitem>
++          <para>
++            A little more extreme than debug.
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term>
++          <option>nullok</option>
++        </term>
++        <listitem>
++          <para>
++            The default action of this module is to not permit the
++            user access to a service if their official password is blank.
++            The <option>nullok</option> argument overrides this default
++            and allows any user with a blank password to access the
++            service.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>nullok_secure</option>
++        </term>
++        <listitem>
++          <para>
++            The default action of this module is to not permit the
++            user access to a service if their official password is blank.
++            The <option>nullok_secure</option> argument overrides this
++            default and allows any user with a blank password to access
++            the service as long as the value of PAM_TTY is set to one of
++	    the values found in /etc/securetty.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>try_first_pass</option>
++        </term>
++        <listitem>
++          <para>
++            Before prompting the user for their password, the module first
++            tries the previous stacked module's password in case that
++            satisfies this module as well.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>use_first_pass</option>
++        </term>
++        <listitem>
++          <para>
++            The argument <option>use_first_pass</option> forces the module
++            to use a previous stacked modules password and will never prompt
++            the user - if no password is available or the password is not
++            appropriate, the user will be denied access.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>nodelay</option>
++        </term>
++        <listitem>
++          <para>
++            This argument can be used to discourage the authentication
++            component from requesting a delay should the authentication
++            as a whole fail. The default action is for the module to
++            request a delay-on-failure of the order of two second.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>use_authtok</option>
++        </term>
++        <listitem>
++          <para>
++            When password changing enforce the module to set the new
++            password to the one provided by a previously stacked
++            <option>password</option> module (this is used in the
++            example of the stacking of the <command>pam_cracklib</command>
++            module documented below).
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>not_set_pass</option>
++        </term>
++        <listitem>
++          <para>
++            This argument is used to inform the module that it is not to
++            pay attention to/make available the old or new passwords from/to
++            other (stacked) password modules.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>nis</option>
++        </term>
++        <listitem>
++          <para>
++            NIS RPC is used for setting new passwords.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>remember=<replaceable>n</replaceable></option>
++        </term>
++        <listitem>
++          <para>
++            The last <replaceable>n</replaceable> passwords for each
++            user are saved in <filename>/etc/security/opasswd</filename>
++            in order to force password change history and keep the user
++            from alternating between the same password too frequently.
++            Instead of this option the <command>pam_pwhistory</command>
++            module should be used.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>shadow</option>
++        </term>
++        <listitem>
++          <para>
++            Try to maintain a shadow based system.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>md5</option>
++        </term>
++        <listitem>
++          <para>
++            When a user changes their password next, encrypt
++            it with the MD5 algorithm.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>bigcrypt</option>
++        </term>
++        <listitem>
++          <para>
++            When a user changes their password next,
++            encrypt it with the DEC C2 algorithm.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>sha256</option>
++        </term>
++        <listitem>
++          <para>
++            When a user changes their password next,
++            encrypt it with the SHA256 algorithm. If the
++            SHA256 algorithm is not known to the <citerefentry>
++	    <refentrytitle>crypt</refentrytitle><manvolnum>3</manvolnum>
++            </citerefentry> function,
++            fall back to MD5.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>sha512</option>
++        </term>
++        <listitem>
++          <para>
++            When a user changes their password next,
++            encrypt it with the SHA512 algorithm. If the
++            SHA512 algorithm is not known to the <citerefentry>
++	    <refentrytitle>crypt</refentrytitle><manvolnum>3</manvolnum>
++            </citerefentry> function,
++            fall back to MD5.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>blowfish</option>
++        </term>
++        <listitem>
++          <para>
++            When a user changes their password next,
++            encrypt it with the blowfish algorithm. If the
++            blowfish algorithm is not known to the <citerefentry>
++	    <refentrytitle>crypt</refentrytitle><manvolnum>3</manvolnum>
++            </citerefentry> function,
++            fall back to MD5.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>rounds=<replaceable>n</replaceable></option>
++        </term>
++        <listitem>
++          <para>
++            Set the optional number of rounds of the SHA256, SHA512
++            and blowfish password hashing algorithms to
++            <replaceable>n</replaceable>.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>broken_shadow</option>
++        </term>
++        <listitem>
++          <para>
++            Ignore errors reading shadow information for
++            users in the account management module.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>minlen=<replaceable>n</replaceable></option>
++        </term>
++        <listitem>
++          <para>
++            Set a minimum password length of <replaceable>n</replaceable>
++            characters.  The default value is 6.  The maximum for DES
++            crypt-based passwords is 8 characters.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>
++          <option>obscure</option>
++        </term>
++        <listitem>
++          <para>
++            Enable some extra checks on password strength.  These checks
++            are based on the "obscure" checks in the original shadow
++            package.  The behavior is similar to the pam_cracklib
++            module, but for non-dictionary-based checks.  The following
++            checks are implemented:
++            <variablelist>
++              <varlistentry>
++                <term>
++                  <option>Palindrome</option>
++                </term>
++                <listitem>
++                  <para>
++                    Verifies that the new password is not a palindrome
++                    of (i.e., the reverse of) the previous one.
++                  </para>
++                </listitem>
++              </varlistentry>
++              <varlistentry>
++                <term>
++                  <option>Case Change Only</option>
++                </term>
++                <listitem>
++                  <para>
++                    Verifies that the new password isn't the same as the
++                    old one with a change of case.
++                  </para>
++                </listitem>
++              </varlistentry>
++              <varlistentry>
++                <term>
++                  <option>Similar</option>
++                </term>
++                <listitem>
++                  <para>
++                    Verifies that the new password isn't too much like
++                    the previous one.
++                  </para>
++                </listitem>
++              </varlistentry>
++              <varlistentry>
++                <term>
++                  <option>Simple</option>
++                </term>
++                <listitem>
++                  <para>
++                    Is the new password too simple?  This is based on
++                    the length of the password and the number of
++                    different types of characters (alpha, numeric, etc.)
++                    used.
++                  </para>
++                </listitem>
++              </varlistentry>
++              <varlistentry>
++                <term>
++                  <option>Rotated</option>
++                </term>
++                <listitem>
++                  <para>
++                    Is the new password a rotated version of the old
++                    password?  (E.g., "billy" and "illyb")
++                  </para>
++                </listitem>
++              </varlistentry>
++            </variablelist>
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++    <para>
++      Invalid arguments are logged with  <citerefentry>
++      <refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum>
++      </citerefentry>.
++    </para>
++  </refsect1>
++
++  <refsect1 xml:id="pam_extrausers-types">
++    <title>MODULE TYPES PROVIDED</title>
++    <para>
++      All module types (<option>account</option>, <option>auth</option>,
++      <option>password</option> and <option>session</option>) are provided.
++    </para>
++  </refsect1>
++
++  <refsect1 xml:id="pam_extrausers-return_values">
++    <title>RETURN VALUES</title>
++    <variablelist>
++      <varlistentry>
++        <term>PAM_IGNORE</term>
++        <listitem>
++          <para>
++            Ignore this module.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++     </refsect1>
++
++  <refsect1 xml:id='pam_extrausers-examples'>
++    <title>EXAMPLES</title>
++    <para>
++      An example usage for <filename>/etc/pam.d/common-password</filename>
++      might be:
++      <programlisting>
++password        [success=2 default=ignore]      pam_extrausers.so obscure sha512
++password        [success=1 default=ignore]      pam_unix.so obscure sha512
++# here's the fallback if no module succeeds
++password        requisite                       pam_deny.so
++# prime the stack with a positive return value if there isn't one already;
++# this avoids us returning an error just because nothing sets a success code
++# since the modules above will each just jump around
++password        required                        pam_permit.so
++# and here are more per-package modules (the "Additional" block)
++password        optional        pam_gnome_keyring.so
++password        optional        pam_ecryptfs.so
++      </programlisting>
++    </para>
++  </refsect1>
++
++  <refsect1 xml:id='pam_extrausers-see_also'>
++    <title>SEE ALSO</title>
++    <para>
++      <citerefentry>
++	<refentrytitle>login.defs</refentrytitle><manvolnum>5</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>pam.conf</refentrytitle><manvolnum>5</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>pam.d</refentrytitle><manvolnum>5</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++	<refentrytitle>pam</refentrytitle><manvolnum>7</manvolnum>
++      </citerefentry>
++    </para>
++  </refsect1>
++
++  <refsect1 xml:id='pam_extrausers-author'>
++    <title>AUTHOR</title>
++      <para>
++        pam_extrausers was written by various people.
++      </para>
++  </refsect1>
++
++</refentry>
+--- a/modules/meson.build
++++ b/modules/meson.build
+@@ -11,6 +11,7 @@
+ subdir('pam_echo')
+ subdir('pam_env')
+ subdir('pam_exec')
++subdir('pam_extrausers')
+ subdir('pam_faildelay')
+ subdir('pam_faillock')
+ subdir('pam_filter')
+--- /dev/null
++++ b/modules/pam_extrausers/README.xml
+@@ -0,0 +1,27 @@
++<article xmlns="http://docbook.org/ns/docbook" version="5.0">
++
++  <info>
++
++    <title>
++      <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_extrausers.8.xml" xpointer='xpointer(id("pam_extrausers-name")/*)'/>
++    </title>
++
++  </info>
++
++  <section>
++    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_extrausers.8.xml" xpointer='xpointer(id("pam_extrausers-description")/*)'/>
++  </section>
++
++  <section>
++    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_extrausers.8.xml" xpointer='xpointer(id("pam_extrausers-options")/*)'/>
++  </section>
++
++  <section>
++    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_extrausers.8.xml" xpointer='xpointer(id("pam_extrausers-examples")/*)'/>
++  </section>
++
++  <section>
++    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_extrausers.8.xml" xpointer='xpointer(id("pam_extrausers-author")/*)'/>
++  </section>
++
++</article>
+--- /dev/null
++++ b/modules/pam_extrausers/meson.build
+@@ -0,0 +1,564 @@
++# -*- mode: meson -*-
++
++module = fs.name(meson.current_source_dir())
++
++# pam_module.so
++
++pam_module_src = [module + '.c']
++pam_module_c_args = []
++pam_module_deps = [libpam_internal_dep, libpam_dep]
++
++if module == 'pam_env'
++  pam_module_deps += [libeconf]
++endif
++if module == 'pam_extrausers'
++  pam_module_src = ['bigcrypt.c',
++                    'pam_unix_acct.c',
++                    'pam_unix_auth.c',
++                    'pam_unix_passwd.c',
++                    'pam_unix_sess.c',
++                    'support.c',
++                    'passverify.c',
++                    'md5_good.c',
++                    'md5_broken.c',
++                    'yppasswd_xdr.c',
++                    'obscure.c',
++                   ]
++  pam_module_c_args += ['-DCHKPWD_HELPER="@0@"'.format(sbindir / 'pam_extrausers_chkpwd'),
++                        '-DUPDATE_HELPER="@0@"'.format(sbindir / 'pam_extrausers_update')]
++  pam_module_deps += [libcrypt, libselinux, libtirpc, libnsl]
++endif
++if module == 'pam_faillock'
++  pam_module_src += ['faillock.c', 'faillock_config.c']
++  pam_module_deps += [libaudit]
++endif
++if module == 'pam_issue'
++  pam_module_deps += [libsystemd]
++endif
++if module == 'pam_keyinit'
++  if not enable_pam_keyinit
++    subdir_done()
++  endif
++endif
++if module == 'pam_lastlog'
++  if not enable_pam_lastlog
++    subdir_done()
++  endif
++  pam_module_deps += [libutil]
++endif
++if module == 'pam_limits'
++  limits_conf_dir = sconfigdir / 'limits.d'
++  pam_module_c_args += ['-DLIMITS_FILE_DIR="@0@"'.format(limits_conf_dir)]
++  pam_module_deps += [libsystemd]
++endif
++if module == 'pam_loginuid'
++  pam_module_deps += [libaudit]
++endif
++if module == 'pam_mkhomedir'
++  pam_module_c_args += ['-DMKHOMEDIR_HELPER="@0@"'.format(sbindir / 'mkhomedir_helper')]
++endif
++if module == 'pam_namespace'
++  if cdata.get('HAVE_UNSHARE', 0) == 0
++    subdir_done()
++  endif
++  pam_module_src += ['md5.c', 'argv_parse.c']
++  pam_module_deps += [libselinux]
++endif
++if module == 'pam_pwhistory'
++  pam_module_src += ['opasswd.c', 'pwhistory_config.c']
++  if libselinux.found()
++    pam_module_c_args += ['-DPWHISTORY_HELPER="@0@"'.format(sbindir / 'pwhistory_helper')]
++  endif
++  pam_module_deps += [libcrypt, libselinux]
++endif
++if module == 'pam_rhosts'
++  if cdata.get('HAVE_RUSEROK', 0) == 0 or cdata.get('HAVE_RUSEROK_AF', 0) == 0
++    subdir_done()
++  endif
++endif
++if module == 'pam_rootok'
++  pam_module_deps += [libselinux, libaudit]
++endif
++if module == 'pam_selinux'
++  if not libselinux.found()
++    subdir_done()
++  endif
++  pam_module_deps += [libselinux, libaudit]
++endif
++if module == 'pam_sepermit'
++  if not libselinux.found()
++    subdir_done()
++  endif
++  pam_module_deps += [libselinux]
++  sepermit_lockdir = localstatedir / 'run' / 'sepermit'
++  pam_module_c_args += ['-DSEPERMIT_LOCKDIR="@0@"'.format(sepermit_lockdir)]
++endif
++if module == 'pam_setquota'
++  if cdata.get('HAVE_QUOTACTL', 0) == 0
++    subdir_done()
++  endif
++endif
++if module == 'pam_shells'
++  pam_module_deps += [libeconf]
++endif
++if module == 'pam_timestamp'
++  if cdata.get('WITH_OPENSSL', 0) == 1
++    pam_module_src += ['hmac_openssl_wrapper.c']
++  else
++    pam_module_src += ['hmacsha1.c', 'sha1.c']
++  endif
++  pam_module_deps += [libcrypto, libsystemd]
++endif
++if module == 'pam_tty_audit'
++  if cdata.get('HAVE_STRUCT_AUDIT_TTY_STATUS', 0) == 0
++    subdir_done()
++  endif
++endif
++if module == 'pam_unix'
++  if not enable_pam_unix
++    subdir_done()
++  endif
++  pam_module_src = ['bigcrypt.c',
++                    'pam_unix_acct.c',
++                    'pam_unix_auth.c',
++                    'pam_unix_passwd.c',
++                    'pam_unix_sess.c',
++                    'obscure.c',
++                    'support.c',
++                    'passverify.c',
++                    'md5_good.c',
++                    'md5_broken.c',
++                   ]
++  if enable_nis
++    pam_module_src += ['yppasswd_xdr.c']
++  endif
++  pam_module_c_args += ['-DCHKPWD_HELPER="@0@"'.format(sbindir / 'unix_chkpwd'),
++                        '-DUPDATE_HELPER="@0@"'.format(sbindir / 'unix_update')]
++  pam_module_deps += [libcrypt, libselinux, libtirpc, libnsl]
++endif
++if module == 'pam_userdb'
++  if not enable_pam_userdb
++    subdir_done()
++  endif
++  pam_module_deps += [libdb, libcrypt]
++endif
++if module == 'pam_xauth'
++  pam_module_deps += [libselinux]
++endif
++
++pam_module = shared_module(
++  module,
++  name_prefix: '',
++  sources: pam_module_src,
++  dependencies: pam_module_deps,
++  c_args: pam_module_c_args,
++  link_depends: pam_module_link_deps,
++  link_args: pam_module_link_args,
++  install: true,
++  install_dir: securedir,
++)
++
++
++# pam_module.8
++
++pam_module_mans = [[module + '.8', []]]
++if module == 'pam_access'
++  pam_module_mans += [['access.conf.5', []]]
++endif
++if module == 'pam_env'
++  pam_module_mans += [['pam_env.conf.5', ['environment.5']]]
++endif
++if module == 'pam_group'
++  pam_module_mans += [['group.conf.5', []]]
++endif
++if module == 'pam_faillock'
++  pam_module_mans += [['faillock.8', []],
++                      ['faillock.conf.5', []]]
++endif
++if module == 'pam_limits'
++  pam_module_mans += [['limits.conf.5', []]]
++endif
++if module == 'pam_mkhomedir'
++  pam_module_mans += [['mkhomedir_helper.8', []]]
++endif
++if module == 'pam_namespace'
++  pam_module_mans += [['namespace.conf.5', []],
++                      [module + '_helper.8', []]]
++endif
++if module == 'pam_pwhistory'
++  pam_module_mans += [['pwhistory.conf.5', []]]
++  if libselinux.found()
++    pam_module_mans += [['pwhistory_helper.8', []]]
++  endif
++endif
++if module == 'pam_sepermit'
++  pam_module_mans += [['sepermit.conf.5', []]]
++endif
++if module == 'pam_time'
++  pam_module_mans += [['time.conf.5', []]]
++endif
++if module == 'pam_timestamp'
++  pam_module_mans += [['pam_timestamp_check.8', []]]
++endif
++if module == 'pam_unix'
++  pam_module_mans += [['unix_chkpwd.8', []]]
++  if libselinux.found()
++    pam_module_mans += [['unix_update.8', []]]
++  endif
++endif
++
++foreach man: pam_module_mans
++  xml = man[0] + '.xml'
++
++  run_command([prog_xmllint,
++               '--nonet',
++               '--noout',
++               '--xinclude',
++               '--relaxng', docbook_rng,
++               xml],
++              check: true)
++
++  custom_target(man[0],
++    input: xml,
++    output: man,
++    depends: [custom_man_xsl, pam_module],
++    command: [prog_xsltproc,
++              '-o', '@OUTPUT0@',
++              '--nonet',
++              '--xinclude',
++              '--path', meson.current_source_dir(),
++              stringparam_vendordir,
++              stringparam_profileconditions,
++              custom_man_xsl,
++              '@INPUT@'],
++    install: true,
++    install_dir: mandir / 'man' + man[0].substring(-1),
++    install_tag: 'man',
++  )
++endforeach
++
++
++# README
++
++readme_html = custom_target(
++  input: 'README.xml',
++  output: 'README.html',
++  depends: pam_module,
++  command: [prog_xsltproc,
++            '-o', '@OUTPUT@',
++            '--nonet',
++            '--xinclude',
++            '--path', meson.current_source_dir(),
++            '--stringparam', 'generate.toc', 'none',
++            stringparam_vendordir,
++            stringparam_profileconditions,
++            txt_stylesheet,
++            '@INPUT@'],
++)
++
++custom_target(
++  input: readme_html,
++  output: module + '.txt',
++  command: [redir_exe,
++            '@INPUT@',
++            '@OUTPUT@',
++            browser],
++  env:docs_env,
++  install: true,
++  install_dir: docdir / 'modules',
++  install_tag: 'doc',
++)
++
++
++# module-specific configuration files and helpers
++
++if module == 'pam_access'
++  install_data(
++    'access.conf',
++    install_dir: vendor_sconfigdir,
++    install_tag: 'config',
++  )
++endif
++if module == 'pam_env'
++  install_data(
++    'pam_env.conf',
++    install_dir: vendor_sconfigdir,
++    install_tag: 'config',
++  )
++  install_data(
++    'environment',
++    install_dir: vendor_sysconfdir,
++    install_tag: 'config',
++  )
++endif
++if module == 'pam_extrausers'
++  executable(
++    'pam_extrausers_chkpwd',
++    sources: ['unix_chkpwd.c',
++              'bigcrypt.c',
++              'md5_good.c',
++              'md5_broken.c',
++              'passverify.c',
++             ],
++    c_args: ['-DHELPER_COMPILE="pam_extrausers_chkpwd"'],
++    link_args: exe_link_args,
++    dependencies: [libpam_internal_dep, libpam_dep, libcrypt, libselinux, libaudit],
++    install: true,
++    install_dir: sbindir,
++  )
++  executable(
++    'pam_extrausers_update',
++    sources: ['unix_update.c',
++              'bigcrypt.c',
++              'md5_good.c',
++              'md5_broken.c',
++              'passverify.c',
++             ],
++    c_args: ['-DHELPER_COMPILE="pam_extrausers_update"'],
++    link_args: exe_link_args,
++    dependencies: [libpam_internal_dep, libpam_dep, libcrypt, libselinux, libaudit],
++    install: true,
++    install_dir: sbindir,
++  )
++  executable(
++    'bigcrypt',
++    sources: ['bigcrypt.c', 'bigcrypt_main.c'],
++    dependencies: [libpam_internal_dep, libpam_dep, libcrypt],
++  )
++endif
++if module == 'pam_group'
++  install_data(
++    'group.conf',
++    install_dir: vendor_sconfigdir,
++    install_tag: 'config',
++  )
++endif
++if module == 'pam_faillock'
++  executable(
++    'faillock',
++    sources: ['main.c', 'faillock.c', 'faillock_config.c'],
++    link_args: exe_link_args,
++    dependencies: [libpam_internal_dep, libpam_dep, libaudit],
++    install: true,
++    install_dir: sbindir,
++  )
++  install_data(
++    'faillock.conf',
++    install_dir: vendor_sconfigdir,
++    install_tag: 'config',
++  )
++endif
++if module == 'pam_filter'
++  install_data(
++    'pam_filter.h',
++    install_dir: includedir,
++    install_tag: 'devel',
++  )
++endif
++if module == 'pam_limits'
++  install_data(
++    'limits.conf',
++    install_dir: vendor_sconfigdir,
++    install_tag: 'config',
++  )
++  install_emptydir(
++    limits_conf_dir,
++    install_tag: 'config',
++  )
++endif
++if module == 'pam_mkhomedir'
++  executable(
++    'mkhomedir_helper',
++    sources: ['mkhomedir_helper.c'],
++    link_args: exe_link_args,
++    dependencies: [libpam_internal_dep, libpam_dep],
++    install: true,
++    install_dir: sbindir,
++  )
++endif
++if module == 'pam_namespace'
++  pam_namespace_helper = configure_file(
++    input: 'pam_namespace_helper.in',
++    output: 'pam_namespace_helper',
++    configuration: cdata
++  )
++  install_data(
++    pam_namespace_helper,
++    install_mode: 'rwxr-xr-x',
++    install_dir: sbindir,
++    install_tag: 'bin',
++  )
++  pam_namespace_service = configure_file(
++    input: 'pam_namespace.service.in',
++    output: 'pam_namespace.service',
++    configuration: cdata
++  )
++  install_data(
++    pam_namespace_service,
++    install_dir: systemdunitdir,
++    install_tag: 'config',
++  )
++  install_data(
++    'namespace.conf',
++    install_dir: vendor_sconfigdir,
++    install_tag: 'config',
++  )
++  install_data(
++    'namespace.init',
++    install_mode: 'rwxr-xr-x',
++    install_dir: vendor_sconfigdir,
++    install_tag: 'config',
++  )
++  install_emptydir(
++    sconfigdir / 'namespace.d',
++    install_tag: 'config',
++  )
++endif
++if module == 'pam_pwhistory'
++  executable(
++    'pwhistory_helper',
++    sources: ['pwhistory_helper.c', 'opasswd.c'],
++    c_args: ['-DHELPER_COMPILE="pwhistory_helper"'],
++    link_args: exe_link_args,
++    dependencies: [libpam_internal_dep, libpam_dep, libcrypt],
++    install: true,
++    install_dir: sbindir,
++  )
++  install_data(
++    'pwhistory.conf',
++    install_dir: vendor_sconfigdir,
++    install_tag: 'config',
++  )
++endif
++if module == 'pam_selinux'
++  executable(
++    'pam_selinux_check',
++    sources: ['pam_selinux_check.c'],
++    include_directories: [libpamc_inc],
++    link_args: exe_link_args,
++    dependencies: [libpam_internal_dep, libpam_dep, libpam_misc_dep],
++  )
++endif
++if module == 'pam_sepermit'
++  install_data(
++    'sepermit.conf',
++    install_dir: vendor_sconfigdir,
++    install_tag: 'config',
++  )
++  install_emptydir(
++    sepermit_lockdir,
++    install_tag: 'config',
++  )
++endif
++if module == 'pam_time'
++  install_data(
++    'time.conf',
++    install_dir: vendor_sconfigdir,
++    install_tag: 'config',
++  )
++endif
++if module == 'pam_timestamp'
++  executable(
++    'pam_timestamp_check',
++    sources: ['pam_timestamp_check.c'],
++    link_args: exe_link_args,
++    dependencies: [libpam_internal_dep, libpam_dep, libsystemd],
++    install: true,
++    install_dir: sbindir,
++  )
++endif
++if module == 'pam_unix'
++  executable(
++    'unix_chkpwd',
++    sources: ['unix_chkpwd.c',
++              'audit.c',
++              'bigcrypt.c',
++              'md5_good.c',
++              'md5_broken.c',
++              'passverify.c',
++             ],
++    c_args: ['-DHELPER_COMPILE="unix_chkpwd"'],
++    link_args: exe_link_args,
++    dependencies: [libpam_internal_dep, libpam_dep, libcrypt, libselinux, libaudit],
++    install: true,
++    install_dir: sbindir,
++  )
++  if libselinux.found()
++    executable(
++      'unix_update',
++      sources: ['unix_update.c',
++                'audit.c',
++                'bigcrypt.c',
++                'md5_good.c',
++                'md5_broken.c',
++                'passverify.c',
++               ],
++      c_args: ['-DHELPER_COMPILE="unix_update"'],
++      link_args: exe_link_args,
++      dependencies: [libpam_internal_dep, libpam_dep, libcrypt, libselinux, libaudit],
++      install: true,
++      install_dir: sbindir,
++    )
++  endif
++  executable(
++    'bigcrypt',
++    sources: ['bigcrypt.c', 'bigcrypt_main.c'],
++    dependencies: [libpam_internal_dep, libpam_dep, libcrypt],
++  )
++endif
++
++
++# tests
++
++test(
++  'dlopen ' + module,
++  tst_dlopen,
++  args: [pam_module],
++)
++
++tst_module_retval_name = 'tst-' + module + '-retval'
++tst_module_retval_src = tst_module_retval_name + '.c'
++
++if fs.exists(tst_module_retval_src)
++  tst_module_retval_link_args = ''
++  if module == 'pam_canonicalize_user'
++    tst_module_retval_link_args = '-Wl,--export-dynamic'
++  endif
++
++  tst_module_retval_deps = [libpam_internal_dep, libpam_dep]
++  if module == 'pam_rootok'
++    tst_module_retval_deps += [libselinux, libaudit]
++  endif
++
++  tst_module_retval = executable(
++    tst_module_retval_name,
++    sources: tst_module_retval_src,
++    dependencies: tst_module_retval_deps,
++    link_args: tst_module_retval_link_args,
++  )
++
++  test(
++    tst_module_retval_name,
++    chdir_meson_build_subdir,
++    args: [tst_module_retval],
++    env: ['MESON_BUILD_SUBDIR=' + meson.current_build_dir()],
++  )
++endif
++
++
++if module == 'pam_timestamp' and cdata.get('WITH_OPENSSL', 0) != 1
++  hmacfile_exe = executable(
++    'hmacfile',
++    sources: ['hmacfile.c', 'hmacsha1.c', 'sha1.c'],
++    dependencies: [libpam_internal_dep, libpam_dep],
++  )
++  test(
++    'pam_timestamp hmacfile',
++    hmacfile_exe,
++  )
++endif
++
++
++if module == 'pam_filter'
++  subdir('upperLOWER')
++endif
+--- a/meson.build
++++ b/meson.build
+@@ -414,59 +414,57 @@
+ 
+ 
+ enable_pam_unix = not get_option('pam_unix').disabled()
+-if enable_pam_unix
+-  if get_option('lckpwdf')
+-    cdata.set('USE_LCKPWDF', 1)
+-    foreach f: ['lckpwdf']
+-      if cc.has_function(f, prefix: '#include <shadow.h>')
+-        cdata.set('HAVE_' + f.to_upper(), 1)
+-      endif
+-    endforeach
+-  endif
++if get_option('lckpwdf')
++  cdata.set('USE_LCKPWDF', 1)
++  foreach f: ['lckpwdf']
++    if cc.has_function(f, prefix: '#include <shadow.h>')
++      cdata.set('HAVE_' + f.to_upper(), 1)
++    endif
++  endforeach
++endif
++
++feature_nis = get_option('nis')
++if feature_nis.disabled()
++  enable_nis = false
++  libtirpc = null_dep
++  libnsl = null_dep
++else
++  # If libtirpc is available, prefer that over the system implementation.
++  libtirpc = dependency('libtirpc', required: false)
++  enable_nis = true
++  foreach f: ['getrpcport',
++              'rpcb_getaddr',
++             ]
++    if cc.has_function(f, prefix: '#include <rpc/rpc.h>',
++                       dependencies: libtirpc)
++      cdata.set('HAVE_' + f.to_upper(), 1)
++      cdata.set('HAVE_DECL_' + f.to_upper(), 1)
++    endif
++  endforeach
+ 
+-  feature_nis = get_option('nis')
+-  if feature_nis.disabled()
+-    enable_nis = false
+-    libtirpc = null_dep
+-    libnsl = null_dep
+-  else
+-    # If libtirpc is available, prefer that over the system implementation.
+-    libtirpc = dependency('libtirpc', required: false)
+-    enable_nis = true
+-    foreach f: ['getrpcport',
+-                'rpcb_getaddr',
++  libnsl = dependency('libnsl', required: feature_nis)
++  enable_nis = libnsl.found()
++
++  if enable_nis
++    foreach f: ['yp_bind',
++                'yp_get_default_domain',
++                'yp_match',
++                'yp_unbind',
+                ]
+-      if cc.has_function(f, prefix: '#include <rpc/rpc.h>',
+-                         dependencies: libtirpc)
+-        cdata.set('HAVE_' + f.to_upper(), 1)
+-        cdata.set('HAVE_DECL_' + f.to_upper(), 1)
++      if not cc.has_function(f, prefix: '''#include <rpcsvc/ypclnt.h>
++                                           #include <rpcsvc/yp_prot.h>''',
++                             dependencies: [libnsl, libtirpc])
++        enable_nis = false
++        libnsl = null_dep
++        break
+       endif
+     endforeach
++  endif
+ 
+-    libnsl = dependency('libnsl', required: feature_nis)
+-    enable_nis = libnsl.found()
+-
+-    if enable_nis
+-      foreach f: ['yp_bind',
+-                  'yp_get_default_domain',
+-                  'yp_match',
+-                  'yp_unbind',
+-                 ]
+-        if not cc.has_function(f, prefix: '''#include <rpcsvc/ypclnt.h>
+-                                             #include <rpcsvc/yp_prot.h>''',
+-                               dependencies: [libnsl, libtirpc])
+-          enable_nis = false
+-          libnsl = null_dep
+-          break
+-        endif
+-      endforeach
+-    endif
+-
+-    if enable_nis
+-      cdata.set('HAVE_NIS', 1)
+-    elif feature_nis.enabled()
+-      error('NIS is enabled but required interfaces are not available')
+-    endif
++  if enable_nis
++    cdata.set('HAVE_NIS', 1)
++  elif feature_nis.enabled()
++    error('NIS is enabled but required interfaces are not available')
+   endif
+ endif
+ 
diff -pruN 1.7.0-5/debian/patches/fix-pam_motd-ftbfs.patch 1.7.0-5ubuntu2/debian/patches/fix-pam_motd-ftbfs.patch
--- 1.7.0-5/debian/patches/fix-pam_motd-ftbfs.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/patches/fix-pam_motd-ftbfs.patch	2025-07-03 16:33:16.000000000 +0000
@@ -0,0 +1,20 @@
+Patch for Ubuntu to fix FTBFS on oracular
+
+Change in display_legal() of pam_motd.c as pam_get_item() expects third
+argument as 'const void **'.
+
+Authors: Nishit Majithia <nishit.majithia@canonical.com>
+
+Upstream status: Ubuntu-specific
+
+--- pam-1.5.3.orig/modules/pam_motd/pam_motd.c
++++ pam-1.5.3/modules/pam_motd/pam_motd.c
+@@ -389,7 +389,7 @@ int display_legal(pam_handle_t *pamh)
+     struct stat s;
+     int f;
+     /* Get the user name to determine if we need to print the disclaimer */
+-    rc = pam_get_item(pamh, PAM_USER, &user);
++    rc = pam_get_item(pamh, PAM_USER, (const void **)&user);
+     if (rc == PAM_SUCCESS && user != NULL && *(const char *)user != '\0')
+     {
+         PAM_MODUTIL_DEF_PRIVS(privs);
diff -pruN 1.7.0-5/debian/patches/pam_env-remove-deprecation-notice-for-user_readenv.patch 1.7.0-5ubuntu2/debian/patches/pam_env-remove-deprecation-notice-for-user_readenv.patch
--- 1.7.0-5/debian/patches/pam_env-remove-deprecation-notice-for-user_readenv.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/patches/pam_env-remove-deprecation-notice-for-user_readenv.patch	2025-07-03 16:33:16.000000000 +0000
@@ -0,0 +1,41 @@
+Description: drop deprecation warning in pam_env
+ In version 1.5.0[1], PAM upstream added a deprecation warning[2] keyed on the
+ user_readenv option, signaling that the feature of reading user environment
+ files will be removed in the future. This was brought to Ubuntu's attention
+ via bug LP: #2059859[3], but since we were inside Beta Freeze for Ubuntu Noble
+ 24.04 already, removing the user_readenv=1 option we add to sshd's PAM config
+ would introduce the kind of change in behavior that is not allowed during a
+ Beta Freeze.
+ .
+ Since such a change will also never be allowed in a Stable Release Update
+ (SRU), we decided to remove the deprecation warning for Ubuntu Noble 24.04 to
+ avoid the unecessary warning to our users.
+ .
+ This reverts commit[2], bar the NEWS and manpage changes.
+ .
+ After the 24.04 release, i.e., for 24.10 and later, this patch should be
+ removed and the openssh PAM configuration changed instead.
+ .
+ 1. https://github.com/linux-pam/linux-pam/releases/tag/v1.5.0
+ 2. https://github.com/linux-pam/linux-pam/commit/ecd526743a27157c5210b0ce9867c43a2fa27784
+ 3. https://bugs.launchpad.net/ubuntu/+source/openssh/+bug/2059859
+Author: Andreas Hasenack <andreas.hasenack@canonical.com>
+Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1018106
+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/openssh/+bug/2059859
+Forwarded: no
+Last-Update: 2024-04-10
+
+diff --git a/modules/pam_env/pam_env.c b/modules/pam_env/pam_env.c
+index d2b4cb10..033f0428 100644
+--- a/modules/pam_env/pam_env.c
++++ b/modules/pam_env/pam_env.c
+@@ -133,9 +133,6 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv,
+ 	  pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
+     }
+ 
+-    if (*user_readenv)
+-	pam_syslog(pamh, LOG_DEBUG, "deprecated reading of user environment enabled");
+-
+     return ctrl;
+ }
+ 
diff -pruN 1.7.0-5/debian/patches/pam_motd-legal-notice 1.7.0-5ubuntu2/debian/patches/pam_motd-legal-notice
--- 1.7.0-5/debian/patches/pam_motd-legal-notice	1970-01-01 00:00:00.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/patches/pam_motd-legal-notice	2025-07-03 16:33:16.000000000 +0000
@@ -0,0 +1,90 @@
+Patch for Ubuntu bug #399071
+
+Display the contents of /etc/legal as part of the MOTD, the first time the
+user logs in, and set a flag in the user's homedir if possible to prevent
+repeat displays.
+
+Authors: Dustin Kirkland <kirkland@canonical.com>
+
+Upstream status: Ubuntu-specific, maybe submit to Debian
+
+Index: pam/modules/pam_motd/pam_motd.c
+===================================================================
+--- pam.orig/modules/pam_motd/pam_motd.c
++++ pam/modules/pam_motd/pam_motd.c
+@@ -348,6 +348,65 @@
+     return PAM_SUCCESS;
+ }
+ 
++int display_legal(pam_handle_t *pamh)
++{
++    int retval = PAM_IGNORE, rc;
++    char *user = NULL;
++    char *dir = NULL;
++    char *flag = NULL;
++    struct passwd *pwd = NULL;
++    struct stat s;
++    int f;
++    /* Get the user name to determine if we need to print the disclaimer */
++    rc = pam_get_item(pamh, PAM_USER, &user);
++    if (rc == PAM_SUCCESS && user != NULL && *(const char *)user != '\0')
++    {
++        PAM_MODUTIL_DEF_PRIVS(privs);
++
++        /* Get the password entry */
++        pwd = pam_modutil_getpwnam (pamh, user);
++        if (pwd != NULL)
++        {
++            if (pam_modutil_drop_priv(pamh, &privs, pwd)) {
++                pam_syslog(pamh, LOG_ERR,
++                           "Unable to change UID to %d temporarily\n",
++                           pwd->pw_uid);
++                retval = PAM_SESSION_ERR;
++                goto finished;
++            }
++
++            if (asprintf(&dir, "%s/.cache", pwd->pw_dir) == -1 || !dir)
++                goto finished;
++            if (asprintf(&flag, "%s/motd.legal-displayed", dir) == -1 || !flag)
++                goto finished;
++
++            if (stat(flag, &s) != 0)
++            {
++                int fd = open("/etc/legal", O_RDONLY, 0);
++                if (fd >= 0) {
++                    try_to_display_fd(pamh, fd);
++                    close(fd);
++                }
++                mkdir(dir, 0700);
++                f = open(flag, O_WRONLY|O_CREAT|O_EXCL,
++                         S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
++                if (f>=0) close(f);
++            }
++
++finished:
++            if (pam_modutil_regain_priv(pamh, &privs)) {
++                pam_syslog(pamh, LOG_ERR,
++                           "Unable to change UID back to %d\n", privs.old_uid);
++                retval = PAM_SESSION_ERR;
++            }
++
++            _pam_drop(flag);
++            _pam_drop(dir);
++        }
++    }
++    return retval;
++}
++
+ int pam_sm_open_session(pam_handle_t *pamh, int flags,
+ 			int argc, const char **argv)
+ {
+@@ -446,6 +505,9 @@
+                             motd_dir_path_split, num_motd_dir_paths,
+                             report_missing);
+ 
++    /* Display the legal disclaimer only if necessary */
++    retval = display_legal(pamh);
++
+   out:
+     _pam_drop(motd_path_copy);
+     _pam_drop(motd_path_split);
diff -pruN 1.7.0-5/debian/patches/pam_umask_usergroups_from_login.defs.patch 1.7.0-5ubuntu2/debian/patches/pam_umask_usergroups_from_login.defs.patch
--- 1.7.0-5/debian/patches/pam_umask_usergroups_from_login.defs.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/patches/pam_umask_usergroups_from_login.defs.patch	2025-07-03 16:33:16.000000000 +0000
@@ -0,0 +1,66 @@
+Description: Deprecate pam_unix' explicit "usergroups" option and instead read it from /etc/login.def's "USERGROUP_ENAB" option if umask is only defined there. This restores compatibility with the pre-PAM behaviour of login. See https://blueprints.launchpad.net/ubuntu/+spec/umask-to-0002.
+Author: Martin Pitt <martin.pitt@ubuntu.com>
+Bug-Debian: http://bugs.debian.org/583958
+Last-Update: 2019-02-12
+
+=== modified file 'modules/pam_umask/pam_umask.c'
+Index: pam/modules/pam_umask/pam_umask.c
+===================================================================
+--- pam.orig/modules/pam_umask/pam_umask.c
++++ pam/modules/pam_umask/pam_umask.c
+@@ -95,6 +95,8 @@
+ get_options (pam_handle_t *pamh, options_t *options,
+ 	     int argc, const char **argv)
+ {
++  char *result;
++
+   memset (options, 0, sizeof (options_t));
+ 
+   options->usergroups = DEFAULT_USERGROUPS_SETTING;
+@@ -105,6 +107,20 @@
+ 
+   if (options->umask == NULL) {
+     options->login_umask = pam_modutil_search_key (pamh, LOGIN_DEFS, "UMASK");
++    /* login.defs' USERGROUPS_ENAB will modify the UMASK setting there by way
++     * of usergroups; but we don't want it to influence umask definitions
++     * from other places (like GECOS). This restores compatibility with
++     * shadow from the pre-PAM age.
++     */
++    if (options->login_umask != NULL)
++    {
++      result = pam_modutil_search_key (pamh, LOGIN_DEFS, "USERGROUPS_ENAB");
++      if (result != NULL)
++      {
++        options->usergroups = (strcasecmp (result, "yes") == 0);
++        free (result);
++      }
++    }
+     if (options->login_umask == NULL)
+       options->login_umask = pam_modutil_search_key (pamh, LOGIN_CONF, "UMASK");
+     options->umask = options->login_umask;
+Index: pam/modules/pam_umask/pam_umask.8.xml
+===================================================================
+--- pam.orig/modules/pam_umask/pam_umask.8.xml
++++ pam/modules/pam_umask/pam_umask.8.xml
+@@ -61,7 +61,8 @@
+         </listitem>
+         <listitem>
+           <para>
+-            UMASK entry from /etc/login.defs
++            UMASK entry from /etc/login.defs (influenced by USERGROUPS_ENAB in
++	    /etc/login.defs)
+           </para>
+         </listitem>
+         <listitem>
+@@ -118,6 +119,11 @@
+               If the user is not root and the username is the same as
+               primary group name, the umask group bits are set to be the
+               same as owner bits (examples: 022 -&gt; 002, 077 -&gt; 007).
++	      Note that using this option explicitly is discouraged. pam_umask
++	      enables this functionality by default if /etc/login.defs enables
++	      USERGROUPS_ENAB, and the umask is not set explicitly in other
++	      places than /etc/login.defs (this is compatible with login's
++	      behaviour without PAM).
+             </para>
+           </listitem>
+         </varlistentry>
diff -pruN 1.7.0-5/debian/patches/series 1.7.0-5ubuntu2/debian/patches/series
--- 1.7.0-5/debian/patches/series	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/patches/series	2025-07-03 16:33:16.000000000 +0000
@@ -5,13 +5,18 @@ make_documentation_reproducible.patch
 036_pam_wheel_getlogin_considered_harmful
 pam_limits_explicit_root
 pam_limits_fallback_defaults
-pam-limits-nofile-fd-setsize-cap
 032_pam_limits_EPERM_NOT_FATAL
 008_modules_pam_limits_chroot
 040_pam_limits_log_failure
 045_pam_dispatch_jump_is_ignore
 PAM-manpage-section
 update-motd
+pam_motd-legal-notice
+ubuntu-rlimit_nice_correction 
+update-motd-manpage-ref
+pam_umask_usergroups_from_login.defs.patch
+extrausers.patch
+pam-limits-nofile-fd-setsize-cap
 lib_security_multiarch_compat
 nullok_secure-compat.patch
 pam_mkhomedir_stat_before_opendir
@@ -21,3 +26,5 @@ upstream/0020-pam_namespace-from-v1.7.1.
 0001-pam_access-fix-group-name-match-regression.patch
 upstream/0022-pam_access-rework-resolving-of-tokens-as-hostname.patch
 0023-Reapply-man-page-section-changes-after-importing-1.7.patch
+pam_env-remove-deprecation-notice-for-user_readenv.patch
+fix-pam_motd-ftbfs.patch
diff -pruN 1.7.0-5/debian/patches/ubuntu-rlimit_nice_correction 1.7.0-5ubuntu2/debian/patches/ubuntu-rlimit_nice_correction
--- 1.7.0-5/debian/patches/ubuntu-rlimit_nice_correction	1970-01-01 00:00:00.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/patches/ubuntu-rlimit_nice_correction	2025-07-03 16:33:16.000000000 +0000
@@ -0,0 +1,17 @@
+Index: pam.ubuntu/modules/pam_limits/pam_limits.c
+===================================================================
+--- pam.ubuntu.orig/modules/pam_limits/pam_limits.c
++++ pam.ubuntu/modules/pam_limits/pam_limits.c
+@@ -362,6 +362,12 @@
+ 		    pl->limits[i].limit.rlim_cur = 8192*1024;
+ 		    pl->limits[i].limit.rlim_max = RLIM_INFINITY;
+ 		    break;
++#ifdef RLIMIT_NICE
++		case RLIMIT_NICE:
++		    pl->limits[i].limit.rlim_cur = 20;
++		    pl->limits[i].limit.rlim_max = 20;
++		    break;
++#endif
+ 		case RLIMIT_NOFILE:
+ 		    pl->limits[i].limit.rlim_cur = 1024;
+ 		    pl->limits[i].limit.rlim_max = 1024;
diff -pruN 1.7.0-5/debian/patches/update-motd-manpage-ref 1.7.0-5ubuntu2/debian/patches/update-motd-manpage-ref
--- 1.7.0-5/debian/patches/update-motd-manpage-ref	1970-01-01 00:00:00.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/patches/update-motd-manpage-ref	2025-07-03 16:33:16.000000000 +0000
@@ -0,0 +1,14 @@
+Index: pam.ubuntu/modules/pam_motd/pam_motd.8.xml
+===================================================================
+--- pam.ubuntu.orig/modules/pam_motd/pam_motd.8.xml
++++ pam.ubuntu/modules/pam_motd/pam_motd.8.xml
+@@ -100,6 +100,9 @@
+       </citerefentry>,
+       <citerefentry>
+ 	<refentrytitle>pam</refentrytitle><manvolnum>7</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++       <refentrytitle>update-motd</refentrytitle><manvolnum>5</manvolnum>
+       </citerefentry>
+     </para>
+   </refsect1>
diff -pruN 1.7.0-5/debian/po/eu.po 1.7.0-5ubuntu2/debian/po/eu.po
--- 1.7.0-5/debian/po/eu.po	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/po/eu.po	2025-07-03 16:33:16.000000000 +0000
@@ -56,11 +56,6 @@ msgstr "Pantaila kudeatzailea eskuz berr
 #. Description
 #: ../libpam0g.templates:2001
 #, fuzzy
-#| msgid ""
-#| "The kdm, wdm, and xdm display managers require a restart for the new "
-#| "version of libpam, but there are X login sessions active on your system "
-#| "that would be terminated by this restart.  You will therefore need to "
-#| "restart these services by hand before further X logins will be possible."
 msgid ""
 "The wdm and xdm display managers require a restart for the new version of "
 "libpam, but there are X login sessions active on your system that would be "
@@ -200,7 +195,6 @@ msgstr ""
 #. Description
 #: ../libpam-runtime.templates:5001
 #, fuzzy
-#| msgid "Incompatible PAM profiles selected."
 msgid "No PAM profiles have been selected."
 msgstr "PAM profil bateraezinak hautatuak."
 
diff -pruN 1.7.0-5/debian/po/fi.po 1.7.0-5ubuntu2/debian/po/fi.po
--- 1.7.0-5/debian/po/fi.po	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/po/fi.po	2025-07-03 16:33:16.000000000 +0000
@@ -51,11 +51,6 @@ msgstr "NÃ¤ytÃ¶nhallintaohjelma tulee kÃ
 #. Description
 #: ../libpam0g.templates:2001
 #, fuzzy
-#| msgid ""
-#| "The kdm, wdm, and xdm display managers require a restart for the new "
-#| "version of libpam, but there are X login sessions active on your system "
-#| "that would be terminated by this restart.  You will therefore need to "
-#| "restart these services by hand before further X logins will be possible."
 msgid ""
 "The wdm and xdm display managers require a restart for the new version of "
 "libpam, but there are X login sessions active on your system that would be "
diff -pruN 1.7.0-5/debian/po/vi.po 1.7.0-5ubuntu2/debian/po/vi.po
--- 1.7.0-5/debian/po/vi.po	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/po/vi.po	2025-07-03 16:33:16.000000000 +0000
@@ -53,11 +53,6 @@ msgstr "TrÃ¬nh quáº£n lÃ½ trÃ¬nh bÃ y ph
 #. Description
 #: ../libpam0g.templates:2001
 #, fuzzy
-#| msgid ""
-#| "The kdm, wdm, and xdm display managers require a restart for the new "
-#| "version of libpam, but there are X login sessions active on your system "
-#| "that would be terminated by this restart.  You will therefore need to "
-#| "restart these services by hand before further X logins will be possible."
 msgid ""
 "The wdm and xdm display managers require a restart for the new version of "
 "libpam, but there are X login sessions active on your system that would be "
diff -pruN 1.7.0-5/debian/rules 1.7.0-5ubuntu2/debian/rules
--- 1.7.0-5/debian/rules	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/rules	2025-07-03 16:33:16.000000000 +0000
@@ -43,6 +43,7 @@ override_dh_auto_configure:
 		-Dnis=disabled \
 		-Dusergroups=true \
 		$(meson_OPTS)
+	chmod 775 modules/pam_faillock/tst-pam_faillock
 
 # .install files don't have "except for" handling, so we need to exclude
 # our module that doesn't match right here
@@ -78,6 +79,8 @@ override_dh_fixperms:
 ifneq (,$(findstring libpam-modules, $(shell dh_listpackages)))
 	chgrp shadow $(d)/libpam-modules-bin/usr/sbin/unix_chkpwd
 	chmod 02755 $(d)/libpam-modules-bin/usr/sbin/unix_chkpwd
+	chgrp shadow $(d)/libpam-modules-bin/usr/sbin/pam_extrausers_chkpwd
+	chmod 02755 $(d)/libpam-modules-bin/usr/sbin/pam_extrausers_chkpwd
 endif
 
 override_dh_installchangelogs:
diff -pruN 1.7.0-5/debian/tests/control 1.7.0-5ubuntu2/debian/tests/control
--- 1.7.0-5/debian/tests/control	2025-06-29 17:40:46.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/tests/control	2025-07-03 16:33:16.000000000 +0000
@@ -5,3 +5,7 @@ Restrictions:  needs-root, allow-stderr
 Tests: pam-test
 Depends: libpam-modules, libpam-runtime, libpam0g, python3-pam
 Restrictions:  needs-root
+
+Tests: usr-lib-config
+Depends: libpam-modules, libpam-runtime, libpam0g, python3-pam
+Restrictions: needs-root, breaks-testbed
diff -pruN 1.7.0-5/debian/tests/usr-lib-config 1.7.0-5ubuntu2/debian/tests/usr-lib-config
--- 1.7.0-5/debian/tests/usr-lib-config	1970-01-01 00:00:00.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/tests/usr-lib-config	2025-07-03 16:33:16.000000000 +0000
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+set -e
+
+# Move everything but the toplevel passwd config
+mv /etc/pam.d/* /usr/lib/pam.d/
+mv /usr/lib/pam.d/passwd /etc/pam.d/
+
+useradd -s /bin/bash pam_test 2>&1 || true
+python3 debian/tests/pam-test.py
diff -pruN 1.7.0-5/debian/update-motd.5 1.7.0-5ubuntu2/debian/update-motd.5
--- 1.7.0-5/debian/update-motd.5	1970-01-01 00:00:00.000000000 +0000
+++ 1.7.0-5ubuntu2/debian/update-motd.5	2025-07-03 16:33:16.000000000 +0000
@@ -0,0 +1,67 @@
+.TH update-motd 5 "13 April 2010" "update-motd"
+
+.SH NAME
+update-motd \- dynamic MOTD generation
+
+.SH SYNOPSIS
+.B /etc/update-motd.d/*
+
+.SH DESCRIPTION
+UNIX/Linux system administrators often communicate important information to console and remote users by maintaining text in the file \fI/etc/motd\fP, which is displayed by the \fBpam_motd\fP(8) module on interactive shell logins.
+
+Traditionally, this file is static text, typically installed by the distribution and only updated on release upgrades, or overwritten by the local administrator with pertinent information.
+
+Ubuntu introduced the \fBupdate-motd\fP framework, by which the \fBmotd\fP(5) is dynamically assembled from a collection of scripts at login.
+
+Executable scripts in \fI/etc/update-motd.d/*\fP are executed by \fBpam_motd\fP(8) as the root user at each login, and this information is concatenated in \fI/run/motd.dynamic\fP.  The order of script execution is determined by the \fBrun-parts\fP(8) --lsbsysinit option (basically alphabetical order, with a few caveats).
+
+On Ubuntu systems, \fI/etc/motd\fP is typically a symbolic link to \fI/run/motd.dynamic\fP.
+
+.SH BEST PRACTICES
+MOTD fragments must be scripts in \fI/etc/update-motd.d\fP, must be executable, and must emit information on standard out.
+
+Scripts should be named named NN-xxxxxx where NN is a two digit number indicating their position in the MOTD, and xxxxxx is an appropriate name for the script.
+
+Scripts must not have filename extensions, per \fBrun-parts\fP(8) --lsbsysinit instructions.
+
+Packages should add scripts directly into \fI/etc/update-motd.d\fP, rather than symlinks to other scripts, such that administrators can modify or remove these scripts and upgrades will not wipe the local changes.  Consider using a simple shell script that simply calls \fBexec\fP on the external utility.
+
+Long running operations (such as network calls) or resource intensive scripts should cache output, and only update that output if it is deemed expired.  For instance:
+
+  /etc/update-motd.d/50-news
+  #!/bin/sh
+  out=/run/foo
+  script="w3m -dump http://news.google.com/"
+  if [ -f "$out" ]; then
+    # Output exists, print it
+    echo
+    cat "$out"
+    # See if it's expired, and background update
+    lastrun=$(stat -c %Y "$out") || lastrun=0
+    expiration=$(expr $lastrun + 86400)
+    if [ $(date +%s) -ge $expiration ]; then
+      $script > "$out" &
+    fi
+  else
+    # No cache at all, so update in the background
+    $script > "$out" &
+  fi
+
+Scripts should emit a blank line before output, and end with a newline character.  For instance:
+
+  /etc/update-motd/05-lsb-release
+  #!/bin/sh
+  echo
+  lsb-release -a
+
+.SH FILES
+\fI/etc/motd\fP, \fI/run/motd.dynamic\fP, \fI/etc/update-motd.d\fP
+
+
+.SH SEE ALSO
+\fBmotd\fP(5), \fBpam_motd\fP(8), \fBrun-parts\fP(8)
+
+.SH AUTHOR
+This manpage and the update-motd framework was written by Dustin Kirkland <kirkland@canonical.com> for Ubuntu systems (but may be used by others).  Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
