示例#1
0
/**
 * Kill an client identified by its nick name.
 *
 * Please note that after killig a client, its CLIENT cond CONNECTION
 * structures are invalid. So the caller must make sure on its own not to
 * access data of probably killed clients after calling this function!
 *
 * @param Client The client from which the command leading to the KILL has
 *		been received, or NULL. The KILL will no be forwarded in this
 *		direction. Only relevant when From is set, too.
 * @param From The client from which the command originated, or NULL for
		the local server.
 * @param Nick The nick name to kill.
 * @param Reason Text to send as reason to the client and other servers.
 */
GLOBAL bool
IRC_KillClient(CLIENT *Client, CLIENT *From, const char *Nick, const char *Reason)
{
	const char *msg;
	CONN_ID my_conn, conn;
	CLIENT *c;

	/* Do we know such a client in the network? */
	c = Client_Search(Nick);
	if (!c) {
		LogDebug("Client with nick \"%s\" is unknown, not forwaring.", Nick);
		return CONNECTED;
	}

	/* Inform other servers */
	IRC_WriteStrServersPrefix(From ? Client : NULL,
				  From ? From : Client_ThisServer(),
				  "KILL %s :%s", Nick, Reason);

	if (Client_Type(c) != CLIENT_USER && Client_Type(c) != CLIENT_GOTNICK) {
		/* Target of this KILL is not a regular user, this is
		 * invalid! So we ignore this case if we received a
		 * regular KILL from the network and try to kill the
		 * client/connection anyway (but log an error!) if the
		 * origin is the local server. */

		if (Client != Client_ThisServer()) {
			/* Invalid KILL received from remote */
			if (Client_Type(c) == CLIENT_SERVER)
				msg = ERR_CANTKILLSERVER_MSG;
			else
				msg = ERR_NOPRIVILEGES_MSG;
			return IRC_WriteErrClient(Client, msg, Client_ID(Client));
		}

		Log(LOG_ERR,
		    "Got KILL for invalid client type: %d, \"%s\"!",
		    Client_Type(c), Nick);
	}

	/* Save ID of this connection */
	my_conn = Client_Conn(Client);

	/* Kill the client NOW:
	 *  - Close the local connection (if there is one),
	 *  - Destroy the CLIENT structure for remote clients.
	 * Note: Conn_Close() removes the CLIENT structure as well. */
	conn = Client_Conn(c);
	if(conn > NONE)
		Conn_Close(conn, NULL, Reason, true);
	else
		Client_Destroy(c, NULL, Reason, false);

	/* Are we still connected or were we killed, too? */
	if (my_conn > NONE && Conn_GetClient(my_conn))
		return CONNECTED;
	else
		return DISCONNECTED;
}
示例#2
0
文件: login.c 项目: LucentW/ngircd
/**
 * Finish client registration.
 *
 * Introduce the new client to the network and send all "hello messages"
 * to it after authentication has been succeeded.
 *
 * @param Client The client logging in.
 * @return CONNECTED or DISCONNECTED.
 */
GLOBAL bool
Login_User_PostAuth(CLIENT *Client)
{
	REQUEST Req;
	char modes[CLIENT_MODE_LEN + 1];

	assert(Client != NULL);

	if (Class_HandleServerBans(Client) != CONNECTED)
		return DISCONNECTED;

	Client_Introduce(NULL, Client, CLIENT_USER);

	if (!IRC_WriteStrClient
	    (Client, RPL_WELCOME_MSG, Client_ID(Client), Client_Mask(Client)))
		return false;
	if (!IRC_WriteStrClient
	    (Client, RPL_YOURHOST_MSG, Client_ID(Client),
	     Client_ID(Client_ThisServer()), PACKAGE_VERSION, HOST_CPU,
	     HOST_VENDOR, HOST_OS))
		return false;
	if (!IRC_WriteStrClient
	    (Client, RPL_CREATED_MSG, Client_ID(Client), NGIRCd_StartStr))
		return false;
	if (!IRC_WriteStrClient
	    (Client, RPL_MYINFO_MSG, Client_ID(Client),
	     Client_ID(Client_ThisServer()), PACKAGE_VERSION, USERMODES,
	     CHANMODES))
		return false;

	/* Features supported by this server (005 numeric, ISUPPORT),
	 * see <http://www.irc.org/tech_docs/005.html> for details. */
	if (!IRC_Send_ISUPPORT(Client))
		return DISCONNECTED;

	if (!IRC_Send_LUSERS(Client))
		return DISCONNECTED;
	if (!IRC_Show_MOTD(Client))
		return DISCONNECTED;

	/* Set default user modes */
	if (Conf_DefaultUserModes[0]) {
		snprintf(modes, sizeof(modes), "+%s", Conf_DefaultUserModes);
		Req.prefix = Client_ID(Client_ThisServer());
		Req.command = "MODE";
		Req.argc = 2;
		Req.argv[0] = Client_ID(Client);
		Req.argv[1] = modes;
		IRC_MODE(Client, &Req);
	} else
		IRC_SetPenalty(Client, 1);

	return CONNECTED;
}
示例#3
0
文件: numeric.c 项目: LucentW/ngircd
/**
 * Announce new server in the network
 * @param Client New server
 * @param Server Existing server in the network
 */
static bool
Announce_Server(CLIENT * Client, CLIENT * Server)
{
	CLIENT *c;

	if (Client_Conn(Server) > NONE) {
		/* Announce the new server to the one already registered
		 * which is directly connected to the local server */
		if (!IRC_WriteStrClient
		    (Server, "SERVER %s %d %d :%s", Client_ID(Client),
		     Client_Hops(Client) + 1, Client_MyToken(Client),
		     Client_Info(Client)))
			return DISCONNECTED;
	}

	if (Client_Hops(Server) == 1)
		c = Client_ThisServer();
	else
		c = Client_TopServer(Server);

	/* Inform new server about the one already registered in the network */
	return IRC_WriteStrClientPrefix(Client, c, "SERVER %s %d %d :%s",
		Client_ID(Server), Client_Hops(Server) + 1,
		Client_MyToken(Server), Client_Info(Server));
} /* Announce_Server */
示例#4
0
文件: client.c 项目: kazcw/pande
/**
 * Introduce a new user or service client in the network.
 *
 * @param From Remote server introducing the client or NULL (local).
 * @param Client New client.
 * @param Type Type of the client (CLIENT_USER or CLIENT_SERVICE).
 */
