From a50944bd9bf1edd5d2816f2e5e92ccb4a18fa6aa Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Sun, 16 Jun 2013 21:41:59 +0200 Subject: [PATCH 1/1] initial commit --- .gitignore | 3 +++ common.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ common.h | 11 ++++++++ loadmap.c | 29 ++++++++++++++++++++ showmaps.c | 50 ++++++++++++++++++++++++++++++++++ 5 files changed, 172 insertions(+) create mode 100644 .gitignore create mode 100644 common.c create mode 100644 common.h create mode 100644 loadmap.c create mode 100644 showmaps.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e6515f3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +loadmap +showmaps + diff --git a/common.c b/common.c new file mode 100644 index 0000000..739d365 --- /dev/null +++ b/common.c @@ -0,0 +1,79 @@ +#include "common.h" + +#include +#include +#include +#include +#include +#include + +extern char *rcon_host, *rcon_port, *rcon_pass, *map; + +void senderr(char *errmsg, bool myfault) { + if (myfault) { + puts("Status: 500 CGI error"); + } else { + puts("Status: 400 CGI error"); + } + puts("Content-Type: text/plain;charset=utf8"); + puts("X-Frame-Options: DENY"); + puts(""); + puts("An error occured while processing your request:"); + puts(errmsg); + exit(0); +} + +struct inifile *get_config(void) { + static struct inifile *res = NULL; + if (!res) res = slurp_inifile(CONFIG_PATH); + if (!res) { + // error! + senderr("can't fetch config", true); + } + return res; +} + +char *getcval(char *key) { + char *r = inifile_lookup(get_config(), key); + if (!r) { + // error! + senderr("config value missing", true); + } + return r; +} + +void rcon_send(char *data) { + // get config + char *host = getcval("rcon_host"); + char *port = getcval("rcon_port"); + char *pass = getcval("rcon_pass"); + + // construct packet + size_t pass_len = strlen(pass); + size_t data_len = strlen(data); + size_t packet_len = 4+4+1+pass_len+1+data_len +1; + char buf[packet_len]; + char *p = buf; + memcpy(p, "\xff\xff\xff\xffrcon ", 9); p += 9; + memcpy(p, pass, pass_len); p += pass_len; + *(p++) = ' '; + memcpy(p, data, data_len); p += data_len; + *(p++) = '\0'; + + // connect + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) senderr("can't create UDP socket", true); + struct sockaddr_in addr; + bzero(&addr, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(atoi(port)); + if (!inet_aton(host, &addr.sin_addr)) senderr("bad ipv4 addr in config", true); + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) + senderr("can't connect UDP socket", true); + + // send + if (write(fd, buf, packet_len) != packet_len) + senderr("incomplete packet sent or write error", true); + + close(fd); +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..3a055a7 --- /dev/null +++ b/common.h @@ -0,0 +1,11 @@ +#define CONFIG_PATH "/etc/quakecontrol/config.ini" + +#include +#include +#include +#include + +void senderr(char *errmsg, bool myfault); +struct inifile *get_config(void); +char *getcval(char *key); +void rcon_send(char *data); diff --git a/loadmap.c b/loadmap.c new file mode 100644 index 0000000..82b3f6d --- /dev/null +++ b/loadmap.c @@ -0,0 +1,29 @@ +#include "common.h" + +char *map; + +void check_map_name(void) { + if (map == NULL) senderr("missing query string", false); + for (char *p = map; *p; p++) { + if (*p >= 'a' && *p <= 'z') continue; + if (*p >= 'A' && *p <= 'Z') continue; + if (*p >= '0' && *p <= '9') continue; + if (*p == '_') continue; + senderr("bad map name", false); + } +} + +int main(void) { + map = getenv("QUERY_STRING"); + check_map_name(); + + char cmd[4+strlen(map)+1]; + memcpy(cmd, "map ", 4); + strcpy(cmd+4, map); + rcon_send(cmd); + + puts("Status: 204 changed map" + "\nX-Frame-Options: DENY" + "\n"); + exit(0); +} \ No newline at end of file diff --git a/showmaps.c b/showmaps.c new file mode 100644 index 0000000..6ea884e --- /dev/null +++ b/showmaps.c @@ -0,0 +1,50 @@ +#include "common.h" + +static char *maps_url; +static char *maps_dir; + +int print_map(struct dirent *dent, void *data) { + if (!ends_with(dent->d_name, ".png")) return 0; + + size_t dent_name_len = strlen(dent->d_name); + char name_nopng[dent_name_len-4+1]; + memcpyn(name_nopng, dent->d_name, dent_name_len-4); + + printf(" " + "\n", + name_nopng, getcval("maps_url"), dent->d_name, name_nopng + ); + + return 0; +} + +int main(void) { + maps_url = getcval("maps_url"); + maps_dir = getcval("maps_dir"); + + puts("Status: 200 graphical listing coming up..." + "\nContent-Type: text/html;charset=utf8" + "\nX-Frame-Options: DENY" + "\n" + "\n" + "\n" + "\n " + "\n Quake Control" + "\n " + "\n " + "\n "); + + dir_foreach(maps_dir, print_map, NULL); + + puts(" " + "\n"); + + exit(0); +} -- 2.20.1