X-Git-Url: http://sjero.net/git/?a=blobdiff_plain;f=src%2Fftp-basic.c;h=131652333243902866c2408faabb3ff1a3c95df9;hb=277e840a0f8e3ec8800cfe7407fe3c16000bc622;hp=469263be21d80f98113857f8b6bd627fe24e470e;hpb=c8e92cdbd6c38bb771ab0b9c88c92114f1b0315e;p=wget diff --git a/src/ftp-basic.c b/src/ftp-basic.c index 469263be..13165233 100644 --- a/src/ftp-basic.c +++ b/src/ftp-basic.c @@ -6,7 +6,7 @@ This file is part of GNU Wget. GNU Wget is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + (at your option) any later version. GNU Wget is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -34,33 +34,17 @@ so, delete this exception statement from your version. */ #include #include -#ifdef HAVE_STRING_H -# include -#else -# include -#endif +#include #ifdef HAVE_UNISTD_H # include #endif -#include - -/* For inet_ntop. */ -#ifndef WINDOWS -#include -#include -#include -#endif - -#ifdef WINDOWS -# include -#endif #include "wget.h" #include "utils.h" -#include "rbuf.h" #include "connect.h" #include "host.h" #include "ftp.h" +#include "retr.h" char ftp_last_respline[128]; @@ -68,47 +52,46 @@ char ftp_last_respline[128]; /* Get the response of FTP server and allocate enough room to handle it. and characters are stripped from the line, and the line is 0-terminated. All the response lines but the last one are - skipped. The last line is determined as described in RFC959. */ + skipped. The last line is determined as described in RFC959. + + If the line is successfully read, FTPOK is returned, and *ret_line + is assigned a freshly allocated line. Otherwise, FTPRERR is + returned, and the value of *ret_line should be ignored. */ + uerr_t -ftp_response (struct rbuf *rbuf, char **line) +ftp_response (int fd, char **ret_line) { - int i; - int bufsize = 40; - - *line = (char *)xmalloc (bufsize); - do + while (1) { - for (i = 0; 1; i++) - { - int res; - if (i > bufsize - 1) - *line = (char *)xrealloc (*line, (bufsize <<= 1)); - res = RBUF_READCHAR (rbuf, *line + i); - /* RES is number of bytes read. */ - if (res == 1) - { - if ((*line)[i] == '\n') - { - (*line)[i] = '\0'; - /* Get rid of \r. */ - if (i > 0 && (*line)[i - 1] == '\r') - (*line)[i - 1] = '\0'; - break; - } - } - else - return FTPRERR; - } + char *p; + char *line = fd_read_line (fd); + if (!line) + return FTPRERR; + + /* Strip trailing CRLF before printing the line, so that + escnonprint doesn't include bogus \012 and \015. */ + p = strchr (line, '\0'); + if (p > line && p[-1] == '\n') + *--p = '\0'; + if (p > line && p[-1] == '\r') + *--p = '\0'; + if (opt.server_response) - logprintf (LOG_ALWAYS, "%s\n", *line); + logprintf (LOG_NOTQUIET, "%s\n", escnonprint (line)); else - DEBUGP (("%s\n", *line)); + DEBUGP (("%s\n", escnonprint (line))); + + /* The last line of output is the one that begins with "ddd ". */ + if (ISDIGIT (line[0]) && ISDIGIT (line[1]) && ISDIGIT (line[2]) + && line[3] == ' ') + { + strncpy (ftp_last_respline, line, sizeof (ftp_last_respline)); + ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0'; + *ret_line = line; + return FTPOK; + } + xfree (line); } - while (!(i >= 3 && ISDIGIT (**line) && ISDIGIT ((*line)[1]) && - ISDIGIT ((*line)[2]) && (*line)[3] == ' ')); - strncpy (ftp_last_respline, *line, sizeof (ftp_last_respline)); - ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0'; - return FTPOK; } /* Returns the malloc-ed FTP request, ending with , printing @@ -117,10 +100,31 @@ ftp_response (struct rbuf *rbuf, char **line) static char * ftp_request (const char *command, const char *value) { - char *res = (char *)xmalloc (strlen (command) - + (value ? (1 + strlen (value)) : 0) - + 2 + 1); - sprintf (res, "%s%s%s\r\n", command, value ? " " : "", value ? value : ""); + char *res; + if (value) + { + /* Check for newlines in VALUE (possibly injected by the %0A URL + escape) making the callers inadvertently send multiple FTP + commands at once. Without this check an attacker could + intentionally redirect to ftp://server/fakedir%0Acommand.../ + and execute arbitrary FTP command on a remote FTP server. */ + if (strpbrk (value, "\r\n")) + { + /* Copy VALUE to the stack and modify CR/LF to space. */ + char *defanged, *p; + STRDUP_ALLOCA (defanged, value); + for (p = defanged; *p; p++) + if (*p == '\r' || *p == '\n') + *p = ' '; + DEBUGP (("\nDetected newlines in %s \"%s\"; changing to %s \"%s\"\n", + command, escnonprint (value), command, escnonprint (defanged))); + /* Make VALUE point to the defanged copy of the string. */ + value = defanged; + } + res = concat_strings (command, " ", value, "\r\n", (char *) 0); + } + else + res = concat_strings (command, "\r\n", (char *) 0); if (opt.server_response) { /* Hack: don't print out password. */ @@ -137,19 +141,16 @@ ftp_request (const char *command, const char *value) /* Sends the USER and PASS commands to the server, to control connection socket csock. */ uerr_t -ftp_login (struct rbuf *rbuf, const char *acc, const char *pass) +ftp_login (int csock, const char *acc, const char *pass) { uerr_t err; char *request, *respline; int nwritten; /* Get greeting. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) - { - xfree (respline); - return err; - } + return err; if (*respline != '2') { xfree (respline); @@ -158,7 +159,7 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass) xfree (respline); /* Send USER username. */ request = ftp_request ("USER", acc); - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); @@ -166,12 +167,9 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass) } xfree (request); /* Get appropriate response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) - { - xfree (respline); - return err; - } + return err; /* An unprobable possibility of logging without a password. */ if (*respline == '2') { @@ -184,7 +182,7 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass) xfree (respline); return FTPLOGREFUSED; } -#ifdef USE_OPIE +#ifdef ENABLE_OPIE { static const char *skey_head[] = { "331 s/key ", @@ -221,11 +219,11 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass) pass = skey_response (skey_sequence, seed, pass); } } -#endif /* USE_OPIE */ +#endif /* ENABLE_OPIE */ xfree (respline); /* Send PASS password. */ request = ftp_request ("PASS", pass); - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); @@ -233,12 +231,9 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass) } xfree (request); /* Get appropriate response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) - { - xfree (respline); - return err; - } + return err; if (*respline != '2') { xfree (respline); @@ -271,7 +266,7 @@ ip_address_to_port_repr (const ip_address *addr, int port, char *buf, server. Use acceptport after RETR, to get the socket of data connection. */ uerr_t -ftp_port (struct rbuf *rbuf, int *local_sock) +ftp_port (int csock, int *local_sock) { uerr_t err; char *request, *respline; @@ -281,12 +276,9 @@ ftp_port (struct rbuf *rbuf, int *local_sock) /* Must contain the argument of PORT (of the form a,b,c,d,e,f). */ char bytes[6 * 4 + 1]; - assert (rbuf != NULL); - assert (rbuf_initialized_p (rbuf)); - /* Get the address of this side of the connection. */ - if (!conaddr (RBUF_FD (rbuf), &addr)) - return BINDERR; + if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL)) + return FTPSYSERR; assert (addr.type == IPV4_ADDRESS); @@ -294,36 +286,35 @@ ftp_port (struct rbuf *rbuf, int *local_sock) port = 0; /* Bind the port. */ - err = bindport (&addr, &port, local_sock); - if (err != BINDOK) - return err; + *local_sock = bind_local (&addr, &port); + if (*local_sock < 0) + return FTPSYSERR; /* Construct the argument of PORT (of the form a,b,c,d,e,f). */ ip_address_to_port_repr (&addr, port, bytes, sizeof (bytes)); /* Send PORT request. */ request = ftp_request ("PORT", bytes); - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); - xclose (*local_sock); + fd_close (*local_sock); return WRITEFAILED; } xfree (request); /* Get appropriate response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) { - xfree (respline); - xclose (*local_sock); + fd_close (*local_sock); return err; } if (*respline != '2') { xfree (respline); - xclose (*local_sock); + fd_close (*local_sock); return FTPPORTERR; } xfree (respline); @@ -368,7 +359,7 @@ ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf, server. Use acceptport after RETR, to get the socket of data connection. */ uerr_t -ftp_lprt (struct rbuf *rbuf, int *local_sock) +ftp_lprt (int csock, int *local_sock) { uerr_t err; char *request, *respline; @@ -378,12 +369,9 @@ ftp_lprt (struct rbuf *rbuf, int *local_sock) /* Must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */ char bytes[21 * 4 + 1]; - assert (rbuf != NULL); - assert (rbuf_initialized_p (rbuf)); - /* Get the address of this side of the connection. */ - if (!conaddr (RBUF_FD (rbuf), &addr)) - return BINDERR; + if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL)) + return FTPSYSERR; assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS); @@ -391,35 +379,34 @@ ftp_lprt (struct rbuf *rbuf, int *local_sock) port = 0; /* Bind the port. */ - err = bindport (&addr, &port, local_sock); - if (err != BINDOK) - return err; + *local_sock = bind_local (&addr, &port); + if (*local_sock < 0) + return FTPSYSERR; /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */ ip_address_to_lprt_repr (&addr, port, bytes, sizeof (bytes)); /* Send PORT request. */ request = ftp_request ("LPRT", bytes); - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); - xclose (*local_sock); + fd_close (*local_sock); return WRITEFAILED; } xfree (request); /* Get appropriate response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) { - xfree (respline); - xclose (*local_sock); + fd_close (*local_sock); return err; } if (*respline != '2') { xfree (respline); - xclose (*local_sock); + fd_close (*local_sock); return FTPPORTERR; } xfree (respline); @@ -450,7 +437,7 @@ ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf, server. Use acceptport after RETR, to get the socket of data connection. */ uerr_t -ftp_eprt (struct rbuf *rbuf, int *local_sock) +ftp_eprt (int csock, int *local_sock) { uerr_t err; char *request, *respline; @@ -458,16 +445,13 @@ ftp_eprt (struct rbuf *rbuf, int *local_sock) int nwritten; int port; /* Must contain the argument of EPRT (of the form |af|addr|port|). - * 4 chars for the | separators, ENABLE_IPV6_ADDRSTRLEN chars for addr + * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr * 1 char for af (1-2) and 5 chars for port (0-65535) */ char bytes[4 + INET6_ADDRSTRLEN + 1 + 5 + 1]; - assert (rbuf != NULL); - assert (rbuf_initialized_p(rbuf)); - /* Get the address of this side of the connection. */ - if (!conaddr (RBUF_FD (rbuf), &addr)) - return BINDERR; + if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL)) + return FTPSYSERR; assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS); @@ -475,35 +459,34 @@ ftp_eprt (struct rbuf *rbuf, int *local_sock) port = 0; /* Bind the port. */ - err = bindport (&addr, &port, local_sock); - if (err != BINDOK) - return err; + *local_sock = bind_local (&addr, &port); + if (*local_sock < 0) + return FTPSYSERR; - /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */ + /* Construct the argument of EPRT (of the form |af|addr|port|). */ ip_address_to_eprt_repr (&addr, port, bytes, sizeof (bytes)); /* Send PORT request. */ request = ftp_request ("EPRT", bytes); - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); - xclose (*local_sock); + fd_close (*local_sock); return WRITEFAILED; } xfree (request); /* Get appropriate response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) { - xfree (respline); - xclose (*local_sock); + fd_close (*local_sock); return err; } if (*respline != '2') { xfree (respline); - xclose (*local_sock); + fd_close (*local_sock); return FTPPORTERR; } xfree (respline); @@ -515,24 +498,22 @@ ftp_eprt (struct rbuf *rbuf, int *local_sock) transfer. Reads the response from server and parses it. Reads the host and port addresses and returns them. */ uerr_t -ftp_pasv (struct rbuf *rbuf, ip_address *addr, int *port) +ftp_pasv (int csock, ip_address *addr, int *port) { char *request, *respline, *s; int nwritten, i; uerr_t err; unsigned char tmp[6]; - assert (rbuf != NULL); - assert (rbuf_initialized_p (rbuf)); assert (addr != NULL); assert (port != NULL); - memset (addr, 0, sizeof (ip_address)); + xzero (*addr); /* Form the request. */ request = ftp_request ("PASV", NULL); /* And send it. */ - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); @@ -540,12 +521,9 @@ ftp_pasv (struct rbuf *rbuf, ip_address *addr, int *port) } xfree (request); /* Get the server response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) - { - xfree (respline); - return err; - } + return err; if (*respline != '2') { xfree (respline); @@ -584,7 +562,7 @@ ftp_pasv (struct rbuf *rbuf, ip_address *addr, int *port) transfer. Reads the response from server and parses it. Reads the host and port addresses and returns them. */ uerr_t -ftp_lpsv (struct rbuf *rbuf, ip_address *addr, int *port) +ftp_lpsv (int csock, ip_address *addr, int *port) { char *request, *respline, *s; int nwritten, i, af, addrlen, portlen; @@ -592,18 +570,16 @@ ftp_lpsv (struct rbuf *rbuf, ip_address *addr, int *port) unsigned char tmp[16]; unsigned char tmpprt[2]; - assert (rbuf != NULL); - assert (rbuf_initialized_p(rbuf)); assert (addr != NULL); assert (port != NULL); - memset (addr, 0, sizeof (ip_address)); + xzero (*addr); /* Form the request. */ request = ftp_request ("LPSV", NULL); /* And send it. */ - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); @@ -612,12 +588,9 @@ ftp_lpsv (struct rbuf *rbuf, ip_address *addr, int *port) xfree (request); /* Get the server response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) - { - xfree (respline); - return err; - } + return err; if (*respline != '2') { xfree (respline); @@ -750,36 +723,25 @@ ftp_lpsv (struct rbuf *rbuf, ip_address *addr, int *port) transfer. Reads the response from server and parses it. Reads the host and port addresses and returns them. */ uerr_t -ftp_epsv (struct rbuf *rbuf, ip_address *ip, int *port) +ftp_epsv (int csock, ip_address *ip, int *port) { char *request, *respline, *start, delim, *s; int nwritten, i; uerr_t err; int tport; - socklen_t addrlen; - struct sockaddr_storage ss; - struct sockaddr *sa = (struct sockaddr *)&ss; - assert (rbuf != NULL); - assert (rbuf_initialized_p(rbuf)); assert (ip != NULL); assert (port != NULL); - addrlen = sizeof (ss); - if (getpeername (rbuf->fd, sa, &addrlen) < 0) - /* Mauro Tortonesi: HOW DO WE HANDLE THIS ERROR? */ - return CONPORTERR; - - assert (sa->sa_family == AF_INET || sa->sa_family == AF_INET6); - - sockaddr_get_data (sa, ip, NULL); + /* IP already contains the IP address of the control connection's + peer, so we don't need to call socket_ip_address here. */ /* Form the request. */ /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */ - request = ftp_request ("EPSV", (sa->sa_family == AF_INET ? "1" : "2")); + request = ftp_request ("EPSV", (ip->type == IPV4_ADDRESS ? "1" : "2")); /* And send it. */ - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); @@ -788,12 +750,9 @@ ftp_epsv (struct rbuf *rbuf, ip_address *ip, int *port) xfree (request); /* Get the server response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) - { - xfree (respline); - return err; - } + return err; if (*respline != '2') { xfree (respline); @@ -867,7 +826,7 @@ ftp_epsv (struct rbuf *rbuf, ip_address *ip, int *port) /* Sends the TYPE request to the server. */ uerr_t -ftp_type (struct rbuf *rbuf, int type) +ftp_type (int csock, int type) { char *request, *respline; int nwritten; @@ -879,7 +838,7 @@ ftp_type (struct rbuf *rbuf, int type) stype[1] = 0; /* Send TYPE request. */ request = ftp_request ("TYPE", stype); - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); @@ -887,12 +846,9 @@ ftp_type (struct rbuf *rbuf, int type) } xfree (request); /* Get appropriate response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) - { - xfree (respline); - return err; - } + return err; if (*respline != '2') { xfree (respline); @@ -906,7 +862,7 @@ ftp_type (struct rbuf *rbuf, int type) /* Changes the working directory by issuing a CWD command to the server. */ uerr_t -ftp_cwd (struct rbuf *rbuf, const char *dir) +ftp_cwd (int csock, const char *dir) { char *request, *respline; int nwritten; @@ -914,7 +870,7 @@ ftp_cwd (struct rbuf *rbuf, const char *dir) /* Send CWD request. */ request = ftp_request ("CWD", dir); - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); @@ -922,12 +878,9 @@ ftp_cwd (struct rbuf *rbuf, const char *dir) } xfree (request); /* Get appropriate response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) - { - xfree (respline); - return err; - } + return err; if (*respline == '5') { xfree (respline); @@ -945,16 +898,14 @@ ftp_cwd (struct rbuf *rbuf, const char *dir) /* Sends REST command to the FTP server. */ uerr_t -ftp_rest (struct rbuf *rbuf, long offset) +ftp_rest (int csock, wgint offset) { char *request, *respline; int nwritten; uerr_t err; - static char numbuf[24]; /* Buffer for the number */ - number_to_string (numbuf, offset); - request = ftp_request ("REST", numbuf); - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + request = ftp_request ("REST", number_to_static_string (offset)); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); @@ -962,12 +913,9 @@ ftp_rest (struct rbuf *rbuf, long offset) } xfree (request); /* Get appropriate response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) - { - xfree (respline); - return err; - } + return err; if (*respline != '3') { xfree (respline); @@ -980,7 +928,7 @@ ftp_rest (struct rbuf *rbuf, long offset) /* Sends RETR command to the FTP server. */ uerr_t -ftp_retr (struct rbuf *rbuf, const char *file) +ftp_retr (int csock, const char *file) { char *request, *respline; int nwritten; @@ -988,7 +936,7 @@ ftp_retr (struct rbuf *rbuf, const char *file) /* Send RETR request. */ request = ftp_request ("RETR", file); - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); @@ -996,12 +944,9 @@ ftp_retr (struct rbuf *rbuf, const char *file) } xfree (request); /* Get appropriate response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) - { - xfree (respline); - return err; - } + return err; if (*respline == '5') { xfree (respline); @@ -1020,7 +965,7 @@ ftp_retr (struct rbuf *rbuf, const char *file) /* Sends the LIST command to the server. If FILE is NULL, send just `LIST' (no space). */ uerr_t -ftp_list (struct rbuf *rbuf, const char *file) +ftp_list (int csock, const char *file) { char *request, *respline; int nwritten; @@ -1028,7 +973,7 @@ ftp_list (struct rbuf *rbuf, const char *file) /* Send LIST request. */ request = ftp_request ("LIST", file); - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); @@ -1036,12 +981,9 @@ ftp_list (struct rbuf *rbuf, const char *file) } xfree (request); /* Get appropriate respone. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) - { - xfree (respline); - return err; - } + return err; if (*respline == '5') { xfree (respline); @@ -1059,7 +1001,7 @@ ftp_list (struct rbuf *rbuf, const char *file) /* Sends the SYST command to the server. */ uerr_t -ftp_syst (struct rbuf *rbuf, enum stype *server_type) +ftp_syst (int csock, enum stype *server_type) { char *request, *respline; int nwritten; @@ -1067,7 +1009,7 @@ ftp_syst (struct rbuf *rbuf, enum stype *server_type) /* Send SYST request. */ request = ftp_request ("SYST", NULL); - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); @@ -1076,12 +1018,9 @@ ftp_syst (struct rbuf *rbuf, enum stype *server_type) xfree (request); /* Get appropriate response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) - { - xfree (respline); - return err; - } + return err; if (*respline == '5') { xfree (respline); @@ -1099,7 +1038,8 @@ ftp_syst (struct rbuf *rbuf, enum stype *server_type) *server_type = ST_VMS; else if (!strcasecmp (request, "UNIX")) *server_type = ST_UNIX; - else if (!strcasecmp (request, "WINDOWS_NT")) + else if (!strcasecmp (request, "WINDOWS_NT") + || !strcasecmp (request, "WINDOWS2000")) *server_type = ST_WINNT; else if (!strcasecmp (request, "MACOS")) *server_type = ST_MACOS; @@ -1115,7 +1055,7 @@ ftp_syst (struct rbuf *rbuf, enum stype *server_type) /* Sends the PWD command to the server. */ uerr_t -ftp_pwd (struct rbuf *rbuf, char **pwd) +ftp_pwd (int csock, char **pwd) { char *request, *respline; int nwritten; @@ -1123,7 +1063,7 @@ ftp_pwd (struct rbuf *rbuf, char **pwd) /* Send PWD request. */ request = ftp_request ("PWD", NULL); - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); @@ -1131,14 +1071,12 @@ ftp_pwd (struct rbuf *rbuf, char **pwd) } xfree (request); /* Get appropriate response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) - { - xfree (respline); - return err; - } + return err; if (*respline == '5') { + err: xfree (respline); return FTPSRVERR; } @@ -1147,6 +1085,10 @@ ftp_pwd (struct rbuf *rbuf, char **pwd) and everything following it. */ strtok (respline, "\""); request = strtok (NULL, "\""); + if (!request) + /* Treat the malformed response as an error, which the caller has + to handle gracefully anyway. */ + goto err; /* Has the `pwd' been already allocated? Free! */ xfree_null (*pwd); @@ -1161,7 +1103,7 @@ ftp_pwd (struct rbuf *rbuf, char **pwd) /* Sends the SIZE command to the server, and returns the value in 'size'. * If an error occurs, size is set to zero. */ uerr_t -ftp_size (struct rbuf *rbuf, const char *file, long int *size) +ftp_size (int csock, const char *file, wgint *size) { char *request, *respline; int nwritten; @@ -1169,7 +1111,7 @@ ftp_size (struct rbuf *rbuf, const char *file, long int *size) /* Send PWD request. */ request = ftp_request ("SIZE", file); - nwritten = xwrite (RBUF_FD (rbuf), request, strlen (request), -1); + nwritten = fd_write (csock, request, strlen (request), -1); if (nwritten < 0) { xfree (request); @@ -1178,10 +1120,9 @@ ftp_size (struct rbuf *rbuf, const char *file, long int *size) } xfree (request); /* Get appropriate response. */ - err = ftp_response (rbuf, &respline); + err = ftp_response (csock, &respline); if (err != FTPOK) { - xfree (respline); *size = 0; return err; } @@ -1197,8 +1138,8 @@ ftp_size (struct rbuf *rbuf, const char *file, long int *size) } errno = 0; - *size = strtol (respline + 4, NULL, 0); - if (errno) + *size = str_to_wgint (respline + 4, NULL, 10); + if (errno) { /* * Couldn't parse the response for some reason. On the (few)