Magellan Linux

Contents of /tags/mkinitrd-6_2_0/busybox/libbb/obscure.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 996 - (show annotations) (download)
Sun May 30 11:54:28 2010 UTC (14 years ago) by niro
File MIME type: text/plain
File size: 4555 byte(s)
tagged 'mkinitrd-6_2_0'
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 tarball for details.
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
44 static int string_checker_helper(const char *p1, const char *p2) __attribute__ ((__pure__));
45
46 static int string_checker_helper(const char *p1, const char *p2)
47 {
48 /* as-is or capitalized */
49 if (strcasecmp(p1, p2) == 0
50 /* as sub-string */
51 || strcasestr(p2, p1) != NULL
52 /* invert in case haystack is shorter than needle */
53 || strcasestr(p1, p2) != NULL)
54 return 1;
55 return 0;
56 }
57
58 static int string_checker(const char *p1, const char *p2)
59 {
60 int size;
61 /* check string */
62 int ret = string_checker_helper(p1, p2);
63 /* Make our own copy */
64 char *p = xstrdup(p1);
65 /* reverse string */
66 size = strlen(p);
67
68 while (size--) {
69 *p = p1[size];
70 p++;
71 }
72 /* restore pointer */
73 p -= strlen(p1);
74 /* check reversed string */
75 ret |= string_checker_helper(p, p2);
76 /* clean up */
77 memset(p, 0, strlen(p1));
78 free(p);
79 return ret;
80 }
81
82 #define LOWERCASE 1
83 #define UPPERCASE 2
84 #define NUMBERS 4
85 #define SPECIAL 8
86
87 static const char *obscure_msg(const char *old_p, const char *new_p, const struct passwd *pw)
88 {
89 int i;
90 int c;
91 int length;
92 int mixed = 0;
93 /* Add 2 for each type of characters to the minlen of password */
94 int size = CONFIG_PASSWORD_MINLEN + 8;
95 const char *p;
96 char *hostname;
97
98 /* size */
99 if (!new_p || (length = strlen(new_p)) < CONFIG_PASSWORD_MINLEN)
100 return "too short";
101
102 /* no username as-is, as sub-string, reversed, capitalized, doubled */
103 if (string_checker(new_p, pw->pw_name)) {
104 return "similar to username";
105 }
106 /* no gecos as-is, as sub-string, reversed, capitalized, doubled */
107 if (*pw->pw_gecos && string_checker(new_p, pw->pw_gecos)) {
108 return "similar to gecos";
109 }
110 /* hostname as-is, as sub-string, reversed, capitalized, doubled */
111 hostname = safe_gethostname();
112 i = string_checker(new_p, hostname);
113 free(hostname);
114 if (i)
115 return "similar to hostname";
116
117 /* Should / Must contain a mix of: */
118 for (i = 0; i < length; i++) {
119 if (islower(new_p[i])) { /* a-z */
120 mixed |= LOWERCASE;
121 } else if (isupper(new_p[i])) { /* A-Z */
122 mixed |= UPPERCASE;
123 } else if (isdigit(new_p[i])) { /* 0-9 */
124 mixed |= NUMBERS;
125 } else { /* special characters */
126 mixed |= SPECIAL;
127 }
128 /* More than 50% similar characters ? */
129 c = 0;
130 p = new_p;
131 while (1) {
132 p = strchr(p, new_p[i]);
133 if (p == NULL) {
134 break;
135 }
136 c++;
137 if (!++p) {
138 break; /* move past the matched char if possible */
139 }
140 }
141
142 if (c >= (length / 2)) {
143 return "too many similar characters";
144 }
145 }
146 for (i=0; i<4; i++)
147 if (mixed & (1<<i)) size -= 2;
148 if (length < size)
149 return "too weak";
150
151 if (old_p && old_p[0] != '\0') {
152 /* check vs. old password */
153 if (string_checker(new_p, old_p)) {
154 return "similar to old password";
155 }
156 }
157 return NULL;
158 }
159
160 int FAST_FUNC obscure(const char *old, const char *newval, const struct passwd *pw)
161 {
162 const char *msg;
163
164 msg = obscure_msg(old, newval, pw);
165 if (msg) {
166 printf("Bad password: %s\n", msg);
167 return 1;
168 }
169 return 0;
170 }