#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stat.h>

#define VERSION "4.1f Amiga RELEASE"

char oldcurdir[200];

char *remote=0, *domail=0, *pwl=0,*fgnd=0,*nice=0,*rcvr=0,*verbose=0;

char outinit[200],inputfile[200],univbuffer[200];

int inputline(FILE *fp,char *buffer)
{
  int i,c;

  for(i=0;i<200;i++) {
    c=fgetc(fp);
    if(c==EOF) break;
    if(c=='\n') break;
    buffer[i]=c;
  }
  buffer[i]=0;
  return(c);
}
long filesize(char *fn)
{
  struct stat *st;

  if(st=malloc(sizeof(struct stat))) {
    if(stat(fn,st)==0) {
      return(st->st_size);
    }
  }
  return(0);
}
int pwcmp(char **entry1,char **entry2)
{
  int i,j=0,k;
  char *e1,*e2;

  e1=*entry1;
  e2=*entry2;

  for(i=0;e1[i]!=0;i++) {
    if(e1[i]==':') {
      if(j==0) j++;
    } else {
      break;
    }
  }
  for(k=j=0;e2[k]!=0;k++) {
    if(e2[k]==':') {
      if(j==0) j++;
    } else {
      return(strcmp(&e1[j],&e2[k]));
    }
  }
  return(0);
}

int pwsort(char *filename,int (*cmp)(char **,char **))
{
  FILE *fp;
  char *file;
  int size;
  int i,j;
  int entryc=0;
  char **entries;

  size=filesize(filename);
  if(file=malloc(size+2)) {
    if(fp=fopen(filename,"r")) {
      fread(file,size,1,fp);
      file[size]=0;
      file[size+1]=0;
      fclose(fp);
      for(i=0;i<size;i++) {
        if(file[i]=='\n') {
          entryc++;
          file[i]=0;
        }
      }
      if(entries=malloc(sizeof(char *)*(entryc+1))) {
        for(i=j=0;i<size;i++) {
          if(file[i]==0) {
            j++;
            entries[j]=&file[i+1];
          }
        }
        entries[0]=file;
        qsort(entries,entryc,4,cmp);
        if(fp=fopen(filename,"w")) {
          for(i=0;i<entryc;i++) {
            fprintf(fp,"%s\n",entries[i]);
          }
          fclose(fp);
        }
        free(entries);
      }
    }
    free(file);
  }
  return(1);
}
char *getfieldno(int field,char *buffer)
{
  char *buffer2;
  int i;

  buffer2=buffer;

  for(i=0;i<field;i++) {
    buffer2=buffer2+strlen(buffer2)+1;
  }
  return(buffer2);
}

/* Returns 0 if the pw is not mentioned in the feedback          */
/* Returns -1 if the pw cannot be cracked                        */
/* Returns address to decrypted pw if it's found in the feedback */

