diff --git a/src/Makefile b/src/Makefile index d31695c..5b83d50 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,7 @@ -all: in.tokend register.cgi +all: in.tokend register.cgi pointscli in.tokend: in.tokend.o xxtea.o register.cgi: register.cgi.o cgi.o +pointscli: common.o pointscli.o diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..d168b19 --- /dev/null +++ b/src/common.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + +int +timestamp(char *now, size_t nowlen) +{ + time_t t; + struct tm tmp; + + time(&t); + if (NULL == gmtime_r(&t, &tmp)) { + perror("gmtime_r"); + return -1; + } + + if (0 == strftime(now, nowlen, "%Y-%m-%dT%H:%M:%SZ", &tmp)) { + return -1; + } + + return 0; +} + +int +team_exists(char *teamhash) +{ + struct stat buf; + char filename[100]; + int ret; + int i; + + /* Check for invalid characters. */ + for (i = 0; teamhash[i]; i += 1) { + if (! isalnum(teamhash[i])) { + return 0; + } + } + + /* 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. */ + ret = lstat(filename, &buf); + if (-1 == ret) { + return 0; + } + + return 1; +} + +int +award_points(char *teamhash, char *category, int points) +{ + char now[40]; + char line[100]; + int linelen; + int fd; + int ret; + + if (! team_exists(teamhash)) { + return -2; + } + + ret = timestamp(now, sizeof(now)); + if (-1 == ret) { + return -3; + } + linelen = snprintf(line, sizeof(line), + "%s %s %s %d\n", + now, teamhash, category, points); + if (sizeof(line) == linelen) { + return -1; + } + + fd = open(pointslog, O_WRONLY | O_CREAT, 0666); + if (-1 == fd) { + return -1; + } + + ret = lockf(fd, F_LOCK, 0); + if (-1 == ret) { + close(fd); + return -1; + } + + ret = lseek(fd, 0, SEEK_END); + if (-1 == ret) { + close(fd); + return -1; + } + + write(fd, line, linelen); + close(fd); + return 0; +} diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..b8a238c --- /dev/null +++ b/src/common.h @@ -0,0 +1,11 @@ +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#define teamdir "/var/lib/ctf/teams" +#define pointslog "/var/lib/ctf/points.log" + +int timestamp(char *now, size_t nowlen); +int team_exists(char *teamhash); +int award_points(char *teamhash, char *category, int point); + +#endif diff --git a/src/pointscli.c b/src/pointscli.c new file mode 100644 index 0000000..f74d512 --- /dev/null +++ b/src/pointscli.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include "common.h" + +int +main(int argc, char *argv[]) +{ + int points; + int ret; + + if (argc != 4) { + fprintf(stderr, "Usage: pointscli TEAM CATEGORY POINTS\n"); + return EX_USAGE; + } + + points = atoi(argv[3]); + if (0 == points) { + fprintf(stderr, "Error: award 0 points?\n"); + return EX_USAGE; + } + + ret = award_points(argv[1], argv[2], points); + switch (ret) { + case -3: + fprintf(stderr, "Runtime error\n"); + return EX_SOFTWARE; + case -2: + fprintf(stderr, "No such team\n"); + return EX_NOUSER; + case -1: + perror("Couldn't award points"); + return EX_UNAVAILABLE; + } + + return 0; +}