-- 
5 GB Mailbox, 50 FreeSMS http://www.gmx.net/de/go/promail
+++ GMX - die erste Adresse für Mail, Message, More +++
--- unzoo.c.orig        2005-05-17 11:34:37.577239432 +0200
+++ unzoo.c     2005-05-17 11:34:02.499572048 +0200
@@ -2479,7 +2479,7 @@
 
 /****************************************************************************
 **
-*F  ExtrArch(<bim>,<out>,<ovr>,<pre>,<arc>,<filec>,<files>) . extract members
+*F  ExtrArch(<bim>,<out>,<ovr>,<pre>,<frc>,<arc>,<filec>,<files>) . extract 
members
 **
 **  'ExtrArch' extracts the members  of the archive with  the name <arc> that
 **  match one  of the file name  patterns '<files>[0] .. <files>[<filec>-1]'.
@@ -2491,12 +2491,15 @@
 **  stdout, i.e., to the screen.  and if it  is 2, the members are extracted.
 **  If <ovr> is 0, members will not overwrite  existing files; otherwise they
 **  will.  <pre> is a prefix that is prepended to all path names.
+**  <frc> is 1 if the user requested extraction of members even if this would
+** result in a directory traversal.
 */
-int             ExtrArch ( bim, out, ovr, pre, arc, filec, files )
+int             ExtrArch ( bim, out, ovr, pre, frc, arc, filec, files )
     unsigned long       bim;
     unsigned long       out;
     unsigned long       ovr;
     char *              pre;
+    unsigned long       frc;
     char *              arc;
     unsigned long       filec;
     char *              files [];
@@ -2582,6 +2585,94 @@
             continue;
         }
 