char *guessable(char *fbname,char *pw)
{
  FILE *fb;
  char *file;
  int size;
  char *found;
  int i;

  size=filesize(fbname);

  if(file=malloc(size+1)) {
    file[size]=0;
    if(fb=fopen(fbname,"r")) {
      fread(file,size,1,fb);
      found=strstr(file,pw);
      if(found) {
        for(i=0;i+found<size+pw;i++) {
          if(found[i]==':') break;
        }
        if(i+found==size+pw) found=0;
      }
      fclose(fb);
    }
    free(file);
  }
  if(found) {
    if(found[i+1]=='N') return((char *)-1);
    return(&found[i+3]);
  }
  return((char *)0);
}
void joinawk(char *pwname,char *fbname,char *destname)
{
  FILE *pw,*dest;
  int i,j;

  if(dest=fopen(destname,"a")) {
    if(pw=fopen(pwname,"r")) {
      while(inputline(pw,univbuffer)!=EOF) {
        for(i=j=0;univbuffer[i]!=0;i++) {
          if(univbuffer[i]==':') {
            univbuffer[i]=0;
            j++;
          }
        }
        if(j!=7) printf("join: Rejected '%s': does not have 8 fields\n", getfieldno(1,univbuffer));
        else {
          if(*(getfieldno(2,univbuffer))==0) {
            printf("join: %s Warning! %s (%s in %s) has a NULL password!\n","date",getfieldno(1,univbuffer),getfieldno(6,univbuffer),univbuffer);
          } else {
            if(((getfieldno(2,univbuffer))[0]=='*' || (getfieldno(2,univbuffer))[0]=='!' || (getfieldno(2,univbuffer))[0]==' ') && (getfieldno(2,univbuffer))[1]==0) {
              printf("join: %s User %s (in %s) has a locked password:- %s\n","date",getfieldno(1,univbuffer),univbuffer,getfieldno(2,univbuffer));
            } else {
              i=(int)guessable(fbname,getfieldno(1,univbuffer));
              if(i!=0 && i!=-1) {
                if(*(getfieldno(3,univbuffer))=='0') {
                  printf("join: %s Guessed ROOT PASSWORD %s (%s in %s) [%s] %s\n", "date", getfieldno(1,univbuffer), getfieldno(7,univbuffer), univbuffer, guessable(fbname,getfieldno(2,univbuffer)), getfieldno(2,univbuffer));
                } else {
                  printf("join: %s Guessed %s (%s in %s) [%s] %s\n", "date", getfieldno(1,univbuffer), getfieldno(7,univbuffer), univbuffer, guessable(fbname,getfieldno(2,univbuffer)), getfieldno(2,univbuffer));
                }
              } else {
                if(i==0) fprintf(dest,"%s:%s:%s:%s:%s:%s:%s:%s\n",univbuffer,getfieldno(1,univbuffer),getfieldno(2,univbuffer),getfieldno(2,univbuffer),getfieldno(3,univbuffer),getfieldno(4,univbuffer),getfieldno(4,univbuffer),getfieldno(5,univbuffer),getfieldno(6,univbuffer),getfieldno(7,univbuffer));
              }
            }
          }
        }
      }
      fclose(pw);
    }
    fclose(dest);
  }
}
void AddFileName(char *filename,char *outfile)
{
  int i;
  char buffer2[30];
  FILE *fp,*out;

  if(fp=fopen(filename,"r")) {
    if(out=fopen(outfile,"a")) {
      for(i=0;filename[i]!=0 && i<29;i++) {
        if(filename[i]==':') buffer2[i]='/';
        else buffer2[i]=filename[i];
      }
      buffer2[i]=0;
      while(inputline(fp,univbuffer)!=EOF) {
        fprintf(out,"%s:%s\n",buffer2,univbuffer);
      }
      fclose(out);
    }
    fclose(fp);
  }
}
int dojoin(char *argv[],int argc,int first)
{
  FILE *warn;
  char buffer[200];
  char buffer2[200];
  char buffer3[200];
  int i;

  tmpnam(buffer2);
  tmpnam(buffer3);
  sprintf(buffer,"type Runtime/F#? >%s",buffer3);
  system(buffer);
  for(i=first;i<argc;i++) {
    AddFileName(argv[i],buffer2);
  }
  pwsort(buffer2,&pwcmp);
  joinawk(buffer2,buffer3,inputfile);

  return(1);
}
int uniq(char *infilename,char *outfilename)
{
  FILE *in,*out;
  char buffer[2][200];
  char bufno=0;
  int retval=0;

  if(in=fopen(infilename,"r")) {
    if(out=fopen(outfilename,"w")) {
      while(inputline(in,buffer[bufno])!=EOF) {
        if(strcmp(buffer[0],buffer[1])) {
          fprintf(out,"%s\n",buffer[bufno]);
        }
        bufno^=1;
      }
      retval=1;
      fclose(out);
    }
    fclose(in);
  }
  return(retval);
}

