Blame SOURCES/0063-curl-7.29.0-CVE-2018-1000120.patch

f0f8d7
From 5452fdc5ae93f3571074c591fdf28cdf630796a0 Mon Sep 17 00:00:00 2001
f0f8d7
From: Daniel Stenberg <daniel@haxx.se>
f0f8d7
Date: Tue, 12 Sep 2017 09:29:01 +0200
f0f8d7
Subject: [PATCH 1/3] FTP: URL decode path for dir listing in nocwd mode
f0f8d7
f0f8d7
Reported-by: Zenju on github
f0f8d7
f0f8d7
Test 244 added to verify
f0f8d7
Fixes #1974
f0f8d7
Closes #1976
f0f8d7
f0f8d7
Upstream-commit: ecf21c551fa3426579463abe34b623111b8d487c
f0f8d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f0f8d7
---
f0f8d7
 lib/ftp.c              | 93 +++++++++++++++++++++++---------------------------
f0f8d7
 tests/data/Makefile.am |  3 +-
f0f8d7
 tests/data/test244     | 54 +++++++++++++++++++++++++++++
f0f8d7
 3 files changed, 99 insertions(+), 51 deletions(-)
f0f8d7
 create mode 100644 tests/data/test244
f0f8d7
f0f8d7
diff --git a/lib/ftp.c b/lib/ftp.c
f0f8d7
index bcba6bb..fb3a716 100644
f0f8d7
--- a/lib/ftp.c
f0f8d7
+++ b/lib/ftp.c
f0f8d7
@@ -1003,7 +1003,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
f0f8d7
     char *port_start = NULL;
f0f8d7
     char *port_sep = NULL;
f0f8d7
 
f0f8d7
-    addr = calloc(addrlen+1, 1);
f0f8d7
+    addr = calloc(addrlen + 1, 1);
f0f8d7
     if(!addr)
f0f8d7
       return CURLE_OUT_OF_MEMORY;
f0f8d7
 
f0f8d7
@@ -1041,7 +1041,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
f0f8d7
     /* parse the port */