+        /* check the path for directory traversal                          */
+        if (frc != 1) {
+            /* but only if the user did not request otherwise              */
+
+            /* building the universal path of this member                  */
+            char patu [sizeof(Entry.diru) + sizeof(Entry.namu) + 1];
+            strcpy( patu, Entry.diru );
+            if ( strlen(patu) && patu[strlen(patu)-1] != '/') strcat( patu, 
"/" );
+            strcat( patu, (Entry.lnamu ? Entry.namu : Entry.nams) );
+
+            int found_trav = 0;
+
+            if ( strstr( patu, "/../" )) {
+                found_trav = 1;
+
+                /* remove "/../" from the path                             */
+                char tmp [sizeof(patu)];
+                char *p;
+                char *q;
+                memset(tmp, 0, sizeof(tmp));
+                q = patu;
+
+                while ( !strncmp(q, "/../", 4) ) {
+                    q += 3;
+                }
+                if (q[0] == '/') q++;
+
+                while ((p = strstr( q, "/../" )) != NULL) {
+                    if (q[0] == '/') q++;
+                    if (p > q) strncat(tmp, q, p-q);
+                    if (tmp[strlen(tmp)-1] != '/') strcat(tmp, "/");
+                    p += 3;
+                    q = p;
+                }
+                strncat(tmp, q+1, patu + strlen(patu) - q);
+                strcpy(patu, tmp);
+
+                printf("unzoo: skipped \"/../\" path component(s) in '%s'\n", 
Entry.patl);
+            }
+            if ( *patu == '/' && !strlen( pre ) ) {
+                found_trav = 1;
+
+                char *p = malloc(sizeof(patu));
+                char *q = p;
+                memset(p, 0, sizeof(patu));
+                strcpy(p, patu);
+                while ( q[0] == '/' ) q++;
+                strcpy(patu, q);
+                free(p);
+
+                printf("unzoo: skipped root directory path component in 
'%s'\n", patl);
+            }
+            if ( !strncmp( patu, "../", 3 )) {
+                found_trav = 1;
+
+                char tmp [sizeof(patu)];
+                memset(tmp, 0, sizeof(tmp));
+                strcpy(tmp, patu + 3);
+                strcpy(patu, tmp);
+
+                printf("unzoo: skipped \"../\" path component in '%s'\n", 
patl);
+            }
+
+            if (found_trav) {
+                /* patu contains the sanitized 'universal' path, i.e.      */
+                /* separated by '/' characters, including the file name.   */
+
+                char *f = strrchr( patu, '/' );
+                *f++ = '\0';
+                /* Now, patu points to the directory part, f to the file   */
+
+                strcpy( Entry.diru, patu );
+                strcpy( (Entry.lnamu ? Entry.namu : Entry.nams), f );
+
+                /* convert the names to local format                       */
+                if ( Entry.system == 0 || Entry.system == 2 ) {
+                    CONV_DIRE( Entry.dirl, Entry.diru );
+                    CONV_NAME( Entry.naml, (Entry.lnamu ? Entry.namu : 
Entry.nams) );
+                }
+                else {
+                    strcpy( Entry.dirl, Entry.diru );
+                    strcpy( Entry.naml, (Entry.lnamu ? Entry.namu : 
Entry.nams) );
+                }
+                strcpy( Entry.patl, Entry.dirl );
+                strcat( Entry.patl, Entry.naml );
+            }
+        }
+
         /* check that such a file does not already exist                   */
         strcpy( patl, pre );  strcat( patl, Entry.patl );
         if ( out == 2 && ovr == 0 && OpenReadFile(patl,0L) ) {
@@ -2740,7 +2831,7 @@
     printf("  <file>: list only files matching at least one pattern,\n");
     printf("          '?' matches any char, '*' matches any string.\n");
     printf("\n");
-    printf("unzoo -x [-abnpo] [-j <prefix>] <archive>[.zoo] [<file>..]\n");
+    printf("unzoo -x [-abnpo] [-t] [-j <prefix>] <archive>[.zoo] 
[<file>..]\n");
     printf("  extract the members of the archive\n");
     printf("  -a:  extract all members as text files ");
     printf("(not only those with !TEXT! comments)\n");
@@ -2750,6 +2841,10 @@
     printf("  -p:  extract to stdout\n");
     printf("  -o:  extract over existing files\n");
     printf("  -j:  extract to '<prefix><membername>'\n");
+    printf("  -f:  force extraction of members to their original locations\n");
+    printf("       even if this results in files extracted outside the\n");
+    printf("       working directory. THIS COULD POTENTIALLY OVERWRITE\n");
+    printf("       IMPORTANT FILES, SO USE WITH CARE!\n");
     printf("  <file>: extract only files matching at least one pattern,\n");
     printf("          '?' matches any char, '*' matches any string.\n");
     return 1;
@@ -2773,6 +2868,7 @@
     unsigned long       bim;            /* extraction mode option          */
     unsigned long       out;            /* output destination option       */
     unsigned long       ovr;            /* overwrite file option           */
+    unsigned long       frc;            /* force extraction option         */
     char *              pre;            /* prefix to prepend to path names */
     char                argl [256];     /* interactive command line        */
     int                 argd;           /* interactive command count       */
@@ -2792,7 +2888,7 @@
     do {
 
         /* scan the command line arguments                                 */
-        cmd = 1;  ver = 0;  bim = 0;  out = 2;  ovr = 0;
+        cmd = 1;  ver = 0;  bim = 0;  out = 2;  ovr = 0; frc = 0;
         pre = "";
         while ( 1 < argc && argv[1][0] == '-' ) {
             if ( argv[1][2] != '\0' )  cmd = 0;
@@ -2802,6 +2898,7 @@
             case 'x': case 'X': if ( cmd != 0 )  cmd = 2;            break;
             case 'a': case 'A': if ( cmd != 2 )  cmd = 0;  bim = 1;  break;
             case 'b': case 'B': if ( cmd != 2 )  cmd = 0;  bim = 2;  break;
+            case 'f': case 'F': if ( cmd != 2 )  cmd = 0;  frc = 1; break;
             case 'n': case 'N': if ( cmd != 2 )  cmd = 0;  out = 0;  break;
             case 'p': case 'P': if ( cmd != 2 )  cmd = 0;  out = 1;  break;
             case 'o': case 'O': if ( cmd != 2 )  cmd = 0;  ovr = 1;  break;
@@ -2818,7 +2915,7 @@
             res = ListArch( ver, argv[1],
                             (unsigned long)argc-2, argv+2 );
         else if ( cmd == 2 && 1 < argc )
-            res = ExtrArch( bim, out, ovr, pre, argv[1],
+            res = ExtrArch( bim, out, ovr, pre, frc, argv[1],
                             (unsigned long)argc-2, argv+2 );
         else
             res = HelpArch();

Reply via email to