GLOBAL void
Client_Introduce(CLIENT *From, CLIENT *Client, int Type)
{
	/* Set client type (user or service) */
	Client_SetType(Client, Type);

	if (From) {
		if (Conf_NickIsService(Conf_GetServer(Client_Conn(From)),
				   Client_ID(Client)))
			Client_SetType(Client, CLIENT_SERVICE);
		LogDebug("%s \"%s\" (+%s) registered (via %s, on %s, %d hop%s).",
			 Client_TypeText(Client), Client_Mask(Client),
			 Client_Modes(Client), Client_ID(From),
			 Client_ID(Client_Introducer(Client)),
			 Client_Hops(Client), Client_Hops(Client) > 1 ? "s": "");
	} else {
		Log(LOG_NOTICE, "%s \"%s\" registered (connection %d).",
		    Client_TypeText(Client), Client_Mask(Client),
		    Client_Conn(Client));
		Log_ServerNotice('c', "Client connecting: %s (%s@%s) [%s] - %s",
			         Client_ID(Client), Client_User(Client),
				 Client_Hostname(Client),
				 Conn_IPA(Client_Conn(Client)),
				 Client_TypeText(Client));
	}

	/* Inform other servers */
	IRC_WriteStrServersPrefixFlag_CB(From,
				From != NULL ? From : Client_ThisServer(),
				'\0', cb_introduceClient, (void *)Client);
} /* Client_Introduce */
示例#5
0
文件: irc-mode.c 项目: LucentW/ngircd
/**
 * Handler for the IRC "MODE" command.
 *
 * This function detects whether user or channel modes should be modified
 * and calls the appropriate sub-functions.
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @return CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_MODE( CLIENT *Client, REQUEST *Req )
{
	CLIENT *cl, *origin;
	CHANNEL *chan;

	assert(Client != NULL);
	assert(Req != NULL);

	_IRC_GET_SENDER_OR_RETURN_(origin, Req, Client)

	/* Test for "fake" MODE commands injected by this local instance,
	 * for example when handling the "DefaultUserModes" settings.
	 * This doesn't harm real commands, because prefixes of regular
	 * clients are checked in Validate_Prefix() and can't be faked. */
	if (Req->prefix && Client_Search(Req->prefix) == Client_ThisServer())
		Client = Client_Search(Req->prefix);

	/* Channel or user mode? */
	cl = NULL; chan = NULL;
	if (Client_IsValidNick(Req->argv[0]))
		cl = Client_Search(Req->argv[0]);
	if (Channel_IsValidName(Req->argv[0]))
		chan = Channel_Search(Req->argv[0]);

	if (cl)
		return Client_Mode(Client, Req, origin, cl);
	if (chan)
		return Channel_Mode(Client, Req, origin, chan);

	/* No target found! */
	return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
			Client_ID(Client), Req->argv[0]);
} /* IRC_MODE */
示例#6
0
文件: irc.c 项目: ngircd/ngircd
/**
 * Handler for the IRC "KILL" command.
 *
 * This function implements the IRC command "KILL" which is used to selectively
 * disconnect clients. It can be used by IRC operators and servers, for example
 * to "solve" nick collisions after netsplits. See RFC 2812 section 3.7.1.
 *
 * Please note that this function is also called internally, without a real
 * KILL command being received over the network! Client is Client_ThisServer()
 * in this case, and the prefix in Req is NULL.
 *
 * @param Client The client from which this command has been received or
 * Client_ThisServer() when generated interanlly.
 * @param Req Request structure with prefix and all parameters.
 * @return CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_KILL(CLIENT *Client, REQUEST *Req)
{
	CLIENT *prefix;
	char reason[COMMAND_LEN];

	assert (Client != NULL);
	assert (Req != NULL);

	if (Client_Type(Client) != CLIENT_SERVER && !Op_Check(Client, Req))
		return Op_NoPrivileges(Client, Req);

	/* Get prefix (origin); use the client if no prefix is given. */
	if (Req->prefix)
		prefix = Client_Search(Req->prefix);
	else
		prefix = Client;

	/* Log a warning message and use this server as origin when the
	 * prefix (origin) is invalid. And this is the reason why we don't
	 * use the _IRC_GET_SENDER_OR_RETURN_ macro above! */
	if (!prefix) {
		Log(LOG_WARNING, "Got KILL with invalid prefix: \"%s\"!",
		    Req->prefix );
		prefix = Client_ThisServer();
	}

	if (Client != Client_ThisServer())
		Log(LOG_NOTICE|LOG_snotice,
		    "Got KILL command from \"%s\" for \"%s\": \"%s\".",
		    Client_Mask(prefix), Req->argv[0], Req->argv[1]);

	/* Build reason string: Prefix the "reason" if the originator is a
	 * regular user, so users can't spoof KILLs of servers. */
	if (Client_Type(Client) == CLIENT_USER)
		snprintf(reason, sizeof(reason), "KILLed by %s: %s",
			 Client_ID(Client), Req->argv[1]);
	else
		strlcpy(reason, Req->argv[1], sizeof(reason));

	return IRC_KillClient(Client, prefix, Req->argv[0], reason);
}
示例#7
0
static void
Dump_State(void)
{
    Log(LOG_DEBUG, "--- Internal server state: %s ---",
        Client_ID(Client_ThisServer()));
    Log(LOG_DEBUG, "time()=%ld", time(NULL));
    Conf_DebugDump();
    Conn_DebugDump();
    Client_DebugDump();
    Log(LOG_DEBUG, "--- End of state dump ---");
} /* Dump_State */
示例#8
0
文件: client.c 项目: kazcw/pande
/**
 * Search first CLIENT structure matching a given mask of a server.
 *
 * The order of servers is arbitrary, but this function makes sure that the
 * local server is always returned if the mask matches it.
 *
 * @return Pointer to CLIENT structure or NULL if no server could be found.
 */
GLOBAL CLIENT *
Client_SearchServer(const char *Mask)
{
	CLIENT *c;

	assert(Mask != NULL);

	/* First check if mask matches the local server */
	if (MatchCaseInsensitive(Mask, Client_ID(Client_ThisServer())))
		return Client_ThisServer();

	c = My_Clients;
	while (c) {
		if (Client_Type(c) == CLIENT_SERVER) {
			/* This is a server: check if Mask matches */
			if (MatchCaseInsensitive(Mask, c->id))
				return c;
		}
		c = (CLIENT *)c->next;
	}
	return NULL;
}
示例#9
0
文件: channel.c 项目: Flupsy/ngircd
/**
 * Check if a client is allowed to send to a specific channel.
 *
 * @param Chan The channel to check.
 * @param From The client that wants to send.
 * @return true if the client is allowed to send, false otherwise.
 */
static bool
Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
{
	bool is_member, has_voice, is_halfop, is_op, is_chanadmin, is_owner;

	is_member = has_voice = is_halfop = is_op = is_chanadmin = is_owner = false;

	/* The server itself always can send messages :-) */
	if (Client_ThisServer() == From)
		return true;

	if (Channel_IsMemberOf(Chan, From)) {
		is_member = true;
		if (Channel_UserHasMode(Chan, From, 'v'))
			has_voice = true;
		if (Channel_UserHasMode(Chan, From, 'h'))
			is_halfop = true;
		if (Channel_UserHasMode(Chan, From, 'o'))
			is_op = true;
		if (Channel_UserHasMode(Chan, From, 'a'))
			is_chanadmin = true;
		if (Channel_UserHasMode(Chan, From, 'q'))
			is_owner = true;
	}

	/*
	 * Is the client allowed to write to channel?
	 *
	 * If channel mode n set: non-members cannot send to channel.
	 * If channel mode m set: need voice.
	 */
	if (Channel_HasMode(Chan, 'n') && !is_member)
		return false;

	if (Channel_HasMode(Chan, 'M') && !Client_HasMode(From, 'R')
	    && !Client_HasMode(From, 'o'))
		return false;

	if (has_voice || is_halfop || is_op || is_chanadmin || is_owner)
		return true;

	if (Channel_HasMode(Chan, 'm'))
		return false;

	if (Lists_Check(&Chan->list_excepts, From))
		return true;

	return !Lists_Check(&Chan->list_bans, From);
}
示例#10
0
文件: channel.c 项目: Flupsy/ngircd
/**
 * Log a message to the local &SERVER channel, if it exists.
 */
GLOBAL void
Channel_LogServer(const char *msg)
{
	CHANNEL *sc;
	CLIENT *c;

	assert(msg != NULL);

	sc = Channel_Search("&SERVER");
	if (!sc)
		return;

	c = Client_ThisServer();
	Channel_Write(sc, c, c, "PRIVMSG", false, msg);
} /* Channel_LogServer */
示例#11
0
static void
Dump_State(void)
{
	Log(LOG_DEBUG, "--- Internal server state: %s ---",
	    Client_ID(Client_ThisServer()));
#ifdef HAVE_LONG_LONG
	Log(LOG_DEBUG, "time()=%llu", (unsigned long long)time(NULL));
#else
	Log(LOG_DEBUG, "time()=%lu", (unsigned long)time(NULL));
#endif
	Conf_DebugDump();
	Conn_DebugDump();
	Client_DebugDump();
	Log(LOG_DEBUG, "--- End of state dump ---");
} /* Dump_State */
示例#12
0
/**
 * Kill all users with a specific nick name in the network.
 *
 * @param Nick		Nick name.
 * @param Reason	Reason for the KILL.
 */
static void
Kill_Nick(char *Nick, char *Reason)
{
	REQUEST r;

	assert (Nick != NULL);
	assert (Reason != NULL);

	r.prefix = NULL;
	r.argv[0] = Nick;
	r.argv[1] = Reason;
	r.argc = 2;

	Log(LOG_ERR, "User(s) with nick \"%s\" will be disconnected: %s",
	    Nick, Reason);

	IRC_KILL(Client_ThisServer(), &r);
} /* Kill_Nick */
示例#13
0
文件: client.c 项目: kazcw/pande
/**
 * Update (and generate, if necessary) the cloaked hostname of a client.
 *
 * The newly set cloaked hostname is announced in the network using METADATA
 * commands to peers that support this feature.
 *
 * @param Client The client of which the cloaked hostname should be updated.
 * @param Origin The originator of the hostname change, or NULL if this server.
 * @param Hostname The new cloaked hostname, or NULL if it should be generated.
 */
