1
0

proc.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238
  1. /*
  2. * Copyright (c) 2007-2008, Cameron Rich
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. *
  9. * * Redistributions of source code must retain the above copyright notice,
  10. * this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. * * Neither the name of the axTLS project nor the names of its contributors
  15. * may be used to endorse or promote products derived from this software
  16. * without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  22. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  23. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  25. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  26. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  27. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <ctype.h>
  33. #include <sys/types.h>
  34. #include <sys/stat.h>
  35. #include <fcntl.h>
  36. #include <time.h>
  37. #include <string.h>
  38. #include "axhttp.h"
  39. #define HTTP_VERSION "HTTP/1.1"
  40. static const char * index_file = "index.html";
  41. static int special_read(struct connstruct *cn, void *buf, size_t count);
  42. static int special_write(struct connstruct *cn,
  43. const char *buf, size_t count);
  44. static void send_error(struct connstruct *cn, int err);
  45. static int hexit(char c);
  46. static void urldecode(char *buf);
  47. static void buildactualfile(struct connstruct *cn);
  48. static int sanitizefile(const char *buf);
  49. static int sanitizehost(char *buf);
  50. static int htaccess_check(struct connstruct *cn);
  51. static const char *getmimetype(const char *name);
  52. #if defined(CONFIG_HTTP_DIRECTORIES)
  53. static void urlencode(const uint8_t *s, char *t);
  54. static void procdirlisting(struct connstruct *cn);
  55. #endif
  56. #if defined(CONFIG_HTTP_HAS_CGI)
  57. static void proccgi(struct connstruct *cn);
  58. static void decode_path_info(struct connstruct *cn, char *path_info);
  59. static int init_read_post_data(char *buf, char *data, struct connstruct *cn, int old_rv);
  60. #endif
  61. #ifdef CONFIG_HTTP_HAS_AUTHORIZATION
  62. static int auth_check(struct connstruct *cn);
  63. #endif
  64. #if AXDEBUG
  65. #define AXDEBUGSTART \
  66. { \
  67. FILE *axdout; \
  68. axdout = fopen("/var/log/axdebug", "a"); \
  69. #define AXDEBUGEND \
  70. fclose(axdout); \
  71. }
  72. #else /* AXDEBUG */
  73. #define AXDEBUGSTART
  74. #define AXDEBUGEND
  75. #endif /* AXDEBUG */
  76. /* Returns 1 if elems should continue being read, 0 otherwise */
  77. static int procheadelem(struct connstruct *cn, char *buf)
  78. {
  79. char *delim, *value;
  80. if ((delim = strchr(buf, ' ')) == NULL)
  81. return 0;
  82. *delim = 0;
  83. value = delim+1;
  84. if (strcmp(buf, "GET") == 0 || strcmp(buf, "HEAD") == 0 ||
  85. strcmp(buf, "POST") == 0)
  86. {
  87. if (buf[0] == 'H')
  88. cn->reqtype = TYPE_HEAD;
  89. else if (buf[0] == 'P')
  90. cn->reqtype = TYPE_POST;
  91. if ((delim = strchr(value, ' ')) == NULL) /* expect HTTP type */
  92. return 0;
  93. *delim = 0;
  94. urldecode(value);
  95. if (sanitizefile(value) == 0)
  96. {
  97. send_error(cn, 403);
  98. return 0;
  99. }
  100. #if defined(CONFIG_HTTP_HAS_CGI)
  101. decode_path_info(cn, value);
  102. #else
  103. my_strncpy(cn->filereq, value, MAXREQUESTLENGTH);
  104. #endif
  105. cn->if_modified_since = -1;
  106. }
  107. else if (strcmp(buf, "Host:") == 0)
  108. {
  109. if (sanitizehost(value) == 0)
  110. {
  111. removeconnection(cn);
  112. return 0;
  113. }
  114. my_strncpy(cn->server_name, value, MAXREQUESTLENGTH);
  115. }
  116. else if (strcmp(buf, "Connection:") == 0 && strcmp(value, "close") == 0)
  117. {
  118. cn->close_when_done = 1;
  119. }
  120. else if (strcmp(buf, "If-Modified-Since:") == 0)
  121. {
  122. cn->if_modified_since = tdate_parse(value);
  123. }
  124. else if (strcmp(buf, "Expect:") == 0)
  125. {
  126. send_error(cn, 417); /* expectation failed */
  127. return 0;
  128. }
  129. #ifdef CONFIG_HTTP_HAS_AUTHORIZATION
  130. else if (strcmp(buf, "Authorization:") == 0 &&
  131. strncmp(value, "Basic ", 6) == 0)
  132. {
  133. int size;
  134. if (base64_decode(&value[6], strlen(&value[6]),
  135. (uint8_t *)cn->authorization, &size))
  136. cn->authorization[0] = 0; /* error */
  137. else
  138. cn->authorization[size] = 0;
  139. }
  140. #endif
  141. #if defined(CONFIG_HTTP_HAS_CGI)
  142. else if (strcmp(buf, "Content-Length:") == 0)
  143. {
  144. sscanf(value, "%d", &cn->content_length);
  145. }
  146. else if (strcmp(buf, "Cookie:") == 0)
  147. {
  148. my_strncpy(cn->cookie, value, MAXREQUESTLENGTH);
  149. }
  150. #endif
  151. return 1;
  152. }
  153. #if defined(CONFIG_HTTP_DIRECTORIES)
  154. static void procdirlisting(struct connstruct *cn)
  155. {
  156. char buf[MAXREQUESTLENGTH];
  157. char actualfile[1024];
  158. if (cn->reqtype == TYPE_HEAD)
  159. {
  160. snprintf(buf, sizeof(buf), HTTP_VERSION
  161. " 200 OK\nContent-Type: text/html\n\n");
  162. write(cn->networkdesc, buf, strlen(buf));
  163. removeconnection(cn);
  164. return;
  165. }
  166. strcpy(actualfile, cn->actualfile);
  167. #ifdef WIN32
  168. strcat(actualfile, "*");
  169. cn->dirp = FindFirstFile(actualfile, &cn->file_data);
  170. if (cn->dirp == INVALID_HANDLE_VALUE)
  171. {
  172. send_error(cn, 404);
  173. return;
  174. }
  175. #else
  176. if ((cn->dirp = opendir(actualfile)) == NULL)
  177. {
  178. send_error(cn, 404);
  179. return;
  180. }
  181. #endif
  182. snprintf(buf, sizeof(buf), HTTP_VERSION
  183. " 200 OK\nContent-Type: text/html\n\n"
  184. "<html><body>\n<title>Directory Listing</title>\n"
  185. "<h3>Directory listing of %s://%s%s</h3><br />\n",
  186. cn->is_ssl ? "https" : "http", cn->server_name, cn->filereq);
  187. special_write(cn, buf, strlen(buf));
  188. cn->state = STATE_DOING_DIR;
  189. }
  190. void procdodir(struct connstruct *cn)
  191. {
  192. #ifndef WIN32
  193. struct dirent *dp;
  194. #endif
  195. char buf[MAXREQUESTLENGTH];
  196. char encbuf[1024];
  197. char *file;
  198. do
  199. {
  200. buf[0] = 0;
  201. #ifdef WIN32
  202. if (!FindNextFile(cn->dirp, &cn->file_data))
  203. #else
  204. if ((dp = readdir(cn->dirp)) == NULL)
  205. #endif
  206. {
  207. snprintf(buf, sizeof(buf), "</body></html>\n");
  208. special_write(cn, buf, strlen(buf));
  209. removeconnection(cn);
  210. #ifndef WIN32
  211. closedir(cn->dirp);
  212. #endif
  213. return;
  214. }
  215. #ifdef WIN32
  216. file = cn->file_data.cFileName;
  217. #else
  218. file = dp->d_name;
  219. #endif
  220. /* if no index file, don't display the ".." directory */
  221. if (cn->filereq[0] == '/' && cn->filereq[1] == '\0' &&
  222. strcmp(file, "..") == 0)
  223. continue;
  224. /* don't display files beginning with "." */
  225. if (file[0] == '.' && file[1] != '.')
  226. continue;
  227. /* make sure a '/' is at the end of a directory */
  228. if (cn->filereq[strlen(cn->filereq)-1] != '/')
  229. strcat(cn->filereq, "/");
  230. /* see if the dir + file is another directory */
  231. snprintf(buf, sizeof(buf), "%s%s", cn->actualfile, file);
  232. if (isdir(buf))
  233. strcat(file, "/");
  234. urlencode((uint8_t *)file, encbuf);
  235. snprintf(buf, sizeof(buf), "<a href=\"%s%s\">%s</a><br />\n",
  236. cn->filereq, encbuf, file);
  237. } while (special_write(cn, buf, strlen(buf)));
  238. }
  239. /* Encode funny chars -> %xx in newly allocated storage */
  240. /* (preserves '/' !) */
  241. static void urlencode(const uint8_t *s, char *t)
  242. {
  243. const uint8_t *p = s;
  244. char *tp = t;
  245. for (; *p; p++)
  246. {
  247. if ((*p > 0x00 && *p < ',') ||
  248. (*p > '9' && *p < 'A') ||
  249. (*p > 'Z' && *p < '_') ||
  250. (*p > '_' && *p < 'a') ||
  251. (*p > 'z' && *p < 0xA1))
  252. {
  253. sprintf((char *)tp, "%%%02X", *p);
  254. tp += 3;
  255. }
  256. else
  257. {
  258. *tp = *p;
  259. tp++;
  260. }
  261. }
  262. *tp='\0';
  263. }
  264. #endif
  265. void procreadhead(struct connstruct *cn)
  266. {
  267. char buf[MAXREQUESTLENGTH*4], *tp, *next;
  268. int rv;
  269. memset(buf, 0, MAXREQUESTLENGTH*4);
  270. rv = special_read(cn, buf, sizeof(buf)-1);
  271. if (rv <= 0)
  272. {
  273. if (rv < 0) /* really dead? */
  274. removeconnection(cn);
  275. return;
  276. }
  277. buf[rv] = '\0';
  278. next = tp = buf;
  279. #ifdef CONFIG_HTTP_HAS_AUTHORIZATION
  280. cn->authorization[0] = 0;
  281. #endif
  282. /* Split up lines and send to procheadelem() */
  283. while (*next != '\0')
  284. {
  285. /* If we have a blank line, advance to next stage */
  286. if (*next == '\r' || *next == '\n')
  287. {
  288. #if defined(CONFIG_HTTP_HAS_CGI)
  289. if (cn->reqtype == TYPE_POST && cn->content_length > 0)
  290. {
  291. if (init_read_post_data(buf,next,cn,rv) == 0)
  292. return;
  293. }
  294. #endif
  295. buildactualfile(cn);
  296. cn->state = STATE_WANT_TO_SEND_HEAD;
  297. return;
  298. }
  299. while (*next != '\r' && *next != '\n' && *next != '\0')
  300. next++;
  301. if (*next == '\r')
  302. {
  303. *next = '\0';
  304. next += 2;
  305. }
  306. else if (*next == '\n')
  307. *next++ = '\0';
  308. if (procheadelem(cn, tp) == 0)
  309. return;
  310. tp = next;
  311. }
  312. }
  313. /* In this function we assume that the file has been checked for
  314. * maliciousness (".."s, etc) and has been decoded
  315. */
  316. void procsendhead(struct connstruct *cn)
  317. {
  318. char buf[MAXREQUESTLENGTH];
  319. struct stat stbuf;
  320. time_t now = cn->timeout - CONFIG_HTTP_TIMEOUT;
  321. char date[32];
  322. int file_exists;
  323. /* are we trying to access a file over the HTTP connection instead of a
  324. * HTTPS connection? Or is this directory disabled? */
  325. if (htaccess_check(cn))
  326. {
  327. send_error(cn, 403);
  328. return;
  329. }
  330. #ifdef CONFIG_HTTP_HAS_AUTHORIZATION
  331. if (auth_check(cn)) /* see if there is a '.htpasswd' file */
  332. {
  333. #ifdef CONFIG_HTTP_VERBOSE
  334. printf("axhttpd: access to %s denied\n", cn->filereq); TTY_FLUSH();
  335. #endif
  336. removeconnection(cn);
  337. return;
  338. }
  339. #endif
  340. file_exists = stat(cn->actualfile, &stbuf);
  341. #if defined(CONFIG_HTTP_HAS_CGI)
  342. if (file_exists != -1 && cn->is_cgi)
  343. {
  344. if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile))
  345. {
  346. /* A non-executable file, or directory? */
  347. send_error(cn, 403);
  348. }
  349. else
  350. proccgi(cn);
  351. return;
  352. }
  353. #endif
  354. /* look for "index.html"? */
  355. if (isdir(cn->actualfile))
  356. {
  357. char tbuf[MAXREQUESTLENGTH];
  358. snprintf(tbuf, MAXREQUESTLENGTH, "%s%s", cn->actualfile, index_file);
  359. if ((file_exists = stat(tbuf, &stbuf)) != -1)
  360. my_strncpy(cn->actualfile, tbuf, MAXREQUESTLENGTH);
  361. else
  362. {
  363. #if defined(CONFIG_HTTP_DIRECTORIES)
  364. /* If not, we do a directory listing of it */
  365. procdirlisting(cn);
  366. #else
  367. send_error(cn, 404);
  368. #endif
  369. return;
  370. }
  371. }
  372. if (file_exists == -1)
  373. {
  374. send_error(cn, 404);
  375. return;
  376. }
  377. strcpy(date, ctime(&now));
  378. /* has the file been read before? */
  379. if (cn->if_modified_since != -1 && (cn->if_modified_since == 0 ||
  380. cn->if_modified_since >= stbuf.st_mtime))
  381. {
  382. snprintf(buf, sizeof(buf), HTTP_VERSION" 304 Not Modified\nServer: "
  383. "%s\nDate: %s\n", server_version, date);
  384. special_write(cn, buf, strlen(buf));
  385. cn->state = STATE_WANT_TO_READ_HEAD;
  386. return;
  387. }
  388. if (cn->reqtype == TYPE_HEAD)
  389. {
  390. removeconnection(cn);
  391. return;
  392. }
  393. else
  394. {
  395. int flags = O_RDONLY;
  396. #if defined(WIN32) || defined(CONFIG_PLATFORM_CYGWIN)
  397. flags |= O_BINARY;
  398. #endif
  399. cn->filedesc = open(cn->actualfile, flags);
  400. if (cn->filedesc < 0)
  401. {
  402. send_error(cn, 404);
  403. return;
  404. }
  405. snprintf(buf, sizeof(buf), HTTP_VERSION" 200 OK\nServer: %s\n"
  406. "Content-Type: %s\nContent-Length: %ld\n"
  407. "Date: %sLast-Modified: %s\n", server_version,
  408. getmimetype(cn->actualfile), (long) stbuf.st_size,
  409. date, ctime(&stbuf.st_mtime)); /* ctime() has a \n on the end */
  410. special_write(cn, buf, strlen(buf));
  411. #ifdef CONFIG_HTTP_VERBOSE
  412. printf("axhttpd: %s:/%s\n", cn->is_ssl ? "https" : "http", cn->filereq);
  413. TTY_FLUSH();
  414. #endif
  415. #ifdef WIN32
  416. for (;;)
  417. {
  418. procreadfile(cn);
  419. if (cn->filedesc == -1)
  420. break;
  421. do
  422. {
  423. procsendfile(cn);
  424. } while (cn->state != STATE_WANT_TO_READ_FILE);
  425. }
  426. #else
  427. cn->state = STATE_WANT_TO_READ_FILE;
  428. #endif
  429. }
  430. }
  431. void procreadfile(struct connstruct *cn)
  432. {
  433. int rv = read(cn->filedesc, cn->databuf, BLOCKSIZE);
  434. if (rv <= 0)
  435. {
  436. close(cn->filedesc);
  437. cn->filedesc = -1;
  438. if (cn->close_when_done) /* close immediately */
  439. removeconnection(cn);
  440. else
  441. { /* keep socket open - HTTP 1.1 */
  442. cn->state = STATE_WANT_TO_READ_HEAD;
  443. cn->numbytes = 0;
  444. }
  445. return;
  446. }
  447. cn->numbytes = rv;
  448. cn->state = STATE_WANT_TO_SEND_FILE;
  449. }
  450. void procsendfile(struct connstruct *cn)
  451. {
  452. int rv = special_write(cn, cn->databuf, cn->numbytes);
  453. if (rv < 0)
  454. removeconnection(cn);
  455. else if (rv == cn->numbytes)
  456. {
  457. cn->state = STATE_WANT_TO_READ_FILE;
  458. }
  459. else if (rv == 0)
  460. {
  461. /* Do nothing */
  462. }
  463. else
  464. {
  465. memmove(cn->databuf, cn->databuf + rv, cn->numbytes - rv);
  466. cn->numbytes -= rv;
  467. }
  468. }
  469. #if defined(CONFIG_HTTP_HAS_CGI)
  470. /* Should this be a bit more dynamic? It would mean more calls to malloc etc */
  471. #define CGI_ARG_SIZE 17
  472. static void proccgi(struct connstruct *cn)
  473. {
  474. int tpipe[2], spipe[2];
  475. char *myargs[2];
  476. char cgienv[CGI_ARG_SIZE][MAXREQUESTLENGTH];
  477. char * cgiptr[CGI_ARG_SIZE+4];
  478. const char *type = "HEAD";
  479. int cgi_index = 0, i;
  480. pid_t pid;
  481. #ifdef WIN32
  482. int tmp_stdout;
  483. #endif
  484. snprintf(cgienv[0], MAXREQUESTLENGTH,
  485. HTTP_VERSION" 200 OK\nServer: %s\n%s",
  486. server_version, (cn->reqtype == TYPE_HEAD) ? "\n" : "");
  487. special_write(cn, cgienv[0], strlen(cgienv[0]));
  488. if (cn->reqtype == TYPE_HEAD)
  489. {
  490. removeconnection(cn);
  491. return;
  492. }
  493. #ifdef CONFIG_HTTP_VERBOSE
  494. printf("[CGI]: %s:/%s\n", cn->is_ssl ? "https" : "http", cn->filereq);
  495. TTY_FLUSH();
  496. #endif
  497. /* win32 cgi is a bit too painful */
  498. #ifndef WIN32
  499. /* set up pipe that is used for sending POST query data to CGI script*/
  500. if (cn->reqtype == TYPE_POST)
  501. {
  502. if (pipe(spipe) == -1)
  503. {
  504. printf("[CGI]: could not create pipe");
  505. TTY_FLUSH();
  506. return;
  507. }
  508. }
  509. if (pipe(tpipe) == -1)
  510. {
  511. printf("[CGI]: could not create pipe");
  512. TTY_FLUSH();
  513. return;
  514. }
  515. /*
  516. * use vfork() instead of fork() for performance
  517. */
  518. if ((pid = vfork()) > 0) /* parent */
  519. {
  520. /* Send POST query data to CGI script */
  521. if ((cn->reqtype == TYPE_POST) && (cn->content_length > 0))
  522. {
  523. write(spipe[1], cn->post_data, cn->content_length);
  524. close(spipe[0]);
  525. close(spipe[1]);
  526. /* free the memory that is allocated in read_post_data() */
  527. free(cn->post_data);
  528. cn->post_data = NULL;
  529. }
  530. /* Close the write descriptor */
  531. close(tpipe[1]);
  532. cn->filedesc = tpipe[0];
  533. cn->state = STATE_WANT_TO_READ_FILE;
  534. cn->close_when_done = 1;
  535. return;
  536. }
  537. if (pid < 0) /* vfork failed */
  538. exit(1);
  539. /* The problem child... */
  540. /* Our stdout/stderr goes to the socket */
  541. dup2(tpipe[1], 1);
  542. dup2(tpipe[1], 2);
  543. /* If it was a POST request, send the socket data to our stdin */
  544. if (cn->reqtype == TYPE_POST)
  545. dup2(spipe[0], 0);
  546. else /* Otherwise we can shutdown the read side of the sock */
  547. shutdown(cn->networkdesc, 0);
  548. myargs[0] = cn->actualfile;
  549. myargs[1] = NULL;
  550. /*
  551. * set the cgi args. A url is defined by:
  552. * http://$SERVER_NAME:$SERVER_PORT$SCRIPT_NAME$PATH_INFO?$QUERY_STRING
  553. * TODO: other CGI parameters?
  554. */
  555. sprintf(cgienv[cgi_index++], "SERVER_SOFTWARE=%s", server_version);
  556. strcpy(cgienv[cgi_index++], "DOCUMENT_ROOT=" CONFIG_HTTP_WEBROOT);
  557. snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
  558. "SERVER_NAME=%s", cn->server_name);
  559. sprintf(cgienv[cgi_index++], "SERVER_PORT=%d",
  560. cn->is_ssl ? CONFIG_HTTP_HTTPS_PORT : CONFIG_HTTP_PORT);
  561. snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
  562. "REQUEST_URI=%s", cn->uri_request);
  563. snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
  564. "SCRIPT_NAME=%s", cn->filereq);
  565. snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
  566. "PATH_INFO=%s", cn->uri_path_info);
  567. snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
  568. "QUERY_STRING=%s", cn->uri_query);
  569. snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
  570. "REMOTE_ADDR=%s", cn->remote_addr);
  571. snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
  572. "HTTP_COOKIE=%s", cn->cookie); /* note: small size */
  573. #if defined(CONFIG_HTTP_HAS_AUTHORIZATION)
  574. snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
  575. "REMOTE_USER=%s", cn->authorization);
  576. #endif
  577. switch (cn->reqtype)
  578. {
  579. case TYPE_GET:
  580. type = "GET";
  581. break;
  582. case TYPE_POST:
  583. type = "POST";
  584. sprintf(cgienv[cgi_index++],
  585. "CONTENT_LENGTH=%d", cn->content_length);
  586. strcpy(cgienv[cgi_index++], /* hard-code? */
  587. "CONTENT_TYPE=application/x-www-form-urlencoded");
  588. break;
  589. }
  590. sprintf(cgienv[cgi_index++], "REQUEST_METHOD=%s", type);
  591. if (cn->is_ssl)
  592. strcpy(cgienv[cgi_index++], "HTTPS=on");
  593. #ifdef CONFIG_PLATFORM_CYGWIN
  594. /* TODO: find out why Lua needs this */
  595. strcpy(cgienv[cgi_index++], "PATH=/usr/bin");
  596. #endif
  597. if (cgi_index >= CGI_ARG_SIZE)
  598. {
  599. printf("Content-type: text/plain\n\nToo many CGI args (%d, %d)\n",
  600. cgi_index, CGI_ARG_SIZE);
  601. _exit(1);
  602. }
  603. /* copy across the pointer indexes */
  604. for (i = 0; i < cgi_index; i++)
  605. cgiptr[i] = cgienv[i];
  606. cgiptr[i++] = "AUTH_TYPE=Basic";
  607. cgiptr[i++] = "GATEWAY_INTERFACE=CGI/1.1";
  608. cgiptr[i++] = "SERVER_PROTOCOL="HTTP_VERSION;
  609. cgiptr[i] = NULL;
  610. execve(myargs[0], myargs, cgiptr);
  611. printf("Content-type: text/plain\n\nshouldn't get here\n");
  612. _exit(1);
  613. #endif
  614. }
  615. static char * cgi_filetype_match(struct connstruct *cn, const char *fn)
  616. {
  617. struct cgiextstruct *tp = cgiexts;
  618. while (tp != NULL)
  619. {
  620. char *t;
  621. if ((t = strstr(fn, tp->ext)) != NULL)
  622. {
  623. t += strlen(tp->ext);
  624. if (*t == '/' || *t == '\0')
  625. {
  626. #ifdef CONFIG_HTTP_ENABLE_LUA
  627. if (strcmp(tp->ext, ".lua") == 0 || strcmp(tp->ext, ".lp") == 0)
  628. cn->is_lua = 1;
  629. #endif
  630. return t;
  631. }
  632. else
  633. return NULL;
  634. }
  635. tp = tp->next;
  636. }
  637. return NULL;
  638. }
  639. static void decode_path_info(struct connstruct *cn, char *path_info)
  640. {
  641. char *cgi_delim;
  642. cn->is_cgi = 0;
  643. #ifdef CONFIG_HTTP_ENABLE_LUA
  644. cn->is_lua = 0;
  645. #endif
  646. *cn->uri_request = '\0';
  647. *cn->uri_path_info = '\0';
  648. *cn->uri_query = '\0';
  649. my_strncpy(cn->uri_request, path_info, MAXREQUESTLENGTH);
  650. /* query info? */
  651. if ((cgi_delim = strchr(path_info, '?')))
  652. {
  653. *cgi_delim = '\0';
  654. my_strncpy(cn->uri_query, cgi_delim+1, MAXREQUESTLENGTH);
  655. }
  656. if ((cgi_delim = cgi_filetype_match(cn, path_info)) != NULL)
  657. {
  658. cn->is_cgi = 1; /* definitely a CGI script */
  659. /* path info? */
  660. if (*cgi_delim != '\0')
  661. {
  662. my_strncpy(cn->uri_path_info, cgi_delim, MAXREQUESTLENGTH);
  663. *cgi_delim = '\0';
  664. }
  665. }
  666. /* the bit at the start must be the script name */
  667. my_strncpy(cn->filereq, path_info, MAXREQUESTLENGTH);
  668. }
  669. static int init_read_post_data(char *buf, char *data,
  670. struct connstruct *cn, int old_rv)
  671. {
  672. char *next = data;
  673. int rv = old_rv;
  674. char *post_data;
  675. /* Too much Post data to send. MAXPOSTDATASIZE should be
  676. configured (now it can be chaged in the header file) */
  677. if (cn->content_length > MAXPOSTDATASIZE)
  678. {
  679. send_error(cn, 418);
  680. return 0;
  681. }
  682. /* remove CRLF */
  683. while ((*next == '\r' || *next == '\n') && (next < &buf[rv]))
  684. next++;
  685. if (cn->post_data == NULL)
  686. {
  687. cn->post_data = (char *) calloc(1, (cn->content_length + 1));
  688. /* Allocate buffer for the POST data that will be used by proccgi
  689. to send POST data to the CGI script */
  690. if (cn->post_data == NULL)
  691. {
  692. printf("axhttpd: could not allocate memory for POST data\n");
  693. TTY_FLUSH();
  694. send_error(cn, 599);
  695. return 0;
  696. }
  697. }
  698. cn->post_state = 0;
  699. cn->post_read = 0;
  700. post_data = cn->post_data;
  701. while (next < &buf[rv])
  702. {
  703. /*copy POST data to buffer*/
  704. *post_data = *next;
  705. post_data++;
  706. next++;
  707. cn->post_read++;
  708. if (cn->post_read == cn->content_length)
  709. {
  710. /* No more POST data to be copied */
  711. *post_data = '\0';
  712. return 1;
  713. }
  714. }
  715. /* More POST data has to be read. read_post_data will continue with that */
  716. cn->post_state = 1;
  717. return 0;
  718. }
  719. void read_post_data(struct connstruct *cn)
  720. {
  721. char buf[MAXREQUESTLENGTH*4], *next;
  722. char *post_data;
  723. int rv;
  724. bzero(buf,MAXREQUESTLENGTH*4);
  725. rv = special_read(cn, buf, sizeof(buf)-1);
  726. if (rv <= 0)
  727. {
  728. if (rv < 0) /* really dead? */
  729. removeconnection(cn);
  730. return;
  731. }
  732. buf[rv] = '\0';
  733. next = buf;
  734. post_data = &cn->post_data[cn->post_read];
  735. while (next < &buf[rv])
  736. {
  737. *post_data = *next;
  738. post_data++;
  739. next++;
  740. cn->post_read++;
  741. if (cn->post_read == cn->content_length)
  742. {
  743. /* No more POST data to be copied */
  744. *post_data='\0';
  745. cn->post_state = 0;
  746. buildactualfile(cn);
  747. cn->state = STATE_WANT_TO_SEND_HEAD;
  748. return;
  749. }
  750. }
  751. /* More POST data to read */
  752. }
  753. #endif /* CONFIG_HTTP_HAS_CGI */
  754. /* Decode string %xx -> char (in place) */
  755. static void urldecode(char *buf)
  756. {
  757. int v;
  758. char *p, *s, *w;
  759. w = p = buf;
  760. while (*p)
  761. {
  762. v = 0;
  763. if (*p == '%')
  764. {
  765. s = p;
  766. s++;
  767. if (isxdigit((int) s[0]) && isxdigit((int) s[1]))
  768. {
  769. v = hexit(s[0])*16 + hexit(s[1]);
  770. if (v)
  771. {
  772. /* do not decode %00 to null char */
  773. *w = (char)v;
  774. p = &s[1];
  775. }
  776. }
  777. }
  778. if (!v) *w=*p;
  779. p++;
  780. w++;
  781. }
  782. *w='\0';
  783. }
  784. static int hexit(char c)
  785. {
  786. if (c >= '0' && c <= '9')
  787. return c - '0';
  788. else if (c >= 'a' && c <= 'f')
  789. return c - 'a' + 10;
  790. else if (c >= 'A' && c <= 'F')
  791. return c - 'A' + 10;
  792. else
  793. return 0;
  794. }
  795. static void buildactualfile(struct connstruct *cn)
  796. {
  797. char *cp;
  798. snprintf(cn->actualfile, MAXREQUESTLENGTH, ".%s", cn->filereq);
  799. #ifndef WIN32
  800. /* Add directory slash if not there */
  801. if (isdir(cn->actualfile) &&
  802. cn->actualfile[strlen(cn->actualfile)-1] != '/')
  803. strcat(cn->actualfile, "/");
  804. /* work out the directory name */
  805. strncpy(cn->dirname, cn->actualfile, MAXREQUESTLENGTH);
  806. if ((cp = strrchr(cn->dirname, '/')) == NULL)
  807. cn->dirname[0] = 0;
  808. else
  809. *cp = 0;
  810. #else
  811. {
  812. char curr_dir[MAXREQUESTLENGTH];
  813. char path[MAXREQUESTLENGTH];
  814. char *t = cn->actualfile;
  815. GetCurrentDirectory(MAXREQUESTLENGTH, curr_dir);
  816. /* convert all the forward slashes to back slashes */
  817. while ((t = strchr(t, '/')))
  818. *t++ = '\\';
  819. snprintf(path, MAXREQUESTLENGTH, "%s%s", curr_dir, cn->actualfile);
  820. memcpy(cn->actualfile, path, MAXREQUESTLENGTH);
  821. /* Add directory slash if not there */
  822. if (isdir(cn->actualfile) &&
  823. cn->actualfile[strlen(cn->actualfile)-1] != '\\')
  824. strcat(cn->actualfile, "\\");
  825. /* work out the directory name */
  826. strncpy(cn->dirname, cn->actualfile, MAXREQUESTLENGTH);
  827. if ((cp = strrchr(cn->dirname, '\\')) == NULL)
  828. cn->dirname[0] = 0;
  829. else
  830. *cp = 0;
  831. }
  832. #endif
  833. #if defined(CONFIG_HTTP_ENABLE_LUA)
  834. /*
  835. * Use the lua launcher if this file has a lua extension. Put this at the
  836. * end as we need the directory name.
  837. */
  838. if (cn->is_lua)
  839. sprintf(cn->actualfile, "%s%s", CONFIG_HTTP_LUA_PREFIX,
  840. CONFIG_HTTP_LUA_CGI_LAUNCHER);
  841. #endif
  842. }
  843. static int sanitizefile(const char *buf)
  844. {
  845. int len, i;
  846. /* Don't accept anything not starting with a / */
  847. if (*buf != '/')
  848. return 0;
  849. len = strlen(buf);
  850. for (i = 0; i < len; i++)
  851. {
  852. /* Check for "/." i.e. don't send files starting with a . */
  853. if (buf[i] == '/' && buf[i+1] == '.')
  854. return 0;
  855. }
  856. return 1;
  857. }
  858. static int sanitizehost(char *buf)
  859. {
  860. while (*buf != '\0')
  861. {
  862. /* Handle the port */
  863. if (*buf == ':')
  864. {
  865. *buf = '\0';
  866. return 1;
  867. }
  868. /* Enforce some basic URL rules... */
  869. if ((isalnum(*buf) == 0 && *buf != '-' && *buf != '.') ||
  870. (*buf == '.' && *(buf+1) == '.') ||
  871. (*buf == '.' && *(buf+1) == '-') ||
  872. (*buf == '-' && *(buf+1) == '.'))
  873. return 0;
  874. buf++;
  875. }
  876. return 1;
  877. }
  878. static FILE * exist_check(struct connstruct *cn, const char *check_file)
  879. {
  880. char pathname[MAXREQUESTLENGTH];
  881. snprintf(pathname, MAXREQUESTLENGTH, "%s/%s", cn->dirname, check_file);
  882. return fopen(pathname, "r");
  883. }
  884. #ifdef CONFIG_HTTP_HAS_AUTHORIZATION
  885. static void send_authenticate(struct connstruct *cn, const char *realm)
  886. {
  887. char buf[1024];
  888. snprintf(buf, sizeof(buf), HTTP_VERSION" 401 Unauthorized\n"
  889. "WWW-Authenticate: Basic\n"
  890. "realm=\"%s\"\n", realm);
  891. special_write(cn, buf, strlen(buf));
  892. }
  893. static int check_digest(char *salt, const char *msg_passwd)
  894. {
  895. uint8_t b256_salt[MAXREQUESTLENGTH];
  896. uint8_t real_passwd[MD5_SIZE];
  897. int salt_size;
  898. char *b64_passwd;
  899. uint8_t md5_result[MD5_SIZE];
  900. MD5_CTX ctx;
  901. /* retrieve the salt */
  902. if ((b64_passwd = strchr(salt, '$')) == NULL)
  903. return -1;
  904. *b64_passwd++ = 0;
  905. if (base64_decode(salt, strlen(salt), b256_salt, &salt_size))
  906. return -1;
  907. if (base64_decode(b64_passwd, strlen(b64_passwd), real_passwd, NULL))
  908. return -1;
  909. /* very simple MD5 crypt algorithm, but then the salt we use is large */
  910. MD5_Init(&ctx);
  911. MD5_Update(&ctx, b256_salt, salt_size); /* process the salt */
  912. MD5_Update(&ctx, (uint8_t *)msg_passwd, strlen(msg_passwd));
  913. MD5_Final(md5_result, &ctx);
  914. return memcmp(md5_result, real_passwd, MD5_SIZE);/* 0 = ok */
  915. }
  916. static int auth_check(struct connstruct *cn)
  917. {
  918. char line[MAXREQUESTLENGTH];
  919. FILE *fp;
  920. char *cp;
  921. if ((fp = exist_check(cn, ".htpasswd")) == NULL)
  922. return 0; /* no .htpasswd file, so let though */
  923. if (cn->authorization[0] == 0)
  924. goto error;
  925. /* cn->authorization is in form "username:password" */
  926. if ((cp = strchr(cn->authorization, ':')) == NULL)
  927. goto error;
  928. else
  929. *cp++ = 0; /* cp becomes the password */
  930. while (fgets(line, sizeof(line), fp) != NULL)
  931. {
  932. char *b64_file_passwd;
  933. int l = strlen(line);
  934. /* nuke newline */
  935. if (line[l-1] == '\n')
  936. line[l-1] = 0;
  937. /* line is form "username:salt(b64)$password(b64)" */
  938. if ((b64_file_passwd = strchr(line, ':')) == NULL)
  939. continue;
  940. *b64_file_passwd++ = 0;
  941. if (strcmp(line, cn->authorization)) /* our user? */
  942. continue;
  943. if (check_digest(b64_file_passwd, cp) == 0)
  944. {
  945. fclose(fp);
  946. return 0;
  947. }
  948. }
  949. error:
  950. fclose(fp);
  951. send_authenticate(cn, cn->server_name);
  952. return -1;
  953. }
  954. #endif
  955. static int htaccess_check(struct connstruct *cn)
  956. {
  957. char line[MAXREQUESTLENGTH];
  958. FILE *fp;
  959. int ret = 0;
  960. if ((fp = exist_check(cn, ".htaccess")) == NULL)
  961. return 0; /* no .htaccess file, so let though */
  962. while (fgets(line, sizeof(line), fp) != NULL)
  963. {
  964. if (strstr(line, "Deny all") || /* access to this dir denied */
  965. /* Access will be denied unless SSL is active */
  966. (!cn->is_ssl && strstr(line, "SSLRequireSSL")) ||
  967. /* Access will be denied if SSL is active */
  968. (cn->is_ssl && strstr(line, "SSLDenySSL")))
  969. {
  970. ret = -1;
  971. break;
  972. }
  973. }
  974. fclose(fp);
  975. return ret;
  976. }
  977. static void send_error(struct connstruct *cn, int err)
  978. {
  979. char buf[MAXREQUESTLENGTH];
  980. char *title;
  981. char *text;
  982. switch (err)
  983. {
  984. case 403:
  985. title = "Forbidden";
  986. text = "File is protected";
  987. #ifdef CONFIG_HTTP_VERBOSE
  988. printf("axhttpd: access to %s denied\n", cn->filereq); TTY_FLUSH();
  989. #endif
  990. break;
  991. case 404:
  992. title = "Not Found";
  993. text = title;
  994. break;
  995. case 418:
  996. title = "POST data size is to large";
  997. text = title;
  998. break;
  999. default:
  1000. title = "Unknown";
  1001. text = "Unknown";
  1002. break;
  1003. }
  1004. snprintf(buf, MAXREQUESTLENGTH, "HTTP/1.1 %d %s\n"
  1005. "Content-Type: text/html\n"
  1006. "Cache-Control: no-cache,no-store\n"
  1007. "Connection: close\n\n"
  1008. "<html>\n<head>\n<title>%d %s</title></head>\n"
  1009. "<body><h1>%d %s</h1>\n</body></html>\n",
  1010. err, title, err, title, err, text);
  1011. special_write(cn, buf, strlen(buf));
  1012. removeconnection(cn);
  1013. }
  1014. static const char *getmimetype(const char *name)
  1015. {
  1016. /* only bother with a few mime types - let the browser figure the rest out */
  1017. if (strstr(name, ".htm"))
  1018. return "text/html";
  1019. else if (strstr(name, ".css"))
  1020. return "text/css";
  1021. else
  1022. return "application/octet-stream";
  1023. }
  1024. static int special_write(struct connstruct *cn,
  1025. const char *buf, size_t count)
  1026. {
  1027. if (cn->is_ssl)
  1028. {
  1029. SSL *ssl = cn->ssl;
  1030. return ssl ? ssl_write(ssl, (uint8_t *)buf, count) : -1;
  1031. }
  1032. else
  1033. return SOCKET_WRITE(cn->networkdesc, buf, count);
  1034. }
  1035. static int special_read(struct connstruct *cn, void *buf, size_t count)
  1036. {
  1037. int res;
  1038. if (cn->is_ssl)
  1039. {
  1040. uint8_t *read_buf;
  1041. if ((res = ssl_read(cn->ssl, &read_buf)) > SSL_OK)
  1042. {
  1043. memcpy(buf, read_buf, res > (int)count ? count : res);
  1044. }
  1045. }
  1046. else
  1047. res = SOCKET_READ(cn->networkdesc, buf, count);
  1048. return res;
  1049. }