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