/*! \brief NICK 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 -> server nick change * - parv[0] = command * - parv[1] = nickname * - parv[2] = timestamp */ static int ms_nick(struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; if (parc != 3 || EmptyString(parv[parc - 1])) return 0; if (IsServer(source_p)) return 0; /* Servers can't change nicks.. */ if (check_clean_nick(source_p, parv[1], source_p->servptr)) return 0; /* If the nick doesn't exist, allow it and process like normal */ if ((target_p = hash_find_client(parv[1])) == NULL) change_remote_nick(source_p, parv); else if (IsUnknown(target_p)) { /* We're not living in the past anymore, an unknown client is local only. */ exit_client(target_p, "Overridden by other sign on"); change_remote_nick(source_p, parv); } else if (target_p == source_p) { if (strcmp(target_p->name, parv[1])) change_remote_nick(source_p, parv); } else if (perform_nick_change_collides(source_p, target_p, parc, parv)) change_remote_nick(source_p, parv); return 0; }
/*! \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; }
/*! \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); }
/* * 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); }