/* * 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-2012 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, bstring pass) { int len=0, alpha=0, i=0, digits=0, special=0; if(!sock) return(false); len = pass.length(); 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); } if(player->getProxyName() != "") { player->print("You are unable to change the password of a proxied character.\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, bstring 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 { strncpy(sock->tempstr[1], str.c_str(), 255); sock->tempstr[1][255] = '\0'; 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(str.equals(sock->tempstr[1])) { if(!player->isCt()) logn("log.passwd", "(%s)\n %s changed %s password. Old: %s New: %s\n", player->getSock()->getHostname().c_str(), player->getCName(), 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->getCName(), 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; } }