Esempio n. 1
0
CmdResult CommandAddLine::Handle(User* usr, std::vector<std::string>& params)
{
	XLineFactory* xlf = ServerInstance->XLines->GetFactory(params[0]);
	const std::string& setter = usr->nick;

	if (!xlf)
	{
		ServerInstance->SNO->WriteToSnoMask('d',"%s sent me an unknown ADDLINE type (%s).",setter.c_str(),params[0].c_str());
		return CMD_FAILURE;
	}

	XLine* xl = NULL;
	try
	{
		xl = xlf->Generate(ServerInstance->Time(), ConvToInt(params[4]), params[2], params[5], params[1]);
	}
	catch (ModuleException &e)
	{
		ServerInstance->SNO->WriteToSnoMask('d',"Unable to ADDLINE type %s from %s: %s", params[0].c_str(), setter.c_str(), e.GetReason().c_str());
		return CMD_FAILURE;
	}
	xl->SetCreateTime(ConvToInt(params[3]));
	if (ServerInstance->XLines->AddLine(xl, NULL))
	{
		if (xl->duration)
		{
			std::string timestr = InspIRCd::TimeString(xl->expiry);
			ServerInstance->SNO->WriteToSnoMask('X',"%s added %s%s on %s to expire on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "",
					params[1].c_str(), timestr.c_str(), params[5].c_str());
		}
		else
		{
			ServerInstance->SNO->WriteToSnoMask('X',"%s added permanent %s%s on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "",
					params[1].c_str(),params[5].c_str());
		}

		TreeServer* remoteserver = TreeServer::Get(usr);

		if (!remoteserver->IsBursting())
		{
			ServerInstance->XLines->ApplyLines();
		}
		return CMD_SUCCESS;
	}
	else
	{
		delete xl;
		return CMD_FAILURE;
	}
}
Esempio n. 2
0
time_t ServerCommand::ExtractTS(const std::string& tsstr)
{
	time_t TS = ConvToInt(tsstr);
	if (!TS)
		throw ProtocolException("Invalid TS");
	return TS;
}
Esempio n. 3
0
	void unserialize(SerializeFormat format, Extensible* container, const std::string& value)
	{
		if (format == FORMAT_NETWORK)
			return;

		callerid_data* dat = new callerid_data;
		irc::commasepstream s(value);
		std::string tok;
		if (s.GetToken(tok))
			dat->lastnotify = ConvToInt(tok);

		while (s.GetToken(tok))
		{
			User *u = ServerInstance->FindNick(tok);
			if ((u) && (u->registered == REG_ALL) && (!u->quitting))
			{
				if (dat->accepting.insert(u).second)
				{
					callerid_data* other = this->get(u, true);
					other->wholistsme.push_back(dat);
				}
			}
		}

		void* old = set_raw(container, dat);
		if (old)
			this->free(old);
	}
Esempio n. 4
0
bool irc::tokenstream::GetToken(long &token)
{
	std::string tok;
	bool returnval = GetToken(tok);
	token = ConvToInt(tok);
	return returnval;
}
Esempio n. 5
0
	ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
	{
		if (adding)
		{
			std::string::size_type colon = parameter.find(':');
			if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos))
			{
				source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str());
				return MODEACTION_DENY;
			}

			/* Set up the flood parameters for this channel */
			unsigned int njoins = ConvToInt(parameter.substr(0, colon));
			unsigned int nsecs = ConvToInt(parameter.substr(colon+1));
			if ((njoins<1) || (nsecs<1))
			{
				source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str());
				return MODEACTION_DENY;
			}

			joinfloodsettings jfs(nsecs, njoins);
			joinfloodsettings* f = ext.get(channel);
			if ((f) && (*f == jfs))
				// mode params match
				return MODEACTION_DENY;

			ext.set(channel, jfs);
			parameter = ConvToStr(njoins) + ":" + ConvToStr(nsecs);
			channel->SetModeParam(this, parameter);
			return MODEACTION_ALLOW;
		}
		else
		{
			if (!channel->IsModeSet(this))
				return MODEACTION_DENY;

			joinfloodsettings* f = ext.get(channel);
			if (f)
			{
				ext.unset(channel);
				channel->SetModeParam(this, "");
				return MODEACTION_ALLOW;
			}
		}
		return MODEACTION_DENY;
	}
Esempio n. 6
0
ModeAction ModeChannelLimit::OnSet(User* user, Channel* chan, std::string& parameter)
{
    int limit = ConvToInt(parameter);
    if (limit < 0)
        return MODEACTION_DENY;

    ext.set(chan, limit);
    return MODEACTION_ALLOW;
}
Esempio n. 7
0
	ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
	{
		if (adding)
		{
			std::string::size_type colon = parameter.find(':');
			if (colon == std::string::npos || parameter.find('-') != std::string::npos)
			{
				source->WriteNumeric(608, "%s %s :Invalid slowmode parameter", source->nick.c_str(),channel->name.c_str());
				return MODEACTION_DENY;
			}

			/* Set up the slowmode parameters for this channel */
			unsigned int nlines = ConvToInt(parameter.substr(0, colon));
			unsigned int nsecs = ConvToInt(parameter.substr(colon+1));

			if ((nlines < 2) || nsecs < 1)
			{
				source->WriteNumeric(608, "%s %s :Invalid slowmode parameter", source->nick.c_str(), channel->name.c_str());
				return MODEACTION_DENY;
			}

			slowmodesettings* f = ext.get(channel);
			if (f && nlines == f->lines && nsecs == f->secs)
				// mode params match
				return MODEACTION_DENY;

			ext.set(channel, new slowmodesettings(nlines, nsecs));
			parameter = ConvToStr(nlines) + ":" + ConvToStr(nsecs);
			channel->SetModeParam(GetModeChar(), parameter);
			return MODEACTION_ALLOW;
		}
		else
		{
			if (!channel->IsModeSet(GetModeChar()))
				return MODEACTION_DENY;

			ext.unset(channel);
			channel->SetModeParam(GetModeChar(), "");
			return MODEACTION_ALLOW;
		}
	}
