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 (strcasecmp(p1, p2) == 0
50
51 || strcasestr(p2, p1) != NULL
52
53 || strcasestr(p1, p2) != NULL)
54 return 1;
55 return 0;
56}
57
58static int string_checker(const char *p1, const char *p2)
59{
60 int size;
61
62 int ret = string_checker_helper(p1, p2);
63
64 char *p = xstrdup(p1);
65
66 size = strlen(p);
67
68 while (size--) {
69 *p = p1[size];
70 p++;
71 }
72
73 p -= strlen(p1);
74
75 ret |= string_checker_helper(p, p2);
76
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
87static 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
94 int size = CONFIG_PASSWORD_MINLEN + 8;
95 const char *p;
96 char *hostname;
97
98
99 if (!new_p || (length = strlen(new_p)) < CONFIG_PASSWORD_MINLEN)
100 return "too short";
101
102
103 if (string_checker(new_p, pw->pw_name)) {
104 return "similar to username";
105 }
106
107 if (*pw->pw_gecos && string_checker(new_p, pw->pw_gecos)) {
108 return "similar to gecos";
109 }
110
111 hostname = safe_gethostname();
112 i = string_checker(new_p, hostname);
113 free(hostname);
114 if (i)
115 return "similar to hostname";
116
117
118 for (i = 0; i < length; i++) {
119 if (islower(new_p[i])) {
120 mixed |= LOWERCASE;
121 } else if (isupper(new_p[i])) {
122 mixed |= UPPERCASE;
123 } else if (isdigit(new_p[i])) {
124 mixed |= NUMBERS;
125 } else {
126 mixed |= SPECIAL;
127 }
128
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;
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
153 if (string_checker(new_p, old_p)) {
154 return "similar to old password";
155 }
156 }
157 return NULL;
158}
159
160int 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}
171