diff -pruN 1.3.1-5/debian/changelog 1.3.1-5ubuntu6/debian/changelog
--- 1.3.1-5/debian/changelog	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/changelog	2020-08-06 01:10:51.000000000 +0000
@@ -1,3 +1,76 @@
+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
@@ -6,6 +79,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.
@@ -28,6 +145,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.
@@ -119,6 +290,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.
@@ -186,6 +419,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.
@@ -194,6 +495,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.
@@ -204,6 +575,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
@@ -220,6 +663,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.
@@ -253,6 +744,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 ]
@@ -266,6 +798,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
@@ -287,6 +859,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.
@@ -323,6 +945,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:
@@ -350,6 +1021,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
@@ -377,6 +1091,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 ]
@@ -431,6 +1198,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 ]
@@ -447,6 +1272,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.
@@ -464,6 +1356,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 ]
@@ -482,6 +1414,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
@@ -540,6 +1558,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.
@@ -577,6 +1621,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
@@ -595,6 +1671,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
@@ -605,6 +1715,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
@@ -613,6 +1758,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.
@@ -640,6 +1810,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,
@@ -689,6 +1900,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 ]
@@ -717,6 +1958,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.
@@ -760,6 +2036,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
@@ -787,6 +2099,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 ]
@@ -823,6 +2166,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'.
@@ -856,6 +2244,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:
@@ -890,6 +2328,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
@@ -925,6 +2424,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.
@@ -947,6 +2551,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
@@ -956,6 +2642,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
@@ -980,6 +2700,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.
@@ -1095,6 +2858,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:
@@ -1121,6 +2947,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
@@ -1165,6 +3083,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
@@ -1411,6 +3378,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
@@ -1463,6 +3456,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.
@@ -1473,6 +3472,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
@@ -1553,6 +3660,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
@@ -1972,8 +4107,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
@@ -2779,3 +4912,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.3.1-5/debian/control 1.3.1-5ubuntu6/debian/control
--- 1.3.1-5/debian/control	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/control	2020-07-03 01:59:30.000000000 +0000
@@ -2,13 +2,15 @@ Source: pam
 Section: libs
 Priority: optional
 Uploaders: Sam Hartman <hartmans@debian.org>
-Maintainer: Steve Langasek <vorlon@debian.org>
+XSBC-Original-Maintainer: Steve Langasek <vorlon@debian.org>
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
 Standards-Version: 4.3.0
 Build-Depends: libcrack2-dev (>= 2.8), bzip2, debhelper (>= 9), quilt (>= 0.48-1), flex, libdb-dev, libselinux1-dev [linux-any], po-debconf, dh-autoreconf, autopoint, libaudit-dev [linux-any] <!stage1>, pkg-config, libfl-dev, libfl-dev:native, docbook-xsl, docbook-xml, xsltproc, libxml2-utils, w3m
 Build-Conflicts-Indep: 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-Bzr: https://code.launchpad.net/~ubuntu-core-dev/pam/ubuntu
+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
 
