chris@mimsy.UUCP (Chris Torek) (12/09/88)
In article <375@stca77.stc.oz> peter@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@mimsy.umd.edu Path: uunet!mimsy!chris