A new C-based register.cgi

This commit is contained in:
Neale Pickett 2010-09-03 14:54:57 -06:00
parent 8d4fea620b
commit be41c32fd1
4 changed files with 217 additions and 2 deletions

View File

@ -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

90
src/cgi.c Normal file
View File

@ -0,0 +1,90 @@
#include <stdlib.h>
#include <stdio.h>
#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"
"<h1>Method not allowed</h1>\n"
"<p>I only speak POST. Sorry.</p>\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;
}
}
}

9
src/cgi.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef __CGI_H__
#define __CGI_H__
#include <stddef.h>
int cgi_init();
size_t read_item(char *str, size_t maxlen);
#endif

113
src/register.cgi.c Normal file
View File

@ -0,0 +1,113 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <ctype.h>
#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("<h1>%s</h1>\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",
("<p>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.</p>"
"<p>If you're just trying to find your team hash again,"
"it's <samp>%s</samp>.</p>"),
hash);
return 0;
}
write(fd, team, teamlen);
close(fd);
}
/* Let them know what their hash is. */
page("Team registered",
("<p>Team hash: <samp>%s</samp></p>"
"<p><b>Save your team hash somewhere!</b>. You will need it "
"to claim points.</b></p>"),
hash);
return 0;
}