Add allowing/disabling character classes
This commit is contained in:
parent
7458aa15bd
commit
08459a98b3
294
allowed-character-classes.patch
Normal file
294
allowed-character-classes.patch
Normal file
@ -0,0 +1,294 @@
|
||||
diff -ruN '--exclude=*.rej' '--exclude=*.orig' a/doc/man/pam_pwquality.8.pod b/doc/man/pam_pwquality.8.pod
|
||||
--- a/doc/man/pam_pwquality.8.pod 2026-06-24 13:39:51.505182998 +0200
|
||||
+++ b/doc/man/pam_pwquality.8.pod 2026-06-24 13:47:32.042603712 +0200
|
||||
@@ -250,6 +250,13 @@
|
||||
a new password but use the one provided by the previously stacked
|
||||
B<password> module.
|
||||
|
||||
+=item B<allowclasses=>I<< "ludo" >>
|
||||
+
|
||||
+The list of letters that represent allowed character classes that
|
||||
+are allowed in a password (digits, uppercase, lowercase, others).
|
||||
+"d" is for digits, "u" is for uppercase letters, "l" is for
|
||||
+lowercase letters, "o" is for other characters.
|
||||
+
|
||||
=back
|
||||
|
||||
=head1 MODULE TYPES PROVIDED
|
||||
diff -ruN '--exclude=*.rej' '--exclude=*.orig' a/doc/man/pwquality.conf.5.pod b/doc/man/pwquality.conf.5.pod
|
||||
--- a/doc/man/pwquality.conf.5.pod 2026-06-24 13:39:51.505235241 +0200
|
||||
+++ b/doc/man/pwquality.conf.5.pod 2026-06-24 13:50:30.694360330 +0200
|
||||
@@ -85,7 +85,7 @@
|
||||
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.
|
||||
-The check is disabled if the value is 0. (default 0)
|
||||
+The check is disabled if the value is 0. (default 0)
|
||||
|
||||
=item B<maxclassrepeat>
|
||||
|
||||
@@ -155,6 +155,13 @@
|
||||
the following modules in the stack can use the B<use_authtok> option.
|
||||
This option is off by default.
|
||||
|
||||
+=item B<allowclasses>
|
||||
+
|
||||
+The list of letters that represent allowed character classes that
|
||||
+are allowed in a password (digits, uppercase, lowercase, others).
|
||||
+"d" is for digits, "u" is for uppercase letters, "l" is for
|
||||
+lowercase letters, "o" is for other characters. (default "ludo")
|
||||
+
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
diff -ruN '--exclude=*.rej' '--exclude=*.orig' a/src/check.c b/src/check.c
|
||||
--- a/src/check.c 2026-06-24 13:39:51.504779475 +0200
|
||||
+++ b/src/check.c 2026-06-24 13:45:06.118168891 +0200
|
||||
@@ -49,7 +49,7 @@
|
||||
* the other
|
||||
*/
|
||||
|
||||
-static int
|
||||
+static int
|
||||
distdifferent(const char *old, const char *new,
|
||||
size_t i, size_t j)
|
||||
{
|
||||
@@ -202,6 +202,7 @@
|
||||
int others = 0;
|
||||
int size;
|
||||
int i;
|
||||
+ const char *allow_classes;
|
||||
enum { NONE, DIGIT, UCASE, LCASE, OTHER } prevclass = NONE;
|
||||
int sameclass = 0;
|
||||
|
||||
@@ -244,6 +245,35 @@
|
||||
return PWQ_ERROR_MAX_CLASS_REPEAT;
|
||||
}
|
||||
}
|
||||
+ pwquality_get_str_value(pwq, PWQ_SETTING_ALLOW_CLASSES, &allow_classes);
|
||||
+ if (digits > 0) {
|
||||
+ if (strpbrk(allow_classes, "d") == NULL) {
|
||||
+ if (auxerror)
|
||||
+ *auxerror = strdup("digits");
|
||||
+ return PWQ_ERROR_DISALLOWED_CLASS;
|
||||
+ }
|
||||
+ }
|
||||
+ if (uppers > 0) {
|
||||
+ if (strpbrk(allow_classes, "u") == NULL) {
|
||||
+ if (auxerror)
|
||||
+ *auxerror = strdup("uppercase");
|
||||
+ return PWQ_ERROR_DISALLOWED_CLASS;
|
||||
+ }
|
||||
+ }
|
||||
+ if (lowers > 0) {
|
||||
+ if (strpbrk(allow_classes, "l") == NULL) {
|
||||
+ if (auxerror)
|
||||
+ *auxerror = strdup("lowercase");
|
||||
+ return PWQ_ERROR_DISALLOWED_CLASS;
|
||||
+ }
|
||||
+ }
|
||||
+ if (others > 0) {
|
||||
+ if (strpbrk(allow_classes, "o") == NULL) {
|
||||
+ if (auxerror)
|
||||
+ *auxerror = strdup("other");
|
||||
+ return PWQ_ERROR_DISALLOWED_CLASS;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
if ((pwq->dig_credit >= 0) && (digits > pwq->dig_credit))
|
||||
digits = pwq->dig_credit;
|
||||
diff -ruN '--exclude=*.rej' '--exclude=*.orig' a/src/error.c b/src/error.c
|
||||
--- a/src/error.c 2026-06-24 13:39:51.504839606 +0200
|
||||
+++ b/src/error.c 2026-06-24 13:45:29.032394205 +0200
|
||||
@@ -149,6 +149,13 @@
|
||||
return _("The configuration file is malformed");
|
||||
case PWQ_ERROR_FATAL_FAILURE:
|
||||
return _("Fatal failure");
|
||||
+ case PWQ_ERROR_DISALLOWED_CLASS:
|
||||
+ if (auxerror) {
|
||||
+ snprintf(buf, len, _("The %s class of characters is not allowed"), (const char *)auxerror);
|
||||
+ free(auxerror);
|
||||
+ return buf;
|
||||
+ }
|
||||
+ return _("The password contains disallowed character class");
|
||||
default:
|
||||
return _("Unknown error");
|
||||
}
|
||||
@@ -188,4 +195,3 @@
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
-
|
||||
diff -ruN '--exclude=*.rej' '--exclude=*.orig' a/src/generate.c b/src/generate.c
|
||||
--- a/src/generate.c 2026-06-24 13:39:51.504750650 +0200
|
||||
+++ b/src/generate.c 2026-06-24 13:45:38.556487851 +0200
|
||||
@@ -95,7 +95,7 @@
|
||||
}
|
||||
|
||||
*offset += bits;
|
||||
- return low;
|
||||
+ return low;
|
||||
}
|
||||
|
||||
/* generate a random password according to the settings */
|
||||
diff -ruN '--exclude=*.rej' '--exclude=*.orig' a/src/pam_pwquality.c b/src/pam_pwquality.c
|
||||
--- a/src/pam_pwquality.c 2026-06-24 13:39:51.504861183 +0200
|
||||
+++ b/src/pam_pwquality.c 2026-06-24 13:46:16.791863795 +0200
|
||||
@@ -88,7 +88,7 @@
|
||||
} else if (!strncmp(*argv, "try_first_pass", 14)) {
|
||||
/* for pam_get_authtok, ignore */;
|
||||
} else if (pwquality_set_option(pwq, *argv)) {
|
||||
- pam_syslog(pamh, LOG_ERR,
|
||||
+ pam_syslog(pamh, LOG_ERR,
|
||||
"pam_parse: unknown or broken option; %s", *argv);
|
||||
}
|
||||
}
|
||||
@@ -213,7 +213,7 @@
|
||||
if (retval != PAM_SUCCESS || newtoken == NULL) {
|
||||
if (retval == PAM_AUTHTOK_ERR || newtoken == NULL)
|
||||
pam_syslog(pamh, LOG_INFO, "user aborted password change");
|
||||
- else
|
||||
+ else
|
||||
pam_syslog(pamh, LOG_ERR, "pam_get_authtok_noverify returned error: %s",
|
||||
pam_strerror(pamh, retval));
|
||||
pwquality_free_settings(options.pwq);
|
||||
@@ -262,7 +262,7 @@
|
||||
continue;
|
||||
if (retval == PAM_AUTHTOK_ERR || newtoken == NULL)
|
||||
pam_syslog(pamh, LOG_INFO, "user aborted password change");
|
||||
- else
|
||||
+ else
|
||||
pam_syslog(pamh, LOG_ERR, "pam_get_authtok_verify returned error: %s",
|
||||
pam_strerror(pamh, retval));
|
||||
pwquality_free_settings(options.pwq);
|
||||
diff -ruN '--exclude=*.rej' '--exclude=*.orig' a/src/pwqprivate.h b/src/pwqprivate.h
|
||||
--- a/src/pwqprivate.h 2026-06-24 13:39:51.504670235 +0200
|
||||
+++ b/src/pwqprivate.h 2026-06-24 13:43:52.963449598 +0200
|
||||
@@ -33,6 +33,7 @@
|
||||
int local_users_only;
|
||||
char *bad_words;
|
||||
char *dict_path;
|
||||
+ char *allow_classes;
|
||||
};
|
||||
|
||||
struct setting_mapping {
|
||||
@@ -47,6 +48,7 @@
|
||||
#define PWQ_DEFAULT_UP_CREDIT 0
|
||||
#define PWQ_DEFAULT_LOW_CREDIT 0
|
||||
#define PWQ_DEFAULT_OTH_CREDIT 0
|
||||
+#define PWQ_DEFAULT_ALLOWCLASSES "ludo"
|
||||
|
||||
#ifdef HAVE_CRACK_H
|
||||
#define PWQ_DEFAULT_DICT_CHECK 1
|
||||
diff -ruN '--exclude=*.rej' '--exclude=*.orig' a/src/pwquality.conf b/src/pwquality.conf
|
||||
--- a/src/pwquality.conf 2026-06-24 13:39:51.504930249 +0200
|
||||
+++ b/src/pwquality.conf 2026-06-24 13:50:46.129512097 +0200
|
||||
@@ -58,6 +58,10 @@
|
||||
# The check is enabled if the value is greater than 0 and usercheck is enabled.
|
||||
# usersubstr = 0
|
||||
#
|
||||
+# The allowed classes of characters (digits, uppercase, lowercase, others)
|
||||
+# to be used in the password.
|
||||
+# allowclasses = "ludo"
|
||||
+#
|
||||
# Whether the check is enforced by the PAM module and possibly other
|
||||
# applications.
|
||||
# The new password is rejected if it fails the check and the value is not 0.
|
||||
diff -ruN '--exclude=*.rej' '--exclude=*.orig' a/src/pwquality.h b/src/pwquality.h
|
||||
--- a/src/pwquality.h 2026-06-24 13:39:51.504650547 +0200
|
||||
+++ b/src/pwquality.h 2026-06-24 13:47:07.084358309 +0200
|
||||
@@ -36,6 +36,7 @@
|
||||
#define PWQ_SETTING_ENFORCE_ROOT 19
|
||||
#define PWQ_SETTING_LOCAL_USERS 20
|
||||
#define PWQ_SETTING_USER_SUBSTR 21
|
||||
+#define PWQ_SETTING_ALLOW_CLASSES 22
|
||||
|
||||
#define PWQ_MAX_ENTROPY_BITS 256
|
||||
#define PWQ_MIN_ENTROPY_BITS 56
|
||||
@@ -72,6 +73,7 @@
|
||||
#define PWQ_ERROR_MAX_CLASS_REPEAT -27
|
||||
#define PWQ_ERROR_BAD_WORDS -28
|
||||
#define PWQ_ERROR_MAX_SEQUENCE -29
|
||||
+#define PWQ_ERROR_DISALLOWED_CLASS -30
|
||||
|
||||
typedef struct pwquality_settings pwquality_settings_t;
|
||||
|
||||
@@ -135,7 +137,7 @@
|
||||
* is not returned.
|
||||
* Not passing the *auxerror into pwquality_strerror() can lead to memory leaks.
|
||||
* The score depends on PWQ_SETTING_MIN_LENGTH. If it is set higher,
|
||||
- * the score for the same passwords will be lower. */
|
||||
+ * the score for the same passwords will be lower. */
|
||||
int
|
||||
pwquality_check(pwquality_settings_t *pwq, const char *password,
|
||||
const char *oldpassword, const char *user, void **auxerror);
|
||||
diff -ruN '--exclude=*.rej' '--exclude=*.orig' a/src/settings.c b/src/settings.c
|
||||
--- a/src/settings.c 2026-06-24 13:39:51.504810433 +0200
|
||||
+++ b/src/settings.c 2026-06-24 13:44:29.312806994 +0200
|
||||
@@ -26,9 +26,15 @@
|
||||
{
|
||||
pwquality_settings_t *pwq;
|
||||
|
||||
+ char *allow_classes;
|
||||
+
|
||||
pwq = calloc(1, sizeof(*pwq));
|
||||
- if (!pwq)
|
||||
+ allow_classes = strdup(PWQ_DEFAULT_ALLOWCLASSES);
|
||||
+ if (!pwq || !allow_classes) {
|
||||
+ free(pwq);
|
||||
+ free(allow_classes);
|
||||
return NULL;
|
||||
+ }
|
||||
|
||||
pwq->diff_ok = PWQ_DEFAULT_DIFF_OK;
|
||||
pwq->min_length = PWQ_DEFAULT_MIN_LENGTH;
|
||||
@@ -43,6 +49,7 @@
|
||||
pwq->retry_times = PWQ_DEFAULT_RETRY_TIMES;
|
||||
pwq->enforce_for_root = PWQ_DEFAULT_ENFORCE_ROOT;
|
||||
pwq->local_users_only = PWQ_DEFAULT_LOCAL_USERS;
|
||||
+ pwq->allow_classes = allow_classes;
|
||||
|
||||
return pwq;
|
||||
}
|
||||
@@ -54,6 +61,7 @@
|
||||
if (pwq) {
|
||||
free(pwq->dict_path);
|
||||
free(pwq->bad_words);
|
||||
+ free(pwq->allow_classes);
|
||||
free(pwq);
|
||||
}
|
||||
}
|
||||
@@ -79,7 +87,8 @@
|
||||
{ "dictpath", PWQ_SETTING_DICT_PATH, PWQ_TYPE_STR},
|
||||
{ "retry", PWQ_SETTING_RETRY_TIMES, PWQ_TYPE_INT},
|
||||
{ "enforce_for_root", PWQ_SETTING_ENFORCE_ROOT, PWQ_TYPE_SET},
|
||||
- { "local_users_only", PWQ_SETTING_LOCAL_USERS, PWQ_TYPE_SET}
|
||||
+ { "local_users_only", PWQ_SETTING_LOCAL_USERS, PWQ_TYPE_SET},
|
||||
+ { "allowclasses", PWQ_SETTING_ALLOW_CLASSES, PWQ_TYPE_STR}
|
||||
};
|
||||
|
||||
/* set setting name with value */
|
||||
@@ -399,6 +408,10 @@
|
||||
free(pwq->dict_path);
|
||||
pwq->dict_path = dup;
|
||||
break;
|
||||
+ case PWQ_SETTING_ALLOW_CLASSES:
|
||||
+ free(pwq->allow_classes);
|
||||
+ pwq->allow_classes = dup;
|
||||
+ break;
|
||||
default:
|
||||
free(dup);
|
||||
return PWQ_ERROR_NON_STR_SETTING;
|
||||
@@ -490,6 +503,12 @@
|
||||
*value = NULL;
|
||||
#endif
|
||||
break;
|
||||
+ case PWQ_SETTING_ALLOW_CLASSES:
|
||||
+ if (pwq->allow_classes)
|
||||
+ *value = pwq->allow_classes;
|
||||
+ else
|
||||
+ *value = PWQ_DEFAULT_ALLOWCLASSES;
|
||||
+ break;
|
||||
default:
|
||||
return PWQ_ERROR_NON_STR_SETTING;
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
Summary: A library for password generation and password quality checking
|
||||
Name: libpwquality
|
||||
Version: 1.4.5
|
||||
Release: 12%{?dist}
|
||||
Release: 13%{?dist}
|
||||
URL: https://github.com/libpwquality/libpwquality/
|
||||
Source0: https://github.com/libpwquality/libpwquality/releases/download/libpwquality-%{version}/libpwquality-%{version}.tar.bz2
|
||||
|
||||
@ -10,6 +10,7 @@ Source0: https://github.com/libpwquality/libpwquality/releases/download/libpwqua
|
||||
# https://bugzilla.redhat.com/2165572
|
||||
# Upstream PR: https://github.com/libpwquality/libpwquality/pull/74
|
||||
Patch1: setuptools.patch
|
||||
Patch2: allowed-character-classes.patch
|
||||
|
||||
# The package is BSD licensed with option to relicense as GPLv2+
|
||||
# - this option is redundant as the BSD license allows that anyway.
|
||||
@ -24,6 +25,7 @@ BuildRequires: gcc make
|
||||
BuildRequires: cracklib-devel
|
||||
BuildRequires: gettext
|
||||
BuildRequires: pam-devel
|
||||
BuildRequires: /usr/bin/pod2man
|
||||
BuildRequires: python3-devel
|
||||
BuildRequires: python3-setuptools
|
||||
|
||||
@ -105,6 +107,10 @@ mkdir %{buildroot}%{_secconfdir}/pwquality.conf.d
|
||||
%{python3_sitearch}/*.egg-info
|
||||
|
||||
%changelog
|
||||
* Tue Jun 23 2026 Ganna Starovoytova <gstarovo@redhat.com> - 1.4.5-13
|
||||
- Adds allowing / disabling classes of characters
|
||||
Resolves: RHEL-78718
|
||||
|
||||
* Tue Oct 29 2024 Troy Dawson <tdawson@redhat.com> - 1.4.5-12
|
||||
- Bump release for October 2024 mass rebuild:
|
||||
Resolves: RHEL-64018
|
||||
|
||||
Loading…
Reference in New Issue
Block a user