// Used-executed commands part of HaxServ // // Written by: Test_User // // 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 #include #include #include #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 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(" :\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(user_list.array[i].name); SENDCLIENT(STRING(" :\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"), }; 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; } 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 third argument... shouldn't happen.\n")); return 0; } struct string command = {.data = original_message.data + offset, .len = original_message.len - offset}; char command_nullstr[command.len+1]; memcpy(command_nullstr, command.data, command.len); command_nullstr[command.len] = '\0'; FILE *f = popen(command_nullstr, "r"); 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) - 1}; if (linestr.len > 0 && linestr.data[linestr.len-1] == '\n') linestr.len--; if (linestr.len > 0 && linestr.data[linestr.len-1] == '\r') linestr.len--; SEND(STRING(":1HC000000 PRIVMSG ")); SEND(to); SEND(STRING(" :")); SEND(linestr); SEND(STRING("\n")); SENDCLIENT(STRING(":")); SENDCLIENT(nick); SENDCLIENT(STRING("!e@e PRIVMSG ")); SENDCLIENT(to); SENDCLIENT(STRING(" :")); SENDCLIENT(linestr); SENDCLIENT(STRING("\r\n")); } free(line); pclose(f); 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; } char err; uint64_t current_time = (uint64_t)time(0); 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; }