last_patch_109 from Vladimir N. Oleynik
Busybox`s httpd have the defect (from born): ip 1.2.3.1 have true comparing also with 1.2.3.10-1.2.3.19 and 1.2.3.100-1.2.3.199. Last patch removed this bug and added feature: allow/deny rule can support network/netmask example: 1.2.3.0/255.255.255.128 or network/mask_bits example: 1.2.3.0/25 now; old format 1 1.2 1.2.3 1.2.3.4 too support and converted to 1/8 1.2/16 1.2.3/24 1.2.3.4/32 automaticaly. Also, current CVS have small problem: ignores A:IP, (loses 'A', 'a' only work). Corrected.
This commit is contained in:
parent
350733abb8
commit
b65422cf65
@ -49,9 +49,9 @@
|
||||
*
|
||||
* 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:172.20. # Allow address from 172.20.0.0/16
|
||||
* A:10.0.0.0/25 # Allow any address from 10.0.0.0-10.0.0.127
|
||||
* A:10.0.0.0/255.255.255.128 # Allow any address that previous set
|
||||
* 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/
|
||||
@ -75,9 +75,8 @@
|
||||
*
|
||||
* Example:
|
||||
* 1. Allow only specified addresses
|
||||
* 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 previous set and 10.100-109.X.X
|
||||
* A:127.0.0.1 # Allow local loopback connections
|
||||
* D:* # Deny from other IP connections
|
||||
*
|
||||
@ -87,8 +86,7 @@
|
||||
* 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.
|
||||
* any existing settings as if it was appended to the original configuration.
|
||||
*
|
||||
* subdir paths are relative to the containing subdir and thus cannot
|
||||
* affect the parent rules.
|
||||
@ -122,7 +120,7 @@
|
||||
#include "busybox.h"
|
||||
|
||||
|
||||
static const char httpdVersion[] = "busybox httpd/1.28 22-Jun-2003";
|
||||
static const char httpdVersion[] = "busybox httpd/1.30 7-Sep-2003";
|
||||
static const char default_path_httpd_conf[] = "/etc";
|
||||
static const char httpd_conf[] = "httpd.conf";
|
||||
static const char home[] = "./";
|
||||
@ -221,6 +219,13 @@ typedef struct HT_ACCESS {
|
||||
char before_colon[1]; /* really bigger, must last */
|
||||
} Htaccess;
|
||||
|
||||
typedef struct HT_ACCESS_IP {
|
||||
unsigned int ip;
|
||||
unsigned int mask;
|
||||
int allow_deny;
|
||||
struct HT_ACCESS_IP *next;
|
||||
} Htaccess_IP;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
#ifdef CONFIG_FEATURE_HTTPD_CGI
|
||||
@ -234,7 +239,10 @@ typedef struct
|
||||
#endif
|
||||
const char *configFile;
|
||||
|
||||
char rmt_ip[16]; /* for set env REMOTE_ADDR */
|
||||
unsigned int rmt_ip;
|
||||
#if defined(CONFIG_FEATURE_HTTPD_CGI) || defined(DEBUG)
|
||||
char rmt_ip_str[16]; /* for set env REMOTE_ADDR */
|
||||
#endif
|
||||
unsigned port; /* server initial port and for
|
||||
set env REMOTE_PORT */
|
||||
|
||||
@ -242,7 +250,7 @@ typedef struct
|
||||
off_t ContentLength; /* -1 - unknown */
|
||||
time_t last_mod;
|
||||
|
||||
Htaccess *ip_a_d; /* config allow/deny lines */
|
||||
Htaccess_IP *ip_a_d; /* config allow/deny lines */
|
||||
int flg_deny_all;
|
||||
#ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
|
||||
Htaccess *auth; /* config user:password lines */
|
||||
@ -353,7 +361,83 @@ static const char RFC1123FMT[] = "%a, %d %b %Y %H:%M:%S GMT";
|
||||
static const char Content_length[] = "Content-length:";
|
||||
|
||||
|
||||
static int
|
||||
scan_ip (const char **ep, unsigned int *ip, unsigned char endc)
|
||||
{
|
||||
const char *p = *ep;
|
||||
int auto_mask = 8;
|
||||
int j;
|
||||
|
||||
*ip = 0;
|
||||
for (j = 0; j < 4; j++) {
|
||||
unsigned int octet;
|
||||
|
||||
if ((*p < '0' || *p > '9') && (*p != '/' || j == 0) && *p != 0)
|
||||
return -auto_mask;
|
||||
octet = 0;
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
octet *= 10;
|
||||
octet += *p - '0';
|
||||
if (octet > 255)
|
||||
return -auto_mask;
|
||||
p++;
|
||||
}
|
||||
if (*p == '.')
|
||||
p++;
|
||||
if (*p != '/' && *p != 0)
|
||||
auto_mask += 8;
|
||||
*ip = ((*ip) << 8) | octet;
|
||||
}
|
||||
if (*p != 0) {
|
||||
if (*p != endc)
|
||||
return -auto_mask;
|
||||
p++;
|
||||
if(*p == 0)
|
||||
return -auto_mask;
|
||||
}
|
||||
*ep = p;
|
||||
return auto_mask;
|
||||
}
|
||||
|
||||
static int
|
||||
scan_ip_mask (const char *ipm, unsigned int *ip, unsigned int *mask)
|
||||
{
|
||||
int i;
|
||||
unsigned int msk;
|
||||
|
||||
i = scan_ip(&ipm, ip, '/');
|
||||
if(i < 0)
|
||||
return i;
|
||||
if(*ipm) {
|
||||
const char *p = ipm;
|
||||
|
||||
i = 0;
|
||||
while (*p) {
|
||||
if (*p < '0' || *p > '9') {
|
||||
if (*p == '.') {
|
||||
i = scan_ip (&ipm, mask, 0);
|
||||
return i != 32;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
i *= 10;
|
||||
i += *p - '0';
|
||||
p++;
|
||||
}
|
||||
}
|
||||
if (i > 32 || i < 0)
|
||||
return -1;
|
||||
msk = 0x80000000;
|
||||
*mask = 0;
|
||||
while (i > 0) {
|
||||
*mask |= msk;
|
||||
msk >>= 1;
|
||||
i--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FEATURE_HTTPD_BASIC_AUTH) || defined(CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES)
|
||||
static void free_config_lines(Htaccess **pprev)
|
||||
{
|
||||
Htaccess *prev = *pprev;
|
||||
@ -366,6 +450,7 @@ static void free_config_lines(Htaccess **pprev)
|
||||
}
|
||||
*pprev = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* flag */
|
||||
#define FIRST_PARSE 0
|
||||
@ -411,18 +496,29 @@ static void parse_conf(const char *path, int flag)
|
||||
char *c, *p;
|
||||
|
||||
/* free previous ip setup if present */
|
||||
free_config_lines(&config->ip_a_d);
|
||||
Htaccess_IP *pip = config->ip_a_d;
|
||||
|
||||
while( pip ) {
|
||||
Htaccess_IP *cur_ipl = pip;
|
||||
|
||||
pip = cur_ipl->next;
|
||||
free(cur_ipl);
|
||||
}
|
||||
config->ip_a_d = NULL;
|
||||
|
||||
config->flg_deny_all = 0;
|
||||
|
||||
#if defined(CONFIG_FEATURE_HTTPD_BASIC_AUTH) || defined(CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES)
|
||||
/* 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)
|
||||
free_config_lines(&config->auth);
|
||||
#endif
|
||||
; /* appease compiler warnings if option is not set */
|
||||
#ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
|
||||
free_config_lines(&config->mime_a);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if(flag == SUBDIR_PARSE || cf == NULL) {
|
||||
cf = alloca(strlen(path) + sizeof(httpd_conf) + 2);
|
||||
@ -477,7 +573,7 @@ static void parse_conf(const char *path, int flag)
|
||||
|
||||
if(*p0 == 'a')
|
||||
*p0 = 'A';
|
||||
else if(*p0 != 'D'
|
||||
else if(*p0 != 'D' && *p0 != 'A'
|
||||
#ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
|
||||
&& *p0 != '/'
|
||||
#endif
|
||||
@ -486,7 +582,35 @@ static void parse_conf(const char *path, int flag)
|
||||
#endif
|
||||
)
|
||||
continue;
|
||||
if(*p0 == 'A' || *p0 == 'D') {
|
||||
/* storing current config IP line */
|
||||
pip = calloc(1, sizeof(Htaccess_IP));
|
||||
if(pip) {
|
||||
if(scan_ip_mask (c, &(pip->ip), &(pip->mask))) {
|
||||
/* syntax IP{/mask} error detected, protect all */
|
||||
*p0 = 'D';
|
||||
pip->mask = 0;
|
||||
}
|
||||
pip->allow_deny = *p0;
|
||||
if(*p0 == 'D') {
|
||||
/* Deny:form_IP move top */
|
||||
pip->next = config->ip_a_d;
|
||||
config->ip_a_d = pip;
|
||||
} else {
|
||||
/* add to bottom A:form_IP config line */
|
||||
Htaccess_IP *prev_IP = config->ip_a_d;
|
||||
|
||||
if(prev_IP == NULL) {
|
||||
config->ip_a_d = pip;
|
||||
} else {
|
||||
while(prev_IP->next)
|
||||
prev_IP = prev_IP->next;
|
||||
prev_IP->next = pip;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
|
||||
if(*p0 == '/') {
|
||||
/* make full path from httpd root / curent_path / config_line_path */
|
||||
@ -526,8 +650,9 @@ static void parse_conf(const char *path, int flag)
|
||||
sprintf(p0, "%s:%s", p0, c);
|
||||
}
|
||||
#endif
|
||||
/* storing current config line */
|
||||
|
||||
#if defined(CONFIG_FEATURE_HTTPD_BASIC_AUTH) || defined(CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES)
|
||||
/* storing current config line */
|
||||
cur = calloc(1, sizeof(Htaccess) + strlen(p0));
|
||||
if(cur) {
|
||||
cf = strcpy(cur->before_colon, p0);
|
||||
@ -538,24 +663,6 @@ static void parse_conf(const char *path, int flag)
|
||||
if(*cf == '/')
|
||||
free(p0);
|
||||
#endif
|
||||
if(*cf == 'A' || *cf == 'D') {
|
||||
if(*cf == 'D') {
|
||||
/* Deny:form_IP move top */
|
||||
cur->next = config->ip_a_d;
|
||||
config->ip_a_d = cur;
|
||||
} else {
|
||||
/* add to bottom A:form_IP config line */
|
||||
Htaccess *prev_IP = config->ip_a_d;
|
||||
|
||||
if(prev_IP == NULL) {
|
||||
config->ip_a_d = cur;
|
||||
} else {
|
||||
while(prev_IP->next)
|
||||
prev_IP = prev_IP->next;
|
||||
prev_IP->next = cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
|
||||
else if(*cf == '.') {
|
||||
/* config .mime line move top for overwrite previous */
|
||||
@ -594,6 +701,7 @@ static void parse_conf(const char *path, int flag)
|
||||
prev = cur;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -1100,10 +1208,10 @@ static int sendCgi(const char *url,
|
||||
addEnv("SERVER", "PROTOCOL", "HTTP/1.0");
|
||||
addEnv("GATEWAY_INTERFACE", "", "CGI/1.1");
|
||||
#ifdef CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
|
||||
addEnv("REMOTE", "ADDR", config->rmt_ip);
|
||||
addEnv("REMOTE", "ADDR", config->rmt_ip_str);
|
||||
addEnvPort("REMOTE");
|
||||
#else
|
||||
addEnv("REMOTE_ADDR", "", config->rmt_ip);
|
||||
addEnv("REMOTE_ADDR", "", config->rmt_ip_str);
|
||||
#endif
|
||||
if(bodyLen) {
|
||||
char sbl[32];
|
||||
@ -1288,17 +1396,45 @@ static int sendFile(const char *url, char *buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int checkPermIP(void)
|
||||
{
|
||||
Htaccess_IP * cur;
|
||||
|
||||
/* This could stand some work */
|
||||
for (cur = config->ip_a_d; cur; cur = cur->next) {
|
||||
#ifdef DEBUG
|
||||
if (config->debugHttpd) {
|
||||
fprintf(stderr, "checkPermIP: '%s' ? ", config->rmt_ip_str);
|
||||
fprintf(stderr, "'%u.%u.%u.%u/%u.%u.%u.%u'\n",
|
||||
(unsigned char)(cur->ip >> 24),
|
||||
(unsigned char)(cur->ip >> 16),
|
||||
(unsigned char)(cur->ip >> 8),
|
||||
cur->ip & 0xff,
|
||||
(unsigned char)(cur->mask >> 24),
|
||||
(unsigned char)(cur->mask >> 16),
|
||||
(unsigned char)(cur->mask >> 8),
|
||||
cur->mask & 0xff);
|
||||
}
|
||||
#endif
|
||||
if((config->rmt_ip & cur->mask) == cur->ip)
|
||||
return cur->allow_deny == 'A'; /* Allow/Deny */
|
||||
}
|
||||
|
||||
/* if uncofigured, return 1 - access from all */
|
||||
return !config->flg_deny_all;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
> $Function: checkPerm()
|
||||
*
|
||||
* $Description: Check the permission file for access.
|
||||
* $Description: Check the permission file for access password protected.
|
||||
*
|
||||
* If config file isn't present, everything is allowed.
|
||||
* Entries are of the form you can see example from header source
|
||||
*
|
||||
* $Parameters:
|
||||
* (const char *) path . . . . The file path or NULL for ip addresses.
|
||||
* (const char *) path . . . . The file path.
|
||||
* (const char *) request . . . User information to validate.
|
||||
*
|
||||
* $Return: (int) . . . . . . . . . 1 if request OK, 0 otherwise.
|
||||
@ -1312,25 +1448,19 @@ static int checkPerm(const char *path, const char *request)
|
||||
const char *p;
|
||||
const char *p0;
|
||||
|
||||
int ipaddr = path == NULL;
|
||||
const char *prev = NULL;
|
||||
|
||||
/* This could stand some work */
|
||||
for (cur = ipaddr ? config->ip_a_d : config->auth; cur; cur = cur->next) {
|
||||
for (cur = config->auth; cur; cur = cur->next) {
|
||||
p0 = cur->before_colon;
|
||||
if(prev != NULL && strcmp(prev, p0) != 0)
|
||||
continue; /* find next identical */
|
||||
p = cur->after_colon;
|
||||
#ifdef DEBUG
|
||||
if (config->debugHttpd)
|
||||
fprintf(stderr,"checkPerm: '%s' ? '%s'\n",
|
||||
(ipaddr ? (*p ? p : "*") : p0), request);
|
||||
fprintf(stderr,"checkPerm: '%s' ? '%s'\n", p0, request);
|
||||
#endif
|
||||
if(ipaddr) {
|
||||
if(strncmp(p, request, strlen(p)) != 0)
|
||||
continue;
|
||||
return *p0 == 'A'; /* Allow/Deny */
|
||||
} else {
|
||||
{
|
||||
int l = strlen(p0);
|
||||
|
||||
if(strncmp(p0, path, l) == 0 &&
|
||||
@ -1372,33 +1502,9 @@ static int checkPerm(const char *path, const char *request)
|
||||
}
|
||||
} /* for */
|
||||
|
||||
if(ipaddr)
|
||||
return !config->flg_deny_all;
|
||||
return prev == NULL;
|
||||
}
|
||||
|
||||
#else /* ifndef CONFIG_FEATURE_HTTPD_BASIC_AUTH */
|
||||
static int checkPermIP(const char *request)
|
||||
{
|
||||
Htaccess * cur;
|
||||
const char *p;
|
||||
|
||||
/* This could stand some work */
|
||||
for (cur = config->ip_a_d; cur; cur = cur->next) {
|
||||
p = cur->after_colon;
|
||||
#ifdef DEBUG
|
||||
if (config->debugHttpd)
|
||||
fprintf(stderr, "checkPerm: '%s' ? '%s'\n",
|
||||
(*p ? p : "*"), request);
|
||||
#endif
|
||||
if(strncmp(p, request, strlen(p)) == 0)
|
||||
return *cur->before_colon == 'A'; /* Allow/Deny */
|
||||
}
|
||||
|
||||
/* if uncofigured, return 1 - access from all */
|
||||
return !config->flg_deny_all;
|
||||
}
|
||||
#define checkPerm(null, request) checkPermIP(request)
|
||||
#endif /* CONFIG_FEATURE_HTTPD_BASIC_AUTH */
|
||||
|
||||
|
||||
@ -1518,14 +1624,14 @@ BAD_REQUEST:
|
||||
#endif
|
||||
|
||||
test = url;
|
||||
ip_allowed = checkPerm(NULL, config->rmt_ip);
|
||||
ip_allowed = checkPermIP();
|
||||
while(ip_allowed && (test = strchr( test + 1, '/' )) != NULL) {
|
||||
/* have path1/path2 */
|
||||
*test = '\0';
|
||||
if( is_directory(url + 1, 1, &sb) ) {
|
||||
/* may be having subdir config */
|
||||
parse_conf(url + 1, SUBDIR_PARSE);
|
||||
ip_allowed = checkPerm(NULL, config->rmt_ip);
|
||||
ip_allowed = checkPermIP();
|
||||
}
|
||||
*test = '/';
|
||||
}
|
||||
@ -1679,7 +1785,6 @@ static int miniHttpd(int server)
|
||||
int on;
|
||||
struct sockaddr_in fromAddr;
|
||||
|
||||
unsigned int addr;
|
||||
socklen_t fromAddrLen = sizeof(fromAddr);
|
||||
int s = accept(server,
|
||||
(struct sockaddr *)&fromAddr, &fromAddrLen);
|
||||
@ -1688,19 +1793,22 @@ static int miniHttpd(int server)
|
||||
continue;
|
||||
}
|
||||
config->accepted_socket = s;
|
||||
addr = ntohl(fromAddr.sin_addr.s_addr);
|
||||
sprintf(config->rmt_ip, "%u.%u.%u.%u",
|
||||
(unsigned char)(addr >> 24),
|
||||
(unsigned char)(addr >> 16),
|
||||
(unsigned char)(addr >> 8),
|
||||
addr & 0xff);
|
||||
config->rmt_ip = ntohl(fromAddr.sin_addr.s_addr);
|
||||
#if defined(CONFIG_FEATURE_HTTPD_CGI) || defined(DEBUG)
|
||||
sprintf(config->rmt_ip_str, "%u.%u.%u.%u",
|
||||
(unsigned char)(config->rmt_ip >> 24),
|
||||
(unsigned char)(config->rmt_ip >> 16),
|
||||
(unsigned char)(config->rmt_ip >> 8),
|
||||
config->rmt_ip & 0xff);
|
||||
config->port = ntohs(fromAddr.sin_port);
|
||||
#ifdef DEBUG
|
||||
if (config->debugHttpd) {
|
||||
bb_error_msg("connection from IP=%s, port %u\n",
|
||||
config->rmt_ip, config->port);
|
||||
config->rmt_ip_str, config->port);
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_FEATURE_HTTPD_CGI */
|
||||
|
||||
/* set the KEEPALIVE option to cull dead connections */
|
||||
on = 1;
|
||||
setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof (on));
|
||||
@ -1729,15 +1837,16 @@ static int miniHttpd(void)
|
||||
{
|
||||
struct sockaddr_in fromAddrLen;
|
||||
socklen_t sinlen = sizeof (struct sockaddr_in);
|
||||
unsigned int addr;
|
||||
|
||||
getpeername (0, (struct sockaddr *)&fromAddrLen, &sinlen);
|
||||
addr = ntohl(fromAddrLen.sin_addr.s_addr);
|
||||
sprintf(config->rmt_ip, "%u.%u.%u.%u",
|
||||
(unsigned char)(addr >> 24),
|
||||
(unsigned char)(addr >> 16),
|
||||
(unsigned char)(addr >> 8),
|
||||
addr & 0xff);
|
||||
config->rmt_ip = ntohl(fromAddrLen.sin_addr.s_addr);
|
||||
#if defined(CONFIG_FEATURE_HTTPD_CGI) || defined(DEBUG)
|
||||
sprintf(config->rmt_ip_str, "%u.%u.%u.%u",
|
||||
(unsigned char)(config->rmt_ip >> 24),
|
||||
(unsigned char)(config->rmt_ip >> 16),
|
||||
(unsigned char)(config->rmt_ip >> 8),
|
||||
config->rmt_ip & 0xff);
|
||||
#endif
|
||||
config->port = ntohs(fromAddrLen.sin_port);
|
||||
handleIncoming();
|
||||
return 0;
|
||||
@ -1750,12 +1859,12 @@ static void sighup_handler(int sig)
|
||||
/* set and reset */
|
||||
struct sigaction sa;
|
||||
|
||||
parse_conf(default_path_httpd_conf,
|
||||
sig == SIGHUP ? SIGNALED_PARSE : FIRST_PARSE);
|
||||
sa.sa_handler = sighup_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
parse_conf(default_path_httpd_conf,
|
||||
sig == SIGHUP ? SIGNALED_PARSE : FIRST_PARSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user