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