GLOBAL void
Client_UpdateCloakedHostname(CLIENT *Client, CLIENT *Origin,
			     const char *Hostname)
{
	char Cloak_Buffer[CLIENT_HOST_LEN];

	assert(Client != NULL);
	if (!Origin)
		Origin = Client_ThisServer();

	if (!Client->cloaked) {
		Client->cloaked = malloc(CLIENT_HOST_LEN);
		if (!Client->cloaked)
			return;
	}

	if (!Hostname) {
		/* Generate new cloaked hostname */
		if (*Conf_CloakHostModeX) {
			strlcpy(Cloak_Buffer, Client->host,
				sizeof(Cloak_Buffer));
			strlcat(Cloak_Buffer, Conf_CloakHostSalt,
				sizeof(Cloak_Buffer));
			snprintf(Client->cloaked, CLIENT_HOST_LEN,
				 Conf_CloakHostModeX, Hash(Cloak_Buffer));
		} else
			strlcpy(Client->cloaked, Client_ID(Client->introducer),
				CLIENT_HOST_LEN);
	} else
		strlcpy(Client->cloaked, Hostname, CLIENT_HOST_LEN);
	LogDebug("Cloaked hostname of \"%s\" updated to \"%s\"",
		 Client_ID(Client), Client->cloaked);

	/* Inform other servers in the network */
	IRC_WriteStrServersPrefixFlag(Client_NextHop(Origin), Origin, 'M',
				      "METADATA %s cloakhost :%s",
				      Client_ID(Client), Client->cloaked);
}
示例#14
0
文件: channel.c 项目: Flupsy/ngircd
/**
 * Generate predefined persistent channels and &SERVER
 */
GLOBAL void
Channel_InitPredefined( void )
{
	CHANNEL *new_chan;
	const struct Conf_Channel *conf_chan;
	const char *c;
	size_t i, channel_count = array_length(&Conf_Channels, sizeof(*conf_chan));

	conf_chan = array_start(&Conf_Channels);

	assert(channel_count == 0 || conf_chan != NULL);

	for (i = 0; i < channel_count; i++, conf_chan++) {
		if (!conf_chan->name[0])
			continue;
		if (!Channel_IsValidName(conf_chan->name)) {
			Log(LOG_ERR,
			    "Can't create pre-defined channel: invalid name: \"%s\"",
			    conf_chan->name);
			continue;
		}

		new_chan = Channel_Search(conf_chan->name);
		if (new_chan) {
			Log(LOG_INFO,
			    "Can't create pre-defined channel \"%s\": name already in use.",
			    conf_chan->name);
			Set_KeyFile(new_chan, conf_chan->keyfile);
			continue;
		}

		new_chan = Channel_Create(conf_chan->name);
		if (!new_chan) {
			Log(LOG_ERR, "Can't create pre-defined channel \"%s\"!",
							conf_chan->name);
			continue;
		}
		Log(LOG_INFO, "Created pre-defined channel \"%s\".",
						conf_chan->name);

		Channel_ModeAdd(new_chan, 'P');

		if (conf_chan->topic[0])
			Channel_SetTopic(new_chan, NULL, conf_chan->topic);

		c = conf_chan->modes;
		while (*c)
			Channel_ModeAdd(new_chan, *c++);

		Channel_SetKey(new_chan, conf_chan->key);
		Channel_SetMaxUsers(new_chan, conf_chan->maxusers);
		Set_KeyFile(new_chan, conf_chan->keyfile);
	}
	if (channel_count)
		array_free(&Conf_Channels);

	/* Make sure the local &SERVER channel exists */
	if (!Channel_Search("&SERVER")) {
		new_chan = Channel_Create("&SERVER");
		if (new_chan) {
			Channel_SetModes(new_chan, "mnPt");
			Channel_SetTopic(new_chan, Client_ThisServer(),
					 "Server Messages");
		} else
			Log(LOG_ERR, "Failed to create \"&SERVER\" channel!");
	} else
		LogDebug("Required channel \"&SERVER\" already exists, ok.");
} /* Channel_InitPredefined */
示例#15
0
GLOBAL bool
IRC_NJOIN( CLIENT *Client, REQUEST *Req )
{
	char nick_in[COMMAND_LEN], nick_out[COMMAND_LEN], *channame, *ptr, modes[8];
	bool is_op, is_voiced;
	CHANNEL *chan;
	CLIENT *c;
	
	assert( Client != NULL );
	assert( Req != NULL );

	if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );

	strlcpy( nick_in, Req->argv[1], sizeof( nick_in ));
	strcpy( nick_out, "" );

	channame = Req->argv[0];
	ptr = strtok( nick_in, "," );
	while( ptr )
	{
		is_op = is_voiced = false;
		
		/* cut off prefixes */
		while(( *ptr == '@' ) || ( *ptr == '+' ))
		{
			if( *ptr == '@' ) is_op = true;
			if( *ptr == '+' ) is_voiced = true;
			ptr++;
		}

		c = Client_Search( ptr );
		if( c )
		{
			Channel_Join( c, channame );
			chan = Channel_Search( channame );
			assert( chan != NULL );
			
			if( is_op ) Channel_UserModeAdd( chan, c, 'o' );
			if( is_voiced ) Channel_UserModeAdd( chan, c, 'v' );

			/* announce to channel... */
			IRC_WriteStrChannelPrefix( Client, chan, c, false, "JOIN :%s", channame );

			/* set Channel-User-Modes */
			strlcpy( modes, Channel_UserModes( chan, c ), sizeof( modes ));
			if( modes[0] )
			{
				/* send modes to channel */
				IRC_WriteStrChannelPrefix( Client, chan, Client, false, "MODE %s +%s %s", channame, modes, Client_ID( c ));
			}

			if( nick_out[0] != '\0' ) strlcat( nick_out, ",", sizeof( nick_out ));
			if( is_op ) strlcat( nick_out, "@", sizeof( nick_out ));
			if( is_voiced ) strlcat( nick_out, "+", sizeof( nick_out ));
			strlcat( nick_out, ptr, sizeof( nick_out ));
		}
		else Log( LOG_ERR, "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!", ptr, channame );
		
		/* search for next Nick */
		ptr = strtok( NULL, "," );
	}

	/* forward to other servers */
	if( nick_out[0] != '\0' ) IRC_WriteStrServersPrefix( Client, Client_ThisServer( ), "NJOIN %s :%s", Req->argv[0], nick_out );

	return CONNECTED;
} /* IRC_NJOIN */
示例#16
0
/**
 * Handler for the IRC "TOPIC" command.
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @return CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_TOPIC( CLIENT *Client, REQUEST *Req )
{
	CHANNEL *chan;
	CLIENT *from;
	char *topic;
	bool r, topic_power;

	assert( Client != NULL );
	assert( Req != NULL );

	_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)

	chan = Channel_Search(Req->argv[0]);
	if (!chan)
		return IRC_WriteErrClient(from, ERR_NOSUCHCHANNEL_MSG,
					  Client_ID(from), Req->argv[0]);

	/* Only remote servers and channel members are allowed to change the
	 * channel topic, and IRC operators when the Conf_OperCanMode option
	 * is set in the server configuration. */
	if (Client_Type(Client) != CLIENT_SERVER) {
		topic_power = Client_HasMode(from, 'o');
		if (!Channel_IsMemberOf(chan, from)
		    && !(Conf_OperCanMode && topic_power))
			return IRC_WriteErrClient(from, ERR_NOTONCHANNEL_MSG,
						  Client_ID(from), Req->argv[0]);
	} else
		topic_power = true;

	if (Req->argc == 1) {
		/* Request actual topic */
		topic = Channel_Topic(chan);
		if (*topic) {
			r = IRC_WriteStrClient(from, RPL_TOPIC_MSG,
					       Client_ID(Client),
					       Channel_Name(chan), topic);
#ifndef STRICT_RFC
			if (!r)
				return r;
			r = IRC_WriteStrClient(from, RPL_TOPICSETBY_MSG,
					       Client_ID(Client),
					       Channel_Name(chan),
					       Channel_TopicWho(chan),
					       Channel_TopicTime(chan));
#endif
			return r;
		}
		else
			return IRC_WriteStrClient(from, RPL_NOTOPIC_MSG,
						  Client_ID(from),
						  Channel_Name(chan));
	}

	if (Channel_HasMode(chan, 't')) {
		/* Topic Lock. Is the user a channel op or IRC operator? */
		if(!topic_power &&
		   !Channel_UserHasMode(chan, from, 'h') &&
		   !Channel_UserHasMode(chan, from, 'o') &&
		   !Channel_UserHasMode(chan, from, 'a') &&
		   !Channel_UserHasMode(chan, from, 'q'))
			return IRC_WriteErrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
						  Client_ID(from),
						  Channel_Name(chan));
	}

	/* Set new topic */
	Channel_SetTopic(chan, from, Req->argv[1]);
	LogDebug("%s \"%s\" set topic on \"%s\": %s",
		 Client_TypeText(from), Client_Mask(from), Channel_Name(chan),
		 Req->argv[1][0] ? Req->argv[1] : "<none>");

	if (Conf_OperServerMode)
		from = Client_ThisServer();

	/* Update channel and forward new topic to other servers */
	if (!Channel_IsLocal(chan))
		IRC_WriteStrServersPrefix(Client, from, "TOPIC %s :%s",
					  Req->argv[0], Req->argv[1]);
	IRC_WriteStrChannelPrefix(Client, chan, from, false, "TOPIC %s :%s",
				  Req->argv[0], Req->argv[1]);

	if (Client_Type(Client) == CLIENT_USER)
		return IRC_WriteStrClientPrefix(Client, Client, "TOPIC %s :%s",
						Req->argv[0], Req->argv[1]);
	else
		return CONNECTED;
} /* IRC_TOPIC */
示例#17
0
/**
 * Handler for the IRC "PONG" command.
 *
 * See RFC 2812, 3.7.3 "Pong message".
 *
 * @param Client	The client from which this command has been received.
 * @param Req		Request structure with prefix and all parameters.
 * @returns		CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_PONG(CLIENT *Client, REQUEST *Req)
{
	CLIENT *target, *from;
	CONN_ID conn;
#ifndef STRICT_RFC
	long auth_ping;
#endif
	char *s;

	assert(Client != NULL);
	assert(Req != NULL);

	/* Wrong number of arguments? */
	if (Req->argc < 1) {
		if (Client_Type(Client) == CLIENT_USER)
			return IRC_WriteStrClient(Client, ERR_NOORIGIN_MSG,
						  Client_ID(Client));
		else
			return CONNECTED;
	}
	if (Req->argc > 2) {
		if (Client_Type(Client) == CLIENT_USER)
			return IRC_WriteStrClient(Client,
						  ERR_NEEDMOREPARAMS_MSG,
						  Client_ID(Client),
						  Req->command);
		else
			return CONNECTED;
	}

	/* Forward? */
	if (Req->argc == 2 && Client_Type(Client) == CLIENT_SERVER) {
		target = Client_Search(Req->argv[0]);
		if (!target)
			return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG,
					Client_ID(Client), Req->argv[0]);

		from = Client_Search(Req->prefix);

		if (target != Client_ThisServer() && target != from) {
			/* Ok, we have to forward the message. */
			if (!from)
				return IRC_WriteStrClient(Client,
						ERR_NOSUCHSERVER_MSG,
						Client_ID(Client), Req->prefix);

			if (Client_Type(Client_NextHop(target)) != CLIENT_SERVER)
				s = Client_ID(from);
			else
				s = Req->argv[0];
			return IRC_WriteStrClientPrefix(target, from,
				 "PONG %s :%s", s, Req->argv[1]);
		}
	}

	/* The connection timestamp has already been updated when the data has
	 * been read from so socket, so we don't need to update it here. */

	conn = Client_Conn(Client);

