Logo Search packages:      
Sourcecode: rageircd version File versions  Download package

parse.c

/*
 * RageIRCd: an advanced Internet Relay Chat daemon (ircd).
 * (C) 2000-2005 the RageIRCd Development Team, all rights reserved.
 *
 * This software is free, licensed under the General Public License.
 * Please refer to doc/LICENSE and doc/README for further details.
 *
 * $Id: parse.c,v 1.145.2.2 2004/12/13 23:33:06 amcwilliam Exp $
 */

#include "struct.h"
#include "common.h"
#include "setup.h"
#define INCLUDE_MSG_PTR
#include "msg.h"
#undef INCLUDE_MSG_PTR
#include "sys.h"
#include "numeric.h"
#include "h.h"
#include "memory.h"
#include "xmode.h"

#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif

#ifndef STATIC_MODULES
static char *core_commands[] = {
      "JOIN", "KICK", "NOTICE", "PRIVMSG",
      "MODE", "NICK", "PART", "PING",
      "PONG", "QUIT", "USER", NULL
};
#endif

static char *para[MAXPARA + 1];
static char sender[HOSTLEN + 1];

Command *command_table[256];
Command *token_table[256];

void init_command_table(void)
{
      memset(command_table, '\0', sizeof(command_table));
      memset(token_table, '\0', sizeof(token_table));
}

static inline Command *find_command(char *msg, int (*func)(), int no_tok1only)
{
      Command *cmd;

      for (cmd = command_table[ToUpper(*msg)]; cmd != NULL; cmd = cmd->next) {
            ASSERT(cmd->msg != NULL);

            if (no_tok1only && (cmd->msg->flags & CMDFLAG_TOK1ONLY)) {
                  continue;
            }
            if (mycmp(cmd->msg->msg_str, msg)) {
                  continue;
            }
            if (func == NULL || (func != NULL && (cmd->func == func))) {
                  return cmd;
            }
      }
      return NULL;
}

#ifndef STATIC_MODULES
int check_core_commands()
{
      int i, retval = 1;

      for (i = 0; core_commands[i] != NULL; i++) {
            if (!find_command(core_commands[i], NULL, 1)) {
                  report(1, "ERROR: core command %s cannot be found.", core_commands[i]);
                  retval = 0;
            }
      }

      return retval;
}
#endif

Command *add_command(msg_ptr *msg, int (*func)())
{
      Command *cmd = NULL;

      if (msg->tok_str != NULL) {
            cmd = token_table[(unsigned char)*msg->tok_str];
      }
      if (cmd == NULL) {
            cmd = find_command(msg->msg_str, NULL, 1);
      }
      if (cmd != NULL) {
            ircdlog(LOG_ERROR, "Ignoring duplicate command %s[%s] (already exists!)",
                  msg->msg_str, msg->tok_str != NULL ? msg->tok_str : "NO TOKEN");
            return NULL;
      }

      if (msg->tok_str != NULL && (token_table[(unsigned char)*msg->tok_str] != NULL)) {
            ircdlog(LOG_ERROR, "TOKEN COLLISION! [%s] %s-vs-%s", msg->tok_str,
                  msg->msg_str, token_table[(unsigned char)*msg->tok_str]->msg);
            return NULL;
      }

      cmd = (Command *)MyMalloc(sizeof(Command));
      cmd->msg = msg;
      cmd->func = func;
      cmd->count = 0;
      cmd->bytes = 0L;
      cmd->prev = NULL;

      if ((cmd->next = command_table[ToUpper(*msg->msg_str)]) != NULL) {
            cmd->next->prev = cmd;
      }
      command_table[ToUpper(*msg->msg_str)] = cmd;

      if (msg->tok_str != NULL) {
            token_table[(unsigned char)*msg->tok_str] = cmd;
      }

      return cmd;
}

static inline void del_one_command(Command *cmd)
{
      ASSERT(cmd != NULL);

      if (cmd->prev != NULL) {
            cmd->prev->next = cmd->next;
      }
      else {
            command_table[ToUpper(*cmd->msg->msg_str)] = cmd->next;
      }
      if (cmd->next != NULL) {
            cmd->next->prev = cmd->prev;
      }
      MyFree(cmd);
}

