diff options
Diffstat (limited to 'networking/httpd.c')
-rw-r--r-- | networking/httpd.c | 297 |
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 | ||
335 | static 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 | ||
453 | struct globals { | 465 | struct 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 */ |
563 | enum { | 592 | enum { |
@@ -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 | ||
1583 | static 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 | ||
1527 | static void setenv1(const char *name, const char *value) | 1624 | static 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 | */ |
2170 | static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN; | ||
2171 | static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM) | 2339 | static 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 |
2636 | static void mini_httpd(int server_socket) NORETURN; | 2822 | static void mini_httpd(int server_socket) NORETURN; |
2637 | static void mini_httpd(int server_socket) | 2823 | static 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 */ | ||
2910 | static void mini_httpd_win32(int sock, int argc, char **argv) NORETURN; | ||
2911 | static 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 | ||
2961 | static 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 | ||
2740 | static void sighup_handler(int sig UNUSED_PARAM) | 2983 | static 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 | ||
2747 | enum { | 2991 | enum { |
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 | } |