blob: 6244970de2f88615c2524af016de16d50ac1b9d2 [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
"Vladimir N. Oleynik"1f17d322006-01-31 12:36:51 +0000165 else if ( strstr(newval, pwdp->pw_name) )
Rob Landleybec26522006-02-05 03:31:44 +0000166 msg = "username in password";
"Vladimir N. Oleynik"1f17d322006-01-31 12:36:51 +0000167
Eric Andersen3124a9e2003-07-30 07:57:06 +0000168 else {
169 safe_strncpy(wrapped + lenwrap, wrapped, lenwrap + 1);
170 if (strstr(wrapped, newmono))
171 msg = "rotated";
172 }
Eric Andersen27f64e12002-06-23 04:24:25 +0000173
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +0000174 memset(newmono, 0, strlen(newmono));
175 memset(wrapped, 0, lenwrap * 2);
Eric Andersen27f64e12002-06-23 04:24:25 +0000176 free(newmono);
Eric Andersen27f64e12002-06-23 04:24:25 +0000177 free(wrapped);
178
179 return msg;
180}
181
Eric Andersen71ae64b2002-10-10 04:20:21 +0000182static const char *
183obscure_msg(const char *old, const char *newval, const struct passwd *pwdp)
Eric Andersen27f64e12002-06-23 04:24:25 +0000184{
185 int maxlen, oldlen, newlen;
Eric Andersen71ae64b2002-10-10 04:20:21 +0000186 char *new1, *old1;
187 const char *msg;
Eric Andersen27f64e12002-06-23 04:24:25 +0000188
189 oldlen = strlen(old);
190 newlen = strlen(newval);
191
"Vladimir N. Oleynik"1f17d322006-01-31 12:36:51 +0000192#if 0 /* why not check the password when set for the first time? --marekm */
Eric Andersen27f64e12002-06-23 04:24:25 +0000193 if (old[0] == '\0')
194 /* return (1); */
195 return NULL;
196#endif
197
198 if (newlen < 5)
199 return "too short";
200
201 /*
202 * Remaining checks are optional.
203 */
204 /* Not for us -- Sean
205 *if (!getdef_bool("OBSCURE_CHECKS_ENAB"))
206 * return NULL;
207 */
208 msg = password_check(old, newval, pwdp);
209 if (msg)
210 return msg;
211
212 /* The traditional crypt() truncates passwords to 8 chars. It is
213 possible to circumvent the above checks by choosing an easy
214 8-char password and adding some random characters to it...
215 Example: "password$%^&*123". So check it again, this time
216 truncated to the maximum length. Idea from npasswd. --marekm */
217
218 maxlen = 8;
219 if (oldlen <= maxlen && newlen <= maxlen)
220 return NULL;
221
Manuel Novoa III cad53642003-03-19 09:13:01 +0000222 new1 = (char *) bb_xstrdup(newval);
223 old1 = (char *) bb_xstrdup(old);
Eric Andersen27f64e12002-06-23 04:24:25 +0000224 if (newlen > maxlen)
225 new1[maxlen] = '\0';
226 if (oldlen > maxlen)
227 old1[maxlen] = '\0';
228
229 msg = password_check(old1, new1, pwdp);
230
Bernhard Reutner-Fischerdd9dce12006-01-12 15:38:12 +0000231 memset(new1, 0, newlen);
232 memset(old1, 0, oldlen);
Eric Andersen27f64e12002-06-23 04:24:25 +0000233 free(new1);
234 free(old1);
235
236 return msg;
237}
238
239/*
240 * Obscure - see if password is obscure enough.
241 *
242 * The programmer is encouraged to add as much complexity to this
243 * routine as desired. Included are some of my favorite ways to
244 * check passwords.
245 */
246
Rob Landleydfba7412006-03-06 20:47:33 +0000247int obscure(const char *old, const char *newval, const struct passwd *pwdp)
Eric Andersen27f64e12002-06-23 04:24:25 +0000248{
Eric Andersen71ae64b2002-10-10 04:20:21 +0000249 const char *msg = obscure_msg(old, newval, pwdp);
Eric Andersen27f64e12002-06-23 04:24:25 +0000250
251 /* if (msg) { */
252 if (msg != NULL) {
253 printf("Bad password: %s.\n", msg);
254 /* return 0; */
255 return 1;
256 }
257 /* return 1; */
258 return 0;
259}