source: trunk/essentials/net-misc/wget/src/ftp-basic.c@ 3609

Last change on this file since 3609 was 3440, checked in by bird, 19 years ago

wget 1.10.2

File size: 28.2 KB
Line 
1/* Basic FTP routines.
2 Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
3
4This file is part of GNU Wget.
5
6GNU Wget is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11GNU Wget is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with Wget; if not, write to the Free Software
18Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20In addition, as a special exception, the Free Software Foundation
21gives permission to link the code of its release of Wget with the
22OpenSSL project's "OpenSSL" library (or with modified versions of it
23that use the same license as the "OpenSSL" library), and distribute
24the linked executables. You must obey the GNU General Public License
25in all respects for all of the code used other than "OpenSSL". If you
26modify this file, you may extend this exception to your version of the
27file, but you are not obligated to do so. If you do not wish to do
28so, delete this exception statement from your version. */
29
30#include <config.h>
31
32#include <assert.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <errno.h>
36
37#ifdef HAVE_STRING_H
38# include <string.h>
39#else
40# include <strings.h>
41#endif
42#ifdef HAVE_UNISTD_H
43# include <unistd.h>
44#endif
45#include <sys/types.h>
46
47#include "wget.h"
48#include "utils.h"
49#include "connect.h"
50#include "host.h"
51#include "ftp.h"
52#include "retr.h"
53
54char ftp_last_respline[128];
55
56
57
58/* Get the response of FTP server and allocate enough room to handle
59 it. <CR> and <LF> characters are stripped from the line, and the
60 line is 0-terminated. All the response lines but the last one are
61 skipped. The last line is determined as described in RFC959.
62
63 If the line is successfully read, FTPOK is returned, and *ret_line
64 is assigned a freshly allocated line. Otherwise, FTPRERR is
65 returned, and the value of *ret_line should be ignored. */
66
67uerr_t
68ftp_response (int fd, char **ret_line)
69{
70 while (1)
71 {
72 char *p;
73 char *line = fd_read_line (fd);
74 if (!line)
75 return FTPRERR;
76
77 /* Strip trailing CRLF before printing the line, so that
78 escnonprint doesn't include bogus \012 and \015. */
79 p = strchr (line, '\0');
80 if (p > line && p[-1] == '\n')
81 *--p = '\0';
82 if (p > line && p[-1] == '\r')
83 *--p = '\0';
84
85 if (opt.server_response)
86 logprintf (LOG_NOTQUIET, "%s\n", escnonprint (line));
87 else
88 DEBUGP (("%s\n", escnonprint (line)));
89
90 /* The last line of output is the one that begins with "ddd ". */
91 if (ISDIGIT (line[0]) && ISDIGIT (line[1]) && ISDIGIT (line[2])
92 && line[3] == ' ')
93 {
94 strncpy (ftp_last_respline, line, sizeof (ftp_last_respline));
95 ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0';
96 *ret_line = line;
97 return FTPOK;
98 }
99 xfree (line);
100 }
101}
102
103/* Returns the malloc-ed FTP request, ending with <CR><LF>, printing
104 it if printing is required. If VALUE is NULL, just use
105 command<CR><LF>. */
106static char *
107ftp_request (const char *command, const char *value)
108{
109 char *res;
110 if (value)
111 {
112 /* Check for newlines in VALUE (possibly injected by the %0A URL
113 escape) making the callers inadvertently send multiple FTP
114 commands at once. Without this check an attacker could
115 intentionally redirect to ftp://server/fakedir%0Acommand.../
116 and execute arbitrary FTP command on a remote FTP server. */
117 if (strpbrk (value, "\r\n"))
118 {
119 /* Copy VALUE to the stack and modify CR/LF to space. */
120 char *defanged, *p;
121 STRDUP_ALLOCA (defanged, value);
122 for (p = defanged; *p; p++)
123 if (*p == '\r' || *p == '\n')
124 *p = ' ';
125 DEBUGP (("\nDetected newlines in %s \"%s\"; changing to %s \"%s\"\n",
126 command, escnonprint (value), command, escnonprint (defanged)));
127 /* Make VALUE point to the defanged copy of the string. */
128 value = defanged;
129 }
130 res = concat_strings (command, " ", value, "\r\n", (char *) 0);
131 }
132 else
133 res = concat_strings (command, "\r\n", (char *) 0);
134 if (opt.server_response)
135 {
136 /* Hack: don't print out password. */
137 if (strncmp (res, "PASS", 4) != 0)
138 logprintf (LOG_ALWAYS, "--> %s\n", res);
139 else
140 logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n\n");
141 }
142 else
143 DEBUGP (("\n--> %s\n", res));
144 return res;
145}
146
147/* Sends the USER and PASS commands to the server, to control
148 connection socket csock. */
149uerr_t
150ftp_login (int csock, const char *acc, const char *pass)
151{
152 uerr_t err;
153 char *request, *respline;
154 int nwritten;
155
156 /* Get greeting. */
157 err = ftp_response (csock, &respline);
158 if (err != FTPOK)
159 return err;
160 if (*respline != '2')
161 {
162 xfree (respline);
163 return FTPSRVERR;
164 }
165 xfree (respline);
166 /* Send USER username. */
167 request = ftp_request ("USER", acc);
168 nwritten = fd_write (csock, request, strlen (request), -1.0);
169 if (nwritten < 0)
170 {
171 xfree (request);
172 return WRITEFAILED;
173 }
174 xfree (request);
175 /* Get appropriate response. */
176 err = ftp_response (csock, &respline);
177 if (err != FTPOK)
178 return err;
179 /* An unprobable possibility of logging without a password. */
180 if (*respline == '2')
181 {
182 xfree (respline);
183 return FTPOK;
184 }
185 /* Else, only response 3 is appropriate. */
186 if (*respline != '3')
187 {
188 xfree (respline);
189 return FTPLOGREFUSED;
190 }
191#ifdef ENABLE_OPIE
192 {