This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / usr.bin / ftp / ftp.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1985, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char sccsid[] = "@(#)ftp.c 5.38 (Berkeley) 4/22/91";
36#endif /* not lint */
37
38#include <sys/param.h>
39#include <sys/stat.h>
40#include <sys/ioctl.h>
41#include <sys/socket.h>
42#include <sys/time.h>
43#include <sys/file.h>
44
45#include <netinet/in.h>
46#include <netinet/in_systm.h>
47#include <netinet/ip.h>
48#include <arpa/ftp.h>
49#include <arpa/telnet.h>
50
51#include <stdio.h>
52#include <signal.h>
53#include <errno.h>
54#include <netdb.h>
55#include <fcntl.h>
56#include <pwd.h>
57#include <varargs.h>
58
59#include "ftp_var.h"
60
61struct sockaddr_in hisctladdr;
62struct sockaddr_in data_addr;
63int data = -1;
64int abrtflag = 0;
65int ptflag = 0;
66struct sockaddr_in myctladdr;
67uid_t getuid();
68sig_t lostpeer();
69off_t restart_point = 0;
70
71extern char *strerror();
72extern int connected, errno;
73
74FILE *cin, *cout;
75FILE *dataconn();
76
77char *
78hookup(host, port)
79 char *host;
80 int port;
81{
82 register struct hostent *hp = 0;
83 int s, len, tos;
84 static char hostnamebuf[80];
85
86 bzero((char *)&hisctladdr, sizeof (hisctladdr));
87 hisctladdr.sin_addr.s_addr = inet_addr(host);
88 if (hisctladdr.sin_addr.s_addr != -1) {
89 hisctladdr.sin_family = AF_INET;
90 (void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
91 } else {
92 hp = gethostbyname(host);
93 if (hp == NULL) {
94 fprintf(stderr, "ftp: %s: ", host);
95 herror((char *)NULL);
96 code = -1;
97 return((char *) 0);
98 }
99 hisctladdr.sin_family = hp->h_addrtype;
100 bcopy(hp->h_addr_list[0],
101 (caddr_t)&hisctladdr.sin_addr, hp->h_length);
102 (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
103 }
104 hostname = hostnamebuf;
105 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
106 if (s < 0) {
107 perror("ftp: socket");
108 code = -1;
109 return (0);
110 }
111 hisctladdr.sin_port = port;
112 while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
113 if (hp && hp->h_addr_list[1]) {
114 int oerrno = errno;
115 extern char *inet_ntoa();
116
117 fprintf(stderr, "ftp: connect to address %s: ",
118 inet_ntoa(hisctladdr.sin_addr));
119 errno = oerrno;
120 perror((char *) 0);
121 hp->h_addr_list++;
122 bcopy(hp->h_addr_list[0],
123 (caddr_t)&hisctladdr.sin_addr, hp->h_length);
124 fprintf(stdout, "Trying %s...\n",
125 inet_ntoa(hisctladdr.sin_addr));
126 (void) close(s);
127 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
128 if (s < 0) {
129 perror("ftp: socket");
130 code = -1;
131 return (0);
132 }
133 continue;
134 }
135 perror("ftp: connect");
136 code = -1;
137 goto bad;
138 }
139 len = sizeof (myctladdr);
140 if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
141 perror("ftp: getsockname");
142 code = -1;
143 goto bad;
144 }
145#ifdef IP_TOS
146 tos = IPTOS_LOWDELAY;
147 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
148 perror("ftp: setsockopt TOS (ignored)");
149#endif
150 cin = fdopen(s, "r");
151 cout = fdopen(s, "w");
152 if (cin == NULL || cout == NULL) {
153 fprintf(stderr, "ftp: fdopen failed.\n");
154 if (cin)
155 (void) fclose(cin);
156 if (cout)
157 (void) fclose(cout);
158 code = -1;
159 goto bad;
160 }
161 if (verbose)
162 printf("Connected to %s.\n", hostname);
163 if (getreply(0) > 2) { /* read startup message from server */
164 if (cin)
165 (void) fclose(cin);
166 if (cout)
167 (void) fclose(cout);
168 code = -1;
169 goto bad;
170 }
171#ifdef SO_OOBINLINE
172 {
173 int on = 1;
174
175 if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
176 < 0 && debug) {
177 perror("ftp: setsockopt");
178 }
179 }
180#endif /* SO_OOBINLINE */
181
182 return (hostname);
183bad:
184 (void) close(s);
185 return ((char *)0);
186}
187
188login(host)
189 char *host;
190{
191 char tmp[80];
192 char *user, *pass, *acct, *getlogin(), *getpass();
193 int n, aflag = 0;
194
195 user = pass = acct = 0;
196 if (ruserpass(host, &user, &pass, &acct) < 0) {
197 code = -1;
198 return(0);
199 }
200 while (user == NULL) {
201 char *myname = getlogin();
202
203 if (myname == NULL) {
204 struct passwd *pp = getpwuid(getuid());
205
206 if (pp != NULL)
207 myname = pp->pw_name;
208 }
209 if (myname)
210 printf("Name (%s:%s): ", host, myname);
211 else
212 printf("Name (%s): ", host);
213 (void) fgets(tmp, sizeof(tmp) - 1, stdin);
214 tmp[strlen(tmp) - 1] = '\0';
215 if (*tmp == '\0')
216 user = myname;
217 else
218 user = tmp;
219 }
220 n = command("USER %s", user);
221 if (n == CONTINUE) {
222 if (pass == NULL)
223 pass = getpass("Password:");
224 n = command("PASS %s", pass);
225 }
226 if (n == CONTINUE) {
227 aflag++;
228 acct = getpass("Account:");
229 n = command("ACCT %s", acct);
230 }
231 if (n != COMPLETE) {
232 fprintf(stderr, "Login failed.\n");
233 return (0);
234 }
235 if (!aflag && acct != NULL)
236 (void) command("ACCT %s", acct);
237 if (proxy)
238 return(1);
239 for (n = 0; n < macnum; ++n) {
240 if (!strcmp("init", macros[n].mac_name)) {
241 (void) strcpy(line, "$init");
242 makeargv();
243 domacro(margc, margv);
244 break;
245 }
246 }
247 return (1);
248}
249
250void
251cmdabort()
252{
253 extern jmp_buf ptabort;
254
255 printf("\n");
256 (void) fflush(stdout);
257 abrtflag++;
258 if (ptflag)
259 longjmp(ptabort,1);
260}
261
262/*VARARGS*/
263command(va_alist)
264va_dcl
265{
266 va_list ap;
267 char *fmt;
268 int r;
269 sig_t oldintr;
270 void cmdabort();
271
272 abrtflag = 0;
273 if (debug) {
274 printf("---> ");
275 va_start(ap);
276 fmt = va_arg(ap, char *);
277 if (strncmp("PASS ", fmt, 5) == 0)
278 printf("PASS XXXX");
279 else
280 vfprintf(stdout, fmt, ap);
281 va_end(ap);
282 printf("\n");
283 (void) fflush(stdout);
284 }
285 if (cout == NULL) {
286 perror ("No control connection for command");
287 code = -1;
288 return (0);
289 }
290 oldintr = signal(SIGINT, cmdabort);
291 va_start(ap);
292 fmt = va_arg(ap, char *);
293 vfprintf(cout, fmt, ap);
294 va_end(ap);
295 fprintf(cout, "\r\n");
296 (void) fflush(cout);
297 cpend = 1;
298 r = getreply(!strcmp(fmt, "QUIT"));
299 if (abrtflag && oldintr != SIG_IGN)
300 (*oldintr)(SIGINT);
301 (void) signal(SIGINT, oldintr);
302 return(r);
303}
304
305char reply_string[BUFSIZ]; /* last line of previous reply */
306
307#include <ctype.h>
308
309getreply(expecteof)
310 int expecteof;
311{
312 register int c, n;
313 register int dig;
314 register char *cp;
315 int originalcode = 0, continuation = 0;
316 sig_t oldintr;
317 int pflag = 0;
318 char *pt = pasv;
319 void cmdabort();
320
321 oldintr = signal(SIGINT, cmdabort);
322 for (;;) {
323 dig = n = code = 0;
324 cp = reply_string;
325 while ((c = getc(cin)) != '\n') {
326 if (c == IAC) { /* handle telnet commands */
327 switch (c = getc(cin)) {
328 case WILL:
329 case WONT:
330 c = getc(cin);
331 fprintf(cout, "%c%c%c", IAC, DONT, c);
332 (void) fflush(cout);
333 break;
334 case DO:
335 case DONT:
336 c = getc(cin);
337 fprintf(cout, "%c%c%c", IAC, WONT, c);
338 (void) fflush(cout);
339 break;
340 default:
341 break;
342 }
343 continue;
344 }
345 dig++;
346 if (c == EOF) {
347 if (expecteof) {
348 (void) signal(SIGINT,oldintr);
349 code = 221;
350 return (0);
351 }
352 lostpeer();
353 if (verbose) {
354 printf("421 Service not available, remote server has closed connection\n");
355 (void) fflush(stdout);
356 }
357 code = 421;
358 return(4);
359 }
360 if (c != '\r' && (verbose > 0 ||
361 (verbose > -1 && n == '5' && dig > 4))) {
362 if (proxflag &&
363 (dig == 1 || dig == 5 && verbose == 0))
364 printf("%s:",hostname);
365 (void) putchar(c);
366 }
367 if (dig < 4 && isdigit(c))
368 code = code * 10 + (c - '0');
369 if (!pflag && code == 227)
370 pflag = 1;
371 if (dig > 4 && pflag == 1 && isdigit(c))
372 pflag = 2;
373 if (pflag == 2) {
374 if (c != '\r' && c != ')')
375 *pt++ = c;
376 else {
377 *pt = '\0';
378 pflag = 3;
379 }
380 }
381 if (dig == 4 && c == '-') {
382 if (continuation)
383 code = 0;
384 continuation++;
385 }
386 if (n == 0)
387 n = c;
388 if (cp < &reply_string[sizeof(reply_string) - 1])
389 *cp++ = c;
390 }
391 if (verbose > 0 || verbose > -1 && n == '5') {
392 (void) putchar(c);
393 (void) fflush (stdout);
394 }
395 if (continuation && code != originalcode) {
396 if (originalcode == 0)
397 originalcode = code;
398 continue;
399 }
400 *cp = '\0';
401 if (n != '1')
402 cpend = 0;
403 (void) signal(SIGINT,oldintr);
404 if (code == 421 || originalcode == 421)
405 lostpeer();
406 if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
407 (*oldintr)(SIGINT);
408 return (n - '0');
409 }
410}
411
412empty(mask, sec)
413 struct fd_set *mask;
414 int sec;
415{
416 struct timeval t;
417
418 t.tv_sec = (long) sec;
419 t.tv_usec = 0;
420 return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
421}
422
423jmp_buf sendabort;
424
425void
426abortsend()
427{
428
429 mflag = 0;
430 abrtflag = 0;
431 printf("\nsend aborted\nwaiting for remote to finish abort\n");
432 (void) fflush(stdout);
433 longjmp(sendabort, 1);
434}
435
436#define HASHBYTES 1024
437
438sendrequest(cmd, local, remote, printnames)
439 char *cmd, *local, *remote;
440 int printnames;
441{
442 struct stat st;
443 struct timeval start, stop;
444 register int c, d;
445 FILE *fin, *dout = 0, *popen();
446 int (*closefunc)(), pclose(), fclose();
447 sig_t oldintr, oldintp;
448 long bytes = 0, hashbytes = HASHBYTES;
449 char *lmode, buf[BUFSIZ], *bufp;
450 void abortsend();
451
452 if (verbose && printnames) {
453 if (local && *local != '-')
454 printf("local: %s ", local);
455 if (remote)
456 printf("remote: %s\n", remote);
457 }
458 if (proxy) {
459 proxtrans(cmd, local, remote);
460 return;
461 }
462 if (curtype != type)
463 changetype(type, 0);
464 closefunc = NULL;
465 oldintr = NULL;
466 oldintp = NULL;
467 lmode = "w";
468 if (setjmp(sendabort)) {
469 while (cpend) {
470 (void) getreply(0);
471 }
472 if (data >= 0) {
473 (void) close(data);
474 data = -1;
475 }
476 if (oldintr)
477 (void) signal(SIGINT,oldintr);
478 if (oldintp)
479 (void) signal(SIGPIPE,oldintp);
480 code = -1;
481 return;
482 }
483 oldintr = signal(SIGINT, abortsend);
484 if (strcmp(local, "-") == 0)
485 fin = stdin;
486 else if (*local == '|') {
487 oldintp = signal(SIGPIPE,SIG_IGN);
488 fin = popen(local + 1, "r");
489 if (fin == NULL) {
490 perror(local + 1);
491 (void) signal(SIGINT, oldintr);
492 (void) signal(SIGPIPE, oldintp);
493 code = -1;
494 return;
495 }
496 closefunc = pclose;
497 } else {
498 fin = fopen(local, "r");
499 if (fin == NULL) {
500 fprintf(stderr, "local: %s: %s\n", local,
501 strerror(errno));
502 (void) signal(SIGINT, oldintr);
503 code = -1;
504 return;
505 }
506 closefunc = fclose;
507 if (fstat(fileno(fin), &st) < 0 ||
508 (st.st_mode&S_IFMT) != S_IFREG) {
509 fprintf(stdout, "%s: not a plain file.\n", local);
510 (void) signal(SIGINT, oldintr);
511 fclose(fin);
512 code = -1;
513 return;
514 }
515 }
516 if (initconn()) {
517 (void) signal(SIGINT, oldintr);
518 if (oldintp)
519 (void) signal(SIGPIPE, oldintp);
520 code = -1;
521 if (closefunc != NULL)
522 (*closefunc)(fin);
523 return;
524 }
525 if (setjmp(sendabort))
526 goto abort;
527
528 if (restart_point &&
529 (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
530 if (fseek(fin, (long) restart_point, 0) < 0) {
531 fprintf(stderr, "local: %s: %s\n", local,
532 strerror(errno));
533 restart_point = 0;
534 if (closefunc != NULL)
535 (*closefunc)(fin);
536 return;
537 }
538 if (command("REST %ld", (long) restart_point)
539 != CONTINUE) {
540 restart_point = 0;
541 if (closefunc != NULL)
542 (*closefunc)(fin);
543 return;
544 }
545 restart_point = 0;
546 lmode = "r+w";
547 }
548 if (remote) {
549 if (command("%s %s", cmd, remote) != PRELIM) {
550 (void) signal(SIGINT, oldintr);
551 if (oldintp)
552 (void) signal(SIGPIPE, oldintp);
553 if (closefunc != NULL)
554 (*closefunc)(fin);
555 return;
556 }
557 } else
558 if (command("%s", cmd) != PRELIM) {
559 (void) signal(SIGINT, oldintr);
560 if (oldintp)
561 (void) signal(SIGPIPE, oldintp);
562 if (closefunc != NULL)
563 (*closefunc)(fin);
564 return;
565 }
566 dout = dataconn(lmode);
567 if (dout == NULL)
568 goto abort;
569 (void) gettimeofday(&start, (struct timezone *)0);
570 oldintp = signal(SIGPIPE, SIG_IGN);
571 switch (curtype) {
572
573 case TYPE_I:
574 case TYPE_L:
575 errno = d = 0;
576 while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
577 bytes += c;
578 for (bufp = buf; c > 0; c -= d, bufp += d)
579 if ((d = write(fileno(dout), bufp, c)) <= 0)
580 break;
581 if (hash) {
582 while (bytes >= hashbytes) {
583 (void) putchar('#');
584 hashbytes += HASHBYTES;
585 }
586 (void) fflush(stdout);
587 }
588 }
589 if (hash && bytes > 0) {
590 if (bytes < HASHBYTES)
591 (void) putchar('#');
592 (void) putchar('\n');
593 (void) fflush(stdout);
594 }
595 if (c < 0)
596 fprintf(stderr, "local: %s: %s\n", local,
597 strerror(errno));
598 if (d < 0) {
599 if (errno != EPIPE)
600 perror("netout");
601 bytes = -1;
602 }
603 break;
604
605 case TYPE_A:
606 while ((c = getc(fin)) != EOF) {
607 if (c == '\n') {
608 while (hash && (bytes >= hashbytes)) {
609 (void) putchar('#');
610 (void) fflush(stdout);
611 hashbytes += HASHBYTES;
612 }
613 if (ferror(dout))
614 break;
615 (void) putc('\r', dout);
616 bytes++;
617 }
618 (void) putc(c, dout);
619 bytes++;
620 /* if (c == '\r') { */
621 /* (void) putc('\0', dout); /* this violates rfc */
622 /* bytes++; */
623 /* } */
624 }
625 if (hash) {
626 if (bytes < hashbytes)
627 (void) putchar('#');
628 (void) putchar('\n');
629 (void) fflush(stdout);
630 }
631 if (ferror(fin))
632 fprintf(stderr, "local: %s: %s\n", local,
633 strerror(errno));
634 if (ferror(dout)) {
635 if (errno != EPIPE)
636 perror("netout");
637 bytes = -1;
638 }
639 break;
640 }
641 (void) gettimeofday(&stop, (struct timezone *)0);
642 if (closefunc != NULL)
643 (*closefunc)(fin);
644 (void) fclose(dout);
645 (void) getreply(0);
646 (void) signal(SIGINT, oldintr);
647 if (oldintp)
648 (void) signal(SIGPIPE, oldintp);
649 if (bytes > 0)
650 ptransfer("sent", bytes, &start, &stop);
651 return;
652abort:
653 (void) gettimeofday(&stop, (struct timezone *)0);
654 (void) signal(SIGINT, oldintr);
655 if (oldintp)
656 (void) signal(SIGPIPE, oldintp);
657 if (!cpend) {
658 code = -1;
659 return;
660 }
661 if (data >= 0) {
662 (void) close(data);
663 data = -1;
664 }
665 if (dout)
666 (void) fclose(dout);
667 (void) getreply(0);
668 code = -1;
669 if (closefunc != NULL && fin != NULL)
670 (*closefunc)(fin);
671 if (bytes > 0)
672 ptransfer("sent", bytes, &start, &stop);
673}
674
675jmp_buf recvabort;
676
677void
678abortrecv()
679{
680
681 mflag = 0;
682 abrtflag = 0;
683 printf("\nreceive aborted\nwaiting for remote to finish abort\n");
684 (void) fflush(stdout);
685 longjmp(recvabort, 1);
686}
687
688recvrequest(cmd, local, remote, lmode, printnames)
689 char *cmd, *local, *remote, *lmode;
690{
691 FILE *fout, *din = 0, *popen();
692 int (*closefunc)(), pclose(), fclose();
693 sig_t oldintr, oldintp;
694 int is_retr, tcrflag, bare_lfs = 0;
695 char *gunique();
696 static int bufsize;
697 static char *buf;
698 long bytes = 0, hashbytes = HASHBYTES;
699 register int c, d;
700 struct timeval start, stop;
701 struct stat st;
702 off_t lseek();
703 void abortrecv();
704 char *malloc();
705
706 is_retr = strcmp(cmd, "RETR") == 0;
707 if (is_retr && verbose && printnames) {
708 if (local && *local != '-')
709 printf("local: %s ", local);
710 if (remote)
711 printf("remote: %s\n", remote);
712 }
713 if (proxy && is_retr) {
714 proxtrans(cmd, local, remote);
715 return;
716 }
717 closefunc = NULL;
718 oldintr = NULL;
719 oldintp = NULL;
720 tcrflag = !crflag && is_retr;
721 if (setjmp(recvabort)) {
722 while (cpend) {
723 (void) getreply(0);
724 }
725 if (data >= 0) {
726 (void) close(data);
727 data = -1;
728 }
729 if (oldintr)
730 (void) signal(SIGINT, oldintr);
731 code = -1;
732 return;
733 }
734 oldintr = signal(SIGINT, abortrecv);
735 if (strcmp(local, "-") && *local != '|') {
736 if (access(local, 2) < 0) {
737 char *dir = rindex(local, '/');
738
739 if (errno != ENOENT && errno != EACCES) {
740 fprintf(stderr, "local: %s: %s\n", local,
741 strerror(errno));
742 (void) signal(SIGINT, oldintr);
743 code = -1;
744 return;
745 }
746 if (dir != NULL)
747 *dir = 0;
748 d = access(dir ? local : ".", 2);
749 if (dir != NULL)
750 *dir = '/';
751 if (d < 0) {
752 fprintf(stderr, "local: %s: %s\n", local,
753 strerror(errno));
754 (void) signal(SIGINT, oldintr);
755 code = -1;
756 return;
757 }
758 if (!runique && errno == EACCES &&
759 chmod(local, 0600) < 0) {
760 fprintf(stderr, "local: %s: %s\n", local,
761 strerror(errno));
762 (void) signal(SIGINT, oldintr);
763 (void) signal(SIGINT, oldintr);
764 code = -1;
765 return;
766 }
767 if (runique && errno == EACCES &&
768 (local = gunique(local)) == NULL) {
769 (void) signal(SIGINT, oldintr);
770 code = -1;
771 return;
772 }
773 }
774 else if (runique && (local = gunique(local)) == NULL) {
775 (void) signal(SIGINT, oldintr);
776 code = -1;
777 return;
778 }
779 }
780 if (!is_retr) {
781 if (curtype != TYPE_A)
782 changetype(TYPE_A, 0);
783 } else if (curtype != type)
784 changetype(type, 0);
785 if (initconn()) {
786 (void) signal(SIGINT, oldintr);
787 code = -1;
788 return;
789 }
790 if (setjmp(recvabort))
791 goto abort;
792 if (is_retr && restart_point &&
793 command("REST %ld", (long) restart_point) != CONTINUE)
794 return;
795 if (remote) {
796 if (command("%s %s", cmd, remote) != PRELIM) {
797 (void) signal(SIGINT, oldintr);
798 return;
799 }
800 } else {
801 if (command("%s", cmd) != PRELIM) {
802 (void) signal(SIGINT, oldintr);
803 return;
804 }
805 }
806 din = dataconn("r");
807 if (din == NULL)
808 goto abort;
809 if (strcmp(local, "-") == 0)
810 fout = stdout;
811 else if (*local == '|') {
812 oldintp = signal(SIGPIPE, SIG_IGN);
813 fout = popen(local + 1, "w");
814 if (fout == NULL) {
815 perror(local+1);
816 goto abort;
817 }
818 closefunc = pclose;
819 } else {
820 fout = fopen(local, lmode);
821 if (fout == NULL) {
822 fprintf(stderr, "local: %s: %s\n", local,
823 strerror(errno));
824 goto abort;
825 }
826 closefunc = fclose;
827 }
828 if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
829 st.st_blksize = BUFSIZ;
830 if (st.st_blksize > bufsize) {
831 if (buf)
832 (void) free(buf);
833 buf = malloc((unsigned)st.st_blksize);
834 if (buf == NULL) {
835 perror("malloc");
836 bufsize = 0;
837 goto abort;
838 }
839 bufsize = st.st_blksize;
840 }
841 (void) gettimeofday(&start, (struct timezone *)0);
842 switch (curtype) {
843
844 case TYPE_I:
845 case TYPE_L:
846 if (restart_point &&
847 lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
848 fprintf(stderr, "local: %s: %s\n", local,
849 strerror(errno));
850 if (closefunc != NULL)
851 (*closefunc)(fout);
852 return;
853 }
854 errno = d = 0;
855 while ((c = read(fileno(din), buf, bufsize)) > 0) {
856 if ((d = write(fileno(fout), buf, c)) != c)
857 break;
858 bytes += c;
859 if (hash) {
860 while (bytes >= hashbytes) {
861 (void) putchar('#');
862 hashbytes += HASHBYTES;
863 }
864 (void) fflush(stdout);
865 }
866 }
867 if (hash && bytes > 0) {
868 if (bytes < HASHBYTES)
869 (void) putchar('#');
870 (void) putchar('\n');
871 (void) fflush(stdout);
872 }
873 if (c < 0) {
874 if (errno != EPIPE)
875 perror("netin");
876 bytes = -1;
877 }
878 if (d < c) {
879 if (d < 0)
880 fprintf(stderr, "local: %s: %s\n", local,
881 strerror(errno));
882 else
883 fprintf(stderr, "%s: short write\n", local);
884 }
885 break;
886
887 case TYPE_A:
888 if (restart_point) {
889 register int i, n, ch;
890
891 if (fseek(fout, 0L, L_SET) < 0)
892 goto done;
893 n = restart_point;
894 for (i = 0; i++ < n;) {
895 if ((ch = getc(fout)) == EOF)
896 goto done;
897 if (ch == '\n')
898 i++;
899 }
900 if (fseek(fout, 0L, L_INCR) < 0) {
901done:
902 fprintf(stderr, "local: %s: %s\n", local,
903 strerror(errno));
904 if (closefunc != NULL)
905 (*closefunc)(fout);
906 return;
907 }
908 }
909 while ((c = getc(din)) != EOF) {
910 if (c == '\n')
911 bare_lfs++;
912 while (c == '\r') {
913 while (hash && (bytes >= hashbytes)) {
914 (void) putchar('#');
915 (void) fflush(stdout);
916 hashbytes += HASHBYTES;
917 }
918 bytes++;
919 if ((c = getc(din)) != '\n' || tcrflag) {
920 if (ferror(fout))
921 goto break2;
922 (void) putc('\r', fout);
923 if (c == '\0') {
924 bytes++;
925 goto contin2;
926 }
927 if (c == EOF)
928 goto contin2;
929 }
930 }
931 (void) putc(c, fout);
932 bytes++;
933 contin2: ;
934 }
935break2:
936 if (bare_lfs) {
937 printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs);
938 printf("File may not have transferred correctly.\n");
939 }
940 if (hash) {
941 if (bytes < hashbytes)
942 (void) putchar('#');
943 (void) putchar('\n');
944 (void) fflush(stdout);
945 }
946 if (ferror(din)) {
947 if (errno != EPIPE)
948 perror("netin");
949 bytes = -1;
950 }
951 if (ferror(fout))
952 fprintf(stderr, "local: %s: %s\n", local,
953 strerror(errno));
954 break;
955 }
956 if (closefunc != NULL)
957 (*closefunc)(fout);
958 (void) signal(SIGINT, oldintr);
959 if (oldintp)
960 (void) signal(SIGPIPE, oldintp);
961 (void) gettimeofday(&stop, (struct timezone *)0);
962 (void) fclose(din);
963 (void) getreply(0);
964 if (bytes > 0 && is_retr)
965 ptransfer("received", bytes, &start, &stop);
966 return;
967abort:
968
969/* abort using RFC959 recommended IP,SYNC sequence */
970
971 (void) gettimeofday(&stop, (struct timezone *)0);
972 if (oldintp)
973 (void) signal(SIGPIPE, oldintr);
974 (void) signal(SIGINT, SIG_IGN);
975 if (!cpend) {
976 code = -1;
977 (void) signal(SIGINT, oldintr);
978 return;
979 }
980
981 abort_remote(din);
982 code = -1;
983 if (data >= 0) {
984 (void) close(data);
985 data = -1;
986 }
987 if (closefunc != NULL && fout != NULL)
988 (*closefunc)(fout);
989 if (din)
990 (void) fclose(din);
991 if (bytes > 0)
992 ptransfer("received", bytes, &start, &stop);
993 (void) signal(SIGINT, oldintr);
994}
995
996/*
997 * Need to start a listen on the data channel before we send the command,
998 * otherwise the server's connect may fail.
999 */
1000initconn()
1001{
1002 register char *p, *a;
1003 int result, len, tmpno = 0;
1004 int on = 1;
1005
1006noport:
1007 data_addr = myctladdr;
1008 if (sendport)
1009 data_addr.sin_port = 0; /* let system pick one */
1010 if (data != -1)
1011 (void) close(data);
1012 data = socket(AF_INET, SOCK_STREAM, 0);
1013 if (data < 0) {
1014 perror("ftp: socket");
1015 if (tmpno)
1016 sendport = 1;
1017 return (1);
1018 }
1019 if (!sendport)
1020 if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
1021 perror("ftp: setsockopt (reuse address)");
1022 goto bad;
1023 }
1024 if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
1025 perror("ftp: bind");
1026 goto bad;
1027 }
1028 if (options & SO_DEBUG &&
1029 setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
1030 perror("ftp: setsockopt (ignored)");
1031 len = sizeof (data_addr);
1032 if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1033 perror("ftp: getsockname");
1034 goto bad;
1035 }
1036 if (listen(data, 1) < 0)
1037 perror("ftp: listen");
1038 if (sendport) {
1039 a = (char *)&data_addr.sin_addr;
1040 p = (char *)&data_addr.sin_port;
1041#define UC(b) (((int)b)&0xff)
1042 result =
1043 command("PORT %d,%d,%d,%d,%d,%d",
1044 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1045 UC(p[0]), UC(p[1]));
1046 if (result == ERROR && sendport == -1) {
1047 sendport = 0;
1048 tmpno = 1;
1049 goto noport;
1050 }
1051 return (result != COMPLETE);
1052 }
1053 if (tmpno)
1054 sendport = 1;
1055#ifdef IP_TOS
1056 on = IPTOS_THROUGHPUT;
1057 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1058 perror("ftp: setsockopt TOS (ignored)");
1059#endif
1060 return (0);
1061bad:
1062 (void) close(data), data = -1;
1063 if (tmpno)
1064 sendport = 1;
1065 return (1);
1066}
1067
1068FILE *
1069dataconn(lmode)
1070 char *lmode;
1071{
1072 struct sockaddr_in from;
1073 int s, fromlen = sizeof (from), tos;
1074
1075 s = accept(data, (struct sockaddr *) &from, &fromlen);
1076 if (s < 0) {
1077 perror("ftp: accept");
1078 (void) close(data), data = -1;
1079 return (NULL);
1080 }
1081 (void) close(data);
1082 data = s;
1083#ifdef IP_TOS
1084 tos = IPTOS_THROUGHPUT;
1085 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1086 perror("ftp: setsockopt TOS (ignored)");
1087#endif
1088 return (fdopen(data, lmode));
1089}
1090
1091ptransfer(direction, bytes, t0, t1)
1092 char *direction;
1093 long bytes;
1094 struct timeval *t0, *t1;
1095{
1096 struct timeval td;
1097 float s, bs;
1098
1099 if (verbose) {
1100 tvsub(&td, t1, t0);
1101 s = td.tv_sec + (td.tv_usec / 1000000.);
1102#define nz(x) ((x) == 0 ? 1 : (x))
1103 bs = bytes / nz(s);
d233db39 1104 printf("%ld bytes %s in %.3g seconds (%.3g Kbytes/s)\n",
15637ed4
RG
1105 bytes, direction, s, bs / 1024.);
1106 }
1107}
1108
1109/*tvadd(tsum, t0)
1110 struct timeval *tsum, *t0;
1111{
1112
1113 tsum->tv_sec += t0->tv_sec;
1114 tsum->tv_usec += t0->tv_usec;
1115 if (tsum->tv_usec > 1000000)
1116 tsum->tv_sec++, tsum->tv_usec -= 1000000;
1117} */
1118
1119tvsub(tdiff, t1, t0)
1120 struct timeval *tdiff, *t1, *t0;
1121{
1122
1123 tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
1124 tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
1125 if (tdiff->tv_usec < 0)
1126 tdiff->tv_sec--, tdiff->tv_usec += 1000000;
1127}
1128
1129void
1130psabort()
1131{
1132 extern int abrtflag;
1133
1134 abrtflag++;
1135}
1136
1137pswitch(flag)
1138 int flag;
1139{
1140 extern int proxy, abrtflag;
1141 sig_t oldintr;
1142 static struct comvars {
1143 int connect;
1144 char name[MAXHOSTNAMELEN];
1145 struct sockaddr_in mctl;
1146 struct sockaddr_in hctl;
1147 FILE *in;
1148 FILE *out;
1149 int tpe;
1150 int curtpe;
1151 int cpnd;
1152 int sunqe;
1153 int runqe;
1154 int mcse;
1155 int ntflg;
1156 char nti[17];
1157 char nto[17];
1158 int mapflg;
1159 char mi[MAXPATHLEN];
1160 char mo[MAXPATHLEN];
1161 } proxstruct, tmpstruct;
1162 struct comvars *ip, *op;
1163
1164 abrtflag = 0;
1165 oldintr = signal(SIGINT, psabort);
1166 if (flag) {
1167 if (proxy)
1168 return;
1169 ip = &tmpstruct;
1170 op = &proxstruct;
1171 proxy++;
1172 } else {
1173 if (!proxy)
1174 return;
1175 ip = &proxstruct;
1176 op = &tmpstruct;
1177 proxy = 0;
1178 }
1179 ip->connect = connected;
1180 connected = op->connect;
1181 if (hostname) {
1182 (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1183 ip->name[strlen(ip->name)] = '\0';
1184 } else
1185 ip->name[0] = 0;
1186 hostname = op->name;
1187 ip->hctl = hisctladdr;
1188 hisctladdr = op->hctl;
1189 ip->mctl = myctladdr;
1190 myctladdr = op->mctl;
1191 ip->in = cin;
1192 cin = op->in;
1193 ip->out = cout;
1194 cout = op->out;
1195 ip->tpe = type;
1196 type = op->tpe;
1197 ip->curtpe = curtype;
1198 curtype = op->curtpe;
1199 ip->cpnd = cpend;
1200 cpend = op->cpnd;
1201 ip->sunqe = sunique;
1202 sunique = op->sunqe;
1203 ip->runqe = runique;
1204 runique = op->runqe;
1205 ip->mcse = mcase;
1206 mcase = op->mcse;
1207 ip->ntflg = ntflag;
1208 ntflag = op->ntflg;
1209 (void) strncpy(ip->nti, ntin, 16);
1210 (ip->nti)[strlen(ip->nti)] = '\0';
1211 (void) strcpy(ntin, op->nti);
1212 (void) strncpy(ip->nto, ntout, 16);
1213 (ip->nto)[strlen(ip->nto)] = '\0';
1214 (void) strcpy(ntout, op->nto);
1215 ip->mapflg = mapflag;
1216 mapflag = op->mapflg;
1217 (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
1218 (ip->mi)[strlen(ip->mi)] = '\0';
1219 (void) strcpy(mapin, op->mi);
1220 (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
1221 (ip->mo)[strlen(ip->mo)] = '\0';
1222 (void) strcpy(mapout, op->mo);
1223 (void) signal(SIGINT, oldintr);
1224 if (abrtflag) {
1225 abrtflag = 0;
1226 (*oldintr)(SIGINT);
1227 }
1228}
1229
1230jmp_buf ptabort;
1231int ptabflg;
1232
1233void
1234abortpt()
1235{
1236 printf("\n");
1237 (void) fflush(stdout);
1238 ptabflg++;
1239 mflag = 0;
1240 abrtflag = 0;
1241 longjmp(ptabort, 1);
1242}
1243
1244proxtrans(cmd, local, remote)
1245 char *cmd, *local, *remote;
1246{
1247 sig_t oldintr;
1248 int secndflag = 0, prox_type, nfnd;
1249 extern jmp_buf ptabort;
1250 char *cmd2;
1251 struct fd_set mask;
1252 void abortpt();
1253
1254 if (strcmp(cmd, "RETR"))
1255 cmd2 = "RETR";
1256 else
1257 cmd2 = runique ? "STOU" : "STOR";
1258 if ((prox_type = type) == 0) {
1259 if (unix_server && unix_proxy)
1260 prox_type = TYPE_I;
1261 else
1262 prox_type = TYPE_A;
1263 }
1264 if (curtype != prox_type)
1265 changetype(prox_type, 1);
1266 if (command("PASV") != COMPLETE) {
1267 printf("proxy server does not support third party transfers.\n");
1268 return;
1269 }
1270 pswitch(0);
1271 if (!connected) {
1272 printf("No primary connection\n");
1273 pswitch(1);
1274 code = -1;
1275 return;
1276 }
1277 if (curtype != prox_type)
1278 changetype(prox_type, 1);
1279 if (command("PORT %s", pasv) != COMPLETE) {
1280 pswitch(1);
1281 return;
1282 }
1283 if (setjmp(ptabort))
1284 goto abort;
1285 oldintr = signal(SIGINT, abortpt);
1286 if (command("%s %s", cmd, remote) != PRELIM) {
1287 (void) signal(SIGINT, oldintr);
1288 pswitch(1);
1289 return;
1290 }
1291 sleep(2);
1292 pswitch(1);
1293 secndflag++;
1294 if (command("%s %s", cmd2, local) != PRELIM)
1295 goto abort;
1296 ptflag++;
1297 (void) getreply(0);
1298 pswitch(0);
1299 (void) getreply(0);
1300 (void) signal(SIGINT, oldintr);
1301 pswitch(1);
1302 ptflag = 0;
1303 printf("local: %s remote: %s\n", local, remote);
1304 return;
1305abort:
1306 (void) signal(SIGINT, SIG_IGN);
1307 ptflag = 0;
1308 if (strcmp(cmd, "RETR") && !proxy)
1309 pswitch(1);
1310 else if (!strcmp(cmd, "RETR") && proxy)
1311 pswitch(0);
1312 if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
1313 if (command("%s %s", cmd2, local) != PRELIM) {
1314 pswitch(0);
1315 if (cpend)
1316 abort_remote((FILE *) NULL);
1317 }
1318 pswitch(1);
1319 if (ptabflg)
1320 code = -1;
1321 (void) signal(SIGINT, oldintr);
1322 return;
1323 }
1324 if (cpend)
1325 abort_remote((FILE *) NULL);
1326 pswitch(!proxy);
1327 if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
1328 if (command("%s %s", cmd2, local) != PRELIM) {
1329 pswitch(0);
1330 if (cpend)
1331 abort_remote((FILE *) NULL);
1332 pswitch(1);
1333 if (ptabflg)
1334 code = -1;
1335 (void) signal(SIGINT, oldintr);
1336 return;
1337 }
1338 }
1339 if (cpend)
1340 abort_remote((FILE *) NULL);
1341 pswitch(!proxy);
1342 if (cpend) {
1343 FD_ZERO(&mask);
1344 FD_SET(fileno(cin), &mask);
1345 if ((nfnd = empty(&mask, 10)) <= 0) {
1346 if (nfnd < 0) {
1347 perror("abort");
1348 }
1349 if (ptabflg)
1350 code = -1;
1351 lostpeer();
1352 }
1353 (void) getreply(0);
1354 (void) getreply(0);
1355 }
1356 if (proxy)
1357 pswitch(0);
1358 pswitch(1);
1359 if (ptabflg)
1360 code = -1;
1361 (void) signal(SIGINT, oldintr);
1362}
1363
1364reset()
1365{
1366 struct fd_set mask;
1367 int nfnd = 1;
1368
1369 FD_ZERO(&mask);
1370 while (nfnd > 0) {
1371 FD_SET(fileno(cin), &mask);
1372 if ((nfnd = empty(&mask,0)) < 0) {
1373 perror("reset");
1374 code = -1;
1375 lostpeer();
1376 }
1377 else if (nfnd) {
1378 (void) getreply(0);
1379 }
1380 }
1381}
1382
1383char *
1384gunique(local)
1385 char *local;
1386{
1387 static char new[MAXPATHLEN];
1388 char *cp = rindex(local, '/');
1389 int d, count=0;
1390 char ext = '1';
1391
1392 if (cp)
1393 *cp = '\0';
1394 d = access(cp ? local : ".", 2);
1395 if (cp)
1396 *cp = '/';
1397 if (d < 0) {
1398 fprintf(stderr, "local: %s: %s\n", local, strerror(errno));
1399 return((char *) 0);
1400 }
1401 (void) strcpy(new, local);
1402 cp = new + strlen(new);
1403 *cp++ = '.';
1404 while (!d) {
1405 if (++count == 100) {
1406 printf("runique: can't find unique file name.\n");
1407 return((char *) 0);
1408 }
1409 *cp++ = ext;
1410 *cp = '\0';
1411 if (ext == '9')
1412 ext = '0';
1413 else
1414 ext++;
1415 if ((d = access(new, 0)) < 0)
1416 break;
1417 if (ext != '0')
1418 cp--;
1419 else if (*(cp - 2) == '.')
1420 *(cp - 1) = '1';
1421 else {
1422 *(cp - 2) = *(cp - 2) + 1;
1423 cp--;
1424 }
1425 }
1426 return(new);
1427}
1428
1429abort_remote(din)
1430FILE *din;
1431{
1432 char buf[BUFSIZ];
1433 int nfnd;
1434 struct fd_set mask;
1435
1436 /*
1437 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1438 * after urgent byte rather than before as is protocol now
1439 */
1440 sprintf(buf, "%c%c%c", IAC, IP, IAC);
1441 if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1442 perror("abort");
1443 fprintf(cout,"%cABOR\r\n", DM);
1444 (void) fflush(cout);
1445 FD_ZERO(&mask);
1446 FD_SET(fileno(cin), &mask);
1447 if (din) {
1448 FD_SET(fileno(din), &mask);
1449 }
1450 if ((nfnd = empty(&mask, 10)) <= 0) {
1451 if (nfnd < 0) {
1452 perror("abort");
1453 }
1454 if (ptabflg)
1455 code = -1;
1456 lostpeer();
1457 }
1458 if (din && FD_ISSET(fileno(din), &mask)) {
1459 while (read(fileno(din), buf, BUFSIZ) > 0)
1460 /* LOOP */;
1461 }
1462 if (getreply(0) == ERROR && code == 552) {
1463 /* 552 needed for nic style abort */
1464 (void) getreply(0);
1465 }
1466 (void) getreply(0);
1467}