X-Git-Url: https://jfr.im/git/solanum.git/blobdiff_plain/5b96d9a6b92f3ca219ff2baab7596cc94580813d..a92275551218402bf4969a7fe613cab27416c4ef:/modules/core/m_nick.c diff --git a/modules/core/m_nick.c b/modules/core/m_nick.c index d7934e57..a5b94d59 100644 --- a/modules/core/m_nick.c +++ b/modules/core/m_nick.c @@ -20,14 +20,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA - * - * $Id: m_nick.c 3518 2007-06-22 21:59:09Z jilles $ */ #include "stdinc.h" #include "client.h" #include "hash.h" -#include "irc_string.h" +#include "match.h" #include "ircd.h" #include "numeric.h" #include "s_conf.h" @@ -38,15 +36,15 @@ #include "s_serv.h" #include "send.h" #include "channel.h" -#include "s_log.h" +#include "logger.h" #include "msg.h" #include "parse.h" #include "modules.h" -#include "common.h" #include "packet.h" #include "scache.h" #include "s_newconf.h" #include "monitor.h" +#include "s_assert.h" /* Give all UID nicks the same TS. This ensures nick TS is always the same on * all servers for each nick-user pair, also if a user with a UID nick changes @@ -55,97 +53,97 @@ */ #define SAVE_NICKTS 100 -static int mr_nick(struct Client *, struct Client *, int, const char **); -static int m_nick(struct Client *, struct Client *, int, const char **); -static int mc_nick(struct Client *, struct Client *, int, const char **); -static int ms_nick(struct Client *, struct Client *, int, const char **); -static int ms_uid(struct Client *, struct Client *, int, const char **); -static int ms_euid(struct Client *, struct Client *, int, const char **); -static int ms_save(struct Client *, struct Client *, int, const char **); -static int can_save(struct Client *); +static void mr_nick(struct MsgBuf *, struct Client *, struct Client *, int, const char **); +static void m_nick(struct MsgBuf *, struct Client *, struct Client *, int, const char **); +static void mc_nick(struct MsgBuf *, struct Client *, struct Client *, int, const char **); +static void ms_nick(struct MsgBuf *, struct Client *, struct Client *, int, const char **); +static void ms_uid(struct MsgBuf *, struct Client *, struct Client *, int, const char **); +static void ms_euid(struct MsgBuf *, struct Client *, struct Client *, int, const char **); +static void ms_save(struct MsgBuf *, struct Client *, struct Client *, int, const char **); +static bool can_save(struct Client *); static void save_user(struct Client *, struct Client *, struct Client *); +static void bad_nickname(struct Client *, const char *); +static void change_remote_nick(struct Client *, struct Client *, time_t, + const char *, int); +static bool clean_username(const char *); +static bool clean_host(const char *); +static bool clean_uid(const char *uid, const char *sid); + +static void set_initial_nick(struct Client *client_p, struct Client *source_p, char *nick); +static void change_local_nick(struct Client *client_p, struct Client *source_p, char *nick, int); +static void register_client(struct Client *client_p, struct Client *server, + const char *nick, time_t newts, int parc, const char *parv[]); +static void perform_nick_collides(struct Client *, struct Client *, + struct Client *, int, const char **, + time_t, const char *, const char *); +static void perform_nickchange_collides(struct Client *, struct Client *, + struct Client *, int, const char **, time_t, const char *); + +static int h_local_nick_change; +static int h_remote_nick_change; struct Message nick_msgtab = { - "NICK", 0, 0, 0, MFLG_SLOW, - {{mr_nick, 0}, {m_nick, 0}, {mc_nick, 3}, {ms_nick, 8}, mg_ignore, {m_nick, 0}} + "NICK", 0, 0, 0, 0, + {{mr_nick, 0}, {m_nick, 0}, {mc_nick, 3}, {ms_nick, 0}, mg_ignore, {m_nick, 0}} }; struct Message uid_msgtab = { - "UID", 0, 0, 0, MFLG_SLOW, + "UID", 0, 0, 0, 0, {mg_ignore, mg_ignore, mg_ignore, {ms_uid, 9}, mg_ignore, mg_ignore} }; struct Message euid_msgtab = { - "EUID", 0, 0, 0, MFLG_SLOW, + "EUID", 0, 0, 0, 0, {mg_ignore, mg_ignore, mg_ignore, {ms_euid, 12}, mg_ignore, mg_ignore} }; struct Message save_msgtab = { - "SAVE", 0, 0, 0, MFLG_SLOW, + "SAVE", 0, 0, 0, 0, {mg_ignore, mg_ignore, mg_ignore, {ms_save, 3}, mg_ignore, mg_ignore} }; mapi_clist_av1 nick_clist[] = { &nick_msgtab, &uid_msgtab, &euid_msgtab, &save_msgtab, NULL }; -DECLARE_MODULE_AV1(nick, NULL, NULL, nick_clist, NULL, NULL, "$Revision: 3518 $"); - -static int change_remote_nick(struct Client *, struct Client *, time_t, - const char *, int); - -static int clean_nick(const char *, int loc_client); -static int clean_username(const char *); -static int clean_host(const char *); -static int clean_uid(const char *uid); +mapi_hlist_av1 nick_hlist[] = { + { "local_nick_change", &h_local_nick_change }, + { "remote_nick_change", &h_remote_nick_change }, + { NULL, NULL } +}; -static void set_initial_nick(struct Client *client_p, struct Client *source_p, char *nick); -static void change_local_nick(struct Client *client_p, struct Client *source_p, char *nick, int); -static int register_client(struct Client *client_p, struct Client *server, - const char *nick, time_t newts, int parc, const char *parv[]); +static const char nick_desc[] = + "Provides the NICK client and server commands as well as the UID, EUID, and SAVE TS6 server commands"; -static int perform_nick_collides(struct Client *, struct Client *, - struct Client *, int, const char **, - time_t, const char *, const char *); -static int perform_nickchange_collides(struct Client *, struct Client *, - struct Client *, int, const char **, time_t, const char *); +DECLARE_MODULE_AV2(nick, NULL, NULL, nick_clist, nick_hlist, NULL, NULL, NULL, nick_desc); /* mr_nick() - * parv[0] = sender prefix * parv[1] = nickname */ -static int -mr_nick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) +static void +mr_nick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; char nick[NICKLEN]; - char *s; - if (strlen(client_p->id) == 3) + if (strlen(client_p->id) == 3 || (source_p->preClient && !EmptyString(source_p->preClient->id))) { exit_client(client_p, client_p, client_p, "Mixing client and server protocol"); - return 0; + return; } - if(parc < 2 || EmptyString(parv[1]) || (parv[1][0] == '~')) + if(parc < 2 || EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name, EmptyString(source_p->name) ? "*" : source_p->name); - return 0; + return; } - /* due to the scandinavian origins, (~ being uppercase of ^) and ~ - * being disallowed as a nick char, we need to chop the first ~ - * instead of just erroring. - */ - if((s = strchr(parv[1], '~'))) - *s = '\0'; - /* copy the nick and terminate it */ - strlcpy(nick, parv[1], sizeof(nick)); + rb_strlcpy(nick, parv[1], ConfigFileEntry.nicklen); /* check the nickname is ok */ if(!clean_nick(nick, 1)) { sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), - me.name, EmptyString(parv[0]) ? "*" : parv[0], parv[1]); - return 0; + me.name, EmptyString(source_p->name) ? "*" : source_p->name, parv[1]); + return; } /* check if the nick is resv'd */ @@ -153,75 +151,64 @@ mr_nick(struct Client *client_p, struct Client *source_p, int parc, const char * { sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, EmptyString(source_p->name) ? "*" : source_p->name, nick); - return 0; + return; } - if(irc_dictionary_find(nd_dict, nick)) + if(rb_dictionary_find(nd_dict, nick)) { sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE), me.name, EmptyString(source_p->name) ? "*" : source_p->name, nick); - return 0; + return; } if((target_p = find_named_client(nick)) == NULL) set_initial_nick(client_p, source_p, nick); else if(source_p == target_p) - strcpy(source_p->name, nick); + rb_strlcpy(source_p->name, nick, sizeof(source_p->name)); else sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick); - - return 0; } /* m_nick() - * parv[0] = sender prefix * parv[1] = nickname */ -static int -m_nick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) +static void +m_nick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; char nick[NICKLEN]; - char *s; - if(parc < 2 || EmptyString(parv[1]) || (parv[1][0] == '~')) + if(parc < 2 || EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name, source_p->name); - return 0; + return; } - /* due to the scandinavian origins, (~ being uppercase of ^) and ~ - * being disallowed as a nick char, we need to chop the first ~ - * instead of just erroring. - */ - if((s = strchr(parv[1], '~'))) - *s = '\0'; - /* mark end of grace period, to prevent nickflooding */ if(!IsFloodDone(source_p)) flood_endgrace(source_p); /* terminate nick to NICKLEN, we dont want clean_nick() to error! */ - strlcpy(nick, parv[1], sizeof(nick)); + rb_strlcpy(nick, parv[1], ConfigFileEntry.nicklen); /* check the nickname is ok */ if(!clean_nick(nick, 1)) { - sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, parv[0], nick); - return 0; + sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, source_p->name, nick); + return; } if(!IsExemptResv(source_p) && find_nick_resv(nick)) { sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, source_p->name, nick); - return 0; + return; } - if(irc_dictionary_find(nd_dict, nick)) + if(rb_dictionary_find(nd_dict, nick)) { sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE), me.name, EmptyString(source_p->name) ? "*" : source_p->name, nick); - return 0; + return; } if((target_p = find_named_client(nick))) @@ -244,36 +231,22 @@ m_nick(struct Client *client_p, struct Client *source_p, int parc, const char *p change_local_nick(client_p, source_p, nick, 1); } else - sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, parv[0], nick); + sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, source_p->name, nick); - return 0; + return; } else change_local_nick(client_p, source_p, nick, 1); - - return 0; } -/* ms_nick() - * +/* mc_nick() + * * server -> server nick change - * parv[0] = sender prefix * parv[1] = nickname * parv[2] = TS when nick change - * - * server introducing new nick - * parv[0] = sender prefix - * parv[1] = nickname - * parv[2] = hop count - * parv[3] = TS - * parv[4] = umode - * parv[5] = username - * parv[6] = hostname - * parv[7] = server - * parv[8] = ircname */ -static int -mc_nick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) +static void +mc_nick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; time_t newts = 0; @@ -281,19 +254,8 @@ mc_nick(struct Client *client_p, struct Client *source_p, int parc, const char * /* if nicks erroneous, or too long, kill */ if(!clean_nick(parv[1], 0)) { - ServerStats->is_kill++; - sendto_realops_snomask(SNO_DEBUG, L_ALL, - "Bad Nick: %s From: %s(via %s)", - parv[1], source_p->servptr->name, client_p->name); - sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)", me.name, parv[1], me.name); - - /* bad nick change, issue kill for the old nick to the rest - * of the network. - */ - kill_client_serv_butone(client_p, source_p, "%s (Bad Nickname)", me.name); - source_p->flags |= FLAGS_KILLED; - exit_client(client_p, source_p, &me, "Bad Nickname"); - return 0; + bad_nickname(client_p, parv[1]); + return; } newts = atol(parv[2]); @@ -319,87 +281,26 @@ mc_nick(struct Client *client_p, struct Client *source_p, int parc, const char * else perform_nickchange_collides(source_p, client_p, target_p, parc, parv, newts, parv[1]); - - return 0; } -static int -ms_nick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) +static void +ms_nick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { - struct Client *target_p; - time_t newts = 0; - - if(parc != 9) - { - sendto_realops_snomask(SNO_GENERAL, L_ALL, - "Dropping server %s due to (invalid) command 'NICK' " - "with %d arguments (expecting 9)", client_p->name, parc); - ilog(L_SERVER, "Excess parameters (%d) for command 'NICK' from %s.", - parc, client_p->name); - exit_client(client_p, client_p, client_p, "Excess parameters to NICK command"); - return 0; - } - - /* if nicks empty, erroneous, or too long, kill */ - if(!clean_nick(parv[1], 0)) - { - ServerStats->is_kill++; - sendto_realops_snomask(SNO_DEBUG, L_ALL, - "Bad Nick: %s From: %s(via %s)", - parv[1], parv[7], client_p->name); - sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)", me.name, parv[1], me.name); - return 0; - } + const char *nick, *server; - /* invalid username or host? */ - if(!clean_username(parv[5]) || !clean_host(parv[6])) - { - ServerStats->is_kill++; - sendto_realops_snomask(SNO_DEBUG, L_ALL, - "Bad user@host: %s@%s From: %s(via %s)", - parv[5], parv[6], parv[7], client_p->name); - sendto_one(client_p, ":%s KILL %s :%s (Bad user@host)", me.name, parv[1], me.name); - return 0; - } + nick = parc > 1 ? parv[1] : "?"; + server = parc > 7 ? parv[7] : "?"; - /* check the length of the clients gecos */ - if(strlen(parv[8]) > REALLEN) - { - char *s = LOCAL_COPY(parv[8]); - /* why exactly do we care? --fl */ - sendto_realops_snomask(SNO_GENERAL, L_ALL, - "Long realname from server %s for %s", parv[7], parv[1]); - - s[REALLEN] = '\0'; - parv[8] = s; - } - - newts = atol(parv[3]); - - target_p = find_named_client(parv[1]); - - /* if the nick doesnt exist, allow it and process like normal */ - if(target_p == NULL) - { - register_client(client_p, NULL, parv[1], newts, parc, parv); - } - else if(IsUnknown(target_p)) - { - exit_client(NULL, target_p, &me, "Overridden"); - register_client(client_p, NULL, parv[1], newts, parc, parv); - } - else if(target_p == source_p) - { - /* client changing case of nick */ - if(strcmp(target_p->name, parv[1])) - register_client(client_p, NULL, parv[1], newts, parc, parv); - } - /* we've got a collision! */ - else - perform_nick_collides(source_p, client_p, target_p, parc, parv, - newts, parv[1], NULL); + sendto_wallops_flags(UMODE_WALLOP, &me, + "Link %s cancelled, TS5 nickname %s on %s introduced (old server?)", + client_p->name, nick, server); + sendto_server(NULL, NULL, CAP_TS6, NOCAPS, + ":%s WALLOPS :Link %s cancelled, TS5 nickname %s on %s introduced (old server?)", + me.id, client_p->name, nick, server); + ilog(L_SERVER, "Link %s cancelled, TS5 nickname %s on %s introduced (old server?)", + client_p->name, nick, server); - return 0; + exit_client(client_p, client_p, &me, "TS5 nickname introduced"); } /* ms_uid() @@ -413,62 +314,61 @@ ms_nick(struct Client *client_p, struct Client *source_p, int parc, const char * * parv[8] - UID * parv[9] - gecos */ -static int -ms_uid(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) +static void +ms_uid(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; time_t newts = 0; + char squitreason[120]; newts = atol(parv[3]); if(parc != 10) { - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Dropping server %s due to (invalid) command 'UID' " "with %d arguments (expecting 10)", client_p->name, parc); ilog(L_SERVER, "Excess parameters (%d) for command 'UID' from %s.", parc, client_p->name); - exit_client(client_p, client_p, client_p, "Excess parameters to UID command"); - return 0; + snprintf(squitreason, sizeof squitreason, + "Excess parameters (%d) to %s command, expecting %d", + parc, "UID", 10); + exit_client(client_p, client_p, client_p, squitreason); + return; } /* if nicks erroneous, or too long, kill */ if(!clean_nick(parv[1], 0)) { - ServerStats->is_kill++; - sendto_realops_snomask(SNO_DEBUG, L_ALL, - "Bad Nick: %s From: %s(via %s)", - parv[1], source_p->name, client_p->name); - sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)", me.id, parv[8], me.name); - return 0; + bad_nickname(client_p, parv[1]); + return; + } + + if(!clean_uid(parv[8], source_p->id)) + { + snprintf(squitreason, sizeof squitreason, + "Invalid UID %s for nick %s on %s/%s", + parv[8], parv[1], source_p->name, source_p->id); + exit_client(client_p, client_p, client_p, squitreason); + return; } if(!clean_username(parv[5]) || !clean_host(parv[6])) { - ServerStats->is_kill++; - sendto_realops_snomask(SNO_DEBUG, L_ALL, + ServerStats.is_kill++; + sendto_realops_snomask(SNO_DEBUG, L_NETWIDE, "Bad user@host: %s@%s From: %s(via %s)", parv[5], parv[6], source_p->name, client_p->name); sendto_one(client_p, ":%s KILL %s :%s (Bad user@host)", me.id, parv[8], me.name); - return 0; - } - - if(!clean_uid(parv[8])) - { - ServerStats->is_kill++; - sendto_realops_snomask(SNO_DEBUG, L_ALL, - "Bad UID: %s From: %s(via %s)", - parv[8], source_p->name, client_p->name); - sendto_one(client_p, ":%s KILL %s :%s (Bad UID)", me.id, parv[8], me.name); - return 0; + return; } /* check length of clients gecos */ if(strlen(parv[9]) > REALLEN) { char *s = LOCAL_COPY(parv[9]); - sendto_realops_snomask(SNO_GENERAL, L_ALL, "Long realname from server %s for %s", - parv[0], parv[1]); + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Long realname from server %s for %s", + source_p->name, parv[1]); s[REALLEN] = '\0'; parv[9] = s; } @@ -488,8 +388,6 @@ ms_uid(struct Client *client_p, struct Client *source_p, int parc, const char *p else perform_nick_collides(source_p, client_p, target_p, parc, parv, newts, parv[1], parv[8]); - - return 0; } /* ms_euid() @@ -505,72 +403,71 @@ ms_uid(struct Client *client_p, struct Client *source_p, int parc, const char *p * parv[10] - account * parv[11] - gecos */ -static int -ms_euid(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) +static void +ms_euid(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; time_t newts = 0; + char squitreason[120]; newts = atol(parv[3]); if(parc != 12) { - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Dropping server %s due to (invalid) command 'EUID' " "with %d arguments (expecting 12)", client_p->name, parc); ilog(L_SERVER, "Excess parameters (%d) for command 'EUID' from %s.", parc, client_p->name); - exit_client(client_p, client_p, client_p, "Excess parameters to EUID command"); - return 0; + snprintf(squitreason, sizeof squitreason, + "Excess parameters (%d) to %s command, expecting %d", + parc, "EUID", 12); + exit_client(client_p, client_p, client_p, squitreason); + return; } /* if nicks erroneous, or too long, kill */ if(!clean_nick(parv[1], 0)) { - ServerStats->is_kill++; - sendto_realops_snomask(SNO_DEBUG, L_ALL, - "Bad Nick: %s From: %s(via %s)", - parv[1], source_p->name, client_p->name); - sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)", me.id, parv[8], me.name); - return 0; + bad_nickname(client_p, parv[1]); + return; + } + + if(!clean_uid(parv[8], source_p->id)) + { + snprintf(squitreason, sizeof squitreason, + "Invalid UID %s for nick %s on %s/%s", + parv[8], parv[1], source_p->name, source_p->id); + exit_client(client_p, client_p, client_p, squitreason); + return; } if(!clean_username(parv[5]) || !clean_host(parv[6])) { - ServerStats->is_kill++; - sendto_realops_snomask(SNO_DEBUG, L_ALL, + ServerStats.is_kill++; + sendto_realops_snomask(SNO_DEBUG, L_NETWIDE, "Bad user@host: %s@%s From: %s(via %s)", parv[5], parv[6], source_p->name, client_p->name); sendto_one(client_p, ":%s KILL %s :%s (Bad user@host)", me.id, parv[8], me.name); - return 0; - } - - if(!clean_uid(parv[8])) - { - ServerStats->is_kill++; - sendto_realops_snomask(SNO_DEBUG, L_ALL, - "Bad UID: %s From: %s(via %s)", - parv[8], source_p->name, client_p->name); - sendto_one(client_p, ":%s KILL %s :%s (Bad UID)", me.id, parv[8], me.name); - return 0; + return; } if(strcmp(parv[9], "*") && !clean_host(parv[9])) { - ServerStats->is_kill++; - sendto_realops_snomask(SNO_DEBUG, L_ALL, + ServerStats.is_kill++; + sendto_realops_snomask(SNO_DEBUG, L_NETWIDE, "Bad realhost: %s From: %s(via %s)", parv[9], source_p->name, client_p->name); sendto_one(client_p, ":%s KILL %s :%s (Bad user@host)", me.id, parv[8], me.name); - return 0; + return; } /* check length of clients gecos */ if(strlen(parv[11]) > REALLEN) { char *s = LOCAL_COPY(parv[11]); - sendto_realops_snomask(SNO_GENERAL, L_ALL, "Long realname from server %s for %s", - parv[0], parv[1]); + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Long realname from server %s for %s", + source_p->name, parv[1]); s[REALLEN] = '\0'; parv[11] = s; } @@ -590,22 +487,20 @@ ms_euid(struct Client *client_p, struct Client *source_p, int parc, const char * else perform_nick_collides(source_p, client_p, target_p, parc, parv, newts, parv[1], parv[8]); - - return 0; } /* ms_save() * parv[1] - UID * parv[2] - TS */ -static int -ms_save(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) +static void +ms_save(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; target_p = find_id(parv[1]); if (target_p == NULL) - return 0; + return; if (!IsPerson(target_p)) sendto_realops_snomask(SNO_GENERAL, L_ALL, "Ignored SAVE message for non-person %s from %s", @@ -620,48 +515,15 @@ ms_save(struct Client *client_p, struct Client *source_p, int parc, const char * sendto_realops_snomask(SNO_SKILL, L_ALL, "Ignored SAVE message for %s from %s", target_p->name, source_p->name); - return 0; -} - -/* clean_nick() - * - * input - nickname to check - * output - 0 if erroneous, else 1 - * side effects - - */ -static int -clean_nick(const char *nick, int loc_client) -{ - int len = 0; - - /* nicks cant start with a digit or -, and must have a length */ - if(*nick == '-' || *nick == '\0') - return 0; - - if(loc_client && IsDigit(*nick)) - return 0; - - for(; *nick; nick++) - { - len++; - if(!IsNickChar(*nick)) - return 0; - } - - /* nicklen is +1 */ - if(len >= NICKLEN) - return 0; - - return 1; } /* clean_username() * * input - username to check - * output - 0 if erroneous, else 0 + * output - false if erroneous, else true * side effects - */ -static int +static bool clean_username(const char *username) { int len = 0; @@ -671,22 +533,22 @@ clean_username(const char *username) len++; if(!IsUserChar(*username)) - return 0; + return false; } if(len > USERLEN) - return 0; + return false; - return 1; + return true; } /* clean_host() * * input - host to check - * output - 0 if erroneous, else 0 + * output - false if erroneous, else true * side effects - */ -static int +static bool clean_host(const char *host) { int len = 0; @@ -696,60 +558,60 @@ clean_host(const char *host) len++; if(!IsHostChar(*host)) - return 0; + return false; } if(len > HOSTLEN) - return 0; + return false; - return 1; + return true; } -static int -clean_uid(const char *uid) +static bool +clean_uid(const char *uid, const char *sid) { int len = 1; + if(strncmp(uid, sid, strlen(sid))) + return false; + if(!IsDigit(*uid++)) - return 0; + return false; for(; *uid; uid++) { len++; if(!IsIdChar(*uid)) - return 0; + return false; } if(len != IDLEN - 1) - return 0; + return false; - return 1; + return true; } static void set_initial_nick(struct Client *client_p, struct Client *source_p, char *nick) { - char buf[USERLEN + 1]; + char note[NICKLEN + 10]; /* This had to be copied here to avoid problems.. */ - source_p->tsinfo = CurrentTime; + source_p->tsinfo = rb_current_time(); if(source_p->name[0]) del_from_client_hash(source_p->name, source_p); - strcpy(source_p->name, nick); + rb_strlcpy(source_p->name, nick, sizeof(source_p->name)); add_to_client_hash(nick, source_p); - /* fd_desc is long enough */ - comm_note(client_p->localClient->F->fd, "Nick: %s", nick); + snprintf(note, sizeof(note), "Nick: %s", nick); + rb_note(client_p->localClient->F, note); if(source_p->flags & FLAGS_SENTUSER) { - strlcpy(buf, source_p->username, sizeof(buf)); - /* got user, heres nick. */ - register_local_user(client_p, source_p, buf); - + register_local_user(client_p, source_p); } } @@ -760,7 +622,9 @@ change_local_nick(struct Client *client_p, struct Client *source_p, struct Client *target_p; rb_dlink_node *ptr, *next_ptr; struct Channel *chptr; + char note[NICKLEN + 10]; int samenick; + hook_cdata hook_info; if (dosend) { @@ -772,13 +636,13 @@ change_local_nick(struct Client *client_p, struct Client *source_p, nick, chptr->chname); return; } - if((source_p->localClient->last_nick_change + ConfigFileEntry.max_nick_time) < CurrentTime) + if((source_p->localClient->last_nick_change + ConfigFileEntry.max_nick_time) < rb_current_time()) source_p->localClient->number_of_nick_changes = 0; - source_p->localClient->last_nick_change = CurrentTime; + source_p->localClient->last_nick_change = rb_current_time(); source_p->localClient->number_of_nick_changes++; - if(ConfigFileEntry.anti_nick_flood && !IsOper(source_p) && + if(ConfigFileEntry.anti_nick_flood && !IsOperGeneral(source_p) && source_p->localClient->number_of_nick_changes > ConfigFileEntry.max_nick_changes) { sendto_one(source_p, form_str(ERR_NICKTOOFAST), @@ -794,48 +658,51 @@ change_local_nick(struct Client *client_p, struct Client *source_p, if(!samenick) { /* force the TS to increase -- jilles */ - if (source_p->tsinfo >= CurrentTime) + if (source_p->tsinfo >= rb_current_time()) source_p->tsinfo++; else - source_p->tsinfo = CurrentTime; + source_p->tsinfo = rb_current_time(); monitor_signoff(source_p); /* we only do bancache for local users -- jilles */ if(source_p->user) invalidate_bancache_user(source_p); } + hook_info.client = source_p; + hook_info.arg1 = source_p->name; + hook_info.arg2 = nick; + call_hook(h_local_nick_change, &hook_info); + sendto_realops_snomask(SNO_NCHANGE, L_ALL, "Nick change: From %s to %s [%s@%s]", source_p->name, nick, source_p->username, source_p->host); /* send the nick change to the users channels */ - sendto_common_channels_local(source_p, ":%s!%s@%s NICK :%s", + sendto_common_channels_local(source_p, NOCAPS, NOCAPS, ":%s!%s@%s NICK :%s", source_p->name, source_p->username, source_p->host, nick); /* send the nick change to servers.. */ if(source_p->user) { - add_history(source_p, 1); + whowas_add_history(source_p, 1); if (dosend) { sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld", use_id(source_p), nick, (long) source_p->tsinfo); - sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s NICK %s :%ld", - source_p->name, nick, (long) source_p->tsinfo); } } /* Finally, add to hash */ del_from_client_hash(source_p->name, source_p); - strcpy(source_p->name, nick); + rb_strlcpy(source_p->name, nick, sizeof(source_p->name)); add_to_client_hash(nick, source_p); if(!samenick) monitor_signon(source_p); /* Make sure everyone that has this client on its accept list - * loses that reference. + * loses that reference. */ /* we used to call del_all_accepts() here, but theres no real reason * to clear a clients own list of accepted clients. So just remove @@ -845,12 +712,12 @@ change_local_nick(struct Client *client_p, struct Client *source_p, { target_p = ptr->data; - dlinkFindDestroy(source_p, &target_p->localClient->allow_list); - dlinkDestroy(ptr, &source_p->on_allow_list); + rb_dlinkFindDestroy(source_p, &target_p->localClient->allow_list); + rb_dlinkDestroy(ptr, &source_p->on_allow_list); } - /* fd_desc is long enough */ - comm_note(client_p->localClient->F->fd, "Nick: %s", nick); + snprintf(note, sizeof(note), "Nick: %s", nick); + rb_note(client_p->localClient->F, note); return; } @@ -858,42 +725,46 @@ change_local_nick(struct Client *client_p, struct Client *source_p, /* * change_remote_nick() */ -static int +static void change_remote_nick(struct Client *client_p, struct Client *source_p, time_t newts, const char *nick, int dosend) { struct nd_entry *nd; int samenick = irccmp(source_p->name, nick) ? 0 : 1; + hook_cdata hook_info; /* client changing their nick - dont reset ts if its same */ if(!samenick) { - source_p->tsinfo = newts ? newts : CurrentTime; + source_p->tsinfo = newts ? newts : rb_current_time(); monitor_signoff(source_p); } - sendto_common_channels_local(source_p, ":%s!%s@%s NICK :%s", + hook_info.client = source_p; + hook_info.arg1 = source_p->name; + hook_info.arg2 = nick; + call_hook(h_remote_nick_change, &hook_info); + + sendto_common_channels_local(source_p, NOCAPS, NOCAPS, ":%s!%s@%s NICK :%s", source_p->name, source_p->username, source_p->host, nick); if(source_p->user) { - add_history(source_p, 1); + whowas_add_history(source_p, 1); if (dosend) { sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld", use_id(source_p), nick, (long) source_p->tsinfo); - sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s NICK %s :%ld", - source_p->name, nick, (long) source_p->tsinfo); } } del_from_client_hash(source_p->name, source_p); /* invalidate nick delay when a remote client uses the nick.. */ - if((nd = irc_dictionary_retrieve(nd_dict, nick))) + if((nd = rb_dictionary_retrieve(nd_dict, nick))) free_nd_entry(nd); - strcpy(source_p->name, nick); + rb_strlcpy(source_p->name, nick, sizeof(source_p->name)); add_to_client_hash(nick, source_p); if(!samenick) @@ -901,11 +772,9 @@ change_remote_nick(struct Client *client_p, struct Client *source_p, /* remove all accepts pointing to the client */ del_all_accepts(source_p); - - return 0; } -static int +static void perform_nick_collides(struct Client *source_p, struct Client *client_p, struct Client *target_p, int parc, const char *parv[], time_t newts, const char *nick, const char *uid) @@ -921,14 +790,14 @@ perform_nick_collides(struct Client *source_p, struct Client *client_p, /* if we dont have a ts, or their TS's are the same, kill both */ if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo)) { - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_SKILL, L_NETWIDE, "Nick collision on %s(%s <- %s)(both %s)", target_p->name, target_p->from->name, client_p->name, action); if (use_save) { save_user(&me, &me, target_p); - ServerStats->is_save++; + ServerStats.is_save++; sendto_one(client_p, ":%s SAVE %s %ld", me.id, uid, (long)newts); register_client(client_p, source_p, @@ -948,12 +817,12 @@ perform_nick_collides(struct Client *source_p, struct Client *client_p, /* we then need to KILL the old client everywhere */ kill_client_serv_butone(NULL, target_p, "%s (Nick collision (new))", me.name); - ServerStats->is_kill++; + ServerStats.is_kill++; target_p->flags |= FLAGS_KILLED; exit_client(client_p, target_p, &me, "Nick collision (new)"); } - return 0; + return; } /* the timestamps are different */ else @@ -979,29 +848,29 @@ perform_nick_collides(struct Client *source_p, struct Client *client_p, sendto_one(client_p, ":%s KILL %s :%s (Nick collision (new))", me.id, uid, me.name); - return 0; + return; } else { if(sameuser) - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_SKILL, L_NETWIDE, "Nick collision on %s(%s <- %s)(older %s)", target_p->name, target_p->from->name, client_p->name, action); else - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_SKILL, L_NETWIDE, "Nick collision on %s(%s <- %s)(newer %s)", target_p->name, target_p->from->name, client_p->name, action); if (use_save) { - ServerStats->is_save++; + ServerStats.is_save++; save_user(&me, &me, target_p); } else { - ServerStats->is_kill++; + ServerStats.is_kill++; sendto_one_numeric(target_p, ERR_NICKCOLLISION, form_str(ERR_NICKCOLLISION), target_p->name); @@ -1013,16 +882,14 @@ perform_nick_collides(struct Client *source_p, struct Client *client_p, (void) exit_client(client_p, target_p, &me, "Nick collision"); } - register_client(client_p, parc >= 10 ? source_p : NULL, + register_client(client_p, source_p, nick, newts, parc, parv); - - return 0; } } } -static int +static void perform_nickchange_collides(struct Client *source_p, struct Client *client_p, struct Client *target_p, int parc, const char *parv[], time_t newts, const char *nick) @@ -1038,14 +905,14 @@ perform_nickchange_collides(struct Client *source_p, struct Client *client_p, /* its a client changing nick and causing a collide */ if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo) || !source_p->user) { - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_SKILL, L_NETWIDE, "Nick change collision from %s to %s(%s <- %s)(both %s)", source_p->name, target_p->name, target_p->from->name, client_p->name, action); if (use_save) { - ServerStats->is_save += 2; + ServerStats.is_save += 2; save_user(&me, &me, target_p); sendto_one(client_p, ":%s SAVE %s %ld", me.id, source_p->id, (long)newts); @@ -1055,13 +922,13 @@ perform_nickchange_collides(struct Client *source_p, struct Client *client_p, } else { - ServerStats->is_kill++; + ServerStats.is_kill++; sendto_one_numeric(target_p, ERR_NICKCOLLISION, form_str(ERR_NICKCOLLISION), target_p->name); kill_client_serv_butone(NULL, source_p, "%s (Nick change collision)", me.name); - ServerStats->is_kill++; + ServerStats.is_kill++; kill_client_serv_butone(NULL, target_p, "%s (Nick change collision)", me.name); @@ -1070,7 +937,7 @@ perform_nickchange_collides(struct Client *source_p, struct Client *client_p, source_p->flags |= FLAGS_KILLED; exit_client(client_p, source_p, &me, "Nick collision(old)"); } - return 0; + return; } else { @@ -1081,19 +948,19 @@ perform_nickchange_collides(struct Client *source_p, struct Client *client_p, (!sameuser && newts > target_p->tsinfo)) { if(sameuser) - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_SKILL, L_NETWIDE, "Nick change collision from %s to %s(%s <- %s)(older %s)", source_p->name, target_p->name, target_p->from->name, client_p->name, action); else - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_SKILL, L_NETWIDE, "Nick change collision from %s to %s(%s <- %s)(newer %s)", source_p->name, target_p->name, target_p->from->name, client_p->name, action); if (use_save) { - ServerStats->is_save++; + ServerStats.is_save++; /* can't broadcast a SAVE because the * nickchange has happened at client_p * but not in other directions -- jilles */ @@ -1105,10 +972,10 @@ perform_nickchange_collides(struct Client *source_p, struct Client *client_p, } else { - ServerStats->is_kill++; + ServerStats.is_kill++; - sendto_one_numeric(target_p, ERR_NICKCOLLISION, - form_str(ERR_NICKCOLLISION), target_p->name); + sendto_one_numeric(source_p, ERR_NICKCOLLISION, + form_str(ERR_NICKCOLLISION), source_p->name); /* kill the client issuing the nickchange */ kill_client_serv_butone(client_p, source_p, @@ -1121,24 +988,24 @@ perform_nickchange_collides(struct Client *source_p, struct Client *client_p, else exit_client(client_p, source_p, &me, "Nick collision(new)"); } - return 0; + return; } else { if(sameuser) - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_SKILL, L_NETWIDE, "Nick collision on %s(%s <- %s)(older %s)", target_p->name, target_p->from->name, client_p->name, action); else - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_SKILL, L_NETWIDE, "Nick collision on %s(%s <- %s)(newer %s)", target_p->name, target_p->from->name, client_p->name, action); if (use_save) { - ServerStats->is_save++; + ServerStats.is_save++; save_user(&me, &me, target_p); } else @@ -1149,7 +1016,7 @@ perform_nickchange_collides(struct Client *source_p, struct Client *client_p, /* kill the client who existed before hand */ kill_client_serv_butone(client_p, target_p, "%s (Nick collision)", me.name); - ServerStats->is_kill++; + ServerStats.is_kill++; target_p->flags |= FLAGS_KILLED; (void) exit_client(client_p, target_p, &me, "Nick collision"); @@ -1158,11 +1025,9 @@ perform_nickchange_collides(struct Client *source_p, struct Client *client_p, } change_remote_nick(client_p, source_p, newts, nick, 1); - - return 0; } -static int +static void register_client(struct Client *client_p, struct Client *server, const char *nick, time_t newts, int parc, const char *parv[]) { @@ -1172,60 +1037,47 @@ register_client(struct Client *client_p, struct Client *server, const char *m; int flag; - if(server == NULL) - { - if((server = find_server(NULL, parv[7])) == NULL) - { - sendto_realops_snomask(SNO_GENERAL, L_ALL, - "Ghost killed: %s on invalid server %s", - nick, parv[7]); - sendto_one(client_p, ":%s KILL %s :%s (Server doesn't exist)", - get_id(&me, client_p), nick, me.name); - return 0; - } - } - source_p = make_client(client_p); user = make_user(source_p); - dlinkAddTail(source_p, &source_p->node, &global_client_list); + rb_dlinkAddTail(source_p, &source_p->node, &global_client_list); source_p->hopcount = atoi(parv[2]); source_p->tsinfo = newts; - strcpy(source_p->name, nick); - strlcpy(source_p->username, parv[5], sizeof(source_p->username)); - strlcpy(source_p->host, parv[6], sizeof(source_p->host)); - strlcpy(source_p->orighost, source_p->host, sizeof(source_p->orighost)); + rb_strlcpy(source_p->name, nick, sizeof(source_p->name)); + rb_strlcpy(source_p->username, parv[5], sizeof(source_p->username)); + rb_strlcpy(source_p->host, parv[6], sizeof(source_p->host)); + rb_strlcpy(source_p->orighost, source_p->host, sizeof(source_p->orighost)); if(parc == 12) { - strlcpy(source_p->info, parv[11], sizeof(source_p->info)); - strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost)); - strlcpy(source_p->id, parv[8], sizeof(source_p->id)); + rb_strlcpy(source_p->info, parv[11], sizeof(source_p->info)); + rb_strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost)); + rb_strlcpy(source_p->id, parv[8], sizeof(source_p->id)); add_to_id_hash(source_p->id, source_p); if (strcmp(parv[9], "*")) { - strlcpy(source_p->orighost, parv[9], sizeof(source_p->orighost)); + rb_strlcpy(source_p->orighost, parv[9], sizeof(source_p->orighost)); if (irccmp(source_p->host, source_p->orighost)) SetDynSpoof(source_p); } if (strcmp(parv[10], "*")) - strlcpy(source_p->user->suser, parv[10], sizeof(source_p->user->suser)); + rb_strlcpy(source_p->user->suser, parv[10], sizeof(source_p->user->suser)); } else if(parc == 10) { - strlcpy(source_p->info, parv[9], sizeof(source_p->info)); - strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost)); - strlcpy(source_p->id, parv[8], sizeof(source_p->id)); + rb_strlcpy(source_p->info, parv[9], sizeof(source_p->info)); + rb_strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost)); + rb_strlcpy(source_p->id, parv[8], sizeof(source_p->id)); add_to_id_hash(source_p->id, source_p); } else { - strlcpy(source_p->info, parv[8], sizeof(source_p->info)); + s_assert(0); } /* remove any nd entries for this nick */ - if((nd = irc_dictionary_retrieve(nd_dict, nick))) + if((nd = rb_dictionary_retrieve(nd_dict, nick))) free_nd_entry(nd); add_to_client_hash(nick, source_p); @@ -1271,7 +1123,7 @@ register_client(struct Client *client_p, struct Client *server, } if(IsOper(source_p) && !IsService(source_p)) - dlinkAddAlloc(source_p, &oper_list); + rb_dlinkAddAlloc(source_p, &oper_list); SetRemoteClient(source_p); @@ -1280,46 +1132,29 @@ register_client(struct Client *client_p, struct Client *server, source_p->servptr = server; - dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->users); - - /* fake direction */ - if(source_p->servptr->from != source_p->from) - { - struct Client *target_p = source_p->servptr->from; - - sendto_realops_snomask(SNO_DEBUG, L_ALL, - "Bad User [%s] :%s USER %s@%s %s, != %s[%s]", - client_p->name, source_p->name, - source_p->username, source_p->host, - server->name, target_p->name, target_p->from->name); - kill_client(client_p, source_p, - "%s (NICK from wrong direction (%s != %s))", - me.name, server->name, target_p->from->name); - source_p->flags |= FLAGS_KILLED; - return exit_client(source_p, source_p, &me, "USER server wrong direction"); - } + rb_dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->users); call_hook(h_new_remote_user, source_p); - return (introduce_client(client_p, source_p, user, nick, parc == 12)); + introduce_client(client_p, source_p, user, nick, parc == 12); } /* Check if we can do SAVE. target_p can be a client to save or a * server introducing a client -- jilles */ -static int +static bool can_save(struct Client *target_p) { struct Client *serv_p; if (MyClient(target_p)) - return 1; + return true; if (!has_id(target_p)) - return 0; + return false; serv_p = IsServer(target_p) ? target_p : target_p->servptr; while (serv_p != NULL && serv_p != &me) { if (!(serv_p->serv->caps & CAP_SAVE)) - return 0; + return false; serv_p = serv_p->servptr; } return serv_p == &me; @@ -1333,11 +1168,11 @@ save_user(struct Client *client_p, struct Client *source_p, { /* This shouldn't happen */ /* Note we only need SAVE support in this direction */ - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Killed %s!%s@%s for nick collision detected by %s (%s does not support SAVE)", target_p->name, target_p->username, target_p->host, source_p->name, target_p->from->name); kill_client_serv_butone(NULL, target_p, "%s (Nick collision (no SAVE support))", me.name); - ServerStats->is_kill++; + ServerStats.is_kill++; target_p->flags |= FLAGS_KILLED; (void) exit_client(NULL, target_p, &me, "Nick collision (no SAVE support)"); @@ -1347,8 +1182,6 @@ save_user(struct Client *client_p, struct Client *source_p, source_p->id, target_p->id, (long)target_p->tsinfo); sendto_server(client_p, NULL, CAP_TS6, CAP_SAVE, ":%s NICK %s :%ld", target_p->id, target_p->id, (long)SAVE_NICKTS); - sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s NICK %s :%ld", - target_p->name, target_p->id, (long)SAVE_NICKTS); if (!IsMe(client_p)) sendto_realops_snomask(SNO_SKILL, L_ALL, "Received SAVE message for %s from %s", @@ -1363,3 +1196,21 @@ save_user(struct Client *client_p, struct Client *source_p, else change_remote_nick(target_p, target_p, SAVE_NICKTS, target_p->id, 0); } + +static void bad_nickname(struct Client *client_p, const char *nick) +{ + char squitreason[100]; + + sendto_wallops_flags(UMODE_WALLOP, &me, + "Squitting %s because of bad nickname %s (NICKLEN mismatch?)", + client_p->name, nick); + sendto_server(NULL, NULL, CAP_TS6, NOCAPS, + ":%s WALLOPS :Squitting %s because of bad nickname %s (NICKLEN mismatch?)", + me.id, client_p->name, nick); + ilog(L_SERVER, "Link %s cancelled, bad nickname %s sent (NICKLEN mismatch?)", + client_p->name, nick); + + snprintf(squitreason, sizeof squitreason, + "Bad nickname introduced [%s]", nick); + exit_client(client_p, client_p, &me, squitreason); +}