/* * bans.cpp * Various functions to ban a person from the mud * ____ _ * | _ \ ___ __ _| |_ __ ___ ___ * | |_) / _ \/ _` | | '_ ` _ \/ __| * | _ < __/ (_| | | | | | | \__ \ * |_| \_\___|\__,_|_|_| |_| |_|___/ * * 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 * */ // C++ Includes //#include <sstream> //#include <iostream> // C Includes //#include <string.h> //#include <stdlib.h> //#include <libxml/xmlmemory.h> //#include <libxml/parser.h> // Mud Includes #include "mud.h" #include "bans.h" Ban::Ban() { reset(); } void Ban::reset() { site = ""; by = ""; time = ""; reason = ""; password = ""; duration = unbanTime = 0; isPrefix = isSuffix = false; } bool Ban::matches(const char* toMatch) { if(site == "*") return(true); else if(isPrefix && isSuffix && strstr(toMatch, site.c_str())) return(true); else if(isPrefix && strPrefix(toMatch, site.c_str())) return(true); else if(isSuffix && strSuffix(toMatch, site.c_str())) return(true); else if(!strcmp(toMatch, site.c_str())) return(true); return(false); } int dmListbans(Player* player, cmd* cmnd) { int found=0; std::ostringstream banStr; banStr << "Current bans:\n"; std::list<Ban*>::iterator it; Ban* ban; for(it = gConfig->bans.begin() ; it != gConfig->bans.end() ; it++) { found++; ban = (*it); banStr << "^c#" << found; banStr << "^xSite: "; if(ban->site[0] == '\0') banStr << "^CEveryone! "; else { banStr << "^C"; if(ban->isSuffix) banStr << "*"; banStr << ban->site; if(ban->isPrefix) banStr << "*"; } banStr << "^XDuration: "; if(ban->duration <= 0) banStr << "Indefinite "; else banStr << ban->duration << " Day(s) "; banStr << "^wBanned by: "; banStr << "^c" << ban->by << "\n"; banStr << " ^wBan Time: "; banStr << "^c" << ban->time << " "; banStr << "^wExpires: "; if(ban->unbanTime) banStr << "^g" << ctime(&ban->unbanTime); else banStr << "^gNever!\n"; banStr << " ^wPassword: "; if(ban->password == "") banStr << "None. "; else { banStr << "^c" << ban->password << " "; } banStr << "^wBan Reason: "; banStr << "^c" << ban->reason << "^x\n\n"; } bstring toPrint = banStr.str(); player->printColor("%s", toPrint.c_str()); if(!found) player->print("No bans!\n"); else player->print("%d Ban(s) found\n", found); return(0); } /* * Unused, apparently. * int dmLoadbans(Creature* player, cmd* cmnd) { if(!player->isDm()) return(PROMPT); gConfig->loadBans(); player->print("Bans reloaded.\n"); dmListbans(player, NULL); return(0); } int dmSavebans(Creature* player, cmd* cmnd) { gConfig->saveBans(); player->print("Bans saved.\n"); return(0); } */ int dmBan(Player* player, cmd* cmnd) { Player* target=0; int i=0, j=0, strLen, len, dur, iTmp = 0; int isPrefix = 0, isSuffix = 0; char *pass=0; char log[128], log2[128], log3[128], log4[128]; Ban* newBan; char str[255], who[255], site[255], comment[255]; long t; strcpy(log,""); strcpy(log2,""); strcpy(log3,""); strcpy(log4,""); strLen = cmnd->fullstr.length(); // This kills all leading whitespace while(i<strLen && isspace(cmnd->fullstr[i])) i++; // This kills the command itself while(i<strLen && !isspace(cmnd->fullstr[i])) i++; // This kills all the white space before the who while(i<strLen && isspace(cmnd->fullstr[i])) i++; len = strlen(&cmnd->fullstr[i]); if(!len) { dmListbans(player, NULL); //player->print("Syntax: *ban <player/site> [dur] [comment] [-p [password]]\n"); return(0); } // This finds out how long the who is while(i+j < strLen && isgraph(cmnd->fullstr[i+j])) j++; memcpy(who, &cmnd->fullstr[i], j); who[j] = '\0'; strcpy(site, who); lowercize(who, 1); target = gServer->findPlayer(who); if(!target || target == player) { if((!strstr(site, "*") && !strstr(site, ".")) || !player->isDm()) { player->print("%s is not on.\n", who); return(0); } } i = i+j; j=0; len = strlen(&cmnd->fullstr[i+1]); if(!len) dur = 0; else { // See if we have a password pass = strstr(&cmnd->fullstr[i], "-p "); if(pass) { // There is a password string then iTmp = i; while(iTmp < strLen && &cmnd->fullstr[iTmp] != pass) iTmp++; pass += 3; while(isspace(*pass)) pass++; // Kill trailing whitespace len = strlen(pass); while(isspace(pass[len-1])) len--; pass[len] = '\0'; } if(iTmp) { // We have a password, everything else stops at the beginging of the -p strLen = iTmp; cmnd->fullstr[iTmp] = '\0'; } // Kill white space while(i < strLen && isspace(cmnd->fullstr[i])) i++; // Find length of the str while(i+j < strLen && isgraph(cmnd->fullstr[i+j])) j++; memcpy(str, &cmnd->fullstr[i], j); str[j] = '\0'; // If its a digit, assume its the length of the ban, otherwise no length // was specified, assume indefinite, and use the rest of the str as the // comment. if(isdigit(str[0])) { dur = atoi(str); // Anything less than 0 becomes 0 (indefinite) anything greater than // 1825 (5 years) becomes 1825 dur = MAX(MIN(dur, 1825), 0); i=i+j; // Kill all whitespace before the comment while(i < strLen && isspace(cmnd->fullstr[i])) i++; } else dur = 0; } strcpy(comment, &cmnd->fullstr[i]); // Kill trailling whitespace on comment len = strlen(comment); while(isspace(comment[len-1])) len--; comment[len] = '\0'; if(target) { if(target->getClass() > BUILDER) { player->print("You can't ban staff! Dumbass.\n"); target->printColor("^r%s tried to siteban you! Kill %s!\n", player->getCName(), player->himHer()); return(0); } } if(!strlen(comment) && !player->isDm()) { player->print("You must give a reason for banning someone.\n"); return(0); } if(target) strcpy(site, target->getSock()->getHostname().c_str()); if(strlen(site) > 1) { if(site[0] == '*') { isSuffix = 1; memmove(&site[0], &site[1], strlen(site)); } if(site[strlen(site) - 1] == '*') { isPrefix = 1; site[strlen(site) - 1] = '\0'; } } if(gConfig->isBanned(site)) { player->print("The address '%s' is already banned.\n", site); return(0); } newBan = new Ban; // The site of the ban newBan->site = site; // Prefix or Suffix? if(isPrefix == 1) newBan->isPrefix = 1; if(isSuffix == 1) newBan->isSuffix = 1; // Who set the ban newBan->by = player->getName(); // Set the ban duration newBan->duration = dur; // Set the ban reason if(strlen(comment)) newBan->reason = comment; else newBan->reason = "No reason given"; // Set the ban time t = time(0); char *timeStr = strdup((char *)ctime(&t)); timeStr[strlen(timeStr)-1] = '\0'; // Get rid of the '\n' newBan->time = timeStr; free(timeStr); if(newBan->duration > 0)// NOW + # of days * # of seconds in a day newBan->unbanTime = time(0) + ((long)newBan->duration * 60*60*24L); // Set the password if(pass) newBan->password = pass; gConfig->addBan(newBan); if(target) sprintf(log, "%s (%s) has been banned", who, newBan->site.c_str()); else sprintf(log, "'%s' has been banned", site); if(dur > 0) sprintf(log2, " for %d day(s) by %s.", newBan->duration, player->getCName()); else sprintf(log2, " indefinitely."); if(newBan->reason != "") sprintf(log3, " Reason: '%s' by %s.", newBan->reason.c_str(), player->getCName()); if(newBan->password != "") sprintf(log4, " Password: '%s'.\n", newBan->password.c_str()); else sprintf(log4, "\n"); strcat(log, log2); strcat(log, log3); strcat(log, log4); log_immort(true, player, "%s", log); logn("log.bans", "%s: %s", player->getCName(), log); gConfig->saveBans(); if(target) { char tmpBuf[1024]; sprintf(tmpBuf, "\n\rThe watcher just arrived.\n\rThe watcher says, \"Begone from this place!\".\n\rThe watcher banishes your soul from this world.\n\r\n\r\n\r"); target->getSock()->write(tmpBuf); target->getSock()->disconnect(); } else { // Determine who's effected by the siteban and drop them *excluding staff* gServer->checkBans(); } return(0); } void Server::checkBans() { static const char* banString = "\n\rThe watcher just arrived.\n\rThe watcher says, \"Begone from this place!\".\n\rThe watcher banishes your soul from this world.\n\r\n\r\n\r"; for(Socket* sock : sockets) { if(sock->getPlayer() && (gConfig->isBanned(sock->getIp().c_str()) || gConfig->isBanned(sock->getHostname().c_str()))) { if(sock->getPlayer()->getClass() <= BUILDER) { sock->write(banString); sock->disconnect(); } } } } int dmUnban(Player* player, cmd* cmnd) { int toDel = 0, i; // Kill any trailing white space in the fullstr i = cmnd->fullstr.length(); while(isspace(cmnd->fullstr[i-1])) i--; cmnd->fullstr[i] = '\0'; // We need a number with the command! if(!strncasecmp(cmnd->fullstr.c_str(), "*unban", i)) toDel = -1; else toDel = cmnd->val[0]; if(toDel <= 0) { player->print("What ban would you like lifted?\n"); return(0); } if(gConfig->deleteBan(toDel)) { player->print("Ban #%d successfully deleted.\n", toDel); gConfig->saveBans(); } else player->print("Ban #%d could not be deleted\n", toDel); return(0); } //********************************************************************* // Misc commands to add new bans, free bans, delete bans and the like //********************************************************************* bool Config::addBan(Ban* toAdd) { bans.push_back(toAdd); return(true); } bool Config::deleteBan(int toDel) { std::list<Ban*>::iterator it; int count=0; for(it = bans.begin() ; it != bans.end() ; it++) { count++; if(count == toDel) { // We've found the clan to delete, now remove it from the list Ban* ban = (*it); bans.erase(it); delete ban; return(true); } } return(false); } //*************************** // isLockedOut //*************************** // This function determines if the player on socket number, fd, is on // a site that is being locked out. If the site is password locked, // then 2 is returned. If it's completely locked, 1 is returned. If // it's not locked out at all, 0 is returned. int Config::isLockedOut( Socket* sock ) { int match=0, count=0; char site[80]; char ip[40]; strncpy(site, sock->getHostname().c_str(), 80); strncpy(ip, sock->getIp().c_str(), 40); site[79] = 0; ip[39] = 0; std::list<Ban*>::iterator it; Ban* ban; for(it = gConfig->bans.begin() ; it != gConfig->bans.end() ; it++) { count++; ban = (*it); // Better safe than sorry if(!ban) continue; if(ban->matches(site) || ban->matches(ip)) { match = 1; break; } } if(match) { if(ban->unbanTime != 0 && time(0) > ban->unbanTime) { // Ban has expired so delete it broadcast(isCt, "^y--- Expiring ban for '%s'", ban->site.c_str()); gConfig->deleteBan(count); gConfig->saveBans(); // See if they're effected by another ban return(isLockedOut(sock)); } if(ban->password != "") { strcpy(sock->tempstr[0], ban->password.c_str()); return (2); } else { char buf[1024]; sprintf(buf, "\n\rYour site is locked out.\n\rSend questions to %s.\n\r", questions_to_email); sock->write(buf); broadcast(isCt, "^yDenying access to '%s(%s)'", sock->getHostname().c_str(), ban->site.c_str()); return(1); } } return(0); } // Returns 1 if the site is on the ban list, 0 otherwise bool Config::isBanned(const char *site) { std::list<Ban*>::iterator it; Ban* ban; for(it = gConfig->bans.begin() ; it != gConfig->bans.end() ; it++) { ban = (*it); // Better safe than sorry if(!ban) continue; if(ban->matches(site)) return(true); } return (false); } // Clears bans void Config::clearBanList() { Ban* ban; while(!bans.empty()) { ban = bans.front(); delete ban; bans.pop_front(); } bans.clear(); }