blob: aa15e409717f2fc40d423cf87fd9c5d080326b7a [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>
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
Eric Andersen71ae64b2002-10-10 04:20:21 +000047static int palindrome(const char *newval)
Eric Andersen27f64e12002-06-23 04:24:25 +000048{
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
64static 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
Eric Andersen71ae64b2002-10-10 04:20:21 +000082static int simple(const char *newval)
Eric Andersen27f64e12002-06-23 04:24:25 +000083{
84 int digits = 0;
85 int uppers = 0;
86 int lowers = 0;
87 int others = 0;
Eric Andersen71ae64b2002-10-10 04:20:21 +000088 int c;
Eric Andersen27f64e12002-06-23 04:24:25 +000089 int size;
90 int i;
91
Eric Andersen71ae64b2002-10-10 04:20:21 +000092 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;
Eric Andersen27f64e12002-06-23 04:24:25 +000099 else
Eric Andersen71ae64b2002-10-10 04:20:21 +0000100 others = c;
Eric Andersen27f64e12002-06-23 04:24:25 +0000101 }
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
124static 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
Eric Andersen71ae64b2002-10-10 04:20:21 +0000133static const char *
134password_check(const char *old, const char *newval, const struct passwd *pwdp)
Eric Andersen27f64e12002-06-23 04:24:25 +0000135{
Eric Andersen71ae64b2002-10-10 04:20:21 +0000136 const char *msg;
137 char *newmono, *wrapped;
138 int lenwrap;
Eric Andersen27f64e12002-06-23 04:24:25 +0000139
140 if (strcmp(newval, old) == 0)
141 return "no change";
Eric Andersen71ae64b2002-10-10 04:20:21 +0000142 if (simple(newval))
143 return "too simple";
Eric Andersen27f64e12002-06-23 04:24:25 +0000144
Eric Andersen71ae64b2002-10-10 04:20:21 +0000145 msg = NULL;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000146 newmono = str_lower(bb_xstrdup(newval));
Eric Andersen481772a2003-08-06 08:33:08 +0000147 lenwrap = strlen(old);
148 wrapped = (char *) xmalloc(lenwrap * 2 + 1);
Eric Andersen71ae64b2002-10-10 04:20:21 +0000149 str_lower(strcpy(wrapped, old));
Eric Andersen27f64e12002-06-23 04:24:25 +0000150
Eric Andersen71ae64b2002-10-10 04:20:21 +0000151 if (palindrome(newmono))
Eric Andersen27f64e12002-06-23 04:24:25 +0000152 msg = "a palindrome";
153
Eric Andersen71ae64b2002-10-10 04:20:21 +0000154 else if (strcmp(wrapped, newmono) == 0)
Eric Andersen27f64e12002-06-23 04:24:25 +0000155 msg = "case changes only";
156
Eric Andersen71ae64b2002-10-10 04:20:21 +0000157 else if (similiar(wrapped, newmono))
Eric Andersen27f64e12002-06-23 04:24:25 +0000158 msg = "too similiar";
159
Eric Andersen3124a9e2003-07-30 07:57:06 +0000160 else {
161 safe_strncpy(wrapped + lenwrap, wrapped, lenwrap + 1);
162 if (strstr(wrapped, newmono))
163 msg = "rotated";
164 }
Eric Andersen27f64e12002-06-23 04:24:25 +0000165
166 bzero(newmono, strlen(newmono));
Eric Andersen481772a2003-08-06 08:33:08 +0000167 bzero(wrapped, lenwrap * 2);
Eric Andersen27f64e12002-06-23 04:24:25 +0000168 free(newmono);
Eric Andersen27f64e12002-06-23 04:24:25 +0000169 free(wrapped);
170
171 return msg;
172}
173
Eric Andersen71ae64b2002-10-10 04:20:21 +0000174static const char *
175obscure_msg(const char *old, const char *newval, const struct passwd *pwdp)
Eric Andersen27f64e12002-06-23 04:24:25 +0000176{
177 int maxlen, oldlen, newlen;
Eric Andersen71ae64b2002-10-10 04:20:21 +0000178 char *new1, *old1;
179 const char *msg;
Eric Andersen27f64e12002-06-23 04:24:25 +0000180
181 oldlen = strlen(old);
182 newlen = strlen(newval);
183
184#if 0 /* why not check the password when set for the first time? --marekm */
185 if (old[0] == '\0')
186 /* return (1); */
187 return NULL;
188#endif
189
190 if (newlen < 5)
191 return "too short";
192
193 /*
194 * Remaining checks are optional.
195 */
196 /* Not for us -- Sean
197 *if (!getdef_bool("OBSCURE_CHECKS_ENAB"))
198 * return NULL;
199 */
200 msg = password_check(old, newval, pwdp);
201 if (msg)
202 return msg;
203
204 /* The traditional crypt() truncates passwords to 8 chars. It is
205 possible to circumvent the above checks by choosing an easy
206 8-char password and adding some random characters to it...
207 Example: "password$%^&*123". So check it again, this time
208 truncated to the maximum length. Idea from npasswd. --marekm */
209
210 maxlen = 8;
211 if (oldlen <= maxlen && newlen <= maxlen)
212 return NULL;
213
Manuel Novoa III cad53642003-03-19 09:13:01 +0000214 new1 = (char *) bb_xstrdup(newval);
215 old1 = (char *) bb_xstrdup(old);
Eric Andersen27f64e12002-06-23 04:24:25 +0000216 if (newlen > maxlen)
217 new1[maxlen] = '\0';
218 if (oldlen > maxlen)
219 old1[maxlen] = '\0';
220
221 msg = password_check(old1, new1, pwdp);
222
223 bzero(new1, newlen);
224 bzero(old1, oldlen);
225 free(new1);
226 free(old1);
227
228 return msg;
229}
230
231/*
232 * Obscure - see if password is obscure enough.
233 *
234 * The programmer is encouraged to add as much complexity to this
235 * routine as desired. Included are some of my favorite ways to
236 * check passwords.
237 */
238
239extern int obscure(const char *old, const char *newval, const struct passwd *pwdp)
240{
Eric Andersen71ae64b2002-10-10 04:20:21 +0000241 const char *msg = obscure_msg(old, newval, pwdp);
Eric Andersen27f64e12002-06-23 04:24:25 +0000242
243 /* if (msg) { */
244 if (msg != NULL) {
245 printf("Bad password: %s.\n", msg);
246 /* return 0; */
247 return 1;
248 }
249 /* return 1; */
250 return 0;
251}