Example #1
0
/*! \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;
}
Example #2
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]);
}
Example #3
0
/*! \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;
}
Example #4
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);
}