1*3a184c67SAntonio Huete Jimenez /* $NetBSD: ftp.c,v 1.24 2021/08/27 01:38:49 lukem Exp $ */
2*3a184c67SAntonio Huete Jimenez /* from NetBSD: ftp.c,v 1.174 2021/08/26 06:23:24 lukem Exp */
36cdfca03SJohn Marino
46cdfca03SJohn Marino /*-
5*3a184c67SAntonio Huete Jimenez * Copyright (c) 1996-2021 The NetBSD Foundation, Inc.
66cdfca03SJohn Marino * All rights reserved.
76cdfca03SJohn Marino *
86cdfca03SJohn Marino * This code is derived from software contributed to The NetBSD Foundation
96cdfca03SJohn Marino * by Luke Mewburn.
106cdfca03SJohn Marino *
116cdfca03SJohn Marino * Redistribution and use in source and binary forms, with or without
126cdfca03SJohn Marino * modification, are permitted provided that the following conditions
136cdfca03SJohn Marino * are met:
146cdfca03SJohn Marino * 1. Redistributions of source code must retain the above copyright
156cdfca03SJohn Marino * notice, this list of conditions and the following disclaimer.
166cdfca03SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
176cdfca03SJohn Marino * notice, this list of conditions and the following disclaimer in the
186cdfca03SJohn Marino * documentation and/or other materials provided with the distribution.
196cdfca03SJohn Marino *
206cdfca03SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
216cdfca03SJohn Marino * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
226cdfca03SJohn Marino * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
236cdfca03SJohn Marino * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
246cdfca03SJohn Marino * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
256cdfca03SJohn Marino * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
266cdfca03SJohn Marino * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
276cdfca03SJohn Marino * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
286cdfca03SJohn Marino * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
296cdfca03SJohn Marino * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
306cdfca03SJohn Marino * POSSIBILITY OF SUCH DAMAGE.
316cdfca03SJohn Marino */
326cdfca03SJohn Marino
336cdfca03SJohn Marino /*
346cdfca03SJohn Marino * Copyright (c) 1985, 1989, 1993, 1994
356cdfca03SJohn Marino * The Regents of the University of California. All rights reserved.
366cdfca03SJohn Marino *
376cdfca03SJohn Marino * Redistribution and use in source and binary forms, with or without
386cdfca03SJohn Marino * modification, are permitted provided that the following conditions
396cdfca03SJohn Marino * are met:
406cdfca03SJohn Marino * 1. Redistributions of source code must retain the above copyright
416cdfca03SJohn Marino * notice, this list of conditions and the following disclaimer.
426cdfca03SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
436cdfca03SJohn Marino * notice, this list of conditions and the following disclaimer in the
446cdfca03SJohn Marino * documentation and/or other materials provided with the distribution.
456cdfca03SJohn Marino * 3. Neither the name of the University nor the names of its contributors
466cdfca03SJohn Marino * may be used to endorse or promote products derived from this software
476cdfca03SJohn Marino * without specific prior written permission.
486cdfca03SJohn Marino *
496cdfca03SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
506cdfca03SJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
516cdfca03SJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
526cdfca03SJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
536cdfca03SJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
546cdfca03SJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
556cdfca03SJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
566cdfca03SJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
576cdfca03SJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
586cdfca03SJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
596cdfca03SJohn Marino * SUCH DAMAGE.
606cdfca03SJohn Marino */
616cdfca03SJohn Marino
626cdfca03SJohn Marino /*
636cdfca03SJohn Marino * Copyright (C) 1997 and 1998 WIDE Project.
646cdfca03SJohn Marino * All rights reserved.
656cdfca03SJohn Marino *
666cdfca03SJohn Marino * Redistribution and use in source and binary forms, with or without
676cdfca03SJohn Marino * modification, are permitted provided that the following conditions
686cdfca03SJohn Marino * are met:
696cdfca03SJohn Marino * 1. Redistributions of source code must retain the above copyright
706cdfca03SJohn Marino * notice, this list of conditions and the following disclaimer.
716cdfca03SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
726cdfca03SJohn Marino * notice, this list of conditions and the following disclaimer in the
736cdfca03SJohn Marino * documentation and/or other materials provided with the distribution.
746cdfca03SJohn Marino * 3. Neither the name of the project nor the names of its contributors
756cdfca03SJohn Marino * may be used to endorse or promote products derived from this software
766cdfca03SJohn Marino * without specific prior written permission.
776cdfca03SJohn Marino *
786cdfca03SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
796cdfca03SJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
806cdfca03SJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
816cdfca03SJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
826cdfca03SJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
836cdfca03SJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
846cdfca03SJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
856cdfca03SJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
866cdfca03SJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
876cdfca03SJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
886cdfca03SJohn Marino * SUCH DAMAGE.
896cdfca03SJohn Marino */
906cdfca03SJohn Marino
916cdfca03SJohn Marino #include "tnftp.h"
926cdfca03SJohn Marino #include <arpa/telnet.h>
936cdfca03SJohn Marino
946cdfca03SJohn Marino #if 0 /* tnftp */
956cdfca03SJohn Marino
966cdfca03SJohn Marino #include <sys/cdefs.h>
976cdfca03SJohn Marino #ifndef lint
986cdfca03SJohn Marino #if 0
996cdfca03SJohn Marino static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94";
1006cdfca03SJohn Marino #else
101*3a184c67SAntonio Huete Jimenez __RCSID(" NetBSD: ftp.c,v 1.174 2021/08/26 06:23:24 lukem Exp ");
1026cdfca03SJohn Marino #endif
1036cdfca03SJohn Marino #endif /* not lint */
1046cdfca03SJohn Marino
1056cdfca03SJohn Marino #include <sys/types.h>
1066cdfca03SJohn Marino #include <sys/stat.h>
1076cdfca03SJohn Marino #include <sys/socket.h>
1086cdfca03SJohn Marino #include <sys/time.h>
1096cdfca03SJohn Marino
1106cdfca03SJohn Marino #include <netinet/in.h>
1116cdfca03SJohn Marino #include <netinet/in_systm.h>
1126cdfca03SJohn Marino #include <netinet/ip.h>
1136cdfca03SJohn Marino #include <arpa/inet.h>
1146cdfca03SJohn Marino #include <arpa/ftp.h>
1156cdfca03SJohn Marino #include <arpa/telnet.h>
1166cdfca03SJohn Marino
1176cdfca03SJohn Marino #include <assert.h>
1186cdfca03SJohn Marino #include <ctype.h>
1196cdfca03SJohn Marino #include <err.h>
1206cdfca03SJohn Marino #include <errno.h>
1216cdfca03SJohn Marino #include <fcntl.h>
1226cdfca03SJohn Marino #include <netdb.h>
1236cdfca03SJohn Marino #include <stdio.h>
1246cdfca03SJohn Marino #include <stdlib.h>
1256cdfca03SJohn Marino #include <string.h>
1266cdfca03SJohn Marino #include <time.h>
1276cdfca03SJohn Marino #include <unistd.h>
1286cdfca03SJohn Marino #include <stdarg.h>
1296cdfca03SJohn Marino
1306cdfca03SJohn Marino #endif /* tnftp */
1316cdfca03SJohn Marino
1326cdfca03SJohn Marino #include "ftp_var.h"
1336cdfca03SJohn Marino
1346cdfca03SJohn Marino volatile sig_atomic_t abrtflag;
1356cdfca03SJohn Marino volatile sig_atomic_t timeoutflag;
1366cdfca03SJohn Marino
1376cdfca03SJohn Marino sigjmp_buf ptabort;
1386cdfca03SJohn Marino int ptabflg;
1396cdfca03SJohn Marino int ptflag = 0;
1406cdfca03SJohn Marino char pasv[BUFSIZ]; /* passive port for proxy data connection */
1416cdfca03SJohn Marino
1426cdfca03SJohn Marino static int empty(FILE *, FILE *, int);
1436cdfca03SJohn Marino __dead static void abort_squared(int);
1446cdfca03SJohn Marino
1456cdfca03SJohn Marino struct sockinet {
1466cdfca03SJohn Marino union sockunion {
1476cdfca03SJohn Marino struct sockaddr_in su_sin;
1486cdfca03SJohn Marino #ifdef INET6
1496cdfca03SJohn Marino struct sockaddr_in6 su_sin6;
1506cdfca03SJohn Marino #endif
1516cdfca03SJohn Marino } si_su;
1526cdfca03SJohn Marino #if !defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN)
1536cdfca03SJohn Marino int si_len;
1546cdfca03SJohn Marino #endif
1556cdfca03SJohn Marino };
1566cdfca03SJohn Marino
1576cdfca03SJohn Marino #if !defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN)
1586cdfca03SJohn Marino # define su_len si_len
1596cdfca03SJohn Marino #else
1606cdfca03SJohn Marino # define su_len si_su.su_sin.sin_len
1616cdfca03SJohn Marino #endif
1626cdfca03SJohn Marino #define su_family si_su.su_sin.sin_family
1636cdfca03SJohn Marino #define su_port si_su.su_sin.sin_port
1646cdfca03SJohn Marino
1656cdfca03SJohn Marino struct sockinet myctladdr, hisctladdr, data_addr;
1666cdfca03SJohn Marino
1676cdfca03SJohn Marino char *
hookup(const char * host,const char * port)1686cdfca03SJohn Marino hookup(const char *host, const char *port)
1696cdfca03SJohn Marino {
1706cdfca03SJohn Marino int s = -1, error;
1716cdfca03SJohn Marino struct addrinfo hints, *res, *res0;
1726cdfca03SJohn Marino static char hostnamebuf[MAXHOSTNAMELEN];
1736cdfca03SJohn Marino socklen_t len;
1746cdfca03SJohn Marino int on = 1;
1756cdfca03SJohn Marino
1766cdfca03SJohn Marino memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
1776cdfca03SJohn Marino memset((char *)&myctladdr, 0, sizeof (myctladdr));
1786cdfca03SJohn Marino memset(&hints, 0, sizeof(hints));
1796cdfca03SJohn Marino hints.ai_flags = AI_CANONNAME;
1806cdfca03SJohn Marino hints.ai_family = family;
1816cdfca03SJohn Marino hints.ai_socktype = SOCK_STREAM;
1826cdfca03SJohn Marino hints.ai_protocol = 0;
1836cdfca03SJohn Marino error = getaddrinfo(host, port, &hints, &res0);
1846cdfca03SJohn Marino if (error) {
1856cdfca03SJohn Marino warnx("Can't lookup `%s:%s': %s", host, port,
1866cdfca03SJohn Marino (error == EAI_SYSTEM) ? strerror(errno)
1876cdfca03SJohn Marino : gai_strerror(error));
1886cdfca03SJohn Marino code = -1;
1896cdfca03SJohn Marino return (0);
1906cdfca03SJohn Marino }
1916cdfca03SJohn Marino
1926cdfca03SJohn Marino if (res0->ai_canonname)
1936cdfca03SJohn Marino (void)strlcpy(hostnamebuf, res0->ai_canonname,
1946cdfca03SJohn Marino sizeof(hostnamebuf));
1956cdfca03SJohn Marino else
1966cdfca03SJohn Marino (void)strlcpy(hostnamebuf, host, sizeof(hostnamebuf));
1976cdfca03SJohn Marino hostname = hostnamebuf;
1986cdfca03SJohn Marino
1996cdfca03SJohn Marino for (res = res0; res; res = res->ai_next) {
2006cdfca03SJohn Marino char hname[NI_MAXHOST], sname[NI_MAXSERV];
2016cdfca03SJohn Marino
2026cdfca03SJohn Marino ai_unmapped(res);
2036cdfca03SJohn Marino if (getnameinfo(res->ai_addr, res->ai_addrlen,
2046cdfca03SJohn Marino hname, sizeof(hname), sname, sizeof(sname),
2056cdfca03SJohn Marino NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
2066cdfca03SJohn Marino strlcpy(hname, "?", sizeof(hname));
2076cdfca03SJohn Marino strlcpy(sname, "?", sizeof(sname));
2086cdfca03SJohn Marino }
2096cdfca03SJohn Marino if (verbose && res0->ai_next) {
2106cdfca03SJohn Marino /* if we have multiple possibilities */
211*3a184c67SAntonio Huete Jimenez #ifdef INET6
212*3a184c67SAntonio Huete Jimenez if(res->ai_family == AF_INET6) {
213*3a184c67SAntonio Huete Jimenez fprintf(ttyout, "Trying [%s]:%s ...\n", hname,
214*3a184c67SAntonio Huete Jimenez sname);
215*3a184c67SAntonio Huete Jimenez } else {
216*3a184c67SAntonio Huete Jimenez #endif
217*3a184c67SAntonio Huete Jimenez fprintf(ttyout, "Trying %s:%s ...\n", hname,
218*3a184c67SAntonio Huete Jimenez sname);
219*3a184c67SAntonio Huete Jimenez #ifdef INET6
220*3a184c67SAntonio Huete Jimenez }
221*3a184c67SAntonio Huete Jimenez #endif
2226cdfca03SJohn Marino }
2236cdfca03SJohn Marino s = socket(res->ai_family, SOCK_STREAM, res->ai_protocol);
2246cdfca03SJohn Marino if (s < 0) {
2256cdfca03SJohn Marino warn("Can't create socket for connection to `%s:%s'",
2266cdfca03SJohn Marino hname, sname);
2276cdfca03SJohn Marino continue;
2286cdfca03SJohn Marino }
2296cdfca03SJohn Marino if (ftp_connect(s, res->ai_addr, res->ai_addrlen,
2306cdfca03SJohn Marino verbose || !res->ai_next) < 0) {
2316cdfca03SJohn Marino close(s);
2326cdfca03SJohn Marino s = -1;
2336cdfca03SJohn Marino continue;
2346cdfca03SJohn Marino }
2356cdfca03SJohn Marino
2366cdfca03SJohn Marino /* finally we got one */
2376cdfca03SJohn Marino break;
2386cdfca03SJohn Marino }
2396cdfca03SJohn Marino if (s < 0) {
2406cdfca03SJohn Marino warnx("Can't connect to `%s:%s'", host, port);
2416cdfca03SJohn Marino code = -1;
2426cdfca03SJohn Marino freeaddrinfo(res0);
2436cdfca03SJohn Marino return 0;
2446cdfca03SJohn Marino }
2456cdfca03SJohn Marino memcpy(&hisctladdr.si_su, res->ai_addr, res->ai_addrlen);
2466cdfca03SJohn Marino hisctladdr.su_len = res->ai_addrlen;
2476cdfca03SJohn Marino freeaddrinfo(res0);
2486cdfca03SJohn Marino res0 = res = NULL;
2496cdfca03SJohn Marino
2506cdfca03SJohn Marino len = hisctladdr.su_len;
2516cdfca03SJohn Marino if (getsockname(s, (struct sockaddr *)&myctladdr.si_su, &len) == -1) {
2526cdfca03SJohn Marino warn("Can't determine my address of connection to `%s:%s'",
2536cdfca03SJohn Marino host, port);
2546cdfca03SJohn Marino code = -1;
2556cdfca03SJohn Marino goto bad;
2566cdfca03SJohn Marino }
2576cdfca03SJohn Marino myctladdr.su_len = len;
2586cdfca03SJohn Marino
2596cdfca03SJohn Marino #ifdef IPTOS_LOWDELAY
2606cdfca03SJohn Marino if (hisctladdr.su_family == AF_INET) {
2616cdfca03SJohn Marino int tos = IPTOS_LOWDELAY;
2626cdfca03SJohn Marino if (setsockopt(s, IPPROTO_IP, IP_TOS,
2636cdfca03SJohn Marino (void *)&tos, sizeof(tos)) == -1) {
2646cdfca03SJohn Marino DWARN("setsockopt %s (ignored)",
2656cdfca03SJohn Marino "IPTOS_LOWDELAY");
2666cdfca03SJohn Marino }
2676cdfca03SJohn Marino }
2686cdfca03SJohn Marino #endif
2696cdfca03SJohn Marino cin = fdopen(s, "r");
2706cdfca03SJohn Marino cout = fdopen(s, "w");
2716cdfca03SJohn Marino if (cin == NULL || cout == NULL) {
2726cdfca03SJohn Marino warnx("Can't fdopen socket");
2736cdfca03SJohn Marino if (cin)
2746cdfca03SJohn Marino (void)fclose(cin);
2756cdfca03SJohn Marino if (cout)
2766cdfca03SJohn Marino (void)fclose(cout);
2776cdfca03SJohn Marino code = -1;
2786cdfca03SJohn Marino goto bad;
2796cdfca03SJohn Marino }
2806cdfca03SJohn Marino if (verbose)
2816cdfca03SJohn Marino fprintf(ttyout, "Connected to %s.\n", hostname);
2826cdfca03SJohn Marino if (getreply(0) > 2) { /* read startup message from server */
2836cdfca03SJohn Marino if (cin)
2846cdfca03SJohn Marino (void)fclose(cin);
2856cdfca03SJohn Marino if (cout)
2866cdfca03SJohn Marino (void)fclose(cout);
2876cdfca03SJohn Marino code = -1;
2886cdfca03SJohn Marino goto bad;
2896cdfca03SJohn Marino }
2906cdfca03SJohn Marino
291*3a184c67SAntonio Huete Jimenez if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
292*3a184c67SAntonio Huete Jimenez (void *)&on, sizeof(on)) == -1) {
293*3a184c67SAntonio Huete Jimenez DWARN("setsockopt %s (ignored)", "SO_KEEPALIVE");
294*3a184c67SAntonio Huete Jimenez }
295*3a184c67SAntonio Huete Jimenez
2966cdfca03SJohn Marino if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE,
2976cdfca03SJohn Marino (void *)&on, sizeof(on)) == -1) {
2986cdfca03SJohn Marino DWARN("setsockopt %s (ignored)", "SO_OOBINLINE");
2996cdfca03SJohn Marino }
3006cdfca03SJohn Marino
3016cdfca03SJohn Marino return (hostname);
3026cdfca03SJohn Marino bad:
3036cdfca03SJohn Marino (void)close(s);
3046cdfca03SJohn Marino return (NULL);
3056cdfca03SJohn Marino }
3066cdfca03SJohn Marino
3076cdfca03SJohn Marino void
cmdabort(int notused)3086cdfca03SJohn Marino cmdabort(int notused)
3096cdfca03SJohn Marino {
3106cdfca03SJohn Marino int oerrno = errno;
3116cdfca03SJohn Marino
3126cdfca03SJohn Marino sigint_raised = 1;
3136cdfca03SJohn Marino alarmtimer(0);
3146cdfca03SJohn Marino if (fromatty)
3156cdfca03SJohn Marino write(fileno(ttyout), "\n", 1);
3166cdfca03SJohn Marino abrtflag++;
3176cdfca03SJohn Marino if (ptflag)
3186cdfca03SJohn Marino siglongjmp(ptabort, 1);
3196cdfca03SJohn Marino errno = oerrno;
3206cdfca03SJohn Marino }
3216cdfca03SJohn Marino
3226cdfca03SJohn Marino void
cmdtimeout(int notused)3236cdfca03SJohn Marino cmdtimeout(int notused)
3246cdfca03SJohn Marino {
3256cdfca03SJohn Marino int oerrno = errno;
3266cdfca03SJohn Marino
3276cdfca03SJohn Marino alarmtimer(0);
3286cdfca03SJohn Marino if (fromatty)
3296cdfca03SJohn Marino write(fileno(ttyout), "\n", 1);
3306cdfca03SJohn Marino timeoutflag++;
3316cdfca03SJohn Marino if (ptflag)
3326cdfca03SJohn Marino siglongjmp(ptabort, 1);
3336cdfca03SJohn Marino errno = oerrno;
3346cdfca03SJohn Marino }
3356cdfca03SJohn Marino
336*3a184c67SAntonio Huete Jimenez static int
issighandler(sigfunc func)337*3a184c67SAntonio Huete Jimenez issighandler(sigfunc func)
338*3a184c67SAntonio Huete Jimenez {
339*3a184c67SAntonio Huete Jimenez return (func != SIG_IGN &&
340*3a184c67SAntonio Huete Jimenez func != SIG_DFL &&
341*3a184c67SAntonio Huete Jimenez #ifdef SIG_HOLD
342*3a184c67SAntonio Huete Jimenez func != SIG_HOLD &&
343*3a184c67SAntonio Huete Jimenez #endif
344*3a184c67SAntonio Huete Jimenez func != SIG_ERR);
345*3a184c67SAntonio Huete Jimenez }
346*3a184c67SAntonio Huete Jimenez
3476cdfca03SJohn Marino /*VARARGS*/
3486cdfca03SJohn Marino int
command(const char * fmt,...)3496cdfca03SJohn Marino command(const char *fmt, ...)
3506cdfca03SJohn Marino {
3516cdfca03SJohn Marino va_list ap;
3526cdfca03SJohn Marino int r;
3536cdfca03SJohn Marino sigfunc oldsigint;
3546cdfca03SJohn Marino
3556cdfca03SJohn Marino #ifndef NO_DEBUG
3566cdfca03SJohn Marino if (ftp_debug) {
3576cdfca03SJohn Marino fputs("---> ", ttyout);
3586cdfca03SJohn Marino va_start(ap, fmt);
3596cdfca03SJohn Marino if (strncmp("PASS ", fmt, 5) == 0)
3606cdfca03SJohn Marino fputs("PASS XXXX", ttyout);
3616cdfca03SJohn Marino else if (strncmp("ACCT ", fmt, 5) == 0)
3626cdfca03SJohn Marino fputs("ACCT XXXX", ttyout);
3636cdfca03SJohn Marino else
3646cdfca03SJohn Marino vfprintf(ttyout, fmt, ap);
3656cdfca03SJohn Marino va_end(ap);
3666cdfca03SJohn Marino putc('\n', ttyout);
3676cdfca03SJohn Marino }
3686cdfca03SJohn Marino #endif
3696cdfca03SJohn Marino if (cout == NULL) {
3706cdfca03SJohn Marino warnx("No control connection for command");
3716cdfca03SJohn Marino code = -1;
3726cdfca03SJohn Marino return (0);
3736cdfca03SJohn Marino }
3746cdfca03SJohn Marino
3756cdfca03SJohn Marino abrtflag = 0;
3766cdfca03SJohn Marino
3776cdfca03SJohn Marino oldsigint = xsignal(SIGINT, cmdabort);
3786cdfca03SJohn Marino
3796cdfca03SJohn Marino va_start(ap, fmt);
3806cdfca03SJohn Marino vfprintf(cout, fmt, ap);
3816cdfca03SJohn Marino va_end(ap);
3826cdfca03SJohn Marino fputs("\r\n", cout);
3836cdfca03SJohn Marino (void)fflush(cout);
3846cdfca03SJohn Marino cpend = 1;
3856cdfca03SJohn Marino r = getreply(!strcmp(fmt, "QUIT"));
386*3a184c67SAntonio Huete Jimenez if (abrtflag && issighandler(oldsigint)) {
3876cdfca03SJohn Marino (*oldsigint)(SIGINT);
388*3a184c67SAntonio Huete Jimenez }
3896cdfca03SJohn Marino (void)xsignal(SIGINT, oldsigint);
3906cdfca03SJohn Marino return (r);
3916cdfca03SJohn Marino }
3926cdfca03SJohn Marino
3936cdfca03SJohn Marino static const char *m421[] = {
3946cdfca03SJohn Marino "remote server timed out. Connection closed",
3956cdfca03SJohn Marino "user interrupt. Connection closed",
3966cdfca03SJohn Marino "remote server has closed connection",
3976cdfca03SJohn Marino };
3986cdfca03SJohn Marino
3996cdfca03SJohn Marino int
getreply(int expecteof)4006cdfca03SJohn Marino getreply(int expecteof)
4016cdfca03SJohn Marino {
4026cdfca03SJohn Marino char current_line[BUFSIZ]; /* last line of previous reply */
4036cdfca03SJohn Marino int c, n, lineno;
4046cdfca03SJohn Marino int dig;
4056cdfca03SJohn Marino int originalcode = 0, continuation = 0;
4066cdfca03SJohn Marino sigfunc oldsigint, oldsigalrm;
4076cdfca03SJohn Marino int pflag = 0;
4086cdfca03SJohn Marino char *cp, *pt = pasv;
4096cdfca03SJohn Marino
4106cdfca03SJohn Marino abrtflag = 0;
4116cdfca03SJohn Marino timeoutflag = 0;
4126cdfca03SJohn Marino
4136cdfca03SJohn Marino oldsigint = xsignal(SIGINT, cmdabort);
4146cdfca03SJohn Marino oldsigalrm = xsignal(SIGALRM, cmdtimeout);
4156cdfca03SJohn Marino
4166cdfca03SJohn Marino for (lineno = 0 ;; lineno++) {
4176cdfca03SJohn Marino dig = n = code = 0;
4186cdfca03SJohn Marino cp = current_line;
4196cdfca03SJohn Marino while (alarmtimer(quit_time ? quit_time : 60),
4206cdfca03SJohn Marino ((c = getc(cin)) != '\n')) {
4216cdfca03SJohn Marino if (c == IAC) { /* handle telnet commands */
4226cdfca03SJohn Marino switch (c = getc(cin)) {
4236cdfca03SJohn Marino case WILL:
4246cdfca03SJohn Marino case WONT:
4256cdfca03SJohn Marino c = getc(cin);
4266cdfca03SJohn Marino fprintf(cout, "%c%c%c", IAC, DONT, c);
4276cdfca03SJohn Marino (void)fflush(cout);
4286cdfca03SJohn Marino break;
4296cdfca03SJohn Marino case DO:
4306cdfca03SJohn Marino case DONT:
4316cdfca03SJohn Marino c = getc(cin);
4326cdfca03SJohn Marino fprintf(cout, "%c%c%c", IAC, WONT, c);
4336cdfca03SJohn Marino (void)fflush(cout);
4346cdfca03SJohn Marino break;
4356cdfca03SJohn Marino default:
4366cdfca03SJohn Marino break;
4376cdfca03SJohn Marino }
4386cdfca03SJohn Marino continue;
4396cdfca03SJohn Marino }
4406cdfca03SJohn Marino dig++;
4416cdfca03SJohn Marino if (c == EOF) {
4426cdfca03SJohn Marino /*
4436cdfca03SJohn Marino * these will get trashed by pswitch()
4446cdfca03SJohn Marino * in lostpeer()
4456cdfca03SJohn Marino */
4466cdfca03SJohn Marino int reply_timeoutflag = timeoutflag;
4476cdfca03SJohn Marino int reply_abrtflag = abrtflag;
4486cdfca03SJohn Marino
4496cdfca03SJohn Marino alarmtimer(0);
4506cdfca03SJohn Marino if (expecteof && feof(cin)) {
4516cdfca03SJohn Marino (void)xsignal(SIGINT, oldsigint);
4526cdfca03SJohn Marino (void)xsignal(SIGALRM, oldsigalrm);
4536cdfca03SJohn Marino code = 221;
4546cdfca03SJohn Marino return (0);
4556cdfca03SJohn Marino }
4566cdfca03SJohn Marino cpend = 0;
4576cdfca03SJohn Marino lostpeer(0);
4586cdfca03SJohn Marino if (verbose) {
4596cdfca03SJohn Marino size_t midx;
4606cdfca03SJohn Marino if (reply_timeoutflag)
4616cdfca03SJohn Marino midx = 0;
4626cdfca03SJohn Marino else if (reply_abrtflag)
4636cdfca03SJohn Marino midx = 1;
4646cdfca03SJohn Marino else
4656cdfca03SJohn Marino midx = 2;
4666cdfca03SJohn Marino (void)fprintf(ttyout,
4676cdfca03SJohn Marino "421 Service not available, %s.\n", m421[midx]);
4686cdfca03SJohn Marino (void)fflush(ttyout);
4696cdfca03SJohn Marino }
4706cdfca03SJohn Marino code = 421;
4716cdfca03SJohn Marino (void)xsignal(SIGINT, oldsigint);
4726cdfca03SJohn Marino (void)xsignal(SIGALRM, oldsigalrm);
4736cdfca03SJohn Marino return (4);
4746cdfca03SJohn Marino }
4756cdfca03SJohn Marino if (c != '\r' && (verbose > 0 ||
4766cdfca03SJohn Marino ((verbose > -1 && n == '5' && dig > 4) &&
4776cdfca03SJohn Marino (((!n && c < '5') || (n && n < '5'))
4786cdfca03SJohn Marino || !retry_connect)))) {
4796cdfca03SJohn Marino if (proxflag &&
4806cdfca03SJohn Marino (dig == 1 || (dig == 5 && verbose == 0)))
4816cdfca03SJohn Marino fprintf(ttyout, "%s:", hostname);
4826cdfca03SJohn Marino (void)putc(c, ttyout);
4836cdfca03SJohn Marino }
4846cdfca03SJohn Marino if (dig < 4 && isdigit(c))
4856cdfca03SJohn Marino code = code * 10 + (c - '0');
4866cdfca03SJohn Marino if (!pflag && (code == 227 || code == 228))
4876cdfca03SJohn Marino pflag = 1;
4886cdfca03SJohn Marino else if (!pflag && code == 229)
4896cdfca03SJohn Marino pflag = 100;
4906cdfca03SJohn Marino if (dig > 4 && pflag == 1 && isdigit(c))
4916cdfca03SJohn Marino pflag = 2;
4926cdfca03SJohn Marino if (pflag == 2) {
4936cdfca03SJohn Marino if (c != '\r' && c != ')') {
4946cdfca03SJohn Marino if (pt < &pasv[sizeof(pasv) - 1])
4956cdfca03SJohn Marino *pt++ = c;
4966cdfca03SJohn Marino } else {
4976cdfca03SJohn Marino *pt = '\0';
4986cdfca03SJohn Marino pflag = 3;
4996cdfca03SJohn Marino }
5006cdfca03SJohn Marino }
5016cdfca03SJohn Marino if (pflag == 100 && c == '(')
5026cdfca03SJohn Marino pflag = 2;
5036cdfca03SJohn Marino if (dig == 4 && c == '-') {
5046cdfca03SJohn Marino if (continuation)
5056cdfca03SJohn Marino code = 0;
5066cdfca03SJohn Marino continuation++;
5076cdfca03SJohn Marino }
5086cdfca03SJohn Marino if (n == 0)
5096cdfca03SJohn Marino n = c;
5106cdfca03SJohn Marino if (cp < ¤t_line[sizeof(current_line) - 1])
5116cdfca03SJohn Marino *cp++ = c;
5126cdfca03SJohn Marino }
5136cdfca03SJohn Marino if (verbose > 0 || ((verbose > -1 && n == '5') &&
5146cdfca03SJohn Marino (n < '5' || !retry_connect))) {
5156cdfca03SJohn Marino (void)putc(c, ttyout);
5166cdfca03SJohn Marino (void)fflush(ttyout);
5176cdfca03SJohn Marino }
5186cdfca03SJohn Marino if (cp[-1] == '\r')
5196cdfca03SJohn Marino cp[-1] = '\0';
5206cdfca03SJohn Marino *cp = '\0';
5216cdfca03SJohn Marino if (lineno == 0)
5226cdfca03SJohn Marino (void)strlcpy(reply_string, current_line,
5236cdfca03SJohn Marino sizeof(reply_string));
5246cdfca03SJohn Marino if (lineno > 0 && code == 0 && reply_callback != NULL)
5256cdfca03SJohn Marino (*reply_callback)(current_line);
5266cdfca03SJohn Marino if (continuation && code != originalcode) {
5276cdfca03SJohn Marino if (originalcode == 0)
5286cdfca03SJohn Marino originalcode = code;
5296cdfca03SJohn Marino continue;
5306cdfca03SJohn Marino }
5316cdfca03SJohn Marino if (n != '1')
5326cdfca03SJohn Marino cpend = 0;
5336cdfca03SJohn Marino alarmtimer(0);
5346cdfca03SJohn Marino (void)xsignal(SIGINT, oldsigint);
5356cdfca03SJohn Marino (void)xsignal(SIGALRM, oldsigalrm);
5366cdfca03SJohn Marino if (code == 421 || originalcode == 421)
5376cdfca03SJohn Marino lostpeer(0);
538*3a184c67SAntonio Huete Jimenez if (abrtflag && oldsigint != cmdabort &&
539*3a184c67SAntonio Huete Jimenez issighandler(oldsigint)) {
5406cdfca03SJohn Marino (*oldsigint)(SIGINT);
541*3a184c67SAntonio Huete Jimenez }
5426cdfca03SJohn Marino if (timeoutflag && oldsigalrm != cmdtimeout &&
543*3a184c67SAntonio Huete Jimenez issighandler(oldsigalrm)) {
5446cdfca03SJohn Marino (*oldsigalrm)(SIGINT);
545*3a184c67SAntonio Huete Jimenez }
5466cdfca03SJohn Marino return (n - '0');
5476cdfca03SJohn Marino }
5486cdfca03SJohn Marino }
5496cdfca03SJohn Marino
5506cdfca03SJohn Marino static int
empty(FILE * ecin,FILE * din,int sec)5516cdfca03SJohn Marino empty(FILE *ecin, FILE *din, int sec)
5526cdfca03SJohn Marino {
5536cdfca03SJohn Marino int nr, nfd;
5546cdfca03SJohn Marino struct pollfd pfd[2];
5556cdfca03SJohn Marino
5566cdfca03SJohn Marino nfd = 0;
5576cdfca03SJohn Marino if (ecin) {
5586cdfca03SJohn Marino pfd[nfd].fd = fileno(ecin);
5596cdfca03SJohn Marino pfd[nfd++].events = POLLIN;
5606cdfca03SJohn Marino }
5616cdfca03SJohn Marino
5626cdfca03SJohn Marino if (din) {
5636cdfca03SJohn Marino pfd[nfd].fd = fileno(din);
5646cdfca03SJohn Marino pfd[nfd++].events = POLLIN;
5656cdfca03SJohn Marino }
5666cdfca03SJohn Marino
5676cdfca03SJohn Marino if ((nr = ftp_poll(pfd, nfd, sec * 1000)) <= 0)
5686cdfca03SJohn Marino return nr;
5696cdfca03SJohn Marino
5706cdfca03SJohn Marino nr = 0;
5716cdfca03SJohn Marino nfd = 0;
5726cdfca03SJohn Marino if (ecin)
5736cdfca03SJohn Marino nr |= (pfd[nfd++].revents & POLLIN) ? 1 : 0;
5746cdfca03SJohn Marino if (din)
5756cdfca03SJohn Marino nr |= (pfd[nfd++].revents & POLLIN) ? 2 : 0;
5766cdfca03SJohn Marino return nr;
5776cdfca03SJohn Marino }
5786cdfca03SJohn Marino
5796cdfca03SJohn Marino sigjmp_buf xferabort;
5806cdfca03SJohn Marino
5816cdfca03SJohn Marino __dead static void
abortxfer(int notused)5826cdfca03SJohn Marino abortxfer(int notused)
5836cdfca03SJohn Marino {
5846cdfca03SJohn Marino char msgbuf[100];
5856cdfca03SJohn Marino size_t len;
5866cdfca03SJohn Marino
5876cdfca03SJohn Marino sigint_raised = 1;
5886cdfca03SJohn Marino alarmtimer(0);
5896cdfca03SJohn Marino mflag = 0;
5906cdfca03SJohn Marino abrtflag = 0;
5916cdfca03SJohn Marino switch (direction[0]) {
5926cdfca03SJohn Marino case 'r':
5936cdfca03SJohn Marino strlcpy(msgbuf, "\nreceive", sizeof(msgbuf));
5946cdfca03SJohn Marino break;
5956cdfca03SJohn Marino case 's':
5966cdfca03SJohn Marino strlcpy(msgbuf, "\nsend", sizeof(msgbuf));
5976cdfca03SJohn Marino break;
5986cdfca03SJohn Marino default:
5996cdfca03SJohn Marino errx(1, "abortxfer: unknown direction `%s'", direction);
6006cdfca03SJohn Marino }
6016cdfca03SJohn Marino len = strlcat(msgbuf, " aborted. Waiting for remote to finish abort.\n",
6026cdfca03SJohn Marino sizeof(msgbuf));
6036cdfca03SJohn Marino write(fileno(ttyout), msgbuf, len);
6046cdfca03SJohn Marino siglongjmp(xferabort, 1);
6056cdfca03SJohn Marino }
6066cdfca03SJohn Marino
6076cdfca03SJohn Marino /*
6086cdfca03SJohn Marino * Read data from infd & write to outfd, using buf/bufsize as the temporary
609*3a184c67SAntonio Huete Jimenez * buffer, dealing with short reads or writes.
6106cdfca03SJohn Marino * If rate_limit != 0, rate-limit the transfer.
6116cdfca03SJohn Marino * If hash_interval != 0, fputc('c', ttyout) every hash_interval bytes.
6126cdfca03SJohn Marino * Updates global variables: bytes.
6136cdfca03SJohn Marino * Returns 0 if ok, 1 if there was a read error, 2 if there was a write error.
6146cdfca03SJohn Marino * In the case of error, errno contains the appropriate error code.
6156cdfca03SJohn Marino */
6166cdfca03SJohn Marino static int
copy_bytes(int infd,int outfd,char * buf,size_t bufsize,int rate_limit,int hash_interval)6176cdfca03SJohn Marino copy_bytes(int infd, int outfd, char *buf, size_t bufsize,
6186cdfca03SJohn Marino int rate_limit, int hash_interval)
6196cdfca03SJohn Marino {
6206cdfca03SJohn Marino volatile off_t hashc;
6216cdfca03SJohn Marino ssize_t inc, outc;
6226cdfca03SJohn Marino char *bufp;
6236cdfca03SJohn Marino struct timeval tvthen, tvnow, tvdiff;
6246cdfca03SJohn Marino off_t bufrem, bufchunk;
6256cdfca03SJohn Marino int serr;
6266cdfca03SJohn Marino
6276cdfca03SJohn Marino hashc = hash_interval;
6286cdfca03SJohn Marino if (rate_limit)
6296cdfca03SJohn Marino bufchunk = rate_limit;
6306cdfca03SJohn Marino else
6316cdfca03SJohn Marino bufchunk = bufsize;
6326cdfca03SJohn Marino
6336cdfca03SJohn Marino while (1) {
6346cdfca03SJohn Marino if (rate_limit) {
6356cdfca03SJohn Marino (void)gettimeofday(&tvthen, NULL);
6366cdfca03SJohn Marino }
6376cdfca03SJohn Marino errno = 0;
6386cdfca03SJohn Marino inc = outc = 0;
6396cdfca03SJohn Marino /* copy bufchunk at a time */
6406cdfca03SJohn Marino bufrem = bufchunk;
6416cdfca03SJohn Marino while (bufrem > 0) {
6426cdfca03SJohn Marino inc = read(infd, buf, MIN((off_t)bufsize, bufrem));
643*3a184c67SAntonio Huete Jimenez if (inc < 0) {
644*3a184c67SAntonio Huete Jimenez if (errno == EINTR || errno == EAGAIN) {
645*3a184c67SAntonio Huete Jimenez continue;
646*3a184c67SAntonio Huete Jimenez }
6476cdfca03SJohn Marino goto copy_done;
648*3a184c67SAntonio Huete Jimenez } else if (inc == 0) {
649*3a184c67SAntonio Huete Jimenez goto copy_done;
650*3a184c67SAntonio Huete Jimenez }
6516cdfca03SJohn Marino bytes += inc;
6526cdfca03SJohn Marino bufrem -= inc;
6536cdfca03SJohn Marino bufp = buf;
6546cdfca03SJohn Marino while (inc > 0) {
6556cdfca03SJohn Marino outc = write(outfd, bufp, inc);
656*3a184c67SAntonio Huete Jimenez if (outc < 0) {
657*3a184c67SAntonio Huete Jimenez if (errno == EINTR || errno == EAGAIN) {
658*3a184c67SAntonio Huete Jimenez continue;
659*3a184c67SAntonio Huete Jimenez }
6606cdfca03SJohn Marino goto copy_done;
661*3a184c67SAntonio Huete Jimenez }
6626cdfca03SJohn Marino inc -= outc;
6636cdfca03SJohn Marino bufp += outc;
6646cdfca03SJohn Marino }
6656cdfca03SJohn Marino if (hash_interval) {
6666cdfca03SJohn Marino while (bytes >= hashc) {
6676cdfca03SJohn Marino (void)putc('#', ttyout);
6686cdfca03SJohn Marino hashc += hash_interval;
6696cdfca03SJohn Marino }
6706cdfca03SJohn Marino (void)fflush(ttyout);
6716cdfca03SJohn Marino }
6726cdfca03SJohn Marino }
6736cdfca03SJohn Marino if (rate_limit) { /* rate limited; wait if necessary */
6746cdfca03SJohn Marino while (1) {
6756cdfca03SJohn Marino (void)gettimeofday(&tvnow, NULL);
6766cdfca03SJohn Marino timersub(&tvnow, &tvthen, &tvdiff);
6776cdfca03SJohn Marino if (tvdiff.tv_sec > 0)
6786cdfca03SJohn Marino break;
6796cdfca03SJohn Marino usleep(1000000 - tvdiff.tv_usec);
6806cdfca03SJohn Marino }
6816cdfca03SJohn Marino }
6826cdfca03SJohn Marino }
6836cdfca03SJohn Marino
6846cdfca03SJohn Marino copy_done:
6856cdfca03SJohn Marino serr = errno;
6866cdfca03SJohn Marino if (hash_interval && bytes > 0) {
6876cdfca03SJohn Marino if (bytes < hash_interval)
6886cdfca03SJohn Marino (void)putc('#', ttyout);
6896cdfca03SJohn Marino (void)putc('\n', ttyout);
6906cdfca03SJohn Marino (void)fflush(ttyout);
6916cdfca03SJohn Marino }
6926cdfca03SJohn Marino errno = serr;
6936cdfca03SJohn Marino if (inc == -1)
6946cdfca03SJohn Marino return 1;
6956cdfca03SJohn Marino if (outc == -1)
6966cdfca03SJohn Marino return 2;
6976cdfca03SJohn Marino
6986cdfca03SJohn Marino return 0;
6996cdfca03SJohn Marino }
7006cdfca03SJohn Marino
7016cdfca03SJohn Marino void
sendrequest(const char * cmd,const char * local,const char * remote,int printnames)7026cdfca03SJohn Marino sendrequest(const char *cmd, const char *local, const char *remote,
7036cdfca03SJohn Marino int printnames)
7046cdfca03SJohn Marino {
7056cdfca03SJohn Marino struct stat st;
7066cdfca03SJohn Marino int c;
7076cdfca03SJohn Marino FILE *volatile fin;
7086cdfca03SJohn Marino FILE *volatile dout;
7096cdfca03SJohn Marino int (*volatile closefunc)(FILE *);
7106cdfca03SJohn Marino sigfunc volatile oldintr;
711*3a184c67SAntonio Huete Jimenez sigfunc volatile oldpipe;
7126cdfca03SJohn Marino off_t volatile hashbytes;
7136cdfca03SJohn Marino int hash_interval;
7146cdfca03SJohn Marino const char *lmode;
7156cdfca03SJohn Marino static size_t bufsize;
7166cdfca03SJohn Marino static char *buf;
7176cdfca03SJohn Marino int oprogress;
7186cdfca03SJohn Marino
7196cdfca03SJohn Marino hashbytes = mark;
7206cdfca03SJohn Marino direction = "sent";
7216cdfca03SJohn Marino dout = NULL;
7226cdfca03SJohn Marino bytes = 0;
7236cdfca03SJohn Marino filesize = -1;
7246cdfca03SJohn Marino oprogress = progress;
7256cdfca03SJohn Marino if (verbose && printnames) {
7266cdfca03SJohn Marino if (*local != '-')
7276cdfca03SJohn Marino fprintf(ttyout, "local: %s ", local);
7286cdfca03SJohn Marino if (remote)
7296cdfca03SJohn Marino fprintf(ttyout, "remote: %s\n", remote);
7306cdfca03SJohn Marino }
7316cdfca03SJohn Marino if (proxy) {
7326cdfca03SJohn Marino proxtrans(cmd, local, remote);
7336cdfca03SJohn Marino return;
7346cdfca03SJohn Marino }
7356cdfca03SJohn Marino if (curtype != type)
7366cdfca03SJohn Marino changetype(type, 0);
7376cdfca03SJohn Marino closefunc = NULL;
738*3a184c67SAntonio Huete Jimenez oldintr = SIG_ERR;
739*3a184c67SAntonio Huete Jimenez oldpipe = SIG_ERR;
7406cdfca03SJohn Marino lmode = "w";
7416cdfca03SJohn Marino if (sigsetjmp(xferabort, 1)) {
7426cdfca03SJohn Marino while (cpend)
7436cdfca03SJohn Marino (void)getreply(0);
7446cdfca03SJohn Marino code = -1;
7456cdfca03SJohn Marino goto cleanupsend;
7466cdfca03SJohn Marino }
7476cdfca03SJohn Marino (void)xsignal(SIGQUIT, psummary);
7486cdfca03SJohn Marino oldintr = xsignal(SIGINT, abortxfer);
7496cdfca03SJohn Marino if (strcmp(local, "-") == 0) {
7506cdfca03SJohn Marino fin = stdin;
7516cdfca03SJohn Marino progress = 0;
7526cdfca03SJohn Marino } else if (*local == '|') {
753*3a184c67SAntonio Huete Jimenez oldpipe = xsignal(SIGPIPE, SIG_IGN);
7546cdfca03SJohn Marino fin = popen(local + 1, "r");
7556cdfca03SJohn Marino if (fin == NULL) {
7566cdfca03SJohn Marino warn("Can't execute `%s'", local + 1);
7576cdfca03SJohn Marino code = -1;
7586cdfca03SJohn Marino goto cleanupsend;
7596cdfca03SJohn Marino }
7606cdfca03SJohn Marino progress = 0;
7616cdfca03SJohn Marino closefunc = pclose;
7626cdfca03SJohn Marino } else {
7636cdfca03SJohn Marino fin = fopen(local, "r");
7646cdfca03SJohn Marino if (fin == NULL) {
7656cdfca03SJohn Marino warn("Can't open `%s'", local);
7666cdfca03SJohn Marino code = -1;
7676cdfca03SJohn Marino goto cleanupsend;
7686cdfca03SJohn Marino }
7696cdfca03SJohn Marino closefunc = fclose;
7706cdfca03SJohn Marino if (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) {
7716cdfca03SJohn Marino fprintf(ttyout, "%s: not a plain file.\n", local);
7726cdfca03SJohn Marino code = -1;
7736cdfca03SJohn Marino goto cleanupsend;
7746cdfca03SJohn Marino }
7756cdfca03SJohn Marino filesize = st.st_size;
7766cdfca03SJohn Marino }
7776cdfca03SJohn Marino if (initconn()) {
7786cdfca03SJohn Marino code = -1;
7796cdfca03SJohn Marino goto cleanupsend;
7806cdfca03SJohn Marino }
7816cdfca03SJohn Marino if (sigsetjmp(xferabort, 1))
7826cdfca03SJohn Marino goto abort;
7836cdfca03SJohn Marino
7846cdfca03SJohn Marino if (restart_point &&
7856cdfca03SJohn Marino (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
7866cdfca03SJohn Marino int rc;
7876cdfca03SJohn Marino
7886cdfca03SJohn Marino rc = -1;
7896cdfca03SJohn Marino switch (curtype) {
7906cdfca03SJohn Marino case TYPE_A:
7916cdfca03SJohn Marino rc = fseeko(fin, restart_point, SEEK_SET);
7926cdfca03SJohn Marino break;
7936cdfca03SJohn Marino case TYPE_I:
7946cdfca03SJohn Marino case TYPE_L:
7956cdfca03SJohn Marino rc = lseek(fileno(fin), restart_point, SEEK_SET);
7966cdfca03SJohn Marino break;
7976cdfca03SJohn Marino }
7986cdfca03SJohn Marino if (rc < 0) {
7996cdfca03SJohn Marino warn("Can't seek to restart `%s'", local);
8006cdfca03SJohn Marino goto cleanupsend;
8016cdfca03SJohn Marino }
8026cdfca03SJohn Marino if (command("REST " LLF, (LLT)restart_point) != CONTINUE)
8036cdfca03SJohn Marino goto cleanupsend;
8046cdfca03SJohn Marino lmode = "r+";
8056cdfca03SJohn Marino }
8066cdfca03SJohn Marino if (remote) {
8076cdfca03SJohn Marino if (command("%s %s", cmd, remote) != PRELIM)
8086cdfca03SJohn Marino goto cleanupsend;
8096cdfca03SJohn Marino } else {
8106cdfca03SJohn Marino if (command("%s", cmd) != PRELIM)
8116cdfca03SJohn Marino goto cleanupsend;
8126cdfca03SJohn Marino }
8136cdfca03SJohn Marino dirchange = 1;
8146cdfca03SJohn Marino dout = dataconn(lmode);
8156cdfca03SJohn Marino if (dout == NULL)
8166cdfca03SJohn Marino goto abort;
8176cdfca03SJohn Marino
8186cdfca03SJohn Marino assert(sndbuf_size > 0);
8196cdfca03SJohn Marino if ((size_t)sndbuf_size > bufsize) {
8206cdfca03SJohn Marino if (buf)
8216cdfca03SJohn Marino (void)free(buf);
8226cdfca03SJohn Marino bufsize = sndbuf_size;
8236cdfca03SJohn Marino buf = ftp_malloc(bufsize);
8246cdfca03SJohn Marino }
8256cdfca03SJohn Marino
8266cdfca03SJohn Marino progressmeter(-1);
827*3a184c67SAntonio Huete Jimenez if (oldpipe == SIG_ERR) {
828*3a184c67SAntonio Huete Jimenez oldpipe = xsignal(SIGPIPE, SIG_IGN);
829*3a184c67SAntonio Huete Jimenez }
8306cdfca03SJohn Marino hash_interval = (hash && (!progress || filesize < 0)) ? mark : 0;
8316cdfca03SJohn Marino
8326cdfca03SJohn Marino switch (curtype) {
8336cdfca03SJohn Marino
8346cdfca03SJohn Marino case TYPE_I:
8356cdfca03SJohn Marino case TYPE_L:
8366cdfca03SJohn Marino c = copy_bytes(fileno(fin), fileno(dout), buf, bufsize,
8376cdfca03SJohn Marino rate_put, hash_interval);
8386cdfca03SJohn Marino if (c == 1) {
8396cdfca03SJohn Marino warn("Reading `%s'", local);
8406cdfca03SJohn Marino } else if (c == 2) {
8416cdfca03SJohn Marino if (errno != EPIPE)
8426cdfca03SJohn Marino warn("Writing to network");
8436cdfca03SJohn Marino bytes = -1;
8446cdfca03SJohn Marino }
8456cdfca03SJohn Marino break;
8466cdfca03SJohn Marino
8476cdfca03SJohn Marino case TYPE_A:
8486cdfca03SJohn Marino while ((c = getc(fin)) != EOF) {
8496cdfca03SJohn Marino if (c == '\n') {
8506cdfca03SJohn Marino while (hash_interval && bytes >= hashbytes) {
8516cdfca03SJohn Marino (void)putc('#', ttyout);
8526cdfca03SJohn Marino (void)fflush(ttyout);
8536cdfca03SJohn Marino hashbytes += mark;
8546cdfca03SJohn Marino }
8556cdfca03SJohn Marino if (ferror(dout))
8566cdfca03SJohn Marino break;
8576cdfca03SJohn Marino (void)putc('\r', dout);
8586cdfca03SJohn Marino bytes++;
8596cdfca03SJohn Marino }
8606cdfca03SJohn Marino (void)putc(c, dout);
8616cdfca03SJohn Marino bytes++;
8626cdfca03SJohn Marino #if 0 /* this violates RFC 959 */
8636cdfca03SJohn Marino if (c == '\r') {
8646cdfca03SJohn Marino (void)putc('\0', dout);
8656cdfca03SJohn Marino bytes++;
8666cdfca03SJohn Marino }
8676cdfca03SJohn Marino #endif
8686cdfca03SJohn Marino }
8696cdfca03SJohn Marino if (hash_interval) {
8706cdfca03SJohn Marino if (bytes < hashbytes)
8716cdfca03SJohn Marino (void)putc('#', ttyout);
8726cdfca03SJohn Marino (void)putc('\n', ttyout);
8736cdfca03SJohn Marino }
8746cdfca03SJohn Marino if (ferror(fin))
8756cdfca03SJohn Marino warn("Reading `%s'", local);
8766cdfca03SJohn Marino if (ferror(dout)) {
8776cdfca03SJohn Marino if (errno != EPIPE)
8786cdfca03SJohn Marino warn("Writing to network");
8796cdfca03SJohn Marino bytes = -1;
8806cdfca03SJohn Marino }
8816cdfca03SJohn Marino break;
8826cdfca03SJohn Marino }
8836cdfca03SJohn Marino
8846cdfca03SJohn Marino progressmeter(1);
8856cdfca03SJohn Marino if (closefunc != NULL) {
8866cdfca03SJohn Marino (*closefunc)(fin);
8876cdfca03SJohn Marino fin = NULL;
8886cdfca03SJohn Marino }
8896cdfca03SJohn Marino (void)fclose(dout);
8906cdfca03SJohn Marino dout = NULL;
8916cdfca03SJohn Marino (void)getreply(0);
8926cdfca03SJohn Marino if (bytes > 0)
8936cdfca03SJohn Marino ptransfer(0);
8946cdfca03SJohn Marino goto cleanupsend;
8956cdfca03SJohn Marino
8966cdfca03SJohn Marino abort:
8976cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr);
898*3a184c67SAntonio Huete Jimenez oldintr = SIG_ERR;
8996cdfca03SJohn Marino if (!cpend) {
9006cdfca03SJohn Marino code = -1;
9016cdfca03SJohn Marino goto cleanupsend;
9026cdfca03SJohn Marino }
9036cdfca03SJohn Marino if (data >= 0) {
9046cdfca03SJohn Marino (void)close(data);
9056cdfca03SJohn Marino data = -1;
9066cdfca03SJohn Marino }
9076cdfca03SJohn Marino if (dout) {
9086cdfca03SJohn Marino (void)fclose(dout);
9096cdfca03SJohn Marino dout = NULL;
9106cdfca03SJohn Marino }
9116cdfca03SJohn Marino (void)getreply(0);
9126cdfca03SJohn Marino code = -1;
9136cdfca03SJohn Marino if (bytes > 0)
9146cdfca03SJohn Marino ptransfer(0);
9156cdfca03SJohn Marino
9166cdfca03SJohn Marino cleanupsend:
917*3a184c67SAntonio Huete Jimenez if (oldintr != SIG_ERR)
9186cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr);
919*3a184c67SAntonio Huete Jimenez if (oldpipe != SIG_ERR)
920*3a184c67SAntonio Huete Jimenez (void)xsignal(SIGPIPE, oldpipe);
9216cdfca03SJohn Marino if (data >= 0) {
9226cdfca03SJohn Marino (void)close(data);
9236cdfca03SJohn Marino data = -1;
9246cdfca03SJohn Marino }
9256cdfca03SJohn Marino if (closefunc != NULL && fin != NULL)
9266cdfca03SJohn Marino (*closefunc)(fin);
9276cdfca03SJohn Marino if (dout)
9286cdfca03SJohn Marino (void)fclose(dout);
9296cdfca03SJohn Marino progress = oprogress;
9306cdfca03SJohn Marino restart_point = 0;
9316cdfca03SJohn Marino bytes = 0;
9326cdfca03SJohn Marino }
9336cdfca03SJohn Marino
9346cdfca03SJohn Marino void
recvrequest(const char * cmd,const char * volatile local,const char * remote,const char * lmode,int printnames,int ignorespecial)9356cdfca03SJohn Marino recvrequest(const char *cmd, const char *volatile local, const char *remote,
9366cdfca03SJohn Marino const char *lmode, int printnames, int ignorespecial)
9376cdfca03SJohn Marino {
9386cdfca03SJohn Marino FILE *volatile fout;
9396cdfca03SJohn Marino FILE *volatile din;
9406cdfca03SJohn Marino int (*volatile closefunc)(FILE *);
9416cdfca03SJohn Marino sigfunc volatile oldintr;
942*3a184c67SAntonio Huete Jimenez sigfunc volatile oldpipe;
9436cdfca03SJohn Marino int c, d;
9446cdfca03SJohn Marino int volatile is_retr;
9456cdfca03SJohn Marino int volatile tcrflag;
9466cdfca03SJohn Marino int volatile bare_lfs;
9476cdfca03SJohn Marino static size_t bufsize;
9486cdfca03SJohn Marino static char *buf;
9496cdfca03SJohn Marino off_t volatile hashbytes;
9506cdfca03SJohn Marino int hash_interval;
9516cdfca03SJohn Marino struct stat st;
9526cdfca03SJohn Marino time_t mtime;
9536cdfca03SJohn Marino struct timeval tval[2];
9546cdfca03SJohn Marino int oprogress;
9556cdfca03SJohn Marino int opreserve;
9566cdfca03SJohn Marino
9576cdfca03SJohn Marino fout = NULL;
9586cdfca03SJohn Marino din = NULL;
9596cdfca03SJohn Marino hashbytes = mark;
9606cdfca03SJohn Marino direction = "received";
9616cdfca03SJohn Marino bytes = 0;
9626cdfca03SJohn Marino bare_lfs = 0;
9636cdfca03SJohn Marino filesize = -1;
9646cdfca03SJohn Marino oprogress = progress;
9656cdfca03SJohn Marino opreserve = preserve;
9666cdfca03SJohn Marino is_retr = (strcmp(cmd, "RETR") == 0);
9676cdfca03SJohn Marino if (is_retr && verbose && printnames) {
9686cdfca03SJohn Marino if (ignorespecial || *local != '-')
9696cdfca03SJohn Marino fprintf(ttyout, "local: %s ", local);
9706cdfca03SJohn Marino if (remote)
9716cdfca03SJohn Marino fprintf(ttyout, "remote: %s\n", remote);
9726cdfca03SJohn Marino }
9736cdfca03SJohn Marino if (proxy && is_retr) {
9746cdfca03SJohn Marino proxtrans(cmd, local, remote);
9756cdfca03SJohn Marino return;
9766cdfca03SJohn Marino }
9776cdfca03SJohn Marino closefunc = NULL;
978*3a184c67SAntonio Huete Jimenez oldintr = SIG_ERR;
979*3a184c67SAntonio Huete Jimenez oldpipe = SIG_ERR;
9806cdfca03SJohn Marino tcrflag = !crflag && is_retr;
9816cdfca03SJohn Marino if (sigsetjmp(xferabort, 1)) {
9826cdfca03SJohn Marino while (cpend)
9836cdfca03SJohn Marino (void)getreply(0);
9846cdfca03SJohn Marino code = -1;
9856cdfca03SJohn Marino goto cleanuprecv;
9866cdfca03SJohn Marino }
9876cdfca03SJohn Marino (void)xsignal(SIGQUIT, psummary);
9886cdfca03SJohn Marino oldintr = xsignal(SIGINT, abortxfer);
9896cdfca03SJohn Marino if (ignorespecial || (strcmp(local, "-") && *local != '|')) {
9906cdfca03SJohn Marino if (access(local, W_OK) < 0) {
9916cdfca03SJohn Marino char *dir = strrchr(local, '/');
9926cdfca03SJohn Marino
9936cdfca03SJohn Marino if (errno != ENOENT && errno != EACCES) {
9946cdfca03SJohn Marino warn("Can't access `%s'", local);
9956cdfca03SJohn Marino code = -1;
9966cdfca03SJohn Marino goto cleanuprecv;
9976cdfca03SJohn Marino }
9986cdfca03SJohn Marino if (dir != NULL)
9996cdfca03SJohn Marino *dir = 0;
10006cdfca03SJohn Marino d = access(dir == local ? "/" :
10016cdfca03SJohn Marino dir ? local : ".", W_OK);
10026cdfca03SJohn Marino if (dir != NULL)
10036cdfca03SJohn Marino *dir = '/';
10046cdfca03SJohn Marino if (d < 0) {
10056cdfca03SJohn Marino warn("Can't access `%s'", local);
10066cdfca03SJohn Marino code = -1;
10076cdfca03SJohn Marino goto cleanuprecv;
10086cdfca03SJohn Marino }
10096cdfca03SJohn Marino if (!runique && errno == EACCES &&
10106cdfca03SJohn Marino chmod(local, (S_IRUSR|S_IWUSR)) < 0) {
10116cdfca03SJohn Marino warn("Can't chmod `%s'", local);
10126cdfca03SJohn Marino code = -1;
10136cdfca03SJohn Marino goto cleanuprecv;
10146cdfca03SJohn Marino }
10156cdfca03SJohn Marino if (runique && errno == EACCES &&
10166cdfca03SJohn Marino (local = gunique(local)) == NULL) {
10176cdfca03SJohn Marino code = -1;
10186cdfca03SJohn Marino goto cleanuprecv;
10196cdfca03SJohn Marino }
10206cdfca03SJohn Marino }
10216cdfca03SJohn Marino else if (runique && (local = gunique(local)) == NULL) {
10226cdfca03SJohn Marino code = -1;
10236cdfca03SJohn Marino goto cleanuprecv;
10246cdfca03SJohn Marino }
10256cdfca03SJohn Marino }
10266cdfca03SJohn Marino if (!is_retr) {
10276cdfca03SJohn Marino if (curtype != TYPE_A)
10286cdfca03SJohn Marino changetype(TYPE_A, 0);
10296cdfca03SJohn Marino } else {
10306cdfca03SJohn Marino if (curtype != type)
10316cdfca03SJohn Marino changetype(type, 0);
10326cdfca03SJohn Marino filesize = remotesize(remote, 0);
10336cdfca03SJohn Marino if (code == 421 || code == -1)
10346cdfca03SJohn Marino goto cleanuprecv;
10356cdfca03SJohn Marino }
10366cdfca03SJohn Marino if (initconn()) {
10376cdfca03SJohn Marino code = -1;
10386cdfca03SJohn Marino goto cleanuprecv;
10396cdfca03SJohn Marino }
10406cdfca03SJohn Marino if (sigsetjmp(xferabort, 1))
10416cdfca03SJohn Marino goto abort;
10426cdfca03SJohn Marino if (is_retr && restart_point &&
10436cdfca03SJohn Marino command("REST " LLF, (LLT) restart_point) != CONTINUE)
10446cdfca03SJohn Marino goto cleanuprecv;
10456cdfca03SJohn Marino if (! EMPTYSTRING(remote)) {
10466cdfca03SJohn Marino if (command("%s %s", cmd, remote) != PRELIM)
10476cdfca03SJohn Marino goto cleanuprecv;
10486cdfca03SJohn Marino } else {
10496cdfca03SJohn Marino if (command("%s", cmd) != PRELIM)
10506cdfca03SJohn Marino goto cleanuprecv;
10516cdfca03SJohn Marino }
10526cdfca03SJohn Marino din = dataconn("r");
10536cdfca03SJohn Marino if (din == NULL)
10546cdfca03SJohn Marino goto abort;
10556cdfca03SJohn Marino if (!ignorespecial && strcmp(local, "-") == 0) {
10566cdfca03SJohn Marino fout = stdout;
10576cdfca03SJohn Marino progress = 0;
10586cdfca03SJohn Marino preserve = 0;
10596cdfca03SJohn Marino } else if (!ignorespecial && *local == '|') {
1060*3a184c67SAntonio Huete Jimenez oldpipe = xsignal(SIGPIPE, SIG_IGN);
10616cdfca03SJohn Marino fout = popen(local + 1, "w");
10626cdfca03SJohn Marino if (fout == NULL) {
10636cdfca03SJohn Marino warn("Can't execute `%s'", local+1);
10646cdfca03SJohn Marino goto abort;
10656cdfca03SJohn Marino }
10666cdfca03SJohn Marino progress = 0;
10676cdfca03SJohn Marino preserve = 0;
10686cdfca03SJohn Marino closefunc = pclose;
10696cdfca03SJohn Marino } else {
10706cdfca03SJohn Marino fout = fopen(local, lmode);
10716cdfca03SJohn Marino if (fout == NULL) {
10726cdfca03SJohn Marino warn("Can't open `%s'", local);
10736cdfca03SJohn Marino goto abort;
10746cdfca03SJohn Marino }
10756cdfca03SJohn Marino closefunc = fclose;
10766cdfca03SJohn Marino }
10776cdfca03SJohn Marino
10786cdfca03SJohn Marino if (fstat(fileno(fout), &st) != -1 && !S_ISREG(st.st_mode)) {
10796cdfca03SJohn Marino progress = 0;
10806cdfca03SJohn Marino preserve = 0;
10816cdfca03SJohn Marino }
10826cdfca03SJohn Marino assert(rcvbuf_size > 0);
10836cdfca03SJohn Marino if ((size_t)rcvbuf_size > bufsize) {
10846cdfca03SJohn Marino if (buf)
10856cdfca03SJohn Marino (void)free(buf);
10866cdfca03SJohn Marino bufsize = rcvbuf_size;
10876cdfca03SJohn Marino buf = ftp_malloc(bufsize);
10886cdfca03SJohn Marino }
10896cdfca03SJohn Marino
10906cdfca03SJohn Marino progressmeter(-1);
10916cdfca03SJohn Marino hash_interval = (hash && (!progress || filesize < 0)) ? mark : 0;
10926cdfca03SJohn Marino
10936cdfca03SJohn Marino switch (curtype) {
10946cdfca03SJohn Marino
10956cdfca03SJohn Marino case TYPE_I:
10966cdfca03SJohn Marino case TYPE_L:
10976cdfca03SJohn Marino if (is_retr && restart_point &&
10986cdfca03SJohn Marino lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
10996cdfca03SJohn Marino warn("Can't seek to restart `%s'", local);
11006cdfca03SJohn Marino goto cleanuprecv;
11016cdfca03SJohn Marino }
11026cdfca03SJohn Marino c = copy_bytes(fileno(din), fileno(fout), buf, bufsize,
11036cdfca03SJohn Marino rate_get, hash_interval);
11046cdfca03SJohn Marino if (c == 1) {
11056cdfca03SJohn Marino if (errno != EPIPE)
11066cdfca03SJohn Marino warn("Reading from network");
11076cdfca03SJohn Marino bytes = -1;
11086cdfca03SJohn Marino } else if (c == 2) {
11096cdfca03SJohn Marino warn("Writing `%s'", local);
11106cdfca03SJohn Marino }
11116cdfca03SJohn Marino break;
11126cdfca03SJohn Marino
11136cdfca03SJohn Marino case TYPE_A:
11146cdfca03SJohn Marino if (is_retr && restart_point) {
11156cdfca03SJohn Marino int ch;
11166cdfca03SJohn Marino off_t i;
11176cdfca03SJohn Marino
11186cdfca03SJohn Marino if (fseeko(fout, (off_t)0, SEEK_SET) < 0)
11196cdfca03SJohn Marino goto done;
11206cdfca03SJohn Marino for (i = 0; i++ < restart_point;) {
11216cdfca03SJohn Marino if ((ch = getc(fout)) == EOF)
11226cdfca03SJohn Marino goto done;
11236cdfca03SJohn Marino if (ch == '\n')
11246cdfca03SJohn Marino i++;
11256cdfca03SJohn Marino }
11266cdfca03SJohn Marino if (fseeko(fout, (off_t)0, SEEK_CUR) < 0) {
11276cdfca03SJohn Marino done:
11286cdfca03SJohn Marino warn("Can't seek to restart `%s'", local);
11296cdfca03SJohn Marino goto cleanuprecv;
11306cdfca03SJohn Marino }
11316cdfca03SJohn Marino }
11326cdfca03SJohn Marino while ((c = getc(din)) != EOF) {
11336cdfca03SJohn Marino if (c == '\n')
11346cdfca03SJohn Marino bare_lfs++;
11356cdfca03SJohn Marino while (c == '\r') {
11366cdfca03SJohn Marino while (hash_interval && bytes >= hashbytes) {
11376cdfca03SJohn Marino (void)putc('#', ttyout);
11386cdfca03SJohn Marino (void)fflush(ttyout);
11396cdfca03SJohn Marino hashbytes += mark;
11406cdfca03SJohn Marino }
11416cdfca03SJohn Marino bytes++;
11426cdfca03SJohn Marino if ((c = getc(din)) != '\n' || tcrflag) {
11436cdfca03SJohn Marino if (ferror(fout))
11446cdfca03SJohn Marino goto break2;
11456cdfca03SJohn Marino (void)putc('\r', fout);
11466cdfca03SJohn Marino if (c == '\0') {
11476cdfca03SJohn Marino bytes++;
11486cdfca03SJohn Marino goto contin2;
11496cdfca03SJohn Marino }
11506cdfca03SJohn Marino if (c == EOF)
11516cdfca03SJohn Marino goto contin2;
11526cdfca03SJohn Marino }
11536cdfca03SJohn Marino }
11546cdfca03SJohn Marino (void)putc(c, fout);
11556cdfca03SJohn Marino bytes++;
11566cdfca03SJohn Marino contin2: ;
11576cdfca03SJohn Marino }
11586cdfca03SJohn Marino break2:
11596cdfca03SJohn Marino if (hash_interval) {
11606cdfca03SJohn Marino if (bytes < hashbytes)
11616cdfca03SJohn Marino (void)putc('#', ttyout);
11626cdfca03SJohn Marino (void)putc('\n', ttyout);
11636cdfca03SJohn Marino }
11646cdfca03SJohn Marino if (ferror(din)) {
11656cdfca03SJohn Marino if (errno != EPIPE)
11666cdfca03SJohn Marino warn("Reading from network");
11676cdfca03SJohn Marino bytes = -1;
11686cdfca03SJohn Marino }
11696cdfca03SJohn Marino if (ferror(fout))
11706cdfca03SJohn Marino warn("Writing `%s'", local);
11716cdfca03SJohn Marino break;
11726cdfca03SJohn Marino }
11736cdfca03SJohn Marino
11746cdfca03SJohn Marino progressmeter(1);
11756cdfca03SJohn Marino if (closefunc != NULL) {
11766cdfca03SJohn Marino (*closefunc)(fout);
11776cdfca03SJohn Marino fout = NULL;
11786cdfca03SJohn Marino }
11796cdfca03SJohn Marino (void)fclose(din);
11806cdfca03SJohn Marino din = NULL;
11816cdfca03SJohn Marino (void)getreply(0);
11826cdfca03SJohn Marino if (bare_lfs) {
11836cdfca03SJohn Marino fprintf(ttyout,
11846cdfca03SJohn Marino "WARNING! %d bare linefeeds received in ASCII mode.\n",
11856cdfca03SJohn Marino bare_lfs);
11866cdfca03SJohn Marino fputs("File may not have transferred correctly.\n", ttyout);
11876cdfca03SJohn Marino }
11886cdfca03SJohn Marino if (bytes >= 0 && is_retr) {
11896cdfca03SJohn Marino if (bytes > 0)
11906cdfca03SJohn Marino ptransfer(0);
11916cdfca03SJohn Marino if (preserve && (closefunc == fclose)) {
11926cdfca03SJohn Marino mtime = remotemodtime(remote, 0);
11936cdfca03SJohn Marino if (mtime != -1) {
11946cdfca03SJohn Marino (void)gettimeofday(&tval[0], NULL);
11956cdfca03SJohn Marino tval[1].tv_sec = mtime;
11966cdfca03SJohn Marino tval[1].tv_usec = 0;
11976cdfca03SJohn Marino if (utimes(local, tval) == -1) {
11986cdfca03SJohn Marino fprintf(ttyout,
11996cdfca03SJohn Marino "Can't change modification time on %s to %s",
12006cdfca03SJohn Marino local,
12016cdfca03SJohn Marino rfc2822time(localtime(&mtime)));
12026cdfca03SJohn Marino }
12036cdfca03SJohn Marino }
12046cdfca03SJohn Marino }
12056cdfca03SJohn Marino }
12066cdfca03SJohn Marino goto cleanuprecv;
12076cdfca03SJohn Marino
12086cdfca03SJohn Marino abort:
12096cdfca03SJohn Marino /*
12106cdfca03SJohn Marino * abort using RFC 959 recommended IP,SYNC sequence
12116cdfca03SJohn Marino */
12126cdfca03SJohn Marino if (! sigsetjmp(xferabort, 1)) {
12136cdfca03SJohn Marino /* this is the first call */
12146cdfca03SJohn Marino (void)xsignal(SIGINT, abort_squared);
12156cdfca03SJohn Marino if (!cpend) {
12166cdfca03SJohn Marino code = -1;
12176cdfca03SJohn Marino goto cleanuprecv;
12186cdfca03SJohn Marino }
12196cdfca03SJohn Marino abort_remote(din);
12206cdfca03SJohn Marino }
12216cdfca03SJohn Marino code = -1;
12226cdfca03SJohn Marino if (bytes > 0)
12236cdfca03SJohn Marino ptransfer(0);
12246cdfca03SJohn Marino
12256cdfca03SJohn Marino cleanuprecv:
1226*3a184c67SAntonio Huete Jimenez if (oldintr != SIG_ERR)
12276cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr);
1228*3a184c67SAntonio Huete Jimenez if (oldpipe != SIG_ERR)
1229*3a184c67SAntonio Huete Jimenez (void)xsignal(SIGPIPE, oldpipe);
12306cdfca03SJohn Marino if (data >= 0) {
12316cdfca03SJohn Marino (void)close(data);
12326cdfca03SJohn Marino data = -1;
12336cdfca03SJohn Marino }
12346cdfca03SJohn Marino if (closefunc != NULL && fout != NULL)
12356cdfca03SJohn Marino (*closefunc)(fout);
12366cdfca03SJohn Marino if (din)
12376cdfca03SJohn Marino (void)fclose(din);
12386cdfca03SJohn Marino progress = oprogress;
12396cdfca03SJohn Marino preserve = opreserve;
12406cdfca03SJohn Marino bytes = 0;
12416cdfca03SJohn Marino }
12426cdfca03SJohn Marino
12436cdfca03SJohn Marino /*
12446cdfca03SJohn Marino * Need to start a listen on the data channel before we send the command,
12456cdfca03SJohn Marino * otherwise the server's connect may fail.
12466cdfca03SJohn Marino */
12476cdfca03SJohn Marino int
initconn(void)12486cdfca03SJohn Marino initconn(void)
12496cdfca03SJohn Marino {
12506cdfca03SJohn Marino char *p, *a;
12516cdfca03SJohn Marino int result, tmpno = 0;
12526cdfca03SJohn Marino int on = 1;
12536cdfca03SJohn Marino int error;
12546cdfca03SJohn Marino unsigned int addr[16], port[2];
12556cdfca03SJohn Marino unsigned int af, hal, pal;
12566cdfca03SJohn Marino socklen_t len;
12576cdfca03SJohn Marino const char *pasvcmd = NULL;
12586cdfca03SJohn Marino int overbose;
12596cdfca03SJohn Marino
12606cdfca03SJohn Marino #ifdef INET6
12616cdfca03SJohn Marino #ifndef NO_DEBUG
12626cdfca03SJohn Marino if (myctladdr.su_family == AF_INET6 && ftp_debug &&
12636cdfca03SJohn Marino (IN6_IS_ADDR_LINKLOCAL(&myctladdr.si_su.su_sin6.sin6_addr) ||
12646cdfca03SJohn Marino IN6_IS_ADDR_SITELOCAL(&myctladdr.si_su.su_sin6.sin6_addr))) {
12656cdfca03SJohn Marino warnx("Use of scoped addresses can be troublesome");
12666cdfca03SJohn Marino }
12676cdfca03SJohn Marino #endif
12686cdfca03SJohn Marino #endif
12696cdfca03SJohn Marino
12706cdfca03SJohn Marino reinit:
12716cdfca03SJohn Marino if (passivemode) {
12726cdfca03SJohn Marino data_addr = myctladdr;
12736cdfca03SJohn Marino data = socket(data_addr.su_family, SOCK_STREAM, 0);
12746cdfca03SJohn Marino if (data < 0) {
12756cdfca03SJohn Marino warn("Can't create socket for data connection");
12766cdfca03SJohn Marino return (1);
12776cdfca03SJohn Marino }
12786cdfca03SJohn Marino if ((options & SO_DEBUG) &&
12796cdfca03SJohn Marino setsockopt(data, SOL_SOCKET, SO_DEBUG,
12806cdfca03SJohn Marino (void *)&on, sizeof(on)) == -1) {
12816cdfca03SJohn Marino DWARN("setsockopt %s (ignored)", "SO_DEBUG");
12826cdfca03SJohn Marino }
12836cdfca03SJohn Marino result = COMPLETE + 1;
12846cdfca03SJohn Marino switch (data_addr.su_family) {
12856cdfca03SJohn Marino case AF_INET:
12866cdfca03SJohn Marino if (epsv4 && !epsv4bad) {
12876cdfca03SJohn Marino pasvcmd = "EPSV";
12886cdfca03SJohn Marino overbose = verbose;
12896cdfca03SJohn Marino if (ftp_debug == 0)
12906cdfca03SJohn Marino verbose = -1;
12916cdfca03SJohn Marino result = command("EPSV");
12926cdfca03SJohn Marino verbose = overbose;
12936cdfca03SJohn Marino if (verbose > 0 &&
12946cdfca03SJohn Marino (result == COMPLETE || !connected))
12956cdfca03SJohn Marino fprintf(ttyout, "%s\n", reply_string);
12966cdfca03SJohn Marino if (!connected)
12976cdfca03SJohn Marino return (1);
12986cdfca03SJohn Marino /*
12996cdfca03SJohn Marino * this code is to be friendly with broken
13006cdfca03SJohn Marino * BSDI ftpd
13016cdfca03SJohn Marino */
13026cdfca03SJohn Marino if (code / 10 == 22 && code != 229) {
13036cdfca03SJohn Marino fputs(
13046cdfca03SJohn Marino "wrong server: return code must be 229\n",
13056cdfca03SJohn Marino ttyout);
13066cdfca03SJohn Marino result = COMPLETE + 1;
13076cdfca03SJohn Marino }
13086cdfca03SJohn Marino if (result != COMPLETE) {
13096cdfca03SJohn Marino epsv4bad = 1;
13106cdfca03SJohn Marino DPRINTF("disabling epsv4 for this "
13116cdfca03SJohn Marino "connection\n");
13126cdfca03SJohn Marino }
13136cdfca03SJohn Marino }
13146cdfca03SJohn Marino if (result != COMPLETE) {
13156cdfca03SJohn Marino pasvcmd = "PASV";
13166cdfca03SJohn Marino result = command("PASV");
13176cdfca03SJohn Marino if (!connected)
13186cdfca03SJohn Marino return (1);
13196cdfca03SJohn Marino }
13206cdfca03SJohn Marino break;
13216cdfca03SJohn Marino #ifdef INET6
13226cdfca03SJohn Marino case AF_INET6:
13236cdfca03SJohn Marino if (epsv6 && !epsv6bad) {
13246cdfca03SJohn Marino pasvcmd = "EPSV";
13256cdfca03SJohn Marino overbose = verbose;
13266cdfca03SJohn Marino if (ftp_debug == 0)
13276cdfca03SJohn Marino verbose = -1;
13286cdfca03SJohn Marino result = command("EPSV");
13296cdfca03SJohn Marino verbose = overbose;
13306cdfca03SJohn Marino if (verbose > 0 &&
13316cdfca03SJohn Marino (result == COMPLETE || !connected))
13326cdfca03SJohn Marino fprintf(ttyout, "%s\n", reply_string);
13336cdfca03SJohn Marino if (!connected)
13346cdfca03SJohn Marino return (1);
13356cdfca03SJohn Marino /*
13366cdfca03SJohn Marino * this code is to be friendly with
13376cdfca03SJohn Marino * broken BSDI ftpd
13386cdfca03SJohn Marino */
13396cdfca03SJohn Marino if (code / 10 == 22 && code != 229) {
13406cdfca03SJohn Marino fputs(
13416cdfca03SJohn Marino "wrong server: return code must be 229\n",
13426cdfca03SJohn Marino ttyout);
13436cdfca03SJohn Marino result = COMPLETE + 1;
13446cdfca03SJohn Marino }
13456cdfca03SJohn Marino if (result != COMPLETE) {
13466cdfca03SJohn Marino epsv6bad = 1;
13476cdfca03SJohn Marino DPRINTF("disabling epsv6 for this "
13486cdfca03SJohn Marino "connection\n");
13496cdfca03SJohn Marino }
13506cdfca03SJohn Marino }
13516cdfca03SJohn Marino if (result != COMPLETE) {
13526cdfca03SJohn Marino pasvcmd = "LPSV";
13536cdfca03SJohn Marino result = command("LPSV");
13546cdfca03SJohn Marino }
13556cdfca03SJohn Marino if (!connected)
13566cdfca03SJohn Marino return (1);
13576cdfca03SJohn Marino break;
13586cdfca03SJohn Marino #endif
13596cdfca03SJohn Marino default:
13606cdfca03SJohn Marino result = COMPLETE + 1;
13616cdfca03SJohn Marino break;
13626cdfca03SJohn Marino }
13636cdfca03SJohn Marino if (result != COMPLETE) {
13646cdfca03SJohn Marino if (activefallback) {
13656cdfca03SJohn Marino (void)close(data);
13666cdfca03SJohn Marino data = -1;
13676cdfca03SJohn Marino passivemode = 0;
13686cdfca03SJohn Marino #if 0
13696cdfca03SJohn Marino activefallback = 0;
13706cdfca03SJohn Marino #endif
13716cdfca03SJohn Marino goto reinit;
13726cdfca03SJohn Marino }
13736cdfca03SJohn Marino fputs("Passive mode refused.\n", ttyout);
13746cdfca03SJohn Marino goto bad;
13756cdfca03SJohn Marino }
13766cdfca03SJohn Marino
13776cdfca03SJohn Marino #define pack2(var, off) \
13786cdfca03SJohn Marino (((var[(off) + 0] & 0xff) << 8) | ((var[(off) + 1] & 0xff) << 0))
13796cdfca03SJohn Marino #define pack4(var, off) \
13806cdfca03SJohn Marino (((var[(off) + 0] & 0xff) << 24) | ((var[(off) + 1] & 0xff) << 16) | \
13816cdfca03SJohn Marino ((var[(off) + 2] & 0xff) << 8) | ((var[(off) + 3] & 0xff) << 0))
13826cdfca03SJohn Marino #define UC(b) (((int)b)&0xff)
13836cdfca03SJohn Marino
13846cdfca03SJohn Marino /*
13856cdfca03SJohn Marino * What we've got at this point is a string of comma separated
13866cdfca03SJohn Marino * one-byte unsigned integer values, separated by commas.
13876cdfca03SJohn Marino */
13886cdfca03SJohn Marino if (strcmp(pasvcmd, "PASV") == 0) {
13896cdfca03SJohn Marino if (data_addr.su_family != AF_INET) {
13906cdfca03SJohn Marino fputs(
13916cdfca03SJohn Marino "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
13926cdfca03SJohn Marino goto bad;
13936cdfca03SJohn Marino }
13946cdfca03SJohn Marino if (code / 10 == 22 && code != 227) {
13956cdfca03SJohn Marino fputs("wrong server: return code must be 227\n",
13966cdfca03SJohn Marino ttyout);
13976cdfca03SJohn Marino goto bad;
13986cdfca03SJohn Marino }
13996cdfca03SJohn Marino error = sscanf(pasv, "%u,%u,%u,%u,%u,%u",
14006cdfca03SJohn Marino &addr[0], &addr[1], &addr[2], &addr[3],
14016cdfca03SJohn Marino &port[0], &port[1]);
14026cdfca03SJohn Marino if (error != 6) {
14036cdfca03SJohn Marino fputs(
14046cdfca03SJohn Marino "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
14056cdfca03SJohn Marino goto bad;
14066cdfca03SJohn Marino }
14076cdfca03SJohn Marino memset(&data_addr, 0, sizeof(data_addr));
14086cdfca03SJohn Marino data_addr.su_family = AF_INET;
14096cdfca03SJohn Marino data_addr.su_len = sizeof(struct sockaddr_in);
14106cdfca03SJohn Marino data_addr.si_su.su_sin.sin_addr.s_addr =
14116cdfca03SJohn Marino htonl(pack4(addr, 0));
14126cdfca03SJohn Marino data_addr.su_port = htons(pack2(port, 0));
1413*3a184c67SAntonio Huete Jimenez if (data_addr.si_su.su_sin.sin_addr.s_addr !=
1414*3a184c67SAntonio Huete Jimenez hisctladdr.si_su.su_sin.sin_addr.s_addr) {
1415*3a184c67SAntonio Huete Jimenez fputs("Passive mode address mismatch.\n",
1416*3a184c67SAntonio Huete Jimenez ttyout);
1417*3a184c67SAntonio Huete Jimenez goto bad;
1418*3a184c67SAntonio Huete Jimenez }
14196cdfca03SJohn Marino } else if (strcmp(pasvcmd, "LPSV") == 0) {
14206cdfca03SJohn Marino if (code / 10 == 22 && code != 228) {
14216cdfca03SJohn Marino fputs("wrong server: return code must be 228\n",
14226cdfca03SJohn Marino ttyout);
14236cdfca03SJohn Marino goto bad;
14246cdfca03SJohn Marino }
14256cdfca03SJohn Marino switch (data_addr.su_family) {
14266cdfca03SJohn Marino case AF_INET:
14276cdfca03SJohn Marino error = sscanf(pasv,
14286cdfca03SJohn Marino "%u,%u,%u,%u,%u,%u,%u,%u,%u",
14296cdfca03SJohn Marino &af, &hal,
14306cdfca03SJohn Marino &addr[0], &addr[1], &addr[2], &addr[3],
14316cdfca03SJohn Marino &pal, &port[0], &port[1]);
14326cdfca03SJohn Marino if (error != 9) {
14336cdfca03SJohn Marino fputs(
14346cdfca03SJohn Marino "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
14356cdfca03SJohn Marino goto bad;
14366cdfca03SJohn Marino }
14376cdfca03SJohn Marino if (af != 4 || hal != 4 || pal != 2) {
14386cdfca03SJohn Marino fputs(
14396cdfca03SJohn Marino "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
14406cdfca03SJohn Marino goto bad;
14416cdfca03SJohn Marino }
14426cdfca03SJohn Marino
14436cdfca03SJohn Marino memset(&data_addr, 0, sizeof(data_addr));
14446cdfca03SJohn Marino data_addr.su_family = AF_INET;
14456cdfca03SJohn Marino data_addr.su_len = sizeof(struct sockaddr_in);
14466cdfca03SJohn Marino data_addr.si_su.su_sin.sin_addr.s_addr =
14476cdfca03SJohn Marino htonl(pack4(addr, 0));
14486cdfca03SJohn Marino data_addr.su_port = htons(pack2(port, 0));
1449*3a184c67SAntonio Huete Jimenez if (data_addr.si_su.su_sin.sin_addr.s_addr !=
1450*3a184c67SAntonio Huete Jimenez hisctladdr.si_su.su_sin.sin_addr.s_addr) {
1451*3a184c67SAntonio Huete Jimenez fputs("Passive mode address mismatch.\n",
1452*3a184c67SAntonio Huete Jimenez ttyout);
1453*3a184c67SAntonio Huete Jimenez goto bad;
1454*3a184c67SAntonio Huete Jimenez }
14556cdfca03SJohn Marino break;
14566cdfca03SJohn Marino #ifdef INET6
14576cdfca03SJohn Marino case AF_INET6:
14586cdfca03SJohn Marino error = sscanf(pasv,
14596cdfca03SJohn Marino "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
14606cdfca03SJohn Marino &af, &hal,
14616cdfca03SJohn Marino &addr[0], &addr[1], &addr[2], &addr[3],
14626cdfca03SJohn Marino &addr[4], &addr[5], &addr[6], &addr[7],
14636cdfca03SJohn Marino &addr[8], &addr[9], &addr[10],
14646cdfca03SJohn Marino &addr[11], &addr[12], &addr[13],
14656cdfca03SJohn Marino &addr[14], &addr[15],
14666cdfca03SJohn Marino &pal, &port[0], &port[1]);
14676cdfca03SJohn Marino if (error != 21) {
14686cdfca03SJohn Marino fputs(
14696cdfca03SJohn Marino "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
14706cdfca03SJohn Marino goto bad;
14716cdfca03SJohn Marino }
14726cdfca03SJohn Marino if (af != 6 || hal != 16 || pal != 2) {
14736cdfca03SJohn Marino fputs(
14746cdfca03SJohn Marino "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
14756cdfca03SJohn Marino goto bad;
14766cdfca03SJohn Marino }
14776cdfca03SJohn Marino
14786cdfca03SJohn Marino memset(&data_addr, 0, sizeof(data_addr));
14796cdfca03SJohn Marino data_addr.su_family = AF_INET6;
14806cdfca03SJohn Marino data_addr.su_len = sizeof(struct sockaddr_in6);
14816cdfca03SJohn Marino {
14826cdfca03SJohn Marino size_t i;
14836cdfca03SJohn Marino for (i = 0; i < sizeof(struct in6_addr); i++) {
14846cdfca03SJohn Marino data_addr.si_su.su_sin6.sin6_addr.s6_addr[i] =
14856cdfca03SJohn Marino UC(addr[i]);
14866cdfca03SJohn Marino }
14876cdfca03SJohn Marino }
14886cdfca03SJohn Marino data_addr.su_port = htons(pack2(port, 0));
1489*3a184c67SAntonio Huete Jimenez if (memcmp(
1490*3a184c67SAntonio Huete Jimenez &data_addr.si_su.su_sin6.sin6_addr,
1491*3a184c67SAntonio Huete Jimenez &hisctladdr.si_su.su_sin6.sin6_addr,
1492*3a184c67SAntonio Huete Jimenez sizeof(data_addr.si_su.su_sin6.sin6_addr))) {
1493*3a184c67SAntonio Huete Jimenez fputs("Passive mode address mismatch.\n",
1494*3a184c67SAntonio Huete Jimenez ttyout);
1495*3a184c67SAntonio Huete Jimenez goto bad;
1496*3a184c67SAntonio Huete Jimenez }
14976cdfca03SJohn Marino break;
14986cdfca03SJohn Marino #endif
14996cdfca03SJohn Marino default:
1500*3a184c67SAntonio Huete Jimenez fputs("Unknown passive mode AF.\n", ttyout);
1501*3a184c67SAntonio Huete Jimenez goto bad;
15026cdfca03SJohn Marino }
15036cdfca03SJohn Marino } else if (strcmp(pasvcmd, "EPSV") == 0) {
15046cdfca03SJohn Marino char delim[4];
15056cdfca03SJohn Marino
15066cdfca03SJohn Marino port[0] = 0;
15076cdfca03SJohn Marino if (code / 10 == 22 && code != 229) {
15086cdfca03SJohn Marino fputs("wrong server: return code must be 229\n",
15096cdfca03SJohn Marino ttyout);
15106cdfca03SJohn Marino goto bad;
15116cdfca03SJohn Marino }
15126cdfca03SJohn Marino if (sscanf(pasv, "%c%c%c%d%c", &delim[0],
15136cdfca03SJohn Marino &delim[1], &delim[2], &port[1],
15146cdfca03SJohn Marino &delim[3]) != 5) {
15156cdfca03SJohn Marino fputs("parse error!\n", ttyout);
15166cdfca03SJohn Marino goto bad;
15176cdfca03SJohn Marino }
15186cdfca03SJohn Marino if (delim[0] != delim[1] || delim[0] != delim[2]
15196cdfca03SJohn Marino || delim[0] != delim[3]) {
15206cdfca03SJohn Marino fputs("parse error!\n", ttyout);
15216cdfca03SJohn Marino goto bad;
15226cdfca03SJohn Marino }
15236cdfca03SJohn Marino data_addr = hisctladdr;
15246cdfca03SJohn Marino data_addr.su_port = htons(port[1]);
15256cdfca03SJohn Marino } else
15266cdfca03SJohn Marino goto bad;
15276cdfca03SJohn Marino
15286cdfca03SJohn Marino if (ftp_connect(data, (struct sockaddr *)&data_addr.si_su,
15296cdfca03SJohn Marino data_addr.su_len, 1) < 0) {
15306cdfca03SJohn Marino if (activefallback) {
15316cdfca03SJohn Marino (void)close(data);
15326cdfca03SJohn Marino data = -1;
15336cdfca03SJohn Marino passivemode = 0;
15346cdfca03SJohn Marino #if 0
15356cdfca03SJohn Marino activefallback = 0;
15366cdfca03SJohn Marino #endif
15376cdfca03SJohn Marino goto reinit;
15386cdfca03SJohn Marino }
15396cdfca03SJohn Marino goto bad;
15406cdfca03SJohn Marino }
15416cdfca03SJohn Marino #ifdef IPTOS_THROUGHPUT
15426cdfca03SJohn Marino if (data_addr.su_family == AF_INET) {
15436cdfca03SJohn Marino on = IPTOS_THROUGHPUT;
15446cdfca03SJohn Marino if (setsockopt(data, IPPROTO_IP, IP_TOS,
15456cdfca03SJohn Marino (void *)&on, sizeof(on)) == -1) {
15466cdfca03SJohn Marino DWARN("setsockopt %s (ignored)",
15476cdfca03SJohn Marino "IPTOS_THROUGHPUT");
15486cdfca03SJohn Marino }
15496cdfca03SJohn Marino }
15506cdfca03SJohn Marino #endif
15516cdfca03SJohn Marino return (0);
15526cdfca03SJohn Marino }
15536cdfca03SJohn Marino
15546cdfca03SJohn Marino noport:
15556cdfca03SJohn Marino data_addr = myctladdr;
15566cdfca03SJohn Marino if (sendport)
15576cdfca03SJohn Marino data_addr.su_port = 0; /* let system pick one */
15586cdfca03SJohn Marino if (data != -1)
15596cdfca03SJohn Marino (void)close(data);
15606cdfca03SJohn Marino data = socket(data_addr.su_family, SOCK_STREAM, 0);
15616cdfca03SJohn Marino if (data < 0) {
15626cdfca03SJohn Marino warn("Can't create socket for data connection");
15636cdfca03SJohn Marino if (tmpno)
15646cdfca03SJohn Marino sendport = 1;
15656cdfca03SJohn Marino return (1);
15666cdfca03SJohn Marino }
15676cdfca03SJohn Marino if (!sendport)
15686cdfca03SJohn Marino if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR,
15696cdfca03SJohn Marino (void *)&on, sizeof(on)) == -1) {
15706cdfca03SJohn Marino warn("Can't set SO_REUSEADDR on data connection");
15716cdfca03SJohn Marino goto bad;
15726cdfca03SJohn Marino }
15736cdfca03SJohn Marino if (bind(data, (struct sockaddr *)&data_addr.si_su,
15746cdfca03SJohn Marino data_addr.su_len) < 0) {
15756cdfca03SJohn Marino warn("Can't bind for data connection");
15766cdfca03SJohn Marino goto bad;
15776cdfca03SJohn Marino }
15786cdfca03SJohn Marino if ((options & SO_DEBUG) &&
15796cdfca03SJohn Marino setsockopt(data, SOL_SOCKET, SO_DEBUG,
15806cdfca03SJohn Marino (void *)&on, sizeof(on)) == -1) {
15816cdfca03SJohn Marino DWARN("setsockopt %s (ignored)", "SO_DEBUG");
15826cdfca03SJohn Marino }
15836cdfca03SJohn Marino len = sizeof(data_addr.si_su);
15846cdfca03SJohn Marino memset((char *)&data_addr, 0, sizeof (data_addr));
15856cdfca03SJohn Marino if (getsockname(data, (struct sockaddr *)&data_addr.si_su, &len) == -1) {
15866cdfca03SJohn Marino warn("Can't determine my address of data connection");
15876cdfca03SJohn Marino goto bad;
15886cdfca03SJohn Marino }
15896cdfca03SJohn Marino data_addr.su_len = len;
15906cdfca03SJohn Marino if (ftp_listen(data, 1) < 0)
15916cdfca03SJohn Marino warn("Can't listen to data connection");
15926cdfca03SJohn Marino
15936cdfca03SJohn Marino if (sendport) {
15946cdfca03SJohn Marino char hname[NI_MAXHOST], sname[NI_MAXSERV];
15956cdfca03SJohn Marino struct sockinet tmp;
15966cdfca03SJohn Marino
15976cdfca03SJohn Marino switch (data_addr.su_family) {
15986cdfca03SJohn Marino case AF_INET:
15996cdfca03SJohn Marino if (!epsv4 || epsv4bad) {
16006cdfca03SJohn Marino result = COMPLETE + 1;
16016cdfca03SJohn Marino break;
16026cdfca03SJohn Marino }
16036cdfca03SJohn Marino #ifdef INET6
1604*3a184c67SAntonio Huete Jimenez /* FALLTHROUGH */
16056cdfca03SJohn Marino case AF_INET6:
16066cdfca03SJohn Marino if (!epsv6 || epsv6bad) {
16076cdfca03SJohn Marino result = COMPLETE + 1;
16086cdfca03SJohn Marino break;
16096cdfca03SJohn Marino }
16106cdfca03SJohn Marino #endif
16116cdfca03SJohn Marino af = (data_addr.su_family == AF_INET) ? 1 : 2;
16126cdfca03SJohn Marino tmp = data_addr;
16136cdfca03SJohn Marino #ifdef INET6
16146cdfca03SJohn Marino if (tmp.su_family == AF_INET6)
16156cdfca03SJohn Marino tmp.si_su.su_sin6.sin6_scope_id = 0;
16166cdfca03SJohn Marino #endif
16176cdfca03SJohn Marino if (getnameinfo((struct sockaddr *)&tmp.si_su,
16186cdfca03SJohn Marino tmp.su_len, hname, sizeof(hname), sname,
16196cdfca03SJohn Marino sizeof(sname), NI_NUMERICHOST | NI_NUMERICSERV)) {
16206cdfca03SJohn Marino result = ERROR;
16216cdfca03SJohn Marino } else {
16226cdfca03SJohn Marino overbose = verbose;
16236cdfca03SJohn Marino if (ftp_debug == 0)
16246cdfca03SJohn Marino verbose = -1;
16256cdfca03SJohn Marino result = command("EPRT |%u|%s|%s|", af, hname,
16266cdfca03SJohn Marino sname);
16276cdfca03SJohn Marino verbose = overbose;
16286cdfca03SJohn Marino if (verbose > 0 &&
16296cdfca03SJohn Marino (result == COMPLETE || !connected))
16306cdfca03SJohn Marino fprintf(ttyout, "%s\n", reply_string);
16316cdfca03SJohn Marino if (!connected)
16326cdfca03SJohn Marino return (1);
16336cdfca03SJohn Marino if (result != COMPLETE) {
16346cdfca03SJohn Marino epsv4bad = 1;
16356cdfca03SJohn Marino DPRINTF("disabling epsv4 for this "
16366cdfca03SJohn Marino "connection\n");
16376cdfca03SJohn Marino }
16386cdfca03SJohn Marino }
16396cdfca03SJohn Marino break;
16406cdfca03SJohn Marino default:
16416cdfca03SJohn Marino result = COMPLETE + 1;
16426cdfca03SJohn Marino break;
16436cdfca03SJohn Marino }
16446cdfca03SJohn Marino if (result == COMPLETE)
16456cdfca03SJohn Marino goto skip_port;
16466cdfca03SJohn Marino
16476cdfca03SJohn Marino switch (data_addr.su_family) {
16486cdfca03SJohn Marino case AF_INET:
16496cdfca03SJohn Marino a = (char *)&data_addr.si_su.su_sin.sin_addr;
16506cdfca03SJohn Marino p = (char *)&data_addr.su_port;
16516cdfca03SJohn Marino result = command("PORT %d,%d,%d,%d,%d,%d",
16526cdfca03SJohn Marino UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
16536cdfca03SJohn Marino UC(p[0]), UC(p[1]));
16546cdfca03SJohn Marino break;
16556cdfca03SJohn Marino #ifdef INET6
16566cdfca03SJohn Marino case AF_INET6: {
16576cdfca03SJohn Marino uint8_t ua[sizeof(data_addr.si_su.su_sin6.sin6_addr)];
16586cdfca03SJohn Marino uint8_t up[sizeof(data_addr.su_port)];
16596cdfca03SJohn Marino
16606cdfca03SJohn Marino memcpy(ua, &data_addr.si_su.su_sin6.sin6_addr,
16616cdfca03SJohn Marino sizeof(ua));
16626cdfca03SJohn Marino memcpy(up, &data_addr.su_port, sizeof(up));
16636cdfca03SJohn Marino
16646cdfca03SJohn Marino result = command(
16656cdfca03SJohn Marino "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
16666cdfca03SJohn Marino 6, 16,
16676cdfca03SJohn Marino ua[0], ua[1], ua[2], ua[3],
16686cdfca03SJohn Marino ua[4], ua[5], ua[6], ua[7],
16696cdfca03SJohn Marino ua[8], ua[9], ua[10], ua[11],
16706cdfca03SJohn Marino ua[12], ua[13], ua[14], ua[15],
16716cdfca03SJohn Marino 2,
16726cdfca03SJohn Marino up[0], up[1]);
16736cdfca03SJohn Marino break;
16746cdfca03SJohn Marino }
16756cdfca03SJohn Marino #endif
16766cdfca03SJohn Marino default:
16776cdfca03SJohn Marino result = COMPLETE + 1; /* xxx */
16786cdfca03SJohn Marino }
16796cdfca03SJohn Marino if (!connected)
16806cdfca03SJohn Marino return (1);
16816cdfca03SJohn Marino skip_port:
16826cdfca03SJohn Marino
16836cdfca03SJohn Marino if (result == ERROR && sendport == -1) {
16846cdfca03SJohn Marino sendport = 0;
16856cdfca03SJohn Marino tmpno = 1;
16866cdfca03SJohn Marino goto noport;
16876cdfca03SJohn Marino }
16886cdfca03SJohn Marino return (result != COMPLETE);
16896cdfca03SJohn Marino }
16906cdfca03SJohn Marino if (tmpno)
16916cdfca03SJohn Marino sendport = 1;
16926cdfca03SJohn Marino #ifdef IPTOS_THROUGHPUT
16936cdfca03SJohn Marino if (data_addr.su_family == AF_INET) {
16946cdfca03SJohn Marino on = IPTOS_THROUGHPUT;
16956cdfca03SJohn Marino if (setsockopt(data, IPPROTO_IP, IP_TOS,
16966cdfca03SJohn Marino (void *)&on, sizeof(on)) == -1) {
16976cdfca03SJohn Marino DWARN("setsockopt %s (ignored)", "IPTOS_THROUGHPUT");
16986cdfca03SJohn Marino }
16996cdfca03SJohn Marino }
17006cdfca03SJohn Marino #endif
17016cdfca03SJohn Marino return (0);
17026cdfca03SJohn Marino bad:
17036cdfca03SJohn Marino (void)close(data);
17046cdfca03SJohn Marino data = -1;
17056cdfca03SJohn Marino if (tmpno)
17066cdfca03SJohn Marino sendport = 1;
17076cdfca03SJohn Marino return (1);
17086cdfca03SJohn Marino }
17096cdfca03SJohn Marino
17106cdfca03SJohn Marino FILE *
dataconn(const char * lmode)17116cdfca03SJohn Marino dataconn(const char *lmode)
17126cdfca03SJohn Marino {
17136cdfca03SJohn Marino struct sockinet from;
17146cdfca03SJohn Marino int s, flags, rv, timeout;
17156cdfca03SJohn Marino struct timeval endtime, now, td;
17166cdfca03SJohn Marino struct pollfd pfd[1];
17176cdfca03SJohn Marino socklen_t fromlen;
17186cdfca03SJohn Marino
17196cdfca03SJohn Marino if (passivemode) /* passive data connection */
17206cdfca03SJohn Marino return (fdopen(data, lmode));
17216cdfca03SJohn Marino
17226cdfca03SJohn Marino /* active mode data connection */
17236cdfca03SJohn Marino
17246cdfca03SJohn Marino if ((flags = fcntl(data, F_GETFL, 0)) == -1)
17256cdfca03SJohn Marino goto dataconn_failed; /* get current socket flags */
17266cdfca03SJohn Marino if (fcntl(data, F_SETFL, flags | O_NONBLOCK) == -1)
17276cdfca03SJohn Marino goto dataconn_failed; /* set non-blocking connect */
17286cdfca03SJohn Marino
17296cdfca03SJohn Marino /* NOTE: we now must restore socket flags on successful exit */
17306cdfca03SJohn Marino
17316cdfca03SJohn Marino /* limit time waiting on listening socket */
17326cdfca03SJohn Marino pfd[0].fd = data;
17336cdfca03SJohn Marino pfd[0].events = POLLIN;
17346cdfca03SJohn Marino (void)gettimeofday(&endtime, NULL); /* determine end time */
17356cdfca03SJohn Marino endtime.tv_sec += (quit_time > 0) ? quit_time: 60;
17366cdfca03SJohn Marino /* without -q, default to 60s */
17376cdfca03SJohn Marino do {
17386cdfca03SJohn Marino (void)gettimeofday(&now, NULL);
17396cdfca03SJohn Marino timersub(&endtime, &now, &td);
17406cdfca03SJohn Marino timeout = td.tv_sec * 1000 + td.tv_usec/1000;
17416cdfca03SJohn Marino if (timeout < 0)
17426cdfca03SJohn Marino timeout = 0;
17436cdfca03SJohn Marino rv = ftp_poll(pfd, 1, timeout);
17446cdfca03SJohn Marino } while (rv == -1 && errno == EINTR); /* loop until poll ! EINTR */
17456cdfca03SJohn Marino if (rv == -1) {
17466cdfca03SJohn Marino warn("Can't poll waiting before accept");
17476cdfca03SJohn Marino goto dataconn_failed;
17486cdfca03SJohn Marino }
17496cdfca03SJohn Marino if (rv == 0) {
17506cdfca03SJohn Marino warnx("Poll timeout waiting before accept");
17516cdfca03SJohn Marino goto dataconn_failed;
17526cdfca03SJohn Marino }
17536cdfca03SJohn Marino
17546cdfca03SJohn Marino /* (non-blocking) accept the connection */
17556cdfca03SJohn Marino fromlen = myctladdr.su_len;
17566cdfca03SJohn Marino do {
17576cdfca03SJohn Marino s = accept(data, (struct sockaddr *) &from.si_su, &fromlen);
17586cdfca03SJohn Marino } while (s == -1 && errno == EINTR); /* loop until accept ! EINTR */
17596cdfca03SJohn Marino if (s == -1) {
17606cdfca03SJohn Marino warn("Can't accept data connection");
17616cdfca03SJohn Marino goto dataconn_failed;
17626cdfca03SJohn Marino }
17636cdfca03SJohn Marino
17646cdfca03SJohn Marino (void)close(data);
17656cdfca03SJohn Marino data = s;
17666cdfca03SJohn Marino if (fcntl(data, F_SETFL, flags) == -1) /* restore socket flags */
17676cdfca03SJohn Marino goto dataconn_failed;
17686cdfca03SJohn Marino
17696cdfca03SJohn Marino #ifdef IPTOS_THROUGHPUT
17706cdfca03SJohn Marino if (from.su_family == AF_INET) {
17716cdfca03SJohn Marino int tos = IPTOS_THROUGHPUT;
17726cdfca03SJohn Marino if (setsockopt(s, IPPROTO_IP, IP_TOS,
17736cdfca03SJohn Marino (void *)&tos, sizeof(tos)) == -1) {
17746cdfca03SJohn Marino DWARN("setsockopt %s (ignored)", "IPTOS_THROUGHPUT");
17756cdfca03SJohn Marino }
17766cdfca03SJohn Marino }
17776cdfca03SJohn Marino #endif
17786cdfca03SJohn Marino return (fdopen(data, lmode));
17796cdfca03SJohn Marino
17806cdfca03SJohn Marino dataconn_failed:
17816cdfca03SJohn Marino (void)close(data);
17826cdfca03SJohn Marino data = -1;
17836cdfca03SJohn Marino return (NULL);
17846cdfca03SJohn Marino }
17856cdfca03SJohn Marino
17866cdfca03SJohn Marino void
psabort(int notused)17876cdfca03SJohn Marino psabort(int notused)
17886cdfca03SJohn Marino {
17896cdfca03SJohn Marino int oerrno = errno;
17906cdfca03SJohn Marino
17916cdfca03SJohn Marino sigint_raised = 1;
17926cdfca03SJohn Marino alarmtimer(0);
17936cdfca03SJohn Marino abrtflag++;
17946cdfca03SJohn Marino errno = oerrno;
17956cdfca03SJohn Marino }
17966cdfca03SJohn Marino
17976cdfca03SJohn Marino void
pswitch(int flag)17986cdfca03SJohn Marino pswitch(int flag)
17996cdfca03SJohn Marino {
18006cdfca03SJohn Marino sigfunc oldintr;
18016cdfca03SJohn Marino static struct comvars {
18026cdfca03SJohn Marino int connect;
18036cdfca03SJohn Marino char name[MAXHOSTNAMELEN];
18046cdfca03SJohn Marino struct sockinet mctl;
18056cdfca03SJohn Marino struct sockinet hctl;
18066cdfca03SJohn Marino FILE *in;
18076cdfca03SJohn Marino FILE *out;
18086cdfca03SJohn Marino int tpe;
18096cdfca03SJohn Marino int curtpe;
18106cdfca03SJohn Marino int cpnd;
18116cdfca03SJohn Marino int sunqe;
18126cdfca03SJohn Marino int runqe;
18136cdfca03SJohn Marino int mcse;
18146cdfca03SJohn Marino int ntflg;
18156cdfca03SJohn Marino char nti[17];
18166cdfca03SJohn Marino char nto[17];
18176cdfca03SJohn Marino int mapflg;
18186cdfca03SJohn Marino char mi[MAXPATHLEN];
18196cdfca03SJohn Marino char mo[MAXPATHLEN];
18206cdfca03SJohn Marino } proxstruct, tmpstruct;
18216cdfca03SJohn Marino struct comvars *ip, *op;
18226cdfca03SJohn Marino
18236cdfca03SJohn Marino abrtflag = 0;
18246cdfca03SJohn Marino oldintr = xsignal(SIGINT, psabort);
18256cdfca03SJohn Marino if (flag) {
18266cdfca03SJohn Marino if (proxy)
18276cdfca03SJohn Marino return;
18286cdfca03SJohn Marino ip = &tmpstruct;
18296cdfca03SJohn Marino op = &proxstruct;
18306cdfca03SJohn Marino proxy++;
18316cdfca03SJohn Marino } else {
18326cdfca03SJohn Marino if (!proxy)
18336cdfca03SJohn Marino return;
18346cdfca03SJohn Marino ip = &proxstruct;
18356cdfca03SJohn Marino op = &tmpstruct;
18366cdfca03SJohn Marino proxy = 0;
18376cdfca03SJohn Marino }
18386cdfca03SJohn Marino ip->connect = connected;
18396cdfca03SJohn Marino connected = op->connect;
18406cdfca03SJohn Marino if (hostname)
18416cdfca03SJohn Marino (void)strlcpy(ip->name, hostname, sizeof(ip->name));
18426cdfca03SJohn Marino else
18436cdfca03SJohn Marino ip->name[0] = '\0';
18446cdfca03SJohn Marino hostname = op->name;
18456cdfca03SJohn Marino ip->hctl = hisctladdr;
18466cdfca03SJohn Marino hisctladdr = op->hctl;
18476cdfca03SJohn Marino ip->mctl = myctladdr;
18486cdfca03SJohn Marino myctladdr = op->mctl;
18496cdfca03SJohn Marino ip->in = cin;
18506cdfca03SJohn Marino cin = op->in;
18516cdfca03SJohn Marino ip->out = cout;
18526cdfca03SJohn Marino cout = op->out;
18536cdfca03SJohn Marino ip->tpe = type;
18546cdfca03SJohn Marino type = op->tpe;
18556cdfca03SJohn Marino ip->curtpe = curtype;
18566cdfca03SJohn Marino curtype = op->curtpe;
18576cdfca03SJohn Marino ip->cpnd = cpend;
18586cdfca03SJohn Marino cpend = op->cpnd;
18596cdfca03SJohn Marino ip->sunqe = sunique;
18606cdfca03SJohn Marino sunique = op->sunqe;
18616cdfca03SJohn Marino ip->runqe = runique;
18626cdfca03SJohn Marino runique = op->runqe;
18636cdfca03SJohn Marino ip->mcse = mcase;
18646cdfca03SJohn Marino mcase = op->mcse;
18656cdfca03SJohn Marino ip->ntflg = ntflag;
18666cdfca03SJohn Marino ntflag = op->ntflg;
18676cdfca03SJohn Marino (void)strlcpy(ip->nti, ntin, sizeof(ip->nti));
18686cdfca03SJohn Marino (void)strlcpy(ntin, op->nti, sizeof(ntin));
18696cdfca03SJohn Marino (void)strlcpy(ip->nto, ntout, sizeof(ip->nto));
18706cdfca03SJohn Marino (void)strlcpy(ntout, op->nto, sizeof(ntout));
18716cdfca03SJohn Marino ip->mapflg = mapflag;
18726cdfca03SJohn Marino mapflag = op->mapflg;
18736cdfca03SJohn Marino (void)strlcpy(ip->mi, mapin, sizeof(ip->mi));
18746cdfca03SJohn Marino (void)strlcpy(mapin, op->mi, sizeof(mapin));
18756cdfca03SJohn Marino (void)strlcpy(ip->mo, mapout, sizeof(ip->mo));
18766cdfca03SJohn Marino (void)strlcpy(mapout, op->mo, sizeof(mapout));
18776cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr);
18786cdfca03SJohn Marino if (abrtflag) {
18796cdfca03SJohn Marino abrtflag = 0;
18806cdfca03SJohn Marino (*oldintr)(SIGINT);
18816cdfca03SJohn Marino }
18826cdfca03SJohn Marino }
18836cdfca03SJohn Marino
18846cdfca03SJohn Marino __dead static void
abortpt(int notused)18856cdfca03SJohn Marino abortpt(int notused)
18866cdfca03SJohn Marino {
18876cdfca03SJohn Marino
18886cdfca03SJohn Marino sigint_raised = 1;
18896cdfca03SJohn Marino alarmtimer(0);
18906cdfca03SJohn Marino if (fromatty)
18916cdfca03SJohn Marino write(fileno(ttyout), "\n", 1);
18926cdfca03SJohn Marino ptabflg++;
18936cdfca03SJohn Marino mflag = 0;
18946cdfca03SJohn Marino abrtflag = 0;
18956cdfca03SJohn Marino siglongjmp(ptabort, 1);
18966cdfca03SJohn Marino }
18976cdfca03SJohn Marino
18986cdfca03SJohn Marino void
proxtrans(const char * cmd,const char * local,const char * remote)18996cdfca03SJohn Marino proxtrans(const char *cmd, const char *local, const char *remote)
19006cdfca03SJohn Marino {
19016cdfca03SJohn Marino sigfunc volatile oldintr;
19026cdfca03SJohn Marino int prox_type, nfnd;
19036cdfca03SJohn Marino int volatile secndflag;
19046cdfca03SJohn Marino const char *volatile cmd2;
19056cdfca03SJohn Marino
1906*3a184c67SAntonio Huete Jimenez oldintr = SIG_ERR;
19076cdfca03SJohn Marino secndflag = 0;
19086cdfca03SJohn Marino if (strcmp(cmd, "RETR"))
19096cdfca03SJohn Marino cmd2 = "RETR";
19106cdfca03SJohn Marino else
19116cdfca03SJohn Marino cmd2 = runique ? "STOU" : "STOR";
19126cdfca03SJohn Marino if ((prox_type = type) == 0) {
19136cdfca03SJohn Marino if (unix_server && unix_proxy)
19146cdfca03SJohn Marino prox_type = TYPE_I;
19156cdfca03SJohn Marino else
19166cdfca03SJohn Marino prox_type = TYPE_A;
19176cdfca03SJohn Marino }
19186cdfca03SJohn Marino if (curtype != prox_type)
19196cdfca03SJohn Marino changetype(prox_type, 1);
19206cdfca03SJohn Marino if (command("PASV") != COMPLETE) {
19216cdfca03SJohn Marino fputs("proxy server does not support third party transfers.\n",
19226cdfca03SJohn Marino ttyout);
19236cdfca03SJohn Marino return;
19246cdfca03SJohn Marino }
19256cdfca03SJohn Marino pswitch(0);
19266cdfca03SJohn Marino if (!connected) {
19276cdfca03SJohn Marino fputs("No primary connection.\n", ttyout);
19286cdfca03SJohn Marino pswitch(1);
19296cdfca03SJohn Marino code = -1;
19306cdfca03SJohn Marino return;
19316cdfca03SJohn Marino }
19326cdfca03SJohn Marino if (curtype != prox_type)
19336cdfca03SJohn Marino changetype(prox_type, 1);
19346cdfca03SJohn Marino if (command("PORT %s", pasv) != COMPLETE) {
19356cdfca03SJohn Marino pswitch(1);
19366cdfca03SJohn Marino return;
19376cdfca03SJohn Marino }
19386cdfca03SJohn Marino if (sigsetjmp(ptabort, 1))
19396cdfca03SJohn Marino goto abort;
19406cdfca03SJohn Marino oldintr = xsignal(SIGINT, abortpt);
19416cdfca03SJohn Marino if ((restart_point &&
19426cdfca03SJohn Marino (command("REST " LLF, (LLT) restart_point) != CONTINUE))
19436cdfca03SJohn Marino || (command("%s %s", cmd, remote) != PRELIM)) {
19446cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr);
19456cdfca03SJohn Marino pswitch(1);
19466cdfca03SJohn Marino return;
19476cdfca03SJohn Marino }
19486cdfca03SJohn Marino sleep(2);
19496cdfca03SJohn Marino pswitch(1);
19506cdfca03SJohn Marino secndflag++;
19516cdfca03SJohn Marino if ((restart_point &&
19526cdfca03SJohn Marino (command("REST " LLF, (LLT) restart_point) != CONTINUE))
19536cdfca03SJohn Marino || (command("%s %s", cmd2, local) != PRELIM))
19546cdfca03SJohn Marino goto abort;
19556cdfca03SJohn Marino ptflag++;
19566cdfca03SJohn Marino (void)getreply(0);
19576cdfca03SJohn Marino pswitch(0);
19586cdfca03SJohn Marino (void)getreply(0);
19596cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr);
19606cdfca03SJohn Marino pswitch(1);
19616cdfca03SJohn Marino ptflag = 0;
19626cdfca03SJohn Marino fprintf(ttyout, "local: %s remote: %s\n", local, remote);
19636cdfca03SJohn Marino return;
19646cdfca03SJohn Marino abort:
19656cdfca03SJohn Marino if (sigsetjmp(xferabort, 1)) {
19666cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr);
19676cdfca03SJohn Marino return;
19686cdfca03SJohn Marino }
19696cdfca03SJohn Marino (void)xsignal(SIGINT, abort_squared);
19706cdfca03SJohn Marino ptflag = 0;
19716cdfca03SJohn Marino if (strcmp(cmd, "RETR") && !proxy)
19726cdfca03SJohn Marino pswitch(1);
19736cdfca03SJohn Marino else if (!strcmp(cmd, "RETR") && proxy)
19746cdfca03SJohn Marino pswitch(0);
19756cdfca03SJohn Marino if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
19766cdfca03SJohn Marino if (command("%s %s", cmd2, local) != PRELIM) {
19776cdfca03SJohn Marino pswitch(0);
19786cdfca03SJohn Marino if (cpend)
19796cdfca03SJohn Marino abort_remote(NULL);
19806cdfca03SJohn Marino }
19816cdfca03SJohn Marino pswitch(1);
19826cdfca03SJohn Marino if (ptabflg)
19836cdfca03SJohn Marino code = -1;
19846cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr);
19856cdfca03SJohn Marino return;
19866cdfca03SJohn Marino }
19876cdfca03SJohn Marino if (cpend)
19886cdfca03SJohn Marino abort_remote(NULL);
19896cdfca03SJohn Marino pswitch(!proxy);
19906cdfca03SJohn Marino if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
19916cdfca03SJohn Marino if (command("%s %s", cmd2, local) != PRELIM) {
19926cdfca03SJohn Marino pswitch(0);
19936cdfca03SJohn Marino if (cpend)
19946cdfca03SJohn Marino abort_remote(NULL);
19956cdfca03SJohn Marino pswitch(1);
19966cdfca03SJohn Marino if (ptabflg)
19976cdfca03SJohn Marino code = -1;
19986cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr);
19996cdfca03SJohn Marino return;
20006cdfca03SJohn Marino }
20016cdfca03SJohn Marino }
20026cdfca03SJohn Marino if (cpend)
20036cdfca03SJohn Marino abort_remote(NULL);
20046cdfca03SJohn Marino pswitch(!proxy);
20056cdfca03SJohn Marino if (cpend) {
20066cdfca03SJohn Marino if ((nfnd = empty(cin, NULL, 10)) <= 0) {
20076cdfca03SJohn Marino if (nfnd < 0)
20086cdfca03SJohn Marino warn("Error aborting proxy command");
20096cdfca03SJohn Marino if (ptabflg)
20106cdfca03SJohn Marino code = -1;
20116cdfca03SJohn Marino lostpeer(0);
20126cdfca03SJohn Marino }
20136cdfca03SJohn Marino (void)getreply(0);
20146cdfca03SJohn Marino (void)getreply(0);
20156cdfca03SJohn Marino }
20166cdfca03SJohn Marino if (proxy)
20176cdfca03SJohn Marino pswitch(0);
20186cdfca03SJohn Marino pswitch(1);
20196cdfca03SJohn Marino if (ptabflg)
20206cdfca03SJohn Marino code = -1;
20216cdfca03SJohn Marino (void)xsignal(SIGINT, oldintr);
20226cdfca03SJohn Marino }
20236cdfca03SJohn Marino
20246cdfca03SJohn Marino void
reset(int argc,char * argv[])20256cdfca03SJohn Marino reset(int argc, char *argv[])
20266cdfca03SJohn Marino {
20276cdfca03SJohn Marino int nfnd = 1;
20286cdfca03SJohn Marino
20296cdfca03SJohn Marino if (argc == 0 && argv != NULL) {
20306cdfca03SJohn Marino UPRINTF("usage: %s\n", argv[0]);
20316cdfca03SJohn Marino code = -1;
20326cdfca03SJohn Marino return;
20336cdfca03SJohn Marino }
20346cdfca03SJohn Marino while (nfnd > 0) {
20356cdfca03SJohn Marino if ((nfnd = empty(cin, NULL, 0)) < 0) {
20366cdfca03SJohn Marino warn("Error resetting connection");
20376cdfca03SJohn Marino code = -1;
20386cdfca03SJohn Marino lostpeer(0);
20396cdfca03SJohn Marino } else if (nfnd)
20406cdfca03SJohn Marino (void)getreply(0);
20416cdfca03SJohn Marino }
20426cdfca03SJohn Marino }
20436cdfca03SJohn Marino
20446cdfca03SJohn Marino char *
gunique(const char * local)20456cdfca03SJohn Marino gunique(const char *local)
20466cdfca03SJohn Marino {
20476cdfca03SJohn Marino static char new[MAXPATHLEN];
20486cdfca03SJohn Marino char *cp = strrchr(local, '/');
20496cdfca03SJohn Marino int d, count=0, len;
20506cdfca03SJohn Marino char ext = '1';
20516cdfca03SJohn Marino
20526cdfca03SJohn Marino if (cp)
20536cdfca03SJohn Marino *cp = '\0';
20546cdfca03SJohn Marino d = access(cp == local ? "/" : cp ? local : ".", W_OK);
20556cdfca03SJohn Marino if (cp)
20566cdfca03SJohn Marino *cp = '/';
20576cdfca03SJohn Marino if (d < 0) {
20586cdfca03SJohn Marino warn("Can't access `%s'", local);
20596cdfca03SJohn Marino return (NULL);
20606cdfca03SJohn Marino }
20616cdfca03SJohn Marino len = strlcpy(new, local, sizeof(new));
20626cdfca03SJohn Marino cp = &new[len];
20636cdfca03SJohn Marino *cp++ = '.';
20646cdfca03SJohn Marino while (!d) {
20656cdfca03SJohn Marino if (++count == 100) {
20666cdfca03SJohn Marino fputs("runique: can't find unique file name.\n",
20676cdfca03SJohn Marino ttyout);
20686cdfca03SJohn Marino return (NULL);
20696cdfca03SJohn Marino }
20706cdfca03SJohn Marino *cp++ = ext;
20716cdfca03SJohn Marino *cp = '\0';
20726cdfca03SJohn Marino if (ext == '9')
20736cdfca03SJohn Marino ext = '0';
20746cdfca03SJohn Marino else
20756cdfca03SJohn Marino ext++;
20766cdfca03SJohn Marino if ((d = access(new, F_OK)) < 0)
20776cdfca03SJohn Marino break;
20786cdfca03SJohn Marino if (ext != '0')
20796cdfca03SJohn Marino cp--;
20806cdfca03SJohn Marino else if (*(cp - 2) == '.')
20816cdfca03SJohn Marino *(cp - 1) = '1';
20826cdfca03SJohn Marino else {
20836cdfca03SJohn Marino *(cp - 2) = *(cp - 2) + 1;
20846cdfca03SJohn Marino cp--;
20856cdfca03SJohn Marino }
20866cdfca03SJohn Marino }
20876cdfca03SJohn Marino return (new);
20886cdfca03SJohn Marino }
20896cdfca03SJohn Marino
20906cdfca03SJohn Marino /*
20916cdfca03SJohn Marino * abort_squared --
20926cdfca03SJohn Marino * aborts abort_remote(). lostpeer() is called because if the user is
20936cdfca03SJohn Marino * too impatient to wait or there's another problem then ftp really
20946cdfca03SJohn Marino * needs to get back to a known state.
20956cdfca03SJohn Marino */
20966cdfca03SJohn Marino static void
abort_squared(int signo)2097*3a184c67SAntonio Huete Jimenez abort_squared(int signo)
20986cdfca03SJohn Marino {
20996cdfca03SJohn Marino char msgbuf[100];
21006cdfca03SJohn Marino size_t len;
21016cdfca03SJohn Marino
21026cdfca03SJohn Marino sigint_raised = 1;
21036cdfca03SJohn Marino alarmtimer(0);
21046cdfca03SJohn Marino len = strlcpy(msgbuf, "\nremote abort aborted; closing connection.\n",
21056cdfca03SJohn Marino sizeof(msgbuf));
21066cdfca03SJohn Marino write(fileno(ttyout), msgbuf, len);
2107*3a184c67SAntonio Huete Jimenez lostpeer(signo);
21086cdfca03SJohn Marino siglongjmp(xferabort, 1);
21096cdfca03SJohn Marino }
21106cdfca03SJohn Marino
21116cdfca03SJohn Marino void
abort_remote(FILE * din)21126cdfca03SJohn Marino abort_remote(FILE *din)
21136cdfca03SJohn Marino {
2114*3a184c67SAntonio Huete Jimenez unsigned char buf[BUFSIZ];
21156cdfca03SJohn Marino int nfnd;
21166cdfca03SJohn Marino
21176cdfca03SJohn Marino if (cout == NULL) {
21186cdfca03SJohn Marino warnx("Lost control connection for abort");
21196cdfca03SJohn Marino if (ptabflg)
21206cdfca03SJohn Marino code = -1;
21216cdfca03SJohn Marino lostpeer(0);
21226cdfca03SJohn Marino return;
21236cdfca03SJohn Marino }
21246cdfca03SJohn Marino /*
21256cdfca03SJohn Marino * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
21266cdfca03SJohn Marino * after urgent byte rather than before as is protocol now
21276cdfca03SJohn Marino */
21286cdfca03SJohn Marino buf[0] = IAC;
21296cdfca03SJohn Marino buf[1] = IP;
21306cdfca03SJohn Marino buf[2] = IAC;
21316cdfca03SJohn Marino if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
21326cdfca03SJohn Marino warn("Can't send abort message");
21336cdfca03SJohn Marino fprintf(cout, "%cABOR\r\n", DM);
21346cdfca03SJohn Marino (void)fflush(cout);
21356cdfca03SJohn Marino if ((nfnd = empty(cin, din, 10)) <= 0) {
21366cdfca03SJohn Marino if (nfnd < 0)
21376cdfca03SJohn Marino warn("Can't send abort message");
21386cdfca03SJohn Marino if (ptabflg)
21396cdfca03SJohn Marino code = -1;
21406cdfca03SJohn Marino lostpeer(0);
21416cdfca03SJohn Marino }
21426cdfca03SJohn Marino if (din && (nfnd & 2)) {
21436cdfca03SJohn Marino while (read(fileno(din), buf, BUFSIZ) > 0)
21446cdfca03SJohn Marino continue;
21456cdfca03SJohn Marino }
21466cdfca03SJohn Marino if (getreply(0) == ERROR && code == 552) {
21476cdfca03SJohn Marino /* 552 needed for nic style abort */
21486cdfca03SJohn Marino (void)getreply(0);
21496cdfca03SJohn Marino }
21506cdfca03SJohn Marino (void)getreply(0);
21516cdfca03SJohn Marino }
21526cdfca03SJohn Marino
21536cdfca03SJohn Marino /*
21546cdfca03SJohn Marino * Ensure that ai->ai_addr is NOT an IPv4 mapped address.
21556cdfca03SJohn Marino * IPv4 mapped address complicates too many things in FTP
21566cdfca03SJohn Marino * protocol handling, as FTP protocol is defined differently
21576cdfca03SJohn Marino * between IPv4 and IPv6.
21586cdfca03SJohn Marino *
21596cdfca03SJohn Marino * This may not be the best way to handle this situation,
21606cdfca03SJohn Marino * since the semantics of IPv4 mapped address is defined in
21616cdfca03SJohn Marino * the kernel. There are configurations where we should use
21626cdfca03SJohn Marino * IPv4 mapped address as native IPv6 address, not as
21636cdfca03SJohn Marino * "an IPv6 address that embeds IPv4 address" (namely, SIIT).
21646cdfca03SJohn Marino *
21656cdfca03SJohn Marino * More complete solution would be to have an additional
21666cdfca03SJohn Marino * getsockopt to grab "real" peername/sockname. "real"
21676cdfca03SJohn Marino * peername/sockname will be AF_INET if IPv4 mapped address
21686cdfca03SJohn Marino * is used to embed IPv4 address, and will be AF_INET6 if
21696cdfca03SJohn Marino * we use it as native. What a mess!
21706cdfca03SJohn Marino */
21716cdfca03SJohn Marino void
ai_unmapped(struct addrinfo * ai)21726cdfca03SJohn Marino ai_unmapped(struct addrinfo *ai)
21736cdfca03SJohn Marino {
21746cdfca03SJohn Marino #ifdef INET6
21756cdfca03SJohn Marino struct sockaddr_in6 *sin6;
21766cdfca03SJohn Marino struct sockaddr_in sin;
21776cdfca03SJohn Marino socklen_t len;
21786cdfca03SJohn Marino
21796cdfca03SJohn Marino if (ai->ai_family != AF_INET6)
21806cdfca03SJohn Marino return;
21816cdfca03SJohn Marino if (ai->ai_addrlen != sizeof(struct sockaddr_in6) ||
21826cdfca03SJohn Marino sizeof(sin) > ai->ai_addrlen)
21836cdfca03SJohn Marino return;
21846cdfca03SJohn Marino sin6 = (struct sockaddr_in6 *)ai->ai_addr;
21856cdfca03SJohn Marino if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
21866cdfca03SJohn Marino return;
21876cdfca03SJohn Marino
21886cdfca03SJohn Marino memset(&sin, 0, sizeof(sin));
21896cdfca03SJohn Marino sin.sin_family = AF_INET;
21906cdfca03SJohn Marino len = sizeof(struct sockaddr_in);
21916cdfca03SJohn Marino memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
21926cdfca03SJohn Marino sizeof(sin.sin_addr));
21936cdfca03SJohn Marino sin.sin_port = sin6->sin6_port;
21946cdfca03SJohn Marino
21956cdfca03SJohn Marino ai->ai_family = AF_INET;
21966cdfca03SJohn Marino #if defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN)
21976cdfca03SJohn Marino sin.sin_len = len;
21986cdfca03SJohn Marino #endif
21996cdfca03SJohn Marino memcpy(ai->ai_addr, &sin, len);
22006cdfca03SJohn Marino ai->ai_addrlen = len;
22016cdfca03SJohn Marino #endif
22026cdfca03SJohn Marino }
22036cdfca03SJohn Marino
22046cdfca03SJohn Marino #ifdef NO_USAGE
22056cdfca03SJohn Marino void
xusage(void)22066cdfca03SJohn Marino xusage(void)
22076cdfca03SJohn Marino {
22086cdfca03SJohn Marino fputs("Usage error\n", ttyout);
22096cdfca03SJohn Marino }
22106cdfca03SJohn Marino #endif
2211