f0f8d7
     if(ip_end != NULL) {
f0f8d7
       if((port_start = strchr(ip_end, ':')) != NULL) {
f0f8d7
-        port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
f0f8d7
+        port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
f0f8d7
         if((port_sep = strchr(port_start, '-')) != NULL) {
f0f8d7
           port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
f0f8d7
         }
f0f8d7
@@ -1469,25 +1469,22 @@ static CURLcode ftp_state_post_listtype(struct connectdata *conn)
f0f8d7
      then just do LIST (in that case: nothing to do here)
f0f8d7
   */
f0f8d7
   char *cmd,*lstArg,*slashPos;
f0f8d7
+  const char *inpath = data->state.path;
f0f8d7
 
f0f8d7
   lstArg = NULL;
f0f8d7
   if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
f0f8d7
-     data->state.path &&
f0f8d7
-     data->state.path[0] &&
f0f8d7
-     strchr(data->state.path,'/')) {
f0f8d7
-
f0f8d7
-    lstArg = strdup(data->state.path);
f0f8d7
-    if(!lstArg)
f0f8d7
-      return CURLE_OUT_OF_MEMORY;
f0f8d7
+     inpath && inpath[0] && strchr(inpath, '/')) {
f0f8d7
+    size_t n = strlen(inpath);
f0f8d7
 
f0f8d7
     /* Check if path does not end with /, as then we cut off the file part */
f0f8d7
-    if(lstArg[strlen(lstArg) - 1] != '/')  {
f0f8d7
-
f0f8d7
+    if(inpath[n - 1] != '/') {
f0f8d7
       /* chop off the file part if format is dir/dir/file */
f0f8d7
-      slashPos = strrchr(lstArg,'/');
f0f8d7
-      if(slashPos)
f0f8d7
-        *(slashPos+1) = '\0';
f0f8d7
+      slashPos = strrchr(inpath, '/');
f0f8d7
+      n = slashPos - inpath;
f0f8d7
     }
f0f8d7
+    result = Curl_urldecode(data, inpath, n, &lstArg, NULL, FALSE);
f0f8d7
+    if(result)
f0f8d7
+      return result;
f0f8d7
   }
f0f8d7
 
f0f8d7
   cmd = aprintf( "%s%s%s",
f0f8d7
@@ -3327,12 +3324,10 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
f0f8d7
   }
f0f8d7
 
f0f8d7
   /* get the "raw" path */
f0f8d7
-  path = curl_easy_unescape(data, path_to_use, 0, NULL);
f0f8d7
-  if(!path) {
f0f8d7
+  result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE);
f0f8d7
+  if(result) {
f0f8d7
     /* out of memory, but we can limp along anyway (and should try to
f0f8d7
      * since we may already be in the out of memory cleanup path) */
f0f8d7
-    if(!result)
f0f8d7
-      result = CURLE_OUT_OF_MEMORY;
f0f8d7
     ftpc->ctl_valid = FALSE; /* mark control connection as bad */
f0f8d7
     conn->bits.close = TRUE; /* mark for connection closure */
f0f8d7
     ftpc->prevpath = NULL; /* no path remembering */
f0f8d7
@@ -3643,7 +3638,7 @@ static CURLcode ftp_range(struct connectdata *conn)
f0f8d7
     }
f0f8d7
     else {
f0f8d7
       /* X-Y */
f0f8d7
-      data->req.maxdownload = (to-from)+1; /* include last byte */
f0f8d7
+      data->req.maxdownload = (to - from) + 1; /* include last byte */
f0f8d7
       data->state.resume_from = from;
f0f8d7
       DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
f0f8d7
                    " getting %" FORMAT_OFF_T " bytes\n",
f0f8d7
@@ -4332,20 +4327,22 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
f0f8d7
     }
f0f8d7
     slash_pos=strrchr(cur_pos, '/');
f0f8d7
     if(slash_pos || !*cur_pos) {
f0f8d7
+      CURLcode result;
f0f8d7
       ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
f0f8d7
       if(!ftpc->dirs)
f0f8d7
         return CURLE_OUT_OF_MEMORY;
f0f8d7
 
f0f8d7
-      ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
f0f8d7
-                                         slash_pos ?
f0f8d7
-                                         curlx_sztosi(slash_pos-cur_pos) : 1,
f0f8d7
-                                         NULL);
f0f8d7
-      if(!ftpc->dirs[0]) {
f0f8d7
+      result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/",
f0f8d7
+                              slash_pos ?
f0f8d7
+                              curlx_sztosi(slash_pos-cur_pos) : 1,
f0f8d7
+                              &ftpc->dirs[0], NULL,
f0f8d7
+                              FALSE);
f0f8d7
+      if(result) {
f0f8d7
         freedirs(ftpc);
f0f8d7
-        return CURLE_OUT_OF_MEMORY;
f0f8d7
+        return result;
f0f8d7
       }
f0f8d7
       ftpc->dirdepth = 1; /* we consider it to be a single dir */
f0f8d7
-      filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
f0f8d7
+      filename = slash_pos ? slash_pos + 1 : cur_pos; /* rest is file name */
f0f8d7
     }
f0f8d7
     else
f0f8d7
       filename = cur_pos;  /* this is a file name only */
f0f8d7
@@ -4377,18 +4374,15 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
f0f8d7
           /* we skip empty path components, like "x//y" since the FTP command
f0f8d7
              CWD requires a parameter and a non-existent parameter a) doesn't
f0f8d7
              work on many servers and b) has no effect on the others. */
f0f8d7
-          int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir);
f0f8d7
-          ftpc->dirs[ftpc->dirdepth] =
f0f8d7
-            curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
f0f8d7
-          if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
f0f8d7
-            failf(data, "no memory");
f0f8d7
-            freedirs(ftpc);
f0f8d7
-            return CURLE_OUT_OF_MEMORY;
f0f8d7
-          }
f0f8d7
-          if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
f0f8d7
+          size_t len = slash_pos - cur_pos + absolute_dir;
f0f8d7
+          CURLcode result =
f0f8d7
+            Curl_urldecode(conn->data, cur_pos - absolute_dir, len,
f0f8d7
+                           &ftpc->dirs[ftpc->dirdepth], NULL,
f0f8d7
+                           TRUE);
f0f8d7
+          if(result) {
f0f8d7
             free(ftpc->dirs[ftpc->dirdepth]);
f0f8d7
             freedirs(ftpc);
f0f8d7
-            return CURLE_URL_MALFORMAT;
f0f8d7
+            return result;
f0f8d7
           }
