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