1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
49 if (strcasestr(p2, p1) != NULL
50
51 || strcasestr(p1, p2) != NULL
52
53
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
64 int ret = string_checker_helper(p1, p2);
65
66 char *p = xstrdup(p1);
67
68
69 i = size = strlen(p1);
70 while (--i >= 0) {
71 *p++ = p1[i];
72 }
73 p -= size;
74
75
76 ret |= string_checker_helper(p, p2);
77
78
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
105 if (!new_p || (length = strlen(new_p)) < CONFIG_PASSWORD_MINLEN)
106 return "too short";
107
108
109 if (string_checker(new_p, pw->pw_name)) {
110 return "similar to username";
111 }
112
113 if (pw->pw_gecos[0] && string_checker(new_p, pw->pw_gecos)) {
114 return "similar to gecos";
115 }
116
117 hostname = safe_gethostname();
118 i = string_checker(new_p, hostname);
119 free(hostname);
120 if (i)
121 return "similar to hostname";
122
123
124 mixed = 0;
125 for (i = 0; i < length; i++) {
126 if (islower(new_p[i])) {
127 mixed |= LOWERCASE;
128 } else if (isupper(new_p[i])) {
129 mixed |= UPPERCASE;
130 } else if (isdigit(new_p[i])) {
131 mixed |= NUMBERS;
132 } else {
133 mixed |= SPECIAL;
134 }
135
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
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
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}
183