#ifndef STRICT_RFC
	/* Check authentication PING-PONG ... */
	auth_ping = Conn_GetAuthPing(conn);
	if (auth_ping) {
		LogDebug("AUTH PONG: waiting for token \"%ld\", got \"%s\" ...",
			 auth_ping, Req->argv[0]);
		if (auth_ping == atoi(Req->argv[0])) {
			Conn_SetAuthPing(conn, 0);
			if (Client_Type(Client) == CLIENT_WAITAUTHPING)
				Login_User(Client);
		} else
			if (!IRC_WriteStrClient(Client,
					"To connect, type /QUOTE PONG %ld",
					auth_ping))
				return DISCONNECTED;
	}
#endif

	if (Client_Type(Client) == CLIENT_SERVER && Conn_LastPing(conn) == 0) {
		Log(LOG_INFO,
		    "Synchronization with \"%s\" done (connection %d): %ld seconds [%ld users, %ld channels]",
		    Client_ID(Client), conn, time(NULL) - Conn_GetSignon(conn),
		    Client_UserCount(), Channel_CountVisible(NULL));
		Conn_UpdatePing(conn);
	} else
		LogDebug("Connection %d: received PONG. Lag: %ld seconds.",
			 conn, time(NULL) - Conn_LastPing(conn));

	return CONNECTED;
} /* IRC_PONG */
示例#18
0
文件: irc.c 项目: mguindin/ngircd
/**
 * Handler for the IRC "KILL" command.
 *
 * This function implements the IRC command "KILL" wich is used to selectively
 * disconnect clients. It can be used by IRC operators and servers, for example
 * to "solve" nick collisions after netsplits. See RFC 2812 section 3.7.1.
 *
 * Please note that this function is also called internally, without a real
 * KILL command being received over the network! Client is Client_ThisServer()
 * in this case, and the prefix in Req is NULL.
 *
 * @param Client	The client from which this command has been received
 *			or Client_ThisServer() when generated interanlly.
 * @param Req		Request structure with prefix and all parameters.
 * @returns		CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_KILL( CLIENT *Client, REQUEST *Req )
{
	CLIENT *prefix, *c;
	char reason[COMMAND_LEN], *msg;
	CONN_ID my_conn, conn;

	assert (Client != NULL);
	assert (Req != NULL);

	if (Client_Type(Client) != CLIENT_SERVER && !Client_OperByMe(Client))
		return IRC_WriteStrClient(Client, ERR_NOPRIVILEGES_MSG,
					  Client_ID(Client));

	if (Req->argc != 2)
		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
					  Client_ID(Client), Req->command);

	/* Get prefix (origin); use the client if no prefix is given. */
	if (Req->prefix)
		prefix = Client_Search(Req->prefix);
	else
		prefix = Client;

	/* Log a warning message and use this server as origin when the
	 * prefix (origin) is invalid. */
	if (!prefix) {
		Log(LOG_WARNING, "Got KILL with invalid prefix: \"%s\"!",
		    Req->prefix );
		prefix = Client_ThisServer();
	}

	if (Client != Client_ThisServer())
		Log(LOG_NOTICE|LOG_snotice,
		    "Got KILL command from \"%s\" for \"%s\": %s",
		    Client_Mask(prefix), Req->argv[0], Req->argv[1]);

	/* Build reason string: Prefix the "reason" if the originator is a
	 * regular user, so users can't spoof KILLs of servers. */
	if (Client_Type(Client) == CLIENT_USER)
		snprintf(reason, sizeof(reason), "KILLed by %s: %s",
			 Client_ID(Client), Req->argv[1]);
	else
		strlcpy(reason, Req->argv[1], sizeof(reason));

	/* Inform other servers */
	IRC_WriteStrServersPrefix(Client, prefix, "KILL %s :%s",
				  Req->argv[0], reason);

	/* Save ID of this connection */
	my_conn = Client_Conn( Client );

	/* Do we host such a client? */
	c = Client_Search( Req->argv[0] );
	if( c )
	{
		if(( Client_Type( c ) != CLIENT_USER ) &&
		   ( Client_Type( c ) != CLIENT_GOTNICK ))
		{
			/* Target of this KILL is not a regular user, this is
			 * invalid! So we ignore this case if we received a
			 * regular KILL from the network and try to kill the
			 * client/connection anyway (but log an error!) if the
			 * origin is the local server. */

			if( Client != Client_ThisServer( ))
			{
				/* Invalid KILL received from remote */
				if( Client_Type( c ) == CLIENT_SERVER )
					msg = ERR_CANTKILLSERVER_MSG;
				else
					msg = ERR_NOPRIVILEGES_MSG;
				return IRC_WriteStrClient( Client, msg,
					Client_ID( Client ));
			}

			Log( LOG_ERR, "Got KILL for invalid client type: %d, \"%s\"!",
			     Client_Type( c ), Req->argv[0] );
		}

		/* Kill the client NOW:
		 *  - Close the local connection (if there is one),
		 *  - Destroy the CLIENT structure for remote clients.
		 * Note: Conn_Close() removes the CLIENT structure as well. */
		conn = Client_Conn( c );
		if(conn > NONE)
			Conn_Close(conn, NULL, reason, true);
		else
			Client_Destroy(c, NULL, reason, false);
	}
	else
		Log( LOG_NOTICE, "Client with nick \"%s\" is unknown here.", Req->argv[0] );

	/* Are we still connected or were we killed, too? */
	if(( my_conn > NONE ) && ( Conn_GetClient( my_conn )))
		return CONNECTED;
	else
		return DISCONNECTED;
} /* IRC_KILL */
示例#19
0
/**
 * Handler for the IRC "LIST" command.
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @return CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_LIST( CLIENT *Client, REQUEST *Req )
{
	char *pattern;
	CHANNEL *chan;
	CLIENT *from, *target;
	int count = 0;

	assert(Client != NULL);
	assert(Req != NULL);

	_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)

	if (Req->argc > 0)
		pattern = strtok(Req->argv[0], ",");
	else
		pattern = "*";

	if (Req->argc == 2) {
		/* Forward to other server? */
		target = Client_Search(Req->argv[1]);
		if (! target || Client_Type(target) != CLIENT_SERVER)
			return IRC_WriteErrClient(from, ERR_NOSUCHSERVER_MSG,
						  Client_ID(Client),
						  Req->argv[1]);

		if (target != Client_ThisServer()) {
			/* Target is indeed an other server, forward it! */
			return IRC_WriteStrClientPrefix(target, from,
							"LIST %s :%s",
							Req->argv[0],
							Req->argv[1]);
		}
	}

	while (pattern) {
		/* Loop through all the channels */
		if (Req->argc > 0)
			ngt_LowerStr(pattern);
		chan = Channel_First();
		while (chan) {
			/* Check search pattern */
			if (MatchCaseInsensitive(pattern, Channel_Name(chan))) {
				/* Gotcha! */
				if (!Channel_HasMode(chan, 's')
				    || Channel_IsMemberOf(chan, from)
				    || (!Conf_MorePrivacy
					&& Client_HasMode(Client, 'o')
					&& Client_Conn(Client) > NONE))
				{
					if ((Conf_MaxListSize > 0)
					    && IRC_CheckListTooBig(from, count,
								   Conf_MaxListSize,
								   "LIST"))
						break;
					if (!IRC_WriteStrClient(from,
					     RPL_LIST_MSG, Client_ID(from),
					     Channel_Name(chan),
					     Channel_MemberCount(chan),
					     Channel_Topic( chan )))
						return DISCONNECTED;
					count++;
				}
			}
			chan = Channel_Next(chan);
		}

		/* Get next name ... */
		if(Req->argc > 0)
			pattern = strtok(NULL, ",");
		else
			pattern = NULL;
	}

	return IRC_WriteStrClient(from, RPL_LISTEND_MSG, Client_ID(from));
} /* IRC_LIST */
示例#20
0
文件: numeric.c 项目: LucentW/ngircd
/**
 * Handle ENDOFMOTD (376) numeric and login remote server.
 * The peer is either an IRC server (no IRC+ protocol), or we got the
 * ENDOFMOTD numeric from an IRC+ server. We have to register the new server.
 */
