diff --git a/Makefile b/Makefile index 10c7c0b..42e28f5 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -BINARIES = forftanks designer.cgi +BINARIES = forftanks upload.cgi HTML = forf.html procs.html intro.html designer.html WWW = style.css grunge.png designer.js figures.js tanks.js nav.html.inc diff --git a/designer.cgi.c b/designer.cgi.c deleted file mode 100644 index 1430444..0000000 --- a/designer.cgi.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * This software has been authored by an employee or employees of Los - * Alamos National Security, LLC, operator of the Los Alamos National - * Laboratory (LANL) under Contract No. DE-AC52-06NA25396 with the U.S. - * Department of Energy. The U.S. Government has rights to use, - * reproduce, and distribute this software. The public may copy, - * distribute, prepare derivative works and publicly display this - * software without charge, provided that this Notice and any statement - * of authorship are reproduced on all copies. Neither the Government - * nor LANS makes any warranty, express or implied, or assumes any - * liability or responsibility for the use of this software. If - * software is modified to produce derivative works, such modified - * software should be clearly marked, so as not to confuse it with the - * version available from LANL. - */ - -#include -#include -#include -#include -#include -#include -#include - -char *BASE_PATH = ""; - -struct { - char *name; - size_t size; -} entries[] = { - {"name", 20}, - {"author", 40}, - {"color", 10}, - {"program", 8192}, - {NULL, 0} -}; - - -size_t inlen; - -int -read_char() -{ - if (inlen) { - inlen -= 1; - return getchar(); - } - return EOF; -} - -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; -} - -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; - } - } -} - -size_t -copy_item(char *filename, size_t maxlen) -{ - FILE *f; - char path[132]; - int c; - size_t pos = 0; - - snprintf(path, sizeof(path), - "%s%05d.%s", BASE_PATH, - getpid(), filename); - f = fopen(path, "w"); - if (! f) { - /* Just send it to the bit bucket */ - maxlen = 0; - } - - while (1) { - c = read_char(); - switch (c) { - case EOF: - case '=': - case '&': - if (f) fclose(f); - return pos; - case '%': - c = read_hex(); - break; - case '+': - c = ' '; - break; - } - if (pos < maxlen) { - fputc(c, f); - pos += 1; - } - } -} - -int -croak(char *msg) -{ - int i; - char path[132]; - - for (i = 0; entries[i].name; i += 1) { - snprintf(path, sizeof(path), - "%s%05d.%s", BASE_PATH, - getpid(), entries[i].name); - unlink(path); - } - - printf("Content-type: text/html\n\n"); - printf("\n"); - printf("\n"); - printf("Tank submission error\n"); - printf("

Tank submission error

\n"); - if (msg) { - printf("

%s.

\n", msg); - } else { - printf("

Something went wrong.

.\n"); - } - printf("

Sorry it didn't work out.

\n"); - printf("

You could go back and try again, though.

\n"); - printf("\n"); - - return 0; -} - -int -main(int argc, char *argv[]) -{ - int sensor[10][4]; - char key[20]; - char token[40]; - size_t len; - - memset(sensor, 0, sizeof(sensor)); - token[0] = '\0'; - - BASE_PATH = getenv("BASE_PATH"); - if (! BASE_PATH) { - BASE_PATH = ""; - } - - { - char *rm = getenv("REQUEST_METHOD"); - - if (! (rm && (0 == strcmp(rm, "POST")))) { - printf("405 Method not allowed\n"); - printf("Allow: POST\n"); - printf("Content-type: text/html\n"); - printf("\n"); - printf("

Method not allowed

\n"); - printf("

I only speak POST. Sorry.

