X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fhelperfuncs.cpp;h=fba76805c0495b1ae9ef5f0463783318b6f69332;hb=b4a174ee9c32d62ea6bf010e837e8c5b1c3d36a3;hp=53529f5395b8e35117bbf444da46631dc9972434;hpb=c16cda5d715241bb4bff8050bee942a8a34a72c0;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/helperfuncs.cpp b/src/helperfuncs.cpp index 53529f539..795f858fa 100644 --- a/src/helperfuncs.cpp +++ b/src/helperfuncs.cpp @@ -1,82 +1,54 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ +/* + * InspIRCd -- Internet Relay Chat Daemon * - * InspIRCd: (C) 2002-2008 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits + * 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 Dennis Friis + * Copyright (C) 2006-2008 Robin Burchell + * Copyright (C) 2005, 2007, 2010 Craig Edwards * - * 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 . */ -/* $Core */ + +#ifdef _WIN32 +#define _CRT_RAND_S +#include +#endif #include "inspircd.h" #include "xline.h" -#include "exitcodes.h" - -std::string InspIRCd::GetServerDescription(const char* servername) -{ - std::string description; - - FOREACH_MOD_I(this,I_OnGetServerDescription,OnGetServerDescription(servername,description)); - - if (!description.empty()) - { - return description; - } - else - { - // not a remote server that can be found, it must be me. - return Config->ServerDesc; - } -} /* Find a user record by nickname and return a pointer to it */ User* InspIRCd::FindNick(const std::string &nick) { if (!nick.empty() && isdigit(*nick.begin())) return FindUUID(nick); - - user_hash::iterator iter = this->Users->clientlist->find(nick); - - if (iter == this->Users->clientlist->end()) - /* Couldn't find it */ - return NULL; - - return iter->second; -} - -User* InspIRCd::FindNick(const char* nick) -{ - if (isdigit(*nick)) - return FindUUID(nick); - - user_hash::iterator iter = this->Users->clientlist->find(nick); - - if (iter == this->Users->clientlist->end()) - return NULL; - - return iter->second; + return FindNickOnly(nick); } User* InspIRCd::FindNickOnly(const std::string &nick) { - user_hash::iterator iter = this->Users->clientlist->find(nick); - - if (iter == this->Users->clientlist->end()) - return NULL; - - return iter->second; -} - -User* InspIRCd::FindNickOnly(const char* nick) -{ - user_hash::iterator iter = this->Users->clientlist->find(nick); + user_hash::iterator iter = this->Users->clientlist.find(nick); - if (iter == this->Users->clientlist->end()) + if (iter == this->Users->clientlist.end()) return NULL; return iter->second; @@ -84,77 +56,33 @@ User* InspIRCd::FindNickOnly(const char* nick) User *InspIRCd::FindUUID(const std::string &uid) { - return FindUUID(uid.c_str()); -} - -User *InspIRCd::FindUUID(const char *uid) -{ - user_hash::iterator finduuid = this->Users->uuidlist->find(uid); + user_hash::iterator finduuid = this->Users->uuidlist.find(uid); - if (finduuid == this->Users->uuidlist->end()) + if (finduuid == this->Users->uuidlist.end()) return NULL; return finduuid->second; } - /* find a channel record by channel name and return a pointer to it */ -Channel* InspIRCd::FindChan(const char* chan) -{ - chan_hash::iterator iter = chanlist->find(chan); - - if (iter == chanlist->end()) - /* Couldn't find it */ - return NULL; - - return iter->second; -} Channel* InspIRCd::FindChan(const std::string &chan) { - chan_hash::iterator iter = chanlist->find(chan); + chan_hash::iterator iter = chanlist.find(chan); - if (iter == chanlist->end()) + if (iter == chanlist.end()) /* Couldn't find it */ return NULL; return iter->second; } -/* Send an error notice to all users, registered or not */ -void InspIRCd::SendError(const std::string &s) -{ - for (std::vector::const_iterator i = this->Users->local_users.begin(); i != this->Users->local_users.end(); i++) - { - if ((*i)->registered == REG_ALL) - { - (*i)->WriteServ("NOTICE %s :%s",(*i)->nick.c_str(),s.c_str()); - } - else - { - /* Unregistered connections receive ERROR, not a NOTICE */ - (*i)->Write("ERROR :" + s); - } - /* This might generate a whole load of EAGAIN, but we dont really - * care about this, as if we call SendError something catastrophic - * has occured anyway, and we wont receive the events for these. - */ - (*i)->FlushWriteBuf(); - } -} - -/* return channel count */ -long InspIRCd::ChannelCount() -{ - return chanlist->size(); -} - bool InspIRCd::IsValidMask(const std::string &mask) { - char* dest = (char*)mask.c_str(); + const char* dest = mask.c_str(); int exclamation = 0; int atsign = 0; - for (char* i = dest; *i; i++) + for (const char* i = dest; *i; i++) { /* out of range character, bad mask */ if (*i < 32 || *i > 126) @@ -177,51 +105,129 @@ bool InspIRCd::IsValidMask(const std::string &mask) if (exclamation != 1 || atsign != 1) return false; + if (mask.length() > ServerInstance->Config->Limits.GetMaxMask()) + return false; + return true; } -/* true for valid channel name, false else */ -bool IsChannelHandler::Call(const char *chname, size_t max) +void InspIRCd::StripColor(std::string &sentence) { - const char *c = chname + 1; + /* refactor this completely due to SQUIT bug since the old code would strip last char and replace with \0 --peavey */ + int seq = 0; - /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */ - if (!chname || *chname != '#') + for (std::string::iterator i = sentence.begin(); i != sentence.end();) { - return false; + 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; } +} - while (*c) +void InspIRCd::ProcessColors(file_cache& input) +{ + /* + * 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 { - switch (*c) + std::string character; + std::string replace; + special_chars(const std::string& c, const std::string& r) + : character(c) + , replace(r) { - case ' ': - case ',': - case 7: - return false; + } + } 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++) + { + std::string ret = *it; + for(int i = 0; special[i].character.empty() == false; ++i) + { + 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()); + } } - c++; + // 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; } +} - size_t len = c - chname; - /* too long a name - note funky pointer arithmetic here. */ - if (len > max) +/* true for valid channel name, false else */ +bool InspIRCd::DefaultIsChannel(const std::string& chname) +{ + if (chname.empty() || chname.length() > ServerInstance->Config->Limits.ChanMax) + return false; + + if (chname[0] != '#') + return false; + + for (std::string::const_iterator i = chname.begin()+1; i != chname.end(); ++i) { - return false; + switch (*i) + { + case ' ': + case ',': + case 7: + return false; + } } return true; } /* true for valid nickname, false else */ -bool IsNickHandler::Call(const char* n, size_t max) +bool InspIRCd::DefaultIsNick(const std::string& n) { - if (!n || !*n) + if (n.empty() || n.length() > ServerInstance->Config->Limits.NickMax) return false; - - unsigned int p = 0; - for (const char* i = n; *i; i++, p++) + + for (std::string::const_iterator i = n.begin(); i != n.end(); ++i) { if ((*i >= 'A') && (*i <= '}')) { @@ -229,7 +235,7 @@ bool IsNickHandler::Call(const char* n, size_t max) continue; } - if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i > n)) + if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i != n.begin())) { /* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */ continue; @@ -239,17 +245,16 @@ bool IsNickHandler::Call(const char* n, size_t max) return false; } - /* too long? or not -- pointer arithmetic rocks */ - return (p < max); + return true; } /* return true for good ident, false else */ -bool IsIdentHandler::Call(const char* n) +bool InspIRCd::DefaultIsIdent(const std::string& n) { - if (!n || !*n) + if (n.empty()) return false; - for (const char* i = n; *i; i++) + for (std::string::const_iterator i = n.begin(); i != n.end(); ++i) { if ((*i >= 'A') && (*i <= '}')) { @@ -267,218 +272,283 @@ bool IsIdentHandler::Call(const char* n) return true; } -bool IsSIDHandler::Call(const std::string &str) +bool InspIRCd::IsHost(const std::string& host) { - /* 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]))); -} + // Hostnames must be non-empty and shorter than the maximum hostname length. + if (host.empty() || host.length() > ServerInstance->Config->Limits.MaxHost) + return false; -/* open the proper logfile */ -bool InspIRCd::OpenLog(char**, int) -{ - /* This function only happens at startup now */ - if (Config->nofork) + 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) { - this->Logs->SetupNoFork(); - } - Config->MyDir = Config->GetFullProgDir(); + unsigned char chr = static_cast(*iter); - /* Attempt to find home directory, portable to windows */ - const char* home = getenv("HOME"); - if (!home) - { - /* No $HOME, log to %USERPROFILE% */ - home = getenv("USERPROFILE"); - if (!home) + // If the current character is a label separator. + if (chr == '.') { - /* Nothing could be found at all, log to current dir */ - Config->logpath = "./startup.log"; - } - } + numdots++; - if (!Config->writelog) return true; // Skip opening default log if -nolog + // 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; - if (!*this->LogFileName) - { - if (Config->logpath.empty()) - { - std::string path = std::string(home) + "/.inspircd"; - // This tries to create the ~/.inspircd. If it succeeds, then we go ahead and use it. - // If it fails due to an existing target, then we use it anyway. - // Either way, we make sure we can get write access to the log at this point. - if (!mkdir(path.c_str(), 0700) || errno == EEXIST) - { - /* Log to ~/.inspircd/ircd.log */ - Config->logpath = path + "/startup.log"; - FILE* fd = fopen(Config->logpath.c_str(), "a+"); - if (!fd) - { - // Could not get write access... Why? - if (errno == ENOTDIR) - // ~/.inspircd is not actually a directory! - printf("\nWARNING: Unable to create directory: %s (Exists and is not a directory)\n", path.c_str()); - else - // Not writable for some other reason (no +w access, readonly fs, file too big, whatever). - printf("\nWARNING: No write access to %s (%s)\n", Config->logpath.c_str(), strerror(errno)); - Config->logpath = "./startup.log"; - } - else - { - Config->log_file = fd; - } - } - else - { - /* Couldn't make ~/.inspircd directory, log to current dir */ - Config->logpath = "./startup.log"; - printf("\nWARNING: Unable to create directory: %s (%s)\n", path.c_str(), strerror(errno)); - } + seendot = true; + continue; } - if (!Config->log_file) - Config->log_file = fopen(Config->logpath.c_str(),"a+"); - } - else - { - Config->log_file = fopen(this->LogFileName,"a+"); - } - - if (!Config->log_file) - { - return false; - } + // If this point is reached then the character is not a dot. + seendot = false; - FileWriter* fw = new FileWriter(this, Config->log_file); - FileLogStream *f = new FileLogStream(this, (Config->forcedebug ? DEBUG : DEFAULT), fw); + // 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; - this->Logs->AddLogType("*", f, true); + numdashes += 1; + continue; + } - return true; -} + // If this point is reached then the character is not a dash. + numdashes = 0; -void InspIRCd::CheckRoot() -{ - if (geteuid() == 0) - { - printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n"); - this->Logs->Log("STARTUP",DEFAULT,"Cant start as root"); - Exit(EXIT_STATUS_ROOT); - } -} + // Alphanumeric characters are allowed at any position. + if ((chr >= '0' && chr <= '9') || (chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z')) + continue; -void InspIRCd::CheckDie() -{ - if (*Config->DieValue) - { - printf("WARNING: %s\n\n",Config->DieValue); - this->Logs->Log("CONFIG",DEFAULT,"Died because of tag: %s",Config->DieValue); - Exit(EXIT_STATUS_DIETAG); + return false; } -} - -void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const std::string &text) -{ - std::string copy_text = text; - - int MOD_RESULT = 0; - FOREACH_RESULT_I(this, I_OnWhoisLine, OnWhoisLine(user, dest, numeric, copy_text)); - if (!MOD_RESULT) - user->WriteServ("%d %s", numeric, copy_text.c_str()); + // 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; } -void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const char* format, ...) +bool InspIRCd::IsSID(const std::string &str) { - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, format); - vsnprintf(textbuffer, MAXBUF, format, argsPtr); - va_end(argsPtr); - - this->SendWhoisLine(user, dest, numeric, std::string(textbuffer)); + /* 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]))); } -/** Refactored by Brain, Jun 2008. Much faster with some clever O(1) array - * lookups and pointer maths. +/** 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. */ -long InspIRCd::Duration(const std::string &str) +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 char multiplier = 0; - long total = 0; - long times = 1; - long subtotal = 0; + unsigned long total = 0; + unsigned long subtotal = 0; /* Iterate each item in the string, looking for number or multiplier */ - for (std::string::const_reverse_iterator i = str.rbegin(); i != str.rend(); ++i) + 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 + ((*i - '0') * times); - times = times * 10; + subtotal = (subtotal * 10) + (*i - '0'); } else { - /* Found something thats not a number, find out how much + /* 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. */ - if (subtotal) - total += subtotal * duration_multi[multiplier]; + unsigned int multiplier = duration_multi[static_cast(*i)]; + if (multiplier == 0) + return false; + + total += subtotal * multiplier; /* Next subtotal please */ subtotal = 0; - multiplier = *i; - times = 1; } } - if (multiplier) + /* Any trailing values built up are treated as raw seconds */ + duration = total + subtotal; + return true; +} + +unsigned long InspIRCd::Duration(const std::string& str) +{ + unsigned long out = 0; + InspIRCd::Duration(str, out); + return out; +} + +bool InspIRCd::IsValidDuration(const std::string& duration) +{ + for (std::string::const_iterator i = duration.begin(); i != duration.end(); ++i) { - total += subtotal * duration_multi[multiplier]; - subtotal = 0; + unsigned char c = *i; + if (((c >= '0') && (c <= '9'))) + continue; + + if (!duration_multi[c]) + return false; } - /* Any trailing values built up are treated as raw seconds */ - return total + subtotal; + return true; } -bool InspIRCd::ULine(const char* sserver) +std::string InspIRCd::DurationString(time_t duration) { - if (!sserver) - return false; - if (!*sserver) - return true; + 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; + + 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"; + + return ret; +} - return (Config->ulines.find(sserver) != Config->ulines.end()); +std::string InspIRCd::Format(va_list& vaList, const char* formatString) +{ + static std::vector formatBuffer(1024); + + while (true) + { + va_list dst; + va_copy(dst, vaList); + + int vsnret = vsnprintf(&formatBuffer[0], formatBuffer.size(), formatString, dst); + va_end(dst); + + if (vsnret > 0 && static_cast(vsnret) < formatBuffer.size()) + { + break; + } + + formatBuffer.resize(formatBuffer.size() * 2); + } + + return std::string(&formatBuffer[0]); } -bool InspIRCd::SilentULine(const char* sserver) +std::string InspIRCd::Format(const char* formatString, ...) { - std::map::iterator n = Config->ulines.find(sserver); - if (n != Config->ulines.end()) - return n->second; - else return false; + std::string ret; + VAFORMAT(ret, formatString, formatString); + return ret; } -std::string InspIRCd::TimeString(time_t curtime) +std::string InspIRCd::TimeString(time_t curtime, const char* format, bool utc) { - return std::string(ctime(&curtime),24); +#ifdef _WIN32 + if (curtime < 0) + curtime = 0; +#endif + + struct tm* timeinfo = utc ? gmtime(&curtime) : localtime(&curtime); + if (!timeinfo) + { + curtime = 0; + timeinfo = localtime(&curtime); + } + + // 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; + + // This is the default format used by asctime without the terminating new line. + if (!format) + format = "%a %b %d %Y %H:%M:%S"; + + char buffer[512]; + if (!strftime(buffer, sizeof(buffer), format, timeinfo)) + buffer[0] = '\0'; + + return buffer; } -// You should only pass a single character to this. -void InspIRCd::AddExtBanChar(char c) +std::string InspIRCd::GenRandomStr(unsigned int length, bool printable) { - std::string &tok = Config->data005; - std::string::size_type ebpos; - - if ((ebpos = tok.find(" EXTBAN=,")) == std::string::npos) + 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()); +} + +// 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) +{ + unsigned long rv; + GenRandom((char*)&rv, sizeof(rv)); + return rv % max; +} + +// This is overridden by a higher-quality algorithm when TLS (SSL) support is loaded +void InspIRCd::DefaultGenRandom(char* output, size_t max) +{ +#if defined HAS_ARC4RANDOM_BUF + arc4random_buf(output, max); +#else + for (unsigned int i = 0; i < max; ++i) +# ifdef _WIN32 { - tok.append(" EXTBAN=,"); - tok.push_back(c); + unsigned int uTemp; + if(rand_s(&uTemp) != 0) + output[i] = rand(); + else + output[i] = uTemp; } - else - tok.insert(ebpos + 9, 1, c); +# else + output[i] = random(); +# endif +#endif }