blob: 18373510fd198ac68f18c772f7d525175b3d1d6e [file] [log] [blame]
Eric Andersen27f64e12002-06-23 04:24:25 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Copyright 1989 - 1994, Julianne Frances Haugh <jockgrrl@austin.rr.com>
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +00004 * Copyright 2006, Bernhard Fischer <busybox@busybox.net>
Eric Andersen27f64e12002-06-23 04:24:25 +00005 * 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
Eric Andersen71ae64b2002-10-10 04:20:21 +000048static int palindrome(const char *newval)
Eric Andersen27f64e12002-06-23 04:24:25 +000049{
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
65static 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
Eric Andersen71ae64b2002-10-10 04:20:21 +000083static int simple(const char *newval)
Eric Andersen27f64e12002-06-23 04:24:25 +000084{
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +000085#define digits 1
86#define uppers 2
Bernhard Reutner-Fischer853c44b2006-01-13 12:03:26 +000087#define lowers 4
88#define others 8
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +000089 int c, is_simple = 0;
Eric Andersen27f64e12002-06-23 04:24:25 +000090 int size;
91 int i;
92
Eric Andersen71ae64b2002-10-10 04:20:21 +000093 for (i = 0; (c = *newval++) != 0; i++) {
94 if (isdigit(c))
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +000095 is_simple |= digits;
Eric Andersen71ae64b2002-10-10 04:20:21 +000096 else if (isupper(c))
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +000097 is_simple |= uppers;
Eric Andersen71ae64b2002-10-10 04:20:21 +000098 else if (islower(c))
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +000099 is_simple |= lowers;
Eric Andersen27f64e12002-06-23 04:24:25 +0000100 else
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +0000101 is_simple |= others;
Eric Andersen27f64e12002-06-23 04:24:25 +0000102 }
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;
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +0000110 if (is_simple & digits)
Eric Andersen27f64e12002-06-23 04:24:25 +0000111 size--;
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +0000112 if (is_simple & uppers)
Eric Andersen27f64e12002-06-23 04:24:25 +0000113 size--;
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +0000114 if (is_simple & lowers)
Eric Andersen27f64e12002-06-23 04:24:25 +0000115 size--;
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +0000116 if (is_simple & others)
Eric Andersen27f64e12002-06-23 04:24:25 +0000117 size--;
118
119 if (size <= i)
120 return 0;
121
122 return 1;
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +0000123#undef digits
124#undef uppers
125#undef lowers
126#undef others
Eric Andersen27f64e12002-06-23 04:24:25 +0000127}
128
129static 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
Eric Andersen71ae64b2002-10-10 04:20:21 +0000138static const char *
139password_check(const char *old, const char *newval, const struct passwd *pwdp)
Eric Andersen27f64e12002-06-23 04:24:25 +0000140{
Eric Andersen71ae64b2002-10-10 04:20:21 +0000141 const char *msg;
142 char *newmono, *wrapped;
143 int lenwrap;
Eric Andersen27f64e12002-06-23 04:24:25 +0000144
145 if (strcmp(newval, old) == 0)
146 return "no change";
Eric Andersen71ae64b2002-10-10 04:20:21 +0000147 if (simple(newval))
148 return "too simple";
Eric Andersen27f64e12002-06-23 04:24:25 +0000149
Eric Andersen71ae64b2002-10-10 04:20:21 +0000150 msg = NULL;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000151 newmono = str_lower(bb_xstrdup(newval));
Eric Andersen481772a2003-08-06 08:33:08 +0000152 lenwrap = strlen(old);
153 wrapped = (char *) xmalloc(lenwrap * 2 + 1);
Eric Andersen71ae64b2002-10-10 04:20:21 +0000154 str_lower(strcpy(wrapped, old));
Eric Andersen27f64e12002-06-23 04:24:25 +0000155
Eric Andersen71ae64b2002-10-10 04:20:21 +0000156 if (palindrome(newmono))
Eric Andersen27f64e12002-06-23 04:24:25 +0000157 msg = "a palindrome";
158
Eric Andersen71ae64b2002-10-10 04:20:21 +0000159 else if (strcmp(wrapped, newmono) == 0)
Eric Andersen27f64e12002-06-23 04:24:25 +0000160 msg = "case changes only";
161
Eric Andersen71ae64b2002-10-10 04:20:21 +0000162 else if (similiar(wrapped, newmono))
Eric Andersen27f64e12002-06-23 04:24:25 +0000163 msg = "too similiar";
164
Eric Andersen3124a9e2003-07-30 07:57:06 +0000165 else {
166 safe_strncpy(wrapped + lenwrap, wrapped, lenwrap + 1);
167 if (strstr(wrapped, newmono))
168 msg = "rotated";
169 }
Eric Andersen27f64e12002-06-23 04:24:25 +0000170
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +0000171 memset(newmono, 0, strlen(newmono));
172 memset(wrapped, 0, lenwrap * 2);
Eric Andersen27f64e12002-06-23 04:24:25 +0000173 free(newmono);
Eric Andersen27f64e12002-06-23 04:24:25 +0000174 free(wrapped);
175
176 return msg;
177}
178
Eric Andersen71ae64b2002-10-10 04:20:21 +0000179static const char *
180obscure_msg(const char *old, const char *newval, const struct passwd *pwdp)
Eric Andersen27f64e12002-06-23 04:24:25 +0000181{
182 int maxlen, oldlen, newlen;
Eric Andersen71ae64b2002-10-10 04:20:21 +0000183 char *new1, *old1;
184 const char *msg;
Eric Andersen27f64e12002-06-23 04:24:25 +0000185
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
Manuel Novoa III cad53642003-03-19 09:13:01 +0000219 new1 = (char *) bb_xstrdup(newval);
220 old1 = (char *) bb_xstrdup(old);
Eric Andersen27f64e12002-06-23 04:24:25 +0000221 if (newlen > maxlen)
222 new1[maxlen] = '\0';
223 if (oldlen > maxlen)
224 old1[maxlen] = '\0';
225
226 msg = password_check(old1, new1, pwdp);
227
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +0000228 memset(new1, 0, newlen);
229 memset(old1, 0, oldlen);
Eric Andersen27f64e12002-06-23 04:24:25 +0000230 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
244extern int obscure(const char *old, const char *newval, const struct passwd *pwdp)
245{
Eric Andersen71ae64b2002-10-10 04:20:21 +0000246 const char *msg = obscure_msg(old, newval, pwdp);
Eric Andersen27f64e12002-06-23 04:24:25 +0000247
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}