/*

	This program is a good example of buffer overflow attack that corrupts 
	data (password) without modifying the address of the variable that stores it.
	
	The program accepts user name as input and loads the stored encrypted password 
	into a buffer. When the user enters a password that is longer than 8 characters, 
	it overwrittes the system password. Thus creating a window of opportunity for 
	a hacker to break into the system.

    The valid usernames and passwords can be found in the init_list function.

	The program uses Caeser Cipher where the shift is 3. 
	For example a,b,c will be d,e,f.. so on and x,y,z will be a,b,c.

 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <cstdlib> 


// defines how long the username/password should be. For a unix system, the length is 8.
#define MAXLENGTH 8

// increase this if more users are added to this system.
#define LISTLENGTH 5


/*
Structure used to store the list of user names 
and their corresponding passwords. More names can be added
by increasing the array length.
*/
struct usrlst {
	char *unames[10];
	char *passwd[10];
};


//Function prototypes
void init_list(struct usrlst *u);
int get_indx(char *pch, struct usrlst *u);
void encode_passwd(const char *, char *);


/* 
The main program.
*/
int main (void) {
	
	struct usrlst usr;
	
	int i=0, pass_indx=-2;
	char ch_tmp='\0';
	// keep the length of the string one greater than the MAXLENGTH to accomodate the '\0' character at the end.
	char buffer[4][MAXLENGTH+1];
	char *usrname, *usrpasswd, *sys_enc_pass, *usr_enc_pass;

    usrname = buffer[0];
	usrpasswd = buffer[1];
	sys_enc_pass = buffer[2];
	usr_enc_pass = buffer[3];
	

	//printf("<%p>,<%p>,<%p>,<%p>\n",&usrname[0],&usrpasswd[0],&sys_enc_pass[0],&usr_enc_pass[0]);
	printf("Password table is shown as below:\n");
	printf("Username \t\t Password \t     Encrypted Password\n");
	printf("  joe \t\t\t ilovemsu \t\t loryhpvx\n");
	printf("  bob \t\t\t manitoba \t\t pdqlwred\n");
	printf("  john \t\t\t inbombay \t\t lperpedb\n");
	printf("  marc \t\t\t hiobiwan \t\t klrelzdq\n");
	printf("  alice \t\t cometous \t\t frphwrxv\n");
	
	init_list(&usr);
	
	
	printf("Please enter your username (lowercase): ");
	gets(usrname);
	
	if(strlen(usrname)>0)
		pass_indx = get_indx(usrname, &usr);
	else
		printf("You entered an invalid username.\nPlease try again.\nGoodbye!!\n");

	if(pass_indx >= 0){
		
		strcpy( sys_enc_pass, usr.passwd[pass_indx] );
		
		//printf("The sys passwd is: %s\n",sys_enc_pass);		

		printf("Please enter the password for user %s: ", usrname);

		ch_tmp='\0';
		i=0;

		for (;;){
			ch_tmp = getch();
			if(i==MAXLENGTH){
				usrpasswd[i] = '\0';
				i++;
			}
			if(ch_tmp=='\r'){
				printf("\n");
				break;
			}
			usrpasswd[i]=ch_tmp;
			//putchar(ch_tmp); //uncomment this if you want to echo the password on the screen
			putchar('*');      //comment this if you want to see the password instead of *
			i++;
		}

		//printf("The password you entered is: %s\n", usrpasswd);
			
		encode_passwd(usrpasswd, usr_enc_pass);
		
		printf("<%s>,<%s>,<%s>,<%s>\n",usrname,usrpasswd,sys_enc_pass,usr_enc_pass);

		if( !strcmp( usr_enc_pass, sys_enc_pass ) ){
			printf("Thank you, your password has been accepted.\nWelcome!!\n");
		}
		else{
			printf("Sorry, your password was not accepted.\nPlease try again.\nGoodbye!!\n");
		}
	}
	system("pause"); 	
	return 0;
}


/*
Encrypt the user entered password and return the caeser cipher back.
The substitution is simply to replace an alphabet with a letter 
standing three places down the alphabet. 
Also note, the replacement alphabets wrap around viz: z->c
*/
void encode_passwd(const char* s, char *r){
	
	int i, ch;

    for(i=0; i<MAXLENGTH; i++){
		ch = s[i] + 3;
		if ( ch > 122 )
			ch -= 26;
		r[i] = ch;
	}

	r[MAXLENGTH] = '\0';

}


/* 
check if the username exists in the database.
if does, get the index of its corresponding password.
return -1 if the username is not found.
*/
int get_indx(char *pch, struct usrlst *u){
	
	int i;
	
	for (i=0; i<LISTLENGTH; i++){
		if(!strcmp(pch, u->unames[i]))
			break;
	}
	if(i<LISTLENGTH)
		return i;
	else{
		printf("The username %s not found in database.\nPlease try again.\nGoodbye!!\n", pch);
		return -1;
	}
}


/* 
store all the usernames and passwords in the usrlst structure.
*/
void init_list(struct usrlst *u){
	
	u->unames[0]="joe";   u->passwd[0]="loryhpvx";  //ilovemsu
	u->unames[1]="bob";   u->passwd[1]="pdqlwred";  //manitoba	
	u->unames[2]="john";  u->passwd[2]="lqerpedb";  //inbombay
	u->unames[3]="marc";  u->passwd[3]="klrelzdq";  //hiobiwan
	u->unames[4]="alice"; u->passwd[4]="frphwrxv";  //cometous
	
}


