Imported Upstream version 7.59.0
[platform/upstream/curl.git] / src / tool_urlglob.c
index b6d5591..f78d058 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * are also available at https://curl.haxx.se/docs/copyright.html.
  *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  ***************************************************************************/
 #include "tool_setup.h"
 
-#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
-#include <curl/mprintf.h>
-
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+#include "tool_cfgable.h"
+#include "tool_doswin.h"
 #include "tool_urlglob.h"
 #include "tool_vms.h"
 
@@ -42,12 +44,12 @@ static CURLcode glob_fixed(URLGlob *glob, char *fixed, size_t len)
   pat->content.Set.ptr_s = 0;
   pat->globindex = -1;
 
-  pat->content.Set.elements = malloc(sizeof(char*));
+  pat->content.Set.elements = malloc(sizeof(char *));
 
   if(!pat->content.Set.elements)
     return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY);
 
-  pat->content.Set.elements[0] = malloc(len+1);
+  pat->content.Set.elements[0] = malloc(len + 1);
   if(!pat->content.Set.elements[0])
     return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY);
 
@@ -64,6 +66,10 @@ static CURLcode glob_fixed(URLGlob *glob, char *fixed, size_t len)
 static int multiply(unsigned long *amount, long with)
 {
   unsigned long sum = *amount * with;
+  if(!with) {
+    *amount = 0;
+    return 0;
+  }
   if(sum/with != *amount)
     return 1; /* didn't fit, bail out */
   *amount = sum;
@@ -107,7 +113,7 @@ static CURLcode glob_set(URLGlob *glob, char **patternp,
                          CURLE_URL_MALFORMAT);
 
       /* add 1 to size since it'll be incremented below */
-      if(multiply(amount, pat->content.Set.size+1))
+      if(multiply(amount, pat->content.Set.size + 1))
         return GLOBERROR("range overflow", 0, CURLE_URL_MALFORMAT);
 
       /* fall-through */
@@ -116,14 +122,14 @@ static CURLcode glob_set(URLGlob *glob, char **patternp,
       *buf = '\0';
       if(pat->content.Set.elements) {
         char **new_arr = realloc(pat->content.Set.elements,
-                                 (pat->content.Set.size + 1) * sizeof(char*));
+                                 (pat->content.Set.size + 1) * sizeof(char *));
         if(!new_arr)
           return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY);
 
         pat->content.Set.elements = new_arr;
       }
       else
-        pat->content.Set.elements = malloc(sizeof(char*));
+        pat->content.Set.elements = malloc(sizeof(char *));
 
       if(!pat->content.Set.elements)
         return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY);