Esempio n. 8
0
	ModeAction OnSet(User* source, Channel* channel, std::string& parameter)
	{
		int v = ConvToInt(parameter);
		if (v <= 0)
			return MODEACTION_DENY;

		if ((IS_LOCAL(source) && ((unsigned int)v > max)))
			v = max;

		ext.set(channel, new KickRejoinData(v));
		return MODEACTION_ALLOW;
	}
Esempio n. 9
0
	ModeAction OnSet(User* source, Channel* channel, std::string& parameter)
	{
		std::string::size_type colon = parameter.find(':');
		if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos))
		{
			source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str());
			return MODEACTION_DENY;
		}

		/* Set up the flood parameters for this channel */
		unsigned int njoins = ConvToInt(parameter.substr(0, colon));
		unsigned int nsecs = ConvToInt(parameter.substr(colon+1));
		if ((njoins<1) || (nsecs<1))
		{
			source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str());
			return MODEACTION_DENY;
		}

		ext.set(channel, new joinfloodsettings(nsecs, njoins));
		return MODEACTION_ALLOW;
	}
Esempio n. 10
0
/** FMODE command - server mode with timestamp checks */
CmdResult CommandFMode::Handle(User* who, std::vector<std::string>& params)
{
	time_t TS = ConvToInt(params[1]);
	if (!TS)
	{
		ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "*** BUG? *** TS of 0 sent to FMODE. Are some services authors smoking craq, or is it 1970 again?. Dropping link.");
		ServerInstance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FMODE with a TS of zero. Total craq, dropping link.", who->server->GetName().c_str());
		return CMD_INVALID;
	}

	/* Extract the TS value of the object, either User or Channel */
	time_t ourTS;
	if (params[0][0] == '#')
	{
		Channel* chan = ServerInstance->FindChan(params[0]);
		if (!chan)
			/* Oops, channel doesn't exist! */
			return CMD_FAILURE;

		ourTS = chan->age;
	}
	else
	{
		User* user = ServerInstance->FindUUID(params[0]);
		if (!user)
			return CMD_FAILURE;

		if (IS_SERVER(user))
			return CMD_INVALID;

		ourTS = user->age;
	}

	/* If the TS is greater than ours, we drop the mode and don't pass it anywhere.
	 */
	if (TS > ourTS)
		return CMD_FAILURE;

	/* TS is equal or less: Merge the mode changes into ours and pass on.
	 */
	std::vector<std::string> modelist;
	modelist.reserve(params.size()-1);
	/* Insert everything into modelist except the TS (params[1]) */
	modelist.push_back(params[0]);
	modelist.insert(modelist.end(), params.begin()+2, params.end());

	ModeParser::ModeProcessFlag flags = ModeParser::MODE_LOCALONLY;
	if ((TS == ourTS) && IS_SERVER(who))
		flags |= ModeParser::MODE_MERGE;

	ServerInstance->Modes->Process(modelist, who, flags);
	return CMD_SUCCESS;
}
Esempio n. 11
0
	ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
	{
		if (adding)
		{
			std::string::size_type colon = parameter.find(':');
			if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos))
			{
				source->WriteNumeric(608, "%s :Invalid flood parameter", channel->name.c_str());
				return MODEACTION_DENY;
			}

			/* Set up the flood parameters for this channel */
			bool ban = (parameter[0] == '*');
			unsigned int nlines = ConvToInt(parameter.substr(ban ? 1 : 0, ban ? colon-1 : colon));
			unsigned int nsecs = ConvToInt(parameter.substr(colon+1));

			if ((nlines<2) || (nsecs<1))
			{
				source->WriteNumeric(608, "%s :Invalid flood parameter", channel->name.c_str());
				return MODEACTION_DENY;
			}

			floodsettings* f = ext.get(channel);
			if ((f) && (nlines == f->lines) && (nsecs == f->secs) && (ban == f->ban))
				// mode params match
				return MODEACTION_DENY;

			ext.set(channel, new floodsettings(ban, nsecs, nlines));
			parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" + ConvToStr(nsecs);
			return MODEACTION_ALLOW;
		}
		else
		{
			if (!channel->IsModeSet(this))
				return MODEACTION_DENY;

			ext.unset(channel);
			return MODEACTION_ALLOW;
		}
	}
