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>
49 #include <sys/socket.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
65 char ftp_last_respline[128];
68 /* Get the response of FTP server and allocate enough room to handle
69 it. <CR> and <LF> characters are stripped from the line, and the
70 line is 0-terminated. All the response lines but the last one are
71 skipped. The last line is determined as described in RFC959. */
73 ftp_response (struct rbuf *rbuf, char **line)
78 *line = (char *)xmalloc (bufsize);
85 *line = (char *)xrealloc (*line, (bufsize <<= 1));
86 res = RBUF_READCHAR (rbuf, *line + i);
87 /* RES is number of bytes read. */
90 if ((*line)[i] == '\n')
94 if (i > 0 && (*line)[i - 1] == '\r')
95 (*line)[i - 1] = '\0';
102 if (opt.server_response)
103 logprintf (LOG_ALWAYS, "%s\n", *line);
105 DEBUGP (("%s\n", *line));
107 while (!(i >= 3 && ISDIGIT (**line) && ISDIGIT ((*line)[1]) &&
108 ISDIGIT ((*line)[2]) && (*line)[3] == ' '));
109 strncpy (ftp_last_respline, *line, sizeof (ftp_last_respline));
110 ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0';
114 /* Returns the malloc-ed FTP request, ending with <CR><LF>, printing
115 it if printing is required. If VALUE is NULL, just use
118 ftp_request (const char *command, const char *value)
120 char *res = (char *)xmalloc (strlen (command)
121 + (value ? (1 + strlen (value)) : 0)
123 sprintf (res, "%s%s%s\r\n", command, value ? " " : "", value ? value : "");
124 if (opt.server_response)
126 /* Hack: don't print out password. */
127 if (strncmp (res, "PASS", 4) != 0)
128 logprintf (LOG_ALWAYS, "--> %s\n", res);
130 logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n\n");
133 DEBUGP (("\n--> %s\n", res));
138 const char *calculate_skey_response PARAMS ((int, const char *, const char *));
141 /* Sends the USER and PASS commands to the server, to control
142 connection socket csock. */
144 ftp_login (struct rbuf *rbuf, const char *acc, const char *pass)
147 char *request, *respline;
151 err = ftp_response (rbuf, &respline);
157 if (*respline != '2')
163 /* Send USER username. */
164 request = ftp_request ("USER", acc);
165 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
172 /* Get appropriate response. */
173 err = ftp_response (rbuf, &respline);
179 /* An unprobable possibility of logging without a password. */
180 if (*respline == '2')
185 /* Else, only response 3 is appropriate. */
186 if (*respline != '3')
189 return FTPLOGREFUSED;
193 static const char *skey_head[] = {
199 for (i = 0; i < countof (skey_head); i++)
201 if (strncasecmp (skey_head[i], respline, strlen (skey_head[i])) == 0)
204 if (i < countof (skey_head))
207 int skey_sequence = 0;
209 for (cp = respline + strlen (skey_head[i]);
210 '0' <= *cp && *cp <= '9';
213 skey_sequence = skey_sequence * 10 + *cp - '0';
221 return FTPLOGREFUSED;
223 if ((cp = calculate_skey_response (skey_sequence, cp, pass)) == 0)
228 #endif /* USE_OPIE */
230 /* Send PASS password. */
231 request = ftp_request ("PASS", pass);
232 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
239 /* Get appropriate response. */
240 err = ftp_response (rbuf, &respline);
246 if (*respline != '2')
257 ip_address_to_port_repr (const ip_address *addr, unsigned short port, char *buf,
262 assert (addr != NULL);
263 assert (addr->type == IPv4_ADDRESS);
264 assert (buf != NULL);
265 /* buf must contain the argument of PORT (of the form a,b,c,d,e,f). */
266 assert (buflen >= 6 * 4);
268 ptr = (unsigned char *)(&addr->addr.ipv4.addr.s_addr);
269 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1],
270 ptr[2], ptr[3], (unsigned) (port & 0xff00) >> 8, port & 0xff);
271 buf[buflen - 1] = '\0';
274 /* Bind a port and send the appropriate PORT command to the FTP
275 server. Use acceptport after RETR, to get the socket of data
278 ftp_port (struct rbuf *rbuf)
281 char *request, *respline;
285 /* Must contain the argument of PORT (of the form a,b,c,d,e,f). */
286 char bytes[6 * 4 + 1];
288 assert (rbuf != NULL);
289 assert (rbuf_initialized_p (rbuf));
291 /* Get the address of this side of the connection. */
292 if (!conaddr (RBUF_FD (rbuf), &addr))
295 assert (addr.type == IPv4_ADDRESS);
297 /* Setting port to 0 lets the system choose a free port. */
301 err = bindport (&addr, &port);
305 /* Construct the argument of PORT (of the form a,b,c,d,e,f). */
306 ip_address_to_port_repr (&addr, port, bytes, sizeof (bytes));
308 /* Send PORT request. */
309 request = ftp_request ("PORT", bytes);
310 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
319 /* Get appropriate response. */
320 err = ftp_response (rbuf, &respline);
327 if (*respline != '2')
339 ip_address_to_lprt_repr (const ip_address *addr, unsigned short port, char *buf,
344 assert (addr != NULL);
345 assert (addr->type == IPv4_ADDRESS || addr->type == IPv6_ADDRESS);
346 assert (buf != NULL);
347 /* buf must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
348 assert (buflen >= 21 * 4);
350 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
354 ptr = (unsigned char *)(&addr->addr.ipv4.addr);
355 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4,
356 ptr[0], ptr[1], ptr[2], ptr[3], 2,
357 (unsigned) (port & 0xff00) >> 8, port & 0xff);
358 buf[buflen - 1] = '\0';
361 ptr = (unsigned char *)(&addr->addr.ipv6.addr);
362 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
363 6, 16, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
364 ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], 2,
365 (unsigned) (port & 0xff00) >> 8, port & 0xff);
366 buf[buflen - 1] = '\0';
371 /* Bind a port and send the appropriate PORT command to the FTP
372 server. Use acceptport after RETR, to get the socket of data
375 ftp_lprt (struct rbuf *rbuf)
378 char *request, *respline;
382 /* Must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
383 char bytes[21 * 4 + 1];
385 assert (rbuf != NULL);
386 assert (rbuf_initialized_p (rbuf));
388 /* Get the address of this side of the connection. */
389 if (!conaddr (RBUF_FD (rbuf), &addr))
392 assert (addr.type == IPv4_ADDRESS || addr.type == IPv6_ADDRESS);
394 /* Setting port to 0 lets the system choose a free port. */
398 err = bindport (&addr, &port);
402 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
403 ip_address_to_lprt_repr (&addr, port, bytes, sizeof (bytes));
405 /* Send PORT request. */
406 request = ftp_request ("LPRT", bytes);
407 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
415 /* Get appropriate response. */
416 err = ftp_response (rbuf, &respline);
423 if (*respline != '2')
434 ip_address_to_eprt_repr (const ip_address *addr, unsigned short port, char *buf,
439 assert (addr != NULL);
440 assert (addr->type == IPv4_ADDRESS || addr->type == IPv6_ADDRESS);
441 assert (buf != NULL);
442 /* buf must contain the argument of EPRT (of the form |af|addr|port|).
443 * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr
444 * 1 char for af (1-2) and 5 chars for port (0-65535) */
445 assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5);
447 /* Construct the argument of EPRT (of the form |af|addr|port|). */
448 afnum = (addr->type == IPv4_ADDRESS ? 1 : 2);
449 snprintf (buf, buflen, "|%d|%s|%d|", afnum, pretty_print_address (addr), port);
450 buf[buflen - 1] = '\0';
453 /* Bind a port and send the appropriate PORT command to the FTP
454 server. Use acceptport after RETR, to get the socket of data
457 ftp_eprt (struct rbuf *rbuf)
460 char *request, *respline;
464 /* Must contain the argument of EPRT (of the form |af|addr|port|).
465 * 4 chars for the | separators, ENABLE_IPV6_ADDRSTRLEN chars for addr
466 * 1 char for af (1-2) and 5 chars for port (0-65535) */
467 char bytes[4 + INET6_ADDRSTRLEN + 1 + 5 + 1];
469 assert (rbuf != NULL);
470 assert (rbuf_initialized_p(rbuf));
472 /* Get the address of this side of the connection. */
473 if (!conaddr (RBUF_FD (rbuf), &addr))
476 assert (addr.type == IPv4_ADDRESS || addr.type == IPv6_ADDRESS);
478 /* Setting port to 0 lets the system choose a free port. */
482 err = bindport (&addr, &port);
486 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
487 ip_address_to_eprt_repr (&addr, port, bytes, sizeof (bytes));
489 /* Send PORT request. */
490 request = ftp_request ("EPRT", bytes);
491 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
499 /* Get appropriate response. */
500 err = ftp_response (rbuf, &respline);
507 if (*respline != '2')
518 /* Similar to ftp_port, but uses `PASV' to initiate the passive FTP
519 transfer. Reads the response from server and parses it. Reads the
520 host and port addresses and returns them. */
522 ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
524 char *request, *respline, *s;
527 unsigned char tmp[6];
529 assert (rbuf != NULL);
530 assert (rbuf_initialized_p(rbuf));
531 assert (addr != NULL);
532 assert (port != NULL);
534 memset (addr, 0, sizeof (ip_address));
536 /* Form the request. */
537 request = ftp_request ("PASV", NULL);
539 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
546 /* Get the server response. */
547 err = ftp_response (rbuf, &respline);
553 if (*respline != '2')
558 /* Parse the request. */
560 for (s += 4; *s && !ISDIGIT (*s); s++);
563 for (i = 0; i < 6; i++)
566 for (; ISDIGIT (*s); s++)
567 tmp[i] = (*s - '0') + 10 * tmp[i];
572 /* When on the last number, anything can be a terminator. */
579 addr->type = IPv4_ADDRESS;
580 /* Mauro Tortonesi: is this safe and/or elegant enough? */
581 memcpy (&addr->addr.ipv4.addr, tmp, 4);
582 *port = ((tmp[4] << 8) & 0xff00) + tmp[5];
588 /* Similar to ftp_lprt, but uses `LPSV' to initiate the passive FTP
589 transfer. Reads the response from server and parses it. Reads the
590 host and port addresses and returns them. */
592 ftp_lpsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
594 char *request, *respline, *s;
595 int nwritten, i, af, addrlen, portlen;
597 unsigned char tmp[16];
598 unsigned char tmpprt[2];
600 assert (rbuf != NULL);
601 assert (rbuf_initialized_p(rbuf));
602 assert (addr != NULL);
603 assert (port != NULL);
605 memset (addr, 0, sizeof (ip_address));
607 /* Form the request. */
608 request = ftp_request ("LPSV", NULL);
611 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
619 /* Get the server response. */
620 err = ftp_response (rbuf, &respline);
626 if (*respline != '2')
632 /* Parse the response. */
634 for (s += 4; *s && !ISDIGIT (*s); s++);
638 /* First, get the address family */
640 for (; ISDIGIT (*s); s++)
641 af = (*s - '0') + 10 * af;
643 if (af != 4 && af != 6)
649 if (!*s || *s++ != ',')
655 /* Then, get the address length */
657 for (; ISDIGIT (*s); s++)
658 addrlen = (*s - '0') + 10 * addrlen;
660 if (!*s || *s++ != ',')
672 if ((af == 4 && addrlen != 4)
673 || (af == 6 && addrlen != 16))
679 /* Now, we get the actual address */
680 for (i = 0; i < addrlen; i++)
683 for (; ISDIGIT (*s); s++)
684 tmp[i] = (*s - '0') + 10 * tmp[i];
694 /* Now, get the port length */
696 for (; ISDIGIT (*s); s++)
697 portlen = (*s - '0') + 10 * portlen;
699 if (!*s || *s++ != ',')
711 /* Finally, we get the port number */
713 for (; ISDIGIT (*s); s++)
714 tmpprt[0] = (*s - '0') + 10 * tmpprt[0];
716 if (!*s || *s++ != ',')
723 for (; ISDIGIT (*s); s++)
724 tmpprt[1] = (*s - '0') + 10 * tmpprt[1];
730 addr->type = IPv4_ADDRESS;
731 memcpy (&addr->addr.ipv4.addr, tmp, 4);
732 *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
733 DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
734 DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
735 DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
736 DEBUGP (("*port is: %d\n", *port));
741 addr->type = IPv6_ADDRESS;
742 memcpy (&addr->addr.ipv6.addr, tmp, 16);
743 *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
744 DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
745 DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
746 DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
747 DEBUGP (("*port is: %d\n", *port));
754 /* Similar to ftp_eprt, but uses `EPSV' to initiate the passive FTP
755 transfer. Reads the response from server and parses it. Reads the
756 host and port addresses and returns them. */
758 ftp_epsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
760 char *request, *respline, *start, delim, *s;
763 unsigned short tport;
765 struct sockaddr_storage ss;
766 struct sockaddr *sa = (struct sockaddr *)&ss;
768 assert (rbuf != NULL);
769 assert (rbuf_initialized_p(rbuf));
770 assert (addr != NULL);
771 assert (port != NULL);
773 addrlen = sizeof (ss);
774 if (getpeername (rbuf->fd, sa, &addrlen) < 0)
775 /* Mauro Tortonesi: HOW DO WE HANDLE THIS ERROR? */
778 assert (sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
780 sockaddr_get_address (sa, NULL, addr);
782 /* Form the request. */
783 /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
784 request = ftp_request ("EPSV", (sa->sa_family == AF_INET ? "1" : "2"));
787 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
795 /* Get the server response. */
796 err = ftp_response (rbuf, &respline);
802 if (*respline != '2')
808 assert (respline != NULL);
810 DEBUGP(("respline is %s\n", respline));
812 /* Parse the response. */
815 /* Skip the useless stuff and get what's inside the parentheses */
816 start = strchr (respline, '(');
823 /* Skip the first two void fields */
826 if (delim < 33 || delim > 126)
832 for (i = 0; i < 2; i++)
841 /* Finally, get the port number */
843 for (i = 1; ISDIGIT (*s); s++)
850 tport = (*s - '0') + 10 * tport;
853 /* Make sure that the response terminates correcty */
873 /* Sends the TYPE request to the server. */
875 ftp_type (struct rbuf *rbuf, int type)
877 char *request, *respline;
882 /* Construct argument. */
885 /* Send TYPE request. */
886 request = ftp_request ("TYPE", stype);
887 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
894 /* Get appropriate response. */
895 err = ftp_response (rbuf, &respline);
901 if (*respline != '2')
904 return FTPUNKNOWNTYPE;
911 /* Changes the working directory by issuing a CWD command to the
914 ftp_cwd (struct rbuf *rbuf, const char *dir)
916 char *request, *respline;
920 /* Send CWD request. */
921 request = ftp_request ("CWD", dir);
922 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
929 /* Get appropriate response. */
930 err = ftp_response (rbuf, &respline);
936 if (*respline == '5')
941 if (*respline != '2')
951 /* Sends REST command to the FTP server. */
953 ftp_rest (struct rbuf *rbuf, long offset)
955 char *request, *respline;
958 static char numbuf[24]; /* Buffer for the number */
960 number_to_string (numbuf, offset);
961 request = ftp_request ("REST", numbuf);
962 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
969 /* Get appropriate response. */
970 err = ftp_response (rbuf, &respline);
976 if (*respline != '3')
986 /* Sends RETR command to the FTP server. */
988 ftp_retr (struct rbuf *rbuf, const char *file)
990 char *request, *respline;
994 /* Send RETR request. */
995 request = ftp_request ("RETR", file);
996 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1003 /* Get appropriate response. */
1004 err = ftp_response (rbuf, &respline);
1010 if (*respline == '5')
1015 if (*respline != '1')
1025 /* Sends the LIST command to the server. If FILE is NULL, send just
1026 `LIST' (no space). */
1028 ftp_list (struct rbuf *rbuf, const char *file)
1030 char *request, *respline;
1034 /* Send LIST request. */
1035 request = ftp_request ("LIST", file);
1036 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1043 /* Get appropriate respone. */
1044 err = ftp_response (rbuf, &respline);
1050 if (*respline == '5')
1055 if (*respline != '1')
1065 /* Sends the SYST command to the server. */
1067 ftp_syst (struct rbuf *rbuf, enum stype *server_type)
1069 char *request, *respline;
1073 /* Send SYST request. */
1074 request = ftp_request ("SYST", NULL);
1075 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1083 /* Get appropriate response. */
1084 err = ftp_response (rbuf, &respline);
1090 if (*respline == '5')
1096 /* Skip the number (215, but 200 (!!!) in case of VMS) */
1097 strtok (respline, " ");
1099 /* Which system type has been reported (we are interested just in the
1100 first word of the server response)? */
1101 request = strtok (NULL, " ");
1103 if (!strcasecmp (request, "VMS"))
1104 *server_type = ST_VMS;
1105 else if (!strcasecmp (request, "UNIX"))
1106 *server_type = ST_UNIX;
1107 else if (!strcasecmp (request, "WINDOWS_NT"))
1108 *server_type = ST_WINNT;
1109 else if (!strcasecmp (request, "MACOS"))
1110 *server_type = ST_MACOS;
1111 else if (!strcasecmp (request, "OS/400"))
1112 *server_type = ST_OS400;
1114 *server_type = ST_OTHER;
1121 /* Sends the PWD command to the server. */
1123 ftp_pwd (struct rbuf *rbuf, char **pwd)
1125 char *request, *respline;
1129 /* Send PWD request. */
1130 request = ftp_request ("PWD", NULL);
1131 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1138 /* Get appropriate response. */
1139 err = ftp_response (rbuf, &respline);
1145 if (*respline == '5')
1151 /* Skip the number (257), leading citation mark, trailing citation mark
1152 and everything following it. */
1153 strtok (respline, "\"");
1154 request = strtok (NULL, "\"");
1156 /* Has the `pwd' been already allocated? Free! */
1159 *pwd = xstrdup (request);
1166 /* Sends the SIZE command to the server, and returns the value in 'size'.
1167 * If an error occurs, size is set to zero. */
1169 ftp_size (struct rbuf *rbuf, const char *file, long int *size)
1171 char *request, *respline;
1175 /* Send PWD request. */
1176 request = ftp_request ("SIZE", file);
1177 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1185 /* Get appropriate response. */
1186 err = ftp_response (rbuf, &respline);
1193 if (*respline == '5')
1196 * Probably means SIZE isn't supported on this server.
1197 * Error is nonfatal since SIZE isn't in RFC 959
1205 *size = strtol (respline + 4, NULL, 0);
1209 * Couldn't parse the response for some reason. On the (few)
1210 * tests I've done, the response is 213 <SIZE> with nothing else -
1211 * maybe something a bit more resilient is necessary. It's not a
1212 * fatal error, however.
1224 /* If URL's params are of the form "type=X", return character X.
1225 Otherwise, return 'I' (the default type). */
1227 ftp_process_type (const char *params)
1230 && 0 == strncasecmp (params, "type=", 5)
1231 && params[5] != '\0')
1232 return TOUPPER (params[5]);