f0f8d7
         }
f0f8d7
         else {
f0f8d7
@@ -4415,15 +4409,12 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
f0f8d7
   } /* switch */
f0f8d7
 
f0f8d7
   if(filename && *filename) {
f0f8d7
-    ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
f0f8d7
-    if(NULL == ftpc->file) {
f0f8d7
-      freedirs(ftpc);
f0f8d7
-      failf(data, "no memory");
f0f8d7
-      return CURLE_OUT_OF_MEMORY;
f0f8d7
-    }
f0f8d7
-    if(isBadFtpString(ftpc->file)) {
f0f8d7
+    CURLcode result =
f0f8d7
+      Curl_urldecode(conn->data, filename, 0,  &ftpc->file, NULL, TRUE);
f0f8d7
+
f0f8d7
+    if(result) {
f0f8d7
       freedirs(ftpc);
f0f8d7
-      return CURLE_URL_MALFORMAT;
f0f8d7
+      return result;
f0f8d7
     }
f0f8d7
   }
f0f8d7
   else
f0f8d7
@@ -4441,15 +4432,17 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
f0f8d7
   if(ftpc->prevpath) {
f0f8d7
     /* prevpath is "raw" so we convert the input path before we compare the
f0f8d7
        strings */
f0f8d7
-    int dlen;
f0f8d7
-    char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
f0f8d7
-    if(!path) {
f0f8d7
+    size_t dlen;
f0f8d7
+    char *path;
f0f8d7
+    CURLcode result =
f0f8d7
+      Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, FALSE);
f0f8d7
+    if(result) {
f0f8d7
       freedirs(ftpc);
f0f8d7
-      return CURLE_OUT_OF_MEMORY;
f0f8d7
+      return result;
f0f8d7
     }
f0f8d7
 
f0f8d7
-    dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0;
f0f8d7
-    if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) &&
f0f8d7
+    dlen -= ftpc->file?strlen(ftpc->file):0;
f0f8d7
+    if((dlen == strlen(ftpc->prevpath)) &&
f0f8d7
        strnequal(path, ftpc->prevpath, dlen)) {
f0f8d7
       infof(data, "Request has same path as previous transfer\n");
f0f8d7
       ftpc->cwddone = TRUE;
f0f8d7
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
f0f8d7
index 56cb286..e7955ee 100644
f0f8d7
--- a/tests/data/Makefile.am
f0f8d7
+++ b/tests/data/Makefile.am
f0f8d7
@@ -28,7 +28,8 @@ test200 test201 test202 test203 test204 test205 test206 test207 test208	\
f0f8d7
 test209 test210 test211 test212 test213 test214 test215 test216 test217	\
f0f8d7
 test218 test220 test221 test222 test223 test224 test225 test226 test227	\
f0f8d7
 test228 test229 test231 test233 test234 test235 test236 test237 test238	\
f0f8d7
-test239 test240 test241 test242 test243 test245 test246 test247 test248	\
f0f8d7
+test239 test240 test241 test242 test243	\
f0f8d7
+test244 test245 test246 test247 test248	\
f0f8d7
 test249 test250 test251 test252 test253 test254 test255 test256 test257	\
f0f8d7
 test258 test259 test260 test261 test262 test263 test264 test265 test266	\
f0f8d7
 test267 test268 test269 test270 test271 test272 test273 test274 test275	\
f0f8d7
diff --git a/tests/data/test244 b/tests/data/test244
f0f8d7
new file mode 100644
f0f8d7
index 0000000..8ce4b63
f0f8d7
--- /dev/null
f0f8d7
+++ b/tests/data/test244
f0f8d7
@@ -0,0 +1,54 @@
f0f8d7
+<testcase>
f0f8d7
+<info>
f0f8d7
+<keywords>
f0f8d7
+FTP
f0f8d7
+PASV
f0f8d7
+CWD
f0f8d7
+--ftp-method
f0f8d7
+nocwd
f0f8d7
+</keywords>
f0f8d7
+</info>
f0f8d7
+#
f0f8d7
+# Server-side
f0f8d7
+<reply>
f0f8d7
+<data mode="text">
f0f8d7
+total 20
f0f8d7
+drwxr-xr-x   8 98       98           512 Oct 22 13:06 .
f0f8d7
+drwxr-xr-x   8 98       98           512 Oct 22 13:06 ..
f0f8d7
+drwxr-xr-x   2 98       98           512 May  2  1996 .NeXT
f0f8d7
+-r--r--r--   1 0        1             35 Jul 16  1996 README
f0f8d7
+lrwxrwxrwx   1 0        1              7 Dec  9  1999 bin -> usr/bin
f0f8d7
+dr-xr-xr-x   2 0        1            512 Oct  1  1997 dev
f0f8d7
+drwxrwxrwx   2 98       98           512 May 29 16:04 download.html
f0f8d7
+dr-xr-xr-x   2 0        1            512 Nov 30  1995 etc
f0f8d7
+drwxrwxrwx   2 98       1            512 Oct 30 14:33 pub
f0f8d7
+dr-xr-xr-x   5 0        1            512 Oct  1  1997 usr
f0f8d7
+</data>
f0f8d7
+</reply>
f0f8d7
+
f0f8d7
+# Client-side
f0f8d7
+<client>
f0f8d7
+<server>
f0f8d7
+ftp
f0f8d7
+</server>
f0f8d7
+ <name>
f0f8d7
+FTP dir listing with nocwd and URL encoded path
f0f8d7
+ </name>
f0f8d7
+ <command>
f0f8d7
+--ftp-method nocwd ftp://%HOSTIP:%FTPPORT/fir%23t/th%69rd/244/
f0f8d7
+</command>
f0f8d7
+</client>
f0f8d7
+
f0f8d7
+# Verify data after the test has been "shot"
f0f8d7
+<verify>
f0f8d7
+<protocol>
f0f8d7
+USER anonymous
f0f8d7
+PASS ftp@example.com
f0f8d7
+PWD
f0f8d7
+EPSV
f0f8d7
+TYPE A
f0f8d7
+LIST fir#t/third/244/
f0f8d7
+QUIT
f0f8d7
+</protocol>
f0f8d7
+</verify>
f0f8d7
+</testcase>
f0f8d7
-- 
f0f8d7
2.14.3
f0f8d7
f0f8d7
f0f8d7
From 295fc8b0dc5c94a1cbf6688bfba768128b13cde6 Mon Sep 17 00:00:00 2001
f0f8d7
From: Daniel Stenberg <daniel@haxx.se>
f0f8d7
Date: Wed, 2 Nov 2016 07:22:27 +0100
f0f8d7
Subject: [PATCH 2/3] ftp_done: don't clobber the passed in error code
f0f8d7
f0f8d7
Coverity CID 1374359 pointed out the unused result value.
f0f8d7
f0f8d7
Upstream-commit: f81a8364618caf99b4691ffd494a9b2d4c9fb1f6
f0f8d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f0f8d7
---
f0f8d7
 lib/ftp.c | 9 +++++----
f0f8d7
 1 file changed, 5 insertions(+), 4 deletions(-)
f0f8d7
f0f8d7
diff --git a/lib/ftp.c b/lib/ftp.c
f0f8d7
index 9da5a24..0259a14 100644
f0f8d7
--- a/lib/ftp.c
f0f8d7
+++ b/lib/ftp.c
f0f8d7
@@ -3323,11 +3323,12 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
f0f8d7
     ftpc->known_filesize = -1;
f0f8d7
   }
f0f8d7
 
f0f8d7
-  /* get the "raw" path */
f0f8d7
-  result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE);
f0f8d7
+  if(!result)
f0f8d7
+    /* get the "raw" path */
f0f8d7
+    result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE);
f0f8d7
   if(result) {
f0f8d7
-    /* out of memory, but we can limp along anyway (and should try to
f0f8d7
-     * since we may already be in the out of memory cleanup path) */
f0f8d7
+    /* We can limp along anyway (and should try to since we may already be in
f0f8d7
+     * the error path) */
f0f8d7
     ftpc->ctl_valid = FALSE; /* mark control connection as bad */
f0f8d7
     conn->bits.close = TRUE; /* mark for connection closure */
f0f8d7
     ftpc->prevpath = NULL; /* no path remembering */
f0f8d7
-- 
f0f8d7
2.14.4
f0f8d7
f0f8d7
f0f8d7
From 9534442aae1da4e6cf2ce815e47dbcd82695c3d4 Mon Sep 17 00:00:00 2001
f0f8d7
From: Daniel Stenberg <daniel@haxx.se>
f0f8d7
Date: Wed, 31 Jan 2018 08:40:11 +0100
f0f8d7
Subject: [PATCH 3/3] FTP: reject path components with control codes
f0f8d7
f0f8d7
Refuse to operate when given path components featuring byte values lower
f0f8d7
than 32.
f0f8d7
f0f8d7
Previously, inserting a %00 sequence early in the directory part when
f0f8d7
using the 'singlecwd' ftp method could make curl write a zero byte
f0f8d7
outside of the allocated buffer.
f0f8d7
f0f8d7
Test case 340 verifies.
f0f8d7
f0f8d7
CVE-2018-1000120
f0f8d7
Reported-by: Duy Phan Thanh
f0f8d7
Bug: https://curl.haxx.se/docs/adv_2018-9cd6.html
f0f8d7
f0f8d7
Upstream-commit: 535432c0adb62fe167ec09621500470b6fa4eb0f
f0f8d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f0f8d7
---
f0f8d7
 lib/ftp.c              |  8 ++++----
f0f8d7
 tests/data/Makefile.am |  1 +
f0f8d7
 tests/data/test340     | 40 ++++++++++++++++++++++++++++++++++++++++
f0f8d7
 3 files changed, 45 insertions(+), 4 deletions(-)
f0f8d7
 create mode 100644 tests/data/test340
f0f8d7
f0f8d7
diff --git a/lib/ftp.c b/lib/ftp.c
f0f8d7
index fb3a716..268efdd 100644
f0f8d7
--- a/lib/ftp.c
f0f8d7
+++ b/lib/ftp.c
f0f8d7
@@ -1482,7 +1482,7 @@ static CURLcode ftp_state_post_listtype(struct connectdata *conn)
f0f8d7
       slashPos = strrchr(inpath, '/');
f0f8d7
       n = slashPos - inpath;
f0f8d7
     }
