2 Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
4 This file is part of GNU Wget.
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables. You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL". If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so. If you do not wish to do
28 so, delete this exception statement from your version. */
45 #include <sys/types.h>
54 char ftp_last_respline[128];
57 /* Get the response of FTP server and allocate enough room to handle
58 it. <CR> and <LF> characters are stripped from the line, and the
59 line is 0-terminated. All the response lines but the last one are
60 skipped. The last line is determined as described in RFC959. */
63 ftp_response (int fd, char **ret_line)
68 char *line = fd_read_line (fd);
72 /* Strip trailing CRLF before printing the line, so that
73 escnonprint doesn't include bogus \012 and \015. */
74 p = strchr (line, '\0');
75 if (p > line && p[-1] == '\n')
77 if (p > line && p[-1] == '\r')
80 if (opt.server_response)
81 logprintf (LOG_NOTQUIET, "%s\n", escnonprint (line));
83 DEBUGP (("%s\n", escnonprint (line)));
85 /* The last line of output is the one that begins with "ddd ". */
86 if (ISDIGIT (line[0]) && ISDIGIT (line[1]) && ISDIGIT (line[2])
89 strncpy (ftp_last_respline, line, sizeof (ftp_last_respline));
90 ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0';
98 /* Returns the malloc-ed FTP request, ending with <CR><LF>, printing
99 it if printing is required. If VALUE is NULL, just use
102 ftp_request (const char *command, const char *value)
107 /* Check for newlines in VALUE (possibly injected by the %0A URL
108 escape) making the callers inadvertently send multiple FTP
109 commands at once. Without this check an attacker could
110 intentionally redirect to ftp://server/fakedir%0Acommand.../
111 and execute arbitrary FTP command on a remote FTP server. */
112 if (strpbrk (value, "\r\n"))
114 /* Copy VALUE to the stack and modify CR/LF to space. */
116 STRDUP_ALLOCA (defanged, value);
117 for (p = defanged; *p; p++)
118 if (*p == '\r' || *p == '\n')
120 DEBUGP (("\nDetected newlines in %s \"%s\"; changing to %s \"%s\"\n",
121 command, escnonprint (value), command, escnonprint (defanged)));
122 /* Make VALUE point to the defanged copy of the string. */
125 res = concat_strings (command, " ", value, "\r\n", (char *) 0);
128 res = concat_strings (command, "\r\n", (char *) 0);
129 if (opt.server_response)
131 /* Hack: don't print out password. */
132 if (strncmp (res, "PASS", 4) != 0)
133 logprintf (LOG_ALWAYS, "--> %s\n", res);
135 logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n\n");
138 DEBUGP (("\n--> %s\n", res));
142 /* Sends the USER and PASS commands to the server, to control
143 connection socket csock. */
145 ftp_login (int csock, const char *acc, const char *pass)
148 char *request, *respline;
152 err = ftp_response (csock, &respline);
155 if (*respline != '2')
161 /* Send USER username. */
162 request = ftp_request ("USER", acc);
163 nwritten = fd_write (csock, request, strlen (request), -1.0);
170 /* Get appropriate response. */
171 err = ftp_response (csock, &respline);
177 /* An unprobable possibility of logging without a password. */
178 if (*respline == '2')
183 /* Else, only response 3 is appropriate. */
184 if (*respline != '3')
187 return FTPLOGREFUSED;
191 static const char *skey_head[] = {
196 const char *seed = NULL;
198 for (i = 0; i < countof (skey_head); i++)
200 int l = strlen (skey_head[i]);
201 if (0 == strncasecmp (skey_head[i], respline, l))
209 int skey_sequence = 0;
211 /* Extract the sequence from SEED. */
212 for (; ISDIGIT (*seed); seed++)
213 skey_sequence = 10 * skey_sequence + *seed - '0';
219 return FTPLOGREFUSED;
221 /* Replace the password with the SKEY response to the
223 pass = skey_response (skey_sequence, seed, pass);
226 #endif /* ENABLE_OPIE */
228 /* Send PASS password. */
229 request = ftp_request ("PASS", pass);
230 nwritten = fd_write (csock, request, strlen (request), -1.0);
237 /* Get appropriate response. */
238 err = ftp_response (csock, &respline);
244 if (*respline != '2')
255 ip_address_to_port_repr (const ip_address *addr, int port, char *buf,
260 assert (addr != NULL);
261 assert (addr->type == IPV4_ADDRESS);
262 assert (buf != NULL);
263 /* buf must contain the argument of PORT (of the form a,b,c,d,e,f). */
264 assert (buflen >= 6 * 4);
266 ptr = ADDRESS_IPV4_DATA (addr);
267 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1],
268 ptr[2], ptr[3], (port & 0xff00) >> 8, port & 0xff);
269 buf[buflen - 1] = '\0';
272 /* Bind a port and send the appropriate PORT command to the FTP
273 server. Use acceptport after RETR, to get the socket of data
276 ftp_port (int csock, int *local_sock)
279 char *request, *respline;
283 /* Must contain the argument of PORT (of the form a,b,c,d,e,f). */
284 char bytes[6 * 4 + 1];
286 /* Get the address of this side of the connection. */
287 if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
290 assert (addr.type == IPV4_ADDRESS);
292 /* Setting port to 0 lets the system choose a free port. */
296 *local_sock = bind_local (&addr, &port);
300 /* Construct the argument of PORT (of the form a,b,c,d,e,f). */
301 ip_address_to_port_repr (&addr, port, bytes, sizeof (bytes));
303 /* Send PORT request. */
304 request = ftp_request ("PORT", bytes);
305 nwritten = fd_write (csock, request, strlen (request), -1.0);
309 fd_close (*local_sock);
314 /* Get appropriate response. */
315 err = ftp_response (csock, &respline);
319 fd_close (*local_sock);
322 if (*respline != '2')
325 fd_close (*local_sock);
334 ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf,
339 assert (addr != NULL);
340 assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
341 assert (buf != NULL);
342 /* buf must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
343 assert (buflen >= 21 * 4);
345 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
349 ptr = ADDRESS_IPV4_DATA (addr);
350 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4,
351 ptr[0], ptr[1], ptr[2], ptr[3], 2,
352 (port & 0xff00) >> 8, port & 0xff);
353 buf[buflen - 1] = '\0';
356 ptr = ADDRESS_IPV6_DATA (addr);
357 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
358 6, 16, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
359 ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], 2,
360 (port & 0xff00) >> 8, port & 0xff);
361 buf[buflen - 1] = '\0';
366 /* Bind a port and send the appropriate PORT command to the FTP
367 server. Use acceptport after RETR, to get the socket of data
370 ftp_lprt (int csock, int *local_sock)
373 char *request, *respline;
377 /* Must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
378 char bytes[21 * 4 + 1];
380 /* Get the address of this side of the connection. */
381 if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
384 assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
386 /* Setting port to 0 lets the system choose a free port. */
390 *local_sock = bind_local (&addr, &port);
394 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
395 ip_address_to_lprt_repr (&addr, port, bytes, sizeof (bytes));
397 /* Send PORT request. */
398 request = ftp_request ("LPRT", bytes);
399 nwritten = fd_write (csock, request, strlen (request), -1.0);
403 fd_close (*local_sock);
407 /* Get appropriate response. */
408 err = ftp_response (csock, &respline);
412 fd_close (*local_sock);
415 if (*respline != '2')
418 fd_close (*local_sock);
426 ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf,
431 assert (addr != NULL);
432 assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
433 assert (buf != NULL);
434 /* buf must contain the argument of EPRT (of the form |af|addr|port|).
435 * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr
436 * 1 char for af (1-2) and 5 chars for port (0-65535) */
437 assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5);
439 /* Construct the argument of EPRT (of the form |af|addr|port|). */
440 afnum = (addr->type == IPV4_ADDRESS ? 1 : 2);
441 snprintf (buf, buflen, "|%d|%s|%d|", afnum, pretty_print_address (addr), port);
442 buf[buflen - 1] = '\0';
445 /* Bind a port and send the appropriate PORT command to the FTP
446 server. Use acceptport after RETR, to get the socket of data
449 ftp_eprt (int csock, int *local_sock)
452 char *request, *respline;
456 /* Must contain the argument of EPRT (of the form |af|addr|port|).
457 * 4 chars for the | separators, ENABLE_IPV6_ADDRSTRLEN chars for addr
458 * 1 char for af (1-2) and 5 chars for port (0-65535) */
459 char bytes[4 + INET6_ADDRSTRLEN + 1 + 5 + 1];
461 /* Get the address of this side of the connection. */
462 if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
465 assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
467 /* Setting port to 0 lets the system choose a free port. */
471 *local_sock = bind_local (&addr, &port);
475 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
476 ip_address_to_eprt_repr (&addr, port, bytes, sizeof (bytes));
478 /* Send PORT request. */
479 request = ftp_request ("EPRT", bytes);
480 nwritten = fd_write (csock, request, strlen (request), -1.0);
484 fd_close (*local_sock);
488 /* Get appropriate response. */
489 err = ftp_response (csock, &respline);
493 fd_close (*local_sock);
496 if (*respline != '2')
499 fd_close (*local_sock);
507 /* Similar to ftp_port, but uses `PASV' to initiate the passive FTP
508 transfer. Reads the response from server and parses it. Reads the
509 host and port addresses and returns them. */
511 ftp_pasv (int csock, ip_address *addr, int *port)
513 char *request, *respline, *s;
516 unsigned char tmp[6];
518 assert (addr != NULL);
519 assert (port != NULL);
523 /* Form the request. */
524 request = ftp_request ("PASV", NULL);
526 nwritten = fd_write (csock, request, strlen (request), -1.0);
533 /* Get the server response. */
534 err = ftp_response (csock, &respline);
540 if (*respline != '2')
545 /* Parse the request. */
547 for (s += 4; *s && !ISDIGIT (*s); s++);
550 for (i = 0; i < 6; i++)
553 for (; ISDIGIT (*s); s++)
554 tmp[i] = (*s - '0') + 10 * tmp[i];
559 /* When on the last number, anything can be a terminator. */
566 addr->type = IPV4_ADDRESS;
567 memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
568 *port = ((tmp[4] << 8) & 0xff00) + tmp[5];
574 /* Similar to ftp_lprt, but uses `LPSV' to initiate the passive FTP
575 transfer. Reads the response from server and parses it. Reads the
576 host and port addresses and returns them. */
578 ftp_lpsv (int csock, ip_address *addr, int *port)
580 char *request, *respline, *s;
581 int nwritten, i, af, addrlen, portlen;
583 unsigned char tmp[16];
584 unsigned char tmpprt[2];
586 assert (addr != NULL);
587 assert (port != NULL);
591 /* Form the request. */
592 request = ftp_request ("LPSV", NULL);
595 nwritten = fd_write (csock, request, strlen (request), -1.0);
603 /* Get the server response. */
604 err = ftp_response (csock, &respline);
610 if (*respline != '2')
616 /* Parse the response. */
618 for (s += 4; *s && !ISDIGIT (*s); s++);
622 /* First, get the address family */
624 for (; ISDIGIT (*s); s++)
625 af = (*s - '0') + 10 * af;
627 if (af != 4 && af != 6)
633 if (!*s || *s++ != ',')
639 /* Then, get the address length */
641 for (; ISDIGIT (*s); s++)
642 addrlen = (*s - '0') + 10 * addrlen;
644 if (!*s || *s++ != ',')
656 if ((af == 4 && addrlen != 4)
657 || (af == 6 && addrlen != 16))
663 /* Now, we get the actual address */
664 for (i = 0; i < addrlen; i++)
667 for (; ISDIGIT (*s); s++)
668 tmp[i] = (*s - '0') + 10 * tmp[i];
678 /* Now, get the port length */
680 for (; ISDIGIT (*s); s++)
681 portlen = (*s - '0') + 10 * portlen;
683 if (!*s || *s++ != ',')
695 /* Finally, we get the port number */
697 for (; ISDIGIT (*s); s++)
698 tmpprt[0] = (*s - '0') + 10 * tmpprt[0];
700 if (!*s || *s++ != ',')
707 for (; ISDIGIT (*s); s++)
708 tmpprt[1] = (*s - '0') + 10 * tmpprt[1];
714 addr->type = IPV4_ADDRESS;
715 memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
716 *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
717 DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
718 DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
719 DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
720 DEBUGP (("*port is: %d\n", *port));
725 addr->type = IPV6_ADDRESS;
726 memcpy (ADDRESS_IPV6_DATA (addr), tmp, 16);
727 *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
728 DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
729 DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
730 DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
731 DEBUGP (("*port is: %d\n", *port));
738 /* Similar to ftp_eprt, but uses `EPSV' to initiate the passive FTP
739 transfer. Reads the response from server and parses it. Reads the
740 host and port addresses and returns them. */
742 ftp_epsv (int csock, ip_address *ip, int *port)
744 char *request, *respline, *start, delim, *s;
750 assert (port != NULL);
752 /* IP already contains the IP address of the control connection's
753 peer, so we don't need to call socket_ip_address here. */
755 /* Form the request. */
756 /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
757 request = ftp_request ("EPSV", (ip->type == IPV4_ADDRESS ? "1" : "2"));
760 nwritten = fd_write (csock, request, strlen (request), -1.0);
768 /* Get the server response. */
769 err = ftp_response (csock, &respline);
775 if (*respline != '2')
781 assert (respline != NULL);
783 DEBUGP(("respline is %s\n", respline));
785 /* Parse the response. */
788 /* Skip the useless stuff and get what's inside the parentheses */
789 start = strchr (respline, '(');
796 /* Skip the first two void fields */
799 if (delim < 33 || delim > 126)
805 for (i = 0; i < 2; i++)
814 /* Finally, get the port number */
816 for (i = 1; ISDIGIT (*s); s++)
823 tport = (*s - '0') + 10 * tport;
826 /* Make sure that the response terminates correcty */
846 /* Sends the TYPE request to the server. */
848 ftp_type (int csock, int type)
850 char *request, *respline;
855 /* Construct argument. */
858 /* Send TYPE request. */
859 request = ftp_request ("TYPE", stype);
860 nwritten = fd_write (csock, request, strlen (request), -1.0);
867 /* Get appropriate response. */
868 err = ftp_response (csock, &respline);
874 if (*respline != '2')
877 return FTPUNKNOWNTYPE;
884 /* Changes the working directory by issuing a CWD command to the
887 ftp_cwd (int csock, const char *dir)
889 char *request, *respline;
893 /* Send CWD request. */
894 request = ftp_request ("CWD", dir);
895 nwritten = fd_write (csock, request, strlen (request), -1.0);
902 /* Get appropriate response. */
903 err = ftp_response (csock, &respline);
909 if (*respline == '5')
914 if (*respline != '2')
924 /* Sends REST command to the FTP server. */
926 ftp_rest (int csock, wgint offset)
928 char *request, *respline;
932 request = ftp_request ("REST", number_to_static_string (offset));
933 nwritten = fd_write (csock, request, strlen (request), -1.0);
940 /* Get appropriate response. */
941 err = ftp_response (csock, &respline);
947 if (*respline != '3')
957 /* Sends RETR command to the FTP server. */
959 ftp_retr (int csock, const char *file)
961 char *request, *respline;
965 /* Send RETR request. */
966 request = ftp_request ("RETR", file);
967 nwritten = fd_write (csock, request, strlen (request), -1.0);
974 /* Get appropriate response. */
975 err = ftp_response (csock, &respline);
981 if (*respline == '5')
986 if (*respline != '1')
996 /* Sends the LIST command to the server. If FILE is NULL, send just
997 `LIST' (no space). */
999 ftp_list (int csock, const char *file)
1001 char *request, *respline;
1005 /* Send LIST request. */
1006 request = ftp_request ("LIST", file);
1007 nwritten = fd_write (csock, request, strlen (request), -1.0);
1014 /* Get appropriate respone. */
1015 err = ftp_response (csock, &respline);
1021 if (*respline == '5')
1026 if (*respline != '1')
1036 /* Sends the SYST command to the server. */
1038 ftp_syst (int csock, enum stype *server_type)
1040 char *request, *respline;
1044 /* Send SYST request. */
1045 request = ftp_request ("SYST", NULL);
1046 nwritten = fd_write (csock, request, strlen (request), -1.0);
1054 /* Get appropriate response. */
1055 err = ftp_response (csock, &respline);
1061 if (*respline == '5')
1067 /* Skip the number (215, but 200 (!!!) in case of VMS) */
1068 strtok (respline, " ");
1070 /* Which system type has been reported (we are interested just in the
1071 first word of the server response)? */
1072 request = strtok (NULL, " ");
1074 if (!strcasecmp (request, "VMS"))
1075 *server_type = ST_VMS;
1076 else if (!strcasecmp (request, "UNIX"))
1077 *server_type = ST_UNIX;
1078 else if (!strcasecmp (request, "WINDOWS_NT")
1079 || !strcasecmp (request, "WINDOWS2000"))
1080 *server_type = ST_WINNT;
1081 else if (!strcasecmp (request, "MACOS"))
1082 *server_type = ST_MACOS;
1083 else if (!strcasecmp (request, "OS/400"))
1084 *server_type = ST_OS400;
1086 *server_type = ST_OTHER;
1093 /* Sends the PWD command to the server. */
1095 ftp_pwd (int csock, char **pwd)
1097 char *request, *respline;
1101 /* Send PWD request. */
1102 request = ftp_request ("PWD", NULL);
1103 nwritten = fd_write (csock, request, strlen (request), -1.0);
1110 /* Get appropriate response. */
1111 err = ftp_response (csock, &respline);
1117 if (*respline == '5')
1123 /* Skip the number (257), leading citation mark, trailing citation mark
1124 and everything following it. */
1125 strtok (respline, "\"");
1126 request = strtok (NULL, "\"");
1128 /* Has the `pwd' been already allocated? Free! */
1131 *pwd = xstrdup (request);
1138 /* Sends the SIZE command to the server, and returns the value in 'size'.
1139 * If an error occurs, size is set to zero. */
1141 ftp_size (int csock, const char *file, wgint *size)
1143 char *request, *respline;
1147 /* Send PWD request. */
1148 request = ftp_request ("SIZE", file);
1149 nwritten = fd_write (csock, request, strlen (request), -1.0);
1157 /* Get appropriate response. */
1158 err = ftp_response (csock, &respline);
1165 if (*respline == '5')
1168 * Probably means SIZE isn't supported on this server.
1169 * Error is nonfatal since SIZE isn't in RFC 959
1177 *size = str_to_wgint (respline + 4, NULL, 10);
1181 * Couldn't parse the response for some reason. On the (few)
1182 * tests I've done, the response is 213 <SIZE> with nothing else -
1183 * maybe something a bit more resilient is necessary. It's not a
1184 * fatal error, however.
1196 /* If URL's params are of the form "type=X", return character X.
1197 Otherwise, return 'I' (the default type). */
1199 ftp_process_type (const char *params)
1202 && 0 == strncasecmp (params, "type=", 5)
1203 && params[5] != '\0')
1204 return TOUPPER (params[5]);