10b0ecb56SDag-Erling Smørgrav /*
2402783abSDag-Erling Smørgrav * Copyright (c) 2000-2002 by Solar Designer. See LICENSE.
30b0ecb56SDag-Erling Smørgrav */
40b0ecb56SDag-Erling Smørgrav
50b0ecb56SDag-Erling Smørgrav #include <stdlib.h>
60b0ecb56SDag-Erling Smørgrav #include <string.h>
70b0ecb56SDag-Erling Smørgrav #include <ctype.h>
80b0ecb56SDag-Erling Smørgrav #include <pwd.h>
90b0ecb56SDag-Erling Smørgrav
100b0ecb56SDag-Erling Smørgrav #include "passwdqc.h"
110b0ecb56SDag-Erling Smørgrav
120b0ecb56SDag-Erling Smørgrav #define REASON_ERROR \
130b0ecb56SDag-Erling Smørgrav "check failed"
140b0ecb56SDag-Erling Smørgrav
150b0ecb56SDag-Erling Smørgrav #define REASON_SAME \
160b0ecb56SDag-Erling Smørgrav "is the same as the old one"
170b0ecb56SDag-Erling Smørgrav #define REASON_SIMILAR \
180b0ecb56SDag-Erling Smørgrav "is based on the old one"
190b0ecb56SDag-Erling Smørgrav
200b0ecb56SDag-Erling Smørgrav #define REASON_SHORT \
210b0ecb56SDag-Erling Smørgrav "too short"
220b0ecb56SDag-Erling Smørgrav #define REASON_LONG \
230b0ecb56SDag-Erling Smørgrav "too long"
240b0ecb56SDag-Erling Smørgrav
250b0ecb56SDag-Erling Smørgrav #define REASON_SIMPLESHORT \
260b0ecb56SDag-Erling Smørgrav "not enough different characters or classes for this length"
270b0ecb56SDag-Erling Smørgrav #define REASON_SIMPLE \
280b0ecb56SDag-Erling Smørgrav "not enough different characters or classes"
290b0ecb56SDag-Erling Smørgrav
300b0ecb56SDag-Erling Smørgrav #define REASON_PERSONAL \
310b0ecb56SDag-Erling Smørgrav "based on personal login information"
320b0ecb56SDag-Erling Smørgrav
330b0ecb56SDag-Erling Smørgrav #define REASON_WORD \
340b0ecb56SDag-Erling Smørgrav "based on a dictionary word and not a passphrase"
350b0ecb56SDag-Erling Smørgrav
360b0ecb56SDag-Erling Smørgrav #define FIXED_BITS 15
370b0ecb56SDag-Erling Smørgrav
380b0ecb56SDag-Erling Smørgrav typedef unsigned long fixed;
390b0ecb56SDag-Erling Smørgrav
400b0ecb56SDag-Erling Smørgrav /*
410b0ecb56SDag-Erling Smørgrav * Calculates the expected number of different characters for a random
420b0ecb56SDag-Erling Smørgrav * password of a given length. The result is rounded down. We use this
430b0ecb56SDag-Erling Smørgrav * with the _requested_ minimum length (so longer passwords don't have
440b0ecb56SDag-Erling Smørgrav * to meet this strict requirement for their length).
450b0ecb56SDag-Erling Smørgrav */
expected_different(int charset,int length)460b0ecb56SDag-Erling Smørgrav static int expected_different(int charset, int length)
470b0ecb56SDag-Erling Smørgrav {
480b0ecb56SDag-Erling Smørgrav fixed x, y, z;
490b0ecb56SDag-Erling Smørgrav
500b0ecb56SDag-Erling Smørgrav x = ((fixed)(charset - 1) << FIXED_BITS) / charset;
510b0ecb56SDag-Erling Smørgrav y = x;
520b0ecb56SDag-Erling Smørgrav while (--length > 0) y = (y * x) >> FIXED_BITS;
530b0ecb56SDag-Erling Smørgrav z = (fixed)charset * (((fixed)1 << FIXED_BITS) - y);
540b0ecb56SDag-Erling Smørgrav
550b0ecb56SDag-Erling Smørgrav return (int)(z >> FIXED_BITS);
560b0ecb56SDag-Erling Smørgrav }
570b0ecb56SDag-Erling Smørgrav
580b0ecb56SDag-Erling Smørgrav /*
590b0ecb56SDag-Erling Smørgrav * A password is too simple if it is too short for its class, or doesn't
600b0ecb56SDag-Erling Smørgrav * contain enough different characters for its class, or doesn't contain
610b0ecb56SDag-Erling Smørgrav * enough words for a passphrase.
620b0ecb56SDag-Erling Smørgrav */
is_simple(passwdqc_params_t * params,const char * newpass)63402783abSDag-Erling Smørgrav static int is_simple(passwdqc_params_t *params, const char *newpass)
640b0ecb56SDag-Erling Smørgrav {
650b0ecb56SDag-Erling Smørgrav int length, classes, words, chars;
660b0ecb56SDag-Erling Smørgrav int digits, lowers, uppers, others, unknowns;
670b0ecb56SDag-Erling Smørgrav int c, p;
680b0ecb56SDag-Erling Smørgrav
690b0ecb56SDag-Erling Smørgrav length = classes = words = chars = 0;
700b0ecb56SDag-Erling Smørgrav digits = lowers = uppers = others = unknowns = 0;
710b0ecb56SDag-Erling Smørgrav p = ' ';
720b0ecb56SDag-Erling Smørgrav while ((c = (unsigned char)newpass[length])) {
730b0ecb56SDag-Erling Smørgrav length++;
740b0ecb56SDag-Erling Smørgrav
750b0ecb56SDag-Erling Smørgrav if (!isascii(c)) unknowns++; else
760b0ecb56SDag-Erling Smørgrav if (isdigit(c)) digits++; else
770b0ecb56SDag-Erling Smørgrav if (islower(c)) lowers++; else
780b0ecb56SDag-Erling Smørgrav if (isupper(c)) uppers++; else
790b0ecb56SDag-Erling Smørgrav others++;
800b0ecb56SDag-Erling Smørgrav
810b0ecb56SDag-Erling Smørgrav if (isascii(c) && isalpha(c) && isascii(p) && !isalpha(p))
820b0ecb56SDag-Erling Smørgrav words++;
830b0ecb56SDag-Erling Smørgrav p = c;
840b0ecb56SDag-Erling Smørgrav
850b0ecb56SDag-Erling Smørgrav if (!strchr(&newpass[length], c))
860b0ecb56SDag-Erling Smørgrav chars++;
870b0ecb56SDag-Erling Smørgrav }
880b0ecb56SDag-Erling Smørgrav
890b0ecb56SDag-Erling Smørgrav if (!length) return 1;
900b0ecb56SDag-Erling Smørgrav
910b0ecb56SDag-Erling Smørgrav /* Upper case characters and digits used in common ways don't increase the
920b0ecb56SDag-Erling Smørgrav * strength of a password */
930b0ecb56SDag-Erling Smørgrav c = (unsigned char)newpass[0];
940b0ecb56SDag-Erling Smørgrav if (uppers && isascii(c) && isupper(c)) uppers--;
950b0ecb56SDag-Erling Smørgrav c = (unsigned char)newpass[length - 1];
960b0ecb56SDag-Erling Smørgrav if (digits && isascii(c) && isdigit(c)) digits--;
970b0ecb56SDag-Erling Smørgrav
980b0ecb56SDag-Erling Smørgrav /* Count the number of different character classes we've seen. We assume
990b0ecb56SDag-Erling Smørgrav * that there're no non-ASCII characters for digits. */
1000b0ecb56SDag-Erling Smørgrav classes = 0;
1010b0ecb56SDag-Erling Smørgrav if (digits) classes++;
1020b0ecb56SDag-Erling Smørgrav if (lowers) classes++;
1030b0ecb56SDag-Erling Smørgrav if (uppers) classes++;
1040b0ecb56SDag-Erling Smørgrav if (others) classes++;
1050b0ecb56SDag-Erling Smørgrav if (unknowns && (!classes || (digits && classes == 1))) classes++;
1060b0ecb56SDag-Erling Smørgrav
1070b0ecb56SDag-Erling Smørgrav for (; classes > 0; classes--)
1080b0ecb56SDag-Erling Smørgrav switch (classes) {
1090b0ecb56SDag-Erling Smørgrav case 1:
1100b0ecb56SDag-Erling Smørgrav if (length >= params->min[0] &&
1110b0ecb56SDag-Erling Smørgrav chars >= expected_different(10, params->min[0]) - 1)
1120b0ecb56SDag-Erling Smørgrav return 0;
1130b0ecb56SDag-Erling Smørgrav return 1;
1140b0ecb56SDag-Erling Smørgrav
1150b0ecb56SDag-Erling Smørgrav case 2:
1160b0ecb56SDag-Erling Smørgrav if (length >= params->min[1] &&
1170b0ecb56SDag-Erling Smørgrav chars >= expected_different(36, params->min[1]) - 1)
1180b0ecb56SDag-Erling Smørgrav return 0;
1190b0ecb56SDag-Erling Smørgrav if (!params->passphrase_words ||
1200b0ecb56SDag-Erling Smørgrav words < params->passphrase_words)
1210b0ecb56SDag-Erling Smørgrav continue;
1220b0ecb56SDag-Erling Smørgrav if (length >= params->min[2] &&
1230b0ecb56SDag-Erling Smørgrav chars >= expected_different(27, params->min[2]) - 1)
1240b0ecb56SDag-Erling Smørgrav return 0;
1250b0ecb56SDag-Erling Smørgrav continue;
1260b0ecb56SDag-Erling Smørgrav
1270b0ecb56SDag-Erling Smørgrav case 3:
1280b0ecb56SDag-Erling Smørgrav if (length >= params->min[3] &&
1290b0ecb56SDag-Erling Smørgrav chars >= expected_different(62, params->min[3]) - 1)
1300b0ecb56SDag-Erling Smørgrav return 0;
1310b0ecb56SDag-Erling Smørgrav continue;
1320b0ecb56SDag-Erling Smørgrav
1330b0ecb56SDag-Erling Smørgrav case 4:
1340b0ecb56SDag-Erling Smørgrav if (length >= params->min[4] &&
1350b0ecb56SDag-Erling Smørgrav chars >= expected_different(95, params->min[4]) - 1)
1360b0ecb56SDag-Erling Smørgrav return 0;
1370b0ecb56SDag-Erling Smørgrav continue;
1380b0ecb56SDag-Erling Smørgrav }
1390b0ecb56SDag-Erling Smørgrav
1400b0ecb56SDag-Erling Smørgrav return 1;
1410b0ecb56SDag-Erling Smørgrav }
1420b0ecb56SDag-Erling Smørgrav
unify(const char * src)143402783abSDag-Erling Smørgrav static char *unify(const char *src)
1440b0ecb56SDag-Erling Smørgrav {
145402783abSDag-Erling Smørgrav const char *sptr;
146402783abSDag-Erling Smørgrav char *dst, *dptr;
1470b0ecb56SDag-Erling Smørgrav int c;
1480b0ecb56SDag-Erling Smørgrav
1490b0ecb56SDag-Erling Smørgrav if (!(dst = malloc(strlen(src) + 1)))
1500b0ecb56SDag-Erling Smørgrav return NULL;
1510b0ecb56SDag-Erling Smørgrav
1520b0ecb56SDag-Erling Smørgrav sptr = src;
1530b0ecb56SDag-Erling Smørgrav dptr = dst;
1540b0ecb56SDag-Erling Smørgrav do {
1550b0ecb56SDag-Erling Smørgrav c = (unsigned char)*sptr;
1560b0ecb56SDag-Erling Smørgrav if (isascii(c) && isupper(c))
1570b0ecb56SDag-Erling Smørgrav *dptr++ = tolower(c);
1580b0ecb56SDag-Erling Smørgrav else
1590b0ecb56SDag-Erling Smørgrav *dptr++ = *sptr;
1600b0ecb56SDag-Erling Smørgrav } while (*sptr++);
1610b0ecb56SDag-Erling Smørgrav
1620b0ecb56SDag-Erling Smørgrav return dst;
1630b0ecb56SDag-Erling Smørgrav }
1640b0ecb56SDag-Erling Smørgrav
reverse(const char * src)165402783abSDag-Erling Smørgrav static char *reverse(const char *src)
1660b0ecb56SDag-Erling Smørgrav {
167402783abSDag-Erling Smørgrav const char *sptr;
168402783abSDag-Erling Smørgrav char *dst, *dptr;
1690b0ecb56SDag-Erling Smørgrav
1700b0ecb56SDag-Erling Smørgrav if (!(dst = malloc(strlen(src) + 1)))
1710b0ecb56SDag-Erling Smørgrav return NULL;
1720b0ecb56SDag-Erling Smørgrav
1730b0ecb56SDag-Erling Smørgrav sptr = &src[strlen(src)];
1740b0ecb56SDag-Erling Smørgrav dptr = dst;
1750b0ecb56SDag-Erling Smørgrav while (sptr > src)
1760b0ecb56SDag-Erling Smørgrav *dptr++ = *--sptr;
1770b0ecb56SDag-Erling Smørgrav *dptr = '\0';
1780b0ecb56SDag-Erling Smørgrav
1790b0ecb56SDag-Erling Smørgrav return dst;
1800b0ecb56SDag-Erling Smørgrav }
1810b0ecb56SDag-Erling Smørgrav
clean(char * dst)1820b0ecb56SDag-Erling Smørgrav static void clean(char *dst)
1830b0ecb56SDag-Erling Smørgrav {
1840b0ecb56SDag-Erling Smørgrav if (dst) {
1850b0ecb56SDag-Erling Smørgrav memset(dst, 0, strlen(dst));
1860b0ecb56SDag-Erling Smørgrav free(dst);
1870b0ecb56SDag-Erling Smørgrav }
1880b0ecb56SDag-Erling Smørgrav }
1890b0ecb56SDag-Erling Smørgrav
1900b0ecb56SDag-Erling Smørgrav /*
1910b0ecb56SDag-Erling Smørgrav * Needle is based on haystack if both contain a long enough common
1920b0ecb56SDag-Erling Smørgrav * substring and needle would be too simple for a password with the
1930b0ecb56SDag-Erling Smørgrav * substring removed.
1940b0ecb56SDag-Erling Smørgrav */
is_based(passwdqc_params_t * params,const char * haystack,const char * needle,const char * original)1950b0ecb56SDag-Erling Smørgrav static int is_based(passwdqc_params_t *params,
196402783abSDag-Erling Smørgrav const char *haystack, const char *needle, const char *original)
1970b0ecb56SDag-Erling Smørgrav {
1980b0ecb56SDag-Erling Smørgrav char *scratch;
1990b0ecb56SDag-Erling Smørgrav int length;
2000b0ecb56SDag-Erling Smørgrav int i, j;
201402783abSDag-Erling Smørgrav const char *p;
2020b0ecb56SDag-Erling Smørgrav int match;
2030b0ecb56SDag-Erling Smørgrav
2040b0ecb56SDag-Erling Smørgrav if (!params->match_length) /* disabled */
2050b0ecb56SDag-Erling Smørgrav return 0;
2060b0ecb56SDag-Erling Smørgrav
2070b0ecb56SDag-Erling Smørgrav if (params->match_length < 0) /* misconfigured */
2080b0ecb56SDag-Erling Smørgrav return 1;
2090b0ecb56SDag-Erling Smørgrav
2100b0ecb56SDag-Erling Smørgrav if (strstr(haystack, needle)) /* based on haystack entirely */
2110b0ecb56SDag-Erling Smørgrav return 1;
2120b0ecb56SDag-Erling Smørgrav
2130b0ecb56SDag-Erling Smørgrav scratch = NULL;
2140b0ecb56SDag-Erling Smørgrav
2150b0ecb56SDag-Erling Smørgrav length = strlen(needle);
2160b0ecb56SDag-Erling Smørgrav for (i = 0; i <= length - params->match_length; i++)
2170b0ecb56SDag-Erling Smørgrav for (j = params->match_length; i + j <= length; j++) {
2180b0ecb56SDag-Erling Smørgrav match = 0;
2190b0ecb56SDag-Erling Smørgrav for (p = haystack; *p; p++)
2200b0ecb56SDag-Erling Smørgrav if (*p == needle[i] && !strncmp(p, &needle[i], j)) {
2210b0ecb56SDag-Erling Smørgrav match = 1;
2220b0ecb56SDag-Erling Smørgrav if (!scratch) {
2230b0ecb56SDag-Erling Smørgrav if (!(scratch = malloc(length + 1)))
2240b0ecb56SDag-Erling Smørgrav return 1;
2250b0ecb56SDag-Erling Smørgrav }
2260b0ecb56SDag-Erling Smørgrav memcpy(scratch, original, i);
2270b0ecb56SDag-Erling Smørgrav memcpy(&scratch[i], &original[i + j],
2280b0ecb56SDag-Erling Smørgrav length + 1 - (i + j));
2290b0ecb56SDag-Erling Smørgrav if (is_simple(params, scratch)) {
2300b0ecb56SDag-Erling Smørgrav clean(scratch);
2310b0ecb56SDag-Erling Smørgrav return 1;
2320b0ecb56SDag-Erling Smørgrav }
2330b0ecb56SDag-Erling Smørgrav }
2340b0ecb56SDag-Erling Smørgrav if (!match) break;
2350b0ecb56SDag-Erling Smørgrav }
2360b0ecb56SDag-Erling Smørgrav
2370b0ecb56SDag-Erling Smørgrav clean(scratch);
2380b0ecb56SDag-Erling Smørgrav
2390b0ecb56SDag-Erling Smørgrav return 0;
2400b0ecb56SDag-Erling Smørgrav }
2410b0ecb56SDag-Erling Smørgrav
2420b0ecb56SDag-Erling Smørgrav /*
2430b0ecb56SDag-Erling Smørgrav * This wordlist check is now the least important given the checks above
2440b0ecb56SDag-Erling Smørgrav * and the support for passphrases (which are based on dictionary words,
2450b0ecb56SDag-Erling Smørgrav * and checked by other means). It is still useful to trap simple short
2460b0ecb56SDag-Erling Smørgrav * passwords (if short passwords are allowed) that are word-based, but
2470b0ecb56SDag-Erling Smørgrav * passed the other checks due to uncommon capitalization, digits, and
2480b0ecb56SDag-Erling Smørgrav * special characters. We (mis)use the same set of words that are used
2490b0ecb56SDag-Erling Smørgrav * to generate random passwords. This list is much smaller than those
2500b0ecb56SDag-Erling Smørgrav * used for password crackers, and it doesn't contain common passwords
2510b0ecb56SDag-Erling Smørgrav * that aren't short English words. Perhaps support for large wordlists
2520b0ecb56SDag-Erling Smørgrav * should still be added, even though this is now of little importance.
2530b0ecb56SDag-Erling Smørgrav */
is_word_based(passwdqc_params_t * params,const char * needle,const char * original)2540b0ecb56SDag-Erling Smørgrav static int is_word_based(passwdqc_params_t *params,
255402783abSDag-Erling Smørgrav const char *needle, const char *original)
2560b0ecb56SDag-Erling Smørgrav {
2570b0ecb56SDag-Erling Smørgrav char word[7];
2580b0ecb56SDag-Erling Smørgrav char *unified;
259402783abSDag-Erling Smørgrav int i;
2600b0ecb56SDag-Erling Smørgrav
2610b0ecb56SDag-Erling Smørgrav word[6] = '\0';
262402783abSDag-Erling Smørgrav for (i = 0; i < 0x1000; i++) {
263402783abSDag-Erling Smørgrav memcpy(word, _passwdqc_wordset_4k[i], 6);
264402783abSDag-Erling Smørgrav if ((int)strlen(word) < params->match_length) continue;
2650b0ecb56SDag-Erling Smørgrav unified = unify(word);
2660b0ecb56SDag-Erling Smørgrav if (is_based(params, unified, needle, original)) {
2670b0ecb56SDag-Erling Smørgrav clean(unified);
2680b0ecb56SDag-Erling Smørgrav return 1;
2690b0ecb56SDag-Erling Smørgrav }
2700b0ecb56SDag-Erling Smørgrav clean(unified);
2710b0ecb56SDag-Erling Smørgrav }
2720b0ecb56SDag-Erling Smørgrav
2730b0ecb56SDag-Erling Smørgrav return 0;
2740b0ecb56SDag-Erling Smørgrav }
2750b0ecb56SDag-Erling Smørgrav
_passwdqc_check(passwdqc_params_t * params,const char * newpass,const char * oldpass,struct passwd * pw)276402783abSDag-Erling Smørgrav const char *_passwdqc_check(passwdqc_params_t *params,
277402783abSDag-Erling Smørgrav const char *newpass, const char *oldpass, struct passwd *pw)
2780b0ecb56SDag-Erling Smørgrav {
2790b0ecb56SDag-Erling Smørgrav char truncated[9], *reversed;
2800b0ecb56SDag-Erling Smørgrav char *u_newpass, *u_reversed;
2810b0ecb56SDag-Erling Smørgrav char *u_oldpass;
2820b0ecb56SDag-Erling Smørgrav char *u_name, *u_gecos;
283402783abSDag-Erling Smørgrav const char *reason;
2840b0ecb56SDag-Erling Smørgrav int length;
2850b0ecb56SDag-Erling Smørgrav
2860b0ecb56SDag-Erling Smørgrav reversed = NULL;
2870b0ecb56SDag-Erling Smørgrav u_newpass = u_reversed = NULL;
2880b0ecb56SDag-Erling Smørgrav u_oldpass = NULL;
2890b0ecb56SDag-Erling Smørgrav u_name = u_gecos = NULL;
2900b0ecb56SDag-Erling Smørgrav
2910b0ecb56SDag-Erling Smørgrav reason = NULL;
2920b0ecb56SDag-Erling Smørgrav
2930b0ecb56SDag-Erling Smørgrav if (oldpass && !strcmp(oldpass, newpass))
2940b0ecb56SDag-Erling Smørgrav reason = REASON_SAME;
2950b0ecb56SDag-Erling Smørgrav
2960b0ecb56SDag-Erling Smørgrav length = strlen(newpass);
2970b0ecb56SDag-Erling Smørgrav
2980b0ecb56SDag-Erling Smørgrav if (!reason && length < params->min[4])
2990b0ecb56SDag-Erling Smørgrav reason = REASON_SHORT;
3000b0ecb56SDag-Erling Smørgrav
3010b0ecb56SDag-Erling Smørgrav if (!reason && length > params->max) {
3020b0ecb56SDag-Erling Smørgrav if (params->max == 8) {
3030b0ecb56SDag-Erling Smørgrav truncated[0] = '\0';
3040b0ecb56SDag-Erling Smørgrav strncat(truncated, newpass, 8);
3050b0ecb56SDag-Erling Smørgrav newpass = truncated;
3060b0ecb56SDag-Erling Smørgrav if (oldpass && !strncmp(oldpass, newpass, 8))
3070b0ecb56SDag-Erling Smørgrav reason = REASON_SAME;
3080b0ecb56SDag-Erling Smørgrav } else
3090b0ecb56SDag-Erling Smørgrav reason = REASON_LONG;
3100b0ecb56SDag-Erling Smørgrav }
3110b0ecb56SDag-Erling Smørgrav
3120b0ecb56SDag-Erling Smørgrav if (!reason && is_simple(params, newpass)) {
3130b0ecb56SDag-Erling Smørgrav if (length < params->min[1] && params->min[1] <= params->max)
3140b0ecb56SDag-Erling Smørgrav reason = REASON_SIMPLESHORT;
3150b0ecb56SDag-Erling Smørgrav else
3160b0ecb56SDag-Erling Smørgrav reason = REASON_SIMPLE;
3170b0ecb56SDag-Erling Smørgrav }
3180b0ecb56SDag-Erling Smørgrav
3190b0ecb56SDag-Erling Smørgrav if (!reason) {
3200b0ecb56SDag-Erling Smørgrav if ((reversed = reverse(newpass))) {
3210b0ecb56SDag-Erling Smørgrav u_newpass = unify(newpass);
3220b0ecb56SDag-Erling Smørgrav u_reversed = unify(reversed);
3230b0ecb56SDag-Erling Smørgrav if (oldpass)
3240b0ecb56SDag-Erling Smørgrav u_oldpass = unify(oldpass);
3250b0ecb56SDag-Erling Smørgrav if (pw) {
3260b0ecb56SDag-Erling Smørgrav u_name = unify(pw->pw_name);
3270b0ecb56SDag-Erling Smørgrav u_gecos = unify(pw->pw_gecos);
3280b0ecb56SDag-Erling Smørgrav }
3290b0ecb56SDag-Erling Smørgrav }
3300b0ecb56SDag-Erling Smørgrav if (!reversed ||
3310b0ecb56SDag-Erling Smørgrav !u_newpass || !u_reversed ||
3320b0ecb56SDag-Erling Smørgrav (oldpass && !u_oldpass) ||
3330b0ecb56SDag-Erling Smørgrav (pw && (!u_name || !u_gecos)))
3340b0ecb56SDag-Erling Smørgrav reason = REASON_ERROR;
3350b0ecb56SDag-Erling Smørgrav }
3360b0ecb56SDag-Erling Smørgrav
3370b0ecb56SDag-Erling Smørgrav if (!reason && oldpass && params->similar_deny &&
3380b0ecb56SDag-Erling Smørgrav (is_based(params, u_oldpass, u_newpass, newpass) ||
3390b0ecb56SDag-Erling Smørgrav is_based(params, u_oldpass, u_reversed, reversed)))
3400b0ecb56SDag-Erling Smørgrav reason = REASON_SIMILAR;
3410b0ecb56SDag-Erling Smørgrav
3420b0ecb56SDag-Erling Smørgrav if (!reason && pw &&
3430b0ecb56SDag-Erling Smørgrav (is_based(params, u_name, u_newpass, newpass) ||
3440b0ecb56SDag-Erling Smørgrav is_based(params, u_name, u_reversed, reversed) ||
3450b0ecb56SDag-Erling Smørgrav is_based(params, u_gecos, u_newpass, newpass) ||
3460b0ecb56SDag-Erling Smørgrav is_based(params, u_gecos, u_reversed, reversed)))
3470b0ecb56SDag-Erling Smørgrav reason = REASON_PERSONAL;
3480b0ecb56SDag-Erling Smørgrav
349402783abSDag-Erling Smørgrav if (!reason && (int)strlen(newpass) < params->min[2] &&
3500b0ecb56SDag-Erling Smørgrav (is_word_based(params, u_newpass, newpass) ||
3510b0ecb56SDag-Erling Smørgrav is_word_based(params, u_reversed, reversed)))
3520b0ecb56SDag-Erling Smørgrav reason = REASON_WORD;
3530b0ecb56SDag-Erling Smørgrav
3540b0ecb56SDag-Erling Smørgrav memset(truncated, 0, sizeof(truncated));
3550b0ecb56SDag-Erling Smørgrav clean(reversed);
3560b0ecb56SDag-Erling Smørgrav clean(u_newpass); clean(u_reversed);
3570b0ecb56SDag-Erling Smørgrav clean(u_oldpass);
3580b0ecb56SDag-Erling Smørgrav clean(u_name); clean(u_gecos);
3590b0ecb56SDag-Erling Smørgrav
3600b0ecb56SDag-Erling Smørgrav return reason;
3610b0ecb56SDag-Erling Smørgrav }
362