"Fossies" - the Fresh Open Source Software Archive

Member "tnftp-20200705/src/ftp.c" (4 Jul 2020, 50557 Bytes) of package /linux/privat/tnftp-20200705.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ftp.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 20151004_vs_20200705.

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