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 e1a447fa1..50595104c 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 | } |
