static Anope::string Unescape(const Anope::string &string) { Anope::string ret = string; for (int i = 0; special[i].character.empty() == false; ++i) if (!special[i].replace.empty()) ret = ret.replace_all_cs(special[i].replace, special[i].character); for (size_t i, last = 0; (i = string.find("&#", last)) != Anope::string::npos;) { last = i + 1; size_t end = string.find(';', i); if (end == Anope::string::npos) break; Anope::string ch = string.substr(i + 2, end - (i + 2)); if (ch.empty()) continue; long l; if (!ch.empty() && ch[0] == 'x') l = strtol(ch.substr(1).c_str(), NULL, 16); else l = strtol(ch.c_str(), NULL, 10); if (l > 0 && l < 256) ret = ret.replace_all_cs("&#" + ch + ";", Anope::string(l)); } return ret; }
Anope::string RealMask(const Anope::string &mask) { /* If it s an existing user, we ignore the hostmask. */ User *u = User::Find(mask, true); if (u) return "*!*@" + u->host; size_t host = mask.find('@'); /* Determine whether we get a nick or a mask. */ if (host != Anope::string::npos) { size_t user = mask.find('!'); /* Check whether we have a nick too.. */ if (user != Anope::string::npos) { if (user > host) /* this should never happen */ return ""; else return mask; } else /* We have user@host. Add nick wildcard. */ return "*!" + mask; } /* We only got a nick.. */ return mask + "!*@*"; }
bool ChannelModeKey::IsValid(Anope::string &value) const { if (!value.empty() && value.find(':') == Anope::string::npos && value.find(',') == Anope::string::npos) return true; return false; }
MyRedisService(Module *c, const Anope::string &n, const Anope::string &h, int p, unsigned d) : Provider(c, n), host(h), port(p), db(d), sock(NULL), sub(NULL), ti(c), in_transaction(false) { sock = new RedisSocket(this, host.find(':') != Anope::string::npos); sock->Connect(host, port); sub = new RedisSocket(this, host.find(':') != Anope::string::npos); sub->Connect(host, port); }
bool AccessGroup::HasPriv(const Anope::string &name) const { if (this->super_admin) return true; else if (!ci || ci->GetLevel(name) == ACCESS_INVALID) return false; /* Privileges prefixed with auto are understood to be given * automatically. Sometimes founders want to not automatically * obtain privileges, so we will let them */ bool auto_mode = !name.find("AUTO"); /* Only grant founder privilege if this isn't an auto mode or if they don't match any entries in this group */ if ((!auto_mode || this->empty()) && this->founder) return true; EventReturn MOD_RESULT; FOREACH_RESULT(OnGroupCheckPriv, MOD_RESULT, (this, name)); if (MOD_RESULT != EVENT_CONTINUE) return MOD_RESULT == EVENT_ALLOW; for (unsigned i = this->size(); i > 0; --i) { ChanAccess *access = this->at(i - 1); if (::HasPriv(*this, access, name)) return true; } return false; }
cidr::cidr(const Anope::string &ip, unsigned char len) { bool ipv6 = ip.find(':') != Anope::string::npos; this->addr.pton(ipv6 ? AF_INET6 : AF_INET, ip); this->cidr_ip = ip; this->cidr_len = len; }
cidr::cidr(const Anope::string &ip) { bool ipv6 = ip.find(':') != Anope::string::npos; size_t sl = ip.find_last_of('/'); if (sl == Anope::string::npos) { this->cidr_ip = ip; this->cidr_len = ipv6 ? 128 : 32; this->addr.pton(ipv6 ? AF_INET6 : AF_INET, ip); } else { Anope::string real_ip = ip.substr(0, sl); Anope::string cidr_range = ip.substr(sl + 1); this->cidr_ip = real_ip; this->cidr_len = ipv6 ? 128 : 32; try { if (cidr_range.is_pos_number_only()) this->cidr_len = convertTo<unsigned int>(cidr_range); } catch (const ConvertException &) { } this->addr.pton(ipv6 ? AF_INET6 : AF_INET, real_ip); } }
void User::Identify(NickServ::Nick *na) { if (this->nick.equals_ci(na->GetNick())) { na->SetLastUsermask(this->GetIdent() + "@" + this->GetDisplayedHost()); na->SetLastRealhost(this->GetIdent() + "@" + this->host); na->SetLastRealname(this->realname); na->SetLastSeen(Anope::CurTime); } IRCD->SendLogin(this, na); this->Login(na->GetAccount()); EventManager::Get()->Dispatch(&Event::NickIdentify::OnNickIdentify, this); if (this->IsServicesOper()) { Anope::string m = this->nc->o->GetType()->modes; if (!m.empty()) { this->SetModes(NULL, "%s", m.c_str()); this->SendMessage(Me, "Changing your usermodes to \002{0}\002", m.c_str()); UserMode *um = ModeManager::FindUserModeByName("OPER"); if (um && !this->HasMode("OPER") && m.find(um->mchar) != Anope::string::npos) IRCD->SendOper(this); } if (IRCD->CanSetVHost && !this->nc->o->GetVhost().empty()) { this->SendMessage(Me, "Changing your vhost to \002{0}\002", this->nc->o->GetVhost()); this->SetDisplayedHost(this->nc->o->GetVhost()); IRCD->SendVhost(this, "", this->nc->o->GetVhost()); } } }
/* strip dots from username, and remove anything after the first + */ Anope::string CleanMail(const Anope::string &email) { size_t host = email.find('@'); if (host == Anope::string::npos) return email; Anope::string username = email.substr(0, host); username = username.replace_all_cs(".", ""); size_t sz = username.find('+'); if (sz != Anope::string::npos) username = username.substr(0, sz); Anope::string cleaned = username + email.substr(host); logger.Debug("cleaned {0} to {1}", email, cleaned); return cleaned; }
MessageSource::MessageSource(const Anope::string &src) : source(src) { /* no source for incoming message is our uplink */ if (src.empty()) this->s = Servers::GetUplink(); else if (IRCD->RequiresID || src.find('.') != Anope::string::npos) this->s = Server::Find(src); if (this->s == NULL) this->u = User::Find(src); }
void Send(Interface *i, const std::vector<std::pair<const char *, size_t> > &args) { if (!sock) { sock = new RedisSocket(this, host.find(':') != Anope::string::npos); sock->Connect(host, port); } this->Send(sock, i, args); }
/** * Get the token * @param str String to search in * @param dilim Character to search for * @param token_number the token number * @return token */ Anope::string myStrGetToken(const Anope::string &str, char dilim, int token_number) { if (str.empty() || str.find(dilim) == Anope::string::npos) return token_number ? "" : str; Anope::string substring; sepstream sep(str, dilim); for (int i = 0; i < token_number + 1 && !sep.StreamEnd() && sep.GetToken(substring); ++i); return substring; }
void Subscribe(Interface *i, const Anope::string &ch) override { if (sub == NULL) { sub = new RedisSocket(this, host.find(':') != Anope::string::npos); sub->Connect(host, port); } std::vector<Anope::string> args = { "SUBSCRIBE", ch }; this->SendCommand(sub, NULL, args); sub->subinterfaces[ch] = i; }
NumberList::NumberList(const Anope::string &list, bool descending) : is_valid(true), desc(descending) { Anope::string error; commasepstream sep(list); Anope::string token; sep.GetToken(token); if (token.empty()) token = list; do { size_t t = token.find('-'); if (t == Anope::string::npos) { unsigned num = convertTo<unsigned>(token, error, false); if (error.empty()) numbers.insert(num); else { if (!this->InvalidRange(list)) { is_valid = false; return; } } } else { Anope::string error2; unsigned num1 = convertTo<unsigned>(token.substr(0, t), error, false); unsigned num2 = convertTo<unsigned>(token.substr(t + 1), error2, false); if (error.empty() && error2.empty()) { for (unsigned i = num1; i <= num2; ++i) numbers.insert(i); } else { if (!this->InvalidRange(list)) { is_valid = false; return; } } } } while (sep.GetToken(token)); }
/** * Checks whether we have a valid, common e-mail address. * This is NOT entirely RFC compliant, and won't be so, because I said * *common* cases. ;) It is very unlikely that e-mail addresses that * are really being used will fail the check. * * @param email Email to Validate * @return bool */ bool MailValidate(const Anope::string &email) { bool has_period = false; static char specials[] = {'(', ')', '<', '>', '@', ',', ';', ':', '\\', '\"', '[', ']', ' '}; if (email.empty()) return false; Anope::string copy = email; size_t at = copy.find('@'); if (at == Anope::string::npos) return false; Anope::string domain = copy.substr(at + 1); copy = copy.substr(0, at); /* Don't accept empty copy or domain. */ if (copy.empty() || domain.empty()) return false; /* Check for forbidden characters in the name */ for (unsigned i = 0, end = copy.length(); i < end; ++i) { if (copy[i] <= 31 || copy[i] >= 127) return false; for (unsigned int j = 0; j < 13; ++j) if (copy[i] == specials[j]) return false; } /* Check for forbidden characters in the domain */ for (unsigned i = 0, end = domain.length(); i < end; ++i) { if (domain[i] <= 31 || domain[i] >= 127) return false; for (unsigned int j = 0; j < 13; ++j) if (domain[i] == specials[j]) return false; if (domain[i] == '.') { if (!i || i == end - 1) return false; has_period = true; } } return has_period; }
/** * Is the given nick a network service * @param nick to check * @param int Check if botserv bots * @return int */ bool nickIsServices(const Anope::string &tempnick, bool bot) { if (tempnick.empty()) return false; Anope::string nick = tempnick; size_t at = nick.find('@'); if (at != Anope::string::npos) { Anope::string servername = nick.substr(at + 1); if (!servername.equals_ci(Config->ServerName)) return false; nick = nick.substr(0, at); } BotInfo *bi = findbot(nick); if (bi) return bot ? true : bi->HasFlag(BI_CORE); return false; }
/** Called on startup to organize our starting arguments in a better way * and check for errors * @param ac number of args * @param av args */ static void ParseCommandLineArguments(int ac, char **av) { for (int i = 1; i < ac; ++i) { Anope::string option = av[i]; Anope::string param; while (!option.empty() && option[0] == '-') option.erase(option.begin()); size_t t = option.find('='); if (t != Anope::string::npos) { param = option.substr(t + 1); option.erase(t); } if (option.empty()) continue; CommandLineArguments.push_back(std::make_pair(option, param)); } }
bool IsIdentValid(const Anope::string &ident) override { if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen")) return false; Anope::string chars = "~}|{ `_^]\\[ .-$"; for (unsigned i = 0; i < ident.length(); ++i) { const char &c = ident[i]; if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) continue; if (chars.find(c) != Anope::string::npos) continue; return false; } return true; }
void User::SetModeInternal(const MessageSource &source, UserMode *um, const Anope::string ¶m) { if (!um) return; this->modes[um->name] = param; if (um->name == "OPER") { ++OperCount; if (this->IsServicesOper()) { Anope::string m = this->nc->o->GetType()->modes; if (!m.empty()) { this->SetModes(NULL, "%s", m.c_str()); this->SendMessage(Me, "Changing your usermodes to \002{0}\002", m); UserMode *oper = ModeManager::FindUserModeByName("OPER"); if (oper && !this->HasMode("OPER") && m.find(oper->mchar) != Anope::string::npos) IRCD->SendOper(this); } if (IRCD->CanSetVHost && !this->nc->o->GetVhost().empty()) { this->SendMessage(Me, "Changing your vhost to \002{0}\002", this->nc->o->GetVhost()); this->SetDisplayedHost(this->nc->o->GetVhost()); IRCD->SendVhost(this, "", this->nc->o->GetVhost()); } } } if (um->name == "CLOAK" || um->name == "VHOST") this->UpdateHost(); EventManager::Get()->Dispatch(&Event::UserModeSet::OnUserModeSet, source, this, um->name); }
bool IRCDProto::IsNickValid(const Anope::string &nick) { /** * RFC: defination of a valid nick * nickname = ( letter / special ) ( letter / digit / special / "-" ) * letter = A-Z / a-z * digit = 0-9 * special = [, ], \, `, _, ^, {, |, } **/ if (nick.empty()) return false; Anope::string special = "[]\\`_^{|}"; for (unsigned int i = 0; i < nick.length(); ++i) if (!(nick[i] >= 'A' && nick[i] <= 'Z') && !(nick[i] >= 'a' && nick[i] <= 'z') && special.find(nick[i]) == Anope::string::npos && (Config && Config->NickChars.find(nick[i]) == Anope::string::npos) && (!i || (!(nick[i] >= '0' && nick[i] <= '9') && nick[i] != '-'))) return false; return true; }
void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) override { if (Anope::ReadOnly) { source.Reply(_("Services are in read-only mode.")); return; } User *u = source.GetUser(); NickServ::Nick *na = NickServ::FindNick(source.GetNick()); if (!na || na->GetAccount() != source.GetAccount()) { source.Reply(_("Access denied.")); //XXX with nonickownership this should be allowed. return; } if (source.GetAccount()->HasFieldS("UNCONFIRMED")) { source.Reply(_("You must confirm your account before you may request a vhost.")); return; } Anope::string rawhostmask = params[0]; Anope::string user, host; size_t a = rawhostmask.find('@'); if (a == Anope::string::npos) host = rawhostmask; else { user = rawhostmask.substr(0, a); host = rawhostmask.substr(a + 1); } if (host.empty()) { this->OnSyntaxError(source, ""); return; } if (!user.empty()) { if (user.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen")) { source.Reply(_("The username \002{0}\002 is too long, please use a username shorter than %d characters."), Config->GetBlock("networkinfo")->Get<unsigned>("userlen")); return; } if (!IRCD->CanSetVIdent) { source.Reply(_("Vhosts may not contain a username.")); return; } if (!IRCD->IsIdentValid(user)) { source.Reply(_("The requested username is not valid.")); return; } } if (host.length() > Config->GetBlock("networkinfo")->Get<unsigned>("hostlen")) { source.Reply(_("The requested vhost is too long, please use a hostname no longer than {0} characters."), Config->GetBlock("networkinfo")->Get<unsigned>("hostlen")); return; } if (!IRCD->IsHostValid(host)) { source.Reply(_("The requested hostname is not valid.")); return; } time_t send_delay = Config->GetModule("memoserv")->Get<time_t>("senddelay"); if (Config->GetModule(this->GetOwner())->Get<bool>("memooper") && send_delay > 0 && u && u->lastmemosend + send_delay > Anope::CurTime) { source.Reply(_("Please wait %d seconds before requesting a new vHost."), send_delay); u->lastmemosend = Anope::CurTime; return; } HostRequest *req = Serialize::New<HostRequest *>(); req->SetNick(na); req->SetIdent(user); req->SetHost(host); req->SetTime(Anope::CurTime); source.Reply(_("Your vhost has been requested.")); this->SendMemos(source, user, host); Log(LOG_COMMAND, source, this) << "to request new vhost " << (!user.empty() ? user + "@" : "") << host; }
bool IRCdMessage::OnPrivmsg(const Anope::string &source, const std::vector<Anope::string> ¶ms) { const Anope::string &receiver = params.size() > 0 ? params[0] : ""; Anope::string message = params.size() > 1 ? params[1] : ""; /* Messages from servers can happen on some IRCds, check for . */ if (source.empty() || receiver.empty() || message.empty() || source.find('.') != Anope::string::npos) return true; User *u = finduser(source); if (!u) { Log() << message << ": user record for " << source << " not found"; BotInfo *bi = findbot(receiver); if (bi) ircdproto->SendMessage(bi, source, "%s", "Internal error - unable to process request."); return true; } if (receiver[0] == '#') { Channel *c = findchan(receiver); if (c) { FOREACH_MOD(I_OnPrivmsg, OnPrivmsg(u, c, message)); } } else { /* If a server is specified (nick@server format), make sure it matches * us, and strip it off. */ Anope::string botname = receiver; size_t s = receiver.find('@'); if (s != Anope::string::npos) { Anope::string servername(receiver.begin() + s + 1, receiver.end()); botname = botname.substr(0, s); if (!servername.equals_ci(Config->ServerName)) return true; } else if (Config->UseStrictPrivMsg) { BotInfo *bi = findbot(receiver); if (!bi) return true; Log(LOG_DEBUG) << "Ignored PRIVMSG without @ from " << source; u->SendMessage(bi, _("\"/msg %s\" is no longer supported. Use \"/msg %s@%s\" or \"/%s\" instead."), receiver.c_str(), receiver.c_str(), Config->ServerName.c_str(), receiver.c_str()); return true; } BotInfo *bi = findbot(botname); if (bi) { EventReturn MOD_RESULT; FOREACH_RESULT(I_OnBotPrivmsg, OnBotPrivmsg(u, bi, message)); if (MOD_RESULT == EVENT_STOP) return true; if (message[0] == '\1' && message[message.length() - 1] == '\1') { if (message.substr(0, 6).equals_ci("\1PING ")) { Anope::string buf = message; buf.erase(buf.begin()); buf.erase(buf.end() - 1); ircdproto->SendCTCP(bi, u->nick, "%s", buf.c_str()); } else if (message.substr(0, 9).equals_ci("\1VERSION\1")) { Module *enc = ModuleManager::FindFirstOf(ENCRYPTION); ircdproto->SendCTCP(bi, u->nick, "VERSION Anope-%s %s :%s - (%s) -- %s", Anope::Version().c_str(), Config->ServerName.c_str(), ircd->name, enc ? enc->name.c_str() : "unknown", Anope::VersionBuildString().c_str()); } return true; } bi->OnMessage(u, message); } } return true; }
EventReturn OnLoadDatabase() override { const Anope::string &db_name = Anope::DataDir + "/" + Config->GetModule(this)->Get<Anope::string>("database", "anope.db"); std::fstream fd(db_name.c_str(), std::ios_base::in | std::ios_base::binary); if (!fd.is_open()) { Log(this) << "Unable to open " << db_name << " for reading!"; return EVENT_STOP; } Serialize::TypeBase *type = nullptr; Serialize::Object *obj = nullptr; for (Anope::string buf; std::getline(fd, buf.str());) { if (buf.find("OBJECT ") == 0) { Anope::string t = buf.substr(7); if (obj) Log(LOG_DEBUG) << "obj != null but got OBJECT"; if (type) Log(LOG_DEBUG) << "type != null but got OBJECT"; type = Serialize::TypeBase::Find(t); obj = nullptr; } else if (buf.find("ID ") == 0) { if (!type || obj) continue; try { Serialize::ID id = convertTo<Serialize::ID>(buf.substr(3)); obj = type->Require(id); } catch (const ConvertException &) { Log(LOG_DEBUG) << "Unable to parse object id " << buf.substr(3); } } else if (buf.find("DATA ") == 0) { if (!type) continue; if (!obj) obj = type->Create(); size_t sp = buf.find(' ', 5); // Skip DATA if (sp == Anope::string::npos) continue; Anope::string key = buf.substr(5, sp - 5), value = buf.substr(sp + 1); Serialize::FieldBase *field = type->GetField(key); if (field) field->UnserializeFromString(obj, value); } else if (buf.find("END") == 0) { type = nullptr; obj = nullptr; } } fd.close(); loaded = true; return EVENT_STOP; }
Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh), cidr_len(0) { Anope::string n, u, h; size_t at = fh.find('@'); if (at != Anope::string::npos) { this->host = fh.substr(at + 1); const Anope::string &nu = fh.substr(0, at); size_t ex = nu.find('!'); if (ex != Anope::string::npos) { this->user = nu.substr(ex + 1); this->nick = nu.substr(0, ex); } else this->user = nu; } else { if (fh.find('.') != Anope::string::npos || fh.find(':') != Anope::string::npos) this->host = fh; else this->nick = fh; } at = this->host.find('#'); if (at != Anope::string::npos) { this->real = this->host.substr(at + 1); this->host = this->host.substr(0, at); } /* If the mask is all *'s it will match anything, so just clear it */ if (this->nick.find_first_not_of("*") == Anope::string::npos) this->nick.clear(); if (this->user.find_first_not_of("*") == Anope::string::npos) this->user.clear(); if (this->host.find_first_not_of("*") == Anope::string::npos) this->host.clear(); else { /* Host might be a CIDR range */ size_t sl = this->host.find_last_of('/'); if (sl != Anope::string::npos) { const Anope::string &cidr_ip = this->host.substr(0, sl), &cidr_range = this->host.substr(sl + 1); sockaddrs addr(cidr_ip); try { if (addr.valid() && cidr_range.is_pos_number_only()) { this->cidr_len = convertTo<unsigned short>(cidr_range); /* If we got here, cidr_len is a valid number. * If cidr_len is >32 (or 128) it is handled later in * cidr::match */ this->host = cidr_ip; Log(LOG_DEBUG) << "Ban " << m << " has cidr " << this->cidr_len; } } catch (const ConvertException &) { } } } if (this->real.find_first_not_of("*") == Anope::string::npos) this->real.clear(); }
sockaddrs::sockaddrs(const Anope::string &address) { this->clear(); if (!address.empty() && address.find_first_not_of_ci("0123456789abcdef.:") == Anope::string::npos) this->pton(address.find(':') != Anope::string::npos ? AF_INET6 : AF_INET, address); }