X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fhelperfuncs.cpp;h=f8ee0d1a65f568d5ddc9629be5a0366b51817bee;hb=78db7544d26cdeffeb2bd8045529fe90bd5d852d;hp=205121edd2b55639665e5bc2e0c26facc5576fd7;hpb=4b7c157f63daae9c59170c8947c1caea48384cf3;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/helperfuncs.cpp b/src/helperfuncs.cpp index 205121edd..f8ee0d1a6 100644 --- a/src/helperfuncs.cpp +++ b/src/helperfuncs.cpp @@ -1,1351 +1,556 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ +/* + * InspIRCd -- Internet Relay Chat Daemon * - * Inspire is copyright (C) 2002-2004 ChatSpike-Dev. - * E-mail: - * - * + * Copyright (C) 2019-2020 Matt Schatz + * Copyright (C) 2018 linuxdaemon + * Copyright (C) 2013 Daniel Vassdal + * Copyright (C) 2013 Adam + * Copyright (C) 2012-2015 Attila Molnar + * Copyright (C) 2012-2014, 2017-2018, 2020 Sadie Powell + * Copyright (C) 2012, 2018 Robby + * Copyright (C) 2012 ChrisTX + * Copyright (C) 2009-2010 Daniel De Graaf + * Copyright (C) 2007, 2010 Craig Edwards + * Copyright (C) 2007 Dennis Friis + * Copyright (C) 2006-2008 Robin Burchell * - * Written by Craig Edwards, Craig McLure, and others. - * This program is free but copyrighted software; see - * the file COPYING for details. + * This file is part of InspIRCd. InspIRCd 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, version 2. * - * --------------------------------------------------- + * 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, see . */ -using namespace std; -#include "inspircd_config.h" -#include "inspircd.h" -#include "inspircd_io.h" -#include "inspircd_util.h" -#include -#include -#include -#include -#include -#ifdef GCC3 -#include -#else -#include +#ifdef _WIN32 +#define _CRT_RAND_S +#include #endif -#include -#include -#include -#include -#include "connection.h" -#include "users.h" -#include "ctables.h" -#include "globals.h" -#include "modules.h" -#include "dynamic.h" -#include "wildcard.h" -#include "message.h" -#include "mode.h" -#include "xline.h" -#include "commands.h" -#include "inspstring.h" -#include "helperfuncs.h" -#include "hashcomp.h" - -extern int MODCOUNT; -extern std::vector modules; - -extern time_t TIME; -extern bool nofork; -extern char lowermap[255]; -extern char ServerName[MAXBUF]; -extern char Network[MAXBUF]; -extern char ServerDesc[MAXBUF]; -extern char list[MAXBUF]; - -extern int debugging; -extern int LogLevel; - -extern std::stringstream config_f; - - - -extern FILE *log_file; -extern userrec* fd_ref_table[65536]; -extern int statsAccept, statsRefused, statsUnknown, statsCollisions, statsDns, statsDnsGood, statsDnsBad, statsConnects, statsSent, statsRecv; - -static char already_sent[65536]; -extern std::vector all_opers; - -extern ClassVector Classes; - -typedef nspace::hash_map, irc::StrHashComp> user_hash; -typedef nspace::hash_map, irc::StrHashComp> chan_hash; -typedef std::deque command_table; - -extern user_hash clientlist; -extern chan_hash chanlist; -extern command_table cmdlist; -extern file_cache MOTD; -extern file_cache RULES; - -void log(int level,char *text, ...) -{ - char textbuffer[MAXBUF]; - va_list argsPtr; - time_t rawtime; - struct tm * timeinfo; - if (level < LogLevel) - return; - - time(&rawtime); - timeinfo = localtime (&rawtime); - - if (log_file) - { - char b[MAXBUF]; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - strlcpy(b,asctime(timeinfo),MAXBUF); - b[24] = ':'; // we know this is the end of the time string - fprintf(log_file,"%s %s\n",b,textbuffer); - if (nofork) - { - // nofork enabled? display it on terminal too - printf("%s %s\n",b,textbuffer); - } - } -} +#include "inspircd.h" +#include "xline.h" +#include "exitcodes.h" +#include -void readfile(file_cache &F, const char* fname) +/* Find a user record by nickname and return a pointer to it */ +User* InspIRCd::FindNick(const std::string &nick) { - FILE* file; - char linebuf[MAXBUF]; - - log(DEBUG,"readfile: loading %s",fname); - F.clear(); - file = fopen(fname,"r"); - if (file) - { - while (!feof(file)) - { - fgets(linebuf,sizeof(linebuf),file); - linebuf[strlen(linebuf)-1]='\0'; - if (linebuf[0] == 0) - { - strcpy(linebuf," "); - } - if (!feof(file)) - { - F.push_back(linebuf); - } - } - fclose(file); - } - else - { - log(DEBUG,"readfile: failed to load file: %s",fname); - } - log(DEBUG,"readfile: loaded %s, %lu lines",fname,(unsigned long)F.size()); + if (!nick.empty() && isdigit(*nick.begin())) + return FindUUID(nick); + return FindNickOnly(nick); } -void Write(int sock,char *text, ...) +User* InspIRCd::FindNickOnly(const std::string &nick) { - if (sock < 0) - return; - if (!text) - { - log(DEFAULT,"*** BUG *** Write was given an invalid parameter"); - return; - } - char textbuffer[MAXBUF]; - va_list argsPtr; - char tb[MAXBUF]; - - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - int bytes = snprintf(tb,MAXBUF,"%s\r\n",textbuffer); - chop(tb); - if (fd_ref_table[sock]) - { - int MOD_RESULT = 0; - FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes)); - fd_ref_table[sock]->AddWriteBuf(tb); - statsSent += bytes; - } - else log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!"); -} + user_hash::iterator iter = this->Users->clientlist.find(nick); -/* write a server formatted numeric response to a single socket */ + if (iter == this->Users->clientlist.end()) + return NULL; -void WriteServ(int sock, char* text, ...) -{ - if (sock < 0) - return; - if (!text) - { - log(DEFAULT,"*** BUG *** WriteServ was given an invalid parameter"); - return; - } - char textbuffer[MAXBUF],tb[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - int bytes = snprintf(tb,MAXBUF,":%s %s\r\n",ServerName,textbuffer); - chop(tb); - if (fd_ref_table[sock]) - { - int MOD_RESULT = 0; - FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes)); - fd_ref_table[sock]->AddWriteBuf(tb); - statsSent += bytes; - } - else log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!"); + return iter->second; } -/* write text from an originating user to originating user */ - -void WriteFrom(int sock, userrec *user,char* text, ...) +User *InspIRCd::FindUUID(const std::string &uid) { - if (sock < 0) - return; - if ((!text) || (!user)) - { - log(DEFAULT,"*** BUG *** WriteFrom was given an invalid parameter"); - return; - } - char textbuffer[MAXBUF],tb[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - int bytes = snprintf(tb,MAXBUF,":%s!%s@%s %s\r\n",user->nick,user->ident,user->dhost,textbuffer); - chop(tb); - if (fd_ref_table[sock]) - { - int MOD_RESULT = 0; - FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes)); - fd_ref_table[sock]->AddWriteBuf(tb); - statsSent += bytes; - } - else log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!"); -} + user_hash::iterator finduuid = this->Users->uuidlist.find(uid); -/* write text to an destination user from a source user (e.g. user privmsg) */ + if (finduuid == this->Users->uuidlist.end()) + return NULL; -void WriteTo(userrec *source, userrec *dest,char *data, ...) -{ - if ((!dest) || (!data)) - { - log(DEFAULT,"*** BUG *** WriteTo was given an invalid parameter"); - return; - } - if (dest->fd == FD_MAGIC_NUMBER) - return; - char textbuffer[MAXBUF],tb[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, data); - vsnprintf(textbuffer, MAXBUF, data, argsPtr); - va_end(argsPtr); - chop(tb); - - // if no source given send it from the server. - if (!source) - { - WriteServ(dest->fd,":%s %s",ServerName,textbuffer); - } - else - { - WriteFrom(dest->fd,source,"%s",textbuffer); - } + return finduuid->second; } +/* find a channel record by channel name and return a pointer to it */ -/* write formatted text from a source user to all users on a channel - * including the sender (NOT for privmsg, notice etc!) */ - -void WriteChannel(chanrec* Ptr, userrec* user, char* text, ...) +Channel* InspIRCd::FindChan(const std::string &chan) { - if ((!Ptr) || (!user) || (!text)) - { - log(DEFAULT,"*** BUG *** WriteChannel was given an invalid parameter"); - return; - } - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - std::vector *ulist = Ptr->GetUsers(); - for (unsigned int j = 0; j < ulist->size(); j++) - { - char* o = (*ulist)[j]; - userrec* otheruser = (userrec*)o; - if (otheruser->fd != FD_MAGIC_NUMBER) - WriteTo(user,otheruser,"%s",textbuffer); - } -} + chan_hash::iterator iter = chanlist.find(chan); -/* write formatted text from a source user to all users on a channel - * including the sender (NOT for privmsg, notice etc!) doesnt send to - * users on remote servers */ + if (iter == chanlist.end()) + /* Couldn't find it */ + return NULL; -void WriteChannelLocal(chanrec* Ptr, userrec* user, char* text, ...) -{ - if ((!Ptr) || (!text)) - { - log(DEFAULT,"*** BUG *** WriteChannel was given an invalid parameter"); - return; - } - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - std::vector *ulist = Ptr->GetUsers(); - for (unsigned int j = 0; j < ulist->size(); j++) - { - char* o = (*ulist)[j]; - userrec* otheruser = (userrec*)o; - if ((otheruser->fd != FD_MAGIC_NUMBER) && (otheruser->fd != -1) && (otheruser != user)) - { - if (!user) - { - WriteServ(otheruser->fd,"%s",textbuffer); - } - else - { - WriteTo(user,otheruser,"%s",textbuffer); - } - } - } + return iter->second; } -void WriteChannelWithServ(char* ServName, chanrec* Ptr, char* text, ...) +bool InspIRCd::IsValidMask(const std::string &mask) { - if ((!Ptr) || (!text)) - { - log(DEFAULT,"*** BUG *** WriteChannelWithServ was given an invalid parameter"); - return; - } - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - - std::vector *ulist = Ptr->GetUsers(); - for (unsigned int j = 0; j < ulist->size(); j++) - { - char* o = (*ulist)[j]; - userrec* otheruser = (userrec*)o; - if (otheruser->fd != FD_MAGIC_NUMBER) - WriteServ(otheruser->fd,"%s",textbuffer); - } -} - -/* write formatted text from a source user to all users on a channel except - * for the sender (for privmsg etc) */ + const char* dest = mask.c_str(); + int exclamation = 0; + int atsign = 0; -void ChanExceptSender(chanrec* Ptr, userrec* user, char* text, ...) -{ - if ((!Ptr) || (!user) || (!text)) - { - log(DEFAULT,"*** BUG *** ChanExceptSender was given an invalid parameter"); - return; - } - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - std::vector *ulist = Ptr->GetUsers(); - for (unsigned int j = 0; j < ulist->size(); j++) - { - char* o = (*ulist)[j]; - userrec* otheruser = (userrec*)o; - if ((otheruser->fd != FD_MAGIC_NUMBER) && (user != otheruser)) - WriteFrom(otheruser->fd,user,"%s",textbuffer); - } -} - -std::string GetServerDescription(char* servername) -{ - std::string description = ""; - FOREACH_MOD OnGetServerDescription(servername,description); - if (description != "") - { - return description; - } - else + for (const char* i = dest; *i; i++) { - return ServerDesc; // not a remote server that can be found, it must be me. - } -} + /* out of range character, bad mask */ + if (*i < 32 || *i > 126) + { + return false; + } -/* write a formatted string to all users who share at least one common - * channel, including the source user e.g. for use in NICK */ + switch (*i) + { + case '!': + exclamation++; + break; + case '@': + atsign++; + break; + } + } -void WriteCommon(userrec *u, char* text, ...) -{ - if (!u) - { - log(DEFAULT,"*** BUG *** WriteCommon was given an invalid parameter"); - return; - } - - if (u->registered != 7) { - log(DEFAULT,"*** BUG *** WriteCommon on an unregistered user"); - return; - } - - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - // FIX: Stops a message going to the same person more than once - memset(&already_sent,0,65536); - - bool sent_to_at_least_one = false; - - for (int i = 0; i < MAXCHANS; i++) - { - if (u->chans[i].channel) - { - std::vector *ulist = u->chans[i].channel->GetUsers(); - for (unsigned int j = 0; j < ulist->size(); j++) - { - char* o = (*ulist)[j]; - userrec* otheruser = (userrec*)o; - if ((otheruser->fd > 0) && (!already_sent[otheruser->fd])) - { - already_sent[otheruser->fd] = 1; - WriteFrom(otheruser->fd,u,"%s",textbuffer); - sent_to_at_least_one = true; - } - } - } - } - // if the user was not in any channels, no users will receive the text. Make sure the user - // receives their OWN message for WriteCommon - if (!sent_to_at_least_one) - { - WriteFrom(u->fd,u,"%s",textbuffer); - } -} + /* valid masks only have 1 ! and @ */ + if (exclamation != 1 || atsign != 1) + return false; -/* write a formatted string to all users who share at least one common - * channel, NOT including the source user e.g. for use in QUIT */ + if (mask.length() > ServerInstance->Config->Limits.GetMaxMask()) + return false; -void WriteCommonExcept(userrec *u, char* text, ...) -{ - if (!u) - { - log(DEFAULT,"*** BUG *** WriteCommon was given an invalid parameter"); - return; - } - - if (u->registered != 7) { - log(DEFAULT,"*** BUG *** WriteCommon on an unregistered user"); - return; - } - - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - memset(&already_sent,0,65536); - - for (int i = 0; i < MAXCHANS; i++) - { - if (u->chans[i].channel) - { - std::vector *ulist = u->chans[i].channel->GetUsers(); - for (unsigned int j = 0; j < ulist->size(); j++) - { - char* o = (*ulist)[j]; - userrec* otheruser = (userrec*)o; - if (u != otheruser) - { - if ((otheruser->fd > 0) && (!already_sent[otheruser->fd])) - { - already_sent[otheruser->fd] = 1; - WriteFrom(otheruser->fd,u,"%s",textbuffer); - } - } - } - } - } + return true; } -void WriteOpers(char* text, ...) +void InspIRCd::StripColor(std::string &sentence) { - if (!text) - { - log(DEFAULT,"*** BUG *** WriteOpers was given an invalid parameter"); - return; - } - - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - for (std::vector::iterator i = all_opers.begin(); i != all_opers.end(); i++) - { - userrec* a = *i; - if ((a) && (a->fd != FD_MAGIC_NUMBER)) - { - if (strchr(a->modes,'s')) - { - // send server notices to all with +s - WriteServ(a->fd,"NOTICE %s :%s",a->nick,textbuffer); - } - } - } + /* refactor this completely due to SQUIT bug since the old code would strip last char and replace with \0 --peavey */ + int seq = 0; + + for (std::string::iterator i = sentence.begin(); i != sentence.end();) + { + if (*i == 3) + seq = 1; + else if (seq && (( ((*i >= '0') && (*i <= '9')) || (*i == ',') ) )) + { + seq++; + if ( (seq <= 4) && (*i == ',') ) + seq = 1; + else if (seq > 3) + seq = 0; + } + else + seq = 0; + + // Strip all control codes too except \001 for CTCP + if (seq || ((*i >= 0) && (*i < 32) && (*i != 1))) + i = sentence.erase(i); + else + ++i; + } } -void ServerNoticeAll(char* text, ...) +void InspIRCd::ProcessColors(file_cache& input) { - if (!text) - return; - - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + /* + * Replace all color codes from the special[] array to actual + * color code chars using C++ style escape sequences. You + * can append other chars to replace if you like -- Justasic + */ + static struct special_chars + { + std::string character; + std::string replace; + special_chars(const std::string& c, const std::string& r) + : character(c) + , replace(r) + { + } + } special[] = { + special_chars("\\b", "\x02"), // Bold + special_chars("\\c", "\x03"), // Color + special_chars("\\i", "\x1D"), // Italic + special_chars("\\m", "\x11"), // Monospace + special_chars("\\r", "\x16"), // Reverse + special_chars("\\s", "\x1E"), // Strikethrough + special_chars("\\u", "\x1F"), // Underline + special_chars("\\x", "\x0F"), // Reset + special_chars("", "") + }; + + for(file_cache::iterator it = input.begin(), it_end = input.end(); it != it_end; it++) { - if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER)) + std::string ret = *it; + for(int i = 0; special[i].character.empty() == false; ++i) { - WriteServ(i->second->fd,"NOTICE $%s :%s",ServerName,textbuffer); + std::string::size_type pos = ret.find(special[i].character); + if(pos == std::string::npos) // Couldn't find the character, skip this line + continue; + + if((pos > 0) && (ret[pos-1] == '\\') && (ret[pos] == '\\')) + continue; // Skip double slashes. + + // Replace all our characters in the array + while(pos != std::string::npos) + { + ret = ret.substr(0, pos) + special[i].replace + ret.substr(pos + special[i].character.size()); + pos = ret.find(special[i].character, pos + special[i].replace.size()); + } } + + // Replace double slashes with a single slash before we return + std::string::size_type pos = ret.find("\\\\"); + while(pos != std::string::npos) + { + ret = ret.substr(0, pos) + "\\" + ret.substr(pos + 2); + pos = ret.find("\\\\", pos + 1); + } + *it = ret; } } -void ServerPrivmsgAll(char* text, ...) +/* true for valid channel name, false else */ +bool InspIRCd::DefaultIsChannel(const std::string& chname) { - if (!text) - return; + if (chname.empty() || chname.length() > ServerInstance->Config->Limits.ChanMax) + return false; - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); + if (chname[0] != '#') + return false; - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + for (std::string::const_iterator i = chname.begin()+1; i != chname.end(); ++i) { - if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER)) + switch (*i) { - WriteServ(i->second->fd,"PRIVMSG $%s :%s",ServerName,textbuffer); + case ' ': + case ',': + case 7: + return false; } } -} - -void NoticeAllOpers(userrec *source, bool local_only, char* text, ...) -{ - if ((!text) || (!source)) - { - log(DEFAULT,"*** BUG *** NoticeAllOpers was given an invalid parameter"); - return; - } - - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - for (std::vector::iterator i = all_opers.begin(); i != all_opers.end(); i++) - { - userrec* a = *i; - if ((a) && (a->fd != FD_MAGIC_NUMBER)) - { - if (strchr(a->modes,'s')) - { - // send server notices to all with +s - WriteServ(a->fd,"NOTICE %s :*** Notice From %s: %s",a->nick,source->nick,textbuffer); - } - } - } + return true; } -// returns TRUE of any users on channel C occupy server 'servername'. -bool ChanAnyOnThisServer(chanrec *c,char* servername) +/* true for valid nickname, false else */ +bool InspIRCd::DefaultIsNick(const std::string& n) { - log(DEBUG,"ChanAnyOnThisServer"); - - std::vector *ulist = c->GetUsers(); - for (unsigned int j = 0; j < ulist->size(); j++) - { - char* o = (*ulist)[j]; - userrec* user = (userrec*)o; - if (!strcasecmp(user->server,servername)) - return true; - } - return false; -} + if (n.empty() || n.length() > ServerInstance->Config->Limits.NickMax) + return false; -// returns true if user 'u' shares any common channels with any users on server 'servername' + for (std::string::const_iterator i = n.begin(); i != n.end(); ++i) + { + if ((*i >= 'A') && (*i <= '}')) + { + /* "A"-"}" can occur anywhere in a nickname */ + continue; + } -bool CommonOnThisServer(userrec* u,const char* servername) -{ - log(DEBUG,"ChanAnyOnThisServer"); - - for (int i = 0; i < MAXCHANS; i++) - { - if (u->chans[i].channel) - { - std::vector *ulist = u->chans[i].channel->GetUsers(); - for (unsigned int j = 0; j < ulist->size(); j++) - { - char* o = (*ulist)[j]; - userrec* user = (userrec*)o; - if (!strcasecmp(user->server,servername)) - return true; - } - } - } - return false; -} + if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i != n.begin())) + { + /* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */ + continue; + } + /* invalid character! abort */ + return false; + } -void WriteMode(const char* modes, int flags, const char* text, ...) -{ - if ((!text) || (!modes) || (!flags)) - { - log(DEFAULT,"*** BUG *** WriteMode was given an invalid parameter"); - return; - } - - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - int modelen = strlen(modes); - - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) - { - if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER)) - { - bool send_to_user = false; - - if (flags == WM_AND) - { - send_to_user = true; - for (int n = 0; n < modelen; n++) - { - if (!hasumode(i->second,modes[n])) - { - send_to_user = false; - break; - } - } - } - else if (flags == WM_OR) - { - send_to_user = false; - for (int n = 0; n < modelen; n++) - { - if (hasumode(i->second,modes[n])) - { - send_to_user = true; - break; - } - } - } - - if (send_to_user) - { - WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,textbuffer); - } - } - } + return true; } -void NoticeAll(userrec *source, bool local_only, char* text, ...) +/* return true for good ident, false else */ +bool InspIRCd::DefaultIsIdent(const std::string& n) { - if ((!text) || (!source)) - { - log(DEFAULT,"*** BUG *** NoticeAll was given an invalid parameter"); - return; - } - - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) - { - if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER)) - { - WriteFrom(i->second->fd,source,"NOTICE $* :%s",textbuffer); - } - } - -} + if (n.empty()) + return false; + for (std::string::const_iterator i = n.begin(); i != n.end(); ++i) + { + if ((*i >= 'A') && (*i <= '}')) + { + continue; + } -void WriteWallOps(userrec *source, bool local_only, char* text, ...) -{ - if ((!text) || (!source)) - { - log(DEFAULT,"*** BUG *** WriteOpers was given an invalid parameter"); - return; - } - - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) - { - if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER)) - { - if (strchr(i->second->modes,'w')) - { - WriteTo(source,i->second,"WALLOPS :%s",textbuffer); - } - } - } -} + if (((*i >= '0') && (*i <= '9')) || (*i == '-') || (*i == '.')) + { + continue; + } -/* convert a string to lowercase. Note following special circumstances - * taken from RFC 1459. Many "official" server branches still hold to this - * rule so i will too; - * - * Because of IRC's scandanavian origin, the characters {}| are - * considered to be the lower case equivalents of the characters []\, - * respectively. This is a critical issue when determining the - * equivalence of two nicknames. - */ + return false; + } -void strlower(char *n) -{ - if (n) - { - for (char* t = n; *t; t++) - *t = lowermap[(unsigned)*t]; - } + return true; } -/* Find a user record by nickname and return a pointer to it */ - -userrec* Find(std::string nick) +bool InspIRCd::IsHost(const std::string& host) { - user_hash::iterator iter = clientlist.find(nick); + // Hostnames must be non-empty and shorter than the maximum hostname length. + if (host.empty() || host.length() > ServerInstance->Config->Limits.MaxHost) + return false; - if (iter == clientlist.end()) - /* Couldn't find it */ - return NULL; + unsigned int numdashes = 0; + unsigned int numdots = 0; + bool seendot = false; + const std::string::const_iterator hostend = host.end() - 1; + for (std::string::const_iterator iter = host.begin(); iter != host.end(); ++iter) + { + unsigned char chr = static_cast(*iter); - return iter->second; -} + // If the current character is a label separator. + if (chr == '.') + { + numdots++; -/* find a channel record by channel name and return a pointer to it */ + // Consecutive separators are not allowed and dashes can not exist at the start or end + // of labels and separators must only exist between labels. + if (seendot || numdashes || iter == host.begin() || iter == hostend) + return false; -chanrec* FindChan(const char* chan) -{ - if (!chan) - { - log(DEFAULT,"*** BUG *** Findchan was given an invalid parameter"); - return NULL; - } + seendot = true; + continue; + } - chan_hash::iterator iter = chanlist.find(chan); + // If this point is reached then the character is not a dot. + seendot = false; - if (iter == chanlist.end()) - /* Couldn't find it */ - return NULL; + // If the current character is a dash. + if (chr == '-') + { + // Consecutive separators are not allowed and dashes can not exist at the start or end + // of labels and separators must only exist between labels. + if (seendot || numdashes >= 2 || iter == host.begin() || iter == hostend) + return false; - return iter->second; -} + numdashes += 1; + continue; + } + // If this point is reached then the character is not a dash. + numdashes = 0; -long GetMaxBans(char* name) -{ - char CM[MAXBUF]; - for (int count = 0; count < ConfValueEnum("banlist",&config_f); count++) - { - ConfValue("banlist","chan",count,CM,&config_f); - if (match(name,CM)) - { - ConfValue("banlist","limit",count,CM,&config_f); - return atoi(CM); - } - } - return 64; -} + // Alphanumeric characters are allowed at any position. + if ((chr >= '0' && chr <= '9') || (chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z')) + continue; -void purge_empty_chans(userrec* u) -{ + return false; + } - int go_again = 1, purge = 0; - - // firstly decrement the count on each channel - for (int f = 0; f < MAXCHANS; f++) - { - if (u->chans[f].channel) - { - u->chans[f].channel->DelUser((char*)u); - } - } - - for (int i = 0; i < MAXCHANS; i++) - { - if (u->chans[i].channel) - { - if (!usercount(u->chans[i].channel)) - { - chan_hash::iterator i2 = chanlist.find(u->chans[i].channel->name); - /* kill the record */ - if (i2 != chanlist.end()) - { - log(DEBUG,"del_channel: destroyed: %s",i2->second->name); - if (i2->second) - delete i2->second; - chanlist.erase(i2); - go_again = 1; - purge++; - u->chans[i].channel = NULL; - } - } - else - { - log(DEBUG,"skipped purge for %s",u->chans[i].channel->name); - } - } - } - log(DEBUG,"completed channel purge, killed %lu",(unsigned long)purge); - - DeleteOper(u); + // Whilst simple hostnames (e.g. localhost) are valid we do not allow the server to use + // them to prevent issues with clients that differentiate between short client and server + // prefixes by checking whether the nickname contains a dot. + return numdots; } - -char scratch[MAXBUF]; -char sparam[MAXBUF]; - -char* chanmodes(chanrec *chan) +bool InspIRCd::IsSID(const std::string &str) { - if (!chan) - { - log(DEFAULT,"*** BUG *** chanmodes was given an invalid parameter"); - strcpy(scratch,""); - return scratch; - } - - strcpy(scratch,""); - strcpy(sparam,""); - if (chan->binarymodes & CM_NOEXTERNAL) - { - strlcat(scratch,"n",MAXMODES); - } - if (chan->binarymodes & CM_TOPICLOCK) - { - strlcat(scratch,"t",MAXMODES); - } - if (chan->key[0]) - { - strlcat(scratch,"k",MAXMODES); - } - if (chan->limit) - { - strlcat(scratch,"l",MAXMODES); - } - if (chan->binarymodes & CM_INVITEONLY) - { - strlcat(scratch,"i",MAXMODES); - } - if (chan->binarymodes & CM_MODERATED) - { - strlcat(scratch,"m",MAXMODES); - } - if (chan->binarymodes & CM_SECRET) - { - strlcat(scratch,"s",MAXMODES); - } - if (chan->binarymodes & CM_PRIVATE) - { - strlcat(scratch,"p",MAXMODES); - } - if (chan->key[0]) - { - strlcat(sparam," ",MAXBUF); - strlcat(sparam,chan->key,MAXBUF); - } - if (chan->limit) - { - char foo[24]; - sprintf(foo," %lu",(unsigned long)chan->limit); - strlcat(sparam,foo,MAXBUF); - } - if (*chan->custom_modes) - { - strlcat(scratch,chan->custom_modes,MAXMODES); - for (int z = 0; chan->custom_modes[z] != 0; z++) - { - std::string extparam = chan->GetModeParameter(chan->custom_modes[z]); - if (extparam != "") - { - strlcat(sparam," ",MAXBUF); - strlcat(sparam,extparam.c_str(),MAXBUF); - } - } - } - log(DEBUG,"chanmodes: %s %s%s",chan->name,scratch,sparam); - strlcat(scratch,sparam,MAXMODES); - return scratch; + /* Returns true if the string given is exactly 3 characters long, + * starts with a digit, and the other two characters are A-Z or digits + */ + return ((str.length() == 3) && isdigit(str[0]) && + ((str[1] >= 'A' && str[1] <= 'Z') || isdigit(str[1])) && + ((str[2] >= 'A' && str[2] <= 'Z') || isdigit(str[2]))); } - -/* compile a userlist of a channel into a string, each nick seperated by - * spaces and op, voice etc status shown as @ and + */ - -void userlist(userrec *user,chanrec *c) -{ - if ((!c) || (!user)) - { - log(DEFAULT,"*** BUG *** userlist was given an invalid parameter"); - return; - } - - snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name); - - std::vector *ulist = c->GetUsers(); - for (unsigned int i = 0; i < ulist->size(); i++) - { - char* o = (*ulist)[i]; - userrec* otheruser = (userrec*)o; - if ((!has_channel(user,c)) && (strchr(otheruser->modes,'i'))) - { - /* user is +i, and source not on the channel, does not show - * nick in NAMES list */ - continue; - } - strlcat(list,cmode(otheruser,c),MAXBUF); - strlcat(list,otheruser->nick,MAXBUF); - strlcat(list," ",MAXBUF); - if (strlen(list)>(480-NICKMAX)) - { - /* list overflowed into - * multiple numerics */ - WriteServ(user->fd,"%s",list); - snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name); - } - } - /* if whats left in the list isnt empty, send it */ - if (list[strlen(list)-1] != ':') - { - WriteServ(user->fd,"%s",list); - } +/** A lookup table of values for multiplier characters used by + * InspIRCd::Duration(). In this lookup table, the indexes for + * the ascii values 'm' and 'M' have the value '60', the indexes + * for the ascii values 'D' and 'd' have a value of '86400', etc. + */ +static const unsigned int duration_multi[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 604800, 0, 31557600, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 604800, 0, 31557600, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +bool InspIRCd::Duration(const std::string& str, unsigned long& duration) +{ + unsigned long total = 0; + unsigned long subtotal = 0; + + /* Iterate each item in the string, looking for number or multiplier */ + for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) + { + /* Found a number, queue it onto the current number */ + if ((*i >= '0') && (*i <= '9')) + { + subtotal = (subtotal * 10) + (*i - '0'); + } + else + { + /* Found something that's not a number, find out how much + * it multiplies the built up number by, multiply the total + * and reset the built up number. + */ + unsigned int multiplier = duration_multi[static_cast(*i)]; + if (multiplier == 0) + return false; + + total += subtotal * multiplier; + + /* Next subtotal please */ + subtotal = 0; + } + } + /* Any trailing values built up are treated as raw seconds */ + duration = total + subtotal; + return true; } -/* return a count of the users on a specific channel accounting for - * invisible users who won't increase the count. e.g. for /LIST */ - -int usercount_i(chanrec *c) +unsigned long InspIRCd::Duration(const std::string& str) { - int count = 0; - - if (!c) - { - log(DEFAULT,"*** BUG *** usercount_i was given an invalid parameter"); - return 0; - } - - strcpy(list,""); - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) - { - if (i->second) - { - if (has_channel(i->second,c)) - { - if (isnick(i->second->nick)) - { - if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i'))) - { - /* user is +i, and source not on the channel, does not show - * nick in NAMES list */ - continue; - } - count++; - } - } - } - } - log(DEBUG,"usercount_i: %s %lu",c->name,(unsigned long)count); - return count; + unsigned long out = 0; + InspIRCd::Duration(str, out); + return out; } - -int usercount(chanrec *c) +bool InspIRCd::IsValidDuration(const std::string& duration) { - if (!c) - { - log(DEFAULT,"*** BUG *** usercount was given an invalid parameter"); - return 0; - } - int count = c->GetUserCounter(); - log(DEBUG,"usercount: %s %lu",c->name,(unsigned long)count); - return count; -} - - -// looks up a users password for their connection class (/ tags) + for (std::string::const_iterator i = duration.begin(); i != duration.end(); ++i) + { + unsigned char c = *i; + if (((c >= '0') && (c <= '9'))) + continue; -char* Passwd(userrec *user) -{ - for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++) - { - if (match(user->host,i->host) && (i->type == CC_ALLOW)) - { - return i->pass; - } - } - return ""; + if (!duration_multi[c]) + return false; + } + return true; } -bool IsDenied(userrec *user) +std::string InspIRCd::DurationString(time_t duration) { - for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++) - { - if (match(user->host,i->host) && (i->type == CC_DENY)) - { - return true; - } - } - return false; -} - + if (duration == 0) + return "0s"; + time_t years = duration / 31449600; + time_t weeks = (duration / 604800) % 52; + time_t days = (duration / 86400) % 7; + time_t hours = (duration / 3600) % 24; + time_t minutes = (duration / 60) % 60; + time_t seconds = duration % 60; + std::string ret; -/* sends out an error notice to all connected clients (not to be used - * lightly!) */ + if (years) + ret = ConvToStr(years) + "y"; + if (weeks) + ret += ConvToStr(weeks) + "w"; + if (days) + ret += ConvToStr(days) + "d"; + if (hours) + ret += ConvToStr(hours) + "h"; + if (minutes) + ret += ConvToStr(minutes) + "m"; + if (seconds) + ret += ConvToStr(seconds) + "s"; -void send_error(char *s) -{ - log(DEBUG,"send_error: %s",s); - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) - { - if (isnick(i->second->nick)) - { - WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,s); - } - else - { - // fix - unregistered connections receive ERROR, not NOTICE - Write(i->second->fd,"ERROR :%s",s); - } - } + return ret; } -void Error(int status) +std::string InspIRCd::Format(va_list& vaList, const char* formatString) { - signal (SIGALRM, SIG_IGN); - signal (SIGPIPE, SIG_IGN); - signal (SIGTERM, SIG_IGN); - signal (SIGABRT, SIG_IGN); - signal (SIGSEGV, SIG_IGN); - signal (SIGURG, SIG_IGN); - signal (SIGKILL, SIG_IGN); - log(DEFAULT,"*** fell down a pothole in the road to perfection ***"); - send_error("Error! Segmentation fault! save meeeeeeeeeeeeee *splat!*"); - Exit(status); -} + static std::vector formatBuffer(1024); -// this function counts all users connected, wether they are registered or NOT. -int usercnt(void) -{ - return clientlist.size(); -} - -// this counts only registered users, so that the percentages in /MAP don't mess up when users are sitting in an unregistered state -int registered_usercount(void) -{ - int c = 0; - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) - { - if (i->second->registered == 7) c++; - } - return c; -} - -int usercount_invisible(void) -{ - int c = 0; - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) - { - if ((isnick(i->second->nick)) && (strchr(i->second->modes,'i'))) c++; - } - return c; -} + while (true) + { + va_list dst; + va_copy(dst, vaList); -int usercount_opers(void) -{ - int c = 0; - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) - { - if ((isnick(i->second->nick)) && (strchr(i->second->modes,'o'))) c++; - } - return c; -} + int vsnret = vsnprintf(&formatBuffer[0], formatBuffer.size(), formatString, dst); + va_end(dst); -int usercount_unknown(void) -{ - int c = 0; - - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) - { - if ((i->second->fd) && (i->second->registered != 7)) - c++; - } - return c; -} + if (vsnret > 0 && static_cast(vsnret) < formatBuffer.size()) + { + break; + } -long chancount(void) -{ - return chanlist.size(); -} + formatBuffer.resize(formatBuffer.size() * 2); + } -long count_servs(void) -{ - return 0; + return std::string(&formatBuffer[0]); } -long servercount(void) +std::string InspIRCd::Format(const char* formatString, ...) { - return count_servs()+1; + std::string ret; + VAFORMAT(ret, formatString, formatString); + return ret; } -long local_count() +std::string InspIRCd::TimeString(time_t curtime, const char* format, bool utc) { - int c = 0; - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) - { - if ((i->second->fd) && (isnick(i->second->nick)) && (!strcasecmp(i->second->server,ServerName))) c++; - } - return c; -} - -void ShowMOTD(userrec *user) -{ - char buf[65536]; - std::string WholeMOTD = ""; - if (!MOTD.size()) - { - WriteServ(user->fd,"422 %s :Message of the day file is missing.",user->nick); - return; - } - snprintf(buf,65535,":%s 375 %s :- %s message of the day\r\n", ServerName, user->nick, ServerName); - WholeMOTD = WholeMOTD + buf; - for (unsigned int i = 0; i != MOTD.size(); i++) - { - snprintf(buf,65535,":%s 372 %s :- %s\r\n", ServerName, user->nick, MOTD[i].c_str()); - WholeMOTD = WholeMOTD + buf; - } - snprintf(buf,65535,":%s 376 %s :End of message of the day.\r\n", ServerName, user->nick); - WholeMOTD = WholeMOTD + buf; - // only one write operation - user->AddWriteBuf(WholeMOTD); - statsSent += WholeMOTD.length(); -} +#ifdef _WIN32 + if (curtime < 0) + curtime = 0; +#endif -void ShowRULES(userrec *user) -{ - if (!RULES.size()) - { - WriteServ(user->fd,"NOTICE %s :Rules file is missing.",user->nick); - return; - } - WriteServ(user->fd,"NOTICE %s :%s rules",user->nick,ServerName); - for (unsigned int i = 0; i != RULES.size(); i++) - { - WriteServ(user->fd,"NOTICE %s :%s",user->nick,RULES[i].c_str()); - } - WriteServ(user->fd,"NOTICE %s :End of %s rules.",user->nick,ServerName); -} + struct tm* timeinfo = utc ? gmtime(&curtime) : localtime(&curtime); + if (!timeinfo) + { + curtime = 0; + timeinfo = localtime(&curtime); + } -// this returns 1 when all modules are satisfied that the user should be allowed onto the irc server -// (until this returns true, a user will block in the waiting state, waiting to connect up to the -// registration timeout maximum seconds) -bool AllModulesReportReady(userrec* user) -{ - for (int i = 0; i <= MODCOUNT; i++) - { - int res = modules[i]->OnCheckReady(user); - if (!res) - return false; - } - return true; -} + // If the calculated year exceeds four digits or is less than the year 1000, + // the behavior of asctime() is undefined + if (timeinfo->tm_year + 1900 > 9999) + timeinfo->tm_year = 9999 - 1900; + else if (timeinfo->tm_year + 1900 < 1000) + timeinfo->tm_year = 0; -char islast(const char* s) -{ - return '+'; -} + // This is the default format used by asctime without the terminating new line. + if (!format) + format = "%a %b %d %Y %H:%M:%S"; -long map_count(const char* s) -{ - int c = 0; - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) - { - if ((i->second->fd) && (isnick(i->second->nick)) && (!strcasecmp(i->second->server,s))) c++; - } - return c; -} + char buffer[512]; + if (!strftime(buffer, sizeof(buffer), format, timeinfo)) + buffer[0] = '\0'; -void createcommand(char* cmd, handlerfunc f, char flags, int minparams,char* source) -{ - command_t comm; - /* create the command and push it onto the table */ - strlcpy(comm.command,cmd,MAXBUF); - strlcpy(comm.source,source,MAXBUF); - comm.handler_function = f; - comm.flags_needed = flags; - comm.min_params = minparams; - comm.use_count = 0; - comm.total_bytes = 0; - cmdlist.push_back(comm); - log(DEBUG,"Added command %s (%lu parameters)",cmd,(unsigned long)minparams); + return buffer; } - -void SetupCommandTable(void) +std::string InspIRCd::GenRandomStr(unsigned int length, bool printable) { - createcommand("USER",handle_user,0,4,""); - createcommand("NICK",handle_nick,0,1,""); - createcommand("QUIT",handle_quit,0,0,""); - createcommand("VERSION",handle_version,0,0,""); - createcommand("PING",handle_ping,0,1,""); - createcommand("PONG",handle_pong,0,1,""); - createcommand("ADMIN",handle_admin,0,0,""); - createcommand("PRIVMSG",handle_privmsg,0,2,""); - createcommand("INFO",handle_info,0,0,""); - createcommand("TIME",handle_time,0,0,""); - createcommand("WHOIS",handle_whois,0,1,""); - createcommand("WALLOPS",handle_wallops,'o',1,""); - createcommand("NOTICE",handle_notice,0,2,""); - createcommand("JOIN",handle_join,0,1,""); - createcommand("NAMES",handle_names,0,0,""); - createcommand("PART",handle_part,0,1,""); - createcommand("KICK",handle_kick,0,2,""); - createcommand("MODE",handle_mode,0,1,""); - createcommand("TOPIC",handle_topic,0,1,""); - createcommand("WHO",handle_who,0,1,""); - createcommand("MOTD",handle_motd,0,0,""); - createcommand("RULES",handle_rules,0,0,""); - createcommand("OPER",handle_oper,0,2,""); - createcommand("LIST",handle_list,0,0,""); - createcommand("DIE",handle_die,'o',1,""); - createcommand("RESTART",handle_restart,'o',1,""); - createcommand("KILL",handle_kill,'o',2,""); - createcommand("REHASH",handle_rehash,'o',0,""); - createcommand("LUSERS",handle_lusers,0,0,""); - createcommand("STATS",handle_stats,0,1,""); - createcommand("USERHOST",handle_userhost,0,1,""); - createcommand("AWAY",handle_away,0,0,""); - createcommand("ISON",handle_ison,0,0,""); - createcommand("SUMMON",handle_summon,0,0,""); - createcommand("USERS",handle_users,0,0,""); - createcommand("INVITE",handle_invite,0,0,""); - createcommand("PASS",handle_pass,0,1,""); - createcommand("TRACE",handle_trace,'o',0,""); - createcommand("WHOWAS",handle_whowas,0,1,""); - createcommand("CONNECT",handle_connect,'o',1,""); - createcommand("SQUIT",handle_squit,'o',0,""); - createcommand("MODULES",handle_modules,0,0,""); - createcommand("LINKS",handle_links,0,0,""); - createcommand("MAP",handle_map,0,0,""); - createcommand("KLINE",handle_kline,'o',1,""); - createcommand("GLINE",handle_gline,'o',1,""); - createcommand("ZLINE",handle_zline,'o',1,""); - createcommand("QLINE",handle_qline,'o',1,""); - createcommand("ELINE",handle_eline,'o',1,""); - createcommand("LOADMODULE",handle_loadmodule,'o',1,""); - createcommand("UNLOADMODULE",handle_unloadmodule,'o',1,""); - createcommand("SERVER",handle_server,0,0,""); - createcommand("COMMANDS",handle_commands,0,0,""); + std::vector str(length); + GenRandom(&str[0], length); + if (printable) + for (size_t i = 0; i < length; i++) + str[i] = 0x3F + (str[i] & 0x3F); + return std::string(&str[0], str.size()); } -bool DirValid(char* dirandfile) +// NOTE: this has a slight bias for lower values if max is not a power of 2. +// Don't use it if that matters. +unsigned long InspIRCd::GenRandomInt(unsigned long max) { - char work[MAXBUF]; - strlcpy(work,dirandfile,MAXBUF); - int p = strlen(work); - // we just want the dir - while (strlen(work)) - { - if (work[p] == '/') - { - work[p] = '\0'; - break; - } - work[p--] = '\0'; - } - char buffer[MAXBUF], otherdir[MAXBUF]; - // Get the current working directory - if( getcwd( buffer, MAXBUF ) == NULL ) - return false; - chdir(work); - if( getcwd( otherdir, MAXBUF ) == NULL ) - return false; - chdir(buffer); - if (strlen(otherdir) >= strlen(work)) - { - otherdir[strlen(work)] = '\0'; - if (!strcmp(otherdir,work)) - { - return true; - } - return false; - } - else return false; + unsigned long rv; + GenRandom((char*)&rv, sizeof(rv)); + return rv % max; } -std::string GetFullProgDir(char** argv, int argc) +// This is overridden by a higher-quality algorithm when TLS (SSL) support is loaded +void InspIRCd::DefaultGenRandom(char* output, size_t max) { - char work[MAXBUF]; - strlcpy(work,argv[0],MAXBUF); - int p = strlen(work); - // we just want the dir - while (strlen(work)) - { - if (work[p] == '/') - { - work[p] = '\0'; - break; - } - work[p--] = '\0'; - } - char buffer[MAXBUF], otherdir[MAXBUF]; - // Get the current working directory - if( getcwd( buffer, MAXBUF ) == NULL ) - return ""; - chdir(work); - if( getcwd( otherdir, MAXBUF ) == NULL ) - return ""; - chdir(buffer); - return otherdir; +#if defined HAS_ARC4RANDOM_BUF + arc4random_buf(output, max); +#else + for (unsigned int i = 0; i < max; ++i) +# ifdef _WIN32 + { + unsigned int uTemp; + if(rand_s(&uTemp) != 0) + output[i] = rand(); + else + output[i] = uTemp; + } +# else + output[i] = random(); +# endif +#endif } -