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