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