httpd.c
上传用户:lampled
上传日期:2007-01-07
资源大小:94k
文件大小:28k
源码类别:

Web服务器

开发平台:

Unix_Linux

  1. /* Copyright (C) 1995, 1996 by Sven Berkvens (sven@stack.nl) */
  2. #include "config.h"
  3. #include <sys/types.h>
  4. #ifdef HAVE_SYS_TIME_H
  5. #include <sys/time.h>
  6. #endif /* HAVE_SYS_TIME_H */
  7. #ifdef HAVE_SYS_RESOURCE_H
  8. #include <sys/resource.h>
  9. #endif /* HAVE_SYS_RESOURCE_H */
  10. #ifdef HAVE_SYS_MMAN_H
  11. #include <sys/mman.h>
  12. #endif /* HAVE_SYS_MMAN_H */
  13. #include <sys/socket.h>
  14. #ifdef HAVE_SYS_WAIT_H
  15. #include <sys/wait.h>
  16. #endif /* HAVE_SYS_WAIT_H */
  17. #include <sys/signal.h>
  18. #include <sys/stat.h>
  19. #ifdef HAVE_SYS_SELECT_H
  20. #include <sys/select.h>
  21. #endif /* HAVE_SYS_SELECT_H */
  22. #ifdef HAVE_SYS_PARAM_H
  23. #include <sys/param.h>
  24. #endif /* HAVE_SYS_PARAM_H */
  25. #ifdef HAVE_SYS_SYSLIMITS_H
  26. #include <sys/syslimits.h>
  27. #endif /* HAVE_SYS_SYSLIMITS_H */
  28. #include <netinet/in.h>
  29. #include <arpa/inet.h>
  30. #include <fcntl.h>
  31. #include <string.h>
  32. #include <stdio.h>
  33. #include <errno.h>
  34. #include <netdb.h>
  35. #ifdef HAVE_TIME_H
  36. #ifdef SYS_TIME_WITH_TIME
  37. #include <time.h>
  38. #endif /* SYS_TIME_WITH_TIME */
  39. #endif /* HAVE_TIME_H */
  40. #include <stdlib.h>
  41. #ifndef NONEWSTYLE
  42. #include <stdarg.h>
  43. #else /* Not not NONEWSTYLE */
  44. #include <varargs.h>
  45. #endif /* NONEWSTYLE */
  46. #include <signal.h>
  47. #include <pwd.h>
  48. #include <grp.h>
  49. #include <unistd.h>
  50. #ifdef HAVE_ERR_H
  51. #include <err.h>
  52. #else /* Not HAVE_ERR_H */
  53. #include "err.h"
  54. #endif /* HAVE_ERR_H */
  55. #include <ctype.h>
  56. #ifdef HAVE_ALLOCA_H
  57. #include <alloca.h>
  58. #endif /* HAVE_ALLOCA_H */
  59. #ifdef HAVE_VFORK_H
  60. #include <vfork.h>
  61. #endif /* HAVE_VFORK_H */
  62. #ifdef HAVE_MEMORY_H
  63. #include <memory.h>
  64. #endif /* HAVE_MEMORY_H */
  65. #include "httpd.h"
  66. #include "methods.h"
  67. #include "local.h"
  68. #include "procname.h"
  69. #include "ssi.h"
  70. #include "extra.h"
  71. #include "cgi.h"
  72. #include "xscrypt.h"
  73. #include "path.h"
  74. #include "convert.h"
  75. #include "setenv.h"
  76. #include "getopt.h"
  77. #include "string.h"
  78. #ifdef __linux__
  79. extern char *tempnam(const char *, const char *);
  80. #endif /* __linux__ */
  81. /* This is for HP/UX */
  82. #ifdef HPUX
  83. #ifndef NOFORWARDS
  84. extern int setpriority PROTO((int, int, int));
  85. #endif /* NOFORWARDS */
  86. #endif /* HPUX */
  87. /* Global variables */
  88. int port, headers, localmode, netbufind, netbufsiz, readlinemode,
  89. headonly, postonly;
  90. static int sd, reqs, number, mainhttpd = 1;
  91. gid_t group_id, origegid;
  92. uid_t user_id, origeuid;
  93. char netbuf[MYBUFSIZ], remotehost[MAXHOSTNAMELEN], orig[MYBUFSIZ],
  94. currenttime[80], dateformat[MYBUFSIZ], real_path[XS_PATH_MAX],
  95. thishostname[MAXHOSTNAMELEN], version[16], error_path[XS_PATH_MAX],
  96. access_path[XS_PATH_MAX], refer_path[XS_PATH_MAX], rootdir[XS_PATH_MAX],
  97. total[XS_PATH_MAX], name[XS_PATH_MAX];
  98. static char browser[MYBUFSIZ], referer[MYBUFSIZ], outputbuffer[SENDBUFSIZE],
  99. thisdomain[MAXHOSTNAMELEN], message503[MYBUFSIZ],
  100. *startparams;
  101. FILE *access_log = NULL, *refer_log = NULL;
  102. time_t modtime;
  103. static struct in_addr thisaddress;
  104. /* Static arrays */
  105. static char six2pr[64] =
  106. {
  107. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  108. 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
  109. 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  110. 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
  111. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
  112. };
  113. /* Prototypes */
  114. #ifndef NOFORWARDS
  115. static VOID filedescrs PROTO((void));
  116. static VOID detach PROTO((void));
  117. static VOID child_handler PROTO((int));
  118. static VOID term_handler PROTO((int));
  119. static VOID open_logs PROTO((int));
  120. static VOID core_handler PROTO((int));
  121. static VOID set_signals PROTO((void));
  122. static int hexdigit PROTO((int));
  123. static int decode PROTO((char *));
  124. static VOID uudecode PROTO((char *));
  125. static VOID process_request PROTO((void));
  126. static VOID setup_environment PROTO((void));
  127. static VOID standalone_main PROTO((void));
  128. #endif /* NOFORWARDS */
  129. extern VOID
  130. stdheaders DECL3(int, lastmod, int, texthtml, int, endline)
  131. {
  132. setcurrenttime();
  133. printf("Date: %srnServer: %srn", currenttime, SERVER_IDENT);
  134. if (lastmod)
  135. printf("Last-modified: %srnExpires: %srn",
  136. currenttime, currenttime);
  137. if (texthtml)
  138. printf("Content-type: text/htmlrn");
  139. if (endline)
  140. printf("rn");
  141. }
  142. static VOID
  143. filedescrs DECL0
  144. {
  145. close(0); if (open(BITBUCKETNAME, O_RDONLY, 0) != 0)
  146. err(1, "Cannot open fd 0 (%s)", BITBUCKETNAME);
  147. if (dup2(0, 1) != 1)
  148. err(1, "Cannot dup2() fd 1");
  149. }
  150. static VOID
  151. detach DECL0
  152. {
  153. pid_t x;
  154. if (chdir("/"))
  155. err(1, "chdir(`/')");
  156. if ((x = fork()) > 0)
  157. exit(0);
  158. else if (x == -1)
  159. err(1, "fork()");
  160. #ifdef HAVE_SETSID
  161. if (setsid() == -1)
  162. err(1, "setsid() failed");
  163. #else /* Not HAVE_SETSID */
  164. if (setpgrp(getpid(), 0)) == -1)
  165. err(1, "setpgrp() failed");
  166. #endif /* HAVE_SETSID */
  167. }
  168. extern VOID
  169. setcurrenttime DECL0
  170. {
  171. time_t thetime;
  172. time(&thetime);
  173. strftime(currenttime, sizeof(currenttime),
  174. "%a, %d %b %Y %T GMT", gmtime(&thetime));
  175. }
  176. static VOID
  177. child_handler DECL1(int, sig)
  178. {
  179. #ifdef NeXT
  180. union wait status;
  181. #else /* Not NeXT */
  182. int status;
  183. #endif /* NeXT */
  184. while (wait3(&status, WNOHANG, NULL) > 0)
  185. /* NOTHING */;
  186. set_signals();
  187. }
  188. static VOID
  189. term_handler DECL1(int, sig)
  190. {
  191. if (mainhttpd)
  192. {
  193. setcurrenttime();
  194. fprintf(stderr, "[%s] Received signal %d, shutting down...n",
  195. currenttime, sig);
  196. fflush(stderr);
  197. mainhttpd = 0;
  198. killpg(0, SIGTERM);
  199. }
  200. exit(0);
  201. }
  202. static VOID
  203. open_logs DECL1(int, sig)
  204. {
  205. FILE *pidlog;
  206. char buffer[XS_PATH_MAX];
  207. uid_t savedeuid;
  208. gid_t savedegid;
  209. int tempfile;
  210. set_signals();
  211. savedeuid = savedegid = -1;
  212. if (!origeuid)
  213. {
  214. savedeuid = geteuid(); seteuid(origeuid);
  215. savedegid = getegid(); setegid(origegid);
  216. }
  217. if (mainhttpd)
  218. {
  219. sprintf(buffer, calcpath(PID_PATH));
  220. remove(buffer);
  221. if ((pidlog = fopen(buffer, "w")))
  222. {
  223. fprintf(pidlog, "%ldn", (long)getpid());
  224. fprintf(pidlog, "%sn", startparams);
  225. fclose(pidlog);
  226. }
  227. signal(SIGHUP, SIG_IGN); killpg(0, SIGHUP);
  228. }
  229. if (access_log)
  230. fclose(access_log);
  231. if (!(access_log = fopen(access_path, "a")))
  232. err(1, "fopen(`%s' [append])", access_path);
  233. #ifndef SETVBUF_REVERSED
  234. setvbuf(access_log, NULL, _IOLBF, 0);
  235. #else /* Not not SETVBUF_REVERSED */
  236. setvbuf(access_log, _IOLBF, NULL, 0);
  237. #endif /* SETVBUF_REVERSED */
  238. fflush(stderr);
  239. close(2);
  240. if ((tempfile = open(error_path, O_CREAT | O_APPEND | O_WRONLY,
  241. S_IWUSR | S_IRUSR | S_IROTH | S_IRGRP)) < 0)
  242. err(1, "open(`%s' [append])", error_path);
  243. if (tempfile != 2)
  244. {
  245. if (dup2(tempfile, 2) == -1)
  246. err(1, "dup2() failed");
  247. close(tempfile);
  248. }
  249. if (refer_log)
  250. fclose(refer_log);
  251. if (!(refer_log = fopen(refer_path, "a")))
  252. err(1, "fopen(`%s' [append])", refer_path);
  253. #ifndef SETVBUF_REVERSED
  254. setvbuf(refer_log, NULL, _IOLBF, 0);
  255. #else /* Not not SETVBUF_REVERSED */
  256. setvbuf(refer_log, _IOLBF, NULL, 0);
  257. #endif /* SETVBUF_REVERSED */
  258. if (mainhttpd)
  259. {
  260. setcurrenttime();
  261. fprintf(stderr, "[%s] httpd: Successful restartn",
  262. currenttime);
  263. }
  264. loadfiletypes();
  265. #ifdef HANDLE_COMPRESSED
  266. loadcompresstypes();
  267. #endif /* HANDLE_COMPRESSED */
  268. set_signals();
  269. if (!origeuid)
  270. {
  271. if (seteuid(savedeuid) == -1)
  272. err(1, "seteuid()");
  273. if (setegid(savedegid) == -1)
  274. err(1, "setegid()");
  275. }
  276. }
  277. extern VOID
  278. alarm_handler DECL1(int, sig)
  279. {
  280. alarm(0); setcurrenttime();
  281. fprintf(stderr, "[%s] httpd: Send timed out for `%s'n",
  282. currenttime, remotehost[0] ? remotehost : "(none)");
  283. exit(1);
  284. }
  285. static VOID
  286. core_handler DECL1(int, sig)
  287. {
  288. const char *env;
  289. alarm(0); setcurrenttime();
  290. env = getenv("DOCUMENT_ARGUMENTS");
  291. fprintf(stderr, "[%s] httpd(pid %ld): FATAL SIGNAL %d [from: `%s' req: `%s' params: `%s' referer: `%s']n",
  292. currenttime, (long)getpid(), sig,
  293. remotehost[0] ? remotehost : "(none)",
  294. orig[0] ? orig : "(none)", env ? env : "(none)",
  295. referer[0] ? referer : "(none)");
  296. exit(1);
  297. }
  298. static VOID
  299. set_signals DECL0
  300. {
  301. struct sigaction action;
  302. #ifdef HAVE_SIGEMPTYSET
  303. sigemptyset(&action.sa_mask);
  304. #else /* Not HAVE_SIGEMPTYSET */
  305. action.sa_mask = 0;
  306. #endif /* HAVE_SIGEMPTYSET */
  307. action.sa_handler = open_logs;
  308. #ifdef SA_RESTART
  309. action.sa_flags = SA_RESTART;
  310. #else /* Not SA_RESTART */
  311. action.sa_flags = 0;
  312. #endif /* SA_RESTART */
  313. sigaction(SIGHUP, &action, NULL);
  314. action.sa_handler = child_handler;
  315. action.sa_flags = 0;
  316. sigaction(SIGCHLD, &action, NULL);
  317. action.sa_handler = alarm_handler;
  318. action.sa_flags = 0;
  319. sigaction(SIGALRM, &action, NULL);
  320. action.sa_handler = term_handler;
  321. action.sa_flags = 0;
  322. sigaction(SIGTERM, &action, NULL);
  323. action.sa_handler = term_handler;
  324. action.sa_flags = 0;
  325. sigaction(SIGINT, &action, NULL);
  326. #ifdef SIGBUS
  327. action.sa_handler = core_handler;
  328. action.sa_flags = 0;
  329. sigaction(SIGBUS, &action, NULL);
  330. #endif /* SIGBUS */
  331. #ifdef SIGSEGV
  332. action.sa_handler = core_handler;
  333. action.sa_flags = 0;
  334. sigaction(SIGSEGV, &action, NULL);
  335. #endif /* SIGSEGV */
  336. }
  337. extern VOID
  338. error DECL1C(char *, message)
  339. {
  340. const char *env;
  341. alarm(180); setcurrenttime();
  342. env = getenv("DOCUMENT_ARGUMENTS");
  343. fprintf(stderr, "[%s] httpd(pid %ld): %s [from: `%s' req: `%s' params: `%s' referer: `%s']n",
  344. currenttime, (long)getpid(), message,
  345. remotehost[0] ? remotehost : "(none)",
  346. orig[0] ? orig : "(none)", env ? env : "(none)",
  347. referer[0] ? referer : "(none)");
  348. if (headers)
  349. {
  350. printf("%s %srn", version, message);
  351. stdheaders(1, 1, 1);
  352. }
  353. if (!headonly)
  354. {
  355. printf("rn<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY>n",
  356. message);
  357. printf("<H1>%s</H1></BODY></HTML>n", message);
  358. }
  359. fflush(stdout); fflush(stderr); alarm(0);
  360. }
  361. extern VOID
  362. redirect DECL2C_(char *, redir, int, permanent)
  363. {
  364. const char *env;
  365. env = getenv("DOCUMENT_ARGUMENTS");
  366. if (headers)
  367. {
  368. printf("%s %s movedrnLocation: %srn", version,
  369. permanent ? "301 Permanently" : "302 Temporarily",
  370. redir);
  371. stdheaders(1, 1, 1);
  372. }
  373. if (!headonly)
  374. {
  375. printf("rn<HTML><HEAD><TITLE>Document has moved</TITLE></HEAD>");
  376. printf("<BODY>n<H1>Document has moved</H1>This document has ");
  377. printf("%smoved to <A HREF="%s%s%s">%s</A>.</BODY></HTML>n",
  378. permanent ? "permanently " : "", redir,
  379. env ? "?" : "", env ? env : "", redir);
  380. }
  381. fflush(stdout);
  382. }
  383. static int
  384. hexdigit DECL1(int, ch)
  385. {
  386. const char *temp, *hexdigits = "0123456789ABCDEF";
  387. if ((temp = strchr(hexdigits, toupper(ch))))
  388. return(temp - hexdigits);
  389. else
  390. {
  391. error("500 Invalid `percent' parameters");
  392. return(-1);
  393. }
  394. }
  395. static int
  396. decode DECL1(char *, str)
  397. {
  398. char *posd, chr;
  399. const char *poss;
  400. int top, bottom;
  401. poss = posd = str;
  402. while ((chr = *poss))
  403. {
  404. if (chr != '%')
  405. {
  406. if (chr == '?')
  407. {
  408. bcopy(poss, posd, strlen(poss) + 1);
  409. return(ERR_NONE);
  410. }
  411. *(posd++) = chr;
  412. poss++;
  413. } else
  414. {
  415. if ((top = hexdigit((int)poss[1])) == -1)
  416. return(ERR_QUIT);
  417. if ((bottom = hexdigit((int)poss[2])) == -1)
  418. return(ERR_QUIT);
  419. *(posd++) = (top << 4) + bottom;
  420. poss += 3;
  421. }
  422. }
  423. *posd = 0;
  424. return(ERR_NONE);
  425. }
  426. static VOID
  427. uudecode DECL1(char *, buffer)
  428. {
  429. unsigned char pr2six[256], bufplain[32], *bufout = bufplain;
  430. int nbytesdecoded, j, nprbytes;
  431. char *bufin = buffer;
  432. for (j = 0; j < 256; j++)
  433. pr2six[j] = 64;
  434. for (j = 0; j < 64; j++)
  435. pr2six[(int)six2pr[j]] = (unsigned char)j;
  436. bufin = buffer;
  437. while (pr2six[(int)*(bufin++)] <= 63)
  438. /* NOTHING HERE */;
  439. nprbytes = bufin - buffer - 1;
  440. nbytesdecoded = ((nprbytes + 3) / 4) * 3;
  441. bufin = buffer;
  442. while (nprbytes > 0)
  443. {
  444. *(bufout++) = (unsigned char) ((pr2six[(int)*bufin] << 2) |
  445. (pr2six[(int)bufin[1]] >> 4));
  446. *(bufout++) = (unsigned char) ((pr2six[(int)bufin[1]] << 4) |
  447. (pr2six[(int)bufin[2]] >> 2));
  448. *(bufout++) = (unsigned char) ((pr2six[(int)bufin[2]] << 6) |
  449. (pr2six[(int)bufin[3]]));
  450. bufin += 4; nprbytes -= 4;
  451. }
  452.    
  453. if (nprbytes & 3)
  454. {
  455. if (pr2six[(int)*(bufin - 2)] > 63)
  456. nbytesdecoded -= 2;
  457. else
  458. nbytesdecoded--;
  459. }
  460. if (nbytesdecoded)
  461. bcopy((char *)bufplain, buffer, nbytesdecoded);
  462. buffer[nbytesdecoded] = 0;
  463. }
  464. extern int
  465. check_auth DECL1(FILE *, authfile)
  466. {
  467. char *search, line[MYBUFSIZ], compare[MYBUFSIZ], *find;
  468. const char *env;
  469. if (!(env = getenv("AUTH_TYPE")))
  470. {
  471. if (headers)
  472. {
  473. printf("%s 401 Unauthorizedrn", version);
  474. printf("WWW-authenticate: basic realm="this page"rn");
  475. stdheaders(1, 1, 1);
  476. }
  477. printf("rn<HTML><HEAD><TITLE>Unauthorized</TITLE></HEAD>n");
  478. printf("<BODY><H1>Unauthorized</H1>nYour client does not ");
  479. printf("understand authentication.n</BODY></HTML>n");
  480. fclose(authfile); return(1);
  481. }
  482. strncpy(line, env, MYBUFSIZ - 1); line[MYBUFSIZ - 1] = 0;
  483. find = line + strlen(line);
  484. while ((find > line) && (*(find - 1) < ' '))
  485. *(--find) = 0;
  486. for (search = line; *search && (*search != ' ') &&
  487. (*search != 9); search++) ;
  488. while ((*search == 9) || (*search == ' '))
  489. search++;
  490. uudecode(search);
  491. if ((find = strchr(search, ':')))
  492. {
  493. *find = 0;
  494. setenv("REMOTE_USER", search, 1);
  495. *find = ':';
  496. setenv("REMOTE_PASSWORD", find + 1, 1);
  497. xs_encrypt(find + 1);
  498. }
  499. while (fgets(compare, MYBUFSIZ, authfile))
  500. {
  501. compare[strlen(compare) - 1] = 0;
  502. if (!strcmp(compare + 1, search))
  503. {
  504. fclose(authfile); return(0);
  505. }
  506. }
  507. fclose(authfile);
  508. server_error("401 Wrong user/password combination", "UNAUTHORIZED");
  509. return(1);
  510. }
  511. extern char *
  512. escape DECL1C(char *, what)
  513. {
  514. char *escapebuf, *w;
  515. if (!(w = escapebuf = (char *)malloc(BUFSIZ)))
  516. return(NULL);
  517. while (*what && ((w - escapebuf) < (BUFSIZ - 10)))
  518. {
  519. switch(*what)
  520. {
  521. case '<':
  522. strcpy(w, "&lt;"); w += 4;
  523. break;
  524. case '>':
  525. strcpy(w, "&gt;"); w += 4;
  526. break;
  527. case '&':
  528. strcpy(w, "&amp;"); w += 5;
  529. break;
  530. case '"':
  531. strcpy(w, "&quot;"); w += 6;
  532. break;
  533. default:
  534. *(w++) = *what;
  535. break;
  536. }
  537. what++;
  538. }
  539. *w = 0;
  540. return(escapebuf);
  541. }
  542. extern VOID
  543. server_error DECL2CC(char *, readable, char *, cgi)
  544. {
  545. struct stat statbuf;
  546. const struct passwd *userinfo;
  547. char *search, cgipath[XS_PATH_MAX], base[XS_PATH_MAX],
  548. *escaped;
  549. const char *env;
  550. if (headonly)
  551. {
  552. error(readable);
  553. return;
  554. }
  555. setenv("ERROR_CODE", cgi, 1);
  556. setenv("ERROR_READABLE", readable, 1);
  557. setenv("ERROR_URL", orig, 1);
  558. setenv("ERROR_URL_EXPANDED", convertpath(orig), 1);
  559. escaped = escape(orig);
  560. setenv("ERROR_URL_ESCAPED", escaped ? escaped : "", 1);
  561. if (escaped)
  562. free(escaped);
  563. env = getenv("DOCUMENT_ARGUMENTS");
  564. if (real_path[1] == '~')
  565. {
  566. if ((search = strchr(real_path + 2, '/')))
  567. *search = 0;
  568. if ((userinfo = getpwnam(real_path + 2)))
  569. {
  570. if (search)
  571. *search = '/';
  572. if (!transform_user_dir(base, userinfo, 0))
  573. {
  574. sprintf(cgipath, "%s/%s/error",
  575. base, HTTPD_SCRIPT_ROOT);
  576. if (!stat(cgipath, &statbuf))
  577. {
  578. sprintf(cgipath, "/~%s/%s/error",
  579. userinfo->pw_name,
  580. HTTPD_SCRIPT_ROOT);
  581. goto EXECUTE;
  582. }
  583. }
  584. }
  585. if (search)
  586. *search = '/';
  587. }
  588. strcpy(base, calcpath(HTTPD_SCRIPT_ROOT_P));
  589. sprintf(cgipath, "%s/error", base);
  590. if (stat(cgipath, &statbuf))
  591. error(readable);
  592. else
  593. {
  594. sprintf(cgipath, "/%s/error", HTTPD_SCRIPT_ROOT);
  595. EXECUTE:
  596. setcurrenttime();
  597. fprintf(stderr, "[%s] httpd(pid %ld): %s [from: `%s' req: `%s' params: `%s' referer: `%s']n",
  598. currenttime, (long)getpid(), readable,
  599. remotehost[0] ? remotehost : "(none)",
  600. orig[0] ? orig : "(none)", env ? env : "(none)",
  601. referer[0] ? referer : "(none)");
  602. do_script(cgipath, headers);
  603. }
  604. }
  605. extern int
  606. readline DECL2(int, sd, char *, buf)
  607. {
  608. char ch, *buf2;
  609. buf2 = buf; *buf2 = 0;
  610. do
  611. {
  612. if (netbufind >= netbufsiz)
  613. {
  614. TRYAGAIN:
  615. netbufsiz = read(sd, netbuf,
  616. readlinemode ? MYBUFSIZ : 1);
  617. if (netbufsiz == -1)
  618. {
  619. if ((errno == EAGAIN) || (errno == EINTR))
  620. {
  621. mysleep(1); goto TRYAGAIN;
  622. }
  623. fprintf(stderr, "[%s] httpd: readline(): %sn",
  624. currenttime, strerror(errno));
  625. if (sd == 0)
  626. error("503 Unexpected network error");
  627. return(ERR_QUIT);
  628. }
  629. if (netbufsiz == 0)
  630. {
  631. if (*buf)
  632. {
  633. *buf2 = 0;
  634. return(ERR_NONE);
  635. }
  636. if (sd == 0)
  637. error("503 You closed the connection!");
  638. return(ERR_QUIT);
  639. }
  640. netbufind = 0;
  641. }
  642. ch = *(buf2++) = netbuf[netbufind++];
  643. } while ((ch != 'n') && (buf2 < (buf + MYBUFSIZ - 64)));
  644. *buf2 = 0;
  645. return(ERR_NONE);
  646. }
  647. static VOID
  648. process_request DECL0
  649. {
  650. char line[MYBUFSIZ], extra[MYBUFSIZ], *temp,
  651. *params, *url, *ver;
  652. int index, readerror;
  653. size_t size;
  654. strcpy(version, "HTTP/0.9");
  655. strcpy(dateformat, "%a %b %e %H:%M:%S %Y");
  656. total[0] = orig[0] = name[0] = referer[0] = line[0] =
  657. real_path[0] = browser[0] = 0;
  658. netbufsiz = netbufind = headonly = postonly = headers = index = 0;
  659. unsetenv("CONTENT_LENGTH"); unsetenv("AUTH_TYPE");
  660. unsetenv("CONTENT_TYPE"); unsetenv("DOCUMENT_ARGUMENTS");
  661. unsetenv("ERROR_CODE"); unsetenv("ERROR_READABLE");
  662. unsetenv("ERROR_URL"); unsetenv("ERROR_URL_ESCAPED");
  663. unsetenv("ERROR_URL_EXPANDED"); unsetenv("REMOTE_USER");
  664. unsetenv("REMOTE_PASSWORD"); unsetenv("HTTP_REFERER");
  665. unsetenv("HTTP_COOKIE");
  666. alarm(180); errno = 0;
  667. readerror = read(0, line, 1);
  668. if (readerror == 1)
  669. readerror = read(0, line + 1, 1);
  670. if (readerror == 1)
  671. readerror = read(0, line + 2, 1);
  672. if (readerror == 1)
  673. readerror = read(0, line + 3, 1);
  674. if (readerror != 1)
  675. {
  676. if (readerror == -1)
  677. fprintf(stderr, "[%s] Request line: read() failed: %sn",
  678. currenttime, strerror(errno));
  679. else
  680. fprintf(stderr, "[%s] Request line: read() got no inputn",
  681. currenttime);
  682. error("400 Unable to read begin of request line");
  683. return;
  684. }
  685. readlinemode = strncasecmp("POST", line, 4);
  686. if (readline(0, line + 4) == ERR_QUIT)
  687. {
  688. error("400 Unable to read request line");
  689. return;
  690. }
  691. size = strlen(line);
  692. bzero(line + size, 16);
  693. temp = orig + strlen(orig);
  694. while ((temp > orig) && (*(temp - 1) <= ' '))
  695. *(--temp) = 0;
  696. url = line;
  697. while (*url && (*url > ' '))
  698. url++;
  699. *(url++) = 0;
  700. while (*url <= ' ')
  701. url++;
  702. ver = url;
  703. while (*ver && (*ver > ' '))
  704. ver++;
  705. *(ver++) = 0;
  706. while (*ver <= ' ')
  707. ver++;
  708. temp = ver;
  709. while (*temp && (*temp > ' '))
  710. temp++;
  711. *temp = 0;
  712. if (!strncasecmp(ver, "HTTP/", 5))
  713. {
  714. headers = 1; strcpy(version, "HTTP/1.0");
  715. setenv("SERVER_PROTOCOL", version, 1);
  716. while (1)
  717. {
  718. char *param;
  719. if (readline(0, extra) == ERR_QUIT)
  720. {
  721. error("400 Unable to read HTTP headers");
  722. return;
  723. }
  724. if (extra[0] <= ' ')
  725. break;
  726. if (!(param = strchr(extra, ':')))
  727. continue;
  728. *(param++) = 0;
  729. while ((*param == ' ') || (*param == 9))
  730. param++;
  731. if (!strcasecmp("Content-length", extra))
  732. setenv("CONTENT_LENGTH", param, 1);
  733. else if (!strcasecmp("Content-type", extra))
  734. setenv("CONTENT_TYPE", param, 1);
  735. else if (!strcasecmp("User-agent", extra))
  736. {
  737. strncpy(browser, param, MYBUFSIZ - 1);
  738. browser[MYBUFSIZ - 1] = 0;
  739. setenv("USER_AGENT", browser, 1);
  740. setenv("HTTP_USER_AGENT", browser, 1);
  741. strtok(browser, "/");
  742. for (temp = browser; *temp; temp++)
  743. *temp = tolower(*temp);
  744. *browser = toupper(*browser);
  745. setenv("USER_AGENT_SHORT", browser, 1);
  746. } else if (!strcasecmp("Referer", extra))
  747. {
  748. strncpy(referer, param, MYBUFSIZ-16);
  749. while (referer[0] &&
  750. referer[strlen(referer) - 1] <= ' ')
  751. referer[strlen(referer) - 1] = 0;
  752. setenv("HTTP_REFERER", referer, 1);
  753. } else if (!strcasecmp("Authorization", extra))
  754. setenv("AUTH_TYPE", param, 1);
  755. else if (!strcasecmp("Cookie", extra))
  756. setenv("HTTP_COOKIE", param, 1);
  757. }
  758. } else
  759. setenv("SERVER_PROTOCOL", version, 1);
  760. if (!getenv("CONTENT_LENGTH"))
  761. setenv("CONTENT_LENGTH", "0", 1);
  762. if (!browser[0])
  763. {
  764. setenv("USER_AGENT", "UNKNOWN", 1);
  765. setenv("HTTP_USER_AGENT", "UNKNOWN", 1);
  766. setenv("USER_AGENT_SHORT", "UNKNOWN", 1);
  767. }
  768. alarm(0);
  769. params = url;
  770. if (decode(params))
  771. return;
  772. size = strlen(params);
  773. bzero(params + size, 16);
  774. bcopy(params, orig, size + 16);
  775. if (referer[0] &&
  776. (!thisdomain[0] || !strcasestr(referer, thisdomain)))
  777. fprintf(refer_log, "%s -> %sn", referer, params);
  778. if (params[0] != '/')
  779. {
  780. server_error("400 Relative URL's are not supported",
  781. "NO_RELATIVE_URLS");
  782. return;
  783. }
  784. setenv("REQUEST_METHOD", line, 1);
  785. if (!strcmp("GET", line))
  786. do_get(params);
  787. else if (!strcmp("HEAD", line))
  788. do_head(params);
  789. else if (!strcmp("POST", line))
  790. do_post(params);
  791. else
  792. server_error("400 Unknown method", "UNKNOWN_METHOD");
  793. }
  794. static VOID
  795. standalone_main DECL0
  796. {
  797. int csd = 0, clen, count, temp;
  798. struct sockaddr_in sa_server, sa_client;
  799. const struct hostent *remote;
  800. pid_t *childs, pid;
  801. struct rlimit limit;
  802. /* Speed hack */
  803. gethostbyname("localhost");
  804. detach(); open_logs(0);
  805. setprocname("xs(MAIN): Initializing deamons...");
  806. if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
  807. err(1, "socket()");
  808. temp = 1;
  809. if ((setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(temp))) == -1)
  810. err(1, "setsockopt(REUSEADDR)");
  811. temp = 1;
  812. if ((setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, &temp, sizeof(temp))) == -1)
  813. err(1, "setsockopt(KEEPALIVE)");
  814. memset(&sa_server, 0, sizeof(sa_server));
  815. sa_server.sin_family = AF_INET;
  816. sa_server.sin_addr = thisaddress;
  817. sa_server.sin_port = htons(port);
  818. if (bind(sd, (struct sockaddr *)&sa_server, sizeof(sa_server)) == -1)
  819. err(1, "bind()");
  820. if (listen(sd, MAXLISTEN))
  821. err(1, "listen()");
  822. #ifdef RLIMIT_NPROC
  823. limit.rlim_max = limit.rlim_cur = RLIM_INFINITY;
  824. setrlimit(RLIMIT_NPROC, &limit);
  825. #endif /* RLIMIT_NPROC */
  826. #ifdef RLIMIT_CPU
  827. limit.rlim_max = limit.rlim_cur = RLIM_INFINITY;
  828. setrlimit(RLIMIT_CPU, &limit);
  829. #endif /* RLIMIT_CPU */
  830. set_signals(); reqs = 0;
  831. if (!(childs = (pid_t *)malloc(sizeof(pid_t) * number)))
  832. errx(1, "malloc() failed");
  833. for (count = 0; count < number; count++)
  834. {
  835. switch(pid = fork())
  836. {
  837. case -1:
  838. warn("fork() failed");
  839. killpg(0, SIGTERM);
  840. exit(1);
  841. case 0:
  842. mainhttpd = 0;
  843. goto CHILD;
  844. default:
  845. childs[count] = pid;
  846. }
  847. }
  848. fflush(stdout);
  849. while (1)
  850. {
  851. setprocname("xs(MAIN): Waiting for dead children");
  852. while (mysleep(30))
  853. /* NOTHING HERE */;
  854. setprocname("xs(MAIN): Searching for dead children");
  855. for (count = 0; count < number; count++)
  856. {
  857. if (kill(childs[count], 0))
  858. {
  859. fflush(stdout);
  860. switch(pid = fork())
  861. {
  862. case -1:
  863. fprintf(stderr,
  864. "[%s] httpd: fork() failed: %sn",
  865. currenttime, strerror(errno));
  866. break;
  867. case 0:
  868. mainhttpd = 0;
  869. goto CHILD;
  870. default:
  871. childs[count] = pid;
  872. }
  873. }
  874. }
  875. }
  876. CHILD:
  877. #ifndef SETVBUF_REVERSED
  878. setvbuf(stdout, outputbuffer, _IOFBF, SENDBUFSIZE);
  879. #else /* Not not SETVBUF_REVERSED */
  880. setvbuf(stdout, _IOFBF, outputbuffer, SENDBUFSIZE);
  881. #endif /* SETVBUF_REVERSED */
  882. while (1)
  883. {
  884. struct linger sl;
  885. setprocname("xs(%d): [Reqs: %06d] Setting up myself to accept a connection",
  886. count + 1, reqs);
  887. if (!origeuid && (seteuid(origeuid) == -1))
  888. err(1, "seteuid(%ld) failed", (long)origeuid);
  889. if (!origeuid && (setegid(origegid) == -1))
  890. err(1, "setegid(%ld) failed", (long)origegid);
  891. filedescrs(); clen = sizeof(sa_client);
  892. setprocname("xs(%d): [Reqs: %06d] Waiting for a connection...",
  893. count + 1, reqs);
  894. csd = accept(sd, (struct sockaddr *)&sa_client, &clen);
  895. if (csd < 0)
  896. {
  897. if (errno == EINTR)
  898. child_handler(SIGCHLD);
  899. continue;
  900. }
  901. setprocname("xs(%d): [Reqs: %06d] accept() gave me a connection...",
  902. count + 1, reqs);
  903. if (fcntl(csd, F_SETFL, 0))
  904. warn("fcntl() in standalone_main");
  905. sl.l_onoff = 1; sl.l_linger = 600;
  906. setsockopt(csd, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl));
  907. #ifdef SO_SNDBUF
  908. temp = SENDBUFSIZE + 64;
  909. setsockopt(csd, SOL_SOCKET, SO_SNDBUF, &temp, sizeof(temp));
  910. #endif /* SO_SNDBUF */
  911. #ifdef SO_RCVBUF
  912. temp = 512;
  913. setsockopt(csd, SOL_SOCKET, SO_RCVBUF, &temp, sizeof(temp));
  914. #endif /* SO_RCVBUF */
  915. dup2(csd, 0); dup2(csd, 1); close(csd);
  916. #ifndef SETVBUF_REVERSED
  917. setvbuf(stdin, NULL, _IONBF, 0);
  918. #else /* Not not SETVBUF_REVERSED */
  919. setvbuf(stdin, _IONBF, NULL, 0);
  920. #endif /* SETVBUF_REVERSED */
  921. if ((remote = gethostbyaddr((char *)&sa_client.sin_addr,
  922. sizeof(struct in_addr), sa_client.sin_family)))
  923. {
  924. strcpy(remotehost, remote->h_name);
  925. setenv("REMOTE_HOST", remotehost, 1);
  926. } else
  927. {
  928. strcpy(remotehost, inet_ntoa(sa_client.sin_addr));
  929. unsetenv("REMOTE_HOST");
  930. }
  931. setenv("REMOTE_ADDR", inet_ntoa(sa_client.sin_addr), 1);
  932. setprocname("xs(%d): Connect from `%s'", count + 1, remotehost);
  933. setcurrenttime();
  934. if (message503[0])
  935. {
  936. alarm(180);
  937. printf("HTTP/1.0 503 BusyrnContent-type: text/plainrnrn");
  938. printf("%sn", message503);
  939. } else
  940. process_request();
  941. alarm(0); reqs++;
  942. fflush(stdout); fflush(stdin); fflush(stderr);
  943. }
  944. /* NOTREACHED */
  945. }
  946. static VOID
  947. setup_environment DECL0
  948. {
  949. char buffer[16];
  950. setenv("SERVER_SOFTWARE", SERVER_IDENT, 1);
  951. setenv("SERVER_NAME", thishostname, 1);
  952. setenv("GATEWAY_INTERFACE", "CGI/1.1", 1);
  953. sprintf(buffer, "%d", port);
  954. setenv("SERVER_PORT", buffer, 1);
  955. sprintf(buffer, "%d", localmode);
  956. setenv("LOCALMODE", buffer, 1);
  957. setenv("HTTPD_ROOT", rootdir, 1);
  958. }
  959. int
  960. main DECL3(int, argc, char **, argv, char **, envp)
  961. {
  962. const struct passwd *userinfo;
  963. const struct group *groupinfo;
  964. int option, num;
  965. const struct hostent *hp;
  966. origeuid = geteuid(); origegid = getegid();
  967. #ifdef HAVE_SETPRIORITY
  968. if (setpriority(PRIO_PROCESS, (pid_t)0, PRIO_MAX))
  969. warn("setpriority");
  970. #endif /* HAVE_SETPRIORITY */
  971. for (num = option = 0; option < argc; option++)
  972. num += (1 + strlen(argv[option]));
  973. if (!(startparams = (char *)malloc(num)))
  974. errx(1, "Cannot malloc memory for startparams");
  975. *startparams = 0;
  976. for (option = 0; option < argc; option++)
  977. {
  978. strcat(startparams, argv[option]);
  979. if (option < argc - 1)
  980. strcat(startparams, " ");
  981. }
  982. port = 80; number = HTTPD_NUMBER; localmode = 1;
  983. strcpy(rootdir, HTTPD_ROOT); message503[0] = 0;
  984. #ifdef THISDOMAIN
  985. strcpy(thisdomain, THISDOMAIN);
  986. #else /* Not THISDOMAIN */
  987. thisdomain[0] = 0;
  988. #endif /* THISDOMAIN */
  989. thisaddress.s_addr = htonl(INADDR_ANY);
  990. if (gethostname(thishostname, MAXHOSTNAMELEN) == -1)
  991. errx(1, "gethostname() failed");
  992. if ((userinfo = getpwnam(HTTPD_USERID)))
  993. user_id = userinfo->pw_uid;
  994. else
  995. user_id = 32767;
  996. if ((groupinfo = getgrnam(HTTPD_GROUPID)))
  997. group_id = groupinfo->gr_gid;
  998. else
  999. group_id = 32766;
  1000. if ((short)user_id == -1)
  1001. err(1, "Check your password file: nobody may not have UID -1 or 65535.");
  1002. if ((short)group_id == -1)
  1003. err(1, "Check your group file: nogroup may not have GID -1 or 65535.");
  1004. sprintf(access_path, "%s/access_log", calcpath(HTTPD_LOG_ROOT));
  1005. sprintf(error_path, "%s/error_log", calcpath(HTTPD_LOG_ROOT));
  1006. sprintf(refer_path, "%s/referer_log", calcpath(HTTPD_LOG_ROOT));
  1007. while ((option = getopt(argc, argv, "a:d:g:l:m:n:p:r:u:A:R:E:")) != EOF)
  1008. {
  1009. switch(option)
  1010. {
  1011. case 'n':
  1012. if ((number = atoi(optarg)) <= 0)
  1013. errx(1, "Invalid number of processes");
  1014. break;
  1015. case 'p':
  1016. if ((port = atoi(optarg)) <= 0)
  1017. errx(1, "Invalid port number");
  1018. break;
  1019. case 'u':
  1020. if ((user_id = atoi(optarg)) > 0)
  1021. break;
  1022. if (!(userinfo = getpwnam(optarg)))
  1023. errx(1, "Invalid user ID");
  1024. user_id = userinfo->pw_uid;
  1025. break;
  1026. case 'g':
  1027. if ((group_id = atoi(optarg)) > 0)
  1028. break;
  1029. if (!(groupinfo = getgrnam(optarg)))
  1030. errx(1, "Invalid group ID");
  1031. group_id = groupinfo->gr_gid;
  1032. break;
  1033. case 'd':
  1034. if (*optarg != '/')
  1035. errx(1, "The -d directory must start with a /");
  1036. strncpy(rootdir, optarg, XS_PATH_MAX-1);
  1037. rootdir[XS_PATH_MAX-1] = 0;
  1038. break;
  1039. case 'a':
  1040. if ((thisaddress.s_addr = inet_addr(optarg)) == -1)
  1041. {
  1042. if ((hp = gethostbyname(optarg)))
  1043. memcpy((char *)&thisaddress,
  1044. hp->h_addr, hp->h_length);
  1045. else
  1046. errx(1, "gethostbyname(`%s') failed",
  1047. optarg);
  1048. }
  1049. strcpy(thishostname, optarg);
  1050. break;
  1051. case 'r':
  1052. strcpy(thisdomain, optarg);
  1053. break;
  1054. case 'l':
  1055. if ((localmode = atoi(optarg)) <= 0)
  1056. errx(1, "Argument to -l is invalid");
  1057. break;
  1058. case 'm':
  1059. strcpy(message503, optarg);
  1060. break;
  1061. case 'A':
  1062. strcpy(access_path, optarg);
  1063. break;
  1064. case 'R':
  1065. strcpy(refer_path, optarg);
  1066. break;
  1067. case 'E':
  1068. strcpy(error_path, optarg);
  1069. break;
  1070. default:
  1071. errx(1, "Usage: httpd [-u username] [-g group] [-p port] [-n number] [-d rootdir]n[-r refer-ignore-domain] [-l localmode] [-a address] [-m service-message]n[-A access-log-path] [-E error-log-path] [-R referer-log-path]");
  1072. }
  1073. }
  1074. initsetprocname(argc, argv, envp);
  1075. setup_environment();
  1076.         standalone_main();
  1077. exit(0);
  1078. }