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