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. */
62 ftp_response (int fd, char **ret_line)
66 char *line = fd_read_line (fd);
69 if (opt.server_response)
70 logputs (LOG_NOTQUIET, escnonprint (line));
72 DEBUGP (("%s", escnonprint (line)));
73 if (ISDIGIT (line[0]) && ISDIGIT (line[1]) && ISDIGIT (line[2])
76 char *p = line + strlen (line);
77 if (p > line && p[-1] == '\n')
79 if (p > line && p[-1] == '\r')
81 strncpy (ftp_last_respline, line, sizeof (ftp_last_respline));
82 ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0';
90 /* Returns the malloc-ed FTP request, ending with <CR><LF>, printing
91 it if printing is required. If VALUE is NULL, just use
94 ftp_request (const char *command, const char *value)
98 res = concat_strings (command, " ", value, "\r\n", (char *) 0);
100 res = concat_strings (command, "\r\n", (char *) 0);
101 if (opt.server_response)
103 /* Hack: don't print out password. */
104 if (strncmp (res, "PASS", 4) != 0)
105 logprintf (LOG_ALWAYS, "--> %s\n", res);
107 logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n\n");
110 DEBUGP (("\n--> %s\n", res));
114 /* Sends the USER and PASS commands to the server, to control
115 connection socket csock. */
117 ftp_login (int csock, const char *acc, const char *pass)
120 char *request, *respline;
124 err = ftp_response (csock, &respline);
127 if (*respline != '2')
133 /* Send USER username. */
134 request = ftp_request ("USER", acc);
135 nwritten = fd_write (csock, request, strlen (request), -1);
142 /* Get appropriate response. */
143 err = ftp_response (csock, &respline);
149 /* An unprobable possibility of logging without a password. */
150 if (*respline == '2')
155 /* Else, only response 3 is appropriate. */
156 if (*respline != '3')
159 return FTPLOGREFUSED;
163 static const char *skey_head[] = {
168 const char *seed = NULL;
170 for (i = 0; i < countof (skey_head); i++)
172 int l = strlen (skey_head[i]);
173 if (0 == strncasecmp (skey_head[i], respline, l))
181 int skey_sequence = 0;
183 /* Extract the sequence from SEED. */
184 for (; ISDIGIT (*seed); seed++)
185 skey_sequence = 10 * skey_sequence + *seed - '0';
191 return FTPLOGREFUSED;
193 /* Replace the password with the SKEY response to the
195 pass = skey_response (skey_sequence, seed, pass);
198 #endif /* ENABLE_OPIE */
200 /* Send PASS password. */
201 request = ftp_request ("PASS", pass);
202 nwritten = fd_write (csock, request, strlen (request), -1);
209 /* Get appropriate response. */
210 err = ftp_response (csock, &respline);
216 if (*respline != '2')
227 ip_address_to_port_repr (const ip_address *addr, int port, char *buf,
232 assert (addr != NULL);
233 assert (addr->type == IPV4_ADDRESS);
234 assert (buf != NULL);
235 /* buf must contain the argument of PORT (of the form a,b,c,d,e,f). */
236 assert (buflen >= 6 * 4);
238 ptr = ADDRESS_IPV4_DATA (addr);
239 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1],
240 ptr[2], ptr[3], (port & 0xff00) >> 8, port & 0xff);
241 buf[buflen - 1] = '\0';
244 /* Bind a port and send the appropriate PORT command to the FTP
245 server. Use acceptport after RETR, to get the socket of data
248 ftp_port (int csock, int *local_sock)
251 char *request, *respline;
255 /* Must contain the argument of PORT (of the form a,b,c,d,e,f). */
256 char bytes[6 * 4 + 1];
258 /* Get the address of this side of the connection. */
259 if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
262 assert (addr.type == IPV4_ADDRESS);
264 /* Setting port to 0 lets the system choose a free port. */
268 *local_sock = bind_local (&addr, &port);
272 /* Construct the argument of PORT (of the form a,b,c,d,e,f). */
273 ip_address_to_port_repr (&addr, port, bytes, sizeof (bytes));
275 /* Send PORT request. */
276 request = ftp_request ("PORT", bytes);
277 nwritten = fd_write (csock, request, strlen (request), -1);
281 fd_close (*local_sock);
286 /* Get appropriate response. */
287 err = ftp_response (csock, &respline);
291 fd_close (*local_sock);
294 if (*respline != '2')
297 fd_close (*local_sock);
306 ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf,
311 assert (addr != NULL);
312 assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
313 assert (buf != NULL);
314 /* buf must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
315 assert (buflen >= 21 * 4);
317 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
321 ptr = ADDRESS_IPV4_DATA (addr);
322 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4,
323 ptr[0], ptr[1], ptr[2], ptr[3], 2,
324 (port & 0xff00) >> 8, port & 0xff);
325 buf[buflen - 1] = '\0';
328 ptr = ADDRESS_IPV6_DATA (addr);
329 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
330 6, 16, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
331 ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], 2,
332 (port & 0xff00) >> 8, port & 0xff);
333 buf[buflen - 1] = '\0';
338 /* Bind a port and send the appropriate PORT command to the FTP
339 server. Use acceptport after RETR, to get the socket of data
342 ftp_lprt (int csock, int *local_sock)
345 char *request, *respline;
349 /* Must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
350 char bytes[21 * 4 + 1];
352 /* Get the address of this side of the connection. */
353 if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
356 assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
358 /* Setting port to 0 lets the system choose a free port. */
362 *local_sock = bind_local (&addr, &port);
366 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
367 ip_address_to_lprt_repr (&addr, port, bytes, sizeof (bytes));
369 /* Send PORT request. */
370 request = ftp_request ("LPRT", bytes);
371 nwritten = fd_write (csock, request, strlen (request), -1);
375 fd_close (*local_sock);
379 /* Get appropriate response. */
380 err = ftp_response (csock, &respline);
384 fd_close (*local_sock);
387 if (*respline != '2')
390 fd_close (*local_sock);
398 ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf,
403 assert (addr != NULL);
404 assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
405 assert (buf != NULL);
406 /* buf must contain the argument of EPRT (of the form |af|addr|port|).
407 * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr
408 * 1 char for af (1-2) and 5 chars for port (0-65535) */
409 assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5);
411 /* Construct the argument of EPRT (of the form |af|addr|port|). */
412 afnum = (addr->type == IPV4_ADDRESS ? 1 : 2);
413 snprintf (buf, buflen, "|%d|%s|%d|", afnum, pretty_print_address (addr), port);
414 buf[buflen - 1] = '\0';
417 /* Bind a port and send the appropriate PORT command to the FTP
418 server. Use acceptport after RETR, to get the socket of data
421 ftp_eprt (int csock, int *local_sock)
424 char *request, *respline;
428 /* Must contain the argument of EPRT (of the form |af|addr|port|).
429 * 4 chars for the | separators, ENABLE_IPV6_ADDRSTRLEN chars for addr
430 * 1 char for af (1-2) and 5 chars for port (0-65535) */
431 char bytes[4 + INET6_ADDRSTRLEN + 1 + 5 + 1];
433 /* Get the address of this side of the connection. */
434 if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
437 assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
439 /* Setting port to 0 lets the system choose a free port. */
443 *local_sock = bind_local (&addr, &port);
447 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
448 ip_address_to_eprt_repr (&addr, port, bytes, sizeof (bytes));
450 /* Send PORT request. */
451 request = ftp_request ("EPRT", bytes);
452 nwritten = fd_write (csock, request, strlen (request), -1);
456 fd_close (*local_sock);
460 /* Get appropriate response. */
461 err = ftp_response (csock, &respline);
465 fd_close (*local_sock);
468 if (*respline != '2')
471 fd_close (*local_sock);
479 /* Similar to ftp_port, but uses `PASV' to initiate the passive FTP
480 transfer. Reads the response from server and parses it. Reads the
481 host and port addresses and returns them. */
483 ftp_pasv (int csock, ip_address *addr, int *port)
485 char *request, *respline, *s;
488 unsigned char tmp[6];
490 assert (addr != NULL);
491 assert (port != NULL);
495 /* Form the request. */
496 request = ftp_request ("PASV", NULL);
498 nwritten = fd_write (csock, request, strlen (request), -1);
505 /* Get the server response. */
506 err = ftp_response (csock, &respline);
512 if (*respline != '2')
517 /* Parse the request. */
519 for (s += 4; *s && !ISDIGIT (*s); s++);
522 for (i = 0; i < 6; i++)
525 for (; ISDIGIT (*s); s++)
526 tmp[i] = (*s - '0') + 10 * tmp[i];
531 /* When on the last number, anything can be a terminator. */
538 addr->type = IPV4_ADDRESS;
539 memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
540 *port = ((tmp[4] << 8) & 0xff00) + tmp[5];
546 /* Similar to ftp_lprt, but uses `LPSV' to initiate the passive FTP
547 transfer. Reads the response from server and parses it. Reads the
548 host and port addresses and returns them. */
550 ftp_lpsv (int csock, ip_address *addr, int *port)
552 char *request, *respline, *s;
553 int nwritten, i, af, addrlen, portlen;
555 unsigned char tmp[16];
556 unsigned char tmpprt[2];
558 assert (addr != NULL);
559 assert (port != NULL);
563 /* Form the request. */
564 request = ftp_request ("LPSV", NULL);
567 nwritten = fd_write (csock, request, strlen (request), -1);
575 /* Get the server response. */
576 err = ftp_response (csock, &respline);
582 if (*respline != '2')
588 /* Parse the response. */
590 for (s += 4; *s && !ISDIGIT (*s); s++);
594 /* First, get the address family */
596 for (; ISDIGIT (*s); s++)
597 af = (*s - '0') + 10 * af;
599 if (af != 4 && af != 6)
605 if (!*s || *s++ != ',')
611 /* Then, get the address length */
613 for (; ISDIGIT (*s); s++)
614 addrlen = (*s - '0') + 10 * addrlen;
616 if (!*s || *s++ != ',')
628 if ((af == 4 && addrlen != 4)
629 || (af == 6 && addrlen != 16))
635 /* Now, we get the actual address */
636 for (i = 0; i < addrlen; i++)
639 for (; ISDIGIT (*s); s++)
640 tmp[i] = (*s - '0') + 10 * tmp[i];
650 /* Now, get the port length */
652 for (; ISDIGIT (*s); s++)
653 portlen = (*s - '0') + 10 * portlen;
655 if (!*s || *s++ != ',')
667 /* Finally, we get the port number */
669 for (; ISDIGIT (*s); s++)
670 tmpprt[0] = (*s - '0') + 10 * tmpprt[0];
672 if (!*s || *s++ != ',')
679 for (; ISDIGIT (*s); s++)
680 tmpprt[1] = (*s - '0') + 10 * tmpprt[1];
686 addr->type = IPV4_ADDRESS;
687 memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
688 *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
689 DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
690 DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
691 DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
692 DEBUGP (("*port is: %d\n", *port));
697 addr->type = IPV6_ADDRESS;
698 memcpy (ADDRESS_IPV6_DATA (addr), tmp, 16);
699 *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
700 DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
701 DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
702 DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
703 DEBUGP (("*port is: %d\n", *port));
710 /* Similar to ftp_eprt, but uses `EPSV' to initiate the passive FTP
711 transfer. Reads the response from server and parses it. Reads the
712 host and port addresses and returns them. */
714 ftp_epsv (int csock, ip_address *ip, int *port)
716 char *request, *respline, *start, delim, *s;
722 assert (port != NULL);
724 /* IP already contains the IP address of the control connection's
725 peer, so we don't need to call socket_ip_address here. */
727 /* Form the request. */
728 /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
729 request = ftp_request ("EPSV", (ip->type == IPV4_ADDRESS ? "1" : "2"));
732 nwritten = fd_write (csock, request, strlen (request), -1);
740 /* Get the server response. */
741 err = ftp_response (csock, &respline);
747 if (*respline != '2')
753 assert (respline != NULL);
755 DEBUGP(("respline is %s\n", respline));
757 /* Parse the response. */
760 /* Skip the useless stuff and get what's inside the parentheses */
761 start = strchr (respline, '(');
768 /* Skip the first two void fields */
771 if (delim < 33 || delim > 126)
777 for (i = 0; i < 2; i++)
786 /* Finally, get the port number */
788 for (i = 1; ISDIGIT (*s); s++)
795 tport = (*s - '0') + 10 * tport;
798 /* Make sure that the response terminates correcty */
818 /* Sends the TYPE request to the server. */
820 ftp_type (int csock, int type)
822 char *request, *respline;
827 /* Construct argument. */
830 /* Send TYPE request. */
831 request = ftp_request ("TYPE", stype);
832 nwritten = fd_write (csock, request, strlen (request), -1);
839 /* Get appropriate response. */
840 err = ftp_response (csock, &respline);
846 if (*respline != '2')
849 return FTPUNKNOWNTYPE;
856 /* Changes the working directory by issuing a CWD command to the
859 ftp_cwd (int csock, const char *dir)
861 char *request, *respline;
865 /* Send CWD request. */
866 request = ftp_request ("CWD", dir);
867 nwritten = fd_write (csock, request, strlen (request), -1);
874 /* Get appropriate response. */
875 err = ftp_response (csock, &respline);
881 if (*respline == '5')
886 if (*respline != '2')
896 /* Sends REST command to the FTP server. */
898 ftp_rest (int csock, wgint offset)
900 char *request, *respline;
904 request = ftp_request ("REST", number_to_static_string (offset));
905 nwritten = fd_write (csock, request, strlen (request), -1);
912 /* Get appropriate response. */
913 err = ftp_response (csock, &respline);
919 if (*respline != '3')
929 /* Sends RETR command to the FTP server. */
931 ftp_retr (int csock, const char *file)
933 char *request, *respline;
937 /* Send RETR request. */
938 request = ftp_request ("RETR", file);
939 nwritten = fd_write (csock, request, strlen (request), -1);
946 /* Get appropriate response. */
947 err = ftp_response (csock, &respline);
953 if (*respline == '5')
958 if (*respline != '1')
968 /* Sends the LIST command to the server. If FILE is NULL, send just
969 `LIST' (no space). */
971 ftp_list (int csock, const char *file)
973 char *request, *respline;
977 /* Send LIST request. */
978 request = ftp_request ("LIST", file);
979 nwritten = fd_write (csock, request, strlen (request), -1);
986 /* Get appropriate respone. */
987 err = ftp_response (csock, &respline);
993 if (*respline == '5')
998 if (*respline != '1')
1008 /* Sends the SYST command to the server. */
1010 ftp_syst (int csock, enum stype *server_type)
1012 char *request, *respline;
1016 /* Send SYST request. */
1017 request = ftp_request ("SYST", NULL);
1018 nwritten = fd_write (csock, request, strlen (request), -1);
1026 /* Get appropriate response. */
1027 err = ftp_response (csock, &respline);
1033 if (*respline == '5')
1039 /* Skip the number (215, but 200 (!!!) in case of VMS) */
1040 strtok (respline, " ");
1042 /* Which system type has been reported (we are interested just in the
1043 first word of the server response)? */
1044 request = strtok (NULL, " ");
1046 if (!strcasecmp (request, "VMS"))
1047 *server_type = ST_VMS;
1048 else if (!strcasecmp (request, "UNIX"))
1049 *server_type = ST_UNIX;
1050 else if (!strcasecmp (request, "WINDOWS_NT")
1051 || !strcasecmp (request, "WINDOWS2000"))
1052 *server_type = ST_WINNT;
1053 else if (!strcasecmp (request, "MACOS"))
1054 *server_type = ST_MACOS;
1055 else if (!strcasecmp (request, "OS/400"))
1056 *server_type = ST_OS400;
1058 *server_type = ST_OTHER;
1065 /* Sends the PWD command to the server. */
1067 ftp_pwd (int csock, char **pwd)
1069 char *request, *respline;
1073 /* Send PWD request. */
1074 request = ftp_request ("PWD", NULL);
1075 nwritten = fd_write (csock, request, strlen (request), -1);
1082 /* Get appropriate response. */
1083 err = ftp_response (csock, &respline);
1089 if (*respline == '5')
1095 /* Skip the number (257), leading citation mark, trailing citation mark
1096 and everything following it. */
1097 strtok (respline, "\"");
1098 request = strtok (NULL, "\"");
1100 /* Has the `pwd' been already allocated? Free! */
1103 *pwd = xstrdup (request);
1110 /* Sends the SIZE command to the server, and returns the value in 'size'.
1111 * If an error occurs, size is set to zero. */
1113 ftp_size (int csock, const char *file, wgint *size)
1115 char *request, *respline;
1119 /* Send PWD request. */
1120 request = ftp_request ("SIZE", file);
1121 nwritten = fd_write (csock, request, strlen (request), -1);
1129 /* Get appropriate response. */
1130 err = ftp_response (csock, &respline);
1137 if (*respline == '5')
1140 * Probably means SIZE isn't supported on this server.
1141 * Error is nonfatal since SIZE isn't in RFC 959
1149 *size = str_to_wgint (respline + 4, NULL, 10);
1153 * Couldn't parse the response for some reason. On the (few)
1154 * tests I've done, the response is 213 <SIZE> with nothing else -
1155 * maybe something a bit more resilient is necessary. It's not a
1156 * fatal error, however.
1168 /* If URL's params are of the form "type=X", return character X.
1169 Otherwise, return 'I' (the default type). */
1171 ftp_process_type (const char *params)
1174 && 0 == strncasecmp (params, "type=", 5)
1175 && params[5] != '\0')
1176 return TOUPPER (params[5]);