347 righe
7.4 KiB
C
347 righe
7.4 KiB
C
/**
|
|
* @PROJECT CGI Bash Shell Interface
|
|
* @COPYRIGHT See COPYING in the top level directory
|
|
* @FILE mimetype.c
|
|
* @PURPOSE Mimetype and file upload handler
|
|
* @DEVELOPERS Nathan Angelacos <nangel@users.sourceforge.net>
|
|
* Rafal Kupiec <belliash@asiotec.eu.org>
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "common.h"
|
|
#include "buffer.h"
|
|
#include "error.h"
|
|
#include "subshell.h"
|
|
#include "buffer.h"
|
|
#include "mimetype.h"
|
|
#include "cbsi.h"
|
|
|
|
void empty_stdin(void) {
|
|
char c[2000];
|
|
while(read(STDIN_FILENO, &c, 2000)) {
|
|
}
|
|
}
|
|
|
|
void mime_var_init(mime_var_t* obj) {
|
|
obj->name = NULL;
|
|
obj->filename = NULL;
|
|
obj->type = NULL;
|
|
obj->tempname = NULL;
|
|
buffer_init(&(obj->value));
|
|
obj->fh = 0;
|
|
}
|
|
|
|
void mime_var_destroy(mime_var_t* obj) {
|
|
int status;
|
|
struct sigaction new_action;
|
|
|
|
if(obj->name) {
|
|
free(obj->name);
|
|
obj->name = NULL;
|
|
}
|
|
if(obj->filename) {
|
|
free(obj->filename);
|
|
obj->filename = NULL;
|
|
}
|
|
if(obj->type) {
|
|
free(obj->type);
|
|
obj->type = NULL;
|
|
}
|
|
if(obj->tempname) {
|
|
free(obj->tempname);
|
|
obj->tempname = NULL;
|
|
}
|
|
buffer_destroy(&(obj->value));
|
|
if(obj->fh) {
|
|
close(abs(obj->fh));
|
|
obj->fh = 0;
|
|
}
|
|
}
|
|
|
|
char* mime_substr(char* start, int len) {
|
|
char* ptr;
|
|
|
|
if(!start) {
|
|
return NULL;
|
|
}
|
|
if(len < 0) {
|
|
return NULL;
|
|
}
|
|
ptr = xmalloc(len + 2);
|
|
memcpy(ptr, start, len);
|
|
return ptr;
|
|
}
|
|
|
|
void mime_tag_add(mime_var_t* obj, char* str) {
|
|
char* a = NULL;
|
|
char* b = NULL;
|
|
static char* tag[] = { "name=\"", "filename=\"", "Content-Type: " };
|
|
|
|
a = strcasestr(str, tag[0]);
|
|
if(a) {
|
|
a += strlen(tag[0]);
|
|
b = strchr(a, '"');
|
|
if(!obj->name) {
|
|
obj->name = mime_substr(a, b - a);
|
|
}
|
|
}
|
|
a = strcasestr(str, tag[1]);
|
|
if(a) {
|
|
a += strlen(tag[1]);
|
|
b = strchr(a, '"');
|
|
if(!obj->filename) {
|
|
obj->filename = mime_substr(a, b - a);
|
|
}
|
|
}
|
|
a = strcasestr(str, tag[2]);
|
|
if(a) {
|
|
a += strlen(tag[2]);
|
|
b = a + strlen(a);
|
|
if(!obj->type) {
|
|
obj->type = mime_substr(a, b - a);
|
|
}
|
|
}
|
|
}
|
|
|
|
void mime_var_putenv(list_t* env, mime_var_t* obj) {
|
|
buffer_t buf;
|
|
|
|
buffer_init(&buf);
|
|
if(obj->filename) {
|
|
buffer_add(&buf, obj->name, strlen(obj->name));
|
|
buffer_add(&buf, "=", 1);
|
|
buffer_add(&buf, (char*) obj->value.data,
|
|
strlen((char*) obj->value.data) + 1);
|
|
myputenv(env, (char*) buf.data, global.file_prefix);
|
|
buffer_reset(&buf);
|
|
buffer_add(&buf, obj->name, strlen(obj->name));
|
|
buffer_add(&buf, "=", 1);
|
|
buffer_add(&buf, obj->filename, strlen(obj->filename) + 1);
|
|
myputenv(env, (char*) buf.data, global.filename_prefix);
|
|
buffer_reset (&buf);
|
|
} else if(obj->name) {
|
|
buffer_add(&(obj->value), "", 1);
|
|
buffer_add(&buf, obj->name, strlen(obj->name));
|
|
buffer_add(&buf, "=", 1);
|
|
buffer_add(&buf, (char*) obj->value.data,
|
|
strlen((char*) obj->value.data) + 1);
|
|
myputenv(env, (char*) buf.data, global.file_prefix);
|
|
buffer_reset(&buf);
|
|
}
|
|
buffer_destroy(&buf);
|
|
}
|
|
|
|
void mime_exec(mime_var_t* obj, char* fifo) {
|
|
int pid;
|
|
char* type;
|
|
char* filename;
|
|
char* name;
|
|
char *c;
|
|
int fh;
|
|
struct sigaction new_action;
|
|
|
|
pid = fork();
|
|
if(pid == -1) {
|
|
empty_stdin();
|
|
die_with_message(NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]);
|
|
}
|
|
if(pid == 0) {
|
|
if(obj->type) {
|
|
type = xmalloc(13 + strlen(obj->type) + 1);
|
|
sprintf(type, "CONTENT_TYPE=%s", obj->type);
|
|
putenv(type);
|
|
}
|
|
if(obj->filename) {
|
|
filename = xmalloc (9 + strlen(obj->filename) + 1);
|
|
sprintf(filename, "FILENAME=%s", obj->filename);
|
|
putenv(filename);
|
|
}
|
|
if(obj->name) {
|
|
name = xmalloc(5 + strlen(obj->name) + 1);
|
|
sprintf(name, "NAME=%s", obj->name);
|
|
putenv(name);
|
|
}
|
|
fh = open(fifo, O_RDONLY);
|
|
while(read(fh, &c, 1)) {
|
|
}
|
|
exit(-1);
|
|
} else {
|
|
new_action.sa_handler = SIG_IGN;
|
|
sigemptyset(&new_action.sa_mask);
|
|
new_action.sa_flags = 0;
|
|
sigaction(SIGPIPE, &new_action, NULL);
|
|
}
|
|
}
|
|
|
|
void mime_var_open_target(mime_var_t* obj) {
|
|
char* tmpname;
|
|
token_t* curtoken;
|
|
curtoken = global.uploadlist;
|
|
int ok;
|
|
|
|
if(global.uploadkb == 0) {
|
|
empty_stdin();
|
|
die_with_message(NULL, NULL, "File uploads are not allowed.");
|
|
}
|
|
ok = -1;
|
|
tmpname = xmalloc(strlen(global.uploaddir) + 8);
|
|
strcpy(tmpname, global.uploaddir);
|
|
strcat(tmpname, "/XXXXXX");
|
|
obj->fh = mkstemp(tmpname);
|
|
if(obj->fh == -1) {
|
|
ok = 0;
|
|
}
|
|
buffer_add(&(obj->value), tmpname, strlen(tmpname));
|
|
if(!ok) {
|
|
empty_stdin();
|
|
die_with_message(NULL, NULL, g_err_msg[E_FILE_OPEN_FAIL], tmpname);
|
|
}
|
|
curtoken = push_token_on_list(curtoken, NULL, tmpname, strlen(tmpname) + 1);
|
|
if(global.uploadlist == NULL) {
|
|
global.uploadlist = curtoken;
|
|
}
|
|
}
|
|
|
|
void mime_var_writer(mime_var_t* obj, char* str, int len) {
|
|
int err;
|
|
|
|
if(!obj->filename) {
|
|
buffer_add(&(obj->value), str, len);
|
|
}
|
|
if((!obj->fh) && (obj->filename)) {
|
|
mime_var_open_target(obj);
|
|
}
|
|
if(obj->fh > 0) {
|
|
err = write(obj->fh, str, len);
|
|
if(err == -1) {
|
|
obj->fh = abs(obj->fh) * -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
int rfc2388_handler(list_t* env) {
|
|
enum mime_state_t { DISCARD, BOUNDARY, HEADER, CONTENT };
|
|
int state;
|
|
int i, x;
|
|
unsigned long max_len, content_length;
|
|
sbuffer_t sbuf;
|
|
char* crlf = "\r\n";
|
|
char* boundary;
|
|
char* str;
|
|
buffer_t buf;
|
|
mime_var_t var;
|
|
|
|
str = getenv("CONTENT_TYPE");
|
|
i = strlen(str) - 9;
|
|
while((i >= 0) && (memcmp("boundary=", str + i, 9))) {
|
|
i--;
|
|
}
|
|
if(i == -1) {
|
|
empty_stdin();
|
|
die_with_message(NULL, NULL, "No Mime Boundary Information Found");
|
|
}
|
|
i = i + 9;
|
|
if(str[i] == '"') {
|
|
i++;
|
|
}
|
|
boundary = xmalloc(strlen(str + i) + 5);
|
|
memcpy(boundary, crlf, 2);
|
|
memcpy(boundary + 2, "--", 2);
|
|
memcpy(boundary + 4, str + i, strlen(str + i) + 1);
|
|
if((i > 0) && (str[i - 1] == '"')) {
|
|
while((boundary[i]) && (boundary[i] != '"')) {
|
|
i++;
|
|
}
|
|
boundary[i] = '\0';
|
|
}
|
|
max_len = ((global.uploadkb == 0) ? 2048 : abs(global.uploadkb)) * 1024;
|
|
content_length = 0;
|
|
sbuffer_init(&sbuf, 1024 * 128);
|
|
sbuf.fh = STDIN;
|
|
if(getenv("CONTENT_LENGTH")) {
|
|
sbuf.maxread = strtoul(getenv("CONTENT_LENGTH"), NULL, 10);
|
|
}
|
|
buffer_init(&buf);
|
|
buffer_add(&buf, "", 1);
|
|
buffer_reset(&buf);
|
|
state = DISCARD;
|
|
str = boundary + 2;
|
|
do {
|
|
x = sbuffer_read(&sbuf, str);
|
|
content_length += sbuf.len;
|
|
if(content_length >= max_len && global.uploadkb != -1) {
|
|
empty_stdin();
|
|
free(boundary);
|
|
sbuffer_destroy(&sbuf);
|
|
buffer_destroy(&buf);
|
|
if(var.name) {
|
|
mime_var_destroy(&var);
|
|
}
|
|
die_with_message(NULL, NULL, "Attempted to send content larger than allowed limits.");
|
|
}
|
|
switch(state) {
|
|
case DISCARD:
|
|
if(x) {
|
|
state = BOUNDARY;
|
|
str = crlf;
|
|
buffer_reset(&buf);
|
|
}
|
|
break;
|
|
case BOUNDARY:
|
|
if(x) {
|
|
buffer_add(&buf, sbuf.segment, sbuf.len);
|
|
if(!memcmp(buf.data, boundary + 2, 2)) {
|
|
str = boundary + 2;
|
|
state = DISCARD;
|
|
} else {
|
|
buffer_reset(&buf);
|
|
mime_var_init(&var);
|
|
state = HEADER;
|
|
str = crlf;
|
|
}
|
|
} else {
|
|
buffer_add(&buf, sbuf.segment, sbuf.len);
|
|
}
|
|
break;
|
|
case HEADER:
|
|
buffer_add(&buf, sbuf.segment, sbuf.len);
|
|
if(x) {
|
|
if(sbuf.len == 0) {
|
|
buffer_reset(&buf);
|
|
state = CONTENT;
|
|
str = boundary;
|
|
} else {
|
|
buffer_add(&buf, "", 1);
|
|
mime_tag_add(&var, (char*) buf.data);
|
|
buffer_reset(&buf);
|
|
}
|
|
}
|
|
break;
|
|
case CONTENT:
|
|
mime_var_writer(&var, (char*) sbuf.segment, sbuf.len);
|
|
if(x) {
|
|
buffer_reset(&buf);
|
|
mime_var_putenv(env, &var);
|
|
mime_var_destroy(&var);
|
|
state = BOUNDARY;
|
|
str = crlf;
|
|
}
|
|
break;
|
|
}
|
|
} while(!sbuf.eof);
|
|
free(boundary);
|
|
sbuffer_destroy(&sbuf);
|
|
buffer_destroy(&buf);
|
|
return 0;
|
|
}
|