diff options
| author | Glenn L McGrath <bug1@ihug.co.nz> | 2003-05-19 05:56:16 +0000 |
|---|---|---|
| committer | Glenn L McGrath <bug1@ihug.co.nz> | 2003-05-19 05:56:16 +0000 |
| commit | 4fe3ff8cffce83b3132223daf80e3e77ca89c259 (patch) | |
| tree | f9f7383cc233313f026058f6f0395114e4fb65ec | |
| parent | 0861e828d028cdb6ad0798143a88c9eb6fabb631 (diff) | |
| download | busybox-w32-4fe3ff8cffce83b3132223daf80e3e77ca89c259.tar.gz busybox-w32-4fe3ff8cffce83b3132223daf80e3e77ca89c259.tar.bz2 busybox-w32-4fe3ff8cffce83b3132223daf80e3e77ca89c259.zip | |
Patch from Glenn Engel
- more comments
- larger allowed number of CGI script variables
- ifdefs for regression test hooks
- default to ./ rather than /www (if unspecified) for compatibility with
earlier versions.
- Allow ip: as a synomym for A: rules for compatibility with earlier
versions.
- Setting of CGI_ARGLIST_ when automatic setting of env vars for form
scripting is utilized. This helps with minimal systems like openap.
| -rw-r--r-- | networking/httpd.c | 178 |
1 files changed, 139 insertions, 39 deletions
diff --git a/networking/httpd.c b/networking/httpd.c index df99f1c8b..e9f4c15bc 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
| @@ -41,33 +41,70 @@ | |||
| 41 | * | 41 | * |
| 42 | * The server can also be invoked as a url arg decoder and html text encoder | 42 | * The server can also be invoked as a url arg decoder and html text encoder |
| 43 | * as follows: | 43 | * as follows: |
| 44 | * foo=`httpd -d $foo` # decode "Hello%20World" as "Hello World" | 44 | * foo=`httpd -d $foo` # decode "Hello%20World" as "Hello World" |
| 45 | * bar=`httpd -e "<Hello World>"` # encode as "<Hello World>" | 45 | * bar=`httpd -e "<Hello World>"` # encode as "<Hello World>" |
| 46 | * Note that url encoding for arguments is not the same as html encoding for | ||
| 47 | * presenation. -d decodes a url-encoded argument while -e encodes in html | ||
| 48 | * for page display. | ||
| 46 | * | 49 | * |
| 47 | * httpd.conf has the following format: | 50 | * httpd.conf has the following format: |
| 51 | * | ||
| 52 | * A:172.20. # Allow any address that begins with 172.20 | ||
| 53 | * A:10.10. # Allow any address that begins with 10.10. | ||
| 54 | * A:10.20 # Allow any address that previous set and 10.200-209.X.X | ||
| 55 | * A:127.0.0.1 # Allow local loopback connections | ||
| 56 | * D:* # Deny from other IP connections | ||
| 57 | * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/ | ||
| 58 | * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ | ||
| 59 | * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ | ||
| 60 | * .au:audio/basic # additional mime type for audio.au files | ||
| 61 | * | ||
| 62 | * A/D may be as a/d or allow/deny - first char case unsensitive | ||
| 63 | * Deny IP rules take precedence over allow rules. Any IP rules after D:* are | ||
| 64 | * ignored. | ||
| 65 | * | ||
| 66 | * | ||
| 67 | * The Deny/Allow IP logic: | ||
| 68 | * | ||
| 69 | * - Default is to allow all. No addresses are denied unless | ||
| 70 | * denied with a D: rule. | ||
| 71 | * - Order of Deny/Allow rules is significant | ||
| 72 | * - Deny rules take precedence over allow rules. | ||
| 73 | * - If a deny all rule (D:*) is used it acts as a catch-all for unmatched | ||
| 74 | * addresses. | ||
| 75 | * - Specification of Allow all (A:*) is a no-op | ||
| 76 | * | ||
| 77 | * Example: | ||
| 78 | * 1. Allow only specified addresses | ||
| 79 | * A:172.20. # Allow any address that begins with 172.20 | ||
| 80 | * A:10.10. # Allow any address that begins with 10.10. | ||
| 81 | * A:10.10 # Allow any address that previous set and 10.100-109.X.X | ||
| 82 | * A:127.0.0.1 # Allow local loopback connections | ||
| 83 | * D:* # Deny from other IP connections | ||
| 84 | * | ||
| 85 | * 2. Only deny specified addresses | ||
| 86 | * D:1.2.3. # deny from 1.2.3.0 - 1.2.3.255 | ||
| 87 | * D:2.3.4. # deny from 2.3.4.0 - 2.3.4.255 | ||
| 88 | * A:* # (optional line added for clarity) | ||
| 89 | * | ||
| 90 | * If a sub directory contains a config file it is parsed and merged with | ||
| 91 | * any existing settings as if it was appended to the original configuration | ||
| 92 | * except that all previous IP config rules are discarded. | ||
| 93 | * | ||
| 94 | * subdir paths are relative to the containing subdir and thus cannot | ||
| 95 | * affect the parent rules. | ||
| 96 | * | ||
| 97 | * Note that since the sub dir is parsed in the forked thread servicing the | ||
| 98 | * subdir http request, any merge is discarded when the process exits. As a | ||
| 99 | * result, the subdir settings only have a lifetime of a single request. | ||
| 100 | * | ||
| 101 | * | ||
| 102 | * If -c is not set, an attempt will be made to open the default | ||
| 103 | * root configuration file. If -c is set and the file is not found, the | ||
| 104 | * server exits with an error. | ||
| 105 | * | ||
| 106 | */ | ||
| 48 | 107 | ||
| 49 | A:172.20. # Allow any address that begins with 172.20 | ||
| 50 | A:10.10. # Allow any address that begins with 10.10. | ||
| 51 | A:10.10 # Allow any address that previous set and 10.100-109.X.X | ||
| 52 | A:127.0.0.1 # Allow local loopback connections | ||
| 53 | D:* # Deny from other IP connections | ||
| 54 | /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/ | ||
| 55 | /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ | ||
| 56 | /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ | ||
| 57 | .au:audio/basic # additional mime type for audio.au files | ||
| 58 | |||
| 59 | A/D may be as a/d or allow/deny - first char case unsensitive parsed only. | ||
| 60 | |||
| 61 | Each subdir can have config file. | ||
| 62 | You can set less IP allow from subdir config. | ||
| 63 | Password protection from subdir config can rewriten previous sets for | ||
| 64 | current or/and next subpathes. | ||
| 65 | For protect as user:pass current subdir and subpathes set from subdir config: | ||
| 66 | /:user:pass | ||
| 67 | /subpath:user2:pass2 | ||
| 68 | |||
| 69 | If -c don`t setted, used httpd root config, else httpd root config skiped. | ||
| 70 | */ | ||
| 71 | 108 | ||
| 72 | #include <stdio.h> | 109 | #include <stdio.h> |
| 73 | #include <ctype.h> /* for isspace */ | 110 | #include <ctype.h> /* for isspace */ |
| @@ -86,10 +123,10 @@ For protect as user:pass current subdir and subpathes set from subdir config: | |||
| 86 | #include "busybox.h" | 123 | #include "busybox.h" |
| 87 | 124 | ||
| 88 | 125 | ||
| 89 | static const char httpdVersion[] = "busybox httpd/1.25 10-May-2003"; | 126 | static const char httpdVersion[] = "busybox httpd/1.26 18-May-2003"; |
| 90 | static const char default_path_httpd_conf[] = "/etc"; | 127 | static const char default_path_httpd_conf[] = "/etc"; |
| 91 | static const char httpd_conf[] = "httpd.conf"; | 128 | static const char httpd_conf[] = "httpd.conf"; |
| 92 | static const char home[] = "/www"; | 129 | static const char home[] = "./"; |
| 93 | 130 | ||
| 94 | // Note: bussybox xfuncs are not used because we want the server to keep running | 131 | // Note: bussybox xfuncs are not used because we want the server to keep running |
| 95 | // if something bad happens due to a malformed user request. | 132 | // if something bad happens due to a malformed user request. |
| @@ -160,7 +197,7 @@ void bb_show_usage(void) | |||
| 160 | 197 | ||
| 161 | /* CGI environ size */ | 198 | /* CGI environ size */ |
| 162 | #ifdef CONFIG_FEATURE_HTTPD_SET_CGI_VARS_TO_ENV | 199 | #ifdef CONFIG_FEATURE_HTTPD_SET_CGI_VARS_TO_ENV |
| 163 | #define ENVSIZE 50 /* set max 35 CGI_variable */ | 200 | #define ENVSIZE 70 /* set max CGI variable */ |
| 164 | #else | 201 | #else |
| 165 | #define ENVSIZE 15 /* minimal requires */ | 202 | #define ENVSIZE 15 /* minimal requires */ |
| 166 | #endif | 203 | #endif |
| @@ -325,7 +362,31 @@ static void free_config_lines(Htaccess **pprev) | |||
| 325 | #define SUBDIR_PARSE 1 | 362 | #define SUBDIR_PARSE 1 |
| 326 | #define SIGNALED_PARSE 2 | 363 | #define SIGNALED_PARSE 2 |
| 327 | #define FIND_FROM_HTTPD_ROOT 3 | 364 | #define FIND_FROM_HTTPD_ROOT 3 |
| 328 | 365 | /**************************************************************************** | |
| 366 | * | ||
| 367 | > $Function: parse_conf() | ||
| 368 | * | ||
| 369 | * $Description: parse configuration file into in-memory linked list. | ||
| 370 | * | ||
| 371 | * The first non-white character is examined to determine if the config line | ||
| 372 | * is one of the following: | ||
| 373 | * .ext:mime/type # new mime type not compiled into httpd | ||
| 374 | * [adAD]:from # ip address allow/deny, * for wildcard | ||
| 375 | * /path:user:pass # username/password | ||
| 376 | * | ||
| 377 | * Any previous IP rules are discarded. | ||
| 378 | * If the flag argument is not SUBDIR_PARSE then all /path and mime rules | ||
| 379 | * are also discarded. That is, previous settings are retained if flag is | ||
| 380 | * SUBDIR_PARSE. | ||
| 381 | * | ||
| 382 | * $Parameters: | ||
| 383 | * (const char *) path . . null for ip address checks, path for password | ||
| 384 | * checks. | ||
| 385 | * (int) flag . . . . . . the source of the parse request. | ||
| 386 | * | ||
| 387 | * $Return: (None) | ||
| 388 | * | ||
| 389 | ****************************************************************************/ | ||
| 329 | static void parse_conf(const char *path, int flag) | 390 | static void parse_conf(const char *path, int flag) |
| 330 | { | 391 | { |
| 331 | FILE *f; | 392 | FILE *f; |
| @@ -335,17 +396,18 @@ static void parse_conf(const char *path, int flag) | |||
| 335 | #endif | 396 | #endif |
| 336 | 397 | ||
| 337 | const char *cf = config->configFile; | 398 | const char *cf = config->configFile; |
| 338 | char buf[80]; | 399 | char buf[160]; |
| 339 | char *p0 = NULL; | 400 | char *p0 = NULL; |
| 340 | char *c, *p; | 401 | char *c, *p; |
| 341 | 402 | ||
| 342 | /* free previous setuped */ | 403 | /* free previous ip setup if present */ |
| 343 | free_config_lines(&config->ip_a_d); | 404 | free_config_lines(&config->ip_a_d); |
| 405 | /* retain previous auth and mime config only for subdir parse */ | ||
| 344 | if(flag != SUBDIR_PARSE) { | 406 | if(flag != SUBDIR_PARSE) { |
| 345 | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH | 407 | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| 346 | free_config_lines(&config->auth) | 408 | free_config_lines(&config->auth) |
| 347 | #endif | 409 | #endif |
| 348 | ; /* syntax confuse */ | 410 | ; /* appease compiler warnings if option is not set */ |
| 349 | #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES | 411 | #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES |
| 350 | free_config_lines(&config->mime_a); | 412 | free_config_lines(&config->mime_a); |
| 351 | #endif | 413 | #endif |
| @@ -363,7 +425,7 @@ static void parse_conf(const char *path, int flag) | |||
| 363 | 425 | ||
| 364 | while((f = fopen(cf, "r")) == NULL) { | 426 | while((f = fopen(cf, "r")) == NULL) { |
| 365 | if(flag != FIRST_PARSE) { | 427 | if(flag != FIRST_PARSE) { |
| 366 | /* config file not found */ | 428 | /* config file not found, no changes to config */ |
| 367 | return; | 429 | return; |
| 368 | } | 430 | } |
| 369 | if(config->configFile) /* if -c option given */ | 431 | if(config->configFile) /* if -c option given */ |
| @@ -376,7 +438,7 @@ static void parse_conf(const char *path, int flag) | |||
| 376 | prev = config->auth; | 438 | prev = config->auth; |
| 377 | #endif | 439 | #endif |
| 378 | /* This could stand some work */ | 440 | /* This could stand some work */ |
| 379 | while ( (p0 = fgets(buf, 80, f)) != NULL) { | 441 | while ( (p0 = fgets(buf, sizeof(buf), f)) != NULL) { |
| 380 | c = NULL; | 442 | c = NULL; |
| 381 | for(p = p0; *p0 != 0 && *p0 != '#'; p0++) { | 443 | for(p = p0; *p0 != 0 && *p0 != '#'; p0++) { |
| 382 | if(!isspace(*p0)) { | 444 | if(!isspace(*p0)) { |
| @@ -393,18 +455,20 @@ static void parse_conf(const char *path, int flag) | |||
| 393 | if(*c == '*') | 455 | if(*c == '*') |
| 394 | *c = 0; /* Allow all */ | 456 | *c = 0; /* Allow all */ |
| 395 | p0 = buf; | 457 | p0 = buf; |
| 458 | if((*p0 == 'i') || (*p0 == 'I')) | ||
| 459 | *p0 = 'A'; // version 1.1/1.2 compatibility for ip: | ||
| 396 | if(*p0 == 'a') | 460 | if(*p0 == 'a') |
| 397 | *p0 = 'A'; | 461 | *p0 = 'A'; |
| 398 | if(*p0 == 'd') | 462 | if(*p0 == 'd') |
| 399 | *p0 = 'D'; | 463 | *p0 = 'D'; |
| 400 | if(*p0 != 'A' && *p0 != 'D' | 464 | if(*p0 != 'A' && *p0 != 'D' |
| 401 | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH | 465 | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| 402 | && *p0 != '/' | 466 | && *p0 != '/' |
| 403 | #endif | 467 | #endif |
| 404 | #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES | 468 | #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES |
| 405 | && *p0 != '.' | 469 | && *p0 != '.' |
| 406 | #endif | 470 | #endif |
| 407 | ) | 471 | ) |
| 408 | continue; | 472 | continue; |
| 409 | 473 | ||
| 410 | if(*p0 == 'A' && *c == 0) { | 474 | if(*p0 == 'A' && *c == 0) { |
| @@ -681,9 +745,12 @@ static void addEnvCgi(const char *pargs) | |||
| 681 | { | 745 | { |
| 682 | char *args; | 746 | char *args; |
| 683 | char *memargs; | 747 | char *memargs; |
| 748 | char *namelist; /* space separated list of arg names */ | ||
| 684 | if (pargs==0) return; | 749 | if (pargs==0) return; |
| 685 | 750 | ||
| 686 | /* args are a list of name=value&name2=value2 sequences */ | 751 | /* args are a list of name=value&name2=value2 sequences */ |
| 752 | namelist = (char *) malloc(strlen(pargs)); | ||
| 753 | if (namelist) namelist[0]=0; | ||
| 687 | memargs = args = strdup(pargs); | 754 | memargs = args = strdup(pargs); |
| 688 | while (args && *args) { | 755 | while (args && *args) { |
| 689 | const char *name = args; | 756 | const char *name = args; |
| @@ -696,8 +763,14 @@ static void addEnvCgi(const char *pargs) | |||
| 696 | if (args) | 763 | if (args) |
| 697 | *args++ = 0; | 764 | *args++ = 0; |
| 698 | addEnv("CGI", name, decodeString(value, 1)); | 765 | addEnv("CGI", name, decodeString(value, 1)); |
| 766 | if (*namelist) strcat(namelist, " "); | ||
| 767 | strcat(namelist,name); | ||
| 699 | } | 768 | } |
| 700 | free(memargs); | 769 | free(memargs); |
| 770 | if (namelist) { | ||
| 771 | addEnv("CGI","ARGLIST_",namelist); | ||
| 772 | free(namelist); | ||
| 773 | } | ||
| 701 | } | 774 | } |
| 702 | #endif /* CONFIG_FEATURE_HTTPD_SET_CGI_VARS_TO_ENV */ | 775 | #endif /* CONFIG_FEATURE_HTTPD_SET_CGI_VARS_TO_ENV */ |
| 703 | 776 | ||
| @@ -1050,10 +1123,11 @@ static int sendCgi(const char *url, | |||
| 1050 | if(script) { | 1123 | if(script) { |
| 1051 | *script = '\0'; | 1124 | *script = '\0'; |
| 1052 | if(chdir(realpath_buff) == 0) { | 1125 | if(chdir(realpath_buff) == 0) { |
| 1053 | *script = '/'; | 1126 | *script = '/'; |
| 1054 | // now run the program. If it fails, use _exit() so no destructors | 1127 | // now run the program. If it fails, |
| 1055 | // get called and make a mess. | 1128 | // use _exit() so no destructors |
| 1056 | execve(realpath_buff, argp, config->envp); | 1129 | // get called and make a mess. |
| 1130 | execve(realpath_buff, argp, config->envp); | ||
| 1057 | } | 1131 | } |
| 1058 | } | 1132 | } |
| 1059 | } | 1133 | } |
| @@ -1605,6 +1679,9 @@ static int miniHttpd(int server) | |||
| 1605 | exit(0); | 1679 | exit(0); |
| 1606 | } | 1680 | } |
| 1607 | close(s); | 1681 | close(s); |
| 1682 | #ifdef TEST | ||
| 1683 | return 0; // exit after processing one request | ||
| 1684 | #endif | ||
| 1608 | } | 1685 | } |
| 1609 | } | 1686 | } |
| 1610 | } // while (1) | 1687 | } // while (1) |
| @@ -1655,6 +1732,10 @@ int httpd_main(int argc, char *argv[]) | |||
| 1655 | #endif | 1732 | #endif |
| 1656 | { | 1733 | { |
| 1657 | const char *home_httpd = home; | 1734 | const char *home_httpd = home; |
| 1735 | #ifdef TEST | ||
| 1736 | const char *testArgs[5]; | ||
| 1737 | int numTestArgs=0; | ||
| 1738 | #endif | ||
| 1658 | 1739 | ||
| 1659 | #ifndef CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY | 1740 | #ifndef CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY |
| 1660 | int server; | 1741 | int server; |
| @@ -1690,6 +1771,9 @@ int httpd_main(int argc, char *argv[]) | |||
| 1690 | #ifdef CONFIG_FEATURE_HTTPD_SETUID | 1771 | #ifdef CONFIG_FEATURE_HTTPD_SETUID |
| 1691 | "u:" | 1772 | "u:" |
| 1692 | #endif | 1773 | #endif |
| 1774 | #ifdef TEST | ||
| 1775 | "t:" | ||
| 1776 | #endif | ||
| 1693 | ); | 1777 | ); |
| 1694 | if (c == EOF) break; | 1778 | if (c == EOF) break; |
| 1695 | switch (c) { | 1779 | switch (c) { |
| @@ -1735,6 +1819,11 @@ int httpd_main(int argc, char *argv[]) | |||
| 1735 | } | 1819 | } |
| 1736 | break; | 1820 | break; |
| 1737 | #endif | 1821 | #endif |
| 1822 | #ifdef TEST | ||
| 1823 | case 't': | ||
| 1824 | testArgs[numTestArgs++]=optarg; | ||
| 1825 | break; | ||
| 1826 | #endif | ||
| 1738 | default: | 1827 | default: |
| 1739 | bb_error_msg("%s", httpdVersion); | 1828 | bb_error_msg("%s", httpdVersion); |
| 1740 | bb_show_usage(); | 1829 | bb_show_usage(); |
| @@ -1762,6 +1851,17 @@ int httpd_main(int argc, char *argv[]) | |||
| 1762 | parse_conf(default_path_httpd_conf, FIRST_PARSE); | 1851 | parse_conf(default_path_httpd_conf, FIRST_PARSE); |
| 1763 | #endif | 1852 | #endif |
| 1764 | 1853 | ||
| 1854 | #ifdef TEST | ||
| 1855 | if (numTestArgs) | ||
| 1856 | { | ||
| 1857 | if (strcmp(testArgs[0],"ip") == 0) testArgs[0] = 0; | ||
| 1858 | if (numTestArgs > 2) | ||
| 1859 | parse_conf(testArgs[2], SUBDIR_PARSE); | ||
| 1860 | int result = printf("%d\n",checkPerm(testArgs[0],testArgs[1])); | ||
| 1861 | return result; | ||
| 1862 | } | ||
| 1863 | #endif | ||
| 1864 | |||
| 1765 | #ifndef CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY | 1865 | #ifndef CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY |
| 1766 | if (!config->debugHttpd) { | 1866 | if (!config->debugHttpd) { |
| 1767 | if (daemon(1, 0) < 0) /* don`t change curent directory */ | 1867 | if (daemon(1, 0) < 0) /* don`t change curent directory */ |
