X-Git-Url: http://sjero.net/git/?a=blobdiff_plain;f=src%2Fftp.c;h=3159171f7c4caa3c26bc92d59aadf83ea0254ca0;hb=30ac043b0a4a9a983dd1b50ce1c89ed953019292;hp=1c4385427562e6258e451816d0d21760597fb752;hpb=024cb5ed3a0263775bc750b06bca74c91b389d2d;p=wget diff --git a/src/ftp.c b/src/ftp.c index 1c438542..3159171f 100644 --- a/src/ftp.c +++ b/src/ftp.c @@ -16,7 +16,17 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wget; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +In addition, as a special exception, the Free Software Foundation +gives permission to link the code of its release of Wget with the +OpenSSL project's "OpenSSL" library (or with modified versions of it +that use the same license as the "OpenSSL" library), and distribute +the linked executables. You must obey the GNU General Public License +in all respects for all of the code used other than "OpenSSL". If you +modify this file, you may extend this exception to your version of the +file, but you are not obligated to do so. If you do not wish to do +so, delete this exception statement from your version. */ #include @@ -33,9 +43,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include -#ifndef WINDOWS -# include /* for h_errno */ -#endif #include "wget.h" #include "utils.h" @@ -51,11 +58,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef errno extern int errno; #endif -#ifndef h_errno -# ifndef __CYGWIN__ -extern int h_errno; -# endif -#endif /* File where the "ls -al" listing will be saved. */ #define LIST_FILENAME ".listing" @@ -71,6 +73,7 @@ typedef struct enum stype rs; /* remote system reported by ftp server */ char *id; /* initial directory */ char *target; /* target file name */ + struct url *proxy; /* FTWK-style proxy */ } ccon; @@ -127,10 +130,8 @@ getftp (struct url *u, long *len, long restval, ccon *con) FILE *fp; char *user, *passwd, *respline; char *tms, *tmrate; - struct wget_timer *timer; - unsigned char pasv_addr[6]; int cmd = con->cmd; - int passive_mode_open = 0; + int pasv_mode_open = 0; long expected_bytes = 0L; assert (con != NULL); @@ -160,20 +161,31 @@ getftp (struct url *u, long *len, long restval, ccon *con) char type_char; struct address_list *al; + char *host = con->proxy ? con->proxy->host : u->host; + int port = con->proxy ? con->proxy->port : u->port; + char *logname = user; + + if (con->proxy) + { + /* If proxy is in use, log in as username@target-site. */ + logname = xmalloc (strlen (user) + 1 + strlen (u->host) + 1); + sprintf (logname, "%s@%s", user, u->host); + } + /* Login to the server: */ /* First: Establish the control connection. */ - al = lookup_host (u->host, 0); + al = lookup_host (host, 0); if (!al) return HOSTERR; - set_connection_host_name (u->host); - csock = connect_to_many (al, u->port, 0); + set_connection_host_name (host); + csock = connect_to_many (al, port, 0); set_connection_host_name (NULL); address_list_release (al); if (csock < 0) - return errno == ECONNREFUSED ? CONREFUSED : CONERROR; + return CONNECT_ERROR (errno); if (cmd & LEAVE_PENDING) rbuf_initialize (&con->rbuf, csock); @@ -188,7 +200,11 @@ getftp (struct url *u, long *len, long restval, ccon *con) logprintf (LOG_VERBOSE, _("Logging in as %s ... "), user); if (opt.server_response) logputs (LOG_ALWAYS, "\n"); - err = ftp_login (&con->rbuf, user, passwd); + err = ftp_login (&con->rbuf, logname, passwd); + + if (con->proxy) + xfree (logname); + /* FTPRERR, FTPSRVERR, WRITEFAILED, FTPLOGREFUSED, FTPLOGINC */ switch (err) { @@ -265,7 +281,7 @@ Error in server response, closing control connection.\n")); abort (); break; } - if (!opt.server_response) + if (!opt.server_response && err != FTPSRVERR) logputs (LOG_VERBOSE, _("done. ")); /* Fourth: Find the initial ftp directory */ @@ -277,7 +293,6 @@ Error in server response, closing control connection.\n")); switch (err) { case FTPRERR: - case FTPSRVERR : logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); @@ -285,6 +300,11 @@ Error in server response, closing control connection.\n")); rbuf_uninitialize (&con->rbuf); return err; break; + case FTPSRVERR : + /* PWD unsupported -- assume "/". */ + FREE_MAYBE (con->id); + con->id = xstrdup ("/"); + break; case FTPOK: /* Everything is OK. */ break; @@ -373,17 +393,31 @@ Error in server response, closing control connection.\n")); /* Change working directory. To change to a non-absolute Unix directory, we need to prepend initial directory - (con->id) to it. Absolute directories "just work". */ + (con->id) to it. Absolute directories "just work". - if (*target != '/') + A relative directory is one that does not begin with '/' + and, on non-Unix OS'es, one that doesn't begin with + ":". */ + + if (target[0] != '/' + && !(con->rs != ST_UNIX + && ISALPHA (target[0]) && target[1] == ':')) { int idlen = strlen (con->id); - char *ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1); - /* idlen == 1 means con->id = "/" */ - sprintf (ntarget, "%s%s%s", con->id, idlen == 1 ? "" : "/", - target); + char *ntarget, *p; + + /* Strip trailing slash(es) from con->id. */ + while (idlen > 0 && con->id[idlen - 1] == '/') + --idlen; + p = ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1); + memcpy (p, con->id, idlen); + p += idlen; + *p++ = '/'; + strcpy (p, target); + DEBUGP (("Prepended initial PWD to relative path:\n")); - DEBUGP ((" old: '%s'\n new: '%s'\n", target, ntarget)); + DEBUGP ((" pwd: '%s'\n old: '%s'\n new: '%s'\n", + con->id, target, ntarget)); target = ntarget; } @@ -494,12 +528,11 @@ Error in server response, closing control connection.\n")); { if (opt.ftp_pasv > 0) { - char thost[256]; - unsigned short tport; - + ip_address passive_addr; + unsigned short passive_port; if (!opt.server_response) logputs (LOG_VERBOSE, "==> PASV ... "); - err = ftp_pasv (&con->rbuf, pasv_addr); + err = ftp_pasv (&con->rbuf, &passive_addr, &passive_port); /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */ switch (err) { @@ -533,40 +566,28 @@ Error in server response, closing control connection.\n")); default: abort (); break; - } + } /* switch(err) */ if (err==FTPOK) { - struct address_list *al; - - sprintf (thost, "%d.%d.%d.%d", - pasv_addr[0], pasv_addr[1], pasv_addr[2], pasv_addr[3]); - tport = (pasv_addr[4] << 8) + pasv_addr[5]; - - al = lookup_host (thost, 0); - if (!al) - { - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); - return HOSTERR; - } - dtsock = connect_to_many (al, tport, 0); - address_list_release (al); - + dtsock = connect_to_one (&passive_addr, passive_port, 1); if (dtsock < 0) { int save_errno = errno; CLOSE (csock); rbuf_uninitialize (&con->rbuf); - return save_errno == ECONNREFUSED ? CONREFUSED : CONERROR; + logprintf (LOG_VERBOSE, _("couldn't connect to %s:%hu: %s\n"), + pretty_print_address (&passive_addr), passive_port, + strerror (save_errno)); + return CONNECT_ERROR (save_errno); } - passive_mode_open= 1; /* Flag to avoid accept port */ + pasv_mode_open = 1; /* Flag to avoid accept port */ if (!opt.server_response) logputs (LOG_VERBOSE, _("done. ")); } /* err==FTP_OK */ } - if (!passive_mode_open) /* Try to use a port command if PASV failed */ + if (!pasv_mode_open) /* Try to use a port command if PASV failed */ { if (!opt.server_response) logputs (LOG_VERBOSE, "==> PORT ... "); @@ -609,15 +630,6 @@ Error in server response, closing control connection.\n")); closeport (dtsock); return err; break; - case HOSTERR: - logputs (LOG_VERBOSE, "\n"); - logprintf (LOG_NOTQUIET, "%s: %s\n", u->host, - herrmsg (h_errno)); - CLOSE (csock); - closeport (dtsock); - rbuf_uninitialize (&con->rbuf); - return HOSTERR; - break; case FTPPORTERR: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("Invalid PORT.\n")); @@ -696,6 +708,18 @@ Error in server response, closing control connection.\n")); if (cmd & DO_RETR) { + /* If we're in spider mode, don't really retrieve anything. The + fact that we got to this point should be proof enough that + the file exists, vaguely akin to HTTP's concept of a "HEAD" + request. */ + if (opt.spider) + { + CLOSE (csock); + closeport (dtsock); + rbuf_uninitialize (&con->rbuf); + return RETRFINISHED; + } + if (opt.verbose) { if (!opt.server_response) @@ -807,7 +831,7 @@ Error in server response, closing control connection.\n")); if (!(cmd & (DO_LIST | DO_RETR))) return RETRFINISHED; - if (!passive_mode_open) /* we are not using pasive mode so we need + if (!pasv_mode_open) /* we are not using pasive mode so we need to accept */ { /* Open the data transmission socket by calling acceptport(). */ @@ -847,7 +871,7 @@ Error in server response, closing control connection.\n")); /* Rewind the output document if the download starts over and if this is the first download. See gethttp() for a longer explanation. */ - if (!restval && global_download_count == 0) + if (!restval && global_download_count == 0 && opt.dfp != stdout) { /* This will silently fail for streams that don't correspond to regular files, but that's OK. */ @@ -875,11 +899,10 @@ Error in server response, closing control connection.\n")); legible (expected_bytes - restval)); logputs (LOG_VERBOSE, _(" (unauthoritative)\n")); } - timer = wtimer_new (); + /* Get the contents of the document. */ - res = get_contents (dtsock, fp, len, restval, expected_bytes, &con->rbuf, 0); - con->dltime = wtimer_elapsed (timer); - wtimer_delete (timer); + res = get_contents (dtsock, fp, len, restval, expected_bytes, &con->rbuf, + 0, &con->dltime); tms = time_str (NULL); tmrate = retr_rate (*len - restval, con->dltime, 0); /* Close data connection socket. */ @@ -1331,6 +1354,11 @@ ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con) /* Else, get it from the file. */ local_size = st.st_size; tml = st.st_mtime; +#ifdef WINDOWS + /* Modification time granularity is 2 seconds for Windows, so + increase local time by 1 second for later comparison. */ + tml++; +#endif /* Compare file sizes only for servers that tell us correct values. Assumme sizes being equal for servers that lie about file size. */ @@ -1565,7 +1593,7 @@ Not descending to `%s' as it is excluded/not-included.\n"), newdir); static uerr_t ftp_retrieve_glob (struct url *u, ccon *con, int action) { - struct fileinfo *orig, *start; + struct fileinfo *f, *orig, *start; uerr_t res; con->cmd |= LEAVE_PENDING; @@ -1578,8 +1606,7 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action) opt.accepts and opt.rejects. */ if (opt.accepts || opt.rejects) { - struct fileinfo *f = orig; - + f = orig; while (f) { if (f->type != FT_DIRECTORY && !acceptable (f->name)) @@ -1591,13 +1618,25 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action) f = f->next; } } + /* Remove all files with possible harmful names */ + f = orig; + while (f) + { + if (has_insecure_name_p(f->name)) + { + logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"), f->name); + f = delelement (f, &start); + } + else + f = f->next; + } /* Now weed out the files that do not match our globbing pattern. If we are dealing with a globbing pattern, that is. */ if (*u->file && (action == GLOBALL || action == GETONE)) { int matchres = 0; - struct fileinfo *f = start; + f = start; while (f) { matchres = fnmatch (u->file, f->name, 0); @@ -1653,7 +1692,7 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action) of URL. Inherently, its capabilities are limited on what can be encoded into a URL. */ uerr_t -ftp_loop (struct url *u, int *dt) +ftp_loop (struct url *u, int *dt, struct url *proxy) { ccon con; /* FTP connection */ uerr_t res; @@ -1666,6 +1705,7 @@ ftp_loop (struct url *u, int *dt) con.st = ON_YOUR_OWN; con.rs = ST_UNIX; con.id = NULL; + con.proxy = proxy; res = RETROK; /* in case it's not used */ /* If the file name is empty, the user probably wants a directory @@ -1717,8 +1757,8 @@ ftp_loop (struct url *u, int *dt) /* ftp_retrieve_glob is a catch-all function that gets called if we need globbing, time-stamping or recursion. Its third argument is just what we really need. */ - ftp_retrieve_glob (u, &con, - (opt.ftp_glob && wild) ? GLOBALL : GETONE); + res = ftp_retrieve_glob (u, &con, + (opt.ftp_glob && wild) ? GLOBALL : GETONE); } else res = ftp_loop_internal (u, NULL, &con);