void DoDict(void)
{
  FILE *fp,*out;
  char buffer[100],buffer2[100],buffer3[100];

  tmpnam(buffer);
  tmpnam(buffer3);

  sprintf(buffer2,"Type DictSrc/#? >%s",buffer);
  system(buffer2);

/* Remove comments */
  if(fp=fopen(buffer,"r")) {
    if(out=fopen(buffer3,"w")) {
      while(inputline(fp,univbuffer)!=EOF) {
        if(univbuffer[0]!='#') fprintf(out,"%s\n",univbuffer);
      }
      fclose(out);
    }
    fclose(fp);
    remove(buffer);
    pwsort(buffer3,(int (* )(char ** , char ** ))&strcmp);
    if(uniq(buffer3,"Dicts/bigdict")) {
      if(fp=fopen("Dicts/.lockfile","w")) {
        fclose(fp);
      }
    }
    remove(buffer3);
  }
}
int main(int argc,char *argv[])
{
  int i;
  char buffer[200];
  char *CRACKHOME;

  if(getcwd(oldcurdir,200)) {
    if(!(CRACKHOME=getenv("CRACK_HOME"))) {
      printf("Warning: CRACK_HOME not defined. Using current directory.\n");
      CRACKHOME=oldcurdir;
    }
    if(chdir(CRACKHOME)) {
      printf("Fatal error: the directory $CRACK_HOME does not exist.\n");
      printf("\n");
      printf("Please set the value of CRACK_HOME in the 'Crack' script to the name of\n");
      printf("the installation directory.\n");
      printf("\n");
      printf("The current working directory is %s\n",getcwd(buffer,200));
    } else {
      printf("Crack "VERSION", The Password Cracker (c) Alec D.E. Muffett, 1992\n");
      printf("Invoked as:");
      for(i=0;i<argc;i++) {
        printf(" %s",argv[i]);
      }
      printf("\n");
      if(argc<2) {
        printf("Usage:    %s [options] [bindir] passwdfile [...]\n",argv[0]);
        printf("Or:       %s -network [options] passwdfile [...]\n",argv[0]);
        printf("Options:-\n");
        printf("	-v              - to produce verbose output\n");
        printf("	-nnicevalue     - to run niced to 'nicevalue'\n");
        printf("	-rpointfile     - to recover a crashed-out job\n");
        printf("	-Rpointfile     - to recover (with verify) a crashed-out job\n");
/*        printf("	-f		- to run in foreground (output to stdout)\n"); */
        printf("	-m		- to mail the user a warning message if cracked\n");
      } else {
        if(access("Dicts/.lockfile",0)!=0) {
          printf("Making dictionary Dicts/bigdict - This may take some time...\n");
          DoDict();
        } else {
          printf("Dictionary Dicts/* intact\n");
        }
        if(access("Dicts/.lockfile",0)==0) {
          if(!strcmp(argv[1],"-network")) {
            printf("Error: Network Crack is not yet implemented!\n");
          } else {
            for(i=1;i<argc;i++) {
              if(argv[i][0]=='-') {
                if(!strcmp(argv[i],"-network")) {
                  printf("Error: -network (if specified) must be first argument\n");
                  goto theend;
                }
                if(argv[i][1]!='X' && argv[i][1]!='m' && argv[i][1]!='l' && argv[i][1]!='f' && argv[i][1]!='n' && argv[i][1]!='r' && argv[i][1]!='v') {
                  printf("Warning: unknown argument %s",argv[i]);
                }
                if(argv[i][1]=='X')
                  remote=argv[i];
                if(argv[i][1]=='m')
                  domail=argv[i];
                if(argv[i][1]=='l')
                  pwl=argv[i];
                if(argv[i][1]=='f')
                  fgnd=argv[i];
                if(argv[i][1]=='n')
                  nice=argv[i];
                if(argv[i][1]=='r')
                  rcvr=argv[i];
                if(argv[i][1]=='v')
                  verbose=argv[i];
              } else break;
            }
            printf("Sorting data for Crack.\n");
            if(remote!=0) {
              printf("Error: Network Crack not yet implemented\n");
            } else {
              strcpy(outinit,"out.");
              tmpnam(inputfile);
              dojoin(argv,argc,i);
              sprintf(buffer,"generic/crack-pwc");
              if(remote) { strcat(buffer," "); strcat(buffer,remote); }
              strcat(buffer," -f ");
              if(pwl) { strcat(buffer," "); strcat(buffer,pwl); }
              if(nice) { strcat(buffer," "); strcat(buffer,nice); }
              if(rcvr) { strcat(buffer," "); strcat(buffer,rcvr); }
              if(verbose) { strcat(buffer," "); strcat(buffer,verbose); }
              strcat(buffer," -i ");
              strcat(buffer,inputfile);
              strcat(buffer," `list Dicts/~(.lockfile) LFORMAT %p%n`");
              system(buffer);
            }
          }
        }
      }
    }
    theend:
    chdir(oldcurdir);
  }
}