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 = iwrite (RBUF_FD (rbuf), request, strlen (request));
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))
208 int skey_sequence = 0;
210 /* Extract the sequence from SEED. */
211 for (; ISDIGIT (*seed); seed++)
212 skey_sequence = 10 * skey_sequence + *seed - '0';
218 return FTPLOGREFUSED;
220 /* Replace the password with the SKEY response to the
222 pass = skey_response (skey_sequence, seed, pass);
225 #endif /* USE_OPIE */
227 /* Send PASS password. */
228 request = ftp_request ("PASS", pass);
229 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
236 /* Get appropriate response. */
237 err = ftp_response (rbuf, &respline);
243 if (*respline != '2')
254 ip_address_to_port_repr (const ip_address *addr, int port, char *buf,
259 assert (addr != NULL);
260 assert (addr->type == IPV4_ADDRESS);
261 assert (buf != NULL);
262 /* buf must contain the argument of PORT (of the form a,b,c,d,e,f). */
263 assert (buflen >= 6 * 4);
265 ptr = ADDRESS_IPV4_DATA (addr);
266 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1],
267 ptr[2], ptr[3], (port & 0xff00) >> 8, port & 0xff);
268 buf[buflen - 1] = '\0';
271 /* Bind a port and send the appropriate PORT command to the FTP
272 server. Use acceptport after RETR, to get the socket of data
275 ftp_port (struct rbuf *rbuf, int *local_sock)
278 char *request, *respline;
282 /* Must contain the argument of PORT (of the form a,b,c,d,e,f). */
283 char bytes[6 * 4 + 1];
285 assert (rbuf != NULL);
286 assert (rbuf_initialized_p (rbuf));
288 /* Get the address of this side of the connection. */
289 if (!conaddr (RBUF_FD (rbuf), &addr))
292 assert (addr.type == IPV4_ADDRESS);
294 /* Setting port to 0 lets the system choose a free port. */
298 err = bindport (&addr, &port, local_sock);
302 /* Construct the argument of PORT (of the form a,b,c,d,e,f). */
303 ip_address_to_port_repr (&addr, port, bytes, sizeof (bytes));
305 /* Send PORT request. */
306 request = ftp_request ("PORT", bytes);
307 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
316 /* Get appropriate response. */
317 err = ftp_response (rbuf, &respline);
324 if (*respline != '2')
336 ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf,
341 assert (addr != NULL);
342 assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
343 assert (buf != NULL);
344 /* buf must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
345 assert (buflen >= 21 * 4);
347 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
351 ptr = ADDRESS_IPV4_DATA (addr);
352 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4,
353 ptr[0], ptr[1], ptr[2], ptr[3], 2,
354 (port & 0xff00) >> 8, port & 0xff);
355 buf[buflen - 1] = '\0';
358 ptr = ADDRESS_IPV6_DATA (addr);
359 snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
360 6, 16, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
361 ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], 2,
362 (port & 0xff00) >> 8, port & 0xff);
363 buf[buflen - 1] = '\0';
368 /* Bind a port and send the appropriate PORT command to the FTP
369 server. Use acceptport after RETR, to get the socket of data
372 ftp_lprt (struct rbuf *rbuf, int *local_sock)
375 char *request, *respline;
379 /* Must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
380 char bytes[21 * 4 + 1];
382 assert (rbuf != NULL);
383 assert (rbuf_initialized_p (rbuf));
385 /* Get the address of this side of the connection. */
386 if (!conaddr (RBUF_FD (rbuf), &addr))
389 assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
391 /* Setting port to 0 lets the system choose a free port. */
395 err = bindport (&addr, &port, local_sock);
399 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
400 ip_address_to_lprt_repr (&addr, port, bytes, sizeof (bytes));
402 /* Send PORT request. */
403 request = ftp_request ("LPRT", bytes);
404 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
412 /* Get appropriate response. */
413 err = ftp_response (rbuf, &respline);
420 if (*respline != '2')
431 ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf,
436 assert (addr != NULL);
437 assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
438 assert (buf != NULL);
439 /* buf must contain the argument of EPRT (of the form |af|addr|port|).
440 * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr
441 * 1 char for af (1-2) and 5 chars for port (0-65535) */
442 assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5);
444 /* Construct the argument of EPRT (of the form |af|addr|port|). */
445 afnum = (addr->type == IPV4_ADDRESS ? 1 : 2);
446 snprintf (buf, buflen, "|%d|%s|%d|", afnum, pretty_print_address (addr), port);
447 buf[buflen - 1] = '\0';
450 /* Bind a port and send the appropriate PORT command to the FTP
451 server. Use acceptport after RETR, to get the socket of data
454 ftp_eprt (struct rbuf *rbuf, int *local_sock)
457 char *request, *respline;
461 /* Must contain the argument of EPRT (of the form |af|addr|port|).
462 * 4 chars for the | separators, ENABLE_IPV6_ADDRSTRLEN chars for addr
463 * 1 char for af (1-2) and 5 chars for port (0-65535) */
464 char bytes[4 + INET6_ADDRSTRLEN + 1 + 5 + 1];
466 assert (rbuf != NULL);
467 assert (rbuf_initialized_p(rbuf));
469 /* Get the address of this side of the connection. */
470 if (!conaddr (RBUF_FD (rbuf), &addr))
473 assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
475 /* Setting port to 0 lets the system choose a free port. */
479 err = bindport (&addr, &port, local_sock);
483 /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
484 ip_address_to_eprt_repr (&addr, port, bytes, sizeof (bytes));
486 /* Send PORT request. */
487 request = ftp_request ("EPRT", bytes);
488 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
496 /* Get appropriate response. */
497 err = ftp_response (rbuf, &respline);
504 if (*respline != '2')
515 /* Similar to ftp_port, but uses `PASV' to initiate the passive FTP
516 transfer. Reads the response from server and parses it. Reads the
517 host and port addresses and returns them. */
519 ftp_pasv (struct rbuf *rbuf, ip_address *addr, int *port)
521 char *request, *respline, *s;
524 unsigned char tmp[6];
526 assert (rbuf != NULL);
527 assert (rbuf_initialized_p (rbuf));
528 assert (addr != NULL);
529 assert (port != NULL);
531 memset (addr, 0, sizeof (ip_address));
533 /* Form the request. */
534 request = ftp_request ("PASV", NULL);
536 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
543 /* Get the server response. */
544 err = ftp_response (rbuf, &respline);
550 if (*respline != '2')
555 /* Parse the request. */
557 for (s += 4; *s && !ISDIGIT (*s); s++);
560 for (i = 0; i < 6; i++)
563 for (; ISDIGIT (*s); s++)
564 tmp[i] = (*s - '0') + 10 * tmp[i];
569 /* When on the last number, anything can be a terminator. */
576 addr->type = IPV4_ADDRESS;
577 memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
578 *port = ((tmp[4] << 8) & 0xff00) + tmp[5];
584 /* Similar to ftp_lprt, but uses `LPSV' to initiate the passive FTP
585 transfer. Reads the response from server and parses it. Reads the
586 host and port addresses and returns them. */
588 ftp_lpsv (struct rbuf *rbuf, ip_address *addr, int *port)
590 char *request, *respline, *s;
591 int nwritten, i, af, addrlen, portlen;
593 unsigned char tmp[16];
594 unsigned char tmpprt[2];
596 assert (rbuf != NULL);
597 assert (rbuf_initialized_p(rbuf));
598 assert (addr != NULL);
599 assert (port != NULL);
601 memset (addr, 0, sizeof (ip_address));
603 /* Form the request. */
604 request = ftp_request ("LPSV", NULL);
607 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
615 /* Get the server response. */
616 err = ftp_response (rbuf, &respline);
622 if (*respline != '2')
628 /* Parse the response. */
630 for (s += 4; *s && !ISDIGIT (*s); s++);
634 /* First, get the address family */
636 for (; ISDIGIT (*s); s++)
637 af = (*s - '0') + 10 * af;
639 if (af != 4 && af != 6)
645 if (!*s || *s++ != ',')
651 /* Then, get the address length */
653 for (; ISDIGIT (*s); s++)
654 addrlen = (*s - '0') + 10 * addrlen;
656 if (!*s || *s++ != ',')
668 if ((af == 4 && addrlen != 4)
669 || (af == 6 && addrlen != 16))
675 /* Now, we get the actual address */
676 for (i = 0; i < addrlen; i++)
679 for (; ISDIGIT (*s); s++)
680 tmp[i] = (*s - '0') + 10 * tmp[i];
690 /* Now, get the port length */
692 for (; ISDIGIT (*s); s++)
693 portlen = (*s - '0') + 10 * portlen;
695 if (!*s || *s++ != ',')
707 /* Finally, we get the port number */
709 for (; ISDIGIT (*s); s++)
710 tmpprt[0] = (*s - '0') + 10 * tmpprt[0];
712 if (!*s || *s++ != ',')
719 for (; ISDIGIT (*s); s++)
720 tmpprt[1] = (*s - '0') + 10 * tmpprt[1];
726 addr->type = IPV4_ADDRESS;
727 memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
728 *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
729 DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
730 DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
731 DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
732 DEBUGP (("*port is: %d\n", *port));
737 addr->type = IPV6_ADDRESS;
738 memcpy (ADDRESS_IPV6_DATA (addr), tmp, 16);
739 *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
740 DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
741 DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
742 DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
743 DEBUGP (("*port is: %d\n", *port));
750 /* Similar to ftp_eprt, but uses `EPSV' to initiate the passive FTP
751 transfer. Reads the response from server and parses it. Reads the
752 host and port addresses and returns them. */
754 ftp_epsv (struct rbuf *rbuf, ip_address *ip, int *port)
756 char *request, *respline, *start, delim, *s;
761 struct sockaddr_storage ss;
762 struct sockaddr *sa = (struct sockaddr *)&ss;
764 assert (rbuf != NULL);
765 assert (rbuf_initialized_p(rbuf));
767 assert (port != NULL);
769 addrlen = sizeof (ss);
770 if (getpeername (rbuf->fd, sa, &addrlen) < 0)
771 /* Mauro Tortonesi: HOW DO WE HANDLE THIS ERROR? */
774 assert (sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
776 sockaddr_get_data (sa, ip, NULL);
778 /* Form the request. */
779 /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
780 request = ftp_request ("EPSV", (sa->sa_family == AF_INET ? "1" : "2"));
783 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
791 /* Get the server response. */
792 err = ftp_response (rbuf, &respline);
798 if (*respline != '2')
804 assert (respline != NULL);
806 DEBUGP(("respline is %s\n", respline));
808 /* Parse the response. */
811 /* Skip the useless stuff and get what's inside the parentheses */
812 start = strchr (respline, '(');
819 /* Skip the first two void fields */
822 if (delim < 33 || delim > 126)
828 for (i = 0; i < 2; i++)
837 /* Finally, get the port number */
839 for (i = 1; ISDIGIT (*s); s++)
846 tport = (*s - '0') + 10 * tport;
849 /* Make sure that the response terminates correcty */
869 /* Sends the TYPE request to the server. */
871 ftp_type (struct rbuf *rbuf, int type)
873 char *request, *respline;
878 /* Construct argument. */
881 /* Send TYPE request. */
882 request = ftp_request ("TYPE", stype);
883 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
890 /* Get appropriate response. */
891 err = ftp_response (rbuf, &respline);
897 if (*respline != '2')
900 return FTPUNKNOWNTYPE;
907 /* Changes the working directory by issuing a CWD command to the
910 ftp_cwd (struct rbuf *rbuf, const char *dir)
912 char *request, *respline;
916 /* Send CWD request. */
917 request = ftp_request ("CWD", dir);
918 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
925 /* Get appropriate response. */
926 err = ftp_response (rbuf, &respline);
932 if (*respline == '5')
937 if (*respline != '2')
947 /* Sends REST command to the FTP server. */
949 ftp_rest (struct rbuf *rbuf, long offset)
951 char *request, *respline;
954 static char numbuf[24]; /* Buffer for the number */
956 number_to_string (numbuf, offset);
957 request = ftp_request ("REST", numbuf);
958 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
965 /* Get appropriate response. */
966 err = ftp_response (rbuf, &respline);
972 if (*respline != '3')
982 /* Sends RETR command to the FTP server. */
984 ftp_retr (struct rbuf *rbuf, const char *file)
986 char *request, *respline;
990 /* Send RETR request. */
991 request = ftp_request ("RETR", file);
992 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
999 /* Get appropriate response. */
1000 err = ftp_response (rbuf, &respline);
1006 if (*respline == '5')
1011 if (*respline != '1')
1021 /* Sends the LIST command to the server. If FILE is NULL, send just
1022 `LIST' (no space). */
1024 ftp_list (struct rbuf *rbuf, const char *file)
1026 char *request, *respline;
1030 /* Send LIST request. */
1031 request = ftp_request ("LIST", file);
1032 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1039 /* Get appropriate respone. */
1040 err = ftp_response (rbuf, &respline);
1046 if (*respline == '5')
1051 if (*respline != '1')
1061 /* Sends the SYST command to the server. */
1063 ftp_syst (struct rbuf *rbuf, enum stype *server_type)
1065 char *request, *respline;
1069 /* Send SYST request. */
1070 request = ftp_request ("SYST", NULL);
1071 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1079 /* Get appropriate response. */
1080 err = ftp_response (rbuf, &respline);
1086 if (*respline == '5')
1092 /* Skip the number (215, but 200 (!!!) in case of VMS) */
1093 strtok (respline, " ");
1095 /* Which system type has been reported (we are interested just in the
1096 first word of the server response)? */
1097 request = strtok (NULL, " ");
1099 if (!strcasecmp (request, "VMS"))
1100 *server_type = ST_VMS;
1101 else if (!strcasecmp (request, "UNIX"))
1102 *server_type = ST_UNIX;
1103 else if (!strcasecmp (request, "WINDOWS_NT"))
1104 *server_type = ST_WINNT;
1105 else if (!strcasecmp (request, "MACOS"))
1106 *server_type = ST_MACOS;
1107 else if (!strcasecmp (request, "OS/400"))
1108 *server_type = ST_OS400;
1110 *server_type = ST_OTHER;
1117 /* Sends the PWD command to the server. */
1119 ftp_pwd (struct rbuf *rbuf, char **pwd)
1121 char *request, *respline;
1125 /* Send PWD request. */
1126 request = ftp_request ("PWD", NULL);
1127 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1134 /* Get appropriate response. */
1135 err = ftp_response (rbuf, &respline);
1141 if (*respline == '5')
1147 /* Skip the number (257), leading citation mark, trailing citation mark
1148 and everything following it. */
1149 strtok (respline, "\"");
1150 request = strtok (NULL, "\"");
1152 /* Has the `pwd' been already allocated? Free! */
1155 *pwd = xstrdup (request);
1162 /* Sends the SIZE command to the server, and returns the value in 'size'.
1163 * If an error occurs, size is set to zero. */
1165 ftp_size (struct rbuf *rbuf, const char *file, long int *size)
1167 char *request, *respline;
1171 /* Send PWD request. */
1172 request = ftp_request ("SIZE", file);
1173 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
1181 /* Get appropriate response. */
1182 err = ftp_response (rbuf, &respline);
1189 if (*respline == '5')
1192 * Probably means SIZE isn't supported on this server.
1193 * Error is nonfatal since SIZE isn't in RFC 959
1201 *size = strtol (respline + 4, NULL, 0);
1205 * Couldn't parse the response for some reason. On the (few)
1206 * tests I've done, the response is 213 <SIZE> with nothing else -
1207 * maybe something a bit more resilient is necessary. It's not a
1208 * fatal error, however.
1220 /* If URL's params are of the form "type=X", return character X.
1221 Otherwise, return 'I' (the default type). */
1223 ftp_process_type (const char *params)
1226 && 0 == strncasecmp (params, "type=", 5)
1227 && params[5] != '\0')
1228 return TOUPPER (params[5]);