password checking (was Re: System Security)

Chris Torek chris at mimsy.UUCP
Fri Dec 9 15:23:34 AEST 1988


In article <375 at stca77.stc.oz> peter at stca77.stc.oz (Peter Jeremy) writes:
>... other logical approach is an improved PASSWD(1) program that prevents
>users using trivial passwords.  Does anyone have such a beast?  What is
>a good (quick*) way of deciding whether a password is trivial?

The following code fragments are from a local password checker.  (This
is used when setting up accounts for the first time.  The requester
types the password into a `form', and no one ever sees it.  No staff
have access to the original unencrypted password [unless of course
we hack the programs :-) ].)

This is the verifier itself.  try() should compare forwards and
backwards, case-independent.  The `hard' part is the dictionary lookup
code (here NOT taken from /usr/bin/look); that is appended.

	if (strlen(p) < 6) {
		gripe("Must be at least 6 characters");
		return (0);
	}
	if (alldigits(p)) {
		gripe("Must have at least one non-digit");
		return (0);
	}
	/* Try login name */
	if (try(Fields[X_LOGIN].e_space, p))
		goto tooeasy;

	/* Try full name, all pieces */
	strcpy(buf, Fields[X_FULLNAME].e_space);
	for (np = buf; np && *np;) {
		if ((sp = strchr(np, ' ')) != NULL)
			*sp = 0;
		if (try(np, p))
			goto tooeasy;
		np = sp ? sp + 1 : NULL;
	}

	/* Try word lists */
	if (lookup(p, dictionary) || lookup(p, localdict) ||
	    lookup(p, badpasswds))
		goto tooeasy;

	...
tooeasy:
	gripe("Too easy to guess");
	return (0);

Here is the dictionary binary-search code.  N.B.: there is a hard
limit on 9 characters for the key (this is enforced by the caller).

FILE	*wordfile;

/*
 * Perform a case independent binary search for target in the (sorted) word
 * list in file filenam. 
 */
lookup(target, filenam)
	char *target, *filenam;
{
	register int c;
	long high, low, mid;
	char key[10], word[80];
#define CMP(s, t) (*(s) == *(t) ? strcmp((s), (t)) : *(s) - *(t))

	if (wordfile != NULL)
		fclose(wordfile);
	if ((wordfile = fopen(filenam, "r")) == NULL)
		return (0);
	strcpy(key, target);
	lower(key);
	low = 0;
	fseek(wordfile, 0L, 2);
	high = ftell(wordfile);
	for (;;) {
		mid = (high + low) >> 1;
		fseek(wordfile, mid, 0);
		do {
			mid++;
			c = getc(wordfile);
		} while (c != EOF && c != '\n');
		if (!getword(word))
			break;
		c = CMP(key, word);
		if (c == 0)	/* found it */
			return (1);
		if (c < 0) {	/* too far */
			if (high == mid)
				break;	/* stop spinning the wheels */
			high = mid;
		} else		/* not far enough */
			low = mid;
	}
	/*
	 * at this point we've narrowed the range as much as we can; now
	 * search until either we find the word, or we go past the key. 
	 */
	fseek(wordfile, low, 0);
	for (;;) {
		if (!getword(word))
			return (0);
		c = CMP(key, word);
		if (c < 0)
			return (0);
		if (c == 0)
			return (1);
	}
#undef CMP
}

/*
 * Read a word and lowercasify it. 
 */
getword(w)
	char *w;
{
	register char *p = w;
	register int c;

	while ((c = getc(wordfile)) != '\n') {
		if (c == EOF)
			if (p == w)
				return (0);
			else
				break;
		*p++ = c;
	}
	*p = 0;
	lower(w);
	return (1);
}

/*
 * Lowercasify a word. 
 */
lower(s)
	register char *s;
{
	register int c;

	while ((c = *s) != 0) {
		if (isupper(c))
			*s = tolower(c);
		s++;
	}
}
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris at mimsy.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.unix.wizards mailing list