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.
This commit is contained in:
Glenn L McGrath 2003-05-19 05:56:16 +00:00
parent 0861e828d0
commit 4fe3ff8cff

View File

@ -43,32 +43,69 @@
* as follows: * as follows:
* foo=`httpd -d $foo` # decode "Hello%20World" as "Hello World" * foo=`httpd -d $foo` # decode "Hello%20World" as "Hello World"
* bar=`httpd -e "<Hello World>"` # encode as "&#60Hello&#32World&#62" * bar=`httpd -e "<Hello World>"` # encode as "&#60Hello&#32World&#62"
* Note that url encoding for arguments is not the same as html encoding for
* presenation. -d decodes a url-encoded argument while -e encodes in html
* for page display.
* *
* httpd.conf has the following format: * httpd.conf has the following format:
*
A:172.20. # Allow any address that begins with 172.20 * A:172.20. # Allow any address that begins with 172.20
A:10.10. # Allow any address that begins with 10.10. * A:10.10. # Allow any address that begins with 10.10.
A:10.10 # Allow any address that previous set and 10.100-109.X.X * A:10.20 # Allow any address that previous set and 10.200-209.X.X
A:127.0.0.1 # Allow local loopback connections * A:127.0.0.1 # Allow local loopback connections
D:* # Deny from other IP connections * D:* # Deny from other IP connections
/cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/ * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/
/adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/
/adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/
.au:audio/basic # additional mime type for audio.au files * .au:audio/basic # additional mime type for audio.au files
*
A/D may be as a/d or allow/deny - first char case unsensitive parsed only. * A/D may be as a/d or allow/deny - first char case unsensitive
* Deny IP rules take precedence over allow rules. Any IP rules after D:* are
Each subdir can have config file. * ignored.
You can set less IP allow from subdir config. *
Password protection from subdir config can rewriten previous sets for *
current or/and next subpathes. * The Deny/Allow IP logic:
For protect as user:pass current subdir and subpathes set from subdir config: *
/:user:pass * - Default is to allow all. No addresses are denied unless
/subpath:user2:pass2 * denied with a D: rule.
* - Order of Deny/Allow rules is significant
If -c don`t setted, used httpd root config, else httpd root config skiped. * - Deny rules take precedence over allow rules.
* - If a deny all rule (D:*) is used it acts as a catch-all for unmatched
* addresses.
* - Specification of Allow all (A:*) is a no-op
*
* Example:
* 1. Allow only specified addresses
* A:172.20. # Allow any address that begins with 172.20
* A:10.10. # Allow any address that begins with 10.10.
* A:10.10 # Allow any address that previous set and 10.100-109.X.X
* A:127.0.0.1 # Allow local loopback connections
* D:* # Deny from other IP connections
*
* 2. Only deny specified addresses
* D:1.2.3. # deny from 1.2.3.0 - 1.2.3.255
* D:2.3.4. # deny from 2.3.4.0 - 2.3.4.255
* A:* # (optional line added for clarity)
*
* If a sub directory contains a config file it is parsed and merged with
* any existing settings as if it was appended to the original configuration
* except that all previous IP config rules are discarded.
*
* subdir paths are relative to the containing subdir and thus cannot
* affect the parent rules.
*
* Note that since the sub dir is parsed in the forked thread servicing the
* subdir http request, any merge is discarded when the process exits. As a
* result, the subdir settings only have a lifetime of a single request.
*
*
* If -c is not set, an attempt will be made to open the default
* root configuration file. If -c is set and the file is not found, the
* server exits with an error.
*
*/ */
#include <stdio.h> #include <stdio.h>
#include <ctype.h> /* for isspace */ #include <ctype.h> /* for isspace */
#include <string.h> #include <string.h>
@ -86,10 +123,10 @@ For protect as user:pass current subdir and subpathes set from subdir config:
#include "busybox.h" #include "busybox.h"
static const char httpdVersion[] = "busybox httpd/1.25 10-May-2003"; static const char httpdVersion[] = "busybox httpd/1.26 18-May-2003";
static const char default_path_httpd_conf[] = "/etc"; static const char default_path_httpd_conf[] = "/etc";
static const char httpd_conf[] = "httpd.conf"; static const char httpd_conf[] = "httpd.conf";
static const char home[] = "/www"; static const char home[] = "./";
// Note: bussybox xfuncs are not used because we want the server to keep running // Note: bussybox xfuncs are not used because we want the server to keep running
// if something bad happens due to a malformed user request. // if something bad happens due to a malformed user request.
@ -160,7 +197,7 @@ void bb_show_usage(void)
/* CGI environ size */ /* CGI environ size */
#ifdef CONFIG_FEATURE_HTTPD_SET_CGI_VARS_TO_ENV #ifdef CONFIG_FEATURE_HTTPD_SET_CGI_VARS_TO_ENV
#define ENVSIZE 50 /* set max 35 CGI_variable */ #define ENVSIZE 70 /* set max CGI variable */
#else #else
#define ENVSIZE 15 /* minimal requires */ #define ENVSIZE 15 /* minimal requires */
#endif #endif
@ -325,7 +362,31 @@ static void free_config_lines(Htaccess **pprev)
#define SUBDIR_PARSE 1 #define SUBDIR_PARSE 1
#define SIGNALED_PARSE 2 #define SIGNALED_PARSE 2
#define FIND_FROM_HTTPD_ROOT 3 #define FIND_FROM_HTTPD_ROOT 3
/****************************************************************************
*
> $Function: parse_conf()
*
* $Description: parse configuration file into in-memory linked list.
*
* The first non-white character is examined to determine if the config line
* is one of the following:
* .ext:mime/type # new mime type not compiled into httpd
* [adAD]:from # ip address allow/deny, * for wildcard
* /path:user:pass # username/password
*
* Any previous IP rules are discarded.
* If the flag argument is not SUBDIR_PARSE then all /path and mime rules
* are also discarded. That is, previous settings are retained if flag is
* SUBDIR_PARSE.
*
* $Parameters:
* (const char *) path . . null for ip address checks, path for password
* checks.
* (int) flag . . . . . . the source of the parse request.
*
* $Return: (None)
*
****************************************************************************/
static void parse_conf(const char *path, int flag) static void parse_conf(const char *path, int flag)
{ {
FILE *f; FILE *f;
@ -335,17 +396,18 @@ static void parse_conf(const char *path, int flag)
#endif #endif
const char *cf = config->configFile; const char *cf = config->configFile;
char buf[80]; char buf[160];
char *p0 = NULL; char *p0 = NULL;
char *c, *p; char *c, *p;
/* free previous setuped */ /* free previous ip setup if present */
free_config_lines(&config->ip_a_d); free_config_lines(&config->ip_a_d);
/* retain previous auth and mime config only for subdir parse */
if(flag != SUBDIR_PARSE) { if(flag != SUBDIR_PARSE) {
#ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
free_config_lines(&config->auth) free_config_lines(&config->auth)
#endif #endif
; /* syntax confuse */ ; /* appease compiler warnings if option is not set */
#ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
free_config_lines(&config->mime_a); free_config_lines(&config->mime_a);
#endif #endif
@ -363,7 +425,7 @@ static void parse_conf(const char *path, int flag)
while((f = fopen(cf, "r")) == NULL) { while((f = fopen(cf, "r")) == NULL) {
if(flag != FIRST_PARSE) { if(flag != FIRST_PARSE) {
/* config file not found */ /* config file not found, no changes to config */
return; return;
} }
if(config->configFile) /* if -c option given */ if(config->configFile) /* if -c option given */
@ -376,7 +438,7 @@ static void parse_conf(const char *path, int flag)
prev = config->auth; prev = config->auth;
#endif #endif
/* This could stand some work */ /* This could stand some work */
while ( (p0 = fgets(buf, 80, f)) != NULL) { while ( (p0 = fgets(buf, sizeof(buf), f)) != NULL) {
c = NULL; c = NULL;
for(p = p0; *p0 != 0 && *p0 != '#'; p0++) { for(p = p0; *p0 != 0 && *p0 != '#'; p0++) {
if(!isspace(*p0)) { if(!isspace(*p0)) {
@ -393,6 +455,8 @@ static void parse_conf(const char *path, int flag)
if(*c == '*') if(*c == '*')
*c = 0; /* Allow all */ *c = 0; /* Allow all */
p0 = buf; p0 = buf;
if((*p0 == 'i') || (*p0 == 'I'))
*p0 = 'A'; // version 1.1/1.2 compatibility for ip:
if(*p0 == 'a') if(*p0 == 'a')
*p0 = 'A'; *p0 = 'A';
if(*p0 == 'd') if(*p0 == 'd')
@ -681,9 +745,12 @@ static void addEnvCgi(const char *pargs)
{ {
char *args; char *args;
char *memargs; char *memargs;
char *namelist; /* space separated list of arg names */
if (pargs==0) return; if (pargs==0) return;
/* args are a list of name=value&name2=value2 sequences */ /* args are a list of name=value&name2=value2 sequences */
namelist = (char *) malloc(strlen(pargs));
if (namelist) namelist[0]=0;
memargs = args = strdup(pargs); memargs = args = strdup(pargs);
while (args && *args) { while (args && *args) {
const char *name = args; const char *name = args;
@ -696,8 +763,14 @@ static void addEnvCgi(const char *pargs)
if (args) if (args)
*args++ = 0; *args++ = 0;
addEnv("CGI", name, decodeString(value, 1)); addEnv("CGI", name, decodeString(value, 1));
if (*namelist) strcat(namelist, " ");
strcat(namelist,name);
} }
free(memargs); free(memargs);
if (namelist) {
addEnv("CGI","ARGLIST_",namelist);
free(namelist);
}
} }
#endif /* CONFIG_FEATURE_HTTPD_SET_CGI_VARS_TO_ENV */ #endif /* CONFIG_FEATURE_HTTPD_SET_CGI_VARS_TO_ENV */
@ -1051,7 +1124,8 @@ static int sendCgi(const char *url,
*script = '\0'; *script = '\0';
if(chdir(realpath_buff) == 0) { if(chdir(realpath_buff) == 0) {
*script = '/'; *script = '/';
// now run the program. If it fails, use _exit() so no destructors // now run the program. If it fails,
// use _exit() so no destructors
// get called and make a mess. // get called and make a mess.
execve(realpath_buff, argp, config->envp); execve(realpath_buff, argp, config->envp);
} }
@ -1605,6 +1679,9 @@ static int miniHttpd(int server)
exit(0); exit(0);
} }
close(s); close(s);
#ifdef TEST
return 0; // exit after processing one request
#endif
} }
} }
} // while (1) } // while (1)
@ -1655,6 +1732,10 @@ int httpd_main(int argc, char *argv[])
#endif #endif
{ {
const char *home_httpd = home; const char *home_httpd = home;
#ifdef TEST
const char *testArgs[5];
int numTestArgs=0;
#endif
#ifndef CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY #ifndef CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY
int server; int server;
@ -1689,6 +1770,9 @@ int httpd_main(int argc, char *argv[])
#endif #endif
#ifdef CONFIG_FEATURE_HTTPD_SETUID #ifdef CONFIG_FEATURE_HTTPD_SETUID
"u:" "u:"
#endif
#ifdef TEST
"t:"
#endif #endif
); );
if (c == EOF) break; if (c == EOF) break;
@ -1734,6 +1818,11 @@ int httpd_main(int argc, char *argv[])
} }
} }
break; break;
#endif
#ifdef TEST
case 't':
testArgs[numTestArgs++]=optarg;
break;
#endif #endif
default: default:
bb_error_msg("%s", httpdVersion); bb_error_msg("%s", httpdVersion);
@ -1762,6 +1851,17 @@ int httpd_main(int argc, char *argv[])
parse_conf(default_path_httpd_conf, FIRST_PARSE); parse_conf(default_path_httpd_conf, FIRST_PARSE);
#endif #endif
#ifdef TEST
if (numTestArgs)
{
if (strcmp(testArgs[0],"ip") == 0) testArgs[0] = 0;
if (numTestArgs > 2)
parse_conf(testArgs[2], SUBDIR_PARSE);
int result = printf("%d\n",checkPerm(testArgs[0],testArgs[1]));
return result;
}
#endif
#ifndef CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY #ifndef CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY
if (!config->debugHttpd) { if (!config->debugHttpd) {
if (daemon(1, 0) < 0) /* don`t change curent directory */ if (daemon(1, 0) < 0) /* don`t change curent directory */