1*6cdfca03SJohn Marino /* $NetBSD: ftp.c,v 1.19 2013/05/05 11:17:31 lukem Exp $ */ 2*6cdfca03SJohn Marino /* from NetBSD: ftp.c,v 1.164 2012/07/04 06:09:37 is Exp */ 3*6cdfca03SJohn Marino 4*6cdfca03SJohn Marino /*- 5*6cdfca03SJohn Marino * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. 6*6cdfca03SJohn Marino * All rights reserved. 7*6cdfca03SJohn Marino * 8*6cdfca03SJohn Marino * This code is derived from software contributed to The NetBSD Foundation 9*6cdfca03SJohn Marino * by Luke Mewburn. 10*6cdfca03SJohn Marino * 11*6cdfca03SJohn Marino * Redistribution and use in source and binary forms, with or without 12*6cdfca03SJohn Marino * modification, are permitted provided that the following conditions 13*6cdfca03SJohn Marino * are met: 14*6cdfca03SJohn Marino * 1. Redistributions of source code must retain the above copyright 15*6cdfca03SJohn Marino * notice, this list of conditions and the following disclaimer. 16*6cdfca03SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright 17*6cdfca03SJohn Marino * notice, this list of conditions and the following disclaimer in the 18*6cdfca03SJohn Marino * documentation and/or other materials provided with the distribution. 19*6cdfca03SJohn Marino * 20*6cdfca03SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21*6cdfca03SJohn Marino * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22*6cdfca03SJohn Marino * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23*6cdfca03SJohn Marino * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24*6cdfca03SJohn Marino * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25*6cdfca03SJohn Marino * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26*6cdfca03SJohn Marino * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27*6cdfca03SJohn Marino * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28*6cdfca03SJohn Marino * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29*6cdfca03SJohn Marino * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30*6cdfca03SJohn Marino * POSSIBILITY OF SUCH DAMAGE. 31*6cdfca03SJohn Marino */ 32*6cdfca03SJohn Marino 33*6cdfca03SJohn Marino /* 34*6cdfca03SJohn Marino * Copyright (c) 1985, 1989, 1993, 1994 35*6cdfca03SJohn Marino * The Regents of the University of California. All rights reserved. 36*6cdfca03SJohn Marino * 37*6cdfca03SJohn Marino * Redistribution and use in source and binary forms, with or without 38*6cdfca03SJohn Marino * modification, are permitted provided that the following conditions 39*6cdfca03SJohn Marino * are met: 40*6cdfca03SJohn Marino * 1. Redistributions of source code must retain the above copyright 41*6cdfca03SJohn Marino * notice, this list of conditions and the following disclaimer. 42*6cdfca03SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright 43*6cdfca03SJohn Marino * notice, this list of conditions and the following disclaimer in the 44*6cdfca03SJohn Marino * documentation and/or other materials provided with the distribution. 45*6cdfca03SJohn Marino * 3. Neither the name of the University nor the names of its contributors 46*6cdfca03SJohn Marino * may be used to endorse or promote products derived from this software 47*6cdfca03SJohn Marino * without specific prior written permission. 48*6cdfca03SJohn Marino * 49*6cdfca03SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50*6cdfca03SJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51*6cdfca03SJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52*6cdfca03SJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53*6cdfca03SJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54*6cdfca03SJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55*6cdfca03SJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56*6cdfca03SJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57*6cdfca03SJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58*6cdfca03SJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59*6cdfca03SJohn Marino * SUCH DAMAGE. 60*6cdfca03SJohn Marino */ 61*6cdfca03SJohn Marino 62*6cdfca03SJohn Marino /* 63*6cdfca03SJohn Marino * Copyright (C) 1997 and 1998 WIDE Project. 64*6cdfca03SJohn Marino * All rights reserved. 65*6cdfca03SJohn Marino * 66*6cdfca03SJohn Marino * Redistribution and use in source and binary forms, with or without 67*6cdfca03SJohn Marino * modification, are permitted provided that the following conditions 68*6cdfca03SJohn Marino * are met: 69*6cdfca03SJohn Marino * 1. Redistributions of source code must retain the above copyright 70*6cdfca03SJohn Marino * notice, this list of conditions and the following disclaimer. 71*6cdfca03SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright 72*6cdfca03SJohn Marino * notice, this list of conditions and the following disclaimer in the 73*6cdfca03SJohn Marino * documentation and/or other materials provided with the distribution. 74*6cdfca03SJohn Marino * 3. Neither the name of the project nor the names of its contributors 75*6cdfca03SJohn Marino * may be used to endorse or promote products derived from this software 76*6cdfca03SJohn Marino * without specific prior written permission. 77*6cdfca03SJohn Marino * 78*6cdfca03SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 79*6cdfca03SJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 80*6cdfca03SJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 81*6cdfca03SJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 82*6cdfca03SJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 83*6cdfca03SJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 84*6cdfca03SJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 85*6cdfca03SJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 86*6cdfca03SJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 87*6cdfca03SJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 88*6cdfca03SJohn Marino * SUCH DAMAGE. 89*6cdfca03SJohn Marino */ 90*6cdfca03SJohn Marino 91*6cdfca03SJohn Marino #include "tnftp.h" 92*6cdfca03SJohn Marino #include <arpa/telnet.h> 93*6cdfca03SJohn Marino 94*6cdfca03SJohn Marino #if 0 /* tnftp */ 95*6cdfca03SJohn Marino 96*6cdfca03SJohn Marino #include <sys/cdefs.h> 97*6cdfca03SJohn Marino #ifndef lint 98*6cdfca03SJohn Marino #if 0 99*6cdfca03SJohn Marino static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94"; 100*6cdfca03SJohn Marino #else 101*6cdfca03SJohn Marino __RCSID(" NetBSD: ftp.c,v 1.164 2012/07/04 06:09:37 is Exp "); 102*6cdfca03SJohn Marino #endif 103*6cdfca03SJohn Marino #endif /* not lint */ 104*6cdfca03SJohn Marino 105*6cdfca03SJohn Marino #include <sys/types.h> 106*6cdfca03SJohn Marino #include <sys/stat.h> 107*6cdfca03SJohn Marino #include <sys/socket.h> 108*6cdfca03SJohn Marino #include <sys/time.h> 109*6cdfca03SJohn Marino 110*6cdfca03SJohn Marino #include <netinet/in.h> 111*6cdfca03SJohn Marino #include <netinet/in_systm.h> 112*6cdfca03SJohn Marino #include <netinet/ip.h> 113*6cdfca03SJohn Marino #include <arpa/inet.h> 114*6cdfca03SJohn Marino #include <arpa/ftp.h> 115*6cdfca03SJohn Marino #include <arpa/telnet.h> 116*6cdfca03SJohn Marino 117*6cdfca03SJohn Marino #include <assert.h> 118*6cdfca03SJohn Marino #include <ctype.h> 119*6cdfca03SJohn Marino #include <err.h> 120*6cdfca03SJohn Marino #include <errno.h> 121*6cdfca03SJohn Marino #include <fcntl.h> 122*6cdfca03SJohn Marino #include <netdb.h> 123*6cdfca03SJohn Marino #include <stdio.h> 124*6cdfca03SJohn Marino #include <stdlib.h> 125*6cdfca03SJohn Marino #include <string.h> 126*6cdfca03SJohn Marino #include <time.h> 127*6cdfca03SJohn Marino #include <unistd.h> 128*6cdfca03SJohn Marino #include <stdarg.h> 129*6cdfca03SJohn Marino 130*6cdfca03SJohn Marino #endif /* tnftp */ 131*6cdfca03SJohn Marino 132*6cdfca03SJohn Marino #include "ftp_var.h" 133*6cdfca03SJohn Marino 134*6cdfca03SJohn Marino volatile sig_atomic_t abrtflag; 135*6cdfca03SJohn Marino volatile sig_atomic_t timeoutflag; 136*6cdfca03SJohn Marino 137*6cdfca03SJohn Marino sigjmp_buf ptabort; 138*6cdfca03SJohn Marino int ptabflg; 139*6cdfca03SJohn Marino int ptflag = 0; 140*6cdfca03SJohn Marino char pasv[BUFSIZ]; /* passive port for proxy data connection */ 141*6cdfca03SJohn Marino 142*6cdfca03SJohn Marino static int empty(FILE *, FILE *, int); 143*6cdfca03SJohn Marino __dead static void abort_squared(int); 144*6cdfca03SJohn Marino 145*6cdfca03SJohn Marino struct sockinet { 146*6cdfca03SJohn Marino union sockunion { 147*6cdfca03SJohn Marino struct sockaddr_in su_sin; 148*6cdfca03SJohn Marino #ifdef INET6 149*6cdfca03SJohn Marino struct sockaddr_in6 su_sin6; 150*6cdfca03SJohn Marino #endif 151*6cdfca03SJohn Marino } si_su; 152*6cdfca03SJohn Marino #if !defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN) 153*6cdfca03SJohn Marino int si_len; 154*6cdfca03SJohn Marino #endif 155*6cdfca03SJohn Marino }; 156*6cdfca03SJohn Marino 157*6cdfca03SJohn Marino #if !defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN) 158*6cdfca03SJohn Marino # define su_len si_len 159*6cdfca03SJohn Marino #else 160*6cdfca03SJohn Marino # define su_len si_su.su_sin.sin_len 161*6cdfca03SJohn Marino #endif 162*6cdfca03SJohn Marino #define su_family si_su.su_sin.sin_family 163*6cdfca03SJohn Marino #define su_port si_su.su_sin.sin_port 164*6cdfca03SJohn Marino 165*6cdfca03SJohn Marino struct sockinet myctladdr, hisctladdr, data_addr; 166*6cdfca03SJohn Marino 167*6cdfca03SJohn Marino char * 168*6cdfca03SJohn Marino hookup(const char *host, const char *port) 169*6cdfca03SJohn Marino { 170*6cdfca03SJohn Marino int s = -1, error; 171*6cdfca03SJohn Marino struct addrinfo hints, *res, *res0; 172*6cdfca03SJohn Marino static char hostnamebuf[MAXHOSTNAMELEN]; 173*6cdfca03SJohn Marino socklen_t len; 174*6cdfca03SJohn Marino int on = 1; 175*6cdfca03SJohn Marino 176*6cdfca03SJohn Marino memset((char *)&hisctladdr, 0, sizeof (hisctladdr)); 177*6cdfca03SJohn Marino memset((char *)&myctladdr, 0, sizeof (myctladdr)); 178*6cdfca03SJohn Marino memset(&hints, 0, sizeof(hints)); 179*6cdfca03SJohn Marino hints.ai_flags = AI_CANONNAME; 180*6cdfca03SJohn Marino hints.ai_family = family; 181*6cdfca03SJohn Marino hints.ai_socktype = SOCK_STREAM; 182*6cdfca03SJohn Marino hints.ai_protocol = 0; 183*6cdfca03SJohn Marino error = getaddrinfo(host, port, &hints, &res0); 184*6cdfca03SJohn Marino if (error) { 185*6cdfca03SJohn Marino warnx("Can't lookup `%s:%s': %s", host, port, 186*6cdfca03SJohn Marino (error == EAI_SYSTEM) ? strerror(errno) 187*6cdfca03SJohn Marino : gai_strerror(error)); 188*6cdfca03SJohn Marino code = -1; 189*6cdfca03SJohn Marino return (0); 190*6cdfca03SJohn Marino } 191*6cdfca03SJohn Marino 192*6cdfca03SJohn Marino if (res0->ai_canonname) 193*6cdfca03SJohn Marino (void)strlcpy(hostnamebuf, res0->ai_canonname, 194*6cdfca03SJohn Marino sizeof(hostnamebuf)); 195*6cdfca03SJohn Marino else 196*6cdfca03SJohn Marino (void)strlcpy(hostnamebuf, host, sizeof(hostnamebuf)); 197*6cdfca03SJohn Marino hostname = hostnamebuf; 198*6cdfca03SJohn Marino 199*6cdfca03SJohn Marino for (res = res0; res; res = res->ai_next) { 200*6cdfca03SJohn Marino char hname[NI_MAXHOST], sname[NI_MAXSERV]; 201*6cdfca03SJohn Marino 202*6cdfca03SJohn Marino ai_unmapped(res); 203*6cdfca03SJohn Marino if (getnameinfo(res->ai_addr, res->ai_addrlen, 204*6cdfca03SJohn Marino hname, sizeof(hname), sname, sizeof(sname), 205*6cdfca03SJohn Marino NI_NUMERICHOST | NI_NUMERICSERV) != 0) { 206*6cdfca03SJohn Marino strlcpy(hname, "?", sizeof(hname)); 207*6cdfca03SJohn Marino strlcpy(sname, "?", sizeof(sname)); 208*6cdfca03SJohn Marino } 209*6cdfca03SJohn Marino if (verbose && res0->ai_next) { 210*6cdfca03SJohn Marino /* if we have multiple possibilities */ 211*6cdfca03SJohn Marino fprintf(ttyout, "Trying %s:%s ...\n", hname, sname); 212*6cdfca03SJohn Marino } 213*6cdfca03SJohn Marino s = socket(res->ai_family, SOCK_STREAM, res->ai_protocol); 214*6cdfca03SJohn Marino if (s < 0) { 215*6cdfca03SJohn Marino warn("Can't create socket for connection to `%s:%s'", 216*6cdfca03SJohn Marino hname, sname); 217*6cdfca03SJohn Marino continue; 218*6cdfca03SJohn Marino } 219*6cdfca03SJohn Marino if (ftp_connect(s, res->ai_addr, res->ai_addrlen, 220*6cdfca03SJohn Marino verbose || !res->ai_next) < 0) { 221*6cdfca03SJohn Marino close(s); 222*6cdfca03SJohn Marino s = -1; 223*6cdfca03SJohn Marino continue; 224*6cdfca03SJohn Marino } 225*6cdfca03SJohn Marino 226*6cdfca03SJohn Marino /* finally we got one */ 227*6cdfca03SJohn Marino break; 228*6cdfca03SJohn Marino } 229*6cdfca03SJohn Marino if (s < 0) { 230*6cdfca03SJohn Marino warnx("Can't connect to `%s:%s'", host, port); 231*6cdfca03SJohn Marino code = -1; 232*6cdfca03SJohn Marino freeaddrinfo(res0); 233*6cdfca03SJohn Marino return 0; 234*6cdfca03SJohn Marino } 235*6cdfca03SJohn Marino memcpy(&hisctladdr.si_su, res->ai_addr, res->ai_addrlen); 236*6cdfca03SJohn Marino hisctladdr.su_len = res->ai_addrlen; 237*6cdfca03SJohn Marino freeaddrinfo(res0); 238*6cdfca03SJohn Marino res0 = res = NULL; 239*6cdfca03SJohn Marino 240*6cdfca03SJohn Marino len = hisctladdr.su_len; 241*6cdfca03SJohn Marino if (getsockname(s, (struct sockaddr *)&myctladdr.si_su, &len) == -1) { 242*6cdfca03SJohn Marino warn("Can't determine my address of connection to `%s:%s'", 243*6cdfca03SJohn Marino host, port); 244*6cdfca03SJohn Marino code = -1; 245*6cdfca03SJohn Marino goto bad; 246*6cdfca03SJohn Marino } 247*6cdfca03SJohn Marino myctladdr.su_len = len; 248*6cdfca03SJohn Marino 249*6cdfca03SJohn Marino #ifdef IPTOS_LOWDELAY 250*6cdfca03SJohn Marino if (hisctladdr.su_family == AF_INET) { 251*6cdfca03SJohn Marino int tos = IPTOS_LOWDELAY; 252*6cdfca03SJohn Marino if (setsockopt(s, IPPROTO_IP, IP_TOS, 253*6cdfca03SJohn Marino (void *)&tos, sizeof(tos)) == -1) { 254*6cdfca03SJohn Marino DWARN("setsockopt %s (ignored)", 255*6cdfca03SJohn Marino "IPTOS_LOWDELAY"); 256*6cdfca03SJohn Marino } 257*6cdfca03SJohn Marino } 258*6cdfca03SJohn Marino #endif 259*6cdfca03SJohn Marino cin = fdopen(s, "r"); 260*6cdfca03SJohn Marino cout = fdopen(s, "w"); 261*6cdfca03SJohn Marino if (cin == NULL || cout == NULL) { 262*6cdfca03SJohn Marino warnx("Can't fdopen socket"); 263*6cdfca03SJohn Marino if (cin) 264*6cdfca03SJohn Marino (void)fclose(cin); 265*6cdfca03SJohn Marino if (cout) 266*6cdfca03SJohn Marino (void)fclose(cout); 267*6cdfca03SJohn Marino code = -1; 268*6cdfca03SJohn Marino goto bad; 269*6cdfca03SJohn Marino } 270*6cdfca03SJohn Marino if (verbose) 271*6cdfca03SJohn Marino fprintf(ttyout, "Connected to %s.\n", hostname); 272*6cdfca03SJohn Marino if (getreply(0) > 2) { /* read startup message from server */ 273*6cdfca03SJohn Marino if (cin) 274*6cdfca03SJohn Marino (void)fclose(cin); 275*6cdfca03SJohn Marino if (cout) 276*6cdfca03SJohn Marino (void)fclose(cout); 277*6cdfca03SJohn Marino code = -1; 278*6cdfca03SJohn Marino goto bad; 279*6cdfca03SJohn Marino } 280*6cdfca03SJohn Marino 281*6cdfca03SJohn Marino if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, 282*6cdfca03SJohn Marino (void *)&on, sizeof(on)) == -1) { 283*6cdfca03SJohn Marino DWARN("setsockopt %s (ignored)", "SO_OOBINLINE"); 284*6cdfca03SJohn Marino } 285*6cdfca03SJohn Marino 286*6cdfca03SJohn Marino return (hostname); 287*6cdfca03SJohn Marino bad: 288*6cdfca03SJohn Marino (void)close(s); 289*6cdfca03SJohn Marino return (NULL); 290*6cdfca03SJohn Marino } 291*6cdfca03SJohn Marino 292*6cdfca03SJohn Marino void 293*6cdfca03SJohn Marino cmdabort(int notused) 294*6cdfca03SJohn Marino { 295*6cdfca03SJohn Marino int oerrno = errno; 296*6cdfca03SJohn Marino 297*6cdfca03SJohn Marino sigint_raised = 1; 298*6cdfca03SJohn Marino alarmtimer(0); 299*6cdfca03SJohn Marino if (fromatty) 300*6cdfca03SJohn Marino write(fileno(ttyout), "\n", 1); 301*6cdfca03SJohn Marino abrtflag++; 302*6cdfca03SJohn Marino if (ptflag) 303*6cdfca03SJohn Marino siglongjmp(ptabort, 1); 304*6cdfca03SJohn Marino errno = oerrno; 305*6cdfca03SJohn Marino } 306*6cdfca03SJohn Marino 307*6cdfca03SJohn Marino void 308*6cdfca03SJohn Marino cmdtimeout(int notused) 309*6cdfca03SJohn Marino { 310*6cdfca03SJohn Marino int oerrno = errno; 311*6cdfca03SJohn Marino 312*6cdfca03SJohn Marino alarmtimer(0); 313*6cdfca03SJohn Marino if (fromatty) 314*6cdfca03SJohn Marino write(fileno(ttyout), "\n", 1); 315*6cdfca03SJohn Marino timeoutflag++; 316*6cdfca03SJohn Marino if (ptflag) 317*6cdfca03SJohn Marino siglongjmp(ptabort, 1); 318*6cdfca03SJohn Marino errno = oerrno; 319*6cdfca03SJohn Marino } 320*6cdfca03SJohn Marino 321*6cdfca03SJohn Marino /*VARARGS*/ 322*6cdfca03SJohn Marino int 323*6cdfca03SJohn Marino command(const char *fmt, ...) 324*6cdfca03SJohn Marino { 325*6cdfca03SJohn Marino va_list ap; 326*6cdfca03SJohn Marino int r; 327*6cdfca03SJohn Marino sigfunc oldsigint; 328*6cdfca03SJohn Marino 329*6cdfca03SJohn Marino #ifndef NO_DEBUG 330*6cdfca03SJohn Marino if (ftp_debug) { 331*6cdfca03SJohn Marino fputs("---> ", ttyout); 332*6cdfca03SJohn Marino va_start(ap, fmt); 333*6cdfca03SJohn Marino if (strncmp("PASS ", fmt, 5) == 0) 334*6cdfca03SJohn Marino fputs("PASS XXXX", ttyout); 335*6cdfca03SJohn Marino else if (strncmp("ACCT ", fmt, 5) == 0) 336*6cdfca03SJohn Marino fputs("ACCT XXXX", ttyout); 337*6cdfca03SJohn Marino else 338*6cdfca03SJohn Marino vfprintf(ttyout, fmt, ap); 339*6cdfca03SJohn Marino va_end(ap); 340*6cdfca03SJohn Marino putc('\n', ttyout); 341*6cdfca03SJohn Marino } 342*6cdfca03SJohn Marino #endif 343*6cdfca03SJohn Marino if (cout == NULL) { 344*6cdfca03SJohn Marino warnx("No control connection for command"); 345*6cdfca03SJohn Marino code = -1; 346*6cdfca03SJohn Marino return (0); 347*6cdfca03SJohn Marino } 348*6cdfca03SJohn Marino 349*6cdfca03SJohn Marino abrtflag = 0; 350*6cdfca03SJohn Marino 351*6cdfca03SJohn Marino oldsigint = xsignal(SIGINT, cmdabort); 352*6cdfca03SJohn Marino 353*6cdfca03SJohn Marino va_start(ap, fmt); 354*6cdfca03SJohn Marino vfprintf(cout, fmt, ap); 355*6cdfca03SJohn Marino va_end(ap); 356*6cdfca03SJohn Marino fputs("\r\n", cout); 357*6cdfca03SJohn Marino (void)fflush(cout); 358*6cdfca03SJohn Marino cpend = 1; 359*6cdfca03SJohn Marino r = getreply(!strcmp(fmt, "QUIT")); 360*6cdfca03SJohn Marino if (abrtflag && oldsigint != SIG_IGN) 361*6cdfca03SJohn Marino (*oldsigint)(SIGINT); 362*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldsigint); 363*6cdfca03SJohn Marino return (r); 364*6cdfca03SJohn Marino } 365*6cdfca03SJohn Marino 366*6cdfca03SJohn Marino static const char *m421[] = { 367*6cdfca03SJohn Marino "remote server timed out. Connection closed", 368*6cdfca03SJohn Marino "user interrupt. Connection closed", 369*6cdfca03SJohn Marino "remote server has closed connection", 370*6cdfca03SJohn Marino }; 371*6cdfca03SJohn Marino 372*6cdfca03SJohn Marino int 373*6cdfca03SJohn Marino getreply(int expecteof) 374*6cdfca03SJohn Marino { 375*6cdfca03SJohn Marino char current_line[BUFSIZ]; /* last line of previous reply */ 376*6cdfca03SJohn Marino int c, n, lineno; 377*6cdfca03SJohn Marino int dig; 378*6cdfca03SJohn Marino int originalcode = 0, continuation = 0; 379*6cdfca03SJohn Marino sigfunc oldsigint, oldsigalrm; 380*6cdfca03SJohn Marino int pflag = 0; 381*6cdfca03SJohn Marino char *cp, *pt = pasv; 382*6cdfca03SJohn Marino 383*6cdfca03SJohn Marino abrtflag = 0; 384*6cdfca03SJohn Marino timeoutflag = 0; 385*6cdfca03SJohn Marino 386*6cdfca03SJohn Marino oldsigint = xsignal(SIGINT, cmdabort); 387*6cdfca03SJohn Marino oldsigalrm = xsignal(SIGALRM, cmdtimeout); 388*6cdfca03SJohn Marino 389*6cdfca03SJohn Marino for (lineno = 0 ;; lineno++) { 390*6cdfca03SJohn Marino dig = n = code = 0; 391*6cdfca03SJohn Marino cp = current_line; 392*6cdfca03SJohn Marino while (alarmtimer(quit_time ? quit_time : 60), 393*6cdfca03SJohn Marino ((c = getc(cin)) != '\n')) { 394*6cdfca03SJohn Marino if (c == IAC) { /* handle telnet commands */ 395*6cdfca03SJohn Marino switch (c = getc(cin)) { 396*6cdfca03SJohn Marino case WILL: 397*6cdfca03SJohn Marino case WONT: 398*6cdfca03SJohn Marino c = getc(cin); 399*6cdfca03SJohn Marino fprintf(cout, "%c%c%c", IAC, DONT, c); 400*6cdfca03SJohn Marino (void)fflush(cout); 401*6cdfca03SJohn Marino break; 402*6cdfca03SJohn Marino case DO: 403*6cdfca03SJohn Marino case DONT: 404*6cdfca03SJohn Marino c = getc(cin); 405*6cdfca03SJohn Marino fprintf(cout, "%c%c%c", IAC, WONT, c); 406*6cdfca03SJohn Marino (void)fflush(cout); 407*6cdfca03SJohn Marino break; 408*6cdfca03SJohn Marino default: 409*6cdfca03SJohn Marino break; 410*6cdfca03SJohn Marino } 411*6cdfca03SJohn Marino continue; 412*6cdfca03SJohn Marino } 413*6cdfca03SJohn Marino dig++; 414*6cdfca03SJohn Marino if (c == EOF) { 415*6cdfca03SJohn Marino /* 416*6cdfca03SJohn Marino * these will get trashed by pswitch() 417*6cdfca03SJohn Marino * in lostpeer() 418*6cdfca03SJohn Marino */ 419*6cdfca03SJohn Marino int reply_timeoutflag = timeoutflag; 420*6cdfca03SJohn Marino int reply_abrtflag = abrtflag; 421*6cdfca03SJohn Marino 422*6cdfca03SJohn Marino alarmtimer(0); 423*6cdfca03SJohn Marino if (expecteof && feof(cin)) { 424*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldsigint); 425*6cdfca03SJohn Marino (void)xsignal(SIGALRM, oldsigalrm); 426*6cdfca03SJohn Marino code = 221; 427*6cdfca03SJohn Marino return (0); 428*6cdfca03SJohn Marino } 429*6cdfca03SJohn Marino cpend = 0; 430*6cdfca03SJohn Marino lostpeer(0); 431*6cdfca03SJohn Marino if (verbose) { 432*6cdfca03SJohn Marino size_t midx; 433*6cdfca03SJohn Marino if (reply_timeoutflag) 434*6cdfca03SJohn Marino midx = 0; 435*6cdfca03SJohn Marino else if (reply_abrtflag) 436*6cdfca03SJohn Marino midx = 1; 437*6cdfca03SJohn Marino else 438*6cdfca03SJohn Marino midx = 2; 439*6cdfca03SJohn Marino (void)fprintf(ttyout, 440*6cdfca03SJohn Marino "421 Service not available, %s.\n", m421[midx]); 441*6cdfca03SJohn Marino (void)fflush(ttyout); 442*6cdfca03SJohn Marino } 443*6cdfca03SJohn Marino code = 421; 444*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldsigint); 445*6cdfca03SJohn Marino (void)xsignal(SIGALRM, oldsigalrm); 446*6cdfca03SJohn Marino return (4); 447*6cdfca03SJohn Marino } 448*6cdfca03SJohn Marino if (c != '\r' && (verbose > 0 || 449*6cdfca03SJohn Marino ((verbose > -1 && n == '5' && dig > 4) && 450*6cdfca03SJohn Marino (((!n && c < '5') || (n && n < '5')) 451*6cdfca03SJohn Marino || !retry_connect)))) { 452*6cdfca03SJohn Marino if (proxflag && 453*6cdfca03SJohn Marino (dig == 1 || (dig == 5 && verbose == 0))) 454*6cdfca03SJohn Marino fprintf(ttyout, "%s:", hostname); 455*6cdfca03SJohn Marino (void)putc(c, ttyout); 456*6cdfca03SJohn Marino } 457*6cdfca03SJohn Marino if (dig < 4 && isdigit(c)) 458*6cdfca03SJohn Marino code = code * 10 + (c - '0'); 459*6cdfca03SJohn Marino if (!pflag && (code == 227 || code == 228)) 460*6cdfca03SJohn Marino pflag = 1; 461*6cdfca03SJohn Marino else if (!pflag && code == 229) 462*6cdfca03SJohn Marino pflag = 100; 463*6cdfca03SJohn Marino if (dig > 4 && pflag == 1 && isdigit(c)) 464*6cdfca03SJohn Marino pflag = 2; 465*6cdfca03SJohn Marino if (pflag == 2) { 466*6cdfca03SJohn Marino if (c != '\r' && c != ')') { 467*6cdfca03SJohn Marino if (pt < &pasv[sizeof(pasv) - 1]) 468*6cdfca03SJohn Marino *pt++ = c; 469*6cdfca03SJohn Marino } else { 470*6cdfca03SJohn Marino *pt = '\0'; 471*6cdfca03SJohn Marino pflag = 3; 472*6cdfca03SJohn Marino } 473*6cdfca03SJohn Marino } 474*6cdfca03SJohn Marino if (pflag == 100 && c == '(') 475*6cdfca03SJohn Marino pflag = 2; 476*6cdfca03SJohn Marino if (dig == 4 && c == '-') { 477*6cdfca03SJohn Marino if (continuation) 478*6cdfca03SJohn Marino code = 0; 479*6cdfca03SJohn Marino continuation++; 480*6cdfca03SJohn Marino } 481*6cdfca03SJohn Marino if (n == 0) 482*6cdfca03SJohn Marino n = c; 483*6cdfca03SJohn Marino if (cp < ¤t_line[sizeof(current_line) - 1]) 484*6cdfca03SJohn Marino *cp++ = c; 485*6cdfca03SJohn Marino } 486*6cdfca03SJohn Marino if (verbose > 0 || ((verbose > -1 && n == '5') && 487*6cdfca03SJohn Marino (n < '5' || !retry_connect))) { 488*6cdfca03SJohn Marino (void)putc(c, ttyout); 489*6cdfca03SJohn Marino (void)fflush(ttyout); 490*6cdfca03SJohn Marino } 491*6cdfca03SJohn Marino if (cp[-1] == '\r') 492*6cdfca03SJohn Marino cp[-1] = '\0'; 493*6cdfca03SJohn Marino *cp = '\0'; 494*6cdfca03SJohn Marino if (lineno == 0) 495*6cdfca03SJohn Marino (void)strlcpy(reply_string, current_line, 496*6cdfca03SJohn Marino sizeof(reply_string)); 497*6cdfca03SJohn Marino if (lineno > 0 && code == 0 && reply_callback != NULL) 498*6cdfca03SJohn Marino (*reply_callback)(current_line); 499*6cdfca03SJohn Marino if (continuation && code != originalcode) { 500*6cdfca03SJohn Marino if (originalcode == 0) 501*6cdfca03SJohn Marino originalcode = code; 502*6cdfca03SJohn Marino continue; 503*6cdfca03SJohn Marino } 504*6cdfca03SJohn Marino if (n != '1') 505*6cdfca03SJohn Marino cpend = 0; 506*6cdfca03SJohn Marino alarmtimer(0); 507*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldsigint); 508*6cdfca03SJohn Marino (void)xsignal(SIGALRM, oldsigalrm); 509*6cdfca03SJohn Marino if (code == 421 || originalcode == 421) 510*6cdfca03SJohn Marino lostpeer(0); 511*6cdfca03SJohn Marino if (abrtflag && oldsigint != cmdabort && oldsigint != SIG_IGN) 512*6cdfca03SJohn Marino (*oldsigint)(SIGINT); 513*6cdfca03SJohn Marino if (timeoutflag && oldsigalrm != cmdtimeout && 514*6cdfca03SJohn Marino oldsigalrm != SIG_IGN) 515*6cdfca03SJohn Marino (*oldsigalrm)(SIGINT); 516*6cdfca03SJohn Marino return (n - '0'); 517*6cdfca03SJohn Marino } 518*6cdfca03SJohn Marino } 519*6cdfca03SJohn Marino 520*6cdfca03SJohn Marino static int 521*6cdfca03SJohn Marino empty(FILE *ecin, FILE *din, int sec) 522*6cdfca03SJohn Marino { 523*6cdfca03SJohn Marino int nr, nfd; 524*6cdfca03SJohn Marino struct pollfd pfd[2]; 525*6cdfca03SJohn Marino 526*6cdfca03SJohn Marino nfd = 0; 527*6cdfca03SJohn Marino if (ecin) { 528*6cdfca03SJohn Marino pfd[nfd].fd = fileno(ecin); 529*6cdfca03SJohn Marino pfd[nfd++].events = POLLIN; 530*6cdfca03SJohn Marino } 531*6cdfca03SJohn Marino 532*6cdfca03SJohn Marino if (din) { 533*6cdfca03SJohn Marino pfd[nfd].fd = fileno(din); 534*6cdfca03SJohn Marino pfd[nfd++].events = POLLIN; 535*6cdfca03SJohn Marino } 536*6cdfca03SJohn Marino 537*6cdfca03SJohn Marino if ((nr = ftp_poll(pfd, nfd, sec * 1000)) <= 0) 538*6cdfca03SJohn Marino return nr; 539*6cdfca03SJohn Marino 540*6cdfca03SJohn Marino nr = 0; 541*6cdfca03SJohn Marino nfd = 0; 542*6cdfca03SJohn Marino if (ecin) 543*6cdfca03SJohn Marino nr |= (pfd[nfd++].revents & POLLIN) ? 1 : 0; 544*6cdfca03SJohn Marino if (din) 545*6cdfca03SJohn Marino nr |= (pfd[nfd++].revents & POLLIN) ? 2 : 0; 546*6cdfca03SJohn Marino return nr; 547*6cdfca03SJohn Marino } 548*6cdfca03SJohn Marino 549*6cdfca03SJohn Marino sigjmp_buf xferabort; 550*6cdfca03SJohn Marino 551*6cdfca03SJohn Marino __dead static void 552*6cdfca03SJohn Marino abortxfer(int notused) 553*6cdfca03SJohn Marino { 554*6cdfca03SJohn Marino char msgbuf[100]; 555*6cdfca03SJohn Marino size_t len; 556*6cdfca03SJohn Marino 557*6cdfca03SJohn Marino sigint_raised = 1; 558*6cdfca03SJohn Marino alarmtimer(0); 559*6cdfca03SJohn Marino mflag = 0; 560*6cdfca03SJohn Marino abrtflag = 0; 561*6cdfca03SJohn Marino switch (direction[0]) { 562*6cdfca03SJohn Marino case 'r': 563*6cdfca03SJohn Marino strlcpy(msgbuf, "\nreceive", sizeof(msgbuf)); 564*6cdfca03SJohn Marino break; 565*6cdfca03SJohn Marino case 's': 566*6cdfca03SJohn Marino strlcpy(msgbuf, "\nsend", sizeof(msgbuf)); 567*6cdfca03SJohn Marino break; 568*6cdfca03SJohn Marino default: 569*6cdfca03SJohn Marino errx(1, "abortxfer: unknown direction `%s'", direction); 570*6cdfca03SJohn Marino } 571*6cdfca03SJohn Marino len = strlcat(msgbuf, " aborted. Waiting for remote to finish abort.\n", 572*6cdfca03SJohn Marino sizeof(msgbuf)); 573*6cdfca03SJohn Marino write(fileno(ttyout), msgbuf, len); 574*6cdfca03SJohn Marino siglongjmp(xferabort, 1); 575*6cdfca03SJohn Marino } 576*6cdfca03SJohn Marino 577*6cdfca03SJohn Marino /* 578*6cdfca03SJohn Marino * Read data from infd & write to outfd, using buf/bufsize as the temporary 579*6cdfca03SJohn Marino * buffer, dealing with short writes. 580*6cdfca03SJohn Marino * If rate_limit != 0, rate-limit the transfer. 581*6cdfca03SJohn Marino * If hash_interval != 0, fputc('c', ttyout) every hash_interval bytes. 582*6cdfca03SJohn Marino * Updates global variables: bytes. 583*6cdfca03SJohn Marino * Returns 0 if ok, 1 if there was a read error, 2 if there was a write error. 584*6cdfca03SJohn Marino * In the case of error, errno contains the appropriate error code. 585*6cdfca03SJohn Marino */ 586*6cdfca03SJohn Marino static int 587*6cdfca03SJohn Marino copy_bytes(int infd, int outfd, char *buf, size_t bufsize, 588*6cdfca03SJohn Marino int rate_limit, int hash_interval) 589*6cdfca03SJohn Marino { 590*6cdfca03SJohn Marino volatile off_t hashc; 591*6cdfca03SJohn Marino ssize_t inc, outc; 592*6cdfca03SJohn Marino char *bufp; 593*6cdfca03SJohn Marino struct timeval tvthen, tvnow, tvdiff; 594*6cdfca03SJohn Marino off_t bufrem, bufchunk; 595*6cdfca03SJohn Marino int serr; 596*6cdfca03SJohn Marino 597*6cdfca03SJohn Marino hashc = hash_interval; 598*6cdfca03SJohn Marino if (rate_limit) 599*6cdfca03SJohn Marino bufchunk = rate_limit; 600*6cdfca03SJohn Marino else 601*6cdfca03SJohn Marino bufchunk = bufsize; 602*6cdfca03SJohn Marino 603*6cdfca03SJohn Marino while (1) { 604*6cdfca03SJohn Marino if (rate_limit) { 605*6cdfca03SJohn Marino (void)gettimeofday(&tvthen, NULL); 606*6cdfca03SJohn Marino } 607*6cdfca03SJohn Marino errno = 0; 608*6cdfca03SJohn Marino inc = outc = 0; 609*6cdfca03SJohn Marino /* copy bufchunk at a time */ 610*6cdfca03SJohn Marino bufrem = bufchunk; 611*6cdfca03SJohn Marino while (bufrem > 0) { 612*6cdfca03SJohn Marino inc = read(infd, buf, MIN((off_t)bufsize, bufrem)); 613*6cdfca03SJohn Marino if (inc <= 0) 614*6cdfca03SJohn Marino goto copy_done; 615*6cdfca03SJohn Marino bytes += inc; 616*6cdfca03SJohn Marino bufrem -= inc; 617*6cdfca03SJohn Marino bufp = buf; 618*6cdfca03SJohn Marino while (inc > 0) { 619*6cdfca03SJohn Marino outc = write(outfd, bufp, inc); 620*6cdfca03SJohn Marino if (outc < 0) 621*6cdfca03SJohn Marino goto copy_done; 622*6cdfca03SJohn Marino inc -= outc; 623*6cdfca03SJohn Marino bufp += outc; 624*6cdfca03SJohn Marino } 625*6cdfca03SJohn Marino if (hash_interval) { 626*6cdfca03SJohn Marino while (bytes >= hashc) { 627*6cdfca03SJohn Marino (void)putc('#', ttyout); 628*6cdfca03SJohn Marino hashc += hash_interval; 629*6cdfca03SJohn Marino } 630*6cdfca03SJohn Marino (void)fflush(ttyout); 631*6cdfca03SJohn Marino } 632*6cdfca03SJohn Marino } 633*6cdfca03SJohn Marino if (rate_limit) { /* rate limited; wait if necessary */ 634*6cdfca03SJohn Marino while (1) { 635*6cdfca03SJohn Marino (void)gettimeofday(&tvnow, NULL); 636*6cdfca03SJohn Marino timersub(&tvnow, &tvthen, &tvdiff); 637*6cdfca03SJohn Marino if (tvdiff.tv_sec > 0) 638*6cdfca03SJohn Marino break; 639*6cdfca03SJohn Marino usleep(1000000 - tvdiff.tv_usec); 640*6cdfca03SJohn Marino } 641*6cdfca03SJohn Marino } 642*6cdfca03SJohn Marino } 643*6cdfca03SJohn Marino 644*6cdfca03SJohn Marino copy_done: 645*6cdfca03SJohn Marino serr = errno; 646*6cdfca03SJohn Marino if (hash_interval && bytes > 0) { 647*6cdfca03SJohn Marino if (bytes < hash_interval) 648*6cdfca03SJohn Marino (void)putc('#', ttyout); 649*6cdfca03SJohn Marino (void)putc('\n', ttyout); 650*6cdfca03SJohn Marino (void)fflush(ttyout); 651*6cdfca03SJohn Marino } 652*6cdfca03SJohn Marino errno = serr; 653*6cdfca03SJohn Marino if (inc == -1) 654*6cdfca03SJohn Marino return 1; 655*6cdfca03SJohn Marino if (outc == -1) 656*6cdfca03SJohn Marino return 2; 657*6cdfca03SJohn Marino 658*6cdfca03SJohn Marino return 0; 659*6cdfca03SJohn Marino } 660*6cdfca03SJohn Marino 661*6cdfca03SJohn Marino void 662*6cdfca03SJohn Marino sendrequest(const char *cmd, const char *local, const char *remote, 663*6cdfca03SJohn Marino int printnames) 664*6cdfca03SJohn Marino { 665*6cdfca03SJohn Marino struct stat st; 666*6cdfca03SJohn Marino int c; 667*6cdfca03SJohn Marino FILE *volatile fin; 668*6cdfca03SJohn Marino FILE *volatile dout; 669*6cdfca03SJohn Marino int (*volatile closefunc)(FILE *); 670*6cdfca03SJohn Marino sigfunc volatile oldintr; 671*6cdfca03SJohn Marino sigfunc volatile oldintp; 672*6cdfca03SJohn Marino off_t volatile hashbytes; 673*6cdfca03SJohn Marino int hash_interval; 674*6cdfca03SJohn Marino const char *lmode; 675*6cdfca03SJohn Marino static size_t bufsize; 676*6cdfca03SJohn Marino static char *buf; 677*6cdfca03SJohn Marino int oprogress; 678*6cdfca03SJohn Marino 679*6cdfca03SJohn Marino hashbytes = mark; 680*6cdfca03SJohn Marino direction = "sent"; 681*6cdfca03SJohn Marino dout = NULL; 682*6cdfca03SJohn Marino bytes = 0; 683*6cdfca03SJohn Marino filesize = -1; 684*6cdfca03SJohn Marino oprogress = progress; 685*6cdfca03SJohn Marino if (verbose && printnames) { 686*6cdfca03SJohn Marino if (*local != '-') 687*6cdfca03SJohn Marino fprintf(ttyout, "local: %s ", local); 688*6cdfca03SJohn Marino if (remote) 689*6cdfca03SJohn Marino fprintf(ttyout, "remote: %s\n", remote); 690*6cdfca03SJohn Marino } 691*6cdfca03SJohn Marino if (proxy) { 692*6cdfca03SJohn Marino proxtrans(cmd, local, remote); 693*6cdfca03SJohn Marino return; 694*6cdfca03SJohn Marino } 695*6cdfca03SJohn Marino if (curtype != type) 696*6cdfca03SJohn Marino changetype(type, 0); 697*6cdfca03SJohn Marino closefunc = NULL; 698*6cdfca03SJohn Marino oldintr = NULL; 699*6cdfca03SJohn Marino oldintp = NULL; 700*6cdfca03SJohn Marino lmode = "w"; 701*6cdfca03SJohn Marino if (sigsetjmp(xferabort, 1)) { 702*6cdfca03SJohn Marino while (cpend) 703*6cdfca03SJohn Marino (void)getreply(0); 704*6cdfca03SJohn Marino code = -1; 705*6cdfca03SJohn Marino goto cleanupsend; 706*6cdfca03SJohn Marino } 707*6cdfca03SJohn Marino (void)xsignal(SIGQUIT, psummary); 708*6cdfca03SJohn Marino oldintr = xsignal(SIGINT, abortxfer); 709*6cdfca03SJohn Marino if (strcmp(local, "-") == 0) { 710*6cdfca03SJohn Marino fin = stdin; 711*6cdfca03SJohn Marino progress = 0; 712*6cdfca03SJohn Marino } else if (*local == '|') { 713*6cdfca03SJohn Marino oldintp = xsignal(SIGPIPE, SIG_IGN); 714*6cdfca03SJohn Marino fin = popen(local + 1, "r"); 715*6cdfca03SJohn Marino if (fin == NULL) { 716*6cdfca03SJohn Marino warn("Can't execute `%s'", local + 1); 717*6cdfca03SJohn Marino code = -1; 718*6cdfca03SJohn Marino goto cleanupsend; 719*6cdfca03SJohn Marino } 720*6cdfca03SJohn Marino progress = 0; 721*6cdfca03SJohn Marino closefunc = pclose; 722*6cdfca03SJohn Marino } else { 723*6cdfca03SJohn Marino fin = fopen(local, "r"); 724*6cdfca03SJohn Marino if (fin == NULL) { 725*6cdfca03SJohn Marino warn("Can't open `%s'", local); 726*6cdfca03SJohn Marino code = -1; 727*6cdfca03SJohn Marino goto cleanupsend; 728*6cdfca03SJohn Marino } 729*6cdfca03SJohn Marino closefunc = fclose; 730*6cdfca03SJohn Marino if (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) { 731*6cdfca03SJohn Marino fprintf(ttyout, "%s: not a plain file.\n", local); 732*6cdfca03SJohn Marino code = -1; 733*6cdfca03SJohn Marino goto cleanupsend; 734*6cdfca03SJohn Marino } 735*6cdfca03SJohn Marino filesize = st.st_size; 736*6cdfca03SJohn Marino } 737*6cdfca03SJohn Marino if (initconn()) { 738*6cdfca03SJohn Marino code = -1; 739*6cdfca03SJohn Marino goto cleanupsend; 740*6cdfca03SJohn Marino } 741*6cdfca03SJohn Marino if (sigsetjmp(xferabort, 1)) 742*6cdfca03SJohn Marino goto abort; 743*6cdfca03SJohn Marino 744*6cdfca03SJohn Marino if (restart_point && 745*6cdfca03SJohn Marino (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) { 746*6cdfca03SJohn Marino int rc; 747*6cdfca03SJohn Marino 748*6cdfca03SJohn Marino rc = -1; 749*6cdfca03SJohn Marino switch (curtype) { 750*6cdfca03SJohn Marino case TYPE_A: 751*6cdfca03SJohn Marino rc = fseeko(fin, restart_point, SEEK_SET); 752*6cdfca03SJohn Marino break; 753*6cdfca03SJohn Marino case TYPE_I: 754*6cdfca03SJohn Marino case TYPE_L: 755*6cdfca03SJohn Marino rc = lseek(fileno(fin), restart_point, SEEK_SET); 756*6cdfca03SJohn Marino break; 757*6cdfca03SJohn Marino } 758*6cdfca03SJohn Marino if (rc < 0) { 759*6cdfca03SJohn Marino warn("Can't seek to restart `%s'", local); 760*6cdfca03SJohn Marino goto cleanupsend; 761*6cdfca03SJohn Marino } 762*6cdfca03SJohn Marino if (command("REST " LLF, (LLT)restart_point) != CONTINUE) 763*6cdfca03SJohn Marino goto cleanupsend; 764*6cdfca03SJohn Marino lmode = "r+"; 765*6cdfca03SJohn Marino } 766*6cdfca03SJohn Marino if (remote) { 767*6cdfca03SJohn Marino if (command("%s %s", cmd, remote) != PRELIM) 768*6cdfca03SJohn Marino goto cleanupsend; 769*6cdfca03SJohn Marino } else { 770*6cdfca03SJohn Marino if (command("%s", cmd) != PRELIM) 771*6cdfca03SJohn Marino goto cleanupsend; 772*6cdfca03SJohn Marino } 773*6cdfca03SJohn Marino dirchange = 1; 774*6cdfca03SJohn Marino dout = dataconn(lmode); 775*6cdfca03SJohn Marino if (dout == NULL) 776*6cdfca03SJohn Marino goto abort; 777*6cdfca03SJohn Marino 778*6cdfca03SJohn Marino assert(sndbuf_size > 0); 779*6cdfca03SJohn Marino if ((size_t)sndbuf_size > bufsize) { 780*6cdfca03SJohn Marino if (buf) 781*6cdfca03SJohn Marino (void)free(buf); 782*6cdfca03SJohn Marino bufsize = sndbuf_size; 783*6cdfca03SJohn Marino buf = ftp_malloc(bufsize); 784*6cdfca03SJohn Marino } 785*6cdfca03SJohn Marino 786*6cdfca03SJohn Marino progressmeter(-1); 787*6cdfca03SJohn Marino oldintp = xsignal(SIGPIPE, SIG_IGN); 788*6cdfca03SJohn Marino hash_interval = (hash && (!progress || filesize < 0)) ? mark : 0; 789*6cdfca03SJohn Marino 790*6cdfca03SJohn Marino switch (curtype) { 791*6cdfca03SJohn Marino 792*6cdfca03SJohn Marino case TYPE_I: 793*6cdfca03SJohn Marino case TYPE_L: 794*6cdfca03SJohn Marino c = copy_bytes(fileno(fin), fileno(dout), buf, bufsize, 795*6cdfca03SJohn Marino rate_put, hash_interval); 796*6cdfca03SJohn Marino if (c == 1) { 797*6cdfca03SJohn Marino warn("Reading `%s'", local); 798*6cdfca03SJohn Marino } else if (c == 2) { 799*6cdfca03SJohn Marino if (errno != EPIPE) 800*6cdfca03SJohn Marino warn("Writing to network"); 801*6cdfca03SJohn Marino bytes = -1; 802*6cdfca03SJohn Marino } 803*6cdfca03SJohn Marino break; 804*6cdfca03SJohn Marino 805*6cdfca03SJohn Marino case TYPE_A: 806*6cdfca03SJohn Marino while ((c = getc(fin)) != EOF) { 807*6cdfca03SJohn Marino if (c == '\n') { 808*6cdfca03SJohn Marino while (hash_interval && bytes >= hashbytes) { 809*6cdfca03SJohn Marino (void)putc('#', ttyout); 810*6cdfca03SJohn Marino (void)fflush(ttyout); 811*6cdfca03SJohn Marino hashbytes += mark; 812*6cdfca03SJohn Marino } 813*6cdfca03SJohn Marino if (ferror(dout)) 814*6cdfca03SJohn Marino break; 815*6cdfca03SJohn Marino (void)putc('\r', dout); 816*6cdfca03SJohn Marino bytes++; 817*6cdfca03SJohn Marino } 818*6cdfca03SJohn Marino (void)putc(c, dout); 819*6cdfca03SJohn Marino bytes++; 820*6cdfca03SJohn Marino #if 0 /* this violates RFC 959 */ 821*6cdfca03SJohn Marino if (c == '\r') { 822*6cdfca03SJohn Marino (void)putc('\0', dout); 823*6cdfca03SJohn Marino bytes++; 824*6cdfca03SJohn Marino } 825*6cdfca03SJohn Marino #endif 826*6cdfca03SJohn Marino } 827*6cdfca03SJohn Marino if (hash_interval) { 828*6cdfca03SJohn Marino if (bytes < hashbytes) 829*6cdfca03SJohn Marino (void)putc('#', ttyout); 830*6cdfca03SJohn Marino (void)putc('\n', ttyout); 831*6cdfca03SJohn Marino } 832*6cdfca03SJohn Marino if (ferror(fin)) 833*6cdfca03SJohn Marino warn("Reading `%s'", local); 834*6cdfca03SJohn Marino if (ferror(dout)) { 835*6cdfca03SJohn Marino if (errno != EPIPE) 836*6cdfca03SJohn Marino warn("Writing to network"); 837*6cdfca03SJohn Marino bytes = -1; 838*6cdfca03SJohn Marino } 839*6cdfca03SJohn Marino break; 840*6cdfca03SJohn Marino } 841*6cdfca03SJohn Marino 842*6cdfca03SJohn Marino progressmeter(1); 843*6cdfca03SJohn Marino if (closefunc != NULL) { 844*6cdfca03SJohn Marino (*closefunc)(fin); 845*6cdfca03SJohn Marino fin = NULL; 846*6cdfca03SJohn Marino } 847*6cdfca03SJohn Marino (void)fclose(dout); 848*6cdfca03SJohn Marino dout = NULL; 849*6cdfca03SJohn Marino (void)getreply(0); 850*6cdfca03SJohn Marino if (bytes > 0) 851*6cdfca03SJohn Marino ptransfer(0); 852*6cdfca03SJohn Marino goto cleanupsend; 853*6cdfca03SJohn Marino 854*6cdfca03SJohn Marino abort: 855*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr); 856*6cdfca03SJohn Marino oldintr = NULL; 857*6cdfca03SJohn Marino if (!cpend) { 858*6cdfca03SJohn Marino code = -1; 859*6cdfca03SJohn Marino goto cleanupsend; 860*6cdfca03SJohn Marino } 861*6cdfca03SJohn Marino if (data >= 0) { 862*6cdfca03SJohn Marino (void)close(data); 863*6cdfca03SJohn Marino data = -1; 864*6cdfca03SJohn Marino } 865*6cdfca03SJohn Marino if (dout) { 866*6cdfca03SJohn Marino (void)fclose(dout); 867*6cdfca03SJohn Marino dout = NULL; 868*6cdfca03SJohn Marino } 869*6cdfca03SJohn Marino (void)getreply(0); 870*6cdfca03SJohn Marino code = -1; 871*6cdfca03SJohn Marino if (bytes > 0) 872*6cdfca03SJohn Marino ptransfer(0); 873*6cdfca03SJohn Marino 874*6cdfca03SJohn Marino cleanupsend: 875*6cdfca03SJohn Marino if (oldintr) 876*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr); 877*6cdfca03SJohn Marino if (oldintp) 878*6cdfca03SJohn Marino (void)xsignal(SIGPIPE, oldintp); 879*6cdfca03SJohn Marino if (data >= 0) { 880*6cdfca03SJohn Marino (void)close(data); 881*6cdfca03SJohn Marino data = -1; 882*6cdfca03SJohn Marino } 883*6cdfca03SJohn Marino if (closefunc != NULL && fin != NULL) 884*6cdfca03SJohn Marino (*closefunc)(fin); 885*6cdfca03SJohn Marino if (dout) 886*6cdfca03SJohn Marino (void)fclose(dout); 887*6cdfca03SJohn Marino progress = oprogress; 888*6cdfca03SJohn Marino restart_point = 0; 889*6cdfca03SJohn Marino bytes = 0; 890*6cdfca03SJohn Marino } 891*6cdfca03SJohn Marino 892*6cdfca03SJohn Marino void 893*6cdfca03SJohn Marino recvrequest(const char *cmd, const char *volatile local, const char *remote, 894*6cdfca03SJohn Marino const char *lmode, int printnames, int ignorespecial) 895*6cdfca03SJohn Marino { 896*6cdfca03SJohn Marino FILE *volatile fout; 897*6cdfca03SJohn Marino FILE *volatile din; 898*6cdfca03SJohn Marino int (*volatile closefunc)(FILE *); 899*6cdfca03SJohn Marino sigfunc volatile oldintr; 900*6cdfca03SJohn Marino sigfunc volatile oldintp; 901*6cdfca03SJohn Marino int c, d; 902*6cdfca03SJohn Marino int volatile is_retr; 903*6cdfca03SJohn Marino int volatile tcrflag; 904*6cdfca03SJohn Marino int volatile bare_lfs; 905*6cdfca03SJohn Marino static size_t bufsize; 906*6cdfca03SJohn Marino static char *buf; 907*6cdfca03SJohn Marino off_t volatile hashbytes; 908*6cdfca03SJohn Marino int hash_interval; 909*6cdfca03SJohn Marino struct stat st; 910*6cdfca03SJohn Marino time_t mtime; 911*6cdfca03SJohn Marino struct timeval tval[2]; 912*6cdfca03SJohn Marino int oprogress; 913*6cdfca03SJohn Marino int opreserve; 914*6cdfca03SJohn Marino 915*6cdfca03SJohn Marino fout = NULL; 916*6cdfca03SJohn Marino din = NULL; 917*6cdfca03SJohn Marino hashbytes = mark; 918*6cdfca03SJohn Marino direction = "received"; 919*6cdfca03SJohn Marino bytes = 0; 920*6cdfca03SJohn Marino bare_lfs = 0; 921*6cdfca03SJohn Marino filesize = -1; 922*6cdfca03SJohn Marino oprogress = progress; 923*6cdfca03SJohn Marino opreserve = preserve; 924*6cdfca03SJohn Marino is_retr = (strcmp(cmd, "RETR") == 0); 925*6cdfca03SJohn Marino if (is_retr && verbose && printnames) { 926*6cdfca03SJohn Marino if (ignorespecial || *local != '-') 927*6cdfca03SJohn Marino fprintf(ttyout, "local: %s ", local); 928*6cdfca03SJohn Marino if (remote) 929*6cdfca03SJohn Marino fprintf(ttyout, "remote: %s\n", remote); 930*6cdfca03SJohn Marino } 931*6cdfca03SJohn Marino if (proxy && is_retr) { 932*6cdfca03SJohn Marino proxtrans(cmd, local, remote); 933*6cdfca03SJohn Marino return; 934*6cdfca03SJohn Marino } 935*6cdfca03SJohn Marino closefunc = NULL; 936*6cdfca03SJohn Marino oldintr = NULL; 937*6cdfca03SJohn Marino oldintp = NULL; 938*6cdfca03SJohn Marino tcrflag = !crflag && is_retr; 939*6cdfca03SJohn Marino if (sigsetjmp(xferabort, 1)) { 940*6cdfca03SJohn Marino while (cpend) 941*6cdfca03SJohn Marino (void)getreply(0); 942*6cdfca03SJohn Marino code = -1; 943*6cdfca03SJohn Marino goto cleanuprecv; 944*6cdfca03SJohn Marino } 945*6cdfca03SJohn Marino (void)xsignal(SIGQUIT, psummary); 946*6cdfca03SJohn Marino oldintr = xsignal(SIGINT, abortxfer); 947*6cdfca03SJohn Marino if (ignorespecial || (strcmp(local, "-") && *local != '|')) { 948*6cdfca03SJohn Marino if (access(local, W_OK) < 0) { 949*6cdfca03SJohn Marino char *dir = strrchr(local, '/'); 950*6cdfca03SJohn Marino 951*6cdfca03SJohn Marino if (errno != ENOENT && errno != EACCES) { 952*6cdfca03SJohn Marino warn("Can't access `%s'", local); 953*6cdfca03SJohn Marino code = -1; 954*6cdfca03SJohn Marino goto cleanuprecv; 955*6cdfca03SJohn Marino } 956*6cdfca03SJohn Marino if (dir != NULL) 957*6cdfca03SJohn Marino *dir = 0; 958*6cdfca03SJohn Marino d = access(dir == local ? "/" : 959*6cdfca03SJohn Marino dir ? local : ".", W_OK); 960*6cdfca03SJohn Marino if (dir != NULL) 961*6cdfca03SJohn Marino *dir = '/'; 962*6cdfca03SJohn Marino if (d < 0) { 963*6cdfca03SJohn Marino warn("Can't access `%s'", local); 964*6cdfca03SJohn Marino code = -1; 965*6cdfca03SJohn Marino goto cleanuprecv; 966*6cdfca03SJohn Marino } 967*6cdfca03SJohn Marino if (!runique && errno == EACCES && 968*6cdfca03SJohn Marino chmod(local, (S_IRUSR|S_IWUSR)) < 0) { 969*6cdfca03SJohn Marino warn("Can't chmod `%s'", local); 970*6cdfca03SJohn Marino code = -1; 971*6cdfca03SJohn Marino goto cleanuprecv; 972*6cdfca03SJohn Marino } 973*6cdfca03SJohn Marino if (runique && errno == EACCES && 974*6cdfca03SJohn Marino (local = gunique(local)) == NULL) { 975*6cdfca03SJohn Marino code = -1; 976*6cdfca03SJohn Marino goto cleanuprecv; 977*6cdfca03SJohn Marino } 978*6cdfca03SJohn Marino } 979*6cdfca03SJohn Marino else if (runique && (local = gunique(local)) == NULL) { 980*6cdfca03SJohn Marino code = -1; 981*6cdfca03SJohn Marino goto cleanuprecv; 982*6cdfca03SJohn Marino } 983*6cdfca03SJohn Marino } 984*6cdfca03SJohn Marino if (!is_retr) { 985*6cdfca03SJohn Marino if (curtype != TYPE_A) 986*6cdfca03SJohn Marino changetype(TYPE_A, 0); 987*6cdfca03SJohn Marino } else { 988*6cdfca03SJohn Marino if (curtype != type) 989*6cdfca03SJohn Marino changetype(type, 0); 990*6cdfca03SJohn Marino filesize = remotesize(remote, 0); 991*6cdfca03SJohn Marino if (code == 421 || code == -1) 992*6cdfca03SJohn Marino goto cleanuprecv; 993*6cdfca03SJohn Marino } 994*6cdfca03SJohn Marino if (initconn()) { 995*6cdfca03SJohn Marino code = -1; 996*6cdfca03SJohn Marino goto cleanuprecv; 997*6cdfca03SJohn Marino } 998*6cdfca03SJohn Marino if (sigsetjmp(xferabort, 1)) 999*6cdfca03SJohn Marino goto abort; 1000*6cdfca03SJohn Marino if (is_retr && restart_point && 1001*6cdfca03SJohn Marino command("REST " LLF, (LLT) restart_point) != CONTINUE) 1002*6cdfca03SJohn Marino goto cleanuprecv; 1003*6cdfca03SJohn Marino if (! EMPTYSTRING(remote)) { 1004*6cdfca03SJohn Marino if (command("%s %s", cmd, remote) != PRELIM) 1005*6cdfca03SJohn Marino goto cleanuprecv; 1006*6cdfca03SJohn Marino } else { 1007*6cdfca03SJohn Marino if (command("%s", cmd) != PRELIM) 1008*6cdfca03SJohn Marino goto cleanuprecv; 1009*6cdfca03SJohn Marino } 1010*6cdfca03SJohn Marino din = dataconn("r"); 1011*6cdfca03SJohn Marino if (din == NULL) 1012*6cdfca03SJohn Marino goto abort; 1013*6cdfca03SJohn Marino if (!ignorespecial && strcmp(local, "-") == 0) { 1014*6cdfca03SJohn Marino fout = stdout; 1015*6cdfca03SJohn Marino progress = 0; 1016*6cdfca03SJohn Marino preserve = 0; 1017*6cdfca03SJohn Marino } else if (!ignorespecial && *local == '|') { 1018*6cdfca03SJohn Marino oldintp = xsignal(SIGPIPE, SIG_IGN); 1019*6cdfca03SJohn Marino fout = popen(local + 1, "w"); 1020*6cdfca03SJohn Marino if (fout == NULL) { 1021*6cdfca03SJohn Marino warn("Can't execute `%s'", local+1); 1022*6cdfca03SJohn Marino goto abort; 1023*6cdfca03SJohn Marino } 1024*6cdfca03SJohn Marino progress = 0; 1025*6cdfca03SJohn Marino preserve = 0; 1026*6cdfca03SJohn Marino closefunc = pclose; 1027*6cdfca03SJohn Marino } else { 1028*6cdfca03SJohn Marino fout = fopen(local, lmode); 1029*6cdfca03SJohn Marino if (fout == NULL) { 1030*6cdfca03SJohn Marino warn("Can't open `%s'", local); 1031*6cdfca03SJohn Marino goto abort; 1032*6cdfca03SJohn Marino } 1033*6cdfca03SJohn Marino closefunc = fclose; 1034*6cdfca03SJohn Marino } 1035*6cdfca03SJohn Marino 1036*6cdfca03SJohn Marino if (fstat(fileno(fout), &st) != -1 && !S_ISREG(st.st_mode)) { 1037*6cdfca03SJohn Marino progress = 0; 1038*6cdfca03SJohn Marino preserve = 0; 1039*6cdfca03SJohn Marino } 1040*6cdfca03SJohn Marino assert(rcvbuf_size > 0); 1041*6cdfca03SJohn Marino if ((size_t)rcvbuf_size > bufsize) { 1042*6cdfca03SJohn Marino if (buf) 1043*6cdfca03SJohn Marino (void)free(buf); 1044*6cdfca03SJohn Marino bufsize = rcvbuf_size; 1045*6cdfca03SJohn Marino buf = ftp_malloc(bufsize); 1046*6cdfca03SJohn Marino } 1047*6cdfca03SJohn Marino 1048*6cdfca03SJohn Marino progressmeter(-1); 1049*6cdfca03SJohn Marino hash_interval = (hash && (!progress || filesize < 0)) ? mark : 0; 1050*6cdfca03SJohn Marino 1051*6cdfca03SJohn Marino switch (curtype) { 1052*6cdfca03SJohn Marino 1053*6cdfca03SJohn Marino case TYPE_I: 1054*6cdfca03SJohn Marino case TYPE_L: 1055*6cdfca03SJohn Marino if (is_retr && restart_point && 1056*6cdfca03SJohn Marino lseek(fileno(fout), restart_point, SEEK_SET) < 0) { 1057*6cdfca03SJohn Marino warn("Can't seek to restart `%s'", local); 1058*6cdfca03SJohn Marino goto cleanuprecv; 1059*6cdfca03SJohn Marino } 1060*6cdfca03SJohn Marino c = copy_bytes(fileno(din), fileno(fout), buf, bufsize, 1061*6cdfca03SJohn Marino rate_get, hash_interval); 1062*6cdfca03SJohn Marino if (c == 1) { 1063*6cdfca03SJohn Marino if (errno != EPIPE) 1064*6cdfca03SJohn Marino warn("Reading from network"); 1065*6cdfca03SJohn Marino bytes = -1; 1066*6cdfca03SJohn Marino } else if (c == 2) { 1067*6cdfca03SJohn Marino warn("Writing `%s'", local); 1068*6cdfca03SJohn Marino } 1069*6cdfca03SJohn Marino break; 1070*6cdfca03SJohn Marino 1071*6cdfca03SJohn Marino case TYPE_A: 1072*6cdfca03SJohn Marino if (is_retr && restart_point) { 1073*6cdfca03SJohn Marino int ch; 1074*6cdfca03SJohn Marino off_t i; 1075*6cdfca03SJohn Marino 1076*6cdfca03SJohn Marino if (fseeko(fout, (off_t)0, SEEK_SET) < 0) 1077*6cdfca03SJohn Marino goto done; 1078*6cdfca03SJohn Marino for (i = 0; i++ < restart_point;) { 1079*6cdfca03SJohn Marino if ((ch = getc(fout)) == EOF) 1080*6cdfca03SJohn Marino goto done; 1081*6cdfca03SJohn Marino if (ch == '\n') 1082*6cdfca03SJohn Marino i++; 1083*6cdfca03SJohn Marino } 1084*6cdfca03SJohn Marino if (fseeko(fout, (off_t)0, SEEK_CUR) < 0) { 1085*6cdfca03SJohn Marino done: 1086*6cdfca03SJohn Marino warn("Can't seek to restart `%s'", local); 1087*6cdfca03SJohn Marino goto cleanuprecv; 1088*6cdfca03SJohn Marino } 1089*6cdfca03SJohn Marino } 1090*6cdfca03SJohn Marino while ((c = getc(din)) != EOF) { 1091*6cdfca03SJohn Marino if (c == '\n') 1092*6cdfca03SJohn Marino bare_lfs++; 1093*6cdfca03SJohn Marino while (c == '\r') { 1094*6cdfca03SJohn Marino while (hash_interval && bytes >= hashbytes) { 1095*6cdfca03SJohn Marino (void)putc('#', ttyout); 1096*6cdfca03SJohn Marino (void)fflush(ttyout); 1097*6cdfca03SJohn Marino hashbytes += mark; 1098*6cdfca03SJohn Marino } 1099*6cdfca03SJohn Marino bytes++; 1100*6cdfca03SJohn Marino if ((c = getc(din)) != '\n' || tcrflag) { 1101*6cdfca03SJohn Marino if (ferror(fout)) 1102*6cdfca03SJohn Marino goto break2; 1103*6cdfca03SJohn Marino (void)putc('\r', fout); 1104*6cdfca03SJohn Marino if (c == '\0') { 1105*6cdfca03SJohn Marino bytes++; 1106*6cdfca03SJohn Marino goto contin2; 1107*6cdfca03SJohn Marino } 1108*6cdfca03SJohn Marino if (c == EOF) 1109*6cdfca03SJohn Marino goto contin2; 1110*6cdfca03SJohn Marino } 1111*6cdfca03SJohn Marino } 1112*6cdfca03SJohn Marino (void)putc(c, fout); 1113*6cdfca03SJohn Marino bytes++; 1114*6cdfca03SJohn Marino contin2: ; 1115*6cdfca03SJohn Marino } 1116*6cdfca03SJohn Marino break2: 1117*6cdfca03SJohn Marino if (hash_interval) { 1118*6cdfca03SJohn Marino if (bytes < hashbytes) 1119*6cdfca03SJohn Marino (void)putc('#', ttyout); 1120*6cdfca03SJohn Marino (void)putc('\n', ttyout); 1121*6cdfca03SJohn Marino } 1122*6cdfca03SJohn Marino if (ferror(din)) { 1123*6cdfca03SJohn Marino if (errno != EPIPE) 1124*6cdfca03SJohn Marino warn("Reading from network"); 1125*6cdfca03SJohn Marino bytes = -1; 1126*6cdfca03SJohn Marino } 1127*6cdfca03SJohn Marino if (ferror(fout)) 1128*6cdfca03SJohn Marino warn("Writing `%s'", local); 1129*6cdfca03SJohn Marino break; 1130*6cdfca03SJohn Marino } 1131*6cdfca03SJohn Marino 1132*6cdfca03SJohn Marino progressmeter(1); 1133*6cdfca03SJohn Marino if (closefunc != NULL) { 1134*6cdfca03SJohn Marino (*closefunc)(fout); 1135*6cdfca03SJohn Marino fout = NULL; 1136*6cdfca03SJohn Marino } 1137*6cdfca03SJohn Marino (void)fclose(din); 1138*6cdfca03SJohn Marino din = NULL; 1139*6cdfca03SJohn Marino (void)getreply(0); 1140*6cdfca03SJohn Marino if (bare_lfs) { 1141*6cdfca03SJohn Marino fprintf(ttyout, 1142*6cdfca03SJohn Marino "WARNING! %d bare linefeeds received in ASCII mode.\n", 1143*6cdfca03SJohn Marino bare_lfs); 1144*6cdfca03SJohn Marino fputs("File may not have transferred correctly.\n", ttyout); 1145*6cdfca03SJohn Marino } 1146*6cdfca03SJohn Marino if (bytes >= 0 && is_retr) { 1147*6cdfca03SJohn Marino if (bytes > 0) 1148*6cdfca03SJohn Marino ptransfer(0); 1149*6cdfca03SJohn Marino if (preserve && (closefunc == fclose)) { 1150*6cdfca03SJohn Marino mtime = remotemodtime(remote, 0); 1151*6cdfca03SJohn Marino if (mtime != -1) { 1152*6cdfca03SJohn Marino (void)gettimeofday(&tval[0], NULL); 1153*6cdfca03SJohn Marino tval[1].tv_sec = mtime; 1154*6cdfca03SJohn Marino tval[1].tv_usec = 0; 1155*6cdfca03SJohn Marino if (utimes(local, tval) == -1) { 1156*6cdfca03SJohn Marino fprintf(ttyout, 1157*6cdfca03SJohn Marino "Can't change modification time on %s to %s", 1158*6cdfca03SJohn Marino local, 1159*6cdfca03SJohn Marino rfc2822time(localtime(&mtime))); 1160*6cdfca03SJohn Marino } 1161*6cdfca03SJohn Marino } 1162*6cdfca03SJohn Marino } 1163*6cdfca03SJohn Marino } 1164*6cdfca03SJohn Marino goto cleanuprecv; 1165*6cdfca03SJohn Marino 1166*6cdfca03SJohn Marino abort: 1167*6cdfca03SJohn Marino /* 1168*6cdfca03SJohn Marino * abort using RFC 959 recommended IP,SYNC sequence 1169*6cdfca03SJohn Marino */ 1170*6cdfca03SJohn Marino if (! sigsetjmp(xferabort, 1)) { 1171*6cdfca03SJohn Marino /* this is the first call */ 1172*6cdfca03SJohn Marino (void)xsignal(SIGINT, abort_squared); 1173*6cdfca03SJohn Marino if (!cpend) { 1174*6cdfca03SJohn Marino code = -1; 1175*6cdfca03SJohn Marino goto cleanuprecv; 1176*6cdfca03SJohn Marino } 1177*6cdfca03SJohn Marino abort_remote(din); 1178*6cdfca03SJohn Marino } 1179*6cdfca03SJohn Marino code = -1; 1180*6cdfca03SJohn Marino if (bytes > 0) 1181*6cdfca03SJohn Marino ptransfer(0); 1182*6cdfca03SJohn Marino 1183*6cdfca03SJohn Marino cleanuprecv: 1184*6cdfca03SJohn Marino if (oldintr) 1185*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr); 1186*6cdfca03SJohn Marino if (oldintp) 1187*6cdfca03SJohn Marino (void)xsignal(SIGPIPE, oldintp); 1188*6cdfca03SJohn Marino if (data >= 0) { 1189*6cdfca03SJohn Marino (void)close(data); 1190*6cdfca03SJohn Marino data = -1; 1191*6cdfca03SJohn Marino } 1192*6cdfca03SJohn Marino if (closefunc != NULL && fout != NULL) 1193*6cdfca03SJohn Marino (*closefunc)(fout); 1194*6cdfca03SJohn Marino if (din) 1195*6cdfca03SJohn Marino (void)fclose(din); 1196*6cdfca03SJohn Marino progress = oprogress; 1197*6cdfca03SJohn Marino preserve = opreserve; 1198*6cdfca03SJohn Marino bytes = 0; 1199*6cdfca03SJohn Marino } 1200*6cdfca03SJohn Marino 1201*6cdfca03SJohn Marino /* 1202*6cdfca03SJohn Marino * Need to start a listen on the data channel before we send the command, 1203*6cdfca03SJohn Marino * otherwise the server's connect may fail. 1204*6cdfca03SJohn Marino */ 1205*6cdfca03SJohn Marino int 1206*6cdfca03SJohn Marino initconn(void) 1207*6cdfca03SJohn Marino { 1208*6cdfca03SJohn Marino char *p, *a; 1209*6cdfca03SJohn Marino int result, tmpno = 0; 1210*6cdfca03SJohn Marino int on = 1; 1211*6cdfca03SJohn Marino int error; 1212*6cdfca03SJohn Marino unsigned int addr[16], port[2]; 1213*6cdfca03SJohn Marino unsigned int af, hal, pal; 1214*6cdfca03SJohn Marino socklen_t len; 1215*6cdfca03SJohn Marino const char *pasvcmd = NULL; 1216*6cdfca03SJohn Marino int overbose; 1217*6cdfca03SJohn Marino 1218*6cdfca03SJohn Marino #ifdef INET6 1219*6cdfca03SJohn Marino #ifndef NO_DEBUG 1220*6cdfca03SJohn Marino if (myctladdr.su_family == AF_INET6 && ftp_debug && 1221*6cdfca03SJohn Marino (IN6_IS_ADDR_LINKLOCAL(&myctladdr.si_su.su_sin6.sin6_addr) || 1222*6cdfca03SJohn Marino IN6_IS_ADDR_SITELOCAL(&myctladdr.si_su.su_sin6.sin6_addr))) { 1223*6cdfca03SJohn Marino warnx("Use of scoped addresses can be troublesome"); 1224*6cdfca03SJohn Marino } 1225*6cdfca03SJohn Marino #endif 1226*6cdfca03SJohn Marino #endif 1227*6cdfca03SJohn Marino 1228*6cdfca03SJohn Marino reinit: 1229*6cdfca03SJohn Marino if (passivemode) { 1230*6cdfca03SJohn Marino data_addr = myctladdr; 1231*6cdfca03SJohn Marino data = socket(data_addr.su_family, SOCK_STREAM, 0); 1232*6cdfca03SJohn Marino if (data < 0) { 1233*6cdfca03SJohn Marino warn("Can't create socket for data connection"); 1234*6cdfca03SJohn Marino return (1); 1235*6cdfca03SJohn Marino } 1236*6cdfca03SJohn Marino if ((options & SO_DEBUG) && 1237*6cdfca03SJohn Marino setsockopt(data, SOL_SOCKET, SO_DEBUG, 1238*6cdfca03SJohn Marino (void *)&on, sizeof(on)) == -1) { 1239*6cdfca03SJohn Marino DWARN("setsockopt %s (ignored)", "SO_DEBUG"); 1240*6cdfca03SJohn Marino } 1241*6cdfca03SJohn Marino result = COMPLETE + 1; 1242*6cdfca03SJohn Marino switch (data_addr.su_family) { 1243*6cdfca03SJohn Marino case AF_INET: 1244*6cdfca03SJohn Marino if (epsv4 && !epsv4bad) { 1245*6cdfca03SJohn Marino pasvcmd = "EPSV"; 1246*6cdfca03SJohn Marino overbose = verbose; 1247*6cdfca03SJohn Marino if (ftp_debug == 0) 1248*6cdfca03SJohn Marino verbose = -1; 1249*6cdfca03SJohn Marino result = command("EPSV"); 1250*6cdfca03SJohn Marino verbose = overbose; 1251*6cdfca03SJohn Marino if (verbose > 0 && 1252*6cdfca03SJohn Marino (result == COMPLETE || !connected)) 1253*6cdfca03SJohn Marino fprintf(ttyout, "%s\n", reply_string); 1254*6cdfca03SJohn Marino if (!connected) 1255*6cdfca03SJohn Marino return (1); 1256*6cdfca03SJohn Marino /* 1257*6cdfca03SJohn Marino * this code is to be friendly with broken 1258*6cdfca03SJohn Marino * BSDI ftpd 1259*6cdfca03SJohn Marino */ 1260*6cdfca03SJohn Marino if (code / 10 == 22 && code != 229) { 1261*6cdfca03SJohn Marino fputs( 1262*6cdfca03SJohn Marino "wrong server: return code must be 229\n", 1263*6cdfca03SJohn Marino ttyout); 1264*6cdfca03SJohn Marino result = COMPLETE + 1; 1265*6cdfca03SJohn Marino } 1266*6cdfca03SJohn Marino if (result != COMPLETE) { 1267*6cdfca03SJohn Marino epsv4bad = 1; 1268*6cdfca03SJohn Marino DPRINTF("disabling epsv4 for this " 1269*6cdfca03SJohn Marino "connection\n"); 1270*6cdfca03SJohn Marino } 1271*6cdfca03SJohn Marino } 1272*6cdfca03SJohn Marino if (result != COMPLETE) { 1273*6cdfca03SJohn Marino pasvcmd = "PASV"; 1274*6cdfca03SJohn Marino result = command("PASV"); 1275*6cdfca03SJohn Marino if (!connected) 1276*6cdfca03SJohn Marino return (1); 1277*6cdfca03SJohn Marino } 1278*6cdfca03SJohn Marino break; 1279*6cdfca03SJohn Marino #ifdef INET6 1280*6cdfca03SJohn Marino case AF_INET6: 1281*6cdfca03SJohn Marino if (epsv6 && !epsv6bad) { 1282*6cdfca03SJohn Marino pasvcmd = "EPSV"; 1283*6cdfca03SJohn Marino overbose = verbose; 1284*6cdfca03SJohn Marino if (ftp_debug == 0) 1285*6cdfca03SJohn Marino verbose = -1; 1286*6cdfca03SJohn Marino result = command("EPSV"); 1287*6cdfca03SJohn Marino verbose = overbose; 1288*6cdfca03SJohn Marino if (verbose > 0 && 1289*6cdfca03SJohn Marino (result == COMPLETE || !connected)) 1290*6cdfca03SJohn Marino fprintf(ttyout, "%s\n", reply_string); 1291*6cdfca03SJohn Marino if (!connected) 1292*6cdfca03SJohn Marino return (1); 1293*6cdfca03SJohn Marino /* 1294*6cdfca03SJohn Marino * this code is to be friendly with 1295*6cdfca03SJohn Marino * broken BSDI ftpd 1296*6cdfca03SJohn Marino */ 1297*6cdfca03SJohn Marino if (code / 10 == 22 && code != 229) { 1298*6cdfca03SJohn Marino fputs( 1299*6cdfca03SJohn Marino "wrong server: return code must be 229\n", 1300*6cdfca03SJohn Marino ttyout); 1301*6cdfca03SJohn Marino result = COMPLETE + 1; 1302*6cdfca03SJohn Marino } 1303*6cdfca03SJohn Marino if (result != COMPLETE) { 1304*6cdfca03SJohn Marino epsv6bad = 1; 1305*6cdfca03SJohn Marino DPRINTF("disabling epsv6 for this " 1306*6cdfca03SJohn Marino "connection\n"); 1307*6cdfca03SJohn Marino } 1308*6cdfca03SJohn Marino } 1309*6cdfca03SJohn Marino if (result != COMPLETE) { 1310*6cdfca03SJohn Marino pasvcmd = "LPSV"; 1311*6cdfca03SJohn Marino result = command("LPSV"); 1312*6cdfca03SJohn Marino } 1313*6cdfca03SJohn Marino if (!connected) 1314*6cdfca03SJohn Marino return (1); 1315*6cdfca03SJohn Marino break; 1316*6cdfca03SJohn Marino #endif 1317*6cdfca03SJohn Marino default: 1318*6cdfca03SJohn Marino result = COMPLETE + 1; 1319*6cdfca03SJohn Marino break; 1320*6cdfca03SJohn Marino } 1321*6cdfca03SJohn Marino if (result != COMPLETE) { 1322*6cdfca03SJohn Marino if (activefallback) { 1323*6cdfca03SJohn Marino (void)close(data); 1324*6cdfca03SJohn Marino data = -1; 1325*6cdfca03SJohn Marino passivemode = 0; 1326*6cdfca03SJohn Marino #if 0 1327*6cdfca03SJohn Marino activefallback = 0; 1328*6cdfca03SJohn Marino #endif 1329*6cdfca03SJohn Marino goto reinit; 1330*6cdfca03SJohn Marino } 1331*6cdfca03SJohn Marino fputs("Passive mode refused.\n", ttyout); 1332*6cdfca03SJohn Marino goto bad; 1333*6cdfca03SJohn Marino } 1334*6cdfca03SJohn Marino 1335*6cdfca03SJohn Marino #define pack2(var, off) \ 1336*6cdfca03SJohn Marino (((var[(off) + 0] & 0xff) << 8) | ((var[(off) + 1] & 0xff) << 0)) 1337*6cdfca03SJohn Marino #define pack4(var, off) \ 1338*6cdfca03SJohn Marino (((var[(off) + 0] & 0xff) << 24) | ((var[(off) + 1] & 0xff) << 16) | \ 1339*6cdfca03SJohn Marino ((var[(off) + 2] & 0xff) << 8) | ((var[(off) + 3] & 0xff) << 0)) 1340*6cdfca03SJohn Marino #define UC(b) (((int)b)&0xff) 1341*6cdfca03SJohn Marino 1342*6cdfca03SJohn Marino /* 1343*6cdfca03SJohn Marino * What we've got at this point is a string of comma separated 1344*6cdfca03SJohn Marino * one-byte unsigned integer values, separated by commas. 1345*6cdfca03SJohn Marino */ 1346*6cdfca03SJohn Marino if (strcmp(pasvcmd, "PASV") == 0) { 1347*6cdfca03SJohn Marino if (data_addr.su_family != AF_INET) { 1348*6cdfca03SJohn Marino fputs( 1349*6cdfca03SJohn Marino "Passive mode AF mismatch. Shouldn't happen!\n", ttyout); 1350*6cdfca03SJohn Marino error = 1; 1351*6cdfca03SJohn Marino goto bad; 1352*6cdfca03SJohn Marino } 1353*6cdfca03SJohn Marino if (code / 10 == 22 && code != 227) { 1354*6cdfca03SJohn Marino fputs("wrong server: return code must be 227\n", 1355*6cdfca03SJohn Marino ttyout); 1356*6cdfca03SJohn Marino error = 1; 1357*6cdfca03SJohn Marino goto bad; 1358*6cdfca03SJohn Marino } 1359*6cdfca03SJohn Marino error = sscanf(pasv, "%u,%u,%u,%u,%u,%u", 1360*6cdfca03SJohn Marino &addr[0], &addr[1], &addr[2], &addr[3], 1361*6cdfca03SJohn Marino &port[0], &port[1]); 1362*6cdfca03SJohn Marino if (error != 6) { 1363*6cdfca03SJohn Marino fputs( 1364*6cdfca03SJohn Marino "Passive mode address scan failure. Shouldn't happen!\n", ttyout); 1365*6cdfca03SJohn Marino error = 1; 1366*6cdfca03SJohn Marino goto bad; 1367*6cdfca03SJohn Marino } 1368*6cdfca03SJohn Marino error = 0; 1369*6cdfca03SJohn Marino memset(&data_addr, 0, sizeof(data_addr)); 1370*6cdfca03SJohn Marino data_addr.su_family = AF_INET; 1371*6cdfca03SJohn Marino data_addr.su_len = sizeof(struct sockaddr_in); 1372*6cdfca03SJohn Marino data_addr.si_su.su_sin.sin_addr.s_addr = 1373*6cdfca03SJohn Marino htonl(pack4(addr, 0)); 1374*6cdfca03SJohn Marino data_addr.su_port = htons(pack2(port, 0)); 1375*6cdfca03SJohn Marino } else if (strcmp(pasvcmd, "LPSV") == 0) { 1376*6cdfca03SJohn Marino if (code / 10 == 22 && code != 228) { 1377*6cdfca03SJohn Marino fputs("wrong server: return code must be 228\n", 1378*6cdfca03SJohn Marino ttyout); 1379*6cdfca03SJohn Marino error = 1; 1380*6cdfca03SJohn Marino goto bad; 1381*6cdfca03SJohn Marino } 1382*6cdfca03SJohn Marino switch (data_addr.su_family) { 1383*6cdfca03SJohn Marino case AF_INET: 1384*6cdfca03SJohn Marino error = sscanf(pasv, 1385*6cdfca03SJohn Marino "%u,%u,%u,%u,%u,%u,%u,%u,%u", 1386*6cdfca03SJohn Marino &af, &hal, 1387*6cdfca03SJohn Marino &addr[0], &addr[1], &addr[2], &addr[3], 1388*6cdfca03SJohn Marino &pal, &port[0], &port[1]); 1389*6cdfca03SJohn Marino if (error != 9) { 1390*6cdfca03SJohn Marino fputs( 1391*6cdfca03SJohn Marino "Passive mode address scan failure. Shouldn't happen!\n", ttyout); 1392*6cdfca03SJohn Marino error = 1; 1393*6cdfca03SJohn Marino goto bad; 1394*6cdfca03SJohn Marino } 1395*6cdfca03SJohn Marino if (af != 4 || hal != 4 || pal != 2) { 1396*6cdfca03SJohn Marino fputs( 1397*6cdfca03SJohn Marino "Passive mode AF mismatch. Shouldn't happen!\n", ttyout); 1398*6cdfca03SJohn Marino error = 1; 1399*6cdfca03SJohn Marino goto bad; 1400*6cdfca03SJohn Marino } 1401*6cdfca03SJohn Marino 1402*6cdfca03SJohn Marino error = 0; 1403*6cdfca03SJohn Marino memset(&data_addr, 0, sizeof(data_addr)); 1404*6cdfca03SJohn Marino data_addr.su_family = AF_INET; 1405*6cdfca03SJohn Marino data_addr.su_len = sizeof(struct sockaddr_in); 1406*6cdfca03SJohn Marino data_addr.si_su.su_sin.sin_addr.s_addr = 1407*6cdfca03SJohn Marino htonl(pack4(addr, 0)); 1408*6cdfca03SJohn Marino data_addr.su_port = htons(pack2(port, 0)); 1409*6cdfca03SJohn Marino break; 1410*6cdfca03SJohn Marino #ifdef INET6 1411*6cdfca03SJohn Marino case AF_INET6: 1412*6cdfca03SJohn Marino error = sscanf(pasv, 1413*6cdfca03SJohn Marino "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", 1414*6cdfca03SJohn Marino &af, &hal, 1415*6cdfca03SJohn Marino &addr[0], &addr[1], &addr[2], &addr[3], 1416*6cdfca03SJohn Marino &addr[4], &addr[5], &addr[6], &addr[7], 1417*6cdfca03SJohn Marino &addr[8], &addr[9], &addr[10], 1418*6cdfca03SJohn Marino &addr[11], &addr[12], &addr[13], 1419*6cdfca03SJohn Marino &addr[14], &addr[15], 1420*6cdfca03SJohn Marino &pal, &port[0], &port[1]); 1421*6cdfca03SJohn Marino if (error != 21) { 1422*6cdfca03SJohn Marino fputs( 1423*6cdfca03SJohn Marino "Passive mode address scan failure. Shouldn't happen!\n", ttyout); 1424*6cdfca03SJohn Marino error = 1; 1425*6cdfca03SJohn Marino goto bad; 1426*6cdfca03SJohn Marino } 1427*6cdfca03SJohn Marino if (af != 6 || hal != 16 || pal != 2) { 1428*6cdfca03SJohn Marino fputs( 1429*6cdfca03SJohn Marino "Passive mode AF mismatch. Shouldn't happen!\n", ttyout); 1430*6cdfca03SJohn Marino error = 1; 1431*6cdfca03SJohn Marino goto bad; 1432*6cdfca03SJohn Marino } 1433*6cdfca03SJohn Marino 1434*6cdfca03SJohn Marino error = 0; 1435*6cdfca03SJohn Marino memset(&data_addr, 0, sizeof(data_addr)); 1436*6cdfca03SJohn Marino data_addr.su_family = AF_INET6; 1437*6cdfca03SJohn Marino data_addr.su_len = sizeof(struct sockaddr_in6); 1438*6cdfca03SJohn Marino { 1439*6cdfca03SJohn Marino size_t i; 1440*6cdfca03SJohn Marino for (i = 0; i < sizeof(struct in6_addr); i++) { 1441*6cdfca03SJohn Marino data_addr.si_su.su_sin6.sin6_addr.s6_addr[i] = 1442*6cdfca03SJohn Marino UC(addr[i]); 1443*6cdfca03SJohn Marino } 1444*6cdfca03SJohn Marino } 1445*6cdfca03SJohn Marino data_addr.su_port = htons(pack2(port, 0)); 1446*6cdfca03SJohn Marino break; 1447*6cdfca03SJohn Marino #endif 1448*6cdfca03SJohn Marino default: 1449*6cdfca03SJohn Marino error = 1; 1450*6cdfca03SJohn Marino } 1451*6cdfca03SJohn Marino } else if (strcmp(pasvcmd, "EPSV") == 0) { 1452*6cdfca03SJohn Marino char delim[4]; 1453*6cdfca03SJohn Marino 1454*6cdfca03SJohn Marino port[0] = 0; 1455*6cdfca03SJohn Marino if (code / 10 == 22 && code != 229) { 1456*6cdfca03SJohn Marino fputs("wrong server: return code must be 229\n", 1457*6cdfca03SJohn Marino ttyout); 1458*6cdfca03SJohn Marino error = 1; 1459*6cdfca03SJohn Marino goto bad; 1460*6cdfca03SJohn Marino } 1461*6cdfca03SJohn Marino if (sscanf(pasv, "%c%c%c%d%c", &delim[0], 1462*6cdfca03SJohn Marino &delim[1], &delim[2], &port[1], 1463*6cdfca03SJohn Marino &delim[3]) != 5) { 1464*6cdfca03SJohn Marino fputs("parse error!\n", ttyout); 1465*6cdfca03SJohn Marino error = 1; 1466*6cdfca03SJohn Marino goto bad; 1467*6cdfca03SJohn Marino } 1468*6cdfca03SJohn Marino if (delim[0] != delim[1] || delim[0] != delim[2] 1469*6cdfca03SJohn Marino || delim[0] != delim[3]) { 1470*6cdfca03SJohn Marino fputs("parse error!\n", ttyout); 1471*6cdfca03SJohn Marino error = 1; 1472*6cdfca03SJohn Marino goto bad; 1473*6cdfca03SJohn Marino } 1474*6cdfca03SJohn Marino data_addr = hisctladdr; 1475*6cdfca03SJohn Marino data_addr.su_port = htons(port[1]); 1476*6cdfca03SJohn Marino } else 1477*6cdfca03SJohn Marino goto bad; 1478*6cdfca03SJohn Marino 1479*6cdfca03SJohn Marino if (ftp_connect(data, (struct sockaddr *)&data_addr.si_su, 1480*6cdfca03SJohn Marino data_addr.su_len, 1) < 0) { 1481*6cdfca03SJohn Marino if (activefallback) { 1482*6cdfca03SJohn Marino (void)close(data); 1483*6cdfca03SJohn Marino data = -1; 1484*6cdfca03SJohn Marino passivemode = 0; 1485*6cdfca03SJohn Marino #if 0 1486*6cdfca03SJohn Marino activefallback = 0; 1487*6cdfca03SJohn Marino #endif 1488*6cdfca03SJohn Marino goto reinit; 1489*6cdfca03SJohn Marino } 1490*6cdfca03SJohn Marino goto bad; 1491*6cdfca03SJohn Marino } 1492*6cdfca03SJohn Marino #ifdef IPTOS_THROUGHPUT 1493*6cdfca03SJohn Marino if (data_addr.su_family == AF_INET) { 1494*6cdfca03SJohn Marino on = IPTOS_THROUGHPUT; 1495*6cdfca03SJohn Marino if (setsockopt(data, IPPROTO_IP, IP_TOS, 1496*6cdfca03SJohn Marino (void *)&on, sizeof(on)) == -1) { 1497*6cdfca03SJohn Marino DWARN("setsockopt %s (ignored)", 1498*6cdfca03SJohn Marino "IPTOS_THROUGHPUT"); 1499*6cdfca03SJohn Marino } 1500*6cdfca03SJohn Marino } 1501*6cdfca03SJohn Marino #endif 1502*6cdfca03SJohn Marino return (0); 1503*6cdfca03SJohn Marino } 1504*6cdfca03SJohn Marino 1505*6cdfca03SJohn Marino noport: 1506*6cdfca03SJohn Marino data_addr = myctladdr; 1507*6cdfca03SJohn Marino if (sendport) 1508*6cdfca03SJohn Marino data_addr.su_port = 0; /* let system pick one */ 1509*6cdfca03SJohn Marino if (data != -1) 1510*6cdfca03SJohn Marino (void)close(data); 1511*6cdfca03SJohn Marino data = socket(data_addr.su_family, SOCK_STREAM, 0); 1512*6cdfca03SJohn Marino if (data < 0) { 1513*6cdfca03SJohn Marino warn("Can't create socket for data connection"); 1514*6cdfca03SJohn Marino if (tmpno) 1515*6cdfca03SJohn Marino sendport = 1; 1516*6cdfca03SJohn Marino return (1); 1517*6cdfca03SJohn Marino } 1518*6cdfca03SJohn Marino if (!sendport) 1519*6cdfca03SJohn Marino if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, 1520*6cdfca03SJohn Marino (void *)&on, sizeof(on)) == -1) { 1521*6cdfca03SJohn Marino warn("Can't set SO_REUSEADDR on data connection"); 1522*6cdfca03SJohn Marino goto bad; 1523*6cdfca03SJohn Marino } 1524*6cdfca03SJohn Marino if (bind(data, (struct sockaddr *)&data_addr.si_su, 1525*6cdfca03SJohn Marino data_addr.su_len) < 0) { 1526*6cdfca03SJohn Marino warn("Can't bind for data connection"); 1527*6cdfca03SJohn Marino goto bad; 1528*6cdfca03SJohn Marino } 1529*6cdfca03SJohn Marino if ((options & SO_DEBUG) && 1530*6cdfca03SJohn Marino setsockopt(data, SOL_SOCKET, SO_DEBUG, 1531*6cdfca03SJohn Marino (void *)&on, sizeof(on)) == -1) { 1532*6cdfca03SJohn Marino DWARN("setsockopt %s (ignored)", "SO_DEBUG"); 1533*6cdfca03SJohn Marino } 1534*6cdfca03SJohn Marino len = sizeof(data_addr.si_su); 1535*6cdfca03SJohn Marino memset((char *)&data_addr, 0, sizeof (data_addr)); 1536*6cdfca03SJohn Marino if (getsockname(data, (struct sockaddr *)&data_addr.si_su, &len) == -1) { 1537*6cdfca03SJohn Marino warn("Can't determine my address of data connection"); 1538*6cdfca03SJohn Marino goto bad; 1539*6cdfca03SJohn Marino } 1540*6cdfca03SJohn Marino data_addr.su_len = len; 1541*6cdfca03SJohn Marino if (ftp_listen(data, 1) < 0) 1542*6cdfca03SJohn Marino warn("Can't listen to data connection"); 1543*6cdfca03SJohn Marino 1544*6cdfca03SJohn Marino if (sendport) { 1545*6cdfca03SJohn Marino char hname[NI_MAXHOST], sname[NI_MAXSERV]; 1546*6cdfca03SJohn Marino struct sockinet tmp; 1547*6cdfca03SJohn Marino 1548*6cdfca03SJohn Marino switch (data_addr.su_family) { 1549*6cdfca03SJohn Marino case AF_INET: 1550*6cdfca03SJohn Marino if (!epsv4 || epsv4bad) { 1551*6cdfca03SJohn Marino result = COMPLETE + 1; 1552*6cdfca03SJohn Marino break; 1553*6cdfca03SJohn Marino } 1554*6cdfca03SJohn Marino /* FALLTHROUGH */ 1555*6cdfca03SJohn Marino #ifdef INET6 1556*6cdfca03SJohn Marino case AF_INET6: 1557*6cdfca03SJohn Marino if (!epsv6 || epsv6bad) { 1558*6cdfca03SJohn Marino result = COMPLETE + 1; 1559*6cdfca03SJohn Marino break; 1560*6cdfca03SJohn Marino } 1561*6cdfca03SJohn Marino #endif 1562*6cdfca03SJohn Marino af = (data_addr.su_family == AF_INET) ? 1 : 2; 1563*6cdfca03SJohn Marino tmp = data_addr; 1564*6cdfca03SJohn Marino #ifdef INET6 1565*6cdfca03SJohn Marino if (tmp.su_family == AF_INET6) 1566*6cdfca03SJohn Marino tmp.si_su.su_sin6.sin6_scope_id = 0; 1567*6cdfca03SJohn Marino #endif 1568*6cdfca03SJohn Marino if (getnameinfo((struct sockaddr *)&tmp.si_su, 1569*6cdfca03SJohn Marino tmp.su_len, hname, sizeof(hname), sname, 1570*6cdfca03SJohn Marino sizeof(sname), NI_NUMERICHOST | NI_NUMERICSERV)) { 1571*6cdfca03SJohn Marino result = ERROR; 1572*6cdfca03SJohn Marino } else { 1573*6cdfca03SJohn Marino overbose = verbose; 1574*6cdfca03SJohn Marino if (ftp_debug == 0) 1575*6cdfca03SJohn Marino verbose = -1; 1576*6cdfca03SJohn Marino result = command("EPRT |%u|%s|%s|", af, hname, 1577*6cdfca03SJohn Marino sname); 1578*6cdfca03SJohn Marino verbose = overbose; 1579*6cdfca03SJohn Marino if (verbose > 0 && 1580*6cdfca03SJohn Marino (result == COMPLETE || !connected)) 1581*6cdfca03SJohn Marino fprintf(ttyout, "%s\n", reply_string); 1582*6cdfca03SJohn Marino if (!connected) 1583*6cdfca03SJohn Marino return (1); 1584*6cdfca03SJohn Marino if (result != COMPLETE) { 1585*6cdfca03SJohn Marino epsv4bad = 1; 1586*6cdfca03SJohn Marino DPRINTF("disabling epsv4 for this " 1587*6cdfca03SJohn Marino "connection\n"); 1588*6cdfca03SJohn Marino } 1589*6cdfca03SJohn Marino } 1590*6cdfca03SJohn Marino break; 1591*6cdfca03SJohn Marino default: 1592*6cdfca03SJohn Marino result = COMPLETE + 1; 1593*6cdfca03SJohn Marino break; 1594*6cdfca03SJohn Marino } 1595*6cdfca03SJohn Marino if (result == COMPLETE) 1596*6cdfca03SJohn Marino goto skip_port; 1597*6cdfca03SJohn Marino 1598*6cdfca03SJohn Marino switch (data_addr.su_family) { 1599*6cdfca03SJohn Marino case AF_INET: 1600*6cdfca03SJohn Marino a = (char *)&data_addr.si_su.su_sin.sin_addr; 1601*6cdfca03SJohn Marino p = (char *)&data_addr.su_port; 1602*6cdfca03SJohn Marino result = command("PORT %d,%d,%d,%d,%d,%d", 1603*6cdfca03SJohn Marino UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 1604*6cdfca03SJohn Marino UC(p[0]), UC(p[1])); 1605*6cdfca03SJohn Marino break; 1606*6cdfca03SJohn Marino #ifdef INET6 1607*6cdfca03SJohn Marino case AF_INET6: { 1608*6cdfca03SJohn Marino uint8_t ua[sizeof(data_addr.si_su.su_sin6.sin6_addr)]; 1609*6cdfca03SJohn Marino uint8_t up[sizeof(data_addr.su_port)]; 1610*6cdfca03SJohn Marino 1611*6cdfca03SJohn Marino memcpy(ua, &data_addr.si_su.su_sin6.sin6_addr, 1612*6cdfca03SJohn Marino sizeof(ua)); 1613*6cdfca03SJohn Marino memcpy(up, &data_addr.su_port, sizeof(up)); 1614*6cdfca03SJohn Marino 1615*6cdfca03SJohn Marino result = command( 1616*6cdfca03SJohn Marino "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", 1617*6cdfca03SJohn Marino 6, 16, 1618*6cdfca03SJohn Marino ua[0], ua[1], ua[2], ua[3], 1619*6cdfca03SJohn Marino ua[4], ua[5], ua[6], ua[7], 1620*6cdfca03SJohn Marino ua[8], ua[9], ua[10], ua[11], 1621*6cdfca03SJohn Marino ua[12], ua[13], ua[14], ua[15], 1622*6cdfca03SJohn Marino 2, 1623*6cdfca03SJohn Marino up[0], up[1]); 1624*6cdfca03SJohn Marino break; 1625*6cdfca03SJohn Marino } 1626*6cdfca03SJohn Marino #endif 1627*6cdfca03SJohn Marino default: 1628*6cdfca03SJohn Marino result = COMPLETE + 1; /* xxx */ 1629*6cdfca03SJohn Marino } 1630*6cdfca03SJohn Marino if (!connected) 1631*6cdfca03SJohn Marino return (1); 1632*6cdfca03SJohn Marino skip_port: 1633*6cdfca03SJohn Marino 1634*6cdfca03SJohn Marino if (result == ERROR && sendport == -1) { 1635*6cdfca03SJohn Marino sendport = 0; 1636*6cdfca03SJohn Marino tmpno = 1; 1637*6cdfca03SJohn Marino goto noport; 1638*6cdfca03SJohn Marino } 1639*6cdfca03SJohn Marino return (result != COMPLETE); 1640*6cdfca03SJohn Marino } 1641*6cdfca03SJohn Marino if (tmpno) 1642*6cdfca03SJohn Marino sendport = 1; 1643*6cdfca03SJohn Marino #ifdef IPTOS_THROUGHPUT 1644*6cdfca03SJohn Marino if (data_addr.su_family == AF_INET) { 1645*6cdfca03SJohn Marino on = IPTOS_THROUGHPUT; 1646*6cdfca03SJohn Marino if (setsockopt(data, IPPROTO_IP, IP_TOS, 1647*6cdfca03SJohn Marino (void *)&on, sizeof(on)) == -1) { 1648*6cdfca03SJohn Marino DWARN("setsockopt %s (ignored)", "IPTOS_THROUGHPUT"); 1649*6cdfca03SJohn Marino } 1650*6cdfca03SJohn Marino } 1651*6cdfca03SJohn Marino #endif 1652*6cdfca03SJohn Marino return (0); 1653*6cdfca03SJohn Marino bad: 1654*6cdfca03SJohn Marino (void)close(data); 1655*6cdfca03SJohn Marino data = -1; 1656*6cdfca03SJohn Marino if (tmpno) 1657*6cdfca03SJohn Marino sendport = 1; 1658*6cdfca03SJohn Marino return (1); 1659*6cdfca03SJohn Marino } 1660*6cdfca03SJohn Marino 1661*6cdfca03SJohn Marino FILE * 1662*6cdfca03SJohn Marino dataconn(const char *lmode) 1663*6cdfca03SJohn Marino { 1664*6cdfca03SJohn Marino struct sockinet from; 1665*6cdfca03SJohn Marino int s, flags, rv, timeout; 1666*6cdfca03SJohn Marino struct timeval endtime, now, td; 1667*6cdfca03SJohn Marino struct pollfd pfd[1]; 1668*6cdfca03SJohn Marino socklen_t fromlen; 1669*6cdfca03SJohn Marino 1670*6cdfca03SJohn Marino if (passivemode) /* passive data connection */ 1671*6cdfca03SJohn Marino return (fdopen(data, lmode)); 1672*6cdfca03SJohn Marino 1673*6cdfca03SJohn Marino /* active mode data connection */ 1674*6cdfca03SJohn Marino 1675*6cdfca03SJohn Marino if ((flags = fcntl(data, F_GETFL, 0)) == -1) 1676*6cdfca03SJohn Marino goto dataconn_failed; /* get current socket flags */ 1677*6cdfca03SJohn Marino if (fcntl(data, F_SETFL, flags | O_NONBLOCK) == -1) 1678*6cdfca03SJohn Marino goto dataconn_failed; /* set non-blocking connect */ 1679*6cdfca03SJohn Marino 1680*6cdfca03SJohn Marino /* NOTE: we now must restore socket flags on successful exit */ 1681*6cdfca03SJohn Marino 1682*6cdfca03SJohn Marino /* limit time waiting on listening socket */ 1683*6cdfca03SJohn Marino pfd[0].fd = data; 1684*6cdfca03SJohn Marino pfd[0].events = POLLIN; 1685*6cdfca03SJohn Marino (void)gettimeofday(&endtime, NULL); /* determine end time */ 1686*6cdfca03SJohn Marino endtime.tv_sec += (quit_time > 0) ? quit_time: 60; 1687*6cdfca03SJohn Marino /* without -q, default to 60s */ 1688*6cdfca03SJohn Marino do { 1689*6cdfca03SJohn Marino (void)gettimeofday(&now, NULL); 1690*6cdfca03SJohn Marino timersub(&endtime, &now, &td); 1691*6cdfca03SJohn Marino timeout = td.tv_sec * 1000 + td.tv_usec/1000; 1692*6cdfca03SJohn Marino if (timeout < 0) 1693*6cdfca03SJohn Marino timeout = 0; 1694*6cdfca03SJohn Marino rv = ftp_poll(pfd, 1, timeout); 1695*6cdfca03SJohn Marino } while (rv == -1 && errno == EINTR); /* loop until poll ! EINTR */ 1696*6cdfca03SJohn Marino if (rv == -1) { 1697*6cdfca03SJohn Marino warn("Can't poll waiting before accept"); 1698*6cdfca03SJohn Marino goto dataconn_failed; 1699*6cdfca03SJohn Marino } 1700*6cdfca03SJohn Marino if (rv == 0) { 1701*6cdfca03SJohn Marino warnx("Poll timeout waiting before accept"); 1702*6cdfca03SJohn Marino goto dataconn_failed; 1703*6cdfca03SJohn Marino } 1704*6cdfca03SJohn Marino 1705*6cdfca03SJohn Marino /* (non-blocking) accept the connection */ 1706*6cdfca03SJohn Marino fromlen = myctladdr.su_len; 1707*6cdfca03SJohn Marino do { 1708*6cdfca03SJohn Marino s = accept(data, (struct sockaddr *) &from.si_su, &fromlen); 1709*6cdfca03SJohn Marino } while (s == -1 && errno == EINTR); /* loop until accept ! EINTR */ 1710*6cdfca03SJohn Marino if (s == -1) { 1711*6cdfca03SJohn Marino warn("Can't accept data connection"); 1712*6cdfca03SJohn Marino goto dataconn_failed; 1713*6cdfca03SJohn Marino } 1714*6cdfca03SJohn Marino 1715*6cdfca03SJohn Marino (void)close(data); 1716*6cdfca03SJohn Marino data = s; 1717*6cdfca03SJohn Marino if (fcntl(data, F_SETFL, flags) == -1) /* restore socket flags */ 1718*6cdfca03SJohn Marino goto dataconn_failed; 1719*6cdfca03SJohn Marino 1720*6cdfca03SJohn Marino #ifdef IPTOS_THROUGHPUT 1721*6cdfca03SJohn Marino if (from.su_family == AF_INET) { 1722*6cdfca03SJohn Marino int tos = IPTOS_THROUGHPUT; 1723*6cdfca03SJohn Marino if (setsockopt(s, IPPROTO_IP, IP_TOS, 1724*6cdfca03SJohn Marino (void *)&tos, sizeof(tos)) == -1) { 1725*6cdfca03SJohn Marino DWARN("setsockopt %s (ignored)", "IPTOS_THROUGHPUT"); 1726*6cdfca03SJohn Marino } 1727*6cdfca03SJohn Marino } 1728*6cdfca03SJohn Marino #endif 1729*6cdfca03SJohn Marino return (fdopen(data, lmode)); 1730*6cdfca03SJohn Marino 1731*6cdfca03SJohn Marino dataconn_failed: 1732*6cdfca03SJohn Marino (void)close(data); 1733*6cdfca03SJohn Marino data = -1; 1734*6cdfca03SJohn Marino return (NULL); 1735*6cdfca03SJohn Marino } 1736*6cdfca03SJohn Marino 1737*6cdfca03SJohn Marino void 1738*6cdfca03SJohn Marino psabort(int notused) 1739*6cdfca03SJohn Marino { 1740*6cdfca03SJohn Marino int oerrno = errno; 1741*6cdfca03SJohn Marino 1742*6cdfca03SJohn Marino sigint_raised = 1; 1743*6cdfca03SJohn Marino alarmtimer(0); 1744*6cdfca03SJohn Marino abrtflag++; 1745*6cdfca03SJohn Marino errno = oerrno; 1746*6cdfca03SJohn Marino } 1747*6cdfca03SJohn Marino 1748*6cdfca03SJohn Marino void 1749*6cdfca03SJohn Marino pswitch(int flag) 1750*6cdfca03SJohn Marino { 1751*6cdfca03SJohn Marino sigfunc oldintr; 1752*6cdfca03SJohn Marino static struct comvars { 1753*6cdfca03SJohn Marino int connect; 1754*6cdfca03SJohn Marino char name[MAXHOSTNAMELEN]; 1755*6cdfca03SJohn Marino struct sockinet mctl; 1756*6cdfca03SJohn Marino struct sockinet hctl; 1757*6cdfca03SJohn Marino FILE *in; 1758*6cdfca03SJohn Marino FILE *out; 1759*6cdfca03SJohn Marino int tpe; 1760*6cdfca03SJohn Marino int curtpe; 1761*6cdfca03SJohn Marino int cpnd; 1762*6cdfca03SJohn Marino int sunqe; 1763*6cdfca03SJohn Marino int runqe; 1764*6cdfca03SJohn Marino int mcse; 1765*6cdfca03SJohn Marino int ntflg; 1766*6cdfca03SJohn Marino char nti[17]; 1767*6cdfca03SJohn Marino char nto[17]; 1768*6cdfca03SJohn Marino int mapflg; 1769*6cdfca03SJohn Marino char mi[MAXPATHLEN]; 1770*6cdfca03SJohn Marino char mo[MAXPATHLEN]; 1771*6cdfca03SJohn Marino } proxstruct, tmpstruct; 1772*6cdfca03SJohn Marino struct comvars *ip, *op; 1773*6cdfca03SJohn Marino 1774*6cdfca03SJohn Marino abrtflag = 0; 1775*6cdfca03SJohn Marino oldintr = xsignal(SIGINT, psabort); 1776*6cdfca03SJohn Marino if (flag) { 1777*6cdfca03SJohn Marino if (proxy) 1778*6cdfca03SJohn Marino return; 1779*6cdfca03SJohn Marino ip = &tmpstruct; 1780*6cdfca03SJohn Marino op = &proxstruct; 1781*6cdfca03SJohn Marino proxy++; 1782*6cdfca03SJohn Marino } else { 1783*6cdfca03SJohn Marino if (!proxy) 1784*6cdfca03SJohn Marino return; 1785*6cdfca03SJohn Marino ip = &proxstruct; 1786*6cdfca03SJohn Marino op = &tmpstruct; 1787*6cdfca03SJohn Marino proxy = 0; 1788*6cdfca03SJohn Marino } 1789*6cdfca03SJohn Marino ip->connect = connected; 1790*6cdfca03SJohn Marino connected = op->connect; 1791*6cdfca03SJohn Marino if (hostname) 1792*6cdfca03SJohn Marino (void)strlcpy(ip->name, hostname, sizeof(ip->name)); 1793*6cdfca03SJohn Marino else 1794*6cdfca03SJohn Marino ip->name[0] = '\0'; 1795*6cdfca03SJohn Marino hostname = op->name; 1796*6cdfca03SJohn Marino ip->hctl = hisctladdr; 1797*6cdfca03SJohn Marino hisctladdr = op->hctl; 1798*6cdfca03SJohn Marino ip->mctl = myctladdr; 1799*6cdfca03SJohn Marino myctladdr = op->mctl; 1800*6cdfca03SJohn Marino ip->in = cin; 1801*6cdfca03SJohn Marino cin = op->in; 1802*6cdfca03SJohn Marino ip->out = cout; 1803*6cdfca03SJohn Marino cout = op->out; 1804*6cdfca03SJohn Marino ip->tpe = type; 1805*6cdfca03SJohn Marino type = op->tpe; 1806*6cdfca03SJohn Marino ip->curtpe = curtype; 1807*6cdfca03SJohn Marino curtype = op->curtpe; 1808*6cdfca03SJohn Marino ip->cpnd = cpend; 1809*6cdfca03SJohn Marino cpend = op->cpnd; 1810*6cdfca03SJohn Marino ip->sunqe = sunique; 1811*6cdfca03SJohn Marino sunique = op->sunqe; 1812*6cdfca03SJohn Marino ip->runqe = runique; 1813*6cdfca03SJohn Marino runique = op->runqe; 1814*6cdfca03SJohn Marino ip->mcse = mcase; 1815*6cdfca03SJohn Marino mcase = op->mcse; 1816*6cdfca03SJohn Marino ip->ntflg = ntflag; 1817*6cdfca03SJohn Marino ntflag = op->ntflg; 1818*6cdfca03SJohn Marino (void)strlcpy(ip->nti, ntin, sizeof(ip->nti)); 1819*6cdfca03SJohn Marino (void)strlcpy(ntin, op->nti, sizeof(ntin)); 1820*6cdfca03SJohn Marino (void)strlcpy(ip->nto, ntout, sizeof(ip->nto)); 1821*6cdfca03SJohn Marino (void)strlcpy(ntout, op->nto, sizeof(ntout)); 1822*6cdfca03SJohn Marino ip->mapflg = mapflag; 1823*6cdfca03SJohn Marino mapflag = op->mapflg; 1824*6cdfca03SJohn Marino (void)strlcpy(ip->mi, mapin, sizeof(ip->mi)); 1825*6cdfca03SJohn Marino (void)strlcpy(mapin, op->mi, sizeof(mapin)); 1826*6cdfca03SJohn Marino (void)strlcpy(ip->mo, mapout, sizeof(ip->mo)); 1827*6cdfca03SJohn Marino (void)strlcpy(mapout, op->mo, sizeof(mapout)); 1828*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr); 1829*6cdfca03SJohn Marino if (abrtflag) { 1830*6cdfca03SJohn Marino abrtflag = 0; 1831*6cdfca03SJohn Marino (*oldintr)(SIGINT); 1832*6cdfca03SJohn Marino } 1833*6cdfca03SJohn Marino } 1834*6cdfca03SJohn Marino 1835*6cdfca03SJohn Marino __dead static void 1836*6cdfca03SJohn Marino abortpt(int notused) 1837*6cdfca03SJohn Marino { 1838*6cdfca03SJohn Marino 1839*6cdfca03SJohn Marino sigint_raised = 1; 1840*6cdfca03SJohn Marino alarmtimer(0); 1841*6cdfca03SJohn Marino if (fromatty) 1842*6cdfca03SJohn Marino write(fileno(ttyout), "\n", 1); 1843*6cdfca03SJohn Marino ptabflg++; 1844*6cdfca03SJohn Marino mflag = 0; 1845*6cdfca03SJohn Marino abrtflag = 0; 1846*6cdfca03SJohn Marino siglongjmp(ptabort, 1); 1847*6cdfca03SJohn Marino } 1848*6cdfca03SJohn Marino 1849*6cdfca03SJohn Marino void 1850*6cdfca03SJohn Marino proxtrans(const char *cmd, const char *local, const char *remote) 1851*6cdfca03SJohn Marino { 1852*6cdfca03SJohn Marino sigfunc volatile oldintr; 1853*6cdfca03SJohn Marino int prox_type, nfnd; 1854*6cdfca03SJohn Marino int volatile secndflag; 1855*6cdfca03SJohn Marino const char *volatile cmd2; 1856*6cdfca03SJohn Marino 1857*6cdfca03SJohn Marino oldintr = NULL; 1858*6cdfca03SJohn Marino secndflag = 0; 1859*6cdfca03SJohn Marino if (strcmp(cmd, "RETR")) 1860*6cdfca03SJohn Marino cmd2 = "RETR"; 1861*6cdfca03SJohn Marino else 1862*6cdfca03SJohn Marino cmd2 = runique ? "STOU" : "STOR"; 1863*6cdfca03SJohn Marino if ((prox_type = type) == 0) { 1864*6cdfca03SJohn Marino if (unix_server && unix_proxy) 1865*6cdfca03SJohn Marino prox_type = TYPE_I; 1866*6cdfca03SJohn Marino else 1867*6cdfca03SJohn Marino prox_type = TYPE_A; 1868*6cdfca03SJohn Marino } 1869*6cdfca03SJohn Marino if (curtype != prox_type) 1870*6cdfca03SJohn Marino changetype(prox_type, 1); 1871*6cdfca03SJohn Marino if (command("PASV") != COMPLETE) { 1872*6cdfca03SJohn Marino fputs("proxy server does not support third party transfers.\n", 1873*6cdfca03SJohn Marino ttyout); 1874*6cdfca03SJohn Marino return; 1875*6cdfca03SJohn Marino } 1876*6cdfca03SJohn Marino pswitch(0); 1877*6cdfca03SJohn Marino if (!connected) { 1878*6cdfca03SJohn Marino fputs("No primary connection.\n", ttyout); 1879*6cdfca03SJohn Marino pswitch(1); 1880*6cdfca03SJohn Marino code = -1; 1881*6cdfca03SJohn Marino return; 1882*6cdfca03SJohn Marino } 1883*6cdfca03SJohn Marino if (curtype != prox_type) 1884*6cdfca03SJohn Marino changetype(prox_type, 1); 1885*6cdfca03SJohn Marino if (command("PORT %s", pasv) != COMPLETE) { 1886*6cdfca03SJohn Marino pswitch(1); 1887*6cdfca03SJohn Marino return; 1888*6cdfca03SJohn Marino } 1889*6cdfca03SJohn Marino if (sigsetjmp(ptabort, 1)) 1890*6cdfca03SJohn Marino goto abort; 1891*6cdfca03SJohn Marino oldintr = xsignal(SIGINT, abortpt); 1892*6cdfca03SJohn Marino if ((restart_point && 1893*6cdfca03SJohn Marino (command("REST " LLF, (LLT) restart_point) != CONTINUE)) 1894*6cdfca03SJohn Marino || (command("%s %s", cmd, remote) != PRELIM)) { 1895*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr); 1896*6cdfca03SJohn Marino pswitch(1); 1897*6cdfca03SJohn Marino return; 1898*6cdfca03SJohn Marino } 1899*6cdfca03SJohn Marino sleep(2); 1900*6cdfca03SJohn Marino pswitch(1); 1901*6cdfca03SJohn Marino secndflag++; 1902*6cdfca03SJohn Marino if ((restart_point && 1903*6cdfca03SJohn Marino (command("REST " LLF, (LLT) restart_point) != CONTINUE)) 1904*6cdfca03SJohn Marino || (command("%s %s", cmd2, local) != PRELIM)) 1905*6cdfca03SJohn Marino goto abort; 1906*6cdfca03SJohn Marino ptflag++; 1907*6cdfca03SJohn Marino (void)getreply(0); 1908*6cdfca03SJohn Marino pswitch(0); 1909*6cdfca03SJohn Marino (void)getreply(0); 1910*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr); 1911*6cdfca03SJohn Marino pswitch(1); 1912*6cdfca03SJohn Marino ptflag = 0; 1913*6cdfca03SJohn Marino fprintf(ttyout, "local: %s remote: %s\n", local, remote); 1914*6cdfca03SJohn Marino return; 1915*6cdfca03SJohn Marino abort: 1916*6cdfca03SJohn Marino if (sigsetjmp(xferabort, 1)) { 1917*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr); 1918*6cdfca03SJohn Marino return; 1919*6cdfca03SJohn Marino } 1920*6cdfca03SJohn Marino (void)xsignal(SIGINT, abort_squared); 1921*6cdfca03SJohn Marino ptflag = 0; 1922*6cdfca03SJohn Marino if (strcmp(cmd, "RETR") && !proxy) 1923*6cdfca03SJohn Marino pswitch(1); 1924*6cdfca03SJohn Marino else if (!strcmp(cmd, "RETR") && proxy) 1925*6cdfca03SJohn Marino pswitch(0); 1926*6cdfca03SJohn Marino if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ 1927*6cdfca03SJohn Marino if (command("%s %s", cmd2, local) != PRELIM) { 1928*6cdfca03SJohn Marino pswitch(0); 1929*6cdfca03SJohn Marino if (cpend) 1930*6cdfca03SJohn Marino abort_remote(NULL); 1931*6cdfca03SJohn Marino } 1932*6cdfca03SJohn Marino pswitch(1); 1933*6cdfca03SJohn Marino if (ptabflg) 1934*6cdfca03SJohn Marino code = -1; 1935*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr); 1936*6cdfca03SJohn Marino return; 1937*6cdfca03SJohn Marino } 1938*6cdfca03SJohn Marino if (cpend) 1939*6cdfca03SJohn Marino abort_remote(NULL); 1940*6cdfca03SJohn Marino pswitch(!proxy); 1941*6cdfca03SJohn Marino if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ 1942*6cdfca03SJohn Marino if (command("%s %s", cmd2, local) != PRELIM) { 1943*6cdfca03SJohn Marino pswitch(0); 1944*6cdfca03SJohn Marino if (cpend) 1945*6cdfca03SJohn Marino abort_remote(NULL); 1946*6cdfca03SJohn Marino pswitch(1); 1947*6cdfca03SJohn Marino if (ptabflg) 1948*6cdfca03SJohn Marino code = -1; 1949*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr); 1950*6cdfca03SJohn Marino return; 1951*6cdfca03SJohn Marino } 1952*6cdfca03SJohn Marino } 1953*6cdfca03SJohn Marino if (cpend) 1954*6cdfca03SJohn Marino abort_remote(NULL); 1955*6cdfca03SJohn Marino pswitch(!proxy); 1956*6cdfca03SJohn Marino if (cpend) { 1957*6cdfca03SJohn Marino if ((nfnd = empty(cin, NULL, 10)) <= 0) { 1958*6cdfca03SJohn Marino if (nfnd < 0) 1959*6cdfca03SJohn Marino warn("Error aborting proxy command"); 1960*6cdfca03SJohn Marino if (ptabflg) 1961*6cdfca03SJohn Marino code = -1; 1962*6cdfca03SJohn Marino lostpeer(0); 1963*6cdfca03SJohn Marino } 1964*6cdfca03SJohn Marino (void)getreply(0); 1965*6cdfca03SJohn Marino (void)getreply(0); 1966*6cdfca03SJohn Marino } 1967*6cdfca03SJohn Marino if (proxy) 1968*6cdfca03SJohn Marino pswitch(0); 1969*6cdfca03SJohn Marino pswitch(1); 1970*6cdfca03SJohn Marino if (ptabflg) 1971*6cdfca03SJohn Marino code = -1; 1972*6cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr); 1973*6cdfca03SJohn Marino } 1974*6cdfca03SJohn Marino 1975*6cdfca03SJohn Marino void 1976*6cdfca03SJohn Marino reset(int argc, char *argv[]) 1977*6cdfca03SJohn Marino { 1978*6cdfca03SJohn Marino int nfnd = 1; 1979*6cdfca03SJohn Marino 1980*6cdfca03SJohn Marino if (argc == 0 && argv != NULL) { 1981*6cdfca03SJohn Marino UPRINTF("usage: %s\n", argv[0]); 1982*6cdfca03SJohn Marino code = -1; 1983*6cdfca03SJohn Marino return; 1984*6cdfca03SJohn Marino } 1985*6cdfca03SJohn Marino while (nfnd > 0) { 1986*6cdfca03SJohn Marino if ((nfnd = empty(cin, NULL, 0)) < 0) { 1987*6cdfca03SJohn Marino warn("Error resetting connection"); 1988*6cdfca03SJohn Marino code = -1; 1989*6cdfca03SJohn Marino lostpeer(0); 1990*6cdfca03SJohn Marino } else if (nfnd) 1991*6cdfca03SJohn Marino (void)getreply(0); 1992*6cdfca03SJohn Marino } 1993*6cdfca03SJohn Marino } 1994*6cdfca03SJohn Marino 1995*6cdfca03SJohn Marino char * 1996*6cdfca03SJohn Marino gunique(const char *local) 1997*6cdfca03SJohn Marino { 1998*6cdfca03SJohn Marino static char new[MAXPATHLEN]; 1999*6cdfca03SJohn Marino char *cp = strrchr(local, '/'); 2000*6cdfca03SJohn Marino int d, count=0, len; 2001*6cdfca03SJohn Marino char ext = '1'; 2002*6cdfca03SJohn Marino 2003*6cdfca03SJohn Marino if (cp) 2004*6cdfca03SJohn Marino *cp = '\0'; 2005*6cdfca03SJohn Marino d = access(cp == local ? "/" : cp ? local : ".", W_OK); 2006*6cdfca03SJohn Marino if (cp) 2007*6cdfca03SJohn Marino *cp = '/'; 2008*6cdfca03SJohn Marino if (d < 0) { 2009*6cdfca03SJohn Marino warn("Can't access `%s'", local); 2010*6cdfca03SJohn Marino return (NULL); 2011*6cdfca03SJohn Marino } 2012*6cdfca03SJohn Marino len = strlcpy(new, local, sizeof(new)); 2013*6cdfca03SJohn Marino cp = &new[len]; 2014*6cdfca03SJohn Marino *cp++ = '.'; 2015*6cdfca03SJohn Marino while (!d) { 2016*6cdfca03SJohn Marino if (++count == 100) { 2017*6cdfca03SJohn Marino fputs("runique: can't find unique file name.\n", 2018*6cdfca03SJohn Marino ttyout); 2019*6cdfca03SJohn Marino return (NULL); 2020*6cdfca03SJohn Marino } 2021*6cdfca03SJohn Marino *cp++ = ext; 2022*6cdfca03SJohn Marino *cp = '\0'; 2023*6cdfca03SJohn Marino if (ext == '9') 2024*6cdfca03SJohn Marino ext = '0'; 2025*6cdfca03SJohn Marino else 2026*6cdfca03SJohn Marino ext++; 2027*6cdfca03SJohn Marino if ((d = access(new, F_OK)) < 0) 2028*6cdfca03SJohn Marino break; 2029*6cdfca03SJohn Marino if (ext != '0') 2030*6cdfca03SJohn Marino cp--; 2031*6cdfca03SJohn Marino else if (*(cp - 2) == '.') 2032*6cdfca03SJohn Marino *(cp - 1) = '1'; 2033*6cdfca03SJohn Marino else { 2034*6cdfca03SJohn Marino *(cp - 2) = *(cp - 2) + 1; 2035*6cdfca03SJohn Marino cp--; 2036*6cdfca03SJohn Marino } 2037*6cdfca03SJohn Marino } 2038*6cdfca03SJohn Marino return (new); 2039*6cdfca03SJohn Marino } 2040*6cdfca03SJohn Marino 2041*6cdfca03SJohn Marino /* 2042*6cdfca03SJohn Marino * abort_squared -- 2043*6cdfca03SJohn Marino * aborts abort_remote(). lostpeer() is called because if the user is 2044*6cdfca03SJohn Marino * too impatient to wait or there's another problem then ftp really 2045*6cdfca03SJohn Marino * needs to get back to a known state. 2046*6cdfca03SJohn Marino */ 2047*6cdfca03SJohn Marino static void 2048*6cdfca03SJohn Marino abort_squared(int dummy) 2049*6cdfca03SJohn Marino { 2050*6cdfca03SJohn Marino char msgbuf[100]; 2051*6cdfca03SJohn Marino size_t len; 2052*6cdfca03SJohn Marino 2053*6cdfca03SJohn Marino sigint_raised = 1; 2054*6cdfca03SJohn Marino alarmtimer(0); 2055*6cdfca03SJohn Marino len = strlcpy(msgbuf, "\nremote abort aborted; closing connection.\n", 2056*6cdfca03SJohn Marino sizeof(msgbuf)); 2057*6cdfca03SJohn Marino write(fileno(ttyout), msgbuf, len); 2058*6cdfca03SJohn Marino lostpeer(0); 2059*6cdfca03SJohn Marino siglongjmp(xferabort, 1); 2060*6cdfca03SJohn Marino } 2061*6cdfca03SJohn Marino 2062*6cdfca03SJohn Marino void 2063*6cdfca03SJohn Marino abort_remote(FILE *din) 2064*6cdfca03SJohn Marino { 2065*6cdfca03SJohn Marino char buf[BUFSIZ]; 2066*6cdfca03SJohn Marino int nfnd; 2067*6cdfca03SJohn Marino 2068*6cdfca03SJohn Marino if (cout == NULL) { 2069*6cdfca03SJohn Marino warnx("Lost control connection for abort"); 2070*6cdfca03SJohn Marino if (ptabflg) 2071*6cdfca03SJohn Marino code = -1; 2072*6cdfca03SJohn Marino lostpeer(0); 2073*6cdfca03SJohn Marino return; 2074*6cdfca03SJohn Marino } 2075*6cdfca03SJohn Marino /* 2076*6cdfca03SJohn Marino * send IAC in urgent mode instead of DM because 4.3BSD places oob mark 2077*6cdfca03SJohn Marino * after urgent byte rather than before as is protocol now 2078*6cdfca03SJohn Marino */ 2079*6cdfca03SJohn Marino buf[0] = IAC; 2080*6cdfca03SJohn Marino buf[1] = IP; 2081*6cdfca03SJohn Marino buf[2] = IAC; 2082*6cdfca03SJohn Marino if (send(fileno(cout), buf, 3, MSG_OOB) != 3) 2083*6cdfca03SJohn Marino warn("Can't send abort message"); 2084*6cdfca03SJohn Marino fprintf(cout, "%cABOR\r\n", DM); 2085*6cdfca03SJohn Marino (void)fflush(cout); 2086*6cdfca03SJohn Marino if ((nfnd = empty(cin, din, 10)) <= 0) { 2087*6cdfca03SJohn Marino if (nfnd < 0) 2088*6cdfca03SJohn Marino warn("Can't send abort message"); 2089*6cdfca03SJohn Marino if (ptabflg) 2090*6cdfca03SJohn Marino code = -1; 2091*6cdfca03SJohn Marino lostpeer(0); 2092*6cdfca03SJohn Marino } 2093*6cdfca03SJohn Marino if (din && (nfnd & 2)) { 2094*6cdfca03SJohn Marino while (read(fileno(din), buf, BUFSIZ) > 0) 2095*6cdfca03SJohn Marino continue; 2096*6cdfca03SJohn Marino } 2097*6cdfca03SJohn Marino if (getreply(0) == ERROR && code == 552) { 2098*6cdfca03SJohn Marino /* 552 needed for nic style abort */ 2099*6cdfca03SJohn Marino (void)getreply(0); 2100*6cdfca03SJohn Marino } 2101*6cdfca03SJohn Marino (void)getreply(0); 2102*6cdfca03SJohn Marino } 2103*6cdfca03SJohn Marino 2104*6cdfca03SJohn Marino /* 2105*6cdfca03SJohn Marino * Ensure that ai->ai_addr is NOT an IPv4 mapped address. 2106*6cdfca03SJohn Marino * IPv4 mapped address complicates too many things in FTP 2107*6cdfca03SJohn Marino * protocol handling, as FTP protocol is defined differently 2108*6cdfca03SJohn Marino * between IPv4 and IPv6. 2109*6cdfca03SJohn Marino * 2110*6cdfca03SJohn Marino * This may not be the best way to handle this situation, 2111*6cdfca03SJohn Marino * since the semantics of IPv4 mapped address is defined in 2112*6cdfca03SJohn Marino * the kernel. There are configurations where we should use 2113*6cdfca03SJohn Marino * IPv4 mapped address as native IPv6 address, not as 2114*6cdfca03SJohn Marino * "an IPv6 address that embeds IPv4 address" (namely, SIIT). 2115*6cdfca03SJohn Marino * 2116*6cdfca03SJohn Marino * More complete solution would be to have an additional 2117*6cdfca03SJohn Marino * getsockopt to grab "real" peername/sockname. "real" 2118*6cdfca03SJohn Marino * peername/sockname will be AF_INET if IPv4 mapped address 2119*6cdfca03SJohn Marino * is used to embed IPv4 address, and will be AF_INET6 if 2120*6cdfca03SJohn Marino * we use it as native. What a mess! 2121*6cdfca03SJohn Marino */ 2122*6cdfca03SJohn Marino void 2123*6cdfca03SJohn Marino ai_unmapped(struct addrinfo *ai) 2124*6cdfca03SJohn Marino { 2125*6cdfca03SJohn Marino #ifdef INET6 2126*6cdfca03SJohn Marino struct sockaddr_in6 *sin6; 2127*6cdfca03SJohn Marino struct sockaddr_in sin; 2128*6cdfca03SJohn Marino socklen_t len; 2129*6cdfca03SJohn Marino 2130*6cdfca03SJohn Marino if (ai->ai_family != AF_INET6) 2131*6cdfca03SJohn Marino return; 2132*6cdfca03SJohn Marino if (ai->ai_addrlen != sizeof(struct sockaddr_in6) || 2133*6cdfca03SJohn Marino sizeof(sin) > ai->ai_addrlen) 2134*6cdfca03SJohn Marino return; 2135*6cdfca03SJohn Marino sin6 = (struct sockaddr_in6 *)ai->ai_addr; 2136*6cdfca03SJohn Marino if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 2137*6cdfca03SJohn Marino return; 2138*6cdfca03SJohn Marino 2139*6cdfca03SJohn Marino memset(&sin, 0, sizeof(sin)); 2140*6cdfca03SJohn Marino sin.sin_family = AF_INET; 2141*6cdfca03SJohn Marino len = sizeof(struct sockaddr_in); 2142*6cdfca03SJohn Marino memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12], 2143*6cdfca03SJohn Marino sizeof(sin.sin_addr)); 2144*6cdfca03SJohn Marino sin.sin_port = sin6->sin6_port; 2145*6cdfca03SJohn Marino 2146*6cdfca03SJohn Marino ai->ai_family = AF_INET; 2147*6cdfca03SJohn Marino #if defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN) 2148*6cdfca03SJohn Marino sin.sin_len = len; 2149*6cdfca03SJohn Marino #endif 2150*6cdfca03SJohn Marino memcpy(ai->ai_addr, &sin, len); 2151*6cdfca03SJohn Marino ai->ai_addrlen = len; 2152*6cdfca03SJohn Marino #endif 2153*6cdfca03SJohn Marino } 2154*6cdfca03SJohn Marino 2155*6cdfca03SJohn Marino #ifdef NO_USAGE 2156*6cdfca03SJohn Marino void 2157*6cdfca03SJohn Marino xusage(void) 2158*6cdfca03SJohn Marino { 2159*6cdfca03SJohn Marino fputs("Usage error\n", ttyout); 2160*6cdfca03SJohn Marino } 2161*6cdfca03SJohn Marino #endif 2162