diff options
| author | 2019-04-07 00:14:13 -0400 | |
|---|---|---|
| committer | 2019-04-07 00:14:13 -0400 | |
| commit | 5140318f8f758141b4e350871db1fe869eb858dc (patch) | |
| tree | 3cf26f4845b2c4674af81f108fbdbf47a996dcff /src/opercmd.c | |
Import Upstream version 1.1.5upstream/1.1.5
Diffstat (limited to 'src/opercmd.c')
| -rw-r--r-- | src/opercmd.c | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/src/opercmd.c b/src/opercmd.c new file mode 100644 index 0000000..0cae2ad --- /dev/null +++ b/src/opercmd.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2002 Erik Fears + * Copyright (c) 2014-2018 ircd-hybrid development team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include "setup.h" + +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <time.h> + +#include "list.h" +#include "options.h" +#include "irc.h" +#include "log.h" +#include "main.h" +#include "config.h" +#include "opercmd.h" +#include "scan.h" +#include "memory.h" +#include "stats.h" + + +static list_t COMMANDS; /* List of active commands */ + + +/* cmd_check + * + * Start a manual scan on given IP address/hostname. + * + * Parameters: + * param: Parameters of the command + * target: channel command was sent to + * + */ +static void +cmd_check(char *param, const char *target) +{ + scan_manual(param, target); +} + +/* cmd_stat + * + * Send output of stats to channel. + * + * Parameters: + * param: Parameters of the command + * target: channel command was sent to + */ +static void +cmd_stats(char *param, const char *target) +{ + stats_output(target); +} + +/* cmd_fdstat + * + * Send output of stats to channel. + * + * Parameters: + * param: Parameters of the command + * target: channel command was sent to + */ +static void +cmd_fdstat(char *param, const char *target) +{ + fdstats_output(target); +} + +/* command_create + * + * Create a Command struct. + * + * Parameters: + * type: Index in COMMAND_TABLE + * param: Parameters to the command (NULL if there are not any) + * irc_nick: Nickname of user that initiated the command + * target: Target channel (target is ALWAYS a channel) + * + * Return: + * Pointer to new Command + */ +static struct Command * +command_create(const struct OperCommandHash *tab, const char *param, const char *irc_nick, + const char *target) +{ + struct Command *command = xcalloc(sizeof(*command)); + + if (param) + command->param = xstrdup(param); + + command->tab = tab; + command->irc_nick = xstrdup(irc_nick); + command->target = target; + + time(&command->added); + + return command; +} + +/* command_free + * + * Free a command struct + * + * Parameters: + * command: Command struct to free + * + * Return: NONE + */ +static void +command_free(struct Command *command) +{ + if (command->param) + xfree(command->param); + + xfree(command->irc_nick); + xfree(command); +} + +/* command_parse + * + * Parse a command to hopm (sent to a channel hopm is on). The command is parsed + * from the parameters, and if it is a known command it is stored in a queue. A + * userhost is performed on the user to check if they are an IRC operator. When + * a reply is returned (command_userhost), the command will be executed. + * + * Parameters: + * command: Command sent (including parameters) + * target: Channel command was sent to (we only got this far if there was only one recipient) + * source_p: Operator (hopefully) that sent the command. + * + */ +void +command_parse(const char *command, const char *target, const char *source_p) +{ + char *param; /* Parsed parameters */ + static const struct OperCommandHash COMMAND_TABLE[] = + { + { .command = "CHECK", .handler = cmd_check }, + { .command = "SCAN", .handler = cmd_check }, + { .command = "STATS", .handler = cmd_stats }, + { .command = "FDSTAT", .handler = cmd_fdstat }, + { .command = NULL } + }; + + if (OPT_DEBUG) + log_printf("COMMAND -> Parsing command (%s) from %s [%s]", + command, source_p, target); + + /* Only allow OptionsItem.command_queue_size commands in the queue */ + if (LIST_SIZE(&COMMANDS) >= OptionsItem.command_queue_size) + return; + + /* + * Parameter is the first character in command after the first space. + * 'param' will be NULL if: + * 1. There was no space + * 2. There was a space but it was the last character in command, in which case + * param = '\0' + */ + + /* Skip past the botname/!all */ + command = strchr(command, ' '); + + /* + * There is no command OR there is at least nothing + * past that first space. + */ + if (command == NULL || *++command == '\0') + return; + + /* Find the parameters */ + param = strchr(command, ' '); + + if (param) + { + *param = '\0'; + param++; + } + + log_printf("COMMAND -> parsed [%s] [%s]", command, param ? param : ""); + + /* Lookup the command in the table */ + for (const struct OperCommandHash *tab = COMMAND_TABLE; tab->command; ++tab) + { + if (strcasecmp(command, tab->command) == 0) + { + /* Queue this command */ + struct Command *cmd = command_create(tab, param, source_p, target); + + list_add(cmd, &cmd->node, &COMMANDS); + break; + } + } + + irc_send("USERHOST %s", source_p); +} + +/* command_timer + * + * Perform ~1 second actions. + * + * Parameters: NONE + * + * Return: NONE + * + */ +void +command_timer(void) +{ + static unsigned int interval; + node_t *node, *node_next; + time_t present; + + /* Only perform command removal every OptionsItem.command_interval seconds */ + if (interval++ < OptionsItem.command_interval) + return; + else + interval = 0; + + time(&present); + + LIST_FOREACH_SAFE(node, node_next, COMMANDS.head) + { + struct Command *command = node->data; + + if ((present - command->added) > OptionsItem.command_timeout) + { + list_remove(&command->node, &COMMANDS); + command_free(command); /* Cleanup the command */ + } + else /* Since the queue is in order, it's also ordered by time, no nodes after this will be timed out */ + return; + } +} + +/* command_userhost + * + * A 302 reply was received. The reply is parsed to check if the + * user was an operator. If so any commands they had queued are + * executed. + * + * Parameters: + * reply: Reply to USERHOST (ex: :grifferz*=+goats@pc-62-30-219-54-pb.blueyonder.co.uk) + * + * Return: NONE + * + */ +void +command_userhost(const char *reply) +{ + node_t *node, *node_next; + char *tmp; + int oper = 0; + + tmp = strchr(reply, '='); + + /* They quit, ignore it */ + if (tmp == NULL) + return; + + /* Operators have a * flag in a USERHOST reply */ + if (*(tmp - 1) == '*') + oper = 1; + + /* Null terminate it so tmp = the oper's nick */ + if (oper) + *(--tmp) = '\0'; + else + *(tmp) = '\0'; + + /* Find any queued commands that match this user */ + LIST_FOREACH_SAFE(node, node_next, COMMANDS.head) + { + struct Command *command = node->data; + + if (strcmp(command->irc_nick, reply) == 0) + { + if (oper) + command->tab->handler(command->param, command->target); + + list_remove(&command->node, &COMMANDS); + command_free(command); /* Cleanup the command */ + } + } +} |