GLOBAL bool
IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req)
{
	int max_hops, i;
	CLIENT *c;
	CHANNEL *chan;

	Client_SetType(Client, CLIENT_SERVER);

	Log(LOG_NOTICE | LOG_snotice,
	    "Server \"%s\" registered (connection %d, 1 hop - direct link).",
	    Client_ID(Client), Client_Conn(Client));

	/* Get highest hop count */
	max_hops = 0;
	c = Client_First();
	while (c) {
		if (Client_Hops(c) > max_hops)
			max_hops = Client_Hops(c);
		c = Client_Next(c);
	}

	/* Inform the new server about all other servers, and announce the
	 * new server to all the already registered ones. Important: we have
	 * to do this "in order" and can't introduce servers of which the
	 * "toplevel server" isn't known already. */
	for (i = 0; i < (max_hops + 1); i++) {
		for (c = Client_First(); c != NULL; c = Client_Next(c)) {
			if (Client_Type(c) != CLIENT_SERVER)
				continue;	/* not a server */
			if (Client_Hops(c) != i)
				continue;	/* not actual "nesting level" */
			if (c == Client || c == Client_ThisServer())
				continue;	/* that's us or the peer! */

			if (!Announce_Server(Client, c))
				return DISCONNECTED;
		}
	}

	/* Announce all the users to the new server */
	c = Client_First();
	while (c) {
		if (Client_Type(c) == CLIENT_USER ||
		    Client_Type(c) == CLIENT_SERVICE) {
			if (!Client_Announce(Client, Client_ThisServer(), c))
				return DISCONNECTED;
		}
		c = Client_Next(c);
	}

	/* Announce all channels to the new server */
	chan = Channel_First();
	while (chan) {
		if (Channel_IsLocal(chan)) {
			chan = Channel_Next(chan);
			continue;
		}
#ifdef IRCPLUS
		/* Send CHANINFO if the peer supports it */
		if (Client_HasFlag(Client, 'C')) {
			if (!Send_CHANINFO(Client, chan))
				return DISCONNECTED;
		}
#endif

		if (!Announce_Channel(Client, chan))
			return DISCONNECTED;

		/* Get next channel ... */
		chan = Channel_Next(chan);
	}

#ifdef IRCPLUS
	if (Client_HasFlag(Client, 'L')) {
		LogDebug("Synchronizing INVITE- and BAN-lists ...");
		if (!Synchronize_Lists(Client))
			return DISCONNECTED;
	}
#endif

	if (!IRC_WriteStrClient(Client, "PING :%s",
	    Client_ID(Client_ThisServer())))
		return DISCONNECTED;

	return CONNECTED;
} /* IRC_Num_ENDOFMOTD */
示例#21
0
文件: irc-mode.c 项目: LucentW/ngircd
/**
 * Handle channel mode and channel-user mode changes
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @param Origin The originator of the MODE command (prefix).
 * @param Channel The target channel of this MODE command.
 * @return CONNECTED or DISCONNECTED.
 */
