home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume38 / cracklib / part01 < prev    next >
Encoding:
Internet Message Format  |  1993-06-20  |  53.8 KB

  1. From: Alec.Muffett@UK.Sun.COM (Alec David Muffett)
  2. Newsgroups: comp.sources.misc
  3. Subject: v38i001: cracklib - CrackLib: A ProActive Password Security library, Part01/02
  4. Date: 18 Jun 1993 12:43:57 +0100
  5. Sender: aem@aber.ac.uk
  6. Approved: aem@aber.ac.uk
  7. Message-ID: <csm-v38i001=cracklib.124038@aber.ac.uk>
  8. X-Md4-Signature: 07e45cc9df2b4dfce237dbc5df60569e
  9.  
  10. Submitted-by: Alec.Muffett@UK.Sun.COM (Alec David Muffett)
  11. Posting-number: Volume 38, Issue 1
  12. Archive-name: cracklib/part01
  13. Environment: C
  14.  
  15.  
  16.  
  17. CrackLib is a library containing a C function (well, lots of functions
  18. really, but you only need to use one of them) which may be used in a
  19. "passwd"-like program.
  20.  
  21. The idea is simple: try to prevent users from choosing passwords that
  22. could be guessed by "Crack" by filtering them out, at source.
  23.  
  24. CrackLib is an offshoot of the the version 5 "Crack" software, and
  25. contains a considerable number of ideas nicked from the new software. 
  26. At the time of writing, Crack 5 is incomplete (still awaiting purchase
  27. of my home box) - but I though I could share this with you. 
  28.  
  29. NOTE THIS WELL: CrackLib is NOT a replacement "passwd" program. 
  30. CrackLib is a LIBRARY.  CrackLib is what trendy marketdroid types would
  31. probably call an "enabler". 
  32.  
  33. The idea is that you wire it into your _own_ "passwd" program (if you
  34. have source); alternatively, you wire it into something like "shadow"
  35. from off of the net.  You can use it almost _everywhere_. 
  36.  
  37. FOR YOUR INFORMATION:
  38.  
  39. CrackLib has been tested mostly on Suns.  If you can point me at ways
  40. round portability problems (eg: static linking, other libraries, etc)
  41. I'd be most grateful. 
  42.  
  43. A reference copy of CrackLib (+ large dictionary) can be found via
  44. anonymous FTP at: 
  45.  
  46.     black.ox.ac.uk:~ftp/src/security/cracklib25.tar.Z
  47.  
  48.  
  49.                     - alec
  50. --
  51. #! /bin/sh
  52. # into a shell via "sh file" or similar.  To overwrite existing files,
  53. # type "sh file -c".
  54. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  55. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  56. # Contents:  README MANIFEST LICENCE cracklib cracklib/fascist.c
  57. #   cracklib/packlib.c cracklib/rules.c shadow shadow/README,CL util
  58. # Wrapped by alecm@uk-usenet on Fri Jun 18 12:37:27 1993
  59. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  60. echo If this archive is complete, you will see the following message:
  61. echo '          "shar: End of archive 1 (of 2)."'
  62. if test -f 'README' -a "${1}" != "-c" ; then 
  63.   echo shar: Will not clobber existing file \"'README'\"
  64. else
  65.   echo shar: Extracting \"'README'\" \(9021 characters\)
  66.   sed "s/^X//" >'README' <<'END_OF_FILE'
  67. XCrackLib:    A ProActive Password Sanity Library
  68. X
  69. XBy:         Alec Muffett, 16th June, 1993
  70. X
  71. XAddress:    alec.muffett@uk.sun.com
  72. X        alec.muffett@sun.co.uk
  73. X        alec_muffett@hicom.lut.ac.uk
  74. X
  75. X
  76. X- This software is not my fault in any way, nor indeed anybody's -
  77. X
  78. X
  79. X*** What is CrackLib ***
  80. X
  81. X
  82. XCrackLib is a library containing a C function (well, lots of functions
  83. Xreally, but you only need to use one of them) which may be used in a
  84. X"passwd"-like program.
  85. X
  86. XThe idea is simple: try to prevent users from choosing passwords that
  87. Xcould be guessed by "Crack" by filtering them out, at source.
  88. X
  89. XCrackLib is an offshoot of the the version 5 "Crack" software, and
  90. Xcontains a considerable number of ideas nicked from the new software.
  91. X
  92. XAt the time of writing, Crack 5 is incomplete (still awaiting purchase
  93. Xof my home box) - but I though I could share this with you.
  94. X
  95. X[ Incidentally, if Dell or anyone would like to "donate" a Linuxable
  96. X486DX2-66MHz box (EISA/16Mb RAM/640MB HD/AHA1740) as a development
  97. Xplatform for Crack, I'd be more than grateful to hear from you.  8-) ]
  98. X
  99. X
  100. XNOTE THIS WELL: CrackLib is NOT a replacement "passwd" program.
  101. XCrackLib is a LIBRARY.  CrackLib is what trendy marketdroid types would
  102. Xprobably call an "enabler".
  103. X
  104. XThe idea is that you wire it into your _own_ "passwd" program (if you
  105. Xhave source); alternatively, you wire it into something like "shadow"
  106. Xfrom off of the net.  You can use it in other things, too.
  107. X
  108. XYou can use it almost _everywhere_.
  109. X
  110. X
  111. X*** Advantages of CrackLib ***
  112. X
  113. X
  114. X1) it WORKS!
  115. X
  116. XI wrote something similar ("goodpass") a few years back, which went out
  117. Xwith Crack v3.x.
  118. X
  119. XGoodpass was slow and buggy and I think it was used (at least in part)
  120. Xin "npasswd".  Hopefully, CrackLib will supplant "goodpass" entirely.
  121. X
  122. X
  123. X2) it's FAST!
  124. X
  125. XCrackLib finds potential passwords quickly, by using an index file to
  126. Xaccess dictionary words, and by keeping a table to assist binary
  127. Xsearching.
  128. X
  129. X
  130. X3) it's SMALL!
  131. X
  132. XCrackLib's dictionary is modified-DAWG compressed with a chunksize of 16
  133. Xwords (see Crack v5.0 docs (when it comes out) for details) - and then
  134. Xthe index file is built, with one entry per chunk.
  135. X
  136. XThe upshot of all this is that CrackLib can do indexed, binary searches
  137. Xin a 1.4 million word dictionary (raw size ~ 15Mb), but the CrackLib
  138. Xfiles (data+index+watermarks) occupy only ~ 7Mb.  (45% original size)
  139. X
  140. XIt's even efficient over NFS !
  141. X
  142. X
  143. X4) it's MIND-NUMBINGLY THOROUGH!
  144. X
  145. X(is this beginning to read like a B-movie flyer, or what?)
  146. X
  147. XCrackLib makes literally hundreds of tests to determine whether you've
  148. Xchosen a bad password.
  149. X
  150. X* It tries to generate words from your username and gecos entry to tries
  151. Xto match them against what you've chosen.
  152. X
  153. X* It checks for simplistic patterns.
  154. X
  155. X* It then tries to reverse-engineer your password into a dictionary
  156. Xword, and searches for it in your dictionary.
  157. X
  158. X- after all that, it's PROBABLY a safe(-ish) password.  8-)
  159. X
  160. X
  161. X*** Instructions for building CrackLib...
  162. X
  163. X
  164. XSTEP 0) Engage your brain.
  165. X
  166. XI'm interested in improving the CrackLib software, doing bugfixes,
  167. X"guessing technique" improvements, and portability enhancements. 
  168. X
  169. XI'm NOT interested in unhelpful comments like "well, _my_ operating
  170. Xsystem doesn't come with a dictionary".  If it doesn't, either complain
  171. Xto your vendor, or GO AND GET a dictionary off the net. 
  172. X
  173. XCrackLib is NOT a TOOL.  It is not a complete package.  It is not
  174. Xsomething you can utilise directly. 
  175. X
  176. XIt is a resource, an aid, something to enhance the functionality of
  177. Xother software.  You need to (either) write OR modify other software to
  178. Xuse it.  If you can't do this, then you shouldn't be wasting your time
  179. Xwith it. 
  180. X
  181. XRegarding bugs and portability problems: please try to work them out for
  182. Xyourself, and then (please) TELL me about them.  This will help me
  183. Ximprove future versions. 
  184. X
  185. X
  186. XSTEP 1) Edit the Makefile to set your preferred value of DICTPATH
  187. X
  188. XThis it the directory+filename-prefix that your version of CrackLib will
  189. Xgo hunting for, and it must be visible to all programs on all hosts that
  190. Xuse CrackLib
  191. X
  192. XHence, if you want to use a CrackLib binary on a distributed network,
  193. Xthese files are probably best placed on an NFS server.
  194. X
  195. XNote: You have to specify a FILENAME PREFIX too, eg:
  196. X
  197. X    DICTPATH=/usr/local/lib/pw_dict
  198. X
  199. Xwhich will generate:
  200. X
  201. X    /usr/local/lib/pw_dict.pwd
  202. X    /usr/local/lib/pw_dict.pwi
  203. X    /usr/local/lib/pw_dict.hwm
  204. X
  205. Xwhich are the files that CrackLib needs.
  206. X
  207. XThese files are NOT byte-order independent, in fact they are probably
  208. XARCHITECTURE SPECIFIC, mostly due to speed constraints.  If this is a
  209. Xproblem, I suggest you use:
  210. X
  211. X    DICTPATH=/usr/local/lib/pw_dict.sun4
  212. X    DICTPATH=/usr/local/lib/pw_dict.i386
  213. X    DICTPATH=/usr/local/lib/pw_dict.cray
  214. X
  215. X...etc, and build several sets of files, as appropriate.
  216. X
  217. X
  218. X(Hackers Note: Strictly, only *.pwi and *.hwm should be architecture
  219. Xdependent; however, if you build two dictionaries on two different
  220. Xplatforms, you MAY wind up with different *.pwd files too, due to
  221. Xincompatibilities in the std Unix utilities, or from using different
  222. XSOURCEDICTs.
  223. X
  224. XI may try to work this out in the next release.  In the mean time, if
  225. Xyour *.pwd files are EXACTLY identical (use "cmp" to test), you can
  226. Xdelete the multiple copies and use softlinks instead.)
  227. X
  228. X
  229. XSTEP 2) Add to the SOURCEDICT variable, any files continaing extra words
  230. Xthat you wish CrackLib to use.  CrackLib merges all of these files
  231. Xtogether, removes redundant characters, and compresses them.  Generally,
  232. Xthe output file is 40..60% the size of all the input files, combined.
  233. X
  234. XNOTE: THE DEFAULT VALUE OF "SOURCEDICT" CONTAINS "/usr/dict/words" -
  235. Xthis is a file which can be found on many BSD-type Unix systems,
  236. Xcontaining a list of words, one per line, suitable for use with
  237. X"cracklib".  If you do not have such a file, refer to STEP 0.
  238. X
  239. X
  240. XSTEP 3) do:
  241. X
  242. X    % make all
  243. X
  244. Xthen do:
  245. X
  246. X    % make install
  247. X
  248. Xwhich will build the CrackLib dictionary in $DICTPATH.
  249. X
  250. X
  251. X*** NOTE THIS WELL ***
  252. X
  253. XIf you supply massive amounts of text to CrackLib to use a a dictionary,
  254. Xyou must have enough free space available for use by the "sort" command,
  255. Xwhen the dictionary is built.
  256. X
  257. XSo: If you do not have (say) about 20Mb free in /usr/tmp (or whatever
  258. Xtemporary area your "sort" command uses), have a look at the
  259. X"util/mkdict" script.
  260. X
  261. XYou can usually tweak the "sort" command to use any large area of disk
  262. Xyou desire, by use of the "-T" option, and "mkdict" has a hook for this.
  263. X
  264. X
  265. XSTEP 4) Wire a call to "FascistCheck()" into your "passwd" program
  266. X
  267. X
  268. X- Left as an exercise for the reader.
  269. X
  270. X
  271. X*** Example of how to invoke CrackLib
  272. X
  273. XInsert a call to the routine FascistCheck, which is defined thusly:
  274. X
  275. XNAME
  276. X    FascistCheck - check a potential password for guessability
  277. X
  278. X
  279. XSYNOPSIS
  280. X
  281. X    char *FascistCheck(char *pw, char *dictpath);
  282. X
  283. X
  284. XDESCRIPTION
  285. X
  286. X    FascistCheck() takes 2 arguments:
  287. X
  288. X    pw - a string continaing the users chosen "potential password"
  289. X
  290. X    dictpath - the full path name + filename prefix of the
  291. X    CrackLib dictionary, specified in the installation Makefile.
  292. X    (If you still haven't sussed, I'm talking about DICTPATH).
  293. X
  294. X
  295. XRETURN VALUE
  296. X
  297. X    FascistCheck() returns the NULL pointer for a good password,
  298. X    or a pointer to a diagnostic string if it is a bad password.
  299. X
  300. X
  301. XBUGS
  302. X    - it can't catch everything. Just most things.
  303. X
  304. X    - it calls getpwuid(getuid()) to look up the user,
  305. X      this MAY affect poorly written programs
  306. X
  307. X    - using more than one pw_dict file, eg:
  308. X
  309. X        char *msg;
  310. X        if (msg = FascistCheck(pw, "onepath") ||
  311. X            msg = FascistCheck(pw, "anotherpath"))
  312. X        {
  313. X            printf("Bad Password: because %s\n", msg);
  314. X        }
  315. X
  316. X       ...works, but it's a kludge. AVOID IT IF POSSIBLE.
  317. X       Using just the one dictionary is more efficient, anyway.
  318. X
  319. X    - PWOpen() routines should cope with having more than 1
  320. X      dictionary open at a time.  I'll fix this RSN.
  321. X
  322. X
  323. XWORKED EXAMPLE
  324. X
  325. X---- modified extract from BSD distribution - "local_passwd.c" ----
  326. X
  327. X#ifndef CRACKLIB_DICTPATH /* if possible, get from the same Makefile as CrackLib */
  328. X#define CRACKLIB_DICTPATH "/usr/local/lib/pw_dict"
  329. X#endif        /* see examples on how to import DICTPATH into CRACKLIB_DICTPATH */
  330. X...
  331. X...
  332. X...
  333. X    for (buf[0] = '\0', tries = 0;;) {
  334. X        p = getpass("New password:");
  335. X        if (!*p) {
  336. X            (void)printf("Password unchanged.\n");
  337. X            pw_error(NULL, 0, 0);
  338. X        }
  339. X
  340. X#ifndef CRACKLIB_DICTPATH
  341. X        if (strlen(p) <= 5 && (uid != 0 || ++tries < 2)) {
  342. X            (void)printf("Please enter a longer password.\n");
  343. X            continue;
  344. X        }
  345. X        for (t = p; *t && islower(*t); ++t);
  346. X        if (!*t && (uid != 0 || ++tries < 2)) {
  347. X            (void)printf("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\n");
  348. X            continue;
  349. X        }
  350. X#else
  351. X        {
  352. X            char *msg;
  353. X            if (msg = (char *) FascistCheck(pwbuf, CRACKLIB_DICTPATH)) {
  354. X                printf("Please use a different password.\n");
  355. X                printf("The one you have chosen is unsuitable because %s.\n", msg);
  356. X                continue;    /* go round and round until they get it right */
  357. X            }
  358. X        }
  359. X#endif /* CRACKLIB_DICTPATH */
  360. X
  361. X        (void)strcpy(buf, p);
  362. X        if (!strcmp(buf, getpass("Retype new password:")))
  363. X            break;
  364. X        (void)printf("Mismatch; try again, EOF to quit.\n");
  365. X    }
  366. X---- end of extract ----
  367. END_OF_FILE
  368.   if test 9021 -ne `wc -c <'README'`; then
  369.     echo shar: \"'README'\" unpacked with wrong size!
  370.   fi
  371.   # end of 'README'
  372. fi
  373. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  374.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  375. else
  376.   echo shar: Extracting \"'MANIFEST'\" \(1338 characters\)
  377.   sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  378. X   File Name        Archive #    Description
  379. X----------------------------------------------------------
  380. XREADME                     1    Boring docs
  381. XMANIFEST                   1    This file
  382. XHISTORY                    2    Version information
  383. XLICENCE                    1    Licence documentation
  384. XMakefile                   2    Makefile for std distribution
  385. XPOSTER                     2    Cut down blurb for USENET
  386. Xcracklib                   1    Library source code
  387. Xcracklib/Makefile          2    
  388. Xcracklib/fascist.c         1    Pattern matching + API
  389. Xcracklib/genrules.pl       2    
  390. Xcracklib/packer.h          2    Boring config file
  391. Xcracklib/packlib.c         1    DAWG-16 compression library from C5
  392. Xcracklib/rules.c           1    ...more stuff from Crack 5
  393. Xcracklib/stringlib.c       2    ...even more stuff from Crack 5
  394. Xshadow                     1    Stubs for use with JFH's "shadow" suite
  395. Xshadow/README,CL           1    
  396. Xshadow/obscure.c,CL        2    jfh's "obscure" routine with CrackLib
  397. Xutil                       1    support utilities
  398. Xutil/Makefile              2    
  399. Xutil/mkdict                2    dictionary preprocessor
  400. Xutil/packer.c              2    dictionary packer
  401. Xutil/testlib.c             2    password sanity testbed
  402. Xutil/testnum.c             2    numeric dict-lookup testbed
  403. Xutil/teststr.c             2    string dict-lookup testbed
  404. Xutil/unpacker.c            2    dictionary unpacker
  405. END_OF_FILE
  406.   if test 1338 -ne `wc -c <'MANIFEST'`; then
  407.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  408.   fi
  409.   # end of 'MANIFEST'
  410. fi
  411. if test -f 'LICENCE' -a "${1}" != "-c" ; then 
  412.   echo shar: Will not clobber existing file \"'LICENCE'\"
  413. else
  414.   echo shar: Extracting \"'LICENCE'\" \(4851 characters\)
  415.   sed "s/^X//" >'LICENCE' <<'END_OF_FILE'
  416. X(*
  417. XThis document is freely plagiarised from the 'Artistic Licence',
  418. Xdistributed as part of the Perl v4.0 kit by Larry Wall, which is
  419. Xavailable from most major archive sites
  420. X*)
  421. X
  422. XThis documents purpose is to state the conditions under which these
  423. XPackages (See definition below) viz: "Crack", the Unix Password Cracker,
  424. Xand "CrackLib", the Unix Password Checking library, which are held in
  425. Xcopyright by Alec David Edward Muffett, may be copied, such that the
  426. Xcopyright holder maintains some semblance of artistic control over the
  427. Xdevelopment of the packages, while giving the users of the package the
  428. Xright to use and distribute the Package in a more-or-less customary
  429. Xfashion, plus the right to make reasonable modifications. 
  430. X
  431. XSo there.
  432. X
  433. X***************************************************************************
  434. X
  435. XDefinitions:
  436. X
  437. X
  438. XA "Package" refers to the collection of files distributed by the
  439. XCopyright Holder, and derivatives of that collection of files created
  440. Xthrough textual modification, or segments thereof. 
  441. X
  442. X"Standard Version" refers to such a Package if it has not been modified,
  443. Xor has been modified in accordance with the wishes of the Copyright
  444. XHolder.
  445. X
  446. X"Copyright Holder" is whoever is named in the copyright or copyrights
  447. Xfor the package.
  448. X
  449. X"You" is you, if you're thinking about copying or distributing this
  450. XPackage.
  451. X
  452. X"Reasonable copying fee" is whatever you can justify on the basis of
  453. Xmedia cost, duplication charges, time of people involved, and so on.
  454. X(You will not be required to justify it to the Copyright Holder, but
  455. Xonly to the computing community at large as a market that must bear the
  456. Xfee.)
  457. X
  458. X"Freely Available" means that no fee is charged for the item itself,
  459. Xthough there may be fees involved in handling the item.  It also means
  460. Xthat recipients of the item may redistribute it under the same
  461. Xconditions they received it.
  462. X
  463. X
  464. X1.  You may make and give away verbatim copies of the source form of the
  465. XStandard Version of this Package without restriction, provided that you
  466. Xduplicate all of the original copyright notices and associated
  467. Xdisclaimers.
  468. X
  469. X2.  You may apply bug fixes, portability fixes and other modifications
  470. Xderived from the Public Domain or from the Copyright Holder.  A Package
  471. Xmodified in such a way shall still be considered the Standard Version.
  472. X
  473. X3.  You may otherwise modify your copy of this Package in any way,
  474. Xprovided that you insert a prominent notice in each changed file stating
  475. Xhow and when AND WHY you changed that file, and provided that you do at
  476. Xleast ONE of the following:
  477. X
  478. Xa) place your modifications in the Public Domain or otherwise make them
  479. XFreely Available, such as by posting said modifications to Usenet or an
  480. Xequivalent medium, or placing the modifications on a major archive site
  481. Xsuch as uunet.uu.net, or by allowing the Copyright Holder to include
  482. Xyour modifications in the Standard Version of the Package.
  483. X
  484. Xb) use the modified Package only within your corporation or organization.
  485. X
  486. Xc) rename any non-standard executables so the names do not conflict with
  487. Xstandard executables, which must also be provided, and provide separate
  488. Xdocumentation for each non-standard executable that clearly documents
  489. Xhow it differs from the Standard Version.
  490. X
  491. Xd) make other distribution arrangements with the Copyright Holder.
  492. X
  493. X4.  You may distribute the programs of this Package in object code or
  494. Xexecutable form, provided that you do at least ONE of the following:
  495. X
  496. Xa) distribute a Standard Version of the executables and library files,
  497. Xtogether with instructions (in the manual page or equivalent) on where
  498. Xto get the Standard Version.
  499. X
  500. Xb) accompany the distribution with the machine-readable source of the
  501. XPackage with your modifications.
  502. X
  503. Xc) accompany any non-standard executables with their corresponding
  504. XStandard Version executables, giving the non-standard executables
  505. Xnon-standard names, and clearly documenting the differences in manual
  506. Xpages (or equivalent), together with instructions on where to get the
  507. XStandard Version.
  508. X
  509. Xd) make other distribution arrangements with the Copyright Holder.
  510. X
  511. X5.  You may charge a reasonable copying fee for any distribution of this
  512. XPackage.  You may charge any fee you choose for support of this Package. 
  513. XYOU MAY NOT CHARGE A FEE FOR THIS PACKAGE ITSELF.  However, you may
  514. Xdistribute this Package in aggregate with other (possibly commercial)
  515. Xprograms as part of a larger (possibly commercial) software distribution
  516. Xprovided that YOU DO NOT ADVERTISE this package as a product of your
  517. Xown. 
  518. X
  519. X6.  The name of the Copyright Holder may not be used to endorse or
  520. Xpromote products derived from this software without specific prior
  521. Xwritten permission.
  522. X
  523. X7.  THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
  524. XWARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  525. XMERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  526. X
  527. X                The End
  528. END_OF_FILE
  529.   if test 4851 -ne `wc -c <'LICENCE'`; then
  530.     echo shar: \"'LICENCE'\" unpacked with wrong size!
  531.   fi
  532.   # end of 'LICENCE'
  533. fi
  534. if test ! -d 'cracklib' ; then
  535.     echo shar: Creating directory \"'cracklib'\"
  536.     mkdir 'cracklib'
  537. fi
  538. if test -f 'cracklib/fascist.c' -a "${1}" != "-c" ; then 
  539.   echo shar: Will not clobber existing file \"'cracklib/fascist.c'\"
  540. else
  541.   echo shar: Extracting \"'cracklib/fascist.c'\" \(8505 characters\)
  542.   sed "s/^X//" >'cracklib/fascist.c' <<'END_OF_FILE'
  543. X/*
  544. X * This program is copyright Alec Muffett 1993. The author disclaims all 
  545. X * responsibility or liability with respect to it's usage or its effect 
  546. X * upon hardware or computer systems, and maintains copyright as set out 
  547. X * in the "LICENCE" document which accompanies distributions of Crack v4.0 
  548. X * and upwards.
  549. X */
  550. X
  551. Xstatic char vers_id[] = "fascist.c : v2.3p2 Alec Muffett 18 May 1993";
  552. X
  553. X#include "packer.h"
  554. X#include <ctype.h>
  555. X#include <sys/types.h>
  556. X#include <pwd.h>
  557. X
  558. X#define ISSKIP(x) (isspace(x) || ispunct(x))
  559. X
  560. X#define MINDIFF    5
  561. X#define MINLEN 6
  562. X#define MAXSTEP 4
  563. X
  564. Xstatic char *r_destructors[] = {
  565. X    ":",            /* noop - must do this to test raw word. */
  566. X
  567. X    "[",            /* trimming leading/trailing junk */
  568. X    "]",
  569. X    "[[",
  570. X    "]]",
  571. X    "[[[",
  572. X    "]]]",
  573. X
  574. X    "/?p@?p",            /* purging out punctuation/symbols/junk */
  575. X    "/?s@?s",
  576. X    "/?X@?X",
  577. X
  578. X    "/$s$s",            /* transmogrifying "$" back into "s", etc... */
  579. X    "/4s4a",
  580. X    "/2s2a",
  581. X    "/3s3e",
  582. X    "/0s0o",
  583. X    "/1s1i",
  584. X    "/4s4h",
  585. X    "/1s1l",
  586. X    "/$s$s/1s1l",
  587. X    "/2s2a/3s3e",
  588. X    "/0s0o/4s4h",
  589. X    "/1s1l/4s4a",
  590. X    "/2s2a/4s4h",
  591. X    "/$s$s/3s3e",
  592. X    "/$s$s/0s0o",
  593. X    "/1s1i/4s4a",
  594. X    "/$s$s/2s2a",
  595. X    "/$s$s/4s4a",
  596. X    "/0s0o/1s1l",
  597. X    "/3s3e/4s4h",
  598. X    "/1s1l/4s4h",
  599. X    "/$s$s/4s4h",
  600. X    "/1s1i/4s4h",
  601. X    "/2s2a/4s4a",
  602. X    "/$s$s/1s1i",
  603. X    "/0s0o/1s1i",
  604. X    "/1s1i/2s2a",
  605. X    "/1s1i/3s3e",
  606. X    "/0s0o/4s4a",
  607. X    "/1s1l/3s3e",
  608. X    "/3s3e/4s4a",
  609. X    "/0s0o/2s2a",
  610. X    "/0s0o/3s3e",
  611. X    "/1s1l/2s2a",
  612. X    "/0s0o/1s1l/2s2a",
  613. X    "/0s0o/1s1i/4s4h",
  614. X    "/1s1l/2s2a/4s4a",
  615. X    "/2s2a/3s3e/4s4a",
  616. X    "/0s0o/1s1i/2s2a",
  617. X    "/1s1i/2s2a/3s3e",
  618. X    "/0s0o/1s1l/4s4a",
  619. X    "/1s1l/2s2a/4s4h",
  620. X    "/$s$s/0s0o/1s1l",
  621. X    "/$s$s/0s0o/2s2a",
  622. X    "/0s0o/1s1i/3s3e",
  623. X    "/$s$s/0s0o/3s3e",
  624. X    "/1s1i/2s2a/4s4a",
  625. X    "/$s$s/0s0o/4s4a",
  626. X    "/$s$s/0s0o/4s4h",
  627. X    "/0s0o/1s1l/4s4h",
  628. X    "/1s1i/2s2a/4s4h",
  629. X    "/0s0o/1s1l/3s3e",
  630. X    "/$s$s/0s0o/1s1i",
  631. X    "/0s0o/1s1i/4s4a",
  632. X    "/2s2a/3s3e/4s4h",
  633. X    "/1s1l/2s2a/3s3e",
  634. X    "/$s$s/0s0o/1s1l/3s3e",
  635. X    "/0s0o/1s1l/2s2a/4s4a",
  636. X    "/0s0o/1s1i/2s2a/3s3e",
  637. X    "/$s$s/0s0o/1s1i/4s4a",
  638. X    "/$s$s/0s0o/1s1i/3s3e",
  639. X    "/$s$s/0s0o/1s1l/4s4a",
  640. X    "/0s0o/1s1l/2s2a/3s3e",
  641. X    "/$s$s/0s0o/1s1i/2s2a",
  642. X    "/1s1l/2s2a/3s3e/4s4a",
  643. X    "/$s$s/0s0o/1s1l/2s2a",
  644. X    "/$s$s/0s0o/1s1i/4s4h",
  645. X    "/1s1i/2s2a/3s3e/4s4a",
  646. X    "/0s0o/1s1i/2s2a/4s4a",
  647. X    "/0s0o/1s1l/2s2a/4s4h",
  648. X    "/1s1i/2s2a/3s3e/4s4h",
  649. X    "/1s1l/2s2a/3s3e/4s4h",
  650. X    "/0s0o/1s1i/2s2a/4s4h",
  651. X    "/$s$s/0s0o/1s1l/4s4h",
  652. X    "/$s$s/0s0o/1s1i/2s2a/4s4a",
  653. X    "/$s$s/0s0o/1s1l/2s2a/4s4h",
  654. X    "/$s$s/0s0o/1s1i/2s2a/4s4h",
  655. X    "/0s0o/1s1l/2s2a/3s3e/4s4a",
  656. X    "/$s$s/0s0o/1s1l/2s2a/4s4a",
  657. X    "/0s0o/1s1i/2s2a/3s3e/4s4a",
  658. X    "/0s0o/1s1i/2s2a/3s3e/4s4h",
  659. X    "/$s$s/0s0o/1s1l/2s2a/3s3e",
  660. X    "/0s0o/1s1l/2s2a/3s3e/4s4h",
  661. X    "/$s$s/0s0o/1s1i/2s2a/3s3e",
  662. X    "/$s$s/0s0o/1s1l/2s2a/3s3e/4s4h",
  663. X    "/$s$s/0s0o/1s1l/2s2a/3s3e/4s4a",
  664. X    "/$s$s/0s0o/1s1i/2s2a/3s3e/4s4a",
  665. X    "/$s$s/0s0o/1s1i/2s2a/3s3e/4s4h",
  666. X    (char *) 0
  667. X};
  668. X
  669. Xstatic char *r_constructors[] = {
  670. X    ":",
  671. X    "r",
  672. X    "d",
  673. X    "f",
  674. X    "dr",
  675. X    "fr",
  676. X    "rf",
  677. X    (char *) 0
  678. X};
  679. X
  680. Xint
  681. XGTry(rawtext, password)
  682. X    register char *rawtext;
  683. X    register char *password;
  684. X{
  685. X    register int i;
  686. X    register char *mp;
  687. X    int len;
  688. X
  689. X    /* use destructors to turn password into rawtext */
  690. X    /* note use of Reverse() to save duplicating all rules */
  691. X
  692. X    len = strlen(password);
  693. X
  694. X    for (i = 0; r_destructors[i]; i++)
  695. X    {
  696. X    if (!(mp = Mangle(password, r_destructors[i])))
  697. X    {
  698. X        continue;
  699. X    }
  700. X
  701. X#ifdef DEBUG
  702. X    printf("d1->\t%s vs %s\n", mp, rawtext);
  703. X#endif
  704. X    if (!strncmp(mp, rawtext, len))
  705. X    {
  706. X        return (1);
  707. X    }
  708. X#ifdef DEBUG
  709. X    printf("d2->\tr(%s) vs %s\n", mp, rawtext);
  710. X#endif
  711. X    if (!strncmp(Reverse(mp), rawtext, len))
  712. X    {
  713. X        return (1);
  714. X    }
  715. X    }
  716. X
  717. X    /* use constructors to turn rawtext into password */
  718. X
  719. X    for (i = 0; r_constructors[i]; i++)
  720. X    {
  721. X    if (!(mp = Mangle(rawtext, r_constructors[i])))
  722. X    {
  723. X        continue;
  724. X    }
  725. X#ifdef DEBUG
  726. X    printf("c->\t%s vs %s\n", mp, password);
  727. X#endif
  728. X    if (!strncmp(mp, password, len))
  729. X    {
  730. X        return (1);
  731. X    }
  732. X    }
  733. X
  734. X    return (0);
  735. X}
  736. X
  737. Xchar *
  738. XFascistGecos(password, uid)
  739. X    char *password;
  740. X    int uid;
  741. X{
  742. X    int i;
  743. X    int j;
  744. X    int wc;
  745. X    struct passwd *pwp;
  746. X    char gbuffer[STRINGSIZE];
  747. X    char *uwords[STRINGSIZE];
  748. X    char buffer[STRINGSIZE];
  749. X    register char *ptr = 
  750. X        "\101\154\145\143\127\141\163\110\145\162\145";
  751. X
  752. X    if (!(pwp = getpwuid(uid)))
  753. X    {
  754. X    return ("you are not registered in the password file");
  755. X    }
  756. X
  757. X    if (GTry(pwp->pw_name, password))
  758. X    {
  759. X    return ("it is based on your username");
  760. X    }
  761. X
  762. X    strcpy(gbuffer, Lowercase(pwp->pw_gecos));
  763. X
  764. X    wc = 0;
  765. X    ptr = gbuffer;
  766. X
  767. X    while (*ptr)
  768. X    {
  769. X    while (*ptr && ISSKIP(*ptr))
  770. X    {
  771. X        ptr++;
  772. X    }
  773. X
  774. X    if (ptr != gbuffer)
  775. X    {
  776. X        ptr[-1] = '\0';
  777. X    }
  778. X
  779. X    uwords[wc++] = ptr;
  780. X
  781. X    if (wc == STRINGSIZE)
  782. X    {
  783. X        uwords[--wc] = (char *) 0;    /* to hell with it */
  784. X        break;
  785. X    } else
  786. X    {
  787. X        uwords[wc] = (char *) 0;
  788. X    }
  789. X
  790. X    while (*ptr && !ISSKIP(*ptr))
  791. X    {
  792. X        ptr++;
  793. X    }
  794. X
  795. X    if (*ptr)
  796. X    {
  797. X        *(ptr++) = '\0';
  798. X    }
  799. X    }
  800. X#ifdef DEBUG
  801. X    for (i = 0; uwords[i]; i++)
  802. X    {
  803. X        printf("u:\t%s\n", uwords[i]);
  804. X    }
  805. X#endif
  806. X    for (i = 0; uwords[i]; i++)
  807. X    {
  808. X    if (GTry(uwords[i], password))
  809. X    {
  810. X        return ("it is based upon your password entry");
  811. X    }
  812. X    }
  813. X
  814. X    for (j = 1; uwords[j]; j++)
  815. X    {
  816. X    for (i = 0; i < j; i++)
  817. X    {
  818. X        strcpy(buffer, uwords[i]);
  819. X        strcat(buffer, uwords[j]);
  820. X        if (GTry(buffer, password))
  821. X        {
  822. X        return ("it is derived from your password entry");
  823. X        }
  824. X
  825. X        strcpy(buffer, uwords[j]);
  826. X        strcat(buffer, uwords[i]);
  827. X        if (GTry(buffer, password))
  828. X        {
  829. X        return ("it's derived from your password entry");
  830. X        }
  831. X
  832. X        buffer[0] = uwords[i][0];
  833. X        buffer[1] = '\0';
  834. X        strcat(buffer, uwords[j]);
  835. X        if (GTry(buffer, password))
  836. X        {
  837. X        return ("it is derivable from your password entry");
  838. X        }
  839. X
  840. X        buffer[0] = uwords[j][0];
  841. X        buffer[1] = '\0';
  842. X        strcat(buffer, uwords[i]);
  843. X        if (GTry(buffer, password))
  844. X        {
  845. X        return ("it's derivable from your password entry");
  846. X        }
  847. X    }
  848. X    }
  849. X
  850. X    return ((char *) 0);
  851. X}
  852. X
  853. Xchar *
  854. XFascistLook(pwp, instring)
  855. X    PWDICT *pwp;
  856. X    char *instring;
  857. X{
  858. X    register int i;
  859. X    register char *ptr;
  860. X    char junk[STRINGSIZE];
  861. X    register char *jptr;
  862. X    char rpassword[STRINGSIZE];
  863. X    register char *password;
  864. X    int32 notfound;
  865. X
  866. X    notfound = PW_WORDS(pwp);
  867. X    password = rpassword;
  868. X
  869. X    strncpy(password, instring, STRINGSIZE);
  870. X
  871. X    password[STRINGSIZE - 1] = '\0';
  872. X
  873. X    if (strlen(password) < 4)
  874. X    {
  875. X    return ("it's WAY too short");
  876. X    }
  877. X
  878. X    if (strlen(password) < MINLEN)
  879. X    {
  880. X    return ("it is too short");
  881. X    }
  882. X
  883. X    jptr = junk;
  884. X    *jptr = '\0';
  885. X
  886. X    for (i = 0; i < STRINGSIZE && password[i]; i++)
  887. X    {
  888. X    if (!strchr(junk, password[i]))
  889. X    {
  890. X        *(jptr++) = password[i];
  891. X        *jptr = '\0';
  892. X    }
  893. X    }
  894. X
  895. X    if (strlen(junk) < MINDIFF)
  896. X    {
  897. X    return ("it does not contain enough DIFFERENT characters");
  898. X    }
  899. X
  900. X    strcpy(password, Lowercase(password));
  901. X
  902. X    Trim(password);
  903. X
  904. X    while (*password && isspace(*password))
  905. X    {
  906. X    password++;
  907. X    }
  908. X
  909. X    if (!*password)
  910. X    {
  911. X    return ("it is all whitespace");
  912. X    }
  913. X
  914. X    i = 0;
  915. X    ptr = password;
  916. X    while (ptr[0] && ptr[1])
  917. X    {
  918. X    if ((ptr[1] == (ptr[0] + 1)) || (ptr[1] == (ptr[0] - 1)))
  919. X    {
  920. X        i++;
  921. X    }
  922. X    ptr++;
  923. X    }
  924. X
  925. X    if (i > MAXSTEP)
  926. X    {
  927. X    return ("it is too simplistic/systematic");
  928. X    }
  929. X
  930. X    if (PMatch("aadddddda", password))    /* smirk */
  931. X    {
  932. X    return ("it looks like a National Insurance number.");
  933. X    }
  934. X
  935. X    if (ptr = FascistGecos(password, getuid()))
  936. X    {
  937. X    return (ptr);
  938. X    }
  939. X
  940. X    for (i = 0; r_destructors[i]; i++)
  941. X    {
  942. X    char *a;
  943. X    if (!(a = Mangle(password, r_destructors[i])))
  944. X    {
  945. X        continue;
  946. X    }
  947. X    if (FindPW(pwp, a) != notfound)
  948. X    {
  949. X        return ("it is based on a dictionary word");
  950. X    }
  951. X    }
  952. X
  953. X    strcpy(password, Reverse(password));
  954. X
  955. X    for (i = 0; r_destructors[i]; i++)
  956. X    {
  957. X    char *a;
  958. X
  959. X    if (!(a = Mangle(password, r_destructors[i])))
  960. X    {
  961. X        continue;
  962. X    }
  963. X
  964. X    if (FindPW(pwp, a) != notfound)
  965. X    {
  966. X        return ("it is based on a (reversed) dictionary word");
  967. X    }
  968. X    }
  969. X
  970. X    return ((char *) 0);
  971. X}
  972. X
  973. Xchar *
  974. XFascistCheck(password, path)
  975. X    char *password;
  976. X    char *path;
  977. X{
  978. X    static PWDICT *pwp;
  979. X    static char lastpath[STRINGSIZE];
  980. X
  981. X    if (pwp && strncmp(lastpath, path, STRINGSIZE))
  982. X    {
  983. X        PWClose(pwp);
  984. X        pwp = (PWDICT *)0;
  985. X    }
  986. X
  987. X    if (!pwp)
  988. X    {
  989. X    if (!(pwp = PWOpen(path, "r")))
  990. X    {
  991. X        perror("PWOpen");
  992. X        exit(-1);
  993. X    }
  994. X    strncpy(lastpath, path, STRINGSIZE);
  995. X    }
  996. X
  997. X    return (FascistLook(pwp, password));
  998. X}
  999. END_OF_FILE
  1000.   if test 8505 -ne `wc -c <'cracklib/fascist.c'`; then
  1001.     echo shar: \"'cracklib/fascist.c'\" unpacked with wrong size!
  1002.   fi
  1003.   # end of 'cracklib/fascist.c'
  1004. fi
  1005. if test -f 'cracklib/packlib.c' -a "${1}" != "-c" ; then 
  1006.   echo shar: Will not clobber existing file \"'cracklib/packlib.c'\"
  1007. else
  1008.   echo shar: Extracting \"'cracklib/packlib.c'\" \(6603 characters\)
  1009.   sed "s/^X//" >'cracklib/packlib.c' <<'END_OF_FILE'
  1010. X/*
  1011. X * This program is copyright Alec Muffett 1993. The author disclaims all 
  1012. X * responsibility or liability with respect to it's usage or its effect 
  1013. X * upon hardware or computer systems, and maintains copyright as set out 
  1014. X * in the "LICENCE" document which accompanies distributions of Crack v4.0 
  1015. X * and upwards.
  1016. X */
  1017. X
  1018. X#include "packer.h"
  1019. X
  1020. Xstatic char vers_id[] = "packlib.c : v2.3p2 Alec Muffett 18 May 1993";
  1021. X
  1022. XPWDICT *
  1023. XPWOpen(prefix, mode)
  1024. X    char *prefix;
  1025. X    char *mode;
  1026. X{
  1027. X    int32 i;
  1028. X    static PWDICT pdesc;
  1029. X    char iname[STRINGSIZE];
  1030. X    char dname[STRINGSIZE];
  1031. X    char wname[STRINGSIZE];
  1032. X    char buffer[STRINGSIZE];
  1033. X    FILE *dfp;
  1034. X    FILE *ifp;
  1035. X    FILE *wfp;
  1036. X
  1037. X    if (pdesc.header.pih_magic == PIH_MAGIC)
  1038. X    {
  1039. X    fprintf(stderr, "%s: another dictionary already open\n", prefix);
  1040. X    return ((PWDICT *) 0);
  1041. X    }
  1042. X
  1043. X    memset(&pdesc, '\0', sizeof(pdesc));
  1044. X
  1045. X    sprintf(iname, "%s.pwi", prefix);
  1046. X    sprintf(dname, "%s.pwd", prefix);
  1047. X    sprintf(wname, "%s.hwm", prefix);
  1048. X
  1049. X    if (!(pdesc.dfp = fopen(dname, mode)))
  1050. X    {
  1051. X    perror(dname);
  1052. X    return ((PWDICT *) 0);
  1053. X    }
  1054. X
  1055. X    if (!(pdesc.ifp = fopen(iname, mode)))
  1056. X    {
  1057. X    fclose(pdesc.dfp);
  1058. X    perror(iname);
  1059. X    return ((PWDICT *) 0);
  1060. X    }
  1061. X
  1062. X    if (pdesc.wfp = fopen(wname, mode))
  1063. X    {
  1064. X    pdesc.flags |= PFOR_USEHWMS;
  1065. X    }
  1066. X
  1067. X    ifp = pdesc.ifp;
  1068. X    dfp = pdesc.dfp;
  1069. X    wfp = pdesc.wfp;
  1070. X
  1071. X    if (mode[0] == 'w')
  1072. X    {
  1073. X    pdesc.flags |= PFOR_WRITE;
  1074. X    pdesc.header.pih_magic = PIH_MAGIC;
  1075. X    pdesc.header.pih_blocklen = NUMWORDS;
  1076. X    pdesc.header.pih_numwords = 0;
  1077. X
  1078. X    fwrite((char *) &pdesc.header, sizeof(pdesc.header), 1, ifp);
  1079. X    } else
  1080. X    {
  1081. X    pdesc.flags &= ~PFOR_WRITE;
  1082. X
  1083. X    if (!fread((char *) &pdesc.header, sizeof(pdesc.header), 1, ifp))
  1084. X    {
  1085. X        fprintf(stderr, "%s: error reading header\n", prefix);
  1086. X
  1087. X        pdesc.header.pih_magic = 0;
  1088. X        fclose(ifp);
  1089. X        fclose(dfp);
  1090. X        return ((PWDICT *) 0);
  1091. X    }
  1092. X
  1093. X    if (pdesc.header.pih_magic != PIH_MAGIC)
  1094. X    {
  1095. X        fprintf(stderr, "%s: magic mismatch\n", prefix);
  1096. X
  1097. X        pdesc.header.pih_magic = 0;
  1098. X        fclose(ifp);
  1099. X        fclose(dfp);
  1100. X        return ((PWDICT *) 0);
  1101. X    }
  1102. X
  1103. X    if (pdesc.header.pih_blocklen != NUMWORDS)
  1104. X    {
  1105. X        fprintf(stderr, "%s: size mismatch\n", prefix);
  1106. X
  1107. X        pdesc.header.pih_magic = 0;
  1108. X        fclose(ifp);
  1109. X        fclose(dfp);
  1110. X        return ((PWDICT *) 0);
  1111. X    }
  1112. X
  1113. X    if (pdesc.flags & PFOR_USEHWMS)
  1114. X    {
  1115. X        if (fread(pdesc.hwms, 1, sizeof(pdesc.hwms), wfp) != sizeof(pdesc.hwms))
  1116. X        {
  1117. X        pdesc.flags &= ~PFOR_USEHWMS;
  1118. X        }
  1119. X    }
  1120. X    }
  1121. X
  1122. X    return (&pdesc);
  1123. X}
  1124. X
  1125. Xint
  1126. XPWClose(pwp)
  1127. X    PWDICT *pwp;
  1128. X{
  1129. X    if (pwp->header.pih_magic != PIH_MAGIC)
  1130. X    {
  1131. X    fprintf(stderr, "PWClose: close magic mismatch\n");
  1132. X    return (-1);
  1133. X    }
  1134. X
  1135. X    if (pwp->flags & PFOR_WRITE)
  1136. X    {
  1137. X    pwp->flags |= PFOR_FLUSH;
  1138. X    PutPW(pwp, (char *) 0);    /* flush last index if necess */
  1139. X
  1140. X    if (fseek(pwp->ifp, 0L, 0))
  1141. X    {
  1142. X        fprintf(stderr, "index magic fseek failed\n");
  1143. X        return (-1);
  1144. X    }
  1145. X
  1146. X    if (!fwrite((char *) &pwp->header, sizeof(pwp->header), 1, pwp->ifp))
  1147. X    {
  1148. X        fprintf(stderr, "index magic fwrite failed\n");
  1149. X        return (-1);
  1150. X    }
  1151. X
  1152. X    if (pwp->flags & PFOR_USEHWMS)
  1153. X    {
  1154. X        int i;
  1155. X        for (i=1; i<=0xff; i++)
  1156. X        {
  1157. X            if (!pwp->hwms[i])
  1158. X            {
  1159. X                pwp->hwms[i] = pwp->hwms[i-1];
  1160. X            }
  1161. X#ifdef DEBUG
  1162. X            printf("hwm[%02x] = %d\n", i, pwp->hwms[i]);
  1163. X#endif
  1164. X        }
  1165. X        fwrite(pwp->hwms, 1, sizeof(pwp->hwms), pwp->wfp);
  1166. X    }
  1167. X    }
  1168. X
  1169. X    fclose(pwp->ifp);
  1170. X    fclose(pwp->dfp);
  1171. X
  1172. X    pwp->header.pih_magic = 0;
  1173. X
  1174. X    return (0);
  1175. X}
  1176. X
  1177. Xint
  1178. XPutPW(pwp, string)
  1179. X    PWDICT *pwp;
  1180. X    char *string;
  1181. X{
  1182. X    if (!(pwp->flags & PFOR_WRITE))
  1183. X    {
  1184. X    return (-1);
  1185. X    }
  1186. X
  1187. X    if (string)
  1188. X    {
  1189. X    strncpy(pwp->data[pwp->count], string, MAXWORDLEN);
  1190. X    pwp->data[pwp->count][MAXWORDLEN - 1] = '\0';
  1191. X
  1192. X    pwp->hwms[string[0] & 0xff]= pwp->header.pih_numwords;
  1193. X
  1194. X    ++(pwp->count);
  1195. X    ++(pwp->header.pih_numwords);
  1196. X
  1197. X    } else if (!(pwp->flags & PFOR_FLUSH))
  1198. X    {
  1199. X    return (-1);
  1200. X    }
  1201. X
  1202. X    if ((pwp->flags & PFOR_FLUSH) || !(pwp->count % NUMWORDS))
  1203. X    {
  1204. X    int i;
  1205. X    int32 datum;
  1206. X    register char *ostr;
  1207. X
  1208. X    datum = (int32) ftell(pwp->dfp);
  1209. X
  1210. X    fwrite((char *) &datum, sizeof(datum), 1, pwp->ifp);
  1211. X
  1212. X    fputs(pwp->data[0], pwp->dfp);
  1213. X    putc(0, pwp->dfp);
  1214. X
  1215. X    ostr = pwp->data[0];
  1216. X
  1217. X    for (i = 1; i < NUMWORDS; i++)
  1218. X    {
  1219. X        register int j;
  1220. X        register char *nstr;
  1221. X        nstr = pwp->data[i];
  1222. X
  1223. X        if (nstr[0])
  1224. X        {
  1225. X        for (j = 0; ostr[j] && nstr[j] && (ostr[j] == nstr[j]); j++);
  1226. X        putc(j & 0xff, pwp->dfp);
  1227. X        fputs(nstr + j, pwp->dfp);
  1228. X        }
  1229. X        putc(0, pwp->dfp);
  1230. X
  1231. X        ostr = nstr;
  1232. X    }
  1233. X
  1234. X    memset(pwp->data, '\0', sizeof(pwp->data));
  1235. X    pwp->count = 0;
  1236. X    }
  1237. X    return (0);
  1238. X}
  1239. X
  1240. Xchar *
  1241. XGetPW(pwp, number)
  1242. X    PWDICT *pwp;
  1243. X    int32 number;
  1244. X{
  1245. X    int32 datum;
  1246. X    register int i;
  1247. X    register char *ostr;
  1248. X    register char *nstr;
  1249. X    register char *bptr;
  1250. X    char buffer[NUMWORDS * MAXWORDLEN];
  1251. X    static char data[NUMWORDS][MAXWORDLEN];
  1252. X    static int32 prevblock = 0xffffffff;
  1253. X    int32 thisblock;
  1254. X
  1255. X    thisblock = number / NUMWORDS;
  1256. X
  1257. X    if (prevblock == thisblock)
  1258. X    {
  1259. X    return (data[number % NUMWORDS]);
  1260. X    }
  1261. X
  1262. X    if (fseek(pwp->ifp, sizeof(struct pi_header) + (thisblock * sizeof(int32)), 0))
  1263. X    {
  1264. X    perror("(index fseek failed)");
  1265. X    return ((char *) 0);
  1266. X    }
  1267. X
  1268. X    if (!fread((char *) &datum, sizeof(datum), 1, pwp->ifp))
  1269. X    {
  1270. X    perror("(index fread failed)");
  1271. X    return ((char *) 0);
  1272. X    }
  1273. X
  1274. X    if (fseek(pwp->dfp, datum, 0))
  1275. X    {
  1276. X    perror("(data fseek failed)");
  1277. X    return ((char *) 0);
  1278. X    }
  1279. X
  1280. X    if (!fread(buffer, 1, sizeof(buffer), pwp->dfp))
  1281. X    {
  1282. X    perror("(data fread failed)");
  1283. X    return ((char *) 0);
  1284. X    }
  1285. X
  1286. X    prevblock = thisblock;
  1287. X
  1288. X    bptr = buffer;
  1289. X
  1290. X    for (ostr = data[0]; *(ostr++) = *(bptr++); /* nothing */ );
  1291. X
  1292. X    ostr = data[0];
  1293. X
  1294. X    for (i = 1; i < NUMWORDS; i++)
  1295. X    {
  1296. X    nstr = data[i];
  1297. X    strcpy(nstr, ostr);
  1298. X
  1299. X    ostr = nstr + *(bptr++);
  1300. X    while (*(ostr++) = *(bptr++));
  1301. X
  1302. X    ostr = nstr;
  1303. X    }
  1304. X
  1305. X    return (data[number % NUMWORDS]);
  1306. X}
  1307. X
  1308. Xint32
  1309. XFindPW(pwp, string)
  1310. X    PWDICT *pwp;
  1311. X    char *string;
  1312. X{
  1313. X    register int32 lwm;
  1314. X    register int32 hwm;
  1315. X    register int32 middle;
  1316. X    register char *this;
  1317. X    int idx;
  1318. X
  1319. X    if (pwp->flags & PFOR_USEHWMS)
  1320. X    {
  1321. X    idx = string[0] & 0xff;
  1322. X        lwm = idx ? pwp->hwms[idx - 1] : 0;
  1323. X        hwm = pwp->hwms[idx];
  1324. X    } else
  1325. X    {
  1326. X        lwm = 0;
  1327. X        hwm = PW_WORDS(pwp) - 1;
  1328. X    }
  1329. X
  1330. X#ifdef DEBUG
  1331. X    printf("---- %lu, %lu ----\n", lwm, hwm);
  1332. X#endif
  1333. X
  1334. X    for (;;)
  1335. X    {
  1336. X    int cmp;
  1337. X
  1338. X#ifdef DEBUG
  1339. X    printf("%lu, %lu\n", lwm, hwm);
  1340. X#endif
  1341. X
  1342. X    middle = lwm + ((hwm - lwm + 1) / 2);
  1343. X
  1344. X    if (middle == hwm)
  1345. X    {
  1346. X        break;
  1347. X    }
  1348. X
  1349. X    this = GetPW(pwp, middle);
  1350. X    cmp = strcmp(string, this);        /* INLINE ? */
  1351. X
  1352. X    if (cmp < 0)
  1353. X    {
  1354. X        hwm = middle;
  1355. X    } else if (cmp > 0)
  1356. X    {
  1357. X        lwm = middle;
  1358. X    } else
  1359. X    {
  1360. X        return (middle);
  1361. X    }
  1362. X    }
  1363. X
  1364. X    return (PW_WORDS(pwp));
  1365. X}
  1366. END_OF_FILE
  1367.   if test 6603 -ne `wc -c <'cracklib/packlib.c'`; then
  1368.     echo shar: \"'cracklib/packlib.c'\" unpacked with wrong size!
  1369.   fi
  1370.   # end of 'cracklib/packlib.c'
  1371. fi
  1372. if test -f 'cracklib/rules.c' -a "${1}" != "-c" ; then 
  1373.   echo shar: Will not clobber existing file \"'cracklib/rules.c'\"
  1374. else
  1375.   echo shar: Extracting \"'cracklib/rules.c'\" \(15448 characters\)
  1376.   sed "s/^X//" >'cracklib/rules.c' <<'END_OF_FILE'
  1377. X/*
  1378. X * This program is copyright Alec Muffett 1993. The author disclaims all 
  1379. X * responsibility or liability with respect to it's usage or its effect 
  1380. X * upon hardware or computer systems, and maintains copyright as set out 
  1381. X * in the "LICENCE" document which accompanies distributions of Crack v4.0 
  1382. X * and upwards.
  1383. X */
  1384. X
  1385. Xstatic char vers_id[] = "rules.c : v5.0p3 Alec Muffett 20 May 1993";
  1386. X
  1387. X#ifndef IN_CRACKLIB
  1388. X
  1389. X#include "crack.h"
  1390. X
  1391. X#else
  1392. X
  1393. X#include "packer.h"
  1394. X
  1395. Xstatic void
  1396. XDebug(val, a, b, c, d, e, f, g)
  1397. X    int val;
  1398. X    char *a, *b, *c, *d, *e, *f, *g;
  1399. X{
  1400. X    fprintf(stderr, a, b, c, d, e, f);
  1401. X}
  1402. X
  1403. X#endif
  1404. X
  1405. X#define RULE_NOOP    ':'
  1406. X#define RULE_PREPEND    '^'
  1407. X#define RULE_APPEND    '$'
  1408. X#define RULE_REVERSE    'r'
  1409. X#define RULE_UPPERCASE    'u'
  1410. X#define RULE_LOWERCASE    'l'
  1411. X#define RULE_PLURALISE    'p'
  1412. X#define RULE_CAPITALISE    'c'
  1413. X#define RULE_DUPLICATE    'd'
  1414. X#define RULE_REFLECT    'f'
  1415. X#define RULE_SUBSTITUTE    's'
  1416. X#define RULE_MATCH    '/'
  1417. X#define RULE_NOT    '!'
  1418. X#define RULE_LT        '<'
  1419. X#define RULE_GT        '>'
  1420. X#define RULE_EXTRACT    'x'
  1421. X#define RULE_OVERSTRIKE    'o'
  1422. X#define RULE_INSERT    'i'
  1423. X#define RULE_EQUALS    '='
  1424. X#define RULE_PURGE    '@'
  1425. X#define RULE_CLASS    '?'    /* class rule? socialist ethic in cracker? */
  1426. X
  1427. X#define RULE_DFIRST    '['
  1428. X#define RULE_DLAST    ']'
  1429. X#define RULE_MFIRST    '('
  1430. X#define RULE_MLAST    ')'
  1431. X
  1432. Xint
  1433. XSuffix(myword, suffix)
  1434. X    char *myword;
  1435. X    char *suffix;
  1436. X{
  1437. X    register int i;
  1438. X    register int j;
  1439. X    i = strlen(myword);
  1440. X    j = strlen(suffix);
  1441. X
  1442. X    if (i > j)
  1443. X    {
  1444. X    return (STRCMP((myword + i - j), suffix));
  1445. X    } else
  1446. X    {
  1447. X    return (-1);
  1448. X    }
  1449. X}
  1450. X
  1451. Xchar *
  1452. XReverse(str)            /* return a pointer to a reversal */
  1453. X    register char *str;
  1454. X{
  1455. X    register int i;
  1456. X    register int j;
  1457. X    static char area[STRINGSIZE];
  1458. X    j = i = strlen(str);
  1459. X    while (*str)
  1460. X    {
  1461. X    area[--i] = *str++;
  1462. X    }
  1463. X    area[j] = '\0';
  1464. X    return (area);
  1465. X}
  1466. X
  1467. Xchar *
  1468. XUppercase(str)            /* return a pointer to an uppercase */
  1469. X    register char *str;
  1470. X{
  1471. X    register char *ptr;
  1472. X    static char area[STRINGSIZE];
  1473. X    ptr = area;
  1474. X    while (*str)
  1475. X    {
  1476. X    *(ptr++) = CRACK_TOUPPER(*str);
  1477. X    str++;
  1478. X    }
  1479. X    *ptr = '\0';
  1480. X
  1481. X    return (area);
  1482. X}
  1483. X
  1484. Xchar *
  1485. XLowercase(str)            /* return a pointer to an lowercase */
  1486. X    register char *str;
  1487. X{
  1488. X    register char *ptr;
  1489. X    static char area[STRINGSIZE];
  1490. X    ptr = area;
  1491. X    while (*str)
  1492. X    {
  1493. X    *(ptr++) = CRACK_TOLOWER(*str);
  1494. X    str++;
  1495. X    }
  1496. X    *ptr = '\0';
  1497. X
  1498. X    return (area);
  1499. X}
  1500. X
  1501. Xchar *
  1502. XCapitalise(str)            /* return a pointer to an capitalised */
  1503. X    register char *str;
  1504. X{
  1505. X    register char *ptr;
  1506. X    static char area[STRINGSIZE];
  1507. X    ptr = area;
  1508. X
  1509. X    while (*str)
  1510. X    {
  1511. X    *(ptr++) = CRACK_TOLOWER(*str);
  1512. X    str++;
  1513. X    }
  1514. X
  1515. X    *ptr = '\0';
  1516. X    area[0] = CRACK_TOUPPER(area[0]);
  1517. X    return (area);
  1518. X}
  1519. X
  1520. Xchar *
  1521. XPluralise(string)        /* returns a pointer to a plural */
  1522. X    register char *string;
  1523. X{
  1524. X    register int length;
  1525. X    static char area[STRINGSIZE];
  1526. X    length = strlen(string);
  1527. X    strcpy(area, string);
  1528. X
  1529. X    if (!Suffix(string, "ch") ||
  1530. X    !Suffix(string, "ex") ||
  1531. X    !Suffix(string, "ix") ||
  1532. X    !Suffix(string, "sh") ||
  1533. X    !Suffix(string, "ss"))
  1534. X    {
  1535. X    /* bench -> benches */
  1536. X    strcat(area, "es");
  1537. X    } else if (length > 2 && string[length - 1] == 'y')
  1538. X    {
  1539. X    if (strchr("aeiou", string[length - 2]))
  1540. X    {
  1541. X        /* alloy -> alloys */
  1542. X        strcat(area, "s");
  1543. X    } else
  1544. X    {
  1545. X        /* gully -> gullies */
  1546. X        strcpy(area + length - 1, "ies");
  1547. X    }
  1548. X    } else if (string[length - 1] == 's')
  1549. X    {
  1550. X    /* bias -> biases */
  1551. X    strcat(area, "es");
  1552. X    } else
  1553. X    {
  1554. X    /* catchall */
  1555. X    strcat(area, "s");
  1556. X    }
  1557. X
  1558. X    return (area);
  1559. X}
  1560. X
  1561. Xchar *
  1562. XSubstitute(string, old, new)    /* returns pointer to a swapped about copy */
  1563. X    register char *string;
  1564. X    register char old;
  1565. X    register char new;
  1566. X{
  1567. X    register char *ptr;
  1568. X    static char area[STRINGSIZE];
  1569. X    ptr = area;
  1570. X    while (*string)
  1571. X    {
  1572. X    *(ptr++) = (*string == old ? new : *string);
  1573. X    string++;
  1574. X    }
  1575. X    *ptr = '\0';
  1576. X    return (area);
  1577. X}
  1578. X
  1579. Xchar *
  1580. XPurge(string, target)        /* returns pointer to a purged copy */
  1581. X    register char *string;
  1582. X    register char target;
  1583. X{
  1584. X    register char *ptr;
  1585. X    static char area[STRINGSIZE];
  1586. X    ptr = area;
  1587. X    while (*string)
  1588. X    {
  1589. X    if (*string != target)
  1590. X    {
  1591. X        *(ptr++) = *string;
  1592. X    }
  1593. X    string++;
  1594. X    }
  1595. X    *ptr = '\0';
  1596. X    return (area);
  1597. X}
  1598. X/* -------- CHARACTER CLASSES START HERE -------- */
  1599. X
  1600. X/*
  1601. X * this function takes two inputs, a class identifier and a character, and
  1602. X * returns non-null if the given character is a member of the class, based
  1603. X * upon restrictions set out below
  1604. X */
  1605. X
  1606. Xint
  1607. XMatchClass(class, input)
  1608. X    register char class;
  1609. X    register char input;
  1610. X{
  1611. X    register char c;
  1612. X    register int retval;
  1613. X    retval = 0;
  1614. X
  1615. X    switch (class)
  1616. X    {
  1617. X    /* ESCAPE */
  1618. X
  1619. X    case '?':            /* ?? -> ? */
  1620. X    if (input == '?')
  1621. X    {
  1622. X        retval = 1;
  1623. X    }
  1624. X    break;
  1625. X
  1626. X    /* ILLOGICAL GROUPINGS (ie: not in ctype.h) */
  1627. X
  1628. X    case 'V':
  1629. X    case 'v':            /* vowels */
  1630. X    c = CRACK_TOLOWER(input);
  1631. X    if (strchr("aeiou", c))
  1632. X    {
  1633. X        retval = 1;
  1634. X    }
  1635. X    break;
  1636. X
  1637. X    case 'C':
  1638. X    case 'c':            /* consonants */
  1639. X    c = CRACK_TOLOWER(input);
  1640. X    if (strchr("bcdfghjklmnpqrstvwxyz", c))
  1641. X    {
  1642. X        retval = 1;
  1643. X    }
  1644. X    break;
  1645. X
  1646. X    case 'W':
  1647. X    case 'w':            /* whitespace */
  1648. X    if (strchr("\t ", input))
  1649. X    {
  1650. X        retval = 1;
  1651. X    }
  1652. X    break;
  1653. X
  1654. X    case 'P':
  1655. X    case 'p':            /* punctuation */
  1656. X    if (strchr(".`,:;'!?\"", input))
  1657. X    {
  1658. X        retval = 1;
  1659. X    }
  1660. X    break;
  1661. X
  1662. X    case 'S':
  1663. X    case 's':            /* symbols */
  1664. X    if (strchr("$%%^&*()-_+=|\\[]{}#@/~", input))
  1665. X    {
  1666. X        retval = 1;
  1667. X    }
  1668. X    break;
  1669. X
  1670. X    /* LOGICAL GROUPINGS */
  1671. X
  1672. X    case 'L':
  1673. X    case 'l':            /* lowercase */
  1674. X    if (islower(input))
  1675. X    {
  1676. X        retval = 1;
  1677. X    }
  1678. X    break;
  1679. X
  1680. X    case 'U':
  1681. X    case 'u':            /* uppercase */
  1682. X    if (isupper(input))
  1683. X    {
  1684. X        retval = 1;
  1685. X    }
  1686. X    break;
  1687. X
  1688. X    case 'A':
  1689. X    case 'a':            /* alphabetic */
  1690. X    if (isalpha(input))
  1691. X    {
  1692. X        retval = 1;
  1693. X    }
  1694. X    break;
  1695. X
  1696. X    case 'X':
  1697. X    case 'x':            /* alphanumeric */
  1698. X    if (isalnum(input))
  1699. X    {
  1700. X        retval = 1;
  1701. X    }
  1702. X    break;
  1703. X
  1704. X    case 'D':
  1705. X    case 'd':            /* digits */
  1706. X    if (isdigit(input))
  1707. X    {
  1708. X        retval = 1;
  1709. X    }
  1710. X    break;
  1711. X
  1712. X    default:
  1713. X    Debug(1, "MatchClass: unknown class %c\n", class);
  1714. X    return (0);
  1715. X    break;
  1716. X    }
  1717. X
  1718. X    if (isupper(class))
  1719. X    {
  1720. X    return (!retval);
  1721. X    }
  1722. X    return (retval);
  1723. X}
  1724. X
  1725. Xchar *
  1726. XPolyStrchr(string, class)
  1727. X    register char *string;
  1728. X    register char class;
  1729. X{
  1730. X    while (*string)
  1731. X    {
  1732. X    if (MatchClass(class, *string))
  1733. X    {
  1734. X        return (string);
  1735. X    }
  1736. X    string++;
  1737. X    }
  1738. X    return ((char *) 0);
  1739. X}
  1740. X
  1741. Xchar *
  1742. XPolySubst(string, class, new)    /* returns pointer to a swapped about copy */
  1743. X    register char *string;
  1744. X    register char class;
  1745. X    register char new;
  1746. X{
  1747. X    register char *ptr;
  1748. X    static char area[STRINGSIZE];
  1749. X    ptr = area;
  1750. X    while (*string)
  1751. X    {
  1752. X    *(ptr++) = (MatchClass(class, *string) ? new : *string);
  1753. X    string++;
  1754. X    }
  1755. X    *ptr = '\0';
  1756. X    return (area);
  1757. X}
  1758. X
  1759. Xchar *
  1760. XPolyPurge(string, class)    /* returns pointer to a purged copy */
  1761. X    register char *string;
  1762. X    register char class;
  1763. X{
  1764. X    register char *ptr;
  1765. X    static char area[STRINGSIZE];
  1766. X    ptr = area;
  1767. X    while (*string)
  1768. X    {
  1769. X    if (!MatchClass(class, *string))
  1770. X    {
  1771. X        *(ptr++) = *string;
  1772. X    }
  1773. X    string++;
  1774. X    }
  1775. X    *ptr = '\0';
  1776. X    return (area);
  1777. X}
  1778. X/* -------- BACK TO NORMALITY -------- */
  1779. X
  1780. Xint
  1781. XChar2Int(character)
  1782. X    char character;
  1783. X{
  1784. X    if (isdigit(character))
  1785. X    {
  1786. X    return (character - '0');
  1787. X    } else if (islower(character))
  1788. X    {
  1789. X    return (character - 'a' + 10);
  1790. X    } else if (isupper(character))
  1791. X    {
  1792. X    return (character - 'A' + 10);
  1793. X    }
  1794. X    return (-1);
  1795. X}
  1796. X
  1797. Xchar *
  1798. XMangle(input, control)        /* returns a pointer to a controlled Mangle */
  1799. X    char *input;
  1800. X    char *control;
  1801. X{
  1802. X    int limit;
  1803. X    register char *ptr;
  1804. X    static char area[STRINGSIZE];
  1805. X    char area2[STRINGSIZE];
  1806. X    area[0] = '\0';
  1807. X    strcpy(area, input);
  1808. X
  1809. X    for (ptr = control; *ptr; ptr++)
  1810. X    {
  1811. X    switch (*ptr)
  1812. X    {
  1813. X    case RULE_NOOP:
  1814. X        break;
  1815. X    case RULE_REVERSE:
  1816. X        strcpy(area, Reverse(area));
  1817. X        break;
  1818. X    case RULE_UPPERCASE:
  1819. X        strcpy(area, Uppercase(area));
  1820. X        break;
  1821. X    case RULE_LOWERCASE:
  1822. X        strcpy(area, Lowercase(area));
  1823. X        break;
  1824. X    case RULE_CAPITALISE:
  1825. X        strcpy(area, Capitalise(area));
  1826. X        break;
  1827. X    case RULE_PLURALISE:
  1828. X        strcpy(area, Pluralise(area));
  1829. X        break;
  1830. X    case RULE_REFLECT:
  1831. X        strcat(area, Reverse(area));
  1832. X        break;
  1833. X    case RULE_DUPLICATE:
  1834. X        strcpy(area2, area);
  1835. X        strcat(area, area2);
  1836. X        break;
  1837. X    case RULE_GT:
  1838. X        if (!ptr[1])
  1839. X        {
  1840. X        Debug(1, "Mangle: '>' missing argument in '%s'\n", control);
  1841. X        return ((char *) 0);
  1842. X        } else
  1843. X        {
  1844. X        limit = Char2Int(*(++ptr));
  1845. X        if (limit < 0)
  1846. X        {
  1847. X            Debug(1, "Mangle: '>' weird argument in '%s'\n", control);
  1848. X            return ((char *) 0);
  1849. X        }
  1850. X        if (strlen(area) <= limit)
  1851. X        {
  1852. X            return ((char *) 0);
  1853. X        }
  1854. X        }
  1855. X        break;
  1856. X    case RULE_LT:
  1857. X        if (!ptr[1])
  1858. X        {
  1859. X        Debug(1, "Mangle: '<' missing argument in '%s'\n", control);
  1860. X        return ((char *) 0);
  1861. X        } else
  1862. X        {
  1863. X        limit = Char2Int(*(++ptr));
  1864. X        if (limit < 0)
  1865. X        {
  1866. X            Debug(1, "Mangle: '<' weird argument in '%s'\n", control);
  1867. X            return ((char *) 0);
  1868. X        }
  1869. X        if (strlen(area) >= limit)
  1870. X        {
  1871. X            return ((char *) 0);
  1872. X        }
  1873. X        }
  1874. X        break;
  1875. X    case RULE_PREPEND:
  1876. X        if (!ptr[1])
  1877. X        {
  1878. X        Debug(1, "Mangle: prepend missing argument in '%s'\n", control);
  1879. X        return ((char *) 0);
  1880. X        } else
  1881. X        {
  1882. X        area2[0] = *(++ptr);
  1883. X        strcpy(area2 + 1, area);
  1884. X        strcpy(area, area2);
  1885. X        }
  1886. X        break;
  1887. X    case RULE_APPEND:
  1888. X        if (!ptr[1])
  1889. X        {
  1890. X        Debug(1, "Mangle: append missing argument in '%s'\n", control);
  1891. X        return ((char *) 0);
  1892. X        } else
  1893. X        {
  1894. X        register char *string;
  1895. X        string = area;
  1896. X        while (*(string++));
  1897. X        string[-1] = *(++ptr);
  1898. X        *string = '\0';
  1899. X        }
  1900. X        break;
  1901. X    case RULE_EXTRACT:
  1902. X        if (!ptr[1] || !ptr[2])
  1903. X        {
  1904. X        Debug(1, "Mangle: extract missing argument in '%s'\n", control);
  1905. X        return ((char *) 0);
  1906. X        } else
  1907. X        {
  1908. X        register int i;
  1909. X        int start;
  1910. X        int length;
  1911. X        start = Char2Int(*(++ptr));
  1912. X        length = Char2Int(*(++ptr));
  1913. X        if (start < 0 || length < 0)
  1914. X        {
  1915. X            Debug(1, "Mangle: extract: weird argument in '%s'\n", control);
  1916. X            return ((char *) 0);
  1917. X        }
  1918. X        strcpy(area2, area);
  1919. X        for (i = 0; length-- && area2[start + i]; i++)
  1920. X        {
  1921. X            area[i] = area2[start + i];
  1922. X        }
  1923. X        /* cant use strncpy() - no trailing NUL */
  1924. X        area[i] = '\0';
  1925. X        }
  1926. X        break;
  1927. X    case RULE_OVERSTRIKE:
  1928. X        if (!ptr[1] || !ptr[2])
  1929. X        {
  1930. X        Debug(1, "Mangle: overstrike missing argument in '%s'\n", control);
  1931. X        return ((char *) 0);
  1932. X        } else
  1933. X        {
  1934. X        register int i;
  1935. X        i = Char2Int(*(++ptr));
  1936. X        if (i < 0)
  1937. X        {
  1938. X            Debug(1, "Mangle: overstrike weird argument in '%s'\n",
  1939. X              control);
  1940. X            return ((char *) 0);
  1941. X        } else
  1942. X        {
  1943. X            ++ptr;
  1944. X            if (area[i])
  1945. X            {
  1946. X            area[i] = *ptr;
  1947. X            }
  1948. X        }
  1949. X        }
  1950. X        break;
  1951. X    case RULE_INSERT:
  1952. X        if (!ptr[1] || !ptr[2])
  1953. X        {
  1954. X        Debug(1, "Mangle: insert missing argument in '%s'\n", control);
  1955. X        return ((char *) 0);
  1956. X        } else
  1957. X        {
  1958. X        register int i;
  1959. X        register char *p1;
  1960. X        register char *p2;
  1961. X        i = Char2Int(*(++ptr));
  1962. X        if (i < 0)
  1963. X        {
  1964. X            Debug(1, "Mangle: insert weird argument in '%s'\n",
  1965. X              control);
  1966. X            return ((char *) 0);
  1967. X        }
  1968. X        p1 = area;
  1969. X        p2 = area2;
  1970. X        while (i && *p1)
  1971. X        {
  1972. X            i--;
  1973. X            *(p2++) = *(p1++);
  1974. X        }
  1975. X        *(p2++) = *(++ptr);
  1976. X        strcpy(p2, p1);
  1977. X        strcpy(area, area2);
  1978. X        }
  1979. X        break;
  1980. X        /* THE FOLLOWING RULES REQUIRE CLASS MATCHING */
  1981. X
  1982. X    case RULE_PURGE:    /* @x or @?c */
  1983. X        if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
  1984. X        {
  1985. X        Debug(1, "Mangle: delete missing arguments in '%s'\n", control);
  1986. X        return ((char *) 0);
  1987. X        } else if (ptr[1] != RULE_CLASS)
  1988. X        {
  1989. X        strcpy(area, Purge(area, *(++ptr)));
  1990. X        } else
  1991. X        {
  1992. X        strcpy(area, PolyPurge(area, ptr[2]));
  1993. X        ptr += 2;
  1994. X        }
  1995. X        break;
  1996. X    case RULE_SUBSTITUTE:    /* sxy || s?cy */
  1997. X        if (!ptr[1] || !ptr[2] || (ptr[1] == RULE_CLASS && !ptr[3]))
  1998. X        {
  1999. X        Debug(1, "Mangle: subst missing argument in '%s'\n", control);
  2000. X        return ((char *) 0);
  2001. X        } else if (ptr[1] != RULE_CLASS)
  2002. X        {
  2003. X        strcpy(area, Substitute(area, ptr[1], ptr[2]));
  2004. X        ptr += 2;
  2005. X        } else
  2006. X        {
  2007. X        strcpy(area, PolySubst(area, ptr[2], ptr[3]));
  2008. X        ptr += 3;
  2009. X        }
  2010. X        break;
  2011. X    case RULE_MATCH:    /* /x || /?c */
  2012. X        if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
  2013. X        {
  2014. X        Debug(1, "Mangle: '/' missing argument in '%s'\n", control);
  2015. X        return ((char *) 0);
  2016. X        } else if (ptr[1] != RULE_CLASS)
  2017. X        {
  2018. X        if (!strchr(area, *(++ptr)))
  2019. X        {
  2020. X            return ((char *) 0);
  2021. X        }
  2022. X        } else
  2023. X        {
  2024. X        if (!PolyStrchr(area, ptr[2]))
  2025. X        {
  2026. X            return ((char *) 0);
  2027. X        }
  2028. X        ptr += 2;
  2029. X        }
  2030. X        break;
  2031. X    case RULE_NOT:        /* !x || !?c */
  2032. X        if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
  2033. X        {
  2034. X        Debug(1, "Mangle: '!' missing argument in '%s'\n", control);
  2035. X        return ((char *) 0);
  2036. X        } else if (ptr[1] != RULE_CLASS)
  2037. X        {
  2038. X        if (strchr(area, *(++ptr)))
  2039. X        {
  2040. X            return ((char *) 0);
  2041. X        }
  2042. X        } else
  2043. X        {
  2044. X        if (PolyStrchr(area, ptr[2]))
  2045. X        {
  2046. X            return ((char *) 0);
  2047. X        }
  2048. X        ptr += 2;
  2049. X        }
  2050. X        break;
  2051. X        /*
  2052. X         * alternative use for a boomerang, number 1: a standard throwing
  2053. X         * boomerang is an ideal thing to use to tuck the sheets under
  2054. X         * the mattress when making your bed.  The streamlined shape of
  2055. X         * the boomerang allows it to slip easily 'twixt mattress and
  2056. X         * bedframe, and it's curve makes it very easy to hook sheets
  2057. X         * into the gap.
  2058. X         */
  2059. X
  2060. X    case RULE_EQUALS:    /* =nx || =n?c */
  2061. X        if (!ptr[1] || !ptr[2] || (ptr[2] == RULE_CLASS && !ptr[3]))
  2062. X        {
  2063. X        Debug(1, "Mangle: '=' missing argument in '%s'\n", control);
  2064. X        return ((char *) 0);
  2065. X        } else
  2066. X        {
  2067. X        register int i;
  2068. X        if ((i = Char2Int(ptr[1])) < 0)
  2069. X        {
  2070. X            Debug(1, "Mangle: '=' weird argument in '%s'\n", control);
  2071. X            return ((char *) 0);
  2072. X        }
  2073. X        if (ptr[2] != RULE_CLASS)
  2074. X        {
  2075. X            ptr += 2;
  2076. X            if (area[i] != *ptr)
  2077. X            {
  2078. X            return ((char *) 0);
  2079. X            }
  2080. X        } else
  2081. X        {
  2082. X            ptr += 3;
  2083. X            if (!MatchClass(*ptr, area[i]))
  2084. X            {
  2085. X            return ((char *) 0);
  2086. X            }
  2087. X        }
  2088. X        }
  2089. X        break;
  2090. X
  2091. X    case RULE_DFIRST:
  2092. X        if (area[0])
  2093. X        {
  2094. X        register int i;
  2095. X        for (i = 1; area[i]; i++)
  2096. X        {
  2097. X            area[i - 1] = area[i];
  2098. X        }
  2099. X        area[i - 1] = '\0';
  2100. X        }
  2101. X        break;
  2102. X
  2103. X    case RULE_DLAST:
  2104. X        if (area[0])
  2105. X        {
  2106. X        register int i;
  2107. X        for (i = 1; area[i]; i++);
  2108. X        area[i - 1] = '\0';
  2109. X        }
  2110. X        break;
  2111. X
  2112. X    case RULE_MFIRST:
  2113. X        if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
  2114. X        {
  2115. X        Debug(1, "Mangle: '(' missing argument in '%s'\n", control);
  2116. X        return ((char *) 0);
  2117. X        } else
  2118. X        {
  2119. X        if (ptr[1] != RULE_CLASS)
  2120. X        {
  2121. X            ptr++;
  2122. X            if (area[0] != *ptr)
  2123. X            {
  2124. X            return ((char *) 0);
  2125. X            }
  2126. X        } else
  2127. X        {
  2128. X            ptr += 2;
  2129. X            if (!MatchClass(*ptr, area[0]))
  2130. X            {
  2131. X            return ((char *) 0);
  2132. X            }
  2133. X        }
  2134. X        }
  2135. X    case RULE_MLAST:
  2136. X        if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
  2137. X        {
  2138. X        Debug(1, "Mangle: ')' missing argument in '%s'\n", control);
  2139. X        return ((char *) 0);
  2140. X        } else
  2141. X        {
  2142. X        register int i;
  2143. X
  2144. X        for (i = 0; area[i]; i++);
  2145. X
  2146. X        if (i > 0)
  2147. X        {
  2148. X            i--;
  2149. X        } else
  2150. X        {
  2151. X            return ((char *) 0);
  2152. X        }
  2153. X
  2154. X        if (ptr[1] != RULE_CLASS)
  2155. X        {
  2156. X            ptr++;
  2157. X            if (area[i] != *ptr)
  2158. X            {
  2159. X            return ((char *) 0);
  2160. X            }
  2161. X        } else
  2162. X        {
  2163. X            ptr += 2;
  2164. X            if (!MatchClass(*ptr, area[i]))
  2165. X            {
  2166. X            return ((char *) 0);
  2167. X            }
  2168. X        }
  2169. X        }
  2170. X
  2171. X    default:
  2172. X        Debug(1, "Mangle: unknown command %c in %s\n", *ptr, control);
  2173. X        return ((char *) 0);
  2174. X        break;
  2175. X    }
  2176. X    }
  2177. X    if (!area[0])        /* have we deweted de poor widdle fing away? */
  2178. X    {
  2179. X    return ((char *) 0);
  2180. X    }
  2181. X    return (area);
  2182. X}
  2183. X
  2184. Xint
  2185. XPMatch(control, string)
  2186. Xregister char *control;
  2187. Xregister char *string;
  2188. X{
  2189. X    while (*string && *control)
  2190. X    {
  2191. X        if (!MatchClass(*control, *string))
  2192. X        {
  2193. X            return(0);
  2194. X        }
  2195. X
  2196. X        string++;
  2197. X        control++;
  2198. X    }
  2199. X
  2200. X    if (*string || *control)
  2201. X    {
  2202. X        return(0);
  2203. X    }
  2204. X
  2205. X    return(1);
  2206. X}
  2207. END_OF_FILE
  2208.   if test 15448 -ne `wc -c <'cracklib/rules.c'`; then
  2209.     echo shar: \"'cracklib/rules.c'\" unpacked with wrong size!
  2210.   fi
  2211.   # end of 'cracklib/rules.c'
  2212. fi
  2213. if test ! -d 'shadow' ; then
  2214.     echo shar: Creating directory \"'shadow'\"
  2215.     mkdir 'shadow'
  2216. fi
  2217. if test -f 'shadow/README,CL' -a "${1}" != "-c" ; then 
  2218.   echo shar: Will not clobber existing file \"'shadow/README,CL'\"
  2219. else
  2220.   echo shar: Extracting \"'shadow/README,CL'\" \(1362 characters\)
  2221.   sed "s/^X//" >'shadow/README,CL' <<'END_OF_FILE'
  2222. XHi,
  2223. X
  2224. XThis here's a patch for John F Haugh's "shadow" password program, to get
  2225. Xit using "CrackLib".  I'm afraid I haven't had much opportunity to test
  2226. Xit (I don't have the time or resources), but I'd like to know how you
  2227. Xget on using it.
  2228. X
  2229. XInstructions:
  2230. X
  2231. X    1) Read the docs. Build and install CrackLib.
  2232. X
  2233. X    2) Install the latest version of "shadow" (patchlevel 6)
  2234. X     - available from comp.sources.misc archives everywhere.
  2235. X
  2236. X    It's spattered amongst several directories (being a initial
  2237. X    distribution, + patches), so you'll need the contents of:
  2238. X
  2239. X    usenet/comp.sources.misc/volume26/shadow
  2240. X    usenet/comp.sources.misc/volume28/shadow
  2241. X    usenet/comp.sources.misc/volume29/shadow
  2242. X    usenet/comp.sources.misc/volume30/shadow
  2243. X    usenet/comp.sources.misc/volume32/shadow
  2244. X
  2245. X    3) Install the enclosed file as "obscure.c" - it's only a
  2246. X       trivial change, you might like to hack it a bit yourself.
  2247. X
  2248. X    4) Edit the new "obscure.c" to change the value of:
  2249. X
  2250. X    CRACKLIB_DICTPATH
  2251. X
  2252. X       - to whatever you used during the CrackLib installation
  2253. X
  2254. X    5) Change the "shadow" Makefile to that shadow will be linked
  2255. X       with CrackLib, eg:
  2256. X
  2257. X    change:
  2258. X
  2259. X    LIBS = -lcrypt -lndbm
  2260. X
  2261. X    to:
  2262. X
  2263. X    LIBS = /where/ever/cracklib/cracklib.a -lcrypt -lndbm
  2264. X
  2265. X    6) Build and install "shadow"
  2266. X
  2267. X    7) Make sure you have obscure checks enabled
  2268. X
  2269. X    8) Run with it.
  2270. X
  2271. X
  2272. X                    - alec (16 Jun 1993)
  2273. END_OF_FILE
  2274.   if test 1362 -ne `wc -c <'shadow/README,CL'`; then
  2275.     echo shar: \"'shadow/README,CL'\" unpacked with wrong size!
  2276.   fi
  2277.   # end of 'shadow/README,CL'
  2278. fi
  2279. if test ! -d 'util' ; then
  2280.     echo shar: Creating directory \"'util'\"
  2281.     mkdir 'util'
  2282. fi
  2283. echo shar: End of archive 1 \(of 2\).
  2284. cp /dev/null ark1isdone
  2285. MISSING=""
  2286. for I in 1 2 ; do
  2287.     if test ! -f ark${I}isdone ; then
  2288.     MISSING="${MISSING} ${I}"
  2289.     fi
  2290. done
  2291. if test "${MISSING}" = "" ; then
  2292.     echo You have unpacked both archives.
  2293.     rm -f ark[1-9]isdone
  2294. else
  2295.     echo You still must unpack the following archives:
  2296.     echo "        " ${MISSING}
  2297. fi
  2298. exit 0
  2299. exit 0 # Just in case...
  2300.