]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - crypto/heimdal/appl/ftp/ftp/ftp.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / crypto / heimdal / appl / ftp / 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 #include "ftp_locl.h"
35 RCSID ("$Id$");
36
37 struct sockaddr_storage hisctladdr_ss;
38 struct sockaddr *hisctladdr = (struct sockaddr *)&hisctladdr_ss;
39 struct sockaddr_storage data_addr_ss;
40 struct sockaddr *data_addr  = (struct sockaddr *)&data_addr_ss;
41 struct sockaddr_storage myctladdr_ss;
42 struct sockaddr *myctladdr = (struct sockaddr *)&myctladdr_ss;
43 int data = -1;
44 int abrtflag = 0;
45 jmp_buf ptabort;
46 int ptabflg;
47 int ptflag = 0;
48 off_t restart_point = 0;
49
50
51 FILE *cin, *cout;
52
53 typedef void (*sighand) (int);
54
55 char *
56 hookup (const char *host, int port)
57 {
58     static char hostnamebuf[MaxHostNameLen];
59     struct addrinfo *ai, *a;
60     struct addrinfo hints;
61     int error;
62     char portstr[NI_MAXSERV];
63     socklen_t len;
64     int s;
65
66     memset (&hints, 0, sizeof(hints));
67     hints.ai_socktype = SOCK_STREAM;
68     hints.ai_protocol = IPPROTO_TCP;
69     hints.ai_flags    = AI_CANONNAME;
70
71     snprintf (portstr, sizeof(portstr), "%u", ntohs(port));
72
73     error = getaddrinfo (host, portstr, &hints, &ai);
74     if (error) {
75         warnx ("%s: %s", host, gai_strerror(error));
76         code = -1;
77         return NULL;
78     }
79     strlcpy (hostnamebuf, host, sizeof(hostnamebuf));
80     hostname = hostnamebuf;
81
82     s = -1;
83     for (a = ai; a != NULL; a = a->ai_next) {
84         s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
85         if (s < 0)
86             continue;
87
88         if (a->ai_canonname != NULL)
89             strlcpy (hostnamebuf, a->ai_canonname, sizeof(hostnamebuf));
90
91         memcpy (hisctladdr, a->ai_addr, a->ai_addrlen);
92
93         error = connect (s, a->ai_addr, a->ai_addrlen);
94         if (error < 0) {
95             char addrstr[256];
96
97             if (getnameinfo (a->ai_addr, a->ai_addrlen,
98                              addrstr, sizeof(addrstr),
99                              NULL, 0, NI_NUMERICHOST) != 0)
100                 strlcpy (addrstr, "unknown address", sizeof(addrstr));
101
102             warn ("connect %s", addrstr);
103             close (s);
104             s = -1;
105             continue;
106         }
107         break;
108     }
109     freeaddrinfo (ai);
110     if (s < 0) {
111         warnx ("failed to contact %s", host);
112         code = -1;
113         return NULL;
114     }
115
116     len = sizeof(myctladdr_ss);
117     if (getsockname (s, myctladdr, &len) < 0) {
118         warn ("getsockname");
119         code = -1;
120         close (s);
121         return NULL;
122     }
123 #ifdef IPTOS_LOWDELAY
124     socket_set_tos (s, IPTOS_LOWDELAY);
125 #endif
126     cin = fdopen (s, "r");
127     cout = fdopen (s, "w");
128     if (cin == NULL || cout == NULL) {
129         warnx ("fdopen failed.");
130         if (cin)
131             fclose (cin);
132         if (cout)
133             fclose (cout);
134         code = -1;
135         goto bad;
136     }
137     if (verbose)
138         printf ("Connected to %s.\n", hostname);
139     if (getreply (0) > 2) {     /* read startup message from server */
140         if (cin)
141             fclose (cin);
142         if (cout)
143             fclose (cout);
144         code = -1;
145         goto bad;
146     }
147 #if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT)
148     {
149         int on = 1;
150
151         if (setsockopt (s, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof (on))
152             < 0 && debug) {
153             warn ("setsockopt");
154         }
155     }
156 #endif                          /* SO_OOBINLINE */
157
158     return (hostname);
159 bad:
160     close (s);
161     return NULL;
162 }
163
164 int
165 login (char *host)
166 {
167     char tmp[80];
168     char defaultpass[128];
169     char *userstr, *pass, *acctstr;
170     char *ruserstr, *rpass, *racctstr;
171     int n, aflag = 0;
172
173     char *myname = NULL;
174     struct passwd *pw = k_getpwuid(getuid());
175
176     if (pw != NULL)
177         myname = pw->pw_name;
178
179     ruserstr = rpass = racctstr = NULL;
180
181     if(sec_login(host))
182         printf("\n*** Using plaintext user and password ***\n\n");
183     else{
184         printf("Authentication successful.\n\n");
185     }
186
187     if (ruserpassword (host, &ruserstr, &rpass, &racctstr) < 0) {
188         code = -1;
189         return (0);
190     }
191     userstr = ruserstr;
192     pass = rpass;
193     acctstr = racctstr;
194
195     while (userstr == NULL) {
196         if (myname)
197             printf ("Name (%s:%s): ", host, myname);
198         else
199             printf ("Name (%s): ", host);
200         *tmp = '\0';
201         if (fgets (tmp, sizeof (tmp) - 1, stdin) != NULL)
202             tmp[strlen (tmp) - 1] = '\0';
203         if (*tmp == '\0')
204             userstr = myname;
205         else
206             userstr = tmp;
207     }
208     strlcpy(username, userstr, sizeof(username));
209     if (ruserstr)
210         free(ruserstr);
211
212     n = command("USER %s", userstr);
213     if (n == COMPLETE)
214        n = command("PASS dummy"); /* DK: Compatibility with gssftp daemon */
215     else if(n == CONTINUE) {
216         if (pass == NULL) {
217             char prompt[128];
218             if(myname &&
219                (!strcmp(userstr, "ftp") || !strcmp(userstr, "anonymous"))) {
220                 snprintf(defaultpass, sizeof(defaultpass),
221                          "%s@%s", myname, mydomain);
222                 snprintf(prompt, sizeof(prompt),
223                          "Password (%s): ", defaultpass);
224             } else if (sec_complete) {
225                 pass = myname;
226             } else {
227                 *defaultpass = '\0';
228                 snprintf(prompt, sizeof(prompt), "Password: ");
229             }
230             if (pass == NULL) {
231                 pass = defaultpass;
232                 UI_UTIL_read_pw_string (tmp, sizeof (tmp), prompt, 0);
233                 if (tmp[0])
234                     pass = tmp;
235             }
236         }
237         n = command ("PASS %s", pass);
238         if (rpass)
239             free(rpass);
240     }
241     if (n == CONTINUE) {
242         aflag++;
243         UI_UTIL_read_pw_string (tmp, sizeof(tmp), "Account:", 0);
244         acctstr = tmp;
245         n = command ("ACCT %s", acctstr);
246     }
247     if (n != COMPLETE) {
248         if (racctstr)
249             free(racctstr);
250         warnx ("Login failed.");
251         return (0);
252     }
253     if (!aflag && acctstr != NULL)
254         command ("ACCT %s", acctstr);
255     if (racctstr)
256         free(racctstr);
257     if (proxy)
258         return (1);
259     for (n = 0; n < macnum; ++n) {
260         if (!strcmp("init", macros[n].mac_name)) {
261             strlcpy (line, "$init", sizeof (line));
262             makeargv();
263             domacro(margc, margv);
264             break;
265         }
266     }
267     sec_set_protection_level ();
268     return (1);
269 }
270
271 void
272 cmdabort (int sig)
273 {
274
275     printf ("\n");
276     fflush (stdout);
277     abrtflag++;
278     if (ptflag)
279         longjmp (ptabort, 1);
280 }
281
282 int
283 command (char *fmt,...)
284 {
285     va_list ap;
286     int r;
287     sighand oldintr;
288
289     abrtflag = 0;
290     if (cout == NULL) {
291         warn ("No control connection for command");
292         code = -1;
293         return (0);
294     }
295     oldintr = signal(SIGINT, cmdabort);
296     if(debug){
297         printf("---> ");
298         if (strncmp("PASS ", fmt, 5) == 0)
299             printf("PASS XXXX");
300         else {
301             va_start(ap, fmt);
302             vfprintf(stdout, fmt, ap);
303             va_end(ap);
304         }
305     }
306     va_start(ap, fmt);
307     sec_vfprintf(cout, fmt, ap);
308     va_end(ap);
309     if(debug){
310         printf("\n");
311         fflush(stdout);
312     }
313     fprintf (cout, "\r\n");
314     fflush (cout);
315     cpend = 1;
316     r = getreply (!strcmp (fmt, "QUIT"));
317     if (abrtflag && oldintr != SIG_IGN)
318         (*oldintr) (SIGINT);
319     signal (SIGINT, oldintr);
320     return (r);
321 }
322
323 char reply_string[BUFSIZ];      /* last line of previous reply */
324
325 int
326 getreply (int expecteof)
327 {
328     char *p;
329     char *lead_string;
330     int c;
331     struct sigaction sa, osa;
332     char buf[8192];
333     int reply_code;
334     int long_warn = 0;
335
336     sigemptyset (&sa.sa_mask);
337     sa.sa_flags = 0;
338     sa.sa_handler = cmdabort;
339     sigaction (SIGINT, &sa, &osa);
340
341     p = buf;
342
343     reply_code = 0;
344     while (1) {
345         c = getc (cin);
346         switch (c) {
347         case EOF:
348             if (expecteof) {
349                 sigaction (SIGINT, &osa, NULL);
350                 code = 221;
351                 return 0;
352             }
353             lostpeer (0);
354             if (verbose) {
355                 printf ("421 Service not available, "
356                         "remote server has closed connection\n");
357                 fflush (stdout);
358             }
359             code = 421;
360             return (4);
361         case IAC:
362             c = getc (cin);
363             if (c == WILL || c == WONT)
364                 fprintf (cout, "%c%c%c", IAC, DONT, getc (cin));
365             if (c == DO || c == DONT)
366                 fprintf (cout, "%c%c%c", IAC, WONT, getc (cin));
367             continue;
368         case '\n':
369             *p++ = '\0';
370             if(isdigit((unsigned char)buf[0])){
371                 sscanf(buf, "%d", &code);
372                 if(code == 631){
373                     code = 0;
374                     sec_read_msg(buf, prot_safe);
375                     sscanf(buf, "%d", &code);
376                     lead_string = "S:";
377                 } else if(code == 632){
378                     code = 0;
379                     sec_read_msg(buf, prot_private);
380                     sscanf(buf, "%d", &code);
381                     lead_string = "P:";
382                 }else if(code == 633){
383                     code = 0;
384                     sec_read_msg(buf, prot_confidential);
385                     sscanf(buf, "%d", &code);
386                     lead_string = "C:";
387                 }else if(sec_complete)
388                     lead_string = "!!";
389                 else
390                     lead_string = "";
391                 if(code != 0 && reply_code == 0)
392                     reply_code = code;
393                 if (verbose > 0 || (verbose > -1 && code > 499))
394                     fprintf (stdout, "%s%s\n", lead_string, buf);
395                 if (code == reply_code && buf[3] == ' ') {
396                     strlcpy (reply_string, buf, sizeof(reply_string));
397                     if (code >= 200)
398                         cpend = 0;
399                     sigaction (SIGINT, &osa, NULL);
400                     if (code == 421)
401                         lostpeer (0);
402 #if 1
403                     if (abrtflag &&
404                         osa.sa_handler != cmdabort &&
405                         osa.sa_handler != SIG_IGN)
406                         osa.sa_handler (SIGINT);
407 #endif
408                     if (code == 227 || code == 229) {
409                         char *q;
410
411                         q = strchr (reply_string, '(');
412                         if (q) {
413                             q++;
414                             strlcpy(pasv, q, sizeof(pasv));
415                             q = strrchr(pasv, ')');
416                             if (q)
417                                 *q = '\0';
418                         }
419                     }
420                     return code / 100;
421                 }
422             }else{
423                 if(verbose > 0 || (verbose > -1 && code > 499)){
424                     if(sec_complete)
425                         fprintf(stdout, "!!");
426                     fprintf(stdout, "%s\n", buf);
427                 }
428             }
429             p = buf;
430             long_warn = 0;
431             continue;
432         default:
433             if(p < buf + sizeof(buf) - 1)
434                 *p++ = c;
435             else if(long_warn == 0) {
436                 fprintf(stderr, "WARNING: incredibly long line received\n");
437                 long_warn = 1;
438             }
439         }
440     }
441
442 }
443
444
445 #if 0
446 int
447 getreply (int expecteof)
448 {
449     int c, n;
450     int dig;
451     int originalcode = 0, continuation = 0;
452     sighand oldintr;
453     int pflag = 0;
454     char *cp, *pt = pasv;
455
456     oldintr = signal (SIGINT, cmdabort);
457     for (;;) {
458         dig = n = code = 0;
459         cp = reply_string;
460         while ((c = getc (cin)) != '\n') {
461             if (c == IAC) {     /* handle telnet commands */
462                 switch (c = getc (cin)) {
463                 case WILL:
464                 case WONT:
465                     c = getc (cin);
466                     fprintf (cout, "%c%c%c", IAC, DONT, c);
467                     fflush (cout);
468                     break;
469                 case DO:
470                 case DONT:
471                     c = getc (cin);
472                     fprintf (cout, "%c%c%c", IAC, WONT, c);
473                     fflush (cout);
474                     break;
475                 default:
476                     break;
477                 }
478                 continue;
479             }
480             dig++;
481             if (c == EOF) {
482                 if (expecteof) {
483                     signal (SIGINT, oldintr);
484                     code = 221;
485                     return (0);
486                 }
487                 lostpeer (0);
488                 if (verbose) {
489                     printf ("421 Service not available, remote server has closed connection\n");
490                     fflush (stdout);
491                 }
492                 code = 421;
493                 return (4);
494             }
495             if (c != '\r' && (verbose > 0 ||
496                               (verbose > -1 && n == '5' && dig > 4))) {
497                 if (proxflag &&
498                     (dig == 1 || dig == 5 && verbose == 0))
499                     printf ("%s:", hostname);
500                 putchar (c);
501             }
502             if (dig < 4 && isdigit (c))
503                 code = code * 10 + (c - '0');
504             if (!pflag && code == 227)
505                 pflag = 1;
506             if (dig > 4 && pflag == 1 && isdigit (c))
507                 pflag = 2;
508             if (pflag == 2) {
509                 if (c != '\r' && c != ')')
510                     *pt++ = c;
511                 else {
512                     *pt = '\0';
513                     pflag = 3;
514                 }
515             }
516             if (dig == 4 && c == '-') {
517                 if (continuation)
518                     code = 0;
519                 continuation++;
520             }
521             if (n == 0)
522                 n = c;
523             if (cp < &reply_string[sizeof (reply_string) - 1])
524                 *cp++ = c;
525         }
526         if (verbose > 0 || verbose > -1 && n == '5') {
527             putchar (c);
528             fflush (stdout);
529         }
530         if (continuation && code != originalcode) {
531             if (originalcode == 0)
532                 originalcode = code;
533             continue;
534         }
535         *cp = '\0';
536         if(sec_complete){
537             if(code == 631)
538                 sec_read_msg(reply_string, prot_safe);
539             else if(code == 632)
540                 sec_read_msg(reply_string, prot_private);
541             else if(code == 633)
542                 sec_read_msg(reply_string, prot_confidential);
543             n = code / 100 + '0';
544         }
545         if (n != '1')
546             cpend = 0;
547         signal (SIGINT, oldintr);
548         if (code == 421 || originalcode == 421)
549             lostpeer (0);
550         if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
551             (*oldintr) (SIGINT);
552         return (n - '0');
553     }
554 }
555
556 #endif
557
558 int
559 empty (fd_set * mask, int sec)
560 {
561     struct timeval t;
562
563     t.tv_sec = sec;
564     t.tv_usec = 0;
565     return (select (FD_SETSIZE, mask, NULL, NULL, &t));
566 }
567
568 jmp_buf sendabort;
569
570 static RETSIGTYPE
571 abortsend (int sig)
572 {
573
574     mflag = 0;
575     abrtflag = 0;
576     printf ("\nsend aborted\nwaiting for remote to finish abort\n");
577     fflush (stdout);
578     longjmp (sendabort, 1);
579 }
580
581 #define HASHBYTES 1024
582
583 static int
584 copy_stream (FILE * from, FILE * to)
585 {
586     static size_t bufsize;
587     static char *buf;
588     int n;
589     int bytes = 0;
590     int werr = 0;
591     int hashbytes = HASHBYTES;
592     struct stat st;
593
594 #if defined(HAVE_MMAP) && !defined(NO_MMAP)
595     void *chunk;
596     size_t off;
597
598 #define BLOCKSIZE (1024 * 1024 * 10)
599
600 #ifndef MAP_FAILED
601 #define MAP_FAILED (-1)
602 #endif
603
604     if (fstat (fileno (from), &st) == 0 && S_ISREG (st.st_mode)) {
605         /*
606          * mmap zero bytes has potential of loosing, don't do it.
607          */
608         if (st.st_size == 0)
609             return 0;
610         off = 0;
611         while (off != st.st_size) {
612             size_t len;
613             ssize_t res;
614
615             len = st.st_size - off;
616             if (len > BLOCKSIZE)
617                 len = BLOCKSIZE;
618
619             chunk = mmap (0, len, PROT_READ, MAP_SHARED, fileno (from), off);
620             if (chunk == (void *) MAP_FAILED) {
621                 if (off == 0) /* try read if mmap doesn't work */
622                     goto try_read;
623                 break;
624             }
625
626             res = sec_write (fileno (to), chunk, len);
627             if (msync (chunk, len, MS_ASYNC))
628                 warn ("msync");
629             if (munmap (chunk, len) < 0)
630                 warn ("munmap");
631             sec_fflush (to);
632             if (res != len)
633                 return off;
634             off += len;
635         }
636         return off;
637     }
638 try_read:
639 #endif
640
641     buf = alloc_buffer (buf, &bufsize,
642                         fstat (fileno (from), &st) >= 0 ? &st : NULL);
643     if (buf == NULL)
644         return -1;
645
646     while ((n = read (fileno (from), buf, bufsize)) > 0) {
647         werr = sec_write (fileno (to), buf, n);
648         if (werr < 0)
649             break;
650         bytes += werr;
651         while (hash && bytes > hashbytes) {
652             putchar ('#');
653             hashbytes += HASHBYTES;
654         }
655     }
656     sec_fflush (to);
657     if (n < 0)
658         warn ("local");
659
660     if (werr < 0) {
661         if (errno != EPIPE)
662             warn ("netout");
663         bytes = -1;
664     }
665     return bytes;
666 }
667
668 void
669 sendrequest (char *cmd, char *local, char *remote, char *lmode, int printnames)
670 {
671     struct stat st;
672     struct timeval start, stop;
673     int c, d;
674     FILE *fin, *dout = 0;
675     int (*closefunc) (FILE *);
676     RETSIGTYPE (*oldintr)(int), (*oldintp)(int);
677     long bytes = 0, hashbytes = HASHBYTES;
678     char *rmode = "w";
679
680     if (verbose && printnames) {
681         if (strcmp (local, "-") != 0)
682             printf ("local: %s ", local);
683         if (remote)
684             printf ("remote: %s\n", remote);
685     }
686     if (proxy) {
687         proxtrans (cmd, local, remote);
688         return;
689     }
690     if (curtype != type)
691         changetype (type, 0);
692     closefunc = NULL;
693     oldintr = NULL;
694     oldintp = NULL;
695
696     if (setjmp (sendabort)) {
697         while (cpend) {
698             getreply (0);
699         }
700         if (data >= 0) {
701             close (data);
702             data = -1;
703         }
704         if (oldintr)
705             signal (SIGINT, oldintr);
706         if (oldintp)
707             signal (SIGPIPE, oldintp);
708         code = -1;
709         return;
710     }
711     oldintr = signal (SIGINT, abortsend);
712     if (strcmp (local, "-") == 0)
713         fin = stdin;
714     else if (*local == '|') {
715         oldintp = signal (SIGPIPE, SIG_IGN);
716         fin = popen (local + 1, lmode);
717         if (fin == NULL) {
718             warn ("%s", local + 1);
719             signal (SIGINT, oldintr);
720             signal (SIGPIPE, oldintp);
721             code = -1;
722             return;
723         }
724         closefunc = pclose;
725     } else {
726         fin = fopen (local, lmode);
727         if (fin == NULL) {
728             warn ("local: %s", local);
729             signal (SIGINT, oldintr);
730             code = -1;
731             return;
732         }
733         closefunc = fclose;
734         if (fstat (fileno (fin), &st) < 0 || !S_ISREG(st.st_mode)) {
735             fprintf (stdout, "%s: not a plain file.\n", local);
736             signal (SIGINT, oldintr);
737             fclose (fin);
738             code = -1;
739             return;
740         }
741     }
742     if (initconn ()) {
743         signal (SIGINT, oldintr);
744         if (oldintp)
745             signal (SIGPIPE, oldintp);
746         code = -1;
747         if (closefunc != NULL)
748             (*closefunc) (fin);
749         return;
750     }
751     if (setjmp (sendabort))
752         goto abort;
753
754     if (restart_point &&
755         (strcmp (cmd, "STOR") == 0 || strcmp (cmd, "APPE") == 0)) {
756         int rc;
757
758         switch (curtype) {
759         case TYPE_A:
760             rc = fseek (fin, (long) restart_point, SEEK_SET);
761             break;
762         case TYPE_I:
763         case TYPE_L:
764             rc = lseek (fileno (fin), restart_point, SEEK_SET);
765             break;
766         default:
767             abort();
768         }
769         if (rc < 0) {
770             warn ("local: %s", local);
771             restart_point = 0;
772             if (closefunc != NULL)
773                 (*closefunc) (fin);
774             return;
775         }
776         if (command ("REST %ld", (long) restart_point)
777             != CONTINUE) {
778             restart_point = 0;
779             if (closefunc != NULL)
780                 (*closefunc) (fin);
781             return;
782         }
783         restart_point = 0;
784         rmode = "r+w";
785     }
786     if (remote) {
787         if (command ("%s %s", cmd, remote) != PRELIM) {
788             signal (SIGINT, oldintr);
789             if (oldintp)
790                 signal (SIGPIPE, oldintp);
791             if (closefunc != NULL)
792                 (*closefunc) (fin);
793             return;
794         }
795     } else if (command ("%s", cmd) != PRELIM) {
796             signal(SIGINT, oldintr);
797             if (oldintp)
798                 signal(SIGPIPE, oldintp);
799             if (closefunc != NULL)
800                 (*closefunc)(fin);
801             return;
802         }
803     dout = dataconn(rmode);
804     if (dout == NULL)
805         goto abort;
806     set_buffer_size (fileno (dout), 0);
807     gettimeofday (&start, (struct timezone *) 0);
808     oldintp = signal (SIGPIPE, SIG_IGN);
809     switch (curtype) {
810
811     case TYPE_I:
812     case TYPE_L:
813         errno = d = c = 0;
814         bytes = copy_stream (fin, dout);
815         break;
816
817     case TYPE_A:
818         while ((c = getc (fin)) != EOF) {
819             if (c == '\n') {
820                 while (hash && (bytes >= hashbytes)) {
821                     putchar ('#');
822                     fflush (stdout);
823                     hashbytes += HASHBYTES;
824                 }
825                 if (ferror (dout))
826                     break;
827                 sec_putc ('\r', dout);
828                 bytes++;
829             }
830             sec_putc (c, dout);
831             bytes++;
832         }
833         sec_fflush (dout);
834         if (hash) {
835             if (bytes < hashbytes)
836                 putchar ('#');
837             putchar ('\n');
838             fflush (stdout);
839         }
840         if (ferror (fin))
841             warn ("local: %s", local);
842         if (ferror (dout)) {
843             if (errno != EPIPE)
844                 warn ("netout");
845             bytes = -1;
846         }
847         break;
848     }
849     if (closefunc != NULL)
850         (*closefunc) (fin);
851     fclose (dout);
852     gettimeofday (&stop, (struct timezone *) 0);
853     getreply (0);
854     signal (SIGINT, oldintr);
855     if (oldintp)
856         signal (SIGPIPE, oldintp);
857     if (bytes > 0)
858         ptransfer ("sent", bytes, &start, &stop);
859     return;
860 abort:
861     signal (SIGINT, oldintr);
862     if (oldintp)
863         signal (SIGPIPE, oldintp);
864     if (!cpend) {
865         code = -1;
866         return;
867     }
868     if (data >= 0) {
869         close (data);
870         data = -1;
871     }
872     if (dout)
873         fclose (dout);
874     getreply (0);
875     code = -1;
876     if (closefunc != NULL && fin != NULL)
877         (*closefunc) (fin);
878     gettimeofday (&stop, (struct timezone *) 0);
879     if (bytes > 0)
880         ptransfer ("sent", bytes, &start, &stop);
881 }
882
883 jmp_buf recvabort;
884
885 void
886 abortrecv (int sig)
887 {
888
889     mflag = 0;
890     abrtflag = 0;
891     printf ("\nreceive aborted\nwaiting for remote to finish abort\n");
892     fflush (stdout);
893     longjmp (recvabort, 1);
894 }
895
896 void
897 recvrequest (char *cmd, char *local, char *remote,
898              char *lmode, int printnames, int local_given)
899 {
900     FILE *fout = NULL, *din = NULL;
901     int (*closefunc) (FILE *);
902     sighand oldintr, oldintp;
903     int c, d, is_retr, tcrflag, bare_lfs = 0;
904     static size_t bufsize;
905     static char *buf;
906     long bytes = 0, hashbytes = HASHBYTES;
907     struct timeval start, stop;
908     struct stat st;
909
910     is_retr = strcmp (cmd, "RETR") == 0;
911     if (is_retr && verbose && printnames) {
912         if (strcmp (local, "-") != 0)
913             printf ("local: %s ", local);
914         if (remote)
915             printf ("remote: %s\n", remote);
916     }
917     if (proxy && is_retr) {
918         proxtrans (cmd, local, remote);
919         return;
920     }
921     closefunc = NULL;
922     oldintr = NULL;
923     oldintp = NULL;
924     tcrflag = !crflag && is_retr;
925     if (setjmp (recvabort)) {
926         while (cpend) {
927             getreply (0);
928         }
929         if (data >= 0) {
930             close (data);
931             data = -1;
932         }
933         if (oldintr)
934             signal (SIGINT, oldintr);
935         code = -1;
936         return;
937     }
938     oldintr = signal (SIGINT, abortrecv);
939     if (!local_given || (strcmp(local, "-") && *local != '|')) {
940         if (access (local, 2) < 0) {
941             char *dir = strrchr (local, '/');
942
943             if (errno != ENOENT && errno != EACCES) {
944                 warn ("local: %s", local);
945                 signal (SIGINT, oldintr);
946                 code = -1;
947                 return;
948             }
949             if (dir != NULL)
950                 *dir = 0;
951             d = access (dir ? local : ".", 2);
952             if (dir != NULL)
953                 *dir = '/';
954             if (d < 0) {
955                 warn ("local: %s", local);
956                 signal (SIGINT, oldintr);
957                 code = -1;
958                 return;
959             }
960             if (!runique && errno == EACCES &&
961                 chmod (local, 0600) < 0) {
962                 warn ("local: %s", local);
963                 signal (SIGINT, oldintr);
964                 signal (SIGINT, oldintr);
965                 code = -1;
966                 return;
967             }
968             if (runique && errno == EACCES &&
969                 (local = gunique (local)) == NULL) {
970                 signal (SIGINT, oldintr);
971                 code = -1;
972                 return;
973             }
974         } else if (runique && (local = gunique (local)) == NULL) {
975             signal(SIGINT, oldintr);
976             code = -1;
977             return;
978         }
979     }
980     if (!is_retr) {
981         if (curtype != TYPE_A)
982             changetype (TYPE_A, 0);
983     } else if (curtype != type)
984         changetype (type, 0);
985     if (initconn ()) {
986         signal (SIGINT, oldintr);
987         code = -1;
988         return;
989     }
990     if (setjmp (recvabort))
991         goto abort;
992     if (is_retr && restart_point &&
993         command ("REST %ld", (long) restart_point) != CONTINUE)
994         return;
995     if (remote) {
996         if (command ("%s %s", cmd, remote) != PRELIM) {
997             signal (SIGINT, oldintr);
998             return;
999         }
1000     } else {
1001         if (command ("%s", cmd) != PRELIM) {
1002             signal (SIGINT, oldintr);
1003             return;
1004         }
1005     }
1006     din = dataconn ("r");
1007     if (din == NULL)
1008         goto abort;
1009     set_buffer_size (fileno (din), 1);
1010     if (local_given && strcmp (local, "-") == 0)
1011         fout = stdout;
1012     else if (local_given && *local == '|') {
1013         oldintp = signal (SIGPIPE, SIG_IGN);
1014         fout = popen (local + 1, "w");
1015         if (fout == NULL) {
1016             warn ("%s", local + 1);
1017             goto abort;
1018         }
1019         closefunc = pclose;
1020     } else {
1021         fout = fopen (local, lmode);
1022         if (fout == NULL) {
1023             warn ("local: %s", local);
1024             goto abort;
1025         }
1026         closefunc = fclose;
1027     }
1028     buf = alloc_buffer (buf, &bufsize,
1029                         fstat (fileno (fout), &st) >= 0 ? &st : NULL);
1030     if (buf == NULL)
1031         goto abort;
1032
1033     gettimeofday (&start, (struct timezone *) 0);
1034     switch (curtype) {
1035
1036     case TYPE_I:
1037     case TYPE_L:
1038         if (restart_point &&
1039             lseek (fileno (fout), restart_point, SEEK_SET) < 0) {
1040             warn ("local: %s", local);
1041             if (closefunc != NULL)
1042                 (*closefunc) (fout);
1043             return;
1044         }
1045         errno = d = 0;
1046         while ((c = sec_read (fileno (din), buf, bufsize)) > 0) {
1047             if ((d = write (fileno (fout), buf, c)) != c)
1048                 break;
1049             bytes += c;
1050             if (hash) {
1051                 while (bytes >= hashbytes) {
1052                     putchar ('#');
1053                     hashbytes += HASHBYTES;
1054                 }
1055                 fflush (stdout);
1056             }
1057         }
1058         if (hash && bytes > 0) {
1059             if (bytes < HASHBYTES)
1060                 putchar ('#');
1061             putchar ('\n');
1062             fflush (stdout);
1063         }
1064         if (c < 0) {
1065             if (errno != EPIPE)
1066                 warn ("netin");
1067             bytes = -1;
1068         }
1069         if (d < c) {
1070             if (d < 0)
1071                 warn ("local: %s", local);
1072             else
1073                 warnx ("%s: short write", local);
1074         }
1075         break;
1076
1077     case TYPE_A:
1078         if (restart_point) {
1079             int i, n, ch;
1080
1081             if (fseek (fout, 0L, SEEK_SET) < 0)
1082                 goto done;
1083             n = restart_point;
1084             for (i = 0; i++ < n;) {
1085                 if ((ch = sec_getc (fout)) == EOF)
1086                     goto done;
1087                 if (ch == '\n')
1088                     i++;
1089             }
1090             if (fseek (fout, 0L, SEEK_CUR) < 0) {
1091         done:
1092                 warn ("local: %s", local);
1093                 if (closefunc != NULL)
1094                     (*closefunc) (fout);
1095                 return;
1096             }
1097         }
1098         while ((c = sec_getc(din)) != EOF) {
1099             if (c == '\n')
1100                 bare_lfs++;
1101             while (c == '\r') {
1102                 while (hash && (bytes >= hashbytes)) {
1103                     putchar ('#');
1104                     fflush (stdout);
1105                     hashbytes += HASHBYTES;
1106                 }
1107                 bytes++;
1108                 if ((c = sec_getc (din)) != '\n' || tcrflag) {
1109                     if (ferror (fout))
1110                         goto break2;
1111                     putc ('\r', fout);
1112                     if (c == '\0') {
1113                         bytes++;
1114                         goto contin2;
1115                     }
1116                     if (c == EOF)
1117                         goto contin2;
1118                 }
1119             }
1120             putc (c, fout);
1121             bytes++;
1122     contin2:;
1123         }
1124 break2:
1125         if (bare_lfs) {
1126             printf ("WARNING! %d bare linefeeds received in ASCII mode\n",
1127                     bare_lfs);
1128             printf ("File may not have transferred correctly.\n");
1129         }
1130         if (hash) {
1131             if (bytes < hashbytes)
1132                 putchar ('#');
1133             putchar ('\n');
1134             fflush (stdout);
1135         }
1136         if (ferror (din)) {
1137             if (errno != EPIPE)
1138                 warn ("netin");
1139             bytes = -1;
1140         }
1141         if (ferror (fout))
1142             warn ("local: %s", local);
1143         break;
1144     }
1145     if (closefunc != NULL)
1146         (*closefunc) (fout);
1147     signal (SIGINT, oldintr);
1148     if (oldintp)
1149         signal (SIGPIPE, oldintp);
1150     fclose (din);
1151     gettimeofday (&stop, (struct timezone *) 0);
1152     getreply (0);
1153     if (bytes > 0 && is_retr)
1154         ptransfer ("received", bytes, &start, &stop);
1155     return;
1156 abort:
1157
1158     /* abort using RFC959 recommended IP,SYNC sequence  */
1159
1160     if (oldintp)
1161         signal (SIGPIPE, oldintr);
1162     signal (SIGINT, SIG_IGN);
1163     if (!cpend) {
1164         code = -1;
1165         signal (SIGINT, oldintr);
1166         return;
1167     }
1168     abort_remote(din);
1169     code = -1;
1170     if (data >= 0) {
1171         close (data);
1172         data = -1;
1173     }
1174     if (closefunc != NULL && fout != NULL)
1175         (*closefunc) (fout);
1176     if (din)
1177         fclose (din);
1178     gettimeofday (&stop, (struct timezone *) 0);
1179     if (bytes > 0)
1180         ptransfer ("received", bytes, &start, &stop);
1181     signal (SIGINT, oldintr);
1182 }
1183
1184 static int
1185 parse_epsv (const char *str)
1186 {
1187     char sep;
1188     char *end;
1189     int port;
1190
1191     if (*str == '\0')
1192         return -1;
1193     sep = *str++;
1194     if (sep != *str++)
1195         return -1;
1196     if (sep != *str++)
1197         return -1;
1198     port = strtol (str, &end, 0);
1199     if (str == end)
1200         return -1;
1201     if (end[0] != sep || end[1] != '\0')
1202         return -1;
1203     return htons(port);
1204 }
1205
1206 static int
1207 parse_pasv (struct sockaddr_in *sin4, const char *str)
1208 {
1209     int a0, a1, a2, a3, p0, p1;
1210
1211     /*
1212      * What we've got at this point is a string of comma separated
1213      * one-byte unsigned integer values. The first four are the an IP
1214      * address. The fifth is the MSB of the port number, the sixth is the
1215      * LSB. From that we'll prepare a sockaddr_in.
1216      */
1217
1218     if (sscanf (str, "%d,%d,%d,%d,%d,%d",
1219                 &a0, &a1, &a2, &a3, &p0, &p1) != 6) {
1220         printf ("Passive mode address scan failure. "
1221                 "Shouldn't happen!\n");
1222         return -1;
1223     }
1224     if (a0 < 0 || a0 > 255 ||
1225         a1 < 0 || a1 > 255 ||
1226         a2 < 0 || a2 > 255 ||
1227         a3 < 0 || a3 > 255 ||
1228         p0 < 0 || p0 > 255 ||
1229         p1 < 0 || p1 > 255) {
1230         printf ("Can't parse passive mode string.\n");
1231         return -1;
1232     }
1233     memset (sin4, 0, sizeof(*sin4));
1234     sin4->sin_family      = AF_INET;
1235     sin4->sin_addr.s_addr = htonl ((a0 << 24) | (a1 << 16) |
1236                                   (a2 << 8) | a3);
1237     sin4->sin_port = htons ((p0 << 8) | p1);
1238     return 0;
1239 }
1240
1241 static int
1242 passive_mode (void)
1243 {
1244     int port;
1245
1246     data = socket (myctladdr->sa_family, SOCK_STREAM, 0);
1247     if (data < 0) {
1248         warn ("socket");
1249         return (1);
1250     }
1251     if (options & SO_DEBUG)
1252         socket_set_debug (data);
1253     if (command ("EPSV") != COMPLETE) {
1254         if (command ("PASV") != COMPLETE) {
1255             printf ("Passive mode refused.\n");
1256             goto bad;
1257         }
1258     }
1259
1260     /*
1261      * Parse the reply to EPSV or PASV
1262      */
1263
1264     port = parse_epsv (pasv);
1265     if (port > 0) {
1266         data_addr->sa_family = myctladdr->sa_family;
1267         socket_set_address_and_port (data_addr,
1268                                      socket_get_address (hisctladdr),
1269                                      port);
1270     } else {
1271         if (parse_pasv ((struct sockaddr_in *)data_addr, pasv) < 0)
1272             goto bad;
1273     }
1274
1275     if (connect (data, data_addr, socket_sockaddr_size (data_addr)) < 0) {
1276         warn ("connect");
1277         goto bad;
1278     }
1279 #ifdef IPTOS_THROUGHPUT
1280     socket_set_tos (data, IPTOS_THROUGHPUT);
1281 #endif
1282     return (0);
1283 bad:
1284     close (data);
1285     data = -1;
1286     sendport = 1;
1287     return (1);
1288 }
1289
1290
1291 static int
1292 active_mode (void)
1293 {
1294     int tmpno = 0;
1295     socklen_t len;
1296     int result;
1297
1298 noport:
1299     data_addr->sa_family = myctladdr->sa_family;
1300     socket_set_address_and_port (data_addr, socket_get_address (myctladdr),
1301                                  sendport ? 0 : socket_get_port (myctladdr));
1302
1303     if (data != -1)
1304         close (data);
1305     data = socket (data_addr->sa_family, SOCK_STREAM, 0);
1306     if (data < 0) {
1307         warn ("socket");
1308         if (tmpno)
1309             sendport = 1;
1310         return (1);
1311     }
1312     if (!sendport)
1313         socket_set_reuseaddr (data, 1);
1314     if (bind (data, data_addr, socket_sockaddr_size (data_addr)) < 0) {
1315         warn ("bind");
1316         goto bad;
1317     }
1318     if (options & SO_DEBUG)
1319         socket_set_debug (data);
1320     len = sizeof (data_addr_ss);
1321     if (getsockname (data, data_addr, &len) < 0) {
1322         warn ("getsockname");
1323         goto bad;
1324     }
1325     if (listen (data, 1) < 0)
1326         warn ("listen");
1327     if (sendport) {
1328         char addr_str[256];
1329         int inet_af;
1330         int overbose;
1331
1332         if (inet_ntop (data_addr->sa_family, socket_get_address (data_addr),
1333                        addr_str, sizeof(addr_str)) == NULL)
1334             errx (1, "inet_ntop failed");
1335         switch (data_addr->sa_family) {
1336         case AF_INET :
1337             inet_af = 1;
1338             break;
1339 #ifdef HAVE_IPV6
1340         case AF_INET6 :
1341             inet_af = 2;
1342             break;
1343 #endif
1344         default :
1345             errx (1, "bad address family %d", data_addr->sa_family);
1346         }
1347
1348
1349         overbose = verbose;
1350         if (debug == 0)
1351             verbose  = -1;
1352
1353         result = command ("EPRT |%d|%s|%d|",
1354                           inet_af, addr_str,
1355                           ntohs(socket_get_port (data_addr)));
1356         verbose = overbose;
1357
1358         if (result == ERROR) {
1359             struct sockaddr_in *sin4 = (struct sockaddr_in *)data_addr;
1360
1361             unsigned int a = ntohl(sin4->sin_addr.s_addr);
1362             unsigned int p = ntohs(sin4->sin_port);
1363
1364             if (data_addr->sa_family != AF_INET) {
1365                 warnx ("remote server doesn't support EPRT");
1366                 goto bad;
1367             }
1368
1369             result = command("PORT %d,%d,%d,%d,%d,%d",
1370                              (a >> 24) & 0xff,
1371                              (a >> 16) & 0xff,
1372                              (a >> 8) & 0xff,
1373                              a & 0xff,
1374                              (p >> 8) & 0xff,
1375                              p & 0xff);
1376             if (result == ERROR && sendport == -1) {
1377                 sendport = 0;
1378                 tmpno = 1;
1379                 goto noport;
1380             }
1381             return (result != COMPLETE);
1382         }
1383         return result != COMPLETE;
1384     }
1385     if (tmpno)
1386         sendport = 1;
1387
1388
1389 #ifdef IPTOS_THROUGHPUT
1390     socket_set_tos (data, IPTOS_THROUGHPUT);
1391 #endif
1392     return (0);
1393 bad:
1394     close (data);
1395     data = -1;
1396     if (tmpno)
1397         sendport = 1;
1398     return (1);
1399 }
1400
1401 /*
1402  * Need to start a listen on the data channel before we send the command,
1403  * otherwise the server's connect may fail.
1404  */
1405 int
1406 initconn (void)
1407 {
1408     if (passivemode)
1409         return passive_mode ();
1410     else
1411         return active_mode ();
1412 }
1413
1414 FILE *
1415 dataconn (const char *lmode)
1416 {
1417     struct sockaddr_storage from_ss;
1418     struct sockaddr *from = (struct sockaddr *)&from_ss;
1419     socklen_t fromlen = sizeof(from_ss);
1420     int s;
1421
1422     if (passivemode)
1423         return (fdopen (data, lmode));
1424
1425     s = accept (data, from, &fromlen);
1426     if (s < 0) {
1427         warn ("accept");
1428         close (data), data = -1;
1429         return (NULL);
1430     }
1431     close (data);
1432     data = s;
1433 #ifdef IPTOS_THROUGHPUT
1434     socket_set_tos (s, IPTOS_THROUGHPUT);
1435 #endif
1436     return (fdopen (data, lmode));
1437 }
1438
1439 void
1440 ptransfer (char *direction, long int bytes,
1441            struct timeval * t0, struct timeval * t1)
1442 {
1443     struct timeval td;
1444     float s;
1445     float bs;
1446     int prec;
1447     char *unit;
1448
1449     if (verbose) {
1450         td.tv_sec = t1->tv_sec - t0->tv_sec;
1451         td.tv_usec = t1->tv_usec - t0->tv_usec;
1452         if (td.tv_usec < 0) {
1453             td.tv_sec--;
1454             td.tv_usec += 1000000;
1455         }
1456         s = td.tv_sec + (td.tv_usec / 1000000.);
1457         bs = bytes / (s ? s : 1);
1458         if (bs >= 1048576) {
1459             bs /= 1048576;
1460             unit = "M";
1461             prec = 2;
1462         } else if (bs >= 1024) {
1463             bs /= 1024;
1464             unit = "k";
1465             prec = 1;
1466         } else {
1467             unit = "";
1468             prec = 0;
1469         }
1470
1471         printf ("%ld bytes %s in %.3g seconds (%.*f %sbyte/s)\n",
1472                 bytes, direction, s, prec, bs, unit);
1473     }
1474 }
1475
1476 void
1477 psabort (int sig)
1478 {
1479
1480     abrtflag++;
1481 }
1482
1483 void
1484 pswitch (int flag)
1485 {
1486     sighand oldintr;
1487     static struct comvars {
1488         int connect;
1489         char name[MaxHostNameLen];
1490         struct sockaddr_storage mctl;
1491         struct sockaddr_storage hctl;
1492         FILE *in;
1493         FILE *out;
1494         int tpe;
1495         int curtpe;
1496         int cpnd;
1497         int sunqe;
1498         int runqe;
1499         int mcse;
1500         int ntflg;
1501         char nti[17];
1502         char nto[17];
1503         int mapflg;
1504         char mi[MaxPathLen];
1505         char mo[MaxPathLen];
1506     } proxstruct, tmpstruct;
1507     struct comvars *ip, *op;
1508
1509     abrtflag = 0;
1510     oldintr = signal (SIGINT, psabort);
1511     if (flag) {
1512         if (proxy)
1513             return;
1514         ip = &tmpstruct;
1515         op = &proxstruct;
1516         proxy++;
1517     } else {
1518         if (!proxy)
1519             return;
1520         ip = &proxstruct;
1521         op = &tmpstruct;
1522         proxy = 0;
1523     }
1524     ip->connect = connected;
1525     connected = op->connect;
1526     if (hostname) {
1527         strlcpy (ip->name, hostname, sizeof (ip->name));
1528     } else
1529         ip->name[0] = 0;
1530     hostname = op->name;
1531     ip->hctl = hisctladdr_ss;
1532     hisctladdr_ss = op->hctl;
1533     ip->mctl = myctladdr_ss;
1534     myctladdr_ss = op->mctl;
1535     ip->in = cin;
1536     cin = op->in;
1537     ip->out = cout;
1538     cout = op->out;
1539     ip->tpe = type;
1540     type = op->tpe;
1541     ip->curtpe = curtype;
1542     curtype = op->curtpe;
1543     ip->cpnd = cpend;
1544     cpend = op->cpnd;
1545     ip->sunqe = sunique;
1546     sunique = op->sunqe;
1547     ip->runqe = runique;
1548     runique = op->runqe;
1549     ip->mcse = mcase;
1550     mcase = op->mcse;
1551     ip->ntflg = ntflag;
1552     ntflag = op->ntflg;
1553     strlcpy (ip->nti, ntin, sizeof (ip->nti));
1554     strlcpy (ntin, op->nti, 17);
1555     strlcpy (ip->nto, ntout, sizeof (ip->nto));
1556     strlcpy (ntout, op->nto, 17);
1557     ip->mapflg = mapflag;
1558     mapflag = op->mapflg;
1559     strlcpy (ip->mi, mapin, MaxPathLen);
1560     strlcpy (mapin, op->mi, MaxPathLen);
1561     strlcpy (ip->mo, mapout, MaxPathLen);
1562     strlcpy (mapout, op->mo, MaxPathLen);
1563     signal(SIGINT, oldintr);
1564     if (abrtflag) {
1565         abrtflag = 0;
1566         (*oldintr) (SIGINT);
1567     }
1568 }
1569
1570 void
1571 abortpt (int sig)
1572 {
1573
1574     printf ("\n");
1575     fflush (stdout);
1576     ptabflg++;
1577     mflag = 0;
1578     abrtflag = 0;
1579     longjmp (ptabort, 1);
1580 }
1581
1582 void
1583 proxtrans (char *cmd, char *local, char *remote)
1584 {
1585     sighand oldintr = NULL;
1586     int secndflag = 0, prox_type, nfnd;
1587     char *cmd2;
1588     fd_set mask;
1589
1590     if (strcmp (cmd, "RETR"))
1591         cmd2 = "RETR";
1592     else
1593         cmd2 = runique ? "STOU" : "STOR";
1594     if ((prox_type = type) == 0) {
1595         if (unix_server && unix_proxy)
1596             prox_type = TYPE_I;
1597         else
1598             prox_type = TYPE_A;
1599     }
1600     if (curtype != prox_type)
1601         changetype (prox_type, 1);
1602     if (command ("PASV") != COMPLETE) {
1603         printf ("proxy server does not support third party transfers.\n");
1604         return;
1605     }
1606     pswitch (0);
1607     if (!connected) {
1608         printf ("No primary connection\n");
1609         pswitch (1);
1610         code = -1;
1611         return;
1612     }
1613     if (curtype != prox_type)
1614         changetype (prox_type, 1);
1615     if (command ("PORT %s", pasv) != COMPLETE) {
1616         pswitch (1);
1617         return;
1618     }
1619     if (setjmp (ptabort))
1620         goto abort;
1621     oldintr = signal (SIGINT, abortpt);
1622     if (command ("%s %s", cmd, remote) != PRELIM) {
1623         signal (SIGINT, oldintr);
1624         pswitch (1);
1625         return;
1626     }
1627     sleep (2);
1628     pswitch (1);
1629     secndflag++;
1630     if (command ("%s %s", cmd2, local) != PRELIM)
1631         goto abort;
1632     ptflag++;
1633     getreply (0);
1634     pswitch (0);
1635     getreply (0);
1636     signal (SIGINT, oldintr);
1637     pswitch (1);
1638     ptflag = 0;
1639     printf ("local: %s remote: %s\n", local, remote);
1640     return;
1641 abort:
1642     signal (SIGINT, SIG_IGN);
1643     ptflag = 0;
1644     if (strcmp (cmd, "RETR") && !proxy)
1645         pswitch (1);
1646     else if (!strcmp (cmd, "RETR") && proxy)
1647         pswitch (0);
1648     if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
1649         if (command ("%s %s", cmd2, local) != PRELIM) {
1650             pswitch (0);
1651             if (cpend)
1652                 abort_remote ((FILE *) NULL);
1653         }
1654         pswitch (1);
1655         if (ptabflg)
1656             code = -1;
1657         if (oldintr)
1658             signal (SIGINT, oldintr);
1659         return;
1660     }
1661     if (cpend)
1662         abort_remote ((FILE *) NULL);
1663     pswitch (!proxy);
1664     if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
1665         if (command ("%s %s", cmd2, local) != PRELIM) {
1666             pswitch (0);
1667             if (cpend)
1668                 abort_remote ((FILE *) NULL);
1669             pswitch (1);
1670             if (ptabflg)
1671                 code = -1;
1672             signal (SIGINT, oldintr);
1673             return;
1674         }
1675     }
1676     if (cpend)
1677         abort_remote ((FILE *) NULL);
1678     pswitch (!proxy);
1679     if (cpend) {
1680         FD_ZERO (&mask);
1681         if (fileno(cin) >= FD_SETSIZE)
1682             errx (1, "fd too large");
1683         FD_SET (fileno (cin), &mask);
1684         if ((nfnd = empty (&mask, 10)) <= 0) {
1685             if (nfnd < 0) {
1686                 warn ("abort");
1687             }
1688             if (ptabflg)
1689                 code = -1;
1690             lostpeer (0);
1691         }
1692         getreply (0);
1693         getreply (0);
1694     }
1695     if (proxy)
1696         pswitch (0);
1697     pswitch (1);
1698     if (ptabflg)
1699         code = -1;
1700     signal (SIGINT, oldintr);
1701 }
1702
1703 void
1704 reset (int argc, char **argv)
1705 {
1706     fd_set mask;
1707     int nfnd = 1;
1708
1709     FD_ZERO (&mask);
1710     while (nfnd > 0) {
1711         if (fileno (cin) >= FD_SETSIZE)
1712             errx (1, "fd too large");
1713         FD_SET (fileno (cin), &mask);
1714         if ((nfnd = empty (&mask, 0)) < 0) {
1715             warn ("reset");
1716             code = -1;
1717             lostpeer(0);
1718         } else if (nfnd) {
1719             getreply(0);
1720         }
1721     }
1722 }
1723
1724 char *
1725 gunique (char *local)
1726 {
1727     static char new[MaxPathLen];
1728     char *cp = strrchr (local, '/');
1729     int d, count = 0;
1730     char ext = '1';
1731
1732     if (cp)
1733         *cp = '\0';
1734     d = access (cp ? local : ".", 2);
1735     if (cp)
1736         *cp = '/';
1737     if (d < 0) {
1738         warn ("local: %s", local);
1739         return NULL;
1740     }
1741     strlcpy (new, local, sizeof(new));
1742     cp = new + strlen(new);
1743     *cp++ = '.';
1744     while (!d) {
1745         if (++count == 100) {
1746             printf ("runique: can't find unique file name.\n");
1747             return NULL;
1748         }
1749         *cp++ = ext;
1750         *cp = '\0';
1751         if (ext == '9')
1752             ext = '0';
1753         else
1754             ext++;
1755         if ((d = access (new, 0)) < 0)
1756             break;
1757         if (ext != '0')
1758             cp--;
1759         else if (*(cp - 2) == '.')
1760             *(cp - 1) = '1';
1761         else {
1762             *(cp - 2) = *(cp - 2) + 1;
1763             cp--;
1764         }
1765     }
1766     return (new);
1767 }
1768
1769 void
1770 abort_remote (FILE * din)
1771 {
1772     char buf[BUFSIZ];
1773     int nfnd;
1774     fd_set mask;
1775
1776     /*
1777      * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1778      * after urgent byte rather than before as is protocol now
1779      */
1780     snprintf (buf, sizeof (buf), "%c%c%c", IAC, IP, IAC);
1781     if (send (fileno (cout), buf, 3, MSG_OOB) != 3)
1782         warn ("abort");
1783     fprintf (cout, "%c", DM);
1784     sec_fprintf(cout, "ABOR");
1785     sec_fflush (cout);
1786     fprintf (cout, "\r\n");
1787     fflush(cout);
1788     FD_ZERO (&mask);
1789     if (fileno (cin) >= FD_SETSIZE)
1790         errx (1, "fd too large");
1791     FD_SET (fileno (cin), &mask);
1792     if (din) {
1793         if (fileno (din) >= FD_SETSIZE)
1794             errx (1, "fd too large");
1795         FD_SET (fileno (din), &mask);
1796     }
1797     if ((nfnd = empty (&mask, 10)) <= 0) {
1798         if (nfnd < 0) {
1799             warn ("abort");
1800         }
1801         if (ptabflg)
1802             code = -1;
1803         lostpeer (0);
1804     }
1805     if (din && FD_ISSET (fileno (din), &mask)) {
1806         while (read (fileno (din), buf, BUFSIZ) > 0)
1807              /* LOOP */ ;
1808     }
1809     if (getreply (0) == ERROR && code == 552) {
1810         /* 552 needed for nic style abort */
1811         getreply (0);
1812     }
1813     getreply (0);
1814 }