gnuworld/mod.ccontrol/ccontrol.cc

6236 lines
147 KiB
C++

/**
* ccontrol.cc
* Main ccontrol implementation class
*
* @author Daniel Karrels dan@karrels.com
* @author Tomer Cohen MrBean@Undernet.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*
* $Id: ccontrol.cc,v 1.243 2010/09/12 20:28:24 hidden1 Exp $
*/
#define MAJORVER "1"
#define MINORVER "2pl7"
#define RELDATE "05th April, 2012"
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <list>
#include <new>
#include <string>
#include <sstream>
#include <vector>
#include <iostream>
#include <algorithm>
#include <fstream>
#include <cstring>
#include <csignal>
#include <cstdio>
#include <cerrno>
#include "client.h"
#include "iClient.h"
#include "EConfig.h"
#include "events.h"
#include "StringTokenizer.h"
#include "misc.h"
#include "Network.h"
#include "ELog.h"
#include "ccUser.h"
#include "dbHandle.h"
#include "ccontrol.h"
#include "server.h"
#include "Constants.h"
#include "commLevels.h"
#include "ccFloodData.h"
#include "ccUserData.h"
#include "ip.h"
#include "ccontrol_generic.h"
#include "gnuworld_config.h"
RCSTAG( "$Id: ccontrol.cc,v 1.243 2010/09/12 20:28:24 hidden1 Exp $" ) ;
namespace gnuworld
{
using std::ends ;
using std::stringstream ;
using std::string ;
using std::vector ;
using std::cout ;
using std::endl ;
using std::count ;
namespace uworld
{
using namespace std;
/**
* Exported function used by moduleLoader to gain an
* instance of this module.
*/
extern "C"
{
xClient* _gnuwinit(const string& args)
{
return new ccontrol( args );
}
}
bool dbConnected = false;
ccontrol::ccontrol( const string& configFileName )
: xClient( configFileName )
{
elog << "Initializing ccontrol version "
<< MAJORVER << "." << MINORVER
<< " please standby... " << endl;
myHub = 0;
ccHub = 0;
// Read the config file
EConfig conf( configFileName ) ;
sqlHost = conf.Find("sql_host" )->second;
sqlDb = conf.Find( "sql_db" )->second;
sqlPort = conf.Find( "sql_port" )->second;
sqlPass = conf.Require( "sql_pass" )->second;
sqlUser = conf.Require( "sql_user" )->second;
inBurst = true;
inRefresh = false;
string Query = "host=" + sqlHost + " dbname=" + sqlDb + " port=" + sqlPort;
if (strcasecmp(sqlUser,"''"))
{
Query += (" user=" + sqlUser);
}
if (strcasecmp(sqlPass,"''"))
{
Query += (" password=" + sqlPass);
}
elog << Query
<< endl ;
elog << "ccontrol::ccontrol> Attempting to connect to "
<< sqlHost
<< "; Database: "
<< sqlDb
<< endl;
SQLDb = new dbHandle( sqlHost,
::atoi( sqlPort.c_str() ),
sqlDb,
sqlUser,
sqlPass ) ;
//(std::nothrow) cmDatabase( Query.c_str() ) ;
assert( SQLDb != 0 ) ;
//-- Make sure we connected to the SQL database; if
// we didn't we exit entirely.
if (SQLDb->ConnectionBad ())
{
elog << "ccontrol::ccontrol> Unable to connect to SQL server."
<< endl
<< "ccontrol::ccontrol> PostgreSQL error message: "
<< SQLDb->ErrorMessage()
<< endl ;
::exit( 0 ) ;
}
else
{
elog << "ccontrol::ccontrol> Connection established to SQL "
<< endl ;
}
dbConnected = true;
// operChanReason is the reason used when kicking non-opers from
// oper-only channels
operChanReason = conf.Find( "operchanreason" )->second ;
// operChanModes are the modes to set when setting up an oper-only
// channel
operChanModes = conf.Find( "operchanmodes" )->second ;
// Number of channels to show with list channels command
maxListChannels = atoi( conf.Find( "maxlistchannels" )->second.c_str() ) ;
// gLength is the length of time (in seconds) for default glines
gLength = atoi( conf.Find( "glength" )->second.c_str() ) ;
// CCEmail is the email ccontrol will post the last com report under
CCEmail = conf.Require( "ccemail" )->second;
//AbuseMail is the mail that the lastcom report will be post to
AbuseMail = conf.Require( "abuse_mail" )->second;
//GLInterval is the inteval in which ccontrol will check for expired glines
ExpiredInterval = atoi( conf.Require( "Expired_interval" )->second.c_str() );
//Sendmail is the full path of the sendmail program
Sendmail_Path = conf.Require("SendMail")->second;
//SendReport flag that tells ccontrol if the user want the report to be mailed
SendReport = atoi(conf.Require("mail_report")->second.c_str());
maxThreads = atoi(conf.Require("max_threads")->second.c_str());
checkClones = atoi(conf.Require("check_clones")->second.c_str());
showCGIpsInLogs = atoi(conf.Require("showCGIpsInLogs")->second.c_str());
dbConnectionTimer = atoi(conf.Require("dbinterval")->second.c_str());
AnnounceNick = conf.Require("AnnounceNick")->second;
// Set up the oper channels
EConfig::const_iterator ptr = conf.Find( "operchan" ) ;
while( ptr != conf.end() && ptr->first == "operchan" )
{
operChans.push_back( ptr->second ) ;
++ptr ;
}
// Read out the client's message channel
msgChan = conf.Find( "msgchan" )->second ;
// Make sure that the msgChan is in the list of operchans
if( operChans.end() == find( operChans.begin(), operChans.end(), msgChan ) )
{
// Not found, add it to the list of operChans
operChans.push_back( msgChan ) ;
}
// Be sure to use all capital letters for the command name
RegisterCommand( new HELPCommand( this, "HELP", "[topic]"
"\t\tObtain general help or help for a specific command",
true,
commandLevel::flg_HELP,
false,
false,
true,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new INVITECommand( this, "INVITE", "<#channel> "
"\t\tRequest an invitation to a channel",
false,
commandLevel::flg_INVITE,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new JUPECommand( this, "JUPE", "<servername> <reason> "
"Jupe a server for the given reason.",
false,
commandLevel::flg_JUPE,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new MODECommand( this, "MODE", "<channel> <modes> "
"Change modes on the given channel",
false,
commandLevel::flg_MODE,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new SCHANGLINECommand( this, "SCHANGLINE",
"[-u] <#channel> <duration>[time units (s,d,h)] <reason> "
"Gline a given channel for the given reason",
true,
commandLevel::flg_SCHANGLINE,
false,
true,
false,
operLevel::CODERLEVEL,
true ) ) ;
RegisterCommand( new FORCECHANGLINECommand( this, "FORCECHANGLINE",
"[-u] <#channel> <duration>[time units (s,d,h)] <reason> "
"Gline a given channel for the given reason",
true,
commandLevel::flg_FORCECHANGLINE,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new GLINECommand( this, "GLINE",
"<user@host> <duration>[time units (s,d,h)] <reason> "
"Gline a given user@host for the given reason",
true,
commandLevel::flg_GLINE,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new SCANGLINECommand( this, "SCANGLINE", "<mask> "
"Search current network glines for glines matching <mask>",
false,
commandLevel::flg_SCGLINE,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new REMGLINECommand( this, "REMGLINE", "<user@host> "
"Remove the gline matching <mask>",
true,
commandLevel::flg_REMGLINE,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new TRANSLATECommand( this, "TRANSLATE", "<numeric>"
"Translate a numeric into user information",
false,
commandLevel::flg_TRANS,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new WHOISCommand( this, "WHOIS", "<nickname>"
"Obtain information on a given nickname",
false,
commandLevel::flg_WHOIS,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new KICKCommand( this, "KICK", "<channel> <nick> <reason>"
"Kick a user from a channel",
false,
commandLevel::flg_KICK,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
// The following commands deals with operchans, if you want operchans
// just uncomment them
/*
RegisterCommand( new ADDOPERCHANCommand( this, "ADDOPERCHAN", "<channel>"
"Add an oper channel",
false,
commandLevel::flg_ADDOPCHN,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new REMOPERCHANCommand( this, "REMOPERCHAN", "<channel>"
"Remove an oper channel",
false,
commandLevel::flg_REMOPCHN,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new LISTOPERCHANSCommand( this, "LISTOPERCHANS",
"List current IRCoperator only channels",
false,
commandLevel::flg_LOPCHN,
true,
false,
false,operLevel::OPERLEVEL,
false ) ) ;
*/
RegisterCommand( new CHANINFOCommand( this, "CHANINFO", "<channel>"
"Obtain information about a given channel",
false,
commandLevel::flg_CHINFO,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new LOGINCommand( this, "LOGIN", "<USER> <PASS> "
"Authenticate with the bot",
true,
commandLevel::flg_LOGIN,
false,
false,
true,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new DEAUTHCommand( this, "DEAUTH", ""
"Deauthenticate with the bot",
false,
commandLevel::flg_DEAUTH,
false,
false,
true,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new DEAUTHCommand( this, "LOGOUT", ""
"Deauthenticate with the bot",
false,
commandLevel::flg_DEAUTH,
false,
false,
true,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new ADDUSERCommand( this, "ADDUSER",
"<USER> <OPERTYPE> [SERVER*] <PASS> "
"Add a new oper",
true,
commandLevel::flg_ADDNOP,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new REMUSERCommand( this, "REMUSER", "<USER> "
"Remove an oper",
true,
commandLevel::flg_REMOP,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new ADDCOMMANDCommand( this, "ADDCOMMAND",
"<USER> <COMMAND> "
"Add a new command to an oper",
true,
commandLevel::flg_ADDCMD,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new REMCOMMANDCommand( this, "REMCOMMAND",
"<USER> <COMMAND> "
"Remove a command from oper",
true,
commandLevel::flg_DELCMD,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new NEWPASSCommand( this, "NEWPASS", "<PASSWORD> "
"Change password",
true,
commandLevel::flg_NEWPASS,
false,
false,
true,
operLevel::UHSLEVEL,
false ) ) ;
RegisterCommand( new SUSPENDCommand( this, "SUSPEND",
"<OPER> <DURATION> [-l level] <REASON>"
"Suspend an oper",
true,
commandLevel::flg_SUSPEND,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new UNSUSPENDCommand( this, "UNSUSPEND", "<OPER> "
"UnSuspend an oper",
true,
commandLevel::flg_UNSUSPEND,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new MODUSERCommand( this, "MODUSER",
"<OPER> <OPTION> <NEWVALUE> [OPTION] [NEWVALUE] ... "
"Modify an oper",
true,
commandLevel::flg_MODOP,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new MODERATECommand( this, "MODERATE", "<#Channel> "
"Moderate A Channel",
false,
commandLevel::flg_MODERATE,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new UNMODERATECommand( this, "UNMODERATE", "<#Channel> "
"UNModerate A Channel",
false,
commandLevel::flg_UNMODERATE,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new OPCommand( this, "OP", "<#Channel> <nick> [nick] .. "
"Op user(s) on a Channel",
false,
commandLevel::flg_OP,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new DEOPCommand( this, "DEOP", "<#Channel> <nick> [nick] .. "
"Deop user(s) on a Channel",
false,
commandLevel::flg_DEOP,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new LISTHOSTSCommand( this, "LISTHOSTS", "<oper> "
"Shows an oper hosts list",
true,
commandLevel::flg_LISTHOSTS,
false,
true,
false,
operLevel::OPERLEVEL,
false ) );
RegisterCommand(new LISTUSERSCommand(this, "LISTUSERS", "[-l CODER/SMT/ADMIN/OPER/UHS] "
"List users with specific parameters",
true,
commandLevel::flg_LIST,
false,
true,
false,
operLevel::OPERLEVEL,
true));
RegisterCommand( new CLEARCHANCommand( this, "CLEARCHAN", "<#chan> "
"Removes all channel modes",
false,
commandLevel::flg_CLEARCHAN,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new ADDSERVERCommand( this, "ADDSERVER", "<Server> "
"Add a new server to the bot database",
true,
commandLevel::flg_ADDSERVER,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new LEARNNETCommand( this, "LEARNNET", ""
"Update the servers database according to the current situation",
true,
commandLevel::flg_LEARNNET,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new REMSERVERCommand( this, "REMSERVER", "<Server name>"
"Removes a server from the bot database",
true,
commandLevel::flg_REMSERVER,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new CHECKNETCommand( this, "CHECKNET", ""
"Checks if all known servers are in place",
true,
commandLevel::flg_CHECKNET,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new LASTCOMCommand( this, "LASTCOM",
"[number of lines to show]"
"Post you the bot logs",
true,
commandLevel::flg_LASTCOM,
false,
true,
false,
operLevel::OPERLEVEL,
true) ) ;
RegisterCommand( new LASTCOMCommand( this, "LASTCOMM",
"[number of lines to show]"
"Post you the bot logs",
true,
commandLevel::flg_LASTCOM,
false,
true,
false,
operLevel::OPERLEVEL,
true) ) ;
RegisterCommand( new FORCEGLINECommand( this, "FORCEGLINE",
"<user@host> <duration>[time units] <reason> "
"Gline a given user@host for the given reason",
true,
commandLevel::flg_FGLINE,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new SGLINECommand( this, "SGLINE",
"<user@host> <duration>[time units] <reason> "
"Gline a given user@host for the given reason",
true,
commandLevel::flg_SGLINE,
false,
true,
false,
operLevel::CODERLEVEL,
true ) ) ;
RegisterCommand( new REMSGLINECommand( this, "REMSGLINE",
"<user@host> Removes a gline on a given host",
true,
commandLevel::flg_REMSGLINE,
false,
true,
false,
operLevel::CODERLEVEL,
true ) ) ;
RegisterCommand( new EXCEPTIONCommand( this, "EXCEPTIONS",
"(list / add / del) [host mask]"
"Add connection exceptions on hosts",
true,
commandLevel::flg_EXCEPTIONS,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new ANNOUNCECommand( this, "ANNOUNCE",
"[-p] <message>",
false,
commandLevel::flg_ANNOUNCE,
false,
false,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new LISTIGNORESCommand( this, "LISTIGNORES",
"List the ignore list",
false,
commandLevel::flg_LISTIGNORES,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new REMOVEIGNORECommand( this, "REMIGNORE", "(nick/host)"
" Removes a host/nick from the ignore list",
false,
commandLevel::flg_REMIGNORE,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new LISTCommand( this, "LIST", "(glines/servers/nomodechannels/exceptions/channels)"
" Get all kinds of lists from the bot",
false,
commandLevel::flg_LIST,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new COMMANDSCommand( this, "COMMANDS",
"<command> <option> <new value>"
" Change commands options",
true,
commandLevel::flg_COMMANDS,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new GCHANCommand( this, "GCHAN",
"#channel <length/-per> <reason>"
" Set a BADCHAN gline",
true,
commandLevel::flg_GCHAN,
false,
true,
false,
operLevel::CODERLEVEL,
true ) ) ;
RegisterCommand( new REMGCHANCommand( this, "REMGCHAN", "#channel "
" Removes a BADCHAN gline",
true,
commandLevel::flg_GCHAN,
false,
true,
false,
operLevel::CODERLEVEL,
true ) ) ;
RegisterCommand( new USERINFOCommand( this, "USERINFO",
"<usermask/servermask> [-cl] Get information about opers (with optional command listing)",
false,
commandLevel::flg_USERINFO,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new STATUSCommand( this, "STATUS", "Shows debug status ",
false,
commandLevel::flg_STATUS,
false,
true,
false,
operLevel::CODERLEVEL,
true ) ) ;
RegisterCommand( new SHUTDOWNCommand( this, "SHUTDOWN",
" <REASON> Shutdown the bot ",
false,
commandLevel::flg_SHUTDOWN,
false,
true,
false,
operLevel::CODERLEVEL,
true ) ) ;
RegisterCommand( new SCANCommand( this, "SCAN",
" -h <host> / -n <real name> [-v] [-i]"
" Scans for all users which much a certain host / real name ",
false,
commandLevel::flg_SCAN,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new MAXUSERSCommand( this, "MAXUSERS",
"Shows the maximum number of online users ever recorded ",
false,
commandLevel::flg_MAXUSERS,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
RegisterCommand( new CONFIGCommand( this, "CONFIG",
" -GTime <duration in secs> / -VClones <amount> -Clones <amount>"
" -CClones <amount> -CClonesCIDR <size> -CClonesGline <Yes/No>"
" -CClonesGTime <duration>"
" -IClones <amount> -IClonesGline <Yes/No>"
" -CClonesTime <seconds> / -GBCount <count> / -GBInterval <interval in secs> "
" -SGline <Yes/No> "
"Manages all kinds of configuration related values ",
false,
commandLevel::flg_CONFIG,
false,
true,
false,
operLevel::CODERLEVEL,
true ) ) ;
RegisterCommand( new NOMODECommand( this, "NOMODE",
"<ADD/REM> <#channel> [reason] Manage the nomode list ",
false,
commandLevel::flg_NOMODE,
false,
true,
false,
operLevel::SMTLEVEL,
true ) ) ;
RegisterCommand( new SAYCommand( this, "SAY",
"<-s/-b> <#chan/nick> Forced the bot to \"talk\" as the uplink or the bot",
false,
commandLevel::flg_SAY,
false,
true,
false,
operLevel::CODERLEVEL,
true ) ) ;
RegisterCommand( new SAYCommand( this, "DO",
"<-s/-b> <#chan/nick> Forces the bot to \"/me\" as the uplink or the bot",
false,
commandLevel::flg_SAY,
false,
true,
false,
operLevel::CODERLEVEL,
true ) ) ;
RegisterCommand( new REOPCommand( this, "REOP", "<#chan> <nick> "
"Removes all channel ops, and reops the specified nick",
false,
commandLevel::flg_REOP,
false,
true,
false,
operLevel::OPERLEVEL,
false ) ) ;
RegisterCommand( new UNJUPECommand( this, "UNJUPE",
"<server> removes a jupiter on a server",
false,
commandLevel::flg_UNJUPE,
false,
true,
false,
operLevel::OPERLEVEL,
true ) ) ;
elog << "Loading commands ......... ";
loadCommands();
elog << "Done!" << endl;
elog << "Loading glines ........... ";
if(loadGlines())
{
elog << "Done!" << endl;
}
else
{
elog << "Failed!!!" << endl;
}
elog << "Loading exceptions ....... ";
if(loadExceptions())
{
elog << "Done!" << endl;
}
else
{
elog << "Error while loading exceptions!!!! ,"
<< " shutting down"
<< endl;
::exit(1);
}
elog << "Loading users ............ ";
if(loadUsers())
{
elog << "Done!" << endl;
}
else
{
elog << "Failed!!!" << endl;
}
elog << "Loading servers info ..... ";
if(loadServers())
{
elog << "Done!" << endl;
}
else
{
elog << "Failed!!!" << endl;
}
loadMaxUsers();
loadVersions();
loadBadChannels();
if(!loadMisc())
{
glineBurstInterval = 5;
glineBurstCount = 5;
}
connectCount = 0;
connectRetry = 5;
curUsers = 0;
levelMapper.push_back(levelMapperType(operLevel::UHSLEVEL, operLevel::UHSLEVELSTR));
levelMapper.push_back(levelMapperType(operLevel::OPERLEVEL, operLevel::OPERLEVELSTR));
levelMapper.push_back(levelMapperType(operLevel::ADMINLEVEL, operLevel::ADMINLEVELSTR));
levelMapper.push_back(levelMapperType(operLevel::SMTLEVEL, operLevel::SMTLEVELSTR));
levelMapper.push_back(levelMapperType(operLevel::CODERLEVEL, operLevel::CODERLEVELSTR));
levelMapper.push_back(levelMapperType(0,""));
#ifdef LOGTOHD
initLogs();
#endif
}
ccontrol::~ccontrol()
{
// Deallocate each command handler
for( commandMapType::iterator ptr = commandMap.begin() ;
ptr != commandMap.end() ; ++ptr )
{
delete ptr->second ;
ptr->second = 0 ;
}
commandMap.clear() ;
// Deallocate each gline entry
for(glineIterator GLptr = glineList.begin(); GLptr != glineList.end(); ++GLptr)
{
delete GLptr->second;
}
glineList.clear();
for(glineIterator GLptr = rnGlineList.begin(); GLptr != rnGlineList.end(); ++GLptr)
{
delete GLptr->second;
}
rnGlineList.clear();
}
// Register a command handler
bool ccontrol::RegisterCommand( Command* newComm )
{
assert( newComm != NULL ) ;
// Unregister the command handler first; prevent memory leaks
UnRegisterCommand( newComm->getName() ) ;
/*if(!UpdateCommandFromDb(newComm))
elog << "Error cant find command "
<< newComm->getName()
<< " In database"
<< ends;*/
// Insert the new handler
return commandMap.insert( pairType( newComm->getName(), newComm ) ).second ;
}
bool ccontrol::UnRegisterCommand( const string& commName )
{
// Find the command handler
commandMapType::iterator ptr = commandMap.find( commName ) ;
// Was the handler found?
if( ptr == commandMap.end() )
{
// Nope
return false ;
}
// Deallocate the handler
//delete ptr->second ;
// Remove the handler
commandMap.erase( ptr ) ;
// Return success
return true ;
}
void ccontrol::BurstChannels()
{
// msgChan is an operChan as well, no need to burst it separately
for( vector< string >::size_type i = 0 ; i < operChans.size() ; i++ )
{
// Burst our channels
MyUplink->JoinChannel( this, operChans[ i ], operChanModes ) ;
// Receive events for this channel
MyUplink->RegisterChannelEvent( operChans[ i ], this ) ;
}
// Don't forget to call the base class BurstChannels() method
return xClient::BurstChannels() ;
}
bool ccontrol::BurstGlines()
{
ccGline *theGline = 0 ;
for(glineListType::iterator ptr = glineList.begin()
; ptr != glineList.end(); ++ptr)
{
theGline = ptr->second;
addGlineToUplink(theGline);
}
for(glineListType::iterator ptr = rnGlineList.begin()
; ptr != rnGlineList.end(); ++ptr)
{
theGline = ptr->second;
addGlineToUplink(theGline);
}
return xClient::BurstGlines();
}
// I don't really like doing this.
// In order for each of this bot's Command's to have a valid server
// pointer, this method must be overloaded and server must be
// explicitly set for each Command.
void ccontrol::OnAttach()
{
for( commandMapType::iterator ptr = commandMap.begin() ;
ptr != commandMap.end() ; ++ptr )
{
ptr->second->setServer( MyUplink ) ;
}
expiredTimer = MyUplink->RegisterTimer(::time(0) + ExpiredInterval,this,NULL);
dbConnectionCheck = MyUplink->RegisterTimer(::time(0) + dbConnectionTimer,this,NULL);
glineQueueCheck = MyUplink->RegisterTimer(::time(0) + glineBurstInterval, this,NULL);
#ifndef LOGTOHD
if(SendReport)
{
struct tm Now = convertToTmTime(::time(0));
time_t theTime = ::time(0) + ((24 - Now.tm_hour)*3600 - (Now.tm_min)*60) ; //Set the daily timer to 24:00
postDailyLog = MyUplink->RegisterTimer(theTime, this, NULL);
}
#endif
MyUplink->RegisterEvent( EVT_KILL, this );
MyUplink->RegisterEvent( EVT_QUIT, this );
MyUplink->RegisterEvent( EVT_NETJOIN, this );
MyUplink->RegisterEvent( EVT_BURST_CMPLT, this );
MyUplink->RegisterEvent( EVT_GLINE , this );
MyUplink->RegisterEvent( EVT_REMGLINE , this );
MyUplink->RegisterEvent( EVT_NICK , this );
MyUplink->RegisterEvent( EVT_OPER , this );
MyUplink->RegisterEvent( EVT_NETBREAK, this );
xClient::OnAttach() ;
}
void ccontrol::OnShutdown(const std::string& reason)
{
/* handle client shutdown */
MyUplink->UnloadClient(this, reason);
}
void ccontrol::OnPrivateMessage( iClient* theClient,
const string& Message, bool )
{
// Tokenize the message
StringTokenizer st( Message ) ;
if(theClient == Network->findClient(this->getCharYYXXX()))
{
/*
Got message from one self, this should never happen
but in case it does, dont want to create an endless loop
*/
xClient::OnPrivateMessage( theClient, Message ) ;
return ;
}
// Make sure there is a command present
if( st.empty() )
{
//Notice( theClient, "Incomplete command" ) ;
return ;
}
const string Command = string_upper( st[ 0 ] ) ;
ccUser* theUser = IsAuth(theClient);
/*if((!theUser) && !(theClient->isOper()))
{
addFloodData(theClient,flood::MESSAGE_POINTS);
xClient::OnPrivateMessage( theClient, Message ) ;
return ;
}**/
// Attempt to find a handler for this method.
commandIterator commHandler = findCommand( Command ) ;
// Was a handler found?
if( commHandler == command_end() )
{
// Nope, notify the client if he's authenticated
//if(theUser)
if(!theClient->getMode(iClient::MODE_SERVICES))
Notice( theClient, "Unknown command" ) ;
return ;
}
// Check if the user is logged in , and he got
// access to that command
int ComAccess = commHandler->second->getFlags();
//if((!theUser) && (ComAccess) && !(theClient->isOper()))
if ((!theUser) && (ComAccess) && (!(listenNonOpers) && !(theClient->isOper())))
{
addFloodData(theClient,flood::MESSAGE_POINTS);
xClient::OnPrivateMessage( theClient, Message ) ;
return ;
}
if((!theUser) && !(ComAccess & commandLevel::flg_NOLOGIN) && (ComAccess))
{//The user isnt authenticated,
//and he must be to run this command
if((theClient->isOper()) && !(theClient->getMode(iClient::MODE_SERVICES)))
Notice(theClient,"Sorry, you must be authenticated to run this command");
else if(!theClient->isOper())
addFloodData(theClient,flood::MESSAGE_POINTS);
xClient::OnPrivateMessage( theClient, Message ) ;
return ;
}
if (!listenNonOpers)
//If user is not not opered and the command requires to be opered
if((!theClient->isOper()) && (commHandler->second->getNeedOp())) {
addFloodData(theClient,flood::MESSAGE_POINTS);
xClient::OnPrivateMessage(theClient, Message);
return;
}
if((theUser) && (!theClient->isOper()) && (theUser->getNeedOp()))
{
if(!theClient->getMode(iClient::MODE_SERVICES))
Notice(theClient,
"You must be oper'd to use this command");
xClient::OnPrivateMessage(theClient, Message);
return;
}
else if( (ComAccess) && (theUser) && !(theUser->gotAccess(commHandler->second)))
{
if(!theClient->getMode(iClient::MODE_SERVICES) && theClient->isOper())
Notice( theClient, "You don't have access to that command" ) ;
}
else if(( (theUser) && isSuspended(theUser) ) && ( ComAccess ) )
{
if(theClient->getMode(iClient::MODE_SERVICES) && theClient->isOper())
Notice( theClient,
"Sorry, you are suspended");
}
else if(commHandler->second->getIsDisabled())
{
if(!theClient->getMode(iClient::MODE_SERVICES) && theClient->isOper())
Notice(theClient,
"Sorry, this command is currently disabled");
}
else
{
/* do we need a DB connection? */
if (commHandler->second->needsDB())
{
/* check database connection */
if (!dbConnected)
{
/* failed */
if(theClient->isOper() && !theClient->isModeK())
Notice(theClient, "Sorry, the database connection "
"is currently down, please try again later.");
xClient::OnPrivateMessage(theClient, Message);
return;
}
/* database connection is fine */
}
// Log the command
if(!commHandler->second->getNoLog()) //Dont log command which arent suppose to be logged
{
#ifndef LOGTOHD
if(theUser)
DailyLog(theUser,"%s",Message.c_str());
else
DailyLog(theClient,"%s",Message.c_str());
#else
ccLog* newLog = new (std::nothrow) ccLog();
newLog->Time = ::time(0);
newLog->Desc = Message.c_str();
newLog->Host = theClient->getRealNickUserHost().c_str();
if(theUser)
newLog->User = theUser->getUserName().c_str();
else
newLog->User = "Unknown";
newLog->CommandName = Command;
DailyLog(newLog);
#endif
}
// Execute the command handler
commHandler->second->Exec( theClient, Message) ;
}
xClient::OnPrivateMessage( theClient, Message ) ;
}
void ccontrol::OnServerMessage( iServer* Server, const string& Message,
bool )
{
StringTokenizer st( Message ) ;
if(st.size() < 2)
{
xClient::OnServerMessage(Server,Message);
return ;
}
//This is kinda lame
//TODO : add a server message parser
if (!strcasecmp(st[1], "RO")) {
if (st.size() < 7) {
elog << "ccontrol::OnServerMessage> Invalid number "
<< "on parameters on RO! :"
<< Message
<< endl;
xClient::OnServerMessage(Server,Message);
return;
}
else if (st.size() < 8) {
elog << "ccontrol::OnServerMessage> Expected 7 "
<< "parameters on RO! :"
<< Message
<< endl;
xClient::OnServerMessage(Server,Message);
return;
}
ccServer* tmpServer = serversMap[Server->getName()];
if (!tmpServer)
{
serversMap.erase(Server->getName());
xClient::OnServerMessage(Server,Message);
return;
}
timeval now = { 0, 0 } ;
if( ::gettimeofday( &now, 0 ) < 0 )
{
elog << "ccontrol(rpingCheck)> gettimeofday() failed: "
<< strerror( errno )
<< endl ;
xClient::OnServerMessage(Server,Message);
return;
}
time_t lagTime;
lagTime = (now.tv_sec - atoi(st[6])) * 1000 + (now.tv_usec - atoi(st[7])) / 1000;
tmpServer->setLagTime(lagTime);
tmpServer->setLastLagRecv(::time(0));
//if ((lagTime > LAG_TOO_BIG) && ((::time(0) - tmpServer->getLastLagReport()) > LAG_REPORT_INTERVAL)) {
// tmpServer->setLastLagReport(::time(0));
// MsgChanLag("[lag] %s is %ds lagged", Server->getName().c_str(), (int) (lagTime / 1000));
//}
}
//At 391 BGAAA abuseexploits.undernet.org 1246137209 50 :Saturday June 27 2009 -- 23:12 +02:00
if (!strcasecmp(st[1], "391"))
{
ccServer* tmpServer = serversMap[Server->getName()];
if (!tmpServer)
{
serversMap.erase(Server->getName());
xClient::OnServerMessage(Server,Message);
return;
}
timeval now = { 0, 0 } ;
if( ::gettimeofday( &now, 0 ) < 0 )
{
elog << "ccontrol(rpingCheck)> gettimeofday() failed: "
<< strerror( errno )
<< endl ;
xClient::OnServerMessage(Server,Message);
return;
}
if (st.size() < 5)
{
elog << "ccontrol::OnServerMessage> Invalid number "
<< "on parameters on 391! :"
<< Message
<< endl;
xClient::OnServerMessage(Server,Message);
return;
}
int lagTime = tmpServer->getLagTime();
int timeDiff = abs(::time(0) - (atoi(st[3]) - atoi(st[4])));
if ((timeDiff >= MAX_TIME_DIFF) && (lagTime < 5000) && ((::time(0) - timediffServersMap[Server]) > TIMEDIFF_REPORT_INTERVAL))
{
MsgChanLog("Time diff for %s: %ds", tmpServer->getName().c_str(), timeDiff);
timediffServersMap[Server] = ::time(0);
}
//MsgChanLog("Message: %s", Message.c_str());
}
if(!strcasecmp(st[1],"351"))
{
if(st.size() < 5)
{
elog << "ccontrol::OnServerMessage> Invalid number "
<< "on parameters on 351! :"
<< Message
<< endl;
xClient::OnServerMessage(Server,Message);
return ;
}
ccServer* tmpServer = serversMap[Server->getName()];
if(tmpServer)
{
tmpServer->setVersion(st[2] + " - " + st[4]);
}
else
{
serversMap.erase(serversMap.find(Server->getName()));
}
}
xClient::OnServerMessage(Server,Message);
}
bool ccontrol::Notice( const iClient* Target, const string& Message )
{
ccUser* tmpUser = IsAuth(Target);
if((tmpUser) && !(tmpUser->getNotice()))
{
return xClient::Message(Target,"%s",Message.c_str());
}
return xClient::Notice(Target,Message);
}
bool ccontrol::Notice( const iClient* Target, const char* Message, ... )
{
char buffer[ 1024 ] = { 0 } ;
va_list list;
va_start(list, Message);
vsnprintf(buffer, 1024, Message, list);
va_end(list);
ccUser* tmpUser = IsAuth(Target);
if((tmpUser) && !(tmpUser->getNotice()))
{
return xClient::Message(Target,"%s",buffer);
}
return xClient::Notice(Target,"%s",buffer);
}
void ccontrol::OnCTCP( iClient* theClient, const string& CTCP,
const string& Message, bool )
{
ccUser* theUser = IsAuth(theClient);
if((!theUser) && !(theClient->isOper()))
{ //We need to add the flood points for this user
if(!theClient->getCustomData(this))
{
elog << "ccontrol::OnCTCP> Couldnt find custom data for "
<< *theClient << endl;
return ;
}
ccFloodData* floodData = (static_cast< ccUserData* >(
theClient->getCustomData(this) ))->getFlood() ;
if(floodData->addPoints(flood::CTCP_POINTS))
{ //yes we need to ignore this user
ignoreUser(floodData);
MsgChanLog("[FLOOD MESSAGE]: %s has been ignored"
,theClient->getNickName().c_str());
return ;
}
}
else
{
StringTokenizer st(CTCP);
if(st.empty())
{
xClient::DoCTCP(theClient,CTCP,"Error Aren't we missing something?");
return ;
}
else if(st[0] == "PING")
{
xClient::DoCTCP(theClient,CTCP,Message);
return ;
}
else if(st[0] == "GENDER")
{
xClient::DoCTCP(theClient,CTCP,
"Thats a question i am still trying to find the answer to");
return ;
}
else if(st[0] == "SEX")
{
xClient::DoCTCP(theClient,CTCP,
"Sorry i am booked till the end of the year");
return ;
}
else if(st[0] == "POLICE")
{
xClient::DoCTCP(theClient,CTCP,
"Oh crap! where would i hide the drugs now?");
return ;
}
else if(st[0] == "VERSION")
{
xClient::DoCTCP(theClient,CTCP,
" CControl version "
+ string(MAJORVER) + "." + string(MINORVER)
+ " release date: " + RELDATE);
return ;
}
}
}
void ccontrol::OnEvent( const eventType& theEvent,
void* Data1, void* Data2, void* Data3, void* Data4 )
{
int i=0;
int client_addr[4] = { 0 };
struct in_addr tmp_ip;
unsigned long mask_ip;
char *client_ip;
char Log[200];
switch( theEvent )
{
case EVT_QUIT:
case EVT_KILL:
{
/*
* The user disconnected,
* remove his authentication,
* and flood data, and login data
*/
iClient* tmpUser = (theEvent == EVT_QUIT) ?
static_cast< iClient* >( Data1 ) :
static_cast< iClient* >( Data2 ) ;
--curUsers;
string tIP = xIP( tmpUser->getIP()).GetNumericIP();
if(checkClones)
{
/* CIDR checks */
/* convert ip to longip */
i = sscanf(tIP.c_str(), "%d.%d.%d.%d", &client_addr[0], &client_addr[1], &client_addr[2], &client_addr[3]);
mask_ip = ntohl((client_addr[0]) | (client_addr[1] << 8) | (client_addr[2] << 16) | (client_addr[3] << 24));
/* bitshift ip to strip the last (32-cidrmask) bits (leaving a mask for the ip) */
for (i = 0; i < (32-CClonesCIDR); i++)
{
/* right shift */
mask_ip >>= 1;
}
for (i = 0; i < (32-CClonesCIDR); i++)
{
/* left shift */
mask_ip <<= 1;
}
/* convert longip back to ip */
mask_ip = htonl(mask_ip);
tmp_ip.s_addr = mask_ip;
client_ip = inet_ntoa(tmp_ip);
if ((clientsIp24Map.find(client_ip) != clientsIp24Map.end()) &&
(--clientsIp24Map[client_ip] < 1))
{
clientsIp24Map.erase(clientsIp24Map.find(client_ip));
if ((clientsIp24MapLastWarn.find(client_ip) != clientsIp24MapLastWarn.end()) &&
(clientsIp24MapLastWarn[client_ip] > 0))
clientsIp24MapLastWarn.erase(clientsIp24MapLastWarn.find(client_ip));
}
/* ident clones */
sprintf(Log, "%s/%d-%s", client_ip, CClonesCIDR, tmpUser->getUserName().c_str());
if ((clientsIp24IdentMap.find(Log) != clientsIp24IdentMap.end()) &&
(--clientsIp24IdentMap[Log] < 1))
{
clientsIp24IdentMap.erase(clientsIp24IdentMap.find(Log));
if ((clientsIp24IdentMapLastWarn.find(Log) != clientsIp24IdentMapLastWarn.end()) &&
(clientsIp24IdentMapLastWarn[Log] > 0))
clientsIp24IdentMapLastWarn.erase(clientsIp24IdentMapLastWarn.find(Log));
}
if ((clientsIpMap.find(tIP) != clientsIpMap.end()) && (--clientsIpMap[tIP] < 1))
{
clientsIpMap.erase(clientsIpMap.find(tIP));
}
string virtualHost = tmpUser->getDescription() + "@";
int dots = 0;
for(string::size_type ptr = 0;ptr < tIP.size() && dots < 3;++ptr)
{
if(tIP[ptr] == '.')
{
++dots;
}
virtualHost += tIP[ptr];
}
virtualHost += '*';
if ((virtualClientsMap.find(virtualHost) != virtualClientsMap.end()) &&
(--virtualClientsMap[virtualHost] < 1))
{
virtualClientsMap.erase(virtualClientsMap.find(virtualHost));
if ((virtualClientsMapLastWarn.find(virtualHost) != virtualClientsMapLastWarn.end()) &&
(virtualClientsMapLastWarn[virtualHost] > 0))
virtualClientsMapLastWarn.erase(virtualClientsMapLastWarn.find(virtualHost));
}
}
ccUserData* UserData = static_cast< ccUserData* >(
tmpUser->getCustomData(this)) ;
tmpUser->removeCustomData(this);
if( UserData )
{
ccUser *TempAuth = UserData->getDbUser();
if(TempAuth)
{
UserData->setDbUser(NULL);
TempAuth->setClient(NULL);
}
ccFloodData *tempLogin = UserData->getFlood();
if(tempLogin)
{
removeLogin(tempLogin);
if(tempLogin->getIgnoredHost() != "")
{
tempLogin->setNumeric("0");
tempLogin->resetLogins();
}
else
{
delete tempLogin;
}
}
delete UserData;
}
break ;
} // case EVT_KILL/case EVT_QUIT
case EVT_NETJOIN:
{
/*
* We need to update the servers table about the new
* server , and check if we know it
*
*/
iServer* NewServer = static_cast< iServer* >( Data1);
if(NewServer->isJupe()) //Is the server juped?
{
break;
}
/* use Network->findServer as AttachServer sends an iClient rather
* than an iServer object as Data2. Either way should work fine.
*/
iServer* UplinkServer = Network->findServer(NewServer->getUplinkIntYY());
ccServer* CheckServer = getServer(NewServer->getName());
inBurst = true;
if(!CheckServer)
{
MsgChanLog("Unknown server just connected: %s via %s\n",
NewServer->getName().c_str(),
UplinkServer->getName().c_str());
}
else
{
CheckServer->setLastConnected(::time (0));
CheckServer->setUplink(UplinkServer->getName());
CheckServer->setLastNumeric(NewServer->getCharYY());
CheckServer->setNetServer(NewServer);
if(dbConnected)
{
CheckServer->Update();
}
}
break;
}
case EVT_NETBREAK:
{
iServer* NewServer = static_cast< iServer* >( Data1);
string Reason = *(static_cast<string *>(Data3));
if( 0 == Network->findFakeServer( NewServer ) )
// NOTE: Changed --dan
// if(!getUplink()->isJuped(NewServer))
{
ccServer* CheckServer = getServer(NewServer->getName());
if(CheckServer)
{
CheckServer->setSplitReason(Reason);
CheckServer->setLastSplitted(::time(NULL));
CheckServer->setNetServer(NULL);
CheckServer->setLastLagRecv(0);
CheckServer->setLastLagSent(0);
CheckServer->setLagTime(0);
CheckServer->setLastLagReport(0);
if(dbConnected)
{
CheckServer->Update();
}
}
}
inBurst = false;
ccServer* curServer;
const iServer* curNetServer;
for(serversConstIterator ptr = serversMap_begin();
ptr != serversMap_end() && !inBurst; ++ptr)
{
curServer = ptr->second;
curNetServer = curServer->getNetServer();
if((curNetServer) && (curNetServer->isBursting()))
{
inBurst = true;
}
}
break;
}
case EVT_BURST_CMPLT:
{
inBurst = false;
ccServer* curServer;
//refreshOpersIPMap();
const iServer* curNetServer;
for(serversConstIterator ptr = serversMap_begin();
ptr != serversMap_end() && !inBurst; ++ptr)
{
curServer = ptr->second;
curNetServer = curServer->getNetServer();
if((curNetServer) && (curNetServer->isBursting()))
{
inBurst = true;
}
}
checkMaxUsers();
// if(!inBurst)
// {
refreshVersions();
// }
break;
}
case EVT_GLINE:
{
if(!Data1) //TODO: find out how we get this
{
return ;
}
if(!saveGlines)
{
return ;
}
Gline* newG = static_cast< Gline* >(Data1);
ccGline* newGline = findGline(newG->getUserHost());
if(!newGline)
{
newGline = new (std::nothrow) ccGline(SQLDb);
assert (newGline != NULL);
iServer* serverAdded = Network->findServer(newG->getSetBy());
if(serverAdded)
newGline->setAddedBy(serverAdded->getName());
else
newGline->setAddedBy("Unknown");
}
else
{
if(newGline->getLastUpdated() >= newG->getLastmod())
{
return ;
}
}
newGline->setAddedOn(::time(0));
//newGline->setLastUpdated(::time(0));
newGline->setHost(newG->getUserHost());
newGline->setReason(newG->getReason());
newGline->setExpires(newG->getExpiration());
if(saveGlines)
{
newGline->Insert();
//need to load the id
newGline->loadData(newGline->getHost());
}
else
{
newGline->setId("-1");
}
addGline(newGline);
break;
}
case EVT_REMGLINE:
{
if(!Data1)
{
return ;
}
Gline* newG = static_cast< Gline* >(Data1);
ccGline* newGline = findGline(newG->getUserHost());
if(newGline)
{
remGline(newGline);
newGline->Delete();
delete newGline;
}
break;
}
case EVT_NICK:
{
iClient* NewUser = static_cast< iClient* >( Data1);
handleNewClient(NewUser);
break;
}
case EVT_OPER:
{
iClient* theUser = static_cast< iClient* >( Data1);
isNowAnOper(theUser);
break;
}
} // switch()
xClient::OnEvent( theEvent, Data1, Data2, Data3, Data4 ) ;
}
void ccontrol::OnChannelEvent( const channelEventType& theEvent,
Channel* theChan,
void* Data1, void* Data2, void* Data3, void* Data4 )
{
switch( theEvent )
{
case EVT_JOIN:
if( !isOperChan( theChan ) )
{
// We really don't care otherwise
// Note, this shouldn't happen
break ;
}
iClient* theClient = static_cast< iClient* >( Data1 ) ;
if( theClient->isOper() )
{
Op( theChan, theClient ) ;
}
break ;
}
// Call the base class OnChannelEvent()
xClient::OnChannelEvent( theEvent, theChan,
Data1, Data2, Data3, Data4 ) ;
}
void ccontrol::OnTimer(const xServer::timerID& timer_id, void*)
{
if (timer_id == postDailyLog)
{
// Create the lastcom report
CreateReport(::time(0) - 24*3600,::time(0));
// Email the report to the abuse team
MailReport(AbuseMail.c_str(),"Report.log");
/* Refresh Timers */
time_t theTime = time(NULL) + 24*3600;
postDailyLog = MyUplink->RegisterTimer(theTime, this, NULL);
}
else if (timer_id == expiredTimer)
{
refreshGlines();
refreshIgnores();
refreshSuspention();
expiredTimer = MyUplink->RegisterTimer(::time(0) + ExpiredInterval,
this,NULL);
}
else if(timer_id == dbConnectionCheck)
{
checkDbConnection();
dbConnectionCheck = MyUplink->RegisterTimer(::time(0) + dbConnectionTimer,this,NULL);
}
else if(timer_id == glineQueueCheck)
{
processGlineQueue();
glineQueueCheck = MyUplink->RegisterTimer(::time(0) + glineBurstInterval,this,NULL);
}
else if (timer_id == timeCheck)
{
ccServer* TmpServer;
for (serversConstIterator ptr = serversMap_begin(); ptr != serversMap_end(); ++ptr)
{
TmpServer = ptr->second;
if (TmpServer->getNetServer())
{
Write("%s TI :%s", getCharYYXXX().c_str(), TmpServer->getNetServer()->getCharYY().c_str());
}
}
timeCheck = MyUplink->RegisterTimer(::time(0) + 7200, this, NULL);
}
else if (timer_id == rpingCheck)
{
if (myHub == NULL)
{
rpingCheck = MyUplink->RegisterTimer(::time(0) + 60, this, NULL);
return;
}
timeval now = { 0, 0 } ;
if( ::gettimeofday( &now, 0 ) < 0 )
{
elog << "ccontrol(rpingCheck)> gettimeofday() failed: "
<< strerror( errno )
<< endl ;
return;
}
stringstream s;
s << now.tv_usec ;
static int tID = 19;
tID++;
if (tID == 20)
tID = 0;
//iServer* myHub = Network->findServer(getUplink()->getUplinkCharYY());
//ccServer* ccHub = getServer(myHub->getName());
if (ccHub)
if ((ccHub->getLastLagSent() > ccHub->getLastLagRecv()) && ((::time(0) - ccHub->getLastLagSent()) >= 2))
ccHub->setLagTime((::time(0) - ccHub->getLastLagSent()) * 1000);
ccServer* TmpServer;
int counter = -1;
for (serversConstIterator ptr = serversMap_begin(); ptr != serversMap_end(); ++ptr)
{
TmpServer = ptr->second;
/* don't bother reporting on juped servers - they dont exist */
if (TmpServer && (TmpServer->getNetServer()) && (!TmpServer->getNetServer()->isJupe()))
{
counter++;
if ((TmpServer->getLastLagRecv() > 0) && (TmpServer->getLastLagSent() > TmpServer->getLastLagRecv()))
{
if ((::time(0) - TmpServer->getLastLagSent()) >= 2)
TmpServer->setLagTime((::time(0) - TmpServer->getLastLagSent()) * 1000);
if ((::time(0) - TmpServer->getLastLagSent()) >= LAG_TOO_BIG)
{
if ((::time(0) - TmpServer->getLastLagReport()) > LAG_REPORT_INTERVAL)
{
// If it's euworld's hub that is lagged, only report euworld's hub, not every servers.
if ((ccHub == NULL) || (ccHub->getLagTime() < 14000) || (TmpServer->getNetServer()->getIntYY() == myHub->getIntYY()))
{
TmpServer->setLastLagReport(::time(0));
MsgChanLag("[lag] %s is >%ds lagged", TmpServer->getName().c_str(), (int) (TmpServer->getLagTime() / 1000));
}
}
}
continue;
}
// Send RPING to euworld's hub each 30 seconds instead of each minute.
if (((counter % 20) != tID) && (TmpServer->getNetServer()->getIntYY() != myHub->getIntYY()))
continue;
if ((TmpServer->getNetServer()->getIntYY() == myHub->getIntYY()) && ((!ccHub || (::time(0) - ccHub->getLastLagSent()) < 30)))
continue;
Write("%s RI %s %s %d %s :%d %s", getCharYY().c_str(), TmpServer->getNetServer()->getCharYY().c_str(), getCharYYXXX().c_str(), ::time(0), s.str().c_str(), ::time(0), s.str().c_str());
TmpServer->setLastLagSent(::time(0));
}
//BG RI C] BGAAA 1246224483 960943 :1246224474
}
rpingCheck = MyUplink->RegisterTimer(::time(0) + 3, this, NULL);
}
}
void ccontrol::OnConnect()
{
rpingCheck = MyUplink->RegisterTimer(::time(0) + 60, this, NULL);
timeCheck = MyUplink->RegisterTimer(::time(0) + 300, this, NULL);
iServer* tmpServer = Network->findServer(getUplink()->getUplinkCharYY());
ccServer* tServer = getServer(tmpServer->getName());
ccHub = tServer;
myHub = tmpServer;
if(tServer)
{
tServer->setNetServer(tmpServer);
Write("%s V :%s\n",getCharYYXXX().c_str(),
tmpServer->getCharYY().c_str());
}
xClient::OnConnect();
}
bool ccontrol::isOperChan( const string& theChan ) const
{
vector< string >::const_iterator ptr = operChans.begin(),
end = operChans.end() ;
while( ptr != end )
{
if( !strcasecmp( *ptr, theChan ) )
{
return true ;
}
++ptr ;
}
return false ;
}
bool ccontrol::isOperChan( const Channel* theChan ) const
{
assert( theChan != 0 ) ;
return isOperChan( theChan->getName() ) ;
}
// This method does NOT add the channel to any internal tables
bool ccontrol::Join( const string& chanName, const string& chanModes,
time_t joinTime, bool getOps )
{
if( isOnChannel( chanName ) )
{
// Already on this channel
return true ;
}
bool result = xClient::Join( chanName, chanModes, joinTime, getOps ) ;
if( result )
{
MyUplink->RegisterChannelEvent( chanName, this ) ;
}
operChans.push_back( chanName ) ;
return result ;
}
bool ccontrol::Part( const string& chanName )
{
bool foundChannel = false ;
for( vector< string >::iterator ptr = operChans.begin() ;
ptr != operChans.end() ; ++ptr )
{
if( !strcasecmp( (*ptr).c_str(), chanName.c_str() ) )
{
operChans.erase( ptr ) ;
foundChannel = true ;
break ;
}
} // for()
if( !foundChannel )
{
// The bot isn't on the channel
return false ;
}
bool result = xClient::Part( chanName ) ;
if( result )
{
MyUplink->UnRegisterChannelEvent( chanName, this ) ;
}
return result ;
}
/*bool ccontrol::Kick( Channel* theChan, iClient* theClient,
const string& reason )
{
assert( theChan != NULL ) ;
if( !isOnChannel( theChan->getName() ) )
{
return false ;
}
return xClient::Kick( theChan, theClient, reason ) ;
}*/
bool ccontrol::addOperChan( const string& chanName )
{
return addOperChan( chanName, operChanReason ) ;
}
bool ccontrol::addOperChan( const string& chanName, const string& reason )
{
if( isOperChan( chanName ) )
{
return false ;
}
xClient::Join( chanName, operChanModes, 0, true ) ;
MyUplink->RegisterChannelEvent( chanName, this ) ;
operChans.push_back( chanName ) ;
Channel* theChan = Network->findChannel( chanName ) ;
if( NULL == theChan )
{
elog << "ccontrol::addOperChan> Unable to find channel: "
<< chanName << endl ;
return false ;
}
// Kick any users from the channel that aren't opers
vector< iClient* > clientsToKick ;
for( Channel::const_userIterator ptr = theChan->userList_begin() ;
ptr != theChan->userList_end() ; ++ptr )
{
// Dont kick opers and +k ppl
if(( !ptr->second->isOper() ) && ( !ptr->second->getClient()->getMode(iClient::MODE_SERVICES) ))
{
clientsToKick.push_back( ptr->second->getClient() ) ;
}
}
if( !clientsToKick.empty() )
{
xClient::Kick( theChan, clientsToKick, reason ) ;
}
// TODO: set operChanModes
return true ;
}
bool ccontrol::removeOperChan( const string& chanName )
{
// Part() will remove the channel from this client's tables.
Part( chanName ) ;
return true ;
}
void ccontrol::handleNewClient( iClient* NewUser)
{
bool glSet = false;
bool DoGline = false;
int gDuration = maxGlineLen;
int i=0, AffectedUsers = 0;
int client_addr[4] = { 0 };
unsigned long mask_ip;
struct in_addr tmp_ip;
char *clientip;
char client_ip[19];
char Log[200], GlineMask[250], GlineReason[250];
std::stringstream s;
stringListType *OthersList;
GlineReason[0] = '\0';
curUsers++;
if (NewUser->isOper())
isNowAnOper(NewUser);
if(!inBurst)
{
checkMaxUsers();
}
//Create our flood data for this user
ccFloodData* floodData = new (std::nothrow) ccFloodData(NewUser->getCharYYXXX());
assert( floodData != 0 ) ;
ccUserData* UserData = new (std::nothrow) ccUserData(floodData);
NewUser->setCustomData(this,
static_cast< void* >( UserData ) );
if(dbConnected)
{
string tIP = xIP( NewUser->getIP()).GetNumericIP();
if(checkClones)
{
if(strcasecmp(tIP,"0.0.0.0"))
{
/* CIDR checks */
/* convert ip to longip */
i = sscanf(tIP.c_str(), "%d.%d.%d.%d", &client_addr[0], &client_addr[1], &client_addr[2], &client_addr[3]);
mask_ip = ntohl((client_addr[0]) | (client_addr[1] << 8) | (client_addr[2] << 16) | (client_addr[3] << 24));
/* bitshift ip to strip the last (32-cidrmask) bits (leaving a mask for the ip) */
for (i = 0; i < (32-CClonesCIDR); i++)
{
/* right shift */
mask_ip >>= 1;
}
for (i = 0; i < (32-CClonesCIDR); i++)
{
/* left shift */
mask_ip <<= 1;
}
/* convert longip back to ip */
mask_ip = htonl(mask_ip);
tmp_ip.s_addr = mask_ip;
clientip = inet_ntoa(tmp_ip);
strncpy(client_ip, clientip, 18);
client_ip[18] = '\0';
sprintf(Log, "%s/%d-%s", client_ip, CClonesCIDR, NewUser->getUserName().c_str());
int CurIdentConnections = ++clientsIp24IdentMap[Log];
int CurCIDRConnections = ++clientsIp24Map[client_ip];
sprintf(Log,"*@%s/%d", client_ip, CClonesCIDR);
/* check idents to see if we have too many */
if ((CurIdentConnections > maxIClones) && (CurIdentConnections > getExceptions(NewUser->getUserName() + "@" + tIP)) &&
(CurIdentConnections > getExceptions(NewUser->getUserName() + "@" + NewUser->getRealInsecureHost())))
{
/* too many - send a warning to the chanlog if within warning range */
if ((clientsIp24IdentMapLastWarn[Log] + CClonesTime) <= time(NULL))
{
MsgChanLog("Excessive CIDR Ident clones (%d) for %s@%s/%d (will%s GLINE)\n",
CurIdentConnections, NewUser->getUserName().c_str(), client_ip,
CClonesCIDR, IClonesGline ? "" : " _NOT_");
clientsIp24IdentMapLastWarn[Log] = time(NULL);
}
/* check for auto-gline feature */
if (IClonesGline)
{
sprintf(Log,"Glining %s@%s/%d for excessive CIDR ident connections (%d)",
NewUser->getUserName().c_str(), client_ip, CClonesCIDR, CurIdentConnections);
sprintf(GlineMask,"%s@%s/%d", NewUser->getUserName().c_str(), client_ip, CClonesCIDR);
AffectedUsers = CurIdentConnections;
/* set the gline reason */
sprintf(GlineReason,"AUTO [%d] Automatically banned for excessive CIDR ident connections",AffectedUsers);
DoGline = true;
gDuration = maxGlineLen;
}
}
int CurConnections = ++clientsIpMap[tIP];
if (((CurConnections > maxClones)) && (CurConnections > getExceptions(NewUser->getUserName()+"@" + tIP)) &&
(CurConnections > getExceptions(NewUser->getUserName()+"@"+NewUser->getRealInsecureHost())) && (!DoGline))
{
sprintf(Log,"*@%s", NewUser->getRealInsecureHost().c_str());
MsgChanLog("Excessive connections [%d] from host *@%s [%s] server:{%s}\n",
CurConnections,NewUser->getRealInsecureHost().c_str(), tIP.c_str(),
NewUser->getServer()->getName().c_str());
sprintf(Log,"Glining *@%s/32 for excessive connections (%d)",
tIP.c_str(),CurConnections);
sprintf(GlineMask,"*@%s/32",tIP.c_str());
AffectedUsers = CurConnections;
/* set the gline reason */
sprintf(GlineReason,"AUTO [%d] Automatically banned for excessive connections",AffectedUsers);
DoGline = true;
gDuration = maxGlineLen;
}
if (DoGline)
{
iClient* theClient = Network->findClient(this->getCharYYXXX());
#ifndef LOGTOHD
DailyLog(theClient,"%s",Log);
#else
ccLog* newLog = new (std::nothrow) ccLog();
newLog->Time = ::time(0);
newLog->Desc = Log;
newLog->Host = theClient->getRealNickUserHost().c_str();
newLog->User = "Me";
newLog->CommandName = "AUTOGLINE";
DailyLog(newLog);
#endif
glSet = true;
ccGline *tmpGline;
tmpGline = new ccGline(SQLDb);
tmpGline->setHost(GlineMask);
tmpGline->setExpires(::time(0) + gDuration);
tmpGline->setReason(GlineReason);
tmpGline->setAddedOn(::time(0));
tmpGline->setAddedBy(nickName);
tmpGline->setLastUpdated(::time(0));
tmpGline->Insert();
tmpGline->loadData(tmpGline->getHost());
addGline(tmpGline);
if(!getUplink()->isBursting())
addGlineToUplink(tmpGline);
}
else
{
int dots = 0;
string ipClass = "";
for(string::size_type ptr = 0;ptr < tIP.size() && dots < 3;++ptr)
{
if(tIP[ptr] == '.')
{
++dots;
}
ipClass += tIP[ptr];
}
ipClass += '*';
CurConnections = ++virtualClientsMap[NewUser->getDescription() + "@" + ipClass];
if((CurConnections > maxVClones) &&
(CurConnections > getExceptions("*@" + ipClass)))
{
/* check for rate limiting */
if ((virtualClientsMapLastWarn[NewUser->getDescription() + "@" + ipClass] + CClonesTime) <= time(NULL))
{
/* send the chanlog message and dont warn for another CClonesTime seconds */
MsgChanLog("Virtual clones for real name %s on %s, total connections %d\n",
NewUser->getDescription().c_str()
,ipClass.c_str()
,CurConnections);
virtualClientsMapLastWarn[NewUser->getDescription() + "@" + ipClass] = time(NULL);
}
}
}
}
}
/* TODO: actually remove this once we're certain.
if((!glSet))
{
ccGline * tempGline = findMatchingRNGline(NewUser);
if((tempGline) && (tempGline->getExpires() > ::time(0)))
{
glSet = true;
string tIP = xIP( NewUser->getIP()).GetNumericIP();
ccGline * theGline = new (std::nothrow) ccGline(SQLDb);
theGline->setHost(string("*@") + tIP);
theGline->setAddedBy(tempGline->getAddedBy());
theGline->setExpires((tempGline->getExpires() > 3600 + ::time(0)) ? 3600 : tempGline->getExpires() - time(0));
theGline->setAddedOn(tempGline->getAddedOn());
theGline->setLastUpdated(tempGline->getLastUpdated());
theGline->setReason(tempGline->getReason());
queueGline(theGline,false);
}
} */
}
/* check if they are already logged into us */
usersIterator tIterator = usersMap.begin();
while (tIterator != usersMap.end())
{
ccUser* tUser = tIterator->second;
if ((tUser->getLastAuthTS() == NewUser->getConnectTime()) &&
(tUser->getLastAuthNumeric() == NewUser->getCharYYXXX()))
{
/* it seems they are! authenticate them */
/* check if someone else is already authed as them */
if (tUser->getClient())
{
const iClient *tClient = tUser->getClient();
Notice(tClient, "You have just been deauthenticated");
MsgChanLog("Login conflict for user %s from %s and %s\n",
tUser->getUserName().c_str(), NewUser->getNickName().c_str(),
tClient->getNickName().c_str());
deAuthUser(tUser);
}
// tUser->setUserName(tUser->getUserName); // not required as we're already set
tUser->setNumeric(NewUser->getCharYYXXX());
// Try creating an authentication entry for the user
if (AuthUser(tUser, NewUser))
if (!(isSuspended(tUser)))
Notice(NewUser, "Automatic authentication after netsplit successful!", tUser->getUserName().c_str());
else
Notice(NewUser, "Automatic authentication after netsplit successful, however you are suspended", tUser->getUserName().c_str());
else
Notice(NewUser, "Error in authentication", tUser->getUserName().c_str());
MsgChanLog("(%s) - %s: AUTO-AUTHENTICATED (after netsplit)\n", tUser->getUserName().c_str(),
NewUser->getRealNickUserHost().c_str());
/* had enough checking, break out of the loop */
break;
}
++tIterator;
}
/* if we get here, there's no matching user */
}
void ccontrol::addGlineToUplink(ccGline* theGline)
{
int Expires;
if((theGline->getHost().substr(0,1) == "#")
&& (theGline->getExpires() == 0))
{
Expires = gline::PERM_TIME;
}
else
{
Expires = theGline->getExpires() - time(0);
}
MyUplink->setGline(theGline->getAddedBy()
,theGline->getHost(),theGline->getReason()
,Expires,theGline->getLastUpdated(),this);
}
ccUser* ccontrol::IsAuth( const iClient* theClient )
{
if(!theClient)
{
return NULL;
}
ccUserData *tempData = static_cast< ccUserData* >(theClient->getCustomData(this));
if(tempData)
{
return tempData->getDbUser() ;
}
else
{
return NULL;
}
}
int ccontrol::strToLevel(const string& level) {
int i=0;
while(levelMapper[i].first != 0) {
if(!strcasecmp(levelMapper[i].second,level )) {
return levelMapper[i].first;
}
i++;
}
return -1;
}
const string& ccontrol::levelToStr(unsigned int level) {
int i = 0;
while (levelMapper[i].first != 0) {
if (levelMapper[i].first == level) {
return levelMapper[i].second;
}
i++;
}
return levelMapper[i].second; //empty string
}
ccUser* ccontrol::IsAuth( const string& Numeric )
{
return IsAuth(Network->findClient(Numeric));
}
bool ccontrol::AddOper (ccUser* Oper)
{
static const char *Main = "INSERT INTO opers (user_name,password,access,saccess,last_updated_by,last_updated,flags,server,isSuspended,suspend_expires,suspended_by,suspend_level,suspend_reason,isUhs,isOper,isAdmin,isSmt,isCoder,GetLogs,NeedOp,Notice,GetLag,LastPassChangeTS) VALUES ('";
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << Main
<< removeSqlChars(Oper->getUserName()) <<"','"
<< removeSqlChars(Oper->getPassword()) << "',"
<< Oper->getAccess() << ","
<< Oper->getSAccess() << ",'"
<< removeSqlChars(Oper->getLast_Updated_by())
<< "',date_part('epoch', CURRENT_TIMESTAMP)::int,"
<< Oper->getFlags() << ",'"
<< removeSqlChars(Oper->getServer())
<< "' ,"
<< (Oper->getIsSuspended() ? "'t'" : "'n'")
<< "," << Oper->getSuspendExpires()
<< ",'" << Oper->getSuspendedBy()
<< "'," << Oper->getSuspendLevel()
<< ",'" << Oper->getSuspendReason()
<< "'," << (Oper->isUhs() ? "'t'" : "'n'")
<< "," << (Oper->isOper() ? "'t'" : "'n'")
<< "," << (Oper->isAdmin() ? "'t'" : "'n'")
<< "," << (Oper->isSmt() ? "'t'" : "'n'")
<< "," << (Oper->isCoder() ? "'t'" : "'n'")
<< "," << (Oper->getLogs() ? "'t'" : "'n'")
<< "," << (Oper->getNeedOp() ? "'t'" : "'n'")
<< "," << (Oper->getNotice() ? "'t'" : "'n'")
<< "," << (Oper->getLag() ? "'t'" : "'n'")
<< ",date_part('epoch', CURRENT_TIMESTAMP)::int"
<< ")"
<< ends;
if( SQLDb->Exec( theQuery.str().c_str() ) )
{
if(!Oper->loadData(Oper->getUserName()))
return false;
usersMap[Oper->getUserName()] = Oper;
return true;
}
elog << "ccontrol::AddOper> SQL Failure: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
bool ccontrol::DeleteOper (const string& Name)
{
if(!dbConnected)
{
return false;
}
ccUser* tUser = usersMap[Name];
//Delete the user hosts
if(tUser)
{
static const char *tMain = "DELETE FROM hosts WHERE User_Id = ";
stringstream HostQ;
HostQ << tMain;
HostQ << tUser->getID();
HostQ << ends;
#ifdef LOG_SQL
elog << "ccontrol::DeleteOper> "
<< HostQ.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( HostQ ) )
//if( PGRES_COMMAND_OK != status )
{
elog << "ccontrol::DeleteOper> SQL Failure: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
usersMap.erase(usersMap.find(Name));
}
static const char *Main = "DELETE FROM opers WHERE lower(user_name) = '";
stringstream theQuery;
theQuery << Main
<< removeSqlChars(Name)
<< "'"
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::DeleteOper> "
<< theQuery.str().c_str()
<< endl;
#endif
if( SQLDb->Exec( theQuery ) )
//if( PGRES_COMMAND_OK == status )
{
return true;
}
else
{
elog << "ccontrol::DeleteOper> SQL Failure: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
}
int ccontrol::getCommandLevel( const string& Command)
{
commandIterator commHandler = findCommand( Command ) ;
// Was a handler found?
if( commHandler != command_end() )
{
return commHandler->second->getFlags() ;
}
return -1 ;
}
bool ccontrol::AuthUser( ccUser* TempUser,iClient* tUser)
{
if(!tUser->getCustomData(this))
{
elog << "Couldnt find custom data for "
<< tUser->getNickName() << endl;
return false;
}
ccUserData* UserData= static_cast<ccUserData*>(tUser->getCustomData(this));
UserData->setDbUser(TempUser);
TempUser->setClient(tUser);
return true;
}
bool ccontrol::deAuthUser( ccUser* tUser)
{
const iClient* tClient = tUser->getClient();
if(tClient)
{
if(!tClient->getCustomData(this))
{
elog << "Couldnt find custom data for "
<< tClient->getNickName() << endl;
return false;
}
(static_cast<ccUserData*>(tClient->getCustomData(this)))->setDbUser(NULL);
tUser->setClient(NULL);
}
return true;
}
bool ccontrol::UserGotMask( ccUser* user, const string& Host )
{
static const char *Main = "SELECT host FROM hosts WHERE user_id = ";
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << Main
<< user->getID()
<< ';'
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::UserGotMask> "
<< theQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( theQuery, true ) )
//if( PGRES_TUPLES_OK != status )
{
elog << "ccontrol::UserGotMask> SQL Failure: "
<< SQLDb->ErrorMessage()
<< endl ;
return false ;
}
for( unsigned int i = 0 ; i < SQLDb->Tuples() ; i++ )
{
if(match(SQLDb->GetValue(i,0),Host) == 0)
{
return true ;
}
}
return false ;
}
bool ccontrol::UserGotHost( ccUser* user, const string& Host )
{
static const char *Main = "SELECT host FROM hosts WHERE user_id = ";
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << Main
<< user->getID()
<< ';'
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::UserGotHost> "
<< theQuery.str().c_str()
<< endl;
#endif
if( SQLDb->Exec( theQuery, true ) )
//if( PGRES_TUPLES_OK == status )
{
for( unsigned int i = 0 ; i < SQLDb->Tuples() ; i++ )
{
if(!strcasecmp(SQLDb->GetValue(i,0),Host.c_str()))
{
return true ;
}
}
}
return false ;
}
string ccontrol::CryptPass( const string& pass )
{
StringTokenizer st( pass ) ;
const char validChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.$*_";
string salt;
for ( unsigned short int i = 0 ; i < 8 ; i++ )
{
int randNo = 1+(int) (64.0*rand()/(RAND_MAX+1.0));
salt += validChars[randNo];
}
/* Work out a MD5 hash of our salt + password */
md5 hash; // MD5 hash algorithm object.
md5Digest digest; // MD5Digest algorithm object.
stringstream output;
string newPass;
newPass = salt + st.assemble(0);
hash.update( (const unsigned char *)newPass.c_str(), newPass.size() );
hash.report( digest );
/* Convert to Hex */
int data[ MD5_DIGEST_LENGTH ] = { 0 } ;
for( size_t ii = 0; ii < MD5_DIGEST_LENGTH; ii++ )
{
data[ii] = digest[ii];
}
output << hex;
output.fill('0');
for( size_t ii = 0; ii < MD5_DIGEST_LENGTH; ii++ )
{
output << setw(2) << data[ii];
}
output << ends;
return string( salt + output.str().c_str() );
}
bool ccontrol::validUserMask(const string& userMask) const
{
// Check that a '!' exists, and that the nickname
// is no more than 9 characters
StringTokenizer st1( userMask, '!' ) ;
if( (st1.size() != 2) || (st1[ 0 ].size() > 9) )
{
return false ;
}
// Check that a '@' exists and that the username is
// no more than 12 characters
StringTokenizer st2( st1[ 1 ], '@' ) ;
if( (st2.size() != 2) || (st2[ 0 ].size() > 12) )
{
return false ;
}
// Be sure that the hostname is no more than 128 characters
if( st2[ 1 ].size() > 128 )
{
return false ;
}
// Tests have passed
return true ;
}
bool ccontrol::AddHost( ccUser* user, const string& host )
{
if(!dbConnected)
{
return false;
}
static const char *Main = "INSERT INTO hosts (user_id,host) VALUES (";
stringstream theQuery;
theQuery << Main
<< user->getID() <<",'"
<< removeSqlChars(host) << "')"
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::AddHost> "
<< theQuery.str().c_str()
<< endl;
#endif
if( SQLDb->Exec( theQuery ) )
//if( PGRES_COMMAND_OK == status )
{
return true;
}
else
{
elog << "ccontrol::AddHost> SQL Error: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
}
bool ccontrol::DelHost( ccUser* user, const string& host )
{
if(!dbConnected)
{
return false;
}
static const char *Main = "DELETE FROM hosts WHERE user_id = ";
stringstream theQuery;
theQuery << Main
<< user->getID()
<< " And host = '"
<< removeSqlChars(host) << "'"
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::DelHost> "
<< theQuery.str().c_str()
<< endl;
#endif
if( SQLDb->Exec( theQuery ) )
//if( PGRES_COMMAND_OK == status )
{
return true;
}
else
{
elog << "ccontrol::DelHost> SQL Error: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
}
bool ccontrol::listHosts( ccUser* User, iClient* theClient )
{
static const char* queryHeader
= "SELECT host FROM hosts WHERE user_id = ";
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << queryHeader
<< User->getID()
<< ends;
if( !SQLDb->Exec( theQuery, true ) )
//if( PGRES_TUPLES_OK != status )
{
elog << "LISTHOSTS> SQL Error: "
<< SQLDb->ErrorMessage()
<< endl ;
return false ;
}
// SQL Query succeeded
Notice(theClient,"Host list for %s",User->getUserName().c_str());
for (unsigned int i = 0 ; i < SQLDb->Tuples(); i++)
{
Notice(theClient,"%s",SQLDb->GetValue(i, 0).c_str());
}
return true;
}
bool ccontrol::GetHelp( iClient* user, const string& command )
{
static const char *Main = "SELECT line,help FROM help WHERE lower(command) = '";
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << Main
<< string_lower(removeSqlChars(command))
<< "' ORDER BY line"
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::GetHelp> "
<< theQuery.str().c_str()
<< endl;
#endif
if( SQLDb->Exec( theQuery, true ) )
//if( PGRES_TUPLES_OK == status )
{
if(SQLDb->Tuples() > 0 )
{
DoHelp(user);
}
else
{
Notice( user,
"Couldn't find help for %s",
command.c_str());
}
return true;
}
else
{
elog << "ccontrol::GetHelp> SQL Error: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
}
bool ccontrol::GetHelp( iClient* user, const string& command , const string& subcommand)
{
static const char *Main = "SELECT line,help FROM help WHERE lower(command) = '";
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << Main
<< string_lower(removeSqlChars(command))
<< "' and lower(subcommand) = '"
<< string_lower(removeSqlChars(subcommand))
<< "' ORDER BY line"
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::GetHelp> "
<< theQuery.str().c_str()
<< endl;
#endif
if( SQLDb->Exec( theQuery, true ) )
//if( PGRES_TUPLES_OK == status )
{
if(SQLDb->Tuples() > 0 )
{
DoHelp(user);
}
else
{
Notice( user,
"Couldn't find help for %s",
command.c_str());
}
return true;
}
else
{
elog << "ccontrol::GetHelp> SQL Error: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
}
void ccontrol::DoHelp(iClient* theClient)
{
for( unsigned int i = 0 ; i < SQLDb->Tuples() ; i++ )
{
string commInfo = replace(
SQLDb->GetValue( i, 1 ),
"$BOT$",
nickName ) ;
Notice(theClient,"%s",commInfo.c_str());
} // for()
}
string ccontrol::replace( const string& srcString,
const string& from,
const string& to )
{
string retMe( srcString ) ;
string::size_type beginPos = 0 ;
while((beginPos = retMe.find(from)) <= retMe.size())
{
retMe.replace(beginPos,from.size(),to);
}
return retMe ;
}
ccUser* ccontrol::GetOper( const string Name)
{
ccUser* tempUser = usersMap[Name];
if(!tempUser)
{
usersMap.erase(usersMap.find(Name));
}
return tempUser;
}
ccUser* ccontrol::GetOper( unsigned int ID)
{
usersIterator tIterator = usersMap.begin();
while(tIterator != usersMap.end())
{
ccUser* tUser = tIterator->second;;
if(tUser->getID() == ID)
{
return tIterator->second;
}
++tIterator;
}
return NULL;
}
bool ccontrol::addGline( ccGline* TempGline)
{
glineIterator ptr;
if(TempGline->getHost().substr(0,1) == "$") //check if its a realname gline
{
ptr = rnGlineList.find(TempGline->getHost());
if(ptr != rnGlineList.end())
{
if(ptr->second != TempGline)
{
delete ptr->second;
rnGlineList.erase(ptr);
}
}
rnGlineList[TempGline->getHost()] = TempGline;
}
else
{
ptr = glineList.find(TempGline->getHost());
if(ptr != glineList.end())
{
if(ptr->second != TempGline)
{
delete ptr->second;
glineList.erase(ptr);
}
}
glineList[TempGline->getHost()] = TempGline;
}
return true;
}
bool ccontrol::remGline( ccGline* TempGline)
{
if(TempGline->getHost().substr(0,1) == "$")
{
rnGlineList.erase(TempGline->getHost());
}
else
{
glineList.erase(TempGline->getHost()) ;
}
return true;
}
vector< ccGline* > ccontrol::findAllMatchingGlines(const string& Mask)
{
ccGline *tmpGline;
vector< ccGline* > retMe;
for (glineListType::const_iterator ptr = gline_begin(); ptr != gline_end(); ++ptr)
{
tmpGline = ptr->second;
if (!match(Mask,tmpGline->getHost()))
retMe.push_back(tmpGline);
}
for (glineListType::const_iterator ptr = rnGlineList.begin(); ptr != rnGlineList.end(); ++ptr)
{
tmpGline = ptr->second;
if (!match(Mask,tmpGline->getHost()))
retMe.push_back(tmpGline);
}
return retMe;
}
bool ccontrol::removeAllMatchingGlines(const string& Mask)
{
bool AllOk = true;
vector< ccGline* > vGlines;
vGlines = findAllMatchingGlines(Mask);
for (vector< ccGline* >::size_type i = 0; i < vGlines.size(); i++)
{
if (!vGlines.at(i)->Delete())
{
MsgChanLog("Error while removing gline for host %s from the db\n",vGlines[i]->getHost().c_str());
AllOk = false;
}
MyUplink->removeGline(vGlines[i]->getHost(),this);
delete(vGlines.at(i));
}
vGlines.clear();
return AllOk;
}
ccGline* ccontrol::findMatchingGline( const iClient* theClient )
{
ccGline *theGline = 0;
string Host = theClient->getUserName() + '@' + theClient->getRealInsecureHost();
string IP = theClient->getUserName() + '@' + xIP( theClient->getIP()).GetNumericIP();
string RealName = theClient->getDescription();
string glineHost;
for(glineIterator ptr = glineList.begin(); ptr != glineList.end(); ++ptr)
{
theGline = ptr->second;
if((match(theGline->getHost(),Host) == 0) ||
((match(theGline->getHost(),IP) == 0)))
{
if(theGline->getExpires() > ::time(0))
{
return theGline;
}
}
}
for(glineIterator ptr = rnGlineList.begin(); ptr != rnGlineList.end(); ++ptr)
{
theGline = ptr->second;
glineHost = theGline->getHost().substr(1,theGline->getHost().size() - 1);
if(match(glineHost,RealName) == 0)
{
if(theGline->getExpires() > ::time(0))
{
return theGline;
}
}
}
return NULL ;
}
ccGline* ccontrol::findMatchingRNGline( const iClient* theClient )
{
ccGline *theGline = 0;
string RealName = theClient->getDescription();
string glineHost;
for(glineIterator ptr = rnGlineList.begin(); ptr != rnGlineList.end(); ++ptr)
{
theGline = ptr->second;
glineHost = theGline->getHost().substr(1,theGline->getHost().size() - 1);
if(match(glineHost,RealName) == 0)
{
if(theGline->getExpires() > ::time(0))
{
return theGline;
}
}
}
return NULL ;
}
ccGline* ccontrol::findGline( const string& HostName )
{
glineIterator ptr = glineList.find(HostName);
if(ptr != glineList.end())
{
return ptr->second;
}
return NULL ;
}
ccGline* ccontrol::findRealGline( const string& HostName )
{
glineIterator ptr = rnGlineList.find(HostName);
if(ptr != rnGlineList.end())
{
return ptr->second;
}
return NULL ;
}
struct tm ccontrol::convertToTmTime(time_t NOW)
{
return *gmtime(&NOW);
}
// TODO: This method should never exist
char *ccontrol::convertToAscTime(time_t NOW)
{
time_t *tNow = &NOW;
struct tm* Now = gmtime(tNow);
char *ATime = asctime(Now);
ATime[strlen(ATime)-1] = '\0';
return ATime;
}
bool ccontrol::MsgChanLog(const char *Msg, ... )
{
if(!Network->findChannel(msgChan))
{
return false;
}
char buffer[ 1024 ] = { 0 } ;
va_list list;
va_start( list, Msg ) ;
vsprintf( buffer, Msg, list ) ;
va_end( list ) ;
xClient::Notice((Network->findChannel(msgChan))->getName(),"%s",buffer);
usersIterator uIterator;
ccUser* tempUser;
for( uIterator = usersMap.begin();uIterator != usersMap.end();++uIterator)
{
tempUser = uIterator->second;
if((tempUser) && (tempUser->getLogs() ) && (tempUser->getClient()))
{
Notice(tempUser->getClient(),"%s",buffer);
}
}
return true;
}
bool ccontrol::MsgChanLag(const char *Msg, ... )
{
if(!Network->findChannel(msgChan))
{
return false;
}
char buffer[ 1024 ] = { 0 } ;
va_list list;
va_start( list, Msg ) ;
vsprintf( buffer, Msg, list ) ;
va_end( list ) ;
xClient::Notice((Network->findChannel(msgChan))->getName(),"%s",buffer);
usersIterator uIterator;
ccUser* tempUser;
for( uIterator = usersMap.begin();uIterator != usersMap.end();++uIterator)
{
tempUser = uIterator->second;
if((tempUser) && (tempUser->getLag() ) && (tempUser->getClient()))
{
Notice(tempUser->getClient(),"%s",buffer);
}
}
return true;
}
#ifndef LOGTOHD
bool ccontrol::DailyLog(ccUser* Oper, const char *Log, ... )
{
if(!dbConnected)
{
return false;
}
char buffer[ 1024 ] ;
memset( buffer, 0, 1024 ) ;
va_list list;
va_start( list, Log ) ;
vsprintf( buffer, Log, list ) ;
va_end( list ) ;
iClient* theClient = 0 ;
if(Oper)
{
theClient = Network->findClient(Oper->getNumeric());
}
iServer* targetServer = Network->findServer( theClient->getIntYY() ) ;
if( NULL == targetServer )
{
elog << "ccontrol:> Unable to find server: "
<< theClient->getIntYY() << endl ;
return false ;
}
buffer[ 512 ] = 0 ;
static const char *Main = "INSERT INTO comlog (ts,oper,command) VALUES (date_part('epoch', CURRENT_TIMESTAMP)::int,'";
StringTokenizer st(buffer);
commandIterator tCommand = findCommand((string_upper(st[0])));
string log;
if(tCommand != command_end())
{
if(!strcasecmp(tCommand->second->getRealName(),"LOGIN"))
{
if (st.size() > 1)
log.assign(string("LOGIN ") + st[1] + string(" *****") + string(" (") + targetServer->getName() + string(")"));
}
else if(!strcasecmp(tCommand->second->getRealName(),"NEWPASS"))
{
log.assign("NEWPASS *****");
}
else if(!strcasecmp(tCommand->second->getRealName(),"MODUSER"))
{
if(st.size() > 2)
{
log.assign("MODUSER " + st[1] + " ");
unsigned int place = 2;
while(place < st.size())
{
if(!strcasecmp(st[place],"-p"))
{
log.append(" -p ******");
place+=2;
}
else
{
log.append(" " + st[place]);
place++;
}
}
}
}
else if(!strcasecmp(tCommand->second->getRealName(),"ADDUSER"))
{
if(st.size() > 3)
{
log.assign("ADDUSER " + st[1] + string(" ") + st[2]+ " *****");
}
}
else
{
log.assign(buffer);
}
}
else
{
log.assign(buffer);
}
strcpy(buffer,log.c_str());
stringstream theQuery;
theQuery << Main;
if(Oper)
{
theQuery << Oper->getUserName();
}
else
{
theQuery << "Unknown";
}
theQuery << " (" << removeSqlChars(theClient->getRealNickUserHost()) <<")','"
<< removeSqlChars(buffer) << "')"
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::DailyLog> "
<< theQuery.str().c_str()
<< endl;
#endif
if( SQLDb->Exec( theQuery ) )
//if( PGRES_COMMAND_OK == status )
{
return true;
}
else
{
elog << "ccontrol::DailyLog> SQL Error: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
return true;
}
bool ccontrol::DailyLog(iClient* theClient, const char *Log, ... )
{
if(!dbConnected)
{
return false;
}
char buffer[ 1024 ] = { 0 } ;
va_list list;
va_start( list, Log ) ;
vsprintf( buffer, Log, list ) ;
va_end( list ) ;
buffer[512]= '\0';
static const char *Main = "INSERT INTO comlog (ts,oper,command) VALUES (date_part('epoch', CURRENT_TIMESTAMP)::int,'";
StringTokenizer st(buffer);
commandIterator tCommand = findCommand((string_upper(st[0])));
string log;
iServer* targetServer = Network->findServer( theClient->getIntYY() ) ;
if( NULL == targetServer )
{
elog << "ccontrol:> Unable to find server: "
<< theClient->getIntYY() << endl ;
return false ;
}
if(tCommand != command_end())
{
if(!strcasecmp(tCommand->second->getRealName(),"LOGIN"))
{
if (st.size() > 1)
log.assign(string("LOGIN ") + st[1] + string(" *****") + string(" (") + targetServer->getName() + string(")"));
}
else if(!strcasecmp(tCommand->second->getRealName(),"NEWPASS"))
{
log.assign("NEWPASS *****");
}
else if(!strcasecmp(tCommand->second->getRealName(),"MODUSER"))
{
if(st.size() > 2)
{
log.assign("MODUSER " + st[1] + " ");
unsigned int place = 2;
while(place < st.size())
{
if(!strcasecmp(st[place],"-p"))
{
log.append(" -p ******");
place+=2;
}
else
{
log.append(" " + st[place]);
place++;
}
}
}
}
else if(!strcasecmp(tCommand->second->getRealName(),"ADDUSER"))
{
if(st.size() > 3)
{
log.assign("ADDUSER " + st[1] + string(" ") + st[2]+ " *****");
}
}
else
{
log.assign(buffer);
}
}
else
{
log.assign(buffer);
}
strcpy(buffer,log.c_str());
stringstream theQuery;
theQuery << Main
<< "Unknown"
<< " (" << removeSqlChars(theClient->getRealNickUserHost()) <<")','"
<< removeSqlChars(buffer) << "')"
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::DailyLog> "
<< theQuery.str().c_str()
<< endl;
#endif
if( SQLDb->Exec( theQuery ) )
//if( PGRES_COMMAND_OK == status )
{
return true;
}
else
{
elog << "ccontrol::DailyLog> SQL Error: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
return true;
}
#else
bool ccontrol::DailyLog(ccLog* newLog)
{
commandIterator tCommand = findCommand(newLog->CommandName);
string log;
StringTokenizer st(newLog->Desc);
StringTokenizer st2(newLog->Host,'!');
if (st.size() == 0)
return 0;
iClient* theClient = Network->findNick(st2[0]);
iServer* targetServer;
if (theClient != NULL)
{
targetServer = Network->findServer( theClient->getIntYY() ) ;
if( NULL == targetServer )
{
elog << "ccontrol:> Unable to find server: "
<< theClient->getIntYY() << endl ;
return false ;
}
}
if(tCommand != command_end())
{
if(!strcasecmp(tCommand->second->getRealName(),"LOGIN"))
{
if (st.size() > 1)
{
if (theClient != NULL)
log.assign(string("LOGIN ") + st[1] + string(" *****") + string(" (") + targetServer->getName() + string(")"));
else
log.assign(string("LOGIN ") + st[1] + string(" *****"));
}
}
else if(!strcasecmp(tCommand->second->getRealName(),"NEWPASS"))
{
log.assign("NEWPASS *****");
}
else if(!strcasecmp(tCommand->second->getRealName(),"MODUSER"))
{
if(st.size() > 2)
{
log.assign("MODUSER " + st[1] + " ");
unsigned int place = 2;
while(place < st.size())
{
if(!strcasecmp(st[place],"-p"))
{
log.append(" -p ******");
place+=2;
}
else
{
log.append(" " + st[place]);
place++;
}
}
}
}
else if(!strcasecmp(tCommand->second->getRealName(),"ADDUSER"))
{
if(st.size() > 3)
{
log.assign("ADDUSER " + st[1] + string(" ") + st[2]+ " *****");
}
}
else
{
log.assign(newLog->Desc);
}
}
else
{
log.assign(newLog->Desc);
}
newLog->Desc = log;
if(!LogFile.is_open())
{
LogFile.open(LogFileName.c_str(),ios::out|ios::app);
//LogFile.setbuf(NULL,0);
}
if(LogFile.bad())
{//There was a problem in opening the log file
MsgChanLog("Error while logging to the log file %s!\n",LogFileName.c_str());
return true;
}
LogFile.seekp(0,ios::end);
if(!newLog->Save(LogFile))
{
MsgChanLog("Error while logging to the log file!\n");
}
addLog(newLog);
LogFile.close();
if(NumOfLogs > 0)
NumOfLogs++;
return true;
}
#endif
bool ccontrol::CreateReport(time_t From, time_t Til)
{
if(!dbConnected)
{
return false;
}
static const char* queryHeader = "SELECT * FROM comlog WHERE ts >";
stringstream theQuery;
theQuery << queryHeader
<< From
<< " AND ts < "
<< Til
<< " ORDER BY ts DESC"
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::CreateReport> "
<< theQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( theQuery, true ) )
//if( PGRES_TUPLES_OK != status )
{
elog << "ccontrol::CreateReport> SQL Error: "
<< SQLDb->ErrorMessage()
<< endl ;
return false ;
}
// SQL Query succeeded
ofstream tLogFile;
tLogFile.open("Report.log",ios::out);
if(!tLogFile)
{
return false;
}
tLogFile << "ccontrol log for command issued between "
<< convertToAscTime(From)
<< " and up til "
<< convertToAscTime(Til)
<< endl;
for (unsigned int i = 0 ; i < SQLDb->Tuples(); i++)
{
tLogFile << "[ "
<< convertToAscTime(atoi(SQLDb->GetValue(i, 0).c_str()))
<< " - "
<< SQLDb->GetValue(i,1)
<< " ] "
<< SQLDb->GetValue(i,2)
<< endl;
}
tLogFile << "End of debug log"
<< endl ;
tLogFile.close();
return true;
}
bool ccontrol::MailReport(const char *MailTo, const char *ReportFile)
{
ifstream Report;
Report.open(Sendmail_Path.c_str(),ios::in);
if(!Report)
{
MsgChanLog("Error cant find sendmail, check the conf setting and"
" try again\n");
return false;
}
Report.close();
Report.open(ReportFile,ios::in);
if(!Report)
{
MsgChanLog("Error while sending report\n");
return false;
}
ofstream TMail;
TMail.open("Report.mail",ios::out);
if(!TMail)
{
MsgChanLog("Error while sending report\n");
return false;
}
TMail << "Subject : CControl command log report\n";
string line ;
while( std::getline( Report, line ) )
{
TMail << line
<< endl ;
}
TMail.close();
Report.close();
char SendMail[256] = { 0 };
sprintf(SendMail, "%s -f %s %s < Report.mail\n",
Sendmail_Path.c_str(),
CCEmail.c_str(),
MailTo);
system(SendMail);
return true;
}
int ccontrol::checkGline(const string Host,unsigned int Len,unsigned int &Affected)
{
const unsigned int isWildCard = 0x01;
const unsigned int isIP = 0x02;
unsigned int Mask = 0;
unsigned int Dots = 0;
unsigned int GlineType = isIP;
bool ParseEnded = false;
bool isCIDR = false;
int retMe = 0, i = 0;
char CIDRip[16];
int client_addr[4] = { 0 };
unsigned long mask_ip, orig_mask_ip;
string::size_type pos = Host.find_first_of('@');
string Ident = Host.substr(0,pos);
string Hostname = Host.substr(pos+1);
if(Len > gline::MFU_TIME) //Check for maximum time
retMe |= gline::BAD_TIME;
if((signed int) Len < 0)
retMe |= gline::NEG_TIME;
if (Hostname[0] == '.')
retMe |= gline::BAD_HOST;
for(string::size_type pos = 0; pos < Hostname.size();++pos)
{
if(Hostname[pos] =='.')
{
Dots++;
if((GlineType & (isWildCard | isIP)) == isIP)
Mask+=8; //Keep track of the mask
if (Hostname[pos+1] == '.')
retMe |= gline::BAD_HOST;
}
else if((Hostname[pos] =='*') || (Hostname[pos] == '?'))
GlineType |= isWildCard;
else if(Hostname[pos] == '/')
{
if (!(GlineType & isIP)) // must be an ip to specify
return gline::BAD_HOST;
if (Dots>3) // can't have more than 3 dots
return gline::BAD_HOST;
if (GlineType & isWildCard) // cidr may not contain wildcards
return gline::BAD_HOST;
/* copy the mask to CIDRip */
if (pos > 15)
pos = 15;
for (i=0; i<(int) pos; i++)
CIDRip[i] = Hostname[i];
CIDRip[i++] = '\0';
Mask = atol((Hostname.substr(++pos)).c_str());
isCIDR = true;
retMe |= gline::FORCE_NEEDED_HOST;
/* check if the mask matches the cidr size */
i = sscanf(CIDRip, "%d.%d.%d.%d", &client_addr[0], &client_addr[1], &client_addr[2], &client_addr[3]);
mask_ip = ntohl((client_addr[0]) | (client_addr[1] << 8) | (client_addr[2] << 16) | (client_addr[3] << 24));
orig_mask_ip = mask_ip;
for (i = 0; i < (32 - (int) Mask); i++)
{
/* right shift */
mask_ip >>= 1;
}
for (i = 0; i < (32 - (int) Mask); i++)
{
/* left shift */
mask_ip <<= 1;
}
if (mask_ip != orig_mask_ip)
{
/* mask no longer matches the original mask - ip was not on the bit boundary */
retMe |= gline::BAD_CIDRMASK;
}
if (!(Mask) || (Mask > 32))
retMe |= gline::BAD_HOST;
if (Mask < 16)
retMe |= gline::BAD_CIDRLEN;
if (Mask < 32)
GlineType |= isWildCard;
if ((GlineType & isIP) && (isCIDR) && (Dots != 3))
retMe |= gline::BAD_CIDROVERRIDE;
ParseEnded = true;
break;
}
else if((Hostname[pos] > '9') || (Hostname[pos] < '0'))
GlineType &= ~isIP;
}
Affected = Network->countMatchingRealUserHost(Host); //Calculate the number of affected
if((Dots > 3) && (GlineType & isIP)) //IP addy cant have more than 3 dots
retMe |= gline::BAD_HOST;
if(((GlineType & (isIP || isWildCard)) == isIP) && !(ParseEnded))
Mask +=8; //Add the last mask count if needed
if((GlineType & isIP) && (Mask < 24))
retMe |= gline::HUH_NO_HOST; //Its too wide
if(!(GlineType & isIP) && (Dots < 2) && (GlineType & isWildCard))
retMe |= gline::HUH_NO_HOST; //Wildcard gline must have atleast 2 dots
if(Affected > gline::MFGLINE_USERS)
retMe |= gline::FU_NEEDED_USERS; //This gline must be set with -fu flag
if(Len > gline::MFGLINE_TIME)
retMe |= gline::FU_NEEDED_TIME;
if(Len > gline::MGLINE_TIME)
retMe |= gline::FORCE_NEEDED_TIME;
if(GlineType & (isWildCard))
{//Need to check the Ident now
bool hasId = false;
for(string::size_type pos = 0; pos < Ident.size();++pos)
{
if((Ident[pos] == '*') || (Ident[pos] == '?'))
{
continue;
}
else
{ //Its not */? so we have a legal ident
hasId = true;
break;
}
}
if((hasId & (Len > gline::MGLINE_WILD_TIME))
|| (!hasId & (Len > gline::MGLINE_WILD_NOID_TIME)))
{
retMe |= gline::FORCE_NEEDED_WILDTIME;
}
}
if (getExceptions("*@" + Hostname) > 0)
{
retMe |= gline::HUH_IS_EXCEPTION;
}
if (isIpOfOper(Hostname))
retMe |= gline::HUH_IS_IP_OF_OPER;
//if(GlineType & (isWildCard & (Len > gline::MGLINE_WILD_TIME)))
// retMe |= gline::FORCE_NEEDED_WILDTIME;
if(!retMe)
retMe = gline::GLINE_OK;
return retMe;
}
int ccontrol::checkSGline(const string Host,unsigned int Len,unsigned int &Affected)
{
const unsigned int isWildCard = 0x01;
const unsigned int isIP = 0x02;
unsigned int Mask = 0;
unsigned int Dots = 0;
unsigned int GlineType = isIP;
bool ParseEnded = false;
bool hasId = false;
bool isCIDR = false;
int retMe = 0, i = 0;
char CIDRip[16];
int client_addr[4] = { 0 };
unsigned long mask_ip, orig_mask_ip;
string::size_type pos = Host.find_first_of('@');
string Ident = Host.substr(0,pos);
string Hostname = Host.substr(pos+1);
if((signed int)Len < 0)
retMe |= gline::NEG_TIME;
//Check the ident first, if its valid then the gline is ok
Affected = Network->countMatchingUserHost(Host); //Calculate the number of affected
for(string::size_type pos = 0; pos < Ident.size();++pos)
{
if((Ident[pos] == '*') || (Ident[pos] == '?'))
{
continue;
}
else
{ //Its not */? so we have a legal ident
hasId = true;
break;
}
}
if(hasId)
return gline::GLINE_OK;
if (Hostname[0]=='.')
retMe |= gline::BAD_HOST;
for(string::size_type pos = 0; pos < Hostname.size();++pos)
{
if(Hostname[pos] =='.')
{
Dots++;
if((GlineType & (isWildCard | isIP)) == isIP)
Mask+=8; //Keep track of the mask
if (Hostname[pos+1] == '.')
retMe |= gline::BAD_HOST;
}
else if((Hostname[pos] =='*') || (Hostname[pos] == '?'))
GlineType |= isWildCard;
else if(Hostname[pos] == '/')
{
if (!(GlineType & isIP)) // must be an ip to specify CIDR mask
return gline::BAD_HOST;
if (GlineType & isWildCard) // cidr can't contain wildcards
return gline::BAD_HOST;
/* copy the mask to CIDRip */
if (pos > 15)
pos = 15;
for (i=0; i<(int) pos; i++)
CIDRip[i] = Hostname[i];
CIDRip[i++] = '\0';
Mask = atol((Hostname.substr(++pos)).c_str());
isCIDR = true;
/* check if the mask matches the cidr size */
i = sscanf(CIDRip, "%d.%d.%d.%d", &client_addr[0], &client_addr[1], &client_addr[2], &client_addr[3]);
mask_ip = ntohl((client_addr[0]) | (client_addr[1] << 8) | (client_addr[2] << 16) | (client_addr[3] << 24));
orig_mask_ip = mask_ip;
for (i = 0; i < (32 - (int) Mask); i++)
{
/* right shift */
mask_ip >>= 1;
}
for (i = 0; i < (32 - (int) Mask); i++)
{
/* left shift */
mask_ip <<= 1;
}
if (mask_ip != orig_mask_ip)
{
/* mask no longer matches the original mask - ip was not on the bit boundary */
retMe |= gline::BAD_CIDRMASK;
}
if(!(Mask) || (Mask > 32)) // must be under a /32 to be valid
retMe |= gline::BAD_HOST;
if(Mask < 8) // must be a /8 or more specific
retMe |= gline::BAD_CIDRLEN;
if(Mask < 32)
GlineType |= isWildCard;
ParseEnded = true;
break;
}
else if((Hostname[pos] > '9') || (Hostname[pos] < '0'))
GlineType &= ~isIP;
}
if((Dots > 3) && (GlineType & isIP)) //IP addy cant have more than 3 dots
retMe |= gline::BAD_HOST;
if((GlineType & isIP) && (isCIDR) && (Dots != 3))
retMe |= gline::BAD_CIDROVERRIDE;
if(((GlineType & (isIP || isWildCard)) == isIP) && !(ParseEnded))
Mask +=8; //Add the last mask count if needed
if((GlineType & isIP) && (Mask < 8))
retMe |= gline::HUH_NO_HOST; //Its too wide
if(!(GlineType & isIP) && (Dots < 1) && (GlineType & isWildCard))
retMe |= gline::HUH_NO_HOST; //Wildcard gline must have atleast 2 dots
if(!retMe)
retMe = gline::GLINE_OK;
return retMe;
}
bool ccontrol::isSuspended(ccUser *theUser)
{
if( (theUser) && (theUser->getIsSuspended()))
{
//Check if the suspend hadnt already expired
if(::time( 0 ) - theUser->getSuspendExpires() < 0)
{
return true;
}
}
return false;
}
bool ccontrol::refreshSuspention()
{
int totalCount = 0;
usersIterator curUser = usersMap.begin();
ccUser* tempUser;
for(;curUser != usersMap.end();++curUser)
{
tempUser = curUser->second;
if((tempUser->getIsSuspended()) && (tempUser->getSuspendExpires() < ::time(0)))
{
tempUser->setSuspendExpires(0);
tempUser->setSuspendedBy("");
tempUser->setIsSuspended(false);
tempUser->setSuspendLevel(0);
tempUser->setSuspendReason("");
++totalCount;
}
}
static const char *DelMain = "UPDATE opers SET isSuspended = 'n',Suspend_Expires = 0, Suspended_by = '',suspend_level = 0,suspend_reason='' WHERE IsSuspended = 'y' AND suspend_expires < date_part('epoch', CURRENT_TIMESTAMP)::int";
stringstream DelQuery;
DelQuery << DelMain
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::RefreshSuspention> "
<< DelQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( DelQuery ) )
//if( PGRES_COMMAND_OK != status )
{
elog << "ccontrol::refreshSuspention> SQL Failure: "
<< SQLDb->ErrorMessage()
<< endl ;
return false ;
}
if(totalCount > 0)
MsgChanLog("[Refresh Suspend] - %d expired\n",totalCount);
return true;
}
bool ccontrol::refreshVersions()
{
ccServer* curServer;
const iServer* curNetServer;
for(serversConstIterator ptr = serversMap_begin();
ptr != serversMap_end(); ++ptr)
{
curServer = ptr->second;
curNetServer = curServer->getNetServer();
if(curNetServer)
{
Write("%s V :%s\n",getCharYYXXX().c_str(),
curNetServer->getCharYY().c_str());
}
}
return true;
}
bool ccontrol::refreshGlines()
{
if(!dbConnected)
{
return false;
}
int totalFound = 0;
inRefresh = true;
ccGline * tempGline;
list<string> remList;
list<string>::iterator remIterator;
for(glineIterator ptr = glineList.begin();ptr != glineList.end();++ptr)
{
tempGline = ptr->second;
if((tempGline->getExpires() <= ::time(0))
&& ((tempGline->getHost().substr(0,1) != "#") ||
(tempGline->getExpires() != 0)))
{
//remove the gline from the database
tempGline->Delete();
remList.push_back(ptr->first);
// ptr = glineList.erase(ptr);
delete tempGline;
++totalFound;
}
}
for(remIterator = remList.begin();remIterator != remList.end();)
{
glineList.erase(*remIterator);
remIterator = remList.erase(remIterator);
}
for(glineIterator ptr = rnGlineList.begin();ptr != rnGlineList.end();++ptr)
{
tempGline = ptr->second;
if(tempGline->getExpires() <= ::time(0))
{
//remove the gline from the database
tempGline->Delete();
//ptr = rnGlineList.erase(ptr);
remList.push_back(ptr->first);
delete tempGline;
++totalFound;
}
}
for(remIterator = remList.begin();remIterator != remList.end();)
{
rnGlineList.erase(*remIterator);
remIterator = remList.erase(remIterator);
}
inRefresh = false;
//if(totalFound > 0)
// MsgChanLog("[Refresh Glines] - %d expired\n",totalFound);
return true;
}
void ccontrol::queueGline(ccGline* theGline, bool shouldAdd)
{
glineQueue.push_back(glineQueueDataType(theGline,shouldAdd));
}
bool ccontrol::processGlineQueue()
{
if (getUplink()->isBursting() || glineQueue.empty())
{
return true;
}
glineQueueDataType curGlinePtr;
ccGline* curGline;
unsigned int count;
char us[100];
us[0] = '\0';
for(unsigned int i = 0; i< (glineQueue.size() > glineBurstCount ? glineBurstCount : glineQueue.size());++i)
{
curGlinePtr = glineQueue.front();
glineQueue.pop_front();
curGline = curGlinePtr.first;
count = Network->countMatchingRealUserHost(curGline->getHost());
us[0] = '\0';
sprintf(us,"%d",count);
curGline->setReason(string("[") + us + string("] ") + curGline->getReason());
curGline->setExpires(curGline->getExpires() + ::time(0));
addGlineToUplink(curGline);
if(curGlinePtr.second) //Do we need to add it to the db?
{
if(!curGline->Insert())
{
MsgChanLog("Error while adding gline on host %s to the database!\n",
curGline->getHost().c_str());
}
else
{
curGline->loadData(curGline->getHost());
}
addGline(curGline);
} else {
delete curGline;
}
}
return true;
}
bool ccontrol::loadGlines()
{
//static const char *Main = "SELECT * FROM glines WHERE ExpiresAt > date_part('epoch', CURRENT_TIMESTAMP)::int";
if(!dbConnected)
{
return false;
}
static const char *Main = "SELECT Id,Host,AddedBy,AddedOn,ExpiresAt,LastUpdated,Reason FROM glines";
stringstream theQuery;
theQuery << Main
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::loadGlines> "
<< theQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( theQuery, true ) )
//if( PGRES_TUPLES_OK != status )
{
elog << "ccontrol::loadGlines> SQL Failure: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
ccGline *tempGline = NULL;
inRefresh = true;
for( unsigned int i = 0 ; i < SQLDb->Tuples() ; i++ )
{
tempGline = new (std::nothrow) ccGline(SQLDb);
assert( tempGline != NULL ) ;
tempGline->setId(SQLDb->GetValue(i,0));
tempGline->setHost(SQLDb->GetValue(i,1));
tempGline->setAddedBy(SQLDb->GetValue(i,2)) ;
tempGline->setAddedOn(static_cast< time_t >(
atoi( SQLDb->GetValue(i,3).c_str() ) )) ;
tempGline->setExpires(static_cast< time_t >(
atoi( SQLDb->GetValue(i,4).c_str() ) )) ;
tempGline->setLastUpdated(static_cast< time_t >(
atoi( SQLDb->GetValue(i,5).c_str() ) )) ;
tempGline->setReason(SQLDb->GetValue(i,6));
addGline(tempGline);
}
return true;
}
bool ccontrol::loadUsers()
{
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << User::Query
<< ends;
#ifdef LOG_SQL
elog << "ccotrol::loadUsers> "
<< theQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( theQuery, true ) )
//if (PGRES_TUPLES_OK != status)
{
return false;
}
ccUser* tempUser = 0;
for(unsigned int i =0;i<SQLDb->Tuples();++i)
{
tempUser = new (std::nothrow) ccUser(SQLDb);
tempUser->setID(atoi(SQLDb->GetValue(i, 0).c_str()));
tempUser->setUserName(SQLDb->GetValue(i, 1));
tempUser->setPassword(SQLDb->GetValue(i, 2));
tempUser->setAccess(atol(SQLDb->GetValue(i, 3).c_str()));
tempUser->setSAccess(atol(SQLDb->GetValue(i, 4).c_str()));
tempUser->setFlags(atoi(SQLDb->GetValue(i, 5).c_str()));
tempUser->setSuspendExpires(atoi(SQLDb->GetValue(i,6).c_str()));
tempUser->setSuspendedBy(SQLDb->GetValue(i,7));
tempUser->setServer(SQLDb->GetValue(i,8));
tempUser->setIsSuspended(!strcasecmp(SQLDb->GetValue(i,9),"t"));
if(!strcasecmp(SQLDb->GetValue(i,10),"t"))
{
tempUser->setType(operLevel::UHSLEVEL);
}
else if(!strcasecmp(SQLDb->GetValue(i,11),"t"))
{
tempUser->setType(operLevel::OPERLEVEL);
}
else if(!strcasecmp(SQLDb->GetValue(i,12),"t"))
{
tempUser->setType(operLevel::ADMINLEVEL);
}
else if(!strcasecmp(SQLDb->GetValue(i,13),"t"))
{
tempUser->setType(operLevel::SMTLEVEL);
}
else if(!strcasecmp(SQLDb->GetValue(i,14),"t"))
{
tempUser->setType(operLevel::CODERLEVEL);
}
tempUser->setLogs(!strcasecmp(SQLDb->GetValue(i,15),"t"));
tempUser->setNeedOp(!strcasecmp(SQLDb->GetValue(i,16),"t"));
tempUser->setEmail(SQLDb->GetValue(i,17));
tempUser->setSuspendLevel(atoi(SQLDb->GetValue(i,18).c_str()));
tempUser->setSuspendReason(SQLDb->GetValue(i,19));
if(!strcasecmp(SQLDb->GetValue(i,20),"t"))
{
tempUser->setNotice(true);
}
else
{
tempUser->setNotice(false);
}
tempUser->setLag(!strcasecmp(SQLDb->GetValue(i,21),"t"));
tempUser->setPassChangeTS(atoi(SQLDb->GetValue(i,22).c_str()));
usersMap[tempUser->getUserName()]=tempUser;
}
return true;
}
bool ccontrol::loadServers()
{
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << server::Query
<< ends;
#ifdef LOG_SQL
elog << "ccotrol::loadServers> "
<< theQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( theQuery, true ) )
//if (PGRES_TUPLES_OK != status)
{
return false;
}
ccServer* tempServer = 0;
for(unsigned int i =0;i<SQLDb->Tuples();++i)
{
tempServer = new (std::nothrow) ccServer(SQLDb);
assert(tempServer != NULL);
tempServer->loadDataFromDB(i);
serversMap[tempServer->getName()] = tempServer;
}
return true;
}
bool ccontrol::loadMaxUsers()
{
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << "SELECT * FROM misc WHERE VarName = 'MaxUsers';"
<< ends;
#ifdef LOG_SQL
elog << "ccotrol::loadMaxUsers> "
<< theQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( theQuery, true ) )
//if (PGRES_TUPLES_OK != status)
{
elog << "Error on loading maxusers: " << SQLDb->ErrorMessage() << endl;
return false;
}
if(SQLDb->Tuples() == 0)
{
maxUsers = 0;
dateMax = 0;
stringstream insertQ;
insertQ << "INSERT INTO misc (VarName,Value1,Value2) VALUES ('MaxUsers',0,0);"
<< ends;
if( ! SQLDb->Exec( insertQ ) )
// if (PGRES_COMMAND_OK != status)
{
return false;
}
}
else
{
maxUsers = atoi(SQLDb->GetValue(0,1).c_str());
dateMax = atoi(SQLDb->GetValue(0,2).c_str());
}
return true;
}
bool ccontrol::loadVersions()
{
if(!dbConnected)
{
return false;
}
if( !SQLDb->Exec( "SELECT * FROM misc WHERE VarName = 'Version'", true ) )
//if (PGRES_TUPLES_OK != status)
{
return false;
}
for(unsigned int i =0;i<SQLDb->Tuples();++i)
{
VersionsList.push_back(SQLDb->GetValue(i,1));
}
if( !SQLDb->Exec( "SELECT * FROM misc WHERE VarName = 'CheckVer'", true ) )
//if (PGRES_TUPLES_OK != status)
{
return false;
}
if(SQLDb->Tuples() == 0)
{
checkVer = false;
if( !SQLDb->Exec( "INSERT INTO misc (VarName,Value1) VALUES ('CheckVer',0)") )
// if(PGRES_COMMAND_OK != status)
{
return false;
}
}
else
{
checkVer = atoi(SQLDb->GetValue(0,1).c_str());
}
return true;
}
bool ccontrol::loadBadChannels()
{
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << badChannels::Query
<< ends;
#ifdef LOG_SQL
elog << "ccotrol::loadBadChannels> "
<< theQuery.str()
<< endl;
#endif
if( !SQLDb->Exec( theQuery.str(), true ) )
{
//delete[] theQuery.str() ;
//if (PGRES_TUPLES_OK != status)
return false;
}
ccBadChannel* tempBad;
for(unsigned int i =0;i<SQLDb->Tuples();++i)
{
tempBad = new (std::nothrow) ccBadChannel(SQLDb,i);
assert(tempBad != NULL);
badChannelsMap[tempBad->getName()] = tempBad;
}
return true;
}
bool ccontrol::loadMisc()
{
bool gotInterval= false;
bool gotCount = false;
bool gotVClones = false;
bool gotClones = false;
bool gotCClones = false;
bool gotCClonesCIDR = false;
bool gotCClonesTime = false;
bool gotCClonesGline = false;
bool gotCClonesGTime = false;
bool gotIClones = false;
bool gotIClonesGline = false;
bool gotGLen = false;
bool gotSave = false;
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << "SELECT * FROM misc"
<< ends;
#ifdef LOG_SQL
elog << "ccotrol::loadMisc()> "
<< theQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( theQuery, true ) )
//if (PGRES_TUPLES_OK != status)
{
elog << "Error on loading misc : " << SQLDb->ErrorMessage() << endl;
return false;
}
for(unsigned int i=0; i< SQLDb->Tuples();++i)
{
if(!strcasecmp(SQLDb->GetValue(i,0),"GlineBurstCount"))
{
gotCount = true;
glineBurstCount = atoi(SQLDb->GetValue(i,1).c_str());
}
else if(!strcasecmp(SQLDb->GetValue(i,0),"GlineBurstInterval"))
{
gotInterval = true;
glineBurstInterval = atoi(SQLDb->GetValue(i,1).c_str());
}
else if(!strcasecmp(SQLDb->GetValue(i,0),"VClones"))
{
gotVClones = true;
maxVClones = atoi(SQLDb->GetValue(i,1).c_str());
}
else if(!strcasecmp(SQLDb->GetValue(i,0),"Clones"))
{
gotClones = true;
maxClones = atoi(SQLDb->GetValue(i,1).c_str());
}
else if(!strcasecmp(SQLDb->GetValue(i,0),"CClones"))
{
gotCClones = true;
maxCClones = atoi(SQLDb->GetValue(i,1).c_str());
}
else if(!strcasecmp(SQLDb->GetValue(i,0),"CClonesCIDR"))
{
gotCClonesCIDR = true;
CClonesCIDR = atoi(SQLDb->GetValue(i,1).c_str());
}
else if(!strcasecmp(SQLDb->GetValue(i,0),"CClonesTime"))
{
gotCClonesTime = true;
CClonesTime = atoi(SQLDb->GetValue(i,1).c_str());
}
else if(!strcasecmp(SQLDb->GetValue(i,0),"CClonesGline"))
{
gotCClonesGline = true;
CClonesGline = (atoi(SQLDb->GetValue(i,1).c_str()) == 1);
}
else if(!strcasecmp(SQLDb->GetValue(i,0),"IClones"))
{
gotIClones = true;
maxIClones = atoi(SQLDb->GetValue(i,1).c_str());
}
else if(!strcasecmp(SQLDb->GetValue(i,0),"IClonesGline"))
{
gotIClonesGline = true;
IClonesGline = (atoi(SQLDb->GetValue(i,1).c_str()) == 1);
}
else if(!strcasecmp(SQLDb->GetValue(i,0),"GTime"))
{
gotGLen = true;
maxGlineLen = atoi(SQLDb->GetValue(i,1).c_str());
}
else if(!strcasecmp(SQLDb->GetValue(i,0),"SGline"))
{
gotSave = true;
saveGlines = (atoi(SQLDb->GetValue(i,1).c_str()) == 1);
}
else if(!strcasecmp(SQLDb->GetValue(i,0),"CClonesGTime"))
{
gotCClonesGTime = true;
CClonesGTime = atoi(SQLDb->GetValue(i,1).c_str());
}
}
if(!gotCount)
{
glineBurstCount = 5;
updateMisc("GlineBurstCount",glineBurstCount);
}
if(!gotInterval)
{
glineBurstInterval = 5;
updateMisc("GlineBurstInterval",glineBurstInterval);
}
if(!gotClones)
{
maxClones = 32;
updateMisc("Clones",maxClones);
}
if(!gotVClones)
{
maxVClones = 32;
updateMisc("VClones",maxVClones);
}
if(!gotCClones)
{
maxCClones = 275;
updateMisc("CClones",maxCClones);
}
if(!gotCClonesCIDR)
{
CClonesCIDR = 24;
updateMisc("CClonesCIDR",CClonesCIDR);
}
if(!gotCClonesTime)
{
CClonesTime = 60;
updateMisc("CClonesTime",CClonesTime);
}
if(!gotCClonesGline)
{
CClonesGline = false;
updateMisc("CClonesGline",CClonesGline);
}
if(!gotIClones)
{
maxIClones = 20;
updateMisc("IClones",maxIClones);
}
if(!gotIClonesGline)
{
IClonesGline = false;
updateMisc("IClonesGline",IClonesGline);
}
if(!gotGLen)
{
maxGlineLen = 3600;
updateMisc("GTime",maxGlineLen);
}
if(!gotSave)
{
saveGlines = true;
updateMisc("SGline",saveGlines);
}
if(!gotCClonesGTime)
{
CClonesGTime = maxGlineLen;
updateMisc("CClonesGTime",CClonesGTime);
}
return true;
}
void ccontrol::wallopsAsServer(const char *Msg,...)
{
if( 0 == MyUplink )
{
return ;
}
char buffer[ 1024 ] = { 0 } ;
va_list list;
va_start( list , Msg) ;
vsprintf( buffer, Msg , list ) ;
va_end( list ) ;
MyUplink->Wallops( buffer ) ;
}
void ccontrol::addGlinedException( const string &Host )
{
glinedExceptionList.push_back(pair<string,int>(Host, ::time(0)));
}
int ccontrol::isGlinedException( const string &Host )
{
for (glinedExceptionListType::iterator ptr = glinedExceptionList.begin(); ptr != glinedExceptionList.end(); ptr++) {
if ((::time(0) - (ptr)->second) > 300) {
glinedExceptionList.erase(ptr);
continue;
}
if (Host == (ptr)->first) {
return (ptr)->second;
}
}
return 0;
}
int ccontrol::getExceptions( const string &Host )
{
int Exception = 0;
string::size_type pos = Host.find_first_of('@');
string::size_type Maskpos;
string Ident = Host.substr(0,pos);
string Hostname = Host.substr(pos+1);
string MaskHostname, MaskIdent;
for(exceptionIterator ptr = exception_begin();ptr != exception_end();ptr++)
{
/* move the exception host into MaskHostname and strip off the user */
MaskHostname = (*ptr)->getHost().c_str();
Maskpos = MaskHostname.find_first_of('@');
MaskIdent = MaskHostname.substr(0,Maskpos);
if((*(*ptr) == Hostname) || !(match(MaskHostname.substr(Maskpos+1),Hostname)))
{
/* ok, we matched hostname(ip) - check if we match ident too */
if (!match(MaskIdent, Ident))
if((*ptr)->getConnections() > Exception)
{
Exception = (*ptr)->getConnections();
}
}
}
return Exception;
}
bool ccontrol::isCidrMatch( const string& cidrmask1, const string& cidrmask2 )
{
int client_addr[4] = { 0 };
struct in_addr tmp_ip;
unsigned long mask_ip;
char *client_ip;
int i = 0;
int CIDR;
int CIDR1;
int CIDR2;
string cidrmask;
string tIP;
StringTokenizer st;
StringTokenizer st1(cidrmask1, '/');
if (st1.size() != 2)
CIDR1 = 32;
else
CIDR1 = atoi(st1[1].c_str());
StringTokenizer st2(cidrmask2, '/');
if (st2.size() != 2)
CIDR2 = 32;
else
CIDR2 = atoi(st2[1].c_str());
if (CIDR2 > CIDR1) {
CIDR = CIDR1;
cidrmask = cidrmask1;
st = st1;
tIP = st2[0];
}
else {
CIDR = CIDR2;
cidrmask = cidrmask2;
st = st2;
tIP = st1[0];
}
/* CIDR checks */
/* convert ip to longip */
i = sscanf(tIP.c_str(), "%d.%d.%d.%d", &client_addr[0], &client_addr[1], &client_addr[2], &client_addr[3]);
mask_ip = ntohl((client_addr[0]) | (client_addr[1] << 8) | (client_addr[2] << 16) | (client_addr[3] << 24));
/* bitshift ip to strip the last (32-cidrmask) bits (leaving a mask for the ip) */
for (i = 0; i < (32-CIDR); i++) {
/* right shift */
mask_ip >>= 1;
}
for (i = 0; i < (32-CIDR); i++) {
/* left shift */
mask_ip <<= 1;
}
/* convert longip back to ip */
mask_ip = htonl(mask_ip);
tmp_ip.s_addr = mask_ip;
client_ip = inet_ntoa(tmp_ip);
if (strcmp(client_ip,st[0].c_str()) == 0) {
return true;
}
return false;
}
bool ccontrol::isValidCidr( const string& cidrmask )
{
int client_addr[4] = { 0 };
struct in_addr tmp_ip;
unsigned long mask_ip;
char *client_ip;
int i = 0;
int CIDR = 32;
if (cidrmask.size() > 18)
return false;
StringTokenizer st(cidrmask,'/');
if (st.size() != 2)
return false;
StringTokenizer st2(cidrmask,'.');
if (st2.size() != 4)
return false;
CIDR = atoi(st[1].c_str());
if ((CIDR < 0) || (CIDR > 32))
return false;
/* CIDR checks */
/* convert ip to longip */
i = sscanf(st[0].c_str(), "%d.%d.%d.%d", &client_addr[0], &client_addr[1], &client_addr[2], &client_addr[3]);
mask_ip = ntohl((client_addr[0]) | (client_addr[1] << 8) | (client_addr[2] << 16) | (client_addr[3] << 24));
/* bitshift ip to strip the last (32-cidrmask) bits (leaving a mask for the ip) */
for (i = 0; i < (32-CIDR); i++) {
/* right shift */
mask_ip >>= 1;
}
for (i = 0; i < (32-CIDR); i++) {
/* left shift */
mask_ip <<= 1;
}
/* convert longip back to ip */
mask_ip = htonl(mask_ip);
tmp_ip.s_addr = mask_ip;
client_ip = inet_ntoa(tmp_ip);
if (strcmp(client_ip,st[0].c_str()) == 0) {
return true;
}
return false;
}
bool ccontrol::listExceptions( iClient *theClient )
{
Notice(theClient,"-= Exceptions list - listing a total of %d exceptions =-",
exceptionList.size());
for(exceptionIterator ptr = exception_begin();ptr != exception_end();ptr++)
Notice(theClient,"Host: %s Connections: %d AddedBy: %s Reason: %s",
(*ptr)->getHost().c_str(),
(*ptr)->getConnections(),
(*ptr)->getAddedBy().c_str(),
(*ptr)->getReason().c_str());
Notice(theClient,"-= End of exception list =-");
return true;
}
bool ccontrol::isException( const string & Host )
{
for(exceptionIterator ptr = exception_begin();ptr != exception_end();ptr++)
{
if(*(*ptr) == Host)
return true;
}
return false;
}
bool ccontrol::insertException( iClient *theClient , const string& Host , int Connections, const string& Reason )
{
if(!dbConnected)
{
return false;
}
if(isException(Host))
{
Notice(theClient,
"There is already an exception for host %s, "
"please use update",
Host.c_str());
return true;
}
//Create a new ccException structure
ccException* tempException = new (std::nothrow) ccException(SQLDb);
assert(tempException != NULL);
tempException->setHost(removeSqlChars(Host));
tempException->setConnections(Connections);
tempException->setAddedBy(removeSqlChars(theClient->getRealNickUserHost()));
tempException->setAddedOn(::time(0));
tempException->setReason(Reason);
//Update the database, and the internal list
if(!tempException->Insert())
{
delete tempException;
return false;
}
exceptionList.push_back(tempException);
return true;
}
bool ccontrol::delException( iClient *theClient , const string &Host )
{
if(!dbConnected)
{
Notice(theClient, "error: DB not connected.");
return false;
}
if(!isException(removeSqlChars(Host)))
{
Notice(theClient,"Can't find exception for host %s",Host.c_str());
return true;
}
ccException *tempException = NULL;
for(exceptionIterator ptr = exception_begin();ptr != exception_end();)
{
tempException = *ptr;
if(*tempException == removeSqlChars(Host))
{
bool status = tempException->Delete();
ptr = exceptionList.erase(ptr);
delete tempException;
if(!status)
{
return false;
}
}
else
ptr++;
}
return true;
}
ccFloodData *ccontrol::findLogin( const string & Numeric )
{
for(ignoreIterator ptr = ignore_begin() ; ptr != ignore_end() ; ++ptr)
{
if((*ptr)->getNumeric() == Numeric)
{
return *ptr;
}
}
return NULL;
}
void ccontrol::removeLogin( ccFloodData *tempLogin )
{
for(ignoreIterator ptr = ignore_begin() ; ptr != ignore_end() ;)
{
if((*ptr) == tempLogin)
{
ptr = ignoreList.erase(ptr);
}
else
ptr++;
}
}
void ccontrol::addLogin( iClient* tClient)
{
if(!tClient->getCustomData(this))
{
elog << "Couldn't find custom data for "
<< tClient->getNickName() << endl;
return;
}
ccFloodData *LogInfo = static_cast<ccUserData*>( tClient->getCustomData(this))->getFlood();
LogInfo->add_Login();
if(LogInfo->getLogins() > 5)
{
ignoreUser(LogInfo);
}
}
void ccontrol::addFloodData(iClient* theClient, unsigned int floodPoints) {
if (!theClient->getCustomData(this)) {
elog << "Couldnt find custom data for "
<< theClient->getNickName() << endl;
return;
}
ccFloodData* floodData = (static_cast<ccUserData*> (
theClient->getCustomData(this)))->getFlood();
if (floodData->addPoints(flood::MESSAGE_POINTS)) {
// yes we need to ignore this user
ignoreUser(floodData);
MsgChanLog("[FLOOD MESSAGE: %s has been ignored",
theClient->getNickName().c_str());
}
}
int ccontrol::removeIgnore( const string &Host )
{
ccFloodData *tempLogin = 0;
int retMe = IGNORE_NOT_FOUND;
for(ignoreIterator ptr = ignore_begin();ptr!=ignore_end();)
{
tempLogin = *ptr;
if(tempLogin->getIgnoredHost() == Host)
{
stringstream s;
s << getCharYYXXX()
<< " SILENCE "
<< "*"
<< " -"
<< tempLogin->getIgnoredHost()
<< ends;
Write( s );
tempLogin->resetIgnore();
tempLogin->resetLogins();
ptr = ignoreList.erase(ptr);
if(tempLogin->getNumeric() == "0")
{
delete tempLogin;
}
retMe = IGNORE_REMOVED;
}
else
ptr++;
}
return retMe;
}
int ccontrol::removeIgnore( iClient *theClient )
{
string Host = string( "*!*" )
+ theClient->getUserName()
+ string( "@" )
+ theClient->getRealNickUserHost();
int retMe = removeIgnore(Host);
return retMe;
}
void ccontrol::ignoreUser( ccFloodData* Flood )
{
const iClient* theClient = Network->findClient(Flood->getNumeric());
if(theClient->isOper()) {
Notice(theClient,"I don't think I like you anymore, consider yourself ignored!");
}
MsgChanLog("Added %s to my ignore list\n",theClient->getRealNickUserHost().c_str());
string silenceMask = string( "*!*" )
+ theClient->getUserName()
+ "@"
+ theClient->getRealNickUserHost();
stringstream s;
s << getCharYYXXX()
<< " SILENCE "
<< theClient->getCharYYXXX()
<< " "
<< silenceMask
<< ends;
Write( s );
Flood->setIgnoreExpires(::time(0)+ flood::IGNORE_TIME);
Flood->setIgnoredHost(silenceMask);
ignoreList.push_back(Flood);
}
bool ccontrol::listIgnores( iClient *theClient )
{
Notice(theClient,"-= Listing Ignore List =-");
ccFloodData *tempLogin;
for(ignoreIterator ptr = ignore_begin();ptr!=ignore_end();ptr++)
{
tempLogin = *ptr;
if(tempLogin->getIgnoreExpires() > ::time(0))
{
Notice(theClient,"Host: %s Expires: %s [%ld]",
tempLogin->getIgnoredHost().c_str(),
convertToAscTime(tempLogin->getIgnoreExpires()),
(long)tempLogin->getIgnoreExpires());
}
}
Notice(theClient,"-= End Of Ignore List =-");
return true ;
}
bool ccontrol::refreshIgnores()
{
ccFloodData *tempLogin;
unsigned int TotalFound =0;
for(ignoreIterator ptr = ignore_begin();ptr!=ignore_end();)
{
tempLogin = *ptr;
if((tempLogin) &&(tempLogin->getIgnoreExpires() <= ::time(0)))
{
tempLogin->setIgnoreExpires(0);
stringstream s;
s << getCharYYXXX()
<< " SILENCE "
<< "*"
<< " -"
<< tempLogin->getIgnoredHost()
<< ends;
Write( s );
tempLogin->setIgnoredHost("");
if(tempLogin->getNumeric() == "0")
{
delete tempLogin;
}
ptr = ignoreList.erase(ptr);
++TotalFound;
}
else
ptr++;
}
if(TotalFound > 0)
MsgChanLog("[Refresh Ignores] - %d expired\n",TotalFound);
return true;
}
bool ccontrol::loadExceptions()
{
static const char Query[] = "SELECT Host,Connections,AddedBy,AddedOn,Reason FROM Exceptions";
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << Query
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::loadExceptions> "
<< theQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( theQuery, true ) )
//if( PGRES_TUPLES_OK != status )
{
elog << "ccontrol::loadExceptions> SQL Failure: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
ccException *tempException = NULL;
for( unsigned int i = 0 ; i < SQLDb->Tuples() ; i++ )
{
tempException = new (std::nothrow) ccException(SQLDb);
assert( tempException != 0 ) ;
tempException->setHost(SQLDb->GetValue(i,0));
tempException->setConnections(atoi(SQLDb->GetValue(i,1).c_str()));
tempException->setAddedBy(SQLDb->GetValue(i,2)) ;
tempException->setAddedOn(static_cast< time_t >(
atoi( SQLDb->GetValue(i,3).c_str() ) )) ;
tempException->setReason(SQLDb->GetValue(i,4));
exceptionList.push_back(tempException);
}
return true;
}
void ccontrol::listGlines( iClient *theClient, string Mask )
{
ccGline* tempGline;
char gline_set[256];
Notice(theClient,"-= Gline List =-");
for(glineIterator ptr = gline_begin();ptr != gline_end();++ptr)
{
tempGline = ptr->second;
if((tempGline ->getExpires() > ::time(0))
&& (!match(Mask,tempGline->getHost())))
{
sprintf(gline_set, "%s", Duration(time(NULL) - tempGline->getAddedOn()));
Notice(theClient,"Host: %s, Expires: [%ld] %s, Added by %s at [%ld] %s ago",
tempGline->getHost().c_str(),
tempGline->getExpires(),
Duration(tempGline->getExpires() - time(NULL)),
tempGline->getAddedBy().c_str(),
tempGline->getAddedOn(),
gline_set);
}
}
Notice(theClient,"-= RealName Gline List =-");
for(glineIterator ptr = rnGlineList.begin();ptr != rnGlineList.end();++ptr)
{
tempGline = ptr->second;
if((tempGline ->getExpires() > ::time(0))
&& (!match(Mask,tempGline->getHost())))
{
sprintf(gline_set, "%s", Duration(time(NULL) - tempGline->getAddedOn()));
Notice(theClient,"Host: %s, Expires: [%ld] %s, Added by %s at [%ld] %s ago.",
tempGline->getHost().c_str(),
tempGline->getExpires(),
Duration(tempGline->getExpires() - time(NULL)),
tempGline->getAddedBy().c_str(),
tempGline->getAddedOn(),
gline_set);
}
}
Notice(theClient,"-= End Of Gline List =-");
}
void ccontrol::listSuspended( iClient * )
{
}
void ccontrol::listServers( iClient * theClient)
{
ccServer* tmpServer;
for(serversConstIterator ptr = serversMap_begin();ptr != serversMap_end();++ptr)
{
tmpServer = ptr->second;
if(tmpServer->getNetServer())
{
char buf[512];
stringstream s;
s << "(";
if (tmpServer->getLagTime() > 10000)
{
s << "\002" << (int) (tmpServer->getLagTime() / 1000) << "seconds\002)";
}
else if (tmpServer->getLagTime() > 5000)
{
s << "\002" << tmpServer->getLagTime() << "ms\002)";
}
else
{
s << tmpServer->getLagTime() << "ms)";
}
snprintf(buf, sizeof(buf) - 1, "%3s (%4d) Name: %s Version: %s",
tmpServer->getLastNumeric().c_str(),
base64toint(tmpServer->getLastNumeric().c_str()),
tmpServer->getName().c_str(),
tmpServer->getVersion().c_str());
buf[sizeof(buf)-1] = '\0'; //Just in case
Notice(theClient, "%s %s", buf, s.str().c_str());
//Notice(theClient,"%3s (%4d) Name: %s Version: %s",
// tmpServer->getLastNumeric().c_str(),
// base64toint(tmpServer->getLastNumeric().c_str()),
// tmpServer->getName().c_str(),
// tmpServer->getVersion().c_str());
}
else if(tmpServer->getReportMissing())
{
Notice(theClient,"%3s (%4d) Name: %s Version: %s (\002*MISSING*\002)",
tmpServer->getLastNumeric().c_str(),
base64toint(tmpServer->getLastNumeric().c_str()),
tmpServer->getName().c_str(),
tmpServer->getVersion().c_str());
}
else
{
Notice(theClient," Name: %s Version: %s",
tmpServer->getName().c_str(),
tmpServer->getVersion().c_str());
}
}
}
void ccontrol::listBadChannels( iClient* theClient)
{
ccBadChannel* tempBadChan;
Notice(theClient, "-= Bad Channels (NOMODE) List =-");
for(badChannelsIterator ptr = badChannels_begin();ptr != badChannels_end();++ptr)
{
tempBadChan = ptr->second;
Notice(theClient,"Channel: %s - Reason: %s - AddedBy: %s",tempBadChan->getName().c_str(),
tempBadChan->getReason().c_str(),tempBadChan->getAddedBy().c_str());
}
Notice(theClient, "-= End of Bad Channels (NOMODE) List =-");
}
void ccontrol::loadCommands()
{
static const char *Main = "SELECT * FROM Commands";
if(!dbConnected)
{
return;
}
stringstream theQuery;
theQuery << Main
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::loadCommands> "
<< theQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( theQuery, true ) )
//if( PGRES_TUPLES_OK != status )
{
elog << "ccontrol::loadCommands> SQL Failure: "
<< SQLDb->ErrorMessage()
<< endl ;
return;
}
Command* NewCom;
for( unsigned int i = 0 ; i < SQLDb->Tuples() ; i++ )
{
NewCom = findRealCommand(SQLDb->GetValue(i,0));
if(!NewCom)
{
/*elog << "Can't find handler for command "
<< SQLDb->GetValue(i,0)
<< endl; */
}
else
{
NewCom->setName(SQLDb->GetValue(i,1));
if(!strcasecmp(SQLDb->GetValue(i,3),"f"))
NewCom->Enable();
else
NewCom->Disable();
NewCom->setNeedOp(!strcasecmp(SQLDb->GetValue(i,4),"t") ? true : false);
NewCom->setNoLog(!strcasecmp(SQLDb->GetValue(i,5),"t") ? true : false);
}
}
}
bool ccontrol::updateCommand ( Command* Comm)
{
static const char *existsQ = "SELECT RealName from Commands where lower(RealName) = '";
static const char *Main = "UPDATE Commands set name = '";
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << existsQ << string_lower(removeSqlChars(Comm->getRealName())) << "'";
bool update = (SQLDb->Exec(theQuery, true) && (SQLDb->Tuples() > 0));
theQuery.str("");
if(update) {
theQuery << Main
<< removeSqlChars(Comm->getName())
<< "', isDisabled = "
<< (Comm->getIsDisabled() ? "'t'" : "'n'")
<< ", NeedOp = "
<< (Comm->getNeedOp() ? "'t'" : "'n'")
<< ", NoLog = "
<< (Comm->getNoLog() ? "'t'" : "'n'")
<< ", MinLevel = "
<< Comm->getMinLevel()
<< " WHERE lower(RealName) = '"
<< string_lower(removeSqlChars(Comm->getRealName()))
<< "'"
<< ends;
} else {
theQuery << "INSERT into Commands (RealName,Name,Flags,IsDisabled,NeedOp,NoLog,MinLevel,SAccess) VALUES (";
theQuery << "'" << removeSqlChars(Comm->getRealName()) << "',";
theQuery << "'" << removeSqlChars(Comm->getName()) << "',";
theQuery << Comm->getFlags() << ",";
theQuery << (Comm->getIsDisabled() ? "'t'" : "'n'") << ",";
theQuery << (Comm->getNeedOp() ? "'t'" : "'n'") << ",";
theQuery << (Comm->getNoLog() ? "'t'" : "'n'") << ",";
theQuery << Comm->getMinLevel() << ",";
theQuery << (Comm->getSecondAccess() ? "'t'" : "'n'") << ")";
}
#ifdef LOG_SQL
elog << "ccontrol::updateCommands> "
<< theQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( theQuery ) )
//if( PGRES_COMMAND_OK != status )
{
elog << "ccontrol::updateCommands> SQL Failure: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
RegisterCommand(Comm);
return true;
}
Command* ccontrol::findRealCommand( const string& commName)
{
for( commandMapType::iterator ptr = commandMap.begin() ;
ptr != commandMap.end() ; ++ptr )
if(!strcasecmp(ptr->second->getRealName(),commName))
return ptr->second;
return NULL;
}
Command* ccontrol::findCommandInMem( const string& commName)
{
for( commandMapType::iterator ptr = commandMap.begin() ;
ptr != commandMap.end() ; ++ptr )
if(!strcasecmp(ptr->second->getName(),commName))
return ptr->second;
return NULL;
}
bool ccontrol::UpdateCommandFromDb ( Command* Comm )
{
static const char *Main = "SELECT * FROM Commands WHERE lower(RealName) = '";
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << Main
<< string_lower(removeSqlChars(Comm->getRealName()))
<< "'" << ends;
if( !SQLDb->Exec( theQuery, true ) )
//if( PGRES_TUPLES_OK != status )
{
elog << "ccontrol::LoadCommand> SQL Failure: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
if(SQLDb->Tuples() == 0)
return false;
Comm->setName(SQLDb->GetValue(0,1));
if(!strcasecmp(SQLDb->GetValue(0,3),"t"))
Comm->Disable();
else
Comm->Enable();
Comm->setNeedOp((!strcasecmp(SQLDb->GetValue(0,4),"t")) ? true : false);
Comm->setNoLog((!strcasecmp(SQLDb->GetValue(0,5),"t")) ? true : false);
Comm->setMinLevel(atoi(SQLDb->GetValue(0,6).c_str()));
return true;
}
const string ccontrol::expandDbServer(const string& Name)
{
serversMapType::iterator serverIt;
for(serverIt = serversMap.begin();serverIt != serversMap.end();++serverIt)
{
if(!match(Name,serverIt->first))
return serverIt->first;
}
return "";
}
const string ccontrol::removeSqlChars(const string& Msg)
{
string NewString;
for(string::const_iterator ptr = Msg.begin(); ptr != Msg.end() ; ++ptr)
{
if(*ptr == ';')
{
NewString += ' ';
}
else if(*ptr == '\'')
{
NewString += "\\\047";
}
else if(*ptr == '\\')
{
NewString += "\\\134";
}
else
{
NewString += *ptr;
}
}
return NewString;
}
void ccontrol::checkDbConnection()
{
if( SQLDb->ConnectionBad() )
//if(SQLDb->Status() == CONNECTION_BAD) //Check if the connection had died
{
delete(SQLDb);
dbConnected = false;
updateSqldb(NULL);
MsgChanLog("PANIC! - The connection with the database was lost!\n");
MsgChanLog("Attempting to reconnect, attempt %d out of %d\n",
connectCount+1,connectRetry+1);
string Query = "host=" + sqlHost + " dbname=" + sqlDb + " port=" + sqlPort;
if (strcasecmp(sqlUser,"''"))
{
Query += (" user=" + sqlUser);
}
if (strcasecmp(sqlPass,"''"))
{
Query += (" password=" + sqlPass);
}
SQLDb = new dbHandle( sqlHost,
atoi( sqlPort.c_str() ),
sqlDb,
sqlUser,
sqlPass ) ;
// SQLDb = new (std::nothrow) cmDatabase(Query.c_str());
assert(SQLDb != NULL);
if(SQLDb->ConnectionBad())
{
++connectCount;
if(connectCount > connectRetry)
{
MsgChanLog("Can't connect to the database, quitting (no more retries)\n");
::exit(1);
}
else
{
MsgChanLog("Attempt failed\n");
}
}
else
{
dbConnected = true;
MsgChanLog("The PANIC is over, database connectivity restored\n");
updateSqldb(SQLDb);
connectCount = 0;
}
}
}
void ccontrol::updateSqldb(dbHandle* _SQLDb)
{
for(glineIterator ptr = glineList.begin();ptr != glineList.end();++ptr)
{
(ptr->second)->setSqldb(_SQLDb);
}
for(glineIterator ptr = rnGlineList.begin();ptr != rnGlineList.end();++ptr)
{
(ptr->second)->setSqldb(_SQLDb);
}
for(exceptionIterator ptr = exception_begin();ptr != exception_end();++ptr)
{
(*ptr)->setSqldb(_SQLDb);
}
for(usersIterator ptr = usersMap.begin();ptr != usersMap.end();++ptr)
{
ptr->second->setSqldb(_SQLDb);
}
for(serversIterator ptr = serversMap.begin();ptr != serversMap.end();++ptr)
{
ptr->second->setSqldb(_SQLDb);
}
}
void ccontrol::showStatus(iClient* tmpClient)
{
Notice(tmpClient,"CControl version %s.%s [%s]",MAJORVER,MINORVER,RELDATE);
Notice(tmpClient, "Service Uptime: %s", Ago(getUplink()->getStartTime()));
if(checkClones)
{
Notice(tmpClient,"Monitoring %d different clones hosts\n",clientsIpMap.size());
Notice(tmpClient,"and %d different CIDR clones hosts (%d rate-limit entries)\n",
clientsIp24Map.size(), clientsIp24MapLastWarn.size());
Notice(tmpClient,"and %d different CIDR ident clones hosts (%d rate-limit entries)\n",
clientsIp24IdentMap.size(), clientsIp24IdentMapLastWarn.size());
Notice(tmpClient,"and %d different virtual clones hosts (%d rate-limit entries)\n",
virtualClientsMap.size(), virtualClientsMapLastWarn.size());
}
Notice(tmpClient,"%d glines are waiting in the gline queue",glineQueue.size());
Notice(tmpClient,"Allocated Structures:");
Notice(tmpClient,"ccServer: %d, ccGline: %d, ccException: %d, ccUser: %d",
ccServer::numAllocated,
ccGline::numAllocated,
ccException::numAllocated,
ccUser::numAllocated);
Notice(tmpClient,"Total of %d users in the map",usersMap.size());
Notice(tmpClient,"(Gline Burst) - GBCount: %d , GBInterval: %d",
glineBurstCount,
glineBurstInterval);
Notice(tmpClient,"Max Clones: %d, Max Virtual Clones: %d",maxClones,maxVClones);
Notice(tmpClient,"Max Ident Clones: %d per /%d - Auto-Gline: %s",
maxIClones,
CClonesCIDR,
IClonesGline ? "True" : "False");
Notice(tmpClient,"Max CIDR Clones: %d per /%d - Auto-Gline: %s (for %s)",
maxCClones,CClonesCIDR,CClonesGline ? "YES" : "NO",
Duration(CClonesGTime));
Notice(tmpClient," (%s between announcements per block)", Duration(CClonesTime));
Notice(tmpClient,"Save gline is: %s",saveGlines ? "Enabled" : "Disabled");
Notice(tmpClient,"Currently Bursting: %s",inBurst ? "YES" : "NO");
}
bool ccontrol::updateMisc(const string& varName, const unsigned int Value)
{
if(!strcasecmp(varName,"GlineBurstCount"))
{
glineBurstCount = Value;
}
else if(!strcasecmp(varName,"GlineBurstInterval"))
{
glineBurstInterval = Value;
}
else if(!strcasecmp(varName,"Clones"))
{
maxClones = Value;
}
else if(!strcasecmp(varName,"VClones"))
{
maxVClones = Value;
}
else if(!strcasecmp(varName,"CClones"))
{
maxCClones = Value;
}
else if(!strcasecmp(varName,"CClonesCIDR"))
{
CClonesCIDR = Value;
}
else if(!strcasecmp(varName,"CClonesTime"))
{
CClonesTime = Value;
}
else if(!strcasecmp(varName,"CClonesGline"))
{
CClonesGline = (Value == 1);
}
else if(!strcasecmp(varName,"IClones"))
{
maxIClones = Value;
}
else if(!strcasecmp(varName,"IClonesGline"))
{
IClonesGline = (Value == 1);
}
else if(!strcasecmp(varName,"GTime"))
{
maxGlineLen = Value;
}
else if(!strcasecmp(varName,"SGline"))
{
saveGlines = (Value == 1);
}
else if(!strcasecmp(varName,"CClonesGTime"))
{
CClonesGTime = Value;
}
if(!dbConnected)
{
return false;
}
stringstream theQuery;
theQuery << "SELECT * FROM misc WHERE VarName = '"
<< varName << "'"
<< ends;
#ifdef LOG_SQL
elog << "ccotrol::updateMisc> "
<< theQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( theQuery, true ) )
//if (PGRES_TUPLES_OK != status)
{
elog << "Error update misc table : " << SQLDb->ErrorMessage() << endl;
return false;
}
if(SQLDb->Tuples() == 0)
{
stringstream insertQ;
insertQ << "INSERT INTO misc (VarName,Value1) VALUES ('"
<< varName << "',"
<< Value <<")"
<< ends;
if( !SQLDb->Exec( insertQ ) )
// if (PGRES_COMMAND_OK != status)
{
return false;
}
}
else
{
stringstream updateQ;
updateQ << "UPDATE misc SET Value1 = "
<< Value
<< " WHERE VarName = '"
<< varName << "'"
<< ends;
if( !SQLDb->Exec( updateQ ) )
// if (PGRES_COMMAND_OK != status)
{
elog << "Error update misc table : " << SQLDb->ErrorMessage() << endl;
return false;
}
}
return true;
}
unsigned int ccontrol::checkPassword(string NewPass , ccUser* tmpUser)
{
if(NewPass.size() < password::MIN_SIZE)
{
return password::TOO_SHORT;
}
if(!strcasecmp(NewPass,tmpUser->getUserName()))
{
return password::LIKE_UNAME;
}
return password::PASS_OK;
}
ccServer* ccontrol::getServer(const string& Name)
{
serversMapType::iterator serverIt;
serverIt = serversMap.find(Name);
if(serverIt != serversMap.end())
{
return serverIt->second;
}
return NULL;
}
void ccontrol::addServer(ccServer* tempServer)
{
if(!serversMap[tempServer->getName()])
{
serversMap[tempServer->getName()] = tempServer;
}
}
void ccontrol::remServer(ccServer* tempServer)
{
serversMap.erase(serversMap.find(tempServer->getName()));
}
#ifdef LOGTOHD
void ccontrol::initLogs()
{
//TODO: Get this from the conf file
LogFileName = "CommandsLog.Log";
//TODO: Get this from the conf file
LogsToSave = 100;
NumOfLogs = 0;
/* disable buffering */
LogFile.rdbuf()->pubsetbuf(0,0);
/* open file for writing and append */
LogFile.open(LogFileName.c_str(),ios::out|ios::app);
if(LogFile.bad())
{//There was a problem in opening the log file
elog << "Error while initilizing the logs file!\n";
return ;
} else {
LogFile << "** GNUWorld mod.ccontrol restarted **\n";
}
//LogFile.setbuf(NULL,0);
LogFile.close();
}
void ccontrol::addLog(ccLog* newLog)
{
ccLog* oldLog;
while(LogList.size() >= LogsToSave)
{
oldLog = LogList.back();
LogList.pop_back();
delete oldLog;
}
LogList.push_front(newLog);
}
/*
ccontrol::showLogs - sends the lastcom log to a client
loading the logs from the file is done using the
lazy evaluation tactic, meaning it only loads the data from
the hardisk if it has to , thous saving time
*/
void ccontrol::showLogs(iClient* theClient, unsigned int Amount)
{
if(Amount > LogsToSave)
{
Notice(theClient,"Sorry, but you can't view more than the last %d commands",
LogsToSave);
Amount = LogsToSave;
}
if((LogList.size() < Amount)
&& ((NumOfLogs > LogList.size()) || (NumOfLogs == 0)))
{
if((!LogFile.eof() && LogFile.bad()) || !(LogFile.is_open()))
{
LogFile.close();
LogFile.open(LogFileName.c_str(),ios::in|ios::out);
//LogFile.setbuf(NULL,0);
if(LogFile.bad())
{
Notice(theClient,"Error while reading the lastcom report");
MsgChanLog("Error while reading from the lastcom file!\n");
return;
}
}
//Clean the list first
for(ccLogIterator ptr= LogList.begin(); ptr != LogList.end();)
{
delete *ptr;
ptr = LogList.erase(ptr);
}
/*
since every record has its own size, there is no way of knowing
where in the file the last X records are, so we start reading
from the begining of the file, this saves hd space but may
cost some time.
this is done only once if at all per restart, so its
not a big deal *g*
*/
ccLog* tmpLog = 0 ;
LogFile.seekg(0,ios::beg);
NumOfLogs = 0;
while(!LogFile.eof())
{
tmpLog = new (std::nothrow) ccLog();
if(!tmpLog->Load(LogFile))
{
if(!LogFile.eof())
{
Notice(theClient,"Error while reading the lastcom report");
delete tmpLog ;
return;
}
}
else
{
++NumOfLogs;
addLog(tmpLog);
}
}
LogFile.close();
// LogFile.open(LogFileName.c_str(),ios::in|ios::out);
// LogFile.setbuf(NULL,0);
delete tmpLog;
}
//At this point, we should have the log list full of the last LogsToSave
//commands, and we need to show only Amount of them
unsigned int Left = LogList.size();
if(Left == 0)
return;
ccLogIterator curLog = LogList.end();
while(Left > Amount)
{
--curLog;
Left--;
}
if(curLog == LogList.end())
{
--curLog;
}
while(Left > 0)
{
Notice(theClient,"[%s] - [(%s) - %s] - %s",
convertToAscTime((*curLog)->Time),
(*curLog)->User.c_str(),
(*curLog)->Host.c_str(),
(*curLog)->Desc.c_str());
--curLog;
Left--;
}
}
#endif
void ccontrol::OnSignal(int sig)
{
if(sig == SIGUSR1)
saveServersInfo();
else
if(sig == SIGUSR2)
saveChannelsInfo();
xClient::OnSignal(sig);
}
void ccontrol::saveServersInfo()
{
ofstream servFile("ServerList.txt",ios::out);
if(!servFile)
{
elog << "Error while opening server list file!" << endl;
return;
}
gnuworld::xNetwork::const_serverIterator sIterator =
Network->servers_begin();
iServer* curServer;
for(;sIterator != Network->servers_end();++sIterator)
{
curServer = sIterator->second;
if(!curServer)
continue;
servFile << curServer->getName().c_str()
<< " " << curServer->getConnectTime()
<< " " << Network->countClients(curServer)
<< endl;
}
servFile.close();
}
void ccontrol::saveChannelsInfo()
{
ofstream chanFile("ChannelsList.txt",ios::out);
if(!chanFile)
{
elog << "Error while opening server list file!\n";
return;
}
gnuworld::xNetwork::const_channelIterator cIterator =
Network->channels_begin();
Channel* curChannel;
for(;cIterator != Network->channels_end();++cIterator)
{
curChannel = cIterator->second;
if(!curChannel)
continue;
chanFile << curChannel->getName()
<< " " << curChannel->getCreationTime()
<< " " << curChannel->getModeString()
<< " " << curChannel->size()
#ifdef TOPIC_TRACK
<< " " << curChannel->getTopic()
#endif
<< endl;
}
chanFile.close();
}
void ccontrol::checkMaxUsers()
{
if(maxUsers < curUsers)
{
maxUsers = curUsers;
dateMax = ::time(0);
static const char *UPMain = "UPDATE Misc SET Value1 = ";
stringstream DelQuery;
DelQuery << UPMain
<< maxUsers
<< ", Value2 = "
<< dateMax
<< " WHERE VarName = 'MaxUsers'"
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::checkMaxUsers> "
<< DelQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( DelQuery ) )
// if( PGRES_COMMAND_OK != status )
{
elog << "ccontrol::checkMaxUsers> SQL Failure: "
<< SQLDb->ErrorMessage()
<< endl ;
}
}
}
bool ccontrol::addVersion(const string& newVer)
{
static const char* verChar = "INSERT INTO misc (VarName,Value5) VALUES ('Version','";
stringstream VerQuery;
VerQuery << verChar
<< newVer
<< "')"
<< ends;
#ifdef LOG_SQL
elog << "ccontrol::addVersion> "
<< VerQuery.str().c_str()
<< endl;
#endif
if( !SQLDb->Exec( VerQuery ) )
//if( PGRES_COMMAND_OK != status )
{
elog << "ccontrol::addVersion> SQL Failure: "
<< SQLDb->ErrorMessage()
<< endl ;
}
return true;
}
bool ccontrol::remVersion(const string& oldVer)
{
versionsIterator ptr = VersionsList.begin();
for(;ptr != VersionsList.end();)
{
if(!strcasecmp(oldVer,*ptr))
{ //Found the version in the list
ptr = VersionsList.erase(ptr);
}
else
{
++ptr;
}
}
string delS = "DELETE FROM misc WHERE VarName = 'Version' AND lower(Value5) = '"
+ string_lower(removeSqlChars(oldVer)) + "'";
return SQLDb->Exec(delS);
return true;
}
bool ccontrol::isValidVersion(const string& checkVer)
{
versionsIterator ptr = VersionsList.begin();
for(;ptr != VersionsList.end();++ptr)
{
if(!strcasecmp(checkVer,*ptr))
{ //Found the version in the list
return true;
}
}
return false;
}
void ccontrol::listVersions(iClient*)
{
}
bool ccontrol::updateCheckVer(const bool newVal)
{
checkVer = newVal;
stringstream ups;
ups << "UPDATE misc SET Value1 = "
<< (newVal ? 1 : 0)
<< " WHERE VarName = 'CheckVer'"
<< ends;
if( !SQLDb->Exec( ups ) )
//if( PGRES_COMMAND_OK != status )
{
elog << "ccontrol::updateCheckVer> SQL Failure: "
<< SQLDb->ErrorMessage()
<< endl ;
return false;
}
return true;
}
ccBadChannel* ccontrol::isBadChannel(const string& Channel)
{
badChannelsIterator ptr = badChannelsMap.find(Channel);
if(ptr == badChannels_end())
{
return NULL;
}
return ptr->second;
}
void ccontrol::addBadChannel(ccBadChannel* Channel)
{
badChannelsMap[Channel->getName()] = Channel;
}
void ccontrol::remBadChannel(ccBadChannel* Channel)
{
badChannelsMap.erase(badChannelsMap.find(Channel->getName()));
}
bool ccontrol::glineChannelUsers(iClient* theClient, Channel* theChan, const string& reason, unsigned int gLength, const string& addedBy,bool excludeChanWithOper,bool unidented)
{
ccGline *TmpGline;
iClient *TmpClient;
string curIP;
string newMsg = "IP addresses glined from " + theChan->getName() + ": ";
ccUser* tmpUser = IsAuth(theClient);
typedef map<string , int> GlineMapType;
GlineMapType glineList;
GlineMapType::iterator gptr;
list<ccGline*> neededGlines;
list<string> ipList;
int count = 0;
bool foundOper = false;
bool success = true;
bool foundException = false;
bool exceptionForce = false;
for (Channel::const_userIterator ptr = theChan->userList_begin();
ptr != theChan->userList_end(); ++ptr)
{
TmpClient = ptr->second->getClient();
if((excludeChanWithOper) && (TmpClient->isOper()
|| TmpClient->getMode(iClient::MODE_SERVICES))) //Need to stop glining this channel
{
foundOper = true;
success = false;
break;
}
curIP = xIP(TmpClient->getIP()).GetNumericIP();
if (getExceptions("*@" + curIP) > 0)
{
foundException = true;
Notice(theClient, "There is an exception for this user: %s!%s@%s", TmpClient->getNickName().c_str(), TmpClient->getUserName().c_str(), curIP.c_str());
}
if (isIpOfOper(curIP))
{
Notice(theClient, "%s opered globally before and uses the same IP this user uses: %s!%s@%s", getLastNUHOfOperFromIP(curIP).c_str(), TmpClient->getNickName().c_str(), TmpClient->getUserName().c_str(), curIP.c_str());
foundException = true;
}
if ((unidented) && (TmpClient->getUserName().substr(0,1)) != "~")
continue;
gptr = glineList.find("*@" + curIP);
if (gptr != glineList.end())
{
/* duplicate gline - continue to next channel user */
continue;
} else {
glineList["*@" + curIP] = 1;
}
if ((!TmpClient->getMode(iClient::MODE_SERVICES)) &&
!(IsAuth(TmpClient)) && !(TmpClient->isOper()))
{
/* create a new gline and queue it */
TmpGline = new ccGline(SQLDb);
assert(TmpGline != NULL);
if (unidented)
TmpGline->setHost("~*@" + curIP);
else
TmpGline->setHost("*@" + curIP);
TmpGline->setExpires(unsigned(gLength));
TmpGline->setAddedBy(addedBy);
TmpGline->setReason(reason);
TmpGline->setAddedOn(::time(0));
TmpGline->setLastUpdated(::time(0));
neededGlines.push_back(TmpGline);
if (showCGIpsInLogs)
{
count++;
if (count > 1)
newMsg += ",";
newMsg += curIP;
if (newMsg.size() > 300)
{
ipList.push_back(newMsg);
newMsg = "IPs: ";
count = 0;
}
}
}
}
if (showCGIpsInLogs)
ipList.push_back(newMsg);
if (foundException)
{
if (isGlinedException(theChan->getName()) > 0)
{
exceptionForce = true;
if (!(excludeChanWithOper && foundOper))
Notice(theClient,"There is an exception for at least one host on the channel. Channel G-line sent (forced)");
}
else if (!(excludeChanWithOper && foundOper))
{
Notice(theClient,"There is an exception for at least one host on the channel. Send the channel gline again to force.");
addGlinedException(theChan->getName());
}
}
list<ccGline*>::iterator glinesIt = neededGlines.begin();
for(; glinesIt != neededGlines.end(); ++glinesIt)
{
TmpGline = *glinesIt;
((excludeChanWithOper && foundOper) || (foundException && !exceptionForce)) ? delete TmpGline : queueGline(TmpGline);
}
if (showCGIpsInLogs && (!excludeChanWithOper || !foundOper) && (!foundException || exceptionForce))
{
for (list<string>::iterator sItr = ipList.begin(); sItr != ipList.end(); sItr++)
{
newMsg = *sItr;
#ifndef LOGTOHD
if(tmpUser)
DailyLog(tmpUser,"%s",newMsg.c_str());
else
DailyLog(theClient,"%s",newMsg.c_str());
#else
ccLog* newLog = new (std::nothrow) ccLog();
newLog->Time = ::time(0);
newLog->Desc = newMsg.c_str();
newLog->Host = theClient->getRealNickUserHost().c_str();
if(tmpUser)
newLog->User = tmpUser->getUserName().c_str();
else
newLog->User = "Unknown";
newLog->CommandName = (excludeChanWithOper) ? "FORCECHANGLINE" : "SCHANGLINE";
DailyLog(newLog);
}
#endif
}
return success;
}
void ccontrol::isNowAnOper (iClient* theUser)
{
string IP = xIP(theUser->getIP()).GetNumericIP();
opersIPMap[IP] = theUser->getRealNickUserHost();
}
bool ccontrol::isIpOfOper (const string& IP)
{
opersIPMapType::iterator oItr;
if ((oItr = opersIPMap.find(IP)) != opersIPMap.end())
return true;
return false;
}
string ccontrol::getLastNUHOfOperFromIP (const string& IP)
{
if (isIpOfOper(IP))
return opersIPMap[IP];
return string("error");
}
void ccontrol::refreshOpersIPMap()
//That function won't be needed afterall.
{
int count=0;
gnuworld::xNetwork::clientIterator cItr = Network->clients_begin();
for (; cItr != Network->clients_end(); cItr++) {
iClient* theUser = (*cItr).second;
if (theUser->isOper()) {
opersIPMap[xIP(theUser->getIP()).GetNumericIP()] = theUser->getRealNickUserHost();
count++;
}
}
MsgChanLog("Refreshed opers IP list. %d global opers online right now. I have cumulated %d different IPs since I started", count, opersIPMap.size());
}
void ccontrol::announce(iClient* theClient, const string& text)
{
ccUser* tmpUser = IsAuth(theClient);
string yyxxx( MyUplink->getCharYY() + "]]]" ) ;
if (Network->findNick(AnnounceNick) != NULL) {
if (tmpUser && !tmpUser->getLogs())
Notice(theClient, "Nick %s is already in use for ANNOUNCE. Will use my own", AnnounceNick.c_str());
MsgChanLog("Nick %s is already in use for ANNOUNCE. Will use my own", AnnounceNick.c_str());
MyUplink->Write("%s O $* :%s", getCharYYXXX().c_str(), text.c_str());
return;
}
iClient* newClient = new iClient(
MyUplink->getIntYY(),
yyxxx,
AnnounceNick,
"announce",
"AAAAAA",
getHostName(),
getHostName(),
"+ok",
string(),
0,
"Announcement Service.",
::time( 0 ) ) ;
assert( newClient != 0 );
if(!MyUplink->AttachClient( newClient, this ) ) {
if (tmpUser && !tmpUser->getLogs())
Notice(theClient, "Error attaching announce client. Using my own nick for the announce.");
MsgChanLog("Error attaching announce client. Using my own nick for the announce.");
MyUplink->Write("%s O $* :%s", getCharYYXXX().c_str(), text.c_str());
delete newClient;
return;
}
MyUplink->Write("%s O $* :%s", newClient->getCharYYXXX().c_str(), text.c_str());
stringstream Quit;
Quit << "Did what I had to do! (At " << theClient->getNickName() << "'s request)";
if( MyUplink->DetachClient( newClient, Quit.str() ) ) {
delete newClient;
}
}
void ccontrol::privAnnounce(iClient* theClient, const string& text)
{
ccUser* tmpUser = IsAuth(theClient);
string yyxxx( MyUplink->getCharYY() + "]]]" ) ;
if (Network->findNick(AnnounceNick) != NULL) {
if (tmpUser && !tmpUser->getLogs())
Notice(theClient, "Nick %s is already in use for ANNOUNCE. Will use my own", AnnounceNick.c_str());
MsgChanLog("Nick %s is already in use for ANNOUNCE. Will use my own", AnnounceNick.c_str());
for (xNetwork::clientIterator ptr = Network->clients_begin(); ptr != Network->clients_end(); ptr++ )
{
MyUplink->Write("%s PRIVMSG %s :%s", getCharYYXXX().c_str(), ptr->second->getCharYYXXX().c_str(), text.c_str());
}
return;
}
iClient* newClient = new iClient(
MyUplink->getIntYY(),
yyxxx,
AnnounceNick,
"announce",
"AAAAAA",
getHostName(),
getHostName(),
"+ok",
string(),
0,
"Announcement Service.",
::time( 0 ) ) ;
assert( newClient != 0 );
if(!MyUplink->AttachClient( newClient, this ) ) {
if (tmpUser && !tmpUser->getLogs())
Notice(theClient, "Error attaching announce client. Using my own nick for the announce.");
MsgChanLog("Error attaching announce client. Using my own nick for the announce.");
for (xNetwork::clientIterator ptr = Network->clients_begin(); ptr != Network->clients_end(); ptr++ )
{
MyUplink->Write("%s PRIVMSG %s :%s", getCharYYXXX().c_str(), ptr->second->getCharYYXXX().c_str(), text.c_str());
}
delete newClient;
return;
}
for (xNetwork::clientIterator ptr = Network->clients_begin(); ptr != Network->clients_end(); ptr++ )
{
MyUplink->Write("%s PRIVMSG %s :%s", newClient->getCharYYXXX().c_str(), ptr->second->getCharYYXXX().c_str(), text.c_str());
}
stringstream Quit;
Quit << "Did what I had to do! (At " << theClient->getNickName() << "'s request)";
if( MyUplink->DetachClient( newClient, Quit.str() ) ) {
delete newClient;
}
}
}
} // namespace gnuworld