installing okay now

This commit is contained in:
Neale Pickett 2015-04-10 16:37:21 -06:00
parent e8ad4bccde
commit 5b2b19284a
10 changed files with 539 additions and 491 deletions

View File

@ -1,58 +0,0 @@
#! /bin/sh
echo "Figuring out web user..."
for www in www-data http _; do
id $www && break
done
if [ $www = _ ]; then
echo "Unable to determine httpd user on this system. Dying."
exit 1
fi
initialize () {
for i in points.new points.tmp teams; do
mkdir -p state/$i
setfacl -m ${www}:rwx state/$i
done
>> state/points.log
hd < /dev/urandom | awk '{print $3 $4 $5 $6;}' | head -n 100 > state/teams/assigned.txt
}
once () {
if [ -f disabled ]; then
return
fi
if ! [ -d state ]; then
initialize $1
fi
# Collect new points
find state/points.new -type f | while read fn; do
cat $fn >> state/points.log
rm $fn
done
# Generate new puzzles.html
if $KOTH_BASE/puzzles.cgi > www/puzzles.new; then
mv www/puzzles.new www/puzzles.html
fi
# Generate new points.json
if $KOTH_BASE/points > www/points.new; then
mv www/points.new www/points.json
fi
}
cd $(basename $0)
KOTH_BASE=$(pwd)
while true; do
for dn in $KOTH_BASE/*; do
cd $dn
once
done
sleep 5
done

37
bin/new Executable file
View File

@ -0,0 +1,37 @@
#! /bin/sh
newdir=$1
if [ -z "$newdir" ]; then
echo "Usage: $0 NEWDIR"
exit 1
fi
KOTH_BASE=$(cd $(dirname $0)/.. && pwd)
echo "Figuring out web user..."
for www in www-data http _; do
id $www && break
done
if [ $www = _ ]; then
echo "Unable to determine httpd user on this system. Dying."
exit 1
fi
mkdir -p $newdir
cd $newdir
for i in points.new points.tmp teams; do
mkdir -p state/$i
setfacl -m ${www}:rwx state/$i
done
>> state/points.log
if ! [ -f assigned.txt ]; then
hd < /dev/urandom | awk '{print $3 $4 $5 $6;}' | head -n 100 > assigned.txt
fi
mkdir -p www
cp -r $KOTH_BASE/html/* www/
cp $KOTH_BASE/bin/*.cgi www/

30
bin/once Executable file
View File

@ -0,0 +1,30 @@
#! /bin/sh
cd $(dirname $0)
# Do nothing if `disabled` is present
if [ -f disabled ]; then
exit
fi
# Reset to initial state if `reset` is present
if [ -f reset ]; then
rm -f state/teams/* state/points.new/* state/points.tmp/*
> state/points.log
fi
# Collect new points
find state/points.new -type f | while read fn; do
cat $fn >> state/points.log
rm $fn
done
# Generate new puzzles.html
if $KOTH_BASE/puzzles.cgi > www/puzzles.new; then
mv www/puzzles.new www/puzzles.html
fi
# Generate new points.json
if $KOTH_BASE/points > www/points.new; then
mv www/points.new www/points.json
fi

View File

@ -40,7 +40,7 @@ EOF
if [ -z "$hash" ] || [ -z "$team" ]; then if [ -z "$hash" ] || [ -z "$team" ]; then
echo "<p>Empty field, cannot complete request</p>" echo "<p>Empty field, cannot complete request</p>"
elif ! grep -q "^$hash$" state/teams/assigned.txt; then elif ! grep -q "^$hash$" assigned.txt; then
echo "<p>That hash has not been assigned.</p>" echo "<p>That hash has not been assigned.</p>"
elif [ -f state/teams/names/$hash ]; then elif [ -f state/teams/names/$hash ]; then
echo "<p>That hash has already been registered.</p>" echo "<p>That hash has already been registered.</p>"

View File

@ -8,7 +8,7 @@
<h1>Credits</h1> <h1>Credits</h1>
<section> <section>
<p>Dirtbags King of the Hill was created by:</p> <h2>Created By</h2>
<ul> <ul>
<li>Neale Pickett</li> <li>Neale Pickett</li>
@ -26,16 +26,21 @@
<li>William Phillips</li> <li>William Phillips</li>
<li>Should your name be here? Please remind me!</li> <li>Should your name be here? Please remind me!</li>
</ul> </ul>
</section>
<p>Parts of this contest were inspired by contests from:</p> <section>
<h2>Inspiration</h2>
<ul> <ul>
<li>DC949</li> <li>DC949</li>
<li>Tube Warriors</li> <li>Tube Warriors</li>
<li>Sandia National Laboratories</li> <li>Sandia National Laboratories</li>
</ul> </ul>
</section>
<section>
<h2>Thanks</h2>
<p> <p>
Lastly, this contest would not exist were it not for hundreds of This contest would not exist were it not for hundreds of
thousands of lines of code from free software authors around the thousands of lines of code from free software authors around the
world, including: world, including:
</p> </p>

View File

@ -6,7 +6,15 @@
<link rel="stylesheet" href="css/style.css" type="text/css"> <link rel="stylesheet" href="css/style.css" type="text/css">
</head> </head>
<body> <body>
<h1>Tracer FIRE 6</h1> <h1>Tracer FIRE</h1>
<nav>
<ul>
<li><a href="register.html">Register</a></li>
<li><a href="puzzles.html">Puzzles</a></li>
<li><a href="scoreboard.html">Scoreboard</a></li>
</ul>
</nav>
<section> <section>
<h2>Getting Started</h2> <h2>Getting Started</h2>
@ -42,7 +50,7 @@
<h2>Reading Material</h2> <h2>Reading Material</h2>
<p> <p>
Stuck? Need a break? In the bathroom? Stuck? Taking a break?
Here are some things to read. Here are some things to read.
</p> </p>
@ -57,12 +65,5 @@
</ul> </ul>
</section> </section>
<nav>
<ul>
<li><a href="register.html">Register</a></li>
<li><a href="puzzles.html">Puzzles</a></li>
<li><a href="scoreboard.html">Scoreboard</a></li>
</ul>
</nav>
</body> </body>
</html> </html>

View File

@ -2,10 +2,12 @@
<html> <html>
<head> <head>
<title>Team Registration</title> <title>Team Registration</title>
<link rel="stylesheet" href="ctf.css" type="text/css"> <link rel="stylesheet" href="css/style.css" type="text/css">
</head> </head>
<body> <body>
<h1>Team Registration</h1> <h1>Team Registration</h1>
<section>
<p> <p>
Before you can use a token, you must choose a team name. Before you can use a token, you must choose a team name.
You can only do this once per token, You can only do this once per token,
@ -21,5 +23,6 @@
<br> <br>
<input type="submit" value="Register"> <input type="submit" value="Register">
</form> </form>
</section>
</body> </body>
</html> </html>

60
install
View File

@ -1,6 +1,11 @@
#! /bin/sh #! /bin/sh
DESTDIR=${1:-/opt/koth} DESTDIR=$1
if [ -z "$DESTDIR" ]; then
echo "Usage: $0 DESTDIR"
exit
fi
cd $(dirname $0) cd $(dirname $0)
@ -14,15 +19,6 @@ older () {
return 1 return 1
} }
html () {
target=$DESTDIR/${1%mdwn}html
if older $target $1 tmpl/*; then
echo "HTML $1"
mkdir -p $(dirname $target)
./tmpl/mdwntohtml < $1 > $target
fi
}
copy () { copy () {
target=$DESTDIR/$1 target=$DESTDIR/$1
if older $target $1; then if older $target $1; then
@ -41,6 +37,41 @@ cc () {
fi fi
} }
cgi () {
target=$DESTDIR/www/$(basename $1 .c)
if older $target $@; then
mkdir -p $(dirname $target)
src=$1; shift
echo "CC $src"
gcc -Wall -Werror -o $target $@ src/common.c $src
fi
}
setup() {
echo "SETUP"
for i in points.new points.tmp teams; do
dir=$DESTDIR/state/$i
mkdir -p $dir
setfacl -m ${www}:rwx $dir
done
>> $DESTDIR/state/points.log
if ! [ -f $DESTDIR/assigned.txt ]; then
hd </dev/urandom | awk '{print $3 $4 $5 $6;}' | head -n 100 > assigned.txt
fi
}
echo "Figuring out web user..."
for www in www-data http _; do
id $www && break
done
if [ $www = _ ]; then
echo "Unable to determine httpd user on this system. Dying."
exit 1
fi
mkdir -p $DESTDIR || exit 1
git ls-files | while read fn; do git ls-files | while read fn; do
case "$fn" in case "$fn" in
install|.*) install|.*)
@ -53,8 +84,13 @@ git ls-files | while read fn; do
bin/*) bin/*)
copy $fn copy $fn
;; ;;
src/*.cgi.c|src/pointscli.c) src/common.c)
cc src/common.c $fn ;;
src/pointscli.c)
cc $fn src/common.c
;;
src/*.cgi.c)
cgi $fn
;; ;;
src/*.c) src/*.c)
cc $fn cc $fn

View File

@ -12,9 +12,9 @@
#include "common.h" #include "common.h"
#ifdef NODUMP #ifdef NODUMP
# define DUMPf(fmt, args...) #define DUMPf(fmt, args...)
#else #else
# define DUMPf(fmt, args...) fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##args) #define DUMPf(fmt, args...) fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##args)
#endif #endif
#define DUMP() DUMPf("") #define DUMP() DUMPf("")
#define DUMP_d(v) DUMPf("%s = %d", #v, v) #define DUMP_d(v) DUMPf("%s = %d", #v, v)
@ -47,9 +47,9 @@ read_char_argv()
p = argv[1]; p = argv[1];
} }
if (! p) { if (!p) {
return EOF; return EOF;
} else if (! *p) { } else if (!*p) {
arg += 1; arg += 1;
p = argv[arg]; p = argv[arg];
return '&'; return '&';
@ -88,29 +88,29 @@ read_char_stdin()
static int static int
read_char_query_string() read_char_query_string()
{ {
static char *p = (char *)-1; static char *p = (char *) -1;
if ((char *)-1 == p) { if ((char *) -1 == p) {
p = getenv("QUERY_STRING"); p = getenv("QUERY_STRING");
} }
if (! p) { if (!p) {
return EOF; return EOF;
} else if (! *p) { } else if (!*p) {
return EOF; return EOF;
} else { } else {
return *(p++); return *(p++);
} }
} }
static int (* read_char)() = read_char_argv; static int (*read_char) () = read_char_argv;
int int
cgi_init(char *global_argv[]) cgi_init(char *global_argv[])
{ {
char *rm = getenv("REQUEST_METHOD"); char *rm = getenv("REQUEST_METHOD");
if (! rm) { if (!rm) {
read_char = read_char_argv; read_char = read_char_argv;
argv = global_argv; argv = global_argv;
} else if (0 == strcmp(rm, "POST")) { } else if (0 == strcmp(rm, "POST")) {
@ -121,11 +121,7 @@ cgi_init(char *global_argv[])
is_cgi = 1; is_cgi = 1;
} else { } else {
printf(("405 Method not allowed\r\n" printf(("405 Method not allowed\r\n"
"Allow: GET, POST\r\n" "Allow: GET, POST\r\n" "Content-type: text/plain\r\n" "\r\n" "%s is not allowed.\n"), rm);
"Content-type: text/plain\r\n"
"\r\n"
"%s is not allowed.\n"),
rm);
return -1; return -1;
} }
@ -153,12 +149,12 @@ read_hex()
int a = read_char(); int a = read_char();
int b = read_char(); int b = read_char();
return tonum(a)*16 + tonum(b); 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. * 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 size_t
cgi_item(char *str, size_t maxlen) cgi_item(char *str, size_t maxlen)
{ {
@ -197,19 +193,15 @@ cgi_head(char *title)
"<html>\n" "<html>\n"
" <head>\n" " <head>\n"
" <title>%s</title>\n" " <title>%s</title>\n"
" <link rel=\"stylesheet\" href=\"ctf.css\" type=\"text/css\">\n" " <link rel=\"stylesheet\" href=\"css/style.css\">\n"
" </head>\n" " </head>\n"
" <body>\n" " <body><h1>%s</h1><section>\n"), title, title);
" <h1>%s</h1>\n"),
title, title);
} }
void void
cgi_foot() cgi_foot()
{ {
printf("\n" printf("\n</section></body></html>\n");
" </body>\n"
"</html>\n");
} }
void void
@ -237,7 +229,8 @@ cgi_fail(int err)
case ERR_NOTEAM: case ERR_NOTEAM:
cgi_result(409, "No such team", "<p>There is no team with that hash.</p>"); cgi_result(409, "No such team", "<p>There is no team with that hash.</p>");
case ERR_CLAIMED: case ERR_CLAIMED:
cgi_result(409, "Already claimed", "<p>That is the correct answer, but your team has already claimed these points.</p>"); cgi_result(409, "Already claimed",
"<p>That is the correct answer, but your team has already claimed these points.</p>");
default: default:
cgi_result(409, "Failure", "<p>Failure code: %d</p>", err); cgi_result(409, "Failure", "<p>Failure code: %d</p>", err);
} }
@ -267,7 +260,9 @@ cgi_error(char *text)
* Common routines * Common routines
*/ */
/* cut -d$ANCHOR -f2- | grep -Fx "$NEEDLE" */ /*
* cut -d$ANCHOR -f2- | grep -Fx "$NEEDLE"
*/
int int
anchored_search(char const *filename, char const *needle, char const anchor) anchored_search(char const *filename, char const *needle, char const anchor)
{ {
@ -283,10 +278,12 @@ anchored_search(char const *filename, char const *needle, char const anchor)
break; break;
} }
/* Find anchor */ /*
* Find anchor
*/
if (anchor) { if (anchor) {
p = strchr(line, anchor); p = strchr(line, anchor);
if (! p) { if (!p) {
continue; continue;
} }
p += 1; p += 1;
@ -294,17 +291,18 @@ anchored_search(char const *filename, char const *needle, char const anchor)
p = line; p = line;
} }
/* Don't bother with strcmp if string lengths differ. /*
If this string is shorter than the previous, it's okay. This is * Don't bother with strcmp if string lengths differ. If this string is shorter than the previous, it's okay. This
just a performance hack. * is just a performance hack.
*/ */
if ((p[nlen] != '\n') && if ((p[nlen] != '\n') && (p[nlen] != '\0')) {
(p[nlen] != '\0')) {
continue; continue;
} }
p[nlen] = 0; p[nlen] = 0;
/* Okay, now we can compare! */ /*
* Okay, now we can compare!
*/
if (0 == strcmp(p, needle)) { if (0 == strcmp(p, needle)) {
ret = 1; ret = 1;
break; break;
@ -336,12 +334,14 @@ urandom(char *buf, size_t buflen)
} }
} }
/* Fall back to libc's crappy thing */ /*
* Fall back to libc's crappy thing
*/
{ {
int i; int i;
for (i = 0; i < buflen; i += 1) { for (i = 0; i < buflen; i += 1) {
buf[i] = (char)random(); buf[i] = (char) random();
} }
} }
} }
@ -374,7 +374,9 @@ ctf_chdir()
} }
initialized = 1; initialized = 1;
/* chdir to $CTF_BASE */ /*
* chdir to $CTF_BASE
*/
{ {
char const *ctf_base = getenv("CTF_BASE"); char const *ctf_base = getenv("CTF_BASE");
@ -383,12 +385,13 @@ ctf_chdir()
} }
} }
/* Keep going up one directory until there's a packages directory */ /*
* Keep going up one directory until there's a packages directory
*/
for (i = 0; i < 5; i += 1) { for (i = 0; i < 5; i += 1) {
struct stat st; struct stat st;
if ((0 == stat("packages", &st)) && if ((0 == stat("packages", &st)) && S_ISDIR(st.st_mode)) {
S_ISDIR(st.st_mode)) {
return; return;
} }
chdir(".."); chdir("..");
@ -408,7 +411,9 @@ mkpath(char const *type, char const *fmt, va_list ap)
vsnprintf(relpath, sizeof(relpath) - 1, fmt, ap); vsnprintf(relpath, sizeof(relpath) - 1, fmt, ap);
relpath[sizeof(relpath) - 1] = '\0'; relpath[sizeof(relpath) - 1] = '\0';
/* $CTF_BASE/type/relpath */ /*
* $CTF_BASE/type/relpath
*/
my_snprintf(path, sizeof(path), "%s/%s", type, relpath); my_snprintf(path, sizeof(path), "%s/%s", type, relpath);
return path; return path;
} }
@ -445,18 +450,22 @@ team_exists(char const *teamhash)
int ret; int ret;
int i; int i;
if ((! teamhash) || (! *teamhash)) { if ((!teamhash) || (!*teamhash)) {
return 0; 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])) {
return 0; return 0;
} }
} }
/* stat seems to be the preferred way to check for existence. */ /*
* stat seems to be the preferred way to check for existence.
*/
ret = stat(state_path("teams/names/%s", teamhash), &buf); ret = stat(state_path("teams/names/%s", teamhash), &buf);
if (-1 == ret) { if (-1 == ret) {
return 0; return 0;
@ -465,16 +474,11 @@ team_exists(char const *teamhash)
return 1; return 1;
} }
/* Return values: /*
-1: general error * Return values: -1: general error -2: no such team -3: points already awarded
-2: no such team
-3: points already awarded
*/ */
int int
award_points(char const *teamhash, award_points(char const *teamhash, char const *category, const long points, char const *uid)
char const *category,
const long points,
char const *uid)
{ {
char line[100]; char line[100];
int linelen; int linelen;
@ -482,13 +486,11 @@ award_points(char const *teamhash,
FILE *f; FILE *f;
time_t now = time(NULL); time_t now = time(NULL);
if (! team_exists(teamhash)) { if (!team_exists(teamhash)) {
return ERR_NOTEAM; return ERR_NOTEAM;
} }
linelen = snprintf(line, sizeof(line), linelen = snprintf(line, sizeof(line), "%s %s %ld %s", teamhash, category, points, uid);
"%s %s %ld %s",
teamhash, category, points, uid);
if (sizeof(line) <= linelen) { if (sizeof(line) <= linelen) {
return ERR_GENERAL; return ERR_GENERAL;
} }
@ -497,46 +499,39 @@ award_points(char const *teamhash,
return ERR_CLAIMED; return ERR_CLAIMED;
} }
/* At one time I had this writing to a single log file, using lockf. /*
This works, as long as nobody ever tries to edit the log file. * At one time I had this writing to a single log file, using lockf. This works, as long as nobody ever tries to edit the
Editing the log file would require locking it, which would block * log file. Editing the log file would require locking it, which would block everything trying to score, effectively
everything trying to score, effectively taking down the entire * taking down the entire contest. If you can't lock it first--and nothing in busybox lets you do this--you have to bring
contest. If you can't lock it first--and nothing in busybox lets * down pretty much everything manually anyway.
you do this--you have to bring down pretty much everything manually *
anyway. * By putting new scores into new files and periodically appending those files to the main log file, it is possible to stop
* the thing that appends, edit the file at leisure, and then start the appender back up, all without affecting things
By putting new scores into new files and periodically appending * trying to score: they're still able to record their score and move on.
those files to the main log file, it is possible to stop the thing
that appends, edit the file at leisure, and then start the appender
back up, all without affecting things trying to score: they're
still able to record their score and move on.
*/ */
filename = state_path("points.tmp/%lu.%d.%s.%s.%ld", filename = state_path("points.tmp/%lu.%d.%s.%s.%ld", (unsigned long) now, getpid(), teamhash, category, points);
(unsigned long)now, getpid(),
teamhash, category, points);
f = fopen(filename, "w"); f = fopen(filename, "w");
if (! f) { if (!f) {
return ERR_GENERAL; return ERR_GENERAL;
} }
if (EOF == fprintf(f, "%lu %s\n", (unsigned long)now, line)) { if (EOF == fprintf(f, "%lu %s\n", (unsigned long) now, line)) {
return ERR_GENERAL; return ERR_GENERAL;
} }
fclose(f); fclose(f);
/* Rename into points.new */ /*
* Rename into points.new
*/
{ {
char ofn[PATH_MAX]; char ofn[PATH_MAX];
strncpy(ofn, filename, sizeof(ofn)); strncpy(ofn, filename, sizeof(ofn));
filename = state_path("points.new/%lu.%d.%s.%s.%ld", filename = state_path("points.new/%lu.%d.%s.%s.%ld", (unsigned long) now, getpid(), teamhash, category, points);
(unsigned long)now, getpid(),
teamhash, category, points);
rename(ofn, filename); rename(ofn, filename);
} }
return 0; return 0;
} }

View File

@ -12,8 +12,7 @@ main(int argc, char *argv[])
char comment[512]; char comment[512];
if (argc != 5) { if (argc != 5) {
fprintf(stderr, fprintf(stderr, "Usage: pointscli TEAM CATEGORY POINTS 'COMMENT'\n");
"Usage: pointscli TEAM CATEGORY POINTS 'COMMENT'\n");
return EX_USAGE; return EX_USAGE;
} }
ctf_chdir(); ctf_chdir();