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, int 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 = ADDRESS_IPV4_DATA (addr);
269 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1],
270 ptr[2], ptr[3], (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, int *local_sock)
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, local_sock);
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, int 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 = ADDRESS_IPV4_DATA (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 (port & 0xff00) >> 8, port & 0xff);
358 buf[buflen - 1] = '\0';
361 ptr = ADDRESS_IPV6_DATA (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 (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, int *local_sock)
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, local_sock);
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, int 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, int *local_sock)
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, local_sock);
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, int *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 memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
581 *port = ((tmp[4] << 8) & 0xff00) + tmp[5];
587 /* Similar to ftp_lprt, but uses `LPSV' to initiate the passive FTP
588 transfer. Reads the response from server and parses it. Reads the
589 host and port addresses and returns them. */
591 ftp_lpsv (struct rbuf *rbuf, ip_address *addr, int *port)
593 char *request, *respline, *s;
594 int nwritten, i, af, addrlen, portlen;
596 unsigned char tmp[16];
597 unsigned char tmpprt[2];
599 assert (rbuf != NULL);
600 assert (rbuf_initialized_p(rbuf));
601 assert (addr != NULL);
602 assert (port != NULL);
604 memset (addr, 0, sizeof (ip_address));
606 /* Form the request. */
607 request = ftp_request ("LPSV", NULL);
610 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
618 /* Get the server response. */
619 err = ftp_response (rbuf, &respline);
625 if (*respline != '2')
631 /* Parse the response. */
633 for (s += 4; *s && !ISDIGIT (*s); s++);
637 /* First, get the address family */
639 for (; ISDIGIT (*s); s++)
640 af = (*s - '0') + 10 * af;
642 if (af != 4 && af != 6)
648 if (!*s || *s++ != ',')
654 /* Then, get the address length */
656 for (; ISDIGIT (*s); s++)
657 addrlen = (*s - '0') + 10 * addrlen;
659 if (!*s || *s++ != ',')
671 if ((af == 4 && addrlen != 4)
672 || (af == 6 && addrlen != 16))
678 /* Now, we get the actual address */
679 for (i = 0; i < addrlen; i++)
682 for (; ISDIGIT (*s); s++)
683 tmp[i] = (*s - '0') + 10 * tmp[i];
693 /* Now, get the port length */
695 for (; ISDIGIT (*s); s++)
696 portlen = (*s - '0') + 10 * portlen;
698 if (!*s || *s++ != ',')
710 /* Finally, we get the port number */
712 for (; ISDIGIT (*s); s++)
713 tmpprt[0] = (*s - '0') + 10 * tmpprt[0];
715 if (!*s || *s++ != ',')
722 for (; ISDIGIT (*s); s++)
723 tmpprt[1] = (*s - '0') + 10 * tmpprt[1];
729 addr->type = IPV4_ADDRESS;
730 memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
731 *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
732 DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
733 DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
734 DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
735 DEBUGP (("*port is: %d\n", *port));
740 addr->type = IPV6_ADDRESS;
741 memcpy (ADDRESS_IPV6_DATA (addr), tmp, 16);
742 *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
743 DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
744 DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
745 DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
746 DEBUGP (("*port is: %d\n", *port));
753 /* Similar to ftp_eprt, but uses `EPSV' to initiate the passive FTP
754 transfer. Reads the response from server and parses it. Reads the
755 host and port addresses and returns them. */
757 ftp_epsv (struct rbuf *rbuf, ip_address *ip, int *port)
759 char *request, *respline, *start, delim, *s;
764 struct sockaddr_storage ss;
765 struct sockaddr *sa = (struct sockaddr *)&ss;
767 assert (rbuf != NULL);
768 assert (rbuf_initialized_p(rbuf));
770 assert (port != NULL);
772 addrlen = sizeof (ss);
773 if (getpeername (rbuf->fd, sa, &addrlen) < 0)
774 /* Mauro Tortonesi: HOW DO WE HANDLE THIS ERROR? */
777 assert (sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
779 sockaddr_get_data (sa, ip, NULL);
781 /* Form the request. */
782 /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
783 request = ftp_request ("EPSV", (sa->sa_family == AF_INET ? "1" : "2"));
786 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
794 /* Get the server response. */
795 err = ftp_response (rbuf, &respline);
801 if (*respline != '2')
807 assert (respline != NULL);
809 DEBUGP(("respline is %s\n", respline));
811 /* Parse the response. */
814 /* Skip the useless stuff and get what's inside the parentheses */
815 start = strchr (respline, '(');
822 /* Skip the first two void fields */
825 if (delim < 33 || delim > 126)
831 for (i = 0; i < 2; i++)
840 /* Finally, get the port number */
842 for (i = 1; ISDIGIT (*s); s++)
849 tport = (*s - '0') + 10 * tport;
852 /* Make sure that the response terminates correcty */
872 /* Sends the TYPE request to the server. */
874 ftp_type (struct rbuf *rbuf, int type)
876 char *request, *respline;
881 /* Construct argument. */
884 /* Send TYPE request. */
885 request = ftp_request ("TYPE", stype);
886 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
893 /* Get appropriate response. */
894 err = ftp_response (rbuf, &respline);
900 if (*respline != '2')
903 return FTPUNKNOWNTYPE;
910 /* Changes the working directory by issuing a CWD command to the
913 ftp_cwd (struct rbuf *rbuf, const char *dir)
915 char *request, *respline;
919 /* Send CWD request. */
920 request = ftp_request ("CWD", dir);
921 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
928 /* Get appropriate response. */
929 err = ftp_response (rbuf, &respline);
935 if (*respline == '5')
940 if (*respline != '2')
950 /* Sends REST command to the FTP server. */
952 ftp_rest (struct rbuf *rbuf, long offset)
954 char *request, *respline;
957 static char numbuf[24]; /* Buffer for the number */
959 number_to_string (numbuf, offset);
960 request = ftp_request ("REST", numbuf);
961 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
968 /* Get appropriate response. */
969 err = ftp_response (rbuf, &respline);
975 if (*respline != '3')
985 /* Sends RETR command to the FTP server. */
987 ftp_retr (struct rbuf *rbuf, const char *file)
989 char *request, *respline;
993 /* Send RETR request. */
994 request = ftp_request ("RETR", file);
995 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1002 /* Get appropriate response. */
1003 err = ftp_response (rbuf, &respline);
1009 if (*respline == '5')
1014 if (*respline != '1')
1024 /* Sends the LIST command to the server. If FILE is NULL, send just
1025 `LIST' (no space). */
1027 ftp_list (struct rbuf *rbuf, const char *file)
1029 char *request, *respline;
1033 /* Send LIST request. */
1034 request = ftp_request ("LIST", file);
1035 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1042 /* Get appropriate respone. */
1043 err = ftp_response (rbuf, &respline);
1049 if (*respline == '5')
1054 if (*respline != '1')
1064 /* Sends the SYST command to the server. */
1066 ftp_syst (struct rbuf *rbuf, enum stype *server_type)
1068 char *request, *respline;
1072 /* Send SYST request. */
1073 request = ftp_request ("SYST", NULL);
1074 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1082 /* Get appropriate response. */
1083 err = ftp_response (rbuf, &respline);
1089 if (*respline == '5')
1095 /* Skip the number (215, but 200 (!!!) in case of VMS) */
1096 strtok (respline, " ");
1098 /* Which system type has been reported (we are interested just in the
1099 first word of the server response)? */
1100 request = strtok (NULL, " ");
1102 if (!strcasecmp (request, "VMS"))
1103 *server_type = ST_VMS;
1104 else if (!strcasecmp (request, "UNIX"))
1105 *server_type = ST_UNIX;
1106 else if (!strcasecmp (request, "WINDOWS_NT"))
1107 *server_type = ST_WINNT;
1108 else if (!strcasecmp (request, "MACOS"))
1109 *server_type = ST_MACOS;
1110 else if (!strcasecmp (request, "OS/400"))
1111 *server_type = ST_OS400;
1113 *server_type = ST_OTHER;
1120 /* Sends the PWD command to the server. */
1122 ftp_pwd (struct rbuf *rbuf, char **pwd)
1124 char *request, *respline;
1128 /* Send PWD request. */
1129 request = ftp_request ("PWD", NULL);
1130 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1137 /* Get appropriate response. */
1138 err = ftp_response (rbuf, &respline);
1144 if (*respline == '5')
1150 /* Skip the number (257), leading citation mark, trailing citation mark
1151 and everything following it. */
1152 strtok (respline, "\"");
1153 request = strtok (NULL, "\"");
1155 /* Has the `pwd' been already allocated? Free! */
1158 *pwd = xstrdup (request);
1165 /* Sends the SIZE command to the server, and returns the value in 'size'.
1166 * If an error occurs, size is set to zero. */
1168 ftp_size (struct rbuf *rbuf, const char *file, long int *size)
1170 char *request, *respline;
1174 /* Send PWD request. */
1175 request = ftp_request ("SIZE", file);
1176 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1184 /* Get appropriate response. */
1185 err = ftp_response (rbuf, &respline);
1192 if (*respline == '5')
1195 * Probably means SIZE isn't supported on this server.
1196 * Error is nonfatal since SIZE isn't in RFC 959
1204 *size = strtol (respline + 4, NULL, 0);
1208 * Couldn't parse the response for some reason. On the (few)
1209 * tests I've done, the response is 213 <SIZE> with nothing else -
1210 * maybe something a bit more resilient is necessary. It's not a
1211 * fatal error, however.
1223 /* If URL's params are of the form "type=X", return character X.
1224 Otherwise, return 'I' (the default type). */
1226 ftp_process_type (const char *params)
1229 && 0 == strncasecmp (params, "type=", 5)
1230 && params[5] != '\0')
1231 return TOUPPER (params[5]);