\n"); - return 0; - } - - inlen = atoi(getenv("CONTENT_LENGTH")); - } - - while (inlen) { - len = read_item(key, sizeof(key)); - if (0 == strcmp(key, "token")) { - read_item(token, sizeof(token)); - } else if ((3 == len) && ('s' == key[0])) { - /* sensor dealie, key = "s[0-9][rawt]" */ - char val[5]; - int n = key[1] - '0'; - int i; - int p; - - read_item(val, sizeof(val)); - - if (! (n >= 0) && (n <= 9)) { - break; - } - i = atoi(val); - - switch (key[2]) { - case 'r': - p = 0; - break; - case 'a': - p = 1; - break; - case 'w': - p = 2; - break; - default: - p = 3; - i = (val[0] != '\0'); - break; - } - - sensor[n][p] = i; - } else { - int i; - - for (i = 0; entries[i].name; i += 1) { - if (0 == strcmp(key, entries[i].name)) { - len = copy_item(key, entries[i].size); - break; - } - } - } - } - - /* Sanitize token */ - { - char *p = token; - - while (*p) { - if (! isalnum(*p)) { - *p = '_'; - } - p += 1; - } - - if ('\0' == token[0]) { - token[0] = '_'; - token[1] = '\0'; - } - } - - /* Move files into their directory */ - { - char path[132]; - char dest[132]; - struct stat st; - int i; - - snprintf(path, sizeof(path), "%s%s/", BASE_PATH, token); - if (-1 == stat(path, &st)) return croak("Invalid token"); - if (! S_ISDIR(st.st_mode)) return croak("Invalid token"); - for (i = 0; entries[i].name; i += 1) { - snprintf(path, sizeof(path), - "%s%05d.%s", BASE_PATH, - getpid(), entries[i].name); - snprintf(dest, sizeof(dest), - "%s%s/%s", BASE_PATH, - token, entries[i].name); - rename(path, dest); - } - - for (i = 0; i < 10; i += 1) { - FILE *f; - - snprintf(dest, sizeof(dest), - "%s%s/sensor%d", BASE_PATH, - token, i); - f = fopen(dest, "w"); - if (! f) break; - - fprintf(f, "%d %d %d %d\n", - sensor[i][0], - sensor[i][1], - sensor[i][2], - sensor[i][3]); - fclose(f); - } - } - - printf("Content-type: text/html\n\n"); - printf("\n"); - printf("\n"); - printf("\n"); - printf("Tank submitted\n"); - printf("

Tank submitted

\n"); - printf("

You just uploaded a tank!

\n"); - printf("

Let's hope it doesn't suck.