f0f8d7
-    result = Curl_urldecode(data, inpath, n, &lstArg, NULL, FALSE);
f0f8d7
+    result = Curl_urldecode(data, inpath, n, &lstArg, NULL, TRUE);
f0f8d7
     if(result)
f0f8d7
       return result;
f0f8d7
   }
f0f8d7
@@ -3325,7 +3325,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
f0f8d7
 
f0f8d7
   if(!result)
f0f8d7
     /* get the "raw" path */
f0f8d7
-    result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE);
f0f8d7
+    result = Curl_urldecode(data, path_to_use, 0, &path, NULL, TRUE);
f0f8d7
   if(result) {
f0f8d7
     /* We can limp along anyway (and should try to since we may already be in
f0f8d7
      * the error path) */
f0f8d7
@@ -4337,7 +4337,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
f0f8d7
                               slash_pos ?
f0f8d7
                               curlx_sztosi(slash_pos-cur_pos) : 1,
f0f8d7
                               &ftpc->dirs[0], NULL,
f0f8d7
-                              FALSE);
f0f8d7
+                              TRUE);
f0f8d7
       if(result) {
f0f8d7
         freedirs(ftpc);
f0f8d7
         return result;
f0f8d7
@@ -4436,7 +4436,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
f0f8d7
     size_t dlen;
f0f8d7
     char *path;
f0f8d7
     CURLcode result =
f0f8d7
-      Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, FALSE);
f0f8d7
+      Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, TRUE);
f0f8d7
     if(result) {
f0f8d7
       freedirs(ftpc);
f0f8d7
       return result;
f0f8d7
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
f0f8d7
index e7955ee..910db5b 100644
f0f8d7
--- a/tests/data/Makefile.am
f0f8d7
+++ b/tests/data/Makefile.am
f0f8d7
@@ -39,6 +39,7 @@ test294 test295 test296 test297 test298 test299 test300 test301 test302	\
f0f8d7
 test303 test304 test305 test306 test307 test308 test309 test310 test311	\
f0f8d7
 test312 test313 test317 test318 \
f0f8d7
 test320 test321 test322 test323 test324 test350 test351	\
f0f8d7
+test340	\
f0f8d7
 test352 test353 test354 test400 test401 test402 test403 test404 test405	\
f0f8d7
 test406 test407 test408 test409 test500 test501 test502 test503 test504	\
f0f8d7
 test505 test506 test507 test508 test510 test511 test512 test513 test514	\
f0f8d7
diff --git a/tests/data/test340 b/tests/data/test340
f0f8d7
new file mode 100644
f0f8d7
index 0000000..d834d76
f0f8d7
--- /dev/null
f0f8d7
+++ b/tests/data/test340
f0f8d7
@@ -0,0 +1,40 @@
f0f8d7
+<testcase>
f0f8d7
+<info>
f0f8d7
+<keywords>
f0f8d7
+FTP
f0f8d7
+PASV
f0f8d7
+CWD
f0f8d7
+--ftp-method
f0f8d7
+singlecwd
f0f8d7
+</keywords>
f0f8d7
+</info>
f0f8d7
+#
f0f8d7
+# Server-side
f0f8d7
+<reply>
f0f8d7
+</reply>
f0f8d7
+
f0f8d7
+# Client-side
f0f8d7
+<client>
f0f8d7
+<server>
f0f8d7
+ftp
f0f8d7
+</server>
f0f8d7
+ <name>
f0f8d7
+FTP using %00 in path with singlecwd
f0f8d7
+ </name>
f0f8d7
+ <command>
f0f8d7
+--ftp-method singlecwd ftp://%HOSTIP:%FTPPORT/%00first/second/third/340
f0f8d7
+</command>
f0f8d7
+</client>
f0f8d7
+
f0f8d7
+# Verify data after the test has been "shot"
f0f8d7
+<verify>
f0f8d7
+<protocol>
f0f8d7
+USER anonymous
f0f8d7
+PASS ftp@example.com
f0f8d7
+PWD
f0f8d7
+</protocol>
f0f8d7
+<errorcode>
f0f8d7
+3
f0f8d7
+</errorcode>
f0f8d7
+</verify>
f0f8d7
+</testcase>
f0f8d7
-- 
f0f8d7
2.14.3
f0f8d7