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