    /*****************************************************

          Fast DES program module
       - Copyright 1991, Christian Beaumont

       This program is free software; you can
       redistribute it and/or modify it as you see fit.

       This program is distributed in the hope that it
       will be useful, but WITHOUT ANY WARRANTY; without
       even the implied warranty of MERCHANTABILITY or
       FITNESS FOR A PARTICULAR PURPOSE.

    *****************************************************/

#include <stdio.h>
#include <alloc.h>
#include <bios.h>
#include <string.h>
#include <dos.h>
#include <io.h>
#include "fdes.h"

#define PMAX    1300

#define VER_MAJ	2
#define VER_MIN 1

int	 catchup = 0;
char  catchword[40];

int    allflag = 1;
char	 u_name[40];

struct passwd2 *p;
int    n;
long   crypts = 0;


void S_Check(char *s)
{
int i;

	setname(s);

	for(i=0; i<n; i++){
		if(p[i].pw_broken == 0){
			if(shortcrypt(p[i].pw_out96,p[i].pw_salt)){
				printf("%s is %s\n",p[i].pw_user,s);
				strncpy(p[i].pw_passwd,s,8);
				p[i].pw_broken = 1;
			}
			crypts++;
		}
	}
}

void A_Check(void)
{
char try[20];
int i;
		
	for(i=0; i<n; i++){
		if(p[i].pw_broken == 0){
			strcpy(try,p[i].pw_user);
			try[8] = '\0';
			setname(try);
			if(shortcrypt(p[i].pw_out96,p[i].pw_salt)){
				printf("%s is %s\n",p[i].pw_user,try);
				strncpy(p[i].pw_passwd,try,8);
				p[i].pw_broken = 1;
			}
			crypts++;
		}
	}

	for(i=0; i<n; i++){
		if(p[i].pw_broken == 0){
			strcpy(try,p[i].pw_user);
			strcat(try,p[i].pw_user);
			try[8] = '\0';
			setname(try);
			if(shortcrypt(p[i].pw_out96,p[i].pw_salt)){
				printf("%s is %s\n",p[i].pw_user,try);
				strncpy(p[i].pw_passwd,try,9);
				p[i].pw_broken = 1;
			}
			crypts++;
		}
	}
}

void U_Check(char *d)
{
FILE *fin;
char	w[40];
char	s[40];
int   i;

	if((fin = fopen(d,"r")) == NULL){
		printf("Could not open file %s (continuing)\n",d);
		return;
	}

	if(catchup != 0){
		while(fgets(s,39,fin) != NULL){
			*strchr(s,'\n') = '\0';
			if(!strcmp(s,catchword))
				goto Resume;
		}
		return;
	}

Resume:

	catchup = 0;

	for(i=0;i<n;i++){
		if(!strcmp(p[i].pw_user,u_name))
			break;
	}

	if(i == n)
		return;

	if(p[i].pw_broken == 1)
		return;

	while(fgets(s,39,fin) != NULL){
		if(s[0] == '\n')
			continue;
		strcpy(w,s);
		*strchr(w,'\n') = '\0';
		w[8] = '\0';
		crypts++;
		setname(w);
		if(shortcrypt(p[i].pw_out96,p[i].pw_salt)){
			printf("%s is %s\n",p[i].pw_user,w);
			strcpy(p[i].pw_passwd,w);
			p[i].pw_broken = 1;
			return;
		}
		if(kbhit()){
			printf("Terminated just after checking %s\n",s);
			return;
		}
	}
}

void F_Check(char *d)
{
FILE *fin;
char	w[40];
char	s[40];
int   i;

	if((fin = fopen(d,"r")) == NULL){
		printf("Could not open file %s (continuing)\n",d);
		return;
	}

	if(catchup != 0){
		while(fgets(s,39,fin) != NULL){
			*strchr(s,'\n') = '\0';
			if(!strcmp(s,catchword))
				goto Resume;
		}
		return;
	}

Resume:

	catchup = 0;

	while(fgets(s,39,fin) != NULL){
		if(s[0] == '\n')
			continue;
		strcpy(w,s);
		*strchr(w,'\n') = '\0';
		w[8] = '\0';
		setname(w);
		for(i=0; i<n; i++){

			if(shortcrypt(p[i].pw_out96,p[i].pw_salt)){
				printf("%s is %s\n",p[i].pw_user,w);
				strcpy(p[i].pw_passwd,w);
				p[i].pw_broken = 1;
			}
			crypts++;
		}
		if(kbhit()){
			printf("Terminated just after checking %s\n",s);
			return;
		}
	}
}

