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