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 */ |