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 (!conaddr (RBUF_FD (rbuf), &addr))
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 (!conaddr (RBUF_FD (rbuf), &addr))
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 (!conaddr (RBUF_FD (rbuf), &addr))
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 struct sockaddr_storage ss;
761 struct sockaddr *sa = (struct sockaddr *)&ss;
763 assert (rbuf != NULL);
764 assert (rbuf_initialized_p(rbuf));
766 assert (port != NULL);
768 addrlen = sizeof (ss);
769 if (getpeername (rbuf->fd, sa, &addrlen) < 0)
770 /* Mauro Tortonesi: HOW DO WE HANDLE THIS ERROR? */
773 assert (sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
775 sockaddr_get_data (sa, ip, NULL);
777 /* Form the request. */
778 /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
779 request = ftp_request ("EPSV", (sa->sa_family == AF_INET ? "1" : "2"));
782 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
790 /* Get the server response. */
791 err = ftp_response (rbuf, &respline);
797 if (*respline != '2')
803 assert (respline != NULL);
805 DEBUGP(("respline is %s\n", respline));
807 /* Parse the response. */
810 /* Skip the useless stuff and get what's inside the parentheses */
811 start = strchr (respline, '(');
818 /* Skip the first two void fields */
821 if (delim < 33 || delim > 126)
827 for (i = 0; i < 2; i++)
836 /* Finally, get the port number */
838 for (i = 1; ISDIGIT (*s); s++)
845 tport = (*s - '0') + 10 * tport;
848 /* Make sure that the response terminates correcty */
868 /* Sends the TYPE request to the server. */
870 ftp_type (struct rbuf *rbuf, int type)
872 char *request, *respline;
877 /* Construct argument. */
880 /* Send TYPE request. */
881 request = ftp_request ("TYPE", stype);
882 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
889 /* Get appropriate response. */
890 err = ftp_response (rbuf, &respline);
896 if (*respline != '2')
899 return FTPUNKNOWNTYPE;
906 /* Changes the working directory by issuing a CWD command to the
909 ftp_cwd (struct rbuf *rbuf, const char *dir)
911 char *request, *respline;
915 /* Send CWD request. */
916 request = ftp_request ("CWD", dir);
917 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
924 /* Get appropriate response. */
925 err = ftp_response (rbuf, &respline);
931 if (*respline == '5')
936 if (*respline != '2')
946 /* Sends REST command to the FTP server. */
948 ftp_rest (struct rbuf *rbuf, long offset)
950 char *request, *respline;
953 static char numbuf[24]; /* Buffer for the number */
955 number_to_string (numbuf, offset);
956 request = ftp_request ("REST", numbuf);
957 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
964 /* Get appropriate response. */
965 err = ftp_response (rbuf, &respline);
971 if (*respline != '3')
981 /* Sends RETR command to the FTP server. */
983 ftp_retr (struct rbuf *rbuf, const char *file)
985 char *request, *respline;
989 /* Send RETR request. */
990 request = ftp_request ("RETR", file);
991 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
998 /* Get appropriate response. */
999 err = ftp_response (rbuf, &respline);
1005 if (*respline == '5')
1010 if (*respline != '1')
1020 /* Sends the LIST command to the server. If FILE is NULL, send just
1021 `LIST' (no space). */
1023 ftp_list (struct rbuf *rbuf, const char *file)
1025 char *request, *respline;
1029 /* Send LIST request. */
1030 request = ftp_request ("LIST", file);
1031 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
1038 /* Get appropriate respone. */
1039 err = ftp_response (rbuf, &respline);
1045 if (*respline == '5')
1050 if (*respline != '1')
1060 /* Sends the SYST command to the server. */
1062 ftp_syst (struct rbuf *rbuf, enum stype *server_type)
1064 char *request, *respline;
1068 /* Send SYST request. */
1069 request = ftp_request ("SYST", NULL);
1070 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
1078 /* Get appropriate response. */
1079 err = ftp_response (rbuf, &respline);
1085 if (*respline == '5')
1091 /* Skip the number (215, but 200 (!!!) in case of VMS) */
1092 strtok (respline, " ");
1094 /* Which system type has been reported (we are interested just in the
1095 first word of the server response)? */
1096 request = strtok (NULL, " ");
1098 if (!strcasecmp (request, "VMS"))
1099 *server_type = ST_VMS;
1100 else if (!strcasecmp (request, "UNIX"))
1101 *server_type = ST_UNIX;
1102 else if (!strcasecmp (request, "WINDOWS_NT"))
1103 *server_type = ST_WINNT;
1104 else if (!strcasecmp (request, "MACOS"))
1105 *server_type = ST_MACOS;
1106 else if (!strcasecmp (request, "OS/400"))
1107 *server_type = ST_OS400;
1109 *server_type = ST_OTHER;
1116 /* Sends the PWD command to the server. */
1118 ftp_pwd (struct rbuf *rbuf, char **pwd)
1120 char *request, *respline;
1124 /* Send PWD request. */
1125 request = ftp_request ("PWD", NULL);
1126 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
1133 /* Get appropriate response. */
1134 err = ftp_response (rbuf, &respline);
1140 if (*respline == '5')
1146 /* Skip the number (257), leading citation mark, trailing citation mark
1147 and everything following it. */
1148 strtok (respline, "\"");
1149 request = strtok (NULL, "\"");
1151 /* Has the `pwd' been already allocated? Free! */
1154 *pwd = xstrdup (request);
1161 /* Sends the SIZE command to the server, and returns the value in 'size'.
1162 * If an error occurs, size is set to zero. */
1164 ftp_size (struct rbuf *rbuf, const char *file, long int *size)
1166 char *request, *respline;
1170 /* Send PWD request. */
1171 request = ftp_request ("SIZE", file);
1172 nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1);
1180 /* Get appropriate response. */
1181 err = ftp_response (rbuf, &respline);
1188 if (*respline == '5')
1191 * Probably means SIZE isn't supported on this server.
1192 * Error is nonfatal since SIZE isn't in RFC 959
1200 *size = strtol (respline + 4, NULL, 0);
1204 * Couldn't parse the response for some reason. On the (few)
1205 * tests I've done, the response is 213 <SIZE> with nothing else -
1206 * maybe something a bit more resilient is necessary. It's not a
1207 * fatal error, however.
1219 /* If URL's params are of the form "type=X", return character X.
1220 Otherwise, return 'I' (the default type). */
1222 ftp_process_type (const char *params)
1225 && 0 == strncasecmp (params, "type=", 5)
1226 && params[5] != '\0')
1227 return TOUPPER (params[5]);