[BusyBox-cvs] busybox/networking httpd.c,1.12,1.13

Glenn McGrath bug1 at busybox.net
Mon Sep 8 10:59:31 UTC 2003


Update of /var/cvs/busybox/networking
In directory winder:/tmp/cvs-serv31442/networking

Modified Files:
	httpd.c 
Log Message:
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.


Index: httpd.c
===================================================================
RCS file: /var/cvs/busybox/networking/httpd.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- httpd.c	29 Aug 2003 15:53:23 -0000	1.12
+++ httpd.c	8 Sep 2003 10:59:27 -0000	1.13
@@ -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 @@
 	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 @@
 #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 @@
   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 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 @@
     }
     *pprev = NULL;
 }
+#endif
 
 /* flag */
 #define FIRST_PARSE          0
@@ -411,18 +496,29 @@
     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 @@
 
 	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 @@
 #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 @@
 	    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 @@
 	    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 */
@@ -595,6 +702,7 @@
 		}
 	    }
 #endif
+#endif
 	}
    }
    fclose(f);
@@ -1100,10 +1208,10 @@
       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 @@
   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 @@
     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 @@
 	}
     }   /* 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 @@
 #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 @@
 	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 @@
 	    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 @@
 {
   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 @@
 	/* 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
 




More information about the busybox-cvs mailing list