Esempio n. 12
0
	CmdResult Handle(const std::vector<std::string> &parameters, User *user)
	{
		if (!user->server->IsULine())
		{
			// Ulines only
			return CMD_FAILURE;
		}

		Channel* chan = ServerInstance->FindChan(parameters[0]);
		if (!chan)
			return CMD_FAILURE;

		if (parameters.size() == 4)
		{
			// 4 parameter version, set all topic data on the channel to the ones given in the parameters
			time_t topicts = ConvToInt(parameters[1]);
			if (!topicts)
			{
				ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Received SVSTOPIC with a 0 topicts, dropped.");
				return CMD_INVALID;
			}

			std::string newtopic;
			newtopic.assign(parameters[3], 0, ServerInstance->Config->Limits.MaxTopic);
			bool topics_differ = (chan->topic != newtopic);
			if ((topics_differ) || (chan->topicset != topicts) || (chan->setby != parameters[2]))
			{
				// Update when any parameter differs
				chan->topicset = topicts;
				chan->setby.assign(parameters[2], 0, 127);
				chan->topic = newtopic;
				// Send TOPIC to clients only if the actual topic has changed, be silent otherwise
				if (topics_differ)
					chan->WriteChannel(user, "TOPIC %s :%s", chan->name.c_str(), chan->topic.c_str());
			}
		}
		else
		{
			// 1 parameter version, nuke the topic
			bool topic_empty = chan->topic.empty();
			if (!topic_empty || !chan->setby.empty())
			{
				chan->topicset = 0;
				chan->setby.clear();
				chan->topic.clear();
				if (!topic_empty)
					chan->WriteChannel(user, "TOPIC %s :", chan->name.c_str());
			}
		}

		return CMD_SUCCESS;
	}
Esempio n. 13
0
	void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts)
	{
		if (memb->chan->IsModeSet(&kr) && (source != memb->user))
		{
			delaylist* dl = kr.ext.get(memb->chan);
			if (!dl)
			{
				dl = new delaylist;
				kr.ext.set(memb->chan, dl);
			}
			(*dl)[memb->user] = ServerInstance->Time() + ConvToInt(memb->chan->GetModeParameter(&kr));
		}
	}
Esempio n. 14
0
	ModeAction OnModeChange(User* source, User* dest, Channel* chan, std::string& parameter, bool adding)
	{
		if (adding)
		{
			std::string::size_type colon = parameter.find(':');
			if (colon == std::string::npos || parameter.find('-') != std::string::npos)
			{
				source->WriteNumeric(608, "%s %s :Invalid join/part spam parameter", source->nick.c_str(), chan->name.c_str());
				return MODEACTION_DENY;
			}

			unsigned int ncycles = ConvToInt(parameter.substr(0, colon));
			unsigned int nsecs = ConvToInt(parameter.substr(colon+1));

			if (ncycles < 2 || nsecs < 1)
			{
				source->WriteNumeric(608, "%s %s :Invalid join/part spam parameter", source->nick.c_str(), chan->name.c_str());
				return MODEACTION_DENY;
			}

			joinpartspamsettings* jpss = ext.get(chan);
			if (jpss && ncycles == jpss->cycles && nsecs == jpss->secs)
				return MODEACTION_DENY;

			ext.set(chan, new joinpartspamsettings(ncycles, nsecs));
			parameter = ConvToStr(ncycles) + ":" + ConvToStr(nsecs);
			chan->SetModeParam(GetModeChar(), parameter);
			return MODEACTION_ALLOW;
		}
		else
		{
			if (!chan->IsModeSet(GetModeChar()))
				return MODEACTION_DENY;

			ext.unset(chan);
			chan->SetModeParam(GetModeChar(), "");
			return MODEACTION_ALLOW;
		}
	}
Esempio n. 15
0
CmdResult CommandMetadata::Handle(const std::vector<std::string>& params, User *srcuser)
{
	if (params[0] == "*")
	{
		std::string value = params.size() < 3 ? "" : params[2];
		FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(NULL,params[1],value));
		return CMD_SUCCESS;
	}

	if (params[0][0] == '#')
	{
		// Channel METADATA has an additional parameter: the channel TS
		// :22D METADATA #channel 12345 extname :extdata
		if (params.size() < 3)
			return CMD_INVALID;

		Channel* c = ServerInstance->FindChan(params[0]);
		if (!c)
			return CMD_FAILURE;

		time_t ChanTS = ConvToInt(params[1]);
		if (!ChanTS)
			return CMD_INVALID;

		if (c->age < ChanTS)
			// Their TS is newer than ours, discard this command and do not propagate
			return CMD_FAILURE;

		std::string value = params.size() < 4 ? "" : params[3];

		ExtensionItem* item = ServerInstance->Extensions.GetItem(params[2]);
		if (item)
			item->unserialize(FORMAT_NETWORK, c, value);
		FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(c,params[2],value));
	}
	else
	{
		User* u = ServerInstance->FindUUID(params[0]);
		if ((u) && (!IS_SERVER(u)))
		{
			ExtensionItem* item = ServerInstance->Extensions.GetItem(params[1]);
			std::string value = params.size() < 3 ? "" : params[2];

			if (item)
				item->unserialize(FORMAT_NETWORK, u, value);
			FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(u,params[1],value));
		}
	}

	return CMD_SUCCESS;
}
CmdResult CommandWhois::HandleRemote(const std::vector<std::string>& parameters, RemoteUser* target)
{
	if (parameters.size() < 2)
		return CMD_FAILURE;

	User* user = ServerInstance->FindUUID(parameters[0]);
	if (!user)
		return CMD_FAILURE;

	unsigned long idle = ConvToInt(parameters.back());
	DoWhois(user, target, target->signon, idle);

	return CMD_SUCCESS;
}
Esempio n. 17
0
    PBKDF2Hash(const std::string& data)
    {
        irc::sepstream ss(data, ':');
        std::string tok;

        ss.GetToken(tok);
        this->iterations = ConvToInt(tok);

        ss.GetToken(tok);
        this->hash = Base64ToBin(tok);

        ss.GetToken(tok);
        this->salt = Base64ToBin(tok);

        this->length = this->hash.length();
    }