static bool
Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
{
	char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2],
	    argadd[CLIENT_PASS_LEN], *mode_ptr;
	bool connected, set, skiponce, retval, use_servermode,
	     is_halfop, is_op, is_admin, is_owner, is_machine, is_oper;
	int mode_arg, arg_arg, mode_arg_count = 0;
	CLIENT *client;
	long l;
	size_t len;

	is_halfop = is_op = is_admin = is_owner = is_machine = is_oper = false;

	if (Channel_IsModeless(Channel))
		return IRC_WriteErrClient(Client, ERR_NOCHANMODES_MSG,
				Client_ID(Client), Channel_Name(Channel));

	/* Mode request: let's answer it :-) */
	if (Req->argc <= 1)
		return Channel_Mode_Answer_Request(Origin, Channel);

	/* Check if origin is oper and opers can use mode */
	use_servermode = Conf_OperServerMode;
	if(Client_HasMode(Client, 'o') && Conf_OperCanMode) {
		is_oper = true;
	}

	/* Check if client is a server/service */
	if(Client_Type(Client) == CLIENT_SERVER ||
	   Client_Type(Client) == CLIENT_SERVICE) {
		is_machine = true;
	}

	/* Check if client is member of channel or an oper or an server/service */
	if(!Channel_IsMemberOf(Channel, Client) && !is_oper && !is_machine)
		return IRC_WriteErrClient(Origin, ERR_NOTONCHANNEL_MSG,
					  Client_ID(Origin),
					  Channel_Name(Channel));

	mode_arg = 1;
	mode_ptr = Req->argv[mode_arg];
	if (Req->argc > mode_arg + 1)
		arg_arg = mode_arg + 1;
	else
		arg_arg = -1;

	/* Initial state: set or unset modes? */
	skiponce = false;
	switch (*mode_ptr) {
	case '-':
		set = false;
		break;
	case '+':
		set = true;
		break;
	default:
		set = true;
		skiponce = true;
	}

	/* Prepare reply string */
	strcpy(the_modes, set ? "+" : "-");
	the_args[0] = '\0';

	x[1] = '\0';
	connected = CONNECTED;
	while (mode_ptr) {
		if (!skiponce)
			mode_ptr++;
		if (!*mode_ptr) {
			/* Try next argument if there's any */
			if (arg_arg < 0)
				break;
			if (arg_arg > mode_arg)
				mode_arg = arg_arg;
			else
				mode_arg++;

			if (mode_arg >= Req->argc)
				break;
			mode_ptr = Req->argv[mode_arg];

			if (Req->argc > mode_arg + 1)
				arg_arg = mode_arg + 1;
			else
				arg_arg = -1;
		}
		skiponce = false;

		switch (*mode_ptr) {
		case '+':
		case '-':
			if (((*mode_ptr == '+') && !set)
			    || ((*mode_ptr == '-') && set)) {
				/* Action modifier ("+"/"-") must be changed ... */
				len = strlen(the_modes) - 1;
				if (the_modes[len] == '+' || the_modes[len] == '-') {
					/* Adjust last action modifier in result */
					the_modes[len] = *mode_ptr;
				} else {
					/* Append modifier character to result string */
					x[0] = *mode_ptr;
					strlcat(the_modes, x, sizeof(the_modes));
				}
				set = *mode_ptr == '+';
			}
			continue;
		}

		/* Are there arguments left? */
		if (arg_arg >= Req->argc)
			arg_arg = -1;

		if(!is_machine && !is_oper) {
			if (Channel_UserHasMode(Channel, Client, 'q'))
				is_owner = true;
			if (Channel_UserHasMode(Channel, Client, 'a'))
				is_admin = true;
			if (Channel_UserHasMode(Channel, Client, 'o'))
				is_op = true;
			if (Channel_UserHasMode(Channel, Client, 'h'))
				is_halfop = true;
		}

		/* Validate modes */
		x[0] = '\0';
		argadd[0] = '\0';
		client = NULL;
		switch (*mode_ptr) {
		/* --- Channel modes --- */
		case 'R': /* Registered users only */
		case 's': /* Secret channel */
		case 'z': /* Secure connections only */
			if(!is_oper && !is_machine && !is_owner &&
			   !is_admin && !is_op) {
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPRIVSNEEDED_MSG,
					Client_ID(Origin), Channel_Name(Channel));
				goto chan_exit;
			}
		case 'i': /* Invite only */
		case 'V': /* Invite disallow */
		case 'M': /* Only identified nicks can write */
		case 'm': /* Moderated */
		case 'n': /* Only members can write */
		case 'N': /* Can't change nick while on this channel */
		case 'Q': /* No kicks */
		case 't': /* Topic locked */
			if(is_oper || is_machine || is_owner ||
			   is_admin || is_op || is_halfop)
				x[0] = *mode_ptr;
			else
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPRIVSNEEDED_MSG,
					Client_ID(Origin), Channel_Name(Channel));
			break;
		case 'k': /* Channel key */
			if (Mode_Limit_Reached(Client, mode_arg_count++))
				goto chan_exit;
			if (!set) {
				if (is_oper || is_machine || is_owner ||
				    is_admin || is_op || is_halfop) {
					x[0] = *mode_ptr;
					if (Channel_HasMode(Channel, 'k'))
						strlcpy(argadd, "*", sizeof(argadd));
					if (arg_arg > mode_arg)
						arg_arg++;
				} else
					connected = IRC_WriteErrClient(Origin,
						ERR_CHANOPRIVSNEEDED_MSG,
						Client_ID(Origin),
						Channel_Name(Channel));
				break;
			}
			if (arg_arg > mode_arg) {
				if (is_oper || is_machine || is_owner ||
				    is_admin || is_op || is_halfop) {
					Channel_ModeDel(Channel, 'k');
					Channel_SetKey(Channel,
						       Req->argv[arg_arg]);
					strlcpy(argadd, Channel_Key(Channel),
						sizeof(argadd));
					x[0] = *mode_ptr;
				} else {
					connected = IRC_WriteErrClient(Origin,
						ERR_CHANOPRIVSNEEDED_MSG,
						Client_ID(Origin),
						Channel_Name(Channel));
				}
				Req->argv[arg_arg][0] = '\0';
				arg_arg++;
			} else {
#ifdef STRICT_RFC
				/* Only send error message in "strict" mode,
				 * this is how ircd2.11 and others behave ... */
				connected = IRC_WriteErrClient(Origin,
					ERR_NEEDMOREPARAMS_MSG,
					Client_ID(Origin), Req->command);
#endif
				goto chan_exit;
			}
			break;
		case 'l': /* Member limit */
			if (Mode_Limit_Reached(Client, mode_arg_count++))
				goto chan_exit;
			if (!set) {
				if (is_oper || is_machine || is_owner ||
				    is_admin || is_op || is_halfop)
					x[0] = *mode_ptr;
				else
					connected = IRC_WriteErrClient(Origin,
						ERR_CHANOPRIVSNEEDED_MSG,
						Client_ID(Origin),
						Channel_Name(Channel));
				break;
			}
			if (arg_arg > mode_arg) {
				if (is_oper || is_machine || is_owner ||
				    is_admin || is_op || is_halfop) {
					l = atol(Req->argv[arg_arg]);
					if (l > 0 && l < 0xFFFF) {
						Channel_ModeDel(Channel, 'l');
						Channel_SetMaxUsers(Channel, l);
						snprintf(argadd, sizeof(argadd),
							 "%ld", l);
						x[0] = *mode_ptr;
					}
				} else {
					connected = IRC_WriteErrClient(Origin,
						ERR_CHANOPRIVSNEEDED_MSG,
						Client_ID(Origin),
						Channel_Name(Channel));
				}
				Req->argv[arg_arg][0] = '\0';
				arg_arg++;
			} else {
#ifdef STRICT_RFC
				/* Only send error message in "strict" mode,
				 * this is how ircd2.11 and others behave ... */
				connected = IRC_WriteErrClient(Origin,
					ERR_NEEDMOREPARAMS_MSG,
					Client_ID(Origin), Req->command);
#endif
				goto chan_exit;
			}
			break;
		case 'O': /* IRC operators only */
			if (set) {
				/* Only IRC operators are allowed to
				 * set the 'O' channel mode! */
				if(is_oper || is_machine)
					x[0] = 'O';
				else
					connected = IRC_WriteErrClient(Origin,
						ERR_NOPRIVILEGES_MSG,
						Client_ID(Origin));
			} else if(is_oper || is_machine || is_owner ||
				  is_admin || is_op)
				x[0] = 'O';
			else
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPRIVSNEEDED_MSG,
					Client_ID(Origin),
					Channel_Name(Channel));
			break;
		case 'P': /* Persistent channel */
			if (set) {
				/* Only IRC operators are allowed to
				 * set the 'P' channel mode! */
				if(is_oper || is_machine)
					x[0] = 'P';
				else
					connected = IRC_WriteErrClient(Origin,
						ERR_NOPRIVILEGES_MSG,
						Client_ID(Origin));
			} else if(is_oper || is_machine || is_owner ||
				  is_admin || is_op)
				x[0] = 'P';
			else
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPRIVSNEEDED_MSG,
					Client_ID(Origin),
					Channel_Name(Channel));
			break;
		/* --- Channel user modes --- */
		case 'q': /* Owner */
		case 'a': /* Channel admin */
			if(!is_oper && !is_machine && !is_owner && !is_admin) {
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPPRIVTOOLOW_MSG,
					Client_ID(Origin),
					Channel_Name(Channel));
				goto chan_exit;
			}
		case 'o': /* Channel operator */
			if(!is_oper && !is_machine && !is_owner &&
			   !is_admin && !is_op) {
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPRIVSNEEDED_MSG,
					Client_ID(Origin),
					Channel_Name(Channel));
				goto chan_exit;
			}
		case 'h': /* Half Op */
			if(!is_oper && !is_machine && !is_owner &&
			   !is_admin && !is_op) {
				connected = IRC_WriteErrClient(Origin,
					ERR_CHANOPRIVSNEEDED_MSG,
					Client_ID(Origin),
					Channel_Name(Channel));
				goto chan_exit;
			}
		case 'v': /* Voice */
			if (arg_arg > mode_arg) {
				if (is_oper || is_machine || is_owner ||
				    is_admin || is_op || is_halfop) {
					client = Client_Search(Req->argv[arg_arg]);
					if (client)
						x[0] = *mode_ptr;
					else
						connected = IRC_WriteErrClient(Origin,
							ERR_NOSUCHNICK_MSG,
							Client_ID(Origin),
							Req->argv[arg_arg]);
				} else {
					connected = IRC_WriteErrClient(Origin,
						ERR_CHANOPRIVSNEEDED_MSG,
						Client_ID(Origin),
						Channel_Name(Channel));
				}
				Req->argv[arg_arg][0] = '\0';
				arg_arg++;
			} else {
#ifdef STRICT_RFC
				/* Report an error to the client, when a user
				 * mode should be changed but no nickname is
				 * given. But don't do it when not in "strict"
				 * mode, because most other servers don't do
				 * it as well and some clients send "wired"
				 * MODE commands like "MODE #chan -ooo nick". */
				connected = IRC_WriteErrClient(Origin,
					ERR_NEEDMOREPARAMS_MSG,
					Client_ID(Origin), Req->command);
#endif
				goto chan_exit;
			}
			break;
		/* --- Channel lists --- */
		case 'I': /* Invite lists */
		case 'b': /* Ban lists */
		case 'e': /* Channel exception lists */
			if (Mode_Limit_Reached(Client, mode_arg_count++))
				goto chan_exit;
			if (arg_arg > mode_arg) {
				/* modify list */
				if (is_oper || is_machine || is_owner ||
				    is_admin || is_op || is_halfop) {
					connected = set
					   ? Add_To_List(*mode_ptr, Origin,
						Client, Channel,
						Req->argv[arg_arg])
					   : Del_From_List(*mode_ptr, Origin,
						Client, Channel,
						Req->argv[arg_arg]);
				} else {
					connected = IRC_WriteErrClient(Origin,
						ERR_CHANOPRIVSNEEDED_MSG,
						Client_ID(Origin),
						Channel_Name(Channel));
				}
				Req->argv[arg_arg][0] = '\0';
				arg_arg++;
			} else {
				switch (*mode_ptr) {
				case 'I':
					Channel_ShowInvites(Origin, Channel);
					break;
				case 'b':
					Channel_ShowBans(Origin, Channel);
					break;
				case 'e':
					Channel_ShowExcepts(Origin, Channel);
					break;
				}
			}
			break;
		default:
			if (Client_Type(Client) != CLIENT_SERVER) {
				Log(LOG_DEBUG,
				    "Unknown mode \"%c%c\" from \"%s\" on %s!?",
				    set ? '+' : '-', *mode_ptr,
				    Client_ID(Origin), Channel_Name(Channel));
				connected = IRC_WriteErrClient(Origin,
					ERR_UNKNOWNMODE_MSG,
					Client_ID(Origin), *mode_ptr,
					Channel_Name(Channel));
				x[0] = '\0';
			} else {
				Log(LOG_DEBUG,
				    "Handling unknown mode \"%c%c\" from \"%s\" on %s ...",
				    set ? '+' : '-', *mode_ptr,
				    Client_ID(Origin), Channel_Name(Channel));
				x[0] = *mode_ptr;
			}
		}

		if (!connected)
			break;

		/* Is there a valid mode change? */
		if (!x[0])
			continue;

		/* Validate target client */
		if (client && (!Channel_IsMemberOf(Channel, client))) {
			if (!IRC_WriteErrClient(Origin, ERR_USERNOTINCHANNEL_MSG,
						Client_ID(Origin),
						Client_ID(client),
						Channel_Name(Channel)))
				break;
			continue;
		}

		if (client) {
			/* Channel-User-Mode */
			retval = set
			       ? Channel_UserModeAdd(Channel, client, x[0])
			       : Channel_UserModeDel(Channel, client, x[0]);
			if (retval) {
				strlcat(the_args, " ", sizeof(the_args));
				strlcat(the_args, Client_ID(client),
					sizeof(the_args));
				strlcat(the_modes, x, sizeof(the_modes));
				LogDebug
				    ("User \"%s\": Mode change on %s, now \"%s\"",
				     Client_Mask(client), Channel_Name(Channel),
				     Channel_UserModes(Channel, client));
			}
		} else {
			/* Channel-Mode */
			retval = set
			       ? Channel_ModeAdd(Channel, x[0])
			       : Channel_ModeDel(Channel, x[0]);
			if (retval) {
				strlcat(the_modes, x, sizeof(the_modes));
				LogDebug("Channel %s: Mode change, now \"%s\".",
					 Channel_Name(Channel),
					 Channel_Modes(Channel));
			}
		}

		/* Are there additional arguments to add? */
		if (argadd[0]) {
			strlcat(the_args, " ", sizeof(the_args));
			strlcat(the_args, argadd, sizeof(the_args));
		}
	}

      chan_exit:
	/* Are there changed modes? */
	if (the_modes[1]) {
		/* Clean up mode string */
		len = strlen(the_modes) - 1;
		if ((the_modes[len] == '+') || (the_modes[len] == '-'))
			the_modes[len] = '\0';

		if (Client_Type(Client) == CLIENT_SERVER) {
			/* MODE requests for local channels from other servers
			 * are definitely invalid! */
			if (Channel_IsLocal(Channel)) {
				Log(LOG_ALERT, "Got remote MODE command for local channel!? Ignored.");
				return CONNECTED;
			}

			/* Forward mode changes to channel users and all the
			 * other remote servers: */
			IRC_WriteStrServersPrefix(Client, Origin,
				"MODE %s %s%s", Channel_Name(Channel),
				the_modes, the_args);
			IRC_WriteStrChannelPrefix(Client, Channel, Origin,
				false, "MODE %s %s%s", Channel_Name(Channel),
				the_modes, the_args);
		} else {
			if (use_servermode)
				Origin = Client_ThisServer();
			/* Send reply to client and inform other servers and channel users */
			connected = IRC_WriteStrClientPrefix(Client, Origin,
					"MODE %s %s%s", Channel_Name(Channel),
					the_modes, the_args);
			/* Only forward requests for non-local channels */
			if (!Channel_IsLocal(Channel))
				IRC_WriteStrServersPrefix(Client, Origin,
					"MODE %s %s%s", Channel_Name(Channel),
					the_modes, the_args);
			IRC_WriteStrChannelPrefix(Client, Channel, Origin,
				false, "MODE %s %s%s", Channel_Name(Channel),
				the_modes, the_args);
		}
	}

	return connected;
} /* Channel_Mode */
示例#22
0
文件: irc.c 项目: ngircd/ngircd
/*
 * Handler for the IRC "TRACE" command.
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @return CONNECTED or DISCONNECTED.
 */
 GLOBAL bool