int del_command(msg_ptr *msg, int (*func)())
{
      Command *cmd = NULL;

      ASSERT(msg != NULL);
      if (msg->tok_str != NULL) {
            if (token_table[(unsigned char)*msg->tok_str] == NULL) {
                  ircdlog(LOG_ERROR, "Attempted to remove command (%s) with unknown token %s",
                        msg->msg_str, msg->tok_str);
                  return 0;
            }
            if (token_table[(unsigned char)*msg->tok_str]->func != func) {
                  ircdlog(LOG_ERROR, "Function mismatch removing token %s (do you two coppies "
                        "of a single function loaded?!)", msg->tok_str);
                  return 0;
            }
            cmd = token_table[(unsigned char)*msg->tok_str];
            token_table[(unsigned char)*msg->tok_str] = NULL;
      }
      if (cmd == NULL) {
            cmd = find_command(msg->msg_str, func, 0);
      }
      if (cmd == NULL) {
            Debug((DEBUG_DEBUG, "del_command(%s[%s]) ignoring unknown command", msg->msg_str,
                  msg->tok_str != NULL ? msg->tok_str : "NO TOKEN"));
            return 0;
      }

      del_one_command(cmd);
      return 1;
}

int del_command_cmd(Command *cmd)
{
      ASSERT(cmd != NULL);
      ASSERT(cmd->msg != NULL);

      if (cmd->msg->tok_str != NULL) {
            unsigned char t = (unsigned char)*cmd->msg->tok_str;

            if (token_table[t] != NULL && (token_table[t] == cmd)) {
                  token_table[t] = NULL;
            }
      }

      del_one_command(cmd);
      return 1;
}

static int cancel_clients(aClient *cptr, aClient *sptr, char *cmd)
{
      if (IsServer(sptr) || IsMe(sptr)) {
            sendto_realops_lev(DEBUG_LEV, "Message for %s[%s] from %s", sptr->name,
                  sptr->from->name, get_client_name(cptr, IsServer(cptr) ? HIDE_IP : SHOW_IP));
            if (IsServer(cptr)) {
                  sendto_realops_lev(DEBUG_LEV, "Not dropping server %s (%s) for Fake "
                        "Direction", cptr->name, sptr->name);
            }
            else if (IsClient(cptr)) {
                  sendto_realops_lev(DEBUG_LEV, "Would have dropped client %s (%s@%s) "
                        "[%s from %s]", cptr->name, cptr->username, cptr->host,
                        cptr->user->server, cptr->from->name);
            }
            return -1;
      }
      if (IsServer(cptr)) {
            if (CapTS(cptr)) {
                  if (sptr->user != NULL) {
                        sendto_realops_lev(DEBUG_LEV, "Message for %s[%s@%s!%s] from %s "
                              "(TS, ignored)", sptr->name, sptr->username, sptr->host,
                              sptr->from->name, get_client_name(cptr, SHOW_IP));
                        ircdlog(LOG_ERROR, "Ignoring message for %s[%s@%s!%s] from %s (TS): %s",
                              sptr->name, sptr->username, sptr->host, sptr->from->name,
                              get_client_name(cptr, SHOW_IP), cmd);
                  }
                  return 0;
            }

            if (sptr->user != NULL) {
                  sendto_realops_lev(DEBUG_LEV, "Message for %s[%s@%s!%s] from %s",
                        sptr->name, sptr->username, sptr->host, sptr->from->name,
                        get_client_name(cptr, IsServer(cptr) ? HIDE_IP : SHOW_IP));
            }
            if (IsULine(sptr)) {
                  sendto_realops_lev(DEBUG_LEV, "Would have killed super client %s "
                        "for Fake Direction", sptr->name);
                  return 0;
            }

            sendto_serv_kill_msg_butone(NULL, &me, sptr, ":%s (%s[%s] != %s, Fake Prefix)",
                  me.name, sptr->name, sptr->from->name,
                  get_client_name(cptr, IsServer(cptr) ? HIDE_IP : SHOW_IP));
            SetKilled(sptr);
            return exit_client(cptr, sptr, &me, "Fake Prefix");
      }
      return exit_client(cptr, cptr, &me, "Fake Prefix");
}

