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