IRC_TRACE(CLIENT *Client, REQUEST *Req)
{
	CLIENT *from, *target, *c;
	CONN_ID idx, idx2;
	char user[CLIENT_USER_LEN];

	assert(Client != NULL);
	assert(Req != NULL);

	_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
	_IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from)

	/* Forward command to other server? */
	if (target != Client_ThisServer()) {
		/* Send RPL_TRACELINK back to initiator */
		idx = Client_Conn(Client);
		assert(idx > NONE);
		idx2 = Client_Conn(Client_NextHop(target));
		assert(idx2 > NONE);

		if (!IRC_WriteStrClient(from, RPL_TRACELINK_MSG,
					Client_ID(from), PACKAGE_NAME,
					PACKAGE_VERSION, Client_ID(target),
					Client_ID(Client_NextHop(target)),
					Option_String(idx2),
					(long)(time(NULL) - Conn_StartTime(idx2)),
					Conn_SendQ(idx), Conn_SendQ(idx2)))
			return DISCONNECTED;

		/* Forward command */
		IRC_WriteStrClientPrefix(target, from, "TRACE %s", Req->argv[0]);
		return CONNECTED;
	}

	/* Infos about all connected servers */
	c = Client_First();
	while (c) {
		if (Client_Conn(c) > NONE) {
			/* Local client */
			if (Client_Type(c) == CLIENT_SERVER) {
				/* Server link */
				strlcpy(user, Client_User(c), sizeof(user));
				if (user[0] == '~')
					strlcpy(user, "unknown", sizeof(user));
				if (!IRC_WriteStrClient(from,
						RPL_TRACESERVER_MSG,
						Client_ID(from), Client_ID(c),
						user, Client_Hostname(c),
						Client_Mask(Client_ThisServer()),
						Option_String(Client_Conn(c))))
					return DISCONNECTED;
			}
			if (Client_Type(c) == CLIENT_USER
			    && Client_HasMode(c, 'o')) {
				/* IRC Operator */
				if (!IRC_WriteStrClient(from,
						RPL_TRACEOPERATOR_MSG,
						Client_ID(from), Client_ID(c)))
					return DISCONNECTED;
			}
		}
		c = Client_Next( c );
	}

	return IRC_WriteStrClient(from, RPL_TRACEEND_MSG, Client_ID(from),
				  Conf_ServerName, PACKAGE_NAME,
				  PACKAGE_VERSION, NGIRCd_DebugLevel);
} /* IRC_TRACE */
示例#23
0
/**
 * Handler for the IRC command "SQUIT".
 * See RFC 2813 section 4.1.2 and RFC 2812 section 3.1.8.
 */