static void remove_unknown(aClient *cptr, char *sent_by, char *buffer)
{
      if (!IsRegistered(cptr) || IsClient(cptr) || !IsServer(cptr)) {
            if (IsClient(cptr)) {
                  sendto_realops_lev(DEBUG_LEV, "Weirdness: Unknown client prefix (%s) from "
                        "%s, Ignoring %s", buffer, get_client_name(cptr, FALSE), sent_by);
            }
      }
      else if (!strchr(sent_by, '.')) {
            sendto_one_client_nopostfix(cptr, &me, &CMD_KILL, "%s :%s (%s(?) <- %s)", sent_by,
                  me.name, sent_by, get_client_name(cptr, FALSE));
      }
      else {
            sendto_realops_lev(DEBUG_LEV, "Unknown prefix (%s) from %s, SQUITing %s", buffer,
                  get_client_name(cptr, HIDE_IP), sent_by);
            sendto_one_client_nopostfix(cptr, &me, &CMD_SQUIT, "%s :Unknown prefix (%s) from %s",
                  sent_by, buffer, get_client_name(cptr, HIDE_IP));
      }
}

int serv_parse(aClient *cptr, char *buffer, char *bufend)
{
      aClient *from = cptr;
      char *ch, *s;
      int i, numeric = 0, paramcount;
      Command *cmd = NULL;

      if (!IsServer(cptr) && !IsConnecting(cptr) && !IsHandshake(cptr) && !DoingDKEY(cptr)) {
            ircdlog(LOG_ERROR, "FATAL: serv_parse() called for a non-server! [%s]", buffer);
            abort();
      }

      Debug((DEBUG_DEBUG, "Parsing %s: %s", get_client_name(cptr, SHOW_IP), buffer));

      if (DeadSocket(cptr)) {
            return -1;
      }

      s = sender;
      *s = '\0';
      for (ch = buffer; *ch == ' '; ch++);

      para[0] = from->name;

      if (*ch == ':') {
            for (++ch; *ch != '\0' && *ch != ' '; ++ch) {
                  if (s < (sender + HOSTLEN)) {
                        *s++ = *ch;
                  }
            }
            *s = '\0';

            if (*sender != '\0') {
                  Debug((DEBUG_DEBUG, "SERVER: got sender %s [%s]", sender,
                        is_id(sender) ? "SID" : "SERVNICK"));
                  from = is_id(sender) ? find_by_base64_id(sender) : find_client(sender, NULL);

                  if (from == NULL) {
                        Debug((DEBUG_ERROR, "Unknown SERV prefix (%s)(%s) from (%s)", sender,
                              buffer, cptr->name));
                        ircstp->is_unpf++;
                        remove_unknown(cptr, sender, buffer);
                        return -1;
                  }

                  para[0] = from->name;

                  if (from->from != cptr) {
                        ircstp->is_wrdi++;
                        Debug((DEBUG_ERROR, "Message (%s) coming from SERV (%s)", buffer, cptr->name));
                        return cancel_clients(cptr, from, buffer);
                  }
            }
            while (*ch == ' ') {
                  ch++;
            }
      }
                        
      if (*ch == '\0') {
            ircstp->is_empt++;
            Debug((DEBUG_NOTICE, "Empty message from host %s:%s", cptr->name, from->name));
            return -1;
      }

      if (*(ch + 1) == ' ' || *(ch + 1) == '\0') {
            if (token_table[(unsigned char)*ch] != NULL) {
                  cmd = token_table[(unsigned char)*ch];
            }
            if (cmd == NULL) {
                  if (buffer[0] != '\0') {
                        Debug((DEBUG_ERROR, "[serv, tok] unknown (%s) from %s", ch,
                              get_client_name(cptr, SHOW_IP)));
                  }
                  ircstp->is_unco++;
                  return -1;
            }

            paramcount = (cmd->msg->flags & CMDFLAG_SINGLEPARA) ? 1 : MAXPARA;
            i = bufend - ((s != NULL) ? s : ch);
            cmd->bytes += i;
            s = (ch + 1);

            if (*s != '\0') {
                  *s++ = '\0';
            }
            else {
                  s = NULL;
            }
      }
      else if (*(ch + 3) == ' ' && IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2))) {
            cmd = NULL;
            numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10 + (*(ch + 2) - '0');
            paramcount = MAXPARA;
            ircstp->is_num++;
            s = (ch + 3);
            *s++ = '\0';
      }
      else {
            if ((s = strchr(ch, ' ')) != NULL) {
                  *s++ = '\0';
            }
            if ((cmd = find_command(ch, NULL, 1)) == NULL) {
                  if (buffer[0] != '\0') {
                        Debug((DEBUG_ERROR, "[serv] unknown (%s) from %s", ch, get_client_name(cptr, SHOW_IP)));
                  }
                  ircstp->is_unco++;
                  return -1;
            }
            paramcount = (cmd->msg->flags & CMDFLAG_SINGLEPARA) ? 1 : MAXPARA;
            i = bufend - (s != NULL ? s : ch);
            cmd->bytes += i;
      }

      i = 1;
      if (s != NULL) {
            for (;;) {
                  while (*s == ' ') {
                        *s++ = '\0';
                  }
                  if (*s == '\0') {
                        break;
                  }
                  if (*s == ':') {
                        para[i++] = (s + 1);
                        break;
                  }

                  para[i++] = s;
                  if (i >= paramcount) {
                        if (paramcount == MAXPARA && strchr(s, ' ')) {
                              sendto_realops_lev(DEBUG_LEV, "Overflowed MAXPARA on "
                                    "%s from %s",
                                    cmd != NULL ? cmd->msg->msg_str : "numeric",
                                    get_client_name(cptr, HIDE_IP));
                              ircdlog(LOG_ERROR, "Overflowed MAXPARA on %s from %s",
                                    cmd != NULL ? cmd->msg->msg_str : "numeric",
                                    get_client_name(cptr, SHOW_IP));
                        }
                        break;
                  }
                  while (*s != '\0' && *s != ' ') {
                        s++;
                  }
            }
      }

      para[i] = NULL;
      if (cmd == NULL) {
            return do_numeric(numeric, cptr, from, i, para);
      }

      cmd->count++;
      return (*cmd->func)(cptr, from, i, para);
}