@@ -186,43 +192,48 @@ static CURLcode glob_range(URLGlob *glob, char **patternp,
     /* character range detected */
     char min_c;
     char max_c;
-    int step=1;
+    char end_c;
+    unsigned long step = 1;
 
     pat->type = UPTCharRange;
 
-    rc = sscanf(pattern, "%c-%c", &min_c, &max_c);
+    rc = sscanf(pattern, "%c-%c%c", &min_c, &max_c, &end_c);
 
-    if((rc == 2) && (pattern[3] == ':')) {
-      char *endp;
-      unsigned long lstep;
-      errno = 0;
-      lstep = strtoul(&pattern[3], &endp, 10);
-      if(errno || (*endp != ']'))
-        step = -1;
-      else {
-        pattern = endp+1;
-        step = (int)lstep;
-        if(step > (max_c - min_c))
-          step = -1;
+    if(rc == 3) {
+      if(end_c == ':') {
+        char *endp;
+        errno = 0;
+        step = strtoul(&pattern[4], &endp, 10);
+        if(errno || &pattern[4] == endp || *endp != ']')
+          step = 0;
+        else
+          pattern = endp + 1;
       }
+      else if(end_c != ']')
+        /* then this is wrong */
+        rc = 0;
+      else
+        /* end_c == ']' */
+        pattern += 4;
     }
-    else
-      pattern += 4;
 
     *posp += (pattern - *patternp);
 
-    if((rc != 2) || (min_c >= max_c) || ((max_c - min_c) > ('z' - 'a')) ||
-       (step < 0) )
+    if(rc != 3 || !step || step > (unsigned)INT_MAX ||
+       (min_c == max_c && step != 1) ||
+       (min_c != max_c && (min_c > max_c || step > (unsigned)(max_c - min_c) ||
+                           (max_c - min_c) > ('z' - 'a'))))
       /* the pattern is not well-formed */
       return GLOBERROR("bad range", *posp, CURLE_URL_MALFORMAT);
 
     /* if there was a ":[num]" thing, use that as step or else use 1 */
-    pat->content.CharRange.step = step;
+    pat->content.CharRange.step = (int)step;
     pat->content.CharRange.ptr_c = pat->content.CharRange.min_c = min_c;
     pat->content.CharRange.max_c = max_c;
 
-    if(multiply(amount, (pat->content.CharRange.max_c -
-                         pat->content.CharRange.min_c + 1)))
+    if(multiply(amount, ((pat->content.CharRange.max_c -
+                          pat->content.CharRange.min_c) /
+                         pat->content.CharRange.step + 1)))
       return GLOBERROR("range overflow", *posp, CURLE_URL_MALFORMAT);
   }
   else if(ISDIGIT(*pattern)) {
@@ -248,16 +259,25 @@ static CURLcode glob_range(URLGlob *glob, char **patternp,
     errno = 0;
     min_n = strtoul(pattern, &endp, 10);
     if(errno || (endp == pattern))
-      endp=NULL;
+      endp = NULL;
     else {
       if(*endp != '-')
         endp = NULL;
       else {
-        pattern = endp+1;
+        pattern = endp + 1;
+        while(*pattern && ISBLANK(*pattern))
+          pattern++;
+        if(!ISDIGIT(*pattern)) {
+          endp = NULL;
+          goto fail;
+        }
         errno = 0;
         max_n = strtoul(pattern, &endp, 10);
-        if(errno || (*endp == ':')) {
-          pattern = endp+1;
+        if(errno)
+          /* overflow */
+          endp = NULL;
+        else if(*endp == ':') {
+          pattern = endp + 1;
           errno = 0;
           step_n = strtoul(pattern, &endp, 10);
           if(errno)
@@ -267,16 +287,19 @@ static CURLcode glob_range(URLGlob *glob, char **patternp,
         else
           step_n = 1;
         if(endp && (*endp == ']')) {
-          pattern= endp+1;
+          pattern = endp + 1;
         }
         else
           endp = NULL;
       }
     }
 
+    fail:
     *posp += (pattern - *patternp);
 
-    if(!endp || (min_n > max_n) || (step_n > (max_n - min_n)))
+    if(!endp || !step_n ||
+       (min_n == max_n && step_n != 1) ||
+       (min_n != max_n && (min_n > max_n || step_n > (max_n - min_n))))
       /* the pattern is not well-formed */
       return GLOBERROR("bad range", *posp, CURLE_URL_MALFORMAT);
 
@@ -286,8 +309,9 @@ static CURLcode glob_range(URLGlob *glob, char **patternp,
     pat->content.NumRange.max_n = max_n;
     pat->content.NumRange.step = step_n;
 
-    if(multiply(amount, (pat->content.NumRange.max_n -
-                         pat->content.NumRange.min_n + 1)))
+    if(multiply(amount, ((pat->content.NumRange.max_n -
+                          pat->content.NumRange.min_n) /
+                         pat->content.NumRange.step + 1)))
       return GLOBERROR("range overflow", *posp, CURLE_URL_MALFORMAT);
   }
   else
@@ -343,9 +367,11 @@ static CURLcode glob_parse(URLGlob *glob, char *pattern,
     size_t sublen = 0;
     while(*pattern && *pattern != '{') {
       if(*pattern == '[') {
-        /* Skip over potential IPv6 literals. */
-        size_t skip;
-        if(peek_ipv6(pattern, &skip)) {
+        /* skip over IPv6 literals and [] */
+        size_t skip = 0;
+        if(!peek_ipv6(pattern, &skip) && (pattern[1] == ']'))
+          skip = 2;
+        if(skip) {
           memcpy(buf, pattern, skip);
           buf += skip;
           pattern += skip;
@@ -360,8 +386,8 @@ static CURLcode glob_parse(URLGlob *glob, char *pattern,
 
       /* only allow \ to escape known "special letters" */
       if(*pattern == '\\' &&
-         (*(pattern+1) == '{' || *(pattern+1) == '[' ||
-          *(pattern+1) == '}' || *(pattern+1) == ']') ) {
+         (*(pattern + 1) == '{' || *(pattern + 1) == '[' ||
+          *(pattern + 1) == '}' || *(pattern + 1) == ']') ) {
 
         /* escape character, skip '\' */
         ++pattern;
@@ -397,13 +423,13 @@ static CURLcode glob_parse(URLGlob *glob, char *pattern,
       }
     }
 
-    if(++glob->size > GLOB_PATTERN_NUM)
+    if(++glob->size >= GLOB_PATTERN_NUM)
       return GLOBERROR("too many globs", pos, CURLE_URL_MALFORMAT);
   }
   return res;
 }
 
-CURLcode glob_url(URLGlob** glob, char* url, unsigned long *urlnum,
+CURLcode glob_url(URLGlob **glob, char *url, unsigned long *urlnum,
                   FILE *error)
 {
   /*
@@ -420,6 +446,7 @@ CURLcode glob_url(URLGlob** glob, char* url, unsigned long *urlnum,
   glob_buffer = malloc(strlen(url) + 1);
   if(!glob_buffer)
     return CURLE_OUT_OF_MEMORY;
+  glob_buffer[0] = 0;
 
   glob_expand = calloc(1, sizeof(URLGlob));
   if(!glob_expand) {
@@ -497,7 +524,7 @@ CURLcode glob_next_url(char **globbed, URLGlob *glob)
     for(i = 0; carry && (i < glob->size); i++) {
       carry = FALSE;
       pat = &glob->pattern[glob->size - 1 - i];
-      switch (pat->type) {
+      switch(pat->type) {
       case UPTSet:
         if((pat->content.Set.elements) &&
            (++pat->content.Set.ptr_s == pat->content.Set.size)) {
@@ -537,20 +564,25 @@ CURLcode glob_next_url(char **globbed, URLGlob *glob)
     switch(pat->type) {
     case UPTSet:
       if(pat->content.Set.elements) {
-        len = strlen(pat->content.Set.elements[pat->content.Set.ptr_s]);
         snprintf(buf, buflen, "%s",
                  pat->content.Set.elements[pat->content.Set.ptr_s]);
+        len = strlen(buf);
         buf += len;
         buflen -= len;
       }
       break;
     case UPTCharRange:
-      *buf++ = pat->content.CharRange.ptr_c;
+      if(buflen) {
+        *buf++ = pat->content.CharRange.ptr_c;
+        *buf = '\0';
+        buflen--;
+      }
       break;
     case UPTNumRange:
-      len = snprintf(buf, buflen, "%0*ld",
-                     pat->content.NumRange.padlength,
-                     pat->content.NumRange.ptr_n);
+      snprintf(buf, buflen, "%0*ld",
+               pat->content.NumRange.padlength,
+               pat->content.NumRange.ptr_n);
+      len = strlen(buf);
       buf += len;
       buflen -= len;
       break;
@@ -559,7 +591,6 @@ CURLcode glob_next_url(char **globbed, URLGlob *glob)
       return CURLE_FAILED_INIT;
     }
   }
-  *buf = '\0';
 
   *globbed = strdup(glob->glob_buffer);
   if(!*globbed)
@@ -594,12 +625,12 @@ CURLcode glob_match_url(char **result, char *filename, URLGlob *glob)
       unsigned long i;
       char *ptr = filename;
       unsigned long num = strtoul(&filename[1], &filename, 10);
-      URLPattern *pat =NULL;
+      URLPattern *pat = NULL;
 
       if(num < glob->size) {
         num--; /* make it zero based */
         /* find the correct glob entry */
-        for(i=0; i<glob->size; i++) {
+        for(i = 0; i<glob->size; i++) {
           if(glob->pattern[i].globindex == (int)num) {
             pat = &glob->pattern[i];
             break;
@@ -608,7 +639,7 @@ CURLcode glob_match_url(char **result, char *filename, URLGlob *glob)
       }
 
       if(pat) {
-        switch (pat->type) {
+        switch(pat->type) {
         case UPTSet:
           if(pat->content.Set.elements) {
             appendthis = pat->content.Set.elements[pat->content.Set.ptr_s];
@@ -623,7 +654,7 @@ CURLcode glob_match_url(char **result, char *filename, URLGlob *glob)
           appendlen = 1;
           break;
         case UPTNumRange:
-          snprintf(numbuf, sizeof(numbuf), "%0*d",
+          snprintf(numbuf, sizeof(numbuf), "%0*lu",
                    pat->content.NumRange.padlength,
                    pat->content.NumRange.ptr_n);
           appendthis = numbuf;
@@ -663,7 +694,20 @@ CURLcode glob_match_url(char **result, char *filename, URLGlob *glob)
     stringlen += appendlen;
   }
   target[stringlen]= '\0';
+
+#if defined(MSDOS) || defined(WIN32)
+  {
+    char *sanitized;
+    SANITIZEcode sc = sanitize_file_name(&sanitized, target,
+                                         (SANITIZE_ALLOW_PATH |
+                                          SANITIZE_ALLOW_RESERVED));
+    Curl_safefree(target);
+    if(sc)
+      return CURLE_URL_MALFORMAT;
+    target = sanitized;
+  }
+#endif /* MSDOS || WIN32 */
+
   *result = target;
   return CURLE_OK;
 }
-