$OpenBSD: patch-src_sgDiv_c,v 1.1.1.1 2007/06/02 15:26:54 aanriot Exp $
--- src/sgDiv.c.orig	Sun Apr 15 09:48:19 2007
+++ src/sgDiv.c	Wed May 23 17:58:33 2007
@@ -20,6 +20,7 @@
 
 #include "sg.h"
 #include "sgEx.h"
+#include "HTEscape.h"
 
 /* #define METEST 8; */
 
@@ -94,6 +95,8 @@ int parseLine(line, s)
 {
   char *p, *d = NULL, *a = NULL, *e = NULL, *o, *field;
   int i = 0;
+  int report_once = 1;
+  size_t strsz;
   char c;
   int ndx = 0;
   
@@ -126,22 +129,28 @@ int parseLine(line, s)
     */
     /* Fix for multiple slash vulnerability (bug1). */
     /* Check if there are still two or more slashes in sequence which must not happen */
-    int report_once = 1;
+    strsz = strlen(p);
 
-    /* loop thru the string 'p' until the char '?' is hit */
+    /* loop thru the string 'p' until the char '?' is hit or the "end" is hit */
     while('?' != p[ndx] && '\0' != p[ndx])
     {
-      /* if this char and the next char are slashes, 
-         then shift the rest of the string left one char */
-      if('/' == p[ndx] && '/' == p[ndx+1])
-      {
-        size_t sz = strlen(p+ndx+1);
-        strncpy(p+ndx,p+ndx+1, sz);
-        p[ndx+sz] = '\0';
-        if(1 == report_once) {
-          sgLogError("Warning: Possible bypass attempt. Found multiple slashes where only one is expected: %s", s->orig);
-          report_once--;
+        /* in case this is a '://' skip over it, but try to not read past EOS */
+        if(3 <= strsz-ndx) {
+          if(':' == p[ndx] && '/' == p[ndx+1] && '/' == p[ndx+2]) {
+           ndx+=3; /* 3 == strlen("://"); */
+          }
         }
+        
+       /* if this char and the next char are slashes,
+ *           then shift the rest of the string left one char */
+       if('/' == p[ndx] && '/' == p[ndx+1]) {
+         size_t sz = strlen(p+ndx+1);
+         strncpy(p+ndx,p+ndx+1, sz);
+         p[ndx+sz] = '\0';
+          if(1 == report_once) {
+            sgLogError("Warning: Possible bypass attempt. Found multiple slashes where only one is expected: %s", s->orig);
+            report_once--;
+          }
       }
       else
       {
@@ -537,13 +546,13 @@ char *sgRegExpSubst(regexp, pattern)
 #endif
 {
   struct sgRegExp *re;
-  regmatch_t pm;
+  regmatch_t pm[10];
   static char newstring[MAX_BUF];
   char *result = NULL, *p;
   int substlen;
   *newstring='\0';
   for(re = regexp; re != NULL; re = re->next){
-    if (regexec (re->compiled, pattern, 1, &pm, 0) != 0){
+    if (regexec (re->compiled, pattern, sizeof(pm) / sizeof(pm[0]), pm, 0) != 0){
       result = NULL;
     } else {
       substlen = strlen(re->substitute);
@@ -553,21 +562,73 @@ char *sgRegExpSubst(regexp, pattern)
 	*newstring = '\0';
       p = newstring;
       do {
-	if((p - newstring)+ pm.rm_so  >= MAX_BUF)
+	if((p - newstring)+ pm[0].rm_so  >= MAX_BUF)
 	  break;
-	p = strncat(newstring,pattern,pm.rm_so);
-	if((p - newstring)+ substlen  >= MAX_BUF)
-	  break;
-	p = strcat(newstring,re->substitute);	
-	pattern = pattern + pm.rm_eo;
-      } while(regexec (re->compiled, pattern, 1, &pm, REG_NOTBOL)== 0 &&
-	      re->global);
+	p = strncat(newstring,pattern,pm[0].rm_so);
+	{
+	    char *p_cur;
+	    char *p_next;
+
+	    for (p_next = p_cur = re->substitute;
+	       p_next < (re->substitute + substlen);
+	       p_next++)
+	    {
+	       if (*p_next == '\\')
+	       {
+	           if (p_cur < p_next)
+		   {
+		       if (((p - newstring) + (p_next - p_cur)) >= MAX_BUF)
+			   goto err;
+                       p = strncat(newstring, p_cur, p_next - p_cur);
+                   }
+                   p_next++;
+                   if (p_next < (re->substitute + substlen)
+                       && '0' <= *p_next && *p_next <= '9')
+                   {
+                       int i = *p_next - '0';
+                       if ((p - newstring) + (pm[i].rm_eo - pm[i].rm_so) >= MAX_BUF)
+                           goto err;
+                       p = strncat(newstring, pattern + pm[i].rm_so, pm[i].rm_eo - pm[i].rm_so);
+                   }
+                   else
+                   {
+                       if ((p - newstring + 1) >= MAX_BUF)
+                           goto err;
+                       p = strncat(newstring, p_next, 1);
+                   }
+                   p_cur = p_next + 1;
+               }
+               else if (*p_next == '&')
+               {
+                   if (p_cur < p_next)
+                   {
+                       if (((p - newstring) + (p_next - p_cur)) >= MAX_BUF)
+                           goto err;
+                       p = strncat(newstring, p_cur, p_next - p_cur);
+                   }
+                   if (((p - newstring) + (pm[0].rm_eo - pm[0].rm_so)) >= MAX_BUF)
+                       goto err;
+                   p = strncat(newstring, pattern + pm[0].rm_so, pm[0].rm_eo - pm[0].rm_so);
+                   p_cur = p_next + 1;
+               }
+           }
+           if (p_cur < p_next)
+           {
+               if (((p - newstring) + (p_next - p_cur)) >= MAX_BUF)
+                   goto err;
+               p = strncat(newstring, p_cur, p_next - p_cur);
+           }
+       }
+       pattern = pattern + pm[0].rm_eo;
+      } while(regexec (re->compiled, pattern, sizeof(pm) / sizeof(pm[0]), pm, REG_NOTBOL)== 0 &&
+              re->global);
       if((p - newstring)+ strlen(pattern)  <= MAX_BUF)
 	p = strcat(newstring,pattern);
       result = newstring;
       break;
     }
   }
+err:
   return result;
 }
 
