void ContactsRpcOperation::runGetContacts() { TLContactsContacts result; result.tlType = TLValue::ContactsContacts; LocalUser *self = layer()->getUser(); const QVector<UserContact> importedContacts = self->importedContacts(); result.contacts.reserve(importedContacts.size()); result.users.reserve(importedContacts.size()); TLUser userInfo; TLContact outputContact; for (const UserContact &contact : importedContacts) { if (contact.id) { const AbstractUser *contactUser = api()->getAbstractUser(contact.id); Utils::setupTLUser(&userInfo, contactUser, self); result.users.append(userInfo); outputContact.userId = contact.id; outputContact.mutual = userInfo.flags & TLUser::MutualContact; result.contacts.append(outputContact); } else { ++result.savedCount; } } sendRpcReply(result); }
void ContactsRpcOperation::runImportContacts() { qDebug() << Q_FUNC_INFO; TLContactsImportedContacts result; LocalUser *self = layer()->getUser(); for (const TLInputContact &c : m_importContacts.contacts) { UserContact contact; contact.phone = api()->normalizeIdentifier(c.phone); contact.firstName = c.firstName; contact.lastName = c.lastName; AbstractUser *registeredUser = api()->getAbstractUser(contact.phone); if (registeredUser) { contact.id = registeredUser->id(); } else { result.retryContacts.append(c.clientId); } self->importContact(contact); if (registeredUser) { result.users.append(TLUser()); Utils::setupTLUser(&result.users.last(), registeredUser, self); TLImportedContact imported; imported.clientId = c.clientId; imported.userId = contact.id; result.imported.append(imported); } } sendRpcReply(result); }
CmdResult Handle (const std::vector<std::string> ¶meters, User *src) { std::map<std::string,int> closed; for (LocalUserList::const_iterator u = ServerInstance->Users->local_users.begin(); u != ServerInstance->Users->local_users.end(); ++u) { LocalUser* user = *u; if (user->registered != REG_ALL) { ServerInstance->Users->QuitUser(user, "Closing all unknown connections per request"); std::string key = ConvToStr(user->GetIPString())+"."+ConvToStr(user->GetServerPort()); closed[key]++; } } int total = 0; for (std::map<std::string,int>::iterator ci = closed.begin(); ci != closed.end(); ci++) { src->WriteNotice("*** Closed " + ConvToStr(ci->second) + " unknown " + (ci->second == 1 ? "connection" : "connections") + " from [" + ci->first + "]"); total += ci->second; } if (total) src->WriteNotice("*** " + ConvToStr(total) + " unknown " + (total == 1 ? "connection" : "connections") + " closed"); else src->WriteNotice("*** No unknown connections found"); return CMD_SUCCESS; }
void SendAlert(unsigned int numeric, const std::string& nick) { const IRCv3::Monitor::WatcherList* list = manager.GetWatcherList(nick); if (!list) return; for (IRCv3::Monitor::WatcherList::const_iterator i = list->begin(); i != list->end(); ++i) { LocalUser* curr = *i; curr->WriteNumeric(numeric, nick); } }
CmdResult Handle (const std::vector<std::string> ¶meters, User *user) { User* u = ServerInstance->FindNick(parameters[0]); Channel* c = ServerInstance->FindChan(parameters[1]); if ((!c) || (!u) || (u->registered != REG_ALL)) { if (!c) { user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[1].c_str()); } else { user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); } return CMD_FAILURE; } if (IS_LOCAL(user)) { if (c->GetPrefixValue(user) < HALFOP_VALUE) { user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must be a channel %soperator", user->nick.c_str(), c->name.c_str(), c->GetPrefixValue(u) == HALFOP_VALUE ? "" : "half-"); return CMD_FAILURE; } } /* Servers remember invites only for their local users, so act * only if the target is local. Otherwise the command will be * passed to the target users server. */ LocalUser* lu = IS_LOCAL(u); if (lu) { irc::string xname(c->name.c_str()); if (!lu->IsInvited(xname)) { user->SendText(":%s 505 %s %s %s :Is not invited to channel %s", user->server.c_str(), user->nick.c_str(), u->nick.c_str(), c->name.c_str(), c->name.c_str()); return CMD_FAILURE; } user->SendText(":%s 494 %s %s %s :Uninvited", user->server.c_str(), user->nick.c_str(), c->name.c_str(), u->nick.c_str()); lu->RemoveInvite(xname); lu->WriteNumeric(493, "%s :You were uninvited from %s by %s", u->nick.c_str(), c->name.c_str(), user->nick.c_str()); std::string msg = "*** " + user->nick + " uninvited " + u->nick + "."; c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE " + c->name + " :" + msg); ServerInstance->PI->SendChannelNotice(c, 0, msg); } return CMD_SUCCESS; }
void SendAlert(User* user, const std::string& nick, unsigned int numeric, const char* numerictext, time_t shownts) { const IRCv3::Monitor::WatcherList* list = manager.GetWatcherList(nick); if (!list) return; Numeric::Numeric num(numeric); num.push(nick).push(user->ident).push(user->GetDisplayedHost()).push(ConvToStr(shownts)).push(numerictext); for (IRCv3::Monitor::WatcherList::const_iterator i = list->begin(); i != list->end(); ++i) { LocalUser* curr = *i; curr->WriteNumeric(num); } }
void User::WriteCommonQuit(const std::string &normal_text, const std::string &oper_text) { char tb1[MAXBUF]; char tb2[MAXBUF]; if (this->registered != REG_ALL) return; already_sent_t uniq_id = ++LocalUser::already_sent_id; snprintf(tb1,MAXBUF,":%s QUIT :%s",this->GetFullHost().c_str(),normal_text.c_str()); snprintf(tb2,MAXBUF,":%s QUIT :%s",this->GetFullHost().c_str(),oper_text.c_str()); std::string out1 = tb1; std::string out2 = tb2; UserChanList include_c(chans); std::map<User*,bool> exceptions; FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions)); for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i) { LocalUser* u = IS_LOCAL(i->first); if (u && !u->quitting) { u->already_sent = uniq_id; if (i->second) u->Write(IS_OPER(u) ? out2 : out1); } } for (UCListIter v = include_c.begin(); v != include_c.end(); ++v) { const UserMembList* ulist = (*v)->GetUsers(); for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++) { LocalUser* u = IS_LOCAL(i->first); if (u && !u->quitting && (u->already_sent != uniq_id)) { u->already_sent = uniq_id; u->Write(IS_OPER(u) ? out2 : out1); } } } }
CmdResult HandleServerTarget(User* source, const Params& parameters) { // If the source isn't allowed to mass message users then reject // the attempt to mass-message users. if (!source->HasPrivPermission("users/mass-message")) return CMD_FAILURE; // Extract the server glob match from the target parameter. std::string servername(parameters[0], 1); // Fire the pre-message events. MessageTarget msgtarget(&servername); CTCTags::TagMessageDetails msgdetails(parameters.GetTags()); if (!FirePreEvents(source, msgtarget, msgdetails)) return CMD_FAILURE; // If the current server name matches the server name glob then send // the message out to the local users. if (InspIRCd::Match(ServerInstance->Config->ServerName, servername)) { CTCTags::TagMessage message(source, "$*", parameters.GetTags()); const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator iter = list.begin(); iter != list.end(); ++iter) { LocalUser* luser = IS_LOCAL(*iter); // Don't send to unregistered users or the user who is the source. if (luser->registered != REG_ALL || luser == source) continue; // Don't send to exempt users. if (msgdetails.exemptions.count(luser)) continue; // Send to users if they have the capability. if (cap.get(luser)) luser->Send(msgevprov, message); } } // Fire the post-message event. return FirePostEvent(source, msgtarget, msgdetails); }
static void GenerateStatsLl(User* user, string_list& results, char c) { results.push_back(InspIRCd::Format("211 %s nick[ident@%s] sendq cmds_out bytes_out cmds_in bytes_in time_open", user->nick.c_str(), (c == 'l' ? "host" : "ip"))); const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) { LocalUser* u = *i; results.push_back("211 "+user->nick+" "+u->nick+"["+u->ident+"@"+(c == 'l' ? u->dhost : u->GetIPString())+"] "+ConvToStr(u->eh.getSendQSize())+" "+ConvToStr(u->cmds_out)+" "+ConvToStr(u->bytes_out)+" "+ConvToStr(u->cmds_in)+" "+ConvToStr(u->bytes_in)+" "+ConvToStr(ServerInstance->Time() - u->age)); } }
void User::Oper(OperInfo* info) { ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER); if (this->IsModeSet(opermh)) this->UnOper(); this->SetMode(opermh, true); this->oper = info; this->WriteCommand("MODE", "+o"); FOREACH_MOD(OnOper, (this, info->name)); std::string opername; if (info->oper_block) opername = info->oper_block->getString("name"); if (IS_LOCAL(this)) { LocalUser* l = IS_LOCAL(this); std::string vhost = oper->getConfig("vhost"); if (!vhost.empty()) l->ChangeDisplayedHost(vhost.c_str()); std::string opClass = oper->getConfig("class"); if (!opClass.empty()) l->SetClass(opClass); } ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s (using oper '%s')", nick.c_str(), ident.c_str(), host.c_str(), oper->name.c_str(), opername.c_str()); this->WriteNumeric(RPL_YOUAREOPER, ":You are now %s %s", strchr("aeiouAEIOU", oper->name[0]) ? "an" : "a", oper->name.c_str()); ServerInstance->Logs->Log("OPER", LOG_DEFAULT, "%s opered as type: %s", GetFullRealHost().c_str(), oper->name.c_str()); ServerInstance->Users->all_opers.push_back(this); // Expand permissions from config for faster lookup if (IS_LOCAL(this)) oper->init(); FOREACH_MOD(OnPostOper, (this, oper->name, opername)); }
void User::WriteCommonRaw(const std::string &line, bool include_self) { if (this->registered != REG_ALL || quitting) return; LocalUser::already_sent_id++; IncludeChanList include_c(chans.begin(), chans.end()); std::map<User*,bool> exceptions; exceptions[this] = include_self; FOREACH_MOD(OnBuildNeighborList, (this, include_c, exceptions)); for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i) { LocalUser* u = IS_LOCAL(i->first); if (u && !u->quitting) { u->already_sent = LocalUser::already_sent_id; if (i->second) u->Write(line); } } for (IncludeChanList::const_iterator v = include_c.begin(); v != include_c.end(); ++v) { Channel* c = (*v)->chan; const UserMembList* ulist = c->GetUsers(); for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++) { LocalUser* u = IS_LOCAL(i->first); if (u && u->already_sent != LocalUser::already_sent_id) { u->already_sent = LocalUser::already_sent_id; u->Write(line); } } } }
void User::Oper(OperInfo* info) { if (this->IsModeSet('o')) this->UnOper(); this->modes[UM_OPERATOR] = 1; this->oper = info; this->WriteServ("MODE %s :+o", this->nick.c_str()); FOREACH_MOD(I_OnOper, OnOper(this, info->name)); std::string opername; if (info->oper_block) opername = info->oper_block->getString("name"); if (IS_LOCAL(this)) { LocalUser* l = IS_LOCAL(this); std::string vhost = oper->getConfig("vhost"); if (!vhost.empty()) l->ChangeDisplayedHost(vhost.c_str()); std::string opClass = oper->getConfig("class"); if (!opClass.empty()) l->SetClass(opClass); } ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s (using oper '%s')", nick.c_str(), ident.c_str(), host.c_str(), oper->NameStr(), opername.c_str()); this->WriteNumeric(381, "%s :You are now %s %s", nick.c_str(), strchr("aeiouAEIOU", oper->name[0]) ? "an" : "a", oper->NameStr()); ServerInstance->Logs->Log("OPER", DEFAULT, "%s opered as type: %s", GetFullRealHost().c_str(), oper->NameStr()); ServerInstance->Users->all_opers.push_back(this); // Expand permissions from config for faster lookup if (IS_LOCAL(this)) oper->init(); FOREACH_MOD(I_OnPostOper,OnPostOper(this, oper->name, opername)); }
void User::WriteCommonQuit(const std::string &normal_text, const std::string &oper_text) { if (this->registered != REG_ALL) return; already_sent_t uniq_id = ++LocalUser::already_sent_id; const std::string normalMessage = ":" + this->GetFullHost() + " QUIT :" + normal_text; const std::string operMessage = ":" + this->GetFullHost() + " QUIT :" + oper_text; IncludeChanList include_c(chans.begin(), chans.end()); std::map<User*,bool> exceptions; FOREACH_MOD(OnBuildNeighborList, (this, include_c, exceptions)); for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i) { LocalUser* u = IS_LOCAL(i->first); if (u && !u->quitting) { u->already_sent = uniq_id; if (i->second) u->Write(u->IsOper() ? operMessage : normalMessage); } } for (IncludeChanList::const_iterator v = include_c.begin(); v != include_c.end(); ++v) { const UserMembList* ulist = (*v)->chan->GetUsers(); for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++) { LocalUser* u = IS_LOCAL(i->first); if (u && (u->already_sent != uniq_id)) { u->already_sent = uniq_id; u->Write(u->IsOper() ? operMessage : normalMessage); } } } }
ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { LocalUser* user = IS_LOCAL(dest); /* For remote clients, we don't take any action, we just allow it. * The local server where they are will set their cloak instead. * This is fine, as we will receive it later. */ if (!user) { dest->SetMode(this, adding); return MODEACTION_ALLOW; } if (user->uuid == debounce_uid && debounce_ts == ServerInstance->Time()) { // prevent spamming using /mode user +x-x+x-x+x-x if (++debounce_count > 2) return MODEACTION_DENY; } else { debounce_uid = user->uuid; debounce_count = 1; debounce_ts = ServerInstance->Time(); } if (adding == user->IsModeSet(this)) return MODEACTION_DENY; /* don't allow this user to spam modechanges */ if (source == dest) user->CommandFloodPenalty += 5000; if (adding) { std::string* cloak = ext.get(user); if (!cloak) { /* Force creation of missing cloak */ creator->OnUserConnect(user); cloak = ext.get(user); } if (cloak) { user->ChangeDisplayedHost(*cloak); user->SetMode(this, true); return MODEACTION_ALLOW; } else return MODEACTION_DENY; } else { /* User is removing the mode, so restore their real host * and make it match the displayed one. */ user->SetMode(this, false); user->ChangeDisplayedHost(user->host.c_str()); return MODEACTION_ALLOW; } }
/* add a client connection to the sockets list */ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) { /* NOTE: Calling this one parameter constructor for User automatically * allocates a new UUID and places it in the hash_map. */ LocalUser* New = NULL; try { New = new LocalUser(socket, client, server); } catch (...) { ServerInstance->Logs->Log("USERS", DEFAULT,"*** WTF *** Duplicated UUID! -- Crack smoking monkeys have been unleashed."); ServerInstance->SNO->WriteToSnoMask('a', "WARNING *** Duplicate UUID allocated!"); return; } UserIOHandler* eh = &New->eh; /* Give each of the modules an attempt to hook the user for I/O */ FOREACH_MOD(I_OnHookIO, OnHookIO(eh, via)); if (eh->GetIOHook()) { try { eh->GetIOHook()->OnStreamSocketAccept(eh, client, server); } catch (CoreException& modexcept) { ServerInstance->Logs->Log("SOCKET", DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); } } ServerInstance->Logs->Log("USERS", DEBUG,"New user fd: %d", socket); this->unregistered_count++; /* The users default nick is their UUID */ New->nick.assign(New->uuid, 0, ServerInstance->Config->Limits.NickMax); (*(this->clientlist))[New->nick] = New; New->registered = REG_NONE; New->signon = ServerInstance->Time() + ServerInstance->Config->dns_timeout; New->lastping = 1; ServerInstance->Users->AddLocalClone(New); ServerInstance->Users->AddGlobalClone(New); New->localuseriter = this->local_users.insert(local_users.end(), New); if ((this->local_users.size() > ServerInstance->Config->SoftLimit) || (this->local_users.size() >= (unsigned int)ServerInstance->SE->GetMaxFds())) { ServerInstance->SNO->WriteToSnoMask('a', "Warning: softlimit value has been reached: %d clients", ServerInstance->Config->SoftLimit); this->QuitUser(New,"No more connections allowed"); return; } /* * First class check. We do this again in FullConnect after DNS is done, and NICK/USER is recieved. * See my note down there for why this is required. DO NOT REMOVE. :) -- w00t */ New->SetClass(); /* * Check connect class settings and initialise settings into User. * This will be done again after DNS resolution. -- w00t */ New->CheckClass(); if (New->quitting) return; /* * even with bancache, we still have to keep User::exempt current. * besides that, if we get a positive bancache hit, we still won't f**k * them over if they are exempt. -- w00t */ New->exempt = (ServerInstance->XLines->MatchesLine("E",New) != NULL); if (BanCacheHit *b = ServerInstance->BanCache->GetHit(New->GetIPString())) { if (!b->Type.empty() && !New->exempt) { /* user banned */ ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCache: Positive hit for " + New->GetIPString()); if (!ServerInstance->Config->MoronBanner.empty()) New->WriteServ("NOTICE %s :*** %s", New->nick.c_str(), ServerInstance->Config->MoronBanner.c_str()); this->QuitUser(New, b->Reason); return; } else { ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCache: Negative hit for " + New->GetIPString()); } } else { if (!New->exempt) { XLine* r = ServerInstance->XLines->MatchesLine("Z",New); if (r) { r->Apply(New); return; } } } if (!ServerInstance->SE->AddFd(eh, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE)) { ServerInstance->Logs->Log("USERS", DEBUG,"Internal error on new connection"); this->QuitUser(New, "Internal error handling connection"); } /* NOTE: even if dns lookups are *off*, we still need to display this. * BOPM and other stuff requires it. */ New->WriteServ("NOTICE Auth :*** Looking up your hostname..."); if (ServerInstance->Config->RawLog) New->WriteServ("NOTICE Auth :*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded."); FOREACH_MOD(I_OnSetUserIP,OnSetUserIP(New)); if (New->quitting) return; FOREACH_MOD(I_OnUserInit,OnUserInit(New)); if (ServerInstance->Config->NoUserDns) { New->WriteServ("NOTICE %s :*** Skipping host resolution (disabled by server administrator)", New->nick.c_str()); New->dns_done = true; } else { New->StartDNSLookup(); } }
CmdResult HandleChannelTarget(User* source, const Params& parameters, const char* target, PrefixMode* pm) { Channel* chan = ServerInstance->FindChan(target); if (!chan) { // The target channel does not exist. source->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } if (IS_LOCAL(source)) { if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(source)) { // The noextmsg mode is set and the source is not in the channel. source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (no external messages)"); return CMD_FAILURE; } bool no_chan_priv = chan->GetPrefixValue(source) < VOICE_VALUE; if (no_chan_priv && chan->IsModeSet(moderatedmode)) { // The moderated mode is set and the source has no status rank. source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (+m)"); return CMD_FAILURE; } if (no_chan_priv && ServerInstance->Config->RestrictBannedUsers != ServerConfig::BUT_NORMAL && chan->IsBanned(source)) { // The source is banned in the channel and restrictbannedusers is enabled. if (ServerInstance->Config->RestrictBannedUsers == ServerConfig::BUT_RESTRICT_NOTIFY) source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (you're banned)"); return CMD_FAILURE; } } // Fire the pre-message events. MessageTarget msgtarget(chan, pm ? pm->GetPrefix() : 0); CTCTags::TagMessageDetails msgdetails(parameters.GetTags()); if (!FirePreEvents(source, msgtarget, msgdetails)) return CMD_FAILURE; unsigned int minrank = pm ? pm->GetPrefixRank() : 0; CTCTags::TagMessage message(source, chan, parameters.GetTags()); const Channel::MemberMap& userlist = chan->GetUsers(); for (Channel::MemberMap::const_iterator iter = userlist.begin(); iter != userlist.end(); ++iter) { LocalUser* luser = IS_LOCAL(iter->first); // Don't send to remote users or the user who is the source. if (!luser || luser == source) continue; // Don't send to unprivileged or exempt users. if (iter->second->getRank() < minrank || msgdetails.exemptions.count(luser)) continue; // Send to users if they have the capability. if (cap.get(luser)) luser->Send(msgevprov, message); } return FirePostEvent(source, msgtarget, msgdetails); }
void User::DoHostCycle(const std::string &quitline) { char buffer[MAXBUF]; if (!ServerInstance->Config->CycleHosts) return; already_sent_t silent_id = ++LocalUser::already_sent_id; already_sent_t seen_id = ++LocalUser::already_sent_id; UserChanList include_c(chans); std::map<User*,bool> exceptions; FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions)); for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i) { LocalUser* u = IS_LOCAL(i->first); if (u && !u->quitting) { if (i->second) { u->already_sent = seen_id; u->Write(quitline); } else { u->already_sent = silent_id; } } } for (UCListIter v = include_c.begin(); v != include_c.end(); ++v) { Channel* c = *v; snprintf(buffer, MAXBUF, ":%s JOIN %s", GetFullHost().c_str(), c->name.c_str()); std::string joinline(buffer); Membership* memb = c->GetUser(this); std::string modeline = memb->modes; if (modeline.length() > 0) { for(unsigned int i=0; i < memb->modes.length(); i++) modeline.append(" ").append(nick); snprintf(buffer, MAXBUF, ":%s MODE %s +%s", ServerInstance->Config->CycleHostsFromUser ? GetFullHost().c_str() : ServerInstance->Config->ServerName.c_str(), c->name.c_str(), modeline.c_str()); modeline = buffer; } const UserMembList *ulist = c->GetUsers(); for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++) { LocalUser* u = IS_LOCAL(i->first); if (u == NULL || u == this) continue; if (u->already_sent == silent_id) continue; if (u->already_sent != seen_id) { u->Write(quitline); u->already_sent = seen_id; } u->Write(joinline); if (modeline.length() > 0) u->Write(modeline); } } }
CmdResult Handle (const std::vector<std::string> ¶meters, User *user) { int n_done = 0; reason = (parameters.size() < 4) ? "Please use this server/port instead" : parameters[3]; bool redirect_all_immediately = false; redirect_new_users = true; bool direction = true; std::string n_done_s; /* No parameters: jumpserver disabled */ if (!parameters.size()) { if (port) user->WriteNotice("*** Disabled jumpserver (previously set to '" + redirect_to + ":" + ConvToStr(port) + "')"); else user->WriteNotice("*** Jumpserver was not enabled."); port = 0; sslport = 0; redirect_to.clear(); return CMD_SUCCESS; } port = 0; redirect_to.clear(); if (parameters.size() >= 3) { for (std::string::const_iterator n = parameters[2].begin(); n != parameters[2].end(); ++n) { switch (*n) { case '+': direction = true; break; case '-': direction = false; break; case 'a': redirect_all_immediately = direction; break; case 'n': redirect_new_users = direction; break; default: user->WriteNotice("*** Invalid JUMPSERVER flag: " + ConvToStr(*n)); return CMD_FAILURE; break; } } size_t delimpos = parameters[1].find(':'); port = ConvToInt(parameters[1].substr(0, delimpos ? delimpos : std::string::npos)); sslport = (delimpos == std::string::npos ? 0 : ConvToInt(parameters[1].substr(delimpos + 1))); if (parameters[1].find_first_not_of("0123456789:") != std::string::npos || parameters[1].rfind(':') != delimpos || port > 65535 || sslport > 65535) { user->WriteNotice("*** Invalid port number"); return CMD_FAILURE; } if (redirect_all_immediately) { /* Redirect everyone but the oper sending the command */ for (LocalUserList::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); ++i) { LocalUser* t = *i; if (!t->IsOper()) { t->WriteNumeric(10, "%s %s %d :Please use this Server/Port instead", t->nick.c_str(), parameters[0].c_str(), GetPort(t)); ServerInstance->Users->QuitUser(t, reason); n_done++; } } if (n_done) { n_done_s = ConvToStr(n_done); } } if (redirect_new_users) redirect_to = parameters[0]; user->WriteNotice("*** Set jumpserver to server '" + parameters[0] + "' port '" + (port ? ConvToStr(port) : "Auto") + ", SSL " + (sslport ? ConvToStr(sslport) : "Auto") + "', flags '+" + (redirect_all_immediately ? "a" : "") + (redirect_new_users ? "n'" : "'") + (n_done ? " (" + n_done_s + "user(s) redirected): " : ": ") + reason); } return CMD_SUCCESS; }
/** * This function is called once a second from the mainloop. * It is intended to do background checking on all the user structs, e.g. * stuff like ping checks, registration timeouts, etc. */ void UserManager::DoBackgroundUserStuff() { /* * loop over all local users.. */ for (LocalUserList::iterator i = local_users.begin(); i != local_users.end(); ++i) { LocalUser* curr = *i; if (curr->quitting) continue; if (curr->CommandFloodPenalty || curr->eh.getSendQSize()) { unsigned int rate = curr->MyClass->GetCommandRate(); if (curr->CommandFloodPenalty > rate) curr->CommandFloodPenalty -= rate; else curr->CommandFloodPenalty = 0; curr->eh.OnDataReady(); } switch (curr->registered) { case REG_ALL: if (ServerInstance->Time() > curr->nping) { // This user didn't answer the last ping, remove them if (!curr->lastping) { time_t time = ServerInstance->Time() - (curr->nping - curr->MyClass->GetPingTime()); const std::string message = "Ping timeout: " + ConvToStr(time) + (time == 1 ? " seconds" : " second"); this->QuitUser(curr, message); continue; } curr->Write("PING :" + ServerInstance->Config->ServerName); curr->lastping = 0; curr->nping = ServerInstance->Time() + curr->MyClass->GetPingTime(); } break; case REG_NICKUSER: if (AllModulesReportReady(curr)) { /* User has sent NICK/USER, modules are okay, DNS finished. */ curr->FullConnect(); continue; } break; } if (curr->registered != REG_ALL && (ServerInstance->Time() > (curr->age + curr->MyClass->GetRegTimeout()))) { /* * registration timeout -- didnt send USER/NICK/HOST * in the time specified in their connection class. */ this->QuitUser(curr, "Registration timeout"); continue; } } }
/** * This function is called once a second from the mainloop. * It is intended to do background checking on all the user structs, e.g. * stuff like ping checks, registration timeouts, etc. */ void InspIRCd::DoBackgroundUserStuff() { /* * loop over all local users.. */ LocalUserList::reverse_iterator count2 = this->Users->local_users.rbegin(); while (count2 != this->Users->local_users.rend()) { LocalUser *curr = *count2; count2++; if (curr->quitting) continue; if (curr->CommandFloodPenalty || curr->eh.getSendQSize()) { unsigned int rate = curr->MyClass->GetCommandRate(); if (curr->CommandFloodPenalty > rate) curr->CommandFloodPenalty -= rate; else curr->CommandFloodPenalty = 0; curr->eh.OnDataReady(); } switch (curr->registered) { case REG_ALL: if (Time() > curr->nping) { // This user didn't answer the last ping, remove them if (!curr->lastping) { time_t time = this->Time() - (curr->nping - curr->MyClass->GetPingTime()); char message[MAXBUF]; snprintf(message, MAXBUF, "Ping timeout: %ld second%s", (long)time, time > 1 ? "s" : ""); curr->lastping = 1; curr->nping = Time() + curr->MyClass->GetPingTime(); this->Users->QuitUser(curr, message); continue; } curr->Write("PING :%s",this->Config->ServerName.c_str()); curr->lastping = 0; curr->nping = Time() +curr->MyClass->GetPingTime(); } break; case REG_NICKUSER: if (AllModulesReportReady(curr)) { /* User has sent NICK/USER, modules are okay, DNS finished. */ curr->FullConnect(); continue; } break; } if (curr->registered != REG_ALL && (Time() > (curr->age + curr->MyClass->GetRegTimeout()))) { /* * registration timeout -- didnt send USER/NICK/HOST * in the time specified in their connection class. */ this->Users->QuitUser(curr, "Registration timeout"); continue; } } }
CmdResult Handle (const std::vector<std::string> ¶meters, User *user) { if (parameters.size() > 1 && parameters[1] != ServerInstance->Config->ServerName.c_str()) return CMD_SUCCESS; User *targuser; Channel *targchan; std::string checkstr; std::string chliststr; checkstr = ":" + ServerInstance->Config->ServerName + " 304 " + user->nick + " :CHECK"; targuser = ServerInstance->FindNick(parameters[0]); targchan = ServerInstance->FindChan(parameters[0]); /* * Syntax of a /check reply: * :server.name 304 target :CHECK START <target> * :server.name 304 target :CHECK <field> <value> * :server.name 304 target :CHECK END */ user->SendText(checkstr + " START " + parameters[0]); if (targuser) { LocalUser* loctarg = IS_LOCAL(targuser); /* /check on a user */ user->SendText(checkstr + " nuh " + targuser->GetFullHost()); user->SendText(checkstr + " realnuh " + targuser->GetFullRealHost()); user->SendText(checkstr + " realname " + targuser->fullname); user->SendText(checkstr + " modes +" + targuser->FormatModes()); user->SendText(checkstr + " snomasks " + GetSnomasks(targuser)); user->SendText(checkstr + " server " + targuser->server->GetName()); user->SendText(checkstr + " uid " + targuser->uuid); user->SendText(checkstr + " signon " + timestring(targuser->signon)); user->SendText(checkstr + " nickts " + timestring(targuser->age)); if (loctarg) user->SendText(checkstr + " lastmsg " + timestring(loctarg->idle_lastmsg)); if (targuser->IsAway()) { /* user is away */ user->SendText(checkstr + " awaytime " + timestring(targuser->awaytime)); user->SendText(checkstr + " awaymsg " + targuser->awaymsg); } if (targuser->IsOper()) { OperInfo* oper = targuser->oper; /* user is an oper of type ____ */ user->SendText(checkstr + " opertype " + oper->name); if (loctarg) { std::string umodes; std::string cmodes; for(char c='A'; c < 'z'; c++) { ModeHandler* mh = ServerInstance->Modes->FindMode(c, MODETYPE_USER); if (mh && mh->NeedsOper() && loctarg->HasModePermission(c, MODETYPE_USER)) umodes.push_back(c); mh = ServerInstance->Modes->FindMode(c, MODETYPE_CHANNEL); if (mh && mh->NeedsOper() && loctarg->HasModePermission(c, MODETYPE_CHANNEL)) cmodes.push_back(c); } user->SendText(checkstr + " modeperms user="******" channel=" + cmodes); std::string opcmds; for(std::set<std::string>::iterator i = oper->AllowedOperCommands.begin(); i != oper->AllowedOperCommands.end(); i++) { opcmds.push_back(' '); opcmds.append(*i); } std::stringstream opcmddump(opcmds); user->SendText(checkstr + " commandperms", opcmddump); std::string privs; for(std::set<std::string>::iterator i = oper->AllowedPrivs.begin(); i != oper->AllowedPrivs.end(); i++) { privs.push_back(' '); privs.append(*i); } std::stringstream privdump(privs); user->SendText(checkstr + " permissions", privdump); } } if (loctarg) { user->SendText(checkstr + " clientaddr " + loctarg->client_sa.str()); user->SendText(checkstr + " serveraddr " + loctarg->server_sa.str()); std::string classname = loctarg->GetClass()->name; if (!classname.empty()) user->SendText(checkstr + " connectclass " + classname); } else user->SendText(checkstr + " onip " + targuser->GetIPString()); for (UCListIter i = targuser->chans.begin(); i != targuser->chans.end(); i++) { Channel* c = (*i)->chan; chliststr.append(c->GetPrefixChar(targuser)).append(c->name).append(" "); } std::stringstream dump(chliststr); user->SendText(checkstr + " onchans", dump); dumpExt(user, checkstr, targuser); } else if (targchan) { /* /check on a channel */ user->SendText(checkstr + " timestamp " + timestring(targchan->age)); if (targchan->topic[0] != 0) { /* there is a topic, assume topic related information exists */ user->SendText(checkstr + " topic " + targchan->topic); user->SendText(checkstr + " topic_setby " + targchan->setby); user->SendText(checkstr + " topic_setat " + timestring(targchan->topicset)); } user->SendText(checkstr + " modes " + targchan->ChanModes(true)); user->SendText(checkstr + " membercount " + ConvToStr(targchan->GetUserCounter())); /* now the ugly bit, spool current members of a channel. :| */ const UserMembList *ulist= targchan->GetUsers(); /* note that unlike /names, we do NOT check +i vs in the channel */ for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++) { /* * Unlike Asuka, I define a clone as coming from the same host. --w00t */ user->SendText("%s member %-3lu %s%s (%s@%s) %s ", checkstr.c_str(), ServerInstance->Users->GlobalCloneCount(i->first), targchan->GetAllPrefixChars(i->first), i->first->nick.c_str(), i->first->ident.c_str(), i->first->dhost.c_str(), i->first->fullname.c_str()); } const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes(); for (ModeParser::ListModeList::const_iterator i = listmodes.begin(); i != listmodes.end(); ++i) dumpListMode(user, checkstr, (*i)->GetList(targchan)); dumpExt(user, checkstr, targchan); } else { /* /check on an IP address, or something that doesn't exist */ long x = 0; /* hostname or other */ for (user_hash::const_iterator a = ServerInstance->Users->clientlist->begin(); a != ServerInstance->Users->clientlist->end(); a++) { if (InspIRCd::Match(a->second->host, parameters[0], ascii_case_insensitive_map) || InspIRCd::Match(a->second->dhost, parameters[0], ascii_case_insensitive_map)) { /* host or vhost matches mask */ user->SendText(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost() + " " + a->second->GetIPString() + " " + a->second->fullname); } /* IP address */ else if (InspIRCd::MatchCIDR(a->second->GetIPString(), parameters[0])) { /* same IP. */ user->SendText(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost() + " " + a->second->GetIPString() + " " + a->second->fullname); } } user->SendText(checkstr + " matches " + ConvToStr(x)); } user->SendText(checkstr + " END " + parameters[0]); return CMD_SUCCESS; }
/* add a client connection to the sockets list */ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) { /* NOTE: Calling this one parameter constructor for User automatically * allocates a new UUID and places it in the hash_map. */ LocalUser* New = NULL; try { New = new LocalUser(socket, client, server); } catch (...) { ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "*** WTF *** Duplicated UUID! -- Crack smoking monkeys have been unleashed."); ServerInstance->SNO->WriteToSnoMask('a', "WARNING *** Duplicate UUID allocated!"); return; } UserIOHandler* eh = &New->eh; // If this listener has an IO hook provider set then tell it about the connection if (via->iohookprov) via->iohookprov->OnAccept(eh, client, server); ServerInstance->Logs->Log("USERS", LOG_DEBUG, "New user fd: %d", socket); this->unregistered_count++; /* The users default nick is their UUID */ New->nick = New->uuid; this->clientlist[New->nick] = New; New->registered = REG_NONE; New->signon = ServerInstance->Time(); New->lastping = 1; this->AddClone(New); this->local_users.push_front(New); if (this->local_users.size() > ServerInstance->Config->SoftLimit) { ServerInstance->SNO->WriteToSnoMask('a', "Warning: softlimit value has been reached: %d clients", ServerInstance->Config->SoftLimit); this->QuitUser(New,"No more connections allowed"); return; } /* * First class check. We do this again in FullConnect after DNS is done, and NICK/USER is recieved. * See my note down there for why this is required. DO NOT REMOVE. :) -- w00t */ New->SetClass(); /* * Check connect class settings and initialise settings into User. * This will be done again after DNS resolution. -- w00t */ New->CheckClass(ServerInstance->Config->CCOnConnect); if (New->quitting) return; /* * even with bancache, we still have to keep User::exempt current. * besides that, if we get a positive bancache hit, we still won't f**k * them over if they are exempt. -- w00t */ New->exempt = (ServerInstance->XLines->MatchesLine("E",New) != NULL); BanCacheHit* const b = ServerInstance->BanCache.GetHit(New->GetIPString()); if (b) { if (!b->Type.empty() && !New->exempt) { /* user banned */ ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Positive hit for " + New->GetIPString()); if (!ServerInstance->Config->XLineMessage.empty()) New->WriteNumeric(ERR_YOUREBANNEDCREEP, ":" + ServerInstance->Config->XLineMessage); this->QuitUser(New, b->Reason); return; } else { ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Negative hit for " + New->GetIPString()); } } else { if (!New->exempt) { XLine* r = ServerInstance->XLines->MatchesLine("Z",New); if (r) { r->Apply(New); return; } } } if (!SocketEngine::AddFd(eh, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE)) { ServerInstance->Logs->Log("USERS", LOG_DEBUG, "Internal error on new connection"); this->QuitUser(New, "Internal error handling connection"); } if (ServerInstance->Config->RawLog) New->WriteNotice("*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded."); FOREACH_MOD(OnSetUserIP, (New)); if (New->quitting) return; FOREACH_MOD(OnUserInit, (New)); }