/*! \brief UID command handler (called by servers) * * \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 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] = ip * - parv[8] = uid * - parv[9] = ircname (gecos) * * 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] = ip * - parv[ 8] = uid * - parv[ 9] = services id (timestamp) * - parv[10] = ircname (gecos) */ static void ms_uid(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 < 10 || EmptyString(parv[parc-1])) return; if (check_clean_nick(client_p, source_p, parv[1], source_p) || check_clean_user(client_p, parv[1], parv[5], source_p) || check_clean_host(client_p, parv[1], parv[6], source_p)) return; newts = atol(parv[3]); svsid = parc == 11 ? parv[9] : "0"; /* * If there is an ID collision, kill our client, and kill theirs. * This may generate 401's, but it ensures that both clients always * go, even if the other server refuses to do the right thing. */ if ((target_p = hash_find_id(parv[8])) != NULL) { sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "ID collision on %s(%s <- %s)(both killed)", target_p->name, target_p->from->name, client_p->name); kill_client_ll_serv_butone(NULL, target_p, "%s (ID collision)", me.name); ++ServerStats.is_kill; AddFlag(target_p, FLAGS_KILLED); exit_client(target_p, &me, "ID Collision"); return; } if ((target_p = hash_find_client(parv[1])) == NULL) uid_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]); else if (IsUnknown(target_p)) { exit_client(target_p, &me, "Overridden"); uid_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], parv[8]); }
/*! \brief UID command handler * * \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 introducing new nick/UID (without services support) * - parv[0] = command * - parv[1] = nickname * - parv[2] = hop count * - parv[3] = TS * - parv[4] = umode * - parv[5] = username * - parv[6] = hostname * - parv[7] = ip * - parv[8] = uid * - parv[9] = ircname (gecos) * * server introducing new nick/UID (with services support) * - parv[ 0] = command * - parv[ 1] = nickname * - parv[ 2] = hop count * - parv[ 3] = TS * - parv[ 4] = umode * - parv[ 5] = username * - parv[ 6] = hostname * - parv[ 7] = ip * - parv[ 8] = uid * - parv[ 9] = services id (account name) * - parv[10] = ircname (gecos) */ static int ms_uid(struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; if (check_clean_nick(source_p, parv[1], source_p) || check_clean_user(source_p, parv[1], parv[5], source_p) || check_clean_host(source_p, parv[1], parv[6], source_p)) return 0; /* * If there is an ID collision, kill our client, and kill theirs. * This may generate 401's, but it ensures that both clients always * go, even if the other server refuses to do the right thing. */ if ((target_p = hash_find_id(parv[8]))) { sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE, "ID collision on %s(%s <- %s)(both killed)", target_p->name, target_p->from->name, source_p->from->name); sendto_server(NULL, 0, 0, ":%s KILL %s :%s (ID collision)", me.id, target_p->id, me.name); ++ServerStats.is_kill; AddFlag(target_p, FLAGS_KILLED); exit_client(target_p, "ID Collision"); return 0; } if ((target_p = hash_find_client(parv[1])) == NULL) uid_from_server(source_p, parc, parv); else if (IsUnknown(target_p)) { exit_client(target_p, "Overridden by other sign on"); uid_from_server(source_p, parc, parv); } else if (perform_uid_introduction_collides(source_p, target_p, parc, parv)) uid_from_server(source_p, parc, parv); 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); }