1/*
2 * Copyright 1989, 1990, 1991, 1992, John F. Haugh II
3 * All rights reserved.
4 *
5 * Permission is granted to copy and create derivative works for any
6 * non-commercial purpose, provided this copyright notice is preserved
7 * in all copies of source code, or included in human readable form
8 * and conspicuously displayed on all copies of object code or
9 * distribution media.
10 */
11
12#include <ctype.h>
13#ifndef BSD
14#include <string.h>
15#include <memory.h>
16#else
17#include <strings.h>
18#define strchr  index
19#define strrchr rindex
20#endif
21#include "config.h"
22
23#ifndef lint
24static  char    sccsid[] = "@(#)obscure.c       3.6     20:37:32        3/7/92";
25#endif
26
27extern  int     getdef_bool();
28extern  int     getdef_num();
29
30#ifdef  NEED_STRSTR
31/*
32 * strstr - find substring in string
33 */
34
35char *
36strstr (string, pattern)
37char    *string;
38char    *pattern;
39{
40	char    *cp;
41	int     len;
42
43	len = strlen (pattern);
44
45	for (cp = string;cp = strchr (cp, *pattern);) {
46		if (strncmp (cp, pattern, len) == 0)
47			return cp;
48
49		cp++;
50	}
51	return 0;
52}
53#endif
54
55/*
56 * Obscure - see if password is obscure enough.
57 *
58 *      The programmer is encouraged to add as much complexity to this
59 *      routine as desired.  Included are some of my favorite ways to
60 *      check passwords.
61 */
62
63/*ARGSUSED*/
64int     obscure (old, new)
65char    *old;
66char    *new;
67{
68	int     i;
69	char    oldmono[32];
70	char    newmono[32];
71	char    wrapped[64];
72
73	if (old[0] == '\0')
74		return (1);
75
76	if ( strlen(new) < getdef_num("PASS_MIN_LEN", 0) ) {
77		printf ("Too short.  ");
78		return (0);
79	}
80
81	/*
82	 * Remaining checks are optional.
83	 */
84	if ( !getdef_bool("OBSCURE_CHECKS_ENAB") )
85		return (1);
86
87	for (i = 0;new[i];i++)
88		newmono[i] = tolower (new[i]);
89
90	for (i = 0;old[i];i++)
91		oldmono[i] = tolower (old[i]);
92
93	if (strcmp (new, old) == 0) {   /* the same */
94		printf ("No Change.  ");
95		return (0);
96	}
97	if (palindrome (newmono, oldmono))      /* a palindrome */
98		return (0);
99
100	if (strcmp (newmono, oldmono) == 0) {   /* case shifted */
101		printf ("Case changes only.  ");
102		return (0);
103	}
104	if (similiar (newmono, oldmono))        /* jumbled version */
105		return (0);
106
107	if (simple (old, new))                  /* keyspace size */
108		return (0);
109
110	strcpy (wrapped, oldmono);
111	strcat (wrapped, oldmono);
112	if (strstr (wrapped, newmono)) {
113		printf ("Rotated.  ");
114		return (0);
115	}
116
117
118/*
119#define CRACKLIB_DICTPATH       "/usr/local/lib/pw_dict"
120*/
121
122#ifdef CRACKLIB_DICTPATH
123	{
124		char *msg;
125
126		if (msg = (char *) FascistCheck(new, CRACKLIB_DICTPATH))
127		{
128			printf("Problem: %s.  ");
129			return(0);
130		}
131	}
132#else
133#error /* You need to edit and uncomment the value of CRACKLIB_DICTPATH */
134*** : this is a syntax error - it ought to balls up most compilers : ***
135#endif /* CRACKLIB_DICTPATH */
136
137	return (1);
138}
139
140/*
141 * can't be a palindrome - like `R A D A R' or `M A D A M'
142 */
143
144/*ARGSUSED*/
145int     palindrome (old, new)
146char    *old;
147char    *new;
148{
149	int     i, j;
150
151	i = strlen (new);
152
153	for (j = 0;j < i;j++)
154		if (new[i - j - 1] != new[j])
155			return (0);
156
157	printf ("A palindrome.  ");
158	return (1);
159}
160
161/*
162 * more than half of the characters are different ones.
163 */
164
165/*ARGSUSED*/
166int     similiar (old, new)
167char    *old;
168char    *new;
169{
170	int     i, j;
171	char    *strchr ();
172
173	for (i = j = 0;new[i] && old[i];i++)
174		if (strchr (new, tolower (old[i])))
175			j++;
176
177	if (i >= j * 2)
178		return (0);
179
180	printf ("Too similiar.  ");
181	return (1);
182}
183
184/*
185 * a nice mix of characters.
186 */
187
188/*ARGSUSED*/
189int     simple (old, new)
190char    *old;
191char    *new;
192{
193	int     digits = 0;
194	int     uppers = 0;
195	int     lowers = 0;
196	int     others = 0;
197	int     size;
198	int     i;
199
200	for (i = 0;new[i];i++) {
201		if (isdigit (new[i]))
202			digits++;
203		else if (isupper (new[i]))
204			uppers++;
205		else if (islower (new[i]))
206			lowers++;
207		else
208			others++;
209	}
210
211	/*
212	 * The scam is this - a password of only one character type
213	 * must be 8 letters long.  Two types, 7, and so on.
214	 */
215
216	size = 9;
217	if (digits) size--;
218	if (uppers) size--;
219	if (lowers) size--;
220	if (others) size--;
221
222	if (size <= i)
223		return 0;
224
225	printf ("Too Simple.  Use a longer password, or a mix of upper\n");
226	printf ("and lower case letters and numerics.  ");
227	return 1;
228}
229