Esempio n. 18
0
	ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
	{
		if (adding)
		{
			std::string::size_type colon = parameter.find(':');
			if (colon == std::string::npos)
				return MODEACTION_DENY;

			std::string duration = parameter.substr(colon+1);
			if ((IS_LOCAL(source)) && ((duration.length() > 10) || (!IsValidDuration(duration))))
				return MODEACTION_DENY;

			unsigned int len = ConvToInt(parameter.substr(0, colon));
			int time = InspIRCd::Duration(duration);
			if (len == 0 || time < 0)
				return MODEACTION_DENY;
			if (len > maxlines && IS_LOCAL(source))
				return MODEACTION_DENY;
			if (len > maxlines)
				len = maxlines;
			if (parameter == channel->GetModeParameter(this))
				return MODEACTION_DENY;

			HistoryList* history = ext.get(channel);
			if (history)
			{
				// Shrink the list if the new line number limit is lower than the old one
				if (len < history->lines.size())
					history->lines.erase(history->lines.begin(), history->lines.begin() + (history->lines.size() - len));

				history->maxlen = len;
				history->maxtime = time;
			}
			else
			{
				ext.set(channel, new HistoryList(len, time));
			}
		}
		else
		{
			if (!channel->IsModeSet(this))
				return MODEACTION_DENY;
			ext.unset(channel);
		}
		return MODEACTION_ALLOW;
	}
