aboutsummaryrefslogtreecommitdiff
path: root/networking/httpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/httpd.c')
-rw-r--r--networking/httpd.c297
1 files changed, 292 insertions, 5 deletions
diff --git a/networking/httpd.c b/networking/httpd.c
index ddcb03bca..1dae602ee 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -264,7 +264,12 @@
264//kbuild:lib-$(CONFIG_HTTPD) += httpd.o 264//kbuild:lib-$(CONFIG_HTTPD) += httpd.o
265 265
266//usage:#define httpd_trivial_usage 266//usage:#define httpd_trivial_usage
267//usage: IF_NOT_PLATFORM_MINGW32(
267//usage: "[-ifv[v]]" 268//usage: "[-ifv[v]]"
269//usage: )
270//usage: IF_PLATFORM_MINGW32(
271//usage: "[-fv[v]]"
272//usage: )
268//usage: " [-c CONFFILE]" 273//usage: " [-c CONFFILE]"
269//usage: " [-p [IP:]PORT]" 274//usage: " [-p [IP:]PORT]"
270//usage: IF_FEATURE_HTTPD_SETUID(" [-u USER[:GRP]]") 275//usage: IF_FEATURE_HTTPD_SETUID(" [-u USER[:GRP]]")
@@ -273,7 +278,9 @@
273//usage: "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING" 278//usage: "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING"
274//usage:#define httpd_full_usage "\n\n" 279//usage:#define httpd_full_usage "\n\n"
275//usage: "Listen for incoming HTTP requests\n" 280//usage: "Listen for incoming HTTP requests\n"
281//usage: IF_NOT_PLATFORM_MINGW32(
276//usage: "\n -i Inetd mode" 282//usage: "\n -i Inetd mode"
283//usage: )
277//usage: "\n -f Run in foreground" 284//usage: "\n -f Run in foreground"
278//usage: "\n -v[v] Verbose" 285//usage: "\n -v[v] Verbose"
279//usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:"STR(CONFIG_FEATURE_HTTPD_PORT_DEFAULT)")" 286//usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:"STR(CONFIG_FEATURE_HTTPD_PORT_DEFAULT)")"
@@ -292,6 +299,9 @@
292 299
293#include "libbb.h" 300#include "libbb.h"
294#include "common_bufsiz.h" 301#include "common_bufsiz.h"
302#if ENABLE_PLATFORM_MINGW32
303# include "BB_VER.h"
304#endif
295#if ENABLE_PAM 305#if ENABLE_PAM
296/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */ 306/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */
297# undef setlocale 307# undef setlocale
@@ -322,6 +332,8 @@
322 332
323#define HEADER_READ_TIMEOUT 60 333#define HEADER_READ_TIMEOUT 60
324 334
335static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN;
336
325#define STR1(s) #s 337#define STR1(s) #s
326#define STR(s) STR1(s) 338#define STR(s) STR1(s)
327 339
@@ -452,6 +464,13 @@ static const struct {
452 464
453struct globals { 465struct globals {
454 int verbose; /* must be int (used by getopt32) */ 466 int verbose; /* must be int (used by getopt32) */
467#if ENABLE_PLATFORM_MINGW32
468 smallint foreground;
469# if ENABLE_FEATURE_HTTPD_CGI
470 int server_argc;
471 char **server_argv;
472# endif
473#endif
455 smallint flg_deny_all; 474 smallint flg_deny_all;
456#if ENABLE_FEATURE_HTTPD_GZIP 475#if ENABLE_FEATURE_HTTPD_GZIP
457 /* client can handle gzip / we are going to send gzip */ 476 /* client can handle gzip / we are going to send gzip */
@@ -509,6 +528,11 @@ struct globals {
509}; 528};
510#define G (*ptr_to_globals) 529#define G (*ptr_to_globals)
511#define verbose (G.verbose ) 530#define verbose (G.verbose )
531#if ENABLE_PLATFORM_MINGW32
532#define foreground (G.foreground )
533#define server_argc (G.server_argc )
534#define server_argv (G.server_argv )
535#endif
512#define flg_deny_all (G.flg_deny_all ) 536#define flg_deny_all (G.flg_deny_all )
513#if ENABLE_FEATURE_HTTPD_GZIP 537#if ENABLE_FEATURE_HTTPD_GZIP
514# define content_gzip (G.content_gzip ) 538# define content_gzip (G.content_gzip )
@@ -557,7 +581,12 @@ enum {
557} while (0) 581} while (0)
558 582
559 583
584#if !ENABLE_PLATFORM_MINGW32
560#define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1) 585#define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1)
586#else
587/* Not exactly equivalent to strncasecmp(), but OK for its use here */
588#define STRNCASECMP(a, str) (!is_prefixed_with_case((a), (str)))
589#endif
561 590
562/* Prototypes */ 591/* Prototypes */
563enum { 592enum {
@@ -721,8 +750,16 @@ static int parse_conf(const char *path, int flag)
721 750
722 filename = opt_c_configFile; 751 filename = opt_c_configFile;
723 if (flag == SUBDIR_PARSE || filename == NULL) { 752 if (flag == SUBDIR_PARSE || filename == NULL) {
753#if !ENABLE_PLATFORM_MINGW32
724 filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2); 754 filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2);
725 sprintf((char *)filename, "%s/%s", path, HTTPD_CONF); 755 sprintf((char *)filename, "%s/%s", path, HTTPD_CONF);
756#else
757 const char *sd = "";
758 if (root_len(path) == 0 && (path[0] == '/' || path[0] == '\\'))
759 sd = get_system_drive();
760
761 filename = auto_string(xasprintf("%s%s/%s", sd, path, HTTPD_CONF));
762#endif
726 } 763 }
727 764
728 while ((f = fopen_for_read(filename)) == NULL) { 765 while ((f = fopen_for_read(filename)) == NULL) {
@@ -771,6 +808,7 @@ static int parse_conf(const char *path, int flag)
771 * without needless copying, therefore we don't merge 808 * without needless copying, therefore we don't merge
772 * this operation into next while loop. */ 809 * this operation into next while loop. */
773 while ((ch = *p0) != '\0' && ch != '\n' && ch != '#' 810 while ((ch = *p0) != '\0' && ch != '\n' && ch != '#'
811 IF_PLATFORM_MINGW32(&& ch != '\r')
774 && ch != ' ' && ch != '\t' 812 && ch != ' ' && ch != '\t'
775 ) { 813 ) {
776 p0++; 814 p0++;
@@ -778,7 +816,11 @@ static int parse_conf(const char *path, int flag)
778 p = p0; 816 p = p0;
779 /* if we enter this loop, we have some whitespace. 817 /* if we enter this loop, we have some whitespace.
780 * discard it */ 818 * discard it */
819#if !ENABLE_PLATFORM_MINGW32
781 while (ch != '\0' && ch != '\n' && ch != '#') { 820 while (ch != '\0' && ch != '\n' && ch != '#') {
821#else
822 while (ch != '\0' && ch != '\n' && ch != '\r' && ch != '#') {
823#endif
782 if (ch != ' ' && ch != '\t') { 824 if (ch != ' ' && ch != '\t') {
783 *p++ = ch; 825 *p++ = ch;
784 } 826 }
@@ -1311,7 +1353,21 @@ static unsigned get_line(void)
1311 count = 0; 1353 count = 0;
1312 while (1) { 1354 while (1) {
1313 if (hdr_cnt <= 0) { 1355 if (hdr_cnt <= 0) {
1356#if ENABLE_PLATFORM_MINGW32
1357 int nfds = 1;
1358 struct pollfd fds = {STDIN_FILENO, POLLIN, 0};
1359
1360 switch (poll(&fds, nfds, HEADER_READ_TIMEOUT*1000)) {
1361 case 0:
1362 send_REQUEST_TIMEOUT_and_exit(0);
1363 break;
1364 case -1:
1365 bb_simple_perror_msg_and_die("poll");
1366 break;
1367 }
1368#else
1314 alarm(HEADER_READ_TIMEOUT); 1369 alarm(HEADER_READ_TIMEOUT);
1370#endif
1315 hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf); 1371 hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf);
1316 if (hdr_cnt <= 0) 1372 if (hdr_cnt <= 0)
1317 goto ret; 1373 goto ret;
@@ -1523,6 +1579,47 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
1523#endif 1579#endif
1524 1580
1525#if ENABLE_FEATURE_HTTPD_CGI 1581#if ENABLE_FEATURE_HTTPD_CGI
1582# if ENABLE_PLATFORM_MINGW32
1583static void cgi_handler(char **argv)
1584{
1585 struct fd_pair fromCgi; /* CGI -> httpd pipe */
1586 struct fd_pair toCgi; /* httpd -> CGI pipe */
1587
1588 xfunc_error_retval = 242;
1589
1590 if (sscanf(argv[0], "%d:%d:%d:%d", &toCgi.wr, &toCgi.rd,
1591 &fromCgi.wr, &fromCgi.rd) != 4) {
1592 exit(242);
1593 }
1594
1595 /* NB: close _first_, then move fds! */
1596 close(toCgi.wr);
1597 close(fromCgi.rd);
1598 xmove_fd(toCgi.rd, 0); /* replace stdin with the pipe */
1599 xmove_fd(fromCgi.wr, 1); /* replace stdout with the pipe */
1600
1601 if (argv[1][0] && chdir_or_warn(argv[1]) != 0) {
1602 goto error_execing_cgi;
1603 }
1604
1605 /* set argv[0] to name without path */
1606 argv += 2;
1607
1608 /* _NOT_ execvp. We do not search PATH. argv[0] is a filename
1609 * without any dir components and will only match a file
1610 * in the current directory */
1611 if (foreground)
1612 execv(argv[0], argv);
1613 else
1614 httpd_execv_detach(argv[0], argv);
1615 if (verbose)
1616 bb_perror_msg("can't execute '%s'", argv[0]);
1617 error_execing_cgi:
1618 /* send to stdout */
1619 iobuf = xmalloc(IOBUF_SIZE);
1620 send_headers_and_exit(HTTP_NOT_FOUND);
1621}
1622# endif
1526 1623
1527static void setenv1(const char *name, const char *value) 1624static void setenv1(const char *name, const char *value)
1528{ 1625{
@@ -1556,6 +1653,10 @@ static void send_cgi_and_exit(
1556 struct fd_pair toCgi; /* httpd -> CGI pipe */ 1653 struct fd_pair toCgi; /* httpd -> CGI pipe */
1557 char *script, *last_slash; 1654 char *script, *last_slash;
1558 int pid; 1655 int pid;
1656#if ENABLE_PLATFORM_MINGW32
1657 const char *script_dir;
1658 char **argv;
1659#endif
1559 1660
1560 /* Make a copy. NB: caller guarantees: 1661 /* Make a copy. NB: caller guarantees:
1561 * url[0] == '/', url[1] != '/' */ 1662 * url[0] == '/', url[1] != '/' */
@@ -1592,7 +1693,11 @@ static void send_cgi_and_exit(
1592 *script = '\0'; /* cut off /PATH_INFO */ 1693 *script = '\0'; /* cut off /PATH_INFO */
1593 1694
1594 /* SCRIPT_FILENAME is required by PHP in CGI mode */ 1695 /* SCRIPT_FILENAME is required by PHP in CGI mode */
1696#if ENABLE_PLATFORM_MINGW32
1697 if (!is_relative_path(home_httpd)) {
1698#else
1595 if (home_httpd[0] == '/') { 1699 if (home_httpd[0] == '/') {
1700#endif
1596 char *fullpath = concat_path_file(home_httpd, url); 1701 char *fullpath = concat_path_file(home_httpd, url);
1597 setenv1("SCRIPT_FILENAME", fullpath); 1702 setenv1("SCRIPT_FILENAME", fullpath);
1598 } 1703 }
@@ -1642,6 +1747,50 @@ static void send_cgi_and_exit(
1642 xpiped_pair(fromCgi); 1747 xpiped_pair(fromCgi);
1643 xpiped_pair(toCgi); 1748 xpiped_pair(toCgi);
1644 1749
1750#if ENABLE_PLATFORM_MINGW32
1751 /* Find script's dir */
1752 script_dir = "";
1753 script = last_slash;
1754 if (script != url) { /* paranoia */
1755 *script = '\0';
1756 script_dir = url + 1;
1757 }
1758 script++;
1759
1760 argv = xzalloc((server_argc + 9) * sizeof(char *));
1761 argv[0] = (char *)bb_busybox_exec_path;
1762 argv[1] = (char *)"--busybox";
1763 argv[2] = (char *)"-httpd"; // don't daemonise in main()
1764 argv[3] = (char *)"-I0";
1765 memcpy(argv + 4, server_argv, sizeof(*argv) * server_argc);
1766 argv[server_argc + 4] = xasprintf("%d:%d:%d:%d", toCgi.wr, toCgi.rd,
1767 fromCgi.wr, fromCgi.rd);
1768 argv[server_argc + 5] = (char *)script_dir; // script directory
1769 argv[server_argc + 6] = (char *)script; // script name
1770
1771#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
1772 {
1773 char *suffix = strrchr(script, '.');
1774
1775 if (suffix) {
1776 Htaccess *cur;
1777 for (cur = script_i; cur; cur = cur->next) {
1778 if (strcmp(cur->before_colon + 1, suffix) == 0) {
1779 /* found interpreter name */
1780 argv[server_argc + 6] = (char *)cur->after_colon;
1781 argv[server_argc + 7] = (char *)script;
1782 break;
1783 }
1784 }
1785 }
1786 }
1787#endif
1788 /* argv[server_argc + N] = NULL; - xzalloc did it */
1789
1790 pid = foreground ? mingw_spawn(argv) : mingw_spawn_detach(argv);
1791 if (pid == -1)
1792 log_and_exit();
1793#else
1645 pid = vfork(); 1794 pid = vfork();
1646 if (pid < 0) { 1795 if (pid < 0) {
1647 /* TODO: log perror? */ 1796 /* TODO: log perror? */
@@ -1719,6 +1868,7 @@ static void send_cgi_and_exit(
1719 1868
1720 /* Restore variables possibly changed by child */ 1869 /* Restore variables possibly changed by child */
1721 xfunc_error_retval = 0; 1870 xfunc_error_retval = 0;
1871#endif
1722 1872
1723 /* Pump data */ 1873 /* Pump data */
1724 close(fromCgi.wr); 1874 close(fromCgi.wr);
@@ -1770,7 +1920,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
1770 } 1920 }
1771#if ENABLE_FEATURE_HTTPD_ETAG 1921#if ENABLE_FEATURE_HTTPD_ETAG
1772 /* ETag is "hex(last_mod)-hex(file_size)" e.g. "5e132e20-417" */ 1922 /* ETag is "hex(last_mod)-hex(file_size)" e.g. "5e132e20-417" */
1773 sprintf(G.etag, "\"%llx-%llx\"", (unsigned long long)last_mod, (unsigned long long)file_size); 1923 sprintf(G.etag, "\"%"LL_FMT"x-%"LL_FMT"x\"", (unsigned long long)last_mod, (unsigned long long)file_size);
1774 1924
1775 if (G.if_none_match) { 1925 if (G.if_none_match) {
1776 dbg("If-None-Match:'%s' file's ETag:'%s'\n", G.if_none_match, G.etag); 1926 dbg("If-None-Match:'%s' file's ETag:'%s'\n", G.if_none_match, G.etag);
@@ -2025,7 +2175,11 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2025 2175
2026 /* WHY? */ 2176 /* WHY? */
2027 /* If already saw a match, don't accept other different matches */ 2177 /* If already saw a match, don't accept other different matches */
2178#if !ENABLE_PLATFORM_MINGW32
2028 if (prev && strcmp(prev, dir_prefix) != 0) 2179 if (prev && strcmp(prev, dir_prefix) != 0)
2180#else
2181 if (prev && strcasecmp(prev, dir_prefix) != 0)
2182#endif
2029 continue; 2183 continue;
2030 2184
2031 dbg("checkPerm: '%s' ? '%s'\n", dir_prefix, user_and_passwd); 2185 dbg("checkPerm: '%s' ? '%s'\n", dir_prefix, user_and_passwd);
@@ -2033,7 +2187,11 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2033 /* If it's not a prefix match, continue searching */ 2187 /* If it's not a prefix match, continue searching */
2034 len = strlen(dir_prefix); 2188 len = strlen(dir_prefix);
2035 if (len != 1 /* dir_prefix "/" matches all, don't need to check */ 2189 if (len != 1 /* dir_prefix "/" matches all, don't need to check */
2190#if !ENABLE_PLATFORM_MINGW32
2036 && (strncmp(dir_prefix, path, len) != 0 2191 && (strncmp(dir_prefix, path, len) != 0
2192#else
2193 && (strncasecmp(dir_prefix, path, len) != 0
2194#endif
2037 || (path[len] != '/' && path[len] != '\0') 2195 || (path[len] != '/' && path[len] != '\0')
2038 ) 2196 )
2039 ) { 2197 ) {
@@ -2055,6 +2213,7 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2055 goto bad_input; 2213 goto bad_input;
2056 2214
2057 /* compare "user:" */ 2215 /* compare "user:" */
2216# if !ENABLE_PLATFORM_MINGW32
2058 if (cur->after_colon[0] != '*' 2217 if (cur->after_colon[0] != '*'
2059 && strncmp(cur->after_colon, user_and_passwd, 2218 && strncmp(cur->after_colon, user_and_passwd,
2060 colon_after_user - user_and_passwd + 1) != 0 2219 colon_after_user - user_and_passwd + 1) != 0
@@ -2062,11 +2221,20 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2062 continue; 2221 continue;
2063 } 2222 }
2064 /* this cfg entry is '*' or matches username from peer */ 2223 /* this cfg entry is '*' or matches username from peer */
2224# else
2225 if (strncmp(cur->after_colon, user_and_passwd,
2226 colon_after_user - user_and_passwd + 1) != 0
2227 ) {
2228 continue;
2229 }
2230 /* this cfg entry matches username from peer */
2231# endif
2065 2232
2066 passwd = strchr(cur->after_colon, ':'); 2233 passwd = strchr(cur->after_colon, ':');
2067 if (!passwd) 2234 if (!passwd)
2068 goto bad_input; 2235 goto bad_input;
2069 passwd++; 2236 passwd++;
2237# if !ENABLE_PLATFORM_MINGW32
2070 if (passwd[0] == '*') { 2238 if (passwd[0] == '*') {
2071# if ENABLE_PAM 2239# if ENABLE_PAM
2072 struct pam_userinfo userinfo; 2240 struct pam_userinfo userinfo;
@@ -2114,11 +2282,12 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2114 goto check_encrypted; 2282 goto check_encrypted;
2115# endif /* ENABLE_PAM */ 2283# endif /* ENABLE_PAM */
2116 } 2284 }
2285# endif /* !ENABLE_PLATFORM_MINGW32 */
2117 /* Else: passwd is from httpd.conf, it is either plaintext or encrypted */ 2286 /* Else: passwd is from httpd.conf, it is either plaintext or encrypted */
2118 2287
2119 if (passwd[0] == '$' && isdigit(passwd[1])) { 2288 if (passwd[0] == '$' && isdigit(passwd[1])) {
2120 char *encrypted; 2289 char *encrypted;
2121# if !ENABLE_PAM 2290# if !ENABLE_PAM && !ENABLE_PLATFORM_MINGW32
2122 check_encrypted: 2291 check_encrypted:
2123# endif 2292# endif
2124 /* encrypt pwd from peer and check match with local one */ 2293 /* encrypt pwd from peer and check match with local one */
@@ -2167,7 +2336,6 @@ static Htaccess_Proxy *find_proxy_entry(const char *url)
2167/* 2336/*
2168 * Handle timeouts 2337 * Handle timeouts
2169 */ 2338 */
2170static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN;
2171static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM) 2339static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM)
2172{ 2340{
2173 send_headers_and_exit(HTTP_REQUEST_TIMEOUT); 2341 send_headers_and_exit(HTTP_REQUEST_TIMEOUT);
@@ -2231,17 +2399,29 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2231 remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr); 2399 remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr);
2232 } 2400 }
2233# if ENABLE_FEATURE_IPV6 2401# if ENABLE_FEATURE_IPV6
2402# if !ENABLE_PLATFORM_MINGW32
2234 if (fromAddr->u.sa.sa_family == AF_INET6 2403 if (fromAddr->u.sa.sa_family == AF_INET6
2235 && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0 2404 && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0
2236 && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0 2405 && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0
2237 && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff) 2406 && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff)
2238 remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]); 2407 remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]);
2408# else
2409 if (fromAddr->u.sa.sa_family == AF_INET6
2410 && fromAddr->u.sin6.sin6_addr.s6_words[0] == 0
2411 && fromAddr->u.sin6.sin6_addr.s6_words[1] == 0
2412 && fromAddr->u.sin6.sin6_addr.s6_words[2] == 0
2413 && fromAddr->u.sin6.sin6_addr.s6_words[3] == 0
2414 && ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+4)) == 0xffff)
2415 remote_ip = ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+6));
2416# endif
2239# endif 2417# endif
2240 if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip); 2418 if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip);
2241#endif 2419#endif
2242 2420
2421#ifdef SIGALRM
2243 /* Install timeout handler. get_line() needs it. */ 2422 /* Install timeout handler. get_line() needs it. */
2244 signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit); 2423 signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit);
2424#endif
2245 2425
2246 if (!get_line()) { /* EOF or error or empty line */ 2426 if (!get_line()) { /* EOF or error or empty line */
2247 /* Observed Firefox to "speculatively" open 2427 /* Observed Firefox to "speculatively" open
@@ -2580,7 +2760,11 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2580 /* We are done reading headers, disable peer timeout */ 2760 /* We are done reading headers, disable peer timeout */
2581 alarm(0); 2761 alarm(0);
2582 2762
2763#if !ENABLE_PLATFORM_MINGW32
2583 if (strcmp(bb_basename(urlcopy), HTTPD_CONF) == 0) { 2764 if (strcmp(bb_basename(urlcopy), HTTPD_CONF) == 0) {
2765#else
2766 if (strcasecmp(bb_basename(urlcopy), HTTPD_CONF) == 0) {
2767#endif
2584 /* protect listing [/path]/httpd.conf or IP deny */ 2768 /* protect listing [/path]/httpd.conf or IP deny */
2585 send_headers_and_exit(HTTP_FORBIDDEN); 2769 send_headers_and_exit(HTTP_FORBIDDEN);
2586 } 2770 }
@@ -2626,12 +2810,14 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2626 ); 2810 );
2627} 2811}
2628 2812
2813
2629/* 2814/*
2630 * The main http server function. 2815 * The main http server function.
2631 * Given a socket, listen for new connections and farm out 2816 * Given a socket, listen for new connections and farm out
2632 * the processing as a [v]forked process. 2817 * the processing as a [v]forked process.
2633 * Never returns. 2818 * Never returns.
2634 */ 2819 */
2820# if !ENABLE_PLATFORM_MINGW32
2635#if BB_MMU 2821#if BB_MMU
2636static void mini_httpd(int server_socket) NORETURN; 2822static void mini_httpd(int server_socket) NORETURN;
2637static void mini_httpd(int server_socket) 2823static void mini_httpd(int server_socket)
@@ -2720,6 +2906,40 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv)
2720 /* never reached */ 2906 /* never reached */
2721} 2907}
2722#endif 2908#endif
2909#else /* ENABLE_PLATFORM_MINGW32 */
2910static void mini_httpd_win32(int sock, int argc, char **argv) NORETURN;
2911static void mini_httpd_win32(int sock, int argc, char **argv)
2912{
2913 char *argv_copy[argc + 5];
2914
2915 argv_copy[0] = (char *)bb_busybox_exec_path;
2916 argv_copy[1] = (char *)"--busybox";
2917 argv_copy[2] = (char *)"-httpd"; // don't daemonise in main()
2918 argv_copy[3] = (char *)"-I";
2919 memcpy(&argv_copy[5], &argv[1], argc * sizeof(argv[0]));
2920
2921 while (1) {
2922 int n;
2923
2924 /* Wait for connections... */
2925 n = accept(sock, NULL, NULL);
2926 if (n < 0)
2927 continue;
2928
2929 /* set the KEEPALIVE option to cull dead connections */
2930 setsockopt_keepalive(n);
2931
2932 argv_copy[4] = itoa(n);
2933 if ((foreground ?
2934 spawn(argv_copy) : mingw_spawn_detach(argv_copy)) == -1)
2935 bb_perror_msg_and_die("can't execute 'httpd'");
2936
2937 /* parent, or spawn failed */
2938 close(n);
2939 } /* while (1) */
2940 /* never reached */
2941}
2942#endif
2723 2943
2724/* 2944/*
2725 * Process a HTTP connection on stdin/out. 2945 * Process a HTTP connection on stdin/out.
@@ -2737,12 +2957,36 @@ static void mini_httpd_inetd(void)
2737 handle_incoming_and_exit(&fromAddr); 2957 handle_incoming_and_exit(&fromAddr);
2738} 2958}
2739 2959
2960#if ENABLE_PLATFORM_MINGW32
2961static void mingw_daemonize(char **argv)
2962{
2963 char **new_argv;
2964 int fd;
2965
2966 new_argv = grow_argv(argv + 1, 3);
2967 new_argv[0] = (char *)bb_busybox_exec_path;
2968 new_argv[1] = (char *)"--busybox";
2969 // don't daemonise in main(), we explicitly detach below
2970 new_argv[2] = (char *)"-httpd";
2971
2972 fd = xopen(bb_dev_null, O_RDWR);
2973 xdup2(fd, 0);
2974 xdup2(fd, 1);
2975 xdup2(fd, 2);
2976 close(fd);
2977
2978 exit(mingw_spawn_detach(new_argv) == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
2979}
2980#endif
2981
2982#if !ENABLE_PLATFORM_MINGW32
2740static void sighup_handler(int sig UNUSED_PARAM) 2983static void sighup_handler(int sig UNUSED_PARAM)
2741{ 2984{
2742 int sv = errno; 2985 int sv = errno;
2743 parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE); 2986 parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE);
2744 errno = sv; 2987 errno = sv;
2745} 2988}
2989#endif
2746 2990
2747enum { 2991enum {
2748 c_opt_config_file = 0, 2992 c_opt_config_file = 0,
@@ -2780,6 +3024,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2780 IF_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;) 3024 IF_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;)
2781 IF_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;) 3025 IF_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;)
2782 IF_FEATURE_HTTPD_AUTH_MD5(const char *pass;) 3026 IF_FEATURE_HTTPD_AUTH_MD5(const char *pass;)
3027 IF_PLATFORM_MINGW32(int fd;)
2783 3028
2784 INIT_G(); 3029 INIT_G();
2785 3030
@@ -2798,16 +3043,19 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2798 IF_FEATURE_HTTPD_BASIC_AUTH("r:") 3043 IF_FEATURE_HTTPD_BASIC_AUTH("r:")
2799 IF_FEATURE_HTTPD_AUTH_MD5("m:") 3044 IF_FEATURE_HTTPD_AUTH_MD5("m:")
2800 IF_FEATURE_HTTPD_SETUID("u:") 3045 IF_FEATURE_HTTPD_SETUID("u:")
2801 "p:ifv" 3046 IF_NOT_PLATFORM_MINGW32("p:ifv")
3047 IF_PLATFORM_MINGW32("p:I:+fv")
2802 "\0" 3048 "\0"
2803 /* -v counts, -i implies -f */ 3049 /* -v counts, -i implies -f */
2804 "vv:if", 3050 IF_NOT_PLATFORM_MINGW32("vv:if",)
3051 IF_PLATFORM_MINGW32("vv:",)
2805 &opt_c_configFile, &url_for_decode, &home_httpd 3052 &opt_c_configFile, &url_for_decode, &home_httpd
2806 IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode) 3053 IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode)
2807 IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm) 3054 IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm)
2808 IF_FEATURE_HTTPD_AUTH_MD5(, &pass) 3055 IF_FEATURE_HTTPD_AUTH_MD5(, &pass)
2809 IF_FEATURE_HTTPD_SETUID(, &s_ugid) 3056 IF_FEATURE_HTTPD_SETUID(, &s_ugid)
2810 , &bind_addr_or_port 3057 , &bind_addr_or_port
3058 IF_PLATFORM_MINGW32(, &fd)
2811 , &verbose 3059 , &verbose
2812 ); 3060 );
2813 if (opt & OPT_DECODE_URL) { 3061 if (opt & OPT_DECODE_URL) {
@@ -2837,20 +3085,33 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2837 } 3085 }
2838#endif 3086#endif
2839 3087
3088#if !ENABLE_PLATFORM_MINGW32
2840#if !BB_MMU 3089#if !BB_MMU
2841 if (!(opt & OPT_FOREGROUND)) { 3090 if (!(opt & OPT_FOREGROUND)) {
2842 bb_daemonize_or_rexec(0, argv); /* don't change current directory */ 3091 bb_daemonize_or_rexec(0, argv); /* don't change current directory */
2843 re_execed = 0; /* for the following chdir to work */ 3092 re_execed = 0; /* for the following chdir to work */
2844 } 3093 }
2845#endif 3094#endif
3095#else /* ENABLE_PLATFORM_MINGW32 */
3096 foreground = (opt & OPT_FOREGROUND) == OPT_FOREGROUND;
3097 if (!foreground && argv[0][0] != '-')
3098 mingw_daemonize(argv);
3099#endif
3100
2846 /* Chdir to home (unless we were re_exec()ed for NOMMU case 3101 /* Chdir to home (unless we were re_exec()ed for NOMMU case
2847 * in mini_httpd_nommu(): we are already in the home dir then). 3102 * in mini_httpd_nommu(): we are already in the home dir then).
2848 */ 3103 */
3104#if ENABLE_PLATFORM_MINGW32
3105 if (!(opt & OPT_INETD))
3106#else
2849 if (!re_execed) 3107 if (!re_execed)
3108#endif
2850 xchdir(home_httpd); 3109 xchdir(home_httpd);
2851 3110
2852 if (!(opt & OPT_INETD)) { 3111 if (!(opt & OPT_INETD)) {
3112#ifdef SIGCHLD
2853 signal(SIGCHLD, SIG_IGN); 3113 signal(SIGCHLD, SIG_IGN);
3114#endif
2854 server_socket = openServer(); 3115 server_socket = openServer();
2855#if ENABLE_FEATURE_HTTPD_SETUID 3116#if ENABLE_FEATURE_HTTPD_SETUID
2856 /* drop privileges */ 3117 /* drop privileges */
@@ -2884,12 +3145,35 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2884#endif 3145#endif
2885 3146
2886 parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE); 3147 parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE);
3148#if ENABLE_PLATFORM_MINGW32
3149# if ENABLE_FEATURE_HTTPD_CGI
3150 if ((opt & OPT_INETD) && fd == 0) {
3151 cgi_handler(argv + optind);
3152 return 0;
3153 }
3154# endif
3155#else
2887 if (!(opt & OPT_INETD)) 3156 if (!(opt & OPT_INETD))
2888 signal(SIGHUP, sighup_handler); 3157 signal(SIGHUP, sighup_handler);
3158#endif
2889 3159
2890 xfunc_error_retval = 0; 3160 xfunc_error_retval = 0;
3161#if ENABLE_PLATFORM_MINGW32
3162 if (opt & OPT_INETD) {
3163 xmove_fd(fd, 0);
3164 xdup2(0, 1);
3165 while (--fd > 2)
3166 close(fd);
3167# if ENABLE_FEATURE_HTTPD_CGI
3168 /* Skip 'httpd -I N' and omit any non-option arguments */
3169 server_argc = optind - 3;
3170 server_argv = argv + 3;
3171# endif
3172 }
3173#endif
2891 if (opt & OPT_INETD) 3174 if (opt & OPT_INETD)
2892 mini_httpd_inetd(); /* never returns */ 3175 mini_httpd_inetd(); /* never returns */
3176#if !ENABLE_PLATFORM_MINGW32
2893#if BB_MMU 3177#if BB_MMU
2894 if (!(opt & OPT_FOREGROUND)) 3178 if (!(opt & OPT_FOREGROUND))
2895 bb_daemonize(0); /* don't change current directory */ 3179 bb_daemonize(0); /* don't change current directory */
@@ -2897,5 +3181,8 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2897#else 3181#else
2898 mini_httpd_nommu(server_socket, argc, argv); /* never returns */ 3182 mini_httpd_nommu(server_socket, argc, argv); /* never returns */
2899#endif 3183#endif
3184#else /* ENABLE_PLATFORM_MINGW32 */
3185 mini_httpd_win32(server_socket, argc, argv);
3186#endif
2900 /* return 0; */ 3187 /* return 0; */
2901} 3188}