/*! \brief NICK command handler (called by servers and remotely * connected clients) * * \param client_p Pointer to allocated Client struct with physical connection * to this server, i.e. with an open socket connected. * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * * server -> server nick change * - parv[0] = sender prefix * - parv[1] = nickname * - parv[2] = TS when nick change * * server introducing new nick (without services support) * - 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 * * server introducing new nick (with services support) * - 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] = services id (timestamp) * - parv[9] = ircname */ static void ms_nick(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; time_t newts = 0; const char *svsid = "0"; if (parc < 3 || EmptyString(parv[parc - 1])) return; if (parc >= 9) { struct Client *server_p = hash_find_server(parv[7]); if (server_p == NULL) { sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "Invalid server %s from %s for NICK %s", parv[7], source_p->name, parv[1]); sendto_one(client_p, ":%s KILL %s :%s (Server doesn't exist!)", me.name, parv[1], me.name); return; } if (check_clean_nick(client_p, source_p, parv[1], server_p) || check_clean_user(client_p, parv[1], parv[5], server_p) || check_clean_host(client_p, parv[1], parv[6], server_p)) return; if (IsServer(source_p)) newts = atol(parv[3]); if (IsServer(source_p) && parc == 10) svsid = parv[8]; } else if (parc == 3) { if (IsServer(source_p)) /* Servers can't change nicks.. */ return; if (check_clean_nick(client_p, source_p, parv[1], source_p->servptr)) return; newts = atol(parv[2]); } /* If the nick doesnt exist, allow it and process like normal */ if ((target_p = hash_find_client(parv[1])) == NULL) nick_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]); else if (IsUnknown(target_p)) { /* We're not living in the past anymore, an unknown client is local only. */ exit_client(target_p, &me, "Overridden"); nick_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]); } else if (target_p == source_p) { if (strcmp(target_p->name, parv[1])) nick_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]); } else perform_nick_collides(source_p, client_p, target_p, parc, parv, newts, svsid, parv[1], parv[parc-1], NULL); }
static int perform_nick_collides(struct Client *source_p, struct Client *client_p, struct Client *target_p, int parc, char *parv[], time_t newts, char *nick) { int sameuser; /* server introducing new nick */ if(IsServer(source_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_flags(UMODE_ALL, L_ALL, "Nick collision on %s(%s <- %s)(both killed)", target_p->name, target_p->from->name, client_p->name); kill_client_serv_butone(NULL, target_p, "%s (Nick collision (new))", me.name); ServerStats->is_kill++; sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name, target_p->name, target_p->name); target_p->flags |= FLAGS_KILLED; exit_client(client_p, target_p, &me, "Nick collision (new)"); return 0; } /* the timestamps are different */ else { sameuser = (target_p->user) && !irccmp(target_p->username, parv[5]) && !irccmp(target_p->host, parv[6]); /* if the users are the same (loaded a client on a different server) * and the new users ts is older, or the users are different and the * new users ts is newer, ignore the new client and let it do the kill */ if((sameuser && newts < target_p->tsinfo) || (!sameuser && newts > target_p->tsinfo)) { return 0; } else { if(sameuser) sendto_realops_flags(UMODE_ALL, L_ALL, "Nick collision on %s(%s <- %s)(older killed)", target_p->name, target_p->from->name, client_p->name); else sendto_realops_flags(UMODE_ALL, L_ALL, "Nick collision on %s(%s <- %s)(newer killed)", target_p->name, target_p->from->name, client_p->name); ServerStats->is_kill++; sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name, target_p->name, target_p->name); /* if it came from a LL server, itd have been source_p, * so we dont need to mark target_p as known */ kill_client_serv_butone(source_p, target_p, "%s (Nick collision (new))", me.name); target_p->flags |= FLAGS_KILLED; (void) exit_client(client_p, target_p, &me, "Nick collision"); nick_from_server(client_p, source_p, parc, parv, newts, nick); return 0; } } } /* its a client changing nick and causing a collide */ if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo) || !source_p->user) { sendto_realops_flags(UMODE_ALL, L_ALL, "Nick change collision from %s to %s(%s <- %s)(both killed)", source_p->name, target_p->name, target_p->from->name, client_p->name); ServerStats->is_kill++; sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name, target_p->name, target_p->name); /* if we got the message from a LL, it knows about source_p */ kill_client_serv_butone(NULL, source_p, "%s (Nick change collision)", me.name); ServerStats->is_kill++; kill_client_serv_butone(NULL, target_p, "%s (Nick change collision)", me.name); target_p->flags |= FLAGS_KILLED; exit_client(NULL, target_p, &me, "Nick collision(new)"); source_p->flags |= FLAGS_KILLED; exit_client(client_p, source_p, &me, "Nick collision(old)"); return 0; } else { sameuser = !irccmp(target_p->username, source_p->username) && !irccmp(target_p->host, source_p->host); if((sameuser && newts < target_p->tsinfo) || (!sameuser && newts > target_p->tsinfo)) { if(sameuser) sendto_realops_flags(UMODE_ALL, L_ALL, "Nick change collision from %s to %s(%s <- %s)(older killed)", source_p->name, target_p->name, target_p->from->name, client_p->name); else sendto_realops_flags(UMODE_ALL, L_ALL, "Nick change collision from %s to %s(%s <- %s)(newer killed)", source_p->name, target_p->name, target_p->from->name, client_p->name); ServerStats->is_kill++; /* this won't go back to the incoming link, so LL doesnt matter */ kill_client_serv_butone(client_p, source_p, "%s (Nick change collision)", me.name); source_p->flags |= FLAGS_KILLED; if(sameuser) exit_client(client_p, source_p, &me, "Nick collision(old)"); else exit_client(client_p, source_p, &me, "Nick collision(new)"); return 0; } else { if(sameuser) sendto_realops_flags(UMODE_ALL, L_ALL, "Nick collision on %s(%s <- %s)(older killed)", target_p->name, target_p->from->name, client_p->name); else sendto_realops_flags(UMODE_ALL, L_ALL, "Nick collision on %s(%s <- %s)(newer killed)", target_p->name, target_p->from->name, client_p->name); kill_client_serv_butone(source_p, target_p, "%s (Nick collision)", me.name); ServerStats->is_kill++; sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name, target_p->name, target_p->name); target_p->flags |= FLAGS_KILLED; (void) exit_client(client_p, target_p, &me, "Nick collision"); } } /* we should only ever call nick_from_server() here, as * this is a client changing nick, not a new client */ nick_from_server(client_p, source_p, parc, parv, newts, nick); return 0; }
static void perform_nick_collides(struct Client *source_p, struct Client *client_p, struct Client *target_p, int parc, char *parv[], time_t newts, const char *svsid, char *nick, char *gecos, char *uid) { int sameuser = 0; /* Server introducing new nick */ if (IsServer(source_p)) { /* If we don't have a TS, or their TS's are the same, kill both */ if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo)) { sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "Nick collision on %s(%s <- %s)(both killed)", target_p->name, target_p->from->name, client_p->name); /* if we have a UID, issue a kill for it */ if (uid) sendto_one(client_p, ":%s KILL %s :%s (Nick collision (new))", me.id, uid, me.name); kill_client_ll_serv_butone(NULL, target_p, "%s (Nick collision (new))", me.name); ++ServerStats.is_kill; sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name, target_p->name, target_p->name); AddFlag(target_p, FLAGS_KILLED); exit_client(target_p, &me, "Nick collision (new)"); return; } /* the timestamps are different */ else { sameuser = !irccmp(target_p->username, parv[5]) && !irccmp(target_p->host, parv[6]); /* * If the users are the same (loaded a client on a different server) * and the new users ts is older, or the users are different and the * new users ts is newer, ignore the new client and let it do the kill */ if ((sameuser && newts < target_p->tsinfo) || (!sameuser && newts > target_p->tsinfo)) { if (uid) sendto_one(client_p, ":%s KILL %s :%s (Nick collision (new))", me.id, uid, me.name); return; } else { if (sameuser) sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "Nick collision on %s(%s <- %s)(older killed)", target_p->name, target_p->from->name, client_p->name); else sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "Nick collision on %s(%s <- %s)(newer killed)", target_p->name, target_p->from->name, client_p->name); ++ServerStats.is_kill; sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name, target_p->name, target_p->name); /* if it came from a LL server, itd have been source_p, * so we dont need to mark target_p as known */ kill_client_ll_serv_butone(source_p, target_p, "%s (Nick collision (new))", me.name); AddFlag(target_p, FLAGS_KILLED); exit_client(target_p, &me, "Nick collision"); if (!uid && (parc == 9 || parc == 10)) nick_from_server(client_p, source_p, parc, parv, newts, svsid, nick, gecos); else if (uid && (parc == 10 || parc == 11)) uid_from_server(client_p, source_p, parc, parv, newts, svsid, nick, gecos); return; } } } /* its a client changing nick and causing a collide */ if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo)) { sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "Nick change collision from %s to %s(%s <- %s)(both killed)", source_p->name, target_p->name, target_p->from->name, client_p->name); sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name, target_p->name, target_p->name); ++ServerStats.is_kill; kill_client_ll_serv_butone(NULL, source_p, "%s (Nick change collision)", me.name); ++ServerStats.is_kill; kill_client_ll_serv_butone(NULL, target_p, "%s (Nick change collision)", me.name); AddFlag(target_p, FLAGS_KILLED); exit_client(target_p, &me, "Nick collision (new)"); AddFlag(source_p, FLAGS_KILLED); exit_client(source_p, &me, "Nick collision (old)"); return; } else { sameuser = !irccmp(target_p->username, source_p->username) && !irccmp(target_p->host, source_p->host); if ((sameuser && newts < target_p->tsinfo) || (!sameuser && newts > target_p->tsinfo)) { if (sameuser) sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "Nick change collision from %s to %s(%s <- %s)(older killed)", source_p->name, target_p->name, target_p->from->name, client_p->name); else sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "Nick change collision from %s to %s(%s <- %s)(newer killed)", source_p->name, target_p->name, target_p->from->name, client_p->name); ++ServerStats.is_kill; kill_client_ll_serv_butone(client_p, source_p, "%s (Nick change collision)", me.name); AddFlag(source_p, FLAGS_KILLED); if (sameuser) exit_client(source_p, &me, "Nick collision (old)"); else exit_client(source_p, &me, "Nick collision (new)"); return; } else { if (sameuser) sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "Nick collision on %s(%s <- %s)(older killed)", target_p->name, target_p->from->name, client_p->name); else sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "Nick collision on %s(%s <- %s)(newer killed)", target_p->name, target_p->from->name, client_p->name); kill_client_ll_serv_butone(source_p, target_p, "%s (Nick collision)", me.name); ++ServerStats.is_kill; sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name, target_p->name, target_p->name); AddFlag(target_p, FLAGS_KILLED); exit_client(target_p, &me, "Nick collision"); } } /* * we should only ever call nick_from_server() here, as * this is a client changing nick, not a new client */ nick_from_server(client_p, source_p, parc, parv, newts, svsid, nick, gecos); }
/* * ms_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 void ms_nick(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p; char nick[NICKLEN]; time_t newts = 0; if(parc < 2 || BadPtr(parv[1])) { sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]); return; } /* parc == 3 on nickchange, parc == 9 on new nick */ if((IsClient(source_p) && (parc != 3)) || (IsServer(source_p) && ((parc != 9) && (parc != 10)))) { char tbuf[BUFSIZE] = { 0 }; int j; for (j = 0; j < parc; j++) { strcat(tbuf, parv[j]); strcat(tbuf, " "); } sendto_realops_flags(UMODE_ALL, L_ALL, "Dropping server %s due to (invalid) command 'NICK' " "with only %d arguments. (Buf: '%s')", client_p->name, parc, tbuf); ilog(L_CRIT, "Insufficient parameters (%d) for command 'NICK' from %s. Buf: %s", parc, client_p->name, tbuf); exit_client(client_p, client_p, client_p, "Not enough arguments to server command."); return; } /* fix the length of the nick */ strlcpy(nick, parv[1], sizeof(nick)); if ((parc == 9) || (parc == 10)) { if (check_clean_nick(client_p, source_p, nick, parv[1], parv[7])) return; } else { if (check_clean_nick(client_p, source_p, nick, parv[1], (char *)source_p->user->server)) return; } if(parc == 9 || parc == 10) { if(check_clean_user(client_p, nick, parv[5], parv[7]) || check_clean_host(client_p, nick, parv[6], parv[7])) return; /* check the length of the clients gecos */ if(strlen(parv[(parc > 9)? 9 : 8]) > REALLEN) { sendto_realops_flags(UMODE_ALL, L_ALL, "Long realname from server %s for %s", parv[7], parv[1]); parv[(parc > 9)? 9 : 8][REALLEN] = '\0'; } if(IsServer(source_p)) newts = atol(parv[3]); } else { if(!IsServer(source_p)) newts = atol(parv[2]); } /* if the nick doesnt exist, allow it and process like normal */ if(!(target_p = find_client(nick))) { nick_from_server(client_p, source_p, parc, parv, newts, nick); return; } /* we're not living in the past anymore, an unknown client is local only. */ if(IsUnknown(target_p)) { exit_client(NULL, target_p, &me, "Overridden"); nick_from_server(client_p, source_p, parc, parv, newts, nick); return; } if(target_p == source_p) { if(strcmp(target_p->name, nick)) { /* client changing case of nick */ nick_from_server(client_p, source_p, parc, parv, newts, nick); return; } else /* client not changing nicks at all */ return; } perform_nick_collides(source_p, client_p, target_p, parc, parv, newts, nick); }