From be41c32fd165c43862b6ecdfd317b902ecbe66a9 Mon Sep 17 00:00:00 2001 From: Neale Pickett Date: Fri, 3 Sep 2010 14:54:57 -0600 Subject: [PATCH] A new C-based register.cgi --- src/Makefile | 7 ++- src/cgi.c | 90 ++++++++++++++++++++++++++++++++++++ src/cgi.h | 9 ++++ src/register.cgi.c | 113 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 217 insertions(+), 2 deletions(-) create mode 100644 src/cgi.c create mode 100644 src/cgi.h create mode 100644 src/register.cgi.c diff --git a/src/Makefile b/src/Makefile index 318426e..d31695c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,3 +1,6 @@ -all: in.tokend +all: in.tokend register.cgi + +in.tokend: in.tokend.o xxtea.o + +register.cgi: register.cgi.o cgi.o -in.tokend: in.tokend.c xxtea.c \ No newline at end of file diff --git a/src/cgi.c b/src/cgi.c new file mode 100644 index 0000000..eb08a3a --- /dev/null +++ b/src/cgi.c @@ -0,0 +1,90 @@ +#include +#include +#include "cgi.h" + +static size_t inlen = 0; + +int +cgi_init() +{ + char *rm = getenv("REQUEST_METHOD"); + + if (! (rm && (0 == strcmp(rm, "POST")))) { + printf("405 Method not allowed\n" + "Allow: POST\n" + "Content-type: text/html\n" + "\n" + "

Method not allowed

\n" + "

I only speak POST. Sorry.

\n"); + return -1; + } + + inlen = atoi(getenv("CONTENT_LENGTH")); + + return 0; +} + +static int +read_char() +{ + if (inlen) { + inlen -= 1; + return getchar(); + } + return EOF; +} + +static char +tonum(int c) +{ + if ((c >= '0') && (c <= '9')) { + return c - '0'; + } + if ((c >= 'a') && (c <= 'f')) { + return 10 + c - 'a'; + } + if ((c >= 'A') && (c <= 'F')) { + return 10 + c - 'A'; + } + return 0; +} + +static char +read_hex() +{ + int a = read_char(); + int b = read_char(); + + return tonum(a)*16 + tonum(b); +} + +/* Read a key or a value. Since & and = aren't supposed to appear + outside of boundaries, we can use the same function for both. +*/ +size_t +read_item(char *str, size_t maxlen) +{ + int c; + size_t pos = 0; + + while (1) { + c = read_char(); + switch (c) { + case EOF: + case '=': + case '&': + str[pos] = '\0'; + return pos; + case '%': + c = read_hex(); + break; + case '+': + c = ' '; + break; + } + if (pos < maxlen - 1) { + str[pos] = c; + pos += 1; + } + } +} diff --git a/src/cgi.h b/src/cgi.h new file mode 100644 index 0000000..6f68907 --- /dev/null +++ b/src/cgi.h @@ -0,0 +1,9 @@ +#ifndef __CGI_H__ +#define __CGI_H__ + +#include + +int cgi_init(); +size_t read_item(char *str, size_t maxlen); + +#endif diff --git a/src/register.cgi.c b/src/register.cgi.c new file mode 100644 index 0000000..6c65b91 --- /dev/null +++ b/src/register.cgi.c @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cgi.h" + +char *BASE_PATH = "/var/lib/ctf/teams"; + + +unsigned int +djbhash(char const *buf, size_t buflen) +{ + unsigned int h = 5381; + + while (buflen--) { + h = ((h << 5) + h) ^ *(buf++); + } + return h; +} + +void +page(char *title, char *fmt, ...) +{ + FILE *p; + va_list ap; + + printf("Content-type: text/html\r\n\r\n"); + fflush(stdout); + p = popen("./template", "w"); + if (NULL == p) { + printf("

%s

\n", title); + p = stdout; + } else { + fprintf(p, "Title: %s\n", title); + } + va_start(ap, fmt); + vfprintf(p, fmt, ap); + va_end(ap); + fclose(p); +} + +int +main(int argc, char *argv[]) +{ + char team[80]; + size_t teamlen; + char hash[9]; + + if (-1 == cgi_init()) { + return 0; + } + + /* Read in team name, the only thing we care about */ + while (1) { + size_t len; + char key[20]; + + len = read_item(key, sizeof(key)); + if (0 == len) break; + if ((1 == len) && ('t' == key[0])) { + teamlen = read_item(team, sizeof(team)); + } + } + + /* Compute the hash */ + sprintf(hash, "%08x", djbhash(team, teamlen)); + + /* Write team name into file */ + { + char filename[100]; + int fd; + int ret; + + ret = snprintf(filename, sizeof(filename), + "%s/%s", + BASE_PATH, hash); + if (sizeof(filename) == ret) { + printf(("500 Server screwed up\n" + "Content-type: text/plain\n" + "\n" + "The full path to the team hash file is too long.\n")); + return 0; + } + fd = creat(filename, 0444); + if (-1 == fd) { + page("Bad team name", + ("

Either that team name is already in use, or you " + "found a hash collision (way to go). " + "In any case, you're going to " + "have to pick something else.

" + "

If you're just trying to find your team hash again," + "it's %s.

"), + hash); + return 0; + } + write(fd, team, teamlen); + close(fd); + } + + /* Let them know what their hash is. */ + page("Team registered", + ("

Team hash: %s

" + "

Save your team hash somewhere!. You will need it " + "to claim points.

"), + hash); + + return 0; +}