roh/conf/area/
roh/game/talk/
roh/help/
roh/monsters/ocean/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.44b/
/*
 * security.cpp
 *	 Security related functions
 *   ____            _               
 *  |  _ \ ___  __ _| |_ __ ___  ___ 
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *  
 * 	Copyright (C) 2007-2009 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
//#include <stdio.h>
//#include <sys/types.h>
//#include <ctype.h>
//#include <stdarg.h>

#include "mud.h"
//#include "math.h"
//#include "socket.h"
#include "login.h"

bstring Player::hashPassword(bstring pass) {
	// implement md5 or sha1 here if you want 
	return(pass);
}

bstring Player::getPassword() const {
	return(password);
}

bool Player::isPassword(bstring pass) const {
	return(password == hashPassword(pass));
}

void Player::setPassword(bstring pass) {
	lastPassword = password;
	password = hashPassword(pass);
}

const char *passCriteria =
    "Passwords must meet the following criteria:\n"
    "1) Must be from %d to %d characters in length.\n"
    "2) Must contain at least 2 letters.\n"
    "3) Must contain at least 2 numbers or special characters.\n"
    "4) Must contain no leading or trailing spaces.\n";


bool isValidPassword(Socket* sock, char *pass) {
	int			len=0, alpha=0, i=0, digits=0, special=0;

	if(!sock)
		return(false);

	len = strlen(pass);

	if(pass[0] == ' ') {
		sock->print("No leading spaces allowed.\n\n");
		sock->print(passCriteria, PASSWORD_MIN_LENGTH, PASSWORD_MAX_LENGTH);
		return(false);
	}

	if(pass[len-1] == ' ') {
		sock->print("No trailing spaces allowed.\n\n");
		sock->print(passCriteria, PASSWORD_MIN_LENGTH, PASSWORD_MAX_LENGTH);
		return(false);
	}

	if(len < PASSWORD_MIN_LENGTH) {
		sock->print("Too short.\n\n");
		sock->print(passCriteria, PASSWORD_MIN_LENGTH, PASSWORD_MAX_LENGTH);
		return(false);
	}

	if(len > PASSWORD_MAX_LENGTH) {
		sock->print("Too long.\n\n");
		sock->print(passCriteria, PASSWORD_MIN_LENGTH, PASSWORD_MAX_LENGTH);
		return(false);
	}

	for(i=0; i<len; i++) {
		if(isalpha(pass[i]))
			alpha++;
		if(isdigit(pass[i]))
			digits++;
		if(!isalpha(pass[i]) && !isdigit(pass[i]))
			special++;
	}

	if(alpha < 2) {
		sock->print("Not enough letters.\n\n");
		sock->print(passCriteria, PASSWORD_MIN_LENGTH, PASSWORD_MAX_LENGTH);
		return(false);
	}

	if(digits + special < 2) {
		sock->print("Not enough numbers or special characters.\n\n");
		sock->print(passCriteria, PASSWORD_MIN_LENGTH, PASSWORD_MAX_LENGTH);
		return(false);
	}

	return(true);
}

//*********************************************************************
//						cmdPassword
//*********************************************************************
// This function cllls the function to allow
// a player to change their password.

int cmdPassword(Player* player, cmd* cmnd) {
	player->clearFlag(P_AFK);
	if(player->isBraindead()) {
		player->print("You are brain-dead. You can't do that.\n");
		return(0);
	}

	// do not flash output until player hits return
	player->setFlag(P_READING_FILE);
	player->print("%c%c%c\n\r", 255, 251, 1);
	player->print("Current password: ");
	gServer->processOutput();
	//    sock->intrpt &= ~1;
	player->getSock()->setState(CON_CHANGE_PASSWORD);
	return(0);
}

//*********************************************************************
//						changePassword
//*********************************************************************
// This command handles the procedure involved in
// changing a player's password. A player first must enter the 
// correct current password, then the new password, and re enter
// the new password to comfirm it.If the player enters the
// wrong password  or an invalid password (too short or long),
// the password will not be changed and the procedure is aborted.

void changePassword(Socket* sock, char *str ) {
	Player* player = sock->getPlayer();
	gServer->processOutput();

	switch (sock->getState()) {
	case CON_CHANGE_PASSWORD:
		if(player->isPassword(str)) {
			sock->print("%c%c%c\n\r", 255, 251, 1);
			sock->print("New password: ");
			gServer->processOutput();
			sock->intrpt &= ~1;
			player->getSock()->setState(CON_CHANGE_PASSWORD_GET_NEW);
			return;
			//			(fd,changePassword,2);
		} else {
			sock->print("%c%c%c\n\r", 255, 252, 1);
			sock->print("Incorrect password.\n");
			sock->print("Aborting.\n");
			player->clearFlag(P_READING_FILE);
			player->getSock()->setState(CON_PLAYING);
			return;
		}
	case CON_CHANGE_PASSWORD_GET_NEW:
		if(!isValidPassword(sock, str)) {
			sock->print("%c%c%c\n\r", 255, 252, 1);
			sock->print("Aborting.\n");
			player->clearFlag(P_READING_FILE);
			player->getSock()->setState(CON_PLAYING);
			return;
		} else {
			strcpy(sock->tempstr[1], str);
			sock->print("%c%c%c\n\r", 255, 251, 1);
			sock->print("Re-enter password: ");
			gServer->processOutput();
			sock->intrpt &= ~1;
			player->getSock()->setState(CON_CHANGE_PASSWORD_FINISH);
			return;
		}
		break;
	case CON_CHANGE_PASSWORD_FINISH:
		sock->print("%c%c%c\n\r", 255, 252, 1);
		if(!strcmp(sock->tempstr[1],str)) {

			if(!player->isCt())
				logn("log.passwd", "(%s)\n   %s changed %s password. Old: %s New: %s\n", player->getSock()->getHostname().c_str(),
				     player->name, player->hisHer(), player->getPassword().c_str(), sock->tempstr[1]);
			player->setPassword(str);

			sock->print("Password changed.\n");
			broadcast(isDm, "^g%s just changed %s password.", player->name, player->hisHer());

			player->clearFlag(P_READING_FILE);
			player->setFlag(P_PASSWORD_CURRENT);
			player->save(true);
		} else {
			sock->print("Different passwords given.\n");
			sock->print("Aborting.\n");
			player->clearFlag(P_READING_FILE);
		}
		player->getSock()->setState(CON_PLAYING);
		return;
	}
}