Esempio n. 19
0
irc::sockets::cidr_mask::cidr_mask(const std::string& mask)
{
	std::string::size_type bits_chars = mask.rfind('/');
	irc::sockets::sockaddrs sa;

	if (bits_chars == std::string::npos)
	{
		irc::sockets::aptosa(mask, 0, sa);
		sa2cidr(*this, sa, 128);
	}
	else
	{
		int range = ConvToInt(mask.substr(bits_chars + 1));
		irc::sockets::aptosa(mask.substr(0, bits_chars), 0, sa);
		sa2cidr(*this, sa, range);
	}
}
Esempio n. 20
0
CmdResult CommandNum::HandleServer(TreeServer* server, std::vector<std::string>& params)
{
	User* const target = ServerInstance->FindUUID(params[1]);
	if (!target)
		return CMD_FAILURE;

	LocalUser* const localtarget = IS_LOCAL(target);
	if (!localtarget)
		return CMD_SUCCESS;

	Numeric::Numeric numeric(ConvToInt(params[2]));
	// Passing NULL is ok, in that case the numeric source becomes this server
	numeric.SetServer(Utils->FindServerID(params[0]));
	numeric.GetParams().insert(numeric.GetParams().end(), params.begin()+3, params.end());

	localtarget->WriteNumeric(numeric);
	return CMD_SUCCESS;
}
Esempio n. 21
0
CmdResult CommandAway::Handle(User* u, std::vector<std::string>& params)
{
	if (IS_SERVER(u))
		return CMD_INVALID;
	if (params.size())
	{
		FOREACH_MOD(OnSetAway, (u, params[params.size() - 1]));

		if (params.size() > 1)
			u->awaytime = ConvToInt(params[0]);
		else
			u->awaytime = ServerInstance->Time();

		u->awaymsg = params[params.size() - 1];
	}
	else
	{
		FOREACH_MOD(OnSetAway, (u, ""));
		u->awaymsg.clear();
	}
	return CMD_SUCCESS;
}
Esempio n. 22
0
CmdResult CommandIJoin::HandleRemote(RemoteUser* user, std::vector<std::string>& params)
{
	Channel* chan = ServerInstance->FindChan(params[0]);
	if (!chan)
	{
		// Desync detected, recover
		// Ignore the join and send RESYNC, this will result in the remote server sending all channel data to us
		ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Received IJOIN for non-existant channel: " + params[0]);

		CmdBuilder("RESYNC").push(params[0]).Unicast(user);

		return CMD_FAILURE;
	}

	bool apply_modes;
	if (params.size() > 1)
	{
		time_t RemoteTS = ConvToInt(params[1]);
		if (!RemoteTS)
		{
			ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Invalid TS in IJOIN: " + params[1]);
			return CMD_INVALID;
		}

		if (RemoteTS < chan->age)
		{
			ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Attempted to lower TS via IJOIN. Channel=" + params[0] + " RemoteTS=" + params[1] + " LocalTS=" + ConvToStr(chan->age));
			return CMD_INVALID;
		}
		apply_modes = ((params.size() > 2) && (RemoteTS == chan->age));
	}
	else
		apply_modes = false;

	chan->ForceJoin(user, apply_modes ? &params[2] : NULL);
	return CMD_SUCCESS;
}
Esempio n. 23
0
CmdResult CommandUID::HandleServer(TreeServer* remoteserver, std::vector<std::string>& params)
{
	/** Do we have enough parameters:
	 *      0    1    2    3    4    5        6        7     8        9       (n-1)
	 * UID uuid age nick host dhost ident ip.string signon +modes (modepara) :gecos
	 */
	time_t age_t = ConvToInt(params[1]);
	time_t signon = ConvToInt(params[7]);
	std::string empty;
	const std::string& modestr = params[8];

	/* Is this a valid UID, and not misrouted? */
	if (params[0].length() != UIDGenerator::UUID_LENGTH || params[0].substr(0, 3) != remoteserver->GetID())
		return CMD_INVALID;
	/* Check parameters for validity before introducing the client, discovered by dmb */
	if (!age_t)
		return CMD_INVALID;
	if (!signon)
		return CMD_INVALID;
	if (modestr[0] != '+')
		return CMD_INVALID;

	/* check for collision */
	user_hash::iterator iter = ServerInstance->Users->clientlist->find(params[2]);

	if (iter != ServerInstance->Users->clientlist->end())
	{
		/*
		 * Nick collision.
		 */
		int collide = Utils->DoCollision(iter->second, remoteserver, age_t, params[5], params[6], params[0]);
		ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "*** Collision on %s, collide=%d", params[2].c_str(), collide);

		if (collide != 1)
		{
			// Remote client lost, make sure we change their nick for the hash too
			params[2] = params[0];
		}
	}

	/* IMPORTANT NOTE: For remote users, we pass the UUID in the constructor. This automatically
	 * sets it up in the UUID hash for us.
	 */
	User* _new = NULL;
	try
	{
		_new = new RemoteUser(params[0], remoteserver);
	}
	catch (...)
	{
		ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Duplicate UUID %s in client introduction", params[0].c_str());
		return CMD_INVALID;
	}
	(*(ServerInstance->Users->clientlist))[params[2]] = _new;
	_new->nick = params[2];
	_new->host = params[3];
	_new->dhost = params[4];
	_new->ident = params[5];
	_new->fullname = params[params.size() - 1];
	_new->registered = REG_ALL;
	_new->signon = signon;
	_new->age = age_t;

	unsigned int paramptr = 9;

	for (std::string::const_iterator v = modestr.begin(); v != modestr.end(); ++v)
	{
		// Accept more '+' chars, for now
		if (*v == '+')
			continue;

		/* For each mode thats set, find the mode handler and set it on the new user */
		ModeHandler* mh = ServerInstance->Modes->FindMode(*v, MODETYPE_USER);
		if (!mh)
		{
			ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Unrecognised mode '%c' for a user in UID, dropping link", *v);
			return CMD_INVALID;
		}

		if (mh->GetNumParams(true))
		{
			if (paramptr >= params.size() - 1)
				return CMD_INVALID;
			std::string mp = params[paramptr++];
			/* IMPORTANT NOTE:
			 * All modes are assumed to succeed here as they are being set by a remote server.
			 * Modes CANNOT FAIL here. If they DO fail, then the failure is ignored. This is important
			 * to note as all but one modules currently cannot ever fail in this situation, except for
			 * m_servprotect which specifically works this way to prevent the mode being set ANYWHERE
			 * but here, at client introduction. You may safely assume this behaviour is standard and
			 * will not change in future versions if you want to make use of this protective behaviour
			 * yourself.
			 */
			mh->OnModeChange(_new, _new, NULL, mp, true);
		}
		else
			mh->OnModeChange(_new, _new, NULL, empty, true);
		_new->SetMode(mh, true);
	}

	_new->SetClientIP(params[6].c_str());

	ServerInstance->Users->AddGlobalClone(_new);
	remoteserver->UserCount++;

	bool dosend = true;

	if ((Utils->quiet_bursts && remoteserver->bursting) || _new->server->IsSilentULine())
		dosend = false;

	if (dosend)
		ServerInstance->SNO->WriteToSnoMask('C',"Client connecting at %s: %s (%s) [%s]", remoteserver->GetName().c_str(), _new->GetFullRealHost().c_str(), _new->GetIPString().c_str(), _new->fullname.c_str());

	FOREACH_MOD(OnPostConnect, (_new));

	return CMD_SUCCESS;
}
Esempio n. 24
0
/** FJOIN, almost identical to TS6 SJOIN, except for nicklist handling. */
CmdResult CommandFJoin::Handle(const std::vector<std::string>& params, User *srcuser)
{
	SpanningTreeUtilities* Utils = ((ModuleSpanningTree*)(Module*)creator)->Utils;
	/* 1.1+ FJOIN works as follows:
	 *
	 * Each FJOIN is sent along with a timestamp, and the side with the lowest
	 * timestamp 'wins'. From this point on we will refer to this side as the
	 * winner. The side with the higher timestamp loses, from this point on we
	 * will call this side the loser or losing side. This should be familiar to
	 * anyone who's dealt with dreamforge or TS6 before.
	 *
	 * When two sides of a split heal and this occurs, the following things
	 * will happen:
	 *
	 * If the timestamps are exactly equal, both sides merge their privilages
	 * and users, as in InspIRCd 1.0 and ircd2.8. The channels have not been
	 * re-created during a split, this is safe to do.
	 *
	 * If the timestamps are NOT equal, the losing side removes all of its
	 * modes from the channel, before introducing new users into the channel
	 * which are listed in the FJOIN command's parameters. The losing side then
	 * LOWERS its timestamp value of the channel to match that of the winning
	 * side, and the modes of the users of the winning side are merged in with
	 * the losing side.
	 *
	 * The winning side on the other hand will ignore all user modes from the
	 * losing side, so only its own modes get applied. Life is simple for those
	 * who succeed at internets. :-)
	 *
	 * Syntax:
	 * :<sid> FJOIN <chan> <TS> <modes> :[[modes,]<uuid> [[modes,]<uuid> ... ]]
	 * The last parameter is a list consisting of zero or more (modelist, uuid)
	 * pairs (permanent channels may have zero users). The mode list for each
	 * user is a concatenation of the mode letters the user has on the channel
	 * (e.g.: "ov" if the user is opped and voiced). The order of the mode letters
	 * are not important but if a server ecounters an unknown mode letter, it will
	 * drop the link to avoid desync.
	 *
	 * InspIRCd 2.0 and older required a comma before the uuid even if the user
	 * had no prefix modes on the channel, InspIRCd 2.2 and later does not require
	 * a comma in this case anymore.
	 *
	 */

	time_t TS = ConvToInt(params[1]);
	if (!TS)
	{
		ServerInstance->Logs->Log("m_spanningtree",LOG_DEFAULT,"*** BUG? *** TS of 0 sent to FJOIN. Are some services authors smoking craq, or is it 1970 again?. Dropped.");
		ServerInstance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FJOIN with a TS of zero. Total craq. Command was dropped.", srcuser->server.c_str());
		return CMD_INVALID;
	}

	const std::string& channel = params[0];
	Channel* chan = ServerInstance->FindChan(channel);
	bool apply_other_sides_modes = true;

	if (!chan)
	{
		chan = new Channel(channel, TS);
	}
	else
	{
		time_t ourTS = chan->age;
		if (TS != ourTS)
		{
			ServerInstance->SNO->WriteToSnoMask('d', "Merge FJOIN received for %s, ourTS: %lu, TS: %lu, difference: %lu",
				chan->name.c_str(), (unsigned long)ourTS, (unsigned long)TS, (unsigned long)(ourTS - TS));
			/* If our TS is less than theirs, we dont accept their modes */
			if (ourTS < TS)
			{
				apply_other_sides_modes = false;
			}
			else if (ourTS > TS)
			{
				/* Our TS greater than theirs, clear all our modes from the channel, accept theirs. */
				if (Utils->AnnounceTSChange)
					chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :TS for %s changed from %lu to %lu", chan->name.c_str(), channel.c_str(), (unsigned long) ourTS, (unsigned long) TS);

				// while the name is equal in case-insensitive compare, it might differ in case; use the remote version
				chan->name = channel;
				chan->age = TS;
				chan->ClearInvites();

				CommandFJoin::RemoveStatus(chan);

				// XXX: If the channel does not exist in the chan hash at this point, create it so the remote modes can be applied on it.
				// This happens to 0-user permanent channels on the losing side, because those are removed (from the chan hash, then
				// deleted later) as soon as the permchan mode is removed from them.
				if (ServerInstance->FindChan(channel) == NULL)
				{
					chan = new Channel(channel, TS);
				}
			}
		}
	}

	/* First up, apply their channel modes if they won the TS war */
	if (apply_other_sides_modes)
	{
		std::vector<std::string> modelist;
		modelist.push_back(channel);

		/* Remember, params[params.size() - 1] is userlist, and we don't want to apply *that* */
		modelist.insert(modelist.end(), params.begin()+2, params.end()-1);
		ServerInstance->SendMode(modelist, srcuser);
	}

	irc::modestacker modestack(true);
	TreeSocket* src_socket = Utils->FindServer(srcuser->server)->GetRoute()->GetSocket();

	/* Now, process every 'modes,uuid' pair */
	irc::tokenstream users(*params.rbegin());
	std::string item;
	irc::modestacker* modestackptr = (apply_other_sides_modes ? &modestack : NULL);
	while (users.GetToken(item))
	{
		if (!ProcessModeUUIDPair(item, src_socket, chan, modestackptr))
			return CMD_INVALID;
	}

	/* Flush mode stacker if we lost the FJOIN or had equal TS */
	if (apply_other_sides_modes)
		CommandFJoin::ApplyModeStack(srcuser, chan, modestack);

	return CMD_SUCCESS;
}
Esempio n. 25
0
/** FTOPIC command */
CmdResult CommandFTopic::Handle(User* user, std::vector<std::string>& params)
{
	Channel* c = ServerInstance->FindChan(params[0]);
	if (!c)
		return CMD_FAILURE;

	time_t ChanTS = ConvToInt(params[1]);
	if (!ChanTS)
		return CMD_INVALID;

	if (c->age < ChanTS)
		// Our channel TS is older, nothing to do
		return CMD_FAILURE;

	time_t ts = ConvToInt(params[2]);
	if (!ts)
		return CMD_INVALID;

	// Channel::topicset is initialized to 0 on channel creation, so their ts will always win if we never had a topic
	if (ts < c->topicset)
		return CMD_FAILURE;

	// The topic text is always the last parameter
	const std::string& newtopic = params.back();

	// If there is a setter in the message use that, otherwise use the message source
	const std::string& setter = ((params.size() > 4) ? params[3] : (ServerInstance->Config->FullHostInTopic ? user->GetFullHost() : user->nick));

	/*
	 * If the topics were updated at the exact same second, accept
	 * the remote only when it's "bigger" than ours as defined by
	 * string comparision, so non-empty topics always overridde
	 * empty topics if their timestamps are equal
	 *
	 * Similarly, if the topic texts are equal too, keep one topic
	 * setter and discard the other
	 */
	if (ts == c->topicset)
	{
		// Discard if their topic text is "smaller"
		if (c->topic > newtopic)
			return CMD_FAILURE;

		// If the texts are equal in addition to the timestamps, decide which setter to keep
		if ((c->topic == newtopic) && (c->setby >= setter))
			return CMD_FAILURE;
	}

	if (c->topic != newtopic)
	{
		// Update topic only when it differs from current topic
		c->topic.assign(newtopic, 0, ServerInstance->Config->Limits.MaxTopic);
		c->WriteChannel(user, "TOPIC %s :%s", c->name.c_str(), c->topic.c_str());
	}

	// Update setter and settime
	c->setby.assign(setter, 0, 128);
	c->topicset = ts;

	FOREACH_MOD(OnPostTopicChange, (user, c, c->topic));

	return CMD_SUCCESS;
}
Esempio n. 26
0
	CmdResult Handle (const std::vector<std::string> &parameters, 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;
	}
