mirror of https://github.com/dirtbags/moth.git
Many changes, unit test
* Everything in /srv/ctf now, set $CTF_BASE to override that * CGI now accepts parms in argv * Fix bug with uninitialized CGI vars
This commit is contained in:
parent
507dd93d88
commit
8d47593986
|
@ -1,11 +1,11 @@
|
||||||
TARGETS = in.tokend claim.cgi puzzler.cgi pointscli puzzles
|
TARGETS = in.tokend pointscli claim.cgi puzzler.cgi puzzles.cgi
|
||||||
|
|
||||||
all: $(TARGETS)
|
all: $(TARGETS)
|
||||||
|
|
||||||
in.tokend: in.tokend.o xxtea.o
|
in.tokend: in.tokend.o xxtea.o common.o
|
||||||
puzzles: puzzles.o common.o
|
|
||||||
pointscli: pointscli.o common.o
|
pointscli: pointscli.o common.o
|
||||||
|
|
||||||
|
puzzles.cgi: puzzles.cgi.o common.o
|
||||||
claim.cgi: claim.cgi.o common.o
|
claim.cgi: claim.cgi.o common.o
|
||||||
puzzler.cgi: puzzler.cgi.o common.o
|
puzzler.cgi: puzzler.cgi.o common.o
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
char const *tokenlog = "/var/lib/ctf/tokend/tokens.log";
|
|
||||||
char const *claimlog = "/var/lib/ctf/tokend/claim.log";
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char team[9];
|
char team[9];
|
||||||
char token[100];
|
char token[100];
|
||||||
|
|
||||||
/* XXX: This code needs to be tested */
|
team[0] = 0;
|
||||||
return 1;
|
token[0] = 0;
|
||||||
|
|
||||||
if (-1 == cgi_init()) {
|
if (-1 == cgi_init(argv)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +50,7 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
|
|
||||||
/* Does the token exist? */
|
/* Does the token exist? */
|
||||||
if (! fgrepx(token, tokenlog)) {
|
if (! fgrepx(token, srv_path("tokens.db"))) {
|
||||||
cgi_page("Token does not exist", "");
|
cgi_page("Token does not exist", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +66,8 @@ main(int argc, char *argv[])
|
||||||
category[i] = '\0';
|
category[i] = '\0';
|
||||||
|
|
||||||
award_and_log_uniquely(team, category, 1,
|
award_and_log_uniquely(team, category, 1,
|
||||||
claimlog, "%s %s", team, token);
|
"tokens.db",
|
||||||
|
"%s %s", team, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
173
src/common.c
173
src/common.c
|
@ -6,39 +6,56 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <values.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CGI
|
* CGI
|
||||||
*/
|
*/
|
||||||
static size_t inlen = 0;
|
static int is_cgi = 0;
|
||||||
static int is_cgi = 0;
|
static char **argv = NULL;
|
||||||
|
|
||||||
int
|
static int
|
||||||
cgi_init()
|
read_char_argv()
|
||||||
{
|
{
|
||||||
char *rm = getenv("REQUEST_METHOD");
|
static int arg = 0;
|
||||||
|
static char *p;
|
||||||
|
|
||||||
if (! (rm && (0 == strcmp(rm, "POST")))) {
|
if (NULL == argv) {
|
||||||
printf("405 Method not allowed\r\n"
|
return EOF;
|
||||||
"Allow: POST\r\n"
|
|
||||||
"Content-type: text/html\r\n"
|
|
||||||
"\r\n"
|
|
||||||
"<h1>Method not allowed</h1>\n"
|
|
||||||
"<p>I only speak POST. Sorry.</p>\n");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inlen = atoi(getenv("CONTENT_LENGTH"));
|
if (0 == arg) {
|
||||||
is_cgi = 1;
|
arg = 1;
|
||||||
|
p = argv[1];
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
if (! p) {
|
||||||
|
return EOF;
|
||||||
|
} else if (! *p) {
|
||||||
|
arg += 1;
|
||||||
|
p = argv[arg];
|
||||||
|
return '&';
|
||||||
|
}
|
||||||
|
|
||||||
|
return *(p++);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
read_char()
|
read_char_stdin()
|
||||||
{
|
{
|
||||||
|
static int inlen = -1;
|
||||||
|
|
||||||
|
if (-1 == inlen) {
|
||||||
|
char *p = getenv("CONTENT_LENGTH");
|
||||||
|
if (p) {
|
||||||
|
inlen = atoi(p);
|
||||||
|
} else {
|
||||||
|
inlen = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (inlen) {
|
if (inlen) {
|
||||||
inlen -= 1;
|
inlen -= 1;
|
||||||
return getchar();
|
return getchar();
|
||||||
|
@ -46,6 +63,53 @@ read_char()
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
read_char_query_string()
|
||||||
|
{
|
||||||
|
static char *p = (char *)-1;
|
||||||
|
|
||||||
|
if ((char *)-1 == p) {
|
||||||
|
p = getenv("QUERY_STRING");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! p) {
|
||||||
|
return EOF;
|
||||||
|
} else if (! *p) {
|
||||||
|
return EOF;
|
||||||
|
} else {
|
||||||
|
return *(p++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int (* read_char)() = read_char_argv;
|
||||||
|
|
||||||
|
int
|
||||||
|
cgi_init(char *global_argv[])
|
||||||
|
{
|
||||||
|
char *rm = getenv("REQUEST_METHOD");
|
||||||
|
|
||||||
|
if (! rm) {
|
||||||
|
read_char = read_char_argv;
|
||||||
|
argv = global_argv;
|
||||||
|
} else if (0 == strcmp(rm, "POST")) {
|
||||||
|
read_char = read_char_stdin;
|
||||||
|
is_cgi = 1;
|
||||||
|
} else if (0 == strcmp(rm, "GET")) {
|
||||||
|
read_char = read_char_query_string;
|
||||||
|
is_cgi = 1;
|
||||||
|
} else {
|
||||||
|
printf(("405 Method not allowed\r\n"
|
||||||
|
"Allow: GET, POST\r\n"
|
||||||
|
"Content-type: text/plain\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"%s is not allowed.\n"),
|
||||||
|
rm);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static char
|
static char
|
||||||
tonum(int c)
|
tonum(int c)
|
||||||
{
|
{
|
||||||
|
@ -207,22 +271,48 @@ my_snprintf(char *buf, size_t buflen, char *fmt, ...)
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
len = vsnprintf(buf, buflen - 1, fmt, ap);
|
len = vsnprintf(buf, buflen - 1, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
if (len >= 0) {
|
buf[buflen] = '\0';
|
||||||
buf[len] = '\0';
|
if (len >= buflen) {
|
||||||
return len;
|
return buflen - 1;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
srv_path(char const *fmt, ...)
|
||||||
|
{
|
||||||
|
char relpath[PATH_MAX];
|
||||||
|
static char path[PATH_MAX];
|
||||||
|
char *srv;
|
||||||
|
int len;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
len = vsnprintf(relpath, sizeof(relpath) - 1, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
relpath[sizeof(relpath) - 1] = '\0';
|
||||||
|
|
||||||
|
srv = getenv("CTF_BASE");
|
||||||
|
if (! srv) {
|
||||||
|
srv = "/srv/ctf";
|
||||||
|
}
|
||||||
|
|
||||||
|
my_snprintf(path, sizeof(path), "%s/%s", srv, relpath);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
team_exists(char const *teamhash)
|
team_exists(char const *teamhash)
|
||||||
{
|
{
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
char filename[100];
|
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if ((! teamhash) || (! *teamhash)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for invalid characters. */
|
/* Check for invalid characters. */
|
||||||
for (i = 0; teamhash[i]; i += 1) {
|
for (i = 0; teamhash[i]; i += 1) {
|
||||||
if (! isalnum(teamhash[i])) {
|
if (! isalnum(teamhash[i])) {
|
||||||
|
@ -230,15 +320,8 @@ team_exists(char const *teamhash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build filename. */
|
|
||||||
ret = snprintf(filename, sizeof(filename),
|
|
||||||
"%s/%s", teamdir, teamhash);
|
|
||||||
if (sizeof(filename) <= ret) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* lstat seems to be the preferred way to check for existence. */
|
/* lstat seems to be the preferred way to check for existence. */
|
||||||
ret = lstat(filename, &buf);
|
ret = lstat(srv_path("teams/names/%s", teamhash), &buf);
|
||||||
if (-1 == ret) {
|
if (-1 == ret) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -253,8 +336,7 @@ award_points(char const *teamhash,
|
||||||
{
|
{
|
||||||
char line[100];
|
char line[100];
|
||||||
int linelen;
|
int linelen;
|
||||||
char filename[100];
|
char *filename;
|
||||||
int filenamelen;
|
|
||||||
int fd;
|
int fd;
|
||||||
int ret;
|
int ret;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
|
@ -296,13 +378,9 @@ award_points(char const *teamhash,
|
||||||
token log.
|
token log.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
filenamelen = snprintf(filename, sizeof(filename),
|
filename = srv_path("points.new/%d.%d.%s.%s.%ld",
|
||||||
"%s/%d.%d.%s.%s.%ld",
|
now, getpid(),
|
||||||
pointsdir, now, getpid(),
|
teamhash, category, points);
|
||||||
teamhash, category, points);
|
|
||||||
if (sizeof(filename) <= filenamelen) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
||||||
if (-1 == fd) {
|
if (-1 == fd) {
|
||||||
|
@ -322,14 +400,15 @@ void
|
||||||
award_and_log_uniquely(char const *team,
|
award_and_log_uniquely(char const *team,
|
||||||
char const *category,
|
char const *category,
|
||||||
long points,
|
long points,
|
||||||
char const *logfile,
|
char const *dbfile,
|
||||||
char const *fmt, ...)
|
char const *fmt, ...)
|
||||||
{
|
{
|
||||||
char line[200];
|
char *dbpath = srv_path(dbfile);
|
||||||
int len;
|
char line[200];
|
||||||
int ret;
|
int len;
|
||||||
int fd;
|
int ret;
|
||||||
va_list ap;
|
int fd;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
/* Make sure they haven't already claimed these points */
|
/* Make sure they haven't already claimed these points */
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
|
@ -338,13 +417,13 @@ award_and_log_uniquely(char const *team,
|
||||||
if (sizeof(line) <= len) {
|
if (sizeof(line) <= len) {
|
||||||
cgi_error("Log line too long");
|
cgi_error("Log line too long");
|
||||||
}
|
}
|
||||||
if (fgrepx(line, logfile)) {
|
if (fgrepx(line, dbpath)) {
|
||||||
cgi_page("Already claimed",
|
cgi_page("Already claimed",
|
||||||
"<p>Your team has already claimed these points.</p>");
|
"<p>Your team has already claimed these points.</p>");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open and lock logfile */
|
/* Open and lock logfile */
|
||||||
fd = open(logfile, O_WRONLY | O_CREAT, 0666);
|
fd = open(dbpath, O_WRONLY | O_CREAT, 0666);
|
||||||
if (-1 == fd) {
|
if (-1 == fd) {
|
||||||
cgi_error("Unable to open log");
|
cgi_error("Unable to open log");
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#define TEAM_MAX 40
|
#define TEAM_MAX 40
|
||||||
#define CAT_MAX 40
|
#define CAT_MAX 40
|
||||||
|
|
||||||
int cgi_init();
|
int cgi_init(char *global_argv[]);
|
||||||
size_t cgi_item(char *str, size_t maxlen);
|
size_t cgi_item(char *str, size_t maxlen);
|
||||||
void cgi_head(char *title);
|
void cgi_head(char *title);
|
||||||
void cgi_foot();
|
void cgi_foot();
|
||||||
|
@ -14,12 +14,10 @@ void cgi_page(char *title, char *fmt, ...);
|
||||||
void cgi_error(char *fmt, ...);
|
void cgi_error(char *fmt, ...);
|
||||||
|
|
||||||
|
|
||||||
#define teamdir "/var/lib/ctf/teams/names"
|
|
||||||
#define pointsdir "/var/lib/ctf/points/new"
|
|
||||||
|
|
||||||
int fgrepx(char const *needle, char const *filename);
|
int fgrepx(char const *needle, char const *filename);
|
||||||
|
char *srv_path(char const *fmt, ...);
|
||||||
int team_exists(char const *teamhash);
|
int team_exists(char const *teamhash);
|
||||||
int award_points(char const *teamhash,
|
int award_points(char const *teamhacsh,
|
||||||
char const *category,
|
char const *category,
|
||||||
long point);
|
long point);
|
||||||
void award_and_log_uniquely(char const *team,
|
void award_and_log_uniquely(char const *team,
|
||||||
|
|
|
@ -8,13 +8,11 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include "common.h"
|
||||||
#include "xxtea.h"
|
#include "xxtea.h"
|
||||||
|
|
||||||
#define itokenlen 3
|
#define itokenlen 3
|
||||||
|
|
||||||
char const *keydir = "/var/lib/ctf/tokend/keys";
|
|
||||||
char const *tokenlog = "/var/lib/ctf/tokend/tokens.log";
|
|
||||||
|
|
||||||
char const consonants[] = "bcdfghklmnprstvz";
|
char const consonants[] = "bcdfghklmnprstvz";
|
||||||
char const vowels[] = "aeiouy";
|
char const vowels[] = "aeiouy";
|
||||||
|
|
||||||
|
@ -91,16 +89,10 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
/* Read in that service's key. */
|
/* Read in that service's key. */
|
||||||
{
|
{
|
||||||
char path[100];
|
|
||||||
int fd;
|
int fd;
|
||||||
size_t len;
|
size_t len;
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = snprintf(path, sizeof(path),
|
fd = open(srv_path("token.keys/%s", service), O_RDONLY);
|
||||||
"%s/%s.key", keydir, service);
|
|
||||||
if (ret < sizeof(path)) {
|
|
||||||
fd = open(path, O_RDONLY);
|
|
||||||
}
|
|
||||||
if (-1 == fd) {
|
if (-1 == fd) {
|
||||||
write(1, "!nosvc", 6);
|
write(1, "!nosvc", 6);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -139,7 +131,7 @@ main(int argc, char *argv[])
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
fd = open(tokenlog, O_WRONLY | O_CREAT, 0644);
|
fd = open(srv_path("tokens.db"), O_WRONLY | O_CREAT, 0644);
|
||||||
if (-1 == fd) break;
|
if (-1 == fd) break;
|
||||||
|
|
||||||
ret = lockf(fd, F_LOCK, 0);
|
ret = lockf(fd, F_LOCK, 0);
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
char const *logfile = "/var/lib/ctf/puzzler.log";
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv)
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char team[TEAM_MAX];
|
char team[TEAM_MAX];
|
||||||
char category[CAT_MAX];
|
char category[CAT_MAX];
|
||||||
char points_str[5];
|
char points_str[5];
|
||||||
char answer[500];
|
char answer[500];
|
||||||
long points;
|
long points = 0;
|
||||||
|
|
||||||
if (-1 == cgi_init()) {
|
team[0] = 0;
|
||||||
|
category[0] = 0;
|
||||||
|
answer[0] = 0;
|
||||||
|
|
||||||
|
if (-1 == cgi_init(argv)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,26 +61,24 @@ main(int argc, char *argv)
|
||||||
|
|
||||||
/* Check answer (also assures category exists) */
|
/* Check answer (also assures category exists) */
|
||||||
{
|
{
|
||||||
char filename[100];
|
|
||||||
char needle[400];
|
char needle[400];
|
||||||
|
|
||||||
my_snprintf(filename, sizeof(filename),
|
|
||||||
"/srv/%s/answers.txt", category);
|
|
||||||
my_snprintf(needle, sizeof(needle),
|
my_snprintf(needle, sizeof(needle),
|
||||||
"%ld %s", points, answer);
|
"%ld %s", points, answer);
|
||||||
if (! fgrepx(needle, filename)) {
|
if (! fgrepx(needle,
|
||||||
|
srv_path("packages/%s/answers.txt", category))) {
|
||||||
cgi_page("Wrong answer", "");
|
cgi_page("Wrong answer", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
award_and_log_uniquely(team, category, points,
|
award_and_log_uniquely(team, category, points,
|
||||||
logfile, "%s %s %ld", team, category, points);
|
"puzzler.db",
|
||||||
|
"%s %s %ld", team, category, points);
|
||||||
|
|
||||||
cgi_page("Points awarded",
|
cgi_page("Points awarded",
|
||||||
("<p>%d points for %s.</p>\n"
|
("<p>%d points for %s.</p>"
|
||||||
"<p>Patience please: it may be up to 1 minute before "
|
"<!-- awarded %d -->"),
|
||||||
"the next puzzle opens in this category.</p>"),
|
points, team, points);
|
||||||
points, team);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ int ncats = 0;
|
||||||
void
|
void
|
||||||
read_points_by_cat()
|
read_points_by_cat()
|
||||||
{
|
{
|
||||||
FILE *f = fopen("/var/lib/ctf/puzzler.log", "r");
|
FILE *f = fopen(srv_path("puzzler.db"), "r");
|
||||||
char cat[CAT_MAX];
|
char cat[CAT_MAX];
|
||||||
long points;
|
long points;
|
||||||
int i;
|
int i;
|
||||||
|
@ -59,10 +59,13 @@ main(int argc, char *argv[])
|
||||||
int i;
|
int i;
|
||||||
DIR *srv;
|
DIR *srv;
|
||||||
|
|
||||||
|
if (-1 == cgi_init(argv)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
read_points_by_cat();
|
read_points_by_cat();
|
||||||
|
|
||||||
/* Open /srv/ */
|
srv = opendir(srv_path("packages"));
|
||||||
srv = opendir("/srv");
|
|
||||||
if (NULL == srv) {
|
if (NULL == srv) {
|
||||||
cgi_error("Cannot opendir(\"/srv\")");
|
cgi_error("Cannot opendir(\"/srv\")");
|
||||||
}
|
}
|
||||||
|
@ -75,7 +78,6 @@ main(int argc, char *argv[])
|
||||||
struct dirent *e = readdir(srv);
|
struct dirent *e = readdir(srv);
|
||||||
char *cat = e->d_name;
|
char *cat = e->d_name;
|
||||||
DIR *puzzles;
|
DIR *puzzles;
|
||||||
char path[PATH_MAX];
|
|
||||||
long catpoints[PUZZLES_MAX];
|
long catpoints[PUZZLES_MAX];
|
||||||
size_t ncatpoints = 0;
|
size_t ncatpoints = 0;
|
||||||
|
|
||||||
|
@ -84,9 +86,8 @@ main(int argc, char *argv[])
|
||||||
/* We have to lstat anyway to see if it's a directory; may as
|
/* We have to lstat anyway to see if it's a directory; may as
|
||||||
well just barge ahead and watch for errors. */
|
well just barge ahead and watch for errors. */
|
||||||
|
|
||||||
/* Open /srv/$cat/puzzles/ */
|
/* Open /srv/ctf/$cat/puzzles/ */
|
||||||
my_snprintf(path, sizeof(path), "/srv/%s/puzzles", cat);
|
puzzles = opendir(srv_path("packages/%s/puzzles", cat));
|
||||||
puzzles = opendir(path);
|
|
||||||
if (NULL == puzzles) {
|
if (NULL == puzzles) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
10
src/register
10
src/register
|
@ -8,9 +8,11 @@ fi
|
||||||
# Don't overwrite files
|
# Don't overwrite files
|
||||||
set -C
|
set -C
|
||||||
|
|
||||||
|
base=${CTF_BASE:-/srv/ctf}
|
||||||
|
|
||||||
# Assign a color. I spent two days selecting this color pallette for
|
# Assign a color. I spent two days selecting this color pallette for
|
||||||
# people with protanopia. Please don't change these colors.
|
# people with protanopia. Please don't change these colors.
|
||||||
nteams=$(ls /var/lib/ctf/teams/names/ | wc -l)
|
nteams=$(ls $base/teams/names/ | wc -l)
|
||||||
case $(expr $nteams % 15) in
|
case $(expr $nteams % 15) in
|
||||||
0) color=8c7a69 ;;
|
0) color=8c7a69 ;;
|
||||||
1) color=7f7062 ;;
|
1) color=7f7062 ;;
|
||||||
|
@ -39,7 +41,7 @@ esac
|
||||||
# me since all team hashes are in the set /[0-9a-f]{8}/.
|
# me since all team hashes are in the set /[0-9a-f]{8}/.
|
||||||
hash=$(echo "$1" | md5sum | cut -b 1-8)
|
hash=$(echo "$1" | md5sum | cut -b 1-8)
|
||||||
|
|
||||||
echo "$1" > /var/lib/ctf/teams/names/$hash
|
echo "$1" > $base/teams/names/$hash
|
||||||
echo "$color" > /var/lib/ctf/teams/colors/$hash
|
echo "$color" > $base/teams/colors/$hash
|
||||||
|
|
||||||
echo "Registered with hash $hash"
|
echo "Registered with hash: $hash"
|
||||||
|
|
|
@ -63,6 +63,11 @@ function output( t, c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
|
base = ENVIRON["CTF_BASE"]
|
||||||
|
if (! base) {
|
||||||
|
base = "/srv/ctf"
|
||||||
|
}
|
||||||
|
|
||||||
# Only display two decimal places
|
# Only display two decimal places
|
||||||
CONVFMT = "%.2f"
|
CONVFMT = "%.2f"
|
||||||
|
|
||||||
|
@ -95,11 +100,11 @@ BEGIN {
|
||||||
|
|
||||||
# Get team colors and names
|
# Get team colors and names
|
||||||
for (team in teams) {
|
for (team in teams) {
|
||||||
fn = "/var/lib/ctf/teams/colors/" team
|
fn = base "/teams/colors/" team
|
||||||
getline colors_by_team[team] < fn
|
getline colors_by_team[team] < fn
|
||||||
close(fn)
|
close(fn)
|
||||||
|
|
||||||
fn = "/var/lib/ctf/teams/names/" team
|
fn = base "/teams/names/" team
|
||||||
getline names_by_team[team] < fn
|
getline names_by_team[team] < fn
|
||||||
close(fn)
|
close(fn)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
#! /bin/sh -e
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo $*
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
CTF_BASE=/tmp/ctf-test.$$ export CTF_BASE
|
||||||
|
trap "rm -rf $CTF_BASE" 0
|
||||||
|
mkdir $CTF_BASE
|
||||||
|
|
||||||
|
# Some skeletal structure
|
||||||
|
mkdir -p $CTF_BASE/points.new
|
||||||
|
|
||||||
|
# Set up some packages
|
||||||
|
for cat in cat1 cat2 cat3; do
|
||||||
|
mkdir -p $CTF_BASE/packages/$cat
|
||||||
|
cat >$CTF_BASE/packages/$cat/answers.txt <<EOF
|
||||||
|
10 ${cat}answer10
|
||||||
|
20 ${cat}answer20
|
||||||
|
30 ${cat}answer30
|
||||||
|
EOF
|
||||||
|
for i in 10 20 30; do
|
||||||
|
mkdir -p $CTF_BASE/packages/$cat/puzzles/$i
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# Set up some teams
|
||||||
|
mkdir -p $CTF_BASE/teams/names
|
||||||
|
mkdir -p $CTF_BASE/teams/colors
|
||||||
|
for team in team1 team2 team3; do
|
||||||
|
hash=$(./register $team | awk '{print $NF;}')
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## Puzzler tests
|
||||||
|
##
|
||||||
|
|
||||||
|
if ./puzzles.cgi | grep 20; then
|
||||||
|
die "20 points puzzles shouldn't show up here"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ./puzzler.cgi t=$hash c=cat1 p=10 a=cat1answer20 | grep -q 'awarded'; then
|
||||||
|
die "Awarded points with wrong answer"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ./puzzler.cgi t=$hash c=cat2 p=10 a=cat1answer10 | grep -q 'awarded'; then
|
||||||
|
die "Awarded points with wrong category"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ./puzzler.cgi t=$hash c=cat1 p=20 a=cat1answer10 | grep -q 'awarded'; then
|
||||||
|
die "Awarded points with wrong point value"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ./puzzler.cgi t=merfmerfmerfmerf c=cat2 p=10 a=cat1answer10 | grep -q 'awarded'; then
|
||||||
|
die "Awarded points with bad team"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! ./puzzler.cgi t=$hash c=cat1 p=10 a=cat1answer10 | grep -q 'awarded 10'; then
|
||||||
|
die "Didn't award points for correct answer"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! ./puzzles.cgi | grep -q 20; then
|
||||||
|
die "20 point answer didn't show up"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ./puzzler.cgi t=$hash c=cat1 p=10 a=cat1answer10 | grep -q 'awarded 10'; then
|
||||||
|
die "Awarded same points twice"
|
||||||
|
fi
|
||||||
|
|
||||||
|
##
|
||||||
|
## Scoreboard tests
|
||||||
|
##
|
||||||
|
|
||||||
|
if ! cat $CTF_BASE/points.new/* | ./scoreboard | grep -q 'total.*team3: 1'; then
|
||||||
|
die "Scoreboard total incorrect"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! cat $CTF_BASE/points.new/* | ./scoreboard | grep -q 'cat1.*team3: 10'; then
|
||||||
|
die "Scoreboard cat1 points incorrect"
|
||||||
|
fi
|
||||||
|
|
||||||
|
##
|
||||||
|
## Token tests
|
||||||
|
##
|
||||||
|
|
||||||
|
mkdir -p $CTF_BASE/token.keys
|
||||||
|
echo -n '0123456789abcdef' > $CTF_BASE/token.keys/tokencat
|
||||||
|
|
||||||
|
# in.tokend uses a random number generator
|
||||||
|
echo -n 'tokencat' | ./in.tokend > /dev/null
|
||||||
|
|
||||||
|
if ! grep -q 'tokencat:x....-....x' $CTF_BASE/tokens.db; then
|
||||||
|
die "in.tokend didn't write to database"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ./claim.cgi t=lalalala k=$(cat $CTF_BASE/tokens.db) | grep -q success; then
|
||||||
|
die "claim.cgi gave points to a bogus team"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ./claim.cgi t=$hash k=tokencat:xanax-xanax | grep -q success; then
|
||||||
|
die "claim.cgi gave points for a bogus token"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! ./claim.cgi t=$hash k=$(cat $CTF_BASE/tokens.db) | grep -q success; then
|
||||||
|
die "claim.cgi didn't give me any points"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ./claim.cgi t=$hash k=$(cat $CTF_BASE/tokens.db) | grep -q success; then
|
||||||
|
die "claim.cgi gave me points twice for the same token"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ -f $CTF_BASE/points.new/*.$hash.tokencat.1 ]; then
|
||||||
|
die "claim.cgi didn't actually record any points"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$0: All tests passed!"
|
||||||
|
echo "$0: Aren't you just the best programmer ever?"
|
Loading…
Reference in New Issue