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