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. */
34 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <arpa/inet.h>
51 char ftp_last_respline[128];
54 /* Get the response of FTP server and allocate enough room to handle
55 it. <CR> and <LF> characters are stripped from the line, and the
56 line is 0-terminated. All the response lines but the last one are
57 skipped. The last line is determined as described in RFC959. */
59 ftp_response (struct rbuf *rbuf, char **line)
64 *line = (char *)xmalloc (bufsize);
71 *line = (char *)xrealloc (*line, (bufsize <<= 1));
72 res = RBUF_READCHAR (rbuf, *line + i);
73 /* RES is number of bytes read. */
76 if ((*line)[i] == '\n')
80 if (i > 0 && (*line)[i - 1] == '\r')
81 (*line)[i - 1] = '\0';
88 if (opt.server_response)
89 logprintf (LOG_ALWAYS, "%s\n", *line);
91 DEBUGP (("%s\n", *line));
93 while (!(i >= 3 && ISDIGIT (**line) && ISDIGIT ((*line)[1]) &&
94 ISDIGIT ((*line)[2]) && (*line)[3] == ' '));
95 strncpy (ftp_last_respline, *line, sizeof (ftp_last_respline));
96 ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0';
100 /* Returns the malloc-ed FTP request, ending with <CR><LF>, printing
101 it if printing is required. If VALUE is NULL, just use
104 ftp_request (const char *command, const char *value)
106 char *res = (char *)xmalloc (strlen (command)
107 + (value ? (1 + strlen (value)) : 0)
109 sprintf (res, "%s%s%s\r\n", command, value ? " " : "", value ? value : "");
110 if (opt.server_response)
112 /* Hack: don't print out password. */
113 if (strncmp (res, "PASS", 4) != 0)
114 logprintf (LOG_ALWAYS, "--> %s\n", res);
116 logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n");
119 DEBUGP (("\n--> %s\n", res));
124 const char *calculate_skey_response PARAMS ((int, const char *, const char *));
127 /* Sends the USER and PASS commands to the server, to control
128 connection socket csock. */
130 ftp_login (struct rbuf *rbuf, const char *acc, const char *pass)
133 char *request, *respline;
137 err = ftp_response (rbuf, &respline);
143 if (*respline != '2')
149 /* Send USER username. */
150 request = ftp_request ("USER", acc);
151 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
158 /* Get appropriate response. */
159 err = ftp_response (rbuf, &respline);
165 /* An unprobable possibility of logging without a password. */
166 if (*respline == '2')
171 /* Else, only response 3 is appropriate. */
172 if (*respline != '3')
175 return FTPLOGREFUSED;
179 static const char *skey_head[] = {
185 for (i = 0; i < ARRAY_SIZE (skey_head); i++)
187 if (strncasecmp (skey_head[i], respline, strlen (skey_head[i])) == 0)
190 if (i < ARRAY_SIZE (skey_head))
193 int skey_sequence = 0;
195 for (cp = respline + strlen (skey_head[i]);
196 '0' <= *cp && *cp <= '9';
199 skey_sequence = skey_sequence * 10 + *cp - '0';
207 return FTPLOGREFUSED;
209 if ((cp = calculate_skey_response (skey_sequence, cp, pass)) == 0)
214 #endif /* USE_OPIE */
216 /* Send PASS password. */
217 request = ftp_request ("PASS", pass);
218 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
225 /* Get appropriate response. */
226 err = ftp_response (rbuf, &respline);
232 if (*respline != '2')
244 ftp_eprt (struct rbuf *rbuf)
248 char *request, *respline;
252 char ipv6 [8 * (4 * 3 + 3) + 8];
255 /* Setting port to 0 lets the system choose a free port. */
257 err = bindport (&port, ip_default_family);
258 if (err != BINDOK) /* Bind the port. */
261 /* Get the address of this side of the connection. */
262 if (!conaddr (RBUF_FD (rbuf), &in_addr))
263 /* Huh? This is not BINDERR! */
265 inet_ntop (AF_INET6, &in_addr, ipv6, sizeof (ipv6));
267 /* Construct the argument of EPRT (of the form |2|IPv6.ascii|PORT.ascii|). */
268 bytes = alloca (3 + strlen (ipv6) + 1 + numdigit (port) + 1 + 1);
269 sprintf (bytes, "|2|%s|%u|", ipv6, port);
270 /* Send PORT request. */
271 request = ftp_request ("EPRT", bytes);
272 if (0 > iwrite (RBUF_FD (rbuf), request, strlen (request)))
279 /* Get appropriate response. */
280 err = ftp_response (rbuf, &respline);
287 if (*respline != '2')
298 /* Bind a port and send the appropriate PORT command to the FTP
299 server. Use acceptport after RETR, to get the socket of data
302 ftp_port (struct rbuf *rbuf)
305 char *request, *respline;
306 char bytes[6 * 4 +1];
309 ip4_address in_addr_4;
310 unsigned char *in_addr4_ptr = (unsigned char *)&in_addr_4;
316 Only try the Extented Version if we actually use IPv6
318 if (ip_default_family == AF_INET6)
320 err = ftp_eprt (rbuf);
325 /* Setting port to 0 lets the system choose a free port. */
328 err = bindport (&port, AF_INET);
332 /* Get the address of this side of the connection and convert it
334 if (!conaddr (RBUF_FD (rbuf), &in_addr))
335 /* Huh? This is not BINDERR! */
337 if (!map_ip_to_ipv4 (&in_addr, &in_addr_4))
340 /* Construct the argument of PORT (of the form a,b,c,d,e,f). Port
341 is unsigned short so (unsigned) (port & 0xff000) >> 8 is the same
344 sprintf (bytes, "%d,%d,%d,%d,%d,%d",
345 in_addr4_ptr[0], in_addr4_ptr[1], in_addr4_ptr[2], in_addr4_ptr[3],
346 port >> 8, port & 0xff);
347 /* Send PORT request. */
348 request = ftp_request ("PORT", bytes);
349 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
356 /* Get appropriate response. */
357 err = ftp_response (rbuf, &respline);
363 if (*respline != '2')
374 ftp_epsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port,
379 char *request = ftp_request ("EPSV", typ);
380 if (0 > iwrite (RBUF_FD (rbuf), request, strlen (request)))
385 /* Get the server response. */
386 err = ftp_response (rbuf, &respline);
392 if (*respline != '2')
397 /* Parse the request. */
399 /* respline::=229 Entering Extended Passive Mode (|||6446|) */
400 for (s += 4; *s && !ISDIGIT (*s); s++);
404 for (; ISDIGIT (*s); s++)
405 *port = (*s - '0') + 10 * (*port);
407 /* Now we have the port but we need the IPv6 :-( */
409 wget_sockaddr remote;
410 int len = sizeof (remote);
411 struct sockaddr_in *ipv4_sock = ( struct sockaddr_in *)&remote;
412 getpeername (RBUF_FD (rbuf), (struct sockaddr*)&remote, &len);
413 switch(remote.sa.sa_family)
416 memcpy (addr, &remote.sin6.sin6_addr, 16);
419 map_ipv4_to_ip ((ip4_address *)&ipv4_sock->sin_addr, addr);
432 /* Similar to ftp_port, but uses `PASV' to initiate the passive FTP
433 transfer. Reads the response from server and parses it. Reads the
434 host and port addresses and returns them. */
436 ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
438 char *request, *respline, *s;
441 unsigned char addr4[4];
444 if (ip_default_family == AF_INET6)
446 err = ftp_epsv (rbuf, addr, port, "2"); /* try IPv6 with EPSV */
449 err = ftp_epsv (rbuf, addr, port, "1"); /* try IPv4 with EPSV */
454 /* Form the request. */
455 request = ftp_request ("PASV", NULL);
457 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
464 /* Get the server response. */
465 err = ftp_response (rbuf, &respline);
471 if (*respline != '2')
476 /* Parse the request. */
477 /* respline::=227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */
479 for (s += 4; *s && !ISDIGIT (*s); s++);
482 for (i = 0; i < 4; i++)
485 for (; ISDIGIT (*s); s++)
486 addr4[i] = (*s - '0') + 10 * addr4[i];
496 /* Eventually make an IPv4 in IPv6 adress if needed */
497 map_ipv4_to_ip ((ip4_address *)addr4, addr);
500 for (; ISDIGIT (*s); s++)
501 *port = (*s - '0') + 10 * (*port);
511 unsigned short port2 = 0;
512 for (; ISDIGIT (*s); s++)
513 port2 = (*s - '0') + 10 * port2;
514 *port = (*port) * 256 + port2;
520 /* Sends the TYPE request to the server. */
522 ftp_type (struct rbuf *rbuf, int type)
524 char *request, *respline;
529 /* Construct argument. */
532 /* Send TYPE request. */
533 request = ftp_request ("TYPE", stype);
534 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
541 /* Get appropriate response. */
542 err = ftp_response (rbuf, &respline);
548 if (*respline != '2')
551 return FTPUNKNOWNTYPE;
558 /* Changes the working directory by issuing a CWD command to the
561 ftp_cwd (struct rbuf *rbuf, const char *dir)
563 char *request, *respline;
567 /* Send CWD request. */
568 request = ftp_request ("CWD", dir);
569 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
576 /* Get appropriate response. */
577 err = ftp_response (rbuf, &respline);
583 if (*respline == '5')
588 if (*respline != '2')
598 /* Sends REST command to the FTP server. */
600 ftp_rest (struct rbuf *rbuf, long offset)
602 char *request, *respline;
605 static char numbuf[24]; /* Buffer for the number */
607 number_to_string (numbuf, offset);
608 request = ftp_request ("REST", numbuf);
609 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
616 /* Get appropriate response. */
617 err = ftp_response (rbuf, &respline);
623 if (*respline != '3')
633 /* Sends RETR command to the FTP server. */
635 ftp_retr (struct rbuf *rbuf, const char *file)
637 char *request, *respline;
641 /* Send RETR request. */
642 request = ftp_request ("RETR", file);
643 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
650 /* Get appropriate response. */
651 err = ftp_response (rbuf, &respline);
657 if (*respline == '5')
662 if (*respline != '1')
672 /* Sends the LIST command to the server. If FILE is NULL, send just
673 `LIST' (no space). */
675 ftp_list (struct rbuf *rbuf, const char *file)
677 char *request, *respline;
681 /* Send LIST request. */
682 request = ftp_request ("LIST", file);
683 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
690 /* Get appropriate respone. */
691 err = ftp_response (rbuf, &respline);
697 if (*respline == '5')
702 if (*respline != '1')
712 /* Sends the SYST command to the server. */
714 ftp_syst (struct rbuf *rbuf, enum stype *server_type)
716 char *request, *respline;
720 /* Send SYST request. */
721 request = ftp_request ("SYST", NULL);
722 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
730 /* Get appropriate response. */
731 err = ftp_response (rbuf, &respline);
737 if (*respline == '5')
743 /* Skip the number (215, but 200 (!!!) in case of VMS) */
744 strtok (respline, " ");
746 /* Which system type has been reported (we are interested just in the
747 first word of the server response)? */
748 request = strtok (NULL, " ");
750 if (!strcasecmp (request, "VMS"))
751 *server_type = ST_VMS;
752 else if (!strcasecmp (request, "UNIX"))
753 *server_type = ST_UNIX;
754 else if (!strcasecmp (request, "WINDOWS_NT"))
755 *server_type = ST_WINNT;
756 else if (!strcasecmp (request, "MACOS"))
757 *server_type = ST_MACOS;
759 *server_type = ST_OTHER;
766 /* Sends the PWD command to the server. */
768 ftp_pwd (struct rbuf *rbuf, char **pwd)
770 char *request, *respline;
774 /* Send PWD request. */
775 request = ftp_request ("PWD", NULL);
776 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
783 /* Get appropriate response. */
784 err = ftp_response (rbuf, &respline);
790 if (*respline == '5')
796 /* Skip the number (257), leading citation mark, trailing citation mark
797 and everything following it. */
798 strtok (respline, "\"");
799 request = strtok (NULL, "\"");
801 /* Has the `pwd' been already allocated? Free! */
804 *pwd = xstrdup (request);
811 /* Sends the SIZE command to the server, and returns the value in 'size'.
812 * If an error occurs, size is set to zero. */
814 ftp_size (struct rbuf *rbuf, const char *file, long int *size)
816 char *request, *respline;
820 /* Send PWD request. */
821 request = ftp_request ("SIZE", file);
822 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
830 /* Get appropriate response. */
831 err = ftp_response (rbuf, &respline);
838 if (*respline == '5')
841 * Probably means SIZE isn't supported on this server.
842 * Error is nonfatal since SIZE isn't in RFC 959
850 *size = strtol (respline + 4, NULL, 0);
854 * Couldn't parse the response for some reason. On the (few)
855 * tests I've done, the response is 213 <SIZE> with nothing else -
856 * maybe something a bit more resilient is necessary. It's not a
857 * fatal error, however.
869 /* If URL's params are of the form "type=X", return character X.
870 Otherwise, return 'I' (the default type). */
872 ftp_process_type (const char *params)
875 && 0 == strncasecmp (params, "type=", 5)
876 && params[5] != '\0')
877 return TOUPPER (params[5]);