/*! \brief PONG 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: * - parv[0] = command * - parv[1] = origin * - parv[2] = destination */ static int ms_pong(struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; const char *destination = NULL; if (parc < 2 || EmptyString(parv[1])) { sendto_one_numeric(source_p, &me, ERR_NOORIGIN); return 0; } destination = parv[2]; /* Now attempt to route the PONG, comstud pointed out routable PING * is used for SPING. routable PING should also probably be left in * -Dianora * That being the case, we will route, but only for registered clients (a * case can be made to allow them only from servers). -Shadowfax */ if (!EmptyString(destination) && match(destination, me.name) && irccmp(destination, me.id)) { if ((target_p = hash_find_client(destination)) || (target_p = hash_find_id(destination))) sendto_one(target_p, ":%s PONG %s %s", ID_or_name(source_p, target_p), parv[1], ID_or_name(target_p, target_p)); else if (!IsDigit(*destination)) sendto_one_numeric(source_p, &me, ERR_NOSUCHSERVER, destination); } 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; }
/* * parse a buffer. * * NOTE: parse() should not be called recusively by any other functions! */ void parse(struct Client *client_p, char *pbuffer, char *bufend) { struct Client *from = client_p; struct Message *message = NULL; char *para[MAXPARA + 2]; /* <command> + <parameters> + NULL */ char *ch = NULL; char *s = NULL; unsigned int numeric = 0; unsigned int parc = 0; unsigned int paramcount; if (IsDead(client_p)) return; assert(client_p->connection); assert(client_p->connection->fd); assert(client_p->connection->fd->flags.open); assert((bufend - pbuffer) < IRCD_BUFSIZE); for (ch = pbuffer; *ch == ' '; ++ch) /* Skip spaces */ ; if (*ch == ':') { /* * Copy the prefix to 'sender' assuming it terminates * with SPACE (or NULL, which is an error, though). */ const char *const sender = ++ch; if ((s = strchr(ch, ' '))) { *s = '\0'; ch = ++s; } if (*sender && IsServer(client_p)) { if ((from = hash_find_id(sender)) == NULL) from = hash_find_client(sender); /* * Hmm! If the client corresponding to the prefix is not found--what is * the correct action??? Now, I will ignore the message (old IRC just * let it through as if the prefix just wasn't there...) --msa */ if (from == NULL) { ++ServerStats.is_unpf; parse_remove_unknown(client_p, sender, pbuffer); return; } if (from->from != client_p) { ++ServerStats.is_wrdi; sendto_realops_flags(UMODE_DEBUG, L_ADMIN, SEND_NOTICE, "Fake direction: dropped message from %s[%s] via %s", from->name, from->from->name, client_get_name(client_p, SHOW_IP)); sendto_realops_flags(UMODE_DEBUG, L_OPER, SEND_NOTICE, "Fake direction: dropped message from %s[%s] via %s", from->name, from->from->name, client_get_name(client_p, MASK_IP)); return; } } while (*ch == ' ') ++ch; } if (*ch == '\0') { ++ServerStats.is_empt; return; } /* * Extract the command code from the packet. Point s to the end * of the command code and calculate the length using pointer * arithmetic. Note: only need length for numerics and *all* * numerics must have parameters and thus a space after the command * code. -avalon */ /* EOB is 3 characters long but is not a numeric */ if (*(ch + 3) == ' ' && /* Ok, let's see if it's a possible numeric */ IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2))) { numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10 + (*(ch + 2) - '0'); paramcount = 2; /* Destination, and the rest of it */ ++ServerStats.is_num; s = ch + 3; /* I know this is ' ' from above if */ *s++ = '\0'; /* Blow away the ' ', and point s to next part */ } else { if ((s = strchr(ch, ' '))) *s++ = '\0'; if ((message = find_command(ch)) == NULL) { /* * Note: Give error message *only* to recognized * persons. It's a nightmare situation to have * two programs sending "Unknown command"'s or * equivalent to each other at full blast.... * If it has got to person state, it at least * seems to be well behaving. Perhaps this message * should never be generated, though... --msa * Hm, when is the buffer empty -- if a command * code has been found ?? -Armin */ if (*pbuffer) if (IsClient(from)) sendto_one_numeric(from, &me, ERR_UNKNOWNCOMMAND, ch); ++ServerStats.is_unco; return; } assert(message->cmd); paramcount = message->args_max; size_t length = bufend - ((s) ? s : ch); message->bytes += length; } /* * Must the following loop really be so devious? On surface it * splits the message to parameters from blank spaces. But, if * paramcount has been reached, the rest of the message goes into * this last parameter (about same effect as ":" has...) --msa */ /* Note initially true: s == NULL || *(s - 1) == '\0' !! */ para[parc] = ch; if (message && (message->flags & MFLG_EXTRA)) { /* * XXX: This will have to go away after the command handler rewrite */ para[++parc] = message->extra; } if (s) { if (paramcount > MAXPARA) paramcount = MAXPARA; while (true) { while (*s == ' ') *s++ = '\0'; if (*s == '\0') break; if (*s == ':') { /* The rest is single parameter--can include blanks also. */ para[++parc] = s + (numeric == 0); /* Keep the colon if it's a numeric */ break; } para[++parc] = s; if (parc >= paramcount) break; while (*s && *s != ' ') ++s; } } para[++parc] = NULL; if (message) parse_handle_command(message, from, parc, para); else parse_handle_numeric(numeric, from, parc, para); }