X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fircd_relay.c;h=b7a751d7cc4a9446100f904c7c7dd2424867fae3;hb=db5ce1caa14de28c6b333ac3e1484ed068dfd236;hp=d997b90ee09aaece3e87262e7c3969720ade7973;hpb=ae91ef6320f611af74e70a0db2620c338fbaa7d5;p=ircu2.10.12-pk.git diff --git a/ircd/ircd_relay.c b/ircd/ircd_relay.c index d997b90..b7a751d 100644 --- a/ircd/ircd_relay.c +++ b/ircd/ircd_relay.c @@ -19,15 +19,40 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/** @file + * @brief Helper functions to relay various types of messages. + * @version $Id$ + * + * There are four basic types of messages, each with four subtypes. + * + * The basic types are: channel, directed, masked, and private. + * Channel messages are (perhaps obviously) sent directly to a + * channel. Directed messages are sent to "NICK[%host]@server", but + * only allowed if the server is a services server (to avoid + * information leaks for normal clients). Masked messages are sent to + * either *@*host.mask or *.server.mask. Private messages are sent to + * NICK. * - * $Id$ + * The subtypes for each type are: client message, client notice, + * server message, and server notice. Client subtypes are sent by a + * local user, and server subtypes are given to us by a server. + * Notice subtypes correspond to the NOTICE command, and message + * subtypes correspond to the PRIVMSG command. + * + * As a special note, directed messages do not have server subtypes, + * since there is no difference in handling them based on origin. */ +#include "config.h" + #include "ircd_relay.h" #include "channel.h" #include "client.h" #include "hash.h" #include "ircd.h" #include "ircd_chattr.h" +#include "ircd_features.h" +#include "ircd_log.h" #include "ircd_reply.h" #include "ircd_string.h" #include "match.h" @@ -39,7 +64,7 @@ #include "s_user.h" #include "send.h" -#include +/* #include -- Now using assert in ircd_log.h */ #include #include #include @@ -51,6 +76,13 @@ * to be cleaned up a bit. The idea is to factor out the common checks * but not introduce any IsOper/IsUser/MyUser/IsServer etc. stuff. */ + +/** Relay a local user's message to a channel. + * Generates an error if the client cannot send to the channel. + * @param[in] sptr Client that originated the message. + * @param[in] name Name of target channel. + * @param[in] text %Message to relay. + */ void relay_channel_message(struct Client* sptr, const char* name, const char* text) { struct Channel* chptr; @@ -59,24 +91,31 @@ void relay_channel_message(struct Client* sptr, const char* name, const char* te assert(0 != text); if (0 == (chptr = FindChannel(name))) { - send_error_to_client(sptr, ERR_NOSUCHCHANNEL, name); + send_reply(sptr, ERR_NOSUCHCHANNEL, name); return; } /* * This first: Almost never a server/service */ - if (!client_can_send_to_channel(sptr, chptr)) { - send_error_to_client(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); + if (!client_can_send_to_channel(sptr, chptr, 0)) { + send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); return; } if ((chptr->mode.mode & MODE_NOPRIVMSGS) && check_target_limit(sptr, chptr, chptr->chname, 0)) return; - sendmsgto_channel_butone(sptr->from, sptr, chptr, sptr->name, - TOK_PRIVATE, chptr->chname, text); + RevealDelayedJoinIfNeeded(sptr, chptr); + sendcmdto_channel_butone(sptr, CMD_PRIVATE, chptr, cli_from(sptr), + SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, text); } +/** Relay a local user's notice to a channel. + * Silently exits if the client cannot send to the channel. + * @param[in] sptr Client that originated the message. + * @param[in] name Name of target channel. + * @param[in] text %Message to relay. + */ void relay_channel_notice(struct Client* sptr, const char* name, const char* text) { struct Channel* chptr; @@ -89,17 +128,25 @@ void relay_channel_notice(struct Client* sptr, const char* name, const char* tex /* * This first: Almost never a server/service */ - if (!client_can_send_to_channel(sptr, chptr)) + if (!client_can_send_to_channel(sptr, chptr, 0)) return; if ((chptr->mode.mode & MODE_NOPRIVMSGS) && check_target_limit(sptr, chptr, chptr->chname, 0)) - return; + return; - sendmsgto_channel_butone(sptr->from, sptr, chptr, sptr->name, - TOK_NOTICE, chptr->chname, text); + RevealDelayedJoinIfNeeded(sptr, chptr); + sendcmdto_channel_butone(sptr, CMD_NOTICE, chptr, cli_from(sptr), + SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, text); } +/** Relay a message to a channel. + * Generates an error if the client cannot send to the channel, + * or if the channel is a local channel + * @param[in] sptr Client that originated the message. + * @param[in] name Name of target channel. + * @param[in] text %Message to relay. + */ void server_relay_channel_message(struct Client* sptr, const char* name, const char* text) { struct Channel* chptr; @@ -107,25 +154,29 @@ void server_relay_channel_message(struct Client* sptr, const char* name, const c assert(0 != name); assert(0 != text); - if (0 == (chptr = FindChannel(name))) { - /* - * XXX - do we need to send this back from a remote server? - */ - send_error_to_client(sptr, ERR_NOSUCHCHANNEL, name); + if (IsLocalChannel(name) || 0 == (chptr = FindChannel(name))) { + send_reply(sptr, ERR_NOSUCHCHANNEL, name); return; } /* * This first: Almost never a server/service * Servers may have channel services, need to check for it here */ - if (client_can_send_to_channel(sptr, chptr) || IsChannelService(sptr)) { - sendmsgto_channel_butone(sptr->from, sptr, chptr, sptr->name, - TOK_PRIVATE, chptr->chname, text); + if (client_can_send_to_channel(sptr, chptr, 1) || IsChannelService(sptr)) { + sendcmdto_channel_butone(sptr, CMD_PRIVATE, chptr, cli_from(sptr), + SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, text); } else - send_error_to_client(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); + send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); } +/** Relay a notice to a channel. + * Generates an error if the client cannot send to the channel, + * or if the channel is a local channel + * @param[in] sptr Client that originated the message. + * @param[in] name Name of target channel. + * @param[in] text %Message to relay. + */ void server_relay_channel_notice(struct Client* sptr, const char* name, const char* text) { struct Channel* chptr; @@ -133,19 +184,27 @@ void server_relay_channel_notice(struct Client* sptr, const char* name, const ch assert(0 != name); assert(0 != text); - if (0 == (chptr = FindChannel(name))) + if (IsLocalChannel(name) || 0 == (chptr = FindChannel(name))) return; /* * This first: Almost never a server/service * Servers may have channel services, need to check for it here */ - if (client_can_send_to_channel(sptr, chptr) || IsChannelService(sptr)) { - sendmsgto_channel_butone(sptr->from, sptr, chptr, sptr->name, - TOK_NOTICE, chptr->chname, text); + if (client_can_send_to_channel(sptr, chptr, 1) || IsChannelService(sptr)) { + sendcmdto_channel_butone(sptr, CMD_NOTICE, chptr, cli_from(sptr), + SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, text); } } - +/** Relay a directed message. + * Generates an error if the named server does not exist, if it is not + * a services server, or if \a name names a local user and a hostmask + * is specified but does not match. + * @param[in] sptr Client that originated the message. + * @param[in] name Target nickname, with optional "%hostname" suffix. + * @param[in] server Name of target server. + * @param[in] text %Message to relay. + */ void relay_directed_message(struct Client* sptr, char* name, char* server, const char* text) { struct Client* acptr; @@ -156,15 +215,17 @@ void relay_directed_message(struct Client* sptr, char* name, char* server, const assert(0 != text); assert(0 != server); - if (0 == (acptr = FindServer(server + 1))) { - send_error_to_client(sptr, ERR_NOSUCHNICK, name); + if ((acptr = FindServer(server + 1)) == NULL || !IsService(acptr)) + { + send_reply(sptr, ERR_NOSUCHNICK, name); return; } /* * NICK[%host]@server addressed? See if is me first */ - if (!IsMe(acptr)) { - sendto_one(acptr, ":%s %s %s :%s", sptr->name, MSG_PRIVATE, name, text); + if (!IsMe(acptr)) + { + sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", name, text); return; } /* @@ -176,9 +237,24 @@ void relay_directed_message(struct Client* sptr, char* name, char* server, const if ((host = strchr(name, '%'))) *host++ = '\0'; + /* As reported by Vampire-, it's possible to brute force finding users + * by sending a message to each server and see which one succeeded. + * This means we have to remove error reporting. Sigh. Better than + * removing the ability to send directed messages to client servers + * Thanks for the suggestion Vampire=. -- Isomer 2001-08-28 + * Argh, /ping nick@server, disallow messages to non +k clients :/ I hate + * this. -- Isomer 2001-09-16 + */ if (!(acptr = FindUser(name)) || !MyUser(acptr) || - (!EmptyString(host) && 0 != match(host, acptr->user->host))) { - send_error_to_client(sptr, ERR_NOSUCHNICK, name); + (!EmptyString(host) && 0 != match(host, cli_user(acptr)->host)) || + !IsChannelService(acptr)) + { + /* + * By this stage we might as well not bother because they will + * know that this server is currently linked because of the + * increased lag. + */ + send_reply(sptr, ERR_NOSUCHNICK, name); return; } @@ -187,10 +263,18 @@ void relay_directed_message(struct Client* sptr, char* name, char* server, const *--host = '%'; if (!(is_silenced(sptr, acptr))) - sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", - sptr->name, MSG_PRIVATE, name, text); + sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", name, text); } +/** Relay a directed notice. + * Generates an error if the named server does not exist, if it is not + * a services server, or if \a name names a local user and a hostmask + * is specified but does not match. + * @param[in] sptr Client that originated the message. + * @param[in] name Target nickname, with optional "%hostname" suffix. + * @param[in] server Name of target server. + * @param[in] text %Message to relay. + */ void relay_directed_notice(struct Client* sptr, char* name, char* server, const char* text) { struct Client* acptr; @@ -207,7 +291,7 @@ void relay_directed_notice(struct Client* sptr, char* name, char* server, const * NICK[%host]@server addressed? See if is me first */ if (!IsMe(acptr)) { - sendto_one(acptr, ":%s %s %s :%s", sptr->name, MSG_NOTICE, name, text); + sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text); return; } /* @@ -220,7 +304,7 @@ void relay_directed_notice(struct Client* sptr, char* name, char* server, const *host++ = '\0'; if (!(acptr = FindUser(name)) || !MyUser(acptr) || - (!EmptyString(host) && 0 != match(host, acptr->user->host))) + (!EmptyString(host) && 0 != match(host, cli_user(acptr)->host))) return; *server = '@'; @@ -228,10 +312,17 @@ void relay_directed_notice(struct Client* sptr, char* name, char* server, const *--host = '%'; if (!(is_silenced(sptr, acptr))) - sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", - sptr->name, MSG_NOTICE, name, text); + sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text); } +/** Relay a private message from a local user. + * Returns an error if the user does not exist or sending to him would + * exceed the source's free targets. Sends an AWAY status message if + * the target is marked as away. + * @param[in] sptr Client that originated the message. + * @param[in] name Nickname of target user. + * @param[in] text %Message to relay. + */ void relay_private_message(struct Client* sptr, const char* name, const char* text) { struct Client* acptr; @@ -241,32 +332,36 @@ void relay_private_message(struct Client* sptr, const char* name, const char* te assert(0 != text); if (0 == (acptr = FindUser(name))) { - send_error_to_client(sptr, ERR_NOSUCHNICK, name); + send_reply(sptr, ERR_NOSUCHNICK, name); return; } - if (check_target_limit(sptr, acptr, acptr->name, 0) || + if ((!IsChannelService(acptr) && + check_target_limit(sptr, acptr, cli_name(acptr), 0)) || is_silenced(sptr, acptr)) return; /* * send away message if user away */ - if (acptr->user && acptr->user->away) - sendto_one(sptr, rpl_str(RPL_AWAY), - me.name, sptr->name, acptr->name, acptr->user->away); + if (cli_user(acptr) && cli_user(acptr)->away) + send_reply(sptr, RPL_AWAY, cli_name(acptr), cli_user(acptr)->away); /* * deliver the message */ - if (MyUser(acptr)) { + if (MyUser(acptr)) add_target(acptr, sptr); - sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", - sptr->name, MSG_PRIVATE, acptr->name, text); - } - else - sendto_one(acptr, "%s%s %s %s%s :%s", NumNick(sptr), - TOK_PRIVATE, NumNick(acptr), text); + + sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text); } +/** Relay a private notice from a local user. + * Returns an error if the user does not exist or sending to him would + * exceed the source's free targets. Sends an AWAY status message if + * the target is marked as away. + * @param[in] sptr Client that originated the message. + * @param[in] name Nickname of target user. + * @param[in] text %Message to relay. + */ void relay_private_notice(struct Client* sptr, const char* name, const char* text) { struct Client* acptr; @@ -276,22 +371,25 @@ void relay_private_notice(struct Client* sptr, const char* name, const char* tex if (0 == (acptr = FindUser(name))) return; - if (check_target_limit(sptr, acptr, acptr->name, 0) || + if ((!IsChannelService(acptr) && + check_target_limit(sptr, acptr, cli_name(acptr), 0)) || is_silenced(sptr, acptr)) return; /* * deliver the message */ - if (MyUser(acptr)) { + if (MyUser(acptr)) add_target(acptr, sptr); - sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", - sptr->name, MSG_NOTICE, acptr->name, text); - } - else - sendto_one(acptr, "%s%s %s %s%s :%s", NumNick(sptr), - TOK_NOTICE, NumNick(acptr), text); + + sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text); } +/** Relay a private message that arrived from a server. + * Returns an error if the user does not exist. + * @param[in] sptr Client that originated the message. + * @param[in] name Nickname of target user. + * @param[in] text %Message to relay. + */ void server_relay_private_message(struct Client* sptr, const char* name, const char* text) { struct Client* acptr; @@ -302,30 +400,27 @@ void server_relay_private_message(struct Client* sptr, const char* name, const c * nickname addressed? */ if (0 == (acptr = findNUser(name)) || !IsUser(acptr)) { - sendto_one(sptr, - ":%s %d %s * :Target left UnderNet. Failed to deliver: [%.20s]", - me.name, ERR_NOSUCHNICK, sptr->name, text); + send_reply(sptr, SND_EXPLICIT | ERR_NOSUCHNICK, "* :Target left %s. " + "Failed to deliver: [%.20s]", feature_str(FEAT_NETWORK), + text); return; } if (is_silenced(sptr, acptr)) return; - if (MyUser(acptr)) { + if (MyUser(acptr)) add_target(acptr, sptr); - sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", - sptr->name, MSG_PRIVATE, acptr->name, text); - } - else { - if (IsServer(sptr)) - sendto_one(acptr, "%s %s %s%s :%s", NumServ(sptr), - TOK_PRIVATE, NumNick(acptr), text); - else - sendto_one(acptr, "%s%s %s %s%s :%s", NumNick(sptr), - TOK_PRIVATE, NumNick(acptr), text); - } + + sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text); } +/** Relay a private notice that arrived from a server. + * Returns an error if the user does not exist. + * @param[in] sptr Client that originated the message. + * @param[in] name Nickname of target user. + * @param[in] text %Message to relay. + */ void server_relay_private_notice(struct Client* sptr, const char* name, const char* text) { struct Client* acptr; @@ -341,21 +436,19 @@ void server_relay_private_notice(struct Client* sptr, const char* name, const ch if (is_silenced(sptr, acptr)) return; - if (MyUser(acptr)) { + if (MyUser(acptr)) add_target(acptr, sptr); - sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", - sptr->name, MSG_NOTICE, acptr->name, text); - } - else { - if (IsServer(sptr)) - sendto_one(acptr, "%s %s %s%s :%s", NumServ(sptr), - TOK_NOTICE, NumNick(acptr), text); - else - sendto_one(acptr, "%s%s %s %s%s :%s", NumNick(sptr), - TOK_NOTICE, NumNick(acptr), text); - } + + sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text); } +/** Relay a masked message from a local user. + * Sends an error response if there is no top-level domain label in \a + * mask, or if that TLD contains a wildcard. + * @param[in] sptr Client that originated the message. + * @param[in] mask Target mask for the message. + * @param[in] text %Message to relay. + */ void relay_masked_message(struct Client* sptr, const char* mask, const char* text) { const char* s; @@ -368,7 +461,7 @@ void relay_masked_message(struct Client* sptr, const char* mask, const char* tex * look for the last '.' in mask and scan forward */ if (0 == (s = strrchr(mask, '.'))) { - send_error_to_client(sptr, ERR_NOTOPLEVEL, mask); + send_reply(sptr, ERR_NOTOPLEVEL, mask); return; } while (*++s) { @@ -376,7 +469,7 @@ void relay_masked_message(struct Client* sptr, const char* mask, const char* tex break; } if (*s == '*' || *s == '?') { - send_error_to_client(sptr, ERR_WILDTOPLEVEL, mask); + send_reply(sptr, ERR_WILDTOPLEVEL, mask); return; } s = mask; @@ -384,11 +477,20 @@ void relay_masked_message(struct Client* sptr, const char* mask, const char* tex host_mask = 1; ++s; } - sendto_match_butone(IsServer(sptr->from) ? sptr->from : 0, - sptr, s, host_mask ? MATCH_HOST : MATCH_SERVER, - ":%s %s %s :%s", sptr->name, MSG_PRIVATE, mask, text); + + sendcmdto_match_butone(sptr, CMD_PRIVATE, s, + IsServer(cli_from(sptr)) ? cli_from(sptr) : 0, + host_mask ? MATCH_HOST : MATCH_SERVER, + "%s :%s", mask, text); } +/** Relay a masked notice from a local user. + * Sends an error response if there is no top-level domain label in \a + * mask, or if that TLD contains a wildcard. + * @param[in] sptr Client that originated the message. + * @param[in] mask Target mask for the message. + * @param[in] text %Message to relay. + */ void relay_masked_notice(struct Client* sptr, const char* mask, const char* text) { const char* s; @@ -401,7 +503,7 @@ void relay_masked_notice(struct Client* sptr, const char* mask, const char* text * look for the last '.' in mask and scan forward */ if (0 == (s = strrchr(mask, '.'))) { - send_error_to_client(sptr, ERR_NOTOPLEVEL, mask); + send_reply(sptr, ERR_NOTOPLEVEL, mask); return; } while (*++s) { @@ -409,7 +511,7 @@ void relay_masked_notice(struct Client* sptr, const char* mask, const char* text break; } if (*s == '*' || *s == '?') { - send_error_to_client(sptr, ERR_WILDTOPLEVEL, mask); + send_reply(sptr, ERR_WILDTOPLEVEL, mask); return; } s = mask; @@ -417,11 +519,18 @@ void relay_masked_notice(struct Client* sptr, const char* mask, const char* text host_mask = 1; ++s; } - sendto_match_butone(IsServer(sptr->from) ? sptr->from : 0, - sptr, s, host_mask ? MATCH_HOST : MATCH_SERVER, - ":%s %s %s :%s", sptr->name, MSG_NOTICE, mask, text); + + sendcmdto_match_butone(sptr, CMD_NOTICE, s, + IsServer(cli_from(sptr)) ? cli_from(sptr) : 0, + host_mask ? MATCH_HOST : MATCH_SERVER, + "%s :%s", mask, text); } +/** Relay a masked message that arrived from a server. + * @param[in] sptr Client that originated the message. + * @param[in] mask Target mask for the message. + * @param[in] text %Message to relay. + */ void server_relay_masked_message(struct Client* sptr, const char* mask, const char* text) { const char* s = mask; @@ -434,10 +543,17 @@ void server_relay_masked_message(struct Client* sptr, const char* mask, const ch host_mask = 1; ++s; } - sendto_match_butone(sptr->from, sptr, s, host_mask ? MATCH_HOST : MATCH_SERVER, - ":%s %s %s :%s", sptr->name, MSG_PRIVATE, mask, text); + sendcmdto_match_butone(sptr, CMD_PRIVATE, s, + IsServer(cli_from(sptr)) ? cli_from(sptr) : 0, + host_mask ? MATCH_HOST : MATCH_SERVER, + "%s :%s", mask, text); } +/** Relay a masked notice that arrived from a server. + * @param[in] sptr Client that originated the message. + * @param[in] mask Target mask for the message. + * @param[in] text %Message to relay. + */ void server_relay_masked_notice(struct Client* sptr, const char* mask, const char* text) { const char* s = mask; @@ -450,7 +566,9 @@ void server_relay_masked_notice(struct Client* sptr, const char* mask, const cha host_mask = 1; ++s; } - sendto_match_butone(sptr->from, sptr, s, host_mask ? MATCH_HOST : MATCH_SERVER, - ":%s %s %s :%s", sptr->name, MSG_NOTICE, mask, text); + sendcmdto_match_butone(sptr, CMD_NOTICE, s, + IsServer(cli_from(sptr)) ? cli_from(sptr) : 0, + host_mask ? MATCH_HOST : MATCH_SERVER, + "%s :%s", mask, text); }