source: branches/3.2/mindi-busybox/libbb/obscure.c @ 3232

Last change on this file since 3232 was 3232, checked in by Bruno Cornec, 7 years ago
  • Update mindi-busybox to 1.21.1
File size: 4.5 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini weak password checker implementation for busybox
4 *
5 * Copyright (C) 2006 Tito Ragusa <farmatito@tiscali.it>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10/*  A good password:
11    1)  should contain at least six characters (man passwd);
12    2)  empty passwords are not permitted;
13    3)  should contain a mix of four different types of characters
14        upper case letters,
15        lower case letters,
16        numbers,
17        special characters such as !@#$%^&*,;".
18    This password types should not  be permitted:
19    a)  pure numbers: birthdates, social security number, license plate, phone numbers;
20    b)  words and all letters only passwords (uppercase, lowercase or mixed)
21        as palindromes, consecutive or repetitive letters
22        or adjacent letters on your keyboard;
23    c)  username, real name, company name or (e-mail?) address
24        in any form (as-is, reversed, capitalized, doubled, etc.).
25        (we can check only against username, gecos and hostname)
26    d)  common and obvious letter-number replacements
27        (e.g. replace the letter O with number 0)
28        such as "M1cr0$0ft" or "P@ssw0rd" (CAVEAT: we cannot check for them
29        without the use of a dictionary).
30
31    For each missing type of characters an increase of password length is
32    requested.
33
34    If user is root we warn only.
35
36    CAVEAT: some older versions of crypt() truncates passwords to 8 chars,
37    so that aaaaaaaa1Q$ is equal to aaaaaaaa making it possible to fool
38    some of our checks. We don't test for this special case as newer versions
39    of crypt do not truncate passwords.
40*/
41
42#include "libbb.h"
43
44static int string_checker_helper(const char *p1, const char *p2) __attribute__ ((__pure__));
45
46static int string_checker_helper(const char *p1, const char *p2)
47{
48    /* as sub-string */
49    if (strcasestr(p2, p1) != NULL
50    /* invert in case haystack is shorter than needle */
51     || strcasestr(p1, p2) != NULL
52    /* as-is or capitalized */
53    /* || strcasecmp(p1, p2) == 0 - 1st strcasestr should catch this too */
54    ) {
55        return 1;
56    }
57    return 0;
58}
59
60static int string_checker(const char *p1, const char *p2)
61{
62    int size, i;
63    /* check string */
64    int ret = string_checker_helper(p1, p2);
65    /* make our own copy */
66    char *p = xstrdup(p1);
67
68    /* reverse string */
69    i = size = strlen(p1);
70    while (--i >= 0) {
71        *p++ = p1[i];
72    }
73    p -= size; /* restore pointer */
74
75    /* check reversed string */
76    ret |= string_checker_helper(p, p2);
77
78    /* clean up */
79    memset(p, 0, size);
80    free(p);
81
82    return ret;
83}
84
85#define CATEGORIES  4
86
87#define LOWERCASE   1
88#define UPPERCASE   2
89#define NUMBERS     4
90#define SPECIAL     8
91
92#define LAST_CAT    8
93
94static const char *obscure_msg(const char *old_p, const char *new_p, const struct passwd *pw)
95{
96    unsigned length;
97    unsigned size;
98    unsigned mixed;
99    unsigned c;
100    unsigned i;
101    const char *p;
102    char *hostname;
103
104    /* size */
105    if (!new_p || (length = strlen(new_p)) < CONFIG_PASSWORD_MINLEN)
106        return "too short";
107
108    /* no username as-is, as sub-string, reversed, capitalized, doubled */
109    if (string_checker(new_p, pw->pw_name)) {
110        return "similar to username";
111    }
112#ifndef __BIONIC__
113    /* no gecos as-is, as sub-string, reversed, capitalized, doubled */
114    if (pw->pw_gecos[0] && string_checker(new_p, pw->pw_gecos)) {
115        return "similar to gecos";
116    }
117#endif
118    /* hostname as-is, as sub-string, reversed, capitalized, doubled */
119    hostname = safe_gethostname();
120    i = string_checker(new_p, hostname);
121    free(hostname);
122    if (i)
123        return "similar to hostname";
124
125    /* Should / Must contain a mix of: */
126    mixed = 0;
127    for (i = 0; i < length; i++) {
128        if (islower(new_p[i])) {        /* a-z */
129            mixed |= LOWERCASE;
130        } else if (isupper(new_p[i])) { /* A-Z */
131            mixed |= UPPERCASE;
132        } else if (isdigit(new_p[i])) { /* 0-9 */
133            mixed |= NUMBERS;
134        } else  {                       /* special characters */
135            mixed |= SPECIAL;
136        }
137        /* Count i'th char */
138        c = 0;
139        p = new_p;
140        while (1) {
141            p = strchr(p, new_p[i]);
142            if (p == NULL) {
143                break;
144            }
145            c++;
146            p++;
147            if (!*p) {
148                break;
149            }
150        }
151        /* More than 50% similar characters ? */
152        if (c*2 >= length) {
153            return "too many similar characters";
154        }
155    }
156
157    size = CONFIG_PASSWORD_MINLEN + 2*CATEGORIES;
158    for (i = 1; i <= LAST_CAT; i <<= 1)
159        if (mixed & i)
160            size -= 2;
161    if (length < size)
162        return "too weak";
163
164    if (old_p && old_p[0]) {
165        /* check vs. old password */
166        if (string_checker(new_p, old_p)) {
167            return "similar to old password";
168        }
169    }
170
171    return NULL;
172}
173
174int FAST_FUNC obscure(const char *old, const char *newval, const struct passwd *pw)
175{
176    const char *msg;
177
178    msg = obscure_msg(old, newval, pw);
179    if (msg) {
180        printf("Bad password: %s\n", msg);
181        return 1;
182    }
183    return 0;
184}
Note: See TracBrowser for help on using the repository browser.