123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525 |
- // Used-executed commands part of HaxServ
- //
- // Written by: Test_User <hax@andrewyu.org>
- //
- // This is free and unencumbered software released into the public
- // domain.
- //
- // Anyone is free to copy, modify, publish, use, compile, sell, or
- // distribute this software, either in source code form or as a compiled
- // binary, for any purpose, commercial or non-commercial, and by any
- // means.
- //
- // In jurisdictions that recognize copyright laws, the author or authors
- // of this software dedicate any and all copyright interest in the
- // software to the public domain. We make this dedication for the benefit
- // of the public at large and to the detriment of our heirs and
- // successors. We intend this dedication to be an overt act of
- // relinquishment in perpetuity of all present and future rights to this
- // software under copyright law.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- // OTHER DEALINGS IN THE SOFTWARE.
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include "types.h"
- #include "table.h"
- #include "commands.h"
- #include "network.h"
- #include "tls.h"
- #include "config.h"
- #include "utils.h"
- #define MAX_SPAM_COUNT 65536
- struct table user_commands = {0};
- int help_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) {
- for (uint64_t i = 0; i < user_commands.len; i++) {
- struct command_def *def = user_commands.array[i].ptr;
- struct string message[] = {
- command_prefix,
- user_commands.array[i].name,
- STRING("\x0F" " "),
- def->summary,
- };
- privmsg(STRING("1HC000000"), to, sizeof(message)/sizeof(*message), message);
- }
- return 0;
- }
- static struct command_def help_command_def = {
- .func = help_command,
- .privs = {0},
- .local_only = 0,
- .summary = STRING("Shows a list of commands, or, when I write it up, help about a specific command"),
- };
- int raw_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) {
- if (argv[0].len < original_message.len) {
- original_message.data += argv[0].len + 1;
- original_message.len -= argv[0].len + 1;
- SEND(original_message);
- }
- SEND(STRING("\n"));
- return 0;
- }
- static struct command_def raw_command_def = {
- .func = raw_command,
- .privs = STRING("NetAdmin"), // TODO: Make this configurable elsewhere
- .local_only = 0,
- .summary = STRING("Sends a raw message to the server"),
- };
- static struct pref_type_suff {
- struct string pref;
- uint8_t type;
- struct string suff;
- } sus_strings[] = {
- {STRING(":1HC000000 PRIVMSG "), 0, STRING(" :Andrew is very sus.\n")},
- {STRING(":1HC000000 PRIVMSG "), 0, STRING(" :I was the impostor, but you only know because I killed you.\n")},
- {STRING(":1HC000000 PRIVMSG "), 0, STRING(" :\\x1b(0\n")},
- {STRING(":1HC000000 KILL "), 1, STRING(" :Ejected (1 Impostor remains)\n")},
- {STRING(":1HC000000 KILL "), 1, STRING(" :Ejected, and the crewmates have won.\n")},
- }, cr_strings[] = {
- {STRING(":1HC000000 PRIVMSG "), 0, STRING(" :You are now a cruxian toxicpod, kill the sharded crewmates.\n")},
- {STRING(":1HC000000 PRIVMSG "), 0, STRING(" :You are now a cruxian omura, kill the sharded crewmates.\n")},
- {STRING(":1HC000000 PRIVMSG "), 0, STRING(" :You are now a cruxian oct, but you ran out of reactors.\n")},
- {STRING(":1HC000000 KILL "), 1, STRING(" :Eliminated (You became a cruxian eclipse, but were drawn to my bait reactor)\n")},
- {STRING(":1HC000000 PRIVMSG "), 0, STRING(" :You attempted to change into a cruxian navanax, but were caught in the act.\n")},
- };
- int sus_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) {
- uint64_t index = (uint64_t)random() % (sizeof(sus_strings)/sizeof(sus_strings[0]));
- SEND(sus_strings[index].pref);
- if (sus_strings[index].type == 0)
- SEND(to);
- else
- SEND(sender);
- SEND(sus_strings[index].suff);
- return 0;
- }
- static struct command_def sus_command_def = {
- .func = sus_command,
- .privs = {0},
- .local_only = 0,
- .summary = STRING("You seem a bit sus today"),
- };
- int cr_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) {
- uint64_t index = (uint64_t)random() % (sizeof(cr_strings)/sizeof(cr_strings[0]));
- SEND(cr_strings[index].pref);
- if (cr_strings[index].type == 0)
- SEND(to);
- else
- SEND(sender);
- SEND(cr_strings[index].suff);
- return 0;
- }
- static struct command_def cr_command_def = {
- .func = cr_command,
- .privs = {0},
- .local_only = 0,
- .summary = STRING("Join the crux side"),
- };
- int spam_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) {
- if (argc < 3) {
- privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Missing args!")});
- return 0;
- }
- char err;
- uint64_t count = str_to_unsigned(argv[1], &err);
- if (err || (count > MAX_SPAM_COUNT && !is_local)) {
- privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Unknown number or number exceeds limit.")});
- return 0;
- }
- char wasspace = 1;
- uint64_t offset = 0;
- char found = 0;
- for (; offset < original_message.len; offset++) {
- if (original_message.data[offset] == ' ' && !wasspace)
- found++;
- wasspace = (original_message.data[offset] == ' ');
- if (found >= 2 && !wasspace)
- break;
- }
- if (found < 2) {
- WRITES(2, STRING("WARNING: Apparently there was no second argument... shouldn't happen.\n"));
- return 0;
- }
- struct command_def *cmd = get_table_index(user_commands, argv[2]);
- if (cmd) {
- if (!cmd->local_only) {
- if (cmd->privs.len != 0 && sender.len != 3) {
- struct user_info *user = get_table_index(user_list, sender);
- if (!user)
- return 1; // really shouldn't happen
- if (!STRING_EQ(user->opertype, cmd->privs)) {
- SEND(STRING(":1HC000000 NOTICE "));
- SEND(to);
- SEND(STRING(" :You are not authorized to execute that command.\n"));
- return 0;
- }
- if (cmd->func == spam_command) {
- SEND(STRING(":1HC000000 NOTICE "));
- SEND(to);
- SEND(STRING(" :Spam recursion is not allowed. The limit is for your own sake, please do not violate it.\n"));
- return 0;
- }
- }
- } else {
- SEND(STRING(":1HC000000 NOTICE "));
- SEND(to);
- SEND(STRING(" :Spamming of local-only commands is disabled.\n"));
- return 0;
- }
- } else {
- SEND(STRING(":1HC000000 NOTICE "));
- SEND(to);
- SEND(STRING(" :Unknown command.\n"));
- return 0;
- }
- struct string fake_original_message = {.data = original_message.data + offset, .len = original_message.len - offset};
- WRITES(2, fake_original_message);
- WRITES(2, STRING("\n"));
- for (uint64_t i = 0; i < count; i++) {
- int ret = cmd->func(sender, fake_original_message, to, argc - 2, &(argv[2]), 0);
- if (ret)
- return ret;
- }
- return 0;
- }
- static struct command_def spam_command_def = {
- .func = spam_command,
- .privs = STRING("NetAdmin"),
- .local_only = 0,
- .summary = STRING("Repeats a command <n> times"),
- };
- int clear_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) {
- if (argc < 2) {
- privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Missing args!")});
- return 0;
- }
- struct channel_info *channel = get_table_index(channel_list, argv[1]);
- if (!channel) {
- privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("That channel doesn't seem to exist, so is thereby already cleared.")});
- return 0;
- }
- for (uint64_t i = 0; i < channel->user_list.len; i++) {
- // TODO: Proper kick function, will prob come as a part of my next HaxServ rewrite
- SEND(STRING(":1HC000000 KICK "));
- SEND(argv[1]);
- SEND(STRING(" "));
- SEND(channel->user_list.array[i].name);
- SEND(STRING(" :(B\n"));
- if (client_connected) {
- SENDCLIENT(STRING(":"));
- SENDCLIENT(nick);
- SENDCLIENT(STRING("!"));
- SENDCLIENT(nick);
- SENDCLIENT(STRING("@"));
- SENDCLIENT(hostmask);
- SENDCLIENT(STRING(" KICK "));
- SENDCLIENT(argv[1]);
- SENDCLIENT(STRING(" "));
- struct user_info *user = get_table_index(user_list, channel->user_list.array[i].name);
- if (user)
- SENDCLIENT(user->nick);
- else
- SENDCLIENT(channel->user_list.array[i].name);
- SENDCLIENT(STRING(" :(B\r\n"));
- }
- }
- clear_table(&(channel->user_list));
- return 0;
- }
- static struct command_def clear_command_def = {
- .func = clear_command,
- .privs = STRING("NetAdmin"),
- .local_only = 0,
- .summary = STRING("Clears a channel"),
- };
- struct sh_command_args {
- char *command;
- struct string to;
- };
- void * async_sh_command(void *tmp) {
- struct sh_command_args *sh_args = tmp;
- FILE *f = popen(sh_args->command, "r");
- free(sh_args->command);
- char *line = NULL;
- size_t buflen;
- while (1) {
- ssize_t len = getline(&line, &buflen, f);
- if (len <= 0)
- break;
- struct string linestr = {.data = line, .len = (size_t)(len)};
- while (linestr.len > 0 && (linestr.data[linestr.len-1] == '\n' || linestr.data[linestr.len-1] == '\r'))
- linestr.len--;
- if (linestr.len == 0)
- linestr = STRING(" ");
- pthread_mutex_lock(&send_lock);
- SEND(STRING(":1HC000000 PRIVMSG "));
- SEND(sh_args->to);
- SEND(STRING(" :"));
- SEND(linestr);
- SEND(STRING("\n"));
- SENDCLIENT(STRING(":"));
- SENDCLIENT(nick);
- SENDCLIENT(STRING("!e@e PRIVMSG "));
- SENDCLIENT(sh_args->to);
- SENDCLIENT(STRING(" :"));
- SENDCLIENT(linestr);
- SENDCLIENT(STRING("\r\n"));
- pthread_mutex_unlock(&send_lock);
- }
- free(line);
- pclose(f);
- free(sh_args->to.data);
- free(sh_args);
- return 0;
- }
- int sh_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) {
- if (!is_local) {
- return 0;
- }
- if (argc < 2) {
- privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Missing args!")});
- return 0;
- }
- char wasspace = 1;
- uint64_t offset = 0;
- char found = 0;
- for (; offset < original_message.len; offset++) {
- if (original_message.data[offset] == ' ' && !wasspace)
- found++;
- wasspace = (original_message.data[offset] == ' ');
- if (found >= 1 && !wasspace)
- break;
- }
- if (found < 1) {
- WRITES(2, STRING("WARNING: Apparently there was no argument... shouldn't happen.\n"));
- return 0;
- }
- struct string command = {.data = original_message.data + offset, .len = original_message.len - offset};
- struct sh_command_args *sh_args;
- sh_args = malloc(sizeof(*sh_args));
- if (!sh_args) {
- WRITES(2, STRING("ERROR: OOM\n"));
- return 0;
- }
- sh_args->command = malloc(command.len+1);
- if (!sh_args->command) {
- free(sh_args);
- WRITES(2, STRING("ERROR: OOM\n"));
- return 0;
- }
- memcpy(sh_args->command, command.data, command.len);
- sh_args->command[command.len] = '\0';
- sh_args->to.len = to.len;
- sh_args->to.data = malloc(to.len);
- if (!sh_args->to.data) {
- free(sh_args->command);
- free(sh_args);
- WRITES(2, STRING("ERROR: OOM\n"));
- return 0;
- }
- memcpy(sh_args->to.data, to.data, to.len);
- pthread_t trash;
- pthread_create(&trash, NULL, async_sh_command, sh_args);
- return 0;
- }
- static struct command_def sh_command_def = {
- .func = sh_command,
- .privs = STRING("NetAdmin"),
- .local_only = 1,
- .summary = STRING("Executes a command locally"),
- };
- int kill_old_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) {
- if (argc < 2) {
- privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Missing args!")});
- return 0;
- }
- uint64_t current_time = (uint64_t)time(0);
- char err;
- uint64_t age = str_to_unsigned(argv[1], &err);
- if (err) {
- privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Invalid age!")});
- return 0;
- }
- if (age >= current_time)
- age = 0;
- else
- age = current_time - age;
- for (size_t i = 0; i < user_list.len; i++) {
- struct user_info *user = user_list.array[i].ptr;
- if ((user->user_ts <= age || STRING_EQ(user->nick, STRING("OperServ"))) && !STRING_EQ(user->server, STRING("1HC"))) {
- SEND(STRING(":1HC000000 KILL "));
- SEND(user_list.array[i].name);
- SEND(STRING(" :Your connection is too old.\n"));
- }
- }
- return 0;
- }
- static struct command_def kill_old_command_def = {
- .func = kill_old_command,
- .privs = STRING("NetAdmin"),
- .local_only = 0,
- .summary = STRING("Kills old connections (with a time you specify), and OperServ because OperServ is wrong"),
- };
- int echo_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) {
- if (argc < 2) {
- privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Missing args!")});
- return 0;
- }
- char wasspace = 1;
- uint64_t offset = 0;
- char found = 0;
- for (; offset < original_message.len; offset++) {
- if (original_message.data[offset] == ' ' && !wasspace)
- found++;
- wasspace = (original_message.data[offset] == ' ');
- if (found >= 1 && !wasspace)
- break;
- }
- if (found < 1) {
- WRITES(2, STRING("WARNING: Apparently there was no second argument... shouldn't happen.\n"));
- return 0;
- }
- struct string message[] = {{.data = original_message.data + offset, .len = original_message.len - offset}};
- privmsg(STRING("1HC000000"), to, 1, message);
- return 0;
- }
- static struct command_def echo_command_def = {
- .func = echo_command,
- .privs = {0},
- .local_only = 0,
- .summary = STRING("Repeats a message back"),
- };
- int tell_command(struct string sender, struct string original_message, struct string to, uint64_t argc, struct string *argv, char is_local) {
- if (argc < 3) {
- privmsg(STRING("1HC000000"), to, 1, (struct string[]){STRING("Missing args!")});
- return 0;
- }
- char wasspace = 1;
- uint64_t offset = 0;
- char found = 0;
- for (; offset < original_message.len; offset++) {
- if (original_message.data[offset] == ' ' && !wasspace)
- found++;
- wasspace = (original_message.data[offset] == ' ');
- if (found >= 2 && !wasspace)
- break;
- }
- if (found < 2) {
- WRITES(2, STRING("WARNING: Apparently there was no second argument... shouldn't happen.\n"));
- return 0;
- }
- struct string message[] = {{.data = original_message.data + offset, .len = original_message.len - offset}};
- privmsg(STRING("1HC000000"), argv[1], 1, message);
- return 0;
- }
- static struct command_def tell_command_def = {
- .func = tell_command,
- .privs = STRING("NetAdmin"),
- .local_only = 0,
- .summary = STRING("Sends a message to a target"),
- };
- int init_user_commands(void) {
- srandom(time(NULL));
- user_commands.array = malloc(0);
- set_table_index(&user_commands, STRING(":"), &raw_command_def);
- set_table_index(&user_commands, STRING("sus"), &sus_command_def);
- set_table_index(&user_commands, STRING("cr"), &cr_command_def);
- set_table_index(&user_commands, STRING("help"), &help_command_def);
- set_table_index(&user_commands, STRING("spam"), &spam_command_def);
- set_table_index(&user_commands, STRING("clear"), &clear_command_def);
- set_table_index(&user_commands, STRING("sh"), &sh_command_def);
- set_table_index(&user_commands, STRING("kill_old"), &kill_old_command_def);
- set_table_index(&user_commands, STRING("echo"), &echo_command_def);
- set_table_index(&user_commands, STRING("tell"), &tell_command_def);
- return 0;
- }
|