CmdResult Handle (const std::vector<std::string> ¶meters, User *user) { std::string retbuf = "340 " + user->nick + " :"; int nicks = 0; for (int i = 0; i < (int)parameters.size(); i++) { User *u = ServerInstance->FindNick(parameters[i]); if ((u) && (u->registered == REG_ALL)) { retbuf = retbuf + u->nick + (u->IsOper() ? "*" : "") + "="; if (u->IsAway()) retbuf += "-"; else retbuf += "+"; retbuf += u->ident + "@" + u->GetIPString() + " "; nicks++; } } if (nicks != 0) user->WriteServ(retbuf); /* Dont send to the network */ return CMD_SUCCESS; }
CmdResult Handle (const std::vector<std::string> ¶meters, User *user) { std::string retbuf = "340 " + user->nick + " :"; int nicks = 0; bool checked_privs = false; bool has_privs = false; for (int i = 0; i < (int)parameters.size(); i++) { User *u = ServerInstance->FindNick(parameters[i]); if ((u) && (u->registered == REG_ALL)) { // Anyone may query their own IP if (u != user) { if (!checked_privs) { // Do not trigger the insufficient priviliges message more than once checked_privs = true; has_privs = user->HasPrivPermission("users/auspex"); if (!has_privs) user->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - You do not have the required operator privileges"); } if (!has_privs) continue; } retbuf = retbuf + u->nick + (u->IsOper() ? "*" : "") + "="; if (u->IsAway()) retbuf += "-"; else retbuf += "+"; retbuf += u->ident + "@" + u->GetIPString() + " "; nicks++; } } if (nicks != 0) user->WriteServ(retbuf); return CMD_SUCCESS; }
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; }
/** Handle /GLINE */ CmdResult CommandGline::Handle (const std::vector<std::string>& parameters, User *user) { std::string target = parameters[0]; if (parameters.size() >= 3) { IdentHostPair ih; User* find = ServerInstance->FindNick(target); if ((find) && (find->registered == REG_ALL)) { ih.first = "*"; ih.second = find->GetIPString(); target = std::string("*@") + find->GetIPString(); } else ih = ServerInstance->XLines->IdentSplit(target); if (ih.first.empty()) { user->WriteNotice("*** Target not found"); return CMD_FAILURE; } if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user)) return CMD_FAILURE; else if (target.find('!') != std::string::npos) { user->WriteNotice("*** G-Line cannot operate on nick!user@host masks"); return CMD_FAILURE; } unsigned long duration = InspIRCd::Duration(parameters[1]); GLine* gl = new GLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str()); if (ServerInstance->XLines->AddLine(gl, user)) { if (!duration) { ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent G-line for %s: %s",user->nick.c_str(),target.c_str(), parameters[2].c_str()); } else { time_t c_requires_crap = duration + ServerInstance->Time(); std::string timestr = ServerInstance->TimeString(c_requires_crap); ServerInstance->SNO->WriteToSnoMask('x',"%s added timed G-line for %s, expires on %s: %s",user->nick.c_str(),target.c_str(), timestr.c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); } else { delete gl; user->WriteNotice("** G-Line for " + target + " already exists"); } } else { if (ServerInstance->XLines->DelLine(target.c_str(),"G",user)) { ServerInstance->SNO->WriteToSnoMask('x',"%s removed G-line on %s",user->nick.c_str(),target.c_str()); } else { user->WriteNotice("*** G-Line " + target + " not found in list, try /stats g."); } } return CMD_SUCCESS; }
CmdResult Handle(const std::vector<std::string>& parameters, User *user) { /* syntax: SHUN nick!user@host time :reason goes here */ /* 'time' is a human-readable timestring, like 2d3h2s. */ std::string target = parameters[0]; User *find = ServerInstance->FindNick(target); if ((find) && (find->registered == REG_ALL)) target = std::string("*!*@") + find->GetIPString(); if (parameters.size() == 1) { if (ServerInstance->XLines->DelLine(target.c_str(), "SHUN", user)) { ServerInstance->SNO->WriteToSnoMask('x',"%s removed SHUN on %s",user->nick.c_str(),target.c_str()); } else { user->WriteNotice("*** Shun " + target + " not found in list, try /stats H."); return CMD_FAILURE; } } else { // Adding - XXX todo make this respect <insane> tag perhaps.. unsigned long duration; std::string expr; if (parameters.size() > 2) { duration = InspIRCd::Duration(parameters[1]); expr = parameters[2]; } else { duration = 0; expr = parameters[1]; } Shun* r = new Shun(ServerInstance->Time(), duration, user->nick.c_str(), expr.c_str(), target.c_str()); if (ServerInstance->XLines->AddLine(r, user)) { if (!duration) { ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent SHUN for %s: %s", user->nick.c_str(), target.c_str(), expr.c_str()); } else { time_t c_requires_crap = duration + ServerInstance->Time(); std::string timestr = ServerInstance->TimeString(c_requires_crap); ServerInstance->SNO->WriteToSnoMask('x', "%s added timed SHUN for %s to expire on %s: %s", user->nick.c_str(), target.c_str(), timestr.c_str(), expr.c_str()); } } else { delete r; user->WriteNotice("*** Shun for " + target + " already exists"); return CMD_FAILURE; } } return CMD_SUCCESS; }
CmdResult Handle(const std::vector<std::string>& parameters, User *user) { std::string target = parameters[0]; if (parameters.size() >= 3) { IdentHostPair ih; User* find = ServerInstance->FindNick(target); if ((find) && (find->registered == REG_ALL)) { ih.first = "*"; ih.second = find->GetIPString(); target = std::string("*@") + find->GetIPString(); } else ih = ServerInstance->XLines->IdentSplit(target); if (ih.first.empty()) { user->WriteServ("NOTICE %s :*** Target not found", user->nick.c_str()); return CMD_FAILURE; } if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user)) return CMD_FAILURE; else if (target.find('!') != std::string::npos) { std::string message = "NOTICE %s :*** "+linename+"-Line cannot operate on nick!user@host masks"; user->WriteServ(message); return CMD_FAILURE; } XLineFactory* xlf = ServerInstance->XLines->GetFactory(linename); if (!xlf) return CMD_FAILURE; long duration = ServerInstance->Duration(parameters[1]); XLine* al = xlf->Generate(ServerInstance->Time(), duration, user->nick, parameters[2], target); if (ServerInstance->XLines->AddLine(al, user)) { if (!duration) { ServerInstance->SNO->WriteToSnoMask('x', "%s added permanent %s-line for %s: %s",user->nick.c_str(), linename.c_str(), target.c_str(), parameters[2].c_str()); } else { time_t c_requires_crap = duration + ServerInstance->Time(); std::string timestr = ServerInstance->TimeString(c_requires_crap); ServerInstance->SNO->WriteToSnoMask('x',"%s added timed %s-line for %s, expires on %s: %s",user->nick.c_str(),linename.c_str(),target.c_str(),timestr.c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); } else { delete al; user->WriteServ("NOTICE %s :*** %s-Line for %s already exists",user->nick.c_str(),linename.c_str(),target.c_str()); } } else { if (ServerInstance->XLines->DelLine(target.c_str(),linename,user)) { ServerInstance->SNO->WriteToSnoMask('x',"%s removed %s-line on %s",user->nick.c_str(),linename.c_str(),target.c_str()); } else { user->WriteServ("NOTICE %s :*** %s-Line %s not found in list, try /stats %c.",user->nick.c_str(),linename.c_str(),target.c_str(), statschar); } } return CMD_SUCCESS; }
/** Handle /KLINE */ CmdResult CommandKline::Handle (const std::vector<std::string>& parameters, User *user) { std::string target = parameters[0]; if (parameters.size() >= 3) { IdentHostPair ih; User* find = ServerInstance->FindNick(target.c_str()); if (find) { ih.first = "*"; ih.second = find->GetIPString(); target = std::string("*@") + find->GetIPString(); } else ih = ServerInstance->XLines->IdentSplit(target.c_str()); if (ih.first.empty()) { user->WriteServ("NOTICE %s :*** Target not found", user->nick.c_str()); return CMD_FAILURE; } if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user)) return CMD_FAILURE; if (target.find('!') != std::string::npos) { user->WriteServ("NOTICE %s :*** K-Line cannot operate on nick!user@host masks",user->nick.c_str()); return CMD_FAILURE; } long duration = ServerInstance->Duration(parameters[1].c_str()); KLine* kl = new KLine(ServerInstance, ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str()); if (ServerInstance->XLines->AddLine(kl,user)) { if (!duration) { ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent K-line for %s: %s",user->nick.c_str(),target.c_str(), parameters[2].c_str()); } else { time_t c_requires_crap = duration + ServerInstance->Time(); ServerInstance->SNO->WriteToSnoMask('x',"%s added timed K-line for %s, expires on %s: %s",user->nick.c_str(),target.c_str(), ServerInstance->TimeString(c_requires_crap).c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); } else { delete kl; user->WriteServ("NOTICE %s :*** K-Line for %s already exists",user->nick.c_str(),target.c_str()); } } else { if (ServerInstance->XLines->DelLine(target.c_str(),"K",user)) { ServerInstance->SNO->WriteToSnoMask('x',"%s Removed K-line on %s.",user->nick.c_str(),target.c_str()); } else { user->WriteServ("NOTICE %s :*** K-Line %s not found in list, try /stats k.",user->nick.c_str(),target.c_str()); } } return CMD_SUCCESS; }
/* SQL Request */ virtual const char* OnRequest(Request* request) { if(strcmp(SQLRESID, request->GetId()) == 0) { SQLresult* res = static_cast<SQLresult*>(request); User* user = GetAssocUser(this, SQLutils, res->id).S().user; UnAssociate(this, SQLutils, res->id).S(); if(user) { if(res->error.Id() == SQL_NO_ERROR) { std::string* wnick; bool result; if(res->Rows()) { int rowcount=res->Rows(),i; /* Clean Custom User Metadata */ user->Shrink("sqlAllowedIdent"); user->Shrink("sqlAllowedHost"); user->Shrink("sqlvHost"); user->Shrink("sqlTitle"); user->Shrink("sqlumodes"); std::string sqlvHost; std::string sqlTitle; std::string sqlumodes; std::string sqlAllowedIdent; std::string sqlAllowedHost; /* Get Data from SQL (using freeform query. "query" in modules.conf) */ for (i=0; i<rowcount; ++i) { SQLfieldList& currow = res->GetRow(); sqlAllowedIdent = currow[1].d.c_str(); sqlAllowedHost = currow[2].d.c_str(); sqlvHost = currow[3].d.c_str(); sqlTitle = currow[4].d.c_str(); sqlumodes = currow[5].d.c_str(); } std::string* pAllowedIdent = new std::string(sqlAllowedIdent); std::string* pAllowedHost = new std::string(sqlAllowedHost); std::string* pvHost = new std::string(sqlvHost); std::string* pTitle = new std::string(sqlTitle); std::string* pumodes = new std::string(sqlumodes); user->Extend("sqlAllowedIdent",pAllowedIdent); user->Extend("sqlAllowedHost",pAllowedHost); user->Extend("sqlvHost",pvHost); user->Extend("sqlTitle",pTitle); user->Extend("sqlumodes",pumodes); /* Check Allowed Ident@Hostname from SQL */ if (sqlAllowedIdent != "" && sqlAllowedHost != "") { char TheHost[MAXBUF]; char TheIP[MAXBUF]; char TheAllowedUHost[MAXBUF]; snprintf(TheHost,MAXBUF,"%s@%s",user->ident.c_str(), user->host.c_str()); snprintf(TheIP, MAXBUF,"%s@%s",user->ident.c_str(), user->GetIPString()); snprintf(TheAllowedUHost, MAXBUF, "%s@%s", sqlAllowedIdent.c_str(), sqlAllowedHost.c_str()); if (!OneOfMatches(TheHost,TheIP,TheAllowedUHost)) { if (killreasonUHost == "") { killreasonUHost = "Your ident or hostmask did not match the one registered to this nickname. Allowed: $allowedident@$allowedhost"; } std::string tmpKillReason = killreasonUHost; SearchAndReplace(tmpKillReason, "$allowedident", sqlAllowedIdent.c_str()); SearchAndReplace(tmpKillReason, "$allowedhost", sqlAllowedHost.c_str()); /* Run Failure SQL Insert Query (For Logging) */ std::string repfquery = failurequery; if (repfquery != "") { if (user->GetExt("wantsnick", wnick)) { SearchAndReplace(repfquery, "$nick", *wnick); } else { SearchAndReplace(repfquery, "$nick", user->nick); } SearchAndReplace(repfquery, "$host", user->host); SearchAndReplace(repfquery, "$ip", user->GetIPString()); SearchAndReplace(repfquery, "$reason", tmpKillReason.c_str()); SQLrequest req = SQLrequest(this, SQLprovider, databaseid, SQLquery(repfquery)); result = req.Send(); } ServerInstance->Users->QuitUser(user, tmpKillReason); user->Extend("sqlauth_failed"); return NULL; } } /* We got a result, auth user */ user->Extend("sqlauthed"); /* possible ghosting? */ if (user->GetExt("wantsnick", wnick)) { /* no need to check ghosting, this is done in OnPreCommand * and if ghosting is off, user wont have the Extend */ User* InUse = ServerInstance->FindNickOnly(wnick->c_str()); if (InUse) { /* change his nick to UUID so we can take it */ //InUse->ForceNickChange(InUse->uuid.c_str()); /* put user on cull list */ ServerInstance->Users->QuitUser(InUse, "Ghosted by connecting user with same nick."); } /* steal the nick ;) */ user->ForceNickChange(wnick->c_str()); user->Shrink("wantsnick"); } /* Set Account Name (for m_services_account +R/+M channels) */ if (setaccount) { std::string* pAccount = new std::string(user->nick.c_str()); user->Extend("accountname",pAccount); } /* Run Success SQL Update Query */ std::string repsquery = successquery; if (successquery != "") { SearchAndReplace(repsquery, "$nick", user->nick); SearchAndReplace(repsquery, "$host", user->host); SearchAndReplace(repsquery, "$ip", user->GetIPString()); SQLrequest req = SQLrequest(this, SQLprovider, databaseid, SQLquery(repsquery)); result = req.Send(); } /* Returned No Rows */ } else { if (verbose) { /* No rows in result, this means there was no record matching the user */ ServerInstance->SNO->WriteToSnoMask('A', "Forbidden connection from %s!%s@%s (SQL query returned no matches)", user->nick.c_str(), user->ident.c_str(), user->host.c_str()); } /* Run Failure SQL Insert Query (For Logging) */ std::string repfquery = failurequery; if (repfquery != "") { if (user->GetExt("wantsnick", wnick)) { SearchAndReplace(repfquery, "$nick", *wnick); } else { SearchAndReplace(repfquery, "$nick", user->nick); } SearchAndReplace(repfquery, "$host", user->host); SearchAndReplace(repfquery, "$ip", user->GetIPString()); SearchAndReplace(repfquery, "$reason", killreason.c_str()); SQLrequest req = SQLrequest(this, SQLprovider, databaseid, SQLquery(repfquery)); result = req.Send(); } /* Kill user that entered invalid credentials */ ServerInstance->Users->QuitUser(user, killreason); user->Extend("sqlauth_failed"); } /* SQL Failure */ } else { if (verbose) { ServerInstance->SNO->WriteToSnoMask('A', "Forbidden connection from %s!%s@%s (SQL query failed: %s)", user->nick.c_str(), user->ident.c_str(), user->host.c_str(), res->error.Str()); } user->Extend("sqlauth_failed"); } } else { return NULL; } if (!user->GetExt("sqlauthed")) { ServerInstance->Users->QuitUser(user, killreason); } return SQLSUCCESS; } return NULL; }
void TreeSocket::ProcessConnectedLine(std::string& prefix, std::string& command, parameterlist& params) { User* who = ServerInstance->FindUUID(prefix); std::string direction; if (!who) { TreeServer* ServerSource = Utils->FindServer(prefix); if (prefix.empty()) ServerSource = MyRoot; if (ServerSource) { who = ServerSource->ServerUser; } else { /* It is important that we don't close the link here, unknown prefix can occur * due to various race conditions such as the KILL message for a user somehow * crossing the users QUIT further upstream from the server. Thanks jilles! */ if ((prefix.length() == UUID_LENGTH-1) && (isdigit(prefix[0])) && ((command == "FMODE") || (command == "MODE") || (command == "KICK") || (command == "TOPIC") || (command == "KILL") || (command == "ADDLINE") || (command == "DELLINE"))) { /* Special case, we cannot drop these commands as they've been committed already on a * part of the network by the time we receive them, so in this scenario pretend the * command came from a server to avoid desync. */ who = ServerInstance->FindUUID(prefix.substr(0, 3)); if (!who) who = this->MyRoot->ServerUser; } else { ServerInstance->Logs->Log("m_spanningtree", DEBUG, "Command '%s' from unknown prefix '%s'! Dropping entire command.", command.c_str(), prefix.c_str()); return; } } } // Make sure prefix is still good direction = who->server; prefix = who->uuid; /* * Check for fake direction here, and drop any instances that are found. * What is fake direction? Imagine the following server setup: * 0AA <-> 0AB <-> 0AC * Fake direction would be 0AC sending a message to 0AB claiming to be from * 0AA, or something similar. Basically, a message taking a path that *cannot* * be correct. * * When would this be seen? * Well, hopefully never. It could be caused by race conditions, bugs, or * "miscreant" servers, though, so let's check anyway. -- w * * We also check here for totally invalid prefixes (prefixes that are neither * a valid SID or a valid UUID, so that invalid UUID or SID never makes it * to the higher level functions. -- B */ TreeServer* route_back_again = Utils->BestRouteTo(direction); if ((!route_back_again) || (route_back_again->GetSocket() != this)) { if (route_back_again) ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Protocol violation: Fake direction '%s' from connection '%s'", prefix.c_str(),linkID.c_str()); return; } /* * First up, check for any malformed commands (e.g. MODE without a timestamp) * and rewrite commands where necessary (SVSMODE -> MODE for services). -- w */ if (command == "SVSMODE") // This isn't in an "else if" so we still force FMODE for changes on channels. command = "MODE"; // TODO move all this into Commands if (command == "MAP") { Utils->Creator->HandleMap(params, who); } else if (command == "SERVER") { this->RemoteServer(prefix,params); } else if (command == "ERROR") { this->Error(params); } else if (command == "AWAY") { this->Away(prefix,params); } else if (command == "PING") { this->LocalPing(prefix,params); } else if (command == "PONG") { TreeServer *s = Utils->FindServer(prefix); if (s && s->bursting) { ServerInstance->SNO->WriteGlobalSno('l',"Server \002%s\002 has not finished burst, forcing end of burst (send ENDBURST!)", prefix.c_str()); s->FinishBurst(); } this->LocalPong(prefix,params); } else if (command == "VERSION") { this->ServerVersion(prefix,params); } else if (command == "ADDLINE") { this->AddLine(prefix,params); } else if (command == "DELLINE") { this->DelLine(prefix,params); } else if (command == "SAVE") { this->ForceNick(prefix,params); } else if (command == "OPERQUIT") { this->OperQuit(prefix,params); } else if (command == "IDLE") { this->Whois(prefix,params); } else if (command == "PUSH") { this->Push(prefix,params); } else if (command == "SQUIT") { if (params.size() == 2) { this->Squit(Utils->FindServer(params[0]),params[1]); } } else if (command == "SNONOTICE") { if (params.size() >= 2) { ServerInstance->SNO->WriteToSnoMask(params[0][0], "From " + who->nick + ": "+ params[1]); params[1] = ":" + params[1]; Utils->DoOneToAllButSender(prefix, command, params, prefix); } } else if (command == "BURST") { // Set prefix server as bursting TreeServer* ServerSource = Utils->FindServer(prefix); if (!ServerSource) { ServerInstance->SNO->WriteGlobalSno('l', "WTF: Got BURST from a non-server(?): %s", prefix.c_str()); return; } ServerSource->bursting = true; Utils->DoOneToAllButSender(prefix, command, params, prefix); } else if (command == "ENDBURST") { TreeServer* ServerSource = Utils->FindServer(prefix); if (!ServerSource) { ServerInstance->SNO->WriteGlobalSno('l', "WTF: Got ENDBURST from a non-server(?): %s", prefix.c_str()); return; } ServerSource->FinishBurst(); Utils->DoOneToAllButSender(prefix, command, params, prefix); } else if (command == "ENCAP") { this->Encap(who, params); } else if (command == "NICK") { if (params.size() != 2) { SendError("Protocol violation: Wrong number of parameters for NICK message"); return; } if (IS_SERVER(who)) { SendError("Protocol violation: Server changing nick"); return; } if ((isdigit(params[0][0])) && (params[0] != who->uuid)) { SendError("Protocol violation: User changing nick to an invalid UID - " + params[0]); return; } /* Update timestamp on user when they change nicks */ who->age = atoi(params[1].c_str()); /* * On nick messages, check that the nick doesnt already exist here. * If it does, perform collision logic. */ User* x = ServerInstance->FindNickOnly(params[0]); if ((x) && (x != who)) { int collideret = 0; /* x is local, who is remote */ collideret = this->DoCollision(x, who->age, who->ident, who->GetIPString(), who->uuid); if (collideret != 1) { /* * Remote client lost, or both lost, parsing or passing on this * nickchange would be pointless, as the incoming client's server will * soon recieve SVSNICK to change its nick to its UID. :) -- w00t */ return; } } who->ForceNickChange(params[0].c_str()); Utils->RouteCommand(route_back_again, command, params, who); } else { Command* cmd = ServerInstance->Parser->GetHandler(command); if (!cmd) { irc::stringjoiner pmlist(" ", params, 0, params.size() - 1); ServerInstance->Logs->Log("m_spanningtree", SPARSE, "Unrecognised S2S command :%s %s %s", who->uuid.c_str(), command.c_str(), pmlist.GetJoined().c_str()); SendError("Unrecognised command '" + command + "' -- possibly loaded mismatched modules"); return; } if (params.size() < cmd->min_params) { irc::stringjoiner pmlist(" ", params, 0, params.size() - 1); ServerInstance->Logs->Log("m_spanningtree", SPARSE, "Insufficient parameters for S2S command :%s %s %s", who->uuid.c_str(), command.c_str(), pmlist.GetJoined().c_str()); SendError("Insufficient parameters for command '" + command + "'"); return; } if ((!params.empty()) && (params.back().empty()) && (!cmd->allow_empty_last_param)) { // the last param is empty and the command handler doesn't allow that, check if there will be enough params if we drop the last if (params.size()-1 < cmd->min_params) return; params.pop_back(); } CmdResult res = cmd->Handle(params, who); if (res == CMD_INVALID) { irc::stringjoiner pmlist(" ", params, 0, params.size() - 1); ServerInstance->Logs->Log("m_spanningtree", SPARSE, "Error handling S2S command :%s %s %s", who->uuid.c_str(), command.c_str(), pmlist.GetJoined().c_str()); SendError("Error handling '" + command + "' -- possibly loaded mismatched modules"); } else if (res == CMD_SUCCESS) Utils->RouteCommand(route_back_again, command, params, who); } }
CmdResult Handle(const std::vector<std::string>& parameters, User* user) { std::string target = parameters[0]; User* u = ServerInstance->FindNick(target); /* Allow just 'nick' if valid, otherwise force use of 'nick!user@host' */ if (target.find('!') == std::string::npos || target.find('@') == std::string::npos) { if (u && u->registered == REG_ALL) { /* Use *!*@IP if valid nick is given */ target = std::string("*!*@") + u->GetIPString(); } else { user->WriteServ("NOTICE %s :*** NoCreate: No user '%s' found", user->nick.c_str(), target.c_str()); return CMD_FAILURE; } } /* Adding */ if (parameters.size() >= 3) { if (this->MaskIsInsane(target, user)) { user->WriteServ("NOTICE %s :*** NoCreate mask %s flagged as insane", user->nick.c_str(), target.c_str()); return CMD_FAILURE; } long duration = ServerInstance->Duration(parameters[1]); NoCreate* nc = new NoCreate(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), target.c_str()); if (ServerInstance->XLines->AddLine(nc, user)) { if (!duration) { ServerInstance->SNO->WriteToSnoMask('x', "%s added permanent NoCreate %s: %s", user->nick.c_str(), target.c_str(), parameters[2].c_str()); } else { ServerInstance->SNO->WriteToSnoMask('x', "%s added timed NoCreate %s, expires on %s: %s", user->nick.c_str(), target.c_str(), ServerInstance->TimeString(duration + ServerInstance->Time()).c_str(), parameters[2].c_str()); } } else { delete nc; user->WriteServ("NOTICE %s :*** NoCreate %s already exists", user->nick.c_str(), target.c_str()); return CMD_FAILURE; } } /* Removing */ else { if (ServerInstance->XLines->DelLine(target.c_str(), "NOCREATE", user)) { ServerInstance->SNO->WriteToSnoMask('x', "%s removed NoCreate %s", user->nick.c_str(), target.c_str()); } else { user->WriteServ("NOTICE %s :*** NoCreate %s not found in list, try /stats N", user->nick.c_str(), target.c_str()); return CMD_FAILURE; } } return CMD_SUCCESS; }
CmdResult CommandZline::Handle(User* user, const Params& parameters) { std::string target = parameters[0]; if (parameters.size() >= 3) { if (target.find('!') != std::string::npos) { user->WriteNotice("*** You cannot include a nickname in a Z-line, a Z-line must ban only an IP mask."); return CMD_FAILURE; } User *u = ServerInstance->FindNick(target); if ((u) && (u->registered == REG_ALL)) { target = u->GetIPString(); } const char* ipaddr = target.c_str(); if (strchr(ipaddr,'@')) { while (*ipaddr != '@') ipaddr++; ipaddr++; } IPMatcher matcher; if (InsaneBan::MatchesEveryone(ipaddr, matcher, user, "Z", "ipmasks")) return CMD_FAILURE; unsigned long duration; if (!InspIRCd::Duration(parameters[1], duration)) { user->WriteNotice("*** Invalid duration for Z-line."); return CMD_FAILURE; } ZLine* zl = new ZLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ipaddr); if (ServerInstance->XLines->AddLine(zl,user)) { if (!duration) { ServerInstance->SNO.WriteToSnoMask('x',"%s added permanent Z-line for %s: %s", user->nick.c_str(), ipaddr, parameters[2].c_str()); } else { time_t c_requires_crap = duration + ServerInstance->Time(); std::string timestr = InspIRCd::TimeString(c_requires_crap); ServerInstance->SNO.WriteToSnoMask('x',"%s added timed Z-line for %s, expires on %s: %s",user->nick.c_str(),ipaddr, timestr.c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); } else { delete zl; user->WriteNotice("*** Z-line for " + std::string(ipaddr) + " already exists."); } } else { std::string reason; if (ServerInstance->XLines->DelLine(target.c_str(), "Z", reason, user)) { ServerInstance->SNO.WriteToSnoMask('x', "%s removed Z-line on %s: %s", user->nick.c_str(), target.c_str(), reason.c_str()); } else { user->WriteNotice("*** Z-line " + target + " not found in list, try /stats Z."); return CMD_FAILURE; } } return CMD_SUCCESS; }
CmdResult CommandZline::Handle (const std::vector<std::string>& parameters, User *user) { std::string target = parameters[0]; if (parameters.size() >= 3) { if (target.find('!') != std::string::npos) { user->WriteServ("NOTICE %s :*** You cannot include a nickname in a zline, a zline must ban only an IP mask",user->nick.c_str()); return CMD_FAILURE; } User *u = ServerInstance->FindNick(target); if ((u) && (u->registered == REG_ALL)) { target = u->GetIPString(); } const char* ipaddr = target.c_str(); if (strchr(ipaddr,'@')) { while (*ipaddr != '@') ipaddr++; ipaddr++; } if (ServerInstance->IPMatchesEveryone(ipaddr,user)) return CMD_FAILURE; long duration = ServerInstance->Duration(parameters[1].c_str()); ZLine* zl = new ZLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ipaddr); if (ServerInstance->XLines->AddLine(zl,user)) { if (!duration) { ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent Z-line for %s: %s", user->nick.c_str(), ipaddr, parameters[2].c_str()); } else { time_t c_requires_crap = duration + ServerInstance->Time(); std::string timestr = ServerInstance->TimeString(c_requires_crap); ServerInstance->SNO->WriteToSnoMask('x',"%s added timed Z-line for %s, expires on %s: %s",user->nick.c_str(),ipaddr, timestr.c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); } else { delete zl; user->WriteServ("NOTICE %s :*** Z-Line for %s already exists",user->nick.c_str(),ipaddr); } } else { if (ServerInstance->XLines->DelLine(target.c_str(),"Z",user)) { ServerInstance->SNO->WriteToSnoMask('x',"%s removed Z-line on %s",user->nick.c_str(),target.c_str()); } else { user->WriteServ("NOTICE %s :*** Z-Line %s not found in list, try /stats Z.",user->nick.c_str(),target.c_str()); return CMD_FAILURE; } } return CMD_SUCCESS; }
CmdResult Handle(User* user, const Params& parameters) override { /* syntax: SHUN nick!user@host time :reason goes here */ /* 'time' is a human-readable timestring, like 2d3h2s. */ std::string target = parameters[0]; User *find = ServerInstance->FindNick(target); if ((find) && (find->registered == REG_ALL)) target = std::string("*!*@") + find->GetIPString(); if (parameters.size() == 1) { std::string reason; if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "SHUN", reason, user)) { ServerInstance->SNO.WriteToSnoMask('x', "%s removed SHUN on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str()); } else if (ServerInstance->XLines->DelLine(target.c_str(), "SHUN", reason, user)) { ServerInstance->SNO.WriteToSnoMask('x', "%s removed SHUN on %s: %s", user->nick.c_str(), target.c_str(), reason.c_str()); } else { user->WriteNotice("*** Shun " + parameters[0] + " not found in list, try /stats H."); return CMD_FAILURE; } } else { // Adding - XXX todo make this respect <insane> tag perhaps.. unsigned long duration; std::string expr; if (parameters.size() > 2) { if (!InspIRCd::Duration(parameters[1], duration)) { user->WriteNotice("*** Invalid duration for SHUN."); return CMD_FAILURE; } expr = parameters[2]; } else { duration = 0; expr = parameters[1]; } Shun* r = new Shun(ServerInstance->Time(), duration, user->nick.c_str(), expr.c_str(), target.c_str()); if (ServerInstance->XLines->AddLine(r, user)) { if (!duration) { ServerInstance->SNO.WriteToSnoMask('x', "%s added permanent SHUN for %s: %s", user->nick.c_str(), target.c_str(), expr.c_str()); } else { ServerInstance->SNO.WriteToSnoMask('x', "%s added timed SHUN for %s to expire in %s (on %s): %s", user->nick.c_str(), target.c_str(), InspIRCd::DurationString(duration).c_str(), InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), expr.c_str()); } } else { delete r; user->WriteNotice("*** Shun for " + target + " already exists."); return CMD_FAILURE; } } return CMD_SUCCESS; }