$OpenBSD: patch-unix_unix_c,v 1.2 2003/08/17 23:48:40 brad Exp $
--- unix/unix.c.orig	2002-01-21 17:54:42.000000000 -0500
+++ unix/unix.c	2003-08-17 19:25:19.000000000 -0400
@@ -421,7 +421,8 @@ int mapname(__G__ renamed)
  */
 {
     char pathcomp[FILNAMSIZ];      /* path-component buffer */
-    char *pp, *cp=(char *)NULL;    /* character pointers */
+    char *pp, *cp=(char *)NULL,    /* character pointers */
+         *dp=(char *)NULL;
     char *lastsemi=(char *)NULL;   /* pointer to last semi-colon in pathcomp */
 #ifdef ACORN_FTYPE_NFS
     char *lastcomma=(char *)NULL;  /* pointer to last comma in pathcomp */
@@ -429,6 +430,8 @@ int mapname(__G__ renamed)
 #endif
     int quote = FALSE;             /* flags */
     int killed_ddot = FALSE;       /* is set when skipping "../" pathcomp */
+    int killed_qslash = FALSE;     /* is set when skipping "^V/" pathcomp */
+    int snarf_ddot = FALSE;	   /* Is set while scanning for "../" */
     int error = MPN_OK;
     register unsigned workch;      /* hold the character being tested */
 
@@ -467,6 +470,18 @@ int mapname(__G__ renamed)
     while ((workch = (uch)*cp++) != 0) {
 
         if (quote) {                 /* if character quoted, */
+	    if (pp == pathcomp) {
+		quote = FALSE;
+		if (workch == '.')
+		    /* Oh no you don't... */
+	   	    goto ddot_hack;
+	        if (workch == '/') {
+		    /* We *never* allow quote-slash at the beginning */
+		    killed_qslash = TRUE;
+		    continue;
+		}
+	    }
+		
             *pp++ = (char)workch;    /*  include it literally */
             quote = FALSE;
         } else
@@ -481,15 +496,45 @@ int mapname(__G__ renamed)
                 break;
 
             case '.':
-                if (pp == pathcomp) {   /* nothing appended yet... */
+                if (pp == pathcomp) {
+ddot_hack:
+		    /* nothing appended yet... */
                     if (*cp == '/') {   /* don't bother appending "./" to */
                         ++cp;           /*  the path: skip behind the '/' */
                         break;
-                    } else if (!uO.ddotflag && *cp == '.' && cp[1] == '/') {
-                        /* "../" dir traversal detected */
-                        cp += 2;        /*  skip over behind the '/' */
-                        killed_ddot = TRUE; /*  set "show message" flag */
-                        break;
+                    } else if (!uO.ddotflag) {
+
+			/*
+			 * SECURITY: Skip past control characters if the user
+			 * didn't OK use of absolute pathnames. lhh - this is
+			 * a very quick, ugly, inefficient fix; it traverses
+			 * the WHOLE path, eating up these as it comes to it.
+			 */
+			dp = cp;
+			do {
+			    workch = (uch)(*dp);
+			    if (workch == '/' && snarf_ddot) {
+                                /* "../" dir traversal detected */
+                                cp = dp + 1;      /* skip past the '/' */
+                                killed_ddot = TRUE; /* set "show msg" flag */
+                                break;
+                            } else if (workch == '.' && !snarf_ddot) {
+				snarf_ddot = TRUE;
+                	    } else if (isprint(workch) ||
+				       ((workch > 127) && (workch <= 254))) {
+				/*
+				 * Since we found a printable, non-ctrl char,
+				 * we can stop looking for '../', the amount
+				 * in ../!
+				 */
+			        break;
+			    }
+
+			    dp++;
+                        } while (*dp != 0);
+
+			if (killed_ddot)
+			    break;
                     }
                 }
                 *pp++ = '.';
@@ -534,6 +579,16 @@ int mapname(__G__ renamed)
             error = (error & MPN_MASK) | PK_WARN;
     }
 
+    /* Show warning when stripping insecure quoted-slash at beginning of
+       path components */
+    if (killed_qslash && QCOND2) {
+        Info(slide, 0, ((char *)slide,
+          "warning:  skipped root directory component(s) in %s\n",
+          FnFilter1(G.filename)));
+        if (!(error & ~MPN_MASK))
+            error = (error & MPN_MASK) | PK_WARN;
+    }
+
 /*---------------------------------------------------------------------------
     Report if directory was created (and no file to create:  filename ended
     in '/'), check name to be sure it exists, and combine path and name be-
