*
* The server can also be invoked as a url arg decoder and html text encoder
* 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 "<Hello World>"
+ * 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:
+ *
+ * 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 <ctype.h> /* for isspace */
#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 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
// if something bad happens due to a malformed user request.
/* CGI environ size */
#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
#define ENVSIZE 15 /* minimal requires */
#endif
#define SUBDIR_PARSE 1
#define SIGNALED_PARSE 2
#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)
{
FILE *f;
#endif
const char *cf = config->configFile;
- char buf[80];
+ char buf[160];
char *p0 = NULL;
char *c, *p;
- /* free previous setuped */
+ /* free previous ip setup if present */
free_config_lines(&config->ip_a_d);
+ /* retain previous auth and mime config only for subdir parse */
if(flag != SUBDIR_PARSE) {
#ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
free_config_lines(&config->auth)
#endif
- ; /* syntax confuse */
+ ; /* appease compiler warnings if option is not set */
#ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
free_config_lines(&config->mime_a);
#endif
while((f = fopen(cf, "r")) == NULL) {
if(flag != FIRST_PARSE) {
- /* config file not found */
+ /* config file not found, no changes to config */
return;
}
if(config->configFile) /* if -c option given */
prev = config->auth;
#endif
/* This could stand some work */
- while ( (p0 = fgets(buf, 80, f)) != NULL) {
+ while ( (p0 = fgets(buf, sizeof(buf), f)) != NULL) {
c = NULL;
for(p = p0; *p0 != 0 && *p0 != '#'; p0++) {
if(!isspace(*p0)) {
if(*c == '*')
*c = 0; /* Allow all */
p0 = buf;
+ if((*p0 == 'i') || (*p0 == 'I'))
+ *p0 = 'A'; // version 1.1/1.2 compatibility for ip:
if(*p0 == 'a')
*p0 = 'A';
if(*p0 == 'd')
*p0 = 'D';
if(*p0 != 'A' && *p0 != 'D'
#ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
- && *p0 != '/'
+ && *p0 != '/'
#endif
#ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
- && *p0 != '.'
+ && *p0 != '.'
#endif
- )
+ )
continue;
if(*p0 == 'A' && *c == 0) {
{
char *args;
char *memargs;
+ char *namelist; /* space separated list of arg names */
if (pargs==0) return;
/* args are a list of name=value&name2=value2 sequences */
+ namelist = (char *) malloc(strlen(pargs));
+ if (namelist) namelist[0]=0;
memargs = args = strdup(pargs);
while (args && *args) {
const char *name = args;
if (args)
*args++ = 0;
addEnv("CGI", name, decodeString(value, 1));
+ if (*namelist) strcat(namelist, " ");
+ strcat(namelist,name);
}
free(memargs);
+ if (namelist) {
+ addEnv("CGI","ARGLIST_",namelist);
+ free(namelist);
+ }
}
#endif /* CONFIG_FEATURE_HTTPD_SET_CGI_VARS_TO_ENV */
if(script) {
*script = '\0';
if(chdir(realpath_buff) == 0) {
- *script = '/';
- // now run the program. If it fails, use _exit() so no destructors
- // get called and make a mess.
- execve(realpath_buff, argp, config->envp);
+ *script = '/';
+ // now run the program. If it fails,
+ // use _exit() so no destructors
+ // get called and make a mess.
+ execve(realpath_buff, argp, config->envp);
}
}
}
exit(0);
}
close(s);
+#ifdef TEST
+ return 0; // exit after processing one request
+#endif
}
}
} // while (1)
#endif
{
const char *home_httpd = home;
+#ifdef TEST
+ const char *testArgs[5];
+ int numTestArgs=0;
+#endif
#ifndef CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY
int server;
#ifdef CONFIG_FEATURE_HTTPD_SETUID
"u:"
#endif
+#ifdef TEST
+ "t:"
+#endif
);
if (c == EOF) break;
switch (c) {
}
break;
#endif
+#ifdef TEST
+ case 't':
+ testArgs[numTestArgs++]=optarg;
+ break;
+#endif
default:
bb_error_msg("%s", httpdVersion);
bb_show_usage();
parse_conf(default_path_httpd_conf, FIRST_PARSE);
#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
if (!config->debugHttpd) {
if (daemon(1, 0) < 0) /* don`t change curent directory */