/* check_clean_nick() * * input - pointer to source * - * - nickname * - truncated nickname * - origin of client * - pointer to server nick is coming from * output - none * side effects - if nickname is erroneous, or a different length to * truncated nickname, return 1 */ static int check_clean_nick(struct Client *client_p, struct Client *source_p, char *nick, struct Client *server_p) { /* the old code did some wacky stuff here, if the nick is invalid, kill it * and dont bother messing at all */ if (!clean_nick_name(nick, 0)) { ++ServerStats.is_kill; sendto_realops_flags(UMODE_DEBUG, L_ALL, "Bad/long Nick: %s From: %s(via %s)", nick, server_p->name, client_p->name); sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)", me.name, nick, me.name); /* bad nick change */ if (source_p != client_p) { kill_client_ll_serv_butone(client_p, source_p, "%s (Bad Nickname)", me.name); SetKilled(source_p); exit_client(source_p, &me, "Bad Nickname"); } return 1; } return 0; }
/* send_message_remote() * * inputs - pointer to client from message is being sent * - pointer to client to send to * - pointer to preformatted buffer * - length of input buffer * output - none * side effects - Despite the function name, this only sends to directly * connected clients. * */ static void send_message_remote(struct Client *to, struct Client *from, char *buf, int len) { if (!MyConnect(to)) { sendto_realops_flags(UMODE_ALL, L_ALL, "server send message to %s [%s] dropped from %s(Not local server)", to->name, to->from->name, from->name); return; } /* Optimize by checking if (from && to) before everything */ /* we set to->from up there.. */ if (!MyClient(from) && IsPerson(to) && (to == from->from)) { if (IsServer(from)) { sendto_realops_flags(UMODE_ALL, L_ALL, "Send message to %s [%s] dropped from %s(Fake Dir)", to->name, to->from->name, from->name); return; } sendto_realops_flags(UMODE_ALL, L_ALL, "Ghosted: %s[%s@%s] from %s[%s@%s] (%s)", to->name, to->username, to->host, from->name, from->username, from->host, to->from->name); sendto_server(NULL, CAP_TS6, NOCAPS, ":%s KILL %s :%s (%s[%s@%s] Ghosted %s)", me.id, to->name, me.name, to->name, to->username, to->host, to->from->name); sendto_server(NULL, NOCAPS, CAP_TS6, ":%s KILL %s :%s (%s[%s@%s] Ghosted %s)", me.name, to->name, me.name, to->name, to->username, to->host, to->from->name); SetKilled(to); if (IsPerson(from)) sendto_one(from, form_str(ERR_GHOSTEDCLIENT), me.name, from->name, to->name, to->username, to->host, to->from); exit_client(NULL, to, &me, "Ghosted client"); return; } send_message(to, buf, len); }
/*! \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: * * - 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) */ 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; if (parc != 10 || EmptyString(parv[9])) 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]); /* * 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, "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; SetKilled(target_p); exit_client(target_p, &me, "ID Collision"); return; } if ((target_p = find_client(parv[1])) == NULL) uid_from_server(client_p, source_p, parc, parv, newts, parv[1], parv[9]); else if (IsUnknown(target_p)) { exit_client(target_p, &me, "Overridden"); uid_from_server(client_p, source_p, parc, parv, newts, parv[1], parv[9]); } else perform_nick_collides(source_p, client_p, target_p, parc, parv, newts, parv[1], parv[9], parv[8]); }
static void perform_nick_collides(struct Client *source_p, struct Client *client_p, struct Client *target_p, int parc, char *parv[], time_t newts, char *nick, char *gecos, char *uid) { 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); /* 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); SetKilled(target_p); 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, "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_ll_serv_butone(source_p, target_p, "%s (Nick collision (new))", me.name); SetKilled(target_p); exit_client(target_p, &me, "Nick collision"); if (parc == 9) nick_from_server(client_p, source_p, parc, parv, newts, nick, gecos); else if (parc == 10) uid_from_server(client_p, source_p, parc, parv, newts, 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, "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); SetKilled(target_p); exit_client(target_p, &me, "Nick collision (new)"); SetKilled(source_p); 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, "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; kill_client_ll_serv_butone(client_p, source_p, "%s (Nick change collision)", me.name); SetKilled(source_p); 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, "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_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); SetKilled(target_p); 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, nick, gecos); }