#include <mpi.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "mpi_crack.h"

static void	master();
static void	slave();
static char 	words[100];
static char 	hash[20];
static char	buf[100];
static int	checked;

int main(argc,argv)
int	argc;
char	*argv[];
{
	int	myrank;

	if (argc!=3){
		printf("mpi_crack-0.01: jmggarcia@infosel.net.mx\n\n");
		printf("Usage: %s [HASH] [WORDLIST]\n", argv[0]);
		exit(1);
	}
	strcpy(hash, argv[1]);
	strcpy(words,argv[2]);

	MPI_Init(&argc, &argv);
	MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
	if(myrank==0) {
		master();
	} else {
		slave();
	}
	MPI_Finalize();
	return(0);
}

static void master()
{
	int		ntasks, rank, size;
	MPI_Status	status;
	FILE *		fp;


	if ((fp=fopen(words,"ro"))==NULL)
		{
		 printf("Can't open wordlist file, %s\n",words);
		 exit(1);
		};

	MPI_Comm_size(MPI_COMM_WORLD, &ntasks);

	/*
         * Seed the slaves
	 */
	for(rank=1;rank<ntasks;++rank)
		MPI_Send(hash,strlen(hash),MPI_CHAR,rank,
				HASH_VALUE,MPI_COMM_WORLD);

	/*
	 * Receive a result from any slave and dispatch a new work
	 * request until work requests have been exhausted.
	 */
	while(!feof(fp)) {
		memset(buf,0,100);
		MPI_Recv(buf,
			100,
			MPI_CHAR,
			MPI_ANY_SOURCE,
			MPI_ANY_TAG,
			MPI_COMM_WORLD,
			&status);

		switch(status.MPI_TAG){
			case CONFIRMATION:
				printf("Word: %s\n",buf);
				for(rank=1; rank < ntasks; ++rank)
					MPI_Send(0,0,MPI_INT, rank,
						DIETAG,MPI_COMM_WORLD);
				exit;
				break;
			case WORD_REQUEST:
				/* printf("Give next word to %x\n",
					status.MPI_SOURCE); */
				memset(buf,0,100);
				fscanf(fp,"%s\n",buf);
				MPI_Send(buf, strlen(buf), MPI_CHAR,
					status.MPI_SOURCE, WORKTAG,
					MPI_COMM_WORLD);
				break;
		}
	}
	/*
	 * Tell all the slaves to exit
	 */
	for(rank=1; rank < ntasks; ++rank)
		MPI_Send(0,0,MPI_INT, rank, DIETAG, MPI_COMM_WORLD);
	printf("Good password - couldn't guess...\n");
}

static void slave()
{
	int		size;
	MPI_Status	status;
	char		hash[100];
	char 		salt[2];

	memset(hash,0,100);
	MPI_Recv(hash,100,MPI_CHAR,0,HASH_VALUE,MPI_COMM_WORLD, &status);
	strncpy(salt,hash,2);
	if (status.MPI_TAG == DIETAG) {
		return;
	}

	for(;;){
		MPI_Send(0,0,MPI_INT,0,WORD_REQUEST,MPI_COMM_WORLD);
		memset(buf,0,100);
		MPI_Recv(buf, 100, MPI_CHAR, 0, MPI_ANY_TAG,
			MPI_COMM_WORLD, &status);
	/*
	 * Check the tag of the received message.
	 */

		if (status.MPI_TAG == DIETAG) {
			return;
		}
		if(crack(buf,salt,hash)!=0)
		{
		  MPI_Send(buf,100,MPI_CHAR,0,CONFIRMATION,
					MPI_COMM_WORLD);
		}
	}
}


crack (char *buff, char *salt, char *hash)
{
int i;

checked++;
if (strcmp((const char *)crypt (buff, salt), hash) == 0)
        {
        /* send confirm here */
		strcpy (buf, buff);
	return checked;
        }


for (i = 0; i < strlen(buff); i++)
	{
	buff[i] = toupper (buff[i]);
	checked++;
	if (strcmp((const char *)crypt (buff, salt), hash) == 0)
        	{
		strcpy (buf, buff);
	        return checked;
		}
	buff[i] = tolower (buff[i]);
	}

for (i = 0; i < strlen(buff); i++)
	{
	buff[i] = toupper (buff[i]);
	checked++;
	if (strcmp((const char *)crypt (buff, salt), hash) == 0)
        	{
		strcpy (buf, buff);
	        return checked;
		}
	}

for (i = 0; i < strlen(buff); i++)
	{
	buff[i] = tolower (buff[i]);
	
	checked++;
	if (strcmp((const char *)crypt (buff, salt), hash) == 0)
        	{
		strcpy (buf, buff);
	        return checked;
		}
	buff[i] = toupper (buff[i]);

	}


for (i = 0; i < strlen(buff); i++)
	{
	tolower (buff[i]);
	checked++;
	if (strcmp((const char *)crypt (buff, salt), hash) == 0)
        	{
		strcpy (buf, buff);
	        return checked;
		}
	toupper (buff[i]);
	}

/* not found, return here */
return 0;

}
