CGI Bash Shell Interface
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mimetype.c 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /**
  2. * @PROJECT CGI Bash Shell Interface
  3. * @COPYRIGHT See COPYING in the top level directory
  4. * @FILE mimetype.c
  5. * @PURPOSE Mimetype and file upload handler
  6. * @DEVELOPERS Nathan Angelacos <nangel@users.sourceforge.net>
  7. * Rafal Kupiec <belliash@asiotec.eu.org>
  8. */
  9. #include <stdio.h>
  10. #include <unistd.h>
  11. #include <time.h>
  12. #include <sys/mman.h>
  13. #include <sys/types.h>
  14. #include <sys/wait.h>
  15. #include <sys/stat.h>
  16. #include <sys/fcntl.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include "common.h"
  20. #include "buffer.h"
  21. #include "error.h"
  22. #include "subshell.h"
  23. #include "buffer.h"
  24. #include "mimetype.h"
  25. #include "cbsi.h"
  26. void empty_stdin(void) {
  27. char c[2000];
  28. while(read(STDIN_FILENO, &c, 2000)) {
  29. }
  30. }
  31. void mime_var_init(mime_var_t* obj) {
  32. obj->name = NULL;
  33. obj->filename = NULL;
  34. obj->type = NULL;
  35. obj->tempname = NULL;
  36. buffer_init(&(obj->value));
  37. obj->fh = 0;
  38. }
  39. void mime_var_destroy(mime_var_t* obj) {
  40. int status;
  41. struct sigaction new_action;
  42. if(obj->name) {
  43. free(obj->name);
  44. obj->name = NULL;
  45. }
  46. if(obj->filename) {
  47. free(obj->filename);
  48. obj->filename = NULL;
  49. }
  50. if(obj->type) {
  51. free(obj->type);
  52. obj->type = NULL;
  53. }
  54. if(obj->tempname) {
  55. free(obj->tempname);
  56. obj->tempname = NULL;
  57. }
  58. buffer_destroy(&(obj->value));
  59. if(obj->fh) {
  60. close(abs(obj->fh));
  61. obj->fh = 0;
  62. }
  63. }
  64. char* mime_substr(char* start, int len) {
  65. char* ptr;
  66. if(!start) {
  67. return NULL;
  68. }
  69. if(len < 0) {
  70. return NULL;
  71. }
  72. ptr = xmalloc(len + 2);
  73. memcpy(ptr, start, len);
  74. return ptr;
  75. }
  76. void mime_tag_add(mime_var_t* obj, char* str) {
  77. char* a = NULL;
  78. char* b = NULL;
  79. static char* tag[] = { "name=\"", "filename=\"", "Content-Type: " };
  80. a = strcasestr(str, tag[0]);
  81. if(a) {
  82. a += strlen(tag[0]);
  83. b = strchr(a, '"');
  84. if(!obj->name) {
  85. obj->name = mime_substr(a, b - a);
  86. }
  87. }
  88. a = strcasestr(str, tag[1]);
  89. if(a) {
  90. a += strlen(tag[1]);
  91. b = strchr(a, '"');
  92. if(!obj->filename) {
  93. obj->filename = mime_substr(a, b - a);
  94. }
  95. }
  96. a = strcasestr(str, tag[2]);
  97. if(a) {
  98. a += strlen(tag[2]);
  99. b = a + strlen(a);
  100. if(!obj->type) {
  101. obj->type = mime_substr(a, b - a);
  102. }
  103. }
  104. }
  105. void mime_var_putenv(list_t* env, mime_var_t* obj) {
  106. buffer_t buf;
  107. buffer_init(&buf);
  108. if(obj->filename) {
  109. buffer_add(&buf, obj->name, strlen(obj->name));
  110. buffer_add(&buf, "=", 1);
  111. buffer_add(&buf, (char*) obj->value.data,
  112. strlen((char*) obj->value.data) + 1);
  113. myputenv(env, (char*) buf.data, global.file_prefix);
  114. buffer_reset(&buf);
  115. buffer_add(&buf, obj->name, strlen(obj->name));
  116. buffer_add(&buf, "=", 1);
  117. buffer_add(&buf, obj->filename, strlen(obj->filename) + 1);
  118. myputenv(env, (char*) buf.data, global.filename_prefix);
  119. buffer_reset (&buf);
  120. } else if(obj->name) {
  121. buffer_add(&(obj->value), "", 1);
  122. buffer_add(&buf, obj->name, strlen(obj->name));
  123. buffer_add(&buf, "=", 1);
  124. buffer_add(&buf, (char*) obj->value.data,
  125. strlen((char*) obj->value.data) + 1);
  126. myputenv(env, (char*) buf.data, global.file_prefix);
  127. buffer_reset(&buf);
  128. }
  129. buffer_destroy(&buf);
  130. }
  131. void mime_exec(mime_var_t* obj, char* fifo) {
  132. int pid;
  133. char* type;
  134. char* filename;
  135. char* name;
  136. char *c;
  137. int fh;
  138. struct sigaction new_action;
  139. pid = fork();
  140. if(pid == -1) {
  141. empty_stdin();
  142. die_with_message(NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]);
  143. }
  144. if(pid == 0) {
  145. if(obj->type) {
  146. type = xmalloc(13 + strlen(obj->type) + 1);
  147. sprintf(type, "CONTENT_TYPE=%s", obj->type);
  148. putenv(type);
  149. }
  150. if(obj->filename) {
  151. filename = xmalloc (9 + strlen(obj->filename) + 1);
  152. sprintf(filename, "FILENAME=%s", obj->filename);
  153. putenv(filename);
  154. }
  155. if(obj->name) {
  156. name = xmalloc(5 + strlen(obj->name) + 1);
  157. sprintf(name, "NAME=%s", obj->name);
  158. putenv(name);
  159. }
  160. fh = open(fifo, O_RDONLY);
  161. while(read(fh, &c, 1)) {
  162. }
  163. exit(-1);
  164. } else {
  165. new_action.sa_handler = SIG_IGN;
  166. sigemptyset(&new_action.sa_mask);
  167. new_action.sa_flags = 0;
  168. sigaction(SIGPIPE, &new_action, NULL);
  169. }
  170. }
  171. void mime_var_open_target(mime_var_t* obj) {
  172. char* tmpname;
  173. token_t* curtoken;
  174. curtoken = global.uploadlist;
  175. int ok;
  176. if(global.uploadkb == 0) {
  177. empty_stdin();
  178. die_with_message(NULL, NULL, "File uploads are not allowed.");
  179. }
  180. ok = -1;
  181. tmpname = xmalloc(strlen(global.uploaddir) + 8);
  182. strcpy(tmpname, global.uploaddir);
  183. strcat(tmpname, "/XXXXXX");
  184. obj->fh = mkstemp(tmpname);
  185. if(obj->fh == -1) {
  186. ok = 0;
  187. }
  188. buffer_add(&(obj->value), tmpname, strlen(tmpname));
  189. if(!ok) {
  190. empty_stdin();
  191. die_with_message(NULL, NULL, g_err_msg[E_FILE_OPEN_FAIL], tmpname);
  192. }
  193. curtoken = push_token_on_list(curtoken, NULL, tmpname, strlen(tmpname) + 1);
  194. if(global.uploadlist == NULL) {
  195. global.uploadlist = curtoken;
  196. }
  197. }
  198. void mime_var_writer(mime_var_t* obj, char* str, int len) {
  199. int err;
  200. if(!obj->filename) {
  201. buffer_add(&(obj->value), str, len);
  202. }
  203. if((!obj->fh) && (obj->filename)) {
  204. mime_var_open_target(obj);
  205. }
  206. if(obj->fh > 0) {
  207. err = write(obj->fh, str, len);
  208. if(err == -1) {
  209. obj->fh = abs(obj->fh) * -1;
  210. }
  211. }
  212. }
  213. int rfc2388_handler(list_t* env) {
  214. enum mime_state_t { DISCARD, BOUNDARY, HEADER, CONTENT };
  215. int state;
  216. int i, x;
  217. unsigned long max_len, content_length;
  218. sbuffer_t sbuf;
  219. char* crlf = "\r\n";
  220. char* boundary;
  221. char* str;
  222. buffer_t buf;
  223. mime_var_t var;
  224. str = getenv("CONTENT_TYPE");
  225. i = strlen(str) - 9;
  226. while((i >= 0) && (memcmp("boundary=", str + i, 9))) {
  227. i--;
  228. }
  229. if(i == -1) {
  230. empty_stdin();
  231. die_with_message(NULL, NULL, "No Mime Boundary Information Found");
  232. }
  233. i = i + 9;
  234. if(str[i] == '"') {
  235. i++;
  236. }
  237. boundary = xmalloc(strlen(str + i) + 5);
  238. memcpy(boundary, crlf, 2);
  239. memcpy(boundary + 2, "--", 2);
  240. memcpy(boundary + 4, str + i, strlen(str + i) + 1);
  241. if((i > 0) && (str[i - 1] == '"')) {
  242. while((boundary[i]) && (boundary[i] != '"')) {
  243. i++;
  244. }
  245. boundary[i] = '\0';
  246. }
  247. max_len = ((global.uploadkb == 0) ? 2048 : abs(global.uploadkb)) * 1024;
  248. content_length = 0;
  249. sbuffer_init(&sbuf, 1024 * 128);
  250. sbuf.fh = STDIN;
  251. if(getenv("CONTENT_LENGTH")) {
  252. sbuf.maxread = strtoul(getenv("CONTENT_LENGTH"), NULL, 10);
  253. }
  254. buffer_init(&buf);
  255. buffer_add(&buf, "", 1);
  256. buffer_reset(&buf);
  257. state = DISCARD;
  258. str = boundary + 2;
  259. do {
  260. x = sbuffer_read(&sbuf, str);
  261. content_length += sbuf.len;
  262. if(content_length >= max_len && global.uploadkb != -1) {
  263. empty_stdin();
  264. free(boundary);
  265. sbuffer_destroy(&sbuf);
  266. buffer_destroy(&buf);
  267. if(var.name) {
  268. mime_var_destroy(&var);
  269. }
  270. die_with_message(NULL, NULL, "Attempted to send content larger than allowed limits.");
  271. }
  272. switch(state) {
  273. case DISCARD:
  274. if(x) {
  275. state = BOUNDARY;
  276. str = crlf;
  277. buffer_reset(&buf);
  278. }
  279. break;
  280. case BOUNDARY:
  281. if(x) {
  282. buffer_add(&buf, sbuf.segment, sbuf.len);
  283. if(!memcmp(buf.data, boundary + 2, 2)) {
  284. str = boundary + 2;
  285. state = DISCARD;
  286. } else {
  287. buffer_reset(&buf);
  288. mime_var_init(&var);
  289. state = HEADER;
  290. str = crlf;
  291. }
  292. } else {
  293. buffer_add(&buf, sbuf.segment, sbuf.len);
  294. }
  295. break;
  296. case HEADER:
  297. buffer_add(&buf, sbuf.segment, sbuf.len);
  298. if(x) {
  299. if(sbuf.len == 0) {
  300. buffer_reset(&buf);
  301. state = CONTENT;
  302. str = boundary;
  303. } else {
  304. buffer_add(&buf, "", 1);
  305. mime_tag_add(&var, (char*) buf.data);
  306. buffer_reset(&buf);
  307. }
  308. }
  309. break;
  310. case CONTENT:
  311. mime_var_writer(&var, (char*) sbuf.segment, sbuf.len);
  312. if(x) {
  313. buffer_reset(&buf);
  314. mime_var_putenv(env, &var);
  315. mime_var_destroy(&var);
  316. state = BOUNDARY;
  317. str = crlf;
  318. }
  319. break;
  320. }
  321. } while(!sbuf.eof);
  322. free(boundary);
  323. sbuffer_destroy(&sbuf);
  324. buffer_destroy(&buf);
  325. return 0;
  326. }