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

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. /* Global structures */
  82. typedef struct ftypes
  83. {
  84. struct ftypes *next;
  85. char name[32], ext[16];
  86. } ftypes;
  87. #ifdef HANDLE_COMPRESSED
  88. typedef struct ctypes
  89. {
  90. struct ctypes *next;
  91. char prog[XS_PATH_MAX], ext[16];
  92. } ctypes;
  93. #endif /* HANDLE_COMPRESSED */
  94. static ftypes *ftype = NULL;
  95. #ifdef HANDLE_COMPRESSED
  96. static ctypes *ctype = NULL;
  97. #endif /* HANDLE_COMPRESSED */
  98. extern VOID
  99. senduncompressed DECL1(int, fd)
  100. {
  101. #ifdef WANT_SSI
  102. int errval, html;
  103. #endif /* WANT_SSI */
  104. #ifndef HAVE_MMAP
  105. size_t readtotal, writetotal;
  106. #endif /* HAVE_MMAP */
  107. size_t size, written;
  108. char modified[32];
  109. alarm(180);
  110. if ((size = lseek(fd, 0, SEEK_END)) == -1)
  111. {
  112. error("500 Cannot lseek() to end of file");
  113. return;
  114. }
  115. if (lseek(fd, 0, SEEK_SET))
  116. {
  117. error("500 Cannot lseek() to beginning of file");
  118. return;
  119. }
  120. if (headers)
  121. {
  122. printf("%s 200 OKrn", version);
  123. stdheaders(0, 0, 0);
  124. #ifndef WANT_SSI
  125. getfiletype(1);
  126. printf("Content-length: %ldrn", (long)size);
  127. #else /* Not WANT_SSI */
  128. html = getfiletype(1);
  129. if (!html)
  130. printf("Content-length: %ldrn", (long)size);
  131. #endif /* WANT_SSI */
  132. strftime(modified, sizeof(modified),
  133. "%a, %d %b %Y %T GMT", gmtime(&modtime));
  134. printf("Last-modified: %srnrn", modified);
  135. }
  136. #ifdef WANT_SSI
  137. else
  138. {
  139. html = getfiletype(0);
  140. if (html)
  141. printf("rn");
  142. }
  143. #endif /* WANT_SSI */
  144. if (headonly)
  145. goto DONE;
  146. UNPARSED:
  147. #ifdef WANT_SSI
  148. if (!html)
  149. #endif /* WANT_SSI */
  150. #ifdef HAVE_MMAP
  151. {
  152. char *buffer;
  153. if ((buffer = (char *)mmap((caddr_t)0, size, PROT_READ,
  154. MAP_SHARED, fd, 0)) == (char *)-1)
  155. {
  156. fprintf(stderr, "[%s] httpd: mmap() failed: %sn",
  157. currenttime, strerror(errno));
  158. exit(1);
  159. }
  160. alarm((size / MINBYTESPERSEC) + 20);
  161. fflush(stdout);
  162. if ((written = write(fileno(stdout), buffer, size)) != size)
  163. {
  164. if (written != -1)
  165. fprintf(stderr, "[%s] httpd: Aborted for `%s' (%ld of %ld bytes sent)n",
  166. currenttime,
  167. remotehost[0] ? remotehost : "(none)",
  168. (long)written, (long)size);
  169. else
  170. fprintf(stderr, "[%s] httpd: Aborted for `%s'n",
  171. currenttime,
  172. remotehost[0] ? remotehost : "(none)");
  173. }
  174. munmap(buffer, size); size = written;
  175. alarm(0);
  176. }
  177. #else /* Not HAVE_MMAP */
  178. {
  179. char buffer[SENDBUFSIZE];
  180. writetotal = 0;
  181. alarm((size / MINBYTESPERSEC) + 20);
  182. fflush(stdout);
  183. while ((readtotal = read(fd, buffer, SENDBUFSIZE)) > 0)
  184. {
  185. if ((written = write(fileno(stdout), buffer,
  186. readtotal)) != readtotal)
  187. {
  188. fprintf(stderr,
  189. "[%s] httpd: Aborted for `%s' (No mmap) (%ld of %ld bytes sent)n",
  190. currenttime,
  191. remotehost[0] ? remotehost : "(none)",
  192. writetotal + written, size);
  193. size = writetotal;
  194. alarm(0); goto DONE;
  195. }
  196. writetotal += written;
  197. }
  198. size = writetotal;
  199. alarm(0);
  200. }
  201. #endif /* HAVE_MMAP */
  202. #ifdef WANT_SSI
  203. else
  204. {
  205. size = 0;
  206. alarm((size / MINBYTESPERSEC) + 60);
  207. errval = sendwithdirectives(fd, &size);
  208. close(fd);
  209. switch(errval)
  210. {
  211. case ERR_QUIT:
  212. fprintf(stderr, "[%s] httpd: Aborted for `%s' (ERR_QUIT)n",
  213. currenttime,
  214. remotehost[0] ? remotehost : "(none)");
  215. break;
  216. case ERR_CONT:
  217. html = 0; goto UNPARSED;
  218. default:
  219. break;
  220. }
  221. }
  222. #endif /* WANT_SSI */
  223. DONE:
  224. {
  225. char buffer[80];
  226. time_t theclock;
  227. time(&theclock);
  228. strftime(buffer, 80, "%d/%b/%Y:%H:%M:%S", localtime(&theclock));
  229. fprintf(access_log, "%s - - [%s +0000] "%s %s %s" 200 %ldn",
  230. remotehost, buffer, headonly ? "HEAD" : "GET", real_path,
  231. version, size > 0 ? (long)size : (long)0);
  232. }
  233. close(fd);
  234. }
  235. #ifdef HANDLE_COMPRESSED
  236. extern VOID
  237. sendcompressed DECL2_C(int, fd, char *, method)
  238. {
  239. pid_t pid;
  240. int count, processed;
  241. char *tmp;
  242. #ifdef HAVE_TEMPNAM
  243. if (!(tmp = tempnam(TEMPORARYPATH, "xs-www")))
  244. #endif /* HAVE_TEMPNAM */
  245. {
  246. if (!(tmp = (char *)malloc(32 + strlen(TEMPORARYPATH))))
  247. {
  248. error("500 Out of memory in sendcompressed()");
  249. close(fd); return;
  250. }
  251. sprintf(tmp, "%s/.xs-www.%016ld",
  252. TEMPORARYPATH, (long)getpid());
  253. }
  254. remove(tmp);
  255. if ((processed = open(tmp, O_CREAT | O_TRUNC | O_RDWR | O_EXCL,
  256. S_IWUSR | S_IRUSR )) < 0)
  257. {
  258. fprintf(stderr, "[%s] httpd: Cannot open(`%s'): %sn",
  259. currenttime, tmp, strerror(errno));
  260. error("500 Unable to open temporary file");
  261. exit(1);
  262. }
  263. remove(tmp); free(tmp); fflush(stdout);
  264. switch(pid = fork())
  265. {
  266. case -1:
  267. fprintf(stderr, "[%s] httpd: Cannot fork(): %sn",
  268. currenttime, strerror(errno));
  269. error("500 Cannot fork() in sendcompressed()");
  270. close(fd); close(processed); return;
  271. case 0:
  272. #ifdef HAVE_SETSID
  273. if (setsid() == -1)
  274. {
  275. error("500 setsid() failed");
  276. exit(1);
  277. }
  278. #else /* Not HAVE_SETSID */
  279. if (setpgrp(getpid(), 0)) == -1)
  280. {
  281. error("500 setpgrp() failed");
  282. exit(1);
  283. }
  284. #endif /* HAVE_SETSID */
  285. dup2(fd, 0); dup2(processed, 1);
  286. for (count = 3; count < 64; count++)
  287. close(count);
  288. execl(method, method, NULL);
  289. fprintf(stderr, "[%s] httpd: Cannot execl(`%s'): %sn",
  290. currenttime, method, strerror(errno));
  291. error("500 Cannot start conversion program");
  292. exit(1);
  293. default:
  294. close(fd);
  295. if (!kill(pid, 0) && mysleep(180))
  296. {
  297. close(processed);
  298. killpg(pid, SIGTERM);
  299. mysleep(3);
  300. killpg(pid, SIGKILL);
  301. error("500 Conversion program timed out");
  302. return;
  303. }
  304. if (!kill(pid, 0))
  305. {
  306. close(processed);
  307. killpg(pid, SIGKILL);
  308. error("500 Interrupted during conversion");
  309. return;
  310. }
  311. }
  312. senduncompressed(processed);
  313. }
  314. #endif /* HANDLE_COMPRESSED */
  315. extern VOID
  316. do_get DECL1(char *, params)
  317. {
  318. char *temp, auth[XS_PATH_MAX], base[XS_PATH_MAX];
  319. const char *file, *question;
  320. int fd, wasdir;
  321. size_t size;
  322. struct stat statbuf;
  323. const struct passwd *userinfo;
  324. FILE *authfile;
  325. #ifdef HANDLE_COMPRESSED
  326. const ctypes *search = NULL;
  327. #endif /* HANDLE_COMPRESSED */
  328. alarm(240);
  329. question = strchr(params, '?');
  330. while ((temp = strstr(params, "//")))
  331. {
  332. if (!question || (temp < question))
  333. bcopy(temp + 1, temp, strlen(temp));
  334. else
  335. break;
  336. }
  337. strcpy(real_path, params);
  338. bzero(params + strlen(params), 16);
  339. setprocname("xs: Handling `%s' from `%s'", real_path, remotehost);
  340. userinfo = NULL;
  341. if (params[1] == '~')
  342. {
  343. if ((temp = strchr(params + 2, '/')))
  344. *temp = 0;
  345. if (!(userinfo = getpwnam(params + 2)))
  346. {
  347. server_error("404 User is unknown", "USER_UNKNOWN");
  348. return;
  349. }
  350. if (transform_user_dir(base, userinfo, 1))
  351. return;
  352. if (!origeuid)
  353. {
  354. setegid(userinfo->pw_gid);
  355. setgroups(1, (gid_t *)&userinfo->pw_gid);
  356. seteuid(userinfo->pw_uid);
  357. }
  358. if (!geteuid())
  359. {
  360. error("500 Effective UID is not valid");
  361. return;
  362. }
  363. if (temp)
  364. {
  365. *temp = '/';
  366. file = temp;
  367. } else
  368. file = params + strlen(params);
  369. } else
  370. {
  371. file = params;
  372. strcpy(base, calcpath(HTTPD_DOCUMENT_ROOT));
  373. strcat(base, "/");
  374. if (!origeuid)
  375. {
  376. setegid(group_id);
  377. setgroups(1, &group_id);
  378. seteuid(user_id);
  379. }
  380. if (!geteuid())
  381. {
  382. error("500 Effective UID is not valid");
  383. return;
  384. }
  385. }
  386. size = strlen(HTTPD_SCRIPT_ROOT);
  387. if (*file && (!strncmp(file + 1, HTTPD_SCRIPT_ROOT, size)) &&
  388. (file[size + 1] == '/'))
  389. {
  390. do_script(params, 1);
  391. return;
  392. }
  393. if (postonly)
  394. {
  395. server_error("403 Cannot use POST method on non-CGI",
  396. "POST_ON_NON_CGI");
  397. return;
  398. }
  399. if ((temp = strchr(file, '?')))
  400. {
  401. *temp = 0;
  402. setenv("DOCUMENT_ARGUMENTS", temp + 1, 1);
  403. if ((temp = strchr(real_path, '?')))
  404. *temp = 0;
  405. }
  406. if (*file)
  407. wasdir = (file[strlen(file) - 1] == '/');
  408. else
  409. wasdir = 0;
  410. if (strstr(file, "..") || strstr(file, "/.x"))
  411. {
  412. server_error("403 Invalid path specified", "INVALID_PATH");
  413. return;
  414. }
  415. /* if (*file == '/')
  416. file++; */
  417. if ((temp = strrchr(file, '/')))
  418. {
  419. *temp = 0;
  420. size = strlen(base);
  421. ((char *)file)[XS_PATH_MAX - (temp - file + 1 + size)] = 0;
  422. strcpy(base + size, file);
  423. strcat(base + size, "/");
  424. file = temp + 1;
  425. }
  426. if ((!*file) && (wasdir))
  427. strcat(real_path, file = INDEX_HTML);
  428. RETRY:
  429. sprintf(total, "%s/.xsuid", base);
  430. if (!stat(total, &statbuf))
  431. {
  432. if (!origeuid)
  433. {
  434. seteuid(origeuid);
  435. setegid(group_id);
  436. setgroups(1, &group_id);
  437. seteuid(user_id);
  438. }
  439. if (!geteuid())
  440. {
  441. error("500 Effective UID is not valid");
  442. return;
  443. }
  444. }
  445. sprintf(total, "%s%s.redir", base, file);
  446. if ((fd = open(total, O_RDONLY, 0)) >= 0)
  447. {
  448. if ((size = read(fd, total, MYBUFSIZ)) <= 0)
  449. {
  450. error("500 Redirection file error");
  451. close(fd); return;
  452. }
  453. total[size] = 0;
  454. strtok(total, "rn"); redirect(total, 0);
  455. close(fd); return;
  456. }
  457. sprintf(total, "%s/.redir", base);
  458. if ((fd = open(total, O_RDONLY, 0)) >= 0)
  459. {
  460. if ((size = read(fd, total, XS_PATH_MAX - strlen(file) - 16)) <= 0)
  461. {
  462. error("500 Directory redirection file error");
  463. close(fd); return;
  464. }
  465. close(fd);
  466. temp = total + size; *temp = 0;
  467. while ((temp > total) && (*(temp - 1) < ' '))
  468. *(--temp) = 0;
  469. strcat(total, file);
  470. strtok(total, "rn"); redirect(total, 0);
  471. return;
  472. }
  473. sprintf(total, "%s/.noxs", base);
  474. if (!stat(total, &statbuf))
  475. {
  476. server_error("403 Directory is not available", "DIR_NOT_AVAIL");
  477. return;
  478. }
  479. #ifdef HANDLE_COMPRESSED
  480. search = NULL;
  481. #endif /* HANDLE_COMPRESSED */
  482. sprintf(total, "%s%s", base, file);
  483. if (stat(total, &statbuf))
  484. #ifdef HANDLE_COMPRESSED
  485. {
  486. search = ctype;
  487. temp = total + strlen(total);
  488. while (search)
  489. {
  490. strcpy(temp, search->ext);
  491. if (!stat(total, &statbuf))
  492. break;
  493. search = search->next;
  494. }
  495. if (!search)
  496. goto NOTFOUND;
  497. }
  498. #else /* Not HANDLE_COMPRESSED */
  499. goto NOTFOUND;
  500. #endif /* HANDLE_COMPRESSED */
  501. if (!S_ISREG(statbuf.st_mode))
  502. {
  503. if (!S_ISDIR(statbuf.st_mode))
  504. {
  505. server_error("403 Not a regular file", "NOT_REGULAR");
  506. return;
  507. }
  508. if (!strcmp(file, INDEX_HTML) || !strcmp(file, INDEX_HTML_2))
  509. {
  510. error("403 The index may not be a directory");
  511. return;
  512. }
  513. if (wasdir)
  514. {
  515. wasdir = 0;
  516. strcat(real_path, file = INDEX_HTML);
  517. goto RETRY;
  518. } else
  519. {
  520. if (port != 80)
  521. sprintf(total, "http://%s:%d%s/",
  522. thishostname, port, orig);
  523. else
  524. sprintf(total, "http://%s%s/",
  525. thishostname, orig);
  526. redirect(total, 1);
  527. return;
  528. }
  529. }
  530. sprintf(auth, "%s/%s", base, AUTHFILE);
  531. if ((authfile = fopen(auth, "r")))
  532. {
  533. if (check_auth(authfile))
  534. return;
  535. }
  536. modtime = statbuf.st_mtime;
  537. if ((fd = open(total, O_RDONLY, 0)) < 0)
  538. {
  539. server_error("403 File permissions deny access", "PERMISSION");
  540. return;
  541. }
  542. strcpy(name, file);
  543. #ifdef HANDLE_COMPRESSED
  544. if (search)
  545. sendcompressed(fd, search->prog);
  546. else
  547. #endif /* HANDLE_COMPRESSED */
  548. senduncompressed(fd);
  549. return;
  550. NOTFOUND:
  551. if (!strcmp(file, INDEX_HTML) && strcmp(INDEX_HTML, INDEX_HTML_2))
  552. {
  553. strcpy(real_path + strlen(real_path) - strlen(INDEX_HTML),
  554. file = INDEX_HTML_2);
  555. wasdir = 0;
  556. goto RETRY;
  557. }
  558. server_error("404 Requested URL not found", "NOT_FOUND");
  559. }
  560. extern VOID
  561. do_post DECL1(char *, params)
  562. {
  563. postonly = 1;
  564. do_get(params);
  565. }
  566. extern VOID
  567. do_head DECL1(char *, params)
  568. {
  569. headonly = 1;
  570. do_get(params);
  571. }
  572. extern VOID
  573. loadfiletypes DECL0
  574. {
  575. char line[MYBUFSIZ], *end, *comment;
  576. const char *mimepath;
  577. FILE *mime;
  578. ftypes *prev, *new;
  579. while (ftype)
  580. {
  581. new = ftype->next;
  582. free(ftype); ftype = new;
  583. }
  584. mimepath = calcpath(MIMETYPESFILE);
  585. if (!(mime = fopen(mimepath, "r")))
  586. err(1, "fopen(`%s' [read])", mimepath);
  587. prev = NULL;
  588. while (fgets(line, MYBUFSIZ, mime))
  589. {
  590. if ((comment = strchr(line, '#')))
  591. *comment = 0;
  592. end = line + strlen(line);
  593. while ((end > line) && (*(end - 1) <= ' '))
  594. *(--end) = 0;
  595. if (end == line)
  596. continue;
  597. if (!(new = (ftypes *)malloc(sizeof(ftypes))))
  598. errx(1, "Out of memory in loadfiletypes()");
  599. if (prev)
  600. prev->next = new;
  601. else
  602. ftype = new;
  603. prev = new; new->next = NULL;
  604. if (sscanf(line, "%s %s", new->name, new->ext) != 2)
  605. errx(1, "Unable to parse line `%s' in `%s'",
  606. line, mimepath);
  607. }
  608. fclose(mime);
  609. }
  610. #ifdef HANDLE_COMPRESSED
  611. extern VOID
  612. loadcompresstypes DECL0
  613. {
  614. char line[MYBUFSIZ], *end, *comment;
  615. const char *path;
  616. FILE *methods;
  617. ctypes *prev, *new;
  618. while (ctype)
  619. {
  620. new = ctype->next;
  621. free(ctype); ctype = new;
  622. }
  623. path = calcpath(COMPRESS_METHODS);
  624. if (!(methods = fopen(path, "r")))
  625. err(1, "fopen(`%s' [read])", path);
  626. prev = NULL;
  627. while (fgets(line, MYBUFSIZ, methods))
  628. {
  629. if ((comment = strchr(line, '#')))
  630. *comment = 0;
  631. end = line + strlen(line);
  632. while ((end > line) && (*(end - 1) <= ' '))
  633. *(--end) = 0;
  634. if (line == end)
  635. continue;
  636. if (!(new = (ctypes *)malloc(sizeof(ctypes))))
  637. errx(1, "Out of memory in loadcompresstypes()");
  638. if (prev)
  639. prev->next = new;
  640. else
  641. ctype = new;
  642. prev = new; new->next = NULL;
  643. if (sscanf(line, "%s %s", new->prog, new->ext) != 2)
  644. errx(1, "Unable to parse `%s' in `%s'", line, path);
  645. }
  646. fclose(methods);
  647. }
  648. #endif /* HANDLE_COMPRESSED */
  649. extern int
  650. getfiletype DECL1(int, print)
  651. {
  652. const ftypes *search;
  653. const char *ext;
  654. char extension[20];
  655. int count;
  656. if (!(ext = strrchr(name, '.')) || !(*(++ext)))
  657. {
  658. if (print)
  659. printf("Content-type: text/plainrn");
  660. return(0);
  661. }
  662. for (count = 0; ext[count] && (count < 16); count++)
  663. extension[count] = tolower(ext[count]);
  664. extension[count] = 0;
  665. search = ftype;
  666. while (search)
  667. {
  668. if (!strcmp(extension, search->ext))
  669. {
  670. if (print)
  671. printf("Content-type: %srn", search->name);
  672. return(!strcmp(search->name, "text/html"));
  673. }
  674. search = search->next;
  675. }
  676. if (print)
  677. printf("Content-type: application/octet-streamrn");
  678. return(0);
  679. }