6#include "validatorpwquality_p.h"
10#include <QLoggingCategory>
16 const QVariant &options,
17 const QString &userName,
18 const QString &oldPassword,
32 const QVariant &options,
33 const QString &oldPassword,
38 if (!
value.isEmpty()) {
40 pwquality_settings_t *pwq = pwquality_default_settings();
43 bool optionsSet =
false;
44 if (options.isValid()) {
45 if (options.typeId() == QMetaType::QVariantMap) {
46 const QVariantMap map = options.toMap();
48 auto i = map.constBegin();
49 while (i != map.constEnd()) {
50 const QString opt = i.key() + QLatin1Char(
'=') + i.value().toString();
51 const int orv = pwquality_set_option(pwq, opt.toUtf8().constData());
53 QList<char> buf(ValidatorPwQualityPrivate::errStrBufSize);
54 qCWarning(C_VALIDATOR).noquote().nospace()
55 <<
"ValidatorPwQuality: Failed to set pwquality option " << opt
57 << pwquality_strerror(buf.data(), buf.size(), orv,
nullptr);
63 }
else if (options.typeId() == QMetaType::QString) {
64 const QString configFile = options.toString();
65 if (!configFile.isEmpty()) {
66 if (C_VALIDATOR().isWarningEnabled()) {
67 void *auxerror =
nullptr;
68 const int rcrv = pwquality_read_config(
69 pwq, configFile.toUtf8().constData(), &auxerror);
71 QList<char> buf(ValidatorPwQualityPrivate::errStrBufSize);
72 qCWarning(C_VALIDATOR).noquote().nospace()
73 <<
"ValidatorPwQuality: Failed to read configuration file "
75 << pwquality_strerror(buf.data(), buf.size(), rcrv, auxerror);
78 pwquality_read_config(pwq, configFile.toUtf8().constData(),
nullptr);
86 if (C_VALIDATOR().isWarningEnabled()) {
87 void *auxerror =
nullptr;
88 const int rcrv = pwquality_read_config(pwq,
nullptr, &auxerror);
90 QList<char> buf(ValidatorPwQualityPrivate::errStrBufSize);
91 qCWarning(C_VALIDATOR).noquote()
92 <<
"VaidatorPwQuality: Failed to read default configuration file:"
93 << pwquality_strerror(buf.data(), buf.size(), rcrv, auxerror);
96 pwquality_read_config(pwq,
nullptr,
nullptr);
100 const QByteArray pwba =
value.toUtf8();
101 const char *pw = pwba.constData();
102 const QByteArray opwba = oldPassword.toUtf8();
103 const char *opw = opwba.isEmpty() ? nullptr : opwba.constData();
104 const QByteArray uba = user.toUtf8();
105 const char *u = uba.isEmpty() ? nullptr : uba.constData();
107 rv = pwquality_check(pwq, pw, opw, u,
nullptr);
109 pwquality_free_settings(pwq);
112 rv = PWQ_ERROR_MEM_ALLOC;
115 rv = PWQ_ERROR_EMPTY_PASSWORD;
123 const QString &label,
128 if (
label.isEmpty()) {
129 switch (returnValue) {
130 case PWQ_ERROR_MEM_ALLOC:
132 c->
translate(
"Cutelyst::ValidatorPwQuality",
133 "Password quality check failed because of a memory allocation error.");
135 case PWQ_ERROR_SAME_PASSWORD:
136 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
137 "The password is the same as the old one.");
139 case PWQ_ERROR_PALINDROME:
140 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
"The password is a palindrome.");
142 case PWQ_ERROR_CASE_CHANGES_ONLY:
143 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
144 "The password differs with case changes only.");
146 case PWQ_ERROR_TOO_SIMILAR:
147 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
148 "The password is too similar to the old one.");
150 case PWQ_ERROR_USER_CHECK:
151 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
152 "The password contains the user name in some form.");
154 case PWQ_ERROR_GECOS_CHECK:
156 "Cutelyst::ValidatorPwQuality",
157 "The password contains words from the real name of the user in some form.");
159 case PWQ_ERROR_BAD_WORDS:
160 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
161 "The password contains forbidden words in some form.");
163 case PWQ_ERROR_MIN_DIGITS:
164 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
165 "The password contains too few digits.");
167 case PWQ_ERROR_MIN_UPPERS:
168 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
169 "The password contains too few uppercase letters.");
171 case PWQ_ERROR_MIN_LOWERS:
172 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
173 "The password contains too few lowercase letters.");
175 case PWQ_ERROR_MIN_OTHERS:
176 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
177 "The password contains too few non-alphanumeric characters.");
179 case PWQ_ERROR_MIN_LENGTH:
180 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
"The password is too short.");
182 case PWQ_ERROR_ROTATED:
183 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
184 "The password is just the rotated old one.");
186 case PWQ_ERROR_MIN_CLASSES:
187 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
188 "The password does not contain enough different character types.");
190 case PWQ_ERROR_MAX_CONSECUTIVE:
191 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
192 "The password contains too many same characters consecutively.");
194 case PWQ_ERROR_MAX_CLASS_REPEAT:
196 "Cutelyst::ValidatorPwQuality",
197 "The password contains too many characters of the same type consecutively.");
199 case PWQ_ERROR_MAX_SEQUENCE:
200 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
201 "The password contains too long a monotonous string.");
203 case PWQ_ERROR_EMPTY_PASSWORD:
204 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
"No password supplied.");
207 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
208 "Password quality check failed because we cannot obtain random "
209 "numbers from the RNG device.");
211 case PWQ_ERROR_CRACKLIB_CHECK:
212 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
213 "The password fails the dictionary check.");
215 case PWQ_ERROR_UNKNOWN_SETTING:
216 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
217 "Password quality check failed because of an unknown setting.");
219 case PWQ_ERROR_INTEGER:
221 "Cutelyst::ValidatorPwQuality",
222 "Password quality check failed because of a bad integer value in the settings.");
224 case PWQ_ERROR_NON_INT_SETTING:
225 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
226 "Password quality check failed because of a settings entry is not "
229 case PWQ_ERROR_NON_STR_SETTING:
231 "Cutelyst::ValidatorPwQuality",
232 "Password quality check failed because of a settings entry is not of string type.");
234 case PWQ_ERROR_CFGFILE_OPEN:
236 "Cutelyst::ValidatorPwQuality",
237 "Password quality check failed because opening the configuration file failed.");
239 case PWQ_ERROR_CFGFILE_MALFORMED:
241 "Cutelyst::ValidatorPwQuality",
242 "Password quality check failed because the configuration file is malformed.");
244 case PWQ_ERROR_FATAL_FAILURE:
245 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
246 "Password quality check failed because of a fatal failure.");
250 if (returnValue < 0) {
251 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
252 "Password quality check failed because of an unknown error.");
254 if (returnValue < threshold) {
256 "Cutelyst::ValidatorPwQuality",
257 "The password quality score of %1 is below the threshold of %2.")
258 .arg(QString::number(returnValue), QString::number(threshold));
264 switch (returnValue) {
265 case PWQ_ERROR_MEM_ALLOC:
266 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
267 "Password quality check for the “%1“ field failed because of a "
268 "memory allocation error.")
271 case PWQ_ERROR_SAME_PASSWORD:
272 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
273 "The password in the “%1” field is the same as the old one.")
276 case PWQ_ERROR_PALINDROME:
277 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
278 "The password in the “%1” field is a palindrome.")
281 case PWQ_ERROR_CASE_CHANGES_ONLY:
282 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
283 "The password in the “%1” field differs with case changes only.")
286 case PWQ_ERROR_TOO_SIMILAR:
287 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
288 "The password in the “%1” field is too similar to the old one.")
291 case PWQ_ERROR_USER_CHECK:
293 c->
translate(
"Cutelyst::ValidatorPwQuality",
294 "The password in the “%1” field contains the user name in some form.")
297 case PWQ_ERROR_GECOS_CHECK:
298 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
299 "The password in the “%1” field contains words from the real name "
300 "of the user name in some form.")
303 case PWQ_ERROR_BAD_WORDS:
305 "Cutelyst::ValidatorPwQuality",
306 "The password in the “%1” field contains forbidden words in some form.")
309 case PWQ_ERROR_MIN_DIGITS:
310 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
311 "The password in the “%1” field contains too few digits.")
314 case PWQ_ERROR_MIN_UPPERS:
316 c->
translate(
"Cutelyst::ValidatorPwQuality",
317 "The password in the “%1” field contains too few uppercase letters.")
320 case PWQ_ERROR_MIN_LOWERS:
322 c->
translate(
"Cutelyst::ValidatorPwQuality",
323 "The password in the “%1” field contains too few lowercase letters.")
326 case PWQ_ERROR_MIN_OTHERS:
329 "Cutelyst::ValidatorPwQuality",
330 "The password in the “%1” field contains too few non-alphanumeric characters.")
333 case PWQ_ERROR_MIN_LENGTH:
334 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
335 "The password in the “%1” field is too short.")
338 case PWQ_ERROR_ROTATED:
339 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
340 "The password in the “%1” field is just the rotated old one.")
343 case PWQ_ERROR_MIN_CLASSES:
345 "Cutelyst::ValidatorPwQuality",
346 "The password in the “%1” field does not contain enough character types.")
349 case PWQ_ERROR_MAX_CONSECUTIVE:
350 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
351 "The password in the “%1” field contains too many same characters "
355 case PWQ_ERROR_MAX_CLASS_REPEAT:
356 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
357 "The password in the “%1” field contains too many characters of "
358 "the same type consecutively.")
361 case PWQ_ERROR_MAX_SEQUENCE:
362 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
363 "The password in the “%1” field contains contains too long a "
364 "monotonous string.")
367 case PWQ_ERROR_EMPTY_PASSWORD:
368 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
369 "No password supplied in the “%1” field.")
373 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
374 "Password quality check for the “%1“ field failed because we "
375 "cannot obtain random numbers from the RNG device.")
378 case PWQ_ERROR_CRACKLIB_CHECK:
379 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
380 "The password in the “%1” field fails the dictionary check.")
383 case PWQ_ERROR_UNKNOWN_SETTING:
384 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
385 "Password quality check for the “%1“ field failed because of an "
389 case PWQ_ERROR_INTEGER:
390 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
391 "Password quality check for the “%1“ field failed because of a "
392 "bad integer value in the settings.")
395 case PWQ_ERROR_NON_INT_SETTING:
396 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
397 "Password quality check for the “%1“ field failed because of a "
398 "settings entry is not of integer type.")
401 case PWQ_ERROR_NON_STR_SETTING:
402 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
403 "Password quality check for the “%1“ field failed because of a "
404 "settings entry is not of string type.")
407 case PWQ_ERROR_CFGFILE_OPEN:
408 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
409 "Password quality check for the “%1“ field failed because opening "
410 "the configuration file failed.")
413 case PWQ_ERROR_CFGFILE_MALFORMED:
414 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
415 "Password quality check for the “%1“ field failed because the "
416 "configuration file is malformed.")
419 case PWQ_ERROR_FATAL_FAILURE:
422 "Cutelyst::ValidatorPwQuality",
423 "Password quality check for the “%1“ field failed because of a fatal failure.")
428 if (returnValue < 0) {
429 error = c->
translate(
"Cutelyst::ValidatorPwQuality",
430 "Password quality check for the “%1” field failed because of "
434 if (returnValue < threshold) {
436 c->
translate(
"Cutelyst::ValidatorPwQuality",
437 "The quality score of %1 for the password in the “%2” field "
438 "is below the threshold of %3.")
439 .arg(QString::number(returnValue),
label, QString::number(threshold));
453 const QString v =
value(params);
458 if (d->options.isValid()) {
459 if (d->options.typeId() == QMetaType::QVariantMap) {
461 }
else if (d->options.typeId() == QMetaType::QString) {
462 const QString optString = d->options.toString();
463 if (c->
stash().contains(optString)) {
464 opts = c->
stash(optString);
471 if (!d->userName.isEmpty()) {
472 un = params.value(d->userName);
474 un = c->
stash(d->userName).toString();
478 if (!d->oldPassword.isEmpty()) {
479 opw = params.value(d->oldPassword);
481 opw = c->
stash(d->oldPassword).toString();
484 int rv =
validate(v, opts, opw, un);
485 if (rv < d->threshold) {
487 if (C_VALIDATOR().isDebugEnabled()) {
489 QList<char> buf(ValidatorPwQualityPrivate::errStrBufSize);
490 qCDebug(C_VALIDATOR).noquote()
492 << pwquality_strerror(buf.data(), buf.size(), rv,
nullptr);
494 qCDebug(C_VALIDATOR).noquote() <<
debugString(c) <<
"The quality score" << rv
495 <<
"is below the threshold of" << d->threshold;
499 qCDebug(C_VALIDATOR).noquote()
500 <<
"ValidatorPwQuality: \"" << v <<
"\" got a quality score of" << rv;
void stash(const QVariantHash &unite)
QString translate(const char *context, const char *sourceText, const char *disambiguation=nullptr, int n=-1) const
Validates an input field with libpwquality to check password quality.
static QString errorString(Context *c, int returnValue, const QString &label=QString(), int threshold=0)
Returns a human readable string for the return value of ValidatorPwQuality::validate()
QString genericValidationError(Context *c, const QVariant &errorData) const override
Returns a generic error message if validation failed.
~ValidatorPwQuality() override
Deconstructs the ValidatorPwQuality.
ValidatorPwQuality(const QString &field, int threshold=ValidatorPwQuality::defaultThreshold, const QVariant &options=QVariant(), const QString &userName=QString(), const QString &oldPassword=QString(), const ValidatorMessages &messages=ValidatorMessages())
Constructs a new ValidatorPwQuality with the given parameters.
Base class for all validator rules.
QString label(Context *c) const
Returns the human readable field label used for generic error messages.
QString value(const ParamsMultiMap ¶ms) const
Returns the value of the field from the input params.
QString validationError(Context *c, const QVariant &errorData=QVariant()) const
Returns a descriptive error message if validation failed.
QString debugString(Context *c) const
Returns a string that can be used for debug output if validation fails.
static int validate(const QString &value, const QVariant &options=QVariant(), const QString &oldPassword=QString(), const QString &user=QString())
Returns the password quality score for value.
The Cutelyst namespace holds all public Cutelyst API.
QMultiMap< QString, QString > ParamsMultiMap
Stores custom error messages and the input field label.
Contains the result of a single input parameter validation.