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