home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume25 / crack / part04 < prev    next >
Text File  |  1991-11-03  |  57KB  |  2,090 lines

  1. Newsgroups: comp.sources.misc,alt.security
  2. From: aem@aberystwyth.ac.uk (Alec Muffett)
  3. Subject:  v25i008:  crack - The Password Cracker, version 4.0a, Part04/05
  4. Message-ID: <1991Nov3.231604.10335@sparky.imd.sterling.com>
  5. X-Md4-Signature: 6fa07ca5e64c0102b7cdae08238af70d
  6. Date: Sun, 3 Nov 1991 23:16:04 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: aem@aber.ac.uk (Alec David Muffett)
  10. Posting-number: Volume 25, Issue 8
  11. Archive-name: crack/part04
  12. Environment: UNIX
  13. Supersedes: crack: Volume 23, Issue 1-5
  14.  
  15. #! /bin/sh
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 4 (of 5)."
  21. # Contents:  Docs/README.ms Sources/crack-pwc.c
  22. # Wrapped by aem@aberda on Thu Oct 24 11:14:44 1991
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'Docs/README.ms' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'Docs/README.ms'\"
  26. else
  27. echo shar: Extracting \"'Docs/README.ms'\" \(28316 characters\)
  28. sed "s/^X//" >'Docs/README.ms' <<'END_OF_FILE'
  29. X.de C
  30. X.ie n .B "\\$1" \\$2
  31. X.el .CW "\\$1" \\$2
  32. X..
  33. X.TL
  34. X"Crack Version 4.0a"
  35. X.br
  36. XA Sensible Password Checker for Unix
  37. X.AU
  38. XAlec D.E. Muffett
  39. X.AI
  40. XComputer Unit, University College of Wales
  41. XAberystwyth, Wales, SY23 3DB
  42. X.I aem@aber.ac.uk
  43. X+44 970 622492
  44. X.AB
  45. X.B Crack
  46. Xis a freely available program designed to find standard Unix
  47. Xeight-character DES encrypted passwords by standard guessing techniques
  48. Xoutlined below.  It is written to be flexible, configurable and fast,
  49. Xand to be able to make use of several networked hosts via the Berkeley
  50. X.C rsh
  51. Xprogram (or similar), where possible.
  52. X.AE
  53. X.NH 1
  54. XIntroduction to Version 4.0
  55. X.LP
  56. XCrack is now into it's fourth version, and has been reworked extensively
  57. Xto provide extra functionality, and the purpose of this release is to
  58. Xconsolidate as much of this new functionality into as small a package as
  59. Xpossible.  To this end, Crack may appear to be less configurable: it has
  60. Xbeen written on the assumption that you run a fairly modern Unix, one
  61. Xwith BSD functionality, and then patched in order to run on other
  62. Xsystems.
  63. X.LP
  64. XThis, surprisingly enough, has led to neater code, and has made possible
  65. Xthe introduction of greater flexibility which supercedes many of the
  66. Xoptions that could be configured in earlier versions of Crack.  In the
  67. Xsame vein, some of the older options are now mandatory.  These, such as
  68. X.I "feedback mode"
  69. Xand
  70. X.C CRACK_PRINTOUT
  71. Xare no longer supported as options and probably never will be again.
  72. XThere is just a lot of wastage in not running with them, and too many
  73. Xdependencies in other functions to bother programming around them.
  74. X.LP
  75. XThe user interface is basically identical to the previous versions,
  76. Xalthough some people have asked about providing X-windows GUI's to
  77. XCrack, I think it would be a waste of time to do so. Crack has far
  78. Xless options than your ordinary version of
  79. X.C /bin/ls .
  80. X.LP
  81. XWith all that over, let's kick some (ass|arse|but(t)?)\**
  82. X.FS
  83. XAn obscure
  84. X.I lex
  85. Xjoke, inserted only for the purpose of allowing an example footnote for
  86. Xmy reference - sorry - AEM
  87. X.C 8-)
  88. X.FE
  89. X.NH 1
  90. XCrack Methodology - Part 1: Internals
  91. X.LP
  92. XCrack takes a series of password files and throws logic and dictionaries
  93. Xat the passwords therein, in order to find passwords which are based
  94. Xupon personal information or dictionary words, and are therefore
  95. Xinsecure.  It does
  96. X.B not
  97. Xattempt to remedy this situation, and it shoult
  98. X.B NOT
  99. Xbe used in place of getting a really good secure
  100. X.C passwd
  101. Xprogram replacement.
  102. X.LP
  103. XThe above statement defines the purpose of Crack, and embodies a great
  104. Xamount to hard work, graft, screams of
  105. X.I Eureka! ,
  106. Xand a fair amount of swearing too.  There is a great deal of thinking
  107. Xbehind the way that Crack attacks password files, and although not
  108. Xperfect, I certainly hope that Crack will out-do most of it's
  109. Xcompetitors.
  110. X.LP
  111. XCrack works by making several passes over the password entries that you
  112. Xsupply to it.  Each pass works by generating password guesses based upon
  113. Xa sequence of assertions, or rules, supplied to the program by the user.
  114. XThe rules are specified in a simplistic language, in the files
  115. X.C gecos.rules
  116. Xand
  117. X.C dicts.rules
  118. Xin the
  119. X.C Scripts
  120. Xdirectory.
  121. XThe distinction between these two files will be made clear later.
  122. X.LP
  123. XThe rules are written as a simple string of characters, with one rule to
  124. Xa line.  Blank lines, and comment lines beginning with a hash character
  125. X.B #
  126. Xare ignored.  Trailing whitespace is also ignored.  The instructions in
  127. Xthe word are followed left to right, and are applied to the dictionary
  128. Xwords in sequence.  A couple of simple pattern matching primitives are
  129. Xsupplied for selection purposes.  The syntax is as follows:
  130. X.IP :
  131. XNo-op; do nothing to the word. This is useful as a space delimiter.
  132. X.IP <n
  133. XReject the word unless it is
  134. X.B "LESS THAN"
  135. X.I n
  136. Xcharacters long, where
  137. X.I n
  138. Xis a digit 0-9, or a letter a-z for the values 10-35, respectively.
  139. X.IP >n
  140. XReject the word unless it is
  141. X.B "MORE THAN"
  142. X.I n
  143. Xcharacters long, where
  144. X.I n
  145. Xis a digit 0-9, or a letter a-z for the values 10-35, respectively.
  146. X.IP /x
  147. XReject the word unless it contains the character 'x'.
  148. X.IP !y
  149. XReject the word unless it does not contain the character 'y'.
  150. X.IP ^x
  151. XPrepend character 'x' to the word.
  152. X.IP $y
  153. XAppend character 'y' to the word.
  154. X.IP l
  155. XForce the word to lowercase.
  156. X.IP u
  157. XForce the word to uppercase.
  158. X.IP c
  159. XCapitalise the word, lowercasing all other letters.
  160. X.IP r
  161. XReverse the word back-to-front.
  162. X.IP d
  163. XDuplicate the word, so that
  164. X.I fred
  165. Xbecomes
  166. X.I fredfred
  167. X.IP f
  168. XReflect the word (mirror image), so that
  169. X.I fred
  170. Xbecomes
  171. X.I fredderf
  172. X.IP p
  173. XMake best attempt to pluralise the word, assuming that it is lowercase.
  174. X.IP sxy
  175. XSubstitute 'x' for 'y' throughout the word.
  176. X.IP xnm
  177. XExtract the string starting at position 'n' (starts at 0) for a length
  178. Xof up to 'm' characters, where 'n' and 'm' are digits in the range 0-9,
  179. Xor letters a-z for the values 10-35, respectively.
  180. X.sp 1v
  181. X.LP
  182. XSo, example rules could be:
  183. X.IP c
  184. XCapitalise the word.
  185. X.I fred
  186. Xbecomes
  187. X.I Fred
  188. X.IP l$?
  189. XLowercase the word and append a questionmark.
  190. X.I fred
  191. Xbecomes
  192. X.I fred?
  193. X.IP l/oso0c
  194. XLowercase the word, select it only if it contains the letter 'o' and
  195. Xsubstitute all o's for zeros, and capitalise it.
  196. XBoth 
  197. X.I COLLEGE
  198. Xand
  199. X.I college
  200. Xbecome
  201. X.I C0llege
  202. X.IP <8l/i/olsi1so0$=
  203. XReject the word unless it is less that 8 characters long, lowercase the
  204. Xword, reject it if it does not contain both the letter 'i' and the
  205. Xletter 'o', substitute all i's for 1's, substitute all o's for 0's, and
  206. Xappend an = sign. 
  207. X.IP
  208. XThe reasoning for the 8 character test is that since, with standard
  209. X.I crypt()
  210. Xtype algorithms, the password is truncated at 8 characters, there is no
  211. Xpoint in bolting a letter onto the end of a word if it is 8 or more
  212. Xcharacters long already.
  213. X.IP <7l^($)
  214. XReject the word unless it is less than 7 characters long, lowercase it,
  215. Xprepend a '(' and append a ')'.  Thus
  216. X.I fred
  217. Xbecomes
  218. X.I (fred)
  219. X.IP "$ :"
  220. X(ie: <dollar><space><colon>) Append a space character to the word (note
  221. Xthat if you do not add the trailing no-op after the space, a syntax
  222. Xerror will be generated since there is nothing to delineate the space
  223. Xcharacter - remember: trailing whitespace is ignored).
  224. X.sp 1v
  225. X.LP
  226. XBefore you go on, I suggest you browse through the
  227. X.C Scripts/*.rules
  228. Xfiles, and take a look at the rules that I supply as defaults, and try
  229. Xto work out what they do.
  230. X.LP
  231. XThe rules are stored in two different files for two different purposes.
  232. XRules in
  233. X.C Scripts/gecos.rules
  234. Xare applied to data generated by Crack from the pw_gecos and pw_gecos
  235. Xentries of the user's password entry. 
  236. X.LP
  237. XThe data generated by Crack and fed to the gecos rules
  238. Xfor the user
  239. X.I "aem",
  240. Xwho is
  241. X.I "Alec David Muffett, Compunit"
  242. Xwould be:
  243. X.I "aem",
  244. X.I "Alec",
  245. X.I "David",
  246. X.I "Muffett",
  247. X.I "Compunit",
  248. Xand a series of permutations of those words, either re-ordering the
  249. Xwords and joining them together (eg:
  250. X.I "AlecMuffett" ),
  251. Xor making up new words based on initial letters of one word taken with
  252. Xthe rest of another (eg:
  253. X.I "AMuffett" ).
  254. X.LP
  255. XThe entire set of rules in gecos.rules is applied to each of these
  256. Xwords, which creates many more permutations and combinations, all of
  257. Xwhich are tested.  Hence testing the password gecos information under
  258. XCrack v4.0 takes somewhat longer than it used to, but it is far more
  259. Xthorough.
  260. X.sp 1v
  261. X.LP
  262. XAfter a pass has been made over the data based on gecos information,
  263. XCrack makes further passes over the password data using successive rules
  264. Xfrom the
  265. X.C Scripts/dicts.rules
  266. Xby loading the entire
  267. X.C Dicts/bigdict
  268. Xfile into memory, with the rule being applied to each word from that
  269. Xfile.  This generates a
  270. X.I "resident dictionary" ,
  271. Xwhich is generated is sorted and uniqued so as to prevent wasting time
  272. Xon repetition.  After each pass is completed, the memory used by the
  273. Xresident dictionary is freed up, and (hopefully) re-used when the next
  274. Xdictionary is loaded.
  275. X.LP
  276. XThe
  277. X.C Dicts/bigdict
  278. Xdictionary is created by Crack by merging, sorting, and uniq'ing the
  279. Xsource dictionaries, which are to be found in the directory
  280. X.C DictSrc
  281. Xor, alternatively, may be named in the Crack shellscript, via the
  282. X.C $STDDICT
  283. Xvariable. The default dictionary named in the Crack script is
  284. X.C /usr/dict/words .
  285. X.LP
  286. XThe file
  287. X.C DictSrc/bad_pws.dat
  288. Xwhich is meant to provide many of those common, non-dictionary
  289. Xpasswords, such as
  290. X.I 12345678
  291. Xor
  292. X.I qwerty .
  293. XIf you wish to add a dictionary of your own, just copy it into the
  294. X.C DictSrc
  295. Xdirectory (and use 
  296. X.C compress 
  297. Xon it if you wish to save space; Crack will unpack it whilst generating
  298. Xthe big dictionary) and then delete the contents of the
  299. X.C Dicts
  300. Xdirectory by running
  301. X.C Scripts/spotless .
  302. XYour new dictionary will be merged in on the next run.
  303. XFor more information on dictionary attacks, see the paper called
  304. X"Foiling the Cracker: A Survey of, and Improvements to, Password
  305. XSecurity" by Daniel Klein, available from
  306. X.I "ftp.sei.cmu.edu"
  307. Xin
  308. X.I "~/pub/dvk/passwd.*" .
  309. XAlso, please read the
  310. X.C APPENDIX
  311. Xfile supplied with this distribution.\**
  312. X.FS
  313. XExtra dictionaries (those detailed in Dan Klein's paper) can be
  314. Xobtained via anonymous FTP from
  315. X.I uunet.uu.net
  316. X(192.48.96.2) as
  317. X.I ~/pub/dictionaries.tar.Z ;
  318. XCheck an
  319. X.I Archie
  320. Xdatabase for other possible sources of dictionaries.
  321. X.FE
  322. X.LP
  323. XHaving described the method of cracking, perhaps we should now
  324. Xinvestigate the algorithm used to overlay the cracking mechanism.
  325. X.NH 1
  326. XCrack Methodology - Part 2: Feedback Filters
  327. X.LP
  328. XAs is stated above, Crack v4.0 permutes and loads dictionaries directly
  329. Xinto memory, sorts and uniques them, before attempting to use each of
  330. Xthe words as a guess for each users' password.  If Crack correctly
  331. Xguesses a password, it marks the user as 'done' and does not waste
  332. Xfurther time on trying to break that users password.
  333. X.LP
  334. XOnce Crack has finished a dictionary pass, it sweeps the list of users
  335. Xlooking for the passwords it has cracked. It stores the broken passwords
  336. Xin both plaintext and encrypted forms in a
  337. X.I "feedback file"
  338. Xin the directory
  339. X.C Runtime .
  340. XFeedback files have names of the form
  341. X.C Runtime/F.* .
  342. X.LP
  343. XThe purpose of this is so that, when Crack is next invoked, it may
  344. Xrecognise passwords that it has successfully cracked before, and filter
  345. Xthem from the input to the password cracker. This provides an
  346. X.I instant
  347. Xlist of crackable users who have not changed their passwords since the
  348. Xlast time Crack was run. This list appears in a file named
  349. X.C out.i*
  350. Xin the
  351. X.C $CRACK_OUT
  352. Xdirectory, or on
  353. X.I stdout ,
  354. Xif foreground mode is invoked (see
  355. X.I Options ,
  356. Xbelow).
  357. X.LP
  358. XIn a similar vein, when a Crack run terminates normally, it writes out
  359. Xto the feedback file all encrypted passwords that it has
  360. X.B NOT
  361. Xsucceeded in cracking.  Crack will then ignore all of these passwords
  362. Xnext time you run it.
  363. X.LP
  364. XObviously, this is not desirable if you frequently change your
  365. Xdictionaries or rules, and so there is a script provided,
  366. X.C Scripts/mrgfbk
  367. Xwhich sorts your feedback files, merges them into one, and optionally
  368. Xremoves all traces of 'uncrackable' passwords, so that your next Crack
  369. Xrun can have a go at passwords it has not succeeded in breaking before.
  370. X.LP
  371. X.C Mrgfbk
  372. Xis invoked automatically if you run
  373. X.C Scripts/spotless .
  374. X.NH 1
  375. XCrack Methodology - Part 3: Execution and Networking
  376. X.LP
  377. XEach time Crack is invoked, whether networked or not, it generates a
  378. X.I diefile
  379. Xwith a name of the form
  380. X.C Runtime/D.*
  381. X(for network cracks, this file is generated by RCrack, and is of the form
  382. X.C Runtime/D.rem*
  383. Xwhich points to a
  384. X.B real
  385. Xdiefile, named
  386. X.C Runtime/RD.* 
  387. X- see below for details).
  388. X.LP
  389. XThese diefiles contain debugging information about the job, and are
  390. Xgenerated so that all the jobs on the entire network can be called
  391. Xquickly by invoking
  392. X.C Scripts/plaster .
  393. XDiefiles delete themselves after they have been run.
  394. X.LP
  395. XAs you will read in the sections below, Crack has a
  396. X.C "-network"
  397. Xoption: This is designed to be a simple method of automatically
  398. Xspreading the load of password cracking out over several machines on a
  399. Xnetwork, preferably if they are connected by some form of networked
  400. Xfilestore.
  401. X.LP
  402. XWhen
  403. X.C "Crack -network"
  404. Xis invoked, it filters its input in the ordinary way, and then splits
  405. Xits load up amongst several machines which are specified in the file
  406. X.C Scripts/network.conf .
  407. X.LP
  408. XThis file contains a series of hostnames, power ratings, flags, etc,
  409. Xrelevant to the running of Crack on each machine.  Crack then calls
  410. X.C Scripts/RCrack
  411. Xto use the
  412. X.C rsh
  413. Xcommand (or similar) to invoke Crack on the other hosts.  See the RCrack
  414. Xscript, and the example network.conf file for details.
  415. X.NH 1
  416. XInstallation
  417. X.LP
  418. XCrack is one of those most unusual of beasties, a self-installing
  419. Xprogram.  Some people have complained about this apparent weirdness, but
  420. Xit has grown up with Crack ever since the earliest network version, when
  421. XI could not be bothered to log into several different machines with
  422. Xseveral different architectures, just in order to build the binaries. 
  423. XOnce the necessary configuration options have been set, the executables
  424. Xare created via
  425. X.C make
  426. Xby running the Crack shellscript .
  427. X.LP
  428. XCrack's configuration lies in two files, the
  429. X.C Crack
  430. Xshell script, which contains all the installation specific configuration
  431. Xdata, and the file
  432. X.C Sources/conf.h ,
  433. Xwhich contains configuration options specific to various binary platforms.
  434. X.LP
  435. XIn the Crack shellscript, you will have to edit the
  436. X.C CRACK_HOME
  437. Xvariable to the correct value.  This variable should be set to an
  438. Xabsolute path name (names relative to
  439. X.I ~username
  440. Xare OK, so long as you have some sort of
  441. X.C csh )
  442. Xthrough which the directory containing Crack may be accessed on
  443. X.B ALL
  444. Xthe machines that Crack will be run on. There is a similar variable
  445. X.C CRACK_OUT
  446. Xwhich specifies where Crack should put its output files - by default,
  447. Xthis is the same as
  448. X.C "$CRACK_HOME" .
  449. X.LP
  450. XYou will also have to edit the file
  451. X.C Sources/conf.h
  452. Xand work out which switches to enable.  Each
  453. X.C #define
  454. Xhas a small note explaining its purpose.  Where I have been in doubt about
  455. Xthe portability of certain library functions, usually I have re-written
  456. Xit, so you should be OK.  Let me know of your problems, if you have any.
  457. X.LP
  458. XIf you will be using
  459. X.C "Crack -network"
  460. Xyou will then have to generate a
  461. X.C Scripts/network.conf
  462. Xfile. This contains a list of hostnames to
  463. X.C rsh
  464. Xto, what their
  465. X.I "binary type"
  466. Xis (useful when running a network Crack on several different
  467. Xarchitectures), a guesstimate of their
  468. X.I "relative power"
  469. X(take your slowest machine as unary, and measure all others relative to
  470. Xit), and a list of per-host
  471. X.I flags
  472. Xto
  473. X.B add
  474. Xto those specified on the
  475. X.C Crack
  476. Xcommand line, when calling that host.  There is an example of such a
  477. Xfile provided in the Scripts directory - take a look at it.
  478. X.LP
  479. XIf ever you wish to specify a more precise figure as to the relative
  480. Xpower of your machines, or you are simply at a loss, play with the
  481. Xcommand
  482. X.C "make tests"
  483. Xin the source code directory.  This can provide you with the number of
  484. Xfcrypt()s that your machine can do per second, which is a number that
  485. Xyou can plug into your
  486. X.C network.conf
  487. Xas a measure of your machines' power (after rounding the value to an
  488. Xinteger).
  489. X.NH 1
  490. XUsage
  491. X.LP
  492. XOkay, so, let's assume that you have edited your
  493. X.C Crack
  494. Xscript, and your
  495. X.C Sources/conf.h
  496. Xfile, where do you go from here ?
  497. X.LP
  498. X.DS B
  499. X.fi
  500. X.C Crack
  501. X[\c
  502. X.I options ]
  503. X[\c
  504. X.I bindir ]
  505. X.C /etc/passwd
  506. X[...other passwd files]
  507. X.sp 1v
  508. X.C "Crack -network"
  509. X[\c
  510. X.I options ]
  511. X.C /etc/passwd
  512. X[...other passwd files]
  513. X.DE
  514. X.LP
  515. XWhere
  516. X.B bindir
  517. Xis the optional name of the directory where you want the binaries
  518. Xinstalled.  This is useful where you want to be able to run versions of
  519. XCrack on several different architectures. If
  520. X.B bindir
  521. Xdoes not exist, a warning will be issued, and the directory created.
  522. X.QP
  523. XNote:
  524. X.B bindir
  525. Xdefaults to the name
  526. X.C generic
  527. Xif not supplied.
  528. X.QP
  529. X.LP
  530. X.B "Notes for Yellow Pages (NIS) Users:"
  531. XI have occasional queries about how to get Crack running from a YP
  532. Xpassword file.  There are several methods, but by far the simplest is to
  533. Xgenerate a passwd format file by running:-
  534. X.DS B
  535. X.C "ypcat passwd > passwd.yp"
  536. X.DE
  537. Xand then running Crack on this file.
  538. X.NH 1
  539. XOptions
  540. X.IP "\fB-f\fP"
  541. XRuns Crack in
  542. X.I foreground
  543. Xmode, ie: the password cracker is not backgrounded, and messages appear
  544. Xon stdout and stderr as you would expect.  This option is only really
  545. Xuseful for very small password files, or when you want to put a wrapper
  546. Xscript around Crack.
  547. X.IP
  548. XForeground mode is disabled if you try running
  549. X.C "Crack -network -f"
  550. Xon the command line, because of the insensibility of
  551. X.C rsh ing
  552. Xto several machines in turn, waiting for each one to finish before
  553. Xcalling the next. However, please read the section about
  554. X.I "Network Cracking without NFS/RFS" ,
  555. Xbelow.
  556. X.IP "\fB-v\fP"
  557. XSets verbose mode, whereby Crack will print every guess it is trying on
  558. Xa per-user basis.  This is a very quick way of flooding your filestore,
  559. Xbut useful if you think something is going wrong.
  560. X.IP "\fB-m\fP"
  561. XSends mail to any user whose password you crack by invoking
  562. X.C Scripts/nastygram
  563. Xwith their username as an argument.  The reason for using the script is
  564. Xso that a degree of flexibility in the format of the mail message is
  565. Xsupplied; ie: you don't have to recompile code in order to change the
  566. Xmessage.\**
  567. X.FS
  568. XI'm uncertain about the wisdom of mailing someone like this.  If someone
  569. Xbrowses your cracked user's mail somehow, it's like a great big neon
  570. Xsign pointing at the user saying "This Is A Crackable Account - Go For
  571. XIt!".  Not to mention the false sense of security it engenders in the
  572. XSystem Manager that he's "informed" the user to change his password.
  573. XWhat if the user doesn't log on for 3 months? However, so many people
  574. Xhave wired it into their own versions of Crack, I suppose it
  575. X.B must
  576. Xbe provided... AEM
  577. X.FE
  578. X.IP "\fB-nvalue\fP"
  579. XSets the process to be
  580. X.C nice() ed
  581. Xto
  582. X.I value ,
  583. Xso, for example, the switch
  584. X.C \&-n19
  585. Xsets the Crack process to run at the lowest priority.
  586. X.IP "\fB-network\fP"
  587. XThrows Crack into network mode, in which it reads the
  588. X.C Scripts/network.conf
  589. Xfile, splits its input into chunks which are sized according to the
  590. Xpower of the target machine, and calls
  591. X.C rsh
  592. Xto run Crack on that machine.  Options for Crack running on the target
  593. Xmachine may be supplied on the command line (eg: verbose or recover
  594. Xmode), or in the network.conf file if they pertain to specific hosts
  595. X(eg:
  596. X.C nice()
  597. Xvalues).
  598. X.IP "\fB-r<pointfile>\fP"
  599. XThis is only for use when running in
  600. X.I recover
  601. Xmode.  When a running Crack starts pass 2, it periodically saves its
  602. Xstate in a
  603. X.I pointfile ,
  604. Xwith a name of the form
  605. X.C "Runtime/P.*"
  606. XThis file can be used to recover where you were should a host crash.
  607. XSimply invoke Crack in
  608. X.B exactly
  609. Xthe same manner as the last time, with the addition of the
  610. X.C "-r"
  611. Xswitch, (eg:
  612. X.C "-rRuntime/P.12345" )
  613. Xswitch.  Crack will startup and read the file, and jump to roughly where
  614. Xit left off.  If you are cracking a very large password file, this can
  615. Xsave oodles of time after a crash.
  616. X.IP
  617. XIf you were running a
  618. X.I network
  619. XCrack, then the jobs will again be spawned onto all the machines of the
  620. Xoriginal Crack.  The program will then check that the host it is running
  621. Xon is the same as is mentioned in the pointfile.  If it is not, it will
  622. Xquietly die.  Thus, assuming that you supply the same input data and do
  623. Xnot change your
  624. X.C network.conf
  625. Xfile, Crack should pick up where it left off.  This is a bit inelegant,
  626. Xbut it's better than nothing at the moment.
  627. X.IP
  628. XThe method of error recovery outlined above causes headaches for users
  629. Xwho want to do multiprocessing on parallel architectures.  Crack is in
  630. Xno way parallel, and because of the way it's structured (reading stdin
  631. Xfrom shellscript frontends) it is a pain to divide the work amongst
  632. Xseveral processes via
  633. X.C fork() ing.
  634. X.IP
  635. XThe hack solution to get several copies of Crack running on one machine
  636. Xwith
  637. X.I n
  638. Xprocessors at the moment is to insert
  639. X.I n
  640. Xcopies of the entry for your parallel machine into the
  641. X.C Scripts/network.conf
  642. Xfile. If you use the
  643. X.C \&-r
  644. Xoption in these circumstances however, you will get
  645. X.I n
  646. Xcopies of the recovered process running, only one of them will have the
  647. Xcorrect input data.
  648. X.IP
  649. XThe old solution to this problem (see old documentation if you are
  650. Xinterested) has been negated by the introduction of feedback mode, so
  651. Xthe best bet in this particular situation is to wait until the other
  652. Xjobs are done (and have written out lists of uncrackable passwords), and
  653. Xthen re-start the jobs from scratch.  Anyone whose password was not
  654. Xcracked on the first run will be ignored on the second, if they have not
  655. Xchanged it since.  This is inelegant, but it's the best I can do in the
  656. Xlimited time available.
  657. X.NH
  658. XSupport Scripts
  659. X.LP
  660. XThe
  661. X.C Scripts
  662. Xdirectory contains a small number of support and utility scripts, some
  663. Xof which are designed to help Crack users check their progress.
  664. XBriefly, the most useful ones are:-
  665. X.IP "\fBScripts/shadmrg\fP"
  666. XThis is a small (but hopefully readable) script for merging
  667. X.C /etc/passwd
  668. Xand
  669. X.C /etc/shadow
  670. Xon System V style shadow password systems.  It produces the merged data
  671. Xto stdout, and will need redirecting into a file before Crack can work
  672. Xon it.  The script is meant to be fairly lucid, on the grounds that I
  673. Xworry that there are many shadowing schemes out there, and perhaps not
  674. Xall have the same data format.
  675. X.IP
  676. X.B "I have not"
  677. Xwired this facility into the Crack command itself because the world does
  678. X.B NOT
  679. Xrevolve around System V yet, regardless of what some people would have
  680. Xme believe, and I believe that the lack of direct support for NIS
  681. Xoutlined above, sets a precedent.  There are just too many
  682. Xincompatibilities in shadow password schemes for me to hardwire
  683. Xanything.
  684. X.IP "\fBScripts/plaster\fP"
  685. Xwhich is named after a dumb joke, but is a simple frontend to the
  686. X.C "Runtime/D.*"
  687. Xdiefiles that each copy of the password cracker generates. Invoking
  688. X.C Scripts/plaster
  689. Xwill kill off all copies of the password cracker you are running, over
  690. Xthe network or otherwise.
  691. X.IP "\fBScripts/status\fP"
  692. XThis script
  693. X.C rsh es
  694. Xto each machine mentioned in the
  695. X.C Scripts/network.conf
  696. Xfile, and provides some information about processes and uptime on that
  697. Xmachine.  This is useful when you want to find out just how well your
  698. Xpassword crackers are getting on during a
  699. X.C "Crack -network" .
  700. X.IP "\fBScripts/{clean,spotless}\fP"
  701. XThese are really just frontends to a makefile. Invoking
  702. X.C Scripts/clean
  703. Xtidies up the Crack home directory, and removes probably unwanted files,
  704. Xbut leaves the pre-processed dictionary
  705. X.C bigdict
  706. Xintact.
  707. X.C Scripts/spotless
  708. Xdoes the same as
  709. X.C Scripts/clean
  710. Xbut obliterates
  711. X.C bigdict
  712. Xand old output files too, and compresses the feedback files into one.
  713. X.IP "\fBScripts/nastygram\fP"
  714. XThis is the shellscript that is invoked by the password cracker to send
  715. Xmail to users who have guessable passwords, if the
  716. X.C -m
  717. Xoption is used. Edit it at your leisure to suit your system.
  718. X.IP "\fBScripts/guess2fbk\fP"
  719. XThis script takes your
  720. X.C out.*
  721. Xfiles as arguments and reformats the 'Guessed' lines into a slightly
  722. Xmessy
  723. X.I feedback
  724. Xfile, suitable for storing with the others.
  725. X.IP
  726. XAn occasion where this might be useful is when your cracker has guessed
  727. Xmany peoples passwords, and then died for some reason (a crash?) before
  728. Xwriting out the guesses to a feedback file.  Running
  729. X.DS B
  730. X.C "Scripts/guess2fbk out.* >> Runtime/F.new"
  731. X.DE
  732. Xwill save the work that has been done.
  733. X.NH 1
  734. XNetwork Cracking without NFS/RFS
  735. X.LP
  736. XFor those users who have some form of
  737. X.C rsh
  738. Xcommand, but do not have a a networked filestore running between hosts,
  739. Xthere is now a solution which will allow you to do networked cracking,
  740. Xproposed to me by Brian Tompsett at Hull.  Personally, I consider the
  741. Xidea to be potty, but it fills in missing functionality in a wonderfully
  742. Xtacky manner.
  743. X.LP
  744. XFrom the documentation above, you will note that Crack will undo the
  745. X.C "-f"
  746. X.I "(output in foreground)"
  747. Xoption, if it is invoked with the
  748. X.C "-network"
  749. Xswitch at the same time (see the
  750. X.I Options
  751. Xsection above).  This is true, but it does not apply if you specify
  752. X.C "-f"
  753. Xoption in the
  754. X.C network.conf
  755. Xfile.
  756. X.LP
  757. XThe practical upshot of doing this is that remote copies of Crack
  758. Xcan be made to read from
  759. X.I stdin
  760. Xand write to
  761. X.I stdout
  762. Xover a network link, and thus remote processing is accomplished.  I have
  763. Xtweaked Crack in such a way, therefore, that if the
  764. X.C "-f"
  765. Xoption is specified amongst the crack-flags of a host in the
  766. Xnetwork.conf, rather than backgrounding itself on the remote host, the
  767. X.C rsh
  768. Xcommand on the
  769. X.B server
  770. Xis backgrounded, and output is written directly to the files on the
  771. Xserver's filestore.
  772. X.LP
  773. XThere are restrictions upon this method, mostly involving the number of
  774. Xprocesses that a user may run on the server at any one time, and that
  775. Xyou will have to collect feedback output together manually (dropping it
  776. Xinto the
  777. X.C Runtime
  778. Xdirectory on the server).  However, it works. Also, if you try to use
  779. X.C rsh
  780. Xas another user, you will suffer problems if
  781. X.C rsh
  782. Xinsists on reading something from your terminal (eg: a password for the
  783. Xremote account).  Also, recovering using checkpointing goes out the
  784. Xwindow unless you specify the name of the pointfile as it is named
  785. Xon the remote machine.
  786. X.NH 1
  787. XNotes on fast crypt() implementations
  788. X.LP
  789. XThe stdlib version of the
  790. X.C crypt()
  791. Xsubroutine is incredibly slow.  It is a
  792. X.I massive
  793. Xbottleneck to the execution of Crack and on typical platforms that you
  794. Xget at universities, it is rare to find a machine which will achieve
  795. Xmore than 50 standard crypt() s per second.  On low-end diskless
  796. Xworkstations, you may expect 2 or 3 per second.  It was this slowness of
  797. Xthe crypt() algorithm which originally supplied much of the security
  798. XUnix needed.\**
  799. X.FS
  800. XSee: "Password Security, A Case History" by Bob Morris & Ken Thomson, in
  801. Xthe Unix Programmer Docs.
  802. X.FE
  803. X.LP
  804. XThere are now
  805. X.B many
  806. Ximplementations of faster versions of crypt()
  807. Xto be found on the network.  The one supplied with Crack v3.2 and
  808. Xupwards is called
  809. X.C fcrypt() .
  810. XIt was originally written in May 1986 by Robert Baldwin at MIT, and is a
  811. Xgood version of the crypt() subroutine.  I received a copy from Icarus
  812. XSparry at Bath University, who had made a couple of portability
  813. Xenhancements to the code.
  814. X.LP
  815. XI rewrote most of the tables and the KeySchedule generating algorithm in
  816. Xthe original
  817. X.I fdes-init.c
  818. Xto knock 40% off the execution overhead of fcrypt() in the form that it
  819. Xwas shipped to me.  I inlined a bunch of stuff, put it into a single
  820. Xfile, got some advice from Matt Bishop and Bob Baldwin [both of whom I
  821. Xam greatly indebted to] about what to do to the
  822. X.C xform()
  823. Xroutine and to the fcrypt function itself, and tidied up some
  824. Xalgorithms.  I have also added more lookup tables and reduced several
  825. Xformula for faster use.  Fcrypt() is now barely recognisable as being
  826. Xbased on its former incarnation, and it is 3x faster.
  827. X.LP
  828. XOn a DecStation 5000/200, fcrypt() is about 16 times faster than the
  829. Xstandard crypt (your mileage may vary with other architectures and
  830. Xcompilers).  This speed puts fcrypt() into the "moderately fast" league
  831. Xof crypt implementations. There
  832. X.B are
  833. Xfaster versions of crypt to be had (eg:
  834. X.C UFC )
  835. Xwhich may be found on the network.  The advantage of fcrypt() is that I
  836. Xsupport it, understand it, and can distribute and fix it without hassle.
  837. XIf you want to play around with other crypts, that is up to you.  Feel
  838. Xfree.
  839. X.C 8-)
  840. X.NH 1
  841. XConclusions
  842. X.LP
  843. XWhat can be done about brute force attacks on your password file ?
  844. X.LP
  845. XYou must get a drop-in replacement for the
  846. X.C passwd
  847. Xand
  848. X.C yppasswd
  849. Xcommands; one which will stop people from choosing bad passwords in the
  850. Xfirst place.  There are several programs to do this; Matt Bishop's
  851. X.C "passwd+"
  852. Xand Clyde Hoover's
  853. X.C "npasswd"
  854. Xprogram are good examples which are freely available.  Consult an
  855. X.B Archie
  856. Xdatabase for more details on where you can get them from.
  857. X.LP
  858. XIt would be nice if an organisation (such as
  859. X.B CERT ?)
  860. Xcould be persuaded to supply skeletons of
  861. X.I sensible
  862. Xpasswd commands for the public good, as well as an archive of security
  863. Xrelated utilities\**
  864. Xon top of the excellent
  865. X.C COPS .
  866. X.FS
  867. X.C COPS
  868. Xis available for anonymous FTP from
  869. X.I "cert.sei.cmu.edu"
  870. X(128.237.253.5) in
  871. X.I ~/cops
  872. X.FE
  873. XHowever, for Unix security to improve on a global scale, we will also
  874. Xrequire pressure on the vendors, so that programs are written correctly
  875. Xfrom the beginning.
  876. END_OF_FILE
  877. if test 28316 -ne `wc -c <'Docs/README.ms'`; then
  878.     echo shar: \"'Docs/README.ms'\" unpacked with wrong size!
  879. fi
  880. # end of 'Docs/README.ms'
  881. fi
  882. if test -f 'Sources/crack-pwc.c' -a "${1}" != "-c" ; then 
  883.   echo shar: Will not clobber existing file \"'Sources/crack-pwc.c'\"
  884. else
  885. echo shar: Extracting \"'Sources/crack-pwc.c'\" \(23895 characters\)
  886. sed "s/^X//" >'Sources/crack-pwc.c' <<'END_OF_FILE'
  887. X/*
  888. X * This program is copyright Alec Muffett 1991 except for some portions of
  889. X * code in "crack-fcrypt.c" which are copyright Robert Baldwin, Icarus
  890. X * Sparry and Alec Muffett.  The author(s) disclaims all responsibility or
  891. X * liability with respect to it's usage or its effect upon hardware or
  892. X * computer systems, and maintain copyright as set out in the "LICENCE"
  893. X * document which accompanies distributions of Crack v4.0 and upwards.
  894. X */
  895. X
  896. X#include "crack.h"
  897. X
  898. X#define DOTFILESIZE    1024
  899. X#define WORDSTACKSIZE    1024
  900. X
  901. X/*
  902. X * crack-pwc.c - an optimised password cracker. (c) ADE Muffett, Oct 1991. If
  903. X * this won't break your password file, it's unlikely that anything else
  904. X * will.
  905. X */
  906. X
  907. Xchar version[] = "4.0a";        /* version of prog */
  908. Xchar runtime[] = "Runtime";
  909. Xchar feedback_string[] = "!fb!";
  910. Xchar rulefile[] = "Scripts/dicts.rules";
  911. Xchar gecosfile[] = "Scripts/gecos.rules";
  912. Xchar nastygram[] = "Scripts/nastygram";
  913. X
  914. X/* runtime variable declarations */
  915. X
  916. Xint pid;            /* current process ID */
  917. Xint pwlength = 8;        /* significant length of a password */
  918. Xstruct USER *userroot;        /* root of linked list of users */
  919. Xstruct RULE *ruleroot;        /* root of linked list of rules */
  920. Xstruct RULE *gecosroot;        /* root of linked list of (gecos) rules */
  921. Xstruct DICT *dictroot;        /* root of linked list of words */
  922. Xchar **dictbase;        /* root of array of words */
  923. X
  924. X/* datafile variables */
  925. X
  926. Xchar diefile[STRINGSIZE];    /* where die output goes... */
  927. Xchar feedbackfile[STRINGSIZE];    /* where feedback ouytput goes */
  928. Xchar opfile[STRINGSIZE];    /* where Log() output goes */
  929. Xchar pointfile[STRINGSIZE];    /* checkpointing */
  930. Xchar this_hostname[STRINGSIZE];    /* gethostname() hack */
  931. X
  932. X/* recover variables */
  933. X
  934. Xchar old_hostname[STRINGSIZE];    /* next 4 vars used in recovery */
  935. Xchar old_dictname[STRINGSIZE];
  936. Xchar old_rule[STRINGSIZE];
  937. Xint old_usernum;
  938. Xchar old_username[STRINGSIZE];
  939. X
  940. X/* switches */
  941. Xchar input_file[STRINGSIZE];
  942. Xint foreground_bool;
  943. Xint remote_bool;
  944. Xint nice_value;
  945. Xint recover_bool;
  946. Xchar recover_file[STRINGSIZE];
  947. Xint verbose_bool;
  948. Xchar supplied_name[STRINGSIZE];
  949. Xint mail_bool;
  950. X
  951. X/* compare two struct DICTs lexically - hook for qsort() function */
  952. X
  953. Xint
  954. XDictCmp (a, b)
  955. X    char **a;
  956. X    char **b;
  957. X{
  958. X    return (strcmp (*a, *b));
  959. X}
  960. X/* log anything to datafile. */
  961. X
  962. Xvoid
  963. XLog (fmt, a, b, c, d, e, f, g, h, i, j)
  964. X    char *fmt;
  965. X    long int a, b, c, d, e, f, g, h, i, j;
  966. X{
  967. X    long t;
  968. X
  969. X    time (&t);
  970. X    printf ("pwc: %-15.15s ", ctime (&t) + 4);
  971. X    printf (fmt, a, b, c, d, e, f, g, h, i, j);
  972. X    fflush (stdout);
  973. X}
  974. X/* print a guess, giving a single place to mod where necessary */
  975. X
  976. Xvoid
  977. XPrintGuess (eptr, guess)
  978. X    register struct USER *eptr;
  979. X    char *guess;
  980. X{
  981. X    eptr -> done = 1;
  982. X    eptr -> passwd_txt = Clone (guess, 0);    /* ESSENTIAL to FeedBack() */
  983. X
  984. X    Log ("Guessed %s%s (%s in %s) [%s] %s\n",
  985. X     (eptr -> passwd.pw_uid ? "" : "ROOT PASSWORD "),
  986. X     eptr -> passwd.pw_name,
  987. X     eptr -> passwd.pw_shell,
  988. X     eptr -> filename,
  989. X     guess,
  990. X     eptr -> passwd.pw_passwd);
  991. X    if (mail_bool)
  992. X    {
  993. X    char dobuff[STRINGSIZE];
  994. X
  995. X    sprintf ("%s %s", nastygram, eptr -> passwd.pw_name);
  996. X    system (dobuff);
  997. X    }
  998. X}
  999. X/* trap a signal on shutdown */
  1000. X
  1001. Xvoid
  1002. XCatchTERM ()
  1003. X{
  1004. X    /* bury magnets */
  1005. X    /* swallow the rapture */
  1006. X    /* let's gather feathers */
  1007. X    /* don't fall on me - from 'Fall in Me' by R.E.M. */
  1008. X    Log ("Caught a SIGTERM! Commiting suicide...\n");
  1009. X    Log ("<argh!>\n");
  1010. X    sync ();
  1011. X    exit (0);
  1012. X}
  1013. X/* write a pointfile out */
  1014. X
  1015. Xvoid
  1016. XSetPoint (dict, rule, usernum, username)
  1017. X    char *dict;
  1018. X    char *rule;
  1019. X    int usernum;
  1020. X    char *username;
  1021. X{
  1022. X    FILE *fp;
  1023. X    long t;
  1024. X
  1025. X    if (!(fp = fopen (pointfile, "w")))
  1026. X    {
  1027. X    perror (pointfile);
  1028. X    return;
  1029. X    }
  1030. X    time (&t);
  1031. X    fprintf (fp, "host=%s pid=%d pointtime=%s",
  1032. X         this_hostname, pid, ctime (&t));
  1033. X    fprintf (fp, "%s\n", this_hostname);
  1034. X    fprintf (fp, "%s\n", dict);
  1035. X    fprintf (fp, "%s\n", rule);
  1036. X    fprintf (fp, "%d\n", usernum);
  1037. X    fprintf (fp, "%s\n", username);
  1038. X    fclose (fp);
  1039. X}
  1040. X/* read a pointfile in... */
  1041. X
  1042. Xint
  1043. XGetPoint (pf)
  1044. X    char *pf;
  1045. X{
  1046. X    FILE *fp;
  1047. X    char buffer[STRINGSIZE];
  1048. X
  1049. X    if (!(fp = fopen (pf, "r")))
  1050. X    {
  1051. X    perror (pf);
  1052. X    return (-1);
  1053. X    }
  1054. X    /* junk */
  1055. X    if (!fgets (buffer, STRINGSIZE, fp))
  1056. X    {
  1057. X    return (-2);
  1058. X    }
  1059. X    /* hostname */
  1060. X    if (!fgets (old_hostname, STRINGSIZE, fp))
  1061. X    {
  1062. X    return (-3);
  1063. X    }
  1064. X    /* dictname */
  1065. X    if (!fgets (old_dictname, STRINGSIZE, fp))
  1066. X    {
  1067. X    return (-4);
  1068. X    }
  1069. X    /* rule */
  1070. X    if (!fgets (old_rule, STRINGSIZE, fp))
  1071. X    {
  1072. X    return (-5);
  1073. X    }
  1074. X    /* usernum */
  1075. X    if (!fgets (buffer, STRINGSIZE, fp))
  1076. X    {
  1077. X    return (-6);
  1078. X    }
  1079. X    /* username */
  1080. X    if (!fgets (old_username, STRINGSIZE, fp))
  1081. X    {
  1082. X    return (-7);
  1083. X    }
  1084. X    Trim (old_hostname);
  1085. X    if (strcmp (old_hostname, this_hostname))
  1086. X    {
  1087. X    return (-8);
  1088. X    }
  1089. X    Trim (old_dictname);
  1090. X    Trim (old_rule);
  1091. X    old_usernum = atoi (buffer);
  1092. X    Trim (old_username);
  1093. X    fclose (fp);
  1094. X    return (0);
  1095. X}
  1096. X/* jump ':' separated fields in an input */
  1097. X
  1098. Xchar *
  1099. XPWSkip (p)
  1100. X    register char *p;
  1101. X{
  1102. X    while (*p && *p != ':')
  1103. X    {
  1104. X    p++;
  1105. X    }
  1106. X    if (*p)
  1107. X    {
  1108. X    *p++ = '\0';
  1109. X    }
  1110. X    return (p);
  1111. X}
  1112. X/* parse and store a password entry */
  1113. X
  1114. Xstruct USER *
  1115. XParse (buffer)
  1116. X    register char *buffer;
  1117. X{
  1118. X    register char *p;
  1119. X    register struct USER *retval;
  1120. X
  1121. X    retval = (struct USER *) malloc (sizeof (struct USER));
  1122. X    retval -> next = retval -> across = NULL;
  1123. X    retval -> passwd_txt = NULL;
  1124. X    retval -> done = 0;
  1125. X    Trim (buffer);
  1126. X
  1127. X    p = Clone (buffer, 0);
  1128. X    retval -> filename = p;
  1129. X    p = PWSkip (p);
  1130. X    retval -> passwd.pw_name = p;
  1131. X    p = PWSkip (p);
  1132. X    retval -> passwd.pw_passwd = p;
  1133. X    p = PWSkip (p);
  1134. X    retval -> passwd.pw_uid = atoi (p);
  1135. X    p = PWSkip (p);
  1136. X    retval -> passwd.pw_gid = atoi (p);
  1137. X    p = PWSkip (p);
  1138. X    retval -> passwd.pw_gecos = p;
  1139. X    p = PWSkip (p);
  1140. X    retval -> passwd.pw_dir = p;
  1141. X    p = PWSkip (p);
  1142. X    retval -> passwd.pw_shell = p;
  1143. X    return (retval);
  1144. X}
  1145. X/* load pre-formatted password entries off stdin into linked list */
  1146. X
  1147. Xint
  1148. XLoadData ()
  1149. X{
  1150. X    char *ptr;
  1151. X    char salt[2];
  1152. X    char buffer[STRINGSIZE];
  1153. X    int numlines;
  1154. X    int numentries;
  1155. X    register struct USER *new_element;
  1156. X    register struct USER *current_line;
  1157. X
  1158. X    numlines = 0;
  1159. X    numentries = 0;
  1160. X    current_line = NULL;
  1161. X    salt[0] = salt[1] = '*';
  1162. X
  1163. X    while (fgets (buffer, STRINGSIZE, stdin))
  1164. X    {
  1165. X    if (!*buffer || isspace (*buffer))
  1166. X    {
  1167. X        continue;
  1168. X    }
  1169. X    new_element = Parse (buffer);
  1170. X
  1171. X    ptr = new_element -> passwd.pw_passwd;
  1172. X    if (!ptr[0])
  1173. X    {
  1174. X        Log ("Warning! %s (%s in %s) has a NULL password!\n",
  1175. X         new_element -> passwd.pw_name,
  1176. X         new_element -> passwd.pw_shell,
  1177. X         new_element -> filename);
  1178. X        continue;
  1179. X    }
  1180. X    if (strchr (ptr, '*') ||
  1181. X        strchr (ptr, '!') ||
  1182. X        strchr (ptr, ' '))
  1183. X    {
  1184. X        Log ("User %s (in %s) has a locked password:- %s\n",
  1185. X         new_element -> passwd.pw_name,
  1186. X         new_element -> filename,
  1187. X         new_element -> passwd.pw_passwd);
  1188. X        continue;
  1189. X    }
  1190. X    if (strlen (ptr) < 13)
  1191. X    {
  1192. X        Log ("User %s (in %s) has a short crypted password - ignoring.\n",
  1193. X         new_element -> passwd.pw_name,
  1194. X         new_element -> filename);
  1195. X        continue;
  1196. X    }
  1197. X    if (strlen (ptr) > 13)
  1198. X    {
  1199. X        Log ("User %s (in %s) has a long crypted password - truncating.\n",
  1200. X         new_element -> passwd.pw_name,
  1201. X         new_element -> filename);
  1202. X        ptr[13] = '\0';
  1203. X    }
  1204. X    numentries++;
  1205. X
  1206. X    if (ptr[0] == salt[0] && ptr[1] == salt[1])
  1207. X    {
  1208. X        new_element -> across = current_line;
  1209. X        current_line = new_element;
  1210. X    } else
  1211. X    {
  1212. X        if (current_line)
  1213. X        {
  1214. X        current_line -> next = userroot;
  1215. X        }
  1216. X        userroot = current_line;
  1217. X        current_line = new_element;
  1218. X        numlines++;
  1219. X        salt[0] = ptr[0];
  1220. X        salt[1] = ptr[1];
  1221. X    }
  1222. X    }
  1223. X
  1224. X    if (current_line)        /* last one tends to hang about */
  1225. X    {
  1226. X    current_line -> next = userroot;
  1227. X    userroot = current_line;
  1228. X    numlines++;
  1229. X    }
  1230. X    Log ("Loaded %d password entries into %d salted lines.\n",
  1231. X     numentries, --numlines);
  1232. X
  1233. X    return (numentries);
  1234. X}
  1235. X/* and load rules from a standard file into a similar list */
  1236. X
  1237. Xint
  1238. XLoadRules (file, rootpos)
  1239. X    char *file;
  1240. X    struct RULE **rootpos;
  1241. X{
  1242. X    int i;
  1243. X    FILE *fp;
  1244. X    struct RULE *tmproot;
  1245. X    char buffer[STRINGSIZE];
  1246. X    register struct RULE *scratch;
  1247. X
  1248. X    if (!(fp = fopen (file, "r")))
  1249. X    {
  1250. X    Log ("cannot open %s\n", file);
  1251. X    perror (file);
  1252. X    return (-1);
  1253. X    }
  1254. X    i = 0;
  1255. X    tmproot = (struct RULE *) 0;
  1256. X
  1257. X    while (fgets (buffer, STRINGSIZE, fp))
  1258. X    {
  1259. X    Trim (buffer);
  1260. X    if (!buffer[0] || buffer[0] == '#')    /* skip comments in dicts */
  1261. X    {
  1262. X        continue;
  1263. X    }
  1264. X    if (!tmproot)
  1265. X    {
  1266. X        scratch = (struct RULE *) malloc (sizeof (struct RULE));
  1267. X        tmproot = scratch;
  1268. X    } else
  1269. X    {
  1270. X        scratch -> next = (struct RULE *) malloc (sizeof (struct RULE));
  1271. X        scratch = scratch -> next;
  1272. X    }
  1273. X    scratch -> rule = Clone (buffer, 0);    /* full copy */
  1274. X    scratch -> next = (struct RULE *) 0;    /* forward order */
  1275. X    i++;
  1276. X    }
  1277. X    fclose (fp);
  1278. X    Log ("Loaded %d rules from '%s'.\n", i, file);
  1279. X    *rootpos = tmproot;
  1280. X    return (i);
  1281. X}
  1282. X/* load a dictionary into a linked list, sort it into an array */
  1283. X
  1284. Xint
  1285. XLoadDict (file, rule)
  1286. X    char *file;
  1287. X    char *rule;
  1288. X{
  1289. X    register int i;
  1290. X    int nelem;
  1291. X    int tabled;
  1292. X    int discarded;
  1293. X    int rejected;
  1294. X    char *lastptr;
  1295. X    FILE *fp;
  1296. X    register char *mangle;
  1297. X    register struct DICT *scratch;
  1298. X    char buffer[STRINGSIZE];
  1299. X
  1300. X    if (!(fp = fopen (file, "r")))
  1301. X    {
  1302. X    perror (file);
  1303. X    return (-1);
  1304. X    }
  1305. X    nelem = 0;
  1306. X    rejected = 0;
  1307. X    while (fgets (buffer, STRINGSIZE, fp))
  1308. X    {
  1309. X    Trim (buffer);
  1310. X    if (!buffer[0])
  1311. X    {
  1312. X        continue;
  1313. X    }
  1314. X    mangle = Mangle (buffer, rule);
  1315. X
  1316. X    if (!mangle)
  1317. X    {
  1318. X        rejected++;
  1319. X        if (verbose_bool)
  1320. X        {
  1321. X        Log ("Rejected '%s' due to rule specs.\n", buffer);
  1322. X        }
  1323. X        continue;
  1324. X    }
  1325. X    if (dictroot && !strncmp (mangle, dictroot -> word, pwlength))
  1326. X    {
  1327. X        rejected++;
  1328. X        if (verbose_bool)
  1329. X        {
  1330. X        Log ("'%s' ignored on load; duplicated to %d chars.\n",
  1331. X             buffer, pwlength);
  1332. X        }
  1333. X        continue;
  1334. X    }
  1335. X    scratch = (struct DICT *) malloc (sizeof (struct DICT));
  1336. X    scratch -> word = Clone (mangle, pwlength);
  1337. X    scratch -> next = dictroot;
  1338. X    dictroot = scratch;
  1339. X    nelem++;
  1340. X
  1341. X    if (verbose_bool)
  1342. X    {
  1343. X        Log ("Loaded '%s' as '%s' using '%s'\n", buffer, scratch -> word,
  1344. X         rule);
  1345. X    }
  1346. X    }
  1347. X    fclose (fp);
  1348. X
  1349. X    if (nelem <= 0)
  1350. X    {
  1351. X    return (0);
  1352. X    }
  1353. X    Log ("Loaded %d words from '%s' using rule '%s'\n", nelem, file, rule);
  1354. X    Log ("(Rejected %d words during loading)\n", rejected);
  1355. X
  1356. X    dictbase = (char **) calloc (nelem, sizeof (char *));
  1357. X    if (!dictbase)
  1358. X    {
  1359. X    Log ("PANIC: Cannot allocate memory for dictbase structure...\n");
  1360. X    exit (1);
  1361. X    }
  1362. X    tabled = 0;
  1363. X    for (scratch = dictroot; scratch; scratch = scratch -> next)
  1364. X    {
  1365. X    dictbase[tabled++] = scratch -> word;
  1366. X    }
  1367. X
  1368. X    Log ("Stored %d words in table for sorting\n", tabled);
  1369. X
  1370. X    qsort (dictbase, tabled, sizeof (struct DICT *), DictCmp);
  1371. X
  1372. X    discarded = 0;
  1373. X    lastptr = dictbase[0];
  1374. X    for (i = 1; i < tabled; i++)
  1375. X    {
  1376. X    /*
  1377. X     * no point in putting a test-first-char STRCMP macro here, since in
  1378. X     * sorted data, the first char is usually the same...
  1379. X     */
  1380. X    if (!strcmp (lastptr, dictbase[i]))
  1381. X    {
  1382. X        dictbase[i] = (char *) 0;
  1383. X        discarded++;
  1384. X    } else
  1385. X    {
  1386. X        lastptr = dictbase[i];
  1387. X    }
  1388. X    }
  1389. X
  1390. X    Log ("Discarded %d duplicate words in sorted table\n", discarded);
  1391. X    return (nelem);
  1392. X}
  1393. X/* lose the current dictionary */
  1394. X
  1395. Xint
  1396. XDropDict ()
  1397. X{
  1398. X    struct DICT *scratch;
  1399. X
  1400. X    while (dictroot)
  1401. X    {
  1402. X    free (dictroot -> word);
  1403. X    scratch = dictroot -> next;
  1404. X    free (dictroot);
  1405. X    dictroot = scratch;
  1406. X    }
  1407. X    free (dictbase);
  1408. X    return (0);
  1409. X}
  1410. X
  1411. X/*
  1412. X * write a feedback file if there is anything to save - return number
  1413. X * uncracked users
  1414. X */
  1415. X
  1416. Xint
  1417. XFeedBack (log_notdone)
  1418. X    int log_notdone;
  1419. X{
  1420. X    register FILE *fp;
  1421. X    static char fmt[] = "%s:%s:%s:%s\n";
  1422. X    register struct USER *head;
  1423. X    register struct USER *arm;
  1424. X    int done;
  1425. X    int notdone;
  1426. X
  1427. X    notdone = done = 0;
  1428. X
  1429. X    Log ("Sweeping data looking for feedback.\n");
  1430. X
  1431. X    fp = (FILE *) 0;
  1432. X
  1433. X    for (head = userroot; head; head = head -> next)
  1434. X    {
  1435. X    for (arm = head; arm; arm = arm -> across)
  1436. X    {
  1437. X        if (arm -> done)
  1438. X        {
  1439. X            done++;
  1440. X        /* horrible little hack, vile, sick, I love it */
  1441. X        if (!fp)
  1442. X        {
  1443. X            if (!(fp = fopen (feedbackfile, "w")))
  1444. X            {
  1445. X            perror (feedbackfile);
  1446. X            return(-1);
  1447. X            }
  1448. X            Log ("Feedback file opened for writing.\n");
  1449. X        }
  1450. X        fprintf (fp,fmt,feedback_string,
  1451. X             arm -> passwd.pw_passwd,"Y",arm -> passwd_txt);
  1452. X        } else
  1453. X        {
  1454. X            notdone++;
  1455. X        if (log_notdone)
  1456. X        {
  1457. X            if (!fp)    /* and again !!! heheheheheheh */
  1458. X            {
  1459. X            if (!(fp = fopen (feedbackfile, "w")))
  1460. X            {
  1461. X                perror (feedbackfile);
  1462. X                return(-1);
  1463. X            }
  1464. X            Log ("Feedback file opened for writing.\n");
  1465. X            }
  1466. X            /* I think I'm going slightly warped */
  1467. X            fprintf (fp,fmt,feedback_string,
  1468. X                     arm -> passwd.pw_passwd,"N","");
  1469. X        }
  1470. X        }
  1471. X
  1472. X    }
  1473. X    }
  1474. X    if (fp)
  1475. X    {
  1476. X    fclose (fp);
  1477. X    Log ("Closing feedback file.\n");
  1478. X    }
  1479. X    Log("FeedBack: %d users done, %d users left to crack.\n", done, notdone);
  1480. X    return(notdone);
  1481. X}
  1482. X/* try a chain of users with the same salt */
  1483. X
  1484. Xint
  1485. XTryManyUsers (eptr, guess)    /* returns 0 if all done this chain */
  1486. X    register struct USER *eptr;
  1487. X    char *guess;
  1488. X{
  1489. X    register int retval;
  1490. X    char guess_crypted[STRINGSIZE];
  1491. X
  1492. X    if (eptr -> done && !eptr -> across)
  1493. X    {
  1494. X    return (0);
  1495. X    }
  1496. X
  1497. X    strcpy (guess_crypted, crypt (guess, eptr -> passwd.pw_passwd));
  1498. X
  1499. X    retval = 0;
  1500. X
  1501. X    while (eptr)
  1502. X    {
  1503. X    if (verbose_bool)
  1504. X    {
  1505. X        Log ("Trying '%s' on %s from line %s\n",
  1506. X         guess,
  1507. X         eptr -> passwd.pw_name,
  1508. X         eptr -> filename);
  1509. X    }
  1510. X    if (!eptr->done && !STRCMP (guess_crypted, eptr -> passwd.pw_passwd))
  1511. X    {
  1512. X        PrintGuess (eptr, guess);
  1513. X    }
  1514. X    retval += (!(eptr -> done));
  1515. X    eptr = eptr -> across;
  1516. X    }
  1517. X
  1518. X    return (retval);
  1519. X}
  1520. X/* try a word on an individual */
  1521. X
  1522. Xint
  1523. XTryOneUser (eptr, guess)    /* returns non-null on guessed user */
  1524. X    register struct USER *eptr;
  1525. X    register char *guess;
  1526. X{
  1527. X    if (!guess || !*guess || eptr -> done)
  1528. X    {
  1529. X    return (0);
  1530. X    }
  1531. X    if (verbose_bool)
  1532. X    {
  1533. X    Log ("Trying '%s' on %s from %s\n",
  1534. X         guess,
  1535. X         eptr -> passwd.pw_name,
  1536. X         eptr -> filename);
  1537. X    }
  1538. X    if (strcmp (crypt (guess, eptr -> passwd.pw_passwd),
  1539. X        eptr -> passwd.pw_passwd))
  1540. X    {
  1541. X    return (0);
  1542. X    }
  1543. X    PrintGuess (eptr, guess);
  1544. X
  1545. X    return (1);
  1546. X}
  1547. X/* frontend to TryOneUser() to save hassle */
  1548. X
  1549. Xint
  1550. XWordTry (entry_ptr, guess)
  1551. X    register struct USER *entry_ptr;
  1552. X    register char *guess;
  1553. X{
  1554. X    register int i;
  1555. X    struct RULE *ruleptr;
  1556. X    register char *mangle;
  1557. X
  1558. X    if (!guess[0] || !guess[1])
  1559. X    {
  1560. X    return (0);
  1561. X    }
  1562. X    for (ruleptr = gecosroot; ruleptr; ruleptr = ruleptr -> next)
  1563. X    {
  1564. X    if (mangle = Mangle (guess, ruleptr -> rule))
  1565. X    {
  1566. X        if (TryOneUser (entry_ptr, mangle))
  1567. X        {
  1568. X        return (1);
  1569. X        }
  1570. X    }
  1571. X    }
  1572. X    return (0);
  1573. X}
  1574. X/* Special manipulations for the GECOS field and dotfiles */
  1575. X
  1576. Xint
  1577. XParseBuffer (entry_ptr, buffer, advanced)
  1578. X    register struct USER *entry_ptr;
  1579. X    char *buffer;
  1580. X    int advanced;
  1581. X{
  1582. X    int wordcount;
  1583. X    register int i;
  1584. X    register int j;
  1585. X    register char *ptr;
  1586. X    char junk[STRINGSIZE];
  1587. X    char *words[WORDSTACKSIZE];
  1588. X
  1589. X    /* zap all punctuation */
  1590. X    for (ptr = buffer; *ptr; ptr++)
  1591. X    {
  1592. X    if (ispunct (*ptr) || isspace (*ptr))
  1593. X    {
  1594. X        *ptr = ' ';
  1595. X    }
  1596. X    }
  1597. X
  1598. X    /* break up all individual words */
  1599. X    wordcount = 0;
  1600. X    ptr = buffer;
  1601. X    while (*ptr)
  1602. X    {
  1603. X    while (*ptr && isspace (*ptr))
  1604. X    {
  1605. X        ptr++;
  1606. X    }
  1607. X    if (*ptr)
  1608. X    {
  1609. X        words[wordcount++] = ptr;
  1610. X        if (wordcount >= WORDSTACKSIZE)
  1611. X        {
  1612. X        Log ("ParseBuffer: Abort: Stack Full !\n");
  1613. X        return (0);
  1614. X        }
  1615. X    }
  1616. X    while (*ptr && !isspace (*ptr))
  1617. X    {
  1618. X        ptr++;
  1619. X    }
  1620. X
  1621. X    if (*ptr)
  1622. X    {
  1623. X        *(ptr++) = '\0';
  1624. X    }
  1625. X    }
  1626. X
  1627. X    words[wordcount] = (char *) 0;
  1628. X
  1629. X    /* try all the words individually */
  1630. X    if (verbose_bool)
  1631. X    {
  1632. X    Log ("Trying individual words\n");
  1633. X    }
  1634. X    for (i = 0; i < wordcount; i++)
  1635. X    {
  1636. X    if (WordTry (entry_ptr, words[i]))
  1637. X    {
  1638. X        return (1);
  1639. X    }
  1640. X    }
  1641. X
  1642. X    if (!advanced)
  1643. X    {
  1644. X        return (0);
  1645. X    }
  1646. X
  1647. X    /* try pairings of words */
  1648. X    if (verbose_bool)
  1649. X    {
  1650. X    Log ("Trying paired words\n");
  1651. X    }
  1652. X    for (j = 1; j < wordcount; j++)
  1653. X    {
  1654. X    for (i = 0; i < j; i++)
  1655. X    {
  1656. X        /* Skip initials for next pass */
  1657. X        if (!words[i][1] || !words[j][1])
  1658. X        {
  1659. X        continue;
  1660. X        }
  1661. X        strcpy (junk, words[i]);
  1662. X        strcat (junk, words[j]);
  1663. X        if (WordTry (entry_ptr, junk))
  1664. X        {
  1665. X        return (1);
  1666. X        }
  1667. X    }
  1668. X    }
  1669. X
  1670. X    /* try initials + words */
  1671. X    if (verbose_bool)
  1672. X    {
  1673. X    Log ("Trying initial'ed words\n");
  1674. X    }
  1675. X    for (j = 1; j < wordcount; j++)
  1676. X    {
  1677. X    for (i = 0; i < j; i++)
  1678. X    {
  1679. X        junk[0] = words[i][0];
  1680. X        if (islower (junk[0]))
  1681. X        {
  1682. X        junk[0] = toupper (junk[0]);
  1683. X        }
  1684. X        junk[1] = '\0';
  1685. X        strcat (junk, words[j]);
  1686. X        if (WordTry (entry_ptr, junk))
  1687. X        {
  1688. X        return (1);
  1689. X        }
  1690. X    }
  1691. X    }
  1692. X
  1693. X    return (0);
  1694. X}
  1695. X/* run over password entries looking for passwords */
  1696. X
  1697. Xvoid
  1698. XPass1 ()
  1699. X{
  1700. X    int i;
  1701. X    int j;
  1702. X    FILE *fp;
  1703. X    int cracked;
  1704. X    char junk[DOTFILESIZE];
  1705. X    char filename[STRINGSIZE];
  1706. X    struct USER *head;
  1707. X    register char *ptr;
  1708. X    register struct USER *this;
  1709. X    static char *dotfiles[] =
  1710. X    {
  1711. X    ".plan",
  1712. X    ".project",
  1713. X    ".signature",
  1714. X    (char *) 0
  1715. X    };
  1716. X
  1717. X    Log ("Starting pass 1 - password information\n");
  1718. X
  1719. X    for (head = userroot; head; head = head -> next)
  1720. X    {
  1721. X    for (this = head; this; this = this -> across)
  1722. X    {
  1723. X        strcpy (junk, this -> passwd.pw_gecos);
  1724. X
  1725. X        if (WordTry (this, this -> passwd.pw_name) ||
  1726. X        ParseBuffer (this, junk, 1))
  1727. X        {
  1728. X        continue;
  1729. X        }
  1730. X#ifdef CRACK_DOTFILES
  1731. X        for (i = 0; dotfiles[i]; i++)
  1732. X        {
  1733. X        sprintf (filename, "%s/%s", this -> passwd.pw_dir, dotfiles[i]);
  1734. X
  1735. X        if (!(fp = fopen (filename, "r")))
  1736. X        {
  1737. X            continue;
  1738. X        }
  1739. X
  1740. X        j = fread (junk, 1, DOTFILESIZE, fp);
  1741. X
  1742. X        fclose (fp);
  1743. X
  1744. X        if (j <= 1)
  1745. X        {
  1746. X            continue;
  1747. X        }
  1748. X
  1749. X        junk[j - 1] = '\0';    /* definite terminator */
  1750. X
  1751. X        if (verbose_bool)
  1752. X        {
  1753. X            Log("DOTFILES: Checking %d bytes of %s\n", j, filename);
  1754. X        }
  1755. X
  1756. X        if (ParseBuffer (this, junk, 0))
  1757. X        {
  1758. X            continue;
  1759. X        }
  1760. X        }
  1761. X#endif CRACK_DOTFILES
  1762. X    }
  1763. X    }
  1764. X    return;
  1765. X}
  1766. X
  1767. Xvoid
  1768. XPass2 (dictfile)
  1769. X    char *dictfile;
  1770. X{
  1771. X    int i;
  1772. X    int pointuser;
  1773. X    int dictsize;
  1774. X    struct USER *headptr;
  1775. X    struct RULE *ruleptr;
  1776. X
  1777. X    Log ("Starting pass 2 - dictionary words\n");
  1778. X    headptr = (struct USER *) 0;
  1779. X    ruleptr = (struct RULE *) 0;
  1780. X
  1781. X    /* check if we are recovering from a crash */
  1782. X    if (recover_bool)
  1783. X    {
  1784. X    recover_bool = 0;        /* switch off */
  1785. X    for (ruleptr = ruleroot;
  1786. X         ruleptr && strcmp (ruleptr -> rule, old_rule);
  1787. X         ruleptr = ruleptr -> next);
  1788. X    if (!ruleptr)
  1789. X    {
  1790. X        Log ("Fatal: Ran off end of list looking for rule '%s'\n",
  1791. X         old_rule);
  1792. X        exit (1);
  1793. X    }
  1794. X    for (headptr = userroot;    /* skip right number of users */
  1795. X         headptr && old_usernum--;
  1796. X         headptr = headptr -> next);
  1797. X    if (!headptr)
  1798. X    {
  1799. X        Log ("Fatal: Ran off end of list looking for user '%s'\n",
  1800. X         old_username);
  1801. X        exit (1);
  1802. X    }
  1803. X    }
  1804. X
  1805. X    /* start iterating here */
  1806. X    for (ruleptr = (ruleptr ? ruleptr : ruleroot);
  1807. X     ruleptr;
  1808. X     ruleptr = ruleptr -> next)
  1809. X    {
  1810. X    if ((dictsize = LoadDict (dictfile, ruleptr -> rule)) <= 0)
  1811. X    {
  1812. X        Log ("Oops! I got an empty dictionary! Skipping rule '%s'!\n",
  1813. X         ruleptr -> rule);
  1814. X        continue;
  1815. X    }
  1816. X    pointuser = 0;
  1817. X
  1818. X    /* iterate all the users */
  1819. X    for (headptr = (headptr ? headptr : userroot);
  1820. X         headptr;
  1821. X         headptr = headptr -> next)
  1822. X    {
  1823. X        SetPoint (dictfile,
  1824. X              ruleptr -> rule,
  1825. X              pointuser++,
  1826. X              headptr -> passwd.pw_name);
  1827. X
  1828. X        /* iterate all the words */
  1829. X        for (i = 0; i < dictsize; i++)
  1830. X        {
  1831. X        /* skip repeated words... */
  1832. X        if (dictbase[i] && !TryManyUsers (headptr, dictbase[i]))
  1833. X        {
  1834. X            break;
  1835. X        }
  1836. X        }
  1837. X    }
  1838. X    /* free up memory */
  1839. X    DropDict ();
  1840. X    /* write feedback file */
  1841. X    if (!FeedBack (0))
  1842. X    {
  1843. X        Log("FeedBack: information: all users are cracked after this pass\n");
  1844. X        return;
  1845. X    }
  1846. X    /* on next pass, start from top of user list */
  1847. X    headptr = (struct USER *) 0;
  1848. X    }
  1849. X}
  1850. X
  1851. Xint
  1852. Xmain (argc, argv)
  1853. X    int argc;
  1854. X    char *argv[];
  1855. X{
  1856. X    int i;
  1857. X    int uerr;
  1858. X    long t;
  1859. X    int die_bool = 0;
  1860. X    FILE *fp;
  1861. X    char *file;
  1862. X    char *crack_out;
  1863. X    extern int optind;
  1864. X    extern char *optarg;
  1865. X    static char getopt_string[] = "i:fX:n:r:vml:";
  1866. X
  1867. X    uerr = 0;
  1868. X    if (argc == 1)
  1869. X    {
  1870. X    uerr++;
  1871. X    }
  1872. X    while ((i = getopt (argc, argv, getopt_string)) != EOF)
  1873. X    {
  1874. X    switch (i)
  1875. X    {
  1876. X    case 'i':
  1877. X        strcpy (input_file, optarg);
  1878. X        if (!freopen (input_file, "r", stdin))
  1879. X        {
  1880. X        perror (input_file);
  1881. X        exit (1);
  1882. X        }
  1883. X        if (!strncmp(input_file, "/tmp/pw.", 7))
  1884. X        {
  1885. X            unlink(input_file);
  1886. X        }
  1887. X        break;
  1888. X    case 'm':
  1889. X        mail_bool = 1;
  1890. X        break;
  1891. X    case 'f':
  1892. X        foreground_bool = 1;
  1893. X        break;
  1894. X    case 'X':
  1895. X        remote_bool = 1;
  1896. X        strcpy (supplied_name, optarg);
  1897. X        break;
  1898. X    case 'l':
  1899. X        pwlength = atoi (optarg);
  1900. X        break;
  1901. X    case 'n':
  1902. X        nice_value = atoi (optarg);
  1903. X        nice (nice_value);
  1904. X        break;
  1905. X    case 'r':
  1906. X        recover_bool = 1;
  1907. X        strcpy (recover_file, optarg);
  1908. X        break;
  1909. X    case 'v':
  1910. X        verbose_bool = 1;
  1911. X        break;
  1912. X    default:
  1913. X    case '?':
  1914. X        uerr++;
  1915. X        break;
  1916. X    }
  1917. X    }
  1918. X
  1919. X    if (optind >= argc)
  1920. X    {
  1921. X    uerr++;
  1922. X    }
  1923. X    if (uerr)
  1924. X    {
  1925. X    fprintf (stderr,
  1926. X         "Usage:\t%s -%s dictfile [dictfile...]\n",
  1927. X         argv[0],
  1928. X         getopt_string);
  1929. X    exit (1);
  1930. X    }
  1931. X    time (&t);
  1932. X    pid = getpid ();
  1933. X    if (!(crack_out = (char *) getenv ("CRACK_OUT")))
  1934. X    {
  1935. X    crack_out = ".";
  1936. X    }
  1937. X    sprintf (opfile, "%s/out.%d", crack_out, pid);
  1938. X    if (remote_bool)
  1939. X    {
  1940. X    sprintf (diefile, "%s", supplied_name);
  1941. X    } else
  1942. X    {
  1943. X    sprintf (diefile, "%s/D.%d", runtime, pid);
  1944. X    }
  1945. X    sprintf (pointfile, "%s/P.%d", runtime, pid);
  1946. X    sprintf (feedbackfile, "%s/F.%d", runtime, pid);
  1947. X
  1948. X    if (gethostname (this_hostname, STRINGSIZE))
  1949. X    {
  1950. X    perror ("gethostname");
  1951. X    }
  1952. X    if (!foreground_bool)
  1953. X    {
  1954. X    if (!freopen (opfile, "w", stdout))
  1955. X    {
  1956. X        perror ("freopen(stdout)");
  1957. X        exit (1);
  1958. X    }
  1959. X    if (!freopen (opfile, "a", stderr))
  1960. X    {
  1961. X        perror ("freopen(stderr)");
  1962. X        exit (1);
  1963. X    }
  1964. X    }
  1965. X    /*
  1966. X     * don't generate a die file unless we are not 'attached' to a
  1967. X     * terminal...  except when we are remote as well...
  1968. X     */
  1969. X
  1970. X    if (!foreground_bool || (foreground_bool && remote_bool))
  1971. X    {
  1972. X    if (!(fp = fopen (diefile, "w")))
  1973. X    {
  1974. X        perror (diefile);
  1975. X        exit (1);
  1976. X    }
  1977. X    die_bool = 1;
  1978. X    fprintf (fp, "#!/bin/sh\n");
  1979. X    fprintf (fp, "# host=%s pid=%d starttime=%s",
  1980. X         this_hostname, pid, ctime (&t));
  1981. X    fprintf (fp, "kill -TERM %d && rm $0", pid);
  1982. X    fclose (fp);
  1983. X    chmod (diefile, 0700);
  1984. X    }
  1985. X    Log ("Crack v%s: The Password Cracker, (c) ADE Muffett, 1991\n", version);
  1986. X
  1987. X#ifdef FCRYPT
  1988. X    init_des ();
  1989. X#endif
  1990. X
  1991. X    /* Quick, verify that we are sane ! */
  1992. X
  1993. X    if (strcmp (crypt ("fredfred", "fredfred"), "frxWbx4IRuBBA"))
  1994. X    {
  1995. X    Log ("Version of crypt() being used internally is not compatible with standard.\n");
  1996. X    Log ("This could be due to byte ordering problems - see the comments in Sources/conf.h\n");
  1997. X    Log ("If there is another reason for this, edit the source to remove this assertion.\n");
  1998. X    Log ("Terminating...\n");
  1999. X    exit (0);
  2000. X    }
  2001. X    signal (SIGTERM, CatchTERM);
  2002. X
  2003. X    Log ("Loading Data, host=%s pid=%d\n", this_hostname, pid);
  2004. X
  2005. X    if (LoadData () <= 0)
  2006. X    {
  2007. X    Log ("Nothing to Crack. Exiting...\n");
  2008. X    exit (0);
  2009. X    }
  2010. X    if (LoadRules (rulefile, &ruleroot) < 0 ||
  2011. X    LoadRules (gecosfile, &gecosroot) < 0)
  2012. X    {
  2013. X    exit (1);
  2014. X    }
  2015. X    if (!recover_bool)
  2016. X    {
  2017. X    /* We are starting afresh ! Ah, the birds in May ! */
  2018. X    Pass1 ();
  2019. X    if (!FeedBack (0))
  2020. X    {
  2021. X        Log("FeedBack: information: all users are cracked after gecos pass\n");
  2022. X        goto finish_crack;
  2023. X    }
  2024. X    } else
  2025. X    {
  2026. X    int rval;
  2027. X    if (rval = GetPoint (recover_file))
  2028. X    {
  2029. X        Log ("Recovery from file %s not permitted on this host [code %d]\n",
  2030. X         recover_file,
  2031. X         rval);
  2032. X        exit (0);
  2033. X    }
  2034. X    /* Some spodulous creep pulled our plug... */
  2035. X    while ((optind < argc) && strcmp (argv[optind], old_dictname))
  2036. X    {
  2037. X        optind++;
  2038. X    }
  2039. X    }
  2040. X
  2041. X    for (i = optind; i < argc; i++)
  2042. X    {
  2043. X    Pass2 (argv[i]);
  2044. X    }
  2045. X
  2046. X    Log ("Tidying up files...\n");
  2047. X    FeedBack (1);
  2048. X
  2049. Xfinish_crack:
  2050. X
  2051. X    if (die_bool)
  2052. X    {
  2053. X    unlink (diefile);
  2054. X    }
  2055. X    unlink (pointfile);
  2056. X
  2057. X    Log ("Done.\n");
  2058. X
  2059. X    return (0);
  2060. X}
  2061. END_OF_FILE
  2062. if test 23895 -ne `wc -c <'Sources/crack-pwc.c'`; then
  2063.     echo shar: \"'Sources/crack-pwc.c'\" unpacked with wrong size!
  2064. fi
  2065. # end of 'Sources/crack-pwc.c'
  2066. fi
  2067. echo shar: End of archive 4 \(of 5\).
  2068. cp /dev/null ark4isdone
  2069. MISSING=""
  2070. for I in 1 2 3 4 5 ; do
  2071.     if test ! -f ark${I}isdone ; then
  2072.     MISSING="${MISSING} ${I}"
  2073.     fi
  2074. done
  2075. if test "${MISSING}" = "" ; then
  2076.     echo You have unpacked all 5 archives.
  2077.     rm -f ark[1-9]isdone
  2078. else
  2079.     echo You still need to unpack the following archives:
  2080.     echo "        " ${MISSING}
  2081. fi
  2082. ##  End of shell archive.
  2083. exit 0
  2084. exit 0 # Just in case...
  2085. -- 
  2086. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2087. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2088. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2089. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2090.