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