int user_parse(aClient *cptr, char *buffer, char *bufend)
{
      aClient *from = cptr;
      char *ch, *s;
      int i, paramcount = 0;
      Command *cmd = NULL;

      if (IsServer(cptr)) {
            ircdlog(LOG_ERROR, "FATAL: user_parse() called for a server! [%s]", buffer);
            abort();
      }

      Debug((DEBUG_DEBUG, "Parsing %s: %s", get_client_name(cptr, SHOW_IP), buffer));

      if (DeadSocket(cptr)) {
            return -1;
      }

      for (ch = buffer; *ch == ' '; ch++);

      para[0] = from->name;
      if (*ch == ':') {
            while (*ch != '\0' && *ch != ' ') {
                  ch++;
            }
            while (*ch == ' ') {
                  ch++;
            }
      }
      if (*ch == '\0') {
            ircstp->is_empt++;
            Debug((DEBUG_NOTICE, "Empty message from host %s:%s", cptr->name, from->name));
            return -1;
      }

      if ((s = strchr(ch, ' ')) != NULL) {
            *s++ = '\0';
      }
      if ((cmd = find_command(ch, NULL, 1)) == NULL) {
            if (buffer[0] != '\0') {
                  if (IsPerson(from)) {
                        send_me_numeric(from, ERR_UNKNOWNCOMMAND, ch);
                  }
                  Debug((DEBUG_ERROR, "[user] unknown (%s) from %s", ch, get_client_name(cptr, SHOW_IP)));
            }
            ircstp->is_unco++;
            return -1;
      }

      paramcount = (cmd->msg->flags & CMDFLAG_SINGLEPARA) ? 1 : MAXPARA;
      i = bufend - (s != NULL ? s : ch);
      cmd->bytes += i;

      /* Penalise if they're not +F */
      if (!HasMode(cptr, UMODE_NORECVQTHROTTLE)) {
            cptr->since += (2 + i / 120);
      }

      i = 1;
      if (s != NULL) {
            for (;;) {
                  while (*s == ' ') {
                        *s++ = '\0';
                  }
                  if (*s == '\0') {
                        break;
                  }
                  if (*s == ':') {
                        para[i++] = (s + 1);
                        break;
                  }

                  para[i++] = s;
                  if (i >= paramcount) {
                        break;
                  }
                  while (*s != '\0' && *s != ' ') {
                        s++;
                  }
            }
      }

      para[i] = NULL;
      cmd->count++;

      if (!IsRegistered(cptr) && !(cmd->msg->flags & CMDFLAG_UNREGUSE)) {
            send_me_numeric_buf(from, "%s :Register first.", ERR_NOTREGISTERED, ch);
            return -1;
      }
      if (IsClient(cptr) && (cmd->msg->flags & CMDFLAG_RESETIDLE)) {
            ASSERT(from->localUser != NULL);
            from->localUser->last = timeofday;
      }

      return (*cmd->func)(cptr, from, i, para);
}

Generated by  Doxygen 1.6.0   Back to index