Esempio n. 27
0
void TreeSocket::ProcessLine(std::string &line)
{
	std::string prefix;
	std::string command;
	parameterlist params;

	ServerInstance->Logs->Log(MODNAME, LOG_RAWIO, "S[%d] I %s", this->GetFd(), line.c_str());

	Split(line, prefix, command, params);

	if (command.empty())
		return;

	switch (this->LinkState)
	{
		case WAIT_AUTH_1:
			/*
			 * State WAIT_AUTH_1:
			 *  Waiting for SERVER command from remote server. Server initiating
			 *  the connection sends the first SERVER command, listening server
			 *  replies with theirs if its happy, then if the initiator is happy,
			 *  it starts to send its net sync, which starts the merge, otherwise
			 *  it sends an ERROR.
			 */
			if (command == "PASS")
			{
				/*
				 * Ignore this silently. Some services packages insist on sending PASS, even
				 * when it is not required (i.e. by us). We have to ignore this here, otherwise
				 * as it's an unknown command (effectively), it will cause the connection to be
				 * closed, which probably isn't what people want. -- w00t
				 */
			}
			else if (command == "SERVER")
			{
				this->Inbound_Server(params);
			}
			else if (command == "ERROR")
			{
				this->Error(params);
			}
			else if (command == "USER")
			{
				this->SendError("Client connections to this port are prohibited.");
			}
			else if (command == "CAPAB")
			{
				this->Capab(params);
			}
			else
			{
				this->SendError("Invalid command in negotiation phase: " + command);
			}
		break;
		case WAIT_AUTH_2:
			/*
			 * State WAIT_AUTH_2:
			 *  We have sent SERVER to the other side of the connection. Now we're waiting for them to start BURST.
			 *  The other option at this stage of things, of course, is for them to close our connection thanks
			 *  to invalid credentials.. -- w
			 */
			if (command == "SERVER")
			{
				/*
				 * Connection is either attempting to re-auth itself (stupid) or sending netburst without sending BURST.
				 * Both of these aren't allowable, so block them here. -- w
				 */
				this->SendError("You may not re-authenticate or commence netburst without sending BURST.");
			}
			else if (command == "BURST")
			{
				if (params.size())
				{
					time_t them = ConvToInt(params[0]);
					time_t delta = them - ServerInstance->Time();
					if ((delta < -600) || (delta > 600))
					{
						ServerInstance->SNO->WriteGlobalSno('l',"\2ERROR\2: Your clocks are out by %d seconds (this is more than five minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2",abs((long)delta));
						SendError("Your clocks are out by "+ConvToStr(abs((long)delta))+" seconds (this is more than five minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!");
						return;
					}
					else if ((delta < -30) || (delta > 30))
					{
						ServerInstance->SNO->WriteGlobalSno('l',"\2WARNING\2: Your clocks are out by %d seconds. Please consider synching your clocks.", abs((long)delta));
					}
				}

				// Check for duplicate server name/sid again, it's possible that a new
				// server was introduced while we were waiting for them to send BURST.
				// (we do not reserve their server name/sid when they send SERVER, we do it now)
				if (!CheckDuplicate(capab->name, capab->sid))
					return;

				this->LinkState = CONNECTED;
				Utils->timeoutlist.erase(this);

				linkID = capab->name;

				MyRoot = new TreeServer(capab->name, capab->description, capab->sid, Utils->TreeRoot, this, capab->hidden);
				Utils->TreeRoot->AddChild(MyRoot);

				MyRoot->bursting = true;
				this->DoBurst(MyRoot);

				parameterlist sparams;
				sparams.push_back(MyRoot->GetName());
				sparams.push_back("*");
				sparams.push_back("0");
				sparams.push_back(MyRoot->GetID());
				sparams.push_back(":" + MyRoot->GetDesc());
				Utils->DoOneToAllButSender(ServerInstance->Config->GetSID(), "SERVER", sparams, MyRoot);
				Utils->DoOneToAllButSender(MyRoot->GetID(), "BURST", params, MyRoot);
			}
			else if (command == "ERROR")
			{
				this->Error(params);
			}
			else if (command == "CAPAB")
			{
				this->Capab(params);
			}

		break;
		case CONNECTING:
			/*
			 * State CONNECTING:
			 *  We're connecting (OUTGOING) to another server. They are in state WAIT_AUTH_1 until they verify
			 *  our credentials, when they proceed into WAIT_AUTH_2 and send SERVER to us. We then send BURST
			 *  + our netburst, which will put them into CONNECTED state. -- w
			 */
			if (command == "SERVER")
			{
				// Our credentials have been accepted, send netburst. (this puts US into the CONNECTED state)
				this->Outbound_Reply_Server(params);
			}
			else if (command == "ERROR")
			{
				this->Error(params);
			}
			else if (command == "CAPAB")
			{
				this->Capab(params);
			}
		break;
		case CONNECTED:
			/*
			 * State CONNECTED:
			 *  Credentials have been exchanged, we've gotten their 'BURST' (or sent ours).
			 *  Anything from here on should be accepted a little more reasonably.
			 */
			this->ProcessConnectedLine(prefix, command, params);
		break;
		case DYING:
		break;
	}
}
Esempio n. 28
0
/** Handle /INVITE
 */
CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, User *user)
{
	ModResult MOD_RESULT;

	if (parameters.size() == 2 || parameters.size() == 3)
	{
		User* u;
		if (IS_LOCAL(user))
			u = ServerInstance->FindNickOnly(parameters[0]);
		else
			u = ServerInstance->FindNick(parameters[0]);

		Channel* c = ServerInstance->FindChan(parameters[1]);
		time_t timeout = 0;
		if (parameters.size() == 3)
		{
			if (IS_LOCAL(user))
				timeout = ServerInstance->Time() + InspIRCd::Duration(parameters[1]);
			else
				timeout = ConvToInt(parameters[2]);
		}

		if ((!c) || (!u) || (u->registered != REG_ALL))
		{
			user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), c ? parameters[0].c_str() : parameters[1].c_str());
			return CMD_FAILURE;
		}

		if ((IS_LOCAL(user)) && (!c->HasUser(user)))
		{
			user->WriteNumeric(ERR_NOTONCHANNEL, "%s %s :You're not on that channel!",user->nick.c_str(), c->name.c_str());
			return CMD_FAILURE;
		}

		if (c->HasUser(u))
		{
			user->WriteNumeric(ERR_USERONCHANNEL, "%s %s %s :is already on channel",user->nick.c_str(),u->nick.c_str(),c->name.c_str());
			return CMD_FAILURE;
		}

		FIRST_MOD_RESULT(OnUserPreInvite, MOD_RESULT, (user,u,c,timeout));

		if (MOD_RESULT == MOD_RES_DENY)
		{
			return CMD_FAILURE;
		}
		else if (MOD_RESULT == MOD_RES_PASSTHRU)
		{
			if (IS_LOCAL(user))
			{
				unsigned int rank = c->GetPrefixValue(user);
				if (rank < HALFOP_VALUE)
				{
					// Check whether halfop mode is available and phrase error message accordingly
					ModeHandler* mh = ServerInstance->Modes->FindMode('h', MODETYPE_CHANNEL);
					user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must be a channel %soperator",
						user->nick.c_str(), c->name.c_str(), (mh && mh->name == "halfop" ? "half-" : ""));
					return CMD_FAILURE;
				}
			}
		}

		if (IS_LOCAL(u))
		{
			Invitation::Create(c, IS_LOCAL(u), timeout);
			u->WriteFrom(user,"INVITE %s :%s",u->nick.c_str(),c->name.c_str());
		}

		if (IS_LOCAL(user))
			user->WriteNumeric(RPL_INVITING, "%s %s %s",user->nick.c_str(),u->nick.c_str(),c->name.c_str());

		if (ServerInstance->Config->AnnounceInvites != ServerConfig::INVITE_ANNOUNCE_NONE)
		{
			char prefix;
			switch (ServerInstance->Config->AnnounceInvites)
			{
				case ServerConfig::INVITE_ANNOUNCE_OPS:
				{
					prefix = '@';
					break;
				}
				case ServerConfig::INVITE_ANNOUNCE_DYNAMIC:
				{
					PrefixMode* mh = ServerInstance->Modes->FindPrefixMode('h');
					prefix = (mh && mh->name == "halfop" ? mh->GetPrefix() : '@');
					break;
				}
				default:
				{
					prefix = 0;
					break;
				}
			}
			c->WriteAllExceptSender(user, true, prefix, "NOTICE %s :*** %s invited %s into the channel", c->name.c_str(), user->nick.c_str(), u->nick.c_str());
		}
		FOREACH_MOD(OnUserInvite, (user,u,c,timeout));
	}
	else if (IS_LOCAL(user))
	{
		// pinched from ircu - invite with not enough parameters shows channels
		// youve been invited to but haven't joined yet.
		InviteList& il = IS_LOCAL(user)->GetInviteList();
		for (InviteList::const_iterator i = il.begin(); i != il.end(); ++i)
		{
			user->WriteNumeric(RPL_INVITELIST, "%s :%s",user->nick.c_str(), (*i)->chan->name.c_str());
		}
		user->WriteNumeric(RPL_ENDOFINVITELIST, "%s :End of INVITE list",user->nick.c_str());
	}
	return CMD_SUCCESS;
}