\n"); - printf("\n"); - - return 0; -} diff --git a/upload.cgi.c b/upload.cgi.c new file mode 100644 index 0000000..7fc0ea6 --- /dev/null +++ b/upload.cgi.c @@ -0,0 +1,303 @@ +/* + * This software has been authored by an employee or employees of Los + * Alamos National Security, LLC, operator of the Los Alamos National + * Laboratory (LANL) under Contract No. DE-AC52-06NA25396 with the U.S. + * Department of Energy. The U.S. Government has rights to use, + * reproduce, and distribute this software. The public may copy, + * distribute, prepare derivative works and publicly display this + * software without charge, provided that this Notice and any statement + * of authorship are reproduced on all copies. Neither the Government + * nor LANS makes any warranty, express or implied, or assumes any + * liability or responsibility for the use of this software. If + * software is modified to produce derivative works, such modified + * software should be clearly marked, so as not to confuse it with the + * version available from LANL. + */ + +#include +#include +#include +#include +#include +#include +#include + +char *BASE_PATH = ""; + +struct { + char *name; + size_t size; +} entries[] = { + { + "name", 20}, { + "author", 80}, { + "color", 10}, { + "program", 16384}, { + NULL, 0} +}; + + +size_t inlen; + +int +read_char() +{ + if (inlen) { + inlen -= 1; + return getchar(); + } + return EOF; +} + +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; +} + +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; + } + } +} + +size_t +copy_item(char *filename, size_t maxlen) +{ + FILE *f; + char path[132]; + int c; + size_t pos = 0; + + snprintf(path, sizeof(path), "%s%05d.%s", BASE_PATH, getpid(), filename); + f = fopen(path, "w"); + if (!f) { + /* + * Just send it to the bit bucket + */ + maxlen = 0; + } + + while (1) { + c = read_char(); + switch (c) { + case EOF: + case '=': + case '&': + if (f) + fclose(f); + return pos; + case '%': + c = read_hex(); + break; + case '+': + c = ' '; + break; + } + if (pos < maxlen) { + fputc(c, f); + pos += 1; + } + } +} + +int +croak(int code, char *msg) +{ + int i; + char path[132]; + + for (i = 0; entries[i].name; i += 1) { + snprintf(path, sizeof(path), "%s%05d.%s", BASE_PATH, getpid(), entries[i].name); + unlink(path); + } + + printf("Status: %d %s\n", code, msg); + printf("Content-type: text/plain\n"); + printf("\n"); + printf("Error: %s\n", msg); + + return 0; +} + +int +main(int argc, char *argv[]) +{ + int sensor[10][4]; + char key[20]; + char token[40]; + size_t len; + + memset(sensor, 0, sizeof(sensor)); + token[0] = '\0'; + + BASE_PATH = getenv("BASE_PATH"); + if (!BASE_PATH) { + BASE_PATH = ""; + } + + { + char *rm = getenv("REQUEST_METHOD"); + + if (!(rm && (0 == strcmp(rm, "POST")))) { + printf("405 Method not allowed\n"); + printf("Allow: POST\n"); + printf("Content-type: text/plain\n"); + printf("\n"); + printf("Error: I only speak POST\n"); + return 0; + } + + inlen = atoi(getenv("CONTENT_LENGTH")); + } + + while (inlen) { + len = read_item(key, sizeof(key)); + if (0 == strcmp(key, "token")) { + read_item(token, sizeof(token)); + } else if ((3 == len) && ('s' == key[0])) { + /* + * sensor dealie, key = "s[0-9][rawt]" + */ + char val[5]; + int n = key[1] - '0'; + int i; + int p; + + read_item(val, sizeof(val)); + + if (!(n >= 0) && (n <= 9)) { + break; + } + i = atoi(val); + + switch (key[2]) { + case 'r': + p = 0; + break; + case 'a': + p = 1; + break; + case 'w': + p = 2; + break; + default: + p = 3; + i = (val[0] != '\0'); + break; + } + + sensor[n][p] = i; + } else { + int i; + + for (i = 0; entries[i].name; i += 1) { + if (0 == strcmp(key, entries[i].name)) { + len = copy_item(key, entries[i].size); + break; + } + } + } + } + + /* + * Sanitize token + */ + { + char *p = token; + + while (*p) { + if (!isalnum(*p)) { + *p = '_'; + } + p += 1; + } + + if ('\0' == token[0]) { + token[0] = '_'; + token[1] = '\0'; + } + } + + /* + * Move files into their directory + */ + { + char path[132]; + char dest[132]; + struct stat st; + int i; + + snprintf(path, sizeof(path), "%s%s/", BASE_PATH, token); + if (-1 == stat(path, &st)) + return croak(422, "Invalid token"); + if (!S_ISDIR(st.st_mode)) + return croak(422, "Invalid token"); + for (i = 0; entries[i].name; i += 1) { + snprintf(path, sizeof(path), "%s%05d.%s", BASE_PATH, getpid(), entries[i].name); + snprintf(dest, sizeof(dest), "%s%s/%s", BASE_PATH, token, entries[i].name); + rename(path, dest); + } + + for (i = 0; i < 10; i += 1) { + FILE *f; + + snprintf(dest, sizeof(dest), "%s%s/sensor%d", BASE_PATH, token, i); + f = fopen(dest, "w"); + if (!f) + break; + + fprintf(f, "%d %d %d %d\n", sensor[i][0], sensor[i][1], sensor[i][2], sensor[i][3]); + fclose(f); + } + } + + printf("Content-type: text/plain\n"); + printf("\n"); + printf("OK: Tank submitted!\n"); + + return 0; +}