Browse Source

dict: URL decode the entire path always

Reported-by: dekerser on github
Fixes #10298
Closes #10354
Daniel Stenberg 1 year ago
parent
commit
0c3d54269e
1 changed files with 42 additions and 44 deletions
  1. 42 44
      lib/dict.c

+ 42 - 44
lib/dict.c

@@ -98,37 +98,27 @@ const struct Curl_handler Curl_handler_dict = {
   PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
 };
 
-static char *unescape_word(const char *inputbuff)
+#define DYN_DICT_WORD 10000
+static char *unescape_word(const char *input)
 {
-  char *newp = NULL;
-  char *dictp;
-  size_t len;
-
-  CURLcode result = Curl_urldecode(inputbuff, 0, &newp, &len,
-                                   REJECT_NADA);
-  if(!newp || result)
-    return NULL;
-
-  dictp = malloc(len*2 + 1); /* add one for terminating zero */
-  if(dictp) {
-    char *ptr;
-    char ch;
-    int olen = 0;
-    /* According to RFC2229 section 2.2, these letters need to be escaped with
-       \[letter] */
-    for(ptr = newp;
-        (ch = *ptr) != 0;
-        ptr++) {
-      if((ch <= 32) || (ch == 127) ||
-          (ch == '\'') || (ch == '\"') || (ch == '\\')) {
-        dictp[olen++] = '\\';
-      }
-      dictp[olen++] = ch;
-    }
-    dictp[olen] = 0;
+  struct dynbuf out;
+  const char *ptr;
+  CURLcode result = CURLE_OK;
+  Curl_dyn_init(&out, DYN_DICT_WORD);
+
+  /* According to RFC2229 section 2.2, these letters need to be escaped with
+     \[letter] */
+  for(ptr = input; *ptr; ptr++) {
+    char ch = *ptr;
+    if((ch <= 32) || (ch == 127) ||
+       (ch == '\'') || (ch == '\"') || (ch == '\\'))
+      result = Curl_dyn_addn(&out, "\\", 1);
+    if(!result)
+      result = Curl_dyn_addn(&out, ptr, 1);
+    if(result)
+      return NULL;
   }
-  free(newp);
-  return dictp;
+  return Curl_dyn_ptr(&out);
 }
 
 /* sendf() sends formatted data to the server */
@@ -178,20 +168,25 @@ static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data,
 static CURLcode dict_do(struct Curl_easy *data, bool *done)
 {
   char *word;
-  char *eword;
+  char *eword = NULL;
   char *ppath;
   char *database = NULL;
   char *strategy = NULL;
   char *nthdef = NULL; /* This is not part of the protocol, but required
                           by RFC 2229 */
-  CURLcode result = CURLE_OK;
+  CURLcode result;
   struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
 
-  char *path = data->state.up.path;
+  char *path;
 
   *done = TRUE; /* unconditionally */
 
+  /* url-decode path before further evaluation */
+  result = Curl_urldecode(data->state.up.path, 0, &path, NULL, REJECT_CTRL);
+  if(result)
+    return result;
+
   if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
      strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
      strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
@@ -225,8 +220,10 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
     }
 
     eword = unescape_word(word);
-    if(!eword)
-      return CURLE_OUT_OF_MEMORY;
+    if(!eword) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
+    }
 
     result = sendf(sockfd, data,
                    "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
@@ -239,11 +236,9 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
                    strategy,
                    eword);
 
-    free(eword);
-
     if(result) {
       failf(data, "Failed sending DICT request");
-      return result;
+      goto error;
     }
     Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */
   }
@@ -273,8 +268,10 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
     }
 
     eword = unescape_word(word);
-    if(!eword)
-      return CURLE_OUT_OF_MEMORY;
+    if(!eword) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
+    }
 
     result = sendf(sockfd, data,
                    "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
@@ -285,11 +282,9 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
                    database,
                    eword);
 
-    free(eword);
-
     if(result) {
       failf(data, "Failed sending DICT request");
-      return result;
+      goto error;
     }
     Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
   }
@@ -310,13 +305,16 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
                      "QUIT\r\n", ppath);
       if(result) {
         failf(data, "Failed sending DICT request");
-        return result;
+        goto error;
       }
 
       Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
     }
   }
 
-  return CURLE_OK;
+  error:
+  free(eword);
+  free(path);
+  return result;
 }
 #endif /* CURL_DISABLE_DICT */