main(int argc,char *argv[])
{
long	time;
int	i,update;
struct passwd *p1;
FILE *fout;
int got=0;

	if(argc < 2){
          printf("\nGUESS: Unix Password Checker [Version %d.%d]\n",
                VER_MAJ,VER_MIN);

        puts("GUESS - Copyright 1991 Christian Beaumont\n"
              "C_BEAUMONT@UK.AC.LUT.HICOM and Sysop of fidonet node 2:250/301\n"
              "THIS IS A BETA TEST VERSION FOR PUBLIC DISTRIBUTION\n"
              "Use: GUESS [PASSWORD_FILE] [[OPTION] [DICTIONARY]] ...\n"
			  "Options are:\n\n"
			  "      -a       Perform algorithmic check of password file\n"
			  "      -cWORD   Catch up to specified word in dictionary\n"
			  "      -sWORD   Check password file against specifed word only\n"
			  "      -uNAME   Limit checking of dictionary to a certain user name\n"
              "      -w       Permit checking of dictionary to all users\n\n"
              "If you find GUESS useful or have any comments please feel free\n"
              "to contact me.\n\n"
              "Christian Beaumont +44-81-883-5683 (home) +44-81-680-1066 (work)\n"
			  );
		return 1;
	}

	printf("Reading password file ... ");

	for(n=0;getpwent(argv[1])!=NULL;n++);

	printf("\nENTRIES  %d\n",n);

	if(n==0)
		return 1;

	if((p = calloc(n,sizeof(struct passwd2))) == NULL){
		printf("Couldn't allocate space for %d entries",PMAX);
		return 1;
	}

	n = 0;
	while((p1 = getpwent(argv[1])) != NULL){
		if(p1->pw_passwd[0] == '='){
			got++;
			continue;
		}
		if(strlen(p1->pw_passwd) != 13)
			continue;
		if(strchr(p1->pw_passwd,'*') != NULL)
			continue;
		strcpy(p[n].pw_user,p1->pw_user);
		p[n].pw_salt = flatten(p1->pw_passwd,p[n].pw_out96);
		p[n].pw_broken = 0;
		p[n].pw_passwd[0] = '\0';
		n++;
	}

	if(n == 0){
		puts("NO ENTRIES READ");
		return 1;
	}

	if(n == PMAX)
		printf("INSUFFICIENT MEMORY TO READ ALL ENTRIES! (CONTINUING)");

	printf("BROKEN   %d\n",got);
	printf("UNBROKEN %d\n",n);
    printf("PERCENT BROKEN  %d\n",(100 * got)/(got + n));

	puts("Initialising tables");
	init_des();

   time = biostime(0,0);

	for(i=2; i<argc; i++){
		if(argv[i][0] != '-'){
			printf("Checking against file %s\n",argv[i]);
			if(allflag == 1)
				F_Check(argv[i]);
			else
				U_Check(argv[i]);
		} else{
			switch(argv[i][1]){
				case 'c' :
					strcpy(catchword,&argv[i][2]);
					puts(catchword);
					catchup = 1;
					break;
				case 'a' :
					puts("Performing algorithmic check");
					A_Check();
					break;
				case 'u'	:
					strcpy(u_name,&argv[i][2]);
					allflag = 0;
					break;
				case 'w' :
					allflag = 1;
					break;
				case 's'	:
					S_Check(&argv[i][2]);
					break;
				default  :
					printf("Unknown option %c\n",argv[i][1]);
			}
		}
	}

   time = biostime(0,0)-time;
	time++;

   printf("%ld guesses in %d seconds (%d guesses/sec %ld clocks)\n",crypts,
														(int)((time*10)/182),
														(int)((crypts*182)/(time*10)),time);

	if((fout = fopen("$$$.pwd","w")) == NULL){
		printf("Couldn't open file %s\n",argv[1]);
		free(p);
		return 1;
	}

	update = 0;
	for(i=0;i<n;i++)
		if(p[i].pw_broken)
			update++;

	if(update == 0){
		free(p);
		return 0;
	}

	i = 0;
	while((p1 = getpwent(argv[1])) != NULL){
		if(i<n){
			if(!strcmp(p1->pw_user,p[i].pw_user)){
				if(p[i].pw_broken){
					strcpy(p1->pw_passwd,"=");
					strcat(p1->pw_passwd,p[i].pw_passwd);
				}
				i++;
			}
		}
		fprintf(fout,"%s:%s:%d:%d:%s:%s:%s\n",p1->pw_user,p1->pw_passwd,
			p1->pw_uid,p1->pw_gid,p1->pw_gecos,p1->pw_dir,p1->pw_shell);
	}

	fclose(fout);

	free(p);

	unlink(argv[1]);
	rename("$$$.pwd",argv[1]);

	return 0;
}



