]> sjero.net Git - wget/blobdiff - src/ftp-basic.c
[svn] Prevent newlines in FTP command arguments causing inadvertent sending of
[wget] / src / ftp-basic.c
index 5960ade619ad4c49a873fe21982f2f9c93fc6b08..379a6eab8f1447b8d4cd901203cca3e1a2d8f5e1 100644 (file)
@@ -58,26 +58,34 @@ char ftp_last_respline[128];
    it.  <CR> and <LF> characters are stripped from the line, and the
    line is 0-terminated.  All the response lines but the last one are
    skipped.  The last line is determined as described in RFC959.  */
+
 uerr_t
 ftp_response (int fd, char **ret_line)
 {
   while (1)
     {
+      char *p;
       char *line = fd_read_line (fd);
       if (!line)
        return FTPRERR;
+
+      /* Strip trailing CRLF before printing the line, so that
+        escnonprint doesn't include bogus \012 and \015. */
+      p = strchr (line, '\0');
+      if (p > line && p[-1] == '\n')
+       *--p = '\0';
+      if (p > line && p[-1] == '\r')
+       *--p = '\0';
+
       if (opt.server_response)
-        logputs (LOG_NOTQUIET, escnonprint (line));
+       logprintf (LOG_NOTQUIET, "%s\n", escnonprint (line));
       else
-        DEBUGP (("%s", escnonprint (line)));
+        DEBUGP (("%s\n", escnonprint (line)));
+
+      /* The last line of output is the one that begins with "ddd ". */
       if (ISDIGIT (line[0]) && ISDIGIT (line[1]) && ISDIGIT (line[2])
          && line[3] == ' ')
        {
-         char *p = line + strlen (line);
-         if (p > line && p[-1] == '\n')
-           *--p = '\0';
-         if (p > line && p[-1] == '\r')
-           *--p = '\0';
          strncpy (ftp_last_respline, line, sizeof (ftp_last_respline));
          ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0';
          *ret_line = line;
@@ -95,7 +103,27 @@ ftp_request (const char *command, const char *value)
 {
   char *res;
   if (value)
-    res = concat_strings (command, " ", value, "\r\n", (char *) 0);
+    {
+      /* Check for newlines in VALUE (possibly injected by the %0A URL
+        escape) making the callers inadvertently send multiple FTP
+        commands at once.  Without this check an attacker could
+        intentionally redirect to ftp://server/fakedir%0Acommand.../
+        and execute arbitrary FTP command on a remote FTP server.  */
+      if (strpbrk (value, "\r\n"))
+       {
+         /* Copy VALUE to the stack and modify CR/LF to space. */
+         char *defanged, *p;
+         STRDUP_ALLOCA (defanged, value);
+         for (p = defanged; *p; p++)
+           if (*p == '\r' || *p == '\n')
+             *p = ' ';
+         DEBUGP (("\nDetected newlines in %s \"%s\"; changing to %s \"%s\"\n",
+                  command, escnonprint (value), command, escnonprint (defanged)));
+         /* Make VALUE point to the defanged copy of the string. */
+         value = defanged;
+       }
+      res = concat_strings (command, " ", value, "\r\n", (char *) 0);
+    }
   else
     res = concat_strings (command, "\r\n", (char *) 0);
   if (opt.server_response)
@@ -123,10 +151,7 @@ ftp_login (int csock, const char *acc, const char *pass)
   /* Get greeting.  */
   err = ftp_response (csock, &respline);
   if (err != FTPOK)
-    {
-      xfree (respline);
-      return err;
-    }
+    return err;
   if (*respline != '2')
     {
       xfree (respline);
@@ -135,7 +160,7 @@ ftp_login (int csock, const char *acc, const char *pass)
   xfree (respline);
   /* Send USER username.  */
   request = ftp_request ("USER", acc);
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -161,7 +186,7 @@ ftp_login (int csock, const char *acc, const char *pass)
       xfree (respline);
       return FTPLOGREFUSED;
     }
-#ifdef USE_OPIE
+#ifdef ENABLE_OPIE
   {
     static const char *skey_head[] = {
       "331 s/key ",
@@ -198,11 +223,11 @@ ftp_login (int csock, const char *acc, const char *pass)
         pass = skey_response (skey_sequence, seed, pass);
       }
   }
-#endif /* USE_OPIE */
+#endif /* ENABLE_OPIE */
   xfree (respline);
   /* Send PASS password.  */
   request = ftp_request ("PASS", pass);
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -277,7 +302,7 @@ ftp_port (int csock, int *local_sock)
 
   /* Send PORT request.  */
   request = ftp_request ("PORT", bytes);
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -371,7 +396,7 @@ ftp_lprt (int csock, int *local_sock)
 
   /* Send PORT request.  */
   request = ftp_request ("LPRT", bytes);
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -452,7 +477,7 @@ ftp_eprt (int csock, int *local_sock)
 
   /* Send PORT request.  */
   request = ftp_request ("EPRT", bytes);
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -493,12 +518,12 @@ ftp_pasv (int csock, ip_address *addr, int *port)
   assert (addr != NULL);
   assert (port != NULL);
 
-  memset (addr, 0, sizeof (ip_address));
+  xzero (*addr);
 
   /* Form the request.  */
   request = ftp_request ("PASV", NULL);
   /* And send it.  */
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -561,13 +586,13 @@ ftp_lpsv (int csock, ip_address *addr, int *port)
   assert (addr != NULL);
   assert (port != NULL);
 
-  memset (addr, 0, sizeof (ip_address));
+  xzero (*addr);
 
   /* Form the request.  */
   request = ftp_request ("LPSV", NULL);
 
   /* And send it.  */
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -732,7 +757,7 @@ ftp_epsv (int csock, ip_address *ip, int *port)
   request = ftp_request ("EPSV", (ip->type == IPV4_ADDRESS ? "1" : "2"));
 
   /* And send it.  */
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -832,7 +857,7 @@ ftp_type (int csock, int type)
   stype[1] = 0;
   /* Send TYPE request.  */
   request = ftp_request ("TYPE", stype);
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -867,7 +892,7 @@ ftp_cwd (int csock, const char *dir)
 
   /* Send CWD request.  */
   request = ftp_request ("CWD", dir);
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -905,7 +930,7 @@ ftp_rest (int csock, wgint offset)
   uerr_t err;
 
   request = ftp_request ("REST", number_to_static_string (offset));
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -939,7 +964,7 @@ ftp_retr (int csock, const char *file)
 
   /* Send RETR request.  */
   request = ftp_request ("RETR", file);
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -979,7 +1004,7 @@ ftp_list (int csock, const char *file)
 
   /* Send LIST request.  */
   request = ftp_request ("LIST", file);
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -1018,7 +1043,7 @@ ftp_syst (int csock, enum stype *server_type)
 
   /* Send SYST request.  */
   request = ftp_request ("SYST", NULL);
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -1075,7 +1100,7 @@ ftp_pwd (int csock, char **pwd)
 
   /* Send PWD request.  */
   request = ftp_request ("PWD", NULL);
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);
@@ -1121,7 +1146,7 @@ ftp_size (int csock, const char *file, wgint *size)
 
   /* Send PWD request.  */
   request = ftp_request ("SIZE", file);
-  nwritten = fd_write (csock, request, strlen (request), -1);
+  nwritten = fd_write (csock, request, strlen (request), -1.0);
   if (nwritten < 0)
     {
       xfree (request);