source: MondoRescue/branches/2.2.9/mindi-busybox/libbb/obscure.c@ 2725

Last change on this file since 2725 was 2725, checked in by Bruno Cornec, 13 years ago
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
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 /* no gecos as-is, as sub-string, reversed, capitalized, doubled */
113 if (pw->pw_gecos[0] && string_checker(new_p, pw->pw_gecos)) {
114 return "similar to gecos";
115 }
116 /* hostname as-is, as sub-string, reversed, capitalized, doubled */
117 hostname = safe_gethostname();
118 i = string_checker(new_p, hostname);
119 free(hostname);
120 if (i)
121 return "similar to hostname";
122
123 /* Should / Must contain a mix of: */
124 mixed = 0;
125 for (i = 0; i < length; i++) {
126 if (islower(new_p[i])) { /* a-z */
127 mixed |= LOWERCASE;
128 } else if (isupper(new_p[i])) { /* A-Z */
129 mixed |= UPPERCASE;
130 } else if (isdigit(new_p[i])) { /* 0-9 */
131 mixed |= NUMBERS;
132 } else { /* special characters */
133 mixed |= SPECIAL;
134 }
135 /* Count i'th char */
136 c = 0;
137 p = new_p;
138 while (1) {
139 p = strchr(p, new_p[i]);
140 if (p == NULL) {
141 break;
142 }
143 c++;
144 p++;
145 if (!*p) {
146 break;
147 }
148 }
149 /* More than 50% similar characters ? */
150 if (c*2 >= length) {
151 return "too many similar characters";
152 }
153 }
154
155 size = CONFIG_PASSWORD_MINLEN + 2*CATEGORIES;
156 for (i = 1; i <= LAST_CAT; i <<= 1)
157 if (mixed & i)
158 size -= 2;
159 if (length < size)
160 return "too weak";
161
162 if (old_p && old_p[0]) {
163 /* check vs. old password */
164 if (string_checker(new_p, old_p)) {
165 return "similar to old password";
166 }
167 }
168
169 return NULL;
170}
171
172int FAST_FUNC obscure(const char *old, const char *newval, const struct passwd *pw)
173{
174 const char *msg;
175
176 msg = obscure_msg(old, newval, pw);
177 if (msg) {
178 printf("Bad password: %s\n", msg);
179 return 1;
180 }
181 return 0;
182}
Note: See TracBrowser for help on using the repository browser.