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