home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume6 / chkpwd < prev    next >
Text File  |  1989-04-23  |  26KB  |  1,205 lines

  1. Newsgroups: comp.sources.misc
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Subject: v06i091: Password checking routine(s)
  4. Keywords: password sanity checking code
  5. Organization: Moose & Squirrel Software
  6. Reply-To: ut-emx!clyde@cs.utexas.edu (Head UNIX Hacquer)
  7.  
  8. Posting-number: Volume 6, Issue 91
  9. Submitted-by: ut-emx!clyde@cs.utexas.edu (Head UNIX Hacquer)
  10. Archive-name: chkpwd
  11.  
  12. Enclosed is some code that I worked up to do some password checking.
  13. I hope it can be useful to others.
  14.  
  15. #    This is a shell archive.
  16. #    Remove everything above and including the cut line.
  17. #    Then run the rest of the file through sh.
  18. -----cut here-----cut here-----cut here-----cut here-----
  19. #!/bin/sh
  20. # shar:    Shell Archiver
  21. #    Run the following text with /bin/sh to create:
  22. #    README
  23. #    Makefile
  24. #    checkpasswd.h
  25. #    checkpasswd.c
  26. #    makedict.c
  27. #    viewdict.c
  28. #    wormwords
  29. # This archive created: Mon Jan  9 13:27:05 1989
  30. # By:    Head UNIX Hacquer (Moose & Squirrel Software)
  31. echo shar: extracting README '(1040 characters)'
  32. sed 's/^XX//' << \SHAR_EOF > README
  33. XX
  34. XXThis is a password checking program that I wrote after the infamous Internet
  35. XXworm.  I used the password cracking algorithim the worm used in order
  36. XXto check the obviousness of a password.
  37. XX
  38. XXThe routine checkpasswd.c does this.  Read the source for the routine
  39. XXfor details of how it works.  In this package are the following:
  40. XX
  41. XXREADME        This file
  42. XXMakefile    Q.E.D.
  43. XXcheckpasswd.c    Password check routine
  44. XXcheckpasswd.h    Include for checkpasswd calling
  45. XXdriver.c    Test program
  46. XXmakedict.c    Program to build dbm dictionary
  47. XXwormwords    The infamous worm password list
  48. XXviewdict.c    Program to view dbm dictionary
  49. XX
  50. XXI hope this can be a kernel of intelligent password checking for 4BSD systems.
  51. XX
  52. XXI am working on a replacement for the BSD passwd program, which should be
  53. XXavailable soon.
  54. XX
  55. XXContents copyright 1989 Clyde W. Hoover (Moose & Squirrel Software, NotInc.)
  56. XX
  57. XXDistribution unlimited provided copyright notice is retained.
  58. XXPlease spread this around as much as useful.
  59. XX
  60. XX    Clyde Hoover
  61. XX    Computation Center
  62. XX    The University of Texas at Austin
  63. XX    clyde@emx.utexas.edu
  64. SHAR_EOF
  65. if test 1040 -ne "`wc -c README`"
  66. then
  67. echo shar: error transmitting README '(should have been 1040 characters)'
  68. fi
  69. echo shar: extracting Makefile '(670 characters)'
  70. sed 's/^XX//' << \SHAR_EOF > Makefile
  71. XX#
  72. XX#    Make password checking routines and test program
  73. XX
  74. XX#
  75. XX#    The checkpasswd routine depends upon the existence of the ndbm
  76. XX#    routines in the 4.3BSD libc.  Changes will have to be made to
  77. XX#    checkpasswd.c if these are not available.
  78. XX#
  79. XXCFLAGS    = -g
  80. XX
  81. XXpwtest: driver.o checkpasswd.o
  82. XX    cc $(CFLAGS) -o pwtest driver.o checkpasswd.o
  83. XX
  84. XXcheckpasswd.o: checkpasswd.c checkpasswd.h
  85. XX    cc $(CFLAGS) -c checkpasswd.c
  86. XX
  87. XXmakedict: makedict.c
  88. XX    cc $(CFLAGS) -o makedict makedict.c
  89. XX
  90. XXviewdict: viewdict.c
  91. XX    cc $(CFLAGS) -o viewdict viewdict.c
  92. XX
  93. XXpwdict:    wormlist makedict
  94. XX    -rm -f pwdict
  95. XX    cat /usr/dict/words wormlist | makedict pwdict
  96. XX    @echo install pwdict to where PWDICT points to in checkpasswd.c
  97. SHAR_EOF
  98. if test 670 -ne "`wc -c Makefile`"
  99. then
  100. echo shar: error transmitting Makefile '(should have been 670 characters)'
  101. fi
  102. echo shar: extracting checkpasswd.h '(1399 characters)'
  103. sed 's/^XX//' << \SHAR_EOF > checkpasswd.h
  104. XX/*
  105. XX *    passwdcheck.h
  106. XX *
  107. XX *      Copyright 1989 Clyde W. Hoover (Moose & Squirrel Software, NotInc.)
  108. XX *
  109. XX */
  110. XX
  111. XX#define    EXPORT    /**/
  112. XX#define    IMPORT    extern
  113. XX
  114. XX#define    PWCK_FAIL    -1
  115. XX#define    PWCK_OK        0
  116. XX#define    PWCK_NULL    1
  117. XX#define    PWCK_OBVIOUS    2
  118. XX#define    PWCK_FINGER    3
  119. XX#define    PWCK_INDICT    4
  120. XX#define    PWCK_ILLCHAR    5
  121. XX#define    PWCK_SHORT    6
  122. XX
  123. XX/*
  124. XX *    Return codes for checkpassword() are:
  125. XX *
  126. XX *    PWCK_OK if <password> is ok to use
  127. XX *    PWCK_FAIL if something failed during the check process
  128. XX *    PWCK_NULL if <password> is the null string
  129. XX *    PWCK_OBVIOUS if <password> is too "obvious"
  130. XX *        (equals login name, host name, 'zzzz' )
  131. XX *    PWCK_FINGER if <password> is in the users' passwd/finger info
  132. XX *    PWCK_INDICT if <password> is in the dictionaries checked
  133. XX *    PWCK_ILLCHAR if <password> is lexically illegal
  134. XX *    PWCK_SHORT if <password> is too short
  135. XX */
  136. XX
  137. XX/*
  138. XX *    Password checking peference block
  139. XX */
  140. XXstruct pwck_preferences {
  141. XX    char    OneCaseOk,    /* Are single-case pwds acceptable */
  142. XX        CtrlOk,        /* Are control characters acceptable */
  143. XX        CharRunLen,    /* How long can run of characters be  */
  144. XX        MinPwLen;    /* Minimum password length */
  145. XX    char    *EgrepPath;    /* Path to the 'egrep' program */
  146. XX};
  147. XX
  148. XX/*
  149. XX *    Preference list
  150. XX */
  151. XXIMPORT struct pwck_preferences    pwck_preferences;
  152. XX
  153. XX/*
  154. XX *    List of control characters not allowed in passwords
  155. XX */
  156. XXIMPORT char        pwck_illegalcc[];
  157. XX
  158. XX/*
  159. XX *    List of dictionaries to check
  160. XX */
  161. XXIMPORT char        *pwck_dicitonaries[];
  162. XX
  163. SHAR_EOF
  164. if test 1399 -ne "`wc -c checkpasswd.h`"
  165. then
  166. echo shar: error transmitting checkpasswd.h '(should have been 1399 characters)'
  167. fi
  168. echo shar: extracting checkpasswd.c '(13550 characters)'
  169. sed 's/^XX//' << \SHAR_EOF > checkpasswd.c
  170. XX/*
  171. XX *    checkpasswd.c - Login password check routines.
  172. XX *
  173. XX *    Perform various sanity and security checks on a password candidate.
  174. XX *
  175. XX *    Written December, 1988
  176. XX *
  177. XX *    Copyright 1989 Clyde W. Hoover (Moose & Squirrel Software, NotInc.)
  178. XX *
  179. XX *        Clyde Hoover
  180. XX *        Computation Center
  181. XX *        The University of Texas at Austin
  182. XX *        Austin, Texas
  183. XX *        clyde@emx.utexas.edu
  184. XX */
  185. XX
  186. XX#ifndef lint
  187. XXstatic char sccsid[] = "%W% %G% (cc.utexas.edu) %P%";
  188. XX#endif
  189. XX
  190. XX#include <sys/types.h>
  191. XX#include <strings.h>
  192. XX#include <ctype.h>
  193. XX
  194. XX#define    LOCAL    static
  195. XX
  196. XX#include "checkpasswd.h"
  197. XX
  198. XX/*
  199. XX *    Special string compare defines.
  200. XX */
  201. XX#define    try(P,C,V)    { if (cistrcmp(P,C) == 0) return(V); }
  202. XX#define    mtry(P,C,V)    { int i; if ((i = StrAllCmp(P,C,V)) != PWCK_OK) return(i); }
  203. XX
  204. XX/*
  205. XX *    Table of operational parameter preferences.
  206. XX *    May be modified by the caller.
  207. XX */
  208. XXEXPORT
  209. XXstruct pwck_preferences    pwck_preferences = {
  210. XX    1,        /* single-case pwds ok */
  211. XX    1,        /* control chars ok */
  212. XX    3,        /* dup length = 3 */
  213. XX    4,        /* minimum length */
  214. XX    "PATH=/bin:/usr/bin:/usr/ucb; egrep"    /* How to find egrep */
  215. XX};
  216. XX
  217. XX/*
  218. XX *    Table of control chars best avoided -
  219. XX *    mostly commonly-used terminal special chars.
  220. XX *    May be modified by the caller.
  221. XX */
  222. XX#define    ctrl(d)    ('d' & 037)
  223. XX
  224. XXEXPORT
  225. XXchar    pwck_illegalcc[128] = {
  226. XX    ctrl(c), ctrl(d), ctrl(h), /* ctrl(i),*/  ctrl(j), ctrl(m),
  227. XX    ctrl(o), ctrl(r), ctrl(s), ctrl(q), ctrl(z), ctrl(\\),
  228. XX    ctrl([),    /* escape */
  229. XX    '\0177',    /* rubout */
  230. XX    0
  231. XX};
  232. XX
  233. XX#define    PWDICT        "/usr/dict/pwwords"
  234. XX/*
  235. XX *    List of forbidden password dictionaries to look in.
  236. XX *    May be modified by the caller.
  237. XX */
  238. XXstatic char    *pwck_dicitonaries[16] = {
  239. XX    PWDICT,            /* illegal passwords list */
  240. XX    0
  241. XX};
  242. XX
  243. XX/*
  244. XX *    The 'pwck_*' routines all use the PWCK_* return
  245. XX *    codes, which are then propigated up to the caller of checkpassword().
  246. XX *
  247. XX *    All pwck_* routines in the table below are called thusly:
  248. XX *        pwck_*(password, userid)
  249. XX *            password = plaintext password string to test.
  250. XX *            userid = the user id which wants to use <password>.
  251. XX *
  252. XX *    Table of check functions to be called by checkpassword()
  253. XX */
  254. XXint    pwck_lexical(), pwck_local(), pwck_passwd(), pwck_dictionary();
  255. XX
  256. XXtypedef    int    (*function)();
  257. XX
  258. XXLOCAL
  259. XXfunction pwck_vector[] = {
  260. XX    pwck_lexical,
  261. XX    pwck_local,
  262. XX    pwck_passwd,
  263. XX    pwck_dictionary,
  264. XX    0
  265. XX};
  266. XX
  267. XX/* ------------------------------------------------------------------- */
  268. XX
  269. XX/*
  270. XX *    checkpassword - Password candidate sanity checker.
  271. XX *
  272. XX *    Arguments;
  273. XX *        password = plain text password string to check.
  274. XX *        userid = the uid whom the password is for, -1 to disable.
  275. XX *
  276. XX *    Returns:
  277. XX *        PWCK_OK if <password> is ok to use.
  278. XX *        PWCK_FAIL if something failed during the check process.
  279. XX *        PWCK_NULL if <password> is the null string
  280. XX *        PWCK_OBVIOUS if <password> is too "obvious".
  281. XX *            (equals login name, host name, 'zzzz' ).
  282. XX *        PWCK_FINGER if <password> is in the users' passwd/finger info.
  283. XX *        PWCK_INDICT if <password> is in the dictionaries checked.
  284. XX *        PWCK_ILLCHAR if <password> is lexically illegal.
  285. XX *        PWCK_SHORT if <password> is too short.
  286. XX *
  287. XX */
  288. XXcheckpassword(password, userid)
  289. XXchar    *password;        /* Plaintext of password to check */
  290. XXint    userid;            /* The user this is for */
  291. XX{
  292. XX    int        rcode;        /* General purpose scratch */
  293. XX    function    *checkfunc;    /* Check function pointer */
  294. XX
  295. XX    if (password == 0 || *password == 0)
  296. XX        return(PWCK_NULL);        /* Null password */
  297. XX
  298. XX    for (checkfunc = pwck_vector; *checkfunc; checkfunc++) {
  299. XX        if ((rcode = (*checkfunc)(password, userid)) != PWCK_OK)
  300. XX            return(rcode);
  301. XX    }
  302. XX    return(PWCK_OK);
  303. XX}
  304. XX
  305. XX
  306. XX/* ------------------------------------------------------------------- */
  307. XX
  308. XX#define    P_U    0x1     /* Upper case in password */
  309. XX#define    P_L    0x2     /* Lower case in password */
  310. XX#define    P_C    0x4     /* Control chars in password */
  311. XX#define    P_D    0x8     /* Digits in password */
  312. XX#define    P_P    0x10     /* Punctutation chars in password */
  313. XX
  314. XX#define    hasone(P)    (what |= (P))
  315. XX#define    hasany(P)    ((what & (P)) == (P))
  316. XX
  317. XX#define    ccok    pwck_preferences.CtrlOk
  318. XX#define    mcok    pwck_preferences.OneCaseOk
  319. XX#define    runl    pwck_preferences.CharRunLen
  320. XX#define    minl    pwck_preferences.MinPwLen
  321. XX
  322. XX/*
  323. XX *    pwck_lexical - Perform lexical analysis of password candidate.
  324. XX *
  325. XX *    Things which are ok:
  326. XX *        Mixed case
  327. XX *        Digits
  328. XX *        Punctutation
  329. XX *        Control characters (except for those in the forbidden table)
  330. XX *            (controlled by the preferences)
  331. XX *
  332. XX *    Things which are NOT ok:
  333. XX *        Passwords less that 'minl' length
  334. XX *        Runs of more than <runl> of the same character (e.g. 'zzz')
  335. XX *        Single-case strings
  336. XX *            (controlled by the preferences)
  337. XX *
  338. XX *    Things not checked for:
  339. XX *        Cycles of character groups (e.g. 'aabbcc' or 'ababab')
  340. XX */
  341. XXstatic int
  342. XXpwck_lexical(password, userid)
  343. XXchar    *password;
  344. XXint    userid;        /* NOTUSED */
  345. XX{
  346. XX    int    rc;        /* Duplicate character run count */
  347. XX    char    *p = password;    /* Scratch */
  348. XX    char    what = 0,    /* Lexical analysis result flags */
  349. XX        last = 0;    /* Last character seen (for run checks) */
  350. XX
  351. XX    if (minl && strlen(password) < minl)
  352. XX        return(PWCK_SHORT);
  353. XX
  354. XX    for (p = password; *p; p++) {
  355. XX        if (*p != last) {
  356. XX            last = *p;
  357. XX            rc = 0;
  358. XX        }
  359. XX        else {        /* Run of same characters */
  360. XX            if (runl && ++rc >= runl)
  361. XX                return(PWCK_OBVIOUS);
  362. XX        }
  363. XX        if (*p < ' ') {        /* Control character */
  364. XX            if (!ccok)
  365. XX                return(PWCK_ILLCHAR);
  366. XX            if (index (pwck_illegalcc, *p))
  367. XX                return(PWCK_ILLCHAR);
  368. XX            hasone(P_C);
  369. XX        }
  370. XX        else if (isupper(*p))    hasone(P_U);
  371. XX        else if (islower(*p))    hasone(P_L);
  372. XX        else if (ispunct(*p))    hasone(P_P);
  373. XX        else if (isdigit(*p))    hasone(P_D);
  374. XX    }
  375. XX    if (hasany(P_U | P_L))    return(PWCK_OK);    /* UC+lc */
  376. XX    if (hasany(P_D))    return(PWCK_OK);    /* Numbers */
  377. XX    if (hasany(P_P))    return(PWCK_OK);    /* Punctutation chars */
  378. XX    if (hasany(P_C))    return(PWCK_OK);    /* Control chars */
  379. XX    /*
  380. XX     *    Check for mono-case passwords 
  381. XX     */
  382. XX    if (!hasany(P_U) && mcok)    /* All lower case alpha */
  383. XX        return(PWCK_OK);
  384. XX    if (!hasany(P_L) && mcok)    /* All upper case alpha */
  385. XX        return(PWCK_OK);
  386. XX
  387. XX    return(PWCK_ILLCHAR);
  388. XX}
  389. XX#undef    hasone
  390. XX#undef    hasany
  391. XX
  392. XX/*
  393. XX *    pwck_local - Perform 'local' password checks.
  394. XX *
  395. XX *    Returns:
  396. XX *        PWCK_OBVIOUS if <password> == hostname
  397. XX *        PWCK_OK if otherwise
  398. XX */
  399. XXLOCAL int
  400. XXpwck_local(password, userid)
  401. XXchar    *password;
  402. XXint    userid;        /* NOTUSED */
  403. XX{
  404. XX    char    myname[32];        /* Scratch */
  405. XX
  406. XX    (void) gethostname(myname, sizeof(myname));
  407. XX    try(password, myname, PWCK_OBVIOUS);
  408. XX    /*
  409. XX     * Want to try full canoncalized hostname here in case gethostname
  410. XX     * didn't get that for us.
  411. XX     *
  412. XX     * Then look in users' .rhosts and try those strings (maybe)
  413. XX     */
  414. XX    return(PWCK_OK);
  415. XX}
  416. XX
  417. XX/*
  418. XX *    pwck_dictionary - Look in the forbidden password dictionaries.
  419. XX *
  420. XX *    Returns:
  421. XX *        PWCK_INDICT if <password> was in any dictionary
  422. XX *        PWCK_OK if not
  423. XX */
  424. XXLOCAL int
  425. XXpwck_dictionary(password, userid)
  426. XXchar    *password;
  427. XXint    userid;        /* NOTUSED */
  428. XX{
  429. XX    int    i,        /* Counter */
  430. XX        rcode;        /* Return code temp */
  431. XX
  432. XX    for (i = 0; pwck_dicitonaries[i]; i++) {
  433. XX        if ((rcode =
  434. XX             IsInDictionary(pwck_dicitonaries[i], password)) != PWCK_OK)
  435. XX            return(rcode);
  436. XX    }
  437. XX    return(PWCK_OK);
  438. XX}
  439. XX
  440. XX/*
  441. XX *    IsInDictionary - look for <password> in <dictionary>
  442. XX *
  443. XX *    Use a DBM version of the dictionary if present, 
  444. XX *    use egrep to search the flat file if not.
  445. XX *
  446. XX *    Returns:
  447. XX *        PWCK_INDICT if <password> was found in <dictionary>
  448. XX *        PWCK_OK if not
  449. XX */
  450. XX#define    returnwith(code) { dbm_close(dbp); return(code); }
  451. XX#define    EGREP    pwck_preferences.EgrepPath
  452. XX
  453. XX#include <ndbm.h>
  454. XX
  455. XXLOCAL int
  456. XXIsInDictionary(dictionary, password)
  457. XXchar    *dictionary,        /* Pathname of dictionary */
  458. XX    *password;        /* Plaintext of password */
  459. XX{
  460. XX    DBM    *dbp;        /* DBM database pointer */
  461. XX    datum    k,        /* DBM lookup key */
  462. XX        d;        /* DBM lookup datum */
  463. XX    int    uc = isupper(password[0]);    /* Is first char UC? */
  464. XX    char    pwtemp[128];    /* Scratch buffer */
  465. XX
  466. XX    if ((dbp = dbm_open(dictionary, 0, 0)) == (DBM *)0) {
  467. XX        char    command[128];    /* Command build buffer */
  468. XX        int    rc;        /* System() return code */
  469. XX
  470. XX        if (access(dictionary, 0) < 0)
  471. XX            return(PWCK_OK);
  472. XX        /*
  473. XX         * If the first letter is capitalized, look for
  474. XX         * "[wW]ord" else look for "word"
  475. XX         */
  476. XX        if (uc) 
  477. XX            (void) sprintf(command,
  478. XX                "%s -s '^[%c%c]%s$' %s > /dev/null",
  479. XX                EGREP, password[0], password[0] & ~040,
  480. XX                &password[1], dictionary);
  481. XX        else
  482. XX            (void) sprintf(command, "%s -s '^%s$' %s > /dev/null",
  483. XX                EGREP, password, dictionary);
  484. XX        rc = system(command);
  485. XX        if (rc == 0)
  486. XX            return(PWCK_INDICT);
  487. XX        else
  488. XX            return(PWCK_OK);
  489. XX    } 
  490. XX    /*
  491. XX     * Look in the DBM version of the dictionary.
  492. XX     * Look for <password>, then if the first letter
  493. XX     * is capitalized, force to lower and look again.  I don't care
  494. XX     * if <password> is in the dictionary but has mixed case letters,
  495. XX     * but if the first letter has been capitalized, I care because
  496. XX     * that's not a sufficent permutation to be secure.
  497. XX     */
  498. XX    (void) strcpy(pwtemp, password);
  499. XX    k.dptr = pwtemp;
  500. XX    k.dsize = strlen(pwtemp);
  501. XX    d = dbm_fetch(dbp, k);
  502. XX    if (d.dptr)
  503. XX        returnwith(PWCK_INDICT);
  504. XX    if (uc) {
  505. XX        pwtemp[0] |= 040;
  506. XX        d = dbm_fetch(dbp, k);
  507. XX        if (d.dptr)
  508. XX            returnwith(PWCK_INDICT);
  509. XX    }
  510. XX    returnwith(PWCK_OK);
  511. XX}
  512. XX#undef    returnwith
  513. XX
  514. XX
  515. XX/*
  516. XX *    pwck_password - Check password candidate against the users' password
  517. XX *        file information, or any other information that is publicly
  518. XX *        available about this user that a bandit could use as
  519. XX *        password guesses.
  520. XX *
  521. XX *    Here is the place to search your 'finger' database.
  522. XX */
  523. XX#include    <pwd.h>
  524. XX
  525. XXstatic int
  526. XXpwck_passwd(password, userid)
  527. XXchar    *password;
  528. XXint    userid;
  529. XX{
  530. XX    char    temp[128];        /* Scratch */
  531. XX    struct passwd    *pwp;        /* Pointer to user information */
  532. XX
  533. XX    if (userid < 0)            /* Can't do user checks */
  534. XX        return(PWCK_OK);
  535. XX
  536. XX    pwp = getpwuid(userid);
  537. XX    if (pwp == 0)
  538. XX        return(PWCK_FAIL);
  539. XX
  540. XX    try(password, pwp->pw_name, PWCK_OBVIOUS); /* Checks 'name' and 'Name' */
  541. XX
  542. XX    (void) strcpy(temp, pwp->pw_name);
  543. XX    (void) strcat(temp, pwp->pw_name);
  544. XX    try(password, temp, PWCK_OBVIOUS);    /* Check 'namename' */
  545. XX
  546. XX    (void) strcpy(temp, pwp->pw_name);
  547. XX    MirrorString(temp);
  548. XX    try(password, temp, PWCK_OBVIOUS);    /* 'eman' */
  549. XX
  550. XX    /*
  551. XX     * Try every word in user's GECOS entry
  552. XX     */
  553. XX    mtry(password, pwp->pw_gecos, PWCK_FINGER);
  554. XX    return(PWCK_OK);
  555. XX}
  556. XX/* ------------------------------------------------------------------- */
  557. XX/*
  558. XX *    StrAllCmp - Compare all sub-strings (delineated by white space)
  559. XX *
  560. XX *    Returns:
  561. XX *        PWCK_OK if no match found
  562. XX *        rc if match found
  563. XX */
  564. XXLOCAL
  565. XXStrAllCmp(s1, s2, rc)
  566. XXchar    *s1,        /* String to look for */
  567. XX    *s2;        /* String to look for <s1> in */
  568. XXint    rc;        /* What to return on match */
  569. XX{
  570. XX    int    l;        /* Temp */
  571. XX
  572. XX    for (l = strlen(s1); *s2; s2++)
  573. XX        if (cistrncmp(s1, s2, l) == 0)
  574. XX            return (rc);
  575. XX    return(PWCK_OK);
  576. XX}
  577. XX
  578. XX/*
  579. XX *    MirrorString - reverse a string in place
  580. XX */
  581. XXLOCAL
  582. XXMirrorString(s)
  583. XXchar    *s;        /* String to reverse */
  584. XX{
  585. XX    char    *p;    /* Scratch */
  586. XX    char    t[128];    /* Scratch */
  587. XX    
  588. XX    (void) strcpy(t,s);
  589. XX    p = t;
  590. XX    while (*p) p++;        /* Find end of string */
  591. XX    --p;
  592. XX    for (; *s; )
  593. XX        *s++ = *p--;
  594. XX}
  595. XX
  596. XX/*
  597. XX *    Case indepedant string comparasion routines swiped from
  598. XX *    the source to MIT Hesiod.
  599. XX */
  600. XX/*
  601. XX * Copyright (c) 1986 Regents of the University of California.
  602. XX * All rights reserved.  The Berkeley software License Agreement
  603. XX * specifies the terms and conditions for redistribution.
  604. XX */
  605. XX
  606. XX/*
  607. XX * This array is designed for mapping upper and lower case letter
  608. XX * together for a case independent comparison.  The mappings are
  609. XX * based upon ascii character sequences.
  610. XX */
  611. XX
  612. XXLOCAL char charmap[] = {
  613. XX    '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
  614. XX    '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
  615. XX    '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
  616. XX    '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
  617. XX    '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
  618. XX    '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
  619. XX    '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
  620. XX    '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
  621. XX    '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
  622. XX    '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
  623. XX    '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
  624. XX    '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
  625. XX    '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
  626. XX    '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
  627. XX    '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
  628. XX    '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
  629. XX    '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
  630. XX    '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
  631. XX    '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
  632. XX    '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
  633. XX    '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
  634. XX    '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
  635. XX    '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
  636. XX    '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
  637. XX    '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
  638. XX    '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
  639. XX    '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
  640. XX    '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
  641. XX    '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
  642. XX    '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
  643. XX    '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
  644. XX    '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
  645. XX};
  646. XX
  647. XXLOCAL
  648. XXcistrcmp(s1, s2)
  649. XXregister char *s1, *s2;
  650. XX{
  651. XX    register char *cm = charmap;
  652. XX
  653. XX    while (cm[*s1] == cm[*s2++])
  654. XX        if (*s1++=='\0')
  655. XX            return(0);
  656. XX    return(cm[*s1] - cm[*--s2]);
  657. XX}
  658. XX
  659. XXLOCAL
  660. XXcistrncmp(s1, s2, n)
  661. XXregister char *s1, *s2;
  662. XXregister n;
  663. XX{
  664. XX    register char *cm = charmap;
  665. XX
  666. XX    while (--n >= 0 && cm[*s1] == cm[*s2++])
  667. XX        if (*s1++ == '\0')
  668. XX            return(0);
  669. XX    return(n<0 ? 0 : cm[*s1] - cm[*--s2]);
  670. XX}
  671. XX
  672. XX/* END */
  673. SHAR_EOF
  674. if test 13550 -ne "`wc -c checkpasswd.c`"
  675. then
  676. echo shar: error transmitting checkpasswd.c '(should have been 13550 characters)'
  677. fi
  678. echo shar: extracting makedict.c '(653 characters)'
  679. sed 's/^XX//' << \SHAR_EOF > makedict.c
  680. XX/*
  681. XX *    makedict - Make DBM version of password dictionary
  682. XX */
  683. XX
  684. XX#include <sys/file.h>
  685. XX#include <stdio.h>
  686. XX#include <ndbm.h>
  687. XX
  688. XXextern char    *index();
  689. XX
  690. XXchar    line[80];
  691. XX
  692. XXmain(argc, argv)
  693. XXchar    *argv[];
  694. XX{
  695. XX    DBM    *dp;
  696. XX    int    recs = 0;
  697. XX    datum    d,
  698. XX        k;
  699. XX
  700. XX    dp = dbm_open(argv[1], O_RDWR, 0);
  701. XX    if (dp == 0) {
  702. XX        if ((dp = dbm_open(argv[1], O_RDWR|O_CREAT, 0644)) == 0) {
  703. XX            perror("open dbm");
  704. XX            exit(1);
  705. XX        }
  706. XX    }
  707. XX    while (!feof(stdin)) {
  708. XX        char    *p;
  709. XX
  710. XX        fgets(line, 80, stdin);
  711. XX        p = index(line, '\n');
  712. XX        if (p) *p = 0;
  713. XX        d.dptr = line;
  714. XX        d.dsize = strlen(line);
  715. XX        dbm_store(dp, d, d, DBM_INSERT);
  716. XX        recs++;
  717. XX    }
  718. XX    dbm_close(dp);
  719. XX    printf("%s built, %d records\n", argv[1], recs);
  720. XX}
  721. SHAR_EOF
  722. if test 653 -ne "`wc -c makedict.c`"
  723. then
  724. echo shar: error transmitting makedict.c '(should have been 653 characters)'
  725. fi
  726. echo shar: extracting viewdict.c '(406 characters)'
  727. sed 's/^XX//' << \SHAR_EOF > viewdict.c
  728. XX/*
  729. XX *    viewdict - View DBM version of a password dictionary
  730. XX */
  731. XX
  732. XX#include <sys/file.h>
  733. XX#include <ndbm.h>
  734. XX
  735. XXmain(argc, argv)
  736. XXchar    *argv[];
  737. XX{
  738. XX    DBM    *dp;
  739. XX    datum    k;
  740. XX    char    t[128];
  741. XX
  742. XX    if ((dp = dbm_open(argv[1], O_RDONLY, 0)) == 0) {
  743. XX        perror(argv[1]);
  744. XX        exit(1);
  745. XX    }
  746. XX    for (k = dbm_firstkey(dp); k.dptr != 0; k = dbm_nextkey(dp)) {
  747. XX        strncpy(t, k.dptr, k.dsize);
  748. XX        t[k.dsize] = 0;
  749. XX        printf("%s\n", t);
  750. XX    }
  751. XX    exit(0);
  752. XX}
  753. SHAR_EOF
  754. if test 406 -ne "`wc -c viewdict.c`"
  755. then
  756. echo shar: error transmitting viewdict.c '(should have been 406 characters)'
  757. fi
  758. echo shar: extracting wormwords '(3278 characters)'
  759. sed 's/^XX//' << \SHAR_EOF > wormwords
  760. XXaaa
  761. XXacademia
  762. XXaerobics
  763. XXairplane
  764. XXalbany
  765. XXalbatross
  766. XXalbert
  767. XXalex
  768. XXalexander
  769. XXalgebra
  770. XXaliases
  771. XXalphabet
  772. XXama
  773. XXamorphous
  774. XXanalog
  775. XXanchor
  776. XXandromache
  777. XXanimals
  778. XXanswer
  779. XXanthropogenic
  780. XXanvils
  781. XXanything
  782. XXaria
  783. XXariadne
  784. XXarrow
  785. XXarthur
  786. XXathena
  787. XXatmosphere
  788. XXaztecs
  789. XXazure
  790. XXbacchus
  791. XXbailey
  792. XXbanana
  793. XXbananas
  794. XXbandit
  795. XXbanks
  796. XXbarber
  797. XXbaritone
  798. XXbass
  799. XXbassoon
  800. XXbatman
  801. XXbeater
  802. XXbeauty
  803. XXbeethoven
  804. XXbeloved
  805. XXbenz
  806. XXbeowulf
  807. XXberkeley
  808. XXberliner
  809. XXberyl
  810. XXbeverly
  811. XXbicameral
  812. XXbob
  813. XXbrenda
  814. XXbrian
  815. XXbridget
  816. XXbroadway
  817. XXbumbling
  818. XXburgess
  819. XXcampanile
  820. XXcantor
  821. XXcardinal
  822. XXcarmen
  823. XXcarolina
  824. XXcaroline
  825. XXcascades
  826. XXcastle
  827. XXcat
  828. XXcayuga
  829. XXceltics
  830. XXcerulean
  831. XXchange
  832. XXcharles
  833. XXcharming
  834. XXcharon
  835. XXchester
  836. XXcigar
  837. XXclassic
  838. XXclusters
  839. XXcoffee
  840. XXcoke
  841. XXcollins
  842. XXcommrades
  843. XXcomputer
  844. XXcondo
  845. XXcookie
  846. XXcooper
  847. XXcornelius
  848. XXcouscous
  849. XXcreation
  850. XXcreosote
  851. XXcretin
  852. XXdaemon
  853. XXdancer
  854. XXdaniel
  855. XXdanny
  856. XXdave
  857. XXdecember
  858. XXdefoe
  859. XXdeluge
  860. XXdesperate
  861. XXdevelop
  862. XXdieter
  863. XXdigital
  864. XXdiscovery
  865. XXdisney
  866. XXdog
  867. XXdrought
  868. XXduncan
  869. XXeager
  870. XXeasier
  871. XXedges
  872. XXedinburgh
  873. XXedwin
  874. XXedwina
  875. XXegghead
  876. XXeiderdown
  877. XXeileen
  878. XXeinstein
  879. XXelephant
  880. XXelizabeth
  881. XXellen
  882. XXemerald
  883. XXengine
  884. XXengineer
  885. XXenterprise
  886. XXenzyme
  887. XXersatz
  888. XXestablish
  889. XXestate
  890. XXeuclid
  891. XXevelyn
  892. XXextension
  893. XXfairway
  894. XXfelicia
  895. XXfender
  896. XXfermat
  897. XXfidelity
  898. XXfinite
  899. XXfishers
  900. XXflakes
  901. XXfloat
  902. XXflower
  903. XXflowers
  904. XXfoolproof
  905. XXfootball
  906. XXforesight
  907. XXformat
  908. XXforsythe
  909. XXfourier
  910. XXfred
  911. XXfriend
  912. XXfrighten
  913. XXfun
  914. XXfungible
  915. XXgabriel
  916. XXgardner
  917. XXgarfield
  918. XXgauss
  919. XXgeorge
  920. XXgertrude
  921. XXginger
  922. XXglacier
  923. XXgnu
  924. XXgolfer
  925. XXgorgeous
  926. XXgorges
  927. XXgosling
  928. XXgouge
  929. XXgraham
  930. XXgryphon
  931. XXguest
  932. XXguitar
  933. XXgumption
  934. XXguntis
  935. XXhacker
  936. XXhamlet
  937. XXhandily
  938. XXhappening
  939. XXharmony
  940. XXharold
  941. XXharvey
  942. XXhebrides
  943. XXheinlein
  944. XXhello
  945. XXhelp
  946. XXherbert
  947. XXhiawatha
  948. XXhibernia
  949. XXhoney
  950. XXhorse
  951. XXhorus
  952. XXhutchins
  953. XXimbroglio
  954. XXimperial
  955. XXinclude
  956. XXingres
  957. XXinna
  958. XXinnocuous
  959. XXirishman
  960. XXisis
  961. XXjapan
  962. XXjessica
  963. XXjester
  964. XXjixian
  965. XXjohnny
  966. XXjoseph
  967. XXjoshua
  968. XXjudith
  969. XXjuggle
  970. XXjulia
  971. XXkathleen
  972. XXkermit
  973. XXkernel
  974. XXkirkland
  975. XXknight
  976. XXladle
  977. XXlambda
  978. XXlamination
  979. XXlarkin
  980. XXlarry
  981. XXlazarus
  982. XXlebesgue
  983. XXlee
  984. XXleland
  985. XXleroy
  986. XXlewis
  987. XXlight
  988. XXlisa
  989. XXlouis
  990. XXlynne
  991. XXmacintosh
  992. XXmack
  993. XXmaggot
  994. XXmagic
  995. XXmalcolm
  996. XXmark
  997. XXmarkus
  998. XXmarty
  999. XXmarvin
  1000. XXmaster
  1001. XXmaurice
  1002. XXmellon
  1003. XXmerlin
  1004. XXmets
  1005. XXmichael
  1006. XXmichelle
  1007. XXmike
  1008. XXminimum
  1009. XXminsky
  1010. XXmoguls
  1011. XXmoose
  1012. XXmorley
  1013. XXmozart
  1014. XXnancy
  1015. XXnapoleon
  1016. XXnepenthe
  1017. XXness
  1018. XXnetwork
  1019. XXnewton
  1020. XXnext
  1021. XXnoxious
  1022. XXnutrition
  1023. XXnyquist
  1024. XXoceanography
  1025. XXocelot
  1026. XXolivetti
  1027. XXolivia
  1028. XXoracle
  1029. XXorca
  1030. XXorwell
  1031. XXosiris
  1032. XXoutlaw
  1033. XXoxford
  1034. XXpacific
  1035. XXpainless
  1036. XXpakistan
  1037. XXpam
  1038. XXpapers
  1039. XXpassword
  1040. XXpatricia
  1041. XXpenguin
  1042. XXpeoria
  1043. XXpercolate
  1044. XXpersimmon
  1045. XXpersona
  1046. XXpete
  1047. XXpeter
  1048. XXphilip
  1049. XXphoenix
  1050. XXpierre
  1051. XXpizza
  1052. XXplover
  1053. XXplymouth
  1054. XXpolynomial
  1055. XXpondering
  1056. XXpork
  1057. XXposter
  1058. XXpraise
  1059. XXprecious
  1060. XXprelude
  1061. XXprince
  1062. XXprinceton
  1063. XXprotect
  1064. XXprotozoa
  1065. XXpumpkin
  1066. XXpuneet
  1067. XXpuppet
  1068. XXrabbit
  1069. XXrachmaninoff
  1070. XXrainbow
  1071. XXraindrop
  1072. XXraleigh
  1073. XXrandom
  1074. XXrascal
  1075. XXreally
  1076. XXrebecca
  1077. XXremote
  1078. XXrick
  1079. XXripple
  1080. XXrobotics
  1081. XXrochester
  1082. XXrolex
  1083. XXromano
  1084. XXronald
  1085. XXrosebud
  1086. XXrosemary
  1087. XXroses
  1088. XXruben
  1089. XXrules
  1090. XXruth
  1091. XXsal
  1092. XXsaxon
  1093. XXscamper
  1094. XXscheme
  1095. XXscott
  1096. XXscotty
  1097. XXsecret
  1098. XXsensor
  1099. XXserenity
  1100. XXsharks
  1101. XXsharon
  1102. XXsheffield
  1103. XXsheldon
  1104. XXshiva
  1105. XXshivers
  1106. XXshuttle
  1107. XXsignature
  1108. XXsimon
  1109. XXsimple
  1110. XXsinger
  1111. XXsingle
  1112. XXsmile
  1113. XXsmiles
  1114. XXsmooch
  1115. XXsmother
  1116. XXsnatch
  1117. XXsnoopy
  1118. XXsoap
  1119. XXsocrates
  1120. XXsossina
  1121. XXsparrows
  1122. XXspit
  1123. XXspring
  1124. XXspringer
  1125. XXsquires
  1126. XXstrangle
  1127. XXstratford
  1128. XXstuttgart
  1129. XXsubway
  1130. XXsuccess
  1131. XXsummer
  1132. XXsuper
  1133. XXsuperstage
  1134. XXsupport
  1135. XXsupported
  1136. XXsurfer
  1137. XXsuzanne
  1138. XXswearer
  1139. XXsymmetry
  1140. XXtangerine
  1141. XXtape
  1142. XXtarget
  1143. XXtarragon
  1144. XXtaylor
  1145. XXtelephone
  1146. XXtemptation
  1147. XXthailand
  1148. XXtiger
  1149. XXtoggle
  1150. XXtomato
  1151. XXtopography
  1152. XXtortoise
  1153. XXtoyota
  1154. XXtrails
  1155. XXtrivial
  1156. XXtrombone
  1157. XXtubas
  1158. XXtuttle
  1159. XXumesh
  1160. XXunhappy
  1161. XXunicorn
  1162. XXunknown
  1163. XXurchin
  1164. XXutility
  1165. XXvasant
  1166. XXvertigo
  1167. XXvicky
  1168. XXvillage
  1169. XXvirginia
  1170. XXwarren
  1171. XXwater
  1172. XXweenie
  1173. XXwhatnot
  1174. XXwhiting
  1175. XXwhitney
  1176. XXwill
  1177. XXwilliam
  1178. XXwilliamsburg
  1179. XXwillie
  1180. XXwinston
  1181. XXwisconsin
  1182. XXwizard
  1183. XXwombat
  1184. XXwoodwind
  1185. XXwormwood
  1186. XXyacov
  1187. XXyang
  1188. XXyellowstone
  1189. XXyosemite
  1190. XXzap
  1191. XXzimmerman
  1192. SHAR_EOF
  1193. if test 3278 -ne "`wc -c wormwords`"
  1194. then
  1195. echo shar: error transmitting wormwords '(should have been 3278 characters)'
  1196. fi
  1197. #    End of shell archive
  1198. exit 0
  1199. -- 
  1200. Shouter-To-Dead-Parrots @ Univ. of Texas Computation Center; Austin, Texas  
  1201.     clyde@emx.utexas.edu; ...!cs.utexas.edu!ut-emx!clyde
  1202.  
  1203. "You really have to take a broad perspective when giving pat answers
  1204.  to other people's problems."  - Eyebeam
  1205.