From e0f485fa5cca21ba72520a42ad3fed507a62136c466cfd3f946c080808b3faa2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josef=20M=C3=B6llers?=
Date: Mon, 16 Nov 2020 14:19:30 +0000
Subject: [PATCH 1/4] Accepting request 848315 from
home:jmoellers:branches:Linux-PAM
OBS-URL: https://build.opensuse.org/request/show/848315
OBS-URL: https://build.opensuse.org/package/show/Linux-PAM/pam?expand=0&rev=225
---
pam-bsc1178727-initialize-daysleft.patch | 13 +++++++++++++
pam.changes | 9 +++++++++
pam.spec | 2 ++
3 files changed, 24 insertions(+)
create mode 100644 pam-bsc1178727-initialize-daysleft.patch
diff --git a/pam-bsc1178727-initialize-daysleft.patch b/pam-bsc1178727-initialize-daysleft.patch
new file mode 100644
index 0000000..fa3a9b4
--- /dev/null
+++ b/pam-bsc1178727-initialize-daysleft.patch
@@ -0,0 +1,13 @@
+Index: Linux-PAM-1.4.0/modules/pam_unix/pam_unix_acct.c
+===================================================================
+--- Linux-PAM-1.4.0.orig/modules/pam_unix/pam_unix_acct.c
++++ Linux-PAM-1.4.0/modules/pam_unix/pam_unix_acct.c
+@@ -189,7 +189,7 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int
+ unsigned long long ctrl;
+ const void *void_uname;
+ const char *uname;
+- int retval, daysleft;
++ int retval, daysleft = -1;
+ char buf[256];
+
+ D(("called."));
diff --git a/pam.changes b/pam.changes
index dd0bef9..c8fc046 100644
--- a/pam.changes
+++ b/pam.changes
@@ -1,3 +1,12 @@
+-------------------------------------------------------------------
+Fri Nov 13 09:13:18 UTC 2020 - Josef Möllers
+
+- Initialize pam_unix pam_sm_acct_mgmt() local variable "daysleft"
+ to avoid spurious (and misleading)
+ Warning: your password will expire in ... days.
+ fixed upstream with commit db6b293046a
+ [bsc#1178727, pam-bsc1178727-initialize-daysleft.patch]
+
-------------------------------------------------------------------
Tue Nov 10 11:09:39 UTC 2020 - Thorsten Kukuk
diff --git a/pam.spec b/pam.spec
index cfaf920..bc077a8 100644
--- a/pam.spec
+++ b/pam.spec
@@ -48,6 +48,7 @@ Source12: pam-login_defs-check.sh
Patch2: pam-limit-nproc.patch
Patch4: pam-hostnames-in-access_conf.patch
Patch5: pam-xauth_ownership.patch
+Patch6: pam-bsc1178727-initialize-daysleft.patch
BuildRequires: audit-devel
BuildRequires: bison
BuildRequires: cracklib-devel
@@ -141,6 +142,7 @@ cp -a %{SOURCE12} .
%patch2 -p1
%patch4 -p1
%patch5 -p1
+%patch6 -p1
%build
bash ./pam-login_defs-check.sh
From 94ef2ca6a9c927394b4e723b59bd4e0f7ccc4f61535c33ac888744f1afaea23c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josef=20M=C3=B6llers?=
Date: Thu, 19 Nov 2020 11:13:17 +0000
Subject: [PATCH 2/4] Accepting request 849367 from
home:jmoellers:branches:Linux-PAM
OBS-URL: https://build.opensuse.org/request/show/849367
OBS-URL: https://build.opensuse.org/package/show/Linux-PAM/pam?expand=0&rev=226
---
...1177858-dont-free-environment-string.patch | 26 +++++
pam-pam_cracklib-add-usersubstr.patch | 99 +++++++++++++++++++
pam.changes | 17 ++++
pam.spec | 4 +
4 files changed, 146 insertions(+)
create mode 100644 pam-bsc1177858-dont-free-environment-string.patch
create mode 100644 pam-pam_cracklib-add-usersubstr.patch
diff --git a/pam-bsc1177858-dont-free-environment-string.patch b/pam-bsc1177858-dont-free-environment-string.patch
new file mode 100644
index 0000000..9a9670b
--- /dev/null
+++ b/pam-bsc1177858-dont-free-environment-string.patch
@@ -0,0 +1,26 @@
+Index: Linux-PAM-1.4.0/modules/pam_xauth/pam_xauth.c
+===================================================================
+--- Linux-PAM-1.4.0.orig/modules/pam_xauth/pam_xauth.c
++++ Linux-PAM-1.4.0/modules/pam_xauth/pam_xauth.c
+@@ -701,8 +701,9 @@ pam_sm_open_session (pam_handle_t *pamh,
+ pam_syslog(pamh, LOG_ERR,
+ "can't set environment variable '%s'",
+ xauthority);
+- putenv (xauthority); /* The environment owns this string now. */
+- /* Don't free environment variables nor set them to NULL. */
++ if (putenv (xauthority) == 0) /* The environment owns this string now. */
++ xauthority = NULL;
++ /* Don't free environment variables. */
+
+ /* set $DISPLAY in pam handle to make su - work */
+ {
+@@ -765,7 +766,8 @@ cleanup:
+ unsetenv (XAUTHENV);
+ free(cookiefile);
+ free(cookie);
+- free(xauthority);
++ if (xauthority != NULL) /* If it hasn't been successfully passed to putenv() ... */
++ free(xauthority);
+ return retval;
+ }
+
diff --git a/pam-pam_cracklib-add-usersubstr.patch b/pam-pam_cracklib-add-usersubstr.patch
new file mode 100644
index 0000000..977af32
--- /dev/null
+++ b/pam-pam_cracklib-add-usersubstr.patch
@@ -0,0 +1,99 @@
+Index: Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.c
+===================================================================
+--- Linux-PAM-1.4.0.orig/modules/pam_cracklib/pam_cracklib.c
++++ Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.c
+@@ -88,6 +88,7 @@ struct cracklib_options {
+ int reject_user;
+ int gecos_check;
+ int enforce_for_root;
++ int user_substr;
+ const char *cracklib_dictpath;
+ };
+
+@@ -100,6 +101,7 @@ struct cracklib_options {
+ #define CO_LOW_CREDIT 1
+ #define CO_OTH_CREDIT 1
+ #define CO_MIN_WORD_LENGTH 4
++#define CO_MIN_WORD_LENGTH 4
+
+ static int
+ _pam_parse (pam_handle_t *pamh, struct cracklib_options *opt,
+@@ -185,6 +187,10 @@ _pam_parse (pam_handle_t *pamh, struct c
+ if (!*(opt->cracklib_dictpath)) {
+ opt->cracklib_dictpath = CRACKLIB_DICTS;
+ }
++ } else if ((str = pam_str_skip_prefix(*argv, "usersubstr=")) != NULL) {
++ opt->user_substr = strtol(str, &ep, 10);
++ if (ep == str)
++ opt->user_substr = 0;
+ } else {
+ pam_syslog(pamh,LOG_ERR,"pam_parse: unknown option; %s",*argv);
+ }
+@@ -525,13 +531,54 @@ static int wordcheck(const char *new, ch
+ return 0;
+ }
+
+-static int usercheck(struct cracklib_options *opt, const char *new,
++/*
++ * RETURNS: True if the password is unacceptable, else false
++ */
++static int usersubstr(pam_handle_t *pamh, int len, const char *new, char *user)
++{
++ int i, userlen;
++ int bad = 0; // Assume it's OK unless proven otherwise
++ char *subuser = calloc(len+1, sizeof(char));
++
++ if (subuser == NULL) {
++ return 1;
++ }
++
++ userlen = strlen(user);
++
++ if (len >= CO_MIN_WORD_LENGTH &&
++ userlen > len) {
++ for(i = 0; !bad && (i <= userlen - len); i++) {
++ strncpy(subuser, user+i, len+1);
++ subuser[len] = '\0';
++ bad = wordcheck(new, subuser);
++ }
++ } else {
++ // if we already tested substrings, there's no need to test
++ // the whole username; all substrings would've been found :)
++ if (!bad)
++ bad = wordcheck(new, user);
++ }
++
++ free(subuser);
++
++ return bad;
++}
++
++/*
++ * RETURNS: True if the password is unacceptable, else false
++ */
++static int usercheck(pam_handle_t *pamh, struct cracklib_options *opt, const char *new,
+ char *user)
+ {
+- if (!opt->reject_user)
+- return 0;
++ int bad = 0;
++
++ if (opt->reject_user)
++ bad = wordcheck(new, user);
++ if (!bad && opt->user_substr != 0)
++ bad = usersubstr(pamh, opt->user_substr, new, user);
+
+- return wordcheck(new, user);
++ return bad;
+ }
+
+ static char * str_lower(char *string)
+@@ -646,7 +693,7 @@ static const char *password_check(pam_ha
+ if (!msg && sequence(opt, new))
+ msg = _("contains too long of a monotonic character sequence");
+
+- if (!msg && (usercheck(opt, newmono, usermono) || gecoscheck(pamh, opt, newmono, user)))
++ if (!msg && (usercheck(pamh, opt, newmono, usermono) || gecoscheck(pamh, opt, newmono, user)))
+ msg = _("contains the user name in some form");
+
+ free(usermono);
diff --git a/pam.changes b/pam.changes
index c8fc046..f6714bd 100644
--- a/pam.changes
+++ b/pam.changes
@@ -1,3 +1,20 @@
+-------------------------------------------------------------------
+Wed Nov 18 13:02:15 UTC 2020 - Josef Möllers
+
+- pam_cracklib: added code to check whether the password contains
+ a substring of of the user's name of at least characters length
+ in some form.
+ This is enabled by the new parameter "usersubstr="
+ See https://github.com/libpwquality/libpwquality/commit/bfef79dbe6aa525e9557bf4b0a61e6dde12749c4
+ [jsc#SLE-16719, jsc#SLE-16720, pam-pam_cracklib-add-usersubstr.patch]
+
+-------------------------------------------------------------------
+Wed Nov 18 10:02:32 UTC 2020 - Josef Möllers
+
+- pam_xauth.c: do not free() a string which has been (successfully)
+ passed to putenv().
+ [bsc#1177858, pam-bsc1177858-dont-free-environment-string.patch]
+
-------------------------------------------------------------------
Fri Nov 13 09:13:18 UTC 2020 - Josef Möllers
diff --git a/pam.spec b/pam.spec
index bc077a8..35da088 100644
--- a/pam.spec
+++ b/pam.spec
@@ -49,6 +49,8 @@ Patch2: pam-limit-nproc.patch
Patch4: pam-hostnames-in-access_conf.patch
Patch5: pam-xauth_ownership.patch
Patch6: pam-bsc1178727-initialize-daysleft.patch
+Patch8: pam-bsc1177858-dont-free-environment-string.patch
+Patch9: pam-pam_cracklib-add-usersubstr.patch
BuildRequires: audit-devel
BuildRequires: bison
BuildRequires: cracklib-devel
@@ -143,6 +145,8 @@ cp -a %{SOURCE12} .
%patch4 -p1
%patch5 -p1
%patch6 -p1
+%patch8 -p1
+%patch9 -p1
%build
bash ./pam-login_defs-check.sh
From 6c6194062905a9498a5a2f4268283e23d6e5a569e62fe4bcc98e40172c20ccfe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josef=20M=C3=B6llers?=
Date: Thu, 19 Nov 2020 13:56:42 +0000
Subject: [PATCH 3/4] Accepting request 849441 from
home:jmoellers:branches:Linux-PAM
OBS-URL: https://build.opensuse.org/request/show/849441
OBS-URL: https://build.opensuse.org/package/show/Linux-PAM/pam?expand=0&rev=227
---
pam-pam_cracklib-add-usersubstr.patch | 158 ++++++++++++++++++++------
1 file changed, 122 insertions(+), 36 deletions(-)
diff --git a/pam-pam_cracklib-add-usersubstr.patch b/pam-pam_cracklib-add-usersubstr.patch
index 977af32..b3f55b1 100644
--- a/pam-pam_cracklib-add-usersubstr.patch
+++ b/pam-pam_cracklib-add-usersubstr.patch
@@ -1,3 +1,107 @@
+Index: Linux-PAM-1.4.0/doc/sag/Linux-PAM_SAG.txt
+===================================================================
+--- Linux-PAM-1.4.0.orig/doc/sag/Linux-PAM_SAG.txt
++++ Linux-PAM-1.4.0/doc/sag/Linux-PAM_SAG.txt
+@@ -1003,6 +1003,14 @@ reject_username
+ Check whether the name of the user in straight or reversed form is
+ contained in the new password. If it is found the new password is rejected.
+
++usersubstr=N
++
++ Reject passwords which contain any substring of N or more consecutive
++ characters of the user's name straight or in reverse order.
++ N must be at least 4 for this to be applicable.
++ Also, usernames shorter than N are not checked.
++ If such a substring is found, the password is rejected.
++
+ gecoscheck
+
+ Check whether the words from the GECOS field (usually full name of the
+Index: Linux-PAM-1.4.0/doc/sag/html/sag-pam_cracklib.html
+===================================================================
+--- Linux-PAM-1.4.0.orig/doc/sag/html/sag-pam_cracklib.html
++++ Linux-PAM-1.4.0/doc/sag/html/sag-pam_cracklib.html
+@@ -198,6 +198,15 @@
+ form is contained in the new password. If it is found the
+ new password is rejected.
+
++ usersubstr=N
++
++ Reject passwords which contain any substring of N or more
++ consecutive characters of the user's name straight or in
++ reverse order.
++ N must be at least 4 for this to be applicable.
++ Also, usernames shorter than N are not checked.
++ If such a substring is found, the password is rejected.
++
+ gecoscheck
+
+ Check whether the words from the GECOS field (usually full name
+Index: Linux-PAM-1.4.0/modules/pam_cracklib/README
+===================================================================
+--- Linux-PAM-1.4.0.orig/modules/pam_cracklib/README
++++ Linux-PAM-1.4.0/modules/pam_cracklib/README
+@@ -179,6 +179,14 @@ reject_username
+ Check whether the name of the user in straight or reversed form is
+ contained in the new password. If it is found the new password is rejected.
+
++usersubstr=N
++
++ Reject passwords which contain any substring of N or more consecutive
++ characters of the user's name straight or in reverse order.
++ N must be at least 4 for this to be applicable.
++ Also, usernames shorter than N are not checked.
++ If such a substring is found, the password is rejected.
++
+ gecoscheck
+
+ Check whether the words from the GECOS field (usually full name of the
+Index: Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.8
+===================================================================
+--- Linux-PAM-1.4.0.orig/modules/pam_cracklib/pam_cracklib.8
++++ Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.8
+@@ -232,6 +232,15 @@ Reject passwords which contain more than
+ Check whether the name of the user in straight or reversed form is contained in the new password\&. If it is found the new password is rejected\&.
+ .RE
+ .PP
++\fBusersubstr=\fR\fB\fIN\fR\fR
++.RS 4
++Reject passwords which contain any substring of N or more consecutive characters of the user\*(Aqs name straight or in
++reverse order\&.
++N must be at least 4 for this to be applicable\&.
++Also, usernames shorter than N are not checked\&.
++If such a substring is found, the password is rejected\&.
++.RE
++.PP
+ \fBgecoscheck\fR
+ .RS 4
+ Check whether the words from the GECOS field (usually full name of the user) longer than 3 characters in straight or reversed form are contained in the new password\&. If any such word is found the new password is rejected\&.
+Index: Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.8.xml
+===================================================================
+--- Linux-PAM-1.4.0.orig/modules/pam_cracklib/pam_cracklib.8.xml
++++ Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.8.xml
+@@ -396,6 +396,21 @@
+
+
+
++
++
++
++
++
++
++ Reject passwords which contain any substring of N or more
++ consecutive characters of the user's name straight or in
++ reverse order. N must be at least 4 for this to be applicable.
++ Also, usernames shorter than N are not checked.
++ If such a substring is found, the password is rejected.
++
++
++
++
+
+
+
Index: Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.c
===================================================================
--- Linux-PAM-1.4.0.orig/modules/pam_cracklib/pam_cracklib.c
@@ -10,15 +114,7 @@ Index: Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.c
const char *cracklib_dictpath;
};
-@@ -100,6 +101,7 @@ struct cracklib_options {
- #define CO_LOW_CREDIT 1
- #define CO_OTH_CREDIT 1
- #define CO_MIN_WORD_LENGTH 4
-+#define CO_MIN_WORD_LENGTH 4
-
- static int
- _pam_parse (pam_handle_t *pamh, struct cracklib_options *opt,
-@@ -185,6 +187,10 @@ _pam_parse (pam_handle_t *pamh, struct c
+@@ -185,6 +186,10 @@ _pam_parse (pam_handle_t *pamh, struct c
if (!*(opt->cracklib_dictpath)) {
opt->cracklib_dictpath = CRACKLIB_DICTS;
}
@@ -29,38 +125,37 @@ Index: Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.c
} else {
pam_syslog(pamh,LOG_ERR,"pam_parse: unknown option; %s",*argv);
}
-@@ -525,13 +531,54 @@ static int wordcheck(const char *new, ch
+@@ -525,13 +530,54 @@ static int wordcheck(const char *new, ch
return 0;
}
--static int usercheck(struct cracklib_options *opt, const char *new,
+/*
+ * RETURNS: True if the password is unacceptable, else false
+ */
-+static int usersubstr(pam_handle_t *pamh, int len, const char *new, char *user)
++static int usersubstr(int len, const char *new, char *user)
+{
+ int i, userlen;
-+ int bad = 0; // Assume it's OK unless proven otherwise
++ int bad = 0; // Assume it's OK unless proven otherwise
+ char *subuser = calloc(len+1, sizeof(char));
+
+ if (subuser == NULL) {
-+ return 1;
++ return 1;
+ }
+
+ userlen = strlen(user);
+
+ if (len >= CO_MIN_WORD_LENGTH &&
-+ userlen > len) {
-+ for(i = 0; !bad && (i <= userlen - len); i++) {
-+ strncpy(subuser, user+i, len+1);
-+ subuser[len] = '\0';
-+ bad = wordcheck(new, subuser);
-+ }
++ userlen > len) {
++ for(i = 0; !bad && (i <= userlen - len); i++) {
++ strncpy(subuser, user+i, len+1);
++ subuser[len] = '\0';
++ bad = wordcheck(new, subuser);
++ }
+ } else {
-+ // if we already tested substrings, there's no need to test
-+ // the whole username; all substrings would've been found :)
-+ if (!bad)
-+ bad = wordcheck(new, user);
++ // if we already tested substrings, there's no need to test
++ // the whole username; all substrings would've been found :)
++ if (!bad)
++ bad = wordcheck(new, user);
+ }
+
+ free(subuser);
@@ -71,7 +166,7 @@ Index: Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.c
+/*
+ * RETURNS: True if the password is unacceptable, else false
+ */
-+static int usercheck(pam_handle_t *pamh, struct cracklib_options *opt, const char *new,
+ static int usercheck(struct cracklib_options *opt, const char *new,
char *user)
{
- if (!opt->reject_user)
@@ -79,21 +174,12 @@ Index: Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.c
+ int bad = 0;
+
+ if (opt->reject_user)
-+ bad = wordcheck(new, user);
++ bad = wordcheck(new, user);
+ if (!bad && opt->user_substr != 0)
-+ bad = usersubstr(pamh, opt->user_substr, new, user);
++ bad = usersubstr(opt->user_substr, new, user);
- return wordcheck(new, user);
+ return bad;
}
static char * str_lower(char *string)
-@@ -646,7 +693,7 @@ static const char *password_check(pam_ha
- if (!msg && sequence(opt, new))
- msg = _("contains too long of a monotonic character sequence");
-
-- if (!msg && (usercheck(opt, newmono, usermono) || gecoscheck(pamh, opt, newmono, user)))
-+ if (!msg && (usercheck(pamh, opt, newmono, usermono) || gecoscheck(pamh, opt, newmono, user)))
- msg = _("contains the user name in some form");
-
- free(usermono);
From c4daf63ae58f8378218ebb9a84606e6ac74e76e054f32b807fe182aa590ab578 Mon Sep 17 00:00:00 2001
From: Thorsten Kukuk
Date: Thu, 19 Nov 2020 15:52:27 +0000
Subject: [PATCH 4/4] - Update to 1.5.0 - obsoletes
pam-bsc1178727-initialize-daysleft.patch - Multiple minor bug fixes,
portability fixes, and documentation improvements. - Extended libpam API
with pam_modutil_check_user_in_passwd function. - pam_faillock: changed
/run/faillock/$USER permissions from 0600 to 0660. - pam_motd: read motd
files with target user credentials skipping unreadable ones. -
pam_pwhistory: added a SELinux helper executable. - pam_unix, pam_usertype:
implemented avoidance of certain timing attacks. - pam_wheel: implemented
PAM_RUSER fallback for the case when getlogin fails. - pam_env: Reading of
the user environment is deprecated and will be removed at some
point in the future. - libpam: pam_modutil_drop_priv() now correctly sets
the target user's supplementary groups, allowing pam_motd to filter
messages accordingly - Refresh pam-xauth_ownership.patch -
pam_tally2-removal.patch: Re-add pam_tally2 for deprecated sub-package -
pam_cracklib-removal.patch: Re-add pam_cracklib for deprecated sub-package
OBS-URL: https://build.opensuse.org/package/show/Linux-PAM/pam?expand=0&rev=228
---
Linux-PAM-1.4.0-docs.tar.xz | 3 -
Linux-PAM-1.4.0.tar.xz | 3 -
Linux-PAM-1.5.0-docs.tar.xz | 3 +
Linux-PAM-1.5.0.tar.xz | 3 +
pam-bsc1178727-initialize-daysleft.patch | 13 -
pam-pam_cracklib-add-usersubstr.patch | 104 --
pam-xauth_ownership.patch | 19 +-
pam.changes | 20 +
pam.spec | 13 +-
pam_cracklib-removal.patch | 1740 ++++++++++++++++++++++
pam_tally2-removal.patch | 1332 +++++++++++++++++
11 files changed, 3115 insertions(+), 138 deletions(-)
delete mode 100644 Linux-PAM-1.4.0-docs.tar.xz
delete mode 100644 Linux-PAM-1.4.0.tar.xz
create mode 100644 Linux-PAM-1.5.0-docs.tar.xz
create mode 100644 Linux-PAM-1.5.0.tar.xz
delete mode 100644 pam-bsc1178727-initialize-daysleft.patch
create mode 100644 pam_cracklib-removal.patch
create mode 100644 pam_tally2-removal.patch
diff --git a/Linux-PAM-1.4.0-docs.tar.xz b/Linux-PAM-1.4.0-docs.tar.xz
deleted file mode 100644
index 273819e..0000000
--- a/Linux-PAM-1.4.0-docs.tar.xz
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:351764a0643052564a4b840320744c7e402112a2a57d2ac04511a6d22dc52e04
-size 477712
diff --git a/Linux-PAM-1.4.0.tar.xz b/Linux-PAM-1.4.0.tar.xz
deleted file mode 100644
index fedf45f..0000000
--- a/Linux-PAM-1.4.0.tar.xz
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:cd6d928c51e64139be3bdb38692c68183a509b83d4f2c221024ccd4bcddfd034
-size 988908
diff --git a/Linux-PAM-1.5.0-docs.tar.xz b/Linux-PAM-1.5.0-docs.tar.xz
new file mode 100644
index 0000000..f465fd7
--- /dev/null
+++ b/Linux-PAM-1.5.0-docs.tar.xz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:75fefd2a601c76d5e289aa8c36234ec2ac398395f4a48caf5ef638c1131019a9
+size 441644
diff --git a/Linux-PAM-1.5.0.tar.xz b/Linux-PAM-1.5.0.tar.xz
new file mode 100644
index 0000000..d5f6b23
--- /dev/null
+++ b/Linux-PAM-1.5.0.tar.xz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:02d39854b508fae9dc713f7733bbcdadbe17b50de965aedddd65bcb6cc7852c8
+size 972228
diff --git a/pam-bsc1178727-initialize-daysleft.patch b/pam-bsc1178727-initialize-daysleft.patch
deleted file mode 100644
index fa3a9b4..0000000
--- a/pam-bsc1178727-initialize-daysleft.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-Index: Linux-PAM-1.4.0/modules/pam_unix/pam_unix_acct.c
-===================================================================
---- Linux-PAM-1.4.0.orig/modules/pam_unix/pam_unix_acct.c
-+++ Linux-PAM-1.4.0/modules/pam_unix/pam_unix_acct.c
-@@ -189,7 +189,7 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int
- unsigned long long ctrl;
- const void *void_uname;
- const char *uname;
-- int retval, daysleft;
-+ int retval, daysleft = -1;
- char buf[256];
-
- D(("called."));
diff --git a/pam-pam_cracklib-add-usersubstr.patch b/pam-pam_cracklib-add-usersubstr.patch
index b3f55b1..8478271 100644
--- a/pam-pam_cracklib-add-usersubstr.patch
+++ b/pam-pam_cracklib-add-usersubstr.patch
@@ -1,107 +1,3 @@
-Index: Linux-PAM-1.4.0/doc/sag/Linux-PAM_SAG.txt
-===================================================================
---- Linux-PAM-1.4.0.orig/doc/sag/Linux-PAM_SAG.txt
-+++ Linux-PAM-1.4.0/doc/sag/Linux-PAM_SAG.txt
-@@ -1003,6 +1003,14 @@ reject_username
- Check whether the name of the user in straight or reversed form is
- contained in the new password. If it is found the new password is rejected.
-
-+usersubstr=N
-+
-+ Reject passwords which contain any substring of N or more consecutive
-+ characters of the user's name straight or in reverse order.
-+ N must be at least 4 for this to be applicable.
-+ Also, usernames shorter than N are not checked.
-+ If such a substring is found, the password is rejected.
-+
- gecoscheck
-
- Check whether the words from the GECOS field (usually full name of the
-Index: Linux-PAM-1.4.0/doc/sag/html/sag-pam_cracklib.html
-===================================================================
---- Linux-PAM-1.4.0.orig/doc/sag/html/sag-pam_cracklib.html
-+++ Linux-PAM-1.4.0/doc/sag/html/sag-pam_cracklib.html
-@@ -198,6 +198,15 @@
- form is contained in the new password. If it is found the
- new password is rejected.
-
-+ usersubstr=N
-+
-+ Reject passwords which contain any substring of N or more
-+ consecutive characters of the user's name straight or in
-+ reverse order.
-+ N must be at least 4 for this to be applicable.
-+ Also, usernames shorter than N are not checked.
-+ If such a substring is found, the password is rejected.
-+
- gecoscheck
-
- Check whether the words from the GECOS field (usually full name
-Index: Linux-PAM-1.4.0/modules/pam_cracklib/README
-===================================================================
---- Linux-PAM-1.4.0.orig/modules/pam_cracklib/README
-+++ Linux-PAM-1.4.0/modules/pam_cracklib/README
-@@ -179,6 +179,14 @@ reject_username
- Check whether the name of the user in straight or reversed form is
- contained in the new password. If it is found the new password is rejected.
-
-+usersubstr=N
-+
-+ Reject passwords which contain any substring of N or more consecutive
-+ characters of the user's name straight or in reverse order.
-+ N must be at least 4 for this to be applicable.
-+ Also, usernames shorter than N are not checked.
-+ If such a substring is found, the password is rejected.
-+
- gecoscheck
-
- Check whether the words from the GECOS field (usually full name of the
-Index: Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.8
-===================================================================
---- Linux-PAM-1.4.0.orig/modules/pam_cracklib/pam_cracklib.8
-+++ Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.8
-@@ -232,6 +232,15 @@ Reject passwords which contain more than
- Check whether the name of the user in straight or reversed form is contained in the new password\&. If it is found the new password is rejected\&.
- .RE
- .PP
-+\fBusersubstr=\fR\fB\fIN\fR\fR
-+.RS 4
-+Reject passwords which contain any substring of N or more consecutive characters of the user\*(Aqs name straight or in
-+reverse order\&.
-+N must be at least 4 for this to be applicable\&.
-+Also, usernames shorter than N are not checked\&.
-+If such a substring is found, the password is rejected\&.
-+.RE
-+.PP
- \fBgecoscheck\fR
- .RS 4
- Check whether the words from the GECOS field (usually full name of the user) longer than 3 characters in straight or reversed form are contained in the new password\&. If any such word is found the new password is rejected\&.
-Index: Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.8.xml
-===================================================================
---- Linux-PAM-1.4.0.orig/modules/pam_cracklib/pam_cracklib.8.xml
-+++ Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.8.xml
-@@ -396,6 +396,21 @@
-
-
-
-+
-+
-+
-+
-+
-+
-+ Reject passwords which contain any substring of N or more
-+ consecutive characters of the user's name straight or in
-+ reverse order. N must be at least 4 for this to be applicable.
-+ Also, usernames shorter than N are not checked.
-+ If such a substring is found, the password is rejected.
-+
-+
-+
-+
-
-
-
Index: Linux-PAM-1.4.0/modules/pam_cracklib/pam_cracklib.c
===================================================================
--- Linux-PAM-1.4.0.orig/modules/pam_cracklib/pam_cracklib.c
diff --git a/pam-xauth_ownership.patch b/pam-xauth_ownership.patch
index 737af6f..9fed067 100644
--- a/pam-xauth_ownership.patch
+++ b/pam-xauth_ownership.patch
@@ -1,8 +1,7 @@
-Index: Linux-PAM-1.4.0/modules/pam_xauth/pam_xauth.c
-===================================================================
---- Linux-PAM-1.4.0.orig/modules/pam_xauth/pam_xauth.c
-+++ Linux-PAM-1.4.0/modules/pam_xauth/pam_xauth.c
-@@ -355,11 +355,13 @@ pam_sm_open_session (pam_handle_t *pamh,
+diff -urN Linux-PAM-1.5.0/modules/pam_xauth/pam_xauth.c Linux-PAM-1.5.0.xauth/modules/pam_xauth/pam_xauth.c
+--- Linux-PAM-1.5.0/modules/pam_xauth/pam_xauth.c 2020-11-10 16:46:13.000000000 +0100
++++ Linux-PAM-1.5.0.xauth/modules/pam_xauth/pam_xauth.c 2020-11-19 11:50:54.176925556 +0100
+@@ -355,11 +355,13 @@
char *cookiefile = NULL, *xauthority = NULL,
*cookie = NULL, *display = NULL, *tmp = NULL,
*xauthlocalhostname = NULL;
@@ -18,7 +17,7 @@ Index: Linux-PAM-1.4.0/modules/pam_xauth/pam_xauth.c
/* Parse arguments. We don't understand many, so no sense in breaking
* this into a separate function. */
-@@ -429,7 +431,16 @@ pam_sm_open_session (pam_handle_t *pamh,
+@@ -429,7 +431,16 @@
retval = PAM_SESSION_ERR;
goto cleanup;
}
@@ -36,7 +35,7 @@ Index: Linux-PAM-1.4.0/modules/pam_xauth/pam_xauth.c
if (rpwd == NULL) {
pam_syslog(pamh, LOG_ERR,
"error determining invoking user's name");
-@@ -518,18 +529,26 @@ pam_sm_open_session (pam_handle_t *pamh,
+@@ -518,18 +529,26 @@
cookiefile);
}
@@ -67,8 +66,8 @@ Index: Linux-PAM-1.4.0/modules/pam_xauth/pam_xauth.c
+ xauth, "-i", "-f", cookiefile, "nlist", display,
NULL) == 0) {
#ifdef WITH_SELINUX
- security_context_t context = NULL;
-@@ -583,12 +602,12 @@ pam_sm_open_session (pam_handle_t *pamh,
+ char *context_raw = NULL;
+@@ -583,12 +602,12 @@
cookiefile,
"nlist",
t,
@@ -85,7 +84,7 @@ Index: Linux-PAM-1.4.0/modules/pam_xauth/pam_xauth.c
"nlist", t, NULL);
}
free(t);
-@@ -673,13 +692,17 @@ pam_sm_open_session (pam_handle_t *pamh,
+@@ -673,13 +692,17 @@
goto cleanup;
}
diff --git a/pam.changes b/pam.changes
index f6714bd..c43791d 100644
--- a/pam.changes
+++ b/pam.changes
@@ -1,3 +1,23 @@
+-------------------------------------------------------------------
+Thu Nov 19 15:43:33 UTC 2020 - Thorsten Kukuk
+
+- Update to 1.5.0
+ - obsoletes pam-bsc1178727-initialize-daysleft.patch
+ - Multiple minor bug fixes, portability fixes, and documentation improvements.
+ - Extended libpam API with pam_modutil_check_user_in_passwd function.
+ - pam_faillock: changed /run/faillock/$USER permissions from 0600 to 0660.
+ - pam_motd: read motd files with target user credentials skipping unreadable ones.
+ - pam_pwhistory: added a SELinux helper executable.
+ - pam_unix, pam_usertype: implemented avoidance of certain timing attacks.
+ - pam_wheel: implemented PAM_RUSER fallback for the case when getlogin fails.
+ - pam_env: Reading of the user environment is deprecated and will be removed
+ at some point in the future.
+ - libpam: pam_modutil_drop_priv() now correctly sets the target user's
+ supplementary groups, allowing pam_motd to filter messages accordingly
+- Refresh pam-xauth_ownership.patch
+- pam_tally2-removal.patch: Re-add pam_tally2 for deprecated sub-package
+- pam_cracklib-removal.patch: Re-add pam_cracklib for deprecated sub-package
+
-------------------------------------------------------------------
Wed Nov 18 13:02:15 UTC 2020 - Josef Möllers
diff --git a/pam.spec b/pam.spec
index 35da088..0585c87 100644
--- a/pam.spec
+++ b/pam.spec
@@ -27,7 +27,7 @@
%endif
Name: pam
#
-Version: 1.4.0
+Version: 1.5.0
Release: 0
Summary: A Security Tool that Provides Authentication for Applications
License: GPL-2.0-or-later OR BSD-3-Clause
@@ -48,7 +48,8 @@ Source12: pam-login_defs-check.sh
Patch2: pam-limit-nproc.patch
Patch4: pam-hostnames-in-access_conf.patch
Patch5: pam-xauth_ownership.patch
-Patch6: pam-bsc1178727-initialize-daysleft.patch
+Patch6: pam_cracklib-removal.patch
+Patch7: pam_tally2-removal.patch
Patch8: pam-bsc1177858-dont-free-environment-string.patch
Patch9: pam-pam_cracklib-add-usersubstr.patch
BuildRequires: audit-devel
@@ -144,7 +145,8 @@ cp -a %{SOURCE12} .
%patch2 -p1
%patch4 -p1
%patch5 -p1
-%patch6 -p1
+%patch6 -R -p1
+%patch7 -R -p1
%patch8 -p1
%patch9 -p1
@@ -316,6 +318,7 @@ done
%{_mandir}/man8/pam_sepermit.8%{?ext_man}
%{_mandir}/man8/pam_setquota.8%{?ext_man}
%{_mandir}/man8/pam_shells.8%{?ext_man}
+%{_mandir}/man8/pam_stress.8%{?ext_man}
%{_mandir}/man8/pam_succeed_if.8%{?ext_man}
%{_mandir}/man8/pam_time.8%{?ext_man}
%{_mandir}/man8/pam_timestamp.8%{?ext_man}
@@ -327,6 +330,7 @@ done
%{_mandir}/man8/pam_warn.8%{?ext_man}
%{_mandir}/man8/pam_wheel.8%{?ext_man}
%{_mandir}/man8/pam_xauth.8%{?ext_man}
+%{_mandir}/man8/pwhistory_helper.8%{?ext_man}
%{_mandir}/man8/unix2_chkpwd.8%{?ext_man}
%{_mandir}/man8/unix_chkpwd.8%{?ext_man}
%{_mandir}/man8/unix_update.8%{?ext_man}
@@ -392,6 +396,7 @@ done
/sbin/mkhomedir_helper
/sbin/pam_namespace_helper
/sbin/pam_timestamp_check
+/sbin/pwhistory_helper
%verify(not mode) %attr(4755,root,shadow) /sbin/unix_chkpwd
%verify(not mode) %attr(4755,root,shadow) /sbin/unix2_chkpwd
%attr(0700,root,root) /sbin/unix_update
@@ -407,8 +412,6 @@ done
/%{_lib}/security/pam_cracklib.so
/%{_lib}/security/pam_tally2.so
/sbin/pam_tally2
-%{_mandir}/man8/pam_cracklib.8%{?ext_man}
-%{_mandir}/man8/pam_tally2.8%{?ext_man}
%files doc
%defattr(644,root,root,755)
diff --git a/pam_cracklib-removal.patch b/pam_cracklib-removal.patch
new file mode 100644
index 0000000..22dbdcb
--- /dev/null
+++ b/pam_cracklib-removal.patch
@@ -0,0 +1,1740 @@
+From d702ff714c309069111899fd07c09e31c414c166 Mon Sep 17 00:00:00 2001
+From: "Dmitry V. Levin"
+Date: Thu, 29 Oct 2020 08:00:00 +0000
+Subject: [PATCH] Remove deprecated pam_cracklib module
+
+* ci/install-dependencies.sh: Remove libcrack2-dev.
+* ci/run-build-and-tests.sh (DISTCHECK_CONFIGURE_FLAGS): Remove
+--enable-cracklib=check.
+* conf/pam.conf: Remove references to pam_cracklib.so.
+* configure.ac: Remove --enable-cracklib option.
+(AC_SUBST): Remove LIBCRACK.
+(AM_CONDITIONAL): Remove COND_BUILD_PAM_CRACKLIB.
+(AC_CONFIG_FILES): Remove modules/pam_cracklib/Makefile.
+* doc/sag/pam_cracklib.xml: Remove.
+* doc/sag/Linux-PAM_SAG.xml: Do not include pam_cracklib.xml.
+* modules/Makefile.am (MAYBE_PAM_CRACKLIB): Remove.
+(SUBDIRS): Remove MAYBE_PAM_CRACKLIB.
+* modules/pam_cracklib/Makefile.am: Remove.
+* modules/pam_cracklib/README.xml: Likewise.
+* modules/pam_cracklib/pam_cracklib.8.xml: Likewise.
+* modules/pam_cracklib/pam_cracklib.c: Likewise.
+* modules/pam_cracklib/tst-pam_cracklib: Likewise.
+* xtests/tst-pam_cracklib1.c: Likewise.
+* xtests/tst-pam_cracklib1.pamd: Likewise.
+* xtests/tst-pam_cracklib2.c: Likewise.
+* xtests/tst-pam_cracklib2.pamd: Likewise.
+* modules/pam_pwhistory/pam_pwhistory.8.xml: Replace pam_cracklib
+in examples with pam_passwdqc.
+* modules/pam_unix/pam_unix.8.xml: Likewise.
+* po/POTFILES.in: Remove ./modules/pam_cracklib/pam_cracklib.c.
+* xtests/.gitignore: Remove tst-pam_cracklib1 and tst-pam_cracklib2.
+* xtests/Makefile.am (EXTRA_DIST): Remove tst-pam_cracklib1.pamd
+and tst-pam_cracklib2.pamd.
+(XTESTS): Remove tst-pam_cracklib1 and tst-pam_cracklib2.
+* NEWS: Document this change.
+---
+ NEWS | 2 +
+ ci/install-dependencies.sh | 1 -
+ ci/run-build-and-tests.sh | 2 +-
+ conf/pam.conf | 5 -
+ configure.ac | 25 +-
+ doc/sag/Linux-PAM_SAG.xml | 2 -
+ doc/sag/pam_cracklib.xml | 34 -
+ modules/Makefile.am | 5 -
+ modules/pam_cracklib/Makefile.am | 33 -
+ modules/pam_cracklib/README.xml | 41 -
+ modules/pam_cracklib/pam_cracklib.8.xml | 592 --------------
+ modules/pam_cracklib/pam_cracklib.c | 899 ----------------------
+ modules/pam_cracklib/tst-pam_cracklib | 2 -
+ modules/pam_pwhistory/pam_pwhistory.8.xml | 6 +-
+ modules/pam_unix/pam_unix.8.xml | 6 +-
+ po/POTFILES.in | 1 -
+ xtests/.gitignore | 2 -
+ xtests/Makefile.am | 2 -
+ xtests/tst-pam_cracklib1.c | 135 ----
+ xtests/tst-pam_cracklib1.pamd | 2 -
+ xtests/tst-pam_cracklib2.c | 143 ----
+ xtests/tst-pam_cracklib2.pamd | 2 -
+ 22 files changed, 10 insertions(+), 1932 deletions(-)
+ delete mode 100644 doc/sag/pam_cracklib.xml
+ delete mode 100644 modules/pam_cracklib/Makefile.am
+ delete mode 100644 modules/pam_cracklib/README.xml
+ delete mode 100644 modules/pam_cracklib/pam_cracklib.8.xml
+ delete mode 100644 modules/pam_cracklib/pam_cracklib.c
+ delete mode 100755 modules/pam_cracklib/tst-pam_cracklib
+ delete mode 100644 xtests/tst-pam_cracklib1.c
+ delete mode 100644 xtests/tst-pam_cracklib1.pamd
+ delete mode 100644 xtests/tst-pam_cracklib2.c
+ delete mode 100644 xtests/tst-pam_cracklib2.pamd
+
+diff --git a/configure.ac b/configure.ac
+index 59327a75..4397124d 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -334,28 +334,6 @@ case "$ac_cv_search_dlopen" in
+ esac
+ AC_SUBST(LIBDL)
+
+-AC_ARG_ENABLE([cracklib],
+- [AS_HELP_STRING([--enable-cracklib],
+- [build deprecated pam_cracklib module])],
+- [], [enable_cracklib=no])
+-LIBCRACK=""
+-case "$enable_cracklib" in
+- no) ;;
+- yes|check)
+- dnl Check for cracklib
+- AC_CHECK_HEADERS([crack.h],
+- [AC_CHECK_LIB([crack], [FascistCheck],
+- [LIBCRACK="-lcrack"])])
+- if test -z "$LIBCRACK"; then
+- if test "$enable_cracklib" = yes; then
+- AC_MSG_FAILURE([failed to find cracklib])
+- fi
+- fi
+- ;;
+- *) AC_MSG_ERROR([bad value $enable_cracklib for --enable-cracklib option]) ;;
+-esac
+-AC_SUBST(LIBCRACK)
+-
+ dnl Look for Linux Auditing library - see documentation
+ AC_ARG_ENABLE([audit],
+ AS_HELP_STRING([--disable-audit],[do not enable audit support]),
+@@ -662,7 +640,6 @@ case "$enable_unix" in
+ *) AC_MSG_ERROR([bad value $enable_unix for --enable-unix option]) ;;
+ esac
+
+-AM_CONDITIONAL([COND_BUILD_PAM_CRACKLIB], [test -n "$LIBCRACK"])
+ AM_CONDITIONAL([COND_BUILD_PAM_KEYINIT], [test "$have_key_syscalls" = 1])
+ AM_CONDITIONAL([COND_BUILD_PAM_LASTLOG], [test "$ac_cv_func_logwtmp" = yes])
+ AM_CONDITIONAL([COND_BUILD_PAM_NAMESPACE], [test "$ac_cv_func_unshare" = yes])
+@@ -682,7 +659,7 @@ AC_CONFIG_FILES([Makefile libpam/Makefile libpamc/Makefile libpamc/test/Makefile
+ po/Makefile.in \
+ Make.xml.rules \
+ modules/Makefile \
+- modules/pam_access/Makefile modules/pam_cracklib/Makefile \
++ modules/pam_access/Makefile \
+ modules/pam_debug/Makefile modules/pam_deny/Makefile \
+ modules/pam_echo/Makefile modules/pam_env/Makefile \
+ modules/pam_faildelay/Makefile modules/pam_faillock/Makefile \
+diff --git a/modules/Makefile.am b/modules/Makefile.am
+index 641108dd..aa03e319 100644
+--- a/modules/Makefile.am
++++ b/modules/Makefile.am
+@@ -2,10 +2,6 @@
+ # Copyright (c) 2005, 2006, 2008 Thorsten Kukuk
+ #
+
+-if COND_BUILD_PAM_CRACKLIB
+- MAYBE_PAM_CRACKLIB = pam_cracklib
+-endif
+-
+ if COND_BUILD_PAM_KEYINIT
+ MAYBE_PAM_KEYINIT = pam_keyinit
+ endif
+@@ -56,7 +52,6 @@ endif
+
+ SUBDIRS := \
+ pam_access \
+- $(MAYBE_PAM_CRACKLIB) \
+ pam_debug \
+ pam_deny \
+ pam_echo \
+diff --git a/modules/pam_cracklib/Makefile.am b/modules/pam_cracklib/Makefile.am
+deleted file mode 100644
+index e11c42d7..00000000
+--- a/modules/pam_cracklib/Makefile.am
++++ /dev/null
+@@ -1,33 +0,0 @@
+-#
+-# Copyright (c) 2005, 2006, 2009 Thorsten Kukuk
+-#
+-
+-CLEANFILES = *~
+-MAINTAINERCLEANFILES = $(MANS) README
+-
+-EXTRA_DIST = $(XMLS)
+-
+-#if HAVE_DOC
+-#dist_man_MANS = pam_cracklib.8
+-#endif
+-XMLS = README.xml pam_cracklib.8.xml
+-dist_check_SCRIPTS = tst-pam_cracklib
+-TESTS = $(dist_check_SCRIPTS)
+-
+-securelibdir = $(SECUREDIR)
+-secureconfdir = $(SCONFIGDIR)
+-
+-AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \
+- $(WARN_CFLAGS)
+-AM_LDFLAGS = -no-undefined -avoid-version -module
+-if HAVE_VERSIONING
+- AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map
+-endif
+-pam_cracklib_la_LIBADD = $(top_builddir)/libpam/libpam.la \
+- @LIBCRACK@ @LIBCRYPT@
+-securelib_LTLIBRARIES = pam_cracklib.la
+-
+-if ENABLE_REGENERATE_MAN
+-dist_noinst_DATA = README
+--include $(top_srcdir)/Make.xml.rules
+-endif
+diff --git a/modules/pam_cracklib/README.xml b/modules/pam_cracklib/README.xml
+deleted file mode 100644
+index c4a7b54c..00000000
+--- a/modules/pam_cracklib/README.xml
++++ /dev/null
+@@ -1,41 +0,0 @@
+-
+-
+--->
+-]>
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+diff --git a/modules/pam_cracklib/pam_cracklib.8.xml b/modules/pam_cracklib/pam_cracklib.8.xml
+deleted file mode 100644
+index 75e44e2d..00000000
+--- a/modules/pam_cracklib/pam_cracklib.8.xml
++++ /dev/null
+@@ -1,592 +0,0 @@
+-
+-
+-
+-
+-
+-
+- pam_cracklib
+- 8
+- Linux-PAM Manual
+-
+-
+-
+- pam_cracklib
+- PAM module to check the password against dictionary words
+-
+-
+-
+-
+- pam_cracklib.so
+-
+- ...
+-
+-
+-
+-
+-
+-
+- DESCRIPTION
+-
+-
+- This module can be plugged into the password stack of
+- a given application to provide some plug-in strength-checking for passwords.
+-
+-
+-
+- The action of this module is to prompt the user for a password and
+- check its strength against a system dictionary and a set of rules for
+- identifying poor choices.
+-
+-
+-
+- The first action is to prompt for a single password, check its
+- strength and then, if it is considered strong, prompt for the password
+- a second time (to verify that it was typed correctly on the first
+- occasion). All being well, the password is passed on to subsequent
+- modules to be installed as the new authentication token.
+-
+-
+-
+- The strength checks works in the following manner: at first the
+- Cracklib routine is called to check if the password
+- is part of a dictionary; if this is not the case an additional set of
+- strength checks is done. These checks are:
+-
+-
+-
+-
+- Palindrome
+-
+-
+- Is the new password a palindrome?
+-
+-
+-
+-
+- Case Change Only
+-
+-
+- Is the new password the old one with only a change of case?
+-
+-
+-
+-
+- Similar
+-
+-
+- Is the new password too much like the old one?
+- This is primarily controlled by one argument,
+- which is a number of character changes
+- (inserts, removals, or replacements) between the old and new
+- password that are enough to accept the new password.
+- This defaults to 5 changes.
+-
+-
+-
+-
+- Simple
+-
+-
+- Is the new password too small?
+- This is controlled by 6 arguments ,
+- ,
+- , ,
+- , and . See the section
+- on the arguments for the details of how these work and there defaults.
+-
+-
+-
+-
+- Rotated
+-
+-
+- Is the new password a rotated version of the old password?
+-
+-
+-
+-
+- Same consecutive characters
+-
+-
+- Optional check for same consecutive characters.
+-
+-
+-
+-
+- Too long monotonic character sequence
+-
+-
+- Optional check for too long monotonic character sequence.
+-
+-
+-
+-
+- Contains user name
+-
+-
+- Optional check whether the password contains the user's name
+- in some form.
+-
+-
+-
+-
+-
+- This module with no arguments will work well for standard unix
+- password encryption. With md5 encryption, passwords can be longer
+- than 8 characters and the default settings for this module can make it
+- hard for the user to choose a satisfactory new password. Notably, the
+- requirement that the new password contain no more than 1/2 of the
+- characters in the old password becomes a non-trivial constraint. For
+- example, an old password of the form "the quick brown fox jumped over
+- the lazy dogs" would be difficult to change... In addition, the
+- default action is to allow passwords as small as 5 characters in
+- length. For a md5 systems it can be a good idea to increase the
+- required minimum size of a password. One can then allow more credit
+- for different kinds of characters but accept that the new password may
+- share most of these characters with the old password.
+-
+-
+-
+-
+-
+-
+- OPTIONS
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- This option makes the module write information to
+-
+- syslog3
+-
+- indicating the behavior of the module (this option does
+- not write password information to the log file).
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- The default action is for the module to use the
+- following prompts when requesting passwords:
+- "New UNIX password: " and "Retype UNIX password: ".
+- The example word UNIX can
+- be replaced with this option, by default it is empty.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- Prompt user at most N times
+- before returning with error. The default is
+- 1.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- This argument will change the default of
+- 5 for the number of character
+- changes in the new password that differentiate it
+- from the old password.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- The minimum acceptable size for the new password (plus
+- one if credits are not disabled which is the default).
+- In addition to the number of characters in the new password,
+- credit (of +1 in length) is given for each different kind
+- of character (other,
+- upper, lower and
+- digit). The default for this parameter
+- is 9 which is good for a old style UNIX
+- password all of the same type of character but may be too low
+- to exploit the added security of a md5 system. Note that
+- there is a pair of length limits in
+- Cracklib itself, a "way too short" limit
+- of 4 which is hard coded in and a defined limit (6) that will
+- be checked without reference to .
+- If you want to allow passwords as short as 5 characters you
+- should not use this module.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- (N >= 0) This is the maximum credit for having digits in
+- the new password. If you have less than or
+- N
+- digits, each digit will count +1 towards meeting the current
+- value. The default for
+- is 1 which is the recommended
+- value for less than 10.
+-
+-
+- (N < 0) This is the minimum number of digits that must
+- be met for a new password.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- (N >= 0) This is the maximum credit for having upper
+- case letters in the new password. If you have less than
+- or N upper case letters each
+- letter will count +1 towards meeting the current
+- value. The default for
+- is 1 which
+- is the recommended value for less
+- than 10.
+-
+-
+- (N < 0) This is the minimum number of upper
+- case letters that must be met for a new password.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- (N >= 0) This is the maximum credit for having
+- lower case letters in the new password. If you have
+- less than or N lower case
+- letters, each letter will count +1 towards meeting the
+- current value. The default for
+- is 1 which is the recommended
+- value for less than 10.
+-
+-
+- (N < 0) This is the minimum number of lower
+- case letters that must be met for a new password.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- (N >= 0) This is the maximum credit for having other
+- characters in the new password. If you have less than or
+- N other characters, each
+- character will count +1 towards meeting the current
+- value. The default for
+- is 1 which is the recommended
+- value for less than 10.
+-
+-
+- (N < 0) This is the minimum number of other
+- characters that must be met for a new password.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- The minimum number of required classes of characters for
+- the new password. The default number is zero. The four
+- classes are digits, upper and lower letters and other
+- characters.
+- The difference to the check is
+- that a specific class if of characters is not required.
+- Instead N out of four of the
+- classes are required.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- Reject passwords which contain more than N same consecutive
+- characters. The default is 0 which means that this check
+- is disabled.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- Reject passwords which contain monotonic character sequences
+- longer than N. The default is 0 which means that this check
+- is disabled. Examples of such sequence are '12345' or 'fedcb'.
+- Note that most such passwords will not pass the simplicity
+- check unless the sequence is only a minor part of the password.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- Reject passwords which contain more than N consecutive
+- characters of the same class. The default is 0 which means
+- that this check is disabled.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- Check whether the name of the user in straight or reversed
+- form is contained in the new password. If it is found the
+- new password is rejected.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- Check whether the words from the GECOS field (usually full name
+- of the user) longer than 3 characters in straight or reversed
+- form are contained in the new password. If any such word is
+- found the new password is rejected.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- The module will return error on failed check also if the user
+- changing the password is root. This option is off by default
+- which means that just the message about the failed check is
+- printed but root can change the password anyway.
+- Note that root is not asked for an old password so the checks
+- that compare the old and new password are not performed.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- This argument is used to force the
+- module to not prompt the user for a new password but use
+- the one provided by the previously stacked
+- password module.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- Path to the cracklib dictionaries.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- MODULE TYPES PROVIDED
+-
+- Only the module type is provided.
+-
+-
+-
+-
+- RETURN VALUES
+-
+-
+-
+-
+- PAM_SUCCESS
+-
+-
+- The new password passes all checks.
+-
+-
+-
+-
+-
+- PAM_AUTHTOK_ERR
+-
+-
+- No new password was entered,
+- the username could not be determined or the new
+- password fails the strength checks.
+-
+-
+-
+-
+-
+- PAM_AUTHTOK_RECOVERY_ERR
+-
+-
+- The old password was not supplied by a previous stacked
+- module or got not requested from the user.
+- The first error can happen if
+- is specified.
+-
+-
+-
+-
+-
+- PAM_SERVICE_ERR
+-
+-
+- A internal error occurred.
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- EXAMPLES
+-
+- For an example of the use of this module, we show how it may be
+- stacked with the password component of
+-
+- pam_unix8
+-
+-
+-#
+-# These lines stack two password type modules. In this example the
+-# user is given 3 opportunities to enter a strong password. The
+-# "use_authtok" argument ensures that the pam_unix module does not
+-# prompt for a password, but instead uses the one provided by
+-# pam_cracklib.
+-#
+-passwd password required pam_cracklib.so retry=3
+-passwd password required pam_unix.so use_authtok
+-
+-
+-
+-
+- Another example (in the /etc/pam.d/passwd format)
+- is for the case that you want to use md5 password encryption:
+-
+-#%PAM-1.0
+-#
+-# These lines allow a md5 systems to support passwords of at least 14
+-# bytes with extra credit of 2 for digits and 2 for others the new
+-# password must have at least three bytes that are not present in the
+-# old password
+-#
+-password required pam_cracklib.so \
+- difok=3 minlen=15 dcredit= 2 ocredit=2
+-password required pam_unix.so use_authtok nullok md5
+-
+-
+-
+-
+- And here is another example in case you don't want to use credits:
+-
+-#%PAM-1.0
+-#
+-# These lines require the user to select a password with a minimum
+-# length of 8 and with at least 1 digit number, 1 upper case letter,
+-# and 1 other character
+-#
+-password required pam_cracklib.so \
+- dcredit=-1 ucredit=-1 ocredit=-1 lcredit=0 minlen=8
+-password required pam_unix.so use_authtok nullok md5
+-
+-
+-
+-
+-
+-
+- SEE ALSO
+-
+-
+- pam.conf5
+- ,
+-
+- pam.d5
+- ,
+-
+- pam8
+-
+-
+-
+-
+-
+- AUTHOR
+-
+- pam_cracklib was written by Cristian Gafton <gafton@redhat.com>
+-
+-
+-
+-
+diff --git a/modules/pam_cracklib/pam_cracklib.c b/modules/pam_cracklib/pam_cracklib.c
+deleted file mode 100644
+index 01291305..00000000
+--- a/modules/pam_cracklib/pam_cracklib.c
++++ /dev/null
+@@ -1,899 +0,0 @@
+-/*
+- * pam_cracklib module
+- *
+- * 0.9. switch to using a distance algorithm in similar()
+- * 0.86. added support for setting minimum numbers of digits, uppers,
+- * lowers, and others
+- * 0.85. added six new options to use this with long passwords.
+- * 0.8. tidied output and improved D(()) usage for debugging.
+- * 0.7. added support for more obscure checks for new passwd.
+- * 0.6. root can reset user passwd to any values (it's only warned)
+- * 0.5. supports retries - 'retry=N' argument
+- * 0.4. added argument 'type=XXX' for 'New XXX password' prompt
+- * 0.3. Added argument 'debug'
+- * 0.2. new password is fed to cracklib for verify after typed once
+- * 0.1. First release
+- *
+- * Written by Cristian Gafton 1996/09/10
+- * Long password support by Philip W. Dalrymple 1997/07/18
+- * See the end of the file for Copyright Information
+- *
+- * Modification for long password systems (>8 chars). The original
+- * module had problems when used in a md5 password system in that it
+- * allowed too short passwords but required that at least half of the
+- * bytes in the new password did not appear in the old one. this
+- * action is still the default and the changes should not break any
+- * current user. This modification adds 6 new options, one to set the
+- * number of bytes in the new password that are not in the old one,
+- * the other five to control the length checking, these are all
+- * documented (or will be before anyone else sees this code) in the PAM
+- * S.A.G. in the section on the cracklib module.
+- */
+-
+-#include "config.h"
+-
+-#include
+-#ifdef HAVE_LIBXCRYPT
+-# include
+-#elif defined(HAVE_CRYPT_H)
+-# include
+-#endif
+-#include
+-#include
+-#include
+-#include
+-#include
+-#include
+-#include
+-#include
+-#include
+-#include
+-#include
+-
+-#ifdef HAVE_CRACK_H
+-#include
+-#else
+-extern char *FascistCheck(char *pw, const char *dictpath);
+-#endif
+-
+-#ifndef CRACKLIB_DICTS
+-#define CRACKLIB_DICTS NULL
+-#endif
+-
+-#ifdef MIN
+-#undef MIN
+-#endif
+-#define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b))
+-
+-#include
+-#include
+-#include
+-#include "pam_inline.h"
+-
+-/* argument parsing */
+-#define PAM_DEBUG_ARG 0x0001
+-
+-struct cracklib_options {
+- int retry_times;
+- int diff_ok;
+- int min_length;
+- int dig_credit;
+- int up_credit;
+- int low_credit;
+- int oth_credit;
+- int min_class;
+- int max_repeat;
+- int max_sequence;
+- int max_class_repeat;
+- int reject_user;
+- int gecos_check;
+- int enforce_for_root;
+- const char *cracklib_dictpath;
+-};
+-
+-#define CO_RETRY_TIMES 1
+-#define CO_DIFF_OK 5
+-#define CO_MIN_LENGTH 9
+-# define CO_MIN_LENGTH_BASE 5
+-#define CO_DIG_CREDIT 1
+-#define CO_UP_CREDIT 1
+-#define CO_LOW_CREDIT 1
+-#define CO_OTH_CREDIT 1
+-#define CO_MIN_WORD_LENGTH 4
+-
+-static int
+-_pam_parse (pam_handle_t *pamh, struct cracklib_options *opt,
+- int argc, const char **argv)
+-{
+- int ctrl=0;
+-
+- /* step through arguments */
+- for (ctrl=0; argc-- > 0; ++argv) {
+- const char *str;
+- char *ep = NULL;
+-
+- /* generic options */
+-
+- if (!strcmp(*argv,"debug"))
+- ctrl |= PAM_DEBUG_ARG;
+- else if ((str = pam_str_skip_prefix(*argv, "type=")) != NULL)
+- pam_set_item (pamh, PAM_AUTHTOK_TYPE, str);
+- else if ((str = pam_str_skip_prefix(*argv, "retry=")) != NULL) {
+- opt->retry_times = strtol(str, &ep, 10);
+- if (!ep || (opt->retry_times < 1))
+- opt->retry_times = CO_RETRY_TIMES;
+- } else if ((str = pam_str_skip_prefix(*argv, "difok=")) != NULL) {
+- opt->diff_ok = strtol(str, &ep, 10);
+- if (!ep || (opt->diff_ok < 0))
+- opt->diff_ok = CO_DIFF_OK;
+- } else if (pam_str_skip_prefix(*argv, "difignore=") != NULL) {
+- /* just ignore */
+- } else if ((str = pam_str_skip_prefix(*argv, "minlen=")) != NULL) {
+- opt->min_length = strtol(str, &ep, 10);
+- if (!ep || (opt->min_length < CO_MIN_LENGTH_BASE))
+- opt->min_length = CO_MIN_LENGTH_BASE;
+- } else if ((str = pam_str_skip_prefix(*argv, "dcredit=")) != NULL) {
+- opt->dig_credit = strtol(str, &ep, 10);
+- if (!ep)
+- opt->dig_credit = 0;
+- } else if ((str = pam_str_skip_prefix(*argv, "ucredit=")) != NULL) {
+- opt->up_credit = strtol(str, &ep, 10);
+- if (!ep)
+- opt->up_credit = 0;
+- } else if ((str = pam_str_skip_prefix(*argv, "lcredit=")) != NULL) {
+- opt->low_credit = strtol(str, &ep, 10);
+- if (!ep)
+- opt->low_credit = 0;
+- } else if ((str = pam_str_skip_prefix(*argv, "ocredit=")) != NULL) {
+- opt->oth_credit = strtol(str, &ep, 10);
+- if (!ep)
+- opt->oth_credit = 0;
+- } else if ((str = pam_str_skip_prefix(*argv, "minclass=")) != NULL) {
+- opt->min_class = strtol(str, &ep, 10);
+- if (!ep)
+- opt->min_class = 0;
+- if (opt->min_class > 4)
+- opt->min_class = 4;
+- } else if ((str = pam_str_skip_prefix(*argv, "maxrepeat=")) != NULL) {
+- opt->max_repeat = strtol(str, &ep, 10);
+- if (!ep)
+- opt->max_repeat = 0;
+- } else if ((str = pam_str_skip_prefix(*argv, "maxsequence=")) != NULL) {
+- opt->max_sequence = strtol(str, &ep, 10);
+- if (!ep)
+- opt->max_sequence = 0;
+- } else if ((str = pam_str_skip_prefix(*argv, "maxclassrepeat=")) != NULL) {
+- opt->max_class_repeat = strtol(str, &ep, 10);
+- if (!ep)
+- opt->max_class_repeat = 0;
+- } else if (!strcmp(*argv, "reject_username")) {
+- opt->reject_user = 1;
+- } else if (!strcmp(*argv, "gecoscheck")) {
+- opt->gecos_check = 1;
+- } else if (!strcmp(*argv, "enforce_for_root")) {
+- opt->enforce_for_root = 1;
+- } else if (pam_str_skip_prefix(*argv, "authtok_type=") != NULL) {
+- /* for pam_get_authtok, ignore */;
+- } else if (!strcmp(*argv, "use_authtok")) {
+- /* for pam_get_authtok, ignore */;
+- } else if (!strcmp(*argv, "use_first_pass")) {
+- /* for pam_get_authtok, ignore */;
+- } else if (!strcmp(*argv, "try_first_pass")) {
+- /* for pam_get_authtok, ignore */;
+- } else if ((str = pam_str_skip_prefix(*argv, "dictpath=")) != NULL) {
+- opt->cracklib_dictpath = str;
+- if (!*(opt->cracklib_dictpath)) {
+- opt->cracklib_dictpath = CRACKLIB_DICTS;
+- }
+- } else {
+- pam_syslog(pamh,LOG_ERR,"pam_parse: unknown option; %s",*argv);
+- }
+- }
+-
+- return ctrl;
+-}
+-
+-/* Helper functions */
+-
+-/*
+- * can't be a palindrome - like `R A D A R' or `M A D A M'
+- */
+-static int palindrome(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;
+-}
+-
+-/*
+- * Calculate how different two strings are in terms of the number of
+- * character removals, additions, and changes needed to go from one to
+- * the other
+- */
+-
+-static int distdifferent(const char *old, const char *new,
+- size_t i, size_t j)
+-{
+- char c, d;
+-
+- if ((i == 0) || (strlen(old) < i)) {
+- c = 0;
+- } else {
+- c = old[i - 1];
+- }
+- if ((j == 0) || (strlen(new) < j)) {
+- d = 0;
+- } else {
+- d = new[j - 1];
+- }
+- return (c != d);
+-}
+-
+-static int distcalculate(int **distances, const char *old, const char *new,
+- size_t i, size_t j)
+-{
+- int tmp = 0;
+-
+- if (distances[i][j] != -1) {
+- return distances[i][j];
+- }
+-
+- tmp = distcalculate(distances, old, new, i - 1, j - 1);
+- tmp = MIN(tmp, distcalculate(distances, old, new, i, j - 1));
+- tmp = MIN(tmp, distcalculate(distances, old, new, i - 1, j));
+- tmp += distdifferent(old, new, i, j);
+-
+- distances[i][j] = tmp;
+-
+- return tmp;
+-}
+-
+-static int distance(const char *old, const char *new)
+-{
+- int **distances = NULL;
+- size_t m, n, i, j, r;
+-
+- m = strlen(old);
+- n = strlen(new);
+- distances = malloc(sizeof(int*) * (m + 1));
+-
+- for (i = 0; i <= m; i++) {
+- distances[i] = malloc(sizeof(int) * (n + 1));
+- for(j = 0; j <= n; j++) {
+- distances[i][j] = -1;
+- }
+- }
+- for (i = 0; i <= m; i++) {
+- distances[i][0] = i;
+- }
+- for (j = 0; j <= n; j++) {
+- distances[0][j] = j;
+- }
+- distances[0][0] = 0;
+-
+- r = distcalculate(distances, old, new, m, n);
+-
+- for (i = 0; i <= m; i++) {
+- memset(distances[i], 0, sizeof(int) * (n + 1));
+- free(distances[i]);
+- }
+- free(distances);
+-
+- return r;
+-}
+-
+-static int similar(struct cracklib_options *opt,
+- const char *old, const char *new)
+-{
+- if (distance(old, new) >= opt->diff_ok) {
+- return 0;
+- }
+-
+- if (strlen(new) >= (strlen(old) * 2)) {
+- return 0;
+- }
+-
+- /* passwords are too similar */
+- return 1;
+-}
+-
+-/*
+- * enough classes of characters
+- */
+-
+-static int minclass (struct cracklib_options *opt,
+- const char *new)
+-{
+- int digits = 0;
+- int uppers = 0;
+- int lowers = 0;
+- int others = 0;
+- int total_class;
+- int i;
+- int retval;
+-
+- D(( "called" ));
+- for (i = 0; new[i]; i++)
+- {
+- if (isdigit (new[i]))
+- digits = 1;
+- else if (isupper (new[i]))
+- uppers = 1;
+- else if (islower (new[i]))
+- lowers = 1;
+- else
+- others = 1;
+- }
+-
+- total_class = digits + uppers + lowers + others;
+-
+- D (("total class: %d\tmin_class: %d", total_class, opt->min_class));
+-
+- if (total_class >= opt->min_class)
+- retval = 0;
+- else
+- retval = 1;
+-
+- return retval;
+-}
+-
+-
+-/*
+- * a nice mix of characters.
+- */
+-static int simple(struct cracklib_options *opt, const char *new)
+-{
+- int digits = 0;
+- int uppers = 0;
+- int lowers = 0;
+- int others = 0;
+- int size;
+- int i;
+- enum { NONE, DIGIT, UCASE, LCASE, OTHER } prevclass = NONE;
+- int sameclass = 0;
+-
+- for (i = 0;new[i];i++) {
+- if (isdigit (new[i])) {
+- digits++;
+- if (prevclass != DIGIT) {
+- prevclass = DIGIT;
+- sameclass = 1;
+- } else
+- sameclass++;
+- }
+- else if (isupper (new[i])) {
+- uppers++;
+- if (prevclass != UCASE) {
+- prevclass = UCASE;
+- sameclass = 1;
+- } else
+- sameclass++;
+- }
+- else if (islower (new[i])) {
+- lowers++;
+- if (prevclass != LCASE) {
+- prevclass = LCASE;
+- sameclass = 1;
+- } else
+- sameclass++;
+- }
+- else {
+- others++;
+- if (prevclass != OTHER) {
+- prevclass = OTHER;
+- sameclass = 1;
+- } else
+- sameclass++;
+- }
+- if (opt->max_class_repeat > 0 && sameclass > opt->max_class_repeat) {
+- return 1;
+- }
+- }
+-
+- /*
+- * The scam was this - a password of only one character type
+- * must be 8 letters long. Two types, 7, and so on.
+- * This is now changed, the base size and the credits or defaults
+- * see the docs on the module for info on these parameters, the
+- * defaults cause the effect to be the same as before the change
+- */
+-
+- if ((opt->dig_credit >= 0) && (digits > opt->dig_credit))
+- digits = opt->dig_credit;
+-
+- if ((opt->up_credit >= 0) && (uppers > opt->up_credit))
+- uppers = opt->up_credit;
+-
+- if ((opt->low_credit >= 0) && (lowers > opt->low_credit))
+- lowers = opt->low_credit;
+-
+- if ((opt->oth_credit >= 0) && (others > opt->oth_credit))
+- others = opt->oth_credit;
+-
+- size = opt->min_length;
+-
+- if (opt->dig_credit >= 0)
+- size -= digits;
+- else if (digits < opt->dig_credit * -1)
+- return 1;
+-
+- if (opt->up_credit >= 0)
+- size -= uppers;
+- else if (uppers < opt->up_credit * -1)
+- return 1;
+-
+- if (opt->low_credit >= 0)
+- size -= lowers;
+- else if (lowers < opt->low_credit * -1)
+- return 1;
+-
+- if (opt->oth_credit >= 0)
+- size -= others;
+- else if (others < opt->oth_credit * -1)
+- return 1;
+-
+- if (size <= i)
+- return 0;
+-
+- return 1;
+-}
+-
+-static int consecutive(struct cracklib_options *opt, const char *new)
+-{
+- char c;
+- int i;
+- int same;
+-
+- if (opt->max_repeat == 0)
+- return 0;
+-
+- for (i = 0; new[i]; i++) {
+- if (i > 0 && new[i] == c) {
+- ++same;
+- if (same > opt->max_repeat)
+- return 1;
+- } else {
+- c = new[i];
+- same = 1;
+- }
+- }
+- return 0;
+-}
+-
+-static int sequence(struct cracklib_options *opt, const char *new)
+-{
+- char c;
+- int i;
+- int sequp = 1;
+- int seqdown = 1;
+-
+- if (opt->max_sequence == 0)
+- return 0;
+-
+- if (new[0] == '\0')
+- return 0;
+-
+- for (i = 1; new[i]; i++) {
+- c = new[i-1];
+- if (new[i] == c+1) {
+- ++sequp;
+- if (sequp > opt->max_sequence)
+- return 1;
+- seqdown = 1;
+- } else if (new[i] == c-1) {
+- ++seqdown;
+- if (seqdown > opt->max_sequence)
+- return 1;
+- sequp = 1;
+- } else {
+- sequp = 1;
+- seqdown = 1;
+- }
+- }
+- return 0;
+-}
+-
+-static int wordcheck(const char *new, char *word)
+-{
+- char *f, *b;
+-
+- if (strstr(new, word) != NULL)
+- return 1;
+-
+- /* now reverse the word, we can do that in place
+- as it is strdup-ed */
+- f = word;
+- b = word+strlen(word)-1;
+- while (f < b) {
+- char c;
+-
+- c = *f;
+- *f = *b;
+- *b = c;
+- --b;
+- ++f;
+- }
+-
+- if (strstr(new, word) != NULL)
+- return 1;
+- return 0;
+-}
+-
+-static int usercheck(struct cracklib_options *opt, const char *new,
+- char *user)
+-{
+- if (!opt->reject_user)
+- return 0;
+-
+- return wordcheck(new, user);
+-}
+-
+-static char * str_lower(char *string)
+-{
+- char *cp;
+-
+- if (!string)
+- return NULL;
+-
+- for (cp = string; *cp; cp++)
+- *cp = tolower(*cp);
+- return string;
+-}
+-
+-static int gecoscheck(pam_handle_t *pamh, struct cracklib_options *opt, const char *new,
+- const char *user)
+-{
+- struct passwd *pwd;
+- char *list;
+- char *p;
+- char *next;
+-
+- if (!opt->gecos_check)
+- return 0;
+-
+- if ((pwd = pam_modutil_getpwnam(pamh, user)) == NULL) {
+- return 0;
+- }
+-
+- list = strdup(pwd->pw_gecos);
+-
+- if (list == NULL || *list == '\0') {
+- free(list);
+- return 0;
+- }
+-
+- for (p = list;;p = next + 1) {
+- next = strchr(p, ' ');
+- if (next)
+- *next = '\0';
+-
+- if (strlen(p) >= CO_MIN_WORD_LENGTH) {
+- str_lower(p);
+- if (wordcheck(new, p)) {
+- free(list);
+- return 1;
+- }
+- }
+-
+- if (!next)
+- break;
+- }
+-
+- free(list);
+- return 0;
+-}
+-
+-static const char *password_check(pam_handle_t *pamh, struct cracklib_options *opt,
+- const char *old, const char *new,
+- const char *user)
+-{
+- const char *msg = NULL;
+- char *oldmono = NULL, *newmono, *wrapped = NULL;
+- char *usermono = NULL;
+-
+- if (old && strcmp(new, old) == 0) {
+- msg = _("is the same as the old one");
+- return msg;
+- }
+-
+- newmono = str_lower(strdup(new));
+- if (!newmono)
+- msg = _("memory allocation error");
+-
+- usermono = str_lower(strdup(user));
+- if (!usermono)
+- msg = _("memory allocation error");
+-
+- if (!msg && old) {
+- oldmono = str_lower(strdup(old));
+- if (oldmono)
+- wrapped = malloc(strlen(oldmono) * 2 + 1);
+- if (wrapped) {
+- strcpy (wrapped, oldmono);
+- strcat (wrapped, oldmono);
+- } else {
+- msg = _("memory allocation error");
+- }
+- }
+-
+- if (!msg && palindrome(newmono))
+- msg = _("is a palindrome");
+-
+- if (!msg && oldmono && strcmp(oldmono, newmono) == 0)
+- msg = _("case changes only");
+-
+- if (!msg && oldmono && similar(opt, oldmono, newmono))
+- msg = _("is too similar to the old one");
+-
+- if (!msg && simple(opt, new))
+- msg = _("is too simple");
+-
+- if (!msg && wrapped && strstr(wrapped, newmono))
+- msg = _("is rotated");
+-
+- if (!msg && minclass (opt, new))
+- msg = _("not enough character classes");
+-
+- if (!msg && consecutive(opt, new))
+- msg = _("contains too many same characters consecutively");
+-
+- if (!msg && sequence(opt, new))
+- msg = _("contains too long of a monotonic character sequence");
+-
+- if (!msg && (usercheck(opt, newmono, usermono) || gecoscheck(pamh, opt, newmono, user)))
+- msg = _("contains the user name in some form");
+-
+- free(usermono);
+- if (newmono) {
+- memset(newmono, 0, strlen(newmono));
+- free(newmono);
+- }
+- if (oldmono) {
+- memset(oldmono, 0, strlen(oldmono));
+- free(oldmono);
+- }
+- if (wrapped) {
+- memset(wrapped, 0, strlen(wrapped));
+- free(wrapped);
+- }
+-
+- return msg;
+-}
+-
+-
+-static int _pam_unix_approve_pass(pam_handle_t *pamh,
+- unsigned int ctrl,
+- struct cracklib_options *opt,
+- const char *pass_old,
+- const char *pass_new)
+-{
+- const char *msg = NULL;
+- const char *user;
+- int retval;
+-
+- if (pass_new == NULL || (pass_old && !strcmp(pass_old,pass_new))) {
+- if (ctrl & PAM_DEBUG_ARG)
+- pam_syslog(pamh, LOG_DEBUG, "bad authentication token");
+- pam_error(pamh, "%s", pass_new == NULL ?
+- _("No password has been supplied.") :
+- _("The password has not been changed."));
+- return PAM_AUTHTOK_ERR;
+- }
+-
+- retval = pam_get_user(pamh, &user, NULL);
+- if (retval != PAM_SUCCESS) {
+- if (ctrl & PAM_DEBUG_ARG)
+- pam_syslog(pamh, LOG_NOTICE, "cannot determine user name: %s",
+- pam_strerror(pamh, retval));
+- return PAM_AUTHTOK_ERR;
+- }
+- /*
+- * if one wanted to hardwire authentication token strength
+- * checking this would be the place
+- */
+- msg = password_check(pamh, opt, pass_old, pass_new, user);
+-
+- if (msg) {
+- if (ctrl & PAM_DEBUG_ARG)
+- pam_syslog(pamh, LOG_NOTICE,
+- "new passwd fails strength check: %s", msg);
+- pam_error(pamh, _("BAD PASSWORD: %s"), msg);
+- return PAM_AUTHTOK_ERR;
+- };
+- return PAM_SUCCESS;
+-
+-}
+-
+-/* The Main Thing (by Cristian Gafton, CEO at this module :-)
+- * (stolen from http://home.netscape.com)
+- */
+-int
+-pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
+-{
+- unsigned int ctrl;
+- struct cracklib_options options;
+-
+- D(("called."));
+-
+- memset(&options, 0, sizeof(options));
+- options.retry_times = CO_RETRY_TIMES;
+- options.diff_ok = CO_DIFF_OK;
+- options.min_length = CO_MIN_LENGTH;
+- options.dig_credit = CO_DIG_CREDIT;
+- options.up_credit = CO_UP_CREDIT;
+- options.low_credit = CO_LOW_CREDIT;
+- options.oth_credit = CO_OTH_CREDIT;
+- options.cracklib_dictpath = CRACKLIB_DICTS;
+-
+- ctrl = _pam_parse(pamh, &options, argc, argv);
+-
+- if (flags & PAM_PRELIM_CHECK) {
+- /* Check for passwd dictionary */
+- /* We cannot do that, since the original path is compiled
+- into the cracklib library and we don't know it. */
+- return PAM_SUCCESS;
+- } else if (flags & PAM_UPDATE_AUTHTOK) {
+- int retval;
+- const void *oldtoken;
+- int tries;
+-
+- D(("do update"));
+-
+-
+- retval = pam_get_item (pamh, PAM_OLDAUTHTOK, &oldtoken);
+- if (retval != PAM_SUCCESS) {
+- if (ctrl & PAM_DEBUG_ARG)
+- pam_syslog(pamh,LOG_ERR,"Can not get old passwd");
+- oldtoken = NULL;
+- }
+-
+- tries = 0;
+- while (tries < options.retry_times) {
+- const char *crack_msg;
+- const char *newtoken = NULL;
+-
+-
+- tries++;
+-
+- /* Planned modus operandi:
+- * Get a passwd.
+- * Verify it against cracklib.
+- * If okay get it a second time.
+- * Check to be the same with the first one.
+- * set PAM_AUTHTOK and return
+- */
+-
+- retval = pam_get_authtok_noverify (pamh, &newtoken, NULL);
+- if (retval != PAM_SUCCESS) {
+- pam_syslog(pamh, LOG_ERR, "pam_get_authtok_noverify returned error: %s",
+- pam_strerror (pamh, retval));
+- continue;
+- } else if (newtoken == NULL) { /* user aborted password change, quit */
+- return PAM_AUTHTOK_ERR;
+- }
+-
+- D(("testing password"));
+- /* now test this passwd against cracklib */
+-
+- D(("against cracklib"));
+- if ((crack_msg = FascistCheck (newtoken, options.cracklib_dictpath))) {
+- if (ctrl & PAM_DEBUG_ARG)
+- pam_syslog(pamh,LOG_DEBUG,"bad password: %s",crack_msg);
+- pam_error (pamh, _("BAD PASSWORD: %s"), crack_msg);
+- if (getuid() || options.enforce_for_root || (flags & PAM_CHANGE_EXPIRED_AUTHTOK))
+- {
+- pam_set_item (pamh, PAM_AUTHTOK, NULL);
+- retval = PAM_AUTHTOK_ERR;
+- continue;
+- }
+- }
+-
+- /* check it for strength too... */
+- D(("for strength"));
+- retval = _pam_unix_approve_pass (pamh, ctrl, &options,
+- oldtoken, newtoken);
+- if (retval != PAM_SUCCESS) {
+- if (getuid() || options.enforce_for_root || (flags & PAM_CHANGE_EXPIRED_AUTHTOK))
+- {
+- pam_set_item(pamh, PAM_AUTHTOK, NULL);
+- retval = PAM_AUTHTOK_ERR;
+- continue;
+- }
+- }
+-
+- retval = pam_get_authtok_verify (pamh, &newtoken, NULL);
+- if (retval != PAM_SUCCESS) {
+- pam_syslog(pamh, LOG_ERR, "pam_get_authtok_verify returned error: %s",
+- pam_strerror (pamh, retval));
+- pam_set_item(pamh, PAM_AUTHTOK, NULL);
+- continue;
+- } else if (newtoken == NULL) { /* user aborted password change, quit */
+- return PAM_AUTHTOK_ERR;
+- }
+-
+- return PAM_SUCCESS;
+- }
+-
+- D(("returning because maxtries reached"));
+-
+- pam_set_item (pamh, PAM_AUTHTOK, NULL);
+-
+- /* if we have only one try, we can use the real reason,
+- else say that there were too many tries. */
+- if (options.retry_times > 1)
+- return PAM_MAXTRIES;
+- else
+- return retval;
+-
+- } else {
+- if (ctrl & PAM_DEBUG_ARG)
+- pam_syslog(pamh, LOG_NOTICE, "UNKNOWN flags setting %02X",flags);
+- return PAM_SERVICE_ERR;
+- }
+-
+- /* Not reached */
+- return PAM_SERVICE_ERR;
+-}
+-
+-
+-
+-/*
+- * Copyright (c) Cristian Gafton , 1996.
+- * 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.
+- *
+- * The following copyright was appended for the long password support
+- * added with the libpam 0.58 release:
+- *
+- * Modificaton Copyright (c) Philip W. Dalrymple III
+- * 1997. All rights reserved
+- *
+- * THE MODIFICATION THAT PROVIDES SUPPORT FOR LONG PASSWORD TYPE CHECKING TO
+- * 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.
+- */
+diff --git a/modules/pam_cracklib/tst-pam_cracklib b/modules/pam_cracklib/tst-pam_cracklib
+deleted file mode 100755
+index 46a7060d..00000000
+--- a/modules/pam_cracklib/tst-pam_cracklib
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#!/bin/sh
+-../../tests/tst-dlopen .libs/pam_cracklib.so
diff --git a/pam_tally2-removal.patch b/pam_tally2-removal.patch
new file mode 100644
index 0000000..59fc8dc
--- /dev/null
+++ b/pam_tally2-removal.patch
@@ -0,0 +1,1332 @@
+From 709e37b7e131d35b0ec30d31f858bc6917dd2b2e Mon Sep 17 00:00:00 2001
+From: "Dmitry V. Levin"
+Date: Thu, 29 Oct 2020 08:00:00 +0000
+Subject: [PATCH] Remove deprecated pam_tally and pam_tally2 modules
+
+* ci/run-build-and-tests.sh (DISTCHECK_CONFIGURE_FLAGS): Remove
+--enable-tally --enable-tally2.
+* configure.ac: Remove --enable-tally and --enable-tally2 options.
+(AM_CONDITIONAL): Remove COND_BUILD_PAM_TALLY and COND_BUILD_PAM_TALLY2.
+(AC_CONFIG_FILES): Remove modules/pam_tally/Makefile and
+modules/pam_tally2/Makefile.
+* doc/sag/pam_tally.xml: Remove.
+* doc/sag/pam_tally2.xml: Likewise.
+* doc/sag/Linux-PAM_SAG.xml: Do not include pam_tally.xml and
+pam_tally2.xml.
+* modules/Makefile.am (MAYBE_PAM_TALLY, MAYBE_PAM_TALLY2): Remove.
+(SUBDIRS): Remove MAYBE_PAM_TALLY and MAYBE_PAM_TALLY2.
+* modules/pam_tally/.gitignore: Remove.
+* modules/pam_tally/Makefile.am: Likewise.
+* modules/pam_tally/README.xml: Likewise.
+* modules/pam_tally/faillog.h: Likewise.
+* modules/pam_tally/pam_tally.8.xml: Likewise.
+* modules/pam_tally/pam_tally.c: Likewise.
+* modules/pam_tally/pam_tally_app.c: Likewise.
+* modules/pam_tally/tst-pam_tally: Likewise.
+* modules/pam_tally2/.gitignore: Likewise.
+* modules/pam_tally2/Makefile.am: Likewise.
+* modules/pam_tally2/README.xml: Likewise.
+* modules/pam_tally2/pam_tally2.8.xml: Likewise.
+* modules/pam_tally2/pam_tally2.c: Likewise.
+* modules/pam_tally2/pam_tally2_app.c: Likewise.
+* modules/pam_tally2/tallylog.h: Likewise.
+* modules/pam_tally2/tst-pam_tally2: Likewise.
+* modules/pam_timestamp/pam_timestamp_check.8.xml: Fix typo by replacing
+pam_tally with pam_timestamp.
+* po/POTFILES.in: Remove ./modules/pam_tally/pam_tally_app.c,
+./modules/pam_tally/pam_tally.c, ./modules/pam_tally2/pam_tally2_app.c,
+and ./modules/pam_tally2/pam_tally2.c.
+* NEWS: Document this change.
+---
+ NEWS | 1 +
+ ci/run-build-and-tests.sh | 2 +-
+ configure.ac | 23 +-
+ doc/sag/Linux-PAM_SAG.xml | 4 -
+ doc/sag/pam_tally.xml | 38 -
+ doc/sag/pam_tally2.xml | 46 -
+ modules/Makefile.am | 10 -
+ modules/pam_tally/.gitignore | 1 -
+ modules/pam_tally/Makefile.am | 41 -
+ modules/pam_tally/README.xml | 41 -
+ modules/pam_tally/faillog.h | 55 -
+ modules/pam_tally/pam_tally.8.xml | 459 --------
+ modules/pam_tally/pam_tally.c | 854 --------------
+ modules/pam_tally/pam_tally_app.c | 6 -
+ modules/pam_tally/tst-pam_tally | 2 -
+ modules/pam_tally2/.gitignore | 1 -
+ modules/pam_tally2/Makefile.am | 45 -
+ modules/pam_tally2/README.xml | 46 -
+ modules/pam_tally2/pam_tally2.8.xml | 450 -------
+ modules/pam_tally2/pam_tally2.c | 1036 -----------------
+ modules/pam_tally2/pam_tally2_app.c | 6 -
+ modules/pam_tally2/tallylog.h | 52 -
+ modules/pam_tally2/tst-pam_tally2 | 2 -
+ .../pam_timestamp/pam_timestamp_check.8.xml | 2 +-
+ po/POTFILES.in | 4 -
+ 25 files changed, 4 insertions(+), 3223 deletions(-)
+ delete mode 100644 doc/sag/pam_tally.xml
+ delete mode 100644 doc/sag/pam_tally2.xml
+ delete mode 100644 modules/pam_tally/.gitignore
+ delete mode 100644 modules/pam_tally/Makefile.am
+ delete mode 100644 modules/pam_tally/README.xml
+ delete mode 100644 modules/pam_tally/faillog.h
+ delete mode 100644 modules/pam_tally/pam_tally.8.xml
+ delete mode 100644 modules/pam_tally/pam_tally.c
+ delete mode 100644 modules/pam_tally/pam_tally_app.c
+ delete mode 100755 modules/pam_tally/tst-pam_tally
+ delete mode 100644 modules/pam_tally2/.gitignore
+ delete mode 100644 modules/pam_tally2/Makefile.am
+ delete mode 100644 modules/pam_tally2/README.xml
+ delete mode 100644 modules/pam_tally2/pam_tally2.8.xml
+ delete mode 100644 modules/pam_tally2/pam_tally2.c
+ delete mode 100644 modules/pam_tally2/pam_tally2_app.c
+ delete mode 100644 modules/pam_tally2/tallylog.h
+ delete mode 100755 modules/pam_tally2/tst-pam_tally2
+
+diff --git a/configure.ac b/configure.ac
+index 4397124d..ad36a6bc 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -613,24 +613,6 @@ test -n "$opt_kerneloverflowuid" ||
+ opt_kerneloverflowuid=65534
+ AC_DEFINE_UNQUOTED(PAM_USERTYPE_OVERFLOW_UID, $opt_kerneloverflowuid, [Kernel overflow uid.])
+
+-#AC_ARG_ENABLE([tally],
+-# [AS_HELP_STRING([--enable-tally],
+-# [build deprecated pam_tally module])],
+-# [], [enable_tally=no])
+-#case "$enable_tally" in
+-# yes|no) ;;
+-# *) AC_MSG_ERROR([bad value $enable_tally for --enable-tally option]) ;;
+-#esac
+-
+-AC_ARG_ENABLE([tally2],
+- [AS_HELP_STRING([--enable-tally2],
+- [build deprecated pam_tally2 module])],
+- [], [enable_tally2=no])
+-case "$enable_tally2" in
+- yes|no) ;;
+- *) AC_MSG_ERROR([bad value $enable_tally2 for --enable-tally2 option]) ;;
+-esac
+-
+ AC_ARG_ENABLE([unix],
+ [AS_HELP_STRING([--disable-unix],
+ [do not build pam_unix module])],
+@@ -647,8 +629,6 @@ AM_CONDITIONAL([COND_BUILD_PAM_RHOSTS], [test "$ac_cv_func_ruserok_af" = yes -o
+ AM_CONDITIONAL([COND_BUILD_PAM_SELINUX], [test -n "$LIBSELINUX"])
+ AM_CONDITIONAL([COND_BUILD_PAM_SEPERMIT], [test -n "$LIBSELINUX"])
+ AM_CONDITIONAL([COND_BUILD_PAM_SETQUOTA], [test "$ac_cv_func_quotactl" = yes])
+-#AM_CONDITIONAL([COND_BUILD_PAM_TALLY], [test "$enable_tally" = yes])
+-AM_CONDITIONAL([COND_BUILD_PAM_TALLY2], [test "$enable_tally2" = yes])
+ AM_CONDITIONAL([COND_BUILD_PAM_TTY_AUDIT], [test "$HAVE_AUDIT_TTY_STATUS" = yes])
+ AM_CONDITIONAL([COND_BUILD_PAM_UNIX], [test "$enable_unix" = yes])
+ AM_CONDITIONAL([COND_BUILD_PAM_USERDB], [test -n "$LIBDB"])
+@@ -678,8 +658,7 @@ AC_CONFIG_FILES([Makefile libpam/Makefile libpamc/Makefile libpamc/test/Makefile
+ modules/pam_securetty/Makefile modules/pam_selinux/Makefile \
+ modules/pam_sepermit/Makefile modules/pam_setquota/Makefile \
+ modules/pam_shells/Makefile modules/pam_stress/Makefile \
+- modules/pam_succeed_if/Makefile \
+- modules/pam_tally2/Makefile modules/pam_time/Makefile \
++ modules/pam_succeed_if/Makefile modules/pam_time/Makefile \
+ modules/pam_timestamp/Makefile modules/pam_tty_audit/Makefile \
+ modules/pam_umask/Makefile \
+ modules/pam_unix/Makefile modules/pam_userdb/Makefile \
+diff --git a/modules/Makefile.am b/modules/Makefile.am
+index aa03e319..8da46410 100644
+--- a/modules/Makefile.am
++++ b/modules/Makefile.am
+@@ -30,14 +30,6 @@ if COND_BUILD_PAM_SETQUOTA
+ MAYBE_PAM_SETQUOTA = pam_setquota
+ endif
+
+-#if COND_BUILD_PAM_TALLY
+-# MAYBE_PAM_TALLY = pam_tally
+-#endif
+-
+-if COND_BUILD_PAM_TALLY2
+- MAYBE_PAM_TALLY2 = pam_tally2
+-endif
+-
+ if COND_BUILD_PAM_TTY_AUDIT
+ MAYBE_PAM_TTY_AUDIT = pam_tty_audit
+ endif
+@@ -85,8 +77,6 @@ SUBDIRS := \
+ pam_shells \
+ pam_stress \
+ pam_succeed_if \
+- $(MAYBE_PAM_TALLY) \
+- $(MAYBE_PAM_TALLY2) \
+ pam_time \
+ pam_timestamp \
+ $(MAYBE_PAM_TTY_AUDIT) \
+diff --git a/modules/pam_tally2/Makefile.am b/modules/pam_tally2/Makefile.am
+deleted file mode 100644
+index 9ca7eabf..00000000
+--- a/modules/pam_tally2/Makefile.am
++++ /dev/null
+@@ -1,45 +0,0 @@
+-#
+-# Copyright (c) 2005, 2006, 2007, 2009 Thorsten Kukuk
+-# Copyright (c) 2008 Red Hat, Inc.
+-#
+-
+-CLEANFILES = *~
+-MAINTAINERCLEANFILES = $(MANS) README
+-
+-EXTRA_DIST = $(XMLS)
+-
+-#if HAVE_DOC
+-#dist_man_MANS = pam_tally2.8
+-#endif
+-XMLS = README.xml pam_tally2.8.xml
+-dist_check_SCRIPTS = tst-pam_tally2
+-TESTS = $(dist_check_SCRIPTS)
+-
+-securelibdir = $(SECUREDIR)
+-secureconfdir = $(SCONFIGDIR)
+-
+-noinst_HEADERS = tallylog.h
+-
+-AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \
+- $(WARN_CFLAGS)
+-
+-pam_tally2_la_LDFLAGS = -no-undefined -avoid-version -module
+-pam_tally2_la_LIBADD = $(top_builddir)/libpam/libpam.la $(LIBAUDIT)
+-if HAVE_VERSIONING
+- pam_tally2_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map
+-endif
+-
+-pam_tally2_CFLAGS = $(AM_CFLAGS) @EXE_CFLAGS@
+-pam_tally2_LDFLAGS = @EXE_LDFLAGS@
+-pam_tally2_LDADD = $(top_builddir)/libpam/libpam.la $(LIBAUDIT)
+-
+-securelib_LTLIBRARIES = pam_tally2.la
+-sbin_PROGRAMS = pam_tally2
+-
+-pam_tally2_la_SOURCES = pam_tally2.c
+-pam_tally2_SOURCES = pam_tally2_app.c
+-
+-if ENABLE_REGENERATE_MAN
+-dist_noinst_DATA = README
+--include $(top_srcdir)/Make.xml.rules
+-endif
+diff --git a/modules/pam_tally2/pam_tally2.c b/modules/pam_tally2/pam_tally2.c
+deleted file mode 100644
+index bcf3188c..00000000
+--- a/modules/pam_tally2/pam_tally2.c
++++ /dev/null
+@@ -1,1036 +0,0 @@
+-/*
+- * pam_tally2 module
+- *
+- * By Tim Baverstock , Multi Media Machine Ltd.
+- * 5 March 1997
+- *
+- * Stuff stolen from pam_rootok and pam_listfile
+- *
+- * Changes by Tomas Mraz 5 January 2005, 26 January 2006
+- * Audit option added for Tomas patch by Sebastien Tricaud 13 January 2005
+- * Portions Copyright 2006, Red Hat, Inc.
+- * Portions Copyright 1989 - 1993, 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"
+-
+-#if defined(MAIN) && defined(MEMORY_DEBUG)
+-# undef exit
+-#endif /* defined(MAIN) && defined(MEMORY_DEBUG) */
+-
+-#include
+-#include
+-#include
+-#include
+-#include
+-#include
+-#include
+-#include
+-#include
+-#include
+-#ifdef HAVE_LIBAUDIT
+-#include
+-#endif
+-
+-#include
+-#include
+-#include
+-#include
+-#include
+-#include "tallylog.h"
+-
+-#ifndef TRUE
+-#define TRUE 1L
+-#define FALSE 0L
+-#endif
+-
+-#ifndef HAVE_FSEEKO
+-#define fseeko fseek
+-#endif
+-
+-#ifndef MAIN
+-#include
+-#endif
+-#include
+-#include
+-#include "pam_inline.h"
+-
+-/*---------------------------------------------------------------------*/
+-
+-#define DEFAULT_LOGFILE "/var/log/tallylog"
+-#define MODULE_NAME "pam_tally2"
+-
+-#define tally_t uint16_t
+-#define TALLY_HI ((tally_t)~0L)
+-
+-struct tally_options {
+- const char *filename;
+- tally_t deny;
+- long lock_time;
+- long unlock_time;
+- long root_unlock_time;
+- unsigned int ctrl;
+-};
+-
+-#define PHASE_UNKNOWN 0
+-#define PHASE_AUTH 1
+-#define PHASE_ACCOUNT 2
+-#define PHASE_SESSION 3
+-
+-#define OPT_MAGIC_ROOT 01
+-#define OPT_FAIL_ON_ERROR 02
+-#define OPT_DENY_ROOT 04
+-#define OPT_QUIET 040
+-#define OPT_AUDIT 0100
+-#define OPT_NOLOGNOTICE 0400
+-#define OPT_SERIALIZE 01000
+-#define OPT_DEBUG 02000
+-
+-#define MAX_LOCK_WAITING_TIME 10
+-
+-/*---------------------------------------------------------------------*/
+-
+-/* some syslogging */
+-
+-#ifdef MAIN
+-#define pam_syslog tally_log
+-static void
+-PAM_FORMAT((printf, 3, 4))
+-tally_log (const pam_handle_t *pamh UNUSED, int priority UNUSED,
+- const char *fmt, ...)
+-{
+- va_list args;
+-
+- va_start(args, fmt);
+- fprintf(stderr, "%s: ", MODULE_NAME);
+- vfprintf(stderr, fmt, args);
+- fprintf(stderr,"\n");
+- va_end(args);
+-}
+-
+-#define pam_modutil_getpwnam(pamh, user) getpwnam(user)
+-#endif
+-
+-/*---------------------------------------------------------------------*/
+-
+-/* --- Support function: parse arguments --- */
+-
+-#ifndef MAIN
+-
+-static void
+-log_phase_no_auth(pam_handle_t *pamh, int phase, const char *argv)
+-{
+- if ( phase != PHASE_AUTH ) {
+- pam_syslog(pamh, LOG_ERR,
+- "option %s allowed in auth phase only", argv);
+- }
+-}
+-
+-static int
+-tally_parse_args(pam_handle_t *pamh, struct tally_options *opts,
+- int phase, int argc, const char **argv)
+-{
+- memset(opts, 0, sizeof(*opts));
+- opts->filename = DEFAULT_LOGFILE;
+- opts->ctrl = OPT_FAIL_ON_ERROR;
+- opts->root_unlock_time = -1;
+-
+- for ( ; argc-- > 0; ++argv ) {
+- const char *str;
+-
+- if ((str = pam_str_skip_prefix(*argv, "file=")) != NULL) {
+- const char *from = str;
+- if ( *from!='/' ) {
+- pam_syslog(pamh, LOG_ERR,
+- "filename not /rooted; %s", *argv);
+- return PAM_AUTH_ERR;
+- }
+- opts->filename = from;
+- }
+- else if ( ! strcmp( *argv, "onerr=fail" ) ) {
+- opts->ctrl |= OPT_FAIL_ON_ERROR;
+- }
+- else if ( ! strcmp( *argv, "onerr=succeed" ) ) {
+- opts->ctrl &= ~OPT_FAIL_ON_ERROR;
+- }
+- else if ( ! strcmp( *argv, "magic_root" ) ) {
+- opts->ctrl |= OPT_MAGIC_ROOT;
+- }
+- else if ( ! strcmp( *argv, "serialize" ) ) {
+- opts->ctrl |= OPT_SERIALIZE;
+- }
+- else if ( ! strcmp( *argv, "debug" ) ) {
+- opts->ctrl |= OPT_DEBUG;
+- }
+- else if ( ! strcmp( *argv, "even_deny_root_account" ) ||
+- ! strcmp( *argv, "even_deny_root" ) ) {
+- log_phase_no_auth(pamh, phase, *argv);
+- opts->ctrl |= OPT_DENY_ROOT;
+- }
+- else if ((str = pam_str_skip_prefix(*argv, "deny=")) != NULL) {
+- log_phase_no_auth(pamh, phase, *argv);
+- if (sscanf(str, "%hu", &opts->deny) != 1) {
+- pam_syslog(pamh, LOG_ERR, "bad number supplied: %s", *argv);
+- return PAM_AUTH_ERR;
+- }
+- }
+- else if ((str = pam_str_skip_prefix(*argv, "lock_time=")) != NULL) {
+- log_phase_no_auth(pamh, phase, *argv);
+- if (sscanf(str, "%ld", &opts->lock_time) != 1) {
+- pam_syslog(pamh, LOG_ERR, "bad number supplied: %s", *argv);
+- return PAM_AUTH_ERR;
+- }
+- }
+- else if ((str = pam_str_skip_prefix(*argv, "unlock_time=")) != NULL) {
+- log_phase_no_auth(pamh, phase, *argv);
+- if (sscanf(str, "%ld", &opts->unlock_time) != 1) {
+- pam_syslog(pamh, LOG_ERR, "bad number supplied: %s", *argv);
+- return PAM_AUTH_ERR;
+- }
+- }
+- else if ((str = pam_str_skip_prefix(*argv, "root_unlock_time=")) != NULL) {
+- log_phase_no_auth(pamh, phase, *argv);
+- if (sscanf(str, "%ld", &opts->root_unlock_time) != 1) {
+- pam_syslog(pamh, LOG_ERR, "bad number supplied: %s", *argv);
+- return PAM_AUTH_ERR;
+- }
+- opts->ctrl |= OPT_DENY_ROOT; /* even_deny_root implied */
+- }
+- else if ( ! strcmp( *argv, "quiet" ) ||
+- ! strcmp ( *argv, "silent")) {
+- opts->ctrl |= OPT_QUIET;
+- }
+- else if ( ! strcmp ( *argv, "no_log_info") ) {
+- opts->ctrl |= OPT_NOLOGNOTICE;
+- }
+- else if ( ! strcmp ( *argv, "audit") ) {
+- opts->ctrl |= OPT_AUDIT;
+- }
+- else {
+- pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
+- }
+- }
+-
+- if (opts->root_unlock_time == -1)
+- opts->root_unlock_time = opts->unlock_time;
+-
+- return PAM_SUCCESS;
+-}
+-
+-#endif /* #ifndef MAIN */
+-
+-/*---------------------------------------------------------------------*/
+-
+-/* --- Support function: get uid (and optionally username) from PAM or
+- cline_user --- */
+-
+-#ifdef MAIN
+-static const char *cline_user=0; /* cline_user is used in the administration prog */
+-#endif
+-
+-static int
+-pam_get_uid(pam_handle_t *pamh, uid_t *uid, const char **userp, struct tally_options *opts)
+-{
+- const char *user = NULL;
+- struct passwd *pw;
+-
+-#ifdef MAIN
+- user = cline_user;
+-
+- if ( !user ) {
+- pam_syslog(pamh, LOG_NOTICE, "cannot determine user name");
+- return PAM_AUTH_ERR;
+- }
+-#else
+- if ((pam_get_user( pamh, &user, NULL )) != PAM_SUCCESS) {
+- user = NULL;
+- }
+-#endif
+-
+- if ( ! ( pw = pam_modutil_getpwnam( pamh, user ) ) ) {
+- opts->ctrl & OPT_AUDIT ?
+- pam_syslog(pamh, LOG_NOTICE, "pam_get_uid; no such user %s", user) :
+- pam_syslog(pamh, LOG_NOTICE, "pam_get_uid; no such user");
+- return PAM_USER_UNKNOWN;
+- }
+-
+- if ( uid ) *uid = pw->pw_uid;
+- if ( userp ) *userp = user;
+- return PAM_SUCCESS;
+-}
+-
+-/*---------------------------------------------------------------------*/
+-
+-/* --- Support functions: set/get tally data --- */
+-
+-#ifndef MAIN
+-
+-struct tally_data {
+- time_t time;
+- int tfile;
+-};
+-
+-static void
+-_cleanup(pam_handle_t *pamh UNUSED, void *void_data, int error_status UNUSED)
+-{
+- struct tally_data *data = void_data;
+- if (data->tfile != -1)
+- close(data->tfile);
+- free(data);
+-}
+-
+-static void
+-tally_set_data( pam_handle_t *pamh, time_t oldtime, int tfile )
+-{
+- struct tally_data *data;
+-
+- if ( (data=malloc(sizeof(*data))) != NULL ) {
+- data->time = oldtime;
+- data->tfile = tfile;
+- pam_set_data(pamh, MODULE_NAME, (void *)data, _cleanup);
+- }
+-}
+-
+-static int
+-tally_get_data( pam_handle_t *pamh, time_t *oldtime, int *tfile )
+-{
+- int rv;
+- const void *void_data;
+- const struct tally_data *data;
+-
+- rv = pam_get_data(pamh, MODULE_NAME, &void_data);
+- if ( rv == PAM_SUCCESS && void_data != NULL && oldtime != NULL ) {
+- data = void_data;
+- *oldtime = data->time;
+- *tfile = data->tfile;
+- }
+- else {
+- rv = -1;
+- *oldtime = 0;
+- }
+- return rv;
+-}
+-#endif /* #ifndef MAIN */
+-
+-/*---------------------------------------------------------------------*/
+-
+-/* --- Support function: open/create tallyfile and return tally for uid --- */
+-
+-/* If on entry tallyfile doesn't exist, creation is attempted. */
+-
+-static void
+-alarm_handler(int sig UNUSED)
+-{ /* we just need to ignore it */
+-}
+-
+-static int
+-get_tally(pam_handle_t *pamh, uid_t uid, const char *filename,
+- int *tfile, struct tallylog *tally, unsigned int ctrl)
+-{
+- struct stat fileinfo;
+- int lstat_ret;
+- void *void_tally = tally;
+- int preopened = 0;
+-
+- if (*tfile != -1) {
+- preopened = 1;
+- goto skip_open;
+- }
+-
+- lstat_ret = lstat(filename, &fileinfo);
+- if (lstat_ret) {
+- *tfile=open(filename, O_APPEND|O_CREAT, S_IRUSR|S_IWUSR);
+- /* Create file, or append-open in pathological case. */
+- if (*tfile == -1) {
+-#ifndef MAIN
+- if (errno == EACCES) {
+- return PAM_IGNORE; /* called with insufficient access rights */
+- }
+-#endif
+- pam_syslog(pamh, LOG_ALERT, "Couldn't create %s: %m", filename);
+- return PAM_AUTH_ERR;
+- }
+- lstat_ret = fstat(*tfile, &fileinfo);
+- close(*tfile);
+- }
+-
+- *tfile = -1;
+-
+- if ( lstat_ret ) {
+- pam_syslog(pamh, LOG_ALERT, "Couldn't stat %s", filename);
+- return PAM_AUTH_ERR;
+- }
+-
+- if ((fileinfo.st_mode & S_IWOTH) || !S_ISREG(fileinfo.st_mode)) {
+- /* If the file is world writable or is not a
+- normal file, return error */
+- pam_syslog(pamh, LOG_ALERT,
+- "%s is either world writable or not a normal file",
+- filename);
+- return PAM_AUTH_ERR;
+- }
+-
+- if ((*tfile = open(filename, O_RDWR)) == -1) {
+-#ifndef MAIN
+- if (errno == EACCES) /* called with insufficient access rights */
+- return PAM_IGNORE;
+-#endif
+- pam_syslog(pamh, LOG_ALERT, "Error opening %s for update: %m", filename);
+-
+- return PAM_AUTH_ERR;
+- }
+-
+-skip_open:
+- if (lseek(*tfile, (off_t)uid*(off_t)sizeof(*tally), SEEK_SET) == (off_t)-1) {
+- pam_syslog(pamh, LOG_ALERT, "lseek failed for %s: %m", filename);
+- if (!preopened) {
+- close(*tfile);
+- *tfile = -1;
+- }
+- return PAM_AUTH_ERR;
+- }
+-
+- if (!preopened && (ctrl & OPT_SERIALIZE)) {
+- /* this code is not thread safe as it uses fcntl locks and alarm()
+- so never use serialize with multithreaded services */
+- struct sigaction newsa, oldsa;
+- unsigned int oldalarm;
+- int rv;
+-
+- memset(&newsa, '\0', sizeof(newsa));
+- newsa.sa_handler = alarm_handler;
+- sigaction(SIGALRM, &newsa, &oldsa);
+- oldalarm = alarm(MAX_LOCK_WAITING_TIME);
+-
+- rv = lockf(*tfile, F_LOCK, sizeof(*tally));
+- /* lock failure is not fatal, we attempt to read the tally anyway */
+-
+- /* reinstate the eventual old alarm handler */
+- if (rv == -1 && errno == EINTR) {
+- if (oldalarm > MAX_LOCK_WAITING_TIME) {
+- oldalarm -= MAX_LOCK_WAITING_TIME;
+- } else if (oldalarm > 0) {
+- oldalarm = 1;
+- }
+- }
+- sigaction(SIGALRM, &oldsa, NULL);
+- alarm(oldalarm);
+- }
+-
+- if (pam_modutil_read(*tfile, void_tally, sizeof(*tally)) != sizeof(*tally)) {
+- memset(tally, 0, sizeof(*tally));
+- }
+-
+- tally->fail_line[sizeof(tally->fail_line)-1] = '\0';
+-
+- return PAM_SUCCESS;
+-}
+-
+-/*---------------------------------------------------------------------*/
+-
+-/* --- Support function: update tallyfile with tally!=TALLY_HI --- */
+-
+-static int
+-set_tally(pam_handle_t *pamh, uid_t uid,
+- const char *filename, int *tfile, struct tallylog *tally)
+-{
+- void *void_tally = tally;
+- if (tally->fail_cnt != TALLY_HI) {
+- if (lseek(*tfile, (off_t)uid * sizeof(*tally), SEEK_SET) == (off_t)-1) {
+- pam_syslog(pamh, LOG_ALERT, "lseek failed for %s: %m", filename);
+- return PAM_AUTH_ERR;
+- }
+- if (pam_modutil_write(*tfile, void_tally, sizeof(*tally)) != sizeof(*tally)) {
+- pam_syslog(pamh, LOG_ALERT, "update (write) failed for %s: %m", filename);
+- return PAM_AUTH_ERR;
+- }
+- }
+-
+- return PAM_SUCCESS;
+-}
+-
+-/*---------------------------------------------------------------------*/
+-
+-/* --- PAM bits --- */
+-
+-#ifndef MAIN
+-
+-#define RETURN_ERROR(i) return ((opts->ctrl & OPT_FAIL_ON_ERROR)?(i):(PAM_SUCCESS))
+-
+-/*---------------------------------------------------------------------*/
+-
+-static int
+-tally_check (tally_t oldcnt, time_t oldtime, pam_handle_t *pamh, uid_t uid,
+- const char *user, struct tally_options *opts,
+- struct tallylog *tally)
+-{
+- int rv = PAM_SUCCESS;
+- int loglevel = LOG_DEBUG;
+-#ifdef HAVE_LIBAUDIT
+- char buf[64];
+- int audit_fd = -1;
+- const void *rhost = NULL, *tty = NULL;
+-#endif
+-
+- if ((opts->ctrl & OPT_MAGIC_ROOT) && getuid() == 0) {
+- return PAM_SUCCESS;
+- }
+- /* magic_root skips tally check */
+-#ifdef HAVE_LIBAUDIT
+- audit_fd = audit_open();
+- /* If there is an error & audit support is in the kernel report error */
+- if ((audit_fd < 0) && !(errno == EINVAL || errno == EPROTONOSUPPORT ||
+- errno == EAFNOSUPPORT))
+- return PAM_SYSTEM_ERR;
+- (void)pam_get_item(pamh, PAM_TTY, &tty);
+- (void)pam_get_item(pamh, PAM_RHOST, &rhost);
+-#endif
+- if (opts->deny != 0 && /* deny==0 means no deny */
+- tally->fail_cnt > opts->deny && /* tally>deny means exceeded */
+- ((opts->ctrl & OPT_DENY_ROOT) || uid)) { /* even_deny stops uid check */
+-#ifdef HAVE_LIBAUDIT
+- if (tally->fail_cnt == opts->deny+1) {
+- /* First say that max number was hit. */
+- snprintf(buf, sizeof(buf), "pam_tally2 uid=%u ", uid);
+- audit_log_user_message(audit_fd, AUDIT_ANOM_LOGIN_FAILURES, buf,
+- rhost, NULL, tty, 1);
+- }
+-#endif
+- if (uid) {
+- /* Unlock time check */
+- if (opts->unlock_time && oldtime) {
+- if (opts->unlock_time + oldtime <= time(NULL)) {
+- /* ignore deny check after unlock_time elapsed */
+-#ifdef HAVE_LIBAUDIT
+- snprintf(buf, sizeof(buf), "pam_tally2 uid=%u ", uid);
+- audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_UNLOCK_TIMED, buf,
+- rhost, NULL, tty, 1);
+-#endif
+- rv = PAM_SUCCESS;
+- goto cleanup;
+- }
+- }
+- } else {
+- /* Root unlock time check */
+- if (opts->root_unlock_time && oldtime) {
+- if (opts->root_unlock_time + oldtime <= time(NULL)) {
+- /* ignore deny check after unlock_time elapsed */
+-#ifdef HAVE_LIBAUDIT
+- snprintf(buf, sizeof(buf), "pam_tally2 uid=%u ", uid);
+- audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_UNLOCK_TIMED, buf,
+- rhost, NULL, tty, 1);
+-#endif
+- rv = PAM_SUCCESS;
+- goto cleanup;
+- }
+- }
+- }
+-
+-#ifdef HAVE_LIBAUDIT
+- if (tally->fail_cnt == opts->deny+1) {
+- /* First say that max number was hit. */
+- audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_LOCK, buf,
+- rhost, NULL, tty, 1);
+- }
+-#endif
+-
+- if (!(opts->ctrl & OPT_QUIET)) {
+- pam_info(pamh, _("The account is locked due to %u failed logins."),
+- (unsigned int)tally->fail_cnt);
+- }
+- loglevel = LOG_NOTICE;
+- rv = PAM_AUTH_ERR; /* Only unconditional failure */
+- goto cleanup;
+- }
+-
+- /* Lock time check */
+- if (opts->lock_time && oldtime) {
+- if (opts->lock_time + oldtime > time(NULL)) {
+- /* don't increase fail_cnt or update fail_time when
+- lock_time applies */
+- tally->fail_cnt = oldcnt;
+- tally->fail_time = oldtime;
+-
+- if (!(opts->ctrl & OPT_QUIET)) {
+- pam_info(pamh,
+- _("The account is temporarily locked (%ld seconds left)."),
+- (long int) (oldtime+opts->lock_time-time(NULL)));
+- }
+- if (!(opts->ctrl & OPT_NOLOGNOTICE)) {
+- pam_syslog(pamh, LOG_NOTICE,
+- "user %s (%lu) has time limit [%lds left]"
+- " since last failure.",
+- user, (unsigned long)uid,
+- (long int) (oldtime+opts->lock_time-time(NULL)));
+- }
+- rv = PAM_AUTH_ERR;
+- goto cleanup;
+- }
+- }
+-
+-cleanup:
+- if (!(opts->ctrl & OPT_NOLOGNOTICE) && (loglevel != LOG_DEBUG || opts->ctrl & OPT_DEBUG)) {
+- pam_syslog(pamh, loglevel,
+- "user %s (%lu) tally %hu, deny %hu",
+- user, (unsigned long)uid, tally->fail_cnt, opts->deny);
+- }
+-#ifdef HAVE_LIBAUDIT
+- if (audit_fd != -1) {
+- close(audit_fd);
+- }
+-#endif
+- return rv;
+-}
+-
+-/* --- tally bump function: bump tally for uid by (signed) inc --- */
+-
+-static int
+-tally_bump (int inc, time_t *oldtime, pam_handle_t *pamh,
+- uid_t uid, const char *user, struct tally_options *opts, int *tfile)
+-{
+- struct tallylog tally;
+- tally_t oldcnt;
+- const void *remote_host = NULL;
+- int i, rv;
+-
+- tally.fail_cnt = 0; /* !TALLY_HI --> Log opened for update */
+-
+- i = get_tally(pamh, uid, opts->filename, tfile, &tally, opts->ctrl);
+- if (i != PAM_SUCCESS) {
+- if (*tfile != -1) {
+- close(*tfile);
+- *tfile = -1;
+- }
+- RETURN_ERROR(i);
+- }
+-
+- /* to remember old fail time (for locktime) */
+- if (oldtime) {
+- *oldtime = (time_t)tally.fail_time;
+- }
+-
+- tally.fail_time = time(NULL);
+-
+- (void) pam_get_item(pamh, PAM_RHOST, &remote_host);
+- if (!remote_host) {
+- (void) pam_get_item(pamh, PAM_TTY, &remote_host);
+- if (!remote_host) {
+- remote_host = "unknown";
+- }
+- }
+-
+- strncpy(tally.fail_line, remote_host,
+- sizeof(tally.fail_line)-1);
+- tally.fail_line[sizeof(tally.fail_line)-1] = 0;
+-
+- oldcnt = tally.fail_cnt;
+-
+- if (!(opts->ctrl & OPT_MAGIC_ROOT) || getuid()) {
+- /* magic_root doesn't change tally */
+- tally.fail_cnt += inc;
+-
+- if (tally.fail_cnt == TALLY_HI) { /* Overflow *and* underflow. :) */
+- tally.fail_cnt -= inc;
+- pam_syslog(pamh, LOG_ALERT, "Tally %sflowed for user %s",
+- (inc<0)?"under":"over",user);
+- }
+- }
+-
+- rv = tally_check(oldcnt, *oldtime, pamh, uid, user, opts, &tally);
+-
+- i = set_tally(pamh, uid, opts->filename, tfile, &tally);
+- if (i != PAM_SUCCESS) {
+- if (*tfile != -1) {
+- close(*tfile);
+- *tfile = -1;
+- }
+- if (rv == PAM_SUCCESS)
+- RETURN_ERROR( i );
+- /* fallthrough */
+- } else if (!(opts->ctrl & OPT_SERIALIZE)) {
+- close(*tfile);
+- *tfile = -1;
+- }
+-
+- return rv;
+-}
+-
+-static int
+-tally_reset (pam_handle_t *pamh, uid_t uid, struct tally_options *opts, int old_tfile)
+-{
+- struct tallylog tally;
+- int tfile = old_tfile;
+- int i;
+-
+- /* resets only if not magic root */
+-
+- if ((opts->ctrl & OPT_MAGIC_ROOT) && getuid() == 0) {
+- return PAM_SUCCESS;
+- }
+-
+- tally.fail_cnt = 0; /* !TALLY_HI --> Log opened for update */
+-
+- i=get_tally(pamh, uid, opts->filename, &tfile, &tally, opts->ctrl);
+- if (i != PAM_SUCCESS) {
+- if (tfile != old_tfile) /* the descriptor is not owned by pam data */
+- close(tfile);
+- RETURN_ERROR(i);
+- }
+-
+- memset(&tally, 0, sizeof(tally));
+-
+- i=set_tally(pamh, uid, opts->filename, &tfile, &tally);
+- if (i != PAM_SUCCESS) {
+- if (tfile != old_tfile) /* the descriptor is not owned by pam data */
+- close(tfile);
+- RETURN_ERROR(i);
+- }
+-
+- if (tfile != old_tfile)
+- close(tfile);
+-
+- return PAM_SUCCESS;
+-}
+-
+-/*---------------------------------------------------------------------*/
+-
+-/* --- authentication management functions (only) --- */
+-
+-int
+-pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED,
+- int argc, const char **argv)
+-{
+- int
+- rv, tfile = -1;
+- time_t
+- oldtime = 0;
+- struct tally_options
+- options, *opts = &options;
+- uid_t
+- uid;
+- const char
+- *user;
+-
+- rv = tally_parse_args(pamh, opts, PHASE_AUTH, argc, argv);
+- if (rv != PAM_SUCCESS)
+- RETURN_ERROR(rv);
+-
+- if (flags & PAM_SILENT)
+- opts->ctrl |= OPT_QUIET;
+-
+- rv = pam_get_uid(pamh, &uid, &user, opts);
+- if (rv != PAM_SUCCESS)
+- RETURN_ERROR(rv);
+-
+- rv = tally_bump(1, &oldtime, pamh, uid, user, opts, &tfile);
+-
+- tally_set_data(pamh, oldtime, tfile);
+-
+- return rv;
+-}
+-
+-int
+-pam_sm_setcred(pam_handle_t *pamh, int flags UNUSED,
+- int argc, const char **argv)
+-{
+- int
+- rv, tfile = -1;
+- time_t
+- oldtime = 0;
+- struct tally_options
+- options, *opts = &options;
+- uid_t
+- uid;
+- const char
+- *user;
+-
+- rv = tally_parse_args(pamh, opts, PHASE_AUTH, argc, argv);
+- if ( rv != PAM_SUCCESS )
+- RETURN_ERROR( rv );
+-
+- rv = pam_get_uid(pamh, &uid, &user, opts);
+- if ( rv != PAM_SUCCESS )
+- RETURN_ERROR( rv );
+-
+- if ( tally_get_data(pamh, &oldtime, &tfile) != 0 )
+- /* no data found */
+- return PAM_SUCCESS;
+-
+- rv = tally_reset(pamh, uid, opts, tfile);
+-
+- pam_set_data(pamh, MODULE_NAME, NULL, NULL);
+-
+- return rv;
+-}
+-
+-/*---------------------------------------------------------------------*/
+-
+-/* --- authentication management functions (only) --- */
+-
+-/* To reset failcount of user on successful login */
+-
+-int
+-pam_sm_acct_mgmt(pam_handle_t *pamh, int flags UNUSED,
+- int argc, const char **argv)
+-{
+- int
+- rv, tfile = -1;
+- time_t
+- oldtime = 0;
+- struct tally_options
+- options, *opts = &options;
+- uid_t
+- uid;
+- const char
+- *user;
+-
+- rv = tally_parse_args(pamh, opts, PHASE_ACCOUNT, argc, argv);
+- if ( rv != PAM_SUCCESS )
+- RETURN_ERROR( rv );
+-
+- rv = pam_get_uid(pamh, &uid, &user, opts);
+- if ( rv != PAM_SUCCESS )
+- RETURN_ERROR( rv );
+-
+- if ( tally_get_data(pamh, &oldtime, &tfile) != 0 )
+- /* no data found */
+- return PAM_SUCCESS;
+-
+- rv = tally_reset(pamh, uid, opts, tfile);
+-
+- pam_set_data(pamh, MODULE_NAME, NULL, NULL);
+-
+- return rv;
+-}
+-
+-/*-----------------------------------------------------------------------*/
+-
+-#else /* #ifndef MAIN */
+-
+-static const char *cline_filename = DEFAULT_LOGFILE;
+-static tally_t cline_reset = TALLY_HI; /* Default is `interrogate only' */
+-static int cline_quiet = 0;
+-
+-/*
+- * Not going to link with pamlib just for these.. :)
+- */
+-
+-static const char *
+-pam_errors( int i )
+-{
+- switch (i) {
+- case PAM_AUTH_ERR: return _("Authentication error");
+- case PAM_SERVICE_ERR: return _("Service error");
+- case PAM_USER_UNKNOWN: return _("Unknown user");
+- default: return _("Unknown error");
+- }
+-}
+-
+-static int
+-getopts( char **argv )
+-{
+- const char *pname = *argv;
+- for ( ; *argv ; (void)(*argv && ++argv) ) {
+- const char *str;
+- if ( !strcmp (*argv,"--file") ) cline_filename=*++argv;
+- else if ( !strcmp(*argv,"-f") ) cline_filename=*++argv;
+- else if ((str = pam_str_skip_prefix(*argv, "--file=")) != NULL)
+- cline_filename = str;
+- else if ( !strcmp (*argv,"--user") ) cline_user=*++argv;
+- else if ( !strcmp (*argv,"-u") ) cline_user=*++argv;
+- else if ((str = pam_str_skip_prefix(*argv, "--user=")) != NULL)
+- cline_user = str;
+- else if ( !strcmp (*argv,"--reset") ) cline_reset=0;
+- else if ( !strcmp (*argv,"-r") ) cline_reset=0;
+- else if ((str = pam_str_skip_prefix(*argv, "--reset=")) != NULL) {
+- if (sscanf(str, "%hu", &cline_reset) != 1)
+- fprintf(stderr,_("%s: Bad number given to --reset=\n"),pname), exit(0);
+- }
+- else if ( !strcmp (*argv,"--quiet") ) cline_quiet=1;
+- else {
+- fprintf(stderr,_("%s: Unrecognised option %s\n"),pname,*argv);
+- return FALSE;
+- }
+- }
+- return TRUE;
+-}
+-
+-static void
+-print_one(const struct tallylog *tally, uid_t uid)
+-{
+- static int once;
+- const char *cp = "[UNKNOWN]";
+- time_t fail_time;
+- struct tm *tm;
+- struct passwd *pwent;
+- const char *username = "[NONAME]";
+- char ptime[80];
+-
+- pwent = getpwuid(uid);
+- fail_time = tally->fail_time;
+- if ((tm = localtime(&fail_time)) != NULL) {
+- strftime (ptime, sizeof (ptime), "%D %H:%M:%S", tm);
+- cp = ptime;
+- }
+- if (pwent) {
+- username = pwent->pw_name;
+- }
+- if (!once) {
+- printf (_("Login Failures Latest failure From\n"));
+- once++;
+- }
+- printf ("%-15.15s %5hu ", username, tally->fail_cnt);
+- if (tally->fail_time) {
+- printf ("%-17.17s %s", cp, tally->fail_line);
+- }
+- putchar ('\n');
+-}
+-
+-int
+-main( int argc UNUSED, char **argv )
+-{
+- struct tallylog tally;
+-
+- if ( ! getopts( argv+1 ) ) {
+- printf(_("%s: [-f rooted-filename] [--file rooted-filename]\n"
+- " [-u username] [--user username]\n"
+- " [-r] [--reset[=n]] [--quiet]\n"),
+- *argv);
+- exit(2);
+- }
+-
+- umask(077);
+-
+- /*
+- * Major difference between individual user and all users:
+- * --user just handles one user, just like PAM.
+- * without --user it handles all users, sniffing cline_filename for nonzeros
+- */
+-
+- if ( cline_user ) {
+- uid_t uid;
+- int tfile = -1;
+- struct tally_options opts;
+- int i;
+-
+- memset(&opts, 0, sizeof(opts));
+- opts.ctrl = OPT_AUDIT;
+- i=pam_get_uid(NULL, &uid, NULL, &opts);
+- if ( i != PAM_SUCCESS ) {
+- fprintf(stderr,"%s: %s\n",*argv,pam_errors(i));
+- exit(1);
+- }
+-
+- if (cline_reset == 0) {
+- struct stat st;
+-
+- if (stat(cline_filename, &st) && errno == ENOENT) {
+- if (!cline_quiet) {
+- memset(&tally, 0, sizeof(tally));
+- print_one(&tally, uid);
+- }
+- return 0; /* no file => nothing to reset */
+- }
+- }
+-
+- i=get_tally(NULL, uid, cline_filename, &tfile, &tally, 0);
+- if ( i != PAM_SUCCESS ) {
+- if (tfile != -1)
+- close(tfile);
+- fprintf(stderr, "%s: %s\n", *argv, pam_errors(i));
+- exit(1);
+- }
+-
+- if ( !cline_quiet )
+- print_one(&tally, uid);
+-
+- if (cline_reset != TALLY_HI) {
+-#ifdef HAVE_LIBAUDIT
+- char buf[64];
+- int audit_fd = audit_open();
+- snprintf(buf, sizeof(buf), "pam_tally2 uid=%u reset=%hu", uid, cline_reset);
+- audit_log_user_message(audit_fd, AUDIT_USER_ACCT,
+- buf, NULL, NULL, ttyname(STDIN_FILENO), 1);
+- if (audit_fd >=0)
+- close(audit_fd);
+-#endif
+- if (cline_reset == 0) {
+- memset(&tally, 0, sizeof(tally));
+- } else {
+- tally.fail_cnt = cline_reset;
+- }
+- i=set_tally(NULL, uid, cline_filename, &tfile, &tally);
+- close(tfile);
+- if (i != PAM_SUCCESS) {
+- fprintf(stderr,"%s: %s\n",*argv,pam_errors(i));
+- exit(1);
+- }
+- } else {
+- close(tfile);
+- }
+- }
+- else /* !cline_user (ie, operate on all users) */ {
+- FILE *tfile=fopen(cline_filename, "r");
+- uid_t uid=0;
+- if (!tfile && cline_reset != 0) {
+- perror(*argv);
+- exit(1);
+- }
+-
+- for ( ; tfile && !feof(tfile); uid++ ) {
+- if ( !fread(&tally, sizeof(tally), 1, tfile)
+- || !tally.fail_cnt ) {
+- continue;
+- }
+- print_one(&tally, uid);
+- }
+- if (tfile)
+- fclose(tfile);
+- if ( cline_reset!=0 && cline_reset!=TALLY_HI ) {
+- fprintf(stderr,_("%s: Can't reset all users to non-zero\n"),*argv);
+- }
+- else if ( !cline_reset ) {
+-#ifdef HAVE_LIBAUDIT
+- char buf[64];
+- int audit_fd = audit_open();
+- snprintf(buf, sizeof(buf), "pam_tally2 uid=all reset=0");
+- audit_log_user_message(audit_fd, AUDIT_USER_ACCT,
+- buf, NULL, NULL, ttyname(STDIN_FILENO), 1);
+- if (audit_fd >=0)
+- close(audit_fd);
+-#endif
+- tfile=fopen(cline_filename, "w");
+- if ( !tfile ) perror(*argv), exit(0);
+- fclose(tfile);
+- }
+- }
+- return 0;
+-}
+-
+-
+-#endif /* #ifndef MAIN */
+diff --git a/modules/pam_tally2/pam_tally2_app.c b/modules/pam_tally2/pam_tally2_app.c
+deleted file mode 100644
+index b72e9bfd..00000000
+--- a/modules/pam_tally2/pam_tally2_app.c
++++ /dev/null
+@@ -1,6 +0,0 @@
+-/*
+- # This seemed like such a good idea at the time. :)
+- */
+-
+-#define MAIN
+-#include "pam_tally2.c"
+diff --git a/modules/pam_tally2/tallylog.h b/modules/pam_tally2/tallylog.h
+deleted file mode 100644
+index 596b1dac..00000000
+--- a/modules/pam_tally2/tallylog.h
++++ /dev/null
+@@ -1,52 +0,0 @@
+-/*
+- * Copyright 2006, Red Hat, Inc.
+- * 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 Red Hat, Inc. 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 RED HAT, INC. 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.
+- */
+-
+-/*
+- * tallylog.h - login failure data file format
+- *
+- * The new login failure file is not compatible with the old faillog(8) format
+- * Each record in the file represents a separate UID and the file
+- * is indexed in that fashion.
+- */
+-
+-
+-#ifndef _TALLYLOG_H
+-#define _TALLYLOG_H
+-
+-#include
+-
+-struct tallylog {
+- char fail_line[52]; /* rhost or tty of last failure */
+- uint16_t reserved; /* reserved for future use */
+- uint16_t fail_cnt; /* failures since last success */
+- uint64_t fail_time; /* time of last failure */
+-};
+-/* 64 bytes / entry */
+-
+-#endif
+diff --git a/modules/pam_tally2/tst-pam_tally2 b/modules/pam_tally2/tst-pam_tally2
+deleted file mode 100755
+index 83c71f41..00000000
+--- a/modules/pam_tally2/tst-pam_tally2
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#!/bin/sh
+-../../tests/tst-dlopen .libs/pam_tally2.so