Patch last_pach62 from vodz. This patch moves all the /proc parsing
[oweals/busybox.git] / libbb / obscure.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Copyright 1989 - 1994, Julianne Frances Haugh <jockgrrl@austin.rr.com>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 /*
32  * This version of obscure.c contains modifications to support "cracklib"
33  * by Alec Muffet (alec.muffett@uk.sun.com).  You must obtain the Cracklib
34  * library source code for this function to operate.
35  */
36
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include "libbb.h"
42
43 /*
44  * can't be a palindrome - like `R A D A R' or `M A D A M'
45  */
46
47 static int palindrome(const char *newval)
48 {
49         int i, j;
50
51         i = strlen(newval);
52
53         for (j = 0; j < i; j++)
54                 if (newval[i - j - 1] != newval[j])
55                         return 0;
56
57         return 1;
58 }
59
60 /*
61  * more than half of the characters are different ones.
62  */
63
64 static int similiar(const char *old, const char *newval)
65 {
66         int i, j;
67
68         for (i = j = 0; newval[i] && old[i]; i++)
69                 if (strchr(newval, old[i]))
70                         j++;
71
72         if (i >= j * 2)
73                 return 0;
74
75         return 1;
76 }
77
78 /*
79  * a nice mix of characters.
80  */
81
82 static int simple(const char *newval)
83 {
84         int digits = 0;
85         int uppers = 0;
86         int lowers = 0;
87         int others = 0;
88         int c;
89         int size;
90         int i;
91
92         for (i = 0; (c = *newval++) != 0; i++) {
93                 if (isdigit(c))
94                         digits = c;
95                 else if (isupper(c))
96                         uppers = c;
97                 else if (islower(c))
98                         lowers = c;
99                 else
100                         others = c;
101         }
102
103         /*
104          * The scam is this - a password of only one character type
105          * must be 8 letters long.  Two types, 7, and so on.
106          */
107
108         size = 9;
109         if (digits)
110                 size--;
111         if (uppers)
112                 size--;
113         if (lowers)
114                 size--;
115         if (others)
116                 size--;
117
118         if (size <= i)
119                 return 0;
120
121         return 1;
122 }
123
124 static char *str_lower(char *string)
125 {
126         char *cp;
127
128         for (cp = string; *cp; cp++)
129                 *cp = tolower(*cp);
130         return string;
131 }
132
133 static const char *
134 password_check(const char *old, const char *newval, const struct passwd *pwdp)
135 {
136         const char *msg;
137         char *newmono, *wrapped;
138         int lenwrap;
139
140         if (strcmp(newval, old) == 0)
141                 return "no change";
142         if (simple(newval))
143                 return "too simple";
144
145         msg = NULL;
146         newmono = str_lower(xstrdup(newval));
147         lenwrap = strlen(old) * 2 + 1;
148         wrapped = (char *) xmalloc(lenwrap);
149         str_lower(strcpy(wrapped, old));
150
151         if (palindrome(newmono))
152                 msg = "a palindrome";
153
154         else if (strcmp(wrapped, newmono) == 0)
155                 msg = "case changes only";
156
157         else if (similiar(wrapped, newmono))
158                 msg = "too similiar";
159
160         else if (strstr(strcat(wrapped, wrapped), newmono))
161                 msg = "rotated";
162
163         bzero(newmono, strlen(newmono));
164         bzero(wrapped, lenwrap);
165         free(newmono);
166         free(wrapped);
167
168         return msg;
169 }
170
171 static const char *
172 obscure_msg(const char *old, const char *newval, const struct passwd *pwdp)
173 {
174         int maxlen, oldlen, newlen;
175         char *new1, *old1;
176         const char *msg;
177
178         oldlen = strlen(old);
179         newlen = strlen(newval);
180
181 #if 0                                                   /* why not check the password when set for the first time?  --marekm */
182         if (old[0] == '\0')
183                 /* return (1); */
184                 return NULL;
185 #endif
186
187         if (newlen < 5)
188                 return "too short";
189
190         /*
191          * Remaining checks are optional.
192          */
193         /* Not for us -- Sean
194          *if (!getdef_bool("OBSCURE_CHECKS_ENAB"))
195          *      return NULL;
196          */
197         msg = password_check(old, newval, pwdp);
198         if (msg)
199                 return msg;
200
201         /* The traditional crypt() truncates passwords to 8 chars.  It is
202            possible to circumvent the above checks by choosing an easy
203            8-char password and adding some random characters to it...
204            Example: "password$%^&*123".  So check it again, this time
205            truncated to the maximum length.  Idea from npasswd.  --marekm */
206
207         maxlen = 8;
208         if (oldlen <= maxlen && newlen <= maxlen)
209                 return NULL;
210
211         new1 = (char *) xstrdup(newval);
212         old1 = (char *) xstrdup(old);
213         if (newlen > maxlen)
214                 new1[maxlen] = '\0';
215         if (oldlen > maxlen)
216                 old1[maxlen] = '\0';
217
218         msg = password_check(old1, new1, pwdp);
219
220         bzero(new1, newlen);
221         bzero(old1, oldlen);
222         free(new1);
223         free(old1);
224
225         return msg;
226 }
227
228 /*
229  * Obscure - see if password is obscure enough.
230  *
231  *      The programmer is encouraged to add as much complexity to this
232  *      routine as desired.  Included are some of my favorite ways to
233  *      check passwords.
234  */
235
236 extern int obscure(const char *old, const char *newval, const struct passwd *pwdp)
237 {
238         const char *msg = obscure_msg(old, newval, pwdp);
239
240         /*  if (msg) { */
241         if (msg != NULL) {
242                 printf("Bad password: %s.\n", msg);
243                 /* return 0; */
244                 return 1;
245         }
246         /* return 1; */
247         return 0;
248 }