X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fhelperfuncs.cpp;h=795f858fa35018171d424ebb70a9051866936355;hb=b4a174ee9c32d62ea6bf010e837e8c5b1c3d36a3;hp=de62a2c7b48215b4f114ae6824e766e5aeaf1078;hpb=04eb0e182dec8518d1dfd15a09b8054d1501a4ef;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/helperfuncs.cpp b/src/helperfuncs.cpp index de62a2c7b..795f858fa 100644 --- a/src/helperfuncs.cpp +++ b/src/helperfuncs.cpp @@ -1,12 +1,18 @@ /* * InspIRCd -- Internet Relay Chat Daemon * + * 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) 2006-2008 Robin Burchell - * Copyright (C) 2005-2008 Craig Edwards - * Copyright (C) 2008 Thomas Stagner - * Copyright (C) 2006-2007 Oliver Lupton * Copyright (C) 2007 Dennis Friis + * Copyright (C) 2006-2008 Robin Burchell + * Copyright (C) 2005, 2007, 2010 Craig Edwards * * 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 @@ -29,22 +35,13 @@ #include "inspircd.h" #include "xline.h" -#include "exitcodes.h" -#include /* 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; + return FindNickOnly(nick); } User* InspIRCd::FindNickOnly(const std::string &nick) @@ -79,25 +76,6 @@ Channel* InspIRCd::FindChan(const std::string &chan) return iter->second; } -/* Send an error notice to all users, registered or not */ -void InspIRCd::SendError(const std::string &s) -{ - const UserManager::LocalList& list = Users.GetLocalUsers(); - for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) - { - User* u = *i; - if (u->registered == REG_ALL) - { - u->WriteNotice(s); - } - else - { - /* Unregistered connections receive ERROR, not a NOTICE */ - u->Write("ERROR :" + s); - } - } -} - bool InspIRCd::IsValidMask(const std::string &mask) { const char* dest = mask.c_str(); @@ -127,7 +105,7 @@ bool InspIRCd::IsValidMask(const std::string &mask) if (exclamation != 1 || atsign != 1) return false; - if (mask.length() > 250) + if (mask.length() > ServerInstance->Config->Limits.GetMaxMask()) return false; return true; @@ -153,7 +131,8 @@ void InspIRCd::StripColor(std::string &sentence) else seq = 0; - if (seq || ((*i == 2) || (*i == 15) || (*i == 22) || (*i == 21) || (*i == 31))) + // Strip all control codes too except \001 for CTCP + if (seq || ((*i >= 0) && (*i < 32) && (*i != 1))) i = sentence.erase(i); else ++i; @@ -171,18 +150,20 @@ void InspIRCd::ProcessColors(file_cache& input) { std::string character; std::string replace; - special_chars(const std::string &c, const std::string &r) : character(c), replace(r) { } - } - - special[] = { - special_chars("\\002", "\002"), // Bold - special_chars("\\037", "\037"), // underline - special_chars("\\003", "\003"), // Color - special_chars("\\017", "\017"), // Stop colors - special_chars("\\u", "\037"), // Alias for underline - special_chars("\\b", "\002"), // Alias for Bold - special_chars("\\x", "\017"), // Alias for stop - special_chars("\\c", "\003"), // Alias for color + 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("", "") }; @@ -218,7 +199,7 @@ void InspIRCd::ProcessColors(file_cache& input) } /* true for valid channel name, false else */ -bool IsChannelHandler::Call(const std::string& chname) +bool InspIRCd::DefaultIsChannel(const std::string& chname) { if (chname.empty() || chname.length() > ServerInstance->Config->Limits.ChanMax) return false; @@ -241,7 +222,7 @@ bool IsChannelHandler::Call(const std::string& chname) } /* true for valid nickname, false else */ -bool IsNickHandler::Call(const std::string& n) +bool InspIRCd::DefaultIsNick(const std::string& n) { if (n.empty() || n.length() > ServerInstance->Config->Limits.NickMax) return false; @@ -268,7 +249,7 @@ bool IsNickHandler::Call(const std::string& n) } /* return true for good ident, false else */ -bool IsIdentHandler::Call(const std::string& n) +bool InspIRCd::DefaultIsIdent(const std::string& n) { if (n.empty()) return false; @@ -291,92 +272,186 @@ bool IsIdentHandler::Call(const std::string& n) return true; } -bool InspIRCd::IsSID(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; -void InspIRCd::CheckRoot() -{ -#ifndef _WIN32 - if (geteuid() == 0) + 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) { - std::cout << "ERROR: You are running an irc server as root! DO NOT DO THIS!" << std::endl << std::endl; - this->Logs->Log("STARTUP", LOG_DEFAULT, "Can't start as root"); - Exit(EXIT_STATUS_ROOT); - } -#endif -} + unsigned char chr = static_cast(*iter); -void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const std::string &text) -{ - std::string copy_text = dest->nick; - copy_text.push_back(' '); - copy_text.append(text); + // If the current character is a label separator. + if (chr == '.') + { + numdots++; + + // 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; + + seendot = true; + continue; + } + + // If this point is reached then the character is not a dot. + seendot = false; + + // 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; - ModResult MOD_RESULT; - FIRST_MOD_RESULT(OnWhoisLine, MOD_RESULT, (user, dest, numeric, copy_text)); + numdashes += 1; + continue; + } + + // If this point is reached then the character is not a dash. + numdashes = 0; + + // Alphanumeric characters are allowed at any position. + if ((chr >= '0' && chr <= '9') || (chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z')) + continue; + + return false; + } - if (MOD_RESULT != MOD_RES_DENY) - user->WriteNumeric(numeric, copy_text); + // 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) { - std::string textbuffer; - VAFORMAT(textbuffer, format, format) - this->SendWhoisLine(user, dest, numeric, 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 2009. 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. */ -unsigned 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; } -const char* InspIRCd::Format(va_list &vaList, const char* formatString) +std::string InspIRCd::DurationString(time_t duration) +{ + 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; +} + +std::string InspIRCd::Format(va_list& vaList, const char* formatString) { static std::vector formatBuffer(1024); @@ -396,12 +471,12 @@ const char* InspIRCd::Format(va_list &vaList, const char* formatString) formatBuffer.resize(formatBuffer.size() * 2); } - return &formatBuffer[0]; + return std::string(&formatBuffer[0]); } -const char* InspIRCd::Format(const char* formatString, ...) +std::string InspIRCd::Format(const char* formatString, ...) { - const char* ret; + std::string ret; VAFORMAT(ret, formatString, formatString); return ret; } @@ -429,7 +504,7 @@ std::string InspIRCd::TimeString(time_t curtime, const char* format, bool utc) // This is the default format used by asctime without the terminating new line. if (!format) - format = "%a %b %d %H:%M:%S %Y"; + format = "%a %b %d %Y %H:%M:%S"; char buffer[512]; if (!strftime(buffer, sizeof(buffer), format, timeinfo)) @@ -438,16 +513,14 @@ std::string InspIRCd::TimeString(time_t curtime, const char* format, bool utc) return buffer; } -std::string InspIRCd::GenRandomStr(int length, bool printable) +std::string InspIRCd::GenRandomStr(unsigned int length, bool printable) { - char* buf = new char[length]; - GenRandom(buf, length); - std::string rv; - rv.resize(length); - for(int i=0; i < length; i++) - rv[i] = printable ? 0x3F + (buf[i] & 0x3F) : buf[i]; - delete[] buf; - return rv; + 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. @@ -459,11 +532,14 @@ unsigned long InspIRCd::GenRandomInt(unsigned long max) return rv % max; } -// This is overridden by a higher-quality algorithm when SSL support is loaded -void GenRandomHandler::Call(char *output, size_t max) +// This is overridden by a higher-quality algorithm when TLS (SSL) support is loaded +void InspIRCd::DefaultGenRandom(char* output, size_t max) { - for(unsigned int i=0; i < max; i++) -#ifdef _WIN32 +#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) @@ -471,32 +547,8 @@ void GenRandomHandler::Call(char *output, size_t max) else output[i] = uTemp; } -#else +# else output[i] = random(); +# endif #endif } - -ModResult OnCheckExemptionHandler::Call(User* user, Channel* chan, const std::string& restriction) -{ - unsigned int mypfx = chan->GetPrefixValue(user); - char minmode = 0; - std::string current; - - irc::spacesepstream defaultstream(ServerInstance->Config->ConfValue("options")->getString("exemptchanops")); - - while (defaultstream.GetToken(current)) - { - std::string::size_type pos = current.find(':'); - if (pos == std::string::npos) - continue; - if (!current.compare(0, pos, restriction)) - minmode = current[pos+1]; - } - - PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(minmode); - if (mh && mypfx >= mh->GetPrefixRank()) - return MOD_RES_ALLOW; - if (mh || minmode == '*') - return MOD_RES_DENY; - return MOD_RES_PASSTHRU; -}