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

@ -41,33 +41,70 @@
* *
* The server can also be invoked as a url arg decoder and html text encoder * The server can also be invoked as a url arg decoder and html text encoder
* 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:10.10. # Allow any address that begins with 10.10.
* A:10.20 # Allow any address that previous set and 10.200-209.X.X
* A:127.0.0.1 # Allow local loopback connections
* D:* # Deny from other IP connections
* /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:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/
* .au:audio/basic # additional mime type for audio.au files
*
* 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
* ignored.
*
*
* The Deny/Allow IP logic:
*
* - Default is to allow all. No addresses are denied unless
* denied with a D: rule.
* - Order of Deny/Allow rules is significant
* - 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.
*
*/
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
/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:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/
.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.
Each subdir can have config file.
You can set less IP allow from subdir config.
Password protection from subdir config can rewriten previous sets for
current or/and next subpathes.
For protect as user:pass current subdir and subpathes set from subdir config:
/:user:pass
/subpath:user2:pass2
If -c don`t setted, used httpd root config, else httpd root config skiped.
*/
#include <stdio.h> #include <stdio.h>
#include <ctype.h> /* for isspace */ #include <ctype.h> /* for isspace */
@ -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,18 +455,20 @@ 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')
*p0 = 'D'; *p0 = 'D';
if(*p0 != 'A' && *p0 != 'D' if(*p0 != 'A' && *p0 != 'D'
#ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
&& *p0 != '/' && *p0 != '/'
#endif #endif
#ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
&& *p0 != '.' && *p0 != '.'
#endif #endif
) )
continue; continue;
if(*p0 == 'A' && *c == 0) { if(*p0 == 'A' && *c == 0) {
@ -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 */
@ -1050,10 +1123,11 @@ static int sendCgi(const char *url,
if(script) { if(script) {
*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,
// get called and make a mess. // use _exit() so no destructors
execve(realpath_buff, argp, config->envp); // get called and make a mess.
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 */