Move CGI routines into common.c

They're still good general-purpose routines, though.
This commit is contained in:
Neale Pickett 2010-09-11 23:22:28 -06:00
parent c3bf43b132
commit 5199cf5cac
7 changed files with 149 additions and 156 deletions

View File

@ -4,8 +4,8 @@ all: $(TARGETS)
in.tokend: in.tokend.o xxtea.o
claim.cgi: claim.cgi.o cgi.o common.o
puzzler.cgi: puzzler.cgi.o cgi.o common.o
claim.cgi: claim.cgi.o common.o
puzzler.cgi: puzzler.cgi.o common.o
pointscli: common.o pointscli.o
clean:

130
src/cgi.c
View File

@ -1,130 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.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\r\n"
"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"));
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
cgi_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;
}
}
}
void
cgi_page(char *title, char *fmt, ...)
{
va_list ap;
printf(("Content-type: text/html\r\n"
"\r\n"
"<!DOCTYPE html>\n"
"<html>\n"
" <head>\n"
" <title>%s</title>\n"
" <link rel=\"stylesheet\" href=\"ctf.css\" type=\"text/css\">\n"
" </head>\n"
" <body>\n"
" <h1>%s</h1>\n"),
title, title);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n"
" </body>\n"
"</html>\n");
exit(0);
}
void
cgi_error(char *fmt, ...)
{
va_list ap;
printf("500 Internal Error\r\n"
"Content-type: text/plain\r\n"
"\r\n");
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
exit(0);
}

View File

@ -1,11 +0,0 @@
#ifndef __CGI_H__
#define __CGI_H__
#include <stddef.h>
int cgi_init();
size_t cgi_item(char *str, size_t maxlen);
void cgi_page(char *title, char *fmt, ...);
void cgi_error(char *fmt, ...);
#endif

View File

@ -1,7 +1,4 @@
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include "cgi.h"
#include <stdlib.h>
#include "common.h"
char const *tokenlog = "/var/lib/ctf/tokend/tokens.log";

View File

@ -3,12 +3,147 @@
#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include "cgi.h"
#include "common.h"
/*
* CGI
*/
static size_t inlen = 0;
int
cgi_init()
{
char *rm = getenv("REQUEST_METHOD");
if (! (rm && (0 == strcmp(rm, "POST")))) {
printf("405 Method not allowed\r\n"
"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"));
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
cgi_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;
}
}
}
void
cgi_page(char *title, char *fmt, ...)
{
va_list ap;
printf(("Content-type: text/html\r\n"
"\r\n"
"<!DOCTYPE html>\n"
"<html>\n"
" <head>\n"
" <title>%s</title>\n"
" <link rel=\"stylesheet\" href=\"ctf.css\" type=\"text/css\">\n"
" </head>\n"
" <body>\n"
" <h1>%s</h1>\n"),
title, title);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n"
" </body>\n"
"</html>\n");
exit(0);
}
void
cgi_error(char *fmt, ...)
{
va_list ap;
printf("500 Internal Error\r\n"
"Content-type: text/plain\r\n"
"\r\n");
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
exit(0);
}
/*
* Common routines
*/
#define EOL(c) ((EOF == (c)) || (0 == (c)) || ('\n' == (c)))
int
@ -181,9 +316,8 @@ award_and_log_uniquely(char const *team,
va_list ap;
/* Make sure they haven't already claimed these points */
/* Leave room for a newline later on */
va_start(ap, fmt);
len = vsnprintf(line, sizeof(line)-1, fmt, ap);
len = vsnprintf(line, sizeof(line), fmt, ap);
va_end(ap);
if (sizeof(line) <= len) {
cgi_error("Log line too long");
@ -213,7 +347,7 @@ award_and_log_uniquely(char const *team,
line[len] = '\n';
lseek(fd, 0, SEEK_END);
if (-1 == write(fd, line, len+1)) {
cgi_error("Unable to log your award");
cgi_error("Unable to append log");
}
close(fd);
}

View File

@ -1,6 +1,14 @@
#ifndef __COMMON_H__
#define __COMMON_H__
#include <stddef.h>
int cgi_init();
size_t cgi_item(char *str, size_t maxlen);
void cgi_page(char *title, char *fmt, ...);
void cgi_error(char *fmt, ...);
#define teamdir "/var/lib/ctf/teams/names"
#define pointsdir "/var/lib/ctf/points/new"

View File

@ -1,10 +1,5 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include "cgi.h"
char const *logfile = "/var/lib/ctf/puzzler.log";