4
0

egg_net.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  1. /*
  2. * Copyright (C) 2000,2001 Florian Sander
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. static struct dcc_table MHTTPD_CON_HTTPD =
  19. {
  20. "HTTPD",
  21. DCT_VALIDIDX,
  22. eof_http,
  23. httpd_accept,
  24. 0,
  25. timeout_listen_httpd,
  26. display_httpd_accept,
  27. 0,
  28. NULL,
  29. 0
  30. };
  31. static struct dcc_table MHTTPD_CON_HTTP =
  32. {
  33. "HTTP",
  34. DCT_VALIDIDX,
  35. eof_http,
  36. http_activity,
  37. &http_timeout,
  38. timeout_http,
  39. display_http,
  40. expmem_http,
  41. kill_http,
  42. #ifdef OLDBOT
  43. out_http,
  44. #else
  45. out_http,
  46. outdone_http
  47. #endif
  48. };
  49. #define http_connection(i) ((struct http_connection_data *) dcc[(i)].u.other)
  50. /* init_httpd()
  51. * initializes a few variables
  52. */
  53. static void init_httpd()
  54. {
  55. httpd_text_buf = NULL;
  56. }
  57. /* expmem_httpd()
  58. * expmem function
  59. */
  60. static int expmem_httpd()
  61. {
  62. int size = 0;
  63. if (httpd_text_buf)
  64. size += strlen(httpd_text_buf) + 1;
  65. return size;
  66. }
  67. /* unload_httpd():
  68. * frees all allocated memory, stops listening and kills all
  69. * existing connections.
  70. */
  71. static void unload_httpd()
  72. {
  73. stop_httpd();
  74. if (httpd_text_buf)
  75. nfree(httpd_text_buf);
  76. }
  77. /* start_httpd():
  78. * starts listening for http connections on the defined port.
  79. */
  80. static void start_httpd(int port)
  81. {
  82. int i, zz;
  83. char tmp[50];
  84. Context;
  85. // a little hack to make httpd listen on the defined vhost
  86. // (or on all vhosts, if none is defined)
  87. // Just set my-ip to the wanted vhost, since open_listen()
  88. // uses this var
  89. sprintf(tmp, "set my-ip \"%s\";", httpd_ip);
  90. do_tcl("httpd-hack-start",
  91. "set my-ip-httpd-backup ${my-ip};"
  92. "set my-hostname-httpd-backup ${my-hostname};"
  93. "set my-hostname \"\"");
  94. do_tcl("httpd-hack-setip", tmp);
  95. // now get a listening socket
  96. zz = open_listen(&port);
  97. // don't forget to restore my-ip when we're done ^_^
  98. do_tcl("httpd-hack-end",
  99. "set my-ip ${my-ip-httpd-backup};"
  100. "set my-hostname ${my-hostname-httpd-backup}");
  101. // ohoh, we didn't get a socket :(
  102. if (zz == (-1)) {
  103. putlog(LOG_MISC, "*", "ERROR! Cannot open listening socket for httpd!");
  104. return;
  105. }
  106. // now add this new socket to our dcc table and display a warning,
  107. // if the table is full
  108. if ((i = new_dcc(&MHTTPD_CON_HTTPD, 0)) == -1) {
  109. putlog(LOG_MISC, "*", "ERROR! Cannot open listening socket for httpd! DCC table is full!");
  110. // better kill the socket, before we get a "phantom-socket" ^_^
  111. killsock(zz);
  112. return;
  113. }
  114. // store the index in a global var, so we can access it easily later...
  115. httpd_dcc_index = i;
  116. // now fill the dcc-struct with information
  117. dcc[i].sock = zz;
  118. dcc[i].addr = (IP) (-559026163);
  119. dcc[i].port = port;
  120. strcpy(dcc[i].nick, "httpd");
  121. strcpy(dcc[i].host, "*");
  122. dcc[i].timeval = now;
  123. putlog(LOG_MISC, "*", "Now listening for http connections on port %d", port);
  124. }
  125. /* stop_httpd()
  126. * kills all httpd connections and listening sockets
  127. */
  128. static void stop_httpd()
  129. {
  130. int i;
  131. for (i = 0; i < dcc_total; i++) {
  132. if (dcc[i].type == &MHTTPD_CON_HTTPD) {
  133. putlog(LOG_MISC, "*",
  134. "no longer listening for http connections on port %d",
  135. dcc[i].port);
  136. killsock(dcc[i].sock);
  137. lostdcc(i);
  138. } else if (dcc[i].type == &MHTTPD_CON_HTTP) {
  139. putlog(LOG_MISC, "*", "killing http connection from %s", dcc[i].host);
  140. killsock(dcc[i].sock);
  141. lostdcc(i);
  142. }
  143. }
  144. }
  145. /* init_http_connection_data():
  146. * inits all variables in our http_connection_data struct
  147. */
  148. static void init_http_connection_data(int idx)
  149. {
  150. http_connection(idx)->traffic = 0;
  151. http_connection(idx)->code = -1;
  152. http_connection(idx)->browser = NULL;
  153. http_connection(idx)->referer = NULL;
  154. http_connection(idx)->path = NULL;
  155. http_connection(idx)->cmd = NULL;
  156. http_connection(idx)->postparams = NULL;
  157. http_connection(idx)->cookies = NULL;
  158. http_connection(idx)->params = NULL;
  159. http_connection(idx)->headers = NULL;
  160. http_connection(idx)->langs = NULL;
  161. http_connection(idx)->getpostparams = 0;
  162. http_connection(idx)->content_length = 0;
  163. }
  164. /* expmem_http()
  165. * expmem's all data allocated to store browser info, referer, cookies, etc...
  166. */
  167. static int expmem_http(void *x)
  168. {
  169. register struct http_connection_data *p = (struct http_connection_data *) x;
  170. int tot = 0;
  171. Context;
  172. if (!p) {
  173. putlog(LOG_MISC, "*", "Can't expmem clientinfo, no pointer. This should not happen!");
  174. return 0;
  175. }
  176. tot += sizeof(struct http_connection_data);
  177. if (p->browser)
  178. tot += strlen(p->browser) + 1;
  179. if (p->referer)
  180. tot += strlen(p->referer) + 1;
  181. if (p->path)
  182. tot += strlen(p->path) + 1;
  183. if (p->cmd)
  184. tot += strlen(p->cmd) + 1;
  185. if (p->postparams)
  186. tot += strlen(p->postparams) + 1;
  187. if (p->cookies)
  188. tot += llist_2string_expmem(p->cookies);
  189. if (p->params)
  190. tot += llist_2string_expmem(p->params);
  191. if (p->headers)
  192. tot += llist_1string_expmem(p->headers);
  193. if (p->langs)
  194. tot += llist_1string_expmem(p->langs);
  195. return tot;
  196. }
  197. /* free_http_connection_data():
  198. * frees all data of our http_connection_data struct
  199. */
  200. static void free_http_connection_data(int idx)
  201. {
  202. if (http_connection(idx)->browser)
  203. nfree(http_connection(idx)->browser);
  204. if (http_connection(idx)->referer)
  205. nfree(http_connection(idx)->referer);
  206. if (http_connection(idx)->path)
  207. nfree(http_connection(idx)->path);
  208. if (http_connection(idx)->cmd)
  209. nfree(http_connection(idx)->cmd);
  210. if (http_connection(idx)->postparams)
  211. nfree(http_connection(idx)->postparams);
  212. if (http_connection(idx)->cookies)
  213. llist_2string_free(http_connection(idx)->cookies);
  214. if (http_connection(idx)->params)
  215. llist_2string_free(http_connection(idx)->params);
  216. if (http_connection(idx)->headers)
  217. llist_1string_free(http_connection(idx)->headers);
  218. if (http_connection(idx)->langs)
  219. llist_1string_free(http_connection(idx)->langs);
  220. n_free(http_connection(idx), __FILE__, __LINE__);
  221. }
  222. /* http_activity():
  223. * handles all the data that the browser sends to us.
  224. */
  225. static void http_activity(int idx, char *buf, int len)
  226. {
  227. char *cmd, *path, *imask, *params;
  228. #ifdef flush_inbuf
  229. int i;
  230. #endif
  231. int lev, content_length;
  232. struct timeval t;
  233. double pre_time;
  234. debug2("%s: %s", dcc[idx].host, buf);
  235. // at first, check if the user is on ignore and therefore should
  236. // be ignored
  237. imask = nmalloc(strlen(dcc[idx].host) + 11);
  238. sprintf(imask, "http!*@%s", dcc[idx].host);
  239. if (match_ignore(imask)) {
  240. debug1("Ignoring http access from %s", dcc[idx].host);
  241. send_http_header(idx, 401);
  242. if (httpd_ignore_msg[0])
  243. dprintf(idx, "%s", httpd_ignore_msg);
  244. killsock(dcc[idx].sock);
  245. lostdcc(idx);
  246. nfree(imask);
  247. return;
  248. }
  249. nfree(imask);
  250. if ((http_connection(idx)->content_length > 0) && (http_connection(idx)->getpostparams)) {
  251. append_postparam_string(idx, buf);
  252. return;
  253. }
  254. // then check for recognized commands which we want to be logged
  255. // (only GET is supported, at the moment)
  256. if ((!strncasecmp(buf, "GET ", 4) || !strncasecmp(buf, "POST ", 5))
  257. && !http_connection(idx)->cmd) {
  258. http_connection(idx)->cmd = nmalloc(strlen(buf) + 1);
  259. strcpy(http_connection(idx)->cmd, buf);
  260. }
  261. // now check if we know the command and store all info that we need
  262. cmd = newsplit(&buf);
  263. // GET: request for a document
  264. if (!strcasecmp(cmd, "GET") || !strcasecmp(cmd, "POST")) {
  265. // at first, check if we're being flooded and kill the connection
  266. // if there were too many requests.
  267. if (http_flood()) {
  268. http_connection(idx)->code = 401;
  269. killsock(dcc[idx].sock);
  270. lostdcc(idx);
  271. return;
  272. }
  273. // if (!strcasecmp(cmd, "POST"))
  274. // http_connection(idx)->getpostparams = 1;
  275. // now log the access
  276. Assert(http_connection(idx)->cmd);
  277. lev = logmodes(httpd_loglevel);
  278. if (lev)
  279. putlog(lev, "*", "%s: %s", dcc[idx].host, http_connection(idx)->cmd);
  280. // and finally store the request, if there wasn't already one before.
  281. if (!http_connection(idx)->path) {
  282. params = newsplit(&buf);
  283. path = csplit(&params, '?');
  284. // cut the parameters off and store them
  285. add_params(idx, params);
  286. http_connection(idx)->path = nmalloc(strlen(path) + 1);
  287. strcpy(http_connection(idx)->path, path);
  288. }
  289. // user-agent: browser-information
  290. } else if (!strcasecmp(cmd, "User-Agent:")) {
  291. if (http_connection(idx)->browser)
  292. return;
  293. http_connection(idx)->browser = nmalloc(strlen(buf) + 1);
  294. strcpy(http_connection(idx)->browser, buf);
  295. } else if (!strcasecmp(cmd, "Referer:")) {
  296. if (http_connection(idx)->referer)
  297. return;
  298. http_connection(idx)->referer = nmalloc(strlen(buf) + 1);
  299. strcpy(http_connection(idx)->referer, buf);
  300. } else if (!strcasecmp(cmd, "Cookie:")) {
  301. add_cookies(idx, buf);
  302. } else if (!strcasecmp(cmd, "Content-Length:") && !http_connection(idx)->content_length) {
  303. content_length = atoi(buf);
  304. debug1("setting content length to %d", content_length);
  305. http_connection(idx)->content_length = content_length;
  306. } else if (!strcasecmp(cmd, "Accept-language:")) {
  307. add_language(idx, buf);
  308. } else if (!buf[0]) {
  309. if (http_connection(idx)->cmd && !(!strncasecmp(http_connection(idx)->cmd, "POST ", 5))) {
  310. debug0("now sending...");
  311. gettimeofday(&t, NULL);
  312. pre_time = (float) t.tv_sec + (((float) t.tv_usec) / 1000000);
  313. process_get_request(idx);
  314. gettimeofday(&t, NULL);
  315. debug1("Processing time: %.3f", ((float) t.tv_sec + (((float) t.tv_usec) / 1000000)) - pre_time);
  316. dcc[idx].status = 1;
  317. #ifndef OLDBOT
  318. /* If there's no data in our socket, we immediately get rid of it.
  319. */
  320. if (!sock_has_data(SOCK_DATA_OUTGOING, dcc[idx].sock)) {
  321. killsock(dcc[idx].sock);
  322. lostdcc(idx);
  323. }
  324. #endif
  325. } else {
  326. debug0("waiting for post params...");
  327. http_connection(idx)->getpostparams = 1;
  328. #ifdef sockoptions
  329. i = sockoptions(dcc[idx].sock, EGG_OPTION_UNSET, SOCK_BUFFER);
  330. if (i)
  331. debug1("WARNING: sockoptions returned %d while trying to deativate "
  332. "buffering for POST parameters!", i);
  333. #endif
  334. #ifdef flush_inbuf
  335. flush_inbuf(idx);
  336. #endif
  337. }
  338. }
  339. }
  340. /* add_cookies()
  341. * simple function to add one or more cookies to the cookie-list
  342. */
  343. static void add_cookies(int idx, char *buf)
  344. {
  345. char *cookie, *name, *value;
  346. while (buf[0]) {
  347. cookie = csplit(&buf, ';');
  348. while (cookie[0] == ' ')
  349. cookie++;
  350. name = csplit(&cookie, '=');
  351. value = cookie;
  352. http_connection(idx)->cookies
  353. = llist_2string_add(http_connection(idx)->cookies, name, value);
  354. }
  355. }
  356. static char *get_cookie_value(int idx, char *name)
  357. {
  358. Assert(idx >= 0);
  359. return llist_2string_get_s2(http_connection(idx)->cookies, name);
  360. }
  361. /* add_params():
  362. * extracts all parameters from the URL and stores them
  363. * in a simple linked list
  364. */
  365. static void add_params(int idx, char *buf)
  366. {
  367. char *param, *name, *value;
  368. if (strchr(buf, '?')) {
  369. debug1("WARNING: '?' found in paramstring '%s'. This should have been "
  370. "already split!", buf);
  371. return;
  372. }
  373. while (buf[0]) {
  374. param = csplit(&buf, '&');
  375. name = csplit(&param, '=');
  376. value = decode_url(param);
  377. debug2("adding parameter: '%s'='%s'", name, value);
  378. http_connection(idx)->params
  379. = llist_2string_add(http_connection(idx)->params, name, value);
  380. }
  381. }
  382. static char *get_param_value(int idx, char *name)
  383. {
  384. Assert(idx >= 0);
  385. return llist_2string_get_s2(http_connection(idx)->params, name);
  386. }
  387. static void add_language(int idx, char *buf)
  388. {
  389. char *lang;
  390. if (buf)
  391. buf = csplit(&buf, ';'); /* strip "; q=1.5", whatever it means... */
  392. while (buf[0]) {
  393. lang = csplit(&buf, ',');
  394. lang = csplit(&lang, '-'); /* en-us => en */
  395. while (lang[0] == ' ')
  396. lang++;
  397. debug1("adding accepted language: '%s'", lang);
  398. http_connection(idx)->langs =
  399. llist_1string_add(http_connection(idx)->langs, lang);
  400. }
  401. }
  402. #ifndef OLDBOT
  403. static void outdone_http(int idx)
  404. {
  405. if (dcc[idx].status) {
  406. killsock(dcc[idx].sock);
  407. lostdcc(idx);
  408. } else
  409. dcc[idx].status = 1;
  410. }
  411. #endif
  412. static void display_http(int idx, char *buf)
  413. {
  414. sprintf(buf, "http connection");
  415. }
  416. static void display_httpd_accept(int idx, char *buf)
  417. {
  418. sprintf(buf, "httpd");
  419. }
  420. static void timeout_http(int idx)
  421. {
  422. #ifdef flush_inbuf
  423. if (http_connection(idx)->getpostparams && http_connection(idx)->path) {
  424. // If there's still something in the inbuffer, then we might still be receivng
  425. // POST parameters or something. Just let the connection live a bit longer.
  426. // (FIXME: DOSable by flooding with body)
  427. if (flush_inbuf(idx) > 0) {
  428. debug0("inbuf not empty on timeout. Flushed...");
  429. dcc[idx].timeval = now;
  430. return;
  431. }
  432. }
  433. #endif
  434. send_http_header(idx, 408);
  435. dprintf(idx, "<html>\n<head><title>408 Request Time-out</title></head>\n"
  436. "<body>\n<H1>Request Time-out</H1><br>\n<p>Your browser didn't "
  437. "send enough information to process the request within %d "
  438. "seconds.</p>\n", http_timeout);
  439. #ifndef flush_inbuf
  440. dprintf(idx, "<p>If your browser did send the information, then the problem "
  441. "is probably that this server doesn't have the netstuff patch "
  442. "installed. Please ask the admin to install it. This "
  443. "patch is needed to receive login-information with browsers "
  444. "as Netscape Navigator, Opera or some others. (That's not a "
  445. "bug in the browser, but a missing network-related function "
  446. "in eggdrop which gets added by the patch)</p>\n");
  447. #endif
  448. dprintf(idx, "</body>\n</html>\n");
  449. killsock(dcc[idx].sock);
  450. lostdcc(idx);
  451. }
  452. static void timeout_listen_httpd(int idx)
  453. {
  454. debug0("timeout httpd listen");
  455. killsock(dcc[idx].sock);
  456. lostdcc(idx);
  457. }
  458. /* kill_http():
  459. * This function called when connection is killed. It
  460. * logs the connection to the logfile, if one exists.
  461. */
  462. static void kill_http(int idx, void *x)
  463. {
  464. char ts[41], test[11];
  465. time_t tt;
  466. FILE *f;
  467. Context;
  468. tt = now;
  469. ctime(&tt);
  470. /* 05/Feb/2000:12:08:17 +0100 */
  471. strftime(test, 19, "%z", localtime(&tt));
  472. // if test contains 'z' then strftime() doesn't support
  473. // %z (timezone-offset) on this system, and we have to
  474. // use a config var instead
  475. if (test[0] != 'z')
  476. strftime(ts, 40, "%d/%b/%Y:%H:%M:%S %z", localtime(&tt));
  477. else
  478. strftime(ts, 40, "%d/%b/%Y:%H:%M:%S", localtime(&tt));
  479. if (httpd_log[0]) {
  480. f = fopen(httpd_log, "a");
  481. if (f == NULL)
  482. putlog(LOG_MISC, "*", "ERROR writing httpd log.");
  483. else {
  484. if (test[0] != 'z')
  485. fprintf(f,
  486. "%s - - [%s] \"%s\" %d %d \"%s\" \"%s\"\n", dcc[idx].host, ts,
  487. http_connection(idx)->cmd ? http_connection(idx)->cmd : "",
  488. http_connection(idx)->code, http_connection(idx)->traffic,
  489. http_connection(idx)->referer ? http_connection(idx)->referer : "-",
  490. http_connection(idx)->browser ? http_connection(idx)->browser : "");
  491. else
  492. fprintf(f,
  493. "%s - - [%s %+05d] \"%s\" %d %d \"%s\" \"%s\"\n",
  494. dcc[idx].host, ts, offset * (-1) * 100,
  495. http_connection(idx)->cmd ? http_connection(idx)->cmd : "",
  496. http_connection(idx)->code, http_connection(idx)->traffic,
  497. http_connection(idx)->referer ? http_connection(idx)->referer : "-",
  498. http_connection(idx)->browser ? http_connection(idx)->browser : "");
  499. fclose(f);
  500. }
  501. }
  502. // don't forget to free the data when we're done.
  503. free_http_connection_data(idx);
  504. }
  505. /* out_http():
  506. * Called when data is sent through the socket. Used to log the
  507. * sent traffic.
  508. */
  509. static void out_http(int idx, char *buf, void *x)
  510. {
  511. register struct http_connection_data *p = (struct http_connection_data *) x;
  512. if (!p) {
  513. putlog(LOG_MISC, "*", "No http_connection pointer. This should not happen!");
  514. return;
  515. }
  516. p->traffic += strlen(buf);
  517. tputs(dcc[idx].sock, buf, strlen(buf));
  518. }
  519. /* http_accept():
  520. * accepts an incoming http connection
  521. */
  522. static void httpd_accept(int idx, char *buf, int len)
  523. {
  524. unsigned long ip;
  525. unsigned short port;
  526. int j = 0, sock, i;
  527. char s[UHOSTLEN];
  528. Context;
  529. if (dcc_total + 1 >= max_dcc) {
  530. j = answer(dcc[idx].sock, s, &ip, &port, 0);
  531. if (j != -1) {
  532. dprintf(-j, "Sorry, too many connections already.\r\n");
  533. killsock(j);
  534. }
  535. return;
  536. }
  537. sock = answer(dcc[idx].sock, s, &ip, &port, 0);
  538. if (sock < 0) {
  539. neterror(s);
  540. putlog(LOG_MISC, "*", "HTTPd: Error accepting connection: %s", s);
  541. return;
  542. }
  543. if ((i = new_dcc(&MHTTPD_CON_HTTP, sizeof(struct http_connection_data))) == (-1)) {
  544. putlog(LOG_MISC, "*", "Error accepting http connection. DCC table is full.");
  545. killsock(sock);
  546. return;
  547. }
  548. dcc[i].sock = sock;
  549. dcc[i].addr = ip;
  550. dcc[i].port = port;
  551. strcpy(dcc[i].nick, "http");
  552. #ifndef OLDBOT
  553. sprintf(s, "%s", iptostr(my_htonl(ip)));
  554. #else
  555. sprintf(s, "%lu.%lu.%lu.%lu", (ip >> 24) & 0xff, (ip >> 16) & 0xff,
  556. (ip >> 8) & 0xff, ip & 0xff); /* dw */
  557. #endif
  558. strcpy(dcc[i].host, s);
  559. dcc[i].timeval = now;
  560. dcc[i].status = 0;
  561. // init http_connection_data struct
  562. init_http_connection_data(i);
  563. }
  564. /* http_flood()
  565. * simple check for floods
  566. */
  567. static int mhttp_time = 0, mhttp_thr = 0;
  568. static int http_flood()
  569. {
  570. if (!max_http_thr || !max_http_time)
  571. return 0;
  572. if ((now - mhttp_time) > max_http_time) {
  573. mhttp_time = now;
  574. mhttp_thr = 0;
  575. }
  576. mhttp_thr++;
  577. if (mhttp_thr > max_http_thr)
  578. return 1;
  579. return 0;
  580. }
  581. static void eof_http(int idx)
  582. {
  583. debug0("eof http");
  584. killsock(dcc[idx].sock);
  585. lostdcc(idx);
  586. }
  587. /* decode_url():
  588. * Decodes all special characters(%3F == '?', %21 == '!', etc)
  589. * and returns the decoded url
  590. */
  591. static char *decode_url(char *paramurl)
  592. {
  593. char *p, *buf, *url, c, hex[5];
  594. long int i;
  595. Context;
  596. // free url-buffer (global var)
  597. if (httpd_text_buf)
  598. nfree(httpd_text_buf);
  599. // initialize url-buffer
  600. httpd_text_buf = nmalloc(1);
  601. httpd_text_buf[0] = 0;
  602. // copy parameter into a buffer
  603. buf = nmalloc(strlen(paramurl) + 1);
  604. strcpy(buf, paramurl);
  605. url = buf;
  606. // now loop to get every encoded char
  607. while ((p = strchr(url, '%'))) {
  608. // '%' marks the beginning of an encoded char, so cut the string here.
  609. p[0] = 0;
  610. // append the first part of the string to our buffer
  611. httpd_text_buf = nrealloc(httpd_text_buf, strlen(httpd_text_buf) + strlen(url) + 1);
  612. strcat(httpd_text_buf, url);
  613. // set the pointer to the beginning of the next string
  614. url = p + 1;
  615. // first check if there are enough chars left to decode
  616. if (strlen(url) >= 2) {
  617. // the number behind '%' is a hex-number which is the ASCII code of
  618. // the char, so dump the hex into a string and scan it
  619. snprintf(hex, 5, "0x%c%c", p[1], p[2]);
  620. i = strtol(hex, NULL, 0);
  621. if (!i) {
  622. i = '?';
  623. debug0("MiniHTTPd: decode_url(): i is 0");
  624. }
  625. c = (char) i;
  626. // now append the decoded char to the url
  627. httpd_text_buf = nrealloc(httpd_text_buf, strlen(httpd_text_buf) + 1 + 1);
  628. sprintf(httpd_text_buf, "%s%c", httpd_text_buf, c);
  629. // increase the pointer to abandon the encoded char
  630. url += 2;
  631. } else {
  632. // just append the original '%' if there weren't enough chars to decode
  633. httpd_text_buf = nrealloc(httpd_text_buf, strlen(httpd_text_buf) + 1 + 1);
  634. strcat(httpd_text_buf, "%");
  635. }
  636. }
  637. // finally append the rest of the param to our buffer. There are no encoded
  638. // chars left.
  639. httpd_text_buf = nrealloc(httpd_text_buf, strlen(httpd_text_buf) + strlen(url) + 1);
  640. strcat(httpd_text_buf, url);
  641. // free the buffer
  642. nfree(buf);
  643. Context;
  644. return httpd_text_buf;
  645. }
  646. /* encode_url():
  647. * encodes all special characters in an url
  648. */
  649. static char encoded_url_buf[128];
  650. static char *eu_last_url;
  651. static char *encode_url(char *url)
  652. {
  653. char *buf;
  654. unsigned char c;
  655. Assert(url);
  656. // if we are going to re-encode the same URL again, then
  657. // save some CPU time and just return our buffer again
  658. // (I guess noone would mess with that buffer, so it _should_
  659. // be save)
  660. if (url == eu_last_url)
  661. return encoded_url_buf;
  662. else
  663. eu_last_url = url;
  664. buf = encoded_url_buf;
  665. while (url[0] && (buf < (encoded_url_buf + 120))) {
  666. c = url[0];
  667. if (((c >= 97) && (c <= 122)) || ((c >= 65) && (c <= 90))) {
  668. buf[0] = c;
  669. buf++;
  670. } else {
  671. buf[0] = '%';
  672. buf++;
  673. snprintf(buf, 3, "%02x", c);
  674. buf += 2;
  675. }
  676. url++;
  677. }
  678. buf[0] = 0;
  679. return encoded_url_buf;
  680. }
  681. /* text2html():
  682. * replaces all strange chars by html-unicode-codes and removes
  683. * stupid color codes */
  684. static char *text2html(char *text)
  685. {
  686. char *buf, ubuf[8];
  687. unsigned char c;
  688. if (httpd_text_buf)
  689. httpd_text_buf = nrealloc(httpd_text_buf, (strlen(text) * sizeof(char) * 7) + 1);
  690. else
  691. httpd_text_buf = nmalloc((strlen(text) * sizeof(char) * 7) + 1);
  692. buf = httpd_text_buf;
  693. *buf = 0;
  694. while (text[0]) {
  695. c = text[0];
  696. if (((c >= 97) && (c <= 122)) || ((c >= 65) && (c <= 90))) {
  697. *buf = c;
  698. buf++;
  699. } else if (c == 3) { /* filter $§%#&-mirc colors! */
  700. /* inspired by src/dcc.c */
  701. if (isdigit(text[1])) {
  702. text++;
  703. if (isdigit(text[1]))
  704. text++;
  705. if (text[1] == ',') {
  706. text++;
  707. if (isdigit(text[1]))
  708. text++;
  709. if (isdigit(text[1]))
  710. text++;
  711. }
  712. }
  713. if (!1) { /* DELETEME!!! */
  714. /* from src/dcc.c */
  715. if (isdigit(text[1])) { /* Is the first char a number? */
  716. text++; /* Skip over the ^C and the first digit */
  717. if (isdigit(text[1]))
  718. text++; /* Is this a double digit number? */
  719. if (text[1] == ',') { /* Do we have a background color next? */
  720. if (isdigit(text[2]))
  721. text += 2; /* Skip over the first background digit */
  722. if (isdigit(text[1]))
  723. text++; /* Is it a double digit? */
  724. }
  725. }
  726. }
  727. } else if ((c == 2) || (c == 7) || (c == 0x16) || (c == 0x1f)) {
  728. /* do nothing, just ignore those $§%#&-codes! */
  729. debug0("deleteme (mini_httpd.c, text2html())");
  730. } else {
  731. snprintf(ubuf, sizeof(ubuf), "&#%d;", (unsigned int) c);
  732. strcpy(buf, ubuf);
  733. buf += strlen(ubuf);
  734. }
  735. text++;
  736. }
  737. *buf = 0;
  738. httpd_text_buf = nrealloc(httpd_text_buf, strlen(httpd_text_buf) + 1);
  739. return httpd_text_buf;
  740. }
  741. /* csplit()
  742. * basically the same as nsplit, but allows you to define
  743. * the divider.
  744. */
  745. static char *csplit(char **rest, char divider)
  746. {
  747. register char *o, *r;
  748. if (!rest)
  749. return *rest = "";
  750. o = *rest;
  751. while (*o == divider)
  752. o++;
  753. r = o;
  754. while (*o && (*o != divider))
  755. o++;
  756. if (*o)
  757. *o++ = 0;
  758. *rest = o;
  759. return r;
  760. }
  761. static void set_cookie(int idx, char *name, char *value)
  762. {
  763. char tbuf[40], *buf;
  764. time_t tt;
  765. int len;
  766. tt = now + 30 * 60 * 60 * 24;
  767. strftime(tbuf, sizeof(tbuf), "%a, %d-%b-%Y %H:%M:%S GMT", localtime(&tt));
  768. len = 34 + strlen(name) + strlen(value) + strlen(tbuf) + 1;
  769. buf = nmalloc(len);
  770. snprintf(buf, len, "Set-Cookie: %s=%s; expires=%s; path=/\n", name, value, tbuf);
  771. http_connection(idx)->headers = llist_1string_add(http_connection(idx)->headers, buf);
  772. nfree(buf);
  773. }
  774. /* append_postparam_string()
  775. * appends this chunk to the buffer that contains the POST parameters.
  776. * when the buffer is filled, processing gets started automatically.
  777. */
  778. static void append_postparam_string(int idx, char *buf)
  779. {
  780. if (!http_connection(idx)->getpostparams) {
  781. debug2("?!? Tried to append post param string '%s' to connection #%d, "
  782. "but this connection doesn't expect any params... probably a bug. :(",
  783. buf, idx);
  784. return;
  785. }
  786. if (!http_connection(idx)->postparams) {
  787. if (!(http_connection(idx)->content_length > 0)) {
  788. send_http_header(idx, 400);
  789. dprintf(idx, "<html><head><title>400 Bad Request</title></head>"
  790. "<body><H1>Bad Request:</H1> invalid "
  791. "content-length '%d'.</body></html>\n",
  792. http_connection(idx)->content_length);
  793. killsock(dcc[idx].sock);
  794. lostdcc(idx);
  795. return;
  796. }
  797. http_connection(idx)->postparams
  798. = nmalloc(http_connection(idx)->content_length + 1);
  799. http_connection(idx)->postparams[0] = 0;
  800. debug1("allocated %d bytes for params", http_connection(idx)->content_length + 1);
  801. }
  802. debug1("appending content: '%s'", buf);
  803. debug1("old: '%s'", http_connection(idx)->postparams);
  804. strncat(http_connection(idx)->postparams,
  805. buf,
  806. http_connection(idx)->content_length);
  807. http_connection(idx)->postparams[http_connection(idx)->content_length] = 0;
  808. debug1("new: '%s'", http_connection(idx)->postparams);
  809. if ((http_connection(idx)->content_length > 0) &&
  810. http_connection(idx)->getpostparams &&
  811. http_connection(idx)->postparams)
  812. {
  813. if (strlen(http_connection(idx)->postparams) >= http_connection(idx)->content_length) {
  814. debug0("parsing params...");
  815. add_params(idx, http_connection(idx)->postparams);
  816. process_request(idx);
  817. }
  818. }
  819. }
  820. /* send_http_header()
  821. * sends the http header
  822. */
  823. static void send_http_header(int idx, int code)
  824. {
  825. struct llist_1string *h;
  826. if (code == 200)
  827. dprintf(idx, "HTTP/1.0 200 OK\n");
  828. else if (code == 401)
  829. dprintf(idx, "HTTP/1.0 401 Access Forbidden\n");
  830. else if (code == 404)
  831. dprintf(idx, "HTTP/1.1 404 Not Found\n");
  832. else if (code == 500)
  833. dprintf(idx, "HTTP/1.1 500 Internal Server Error\n");
  834. else
  835. dprintf(idx, "HTTP/1.0 %d %d\n", code, code);
  836. dprintf(idx, "Server: EggdropMiniHTTPd/%s\n", HTTPD_VERSION);
  837. dprintf(idx, "Content-Type: text/html\n");
  838. for (h = http_connection(idx)->headers; h; h = h->next) {
  839. debug1("Sending additional header: '%s'", h->s1);
  840. dprintf(idx, "%s", h->s1);
  841. }
  842. dprintf(idx, "\n");
  843. http_connection(idx)->code = code;
  844. }
  845. /* process_request():
  846. * calls the main processing function process_get_request(), takes the
  847. * processing time and tries to kill the socket if everything got already
  848. * sent.
  849. */
  850. static void process_request(int idx)
  851. {
  852. struct timeval t;
  853. double pre_time;
  854. Context;
  855. Assert(idx >= 0);
  856. debug0("now sending...");
  857. gettimeofday(&t, NULL);
  858. pre_time = (float) t.tv_sec + (((float) t.tv_usec) / 1000000);
  859. process_get_request(idx);
  860. gettimeofday(&t, NULL);
  861. debug1("Processing time: %.3f", ((float) t.tv_sec + (((float) t.tv_usec) / 1000000)) - pre_time);
  862. dcc[idx].status = 1;
  863. #ifndef OLDBOT
  864. /* If there's no data in our socket, we immediately get rid of it.
  865. */
  866. if (!sock_has_data(SOCK_DATA_OUTGOING, dcc[idx].sock)) {
  867. killsock(dcc[idx].sock);
  868. lostdcc(idx);
  869. }
  870. #endif
  871. }