@@ -36,6 +38,7 @@ Pre-Depends: ${shlibs:Depends}, ${misc:D
 	libpam-modules-bin (= ${binary:Version})
 Conflicts: libpam-motd, libpam-mkhomedir, libpam-umask
 Replaces: libpam0g-util, libpam-umask
+Recommends: update-motd
 Provides: libpam-motd, libpam-mkhomedir, libpam-umask
 Description: Pluggable Authentication Modules for PAM
  This package completes the set of modules for PAM. It includes the
diff -pruN 1.3.1-5/debian/libpam0g.postinst 1.3.1-5ubuntu6/debian/libpam0g.postinst
--- 1.3.1-5/debian/libpam0g.postinst	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/libpam0g.postinst	2020-07-03 01:59:30.000000000 +0000
@@ -115,13 +115,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
 
@@ -142,6 +157,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."
@@ -189,8 +211,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.3.1-5/debian/libpam-modules-bin.install 1.3.1-5ubuntu6/debian/libpam-modules-bin.install
--- 1.3.1-5/debian/libpam-modules-bin.install	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/libpam-modules-bin.install	2018-08-23 23:37:53.000000000 +0000
@@ -4,3 +4,5 @@ sbin/pam_tally		sbin
 sbin/pam_tally2         sbin
 sbin/mkhomedir_helper	sbin
 sbin/pam_timestamp_check	usr/sbin
+sbin/pam_extrausers_chkpwd	sbin
+sbin/pam_extrausers_update	sbin
diff -pruN 1.3.1-5/debian/libpam-modules-bin.lintian-overrides 1.3.1-5ubuntu6/debian/libpam-modules-bin.lintian-overrides
--- 1.3.1-5/debian/libpam-modules-bin.lintian-overrides	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/libpam-modules-bin.lintian-overrides	2020-07-03 01:59:30.000000000 +0000
@@ -1,5 +1,6 @@
 # yes, we know it's sgid, that's the whole point...
 libpam-modules-bin: setgid-binary sbin/unix_chkpwd 2755 root/shadow
+libpam-modules-bin: setgid-binary sbin/pam_extrausers_chkpwd 2755 root/shadow
 # these manpages are in libpam-modules as they document both the module and
 # the helper binary
 libpam-modules-bin: binary-without-manpage sbin/pam_tally
diff -pruN 1.3.1-5/debian/libpam-modules.manpages 1.3.1-5ubuntu6/debian/libpam-modules.manpages
--- 1.3.1-5/debian/libpam-modules.manpages	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/libpam-modules.manpages	2018-08-23 23:37:53.000000000 +0000
@@ -1,2 +1,3 @@
 debian/tmp/usr/share/man/man8/pam_*.8
 debian/tmp/usr/share/man/man5/*conf.5
+debian/update-motd.5
diff -pruN 1.3.1-5/debian/libpam-modules.postinst 1.3.1-5ubuntu6/debian/libpam-modules.postinst
--- 1.3.1-5/debian/libpam-modules.postinst	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/libpam-modules.postinst	2020-07-09 00:02:00.000000000 +0000
@@ -17,6 +17,18 @@ then
 	touch /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 /etc/security/pam_env.conf; then
+		if ! grep -qs ^PATH= /etc/environment; then
+			echo 'PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"' >> /etc/environment
+		elif ! grep -qs "^PATH=.*/snap/bin" /etc/environment; then
+			sed -i '/^PATH="/ s,"$,:/snap/bin",g' /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
diff -pruN 1.3.1-5/debian/local/common-session 1.3.1-5ubuntu6/debian/local/common-session
--- 1.3.1-5/debian/local/common-session	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/local/common-session	2018-08-23 23:37:53.000000000 +0000
@@ -20,6 +20,11 @@ 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
+# 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
 # end of pam-auth-update config
diff -pruN 1.3.1-5/debian/local/common-session-noninteractive 1.3.1-5ubuntu6/debian/local/common-session-noninteractive
--- 1.3.1-5/debian/local/common-session-noninteractive	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/local/common-session-noninteractive	2018-08-23 23:37:53.000000000 +0000
@@ -20,6 +20,11 @@ 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
+# 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
 # end of pam-auth-update config
diff -pruN 1.3.1-5/debian/local/pam-auth-update 1.3.1-5ubuntu6/debian/local/pam-auth-update
--- 1.3.1-5/debian/local/pam-auth-update	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/local/pam-auth-update	2020-07-03 01:59:30.000000000 +0000
@@ -54,9 +54,11 @@ my %md5sums = (
 	'session' => [
 		'240fb92986c885b327cdb21dd641da8c',
 		'4a25673e8b36f1805219027d3be02cd2',
+		'73144a2f4e609a922a51e301cd66a57e',
 	],
 	'session-noninteractive' => [
 		'ad2b78ce1498dd637ef36469430b6ac6',
+		'a20e8df3469bfe25c13a3b39161b30f0',
 	],
 );
 
diff -pruN 1.3.1-5/debian/patches-applied/0001-pam_motd-Export-MOTD_SHOWN-pam-after-showing-MOTD.patch 1.3.1-5ubuntu6/debian/patches-applied/0001-pam_motd-Export-MOTD_SHOWN-pam-after-showing-MOTD.patch
--- 1.3.1-5/debian/patches-applied/0001-pam_motd-Export-MOTD_SHOWN-pam-after-showing-MOTD.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/patches-applied/0001-pam_motd-Export-MOTD_SHOWN-pam-after-showing-MOTD.patch	2020-07-03 01:59:30.000000000 +0000
@@ -0,0 +1,24 @@
+From: Balint Reczey <balint.reczey@canonical.com>
+Date: Wed, 4 Dec 2019 11:48:45 +0100
+Subject: pam_motd: Export MOTD_SHOWN=pam after showing MOTD
+
+This is a useful indication for update-motd profile.d snippet which can
+also try to show MOTD when it is not already shown.
+
+The use-case for that is showing MOTD in shells in containers without
+PAM being involved.
+---
+ modules/pam_motd/pam_motd.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/modules/pam_motd/pam_motd.c
++++ b/modules/pam_motd/pam_motd.c
+@@ -232,6 +232,8 @@
+     /* Display the legal disclaimer only if necessary */
+     retval = display_legal(pamh);
+ 
++    retval = pam_putenv(pamh, "MOTD_SHOWN=pam");
++
+     return retval;
+ }
+ 
diff -pruN 1.3.1-5/debian/patches-applied/0002-pam_motd-Mention-setting-MOTD_SHOWN-pam-in-the-man-p.patch 1.3.1-5ubuntu6/debian/patches-applied/0002-pam_motd-Mention-setting-MOTD_SHOWN-pam-in-the-man-p.patch
--- 1.3.1-5/debian/patches-applied/0002-pam_motd-Mention-setting-MOTD_SHOWN-pam-in-the-man-p.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/patches-applied/0002-pam_motd-Mention-setting-MOTD_SHOWN-pam-in-the-man-p.patch	2020-07-03 01:59:30.000000000 +0000
@@ -0,0 +1,23 @@
+From d35ccc51675d98361c847fc630c60ce74e8d207a Mon Sep 17 00:00:00 2001
+From: Balint Reczey <balint.reczey@canonical.com>
+Date: Wed, 4 Dec 2019 17:54:09 +0100
+Subject: [PATCH] pam_motd: Mention setting MOTD_SHOWN=pam in the man page
+
+---
+ modules/pam_motd/pam_motd.8.xml | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/modules/pam_motd/pam_motd.8.xml
++++ b/modules/pam_motd/pam_motd.8.xml
+@@ -81,6 +81,11 @@
+       <filename>/etc/motd.d</filename>.  Specifying either option (or both)
+       will disable this default behavior.
+     </para>
++    <para>
++      The <emphasis remap='B'>MOTD_SHOWN=pam</emphasis> environment variable
++      is set after showing the motd files, even when all of them were silenced
++      using symbolic links.
++    </para>
+   </refsect1>
+ 
+   <refsect1 id="pam_motd-types">
diff -pruN 1.3.1-5/debian/patches-applied/0003-Return-only-PAM_IGNORE-or-error-from-pam_motd.patch 1.3.1-5ubuntu6/debian/patches-applied/0003-Return-only-PAM_IGNORE-or-error-from-pam_motd.patch
--- 1.3.1-5/debian/patches-applied/0003-Return-only-PAM_IGNORE-or-error-from-pam_motd.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/patches-applied/0003-Return-only-PAM_IGNORE-or-error-from-pam_motd.patch	2020-07-03 01:59:30.000000000 +0000
@@ -0,0 +1,54 @@
+From 73118592885eb3554eddb360d5f6ab65ee6e1c03 Mon Sep 17 00:00:00 2001
+From: Balint Reczey <balint.reczey@canonical.com>
+Date: Tue, 17 Dec 2019 16:48:13 +0100
+Subject: [PATCH 3/3] Return only PAM_IGNORE or error from pam_motd
+
+Follow-up for c81280b16e1831ab0bdd0383486c7e2d1eaf1b5e.
+* modules/pam_motd/pam_motd.c: Return PAM_IGNORE if pam_putenv succeeds.
+* modules/pam_motd/pam_motd.8.xml: Document additional possible return values of the module.
+---
+ modules/pam_motd/pam_motd.8.xml | 18 +++++++++++++++++-
+ modules/pam_motd/pam_motd.c     |  2 +-
+ 2 files changed, 18 insertions(+), 2 deletions(-)
+
+--- a/modules/pam_motd/pam_motd.8.xml
++++ b/modules/pam_motd/pam_motd.8.xml
+@@ -99,10 +99,26 @@
+     <title>RETURN VALUES</title>
+     <variablelist>
+       <varlistentry>
++        <term>PAM_ABORT</term>
++        <listitem>
++           <para>
++             Not all relevant data or options could be obtained.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
++        <term>PAM_BUF_ERR</term>
++        <listitem>
++           <para>
++              Memory buffer error.
++          </para>
++        </listitem>
++      </varlistentry>
++      <varlistentry>
+         <term>PAM_IGNORE</term>
+         <listitem>
+           <para>
+-            This is the only return value of this module.
++            This is the default return value of this module.
+           </para>
+         </listitem>
+       </varlistentry>
+--- a/modules/pam_motd/pam_motd.c
++++ b/modules/pam_motd/pam_motd.c
+@@ -234,7 +234,7 @@
+ 
+     retval = pam_putenv(pamh, "MOTD_SHOWN=pam");
+ 
+-    return retval;
++    return retval == PAM_SUCCESS ? PAM_IGNORE : retval;
+ }
+ 
+ /* end of module definition */
diff -pruN 1.3.1-5/debian/patches-applied/extrausers.patch 1.3.1-5ubuntu6/debian/patches-applied/extrausers.patch
--- 1.3.1-5/debian/patches-applied/extrausers.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/patches-applied/extrausers.patch	2020-07-03 01:59:30.000000000 +0000
@@ -0,0 +1,6570 @@
+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
+Author: Michael Terry <mterry@ubuntu.com>
+Last-Updated: 2019-02-12
+Forwarded: no
+
+Index: pam/modules/pam_extrausers/Makefile.am
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/Makefile.am
+@@ -0,0 +1,66 @@
++#
++# Copyright (c) 2005, 2006, 2009, 2011 Thorsten Kukuk <kukuk@suse.de>
++#
++
++CLEANFILES = *~
++MAINTAINERCLEANFILES = $(MANS)
++
++EXTRA_DIST = md5.c md5_crypt.c lckpwdf.-c $(MANS) \
++		tst-pam_extrausers $(XMLS)
++
++man_MANS = pam_extrausers.8
++XMLS = pam_extrausers.8.xml
++
++#TESTS = tst-pam_extrausers
++
++securelibdir = $(SECUREDIR)
++secureconfdir = $(SCONFIGDIR)
++
++AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \
++	-DCHKPWD_HELPER=\"$(sbindir)/pam_extrausers_chkpwd\" \
++	-DUPDATE_HELPER=\"$(sbindir)/pam_extrausers_update\" \
++	@TIRPC_CFLAGS@ @NSL_CFLAGS@
++
++if HAVE_LIBSELINUX
++  AM_CFLAGS += -D"WITH_SELINUX"
++endif
++
++pam_extrausers_la_LDFLAGS = -no-undefined -avoid-version -module
++if HAVE_VERSIONING
++  pam_extrausers_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map
++endif
++pam_extrausers_la_LIBADD = $(top_builddir)/libpam/libpam.la \
++	@LIBCRYPT@ @LIBSELINUX@ @TIRPC_LIBS@ @NSL_LIBS@ \
++	../pam_securetty/tty_secure.lo
++
++securelib_LTLIBRARIES = pam_extrausers.la
++
++noinst_HEADERS = md5.h support.h yppasswd.h bigcrypt.h passverify.h
++
++sbin_PROGRAMS = pam_extrausers_chkpwd pam_extrausers_update
++
++noinst_PROGRAMS = bigcrypt
++
++pam_extrausers_la_SOURCES = bigcrypt.c pam_unix_acct.c \
++	pam_unix_auth.c pam_unix_passwd.c pam_unix_sess.c support.c \
++	passverify.c yppasswd_xdr.c md5_good.c md5_broken.c obscure.c
++
++bigcrypt_SOURCES = bigcrypt.c bigcrypt_main.c
++bigcrypt_CFLAGS = $(AM_CFLAGS)
++bigcrypt_LDADD = @LIBCRYPT@
++
++pam_extrausers_chkpwd_SOURCES = unix_chkpwd.c md5_good.c md5_broken.c bigcrypt.c \
++	passverify.c
++pam_extrausers_chkpwd_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ -DHELPER_COMPILE=\"pam_extrausers_chkpwd\"
++pam_extrausers_chkpwd_LDFLAGS = @PIE_LDFLAGS@
++pam_extrausers_chkpwd_LDADD = @LIBCRYPT@ @LIBSELINUX@ @LIBAUDIT@
++
++pam_extrausers_update_SOURCES = unix_update.c md5_good.c md5_broken.c bigcrypt.c \
++	passverify.c
++pam_extrausers_update_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ -DHELPER_COMPILE=\"pam_extrausers_update\"
++pam_extrausers_update_LDFLAGS = @PIE_LDFLAGS@
++pam_extrausers_update_LDADD = @LIBCRYPT@ @LIBSELINUX@
++
++if ENABLE_REGENERATE_MAN
++-include $(top_srcdir)/Make.xml.rules
++endif
+Index: pam/modules/pam_extrausers/README
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/README
+@@ -0,0 +1,5 @@
++This is a simple fork of pam_unix, but with the following changes:
++
++ - The expected namespace changes
++ - References to /etc or /etc/secure are replaced with /var/lib/extrausers
++ - Unconditionally use our custom lckpwdf methods and namespace them
+Index: pam/modules/pam_extrausers/bigcrypt.c
+===================================================================
+--- /dev/null
++++ pam/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;
++}
+Index: pam/modules/pam_extrausers/bigcrypt.h
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/bigcrypt.h
+@@ -0,0 +1 @@
++extern char *bigcrypt(const char *key, const char *salt);
+Index: pam/modules/pam_extrausers/bigcrypt_main.c
+===================================================================
+--- /dev/null
++++ pam/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;
++}
+Index: pam/modules/pam_extrausers/lckpwdf.-c
+===================================================================
+--- /dev/null
++++ pam/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 */
+Index: pam/modules/pam_extrausers/md5.c
+===================================================================
+--- /dev/null
++++ pam/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
+Index: pam/modules/pam_extrausers/md5.h
+===================================================================
+--- /dev/null
++++ pam/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 */
+Index: pam/modules/pam_extrausers/md5_broken.c
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/md5_broken.c
+@@ -0,0 +1,4 @@
++#define MD5Name(x) Broken##x
++
++#include "md5.c"
++#include "md5_crypt.c"
+Index: pam/modules/pam_extrausers/md5_crypt.c
+===================================================================
+--- /dev/null
++++ pam/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;
++}
+Index: pam/modules/pam_extrausers/md5_good.c
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/md5_good.c
+@@ -0,0 +1,5 @@
++#define HIGHFIRST
++#define MD5Name(x) Good##x
++
++#include "md5.c"
++#include "md5_crypt.c"
+Index: pam/modules/pam_extrausers/obscure.c
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/obscure.c
+@@ -0,0 +1,198 @@
++/*
++ * 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 "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;
++}
+Index: pam/modules/pam_extrausers/pam_unix_acct.c
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/pam_unix_acct.c
+@@ -0,0 +1,304 @@
++/*
++ * 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 "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;
++}
+Index: pam/modules/pam_extrausers/pam_unix_auth.c
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/pam_unix_auth.c
+@@ -0,0 +1,218 @@
++/*
++ * 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 "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;
++}
+Index: pam/modules/pam_extrausers/pam_unix_passwd.c
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/pam_unix_passwd.c
+@@ -0,0 +1,843 @@
++/*
++ * 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 "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;
++}
+Index: pam/modules/pam_extrausers/pam_unix_sess.c
+===================================================================
+--- /dev/null
++++ pam/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;
++}
+Index: pam/modules/pam_extrausers/pam_unix_static.c
+===================================================================
+--- /dev/null
++++ pam/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
+Index: pam/modules/pam_extrausers/pam_unix_static.h
+===================================================================
+--- /dev/null
++++ pam/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
+Index: pam/modules/pam_extrausers/passverify.c
+===================================================================
+--- /dev/null
++++ pam/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.
++ */
+Index: pam/modules/pam_extrausers/passverify.h
+===================================================================
+--- /dev/null
++++ pam/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.
++ */
+Index: pam/modules/pam_extrausers/support.c
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/support.c
+@@ -0,0 +1,1083 @@
++/*
++ * 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
++
++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
++	        || _pammodutil_tty_secure(pamh, (const char *)uttyname) != PAM_SUCCESS)
++	    {
++	        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;
++
++		if (_pammodutil_tty_secure(pamh, (const char *)uttyname) != PAM_SUCCESS)
++			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.
++ */
+Index: pam/modules/pam_extrausers/support.h
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/support.h
+@@ -0,0 +1,182 @@
++/*
++ * $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 _pammodutil_tty_secure(const pam_handle_t *pamh,
++                                  const char *uttyname);
++
++extern int _unix_run_verify_binary(pam_handle_t *pamh,
++			unsigned int ctrl, const char *user, int *daysleft);
++#endif /* _PAM_UNIX_SUPPORT_H */
+Index: pam/modules/pam_extrausers/unix_chkpwd.c
+===================================================================
+--- /dev/null
++++ pam/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.
++ */
+Index: pam/modules/pam_extrausers/unix_update.c
+===================================================================
+--- /dev/null
++++ pam/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.
++ */
+Index: pam/modules/pam_extrausers/yppasswd.h
+===================================================================
+--- /dev/null
++++ pam/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_ */
+Index: pam/modules/pam_extrausers/yppasswd_xdr.c
+===================================================================
+--- /dev/null
++++ pam/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
+Index: pam/modules/Makefile.am
+===================================================================
+--- pam.orig/modules/Makefile.am
++++ pam/modules/Makefile.am
+@@ -3,7 +3,7 @@
+ #
+ 
+ SUBDIRS = pam_access pam_cracklib pam_debug pam_deny pam_echo \
+-	pam_env pam_exec pam_faildelay pam_filter pam_ftp \
++	pam_env pam_exec pam_extrausers pam_faildelay pam_filter pam_ftp \
+ 	pam_group pam_issue pam_keyinit pam_lastlog pam_limits \
+ 	pam_listfile pam_localuser pam_loginuid pam_mail \
+ 	pam_mkhomedir pam_motd pam_namespace pam_nologin \
+Index: pam/configure.ac
+===================================================================
+--- pam.orig/configure.ac
++++ pam/configure.ac
+@@ -614,6 +614,7 @@
+ 	modules/pam_access/Makefile modules/pam_cracklib/Makefile \
+         modules/pam_debug/Makefile modules/pam_deny/Makefile \
+ 	modules/pam_echo/Makefile modules/pam_env/Makefile \
++	modules/pam_extrausers/Makefile \
+ 	modules/pam_faildelay/Makefile \
+ 	modules/pam_filter/Makefile modules/pam_filter/upperLOWER/Makefile \
+ 	modules/pam_ftp/Makefile modules/pam_group/Makefile \
+Index: pam/modules/pam_extrausers/tst-pam_extrausers
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/tst-pam_extrausers
+@@ -0,0 +1,2 @@
++#!/bin/sh
++../../tests/tst-dlopen .libs/pam_extrausers.so
+Index: pam/modules/pam_extrausers/pam_extrausers.8.xml
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/pam_extrausers.8.xml
+@@ -0,0 +1,488 @@
++<?xml version="1.0" encoding='UTF-8'?>
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
++	"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
++
++<refentry id="pam_extrausers">
++
++  <refmeta>
++    <refentrytitle>pam_extrausers</refentrytitle>
++    <manvolnum>8</manvolnum>
++    <refmiscinfo class="sectdesc">Linux-PAM Manual</refmiscinfo>
++  </refmeta>
++
++  <refnamediv id="pam_extrausers-name">
++    <refname>pam_extrausers</refname>
++    <refpurpose>Module for libnss-extrausers authentication</refpurpose>
++  </refnamediv>
++
++  <refsynopsisdiv>
++    <cmdsynopsis id="pam_extrausers-cmdsynopsis">
++      <command>pam_extrausers.so</command>
++      <arg choice="opt">
++        ...
++      </arg>
++    </cmdsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1 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 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 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 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 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 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 id='pam_extrausers-author'>
++    <title>AUTHOR</title>
++      <para>
++        pam_extrausers was written by various people.
++      </para>
++  </refsect1>
++
++</refentry>
+Index: pam/modules/pam_extrausers/pam_extrausers.8
+===================================================================
+--- /dev/null
++++ pam/modules/pam_extrausers/pam_extrausers.8
+@@ -0,0 +1,269 @@
++'\" t
++.\"     Title: pam_extrausers
++.\"    Author: [see the "AUTHOR" section]
++.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
++.\"      Date: 07/22/2014
++.\"    Manual: Linux-PAM Manual
++.\"    Source: Linux-PAM Manual
++.\"  Language: English
++.\"
++.TH "PAM_EXTRAUSERS" "8" "07/22/2014" "Linux-PAM Manual" "Linux\-PAM Manual"
++.\" -----------------------------------------------------------------
++.\" * Define some portability stuff
++.\" -----------------------------------------------------------------
++.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++.\" http://bugs.debian.org/507673
++.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
++.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++.ie \n(.g .ds Aq \(aq
++.el       .ds Aq '
++.\" -----------------------------------------------------------------
++.\" * set default formatting
++.\" -----------------------------------------------------------------
++.\" disable hyphenation
++.nh
++.\" disable justification (adjust text to left margin only)
++.ad l
++.\" -----------------------------------------------------------------
++.\" * MAIN CONTENT STARTS HERE *
++.\" -----------------------------------------------------------------
++.SH "NAME"
++pam_extrausers \- Module for libnss\-extrausers authentication
++.SH "SYNOPSIS"
++.HP \w'\fBpam_extrausers\&.so\fR\ 'u
++\fBpam_extrausers\&.so\fR [\&.\&.\&.]
++.SH "DESCRIPTION"
++.PP
++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\&.
++.PP
++The account component performs the task of establishing the status of the user\*(Aqs account and password based on the following
++\fIshadow\fR
++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
++\fBPAM_AUTHTOKEN_REQD\fR
++return, delay giving service to the user until they have established a new password\&. The entries listed above are documented in the
++\fBshadow\fR(5)
++manual page\&. Should the user\*(Aqs record not contain one or more of these entries, the corresponding
++\fIshadow\fR
++check is not performed\&.
++.PP
++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\&.
++.PP
++The password component of this module performs the task of updating the user\*(Aqs password\&. The default encryption hash is taken from the
++\fBENCRYPT_METHOD\fR
++variable from
++\fI/etc/login\&.defs\fR
++.PP
++The session component of this module logs when a user logins or leave the system\&.
++.PP
++Remaining arguments, supported by others functions of this module, are silently ignored\&. Other arguments are logged as errors through
++\fBsyslog\fR(3)\&.
++.SH "OPTIONS"
++.PP
++\fBdebug\fR
++.RS 4
++Turns on debugging via
++\fBsyslog\fR(3)\&.
++.RE
++.PP
++\fBaudit\fR
++.RS 4
++A little more extreme than debug\&.
++.RE
++.PP
++\fBnullok\fR
++.RS 4
++The default action of this module is to not permit the user access to a service if their official password is blank\&. The
++\fBnullok\fR
++argument overrides this default and allows any user with a blank password to access the service\&.
++.RE
++.PP
++\fBnullok_secure\fR
++.RS 4
++The default action of this module is to not permit the user access to a service if their official password is blank\&. The
++\fBnullok_secure\fR
++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\&.
++.RE
++.PP
++\fBtry_first_pass\fR
++.RS 4
++Before prompting the user for their password, the module first tries the previous stacked module\*(Aqs password in case that satisfies this module as well\&.
++.RE
++.PP
++\fBuse_first_pass\fR
++.RS 4
++The argument
++\fBuse_first_pass\fR
++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\&.
++.RE
++.PP
++\fBnodelay\fR
++.RS 4
++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\&.
++.RE
++.PP
++\fBuse_authtok\fR
++.RS 4
++When password changing enforce the module to set the new password to the one provided by a previously stacked
++\fBpassword\fR
++module (this is used in the example of the stacking of the
++\fBpam_cracklib\fR
++module documented below)\&.
++.RE
++.PP
++\fBnot_set_pass\fR
++.RS 4
++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\&.
++.RE
++.PP
++\fBnis\fR
++.RS 4
++NIS RPC is used for setting new passwords\&.
++.RE
++.PP
++\fBremember=\fR\fB\fIn\fR\fR
++.RS 4
++The last
++\fIn\fR
++passwords for each user are saved in
++/etc/security/opasswd
++in order to force password change history and keep the user from alternating between the same password too frequently\&. Instead of this option the
++\fBpam_pwhistory\fR
++module should be used\&.
++.RE
++.PP
++\fBshadow\fR
++.RS 4
++Try to maintain a shadow based system\&.
++.RE
++.PP
++\fBmd5\fR
++.RS 4
++When a user changes their password next, encrypt it with the MD5 algorithm\&.
++.RE
++.PP
++\fBbigcrypt\fR
++.RS 4
++When a user changes their password next, encrypt it with the DEC C2 algorithm\&.
++.RE
++.PP
++\fBsha256\fR
++.RS 4
++When a user changes their password next, encrypt it with the SHA256 algorithm\&. If the SHA256 algorithm is not known to the
++\fBcrypt\fR(3)
++function, fall back to MD5\&.
++.RE
++.PP
++\fBsha512\fR
++.RS 4
++When a user changes their password next, encrypt it with the SHA512 algorithm\&. If the SHA512 algorithm is not known to the
++\fBcrypt\fR(3)
++function, fall back to MD5\&.
++.RE
++.PP
++\fBblowfish\fR
++.RS 4
++When a user changes their password next, encrypt it with the blowfish algorithm\&. If the blowfish algorithm is not known to the
++\fBcrypt\fR(3)
++function, fall back to MD5\&.
++.RE
++.PP
++\fBrounds=\fR\fB\fIn\fR\fR
++.RS 4
++Set the optional number of rounds of the SHA256, SHA512 and blowfish password hashing algorithms to
++\fIn\fR\&.
++.RE
++.PP
++\fBbroken_shadow\fR
++.RS 4
++Ignore errors reading shadow information for users in the account management module\&.
++.RE
++.PP
++\fBminlen=\fR\fB\fIn\fR\fR
++.RS 4
++Set a minimum password length of
++\fIn\fR
++characters\&. The default value is 6\&. The maximum for DES crypt\-based passwords is 8 characters\&.
++.RE
++.PP
++\fBobscure\fR
++.RS 4
++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:
++.PP
++\fBPalindrome\fR
++.RS 4
++Verifies that the new password is not a palindrome of (i\&.e\&., the reverse of) the previous one\&.
++.RE
++.PP
++\fBCase Change Only\fR
++.RS 4
++Verifies that the new password isn\*(Aqt the same as the old one with a change of case\&.
++.RE
++.PP
++\fBSimilar\fR
++.RS 4
++Verifies that the new password isn\*(Aqt too much like the previous one\&.
++.RE
++.PP
++\fBSimple\fR
++.RS 4
++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\&.
++.RE
++.PP
++\fBRotated\fR
++.RS 4
++Is the new password a rotated version of the old password? (E\&.g\&., "billy" and "illyb")
++.RE
++.sp
++.RE
++.PP
++Invalid arguments are logged with
++\fBsyslog\fR(3)\&.
++.SH "MODULE TYPES PROVIDED"
++.PP
++All module types (\fBaccount\fR,
++\fBauth\fR,
++\fBpassword\fR
++and
++\fBsession\fR) are provided\&.
++.SH "RETURN VALUES"
++.PP
++PAM_IGNORE
++.RS 4
++Ignore this module\&.
++.RE
++.SH "EXAMPLES"
++.PP
++An example usage for
++/etc/pam\&.d/common\-password
++would be:
++.sp
++.if n \{\
++.RS 4
++.\}
++.nf
++password        [success=2 default=ignore]      pam_extrausers\&.so obscure sha512
++password        [success=1 default=ignore]      pam_unix\&.so obscure sha512
++# here\*(Aqs the fallback if no module succeeds
++password        requisite                       pam_deny\&.so
++# prime the stack with a positive return value if there isn\*(Aqt 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 
++      
++.fi
++.if n \{\
++.RE
++.\}
++.sp
++.SH "SEE ALSO"
++.PP
++\fBlogin.defs\fR(5),
++\fBpam.conf\fR(5),
++\fBpam.d\fR(5),
++\fBpam\fR(7)
++.SH "AUTHOR"
++.PP
++pam_extrausers was written by various people\&.
diff -pruN 1.3.1-5/debian/patches-applied/pam_motd-legal-notice 1.3.1-5ubuntu6/debian/patches-applied/pam_motd-legal-notice
--- 1.3.1-5/debian/patches-applied/pam_motd-legal-notice	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/patches-applied/pam_motd-legal-notice	2020-07-03 01:59:30.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
+@@ -97,6 +97,65 @@
+     }
+ }
+ 
++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)
+ {
+@@ -170,6 +229,9 @@
+     if (motd_dir_path != NULL)
+ 	try_to_display_directory(pamh, motd_dir_path);
+ 
++    /* Display the legal disclaimer only if necessary */
++    retval = display_legal(pamh);
++
+     return retval;
+ }
+ 
diff -pruN 1.3.1-5/debian/patches-applied/pam_umask_usergroups_from_login.defs.patch 1.3.1-5ubuntu6/debian/patches-applied/pam_umask_usergroups_from_login.defs.patch
--- 1.3.1-5/debian/patches-applied/pam_umask_usergroups_from_login.defs.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/patches-applied/pam_umask_usergroups_from_login.defs.patch	2020-07-03 01:59:30.000000000 +0000
@@ -0,0 +1,139 @@
+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
+@@ -87,7 +87,7 @@
+ }
+ 
+ static char *
+-search_key (const char *filename)
++search_key (const char *filename, const char *key)
+ {
+   FILE *fp;
+   char *buf = NULL;
+@@ -146,7 +146,7 @@
+         while (isspace ((int)*cp) || *cp == '=')
+           ++cp;
+ 
+-      if (strcasecmp (tmp, "UMASK") == 0)
++      if (strcasecmp (tmp, key) == 0)
+ 	{
+ 	  retval = strdup (cp);
+ 	  break;
+@@ -163,15 +163,34 @@
+ get_options (const pam_handle_t *pamh, options_t *options,
+ 	     int argc, const char **argv)
+ {
++  char *result;
++
+   memset (options, 0, sizeof (options_t));
+   /* Parse parameters for module */
+   for ( ; argc-- > 0; argv++)
+     parse_option (pamh, *argv, options);
+ 
+   if (options->umask == NULL)
+-    options->umask = search_key (LOGIN_DEFS);
++    {
++      options->umask = search_key (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->umask != NULL)
++	{
++	  result = search_key (LOGIN_DEFS, "USERGROUPS_ENAB");
++	  if (result != NULL)
++	    {
++	      options->usergroups = (strcasecmp (result, "yes") == 0);
++	      free (result);
++	    }
++	}
++    }
++
+   if (options->umask == NULL)
+-    options->umask = search_key (LOGIN_CONF);
++    options->umask = search_key (LOGIN_CONF, "UMASK");
+ 
+   return 0;
+ }
+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
+@@ -58,7 +58,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>
+@@ -115,6 +116,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 -> 002, 077 -> 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>
+Index: pam/modules/pam_umask/pam_umask.8
+===================================================================
+--- pam.orig/modules/pam_umask/pam_umask.8
++++ pam/modules/pam_umask/pam_umask.8
+@@ -68,7 +68,7 @@
+ .sp -1
+ .IP \(bu 2.3
+ .\}
+-UMASK entry from /etc/login\&.defs
++UMASK entry from /etc/login\&.defs (influenced by USERGROUPS_ENAB in /etc/login\&.defs)
+ .RE
+ .sp
+ .RS 4
+@@ -98,7 +98,7 @@
+ .PP
+ \fBusergroups\fR
+ .RS 4
+-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 \-> 002, 077 \-> 007)\&.
++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 \-> 002, 077 \-> 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\*(Aqs behaviour without PAM)\&.
+ .RE
+ .PP
+ \fBumask=\fR\fB\fImask\fR\fR
+Index: pam/modules/pam_umask/README
+===================================================================
+--- pam.orig/modules/pam_umask/README
++++ pam/modules/pam_umask/README
+@@ -15,7 +15,8 @@
+ 
+   • umask= argument
+ 
+-  • UMASK entry from /etc/login.defs
++  • UMASK entry from /etc/login.defs (influenced by USERGROUPS_ENAB in /etc/
++    login.defs)
+ 
+   • UMASK= entry from /etc/default/login
+ 
+@@ -38,7 +39,10 @@
+ 
+     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 ->
+-    002, 077 -> 007).
++    002, 077 -> 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).
+ 
+ umask=mask
+ 
diff -pruN 1.3.1-5/debian/patches-applied/selinux_flask_ftbfs.patch 1.3.1-5ubuntu6/debian/patches-applied/selinux_flask_ftbfs.patch
--- 1.3.1-5/debian/patches-applied/selinux_flask_ftbfs.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/patches-applied/selinux_flask_ftbfs.patch	2020-08-06 01:10:51.000000000 +0000
@@ -0,0 +1,25 @@
+From: Mike Salvatore <mike.salvatore@canonical.com>
+Description: Fix FTBFS due to deprecated selinux/flask.h
+Origin: https://github.com/linux-pam/linux-pam/commit/03f46bbe3f22d800a1516f4c535a1bfb573068de
+Bug: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=956355
+Date: Wed 05 Aug 2020 08:46:35 PM EDT
+--- a/modules/pam_selinux/pam_selinux.c
++++ b/modules/pam_selinux/pam_selinux.c
+@@ -63,8 +63,6 @@
+ 
+ #include <selinux/selinux.h>
+ #include <selinux/get_context_list.h>
+-#include <selinux/flask.h>
+-#include <selinux/av_permissions.h>
+ #include <selinux/selinux.h>
+ #include <selinux/context.h>
+ #include <selinux/get_default_type.h>
+@@ -590,7 +588,7 @@ compute_tty_context(const pam_handle_t *
+   }
+ 
+   if (security_compute_relabel(data->exec_context, data->prev_tty_context,
+-			       SECCLASS_CHR_FILE, &data->tty_context)) {
++			       string_to_security_class("chr_file"), &data->tty_context)) {
+     data->tty_context = NULL;
+     pam_syslog(pamh, LOG_ERR, "Failed to compute new context for %s: %m",
+ 	       data->tty_path);
diff -pruN 1.3.1-5/debian/patches-applied/series 1.3.1-5ubuntu6/debian/patches-applied/series
--- 1.3.1-5/debian/patches-applied/series	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/patches-applied/series	2020-08-06 01:10:51.000000000 +0000
@@ -19,7 +19,16 @@ hurd_no_setfsuid
 cve-2010-4708.patch
 PAM-manpage-section 
 update-motd
+pam_motd-legal-notice
 no_PATH_MAX_on_hurd
+ubuntu-rlimit_nice_correction 
+update-motd-manpage-ref
 lib_security_multiarch_compat
+pam_umask_usergroups_from_login.defs.patch
+extrausers.patch
 pam-limits-nofile-fd-setsize-cap
 fix-autoreconf.patch
+0001-pam_motd-Export-MOTD_SHOWN-pam-after-showing-MOTD.patch
+0002-pam_motd-Mention-setting-MOTD_SHOWN-pam-in-the-man-p.patch
+0003-Return-only-PAM_IGNORE-or-error-from-pam_motd.patch
+selinux_flask_ftbfs.patch
diff -pruN 1.3.1-5/debian/patches-applied/ubuntu-rlimit_nice_correction 1.3.1-5ubuntu6/debian/patches-applied/ubuntu-rlimit_nice_correction
--- 1.3.1-5/debian/patches-applied/ubuntu-rlimit_nice_correction	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/patches-applied/ubuntu-rlimit_nice_correction	2018-08-23 23:37:53.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.3.1-5/debian/patches-applied/update-motd-manpage-ref 1.3.1-5ubuntu6/debian/patches-applied/update-motd-manpage-ref
--- 1.3.1-5/debian/patches-applied/update-motd-manpage-ref	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/patches-applied/update-motd-manpage-ref	2018-08-23 23:37:53.000000000 +0000
@@ -0,0 +1,28 @@
+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>
+Index: pam.ubuntu/modules/pam_motd/pam_motd.8
+===================================================================
+--- pam.ubuntu.orig/modules/pam_motd/pam_motd.8
++++ pam.ubuntu/modules/pam_motd/pam_motd.8
+@@ -79,7 +79,8 @@
+ \fBmotd\fR(5),
+ \fBpam.conf\fR(5),
+ \fBpam.d\fR(5),
+-\fBpam\fR(7)
++\fBpam\fR(7),
++\fBupdate-motd\fR(5)
+ .SH "AUTHOR"
+ .PP
+ pam_motd was written by Ben Collins <bcollins@debian\&.org>\&.
diff -pruN 1.3.1-5/debian/po/eu.po 1.3.1-5ubuntu6/debian/po/eu.po
--- 1.3.1-5/debian/po/eu.po	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/po/eu.po	2018-08-23 23:37:53.000000000 +0000
@@ -51,11 +51,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 "
@@ -195,7 +190,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.3.1-5/debian/po/fi.po 1.3.1-5ubuntu6/debian/po/fi.po
--- 1.3.1-5/debian/po/fi.po	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/po/fi.po	2018-08-23 23:37:53.000000000 +0000
@@ -46,11 +46,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.3.1-5/debian/po/ro.po 1.3.1-5ubuntu6/debian/po/ro.po
--- 1.3.1-5/debian/po/ro.po	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/po/ro.po	2018-08-23 23:37:53.000000000 +0000
@@ -189,7 +189,6 @@ msgstr ""
 #. Description
 #: ../libpam-runtime.templates:5001
 #, fuzzy
-#| msgid "Incompatible PAM profiles selected."
 msgid "No PAM profiles have been selected."
 msgstr "Selecție de profile PAM incompatibile."
 
diff -pruN 1.3.1-5/debian/po/tr.po 1.3.1-5ubuntu6/debian/po/tr.po
--- 1.3.1-5/debian/po/tr.po	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/po/tr.po	2018-08-23 23:37:53.000000000 +0000
@@ -48,11 +48,6 @@ msgstr "Görüntü yöneticisinin elle y
 #. Type: error
 #. Description
 #: ../libpam0g.templates:2001
-#| 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.3.1-5/debian/po/vi.po 1.3.1-5ubuntu6/debian/po/vi.po
--- 1.3.1-5/debian/po/vi.po	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/po/vi.po	2018-08-23 23:37:53.000000000 +0000
@@ -48,11 +48,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.3.1-5/debian/po/zh_CN.po 1.3.1-5ubuntu6/debian/po/zh_CN.po
--- 1.3.1-5/debian/po/zh_CN.po	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/po/zh_CN.po	2018-08-23 23:37:53.000000000 +0000
@@ -50,11 +50,6 @@ msgstr "必须手动重新启动显示
 #. 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.3.1-5/debian/rules 1.3.1-5ubuntu6/debian/rules
--- 1.3.1-5/debian/rules	2019-02-14 07:08:47.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/rules	2020-07-03 01:59:30.000000000 +0000
@@ -62,4 +62,6 @@ override_dh_fixperms:
 ifneq (,$(findstring libpam-modules, $(shell dh_listpackages)))
 	chgrp shadow $(d)/libpam-modules-bin/sbin/unix_chkpwd
 	chmod 02755 $(d)/libpam-modules-bin/sbin/unix_chkpwd
+	chgrp shadow $(d)/libpam-modules-bin/sbin/pam_extrausers_chkpwd
+	chmod 02755 $(d)/libpam-modules-bin/sbin/pam_extrausers_chkpwd
 endif
diff -pruN 1.3.1-5/debian/update-motd.5 1.3.1-5ubuntu6/debian/update-motd.5
--- 1.3.1-5/debian/update-motd.5	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.1-5ubuntu6/debian/update-motd.5	2018-08-23 23:37:53.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 adminstrators 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.
