Fri Aug 7 22:39:47 1998 Matthew D Hancher <mdh@mit.edu>
[krb5.git] / src / appl / gssftp / ftp / ftp.c
1 /*
2  * Copyright (c) 1985, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 static char sccsid[] = "@(#)ftp.c       5.38 (Berkeley) 4/22/91";
36 #endif /* not lint */
37
38 #ifdef HAVE_STDLIB_H
39 #include <stdlib.h>
40 #endif
41 #include <sys/param.h>
42 #include <sys/stat.h>
43 #include <sys/ioctl.h>
44 #ifndef KRB5_KRB4_COMPAT
45 /* krb.h gets this, and Ultrix doesn't protect vs multiple inclusion */
46 #include <sys/socket.h>
47 #endif
48 #include <sys/time.h>
49 #include <sys/file.h>
50 #ifdef HAVE_SYS_SELECT_H
51 #include <sys/select.h>
52 #endif
53
54 #include <netinet/in.h>
55 #include <netinet/in_systm.h>
56 #include <netinet/ip.h>
57 #include <arpa/ftp.h>
58 #include <arpa/telnet.h>
59
60 #include <stdio.h>
61 #include <signal.h>
62 #include <string.h>
63 #include <errno.h>
64 #ifndef KRB5_KRB4_COMPAT
65 /* krb.h gets this, and Ultrix doesn't protect vs multiple inclusion */
66 #include <netdb.h>
67 #endif
68 #include <fcntl.h>
69 #include <pwd.h>
70 #ifndef STDARG
71 #if (defined(__STDC__) && ! defined(VARARGS)) || defined(HAVE_STDARG_H)
72 #define STDARG
73 #endif
74 #endif
75 #ifdef STDARG
76 #include <stdarg.h>
77 #else
78 #include <varargs.h>
79 #endif
80
81 #ifndef L_SET
82 #define L_SET 0
83 #endif
84 #ifndef L_INCR
85 #define L_INCR 1
86 #endif
87
88 #ifdef KRB5_KRB4_COMPAT
89 #include <krb.h>
90
91 KTEXT_ST ticket;
92 CREDENTIALS cred;
93 Key_schedule schedule;
94 MSG_DAT msg_data;
95 #endif /* KRB5_KRB4_COMPAT */
96 #ifdef GSSAPI
97 #include <gssapi/gssapi.h>
98 #include <gssapi/gssapi_generic.h>
99 gss_ctx_id_t gcontext;
100 #endif /* GSSAPI */
101
102
103 static int kerror;      /* XXX needed for all auth types */
104
105 char    *auth_type;     /* Authentication succeeded?  If so, what type? */
106
107 unsigned int maxbuf, actualbuf;
108 unsigned char *ucbuf;
109  
110 #define DEFINITIONS
111 #include "ftp_var.h"
112
113 #define sig_t my_sig_t
114 #define sigtype krb5_sigtype
115 typedef sigtype (*sig_t)();
116
117 struct  sockaddr_in hisctladdr;
118 struct  sockaddr_in hisdataaddr;
119 struct  sockaddr_in data_addr;
120 int     data = -1;
121 int     abrtflag = 0;
122 int     ptflag = 0;
123 struct  sockaddr_in myctladdr;
124 uid_t   getuid();
125 sig_t   lostpeer();
126 off_t   restart_point = 0;
127
128 #define strerror(error) (sys_errlist[error])
129 #ifdef NEED_SYS_ERRLIST
130 extern char *sys_errlist[];
131 #endif
132
133 extern int connected;
134
135 #define herror()        printf("unknown host\n")
136
137 FILE    *cin, *cout;
138 FILE    *dataconn();
139
140 char *
141 hookup(host, port)
142         char *host;
143         int port;
144 {
145         register struct hostent *hp = 0;
146         int s, len, tos;
147         static char hostnamebuf[80];
148
149         memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
150         hisctladdr.sin_addr.s_addr = inet_addr(host);
151         if (hisctladdr.sin_addr.s_addr != -1) {
152                 hisctladdr.sin_family = AF_INET;
153                 (void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
154         } else {
155                 hp = gethostbyname(host);
156                 if (hp == NULL) {
157                         fprintf(stderr, "ftp: %s: ", host);
158                         herror();
159                         code = -1;
160                         return((char *) 0);
161                 }
162                 hisctladdr.sin_family = hp->h_addrtype;
163                 memcpy((caddr_t)&hisctladdr.sin_addr, hp->h_addr_list[0],
164                        sizeof(hisctladdr.sin_addr));
165                 (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
166         }
167         hostname = hostnamebuf;
168         s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
169         if (s < 0) {
170                 perror("ftp: socket");
171                 code = -1;
172                 return (0);
173         }
174         hisctladdr.sin_port = port;
175         while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
176                 if (hp && hp->h_addr_list[1]) {
177                         int oerrno = errno;
178                         extern char *inet_ntoa();
179
180                         fprintf(stderr, "ftp: connect to address %s: ",
181                                 inet_ntoa(hisctladdr.sin_addr));
182                         errno = oerrno;
183                         perror((char *) 0);
184                         hp->h_addr_list++;
185                         memcpy((caddr_t)&hisctladdr.sin_addr,
186                                hp->h_addr_list[0], 
187                                sizeof(hisctladdr.sin_addr));
188                         fprintf(stdout, "Trying %s...\n",
189                                 inet_ntoa(hisctladdr.sin_addr));
190                         (void) close(s);
191                         s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
192                         if (s < 0) {
193                                 perror("ftp: socket");
194                                 code = -1;
195                                 return (0);
196                         }
197                         continue;
198                 }
199                 perror("ftp: connect");
200                 code = -1;
201                 goto bad;
202         }
203         len = sizeof (myctladdr);
204         if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
205                 perror("ftp: getsockname");
206                 code = -1;
207                 goto bad;
208         }
209 #ifdef IP_TOS
210 #ifdef IPTOS_LOWDELAY
211         tos = IPTOS_LOWDELAY;
212         if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
213                 perror("ftp: setsockopt TOS (ignored)");
214 #endif
215 #endif
216         cin = fdopen(s, "r");
217         cout = fdopen(s, "w");
218         if (cin == NULL || cout == NULL) {
219                 fprintf(stderr, "ftp: fdopen failed.\n");
220                 if (cin)
221                         (void) fclose(cin);
222                 if (cout)
223                         (void) fclose(cout);
224                 code = -1;
225                 goto bad;
226         }
227         if (verbose)
228                 printf("Connected to %s.\n", hostname);
229         if (getreply(0) > 2) {  /* read startup message from server */
230                 if (cin)
231                         (void) fclose(cin);
232                 if (cout)
233                         (void) fclose(cout);
234                 code = -1;
235                 goto bad;
236         }
237 #ifdef SO_OOBINLINE
238         {
239         int on = 1;
240
241         if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
242                 < 0 && debug) {
243                         perror("ftp: setsockopt");
244                 }
245         }
246 #endif /* SO_OOBINLINE */
247
248         return (hostname);
249 bad:
250         (void) close(s);
251         return ((char *)0);
252 }
253
254 login(host)
255         char *host;
256 {
257         char tmp[80];
258         char *user, *pass, *acct, *getenv(), *getlogin(), *mygetpass();
259         int n, aflag = 0;
260
261         user = pass = acct = 0;
262         if (ruserpass(host, &user, &pass, &acct) < 0) {
263                 code = -1;
264                 return(0);
265         }
266         while (user == NULL) {
267                 char *myname;
268
269                 myname = getenv("LOGNAME");
270                 if (myname == NULL)
271                         myname = getenv("USER");
272                 if (myname == NULL)
273                         myname = getlogin();
274                 if (myname == NULL) {
275                         struct passwd *pp = getpwuid(getuid());
276
277                         if (pp != NULL)
278                                 myname = pp->pw_name;
279                 }
280                 if (myname)
281                         printf("Name (%s:%s): ", host, myname);
282                 else
283                         printf("Name (%s): ", host);
284                 (void) fgets(tmp, sizeof(tmp) - 1, stdin);
285                 tmp[strlen(tmp) - 1] = '\0';
286                 if (*tmp == '\0')
287                         user = myname;
288                 else
289                         user = tmp;
290         }
291         n = command("USER %s", user);
292         if (n == COMPLETE)
293                 n = command("PASS dummy");
294         else if (n == CONTINUE) {
295 #ifndef NOENCRYPTION
296                 int oldlevel;
297 #endif
298                 if (pass == NULL)
299                         pass = mygetpass("Password:");
300 #ifndef NOENCRYPTION
301                 if ((oldlevel = level) == PROT_S) level = PROT_P;
302 #endif
303                 n = command("PASS %s", pass);
304 #ifndef NOENCRYPTION
305                 /* level may have changed */
306                 if (level == PROT_P) level = oldlevel;
307 #endif
308         }
309         if (n == CONTINUE) {
310                 aflag++;
311                 acct = mygetpass("Account:");
312                 n = command("ACCT %s", acct);
313         }
314         if (n != COMPLETE) {
315                 fprintf(stderr, "Login failed.\n");
316                 return (0);
317         }
318         if (!aflag && acct != NULL)
319                 (void) command("ACCT %s", acct);
320         if (proxy)
321                 return(1);
322         for (n = 0; n < macnum; ++n) {
323                 if (!strcmp("init", macros[n].mac_name)) {
324                         (void) strcpy(line, "$init");
325                         makeargv();
326                         domacro(margc, margv);
327                         break;
328                 }
329         }
330         return (1);
331 }
332
333 sigtype
334 cmdabort(sig)
335         int sig;
336 {
337         extern jmp_buf ptabort;
338
339         printf("\n");
340         (void) fflush(stdout);
341         abrtflag++;
342         if (ptflag)
343                 longjmp(ptabort,1);
344 }
345
346 secure_command(cmd)
347         char *cmd;
348 {
349         char in[FTP_BUFSIZ], out[FTP_BUFSIZ];
350         int length;
351
352         if (auth_type) {
353                 /*
354                  * File protection level also determines whether
355                  * commands are MIC or ENC.  Should be independent ...
356                  */
357 #ifdef KRB5_KRB4_COMPAT
358                 if (strcmp(auth_type, "KERBEROS_V4") == 0)
359                     if ((length = level == PROT_P ?
360                         krb_mk_priv((unsigned char *)cmd, (unsigned char *)out,
361                                 strlen(cmd), schedule,
362                                 &cred.session, &myctladdr, &hisctladdr)
363                       : krb_mk_safe((unsigned char *)cmd, (unsigned char *)out,
364                                 strlen(cmd), &cred.session,
365                                 &myctladdr, &hisctladdr)) == -1) {
366                         fprintf(stderr, "krb_mk_%s failed for KERBEROS_V4\n",
367                                         level == PROT_P ? "priv" : "safe");
368                         return(0);
369                     }
370 #endif /* KRB5_KRB4_COMPAT */
371 #ifdef GSSAPI
372                 /* secure_command (based on level) */
373                 if (strcmp(auth_type, "GSSAPI") == 0) {
374                         gss_buffer_desc in_buf, out_buf;
375                         OM_uint32 maj_stat, min_stat;
376                         int conf_state;
377 /* level = PROT_P; */
378                         in_buf.value = cmd;
379                         in_buf.length = strlen(cmd) + 1;
380                         maj_stat = gss_seal(&min_stat, gcontext,
381                                             (level==PROT_P), /* confidential */
382                                             GSS_C_QOP_DEFAULT,
383                                             &in_buf, &conf_state,
384                                             &out_buf);
385                         if (maj_stat != GSS_S_COMPLETE) {
386                                 /* generally need to deal */
387                                 user_gss_error(maj_stat, min_stat,
388                                                (level==PROT_P)?
389                                                  "gss_seal ENC didn't complete":
390                                                  "gss_seal MIC didn't complete");
391                         } else if ((level == PROT_P) && !conf_state) {
392                                 fprintf(stderr, 
393                                         "GSSAPI didn't encrypt message");
394                         } else {
395                                 if (debug)
396                                   fprintf(stderr, "sealed (%s) %d bytes\n",
397                                           level==PROT_P?"ENC":"MIC", 
398                                           out_buf.length);
399                                 memcpy(out, out_buf.value, 
400                                        length=out_buf.length);
401                                 gss_release_buffer(&min_stat, &out_buf);
402                         }
403                 }
404 #endif /* GSSAPI */
405                 /* Other auth types go here ... */
406                 if (kerror = radix_encode(out, in, &length, 0)) {
407                         fprintf(stderr,"Couldn't base 64 encode command (%s)\n",
408                                         radix_error(kerror));
409                         return(0);
410                 }
411                 fprintf(cout, "%s %s", level == PROT_P ? "ENC" : "MIC", in);
412                 if(debug) 
413                   fprintf(stderr, "secure_command(%s)\nencoding %d bytes %s %s\n",
414                           cmd, length, level==PROT_P ? "ENC" : "MIC", in);
415         } else  fputs(cmd, cout);
416         fprintf(cout, "\r\n");
417         (void) fflush(cout);
418         return(1);
419 }
420
421 #ifdef STDARG
422 command(char *fmt, ...)
423 #else
424 /*VARARGS*/
425 command(va_alist)
426 va_dcl
427 #endif
428 {
429         char in[FTP_BUFSIZ];
430         va_list ap;
431 #ifndef STDARG
432         char *fmt;
433 #endif
434         int r;
435         sig_t oldintr;
436         sigtype cmdabort();
437
438         abrtflag = 0;
439         if (debug) {
440                 if (proxflag) printf("%s ", hostname);
441                 printf("---> ");
442 #ifdef STDARG
443                 va_start(ap, fmt);
444 #else
445                 va_start(ap);
446                 fmt = va_arg(ap, char *);
447 #endif
448                 if (strncmp("PASS ", fmt, 5) == 0)
449                         printf("PASS XXXX");
450                 else 
451                         vfprintf(stdout, fmt, ap);
452                 va_end(ap);
453                 printf("\n");
454                 (void) fflush(stdout);
455         }
456         if (cout == NULL) {
457                 perror ("No control connection for command");
458                 code = -1;
459                 return (0);
460         }
461         oldintr = signal(SIGINT, cmdabort);
462 #ifdef STDARG
463         va_start(ap, fmt);
464 #else
465         va_start(ap);
466         fmt = va_arg(ap, char *);
467 #endif
468         vsprintf(in, fmt, ap);
469         va_end(ap);
470 again:  if (secure_command(in) == 0)
471                 return(0);
472         cpend = 1;
473         r = getreply(!strcmp(fmt, "QUIT"));
474 #ifndef NOENCRYPTION
475         if (r == 533 && level == PROT_P) {
476                 fprintf(stderr,
477                         "ENC command not supported at server; retrying under MIC...\n");
478                 level = PROT_S;
479                 goto again;
480         }
481 #endif
482         if (abrtflag && oldintr != SIG_IGN)
483                 (*oldintr)(SIGINT);
484         (void) signal(SIGINT, oldintr);
485         return(r);
486 }
487
488 char reply_string[FTP_BUFSIZ];          /* last line of previous reply */
489
490 /* for parsing replies to the ADAT command */
491 char *reply_parse, reply_buf[FTP_BUFSIZ], *reply_ptr;
492
493 #include <ctype.h>
494
495 getreply(expecteof)
496         int expecteof;
497 {
498         register int i, c, n;
499         register int dig;
500         register char *cp;
501         int originalcode = 0, continuation = 0;
502         sig_t oldintr;
503         int pflag = 0;
504         char *pt = pasv;
505         sigtype cmdabort();
506         char ibuf[FTP_BUFSIZ], obuf[FTP_BUFSIZ];
507         int safe = 0;
508         extern char *strpbrk(), *strstr();
509
510         ibuf[0] = '\0';
511         if (reply_parse) reply_ptr = reply_buf;
512         oldintr = signal(SIGINT, cmdabort);
513         for (;;) {
514                 obuf[0] = '\0';
515                 dig = n = code = i = 0;
516                 cp = reply_string;
517                 while ((c = ibuf[0] ? ibuf[i++] : getc(cin)) != '\n') {
518                         if (c == IAC) {     /* handle telnet commands */
519                                 switch (c = getc(cin)) {
520                                 case WILL:
521                                 case WONT:
522                                         c = getc(cin);
523                                         fprintf(cout, "%c%c%c", IAC, DONT, c);
524                                         (void) fflush(cout);
525                                         break;
526                                 case DO:
527                                 case DONT:
528                                         c = getc(cin);
529                                         fprintf(cout, "%c%c%c", IAC, WONT, c);
530                                         (void) fflush(cout);
531                                         break;
532                                 default:
533                                         break;
534                                 }
535                                 continue;
536                         }
537                         dig++;
538                         if (c == EOF) {
539                                 if (expecteof) {
540                                         (void) signal(SIGINT,oldintr);
541                                         code = 221;
542                                         return (0);
543                                 }
544                                 lostpeer();
545                                 if (verbose) {
546                                         printf("421 Service not available, remote server has closed connection\n");
547                                         (void) fflush(stdout);
548                                 }
549                                 code = 421;
550                                 return(4);
551                         }
552                         if (n == 0)
553                                 n = c;
554                         if (auth_type && !ibuf[0] &&
555                                 (n == '6' || continuation)) {
556                             if (c != '\r' && dig > 4)
557                                 obuf[i++] = c;
558                         } else {
559                             if (auth_type && !ibuf[0] && dig == 1 && verbose)
560                         printf("Unauthenticated reply received from server:\n");
561                             if (reply_parse) *reply_ptr++ = c;
562                             if (c != '\r' && (verbose > 0 ||
563                                 (verbose > -1 && n == '5' && dig > 4))) {
564                                     if (proxflag &&
565                                         (dig == 1 || dig == 5 && verbose == 0))
566                                                 printf("%s:",hostname);
567                                     (void) putchar(c);
568                             }
569                         }
570                         if (auth_type && !ibuf[0] && n != '6') continue;
571                         if (dig < 4 && isdigit(c))
572                                 code = code * 10 + (c - '0');
573                         if (!pflag && code == 227)
574                                 pflag = 1;
575                         if (dig > 4 && pflag == 1 && isdigit(c))
576                                 pflag = 2;
577                         if (pflag == 2) {
578                                 if (c != '\r' && c != ')')
579                                         *pt++ = c;
580                                 else {
581                                         *pt = '\0';
582                                         pflag = 3;
583                                 }
584                         }
585                         if (dig == 4 && c == '-' && n != '6') {
586                                 if (continuation)
587                                         code = 0;
588                                 continuation++;
589                         }
590                         if (cp < &reply_string[sizeof(reply_string) - 1])
591                                 *cp++ = c;
592                 }
593                 if (auth_type && !ibuf[0] && n != '6')
594                         return(getreply(expecteof));
595                 ibuf[0] = obuf[i] = '\0';
596                 if (code && n == '6')
597                     if (code != 631 && code != 632 && code != 633) {
598                         printf("Unknown reply: %d %s\n", code, obuf);
599                         n = '5';
600                     } else safe = (code == 631);
601                 if (obuf[0])    /* if there is a string to decode */
602                     if (!auth_type) {
603                         printf("Cannot decode reply:\n%d %s\n", code, obuf);
604                         n = '5';
605                     }
606 #ifdef NOENCRYPTION
607                     else if (code == 632) {
608                         printf("Cannot decrypt %d reply: %s\n", code, obuf);
609                         n = '5';
610                     }
611 #endif
612 #ifdef NOCONFIDENTIAL
613                     else if (code == 633) {
614                         printf("Cannot decrypt %d reply: %s\n", code, obuf);
615                         n = '5';
616                     }
617 #endif
618                     else {
619                         int len;
620                         if (kerror = radix_encode(obuf, ibuf, &len, 1)) {
621                             printf("Can't base 64 decode reply %d (%s)\n\"%s\"\n",
622                                         code, radix_error(kerror), obuf);
623                             n = '5';
624                         }
625 #ifdef KRB5_KRB4_COMPAT
626                         else if (strcmp(auth_type, "KERBEROS_V4") == 0)
627                                 if ((kerror = safe ?
628                                   krb_rd_safe((unsigned char *)ibuf, len,
629                                         &cred.session,
630                                         &hisctladdr, &myctladdr, &msg_data)
631                                 : krb_rd_priv((unsigned char *)ibuf, len,
632                                         schedule, &cred.session,
633                                         &hisctladdr, &myctladdr, &msg_data))
634                                 != KSUCCESS) {
635                                   printf("%d reply %s! (krb_rd_%s: %s)\n", code,
636                                         safe ? "modified" : "garbled",
637                                         safe ? "safe" : "priv",
638                                         krb_get_err_text(kerror));
639                                   n = '5';
640                                 } else {
641                                   if (debug) printf("%c:", safe ? 'S' : 'P');
642                                   memcpy(ibuf, msg_data.app_data,
643                                         msg_data.app_length);
644                                   strcpy(&ibuf[msg_data.app_length], "\r\n");
645                                   continue;
646                                 }
647 #endif
648 #ifdef GSSAPI
649                         else if (strcmp(auth_type, "GSSAPI") == 0) {
650                                 gss_buffer_desc xmit_buf, msg_buf;
651                                 OM_uint32 maj_stat, min_stat;
652                                 int conf_state;
653                                 xmit_buf.value = ibuf;
654                                 xmit_buf.length = len;
655                                 /* decrypt/verify the message */
656                                 conf_state = safe;
657                                 maj_stat = gss_unseal(&min_stat, gcontext, 
658                                                       &xmit_buf, &msg_buf, 
659                                                       &conf_state, NULL);
660                                 if (maj_stat != GSS_S_COMPLETE) {
661                                   user_gss_error(maj_stat, min_stat, 
662                                                  "failed unsealing reply");
663                                   n = '5';
664                                 } else {
665                                   memcpy(ibuf, msg_buf.value, 
666                                          msg_buf.length);
667                                   strcpy(&ibuf[msg_buf.length], "\r\n");
668                                   gss_release_buffer(&min_stat,&msg_buf);
669                                   continue;
670                                 }
671                         }
672 #endif
673                         /* Other auth types go here... */
674                     }
675                 else
676                 if (verbose > 0 || verbose > -1 && n == '5') {
677                         (void) putchar(c);
678                         (void) fflush (stdout);
679                 }
680                 if (continuation && code != originalcode) {
681                         if (originalcode == 0)
682                                 originalcode = code;
683                         continue;
684                 }
685                 *cp = '\0';
686                 if (n != '1')
687                         cpend = 0;
688                 (void) signal(SIGINT,oldintr);
689                 if (code == 421 || originalcode == 421)
690                         lostpeer();
691                 if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
692                         (*oldintr)(SIGINT);
693                 if (reply_parse) {
694                         *reply_ptr = '\0';
695                         if (reply_ptr = strstr(reply_buf, reply_parse)) {
696                                 reply_parse = reply_ptr + strlen(reply_parse);
697                                 if (reply_ptr = strpbrk(reply_parse, " \r"))
698                                         *reply_ptr = '\0';
699                         } else reply_parse = reply_ptr;
700                 }
701                 return (n - '0');
702         }
703 }
704
705 empty(mask, sec)
706  fd_set *mask;
707         int sec;
708 {
709         struct timeval t;
710
711         t.tv_sec = (long) sec;
712         t.tv_usec = 0;
713         return(select(32, mask, (fd_set *) 0, (fd_set *) 0, &t));
714 }
715
716 jmp_buf sendabort;
717
718 sigtype
719 abortsend(sig)
720         int sig;
721 {
722
723         mflag = 0;
724         abrtflag = 0;
725         printf("\nsend aborted\nwaiting for remote to finish abort\n");
726         (void) fflush(stdout);
727         longjmp(sendabort, 1);
728 }
729
730 #ifdef STDARG
731 secure_error(char *fmt, ...)
732 #else
733 /* VARARGS1 */
734 secure_error(fmt, p1, p2, p3, p4, p5)
735         char *fmt;
736 #endif
737 {
738 #ifdef STDARG
739         va_list ap;
740
741         va_start(ap, fmt);
742         vfprintf(stderr, fmt, ap);
743         va_end(ap);
744 #else
745         fprintf(stderr, fmt, p1, p2, p3, p4, p5);
746 #endif
747         putc('\n', stderr);
748 }
749
750 #define HASHBYTES 1024
751
752 sendrequest(cmd, local, remote, printnames)
753         char *cmd, *local, *remote;
754         int printnames;
755 {
756         struct stat st;
757         struct timeval start, stop;
758         register int c, d;
759         FILE *fin, *dout = 0, *popen();
760         int (*closefunc)(), pclose(), fclose();
761         sig_t oldintr, oldintp;
762         long bytes = 0, hashbytes = HASHBYTES;
763         char *lmode, buf[FTP_BUFSIZ], *bufp;
764         sigtype abortsend();
765
766         if (verbose && printnames) {
767                 if (local && *local != '-')
768                         printf("local: %s ", local);
769                 if (remote)
770                         printf("remote: %s\n", remote);
771         }
772         if (proxy) {
773                 proxtrans(cmd, local, remote);
774                 return;
775         }
776         if (curtype != type)
777                 changetype(type, 0);
778         closefunc = NULL;
779         oldintr = NULL;
780         oldintp = NULL;
781         lmode = "w";
782         if (setjmp(sendabort)) {
783                 while (cpend) {
784                         (void) getreply(0);
785                 }
786                 if (data >= 0) {
787                         (void) close(data);
788                         data = -1;
789                 }
790                 if (oldintr)
791                         (void) signal(SIGINT,oldintr);
792                 if (oldintp)
793                         (void) signal(SIGPIPE,oldintp);
794                 code = -1;
795                 return;
796         }
797         oldintr = signal(SIGINT, abortsend);
798         if (strcmp(local, "-") == 0)
799                 fin = stdin;
800         else if (*local == '|') {
801                 oldintp = signal(SIGPIPE,SIG_IGN);
802                 fin = popen(local + 1, "r");
803                 if (fin == NULL) {
804                         perror(local + 1);
805                         (void) signal(SIGINT, oldintr);
806                         (void) signal(SIGPIPE, oldintp);
807                         code = -1;
808                         return;
809                 }
810                 closefunc = pclose;
811         } else {
812                 fin = fopen(local, "r");
813                 if (fin == NULL) {
814                         fprintf(stderr, "local: %s: %s\n", local,
815                                 strerror(errno));
816                         (void) signal(SIGINT, oldintr);
817                         code = -1;
818                         return;
819                 }
820                 closefunc = fclose;
821                 if (fstat(fileno(fin), &st) < 0 ||
822                     (st.st_mode&S_IFMT) != S_IFREG) {
823                         fprintf(stdout, "%s: not a plain file.\n", local);
824                         (void) signal(SIGINT, oldintr);
825                         fclose(fin);
826                         code = -1;
827                         return;
828                 }
829         }
830         if (initconn()) {
831                 (void) signal(SIGINT, oldintr);
832                 if (oldintp)
833                         (void) signal(SIGPIPE, oldintp);
834                 code = -1;
835                 if (closefunc != NULL)
836                         (*closefunc)(fin);
837                 return;
838         }
839         if (setjmp(sendabort))
840                 goto abort;
841
842         if (restart_point &&
843             (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
844                 if (fseek(fin, (long) restart_point, 0) < 0) {
845                         fprintf(stderr, "local: %s: %s\n", local,
846                                 strerror(errno));
847                         restart_point = 0;
848                         if (closefunc != NULL)
849                                 (*closefunc)(fin);
850                         return;
851                 }
852                 if (command("REST %ld", (long) restart_point)
853                         != CONTINUE) {
854                         restart_point = 0;
855                         if (closefunc != NULL)
856                                 (*closefunc)(fin);
857                         return;
858                 }
859                 restart_point = 0;
860                 lmode = "r+w";
861         }
862         if (remote) {
863                 if (command("%s %s", cmd, remote) != PRELIM) {
864                         (void) signal(SIGINT, oldintr);
865                         if (oldintp)
866                                 (void) signal(SIGPIPE, oldintp);
867                         if (closefunc != NULL)
868                                 (*closefunc)(fin);
869                         return;
870                 }
871         } else
872                 if (command("%s", cmd) != PRELIM) {
873                         (void) signal(SIGINT, oldintr);
874                         if (oldintp)
875                                 (void) signal(SIGPIPE, oldintp);
876                         if (closefunc != NULL)
877                                 (*closefunc)(fin);
878                         return;
879                 }
880         dout = dataconn(lmode);
881         if (dout == NULL)
882                 goto abort;
883         (void) gettimeofday(&start, (struct timezone *)0);
884         oldintp = signal(SIGPIPE, SIG_IGN);
885         switch (curtype) {
886
887         case TYPE_I:
888         case TYPE_L:
889                 errno = d = 0;
890                 while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
891                         bytes += c;
892                         for (bufp = buf; c > 0; c -= d, bufp += d)
893                                 if ((d = secure_write(fileno(dout), bufp, c)) <= 0)
894                                         break;
895                         if (hash) {
896                                 while (bytes >= hashbytes) {
897                                         (void) putchar('#');
898                                         hashbytes += HASHBYTES;
899                                 }
900                                 (void) fflush(stdout);
901                         }
902                         if (d <= 0 ) 
903   break;
904                 }
905                 if (hash && bytes > 0) {
906                         if (bytes < HASHBYTES)
907                                 (void) putchar('#');
908                         (void) putchar('\n');
909                         (void) fflush(stdout);
910                 }
911                 if (c < 0)
912                         fprintf(stderr, "local: %s: %s\n", local,
913                                 strerror(errno));
914                 if (d < 0 || (d = secure_flush(fileno(dout))) < 0) {
915                         if (d == -1 && errno != EPIPE) 
916                                 perror("netout");
917                         bytes = -1;
918                 }
919                 break;
920
921         case TYPE_A:
922                 while ((c = getc(fin)) != EOF) {
923                         if (c == '\n') {
924                                 while (hash && (bytes >= hashbytes)) {
925                                         (void) putchar('#');
926                                         (void) fflush(stdout);
927                                         hashbytes += HASHBYTES;
928                                 }
929                                 if (ferror(dout) ||
930                                     secure_putc('\r', dout) < 0)
931                                         break;
932                                 bytes++;
933                         }
934                         if (secure_putc(c, dout) < 0)
935                                 break;
936                         bytes++;
937         /*              if (c == '\r') {                                */
938         /*              (void)  putc('\0', dout);  /* this violates rfc */
939         /*                      bytes++;                                */
940         /*              }                                               */      
941                 }
942                 if (hash) {
943                         if (bytes < hashbytes)
944                                 (void) putchar('#');
945                         (void) putchar('\n');
946                         (void) fflush(stdout);
947                 }
948                 if (ferror(fin))
949                         fprintf(stderr, "local: %s: %s\n", local,
950                                 strerror(errno));
951                 d = 0;
952                 if (ferror(dout) || (d = secure_flush(fileno(dout))) < 0) {
953                         if ((ferror(dout) || d == -1) && errno != EPIPE)
954                                 perror("netout");
955                         bytes = -1;
956                 }
957                 break;
958         }
959         (void) gettimeofday(&stop, (struct timezone *)0);
960         if (closefunc != NULL)
961                 (*closefunc)(fin);
962         (void) fclose(dout);
963         (void) getreply(0);
964         (void) signal(SIGINT, oldintr);
965         if (oldintp)
966                 (void) signal(SIGPIPE, oldintp);
967         if (bytes > 0)
968                 ptransfer("sent", bytes, &start, &stop);
969         return;
970 abort:
971         (void) gettimeofday(&stop, (struct timezone *)0);
972         (void) signal(SIGINT, oldintr);
973         if (oldintp)
974                 (void) signal(SIGPIPE, oldintp);
975         if (!cpend) {
976                 code = -1;
977                 return;
978         }
979         if (data >= 0) {
980                 (void) close(data);
981                 data = -1;
982         }
983         if (dout)
984                 (void) fclose(dout);
985         (void) getreply(0);
986         code = -1;
987         if (closefunc != NULL && fin != NULL)
988                 (*closefunc)(fin);
989         if (bytes > 0)
990                 ptransfer("sent", bytes, &start, &stop);
991 }
992
993 jmp_buf recvabort;
994
995 sigtype
996 abortrecv(sig)
997      int sig;
998 {
999
1000         mflag = 0;
1001         abrtflag = 0;
1002         printf("\nreceive aborted\nwaiting for remote to finish abort\n");
1003         (void) fflush(stdout);
1004         longjmp(recvabort, 1);
1005 }
1006
1007 recvrequest(cmd, local, remote, lmode, printnames)
1008         char *cmd, *local, *remote, *lmode;
1009 {
1010         FILE *fout, *din = 0, *popen();
1011         int (*closefunc)(), pclose(), fclose();
1012         sig_t oldintr, oldintp;
1013         int is_retr, tcrflag, bare_lfs = 0;
1014         char *gunique();
1015         static int bufsize;
1016         static char *buf;
1017         int blksize;
1018         long bytes = 0, hashbytes = HASHBYTES;
1019         register int c, d;
1020         struct timeval start, stop;
1021         struct stat st;
1022         off_t lseek();
1023         sigtype abortrecv();
1024
1025         is_retr = strcmp(cmd, "RETR") == 0;
1026         if (is_retr && verbose && printnames) {
1027                 if (local && *local != '-')
1028                         printf("local: %s ", local);
1029                 if (remote)
1030                         printf("remote: %s\n", remote);
1031         }
1032         if (proxy && is_retr) {
1033                 proxtrans(cmd, local, remote);
1034                 return;
1035         }
1036         closefunc = NULL;
1037         oldintr = NULL;
1038         oldintp = NULL;
1039         tcrflag = !crflag && is_retr;
1040         if (setjmp(recvabort)) {
1041                 while (cpend) {
1042                         (void) getreply(0);
1043                 }
1044                 if (data >= 0) {
1045                         (void) close(data);
1046                         data = -1;
1047                 }
1048                 if (oldintr)
1049                         (void) signal(SIGINT, oldintr);
1050                 code = -1;
1051                 return;
1052         }
1053         oldintr = signal(SIGINT, abortrecv);
1054         if (strcmp(local, "-") && *local != '|') {
1055                 if (access(local, 2) < 0) {
1056                         char *dir = strrchr(local, '/');
1057
1058                         if (errno != ENOENT && errno != EACCES) {
1059                                 fprintf(stderr, "local: %s: %s\n", local,
1060                                         strerror(errno));
1061                                 (void) signal(SIGINT, oldintr);
1062                                 code = -1;
1063                                 return;
1064                         }
1065                         if (dir != NULL)
1066                                 *dir = 0;
1067                         d = access(dir ? local : ".", 2);
1068                         if (dir != NULL)
1069                                 *dir = '/';
1070                         if (d < 0) {
1071                                 fprintf(stderr, "local: %s: %s\n", local,
1072                                         strerror(errno));
1073                                 (void) signal(SIGINT, oldintr);
1074                                 code = -1;
1075                                 return;
1076                         }
1077                         if (!runique && errno == EACCES &&
1078                             chmod(local, 0600) < 0) {
1079                                 fprintf(stderr, "local: %s: %s\n", local,
1080                                         strerror(errno));
1081                                 (void) signal(SIGINT, oldintr);
1082                                 (void) signal(SIGINT, oldintr);
1083                                 code = -1;
1084                                 return;
1085                         }
1086                         if (runique && errno == EACCES &&
1087                            (local = gunique(local)) == NULL) {
1088                                 (void) signal(SIGINT, oldintr);
1089                                 code = -1;
1090                                 return;
1091                         }
1092                 }
1093                 else if (runique && (local = gunique(local)) == NULL) {
1094                         (void) signal(SIGINT, oldintr);
1095                         code = -1;
1096                         return;
1097                 }
1098         }
1099         if (!is_retr) {
1100                 if (curtype != TYPE_A)
1101                         changetype(TYPE_A, 0);
1102         } else if (curtype != type)
1103                 changetype(type, 0);
1104         if (initconn()) {
1105                 (void) signal(SIGINT, oldintr);
1106                 code = -1;
1107                 return;
1108         }
1109         if (setjmp(recvabort))
1110                 goto abort;
1111         if (is_retr && restart_point &&
1112             command("REST %ld", (long) restart_point) != CONTINUE)
1113                 return;
1114         if (remote) {
1115                 if (command("%s %s", cmd, remote) != PRELIM) {
1116                         (void) signal(SIGINT, oldintr);
1117                         return;
1118                 }
1119         } else {
1120                 if (command("%s", cmd) != PRELIM) {
1121                         (void) signal(SIGINT, oldintr);
1122                         return;
1123                 }
1124         }
1125         din = dataconn("r");
1126         if (din == NULL)
1127                 goto abort;
1128         if (strcmp(local, "-") == 0)
1129                 fout = stdout;
1130         else if (*local == '|') {
1131                 oldintp = signal(SIGPIPE, SIG_IGN);
1132                 fout = popen(local + 1, "w");
1133                 if (fout == NULL) {
1134                         perror(local+1);
1135                         goto abort;
1136                 }
1137                 closefunc = pclose;
1138         } else {
1139                 fout = fopen(local, lmode);
1140                 if (fout == NULL) {
1141                         fprintf(stderr, "local: %s: %s\n", local,
1142                                 strerror(errno));
1143                         goto abort;
1144                 }
1145                 closefunc = fclose;
1146         }
1147         blksize = FTP_BUFSIZ;
1148 #ifndef NOSTBLKSIZE
1149         if (fstat(fileno(fout), &st) == 0 && st.st_blksize != 0)
1150                 blksize = st.st_blksize;
1151 #endif
1152         if (blksize > bufsize) {
1153                 if (buf)
1154                         (void) free(buf);
1155                 buf = (char *)malloc((unsigned)blksize);
1156                 if (buf == NULL) {
1157                         perror("malloc");
1158                         bufsize = 0;
1159                         goto abort;
1160                 }
1161                 bufsize = blksize;
1162         }
1163         (void) gettimeofday(&start, (struct timezone *)0);
1164         switch (curtype) {
1165
1166         case TYPE_I:
1167         case TYPE_L:
1168                 if (restart_point &&
1169                     lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
1170                         fprintf(stderr, "local: %s: %s\n", local,
1171                                 strerror(errno));
1172                         if (closefunc != NULL)
1173                                 (*closefunc)(fout);
1174                         return;
1175                 }
1176                 errno = d = 0;
1177                 while ((c = secure_read(fileno(din), buf, bufsize)) > 0) {
1178                         if ((d = write(fileno(fout), buf, c)) != c)
1179                                 break;
1180                         bytes += c;
1181                         if (hash) {
1182                                 while (bytes >= hashbytes) {
1183                                         (void) putchar('#');
1184                                         hashbytes += HASHBYTES;
1185                                 }
1186                                 (void) fflush(stdout);
1187                         }
1188                 }
1189                 if (hash && bytes > 0) {
1190                         if (bytes < HASHBYTES)
1191                                 (void) putchar('#');
1192                         (void) putchar('\n');
1193                         (void) fflush(stdout);
1194                 }
1195                 if (c < 0) {
1196                         if (c == -1 && errno != EPIPE)
1197                                 perror("netin");
1198                         bytes = -1;
1199                 }
1200                 if (d < c) {
1201                         if (d < 0)
1202                                 fprintf(stderr, "local: %s: %s\n", local,
1203                                         strerror(errno));
1204                         else
1205                                 fprintf(stderr, "%s: short write\n", local);
1206                 }
1207                 break;
1208
1209         case TYPE_A:
1210                 if (restart_point) {
1211                         register int i, n, ch;
1212
1213                         if (fseek(fout, 0L, L_SET) < 0)
1214                                 goto done;
1215                         n = restart_point;
1216                         for (i = 0; i++ < n;) {
1217                                 if ((ch = getc(fout)) == EOF)
1218                                         goto done;
1219                                 if (ch == '\n')
1220                                         i++;
1221                         }
1222                         if (fseek(fout, 0L, L_INCR) < 0) {
1223 done:
1224                                 fprintf(stderr, "local: %s: %s\n", local,
1225                                         strerror(errno));
1226                                 if (closefunc != NULL)
1227                                         (*closefunc)(fout);
1228                                 return;
1229                         }
1230                 }
1231                 while ((c = secure_getc(din)) >= 0) {
1232                         if (c == '\n')
1233                                 bare_lfs++;
1234                         while (c == '\r') {
1235                                 while (hash && (bytes >= hashbytes)) {
1236                                         (void) putchar('#');
1237                                         (void) fflush(stdout);
1238                                         hashbytes += HASHBYTES;
1239                                 }
1240                                 bytes++;
1241                                 if ((c = secure_getc(din)) != '\n' || tcrflag) {
1242                                         if (ferror(fout))
1243                                                 goto break2;
1244                                         (void) putc('\r', fout);
1245                                         if (c == '\0') {
1246                                                 bytes++;
1247                                                 goto contin2;
1248                                         }
1249                                 }
1250                         }
1251                         if (c < 0) break;
1252                         (void) putc(c, fout);
1253                         bytes++;
1254         contin2:        ;
1255                 }
1256 break2:
1257                 if (bare_lfs) {
1258                         printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs);
1259                         printf("File may not have transferred correctly.\n");
1260                 }
1261                 if (hash) {
1262                         if (bytes < hashbytes)
1263                                 (void) putchar('#');
1264                         (void) putchar('\n');
1265                         (void) fflush(stdout);
1266                 }
1267                 if (ferror(din)) {
1268                         if (errno != EPIPE)
1269                                 perror("netin");
1270                         bytes = -1;
1271                 }
1272                 if (ferror(fout) || c == -2) {
1273                     if (c != -2)
1274                         fprintf(stderr, "local: %s: %s\n", local,
1275                                 strerror(errno));
1276                         bytes = -1;
1277                 }
1278                 break;
1279         }
1280         if (closefunc != NULL)
1281                 (*closefunc)(fout);
1282         (void) signal(SIGINT, oldintr);
1283         if (oldintp)
1284                 (void) signal(SIGPIPE, oldintp);
1285         (void) gettimeofday(&stop, (struct timezone *)0);
1286         (void) fclose(din);
1287         (void) getreply(0);
1288         if (bytes > 0 && is_retr)
1289                 ptransfer("received", bytes, &start, &stop);
1290         return;
1291 abort:
1292
1293 /* abort using RFC959 recommended IP,SYNC sequence  */
1294
1295         (void) gettimeofday(&stop, (struct timezone *)0);
1296         if (oldintp)
1297                 (void) signal(SIGPIPE, oldintr);
1298         (void) signal(SIGINT, SIG_IGN);
1299         if (!cpend) {
1300                 code = -1;
1301                 (void) signal(SIGINT, oldintr);
1302                 return;
1303         }
1304
1305         abort_remote(din);
1306         code = -1;
1307         if (data >= 0) {
1308                 (void) close(data);
1309                 data = -1;
1310         }
1311         if (closefunc != NULL && fout != NULL)
1312                 (*closefunc)(fout);
1313         if (din)
1314                 (void) fclose(din);
1315         if (bytes > 0)
1316                 ptransfer("received", bytes, &start, &stop);
1317         (void) signal(SIGINT, oldintr);
1318 }
1319
1320 /*
1321  * Need to start a listen on the data channel before we send the command,
1322  * otherwise the server's connect may fail.
1323  */
1324 initconn()
1325 {
1326         register char *p, *a;
1327         int result, len, tmpno = 0;
1328         int on = 1;
1329 #ifndef NO_PASSIVE_MODE
1330         int a1,a2,a3,a4,p1,p2;
1331
1332         if (passivemode) {
1333                 data = socket(AF_INET, SOCK_STREAM, 0);
1334                 if (data < 0) {
1335                         perror("ftp: socket");
1336                         return(1);
1337                 }
1338                 if (options & SO_DEBUG &&
1339                     setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
1340                         perror("ftp: setsockopt (ignored)");
1341                 if (command("PASV") != COMPLETE) {
1342                         printf("Passive mode refused.  Turning off passive mode.\n");
1343                         passivemode = 0;
1344                         return initconn();
1345                 }
1346
1347 /*
1348  * What we've got at this point is a string of comma separated
1349  * one-byte unsigned integer values, separated by commas.
1350  * The first four are the an IP address. The fifth is the MSB
1351  * of the port number, the sixth is the LSB. From that we'll
1352  * prepare a sockaddr_in.
1353  */
1354
1355                 if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2) != 6) {
1356                         printf("Passive mode address scan failure. Shouldn't happen!\n");
1357                         return(1);
1358                 };
1359
1360                 data_addr.sin_family = AF_INET;
1361                 data_addr.sin_addr.s_addr = htonl((a1<<24)|(a2<<16)|(a3<<8)|a4);
1362                 data_addr.sin_port = htons((p1<<8)|p2);
1363
1364                 if (connect(data, (struct sockaddr *) &data_addr, sizeof(data_addr))<0) {
1365                         perror("ftp: connect");
1366                         return(1);
1367                 }
1368 #ifdef IP_TOS
1369 #ifdef IPTOS_THROUGHPUT
1370         on = IPTOS_THROUGHPUT;
1371         if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1372                 perror("ftp: setsockopt TOS (ignored)");
1373 #endif
1374 #endif
1375                 hisdataaddr = data_addr;
1376                 return(0);
1377         }
1378 #endif
1379
1380 noport:
1381         data_addr = myctladdr;
1382         if (sendport)
1383                 data_addr.sin_port = 0; /* let system pick one */ 
1384         if (data != -1)
1385                 (void) close(data);
1386         data = socket(AF_INET, SOCK_STREAM, 0);
1387         if (data < 0) {
1388                 perror("ftp: socket");
1389                 if (tmpno)
1390                         sendport = 1;
1391                 return (1);
1392         }
1393         if (!sendport)
1394                 if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
1395                         perror("ftp: setsockopt (reuse address)");
1396                         goto bad;
1397                 }
1398         if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
1399                 perror("ftp: bind");
1400                 goto bad;
1401         }
1402         if (options & SO_DEBUG &&
1403             setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
1404                 perror("ftp: setsockopt (ignored)");
1405         len = sizeof (data_addr);
1406         if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1407                 perror("ftp: getsockname");
1408                 goto bad;
1409         }
1410         if (listen(data, 1) < 0)
1411                 perror("ftp: listen");
1412         if (sendport) {
1413                 a = (char *)&data_addr.sin_addr;
1414                 p = (char *)&data_addr.sin_port;
1415 #define UC(b)   (((int)b)&0xff)
1416                 result =
1417                     command("PORT %d,%d,%d,%d,%d,%d",
1418                       UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1419                       UC(p[0]), UC(p[1]));
1420                 if (result == ERROR && sendport == -1) {
1421                         sendport = 0;
1422                         tmpno = 1;
1423                         goto noport;
1424                 }
1425                 return (result != COMPLETE);
1426         }
1427         if (tmpno)
1428                 sendport = 1;
1429 #ifdef IP_TOS
1430 #ifdef IPTOS_THROUGHPUT
1431         on = IPTOS_THROUGHPUT;
1432         if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1433                 perror("ftp: setsockopt TOS (ignored)");
1434 #endif
1435 #endif
1436         return (0);
1437 bad:
1438         (void) close(data), data = -1;
1439         if (tmpno)
1440                 sendport = 1;
1441         return (1);
1442 }
1443
1444 FILE *
1445 dataconn(lmode)
1446         char *lmode;
1447 {
1448         int s, fromlen = sizeof (hisdataaddr), tos;
1449
1450 #ifndef NO_PASSIVE_MODE
1451 if (passivemode)
1452         return (fdopen(data, lmode));
1453 #endif
1454         s = accept(data, (struct sockaddr *) &hisdataaddr, &fromlen);
1455         if (s < 0) {
1456                 perror("ftp: accept");
1457                 (void) close(data), data = -1;
1458                 return (NULL);
1459         }
1460         (void) close(data);
1461         data = s;
1462 #ifdef IP_TOS
1463 #ifdef IPTOS_THROUGHPUT
1464         tos = IPTOS_THROUGHPUT;
1465         if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1466                 perror("ftp: setsockopt TOS (ignored)");
1467 #endif
1468 #endif
1469         return (fdopen(data, lmode));
1470 }
1471
1472 ptransfer(direction, bytes, t0, t1)
1473         char *direction;
1474         long bytes;
1475         struct timeval *t0, *t1;
1476 {
1477         struct timeval td;
1478         float s, kbs;
1479
1480         if (verbose) {
1481                 tvsub(&td, t1, t0);
1482                 s = td.tv_sec + (td.tv_usec / 1000000.);
1483 #define nz(x)   ((x) == 0 ? 1 : (x))
1484                 kbs = (bytes / nz(s))/1024.0;
1485                 printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
1486                     bytes, direction, s, kbs);
1487         }
1488 }
1489
1490 /*tvadd(tsum, t0)
1491         struct timeval *tsum, *t0;
1492 {
1493
1494         tsum->tv_sec += t0->tv_sec;
1495         tsum->tv_usec += t0->tv_usec;
1496         if (tsum->tv_usec > 1000000)
1497                 tsum->tv_sec++, tsum->tv_usec -= 1000000;
1498 } */
1499
1500 tvsub(tdiff, t1, t0)
1501         struct timeval *tdiff, *t1, *t0;
1502 {
1503
1504         tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
1505         tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
1506         if (tdiff->tv_usec < 0)
1507                 tdiff->tv_sec--, tdiff->tv_usec += 1000000;
1508 }
1509
1510 sigtype
1511 psabort(sig)
1512         int sig;
1513 {
1514         extern int abrtflag;
1515
1516         abrtflag++;
1517 }
1518
1519 pswitch(flag)
1520         int flag;
1521 {
1522         extern int proxy, abrtflag;
1523         sig_t oldintr;
1524         static struct comvars {
1525                 int connect;
1526                 char name[MAXHOSTNAMELEN];
1527                 struct sockaddr_in mctl;
1528                 struct sockaddr_in hctl;
1529                 FILE *in;
1530                 FILE *out;
1531                 int tpe;
1532                 int curtpe;
1533                 int cpnd;
1534                 int sunqe;
1535                 int runqe;
1536                 int mcse;
1537                 int ntflg;
1538                 char nti[17];
1539                 char nto[17];
1540                 int mapflg;
1541                 char mi[MAXPATHLEN];
1542                 char mo[MAXPATHLEN];
1543                 char *authtype;
1544                 int lvl;
1545 #ifdef KRB5_KRB4_COMPAT
1546                 C_Block session;
1547                 Key_schedule schedule;
1548 #endif /* KRB5_KRB4_COMPAT */
1549         } proxstruct, tmpstruct;
1550         struct comvars *ip, *op;
1551
1552         abrtflag = 0;
1553         oldintr = signal(SIGINT, psabort);
1554         if (flag) {
1555                 if (proxy)
1556                         return;
1557                 ip = &tmpstruct;
1558                 op = &proxstruct;
1559                 proxy++;
1560         } else {
1561                 if (!proxy)
1562                         return;
1563                 ip = &proxstruct;
1564                 op = &tmpstruct;
1565                 proxy = 0;
1566         }
1567         ip->connect = connected;
1568         connected = op->connect;
1569         if (hostname) {
1570                 (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1571                 ip->name[strlen(ip->name)] = '\0';
1572         } else
1573                 ip->name[0] = 0;
1574         hostname = op->name;
1575         ip->hctl = hisctladdr;
1576         hisctladdr = op->hctl;
1577         ip->mctl = myctladdr;
1578         myctladdr = op->mctl;
1579         ip->in = cin;
1580         cin = op->in;
1581         ip->out = cout;
1582         cout = op->out;
1583         ip->tpe = type;
1584         type = op->tpe;
1585         ip->curtpe = curtype;
1586         curtype = op->curtpe;
1587         ip->cpnd = cpend;
1588         cpend = op->cpnd;
1589         ip->sunqe = sunique;
1590         sunique = op->sunqe;
1591         ip->runqe = runique;
1592         runique = op->runqe;
1593         ip->mcse = mcase;
1594         mcase = op->mcse;
1595         ip->ntflg = ntflag;
1596         ntflag = op->ntflg;
1597         (void) strncpy(ip->nti, ntin, 16);
1598         (ip->nti)[strlen(ip->nti)] = '\0';
1599         (void) strcpy(ntin, op->nti);
1600         (void) strncpy(ip->nto, ntout, 16);
1601         (ip->nto)[strlen(ip->nto)] = '\0';
1602         (void) strcpy(ntout, op->nto);
1603         ip->mapflg = mapflag;
1604         mapflag = op->mapflg;
1605         (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
1606         (ip->mi)[strlen(ip->mi)] = '\0';
1607         (void) strcpy(mapin, op->mi);
1608         (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
1609         (ip->mo)[strlen(ip->mo)] = '\0';
1610         (void) strcpy(mapout, op->mo);
1611         ip->authtype = auth_type;
1612         auth_type = op->authtype;
1613         ip->lvl = level;
1614         level = op->lvl;
1615         if (!level)
1616                 level = 1;
1617 #ifdef KRB5_KRB4_COMPAT
1618         memcpy(ip->session, cred.session, sizeof(cred.session));
1619         memcpy(cred.session, op->session, sizeof(cred.session));
1620         memcpy(ip->schedule, schedule, sizeof(schedule));
1621         memcpy(schedule, op->schedule, sizeof(schedule));
1622 #endif /* KRB5_KRB4_COMPAT */
1623         (void) signal(SIGINT, oldintr);
1624         if (abrtflag) {
1625                 abrtflag = 0;
1626                 (*oldintr)(SIGINT);
1627         }
1628 }
1629
1630 jmp_buf ptabort;
1631 int ptabflg;
1632
1633 sigtype
1634 abortpt(sig)
1635         int sig;
1636 {
1637         printf("\n");
1638         (void) fflush(stdout);
1639         ptabflg++;
1640         mflag = 0;
1641         abrtflag = 0;
1642         longjmp(ptabort, 1);
1643 }
1644
1645 proxtrans(cmd, local, remote)
1646         char *cmd, *local, *remote;
1647 {
1648         sig_t oldintr;
1649         int secndflag = 0, prox_type, nfnd;
1650         extern jmp_buf ptabort;
1651         char *cmd2;
1652          fd_set mask;
1653         sigtype abortpt();
1654
1655         if (strcmp(cmd, "RETR"))
1656                 cmd2 = "RETR";
1657         else
1658                 cmd2 = runique ? "STOU" : "STOR";
1659         if ((prox_type = type) == 0) {
1660                 if (unix_server && unix_proxy)
1661                         prox_type = TYPE_I;
1662                 else
1663                         prox_type = TYPE_A;
1664         }
1665         if (curtype != prox_type)
1666                 changetype(prox_type, 1);
1667         if (command("PASV") != COMPLETE) {
1668                 printf("proxy server does not support third party transfers.\n");
1669                 return;
1670         }
1671         pswitch(0);
1672         if (!connected) {
1673                 printf("No primary connection\n");
1674                 pswitch(1);
1675                 code = -1;
1676                 return;
1677         }
1678         if (curtype != prox_type)
1679                 changetype(prox_type, 1);
1680         if (command("PORT %s", pasv) != COMPLETE) {
1681                 pswitch(1);
1682                 return;
1683         }
1684         if (setjmp(ptabort))
1685                 goto abort;
1686         oldintr = signal(SIGINT, abortpt);
1687         if (command("%s %s", cmd, remote) != PRELIM) {
1688                 (void) signal(SIGINT, oldintr);
1689                 pswitch(1);
1690                 return;
1691         }
1692         sleep(2);
1693         pswitch(1);
1694         secndflag++;
1695         if (command("%s %s", cmd2, local) != PRELIM)
1696                 goto abort;
1697         ptflag++;
1698         (void) getreply(0);
1699         pswitch(0);
1700         (void) getreply(0);
1701         (void) signal(SIGINT, oldintr);
1702         pswitch(1);
1703         ptflag = 0;
1704         printf("local: %s remote: %s\n", local, remote);
1705         return;
1706 abort:
1707         (void) signal(SIGINT, SIG_IGN);
1708         ptflag = 0;
1709         if (strcmp(cmd, "RETR") && !proxy)
1710                 pswitch(1);
1711         else if (!strcmp(cmd, "RETR") && proxy)
1712                 pswitch(0);
1713         if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
1714                 if (command("%s %s", cmd2, local) != PRELIM) {
1715                         pswitch(0);
1716                         if (cpend)
1717                                 abort_remote((FILE *) NULL);
1718                 }
1719                 pswitch(1);
1720                 if (ptabflg)
1721                         code = -1;
1722                 (void) signal(SIGINT, oldintr);
1723                 return;
1724         }
1725         if (cpend)
1726                 abort_remote((FILE *) NULL);
1727         pswitch(!proxy);
1728         if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
1729                 if (command("%s %s", cmd2, local) != PRELIM) {
1730                         pswitch(0);
1731                         if (cpend)
1732                                 abort_remote((FILE *) NULL);
1733                         pswitch(1);
1734                         if (ptabflg)
1735                                 code = -1;
1736                         (void) signal(SIGINT, oldintr);
1737                         return;
1738                 }
1739         }
1740         if (cpend)
1741                 abort_remote((FILE *) NULL);
1742         pswitch(!proxy);
1743         if (cpend) {
1744                 FD_ZERO(&mask);
1745                 FD_SET(fileno(cin), &mask);
1746                 if ((nfnd = empty(&mask, 10)) <= 0) {
1747                         if (nfnd < 0) {
1748                                 perror("abort");
1749                         }
1750                         if (ptabflg)
1751                                 code = -1;
1752                         lostpeer();
1753                 }
1754                 (void) getreply(0);
1755                 (void) getreply(0);
1756         }
1757         if (proxy)
1758                 pswitch(0);
1759         pswitch(1);
1760         if (ptabflg)
1761                 code = -1;
1762         (void) signal(SIGINT, oldintr);
1763 }
1764
1765 reset()
1766 {
1767    fd_set mask;
1768         int nfnd = 1;
1769
1770         FD_ZERO(&mask);
1771         while (nfnd > 0) {
1772                 FD_SET(fileno(cin), &mask);
1773                 if ((nfnd = empty(&mask,0)) < 0) {
1774                         perror("reset");
1775                         code = -1;
1776                         lostpeer();
1777                 }
1778                 else if (nfnd) {
1779                         (void) getreply(0);
1780                 }
1781         }
1782 }
1783
1784 char *
1785 gunique(local)
1786         char *local;
1787 {
1788         static char new[MAXPATHLEN];
1789         char *cp = strrchr(local, '/');
1790         int d, count=0;
1791         char ext = '1';
1792
1793         if (cp)
1794                 *cp = '\0';
1795         d = access(cp ? local : ".", 2);
1796         if (cp)
1797                 *cp = '/';
1798         if (d < 0) {
1799                 fprintf(stderr, "local: %s: %s\n", local, strerror(errno));
1800                 return((char *) 0);
1801         }
1802         (void) strcpy(new, local);
1803         cp = new + strlen(new);
1804         *cp++ = '.';
1805         while (!d) {
1806                 if (++count == 100) {
1807                         printf("runique: can't find unique file name.\n");
1808                         return((char *) 0);
1809                 }
1810                 *cp++ = ext;
1811                 *cp = '\0';
1812                 if (ext == '9')
1813                         ext = '0';
1814                 else
1815                         ext++;
1816                 if ((d = access(new, 0)) < 0)
1817                         break;
1818                 if (ext != '0')
1819                         cp--;
1820                 else if (*(cp - 2) == '.')
1821                         *(cp - 1) = '1';
1822                 else {
1823                         *(cp - 2) = *(cp - 2) + 1;
1824                         cp--;
1825                 }
1826         }
1827         return(new);
1828 }
1829
1830 #ifdef KRB5_KRB4_COMPAT
1831 char realm[REALM_SZ + 1];
1832 #endif /* KRB5_KRB4_COMPAT */
1833
1834 #ifdef GSSAPI
1835 /* for testing, we don't have an ftp key yet */
1836 char* gss_services[] = { "ftp", "host", 0 };
1837 #endif /* GSSAPI */
1838
1839 do_auth()
1840 {
1841         extern int setsafe();
1842         int oldverbose = verbose;
1843 #ifdef KRB5_KRB4_COMPAT
1844         char *service, inst[INST_SZ];
1845         u_long cksum, checksum = (u_long) getpid();
1846 #endif /* KRB5_KRB4_COMPAT */
1847 #if defined(KRB5_KRB4_COMPAT) || defined(GSSAPI)
1848         u_char out_buf[FTP_BUFSIZ];
1849         int i;
1850 #endif /* KRB5_KRB4_COMPAT */
1851
1852         if (auth_type) return(1);       /* auth already succeeded */
1853
1854         /* Other auth types go here ... */
1855
1856 #ifdef GSSAPI
1857         if (command("AUTH %s", "GSSAPI") == CONTINUE) {
1858           OM_uint32 maj_stat, min_stat;
1859           gss_name_t target_name;
1860           gss_buffer_desc send_tok, recv_tok, *token_ptr;
1861           char stbuf[FTP_BUFSIZ];
1862           char **service_name, **end_service_name;
1863           int comcode;
1864           struct gss_channel_bindings_struct chan;
1865           chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32  */ 
1866           chan.initiator_address.length = 4;
1867           chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
1868           chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
1869           chan.acceptor_address.length = 4;
1870           chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
1871           chan.application_data.length = 0;
1872           chan.application_data.value = 0;
1873
1874           for (end_service_name = gss_services; *end_service_name; )
1875             end_service_name++;
1876           end_service_name--;
1877
1878           if (verbose)
1879             printf("%s accepted as authentication type\n", "GSSAPI");
1880           
1881           /* blob from gss-client */
1882             
1883           
1884           for (service_name = gss_services; *service_name; service_name++) {
1885             
1886             /* ftp@hostname first, the host@hostname */
1887             /* the V5 GSSAPI binding canonicalizes this for us... */
1888             sprintf(stbuf, "%s@%s", *service_name, hostname);
1889             if (debug)
1890               fprintf(stderr, "Trying to authenticate to <%s>\n", stbuf);
1891
1892             send_tok.value = stbuf;
1893             send_tok.length = strlen(stbuf) + 1;
1894             maj_stat = gss_import_name(&min_stat, &send_tok,
1895                                        gss_nt_service_name, &target_name);
1896             
1897             if (maj_stat != GSS_S_COMPLETE) {
1898                     user_gss_error(maj_stat, min_stat, "parsing name");
1899                     secure_error("name parsed <%s>\n", stbuf);
1900                     continue;
1901             }
1902
1903             token_ptr = GSS_C_NO_BUFFER;
1904             gcontext = GSS_C_NO_CONTEXT; /* structure copy */
1905             
1906             do {
1907               if (debug)
1908                 fprintf(stderr, "calling gss_init_sec_context\n");
1909               maj_stat =
1910                 gss_init_sec_context(&min_stat,
1911                                      GSS_C_NO_CREDENTIAL,
1912                                      &gcontext,
1913                                      target_name,
1914                                      GSS_C_NULL_OID,
1915                                      GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
1916                                      (forward ? GSS_C_DELEG_FLAG : 0),
1917                                      0,
1918                                      &chan,     /* channel bindings */
1919                                      token_ptr,
1920                                      NULL,      /* ignore mech type */
1921                                      &send_tok,
1922                                      NULL,      /* ignore ret_flags */
1923                                      NULL);     /* ignore time_rec */
1924               
1925
1926               if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED){
1927                 if (service_name == end_service_name)
1928                   user_gss_error(maj_stat, min_stat, "initializing context");
1929                 (void) gss_release_name(&min_stat, &target_name);
1930                 /* could just be that we missed on the service name */
1931                 goto outer_loop;
1932               }
1933             
1934               if (send_tok.length != 0) {
1935                 int len = send_tok.length;
1936                 reply_parse = "ADAT="; /* for command() later */
1937                 oldverbose = verbose;
1938                 verbose = 0;
1939                 kerror = radix_encode(send_tok.value, out_buf, &len, 0);
1940                 if (kerror)  {
1941                   fprintf(stderr, "Base 64 encoding failed: %s\n",
1942                           radix_error(kerror));
1943                 } else if ((comcode = command("ADAT %s", out_buf))!=COMPLETE
1944                            /* && comcode != 3 (335)*/) {
1945                   fprintf(stderr, "GSSAPI ADAT failed\n");
1946                   /* force out of loop */
1947                   maj_stat = GSS_S_FAILURE;
1948                 } else if (!reply_parse) {
1949                   fprintf(stderr,
1950                           "No authentication data received from server\n");
1951                   if (maj_stat == GSS_S_COMPLETE) {
1952                     fprintf(stderr, "...but no more was needed\n");
1953                     goto gss_complete_loop;
1954                   } else {
1955                     user_gss_error(maj_stat, min_stat, "no reply, huh?");
1956                     goto gss_complete_loop;
1957                   }
1958                 } else if (kerror = radix_encode(reply_parse,out_buf,&i,1)) {
1959                   fprintf(stderr, "Base 64 decoding failed: %s\n",
1960                           radix_error(kerror));
1961                 } else {
1962                   /* everything worked */
1963                   token_ptr = &recv_tok;
1964                   recv_tok.value = out_buf;
1965                   recv_tok.length = i;
1966                   continue;
1967                 }
1968
1969                 /* get out of loop clean */
1970               gss_complete_loop:
1971                 service_name = end_service_name;
1972                 gss_release_buffer(&min_stat, &send_tok);
1973                 gss_release_name(&min_stat, &target_name);
1974                 goto outer_loop;
1975               }
1976             } while (maj_stat == GSS_S_CONTINUE_NEEDED);
1977     outer_loop:
1978             if (maj_stat == GSS_S_COMPLETE)
1979                 break;
1980           }
1981           verbose = oldverbose;
1982           if (maj_stat == GSS_S_COMPLETE) {
1983             if (verbose)
1984               printf("GSSAPI authentication succeeded\n");
1985             reply_parse = NULL;
1986             auth_type = "GSSAPI";
1987             return(1);
1988           } else {
1989             fprintf(stderr, "GSSAPI authentication failed\n");
1990             verbose = oldverbose;
1991             reply_parse = NULL;
1992           }
1993         }
1994 #endif /* GSSAPI */
1995 #ifdef KRB5_KRB4_COMPAT
1996         if (command("AUTH %s", "KERBEROS_V4") == CONTINUE) {
1997             if (verbose)
1998                 printf("%s accepted as authentication type\n", "KERBEROS_V4");
1999
2000             strcpy(inst, (char *) krb_get_phost(hostname));
2001             if (realm[0] == '\0')
2002                 strcpy(realm, (char *) krb_realmofhost(hostname));
2003             if ((kerror = krb_mk_req(&ticket, service = "ftp",
2004                                         inst, realm, checksum))
2005                 && (kerror != KDC_PR_UNKNOWN ||
2006                 (kerror = krb_mk_req(&ticket, service = "rcmd",
2007                                         inst, realm, checksum))))
2008                         fprintf(stderr, "Kerberos V4 krb_mk_req failed: %s\n",
2009                                         krb_get_err_text(kerror));
2010             else if (kerror = krb_get_cred(service, inst, realm, &cred))
2011                         fprintf(stderr, "Kerberos V4 krb_get_cred failed: %s\n",
2012                                         krb_get_err_text(kerror));
2013             else {
2014                 key_sched(cred.session, schedule);
2015                 reply_parse = "ADAT=";
2016                 oldverbose = verbose;
2017                 verbose = 0;
2018                 i = ticket.length;
2019                 if (kerror = radix_encode(ticket.dat, out_buf, &i, 0))
2020                         fprintf(stderr, "Base 64 encoding failed: %s\n",
2021                                         radix_error(kerror));
2022                 else if (command("ADAT %s", out_buf) != COMPLETE)
2023                         fprintf(stderr, "Kerberos V4 authentication failed\n");
2024                 else if (!reply_parse)
2025                         fprintf(stderr,
2026                                "No authentication data received from server\n");
2027                 else if (kerror = radix_encode(reply_parse, out_buf, &i, 1))
2028                         fprintf(stderr, "Base 64 decoding failed: %s\n",
2029                                         radix_error(kerror));
2030                 else if (kerror = krb_rd_safe(out_buf, i, &cred.session,
2031                                             &hisctladdr, &myctladdr, &msg_data))
2032                         fprintf(stderr, "Kerberos V4 krb_rd_safe failed: %s\n",
2033                                         krb_get_err_text(kerror));
2034                 else {
2035                     /* fetch the (modified) checksum */
2036                     (void) memcpy(&cksum, msg_data.app_data, sizeof(cksum));
2037                     if (ntohl(cksum) == checksum + 1) {
2038                         verbose = oldverbose;
2039                         if (verbose)
2040                            printf("Kerberos V4 authentication succeeded\n");
2041                         reply_parse = NULL;
2042                         auth_type = "KERBEROS_V4";
2043                         return(1);
2044                     } else fprintf(stderr,
2045                                 "Kerberos V4 mutual authentication failed\n");
2046                 }
2047                 verbose = oldverbose;
2048                 reply_parse = NULL;
2049             }
2050         } else  fprintf(stderr, "%s rejected as an authentication type\n",
2051                                 "KERBEROS_V4");
2052 #endif /* KRB5_KRB4_COMPAT */
2053
2054         /* Other auth types go here ... */
2055
2056         return(0);
2057 }
2058
2059 setpbsz(size)
2060 unsigned int size;
2061 {
2062         int oldverbose;
2063
2064         if (ucbuf) (void) free(ucbuf);
2065         actualbuf = size;
2066         while ((ucbuf = (unsigned char *)malloc(actualbuf)) == NULL)
2067                 if (actualbuf)
2068                         actualbuf >>= 2;
2069                 else {
2070                         perror("Error while trying to malloc PROT buffer:");
2071                         exit(1);
2072                 }
2073         oldverbose = verbose;
2074         verbose = 0;
2075         reply_parse = "PBSZ=";
2076         if (command("PBSZ %u", actualbuf) != COMPLETE)
2077                 fatal("Cannot set PROT buffer size");
2078         if (reply_parse) {
2079                 if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf)
2080                         maxbuf = actualbuf;
2081         } else  maxbuf = actualbuf;
2082         reply_parse = NULL;
2083         verbose = oldverbose;
2084 }
2085
2086 abort_remote(din)
2087 FILE *din;
2088 {
2089         char buf[FTP_BUFSIZ];
2090         int nfnd;
2091         fd_set mask;
2092
2093         /*
2094          * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
2095          * after urgent byte rather than before as is protocol now
2096          */
2097         sprintf(buf, "%c%c%c", IAC, IP, IAC);
2098         if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
2099                 perror("abort");
2100         putc(DM, cout);
2101         (void) secure_command("ABOR");
2102         FD_ZERO(&mask);
2103         FD_SET(fileno(cin), &mask);
2104         if (din) { 
2105                 FD_SET(fileno(din), &mask);
2106         }
2107         if ((nfnd = empty(&mask, 10)) <= 0) {
2108                 if (nfnd < 0) {
2109                         perror("abort");
2110                 }
2111                 if (ptabflg)
2112                         code = -1;
2113                 lostpeer();
2114         }
2115         if (din && FD_ISSET(fileno(din), &mask)) {
2116                 /* Security: No threat associated with this read. */
2117                 while (read(fileno(din), buf, FTP_BUFSIZ) > 0)
2118                         /* LOOP */;
2119         }
2120         if (getreply(0) == ERROR && code == 552) {
2121                 /* 552 needed for nic style abort */
2122                 (void) getreply(0);
2123         }
2124         (void) getreply(0);
2125 }
2126 #ifdef GSSAPI
2127 user_gss_error(maj_stat, min_stat, s)
2128 OM_uint32 maj_stat, min_stat;
2129 char *s;
2130 {
2131         /* a lot of work just to report the error */
2132         OM_uint32 gmaj_stat, gmin_stat;
2133         gss_buffer_desc msg;
2134         int msg_ctx;
2135         msg_ctx = 0;
2136         while (!msg_ctx) {
2137                 gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
2138                                                GSS_C_GSS_CODE,
2139                                                GSS_C_NULL_OID,
2140                                                &msg_ctx, &msg);
2141                 if ((gmaj_stat == GSS_S_COMPLETE)||
2142                     (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
2143                         fprintf(stderr, "GSSAPI error major: %s\n",
2144                                 (char*)msg.value);
2145                         (void) gss_release_buffer(&gmin_stat, &msg);
2146                 }
2147                 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
2148                         break;
2149         }
2150         msg_ctx = 0;
2151         while (!msg_ctx) {
2152                 gmaj_stat = gss_display_status(&gmin_stat, min_stat,
2153                                                GSS_C_MECH_CODE,
2154                                                GSS_C_NULL_OID,
2155                                                &msg_ctx, &msg);
2156                 if ((gmaj_stat == GSS_S_COMPLETE)||
2157                     (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
2158                         fprintf(stderr, "GSSAPI error minor: %s\n",
2159                                 (char*)msg.value);
2160                         (void) gss_release_buffer(&gmin_stat, &msg);
2161                 }
2162                 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
2163                         break;
2164         }
2165         fprintf(stderr, "GSSAPI error: %s\n", s);
2166 }
2167
2168 secure_gss_error(maj_stat, min_stat, s)
2169      OM_uint32 maj_stat, min_stat;
2170      char *s;
2171 {
2172   return user_gss_error(maj_stat, min_stat, s);
2173 }
2174 #endif /* GSSAPI */