home *** CD-ROM | disk | FTP | other *** search
/ The Hacker's Encyclopedia 1998 / hackers_encyclopedia.iso / hacking / unix / crackunx.txt / Sources / crack-pwc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-25  |  21.8 KB  |  1,167 lines

  1. /*
  2.  * This program is copyright Alec Muffett 1991 except for some portions of
  3.  * code in "crack-fcrypt.c" which are copyright Robert Baldwin, Icarus Sparry
  4.  * and Alec Muffett.  The author(s) disclaims all responsibility or liability
  5.  * with respect to it's usage or its effect upon hardware or computer
  6.  * systems, and maintain copyright as set out in the "LICENCE" document which
  7.  * accompanies distributions of Crack v4.0 and upwards.
  8.  */
  9.  
  10. #include "crack.h"
  11.  
  12. #define DOTFILESIZE    1024
  13. #define WORDSTACKSIZE    512
  14.  
  15. /*
  16.  * crack-pwc.c - an optimised password cracker. (c) ADE Muffett, Feb 1992. If
  17.  * this won't break your password file, it's unlikely that anything else
  18.  * will.
  19.  */
  20.  
  21. /* trap a signal on shutdown */
  22.  
  23. void
  24. CatchTERM ()
  25. {
  26.     /* bury magnets */
  27.     Log ("Caught a SIGTERM! Commiting suicide...\n");
  28.     /* swallow the rapture */
  29.     Log ("<argh!>\n");
  30.     /* let's gather feathers */
  31.     sync ();
  32.     /* don't fall on me */
  33.     exit (0);
  34.     /* 'Fall on Me' by R.E.M. */
  35. }
  36. /* jump ':' separated fields in an input */
  37.  
  38. char *
  39. PWSkip (p)
  40.     register char *p;
  41. {
  42.     while (*p && *p != ':')
  43.     {
  44.     p++;
  45.     }
  46.     if (*p)
  47.     {
  48.     *p++ = '\0';
  49.     }
  50.     return (p);
  51. }
  52.  
  53. char *
  54. Archive (myword)
  55.     register char *myword;
  56. {
  57.     register int i;
  58.     register struct DICT *ptr;
  59.     static struct DICT *arch_root;
  60.  
  61.     for (ptr = arch_root; ptr; ptr = ptr -> next)
  62.     {
  63.     if (!STRCMP (ptr -> word, myword))
  64.     {
  65.         return (ptr -> word);
  66.     }
  67.     }
  68.  
  69.     i = strlen (myword);
  70.  
  71.     ptr = (struct DICT *) malloc (sizeof (struct DICT) + i);
  72.  
  73.     if (ptr)
  74.     {
  75.     strcpy (ptr -> word, myword);
  76.     ptr -> word[i] = '\0';
  77.     ptr -> next = arch_root;
  78.     arch_root = ptr;
  79.     } else
  80.     {
  81.     Log ("Archive/malloc() failed! Fatal lack of memory!\n");
  82.     exit (1);
  83.     }
  84.  
  85.     return (ptr -> word);
  86. }
  87. /* parse and store a password entry */
  88.  
  89. struct USER *
  90. Parse (buffer)
  91.     register char *buffer;
  92. {
  93.     register char *p;
  94.     register struct USER *retval;
  95.  
  96.     retval = (struct USER *) malloc (sizeof (struct USER));
  97.  
  98.     if (!retval)
  99.     {
  100.     Log ("Parse/malloc() failed! Fatal lack of memory!\n");
  101.     exit (1);
  102.     }
  103.     retval -> next = retval -> across = NULL;
  104.     retval -> passwd_txt = NULL;
  105.     retval -> done = 0;
  106.     Trim (buffer);
  107.  
  108.     p = PWSkip (buffer);
  109.     retval -> filename = Archive (buffer);
  110.  
  111.     p = Clone (p);
  112.     if (!p)
  113.     {
  114.     Log ("Parse/Clone() failed! Fatal lack of memory!\n");
  115.     exit (1);
  116.     }
  117.     retval -> passwd.pw_name = p;
  118.  
  119.     p = PWSkip (p);
  120.     retval -> passwd.pw_passwd = p;
  121.  
  122.     p = PWSkip (p);
  123.     retval -> passwd.pw_uid = atoi (p);
  124.  
  125.     p = PWSkip (p);
  126.     retval -> passwd.pw_gid = atoi (p);
  127.  
  128.     p = PWSkip (p);
  129.     retval -> passwd.pw_gecos = p;
  130.  
  131.     p = PWSkip (p);
  132.     retval -> passwd.pw_dir = p;
  133.  
  134.     p = PWSkip (p);
  135.     retval -> passwd.pw_shell = p;
  136.  
  137.     return (retval);
  138. }
  139. /* load pre-formatted password entries off stdin into linked list */
  140.  
  141. int
  142. LoadData ()
  143. {
  144.     int i;
  145.     char *ptr;
  146.     char salt[2];
  147.     char buffer[STRINGSIZE];
  148.     long int numlines;
  149.     long int numentries;
  150.     register struct USER *new_element;
  151.     register struct USER *current_line;
  152.  
  153.     numlines = 0L;
  154.     numentries = 0L;
  155.     current_line = NULL;
  156.     salt[0] = salt[1] = '*';
  157.  
  158.     while (fgets (buffer, STRINGSIZE, stdin))
  159.     {
  160.     if (!*buffer || isspace (*buffer))
  161.     {
  162.         continue;
  163.     }
  164.     new_element = Parse (buffer);
  165.     ptr = new_element -> passwd.pw_passwd;
  166.  
  167.     if (!ptr[0])
  168.     {
  169.         Log ("Warning! %s (%s in %s) has a NULL password!\n",
  170.          new_element -> passwd.pw_name,
  171.          new_element -> passwd.pw_shell,
  172.          new_element -> filename);
  173.         continue;
  174.     }
  175.     if (strchr (ptr, '*') ||
  176.         strchr (ptr, '!') ||
  177.         strchr (ptr, ' '))
  178.     {
  179.         Log ("User %s (in %s) has a locked password:- %s\n",
  180.          new_element -> passwd.pw_name,
  181.          new_element -> filename,
  182.          new_element -> passwd.pw_passwd);
  183.         continue;
  184.     }
  185.     i = strlen (ptr);
  186.  
  187.     if (i < 13)
  188.     {
  189.         Log ("User %s (in %s) has a short pw_passwd field - skipping.\n",
  190.          new_element -> passwd.pw_name,
  191.          new_element -> filename);
  192.         continue;
  193.     }
  194.     if (i > 13)
  195.     {
  196.         Log ("User %s (in %s) has a long pw_passwd field - truncating.\n",
  197.          new_element -> passwd.pw_name,
  198.          new_element -> filename);
  199.         ptr[13] = '\0';
  200.     }
  201.     numentries++;
  202.  
  203.     if (ptr[0] == salt[0] && ptr[1] == salt[1])
  204.     {
  205.         new_element -> across = current_line;
  206.         current_line = new_element;
  207.     } else
  208.     {
  209.         if (current_line)
  210.         {
  211.         current_line -> next = userroot;
  212.         }
  213.         userroot = current_line;
  214.         current_line = new_element;
  215.         numlines++;
  216.         salt[0] = ptr[0];
  217.         salt[1] = ptr[1];
  218.     }
  219.     }
  220.  
  221.     if (current_line)        /* last one tends to hang about */
  222.     {
  223.     current_line -> next = userroot;
  224.     userroot = current_line;
  225.     numlines++;
  226.     }
  227.     --numlines;
  228.  
  229.     if (numentries)
  230.     {
  231.     Log ("Loaded %ld password entries with %ld different salts: %d%%\n",
  232.          numentries,
  233.          numlines,
  234.          ((numlines * 100) / numentries));
  235.     } else
  236.     {
  237.     Log ("No input supplied: everything removed by feedback ?\n");
  238.     }
  239.     return (numentries);
  240. }
  241. /* and load rules from a standard file into a similar list */
  242.  
  243. int
  244. LoadRules (file, rootpos)
  245.     char *file;
  246.     struct RULE **rootpos;
  247. {
  248.     FILE *fp;
  249.     int numrules;
  250.     struct RULE fencepost;
  251.     register struct RULE *addinto;
  252.     register struct RULE *scratch;
  253.     char buffer[STRINGSIZE];
  254.  
  255.     if (!(fp = fopen (file, "r")))
  256.     {
  257.     Log ("cannot open rulefile %s\n", file);
  258.     perror (file);
  259.     return (-1);
  260.     }
  261.     numrules = 0;
  262.     addinto = &fencepost;
  263.     addinto -> next = (struct RULE *) 0;
  264.  
  265.     while (fgets (buffer, STRINGSIZE, fp))
  266.     {
  267.     Trim (buffer);
  268.  
  269.     if (!buffer[0] || buffer[0] == '#')
  270.     {
  271.         continue;
  272.     }
  273.     scratch = (struct RULE *) malloc (sizeof (struct RULE));
  274.  
  275.     if (!scratch)
  276.     {
  277.         Log ("LoadRules/malloc() failed! Fatal lack of memory!\n");
  278.         exit (1);
  279.     }
  280.     scratch -> rule = Clone (buffer);
  281.  
  282.     if (!scratch -> rule)
  283.     {
  284.         Log ("LoadRules/Clone() failed! Fatal lack of memory!\n");
  285.         exit (1);
  286.     }
  287.     scratch -> next = (struct RULE *) 0;
  288.     addinto -> next = scratch;
  289.     addinto = scratch;
  290.     numrules++;
  291.     }
  292.  
  293.     fclose (fp);
  294.     Log ("Loaded %d rules from '%s'.\n", numrules, file);
  295.     *rootpos = fencepost.next;
  296.     return (numrules);
  297. }
  298. /* load a dictionary into a linked list, and sort it */
  299.  
  300. long int
  301. LoadDict (file, rule, contdict)
  302.     char *file;
  303.     char *rule;
  304.     int contdict;
  305. {
  306.     int i;
  307.     int memfilled;
  308.     long int nelem;
  309.     long int rejected;
  310.     register char *mangle;
  311.     register struct DICT *scratch;
  312.     char pipebuff[STRINGSIZE];
  313.  
  314.     static FILE *fp;
  315.     char buffer[STRINGSIZE];
  316.  
  317.     if (contdict && fp)
  318.     {
  319.     goto files_open;
  320.     }
  321. #ifdef COMPRESSION
  322.     if (!Suffix (file, ".Z"))
  323.     {
  324.     sprintf (pipebuff, "%s %s", zcat, file);
  325.     if (!(fp = (FILE *) popen (pipebuff, "r")))
  326.     {
  327.         perror (pipebuff);
  328.         return (0);
  329.     }
  330.     } else if (!Suffix (file, ".z"))
  331.     {
  332.     sprintf (pipebuff, "%s %s", pcat, file);
  333.     if (!(fp = (FILE *) popen (pipebuff, "r")))
  334.     {
  335.         perror (pipebuff);
  336.         return (0);
  337.     }
  338.     } else
  339. #endif    /* COMPRESSION */
  340.     {
  341.     pipebuff[0] = '\0';
  342.     if (!(fp = fopen (file, "r")))
  343.     {
  344.         perror (file);
  345.         return (0);
  346.     }
  347.     }
  348.  
  349.   files_open:
  350.  
  351.     nelem = 0;
  352.     rejected = 0;
  353.     memfilled = 0;
  354.     dictroot = (struct DICT *) 0;
  355.  
  356.     Log ("%s rule '%s' to file '%s'\n",
  357.      contdict ? "Continuing" : "Applying",
  358.      rule,
  359.      file);
  360.  
  361.     while (fgets (buffer, STRINGSIZE, fp))
  362.     {
  363.     Trim (buffer);
  364.  
  365.     if (!buffer[0] || buffer[0] == '#')
  366.     {
  367.         continue;
  368.     }
  369.     mangle = Mangle (buffer, rule);
  370.  
  371.     if (!mangle)
  372.     {
  373.         rejected++;
  374.  
  375.         if (verbose_bool)
  376.         {
  377.         Log ("Rejected '%s' due to rule specs.\n", buffer);
  378.         }
  379.         continue;
  380.     }
  381.     if (dictroot && !strncmp (mangle, dictroot -> word, pwlength))
  382.     {
  383.         rejected++;
  384.  
  385.         if (verbose_bool)
  386.         {
  387.         Log ("Rejected '%s'; duplicated to %d chars.\n", buffer,
  388.              pwlength);
  389.         }
  390.         continue;
  391.     }
  392.     i = strlen (mangle);
  393.  
  394.     if (i > pwlength)
  395.     {
  396.         i = pwlength;
  397.     }
  398.     scratch = (struct DICT *) malloc (sizeof (struct DICT) + i);
  399.  
  400.     if (!scratch)
  401.     {
  402.         Log ("LoadDict/malloc() failed! Shameful lack of memory!\n");
  403.         memfilled = 1;
  404.         goto words_loaded;
  405.     }
  406.     strncpy (scratch -> word, mangle, i);
  407.     scratch -> word[i] = '\0';
  408.     scratch -> next = dictroot;
  409.     dictroot = scratch;
  410.     nelem++;
  411.  
  412.     if (verbose_bool)
  413.     {
  414.         Log ("Loaded '%s' as '%s' using '%s'\n", buffer,
  415.          scratch -> word, rule);
  416.     }
  417.     }
  418.  
  419.     if (pipebuff[0])
  420.     {
  421.     pclose (fp);
  422.     } else
  423.     {
  424.     fclose (fp);
  425.     }
  426.  
  427.     fp = (FILE *) 0;
  428.  
  429.   words_loaded:
  430.  
  431.     if (nelem == 0)
  432.     {
  433.     return (0);
  434.     }
  435.     Log ("Rejected %ld words on loading, %ld words left to sort\n",
  436.      rejected, nelem);
  437.  
  438.     dictroot = (struct DICT *) SortDict (dictroot, nelem);
  439.  
  440.     if (memfilled)
  441.     {
  442.     nelem = -nelem;
  443.     }
  444.     return (nelem);        /* not strict number anymore... */
  445. }
  446. /* lose the current dictionary */
  447.  
  448. int
  449. DropDict ()
  450. {
  451.     register struct DICT *scratch1;
  452.     register struct DICT *scratch2;
  453.  
  454.     scratch1 = dictroot;
  455.     while (scratch1)
  456.     {
  457.     scratch2 = scratch1 -> next;
  458.     free (scratch1);
  459.     scratch1 = scratch2;
  460.     }
  461.     return (0);
  462. }
  463. /*
  464.  * write a feedback file if there is anything to save - return number
  465.  * uncracked users
  466.  */
  467.  
  468. int
  469. FeedBack (log_notdone)
  470.     int log_notdone;
  471. {
  472.     register FILE *fp;
  473.     static char fmt[] = "%s:%s:%s:%s\n";
  474.     register struct USER *head;
  475.     register struct USER *arm;
  476.     int done;
  477.     int notdone;
  478.  
  479.     notdone = done = 0;
  480.  
  481.     if (verbose_bool)
  482.     {
  483.     Log ("Sweeping data looking for feedback.\n");
  484.     }
  485.     fp = (FILE *) 0;
  486.  
  487.     for (head = userroot; head; head = head -> next)
  488.     {
  489.     for (arm = head; arm; arm = arm -> across)
  490.     {
  491.         if (arm -> done)
  492.         {
  493.         done++;
  494.         /* horrible little hack, vile, sick, I love it */
  495.         if (!fp)
  496.         {
  497.             if (!(fp = fopen (feedbackfile, "w")))
  498.             {
  499.             perror (feedbackfile);
  500.             return (-1);
  501.             }
  502.             if (verbose_bool)
  503.             {
  504.             Log ("Feedback file opened for writing.\n");
  505.             }
  506.         }
  507.         fprintf (fp, fmt, feedback_string,
  508.              arm -> passwd.pw_passwd, "Y", arm -> passwd_txt);
  509.         } else
  510.         {
  511.         notdone++;
  512.         if (log_notdone)
  513.         {
  514.             if (!fp)    /* and again !!! heheheheheheh */
  515.             {
  516.             if (!(fp = fopen (feedbackfile, "w")))
  517.             {
  518.                 perror (feedbackfile);
  519.                 return (-1);
  520.             }
  521.             if (verbose_bool)
  522.             {
  523.                 Log ("Feedback file opened for writing.\n");
  524.             }
  525.             }
  526.             /* I think I'm going slightly warped */
  527.             fprintf (fp, fmt, feedback_string,
  528.                  arm -> passwd.pw_passwd, "N", "");
  529.         }
  530.         }
  531.  
  532.     }
  533.     }
  534.     if (fp)
  535.     {
  536.     fclose (fp);
  537.     Log ("Closing feedback file.\n");
  538.     }
  539.     Log ("FeedBack: %d users done, %d users left to crack.\n", done, notdone);
  540.     return (notdone);
  541. }
  542. /* try a chain of users with the same salt */
  543.  
  544. int
  545. TryManyUsers (eptr, guess)    /* returns 0 if all done this chain */
  546.     register struct USER *eptr;
  547.     char *guess;
  548. {
  549.     register int retval;
  550.     char guess_crypted[STRINGSIZE];
  551.  
  552.     if (eptr -> done && !eptr -> across)
  553.     {
  554.     return (0);
  555.     }
  556.     strcpy (guess_crypted, crypt (guess, eptr -> passwd.pw_passwd));
  557.  
  558.     retval = 0;
  559.  
  560.     while (eptr)
  561.     {
  562.     if (verbose_bool)
  563.     {
  564.         Log ("Trying '%s' on %s from line %s\n",
  565.          guess,
  566.          eptr -> passwd.pw_name,
  567.          eptr -> filename);
  568.     }
  569.     if (!eptr -> done && !STRCMP (guess_crypted, eptr -> passwd.pw_passwd))
  570.     {
  571.         PrintGuess (eptr, guess);
  572.     }
  573.     retval += (!(eptr -> done));
  574.     eptr = eptr -> across;
  575.     }
  576.  
  577.     return (retval);
  578. }
  579. /* try a word on an individual */
  580.  
  581. int
  582. TryOneUser (eptr, guess)    /* returns non-null on guessed user */
  583.     register struct USER *eptr;
  584.     register char *guess;
  585. {
  586.     if (!guess || !*guess || eptr -> done)
  587.     {
  588.     return (0);
  589.     }
  590.     if (verbose_bool)
  591.     {
  592.     Log ("Trying '%s' on %s from %s\n",
  593.          guess,
  594.          eptr -> passwd.pw_name,
  595.          eptr -> filename);
  596.     }
  597.     if (strcmp (crypt (guess, eptr -> passwd.pw_passwd),
  598.         eptr -> passwd.pw_passwd))
  599.     {
  600.     return (0);
  601.     }
  602.     PrintGuess (eptr, guess);
  603.  
  604.     return (1);
  605. }
  606. /* frontend to TryOneUser() to save hassle */
  607.  
  608. int
  609. WordTry (entry_ptr, guess)
  610.     register struct USER *entry_ptr;
  611.     register char *guess;
  612. {
  613.     struct RULE *ruleptr;
  614.     register char *mangle;
  615.  
  616.     if (!guess[0] || !guess[1])
  617.     {
  618.     return (0);
  619.     }
  620.     for (ruleptr = gecosroot; ruleptr; ruleptr = ruleptr -> next)
  621.     {
  622.     if (mangle = Mangle (guess, ruleptr -> rule))
  623.     {
  624.         if (TryOneUser (entry_ptr, mangle))
  625.         {
  626.         return (1);
  627.         }
  628.     }
  629.     }
  630.     return (0);
  631. }
  632. /* Special manipulations for the GECOS field and dotfiles */
  633.  
  634. int
  635. ParseBuffer (entry_ptr, buffer, advanced)
  636.     register struct USER *entry_ptr;
  637.     char *buffer;
  638.     int advanced;
  639. {
  640.     int wordcount;
  641.     register int i;
  642.     register int j;
  643.     register char *ptr;
  644.     char junk[STRINGSIZE];
  645.     char *words[WORDSTACKSIZE];
  646.  
  647.     /* zap all punctuation */
  648.     for (ptr = buffer; *ptr; ptr++)
  649.     {
  650.     if (ispunct (*ptr) || isspace (*ptr))
  651.     {
  652.         *ptr = ' ';
  653.     }
  654.     }
  655.  
  656.     /* break up all individual words */
  657.     wordcount = 0;
  658.     ptr = buffer;
  659.     while (*ptr)
  660.     {
  661.     while (*ptr && isspace (*ptr))
  662.     {
  663.         ptr++;
  664.     }
  665.  
  666.     if (*ptr)
  667.     {
  668.         words[wordcount++] = ptr;
  669.         if (wordcount >= WORDSTACKSIZE)
  670.         {
  671.         Log ("ParseBuffer: Abort: Stack Full !\n");
  672.         return (0);
  673.         }
  674.     }
  675.     while (*ptr && !isspace (*ptr))
  676.     {
  677.         ptr++;
  678.     }
  679.  
  680.     if (*ptr)
  681.     {
  682.         *(ptr++) = '\0';
  683.     }
  684.     }
  685.  
  686.     words[wordcount] = (char *) 0;
  687.  
  688.     /* try all the words individually */
  689.     if (verbose_bool)
  690.     {
  691.     Log ("Trying individual words\n");
  692.     }
  693.     for (i = 0; i < wordcount; i++)
  694.     {
  695.     if (WordTry (entry_ptr, words[i]))
  696.     {
  697.         return (1);
  698.     }
  699.     }
  700.  
  701.     if (!advanced)
  702.     {
  703.     return (0);
  704.     }
  705.     /* try pairings of words */
  706.     if (verbose_bool)
  707.     {
  708.     Log ("Trying paired words\n");
  709.     }
  710.     for (j = 1; j < wordcount; j++)
  711.     {
  712.     for (i = 0; i < j; i++)
  713.     {
  714.         /* Skip initials for next pass */
  715.         if (!words[i][1] || !words[j][1])
  716.         {
  717.         continue;
  718.         }
  719.         strcpy (junk, words[i]);
  720.         strcat (junk, words[j]);
  721.  
  722.         if (WordTry (entry_ptr, junk))
  723.         {
  724.         return (1);
  725.         }
  726.         strcpy (junk, words[j]);
  727.         strcat (junk, words[i]);
  728.  
  729.         if (WordTry (entry_ptr, junk))
  730.         {
  731.         return (1);
  732.         }
  733.     }
  734.     }
  735.  
  736.     /* try initials + words */
  737.     if (verbose_bool)
  738.     {
  739.     Log ("Trying initial'ed words\n");
  740.     }
  741.     for (j = 1; j < wordcount; j++)
  742.     {
  743.     for (i = 0; i < j; i++)
  744.     {
  745.         junk[0] = words[i][0];
  746.         junk[0] = CRACK_TOUPPER (junk[0]);
  747.         strcpy (junk + 1, words[j]);
  748.         if (WordTry (entry_ptr, junk))
  749.         {
  750.         return (1);
  751.         }
  752.     }
  753.     }
  754.  
  755.     return (0);
  756. }
  757. /* run over password entries looking for passwords */
  758.  
  759. void
  760. Pass1 ()
  761. {
  762.     struct USER *head;
  763.     char junk[DOTFILESIZE];
  764.     register struct USER *this;
  765.  
  766. #ifdef CRACK_DOTFILES
  767. #ifdef CRACK_DOTSANE
  768. #include <sys/types.h>
  769. #include <sys/stat.h>
  770.     struct stat sb;
  771. #endif    /* CRACK_DOTSANE */
  772.     int i;
  773.     int j;
  774.     FILE *fp;
  775.     char filename[STRINGSIZE];
  776.     static char *dotfiles[] =
  777.     {
  778.     ".plan",
  779.     ".project",
  780.     ".signature",
  781.     (char *) 0
  782.     };
  783. #endif    /* CRACK_DOTFILES */
  784.  
  785.     Log ("Starting pass 1 - password information\n");
  786.  
  787.     for (head = userroot; head; head = head -> next)
  788.     {
  789.     for (this = head; this; this = this -> across)
  790.     {
  791.         strcpy (junk, this -> passwd.pw_gecos);
  792.  
  793.         if (WordTry (this, this -> passwd.pw_name) ||
  794.         ParseBuffer (this, junk, 1))
  795.         {
  796.         continue;
  797.         }
  798. #ifdef CRACK_DOTFILES
  799.         for (i = 0; dotfiles[i]; i++)
  800.         {
  801.         sprintf (filename, "%s/%s", this -> passwd.pw_dir, dotfiles[i]);
  802. #ifdef CRACK_DOTSANE
  803.         if (stat (filename, &sb) < 0)
  804.         {
  805.             continue;
  806.         }
  807.         if ((!(sb.st_mode & S_IFREG))
  808. #ifdef S_IFSOCK
  809.             || ((sb.st_mode & S_IFSOCK) == S_IFSOCK)
  810. #endif    /* S_IFSOCK */
  811.             )
  812.         {
  813.             continue;
  814.         }
  815. #endif    /* CRACK_DOTSANE */
  816.  
  817.         if (!(fp = fopen (filename, "r")))
  818.         {
  819.             continue;
  820.         }
  821.         j = fread (junk, 1, DOTFILESIZE, fp);
  822.         fclose (fp);
  823.  
  824.         if (j <= 2)
  825.         {
  826.             continue;
  827.         }
  828.         junk[j - 1] = '\0';    /* definite terminator */
  829.  
  830.         if (verbose_bool)
  831.         {
  832.             Log ("DOTFILES: Checking %d bytes of %s\n", j, filename);
  833.         }
  834.         if (ParseBuffer (this, junk, 0))
  835.         {
  836.             continue;
  837.         }
  838.         }
  839. #endif    /* CRACK_DOTFILES */
  840.     }
  841.     }
  842.     return;
  843. }
  844.  
  845. void
  846. Pass2 (dictfile)
  847.     char *dictfile;
  848. {
  849.     int pointuser;
  850.     struct USER *headptr;
  851.     struct RULE *ruleptr;
  852.     struct DICT *dictptr;
  853.  
  854.     Log ("Starting pass 2 - dictionary words\n");
  855.     headptr = (struct USER *) 0;
  856.     ruleptr = (struct RULE *) 0;
  857.  
  858.     /* check if we are recovering from a crash */
  859.     if (recover_bool)
  860.     {
  861.     recover_bool = 0;    /* switch off */
  862.  
  863.     for (ruleptr = ruleroot;
  864.          ruleptr && strcmp (ruleptr -> rule, old_rule);
  865.          ruleptr = ruleptr -> next);
  866.  
  867.     if (!ruleptr)
  868.     {
  869.         Log ("Fatal: Ran off end of list looking for rule '%s'\n",
  870.          old_rule);
  871.         exit (1);
  872.     }
  873.     for (headptr = userroot;/* skip right number of users */
  874.          headptr && old_usernum--;
  875.          headptr = headptr -> next);
  876.  
  877.     if (!headptr)
  878.     {
  879.         Log ("Fatal: Ran off end of list looking for user '%s'\n",
  880.          old_username);
  881.         exit (1);
  882.     }
  883.     }
  884.     /* start iterating here */
  885.     for (ruleptr = (ruleptr ? ruleptr : ruleroot);
  886.      ruleptr;
  887.      ruleptr = ruleptr -> next)
  888.     {
  889.     long int rval;
  890.     int continue_dict;
  891.  
  892.     continue_dict = 0;
  893.  
  894.       load_dict:
  895.     rval = LoadDict (dictfile, ruleptr -> rule, continue_dict);
  896.  
  897.     if (rval == 0)
  898.     {
  899.         Log ("Oops! I got an empty dictionary! Skipping rule '%s'!\n",
  900.          ruleptr -> rule);
  901.         continue;
  902.     }
  903.     pointuser = 0;
  904.  
  905.     /* iterate all the users */
  906.     for (headptr = (headptr ? headptr : userroot);
  907.          headptr;
  908.          headptr = headptr -> next)
  909.     {
  910.         SetPoint (dictfile,
  911.               ruleptr -> rule,
  912.               pointuser++,
  913.               headptr -> passwd.pw_name);
  914.  
  915.         /* iterate all the words */
  916.         for (dictptr = dictroot;
  917.          dictptr;
  918.          dictptr = dictptr -> next)
  919.         {
  920.         /* skip repeated words... */
  921.         if (!TryManyUsers (headptr, dictptr -> word))
  922.         {
  923.             break;
  924.         }
  925.         }
  926.     }
  927.  
  928.     /* free up memory */
  929.     DropDict ();
  930.  
  931.     /* write feedback file */
  932.     if (!FeedBack (0))
  933.     {
  934.         Log ("FeedBack: All Users Are Cracked! Bloody Hell!\n");
  935.         return;
  936.     }
  937.     /* on next pass, start from top of user list */
  938.     headptr = (struct USER *) 0;
  939.  
  940.     /* did we REALLY finish this dictionary ? */
  941.     if (rval < 0)
  942.     {
  943.         continue_dict = 1;
  944.         goto load_dict;
  945.     }
  946.     }
  947. }
  948.  
  949. int
  950. main (argc, argv)
  951.     int argc;
  952.     char *argv[];
  953. {
  954.     int i;
  955.     long t;
  956.     int uerr;
  957.     int die_bool = 0;
  958.     FILE *fp;
  959.     char *crack_out;
  960.     extern int optind;
  961.     extern char *optarg;
  962.     static char getopt_string[] = "i:fX:n:r:vml:";
  963.  
  964.     uerr = 0;
  965.  
  966.     if (argc == 1)
  967.     {
  968.     uerr++;
  969.     }
  970.     while ((i = getopt (argc, argv, getopt_string)) != EOF)
  971.     {
  972.     switch (i)
  973.     {
  974.     case 'i':
  975.         strcpy (input_file, optarg);
  976.         if (!freopen (input_file, "r", stdin))
  977.         {
  978.         perror (input_file);
  979.         exit (1);
  980.         }
  981.         if (!strncmp (input_file, "/tmp/pw.", 7))
  982.         {
  983.         unlink (input_file);
  984.         }
  985.         break;
  986.     case 'm':
  987.         mail_bool = 1;
  988.         break;
  989.     case 'f':
  990.         foreground_bool = 1;
  991.         break;
  992.     case 'X':
  993.         remote_bool = 1;
  994.         strcpy (supplied_name, optarg);
  995.         break;
  996.     case 'l':
  997.         pwlength = atoi (optarg);
  998.         break;
  999.     case 'n':
  1000.         nice_value = atoi (optarg);
  1001.         nice (nice_value);
  1002.         break;
  1003.     case 'r':
  1004.         recover_bool = 1;
  1005.         strcpy (recover_file, optarg);
  1006.         break;
  1007.     case 'v':
  1008.         verbose_bool = 1;
  1009.         break;
  1010.     default:
  1011.     case '?':
  1012.         uerr++;
  1013.         break;
  1014.     }
  1015.     }
  1016.  
  1017.     if (optind >= argc)
  1018.     {
  1019.     uerr++;
  1020.     }
  1021.     if (uerr)
  1022.     {
  1023.     fprintf (stderr,
  1024.          "Usage:\t%s -%s dictfile [dictfile...]\n",
  1025.          argv[0],
  1026.          getopt_string);
  1027.     exit (1);
  1028.     }
  1029.     pid = getpid ();
  1030.  
  1031.     if (gethostname (this_hostname, STRINGSIZE))
  1032.     {
  1033.     perror ("gethostname");
  1034.     }
  1035.     if (!(crack_out = (char *) getenv ("CRACK_OUT")))
  1036.     {
  1037.     crack_out = ".";
  1038.     }
  1039.     sprintf (opfile, "%s/out.%s%d", crack_out, this_hostname, pid);
  1040.  
  1041.     if (remote_bool)
  1042.     {
  1043.     sprintf (diefile, "%s", supplied_name);
  1044.     } else
  1045.     {
  1046.     sprintf (diefile, "%s/D%s%d", runtime, this_hostname, pid);
  1047.     }
  1048.     sprintf (pointfile, "%s/P%s%d", runtime, this_hostname, pid);
  1049.     sprintf (feedbackfile, "%s/F%s%d", runtime, this_hostname, pid);
  1050.  
  1051.     if (!foreground_bool)
  1052.     {
  1053.     if (!freopen (opfile, "w", stdout))
  1054.     {
  1055.         perror ("freopen(stdout)");
  1056.         exit (1);
  1057.     }
  1058.     if (!freopen (opfile, "a", stderr))
  1059.     {
  1060.         perror ("freopen(stderr)");
  1061.         exit (1);
  1062.     }
  1063.     }
  1064.     /*
  1065.      * don't generate a die file unless we are not 'attached' to a
  1066.      * terminal...  except when we are remote as well...
  1067.      */
  1068.  
  1069.     time (&t);
  1070.  
  1071.     if (!foreground_bool || (foreground_bool && remote_bool))
  1072.     {
  1073.     if (!(fp = fopen (diefile, "w")))
  1074.     {
  1075.         perror (diefile);
  1076.         exit (1);
  1077.     }
  1078.     die_bool = 1;
  1079.     fprintf (fp, "#!/bin/sh\n");
  1080.     fprintf (fp, "# ID=%s.%d start=%s", this_hostname, pid, ctime (&t));
  1081.     fprintf (fp, "kill -TERM %d && rm $0", pid);
  1082.     fclose (fp);
  1083.     chmod (diefile, 0700);
  1084.     }
  1085.     Log ("Crack v%s: The Password Cracker, (c) Alec D.E. Muffett, 1992\n",
  1086.      version);
  1087.  
  1088. #ifdef FCRYPT
  1089.     init_des ();
  1090. #endif
  1091.  
  1092.     /* Quick, verify that we are sane ! */
  1093.  
  1094.     if (strcmp (crypt ("fredfred", "fredfred"), "frxWbx4IRuBBA"))
  1095.     {
  1096.     Log ("Version of crypt() being used internally is not compatible with standard.\n");
  1097.     Log ("This could be due to byte ordering problems - see the comments in Sources/conf.h\n");
  1098.     Log ("If there is another reason for this, edit the source to remove this assertion.\n");
  1099.     Log ("Terminating...\n");
  1100.     exit (0);
  1101.     }
  1102. #ifndef AMIGA
  1103.     signal (SIGTERM, CatchTERM);
  1104. #endif
  1105.  
  1106.     Log ("Loading Data, host=%s pid=%d\n", this_hostname, pid);
  1107.  
  1108.     if (LoadData () <= 0)
  1109.     {
  1110.     Log ("Nothing to Crack. Exiting...\n");
  1111.     exit (0);
  1112.     }
  1113.     if (LoadRules (rulefile, &ruleroot) < 0 ||
  1114.     LoadRules (gecosfile, &gecosroot) < 0)
  1115.     {
  1116.     exit (1);
  1117.     }
  1118.     if (!recover_bool)
  1119.     {
  1120.     /* We are starting afresh ! Ah, the birds in May ! */
  1121.     Pass1 ();
  1122.  
  1123.     if (!FeedBack (0))
  1124.     {
  1125.         Log ("FeedBack: information: all users are cracked after gecos pass\n");
  1126.         goto finish_crack;
  1127.     }
  1128.     } else
  1129.     {
  1130.     int rval;
  1131.  
  1132.     if (rval = GetPoint (recover_file))
  1133.     {
  1134.         Log ("Recovery from file %s not permitted on this host [code %d]\n",
  1135.          recover_file,
  1136.          rval);
  1137.         exit (0);
  1138.  
  1139.     }
  1140.     /* Some spodulous creep pulled our plug... */
  1141.     while ((optind < argc) && strcmp (argv[optind], old_dictname))
  1142.     {
  1143.         optind++;
  1144.     }
  1145.     }
  1146.  
  1147.     for (i = optind; i < argc; i++)
  1148.     {
  1149.     Pass2 (argv[i]);
  1150.     }
  1151.  
  1152.     Log ("Tidying up files...\n");
  1153.     FeedBack (1);
  1154.  
  1155.   finish_crack:
  1156.  
  1157.     if (die_bool)
  1158.     {
  1159.     unlink (diefile);
  1160.     }
  1161.     unlink (pointfile);
  1162.  
  1163.     Log ("Done.\n");
  1164.  
  1165.     return (0);
  1166. }
  1167.