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));
137 /* Sends the USER and PASS commands to the server, to control
138 connection socket csock. */
140 ftp_login (struct rbuf *rbuf, const char *acc, const char *pass)
143 char *request, *respline;
147 err = ftp_response (rbuf, &respline);
153 if (*respline != '2')
159 /* Send USER username. */
160 request = ftp_request ("USER", acc);
161 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
168 /* Get appropriate response. */
169 err = ftp_response (rbuf, &respline);
175 /* An unprobable possibility of logging without a password. */
176 if (*respline == '2')
181 /* Else, only response 3 is appropriate. */
182 if (*respline != '3')
185 return FTPLOGREFUSED;
189 static const char *skey_head[] = {
194 const char *seed = NULL;
196 for (i = 0; i < countof (skey_head); i++)
198 int l = strlen (skey_head[i]);
199 if (0 == strncasecmp (skey_head[i], respline, l))
207 int skey_sequence = 0;
209 /* Extract the sequence from SEED. */
210 for (; ISDIGIT (*seed); seed++)
211 skey_sequence = 10 * skey_sequence + *seed - '0';
217 return FTPLOGREFUSED;
219 /* Replace the password with the SKEY response to the
221 pass = skey_response (skey_sequence, seed, pass);
224 #endif /* USE_OPIE */
226 /* Send PASS password. */
227 request = ftp_request ("PASS", pass);
228 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
235 /* Get appropriate response. */
236 err = ftp_response (rbuf, &respline);
242 if (*respline != '2')
253 ip_address_to_port_repr (const ip_address *addr, int port, char *buf,
258 assert (addr != NULL);
259 assert (addr->type == IPV4_ADDRESS);
260 assert (buf != NULL);
261 /* buf must contain the argument of PORT (of the form a,b,c,d,e,f). */
262 assert (buflen >= 6 * 4);
264 ptr = ADDRESS_IPV4_DATA (addr);
265 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1],
266 ptr[2], ptr[3], (port & 0xff00) >> 8, port & 0xff);
267 buf[buflen - 1] = '\0';
270 /* Bind a port and send the appropriate PORT command to the FTP
271 server. Use acceptport after RETR, to get the socket of data
274 ftp_port (struct rbuf *rbuf, int *local_sock)
277 char *request, *respline;
281 /* Must contain the argument of PORT (of the form a,b,c,d,e,f). */
282 char bytes[6 * 4 + 1];
284 assert (rbuf != NULL);
285 assert (rbuf_initialized_p (rbuf));
287 /* Get the address of this side of the connection. */
288 if (!socket_ip_address (RBUF_FD (rbuf), &addr, ENDPOINT_LOCAL))
291 assert (addr.type == IPV4_ADDRESS);
293 /* Setting port to 0 lets the system choose a free port. */
297 err = bindport (&addr, &port, local_sock);
301 /* Construct the argument of PORT (of the form a,b,c,d,e,f). */
302 ip_address_to_port_repr (&addr, port, bytes, sizeof (bytes));
304 /* Send PORT request. */
305 request = ftp_request ("PORT", bytes);
306 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
310 xclose (*local_sock);
315 /* Get appropriate response. */
316 err = ftp_response (rbuf, &respline);
320 xclose (*local_sock);
323 if (*respline != '2')
326 xclose (*local_sock);
335 ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf,
340 assert (addr != NULL);
341 assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
342 assert (buf != NULL);
343 /* buf must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
344 assert (buflen >= 21 * 4);
346 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
350 ptr = ADDRESS_IPV4_DATA (addr);
351 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4,
352 ptr[0], ptr[1], ptr[2], ptr[3], 2,
353 (port & 0xff00) >> 8, port & 0xff);
354 buf[buflen - 1] = '\0';
357 ptr = ADDRESS_IPV6_DATA (addr);
358 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
359 6, 16, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
360 ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], 2,
361 (port & 0xff00) >> 8, port & 0xff);
362 buf[buflen - 1] = '\0';
367 /* Bind a port and send the appropriate PORT command to the FTP
368 server. Use acceptport after RETR, to get the socket of data
371 ftp_lprt (struct rbuf *rbuf, int *local_sock)
374 char *request, *respline;
378 /* Must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
379 char bytes[21 * 4 + 1];
381 assert (rbuf != NULL);
382 assert (rbuf_initialized_p (rbuf));
384 /* Get the address of this side of the connection. */
385 if (!socket_ip_address (RBUF_FD (rbuf), &addr, ENDPOINT_LOCAL))
388 assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
390 /* Setting port to 0 lets the system choose a free port. */
394 err = bindport (&addr, &port, local_sock);
398 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
399 ip_address_to_lprt_repr (&addr, port, bytes, sizeof (bytes));
401 /* Send PORT request. */
402 request = ftp_request ("LPRT", bytes);
403 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
407 xclose (*local_sock);
411 /* Get appropriate response. */
412 err = ftp_response (rbuf, &respline);
416 xclose (*local_sock);
419 if (*respline != '2')
422 xclose (*local_sock);
430 ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf,
435 assert (addr != NULL);
436 assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
437 assert (buf != NULL);
438 /* buf must contain the argument of EPRT (of the form |af|addr|port|).
439 * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr
440 * 1 char for af (1-2) and 5 chars for port (0-65535) */
441 assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5);
443 /* Construct the argument of EPRT (of the form |af|addr|port|). */
444 afnum = (addr->type == IPV4_ADDRESS ? 1 : 2);
445 snprintf (buf, buflen, "|%d|%s|%d|", afnum, pretty_print_address (addr), port);
446 buf[buflen - 1] = '\0';
449 /* Bind a port and send the appropriate PORT command to the FTP
450 server. Use acceptport after RETR, to get the socket of data
453 ftp_eprt (struct rbuf *rbuf, int *local_sock)
456 char *request, *respline;
460 /* Must contain the argument of EPRT (of the form |af|addr|port|).
461 * 4 chars for the | separators, ENABLE_IPV6_ADDRSTRLEN chars for addr
462 * 1 char for af (1-2) and 5 chars for port (0-65535) */
463 char bytes[4 + INET6_ADDRSTRLEN + 1 + 5 + 1];
465 assert (rbuf != NULL);
466 assert (rbuf_initialized_p(rbuf));
468 /* Get the address of this side of the connection. */
469 if (!socket_ip_address (RBUF_FD (rbuf), &addr, ENDPOINT_LOCAL))
472 assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
474 /* Setting port to 0 lets the system choose a free port. */
478 err = bindport (&addr, &port, local_sock);
482 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
483 ip_address_to_eprt_repr (&addr, port, bytes, sizeof (bytes));
485 /* Send PORT request. */
486 request = ftp_request ("EPRT", bytes);
487 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
491 xclose (*local_sock);
495 /* Get appropriate response. */
496 err = ftp_response (rbuf, &respline);
500 xclose (*local_sock);
503 if (*respline != '2')
506 xclose (*local_sock);
514 /* Similar to ftp_port, but uses `PASV' to initiate the passive FTP
515 transfer. Reads the response from server and parses it. Reads the
516 host and port addresses and returns them. */
518 ftp_pasv (struct rbuf *rbuf, ip_address *addr, int *port)
520 char *request, *respline, *s;
523 unsigned char tmp[6];
525 assert (rbuf != NULL);
526 assert (rbuf_initialized_p (rbuf));
527 assert (addr != NULL);
528 assert (port != NULL);
530 memset (addr, 0, sizeof (ip_address));
532 /* Form the request. */
533 request = ftp_request ("PASV", NULL);
535 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
542 /* Get the server response. */
543 err = ftp_response (rbuf, &respline);
549 if (*respline != '2')
554 /* Parse the request. */
556 for (s += 4; *s && !ISDIGIT (*s); s++);
559 for (i = 0; i < 6; i++)
562 for (; ISDIGIT (*s); s++)
563 tmp[i] = (*s - '0') + 10 * tmp[i];
568 /* When on the last number, anything can be a terminator. */
575 addr->type = IPV4_ADDRESS;
576 memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
577 *port = ((tmp[4] << 8) & 0xff00) + tmp[5];
583 /* Similar to ftp_lprt, but uses `LPSV' to initiate the passive FTP
584 transfer. Reads the response from server and parses it. Reads the
585 host and port addresses and returns them. */
587 ftp_lpsv (struct rbuf *rbuf, ip_address *addr, int *port)
589 char *request, *respline, *s;
590 int nwritten, i, af, addrlen, portlen;
592 unsigned char tmp[16];
593 unsigned char tmpprt[2];
595 assert (rbuf != NULL);
596 assert (rbuf_initialized_p(rbuf));
597 assert (addr != NULL);
598 assert (port != NULL);
600 memset (addr, 0, sizeof (ip_address));
602 /* Form the request. */
603 request = ftp_request ("LPSV", NULL);
606 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
614 /* Get the server response. */
615 err = ftp_response (rbuf, &respline);
621 if (*respline != '2')
627 /* Parse the response. */
629 for (s += 4; *s && !ISDIGIT (*s); s++);
633 /* First, get the address family */
635 for (; ISDIGIT (*s); s++)
636 af = (*s - '0') + 10 * af;
638 if (af != 4 && af != 6)
644 if (!*s || *s++ != ',')
650 /* Then, get the address length */
652 for (; ISDIGIT (*s); s++)
653 addrlen = (*s - '0') + 10 * addrlen;
655 if (!*s || *s++ != ',')
667 if ((af == 4 && addrlen != 4)
668 || (af == 6 && addrlen != 16))
674 /* Now, we get the actual address */
675 for (i = 0; i < addrlen; i++)
678 for (; ISDIGIT (*s); s++)
679 tmp[i] = (*s - '0') + 10 * tmp[i];
689 /* Now, get the port length */
691 for (; ISDIGIT (*s); s++)
692 portlen = (*s - '0') + 10 * portlen;
694 if (!*s || *s++ != ',')
706 /* Finally, we get the port number */
708 for (; ISDIGIT (*s); s++)
709 tmpprt[0] = (*s - '0') + 10 * tmpprt[0];
711 if (!*s || *s++ != ',')
718 for (; ISDIGIT (*s); s++)
719 tmpprt[1] = (*s - '0') + 10 * tmpprt[1];
725 addr->type = IPV4_ADDRESS;
726 memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
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));
736 addr->type = IPV6_ADDRESS;
737 memcpy (ADDRESS_IPV6_DATA (addr), tmp, 16);
738 *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
739 DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
740 DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
741 DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
742 DEBUGP (("*port is: %d\n", *port));
749 /* Similar to ftp_eprt, but uses `EPSV' to initiate the passive FTP
750 transfer. Reads the response from server and parses it. Reads the
751 host and port addresses and returns them. */
753 ftp_epsv (struct rbuf *rbuf, ip_address *ip, int *port)
755 char *request, *respline, *start, delim, *s;
760 assert (rbuf != NULL);
761 assert (rbuf_initialized_p(rbuf));
763 assert (port != NULL);
765 /* IP already contains the IP address of the control connection's
766 peer, so we don't need to call socket_ip_address here. */
768 /* Form the request. */
769 /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
770 request = ftp_request ("EPSV", (ip->type == IPV4_ADDRESS ? "1" : "2"));
773 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
781 /* Get the server response. */
782 err = ftp_response (rbuf, &respline);
788 if (*respline != '2')
794 assert (respline != NULL);
796 DEBUGP(("respline is %s\n", respline));
798 /* Parse the response. */
801 /* Skip the useless stuff and get what's inside the parentheses */
802 start = strchr (respline, '(');
809 /* Skip the first two void fields */
812 if (delim < 33 || delim > 126)
818 for (i = 0; i < 2; i++)
827 /* Finally, get the port number */
829 for (i = 1; ISDIGIT (*s); s++)
836 tport = (*s - '0') + 10 * tport;
839 /* Make sure that the response terminates correcty */
859 /* Sends the TYPE request to the server. */
861 ftp_type (struct rbuf *rbuf, int type)
863 char *request, *respline;
868 /* Construct argument. */
871 /* Send TYPE request. */
872 request = ftp_request ("TYPE", stype);
873 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
880 /* Get appropriate response. */
881 err = ftp_response (rbuf, &respline);
887 if (*respline != '2')
890 return FTPUNKNOWNTYPE;
897 /* Changes the working directory by issuing a CWD command to the
900 ftp_cwd (struct rbuf *rbuf, const char *dir)
902 char *request, *respline;
906 /* Send CWD request. */
907 request = ftp_request ("CWD", dir);
908 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
915 /* Get appropriate response. */
916 err = ftp_response (rbuf, &respline);
922 if (*respline == '5')
927 if (*respline != '2')
937 /* Sends REST command to the FTP server. */
939 ftp_rest (struct rbuf *rbuf, long offset)
941 char *request, *respline;
944 static char numbuf[24]; /* Buffer for the number */
946 number_to_string (numbuf, offset);
947 request = ftp_request ("REST", numbuf);
948 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
955 /* Get appropriate response. */
956 err = ftp_response (rbuf, &respline);
962 if (*respline != '3')
972 /* Sends RETR command to the FTP server. */
974 ftp_retr (struct rbuf *rbuf, const char *file)
976 char *request, *respline;
980 /* Send RETR request. */
981 request = ftp_request ("RETR", file);
982 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
989 /* Get appropriate response. */
990 err = ftp_response (rbuf, &respline);
996 if (*respline == '5')
1001 if (*respline != '1')
1011 /* Sends the LIST command to the server. If FILE is NULL, send just
1012 `LIST' (no space). */
1014 ftp_list (struct rbuf *rbuf, const char *file)
1016 char *request, *respline;
1020 /* Send LIST request. */
1021 request = ftp_request ("LIST", file);
1022 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
1029 /* Get appropriate respone. */
1030 err = ftp_response (rbuf, &respline);
1036 if (*respline == '5')
1041 if (*respline != '1')
1051 /* Sends the SYST command to the server. */
1053 ftp_syst (struct rbuf *rbuf, enum stype *server_type)
1055 char *request, *respline;
1059 /* Send SYST request. */
1060 request = ftp_request ("SYST", NULL);
1061 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
1069 /* Get appropriate response. */
1070 err = ftp_response (rbuf, &respline);
1076 if (*respline == '5')
1082 /* Skip the number (215, but 200 (!!!) in case of VMS) */
1083 strtok (respline, " ");
1085 /* Which system type has been reported (we are interested just in the
1086 first word of the server response)? */
1087 request = strtok (NULL, " ");
1089 if (!strcasecmp (request, "VMS"))
1090 *server_type = ST_VMS;
1091 else if (!strcasecmp (request, "UNIX"))
1092 *server_type = ST_UNIX;
1093 else if (!strcasecmp (request, "WINDOWS_NT"))
1094 *server_type = ST_WINNT;
1095 else if (!strcasecmp (request, "MACOS"))
1096 *server_type = ST_MACOS;
1097 else if (!strcasecmp (request, "OS/400"))
1098 *server_type = ST_OS400;
1100 *server_type = ST_OTHER;
1107 /* Sends the PWD command to the server. */
1109 ftp_pwd (struct rbuf *rbuf, char **pwd)
1111 char *request, *respline;
1115 /* Send PWD request. */
1116 request = ftp_request ("PWD", NULL);
1117 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
1124 /* Get appropriate response. */
1125 err = ftp_response (rbuf, &respline);
1131 if (*respline == '5')
1137 /* Skip the number (257), leading citation mark, trailing citation mark
1138 and everything following it. */
1139 strtok (respline, "\"");
1140 request = strtok (NULL, "\"");
1142 /* Has the `pwd' been already allocated? Free! */
1145 *pwd = xstrdup (request);
1152 /* Sends the SIZE command to the server, and returns the value in 'size'.
1153 * If an error occurs, size is set to zero. */
1155 ftp_size (struct rbuf *rbuf, const char *file, long int *size)
1157 char *request, *respline;
1161 /* Send PWD request. */
1162 request = ftp_request ("SIZE", file);
1163 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
1171 /* Get appropriate response. */
1172 err = ftp_response (rbuf, &respline);
1179 if (*respline == '5')
1182 * Probably means SIZE isn't supported on this server.
1183 * Error is nonfatal since SIZE isn't in RFC 959
1191 *size = strtol (respline + 4, NULL, 0);
1195 * Couldn't parse the response for some reason. On the (few)
1196 * tests I've done, the response is 213 <SIZE> with nothing else -
1197 * maybe something a bit more resilient is necessary. It's not a
1198 * fatal error, however.
1210 /* If URL's params are of the form "type=X", return character X.
1211 Otherwise, return 'I' (the default type). */
1213 ftp_process_type (const char *params)
1216 && 0 == strncasecmp (params, "type=", 5)
1217 && params[5] != '\0')
1218 return TOUPPER (params[5]);