GLOBAL bool
IRC_SQUIT(CLIENT * Client, REQUEST * Req)
{
	char msg[COMMAND_LEN], logmsg[COMMAND_LEN];
	CLIENT *from, *target;
	CONN_ID con;
	int loglevel;

	assert(Client != NULL);
	assert(Req != NULL);

	if (Client_Type(Client) != CLIENT_SERVER
	    && !Client_HasMode(Client, 'o'))
		return Op_NoPrivileges(Client, Req);

	/* Bad number of arguments? */
	if (Req->argc != 2)
		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
					  Client_ID(Client), Req->command);

	if (Client_Type(Client) == CLIENT_SERVER && Req->prefix) {
		from = Client_Search(Req->prefix);
		if (Client_Type(from) != CLIENT_SERVER
		    && !Op_Check(Client, Req))
			return Op_NoPrivileges(Client, Req);
	} else
		from = Client;
	if (!from)
		return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
					  Client_ID(Client), Req->prefix);

	if (Client_Type(Client) == CLIENT_USER)
		loglevel = LOG_NOTICE | LOG_snotice;
	else
		loglevel = LOG_DEBUG;
	Log(loglevel, "Got SQUIT from %s for \"%s\": \"%s\" ...",
	    Client_ID(from), Req->argv[0], Req->argv[1]);

	target = Client_Search(Req->argv[0]);
	if (Client_Type(Client) != CLIENT_SERVER &&
	    target == Client_ThisServer())
		return Op_NoPrivileges(Client, Req);
	if (!target) {
		/* The server is (already) unknown */
		Log(LOG_WARNING,
		    "Got SQUIT from %s for unknown server \"%s\"!?",
		    Client_ID(Client), Req->argv[0]);
		return CONNECTED;
	}

	con = Client_Conn(target);

	if (Req->argv[1][0])
		if (Client_NextHop(from) != Client || con > NONE)
			snprintf(msg, sizeof(msg), "%s (SQUIT from %s)",
				 Req->argv[1], Client_ID(from));
		else
			strlcpy(msg, Req->argv[1], sizeof(msg));
	else
		snprintf(msg, sizeof(msg), "Got SQUIT from %s",
			 Client_ID(from));

	if (con > NONE) {
		/* We are directly connected to the target server, so we
		 * have to tear down the connection and to inform all the
		 * other remaining servers in the network */
		IRC_SendWallops(Client_ThisServer(), Client_ThisServer(),
				"Received SQUIT %s from %s: %s",
				Req->argv[0], Client_ID(from),
				Req->argv[1][0] ? Req->argv[1] : "-");
		Conn_Close(con, NULL, msg, true);
		if (con == Client_Conn(Client))
			return DISCONNECTED;
	} else {
		/* This server is not directly connected, so the SQUIT must
		 * be forwarded ... */
		if (Client_Type(from) != CLIENT_SERVER) {
			/* The origin is not an IRC server, so don't evaluate
			 * this SQUIT but simply forward it */
			IRC_WriteStrClientPrefix(Client_NextHop(target),
			    from, "SQUIT %s :%s", Req->argv[0], Req->argv[1]);
		} else {
			/* SQUIT has been generated by another server, so
			 * remove the target server from the network! */
			logmsg[0] = '\0';
			if (!strchr(msg, '('))
				snprintf(logmsg, sizeof(logmsg),
					 "%s (SQUIT from %s)", Req->argv[1],
					 Client_ID(from));
			Client_Destroy(target, logmsg[0] ? logmsg : msg,
				       msg, false);
		}
	}
	return CONNECTED;
} /* IRC_SQUIT */
示例#24
0
文件: irc.c 项目: mguindin/ngircd
GLOBAL bool
IRC_TRACE( CLIENT *Client, REQUEST *Req )
{
	CLIENT *from, *target, *c;
	CONN_ID idx, idx2;
	char user[CLIENT_USER_LEN];

	assert( Client != NULL );
	assert( Req != NULL );

	/* Bad number of arguments? */
	if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command );

	/* Search sender */
	if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
	else from = Client;
	if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );

	/* Search target */
	if( Req->argc == 1 ) target = Client_Search( Req->argv[0] );
	else target = Client_ThisServer( );
	
	/* Forward command to other server? */
	if( target != Client_ThisServer( ))
	{
		if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );

		/* Send RPL_TRACELINK back to initiator */
		idx = Client_Conn( Client ); assert( idx > NONE );
		idx2 = Client_Conn( Client_NextHop( target )); assert( idx2 > NONE );
		if( ! IRC_WriteStrClient( from, RPL_TRACELINK_MSG, Client_ID( from ), PACKAGE_NAME, PACKAGE_VERSION, Client_ID( target ), Client_ID( Client_NextHop( target )), Option_String( idx2 ), time( NULL ) - Conn_StartTime( idx2 ), Conn_SendQ( idx ), Conn_SendQ( idx2 ))) return DISCONNECTED;

		/* Forward command */
		IRC_WriteStrClientPrefix( target, from, "TRACE %s", Req->argv[0] );
		return CONNECTED;
	}

	/* Infos about all connected servers */
	c = Client_First( );
	while( c )
	{
		if( Client_Conn( c ) > NONE )
		{
			/* Local client */
			if( Client_Type( c ) == CLIENT_SERVER )
			{
				/* Server link */
				strlcpy( user, Client_User( c ), sizeof( user ));
				if( user[0] == '~' ) strlcpy( user, "unknown", sizeof( user ));
				if( ! IRC_WriteStrClient( from, RPL_TRACESERVER_MSG, Client_ID( from ), Client_ID( c ), user, Client_Hostname( c ), Client_Mask( Client_ThisServer( )), Option_String( Client_Conn( c )))) return DISCONNECTED;
			}
			if(( Client_Type( c ) == CLIENT_USER ) && ( strchr( Client_Modes( c ), 'o' )))
			{
				/* IRC Operator */
				if( ! IRC_WriteStrClient( from, RPL_TRACEOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
			}
		}
		c = Client_Next( c );
	}

	IRC_SetPenalty( Client, 3 );
	return IRC_WriteStrClient( from, RPL_TRACEEND_MSG, Client_ID( from ), Conf_ServerName, PACKAGE_NAME, PACKAGE_VERSION, NGIRCd_DebugLevel );
} /* IRC_TRACE */
示例#25
0
/**
 * Handler for the IRC "PING" command.
 *
 * See RFC 2812, 3.7.2 "Ping message".
 *
 * @param Client	The client from which this command has been received.
 * @param Req		Request structure with prefix and all parameters.
 * @returns		CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_PING(CLIENT *Client, REQUEST *Req)
{
	CLIENT *target, *from;

	assert(Client != NULL);
	assert(Req != NULL);

	if (Req->argc < 1)
		return IRC_WriteStrClient(Client, ERR_NOORIGIN_MSG,
					  Client_ID(Client));
#ifdef STRICT_RFC
	/* Don't ignore additional arguments when in "strict" mode */
	if (Req->argc > 2)
		 return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
					   Client_ID(Client), Req->command);
#endif

	if (Req->argc > 1) {
		/* A target has been specified ... */
		target = Client_Search(Req->argv[1]);

		if (!target || Client_Type(target) != CLIENT_SERVER)
			return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG,
					Client_ID(Client), Req->argv[1]);

		if (target != Client_ThisServer()) {
			/* Ok, we have to forward the PING */
			if (Client_Type(Client) == CLIENT_SERVER)
				from = Client_Search(Req->prefix);
			else
				from = Client;
			if (!from)
				return IRC_WriteStrClient(Client,
						ERR_NOSUCHSERVER_MSG,
						Client_ID(Client), Req->prefix);

			return IRC_WriteStrClientPrefix(target, from,
					"PING %s :%s", Req->argv[0],
					Req->argv[1] );
		}
	}

	if (Client_Type(Client) == CLIENT_SERVER) {
		if (Req->prefix)
			from = Client_Search(Req->prefix);
		else
			from = Client;
	} else
		from = Client_ThisServer();
	if (!from)
		return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG,
					Client_ID(Client), Req->prefix);

	Log(LOG_DEBUG, "Connection %d: got PING, sending PONG ...",
	    Client_Conn(Client));

#ifdef STRICT_RFC
	return IRC_WriteStrClient(Client, "PONG %s :%s",
		Client_ID(from), Client_ID(Client));
#else
	/* Some clients depend on the argument being returned in the PONG
	 * reply (not mentioned in any RFC, though) */
	return IRC_WriteStrClient(Client, "PONG %s :%s",
		Client_ID(from), Req->argv[0]);
#endif
} /* IRC_PING */